From ab95bc2d17507d308a6911aa5016e914887bc92a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radek=20Ma=C5=88=C3=A1k?= Date: Tue, 17 Mar 2026 15:42:30 +0100 Subject: [PATCH 1/3] Bump to k8s to 1.35.1 dependencies --- Makefile | 2 +- go.mod | 344 ++++++++++++---------- go.sum | 765 +++++++++++++++++++++++++------------------------ tools/tools.go | 2 +- 4 files changed, 584 insertions(+), 529 deletions(-) diff --git a/Makefile b/Makefile index 10551279b..ac4bee3c3 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ ENVTEST_K8S_VERSION = 1.33.2 PROJECT_DIR := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST)))) CONTROLLER_GEN = go run ${PROJECT_DIR}/vendor/sigs.k8s.io/controller-tools/cmd/controller-gen ENVTEST = go run ${PROJECT_DIR}/vendor/sigs.k8s.io/controller-runtime/tools/setup-envtest -GOLANGCI_LINT = go run ${PROJECT_DIR}/vendor/github.com/golangci/golangci-lint/cmd/golangci-lint +GOLANGCI_LINT = go run ${PROJECT_DIR}/vendor/github.com/golangci/golangci-lint/v2/cmd/golangci-lint HOME ?= /tmp/kubebuilder-testing ifeq ($(HOME), /) diff --git a/go.mod b/go.mod index b2d04e994..008d14556 100644 --- a/go.mod +++ b/go.mod @@ -1,53 +1,63 @@ module github.com/openshift/cluster-cloud-controller-manager-operator -go 1.24.6 +go 1.25.0 + +// https://github.com/kubernetes/cloud-provider-vsphere/pull/1710 +// Upstream release 1.35.0 vendors k8s 1.36-alpha. This is a patched release to vendor k8s 1.35.1 +replace k8s.io/cloud-provider-vsphere => github.com/openshift-cloud-team/cloud-provider-vsphere v1.19.1-0.20260317135518-758abc9d59a5 require ( github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 github.com/go-logr/logr v1.4.3 - github.com/golangci/golangci-lint v1.62.2 + github.com/golangci/golangci-lint/v2 v2.11.1 github.com/onsi/ginkgo/v2 v2.28.1 github.com/onsi/gomega v1.39.1 - github.com/openshift/api v0.0.0-20260213155647-8fe9fe363807 - github.com/openshift/client-go v0.0.0-20260108185524-48f4ccfc4e13 - github.com/openshift/cluster-api-actuator-pkg/testutils v0.0.0-20250122171707-86066d47a264 - github.com/openshift/controller-runtime-common v0.0.0-20260213175913-767fef058eca - github.com/openshift/library-go v0.0.0-20260213153706-03f1709971c5 - github.com/spf13/cobra v1.9.1 - github.com/spf13/pflag v1.0.9 + github.com/openshift/api v0.0.0-20260306002634-d3bbdada155c + github.com/openshift/client-go v0.0.0-20260306160707-3935d929fc7d + github.com/openshift/cluster-api-actuator-pkg/testutils v0.0.0-20260310144400-bec013a007a8 + github.com/openshift/controller-runtime-common v0.0.0-20260307102856-5db94f69ad3a + github.com/openshift/library-go v0.0.0-20260311094140-ac826d10cb40 + github.com/spf13/cobra v1.10.2 + github.com/spf13/pflag v1.0.10 github.com/stretchr/testify v1.11.1 gopkg.in/gcfg.v1 v1.2.3 - gopkg.in/ini.v1 v1.67.0 + gopkg.in/ini.v1 v1.67.1 gopkg.in/yaml.v2 v2.4.0 - k8s.io/api v0.34.3 - k8s.io/apiextensions-apiserver v0.34.3 - k8s.io/apimachinery v0.34.3 - k8s.io/client-go v0.34.3 - k8s.io/cloud-provider-aws v1.34.1-0.20250912204608-8a0025b4efb1 + k8s.io/api v0.35.1 + k8s.io/apiextensions-apiserver v0.35.1 + k8s.io/apimachinery v0.35.1 + k8s.io/client-go v0.35.1 + k8s.io/cloud-provider-aws v1.35.1 k8s.io/cloud-provider-vsphere v1.34.0 - k8s.io/component-base v0.34.3 - k8s.io/controller-manager v0.34.0 - k8s.io/klog/v2 v2.130.1 - k8s.io/utils v0.0.0-20260108192941-914a6e750570 - sigs.k8s.io/cloud-provider-azure v1.34.1 - sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.9.2 - sigs.k8s.io/controller-runtime v0.22.5 + k8s.io/component-base v0.35.1 + k8s.io/controller-manager v0.35.1 + k8s.io/klog/v2 v2.140.0 + k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 + sigs.k8s.io/cloud-provider-azure v1.35.1 + sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.13.0 + sigs.k8s.io/controller-runtime v0.23.2 sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20251103140007-7a1b16d039d2 - sigs.k8s.io/controller-tools v0.17.1 + sigs.k8s.io/controller-tools v0.20.1 sigs.k8s.io/yaml v1.6.0 ) require ( - 4d63.com/gocheckcompilerdirectives v1.2.1 // indirect - 4d63.com/gochecknoglobals v0.2.1 // indirect + 4d63.com/gocheckcompilerdirectives v1.3.0 // indirect + 4d63.com/gochecknoglobals v0.2.2 // indirect cel.dev/expr v0.24.0 // indirect - github.com/4meepo/tagalign v1.3.4 // indirect - github.com/Abirdcfly/dupword v0.1.3 // indirect - github.com/Antonboom/errname v1.0.0 // indirect - github.com/Antonboom/nilnil v1.0.0 // indirect - github.com/Antonboom/testifylint v1.5.2 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.11.0 // indirect + codeberg.org/chavacava/garif v0.2.0 // indirect + codeberg.org/polyfloyd/go-errorlint v1.9.0 // indirect + dev.gaijin.team/go/exhaustruct/v4 v4.0.0 // indirect + dev.gaijin.team/go/golib v0.6.0 // indirect + github.com/4meepo/tagalign v1.4.3 // indirect + github.com/Abirdcfly/dupword v0.1.7 // indirect + github.com/AdminBenni/iota-mixing v1.0.0 // indirect + github.com/AlwxSin/noinlineerr v1.0.5 // indirect + github.com/Antonboom/errname v1.1.1 // indirect + github.com/Antonboom/nilnil v1.1.1 // indirect + github.com/Antonboom/testifylint v1.6.4 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2 v2.2.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6 v6.4.0 // indirect @@ -58,25 +68,27 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6 v6.2.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.3.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2 v2.0.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.4.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0 // indirect github.com/Azure/msi-dataplane v0.4.3 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0 // indirect - github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect - github.com/Crocmagnon/fatcontext v0.5.3 // indirect - github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect - github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 // indirect + github.com/BurntSushi/toml v1.6.0 // indirect + github.com/Djarvur/go-err113 v0.1.1 // indirect github.com/Masterminds/semver/v3 v3.4.0 // indirect - github.com/OpenPeeDeeP/depguard/v2 v2.2.0 // indirect - github.com/alecthomas/go-check-sumtype v0.2.0 // indirect - github.com/alexkohler/nakedret/v2 v2.0.5 // indirect - github.com/alexkohler/prealloc v1.0.0 // indirect + github.com/MirrexOne/unqueryvet v1.5.4 // indirect + github.com/OpenPeeDeeP/depguard/v2 v2.2.1 // indirect + github.com/alecthomas/chroma/v2 v2.23.1 // indirect + github.com/alecthomas/go-check-sumtype v0.3.1 // indirect + github.com/alexkohler/nakedret/v2 v2.0.6 // indirect + github.com/alexkohler/prealloc v1.1.0 // indirect + github.com/alfatraining/structtag v1.0.0 // indirect github.com/alingse/asasalint v0.0.11 // indirect + github.com/alingse/nilnesserr v0.2.0 // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect - github.com/ashanbrown/forbidigo v1.6.0 // indirect - github.com/ashanbrown/makezero v1.1.1 // indirect - github.com/aws/aws-sdk-go-v2 v1.38.3 // indirect + github.com/ashanbrown/forbidigo/v2 v2.3.0 // indirect + github.com/ashanbrown/makezero/v2 v2.1.0 // indirect + github.com/aws/aws-sdk-go-v2 v1.39.2 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.31 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.6 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.6 // indirect @@ -87,38 +99,46 @@ require ( github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.6 // indirect github.com/aws/aws-sdk-go-v2/service/kms v1.41.0 // indirect github.com/aws/smithy-go v1.23.0 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bkielbasa/cyclop v1.2.3 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/blizzy78/varnamelen v0.8.0 // indirect - github.com/bombsimon/wsl/v4 v4.4.1 // indirect - github.com/breml/bidichk v0.3.2 // indirect - github.com/breml/errchkjson v0.4.0 // indirect - github.com/butuzov/ireturn v0.3.0 // indirect - github.com/butuzov/mirror v1.2.0 // indirect - github.com/catenacyber/perfsprint v0.7.1 // indirect - github.com/ccojocar/zxcvbn-go v1.0.2 // indirect + github.com/bombsimon/wsl/v4 v4.7.0 // indirect + github.com/bombsimon/wsl/v5 v5.6.0 // indirect + github.com/breml/bidichk v0.3.3 // indirect + github.com/breml/errchkjson v0.4.1 // indirect + github.com/butuzov/ireturn v0.4.0 // indirect + github.com/butuzov/mirror v1.3.0 // indirect + github.com/catenacyber/perfsprint v0.10.1 // indirect + github.com/ccojocar/zxcvbn-go v1.0.4 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/charithe/durationcheck v0.0.10 // indirect - github.com/chavacava/garif v0.1.0 // indirect - github.com/ckaznocha/intrange v0.2.1 // indirect - github.com/curioswitch/go-reassign v0.2.0 // indirect - github.com/daixiang0/gci v0.13.5 // indirect + github.com/charithe/durationcheck v0.0.11 // indirect + github.com/charmbracelet/colorprofile v0.3.1 // indirect + github.com/charmbracelet/lipgloss v1.1.0 // indirect + github.com/charmbracelet/x/ansi v0.10.1 // indirect + github.com/charmbracelet/x/cellbuf v0.0.13 // indirect + github.com/charmbracelet/x/term v0.2.1 // indirect + github.com/ckaznocha/intrange v0.3.1 // indirect + github.com/curioswitch/go-reassign v0.3.0 // indirect + github.com/daixiang0/gci v0.13.7 // indirect + github.com/dave/dst v0.27.3 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/denis-tingaikin/go-header v0.5.0 // indirect + github.com/dlclark/regexp2 v1.11.5 // indirect github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/ettle/strcase v0.2.0 // indirect github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/fatih/color v1.18.0 // indirect github.com/fatih/structtag v1.2.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/firefart/nonamedreturns v1.0.5 // indirect + github.com/firefart/nonamedreturns v1.0.6 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/fzipp/gocyclo v0.6.0 // indirect - github.com/ghostiam/protogetter v0.3.8 // indirect - github.com/go-critic/go-critic v0.11.5 // indirect + github.com/ghostiam/protogetter v0.3.20 // indirect + github.com/go-critic/go-critic v0.14.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/zapr v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.21.2 // indirect @@ -132,179 +152,185 @@ require ( github.com/go-toolsmith/astp v1.1.0 // indirect github.com/go-toolsmith/strparse v1.1.0 // indirect github.com/go-toolsmith/typep v1.1.0 // indirect - github.com/go-viper/mapstructure/v2 v2.2.1 // indirect - github.com/go-xmlfmt/xmlfmt v1.1.2 // indirect + github.com/go-viper/mapstructure/v2 v2.5.0 // indirect + github.com/go-xmlfmt/xmlfmt v1.1.3 // indirect github.com/gobuffalo/flect v1.0.3 // indirect github.com/gobwas/glob v0.2.3 // indirect - github.com/gofrs/flock v0.12.1 // indirect - github.com/gogo/protobuf v1.3.2 // indirect + github.com/godoc-lint/godoc-lint v0.11.2 // indirect + github.com/gofrs/flock v0.13.0 // indirect github.com/golang-jwt/jwt/v5 v5.3.0 // indirect - github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect - github.com/golangci/go-printf-func-name v0.1.0 // indirect - github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9 // indirect - github.com/golangci/misspell v0.6.0 // indirect - github.com/golangci/modinfo v0.3.4 // indirect - github.com/golangci/plugin-module-register v0.1.1 // indirect - github.com/golangci/revgrep v0.5.3 // indirect - github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed // indirect + github.com/golangci/asciicheck v0.5.0 // indirect + github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 // indirect + github.com/golangci/go-printf-func-name v0.1.1 // indirect + github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d // indirect + github.com/golangci/golines v0.15.0 // indirect + github.com/golangci/misspell v0.8.0 // indirect + github.com/golangci/plugin-module-register v0.1.2 // indirect + github.com/golangci/revgrep v0.8.0 // indirect + github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e // indirect + github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e // indirect github.com/google/btree v1.1.3 // indirect github.com/google/cel-go v0.26.1 // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/gordonklaus/ineffassign v0.1.0 // indirect + github.com/gordonklaus/ineffassign v0.2.0 // indirect github.com/gostaticanalysis/analysisutil v0.7.1 // indirect - github.com/gostaticanalysis/comment v1.4.2 // indirect - github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect - github.com/gostaticanalysis/nilerr v0.1.1 // indirect + github.com/gostaticanalysis/comment v1.5.0 // indirect + github.com/gostaticanalysis/forcetypeassert v0.2.0 // indirect + github.com/gostaticanalysis/nilerr v0.1.2 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect - github.com/hashicorp/go-version v1.7.0 // indirect - github.com/hashicorp/hcl v1.0.0 // indirect + github.com/hashicorp/go-immutable-radix/v2 v2.1.0 // indirect + github.com/hashicorp/go-version v1.8.0 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hexops/gotextdiff v1.0.3 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/jgautheron/goconst v1.7.1 // indirect + github.com/jgautheron/goconst v1.8.2 // indirect github.com/jingyugao/rowserrcheck v1.1.1 // indirect - github.com/jjti/go-spancheck v0.6.2 // indirect + github.com/jjti/go-spancheck v0.6.5 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/julz/importas v0.1.0 // indirect - github.com/karamaru-alpha/copyloopvar v1.1.0 // indirect - github.com/kisielk/errcheck v1.8.0 // indirect - github.com/kkHAIKE/contextcheck v1.1.5 // indirect - github.com/kulti/thelper v0.6.3 // indirect - github.com/kunwardeep/paralleltest v1.0.10 // indirect + github.com/julz/importas v0.2.0 // indirect + github.com/karamaru-alpha/copyloopvar v1.2.2 // indirect + github.com/kisielk/errcheck v1.10.0 // indirect + github.com/kkHAIKE/contextcheck v1.1.6 // indirect + github.com/kulti/thelper v0.7.1 // indirect + github.com/kunwardeep/paralleltest v1.0.15 // indirect github.com/kylelemons/godebug v1.1.0 // indirect - github.com/kyoh86/exportloopref v0.1.11 // indirect github.com/lasiar/canonicalheader v1.1.2 // indirect - github.com/ldez/gomoddirectives v0.2.4 // indirect - github.com/ldez/tagliatelle v0.5.0 // indirect + github.com/ldez/exptostd v0.4.5 // indirect + github.com/ldez/gomoddirectives v0.8.0 // indirect + github.com/ldez/grignotin v0.10.1 // indirect + github.com/ldez/structtags v0.6.1 // indirect + github.com/ldez/tagliatelle v0.7.2 // indirect + github.com/ldez/usetesting v0.5.0 // indirect github.com/leonklingele/grouper v1.1.2 // indirect - github.com/macabu/inamedparam v0.1.3 // indirect - github.com/magiconair/properties v1.8.7 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/macabu/inamedparam v0.2.0 // indirect github.com/mailru/easyjson v0.9.0 // indirect - github.com/maratori/testableexamples v1.0.0 // indirect - github.com/maratori/testpackage v1.1.1 // indirect - github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect + github.com/manuelarte/embeddedstructfieldcheck v0.4.0 // indirect + github.com/manuelarte/funcorder v0.5.0 // indirect + github.com/maratori/testableexamples v1.0.1 // indirect + github.com/maratori/testpackage v1.1.2 // indirect + github.com/matoous/godox v1.1.0 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect - github.com/mgechev/revive v1.5.1 // indirect + github.com/mgechev/revive v1.15.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/moricho/tparallel v0.3.2 // indirect + github.com/muesli/termenv v0.16.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nakabonne/nestif v0.3.1 // indirect github.com/nishanths/exhaustive v0.12.0 // indirect github.com/nishanths/predeclared v0.2.2 // indirect - github.com/nunnatsa/ginkgolinter v0.18.3 // indirect - github.com/olekukonko/tablewriter v0.0.5 // indirect - github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/nunnatsa/ginkgolinter v0.23.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/polyfloyd/go-errorlint v1.7.0 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.66.1 // indirect - github.com/prometheus/procfs v0.17.0 // indirect - github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1 // indirect - github.com/quasilyte/go-ruleguard/dsl v0.3.22 // indirect + github.com/prometheus/common v0.67.4 // indirect + github.com/prometheus/procfs v0.19.2 // indirect + github.com/quasilyte/go-ruleguard v0.4.5 // indirect + github.com/quasilyte/go-ruleguard/dsl v0.3.23 // indirect github.com/quasilyte/gogrep v0.5.0 // indirect github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect - github.com/raeperd/recvcheck v0.1.2 // indirect + github.com/raeperd/recvcheck v0.2.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/robfig/cron v1.2.0 // indirect - github.com/rogpeppe/go-internal v1.13.1 // indirect - github.com/ryancurrah/gomodguard v1.3.5 // indirect + github.com/rogpeppe/go-internal v1.14.1 // indirect + github.com/ryancurrah/gomodguard v1.4.1 // indirect github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect - github.com/sagikazarmark/locafero v0.4.0 // indirect - github.com/sagikazarmark/slog-shim v0.1.0 // indirect - github.com/sanposhiho/wastedassign/v2 v2.0.7 // indirect - github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect + github.com/sagikazarmark/locafero v0.7.0 // indirect + github.com/sanposhiho/wastedassign/v2 v2.1.0 // indirect + github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect github.com/sashamelentyev/interfacebloat v1.1.0 // indirect - github.com/sashamelentyev/usestdlibvars v1.27.0 // indirect - github.com/securego/gosec/v2 v2.21.4 // indirect - github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect - github.com/sirupsen/logrus v1.9.3 // indirect + github.com/sashamelentyev/usestdlibvars v1.29.0 // indirect + github.com/securego/gosec/v2 v2.24.7 // indirect + github.com/sirupsen/logrus v1.9.4 // indirect github.com/sivchari/containedctx v1.0.3 // indirect - github.com/sivchari/tenv v1.12.1 // indirect - github.com/sonatard/noctx v0.1.0 // indirect + github.com/sonatard/noctx v0.5.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/sourcegraph/go-diff v0.7.0 // indirect - github.com/spf13/afero v1.12.0 // indirect - github.com/spf13/cast v1.6.0 // indirect - github.com/spf13/viper v1.19.0 // indirect + github.com/spf13/afero v1.15.0 // indirect + github.com/spf13/cast v1.7.1 // indirect + github.com/spf13/viper v1.20.1 // indirect github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect - github.com/stbenjam/no-sprintf-host-port v0.1.1 // indirect + github.com/stbenjam/no-sprintf-host-port v0.3.1 // indirect github.com/stoewer/go-strcase v1.3.1 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.6.0 // indirect - github.com/tdakkota/asciicheck v0.2.0 // indirect - github.com/tetafro/godot v1.4.18 // indirect - github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 // indirect - github.com/timonwong/loggercheck v0.10.1 // indirect - github.com/tomarrell/wrapcheck/v2 v2.9.0 // indirect + github.com/tetafro/godot v1.5.4 // indirect + github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 // indirect + github.com/timonwong/loggercheck v0.11.0 // indirect + github.com/tomarrell/wrapcheck/v2 v2.12.0 // indirect github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect - github.com/ultraware/funlen v0.1.0 // indirect - github.com/ultraware/whitespace v0.1.1 // indirect - github.com/uudashr/gocognit v1.1.3 // indirect - github.com/uudashr/iface v1.2.1 // indirect + github.com/ultraware/funlen v0.2.0 // indirect + github.com/ultraware/whitespace v0.2.0 // indirect + github.com/uudashr/gocognit v1.2.1 // indirect + github.com/uudashr/iface v1.4.1 // indirect github.com/x448/float16 v0.8.4 // indirect - github.com/xen0n/gosmopolitan v1.2.2 // indirect + github.com/xen0n/gosmopolitan v1.3.0 // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/yagipy/maintidx v1.0.0 // indirect github.com/yeya24/promlinter v0.3.0 // indirect github.com/ykadowak/zerologlint v0.1.5 // indirect gitlab.com/bosi/decorder v0.4.2 // indirect - go-simpler.org/musttag v0.13.0 // indirect - go-simpler.org/sloglint v0.7.2 // indirect - go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go-simpler.org/musttag v0.14.0 // indirect + go-simpler.org/sloglint v0.11.1 // indirect + go.augendre.info/arangolint v0.4.0 // indirect + go.augendre.info/fatcontext v0.9.0 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect - go.opentelemetry.io/otel v1.37.0 // indirect + go.opentelemetry.io/otel v1.39.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect - go.opentelemetry.io/otel/metric v1.37.0 // indirect - go.opentelemetry.io/otel/sdk v1.37.0 // indirect - go.opentelemetry.io/otel/trace v1.37.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect go.opentelemetry.io/proto/otlp v1.7.1 // indirect - go.uber.org/automaxprocs v1.6.0 // indirect go.uber.org/mock v0.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.47.0 // indirect - golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b // indirect - golang.org/x/exp/typeparams v0.0.0-20241108190413-2d47ceb2692f // indirect - golang.org/x/mod v0.32.0 // indirect - golang.org/x/net v0.49.0 // indirect - golang.org/x/oauth2 v0.30.0 // indirect + golang.org/x/crypto v0.48.0 // indirect + golang.org/x/exp v0.0.0-20250911091902-df9299821621 // indirect + golang.org/x/exp/typeparams v0.0.0-20260209203927-2842357ff358 // indirect + golang.org/x/mod v0.33.0 // indirect + golang.org/x/net v0.51.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.40.0 // indirect - golang.org/x/term v0.39.0 // indirect - golang.org/x/text v0.33.0 // indirect - golang.org/x/time v0.12.0 // indirect - golang.org/x/tools v0.41.0 // indirect - gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect + golang.org/x/sys v0.41.0 // indirect + golang.org/x/term v0.40.0 // indirect + golang.org/x/text v0.34.0 // indirect + golang.org/x/time v0.14.0 // indirect + golang.org/x/tools v0.42.0 // indirect + gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250826171959-ef028d996bc1 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1 // indirect google.golang.org/grpc v1.75.0 // indirect - google.golang.org/protobuf v1.36.8 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - honnef.co/go/tools v0.5.1 // indirect - k8s.io/apiserver v0.34.3 // indirect - k8s.io/kube-aggregator v0.34.1 // indirect + honnef.co/go/tools v0.7.0 // indirect + k8s.io/apiserver v0.35.1 // indirect + k8s.io/code-generator v0.35.1 // indirect + k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b // indirect + k8s.io/kube-aggregator v0.35.1 // indirect k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect - mvdan.cc/gofumpt v0.7.0 // indirect - mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f // indirect + mvdan.cc/gofumpt v0.9.2 // indirect + mvdan.cc/unparam v0.0.0-20251027182757-5beb8c8f8f15 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.33.0 // indirect - sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.8.4 // indirect + sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.11.0 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/kube-storage-version-migrator v0.0.6-0.20230721195810-5c8923c5ff96 // indirect sigs.k8s.io/randfill v1.0.0 // indirect diff --git a/go.sum b/go.sum index 2295f4cc5..6a8be1531 100644 --- a/go.sum +++ b/go.sum @@ -1,23 +1,35 @@ -4d63.com/gocheckcompilerdirectives v1.2.1 h1:AHcMYuw56NPjq/2y615IGg2kYkBdTvOaojYCBcRE7MA= -4d63.com/gocheckcompilerdirectives v1.2.1/go.mod h1:yjDJSxmDTtIHHCqX0ufRYZDL6vQtMG7tJdKVeWwsqvs= -4d63.com/gochecknoglobals v0.2.1 h1:1eiorGsgHOFOuoOiJDy2psSrQbRdIHrlge0IJIkUgDc= -4d63.com/gochecknoglobals v0.2.1/go.mod h1:KRE8wtJB3CXCsb1xy421JfTHIIbmT3U5ruxw2Qu8fSU= +4d63.com/gocheckcompilerdirectives v1.3.0 h1:Ew5y5CtcAAQeTVKUVFrE7EwHMrTO6BggtEj8BZSjZ3A= +4d63.com/gocheckcompilerdirectives v1.3.0/go.mod h1:ofsJ4zx2QAuIP/NO/NAh1ig6R1Fb18/GI7RVMwz7kAY= +4d63.com/gochecknoglobals v0.2.2 h1:H1vdnwnMaZdQW/N+NrkT1SZMTBmcwHe9Vq8lJcYYTtU= +4d63.com/gochecknoglobals v0.2.2/go.mod h1:lLxwTQjL5eIesRbvnzIP3jZtG140FnTdz+AlMa+ogt0= cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= -github.com/4meepo/tagalign v1.3.4 h1:P51VcvBnf04YkHzjfclN6BbsopfJR5rxs1n+5zHt+w8= -github.com/4meepo/tagalign v1.3.4/go.mod h1:M+pnkHH2vG8+qhE5bVc/zeP7HS/j910Fwa9TUSyZVI0= -github.com/Abirdcfly/dupword v0.1.3 h1:9Pa1NuAsZvpFPi9Pqkd93I7LIYRURj+A//dFd5tgBeE= -github.com/Abirdcfly/dupword v0.1.3/go.mod h1:8VbB2t7e10KRNdwTVoxdBaxla6avbhGzb8sCTygUMhw= -github.com/Antonboom/errname v1.0.0 h1:oJOOWR07vS1kRusl6YRSlat7HFnb3mSfMl6sDMRoTBA= -github.com/Antonboom/errname v1.0.0/go.mod h1:gMOBFzK/vrTiXN9Oh+HFs+e6Ndl0eTFbtsRTSRdXyGI= -github.com/Antonboom/nilnil v1.0.0 h1:n+v+B12dsE5tbAqRODXmEKfZv9j2KcTBrp+LkoM4HZk= -github.com/Antonboom/nilnil v1.0.0/go.mod h1:fDJ1FSFoLN6yoG65ANb1WihItf6qt9PJVTn/s2IrcII= -github.com/Antonboom/testifylint v1.5.2 h1:4s3Xhuv5AvdIgbd8wOOEeo0uZG7PbDKQyKY5lGoQazk= -github.com/Antonboom/testifylint v1.5.2/go.mod h1:vxy8VJ0bc6NavlYqjZfmp6EfqXMtBgQ4+mhCojwC1P8= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.0 h1:ci6Yd6nysBRLEodoziB6ah1+YOzZbZk+NYneoA6q+6E= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.0/go.mod h1:QyVsSSN64v5TGltphKLQ2sQxe4OBQg0J1eKRcVBnfgE= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.11.0 h1:MhRfI58HblXzCtWEZCO0feHs8LweePB3s90r7WaR1KU= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.11.0/go.mod h1:okZ+ZURbArNdlJ+ptXoyHNuOETzOl1Oww19rm8I2WLA= +codeberg.org/chavacava/garif v0.2.0 h1:F0tVjhYbuOCnvNcU3YSpO6b3Waw6Bimy4K0mM8y6MfY= +codeberg.org/chavacava/garif v0.2.0/go.mod h1:P2BPbVbT4QcvLZrORc2T29szK3xEOlnl0GiPTJmEqBQ= +codeberg.org/polyfloyd/go-errorlint v1.9.0 h1:VkdEEmA1VBpH6ecQoMR4LdphVI3fA4RrCh2an7YmodI= +codeberg.org/polyfloyd/go-errorlint v1.9.0/go.mod h1:GPRRu2LzVijNn4YkrZYJfatQIdS+TrcK8rL5Xs24qw8= +dev.gaijin.team/go/exhaustruct/v4 v4.0.0 h1:873r7aNneqoBB3IaFIzhvt2RFYTuHgmMjoKfwODoI1Y= +dev.gaijin.team/go/exhaustruct/v4 v4.0.0/go.mod h1:aZ/k2o4Y05aMJtiux15x8iXaumE88YdiB0Ai4fXOzPI= +dev.gaijin.team/go/golib v0.6.0 h1:v6nnznFTs4bppib/NyU1PQxobwDHwCXXl15P7DV5Zgo= +dev.gaijin.team/go/golib v0.6.0/go.mod h1:uY1mShx8Z/aNHWDyAkZTkX+uCi5PdX7KsG1eDQa2AVE= +github.com/4meepo/tagalign v1.4.3 h1:Bnu7jGWwbfpAie2vyl63Zup5KuRv21olsPIha53BJr8= +github.com/4meepo/tagalign v1.4.3/go.mod h1:00WwRjiuSbrRJnSVeGWPLp2epS5Q/l4UEy0apLLS37c= +github.com/Abirdcfly/dupword v0.1.7 h1:2j8sInznrje4I0CMisSL6ipEBkeJUJAmK1/lfoNGWrQ= +github.com/Abirdcfly/dupword v0.1.7/go.mod h1:K0DkBeOebJ4VyOICFdppB23Q0YMOgVafM0zYW0n9lF4= +github.com/AdminBenni/iota-mixing v1.0.0 h1:Os6lpjG2dp/AE5fYBPAA1zfa2qMdCAWwPMCgpwKq7wo= +github.com/AdminBenni/iota-mixing v1.0.0/go.mod h1:i4+tpAaB+qMVIV9OK3m4/DAynOd5bQFaOu+2AhtBCNY= +github.com/AlwxSin/noinlineerr v1.0.5 h1:RUjt63wk1AYWTXtVXbSqemlbVTb23JOSRiNsshj7TbY= +github.com/AlwxSin/noinlineerr v1.0.5/go.mod h1:+QgkkoYrMH7RHvcdxdlI7vYYEdgeoFOVjU9sUhw/rQc= +github.com/Antonboom/errname v1.1.1 h1:bllB7mlIbTVzO9jmSWVWLjxTEbGBVQ1Ff/ClQgtPw9Q= +github.com/Antonboom/errname v1.1.1/go.mod h1:gjhe24xoxXp0ScLtHzjiXp0Exi1RFLKJb0bVBtWKCWQ= +github.com/Antonboom/nilnil v1.1.1 h1:9Mdr6BYd8WHCDngQnNVV0b554xyisFioEKi30sksufQ= +github.com/Antonboom/nilnil v1.1.1/go.mod h1:yCyAmSw3doopbOWhJlVci+HuyNRuHJKIv6V2oYQa8II= +github.com/Antonboom/testifylint v1.6.4 h1:gs9fUEy+egzxkEbq9P4cpcMB6/G0DYdMeiFS87UiqmQ= +github.com/Antonboom/testifylint v1.6.4/go.mod h1:YO33FROXX2OoUfwjz8g+gUxQXio5i9qpVy7nXGbxDD4= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 h1:JXg2dwJUmPB9JmtVmdEB16APJ7jurfbY5jnfXpJoRMc= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0/go.mod h1:YD5h/ldMsG0XiIw7PdyNhLxaM317eFh5yNLccNfGdyw= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1/go.mod h1:IYus9qsFobWIc2YVwe/WPjcnyCkPKtnHAqUYeebc8z0= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8= github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 h1:9iefClla7iYpfYWdzPCRDozdmndjTm8DXdpCzPajMgA= @@ -50,6 +62,8 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1. github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0/go.mod h1:5kakwfW5CjC9KK+Q4wjXAg+ShuIm2mBMua0ZFj2C8PE= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.1 h1:/Zt+cDPnpC3OVDm/JKLOs7M2DKmLRIIp3XIx9pHHiig= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.1/go.mod h1:Ng3urmn6dYe8gnbCMoHHVl5APYz2txho3koEkV2o2HA= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2 v2.0.0 h1:+vh02EiRx2UmL9NDoA36U18Bgwl9luxs6ia0GAI9Rzg= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2 v2.0.0/go.mod h1:iKOtU3WyuNvNc4L1Z4IxHaoO0dGq5tg+uhLix/KRmzE= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.4.0 h1:/g8S6wk65vfC6m3FIxJ+i5QDyN9JWwXI8Hb0Img10hU= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.4.0/go.mod h1:gpl+q95AzZlKVI3xSoseF9QPrypk0hQqBiJYeB/cR/I= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0 h1:nCYfgcSyHZXJI8J0IWE5MsCGlb2xp9fJiXyxWgmOFg4= @@ -58,42 +72,46 @@ github.com/Azure/msi-dataplane v0.4.3 h1:dWPWzY4b54tLIR9T1Q014Xxd/1DxOsMIp6EjRFA github.com/Azure/msi-dataplane v0.4.3/go.mod h1:yAfxdJyvcnvSDfSyOFV9qm4fReEQDl+nZLGeH2ZWSmw= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= -github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0 h1:XkkQbfMyuH2jTSjQjSoihryI8GINRcs4xp8lNawg0FI= -github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk= -github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs= -github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= -github.com/Crocmagnon/fatcontext v0.5.3 h1:zCh/wjc9oyeF+Gmp+V60wetm8ph2tlsxocgg/J0hOps= -github.com/Crocmagnon/fatcontext v0.5.3/go.mod h1:XoCQYY1J+XTfyv74qLXvNw4xFunr3L1wkopIIKG7wGM= -github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM= -github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= -github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 h1:/fTUt5vmbkAcMBt4YQiuC23cV0kEsN1MVMNqeOW43cU= -github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0/go.mod h1:ONJg5sxcbsdQQ4pOW8TGdTidT2TMAUy/2Xhr8mrYaao= +github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 h1:XRzhVemXdgvJqCH0sFfrBUTnUJSBrBf7++ypk+twtRs= +github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk= +github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk= +github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/Djarvur/go-err113 v0.1.1 h1:eHfopDqXRwAi+YmCUas75ZE0+hoBHJ2GQNLYRSxao4g= +github.com/Djarvur/go-err113 v0.1.1/go.mod h1:IaWJdYFLg76t2ihfflPZnM1LIQszWOsFDh2hhhAVF6k= github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= -github.com/OpenPeeDeeP/depguard/v2 v2.2.0 h1:vDfG60vDtIuf0MEOhmLlLLSzqaRM8EMcgJPdp74zmpA= -github.com/OpenPeeDeeP/depguard/v2 v2.2.0/go.mod h1:CIzddKRvLBC4Au5aYP/i3nyaWQ+ClszLIuVocRiCYFQ= -github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk= -github.com/alecthomas/assert/v2 v2.2.2/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ= -github.com/alecthomas/go-check-sumtype v0.2.0 h1:Bo+e4DFf3rs7ME9w/0SU/g6nmzJaphduP8Cjiz0gbwY= -github.com/alecthomas/go-check-sumtype v0.2.0/go.mod h1:WyYPfhfkdhyrdaligV6svFopZV8Lqdzn5pyVBaV6jhQ= -github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk= -github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= -github.com/alexkohler/nakedret/v2 v2.0.5 h1:fP5qLgtwbx9EJE8dGEERT02YwS8En4r9nnZ71RK+EVU= -github.com/alexkohler/nakedret/v2 v2.0.5/go.mod h1:bF5i0zF2Wo2o4X4USt9ntUWve6JbFv02Ff4vlkmS/VU= -github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pOcUuw= -github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE= +github.com/MirrexOne/unqueryvet v1.5.4 h1:38QOxShO7JmMWT+eCdDMbcUgGCOeJphVkzzRgyLJgsQ= +github.com/MirrexOne/unqueryvet v1.5.4/go.mod h1:fs9Zq6eh1LRIhsDIsxf9PONVUjYdFHdtkHIgZdJnyPU= +github.com/OpenPeeDeeP/depguard/v2 v2.2.1 h1:vckeWVESWp6Qog7UZSARNqfu/cZqvki8zsuj3piCMx4= +github.com/OpenPeeDeeP/depguard/v2 v2.2.1/go.mod h1:q4DKzC4UcVaAvcfd41CZh0PWpGgzrVxUYBlgKNGquUo= +github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= +github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= +github.com/alecthomas/chroma/v2 v2.23.1 h1:nv2AVZdTyClGbVQkIzlDm/rnhk1E9bU9nXwmZ/Vk/iY= +github.com/alecthomas/chroma/v2 v2.23.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o= +github.com/alecthomas/go-check-sumtype v0.3.1 h1:u9aUvbGINJxLVXiFvHUlPEaD7VDULsrxJb4Aq31NLkU= +github.com/alecthomas/go-check-sumtype v0.3.1/go.mod h1:A8TSiN3UPRw3laIgWEUOHHLPa6/r9MtoigdlP5h3K/E= +github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs= +github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= +github.com/alexkohler/nakedret/v2 v2.0.6 h1:ME3Qef1/KIKr3kWX3nti3hhgNxw6aqN5pZmQiFSsuzQ= +github.com/alexkohler/nakedret/v2 v2.0.6/go.mod h1:l3RKju/IzOMQHmsEvXwkqMDzHHvurNQfAgE1eVmT40Q= +github.com/alexkohler/prealloc v1.1.0 h1:cKGRBqlXw5iyQGLYhrXrDlcHxugXpTq4tQ5c91wkf8M= +github.com/alexkohler/prealloc v1.1.0/go.mod h1:fT39Jge3bQrfA7nPMDngUfvUbQGQeJyGQnR+913SCig= +github.com/alfatraining/structtag v1.0.0 h1:2qmcUqNcCoyVJ0up879K614L9PazjBSFruTB0GOFjCc= +github.com/alfatraining/structtag v1.0.0/go.mod h1:p3Xi5SwzTi+Ryj64DqjLWz7XurHxbGsq6y3ubePJPus= github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw= github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I= +github.com/alingse/nilnesserr v0.2.0 h1:raLem5KG7EFVb4UIDAXgrv3N2JIaffeKNtcEXkEWd/w= +github.com/alingse/nilnesserr v0.2.0/go.mod h1:1xJPrXonEtX7wyTq8Dytns5P2hNzoWymVUIaKm4HNFg= github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/ashanbrown/forbidigo v1.6.0 h1:D3aewfM37Yb3pxHujIPSpTf6oQk9sc9WZi8gerOIVIY= -github.com/ashanbrown/forbidigo v1.6.0/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU= -github.com/ashanbrown/makezero v1.1.1 h1:iCQ87C0V0vSyO+M9E/FZYbu65auqH0lnsOkf5FcB28s= -github.com/ashanbrown/makezero v1.1.1/go.mod h1:i1bJLCRSCHOcOa9Y6MyF2FTfMZMFdHvxKHxgO5Z1axI= -github.com/aws/aws-sdk-go-v2 v1.38.3 h1:B6cV4oxnMs45fql4yRH+/Po/YU+597zgWqvDpYMturk= -github.com/aws/aws-sdk-go-v2 v1.38.3/go.mod h1:sDioUELIUO9Znk23YVmIk86/9DOpkbyyVb1i/gUNFXY= +github.com/ashanbrown/forbidigo/v2 v2.3.0 h1:OZZDOchCgsX5gvToVtEBoV2UWbFfI6RKQTir2UZzSxo= +github.com/ashanbrown/forbidigo/v2 v2.3.0/go.mod h1:5p6VmsG5/1xx3E785W9fouMxIOkvY2rRV9nMdWadd6c= +github.com/ashanbrown/makezero/v2 v2.1.0 h1:snuKYMbqosNokUKm+R6/+vOPs8yVAi46La7Ck6QYSaE= +github.com/ashanbrown/makezero/v2 v2.1.0/go.mod h1:aEGT/9q3S8DHeE57C88z2a6xydvgx8J5hgXIGWgo0MY= +github.com/aws/aws-sdk-go-v2 v1.39.2 h1:EJLg8IdbzgeD7xgvZ+I8M1e0fL0ptn/M47lianzth0I= +github.com/aws/aws-sdk-go-v2 v1.39.2/go.mod h1:sDioUELIUO9Znk23YVmIk86/9DOpkbyyVb1i/gUNFXY= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.31 h1:oQWSGexYasNpYp4epLGZxxjsDo8BMBh6iNWkTXQvkwk= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.31/go.mod h1:nc332eGUU+djP3vrMI6blS0woaCfHTe3KiSQUVTMRq0= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.6 h1:uF68eJA6+S9iVr9WgX1NaRGyQ/6MdIyc4JNUo6TN1FA= @@ -114,6 +132,8 @@ github.com/aws/aws-sdk-go-v2/service/kms v1.41.0 h1:2jKyib9msVrAVn+lngwlSplG13Rp github.com/aws/aws-sdk-go-v2/service/kms v1.41.0/go.mod h1:RyhzxkWGcfixlkieewzpO3D4P4fTMxhIDqDZWsh0u/4= github.com/aws/smithy-go v1.23.0 h1:8n6I3gXzWJB2DxBDnfxgBaSX6oe0d/t10qGz7OKqMCE= github.com/aws/smithy-go v1.23.0/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bkielbasa/cyclop v1.2.3 h1:faIVMIGDIANuGPWH031CZJTi2ymOQBULs9H21HSMa5w= @@ -122,41 +142,57 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M= github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= -github.com/bombsimon/wsl/v4 v4.4.1 h1:jfUaCkN+aUpobrMO24zwyAMwMAV5eSziCkOKEauOLdw= -github.com/bombsimon/wsl/v4 v4.4.1/go.mod h1:Xu/kDxGZTofQcDGCtQe9KCzhHphIe0fDuyWTxER9Feo= -github.com/breml/bidichk v0.3.2 h1:xV4flJ9V5xWTqxL+/PMFF6dtJPvZLPsyixAoPe8BGJs= -github.com/breml/bidichk v0.3.2/go.mod h1:VzFLBxuYtT23z5+iVkamXO386OB+/sVwZOpIj6zXGos= -github.com/breml/errchkjson v0.4.0 h1:gftf6uWZMtIa/Is3XJgibewBm2ksAQSY/kABDNFTAdk= -github.com/breml/errchkjson v0.4.0/go.mod h1:AuBOSTHyLSaaAFlWsRSuRBIroCh3eh7ZHh5YeelDIk8= -github.com/butuzov/ireturn v0.3.0 h1:hTjMqWw3y5JC3kpnC5vXmFJAWI/m31jaCYQqzkS6PL0= -github.com/butuzov/ireturn v0.3.0/go.mod h1:A09nIiwiqzN/IoVo9ogpa0Hzi9fex1kd9PSD6edP5ZA= -github.com/butuzov/mirror v1.2.0 h1:9YVK1qIjNspaqWutSv8gsge2e/Xpq1eqEkslEUHy5cs= -github.com/butuzov/mirror v1.2.0/go.mod h1:DqZZDtzm42wIAIyHXeN8W/qb1EPlb9Qn/if9icBOpdQ= -github.com/catenacyber/perfsprint v0.7.1 h1:PGW5G/Kxn+YrN04cRAZKC+ZuvlVwolYMrIyyTJ/rMmc= -github.com/catenacyber/perfsprint v0.7.1/go.mod h1:/wclWYompEyjUD2FuIIDVKNkqz7IgBIWXIH3V0Zol50= -github.com/ccojocar/zxcvbn-go v1.0.2 h1:na/czXU8RrhXO4EZme6eQJLR4PzcGsahsBOAwU6I3Vg= -github.com/ccojocar/zxcvbn-go v1.0.2/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60= +github.com/bombsimon/wsl/v4 v4.7.0 h1:1Ilm9JBPRczjyUs6hvOPKvd7VL1Q++PL8M0SXBDf+jQ= +github.com/bombsimon/wsl/v4 v4.7.0/go.mod h1:uV/+6BkffuzSAVYD+yGyld1AChO7/EuLrCF/8xTiapg= +github.com/bombsimon/wsl/v5 v5.6.0 h1:4z+/sBqC5vUmSp1O0mS+czxwH9+LKXtCWtHH9rZGQL8= +github.com/bombsimon/wsl/v5 v5.6.0/go.mod h1:Uqt2EfrMj2NV8UGoN1f1Y3m0NpUVCsUdrNCdet+8LvU= +github.com/breml/bidichk v0.3.3 h1:WSM67ztRusf1sMoqH6/c4OBCUlRVTKq+CbSeo0R17sE= +github.com/breml/bidichk v0.3.3/go.mod h1:ISbsut8OnjB367j5NseXEGGgO/th206dVa427kR8YTE= +github.com/breml/errchkjson v0.4.1 h1:keFSS8D7A2T0haP9kzZTi7o26r7kE3vymjZNeNDRDwg= +github.com/breml/errchkjson v0.4.1/go.mod h1:a23OvR6Qvcl7DG/Z4o0el6BRAjKnaReoPQFciAl9U3s= +github.com/butuzov/ireturn v0.4.0 h1:+s76bF/PfeKEdbG8b54aCocxXmi0wvYdOVsWxVO7n8E= +github.com/butuzov/ireturn v0.4.0/go.mod h1:ghI0FrCmap8pDWZwfPisFD1vEc56VKH4NpQUxDHta70= +github.com/butuzov/mirror v1.3.0 h1:HdWCXzmwlQHdVhwvsfBb2Au0r3HyINry3bDWLYXiKoc= +github.com/butuzov/mirror v1.3.0/go.mod h1:AEij0Z8YMALaq4yQj9CPPVYOyJQyiexpQEQgihajRfI= +github.com/catenacyber/perfsprint v0.10.1 h1:u7Riei30bk46XsG8nknMhKLXG9BcXz3+3tl/WpKm0PQ= +github.com/catenacyber/perfsprint v0.10.1/go.mod h1:DJTGsi/Zufpuus6XPGJyKOTMELe347o6akPvWG9Zcsc= +github.com/ccojocar/zxcvbn-go v1.0.4 h1:FWnCIRMXPj43ukfX000kvBZvV6raSxakYr1nzyNrUcc= +github.com/ccojocar/zxcvbn-go v1.0.4/go.mod h1:3GxGX+rHmueTUMvm5ium7irpyjmm7ikxYFOSJB21Das= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/charithe/durationcheck v0.0.10 h1:wgw73BiocdBDQPik+zcEoBG/ob8uyBHf2iyoHGPf5w4= -github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ= -github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc= -github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww= -github.com/ckaznocha/intrange v0.2.1 h1:M07spnNEQoALOJhwrImSrJLaxwuiQK+hA2DeajBlwYk= -github.com/ckaznocha/intrange v0.2.1/go.mod h1:7NEhVyf8fzZO5Ds7CRaqPEm52Ut83hsTiL5zbER/HYk= +github.com/charithe/durationcheck v0.0.11 h1:g1/EX1eIiKS57NTWsYtHDZ/APfeXKhye1DidBcABctk= +github.com/charithe/durationcheck v0.0.11/go.mod h1:x5iZaixRNl8ctbM+3B2RrPG5t856TxRyVQEnbIEM2X4= +github.com/charmbracelet/colorprofile v0.3.1 h1:k8dTHMd7fgw4bnFd7jXTLZrSU/CQrKnL3m+AxCzDz40= +github.com/charmbracelet/colorprofile v0.3.1/go.mod h1:/GkGusxNs8VB/RSOh3fu0TJmQ4ICMMPApIIVn0KszZ0= +github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= +github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= +github.com/charmbracelet/x/ansi v0.10.1 h1:rL3Koar5XvX0pHGfovN03f5cxLbCF2YvLeyz7D2jVDQ= +github.com/charmbracelet/x/ansi v0.10.1/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE= +github.com/charmbracelet/x/cellbuf v0.0.13 h1:/KBBKHuVRbq1lYx5BzEHBAFBP8VcQzJejZ/IA3iR28k= +github.com/charmbracelet/x/cellbuf v0.0.13/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= +github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= +github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= +github.com/ckaznocha/intrange v0.3.1 h1:j1onQyXvHUsPWujDH6WIjhyH26gkRt/txNlV7LspvJs= +github.com/ckaznocha/intrange v0.3.1/go.mod h1:QVepyz1AkUoFQkpEqksSYpNpUo3c5W7nWh/s6SHIJJk= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo= -github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc= -github.com/daixiang0/gci v0.13.5 h1:kThgmH1yBmZSBCh1EJVxQ7JsHpm5Oms0AMed/0LaH4c= -github.com/daixiang0/gci v0.13.5/go.mod h1:12etP2OniiIdP4q+kjUGrC/rUagga7ODbqsom5Eo5Yk= +github.com/curioswitch/go-reassign v0.3.0 h1:dh3kpQHuADL3cobV/sSGETA8DOv457dwl+fbBAhrQPs= +github.com/curioswitch/go-reassign v0.3.0/go.mod h1:nApPCCTtqLJN/s8HfItCcKV0jIPwluBOvZP+dsJGA88= +github.com/daixiang0/gci v0.13.7 h1:+0bG5eK9vlI08J+J/NWGbWPTNiXPG4WhNLJOkSxWITQ= +github.com/daixiang0/gci v0.13.7/go.mod h1:812WVN6JLFY9S6Tv76twqmNqevN0pa3SX3nih0brVzQ= +github.com/dave/dst v0.27.3 h1:P1HPoMza3cMEquVf9kKy8yXsFirry4zEnWOdYPOoIzY= +github.com/dave/dst v0.27.3/go.mod h1:jHh6EOibnHgcUW3WjKHisiooEkYwqpHLBSX1iOBhEyc= +github.com/dave/jennifer v1.7.1 h1:B4jJJDHelWcDhlRQxWeo0Npa/pYKBLrirAQoTN45txo= +github.com/dave/jennifer v1.7.1/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3RmGZc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8= github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY= +github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= +github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes= github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q= @@ -171,8 +207,8 @@ github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4 github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/firefart/nonamedreturns v1.0.5 h1:tM+Me2ZaXs8tfdDw3X6DOX++wMCOqzYUho6tUTYIdRA= -github.com/firefart/nonamedreturns v1.0.5/go.mod h1:gHJjDqhGM4WyPt639SOZs+G89Ko7QKH5R5BhnO6xJhw= +github.com/firefart/nonamedreturns v1.0.6 h1:vmiBcKV/3EqKY3ZiPxCINmpS431OcE1S47AQUwhrg8E= +github.com/firefart/nonamedreturns v1.0.6/go.mod h1:R8NisJnSIpvPWheCq0mNRXJok6D8h7fagJTF8EMEwCo= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= @@ -181,18 +217,18 @@ github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sa github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= -github.com/ghostiam/protogetter v0.3.8 h1:LYcXbYvybUyTIxN2Mj9h6rHrDZBDwZloPoKctWrFyJY= -github.com/ghostiam/protogetter v0.3.8/go.mod h1:WZ0nw9pfzsgxuRsPOFQomgDVSWtDLJRfQJEhsGbmQMA= +github.com/ghostiam/protogetter v0.3.20 h1:oW7OPFit2FxZOpmMRPP9FffU4uUpfeE/rEdE1f+MzD0= +github.com/ghostiam/protogetter v0.3.20/go.mod h1:FjIu5Yfs6FT391m+Fjp3fbAYJ6rkL/J6ySpZBfnODuI= github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs= github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo= github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M= github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk= github.com/gkampitakis/go-snaps v0.5.15 h1:amyJrvM1D33cPHwVrjo9jQxX8g/7E2wYdZ+01KS3zGE= github.com/gkampitakis/go-snaps v0.5.15/go.mod h1:HNpx/9GoKisdhw9AFOBT1N7DBs9DiHo/hGheFGBZ+mc= -github.com/go-critic/go-critic v0.11.5 h1:TkDTOn5v7EEngMxu8KbuFqFR43USaaH8XRJLz1jhVYA= -github.com/go-critic/go-critic v0.11.5/go.mod h1:wu6U7ny9PiaHaZHcvMDmdysMqvDem162Rh3zWTrqk8M= -github.com/go-faker/faker/v4 v4.6.1 h1:xUyVpAjEtB04l6XFY0V/29oR332rOSPWV4lU8RwDt4k= -github.com/go-faker/faker/v4 v4.6.1/go.mod h1:arSdxNCSt7mOhdk8tEolvHeIJ7eX4OX80wXjKKvkKBY= +github.com/go-critic/go-critic v0.14.3 h1:5R1qH2iFeo4I/RJU8vTezdqs08Egi4u5p6vOESA0pog= +github.com/go-critic/go-critic v0.14.3/go.mod h1:xwntfW6SYAd7h1OqDzmN6hBX/JxsEKl5up/Y2bsxgVQ= +github.com/go-faker/faker/v4 v4.7.0 h1:VboC02cXHl/NuQh5lM2W8b87yp4iFXIu59x4w0RZi4E= +github.com/go-faker/faker/v4 v4.7.0/go.mod h1:u1dIRP5neLB6kTzgyVjdBOV5R1uP7BdxkcWk7tiKQXk= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -229,52 +265,54 @@ github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQi github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ= github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus= github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig= -github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= -github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80U= -github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= +github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= +github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-xmlfmt/xmlfmt v1.1.3 h1:t8Ey3Uy7jDSEisW2K3somuMKIpzktkWptA0iFCnRUWY= +github.com/go-xmlfmt/xmlfmt v1.1.3/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/gobuffalo/flect v1.0.3 h1:xeWBM2nui+qnVvNM4S3foBhCAL2XgPU+a7FdpelbTq4= github.com/gobuffalo/flect v1.0.3/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= -github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= -github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/godoc-lint/godoc-lint v0.11.2 h1:Bp0FkJWoSdNsBikdNgIcgtaoo+xz6I/Y9s5WSBQUeeM= +github.com/godoc-lint/godoc-lint v0.11.2/go.mod h1:iVpGdL1JCikNH2gGeAn3Hh+AgN5Gx/I/cxV+91L41jo= +github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw= +github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0= github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM= -github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= -github.com/golangci/go-printf-func-name v0.1.0 h1:dVokQP+NMTO7jwO4bwsRwLWeudOVUPPyAKJuzv8pEJU= -github.com/golangci/go-printf-func-name v0.1.0/go.mod h1:wqhWFH5mUdJQhweRnldEywnR5021wTdZSNgwYceV14s= -github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9 h1:/1322Qns6BtQxUZDTAT4SdcoxknUki7IAoK4SAXr8ME= -github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9/go.mod h1:Oesb/0uFAyWoaw1U1qS5zyjCg5NP9C9iwjnI4tIsXEE= -github.com/golangci/golangci-lint v1.62.2 h1:b8K5K9PN+rZN1+mKLtsZHz2XXS9aYKzQ9i25x3Qnxxw= -github.com/golangci/golangci-lint v1.62.2/go.mod h1:ILWWyeFUrctpHVGMa1dg2xZPKoMUTc5OIMgW7HZr34g= -github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs= -github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo= -github.com/golangci/modinfo v0.3.4 h1:oU5huX3fbxqQXdfspamej74DFX0kyGLkw1ppvXoJ8GA= -github.com/golangci/modinfo v0.3.4/go.mod h1:wytF1M5xl9u0ij8YSvhkEVPP3M5Mc7XLl1pxH3B2aUM= -github.com/golangci/plugin-module-register v0.1.1 h1:TCmesur25LnyJkpsVrupv1Cdzo+2f7zX0H6Jkw1Ol6c= -github.com/golangci/plugin-module-register v0.1.1/go.mod h1:TTpqoB6KkwOJMV8u7+NyXMrkwwESJLOkfl9TxR1DGFc= -github.com/golangci/revgrep v0.5.3 h1:3tL7c1XBMtWHHqVpS5ChmiAAoe4PF/d5+ULzV9sLAzs= -github.com/golangci/revgrep v0.5.3/go.mod h1:U4R/s9dlXZsg8uJmaR1GrloUr14D7qDl8gi2iPXJH8k= -github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed h1:IURFTjxeTfNFP0hTEi1YKjB/ub8zkpaOqFFMApi2EAs= -github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed/go.mod h1:XLXN8bNw4CGRPaqgl3bv/lhz7bsGPh4/xSaMTbo2vkQ= +github.com/golangci/asciicheck v0.5.0 h1:jczN/BorERZwK8oiFBOGvlGPknhvq0bjnysTj4nUfo0= +github.com/golangci/asciicheck v0.5.0/go.mod h1:5RMNAInbNFw2krqN6ibBxN/zfRFa9S6tA1nPdM0l8qQ= +github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 h1:WUvBfQL6EW/40l6OmeSBYQJNSif4O11+bmWEz+C7FYw= +github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32/go.mod h1:NUw9Zr2Sy7+HxzdjIULge71wI6yEg1lWQr7Evcu8K0E= +github.com/golangci/go-printf-func-name v0.1.1 h1:hIYTFJqAGp1iwoIfsNTpoq1xZAarogrvjO9AfiW3B4U= +github.com/golangci/go-printf-func-name v0.1.1/go.mod h1:Es64MpWEZbh0UBtTAICOZiB+miW53w/K9Or/4QogJss= +github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d h1:viFft9sS/dxoYY0aiOTsLKO2aZQAPT4nlQCsimGcSGE= +github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d/go.mod h1:ivJ9QDg0XucIkmwhzCDsqcnxxlDStoTl89jDMIoNxKY= +github.com/golangci/golangci-lint/v2 v2.11.1 h1:aGbjflzzKNIdOoq/NawrhFjYpkNY4WzPSeIp2zBbzG8= +github.com/golangci/golangci-lint/v2 v2.11.1/go.mod h1:wexdFBIQNhHNhDe1oqzlGFE5dYUqlfccWJKWjoWF1GI= +github.com/golangci/golines v0.15.0 h1:Qnph25g8Y1c5fdo1X7GaRDGgnMHgnxh4Gk4VfPTtRx0= +github.com/golangci/golines v0.15.0/go.mod h1:AZjXd23tbHMpowhtnGlj9KCNsysj72aeZVVHnVcZx10= +github.com/golangci/misspell v0.8.0 h1:qvxQhiE2/5z+BVRo1kwYA8yGz+lOlu5Jfvtx2b04Jbg= +github.com/golangci/misspell v0.8.0/go.mod h1:WZyyI2P3hxPY2UVHs3cS8YcllAeyfquQcKfdeE9AFVg= +github.com/golangci/plugin-module-register v0.1.2 h1:e5WM6PO6NIAEcij3B053CohVp3HIYbzSuP53UAYgOpg= +github.com/golangci/plugin-module-register v0.1.2/go.mod h1:1+QGTsKBvAIvPvoY/os+G5eoqxWn70HYDm2uvUyGuVw= +github.com/golangci/revgrep v0.8.0 h1:EZBctwbVd0aMeRnNUsFogoyayvKHyxlV3CdUA46FX2s= +github.com/golangci/revgrep v0.8.0/go.mod h1:U4R/s9dlXZsg8uJmaR1GrloUr14D7qDl8gi2iPXJH8k= +github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e h1:ai0EfmVYE2bRA5htgAG9r7s3tHsfjIhN98WshBTJ9jM= +github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e/go.mod h1:Vrn4B5oR9qRwM+f54koyeH3yzphlecwERs0el27Fr/s= +github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e h1:gD6P7NEo7Eqtt0ssnqSJNNndxe69DOQ24A5h7+i3KpM= +github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e/go.mod h1:h+wZwLjUTJnm/P2rwlbJdRPZXOzaT36/FwnPnY2inzc= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/cel-go v0.26.1 h1:iPbVVEdkhTX++hpe3lzSk7D3G3QSYqLGoHOcEio+UXQ= github.com/google/cel-go v0.26.1/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM= github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= @@ -285,111 +323,119 @@ github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 h1:z2ogiKUYzX5Is6zr/v github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gordonklaus/ineffassign v0.1.0 h1:y2Gd/9I7MdY1oEIt+n+rowjBNDcLQq3RsH5hwJd0f9s= -github.com/gordonklaus/ineffassign v0.1.0/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= +github.com/gordonklaus/ineffassign v0.2.0 h1:Uths4KnmwxNJNzq87fwQQDDnbNb7De00VOk9Nu0TySs= +github.com/gordonklaus/ineffassign v0.2.0/go.mod h1:TIpymnagPSexySzs7F9FnO1XFTy8IT3a59vmZp5Y9Lw= github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk= github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc= -github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado= -github.com/gostaticanalysis/comment v1.4.2 h1:hlnx5+S2fY9Zo9ePo4AhgYsYHbM2+eAv8m/s1JiCd6Q= github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM= -github.com/gostaticanalysis/forcetypeassert v0.1.0 h1:6eUflI3DiGusXGK6X7cCcIgVCpZ2CiZ1Q7jl6ZxNV70= -github.com/gostaticanalysis/forcetypeassert v0.1.0/go.mod h1:qZEedyP/sY1lTGV1uJ3VhWZ2mqag3IkWsDHVbplHXak= -github.com/gostaticanalysis/nilerr v0.1.1 h1:ThE+hJP0fEp4zWLkWHWcRyI2Od0p7DlgYG3Uqrmrcpk= -github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A= +github.com/gostaticanalysis/comment v1.5.0 h1:X82FLl+TswsUMpMh17srGRuKaaXprTaytmEpgnKIDu8= +github.com/gostaticanalysis/comment v1.5.0/go.mod h1:V6eb3gpCv9GNVqb6amXzEUX3jXLVK/AdA+IrAMSqvEc= +github.com/gostaticanalysis/forcetypeassert v0.2.0 h1:uSnWrrUEYDr86OCxWa4/Tp2jeYDlogZiZHzGkWFefTk= +github.com/gostaticanalysis/forcetypeassert v0.2.0/go.mod h1:M5iPavzE9pPqWyeiVXSFghQjljW1+l/Uke3PXHS6ILY= +github.com/gostaticanalysis/nilerr v0.1.2 h1:S6nk8a9N8g062nsx63kUkF6AzbHGw7zzyHMcpu52xQU= +github.com/gostaticanalysis/nilerr v0.1.2/go.mod h1:A19UHhoY3y8ahoL7YKz6sdjDtduwTSI4CsymaC2htPA= github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= -github.com/gostaticanalysis/testutil v0.4.0 h1:nhdCmubdmDF6VEatUNjgUZBJKWRqugoISdUv3PPQgHY= -github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Repi5x3CuviD3dgAZaBU= +github.com/gostaticanalysis/testutil v0.5.0 h1:Dq4wT1DdTwTGCQQv3rl3IvD5Ld0E6HiY+3Zh0sUGqw8= +github.com/gostaticanalysis/testutil v0.5.0/go.mod h1:OLQSbuM6zw2EvCcXTz1lVq5unyoNft372msDY0nY5Hs= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= +github.com/hashicorp/go-immutable-radix/v2 v2.1.0 h1:CUW5RYIcysz+D3B+l1mDeXrQ7fUvGGCwJfdASSzbrfo= +github.com/hashicorp/go-immutable-radix/v2 v2.1.0/go.mod h1:hgdqLXA4f6NIjRVisM1TJ9aOJVNRqKZj+xDGF6m7PBw= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= -github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/go-version v1.8.0 h1:KAkNb1HAiZd1ukkxDFGmokVZe1Xy9HG6NUp+bPle2i4= +github.com/hashicorp/go-version v1.8.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jgautheron/goconst v1.7.1 h1:VpdAG7Ca7yvvJk5n8dMwQhfEZJh95kl/Hl9S1OI5Jkk= -github.com/jgautheron/goconst v1.7.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= +github.com/jgautheron/goconst v1.8.2 h1:y0XF7X8CikZ93fSNT6WBTb/NElBu9IjaY7CCYQrCMX4= +github.com/jgautheron/goconst v1.8.2/go.mod h1:A0oxgBCHy55NQn6sYpO7UdnA9p+h7cPtoOZUmvNIako= github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs= github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= -github.com/jjti/go-spancheck v0.6.2 h1:iYtoxqPMzHUPp7St+5yA8+cONdyXD3ug6KK15n7Pklk= -github.com/jjti/go-spancheck v0.6.2/go.mod h1:+X7lvIrR5ZdUTkxFYqzJ0abr8Sb5LOo80uOhWNqIrYA= +github.com/jjti/go-spancheck v0.6.5 h1:lmi7pKxa37oKYIMScialXUK6hP3iY5F1gu+mLBPgYB8= +github.com/jjti/go-spancheck v0.6.5/go.mod h1:aEogkeatBrbYsyW6y5TgDfihCulDYciL1B7rG2vSsrU= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE= github.com/joshdk/go-junit v1.0.0/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/julz/importas v0.1.0 h1:F78HnrsjY3cR7j0etXy5+TU1Zuy7Xt08X/1aJnH5xXY= -github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0= -github.com/karamaru-alpha/copyloopvar v1.1.0 h1:x7gNyKcC2vRBO1H2Mks5u1VxQtYvFiym7fCjIP8RPos= -github.com/karamaru-alpha/copyloopvar v1.1.0/go.mod h1:u7CIfztblY0jZLOQZgH3oYsJzpC2A7S6u/lfgSXHy0k= +github.com/julz/importas v0.2.0 h1:y+MJN/UdL63QbFJHws9BVC5RpA2iq0kpjrFajTGivjQ= +github.com/julz/importas v0.2.0/go.mod h1:pThlt589EnCYtMnmhmRYY/qn9lCf/frPOK+WMx3xiJY= +github.com/karamaru-alpha/copyloopvar v1.2.2 h1:yfNQvP9YaGQR7VaWLYcfZUlRP2eo2vhExWKxD/fP6q0= +github.com/karamaru-alpha/copyloopvar v1.2.2/go.mod h1:oY4rGZqZ879JkJMtX3RRkcXRkmUvH0x35ykgaKgsgJY= github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU= github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/errcheck v1.8.0 h1:ZX/URYa7ilESY19ik/vBmCn6zdGQLxACwjAcWbHlYlg= -github.com/kisielk/errcheck v1.8.0/go.mod h1:1kLL+jV4e+CFfueBmI1dSK2ADDyQnlrnrY/FqKluHJQ= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kkHAIKE/contextcheck v1.1.5 h1:CdnJh63tcDe53vG+RebdpdXJTc9atMgGqdx8LXxiilg= -github.com/kkHAIKE/contextcheck v1.1.5/go.mod h1:O930cpht4xb1YQpK+1+AgoM3mFsvxr7uyFptcnWTYUA= +github.com/kisielk/errcheck v1.10.0 h1:Lvs/YAHP24YKg08LA8oDw2z9fJVme090RAXd90S+rrw= +github.com/kisielk/errcheck v1.10.0/go.mod h1:kQxWMMVZgIkDq7U8xtG/n2juOjbLgZtedi0D+/VL/i8= +github.com/kkHAIKE/contextcheck v1.1.6 h1:7HIyRcnyzxL9Lz06NGhiKvenXq7Zw6Q0UQu/ttjfJCE= +github.com/kkHAIKE/contextcheck v1.1.6/go.mod h1:3dDbMRNBFaq8HFXWC1JyvDSPm43CmE6IuHam8Wr0rkg= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kulti/thelper v0.6.3 h1:ElhKf+AlItIu+xGnI990no4cE2+XaSu1ULymV2Yulxs= -github.com/kulti/thelper v0.6.3/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I= -github.com/kunwardeep/paralleltest v1.0.10 h1:wrodoaKYzS2mdNVnc4/w31YaXFtsc21PCTdvWJ/lDDs= -github.com/kunwardeep/paralleltest v1.0.10/go.mod h1:2C7s65hONVqY7Q5Efj5aLzRCNLjw2h4eMc9EcypGjcY= +github.com/kulti/thelper v0.7.1 h1:fI8QITAoFVLx+y+vSyuLBP+rcVIB8jKooNSCT2EiI98= +github.com/kulti/thelper v0.7.1/go.mod h1:NsMjfQEy6sd+9Kfw8kCP61W1I0nerGSYSFnGaxQkcbs= +github.com/kunwardeep/paralleltest v1.0.15 h1:ZMk4Qt306tHIgKISHWFJAO1IDQJLc6uDyJMLyncOb6w= +github.com/kunwardeep/paralleltest v1.0.15/go.mod h1:di4moFqtfz3ToSKxhNjhOZL+696QtJGCFe132CbBLGk= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/kyoh86/exportloopref v0.1.11 h1:1Z0bcmTypkL3Q4k+IDHMWTcnCliEZcaPiIe0/ymEyhQ= -github.com/kyoh86/exportloopref v0.1.11/go.mod h1:qkV4UF1zGl6EkF1ox8L5t9SwyeBAZ3qLMd6up458uqA= github.com/lasiar/canonicalheader v1.1.2 h1:vZ5uqwvDbyJCnMhmFYimgMZnJMjwljN5VGY0VKbMXb4= github.com/lasiar/canonicalheader v1.1.2/go.mod h1:qJCeLFS0G/QlLQ506T+Fk/fWMa2VmBUiEI2cuMK4djI= -github.com/ldez/gomoddirectives v0.2.4 h1:j3YjBIjEBbqZ0NKtBNzr8rtMHTOrLPeiwTkfUJZ3alg= -github.com/ldez/gomoddirectives v0.2.4/go.mod h1:oWu9i62VcQDYp9EQ0ONTfqLNh+mDLWWDO+SO0qSQw5g= -github.com/ldez/tagliatelle v0.5.0 h1:epgfuYt9v0CG3fms0pEgIMNPuFf/LpPIfjk4kyqSioo= -github.com/ldez/tagliatelle v0.5.0/go.mod h1:rj1HmWiL1MiKQuOONhd09iySTEkUuE/8+5jtPYz9xa4= +github.com/ldez/exptostd v0.4.5 h1:kv2ZGUVI6VwRfp/+bcQ6Nbx0ghFWcGIKInkG/oFn1aQ= +github.com/ldez/exptostd v0.4.5/go.mod h1:QRjHRMXJrCTIm9WxVNH6VW7oN7KrGSht69bIRwvdFsM= +github.com/ldez/gomoddirectives v0.8.0 h1:JqIuTtgvFC2RdH1s357vrE23WJF2cpDCPFgA/TWDGpk= +github.com/ldez/gomoddirectives v0.8.0/go.mod h1:jutzamvZR4XYJLr0d5Honycp4Gy6GEg2mS9+2YX3F1Q= +github.com/ldez/grignotin v0.10.1 h1:keYi9rYsgbvqAZGI1liek5c+jv9UUjbvdj3Tbn5fn4o= +github.com/ldez/grignotin v0.10.1/go.mod h1:UlDbXFCARrXbWGNGP3S5vsysNXAPhnSuBufpTEbwOas= +github.com/ldez/structtags v0.6.1 h1:bUooFLbXx41tW8SvkfwfFkkjPYvFFs59AAMgVg6DUBk= +github.com/ldez/structtags v0.6.1/go.mod h1:YDxVSgDy/MON6ariaxLF2X09bh19qL7MtGBN5MrvbdY= +github.com/ldez/tagliatelle v0.7.2 h1:KuOlL70/fu9paxuxbeqlicJnCspCRjH0x8FW+NfgYUk= +github.com/ldez/tagliatelle v0.7.2/go.mod h1:PtGgm163ZplJfZMZ2sf5nhUT170rSuPgBimoyYtdaSI= +github.com/ldez/usetesting v0.5.0 h1:3/QtzZObBKLy1F4F8jLuKJiKBjjVFi1IavpoWbmqLwc= +github.com/ldez/usetesting v0.5.0/go.mod h1:Spnb4Qppf8JTuRgblLrEWb7IE6rDmUpGvxY3iRrzvDQ= github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY= github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= -github.com/macabu/inamedparam v0.1.3 h1:2tk/phHkMlEL/1GNe/Yf6kkR/hkcUdAEY3L0hjYV1Mk= -github.com/macabu/inamedparam v0.1.3/go.mod h1:93FLICAIk/quk7eaPPQvbzihUdn/QkGDwIZEoLtpH6I= -github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= -github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/macabu/inamedparam v0.2.0 h1:VyPYpOc10nkhI2qeNUdh3Zket4fcZjEWe35poddBCpE= +github.com/macabu/inamedparam v0.2.0/go.mod h1:+Pee9/YfGe5LJ62pYXqB89lJ+0k5bsR8Wgz/C0Zlq3U= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= -github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s93SLMxb2vI= -github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE= -github.com/maratori/testpackage v1.1.1 h1:S58XVV5AD7HADMmD0fNnziNHqKvSdDuEKdPD1rNTU04= -github.com/maratori/testpackage v1.1.1/go.mod h1:s4gRK/ym6AMrqpOa/kEbQTV4Q4jb7WeLZzVhVVVOQMc= +github.com/manuelarte/embeddedstructfieldcheck v0.4.0 h1:3mAIyaGRtjK6EO9E73JlXLtiy7ha80b2ZVGyacxgfww= +github.com/manuelarte/embeddedstructfieldcheck v0.4.0/go.mod h1:z8dFSyXqp+fC6NLDSljRJeNQJJDWnY7RoWFzV3PC6UM= +github.com/manuelarte/funcorder v0.5.0 h1:llMuHXXbg7tD0i/LNw8vGnkDTHFpTnWqKPI85Rknc+8= +github.com/manuelarte/funcorder v0.5.0/go.mod h1:Yt3CiUQthSBMBxjShjdXMexmzpP8YGvGLjrxJNkO2hA= +github.com/maratori/testableexamples v1.0.1 h1:HfOQXs+XgfeRBJ+Wz0XfH+FHnoY9TVqL6Fcevpzy4q8= +github.com/maratori/testableexamples v1.0.1/go.mod h1:XE2F/nQs7B9N08JgyRmdGjYVGqxWwClLPCGSQhXQSrQ= +github.com/maratori/testpackage v1.1.2 h1:ffDSh+AgqluCLMXhM19f/cpvQAKygKAJXFl9aUjmbqs= +github.com/maratori/testpackage v1.1.2/go.mod h1:8F24GdVDFW5Ew43Et02jamrVMNXLUNaOynhDssITGfc= github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo= github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg= -github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 h1:gWg6ZQ4JhDfJPqlo2srm/LN17lpybq15AryXIRcWYLE= -github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= +github.com/matoous/godox v1.1.0 h1:W5mqwbyWrwZv6OQ5Z1a/DHGMOvXYCBP3+Ht7KMoJhq4= +github.com/matoous/godox v1.1.0/go.mod h1:jgE/3fUXiTurkdHOLT5WEkThTSuE7yxHv5iWPa80afs= github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE= github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A= -github.com/mgechev/revive v1.5.1 h1:hE+QPeq0/wIzJwOphdVyUJ82njdd8Khp4fUIHGZHW3M= -github.com/mgechev/revive v1.5.1/go.mod h1:lC9AhkJIBs5zwx8wkudyHrU+IJkrEKmpCmGMnIJPk4o= +github.com/mgechev/revive v1.15.0 h1:vJ0HzSBzfNyPbHKolgiFjHxLek9KUijhqh42yGoqZ8Q= +github.com/mgechev/revive v1.15.0/go.mod h1:LlAKO3QQe9OJ0pVZzI2GPa8CbXGZ/9lNpCGvK4T/a8A= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -398,6 +444,8 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFd github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/moricho/tparallel v0.3.2 h1:odr8aZVFA3NZrNybggMkYO3rgPRcqjeQUlBBFVxKHTI= github.com/moricho/tparallel v0.3.2/go.mod h1:OQ+K3b4Ln3l2TZveGCywybl68glfLEwFGqvnjok8b+U= +github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= +github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81U= @@ -406,28 +454,28 @@ github.com/nishanths/exhaustive v0.12.0 h1:vIY9sALmw6T/yxiASewa4TQcFsVYZQQRUQJhK github.com/nishanths/exhaustive v0.12.0/go.mod h1:mEZ95wPIZW+x8kC4TgC+9YCUgiST7ecevsVDTgc2obs= github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk= github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= -github.com/nunnatsa/ginkgolinter v0.18.3 h1:WgS7X3zzmni3vwHSBhvSgqrRgUecN6PQUcfB0j1noDw= -github.com/nunnatsa/ginkgolinter v0.18.3/go.mod h1:BE1xyB/PNtXXG1azrvrqJW5eFH0hSRylNzFy8QHPwzs= +github.com/nunnatsa/ginkgolinter v0.23.0 h1:x3o4DGYOWbBMP/VdNQKgSj+25aJKx2Pe6lHr8gBcgf8= +github.com/nunnatsa/ginkgolinter v0.23.0/go.mod h1:9qN1+0akwXEccwV1CAcCDfcoBlWXHB+ML9884pL4SZ4= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= -github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI= github.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE= github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28= github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg= -github.com/openshift/api v0.0.0-20260213155647-8fe9fe363807 h1:coR/haF16EW8KS1E/PwJfDzMSy4mU9K0H1rcHejqYDY= -github.com/openshift/api v0.0.0-20260213155647-8fe9fe363807/go.mod h1:d5uzF0YN2nQQFA0jIEWzzOZ+edmo6wzlGLvx5Fhz4uY= -github.com/openshift/client-go v0.0.0-20260108185524-48f4ccfc4e13 h1:6rd4zSo2UaWQcAPZfHK9yzKVqH0BnMv1hqMzqXZyTds= -github.com/openshift/client-go v0.0.0-20260108185524-48f4ccfc4e13/go.mod h1:YvOmPmV7wcJxpfhTDuFqqs2Xpb3M3ovsM6Qs/i2ptq4= -github.com/openshift/cluster-api-actuator-pkg/testutils v0.0.0-20250122171707-86066d47a264 h1:KoJiId8Ynajf/ZFodvmayFkDODIL7Vow3LmgR5+oVRg= -github.com/openshift/cluster-api-actuator-pkg/testutils v0.0.0-20250122171707-86066d47a264/go.mod h1:d6xqfLy/cKEGUKfounNsWdAhWAcUYfZyuDgHBCQyfeM= -github.com/openshift/controller-runtime-common v0.0.0-20260213175913-767fef058eca h1:EOc/lbyZxtn1b/BvRwnLpbgBg0F+2RUQd3xMiA4/JsQ= -github.com/openshift/controller-runtime-common v0.0.0-20260213175913-767fef058eca/go.mod h1:59nLF3/IfhAtoQZfUzlCyidTAdlVT6KiVeTicUi2wuA= -github.com/openshift/library-go v0.0.0-20260213153706-03f1709971c5 h1:9Pe6iVOMjt9CdA/vaKBNUSoEIjIe1po5Ha3ABRYXLJI= -github.com/openshift/library-go v0.0.0-20260213153706-03f1709971c5/go.mod h1:K3FoNLgNBFYbFuG+Kr8usAnQxj1w84XogyUp2M8rK8k= +github.com/openshift-cloud-team/cloud-provider-vsphere v1.19.1-0.20260317135518-758abc9d59a5 h1:Mayj50dtdLPzUVmJNHJpM4GpFWq7fcy9FDIoYUfngQ4= +github.com/openshift-cloud-team/cloud-provider-vsphere v1.19.1-0.20260317135518-758abc9d59a5/go.mod h1:3uaiy47HteyMlDjJankjteem/s1hnbRBU1FgbekLMKU= +github.com/openshift/api v0.0.0-20260306002634-d3bbdada155c h1:YQYiDzOLJzwQunxCaa5OpyNyMLPz4HJ2CLaKqUQOQjQ= +github.com/openshift/api v0.0.0-20260306002634-d3bbdada155c/go.mod h1:pyVjK0nZ4sRs4fuQVQ4rubsJdahI1PB94LnQ8sGdvxo= +github.com/openshift/client-go v0.0.0-20260306160707-3935d929fc7d h1:T+9HFgEEcnu1TDDfsO5JcJC6N0/Kzob5AtG9IpITHJ8= +github.com/openshift/client-go v0.0.0-20260306160707-3935d929fc7d/go.mod h1:tIA3XSb/WsC/Fg0YNRfs/JrMrloBKPGF+NKVutd7nMI= +github.com/openshift/cluster-api-actuator-pkg/testutils v0.0.0-20260310144400-bec013a007a8 h1:x62h16RetnB1ZP+zjSM9fsoMz98g95zte+DXeUDF34o= +github.com/openshift/cluster-api-actuator-pkg/testutils v0.0.0-20260310144400-bec013a007a8/go.mod h1:n8RwIitgr5SAfvisrU0Ps+Szrn545DBU7nqtwATZphw= +github.com/openshift/controller-runtime-common v0.0.0-20260307102856-5db94f69ad3a h1:EQfdaEHOOBDkbvyHAn69u6eZDMuHPK3CTr1i89eEmss= +github.com/openshift/controller-runtime-common v0.0.0-20260307102856-5db94f69ad3a/go.mod h1:9HQZbBpikedL8l9mQpaDB4C15FNgLlnNuLP5ADrkVOI= +github.com/openshift/library-go v0.0.0-20260311094140-ac826d10cb40 h1:0Q7pg6Et+9Zg5wlom0hX4viqTtyRSj2uVjX74N6gcBw= +github.com/openshift/library-go v0.0.0-20260311094140-ac826d10cb40/go.mod h1:D797O/ssKTNglbrGchjIguFq+DbyRYdeds5w4/VTrKM= github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= @@ -435,97 +483,89 @@ github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJ github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= -github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= -github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/polyfloyd/go-errorlint v1.7.0 h1:Zp6lzCK4hpBDj8y8a237YK4EPrMXQWvOe3nGoH4pFrU= -github.com/polyfloyd/go-errorlint v1.7.0/go.mod h1:dGWKu85mGHnegQ2SWpEybFityCg3j7ZbwsVUxAOk9gY= -github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= -github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.74.0 h1:AHzMWDxNiAVscJL6+4wkvFRTpMnJqiaZFEKA/osaBXE= github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.74.0/go.mod h1:wAR5JopumPtAZnu0Cjv2PSqV4p4QB09LMhc6fZZTXuA= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= -github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= -github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= -github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= -github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1 h1:+Wl/0aFp0hpuHM3H//KMft64WQ1yX9LdJY64Qm/gFCo= -github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1/go.mod h1:GJLgqsLeo4qgavUoL8JeGFNS7qcisx3awV/w9eWTmNI= -github.com/quasilyte/go-ruleguard/dsl v0.3.22 h1:wd8zkOhSNr+I+8Qeciml08ivDt1pSXe60+5DqOpCjPE= -github.com/quasilyte/go-ruleguard/dsl v0.3.22/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= +github.com/quasilyte/go-ruleguard v0.4.5 h1:AGY0tiOT5hJX9BTdx/xBdoCubQUAE2grkqY2lSwvZcA= +github.com/quasilyte/go-ruleguard v0.4.5/go.mod h1:Vl05zJ538vcEEwu16V/Hdu7IYZWyKSwIy4c88Ro1kRE= +github.com/quasilyte/go-ruleguard/dsl v0.3.23 h1:lxjt5B6ZCiBeeNO8/oQsegE6fLeCzuMRoVWSkXC4uvY= +github.com/quasilyte/go-ruleguard/dsl v0.3.23/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo= github.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng= github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl980XxGFEZSS6KlBGIV0diGdySzxATTWoqaU= github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs= github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= -github.com/raeperd/recvcheck v0.1.2 h1:SjdquRsRXJc26eSonWIo8b7IMtKD3OAT2Lb5G3ZX1+4= -github.com/raeperd/recvcheck v0.1.2/go.mod h1:n04eYkwIR0JbgD73wT8wL4JjPC3wm0nFtzBnWNocnYU= +github.com/raeperd/recvcheck v0.2.0 h1:GnU+NsbiCqdC2XX5+vMZzP+jAJC5fht7rcVTAhX74UI= +github.com/raeperd/recvcheck v0.2.0/go.mod h1:n04eYkwIR0JbgD73wT8wL4JjPC3wm0nFtzBnWNocnYU= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= -github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= -github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryancurrah/gomodguard v1.3.5 h1:cShyguSwUEeC0jS7ylOiG/idnd1TpJ1LfHGpV3oJmPU= -github.com/ryancurrah/gomodguard v1.3.5/go.mod h1:MXlEPQRxgfPQa62O8wzK3Ozbkv9Rkqr+wKjSxTdsNJE= +github.com/ryancurrah/gomodguard v1.4.1 h1:eWC8eUMNZ/wM/PWuZBv7JxxqT5fiIKSIyTvjb7Elr+g= +github.com/ryancurrah/gomodguard v1.4.1/go.mod h1:qnMJwV1hX9m+YJseXEBhd2s90+1Xn6x9dLz11ualI1I= github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9fJfSfdyCU= github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ= -github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= -github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= -github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= -github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= -github.com/sanposhiho/wastedassign/v2 v2.0.7 h1:J+6nrY4VW+gC9xFzUc+XjPD3g3wF3je/NsJFwFK7Uxc= -github.com/sanposhiho/wastedassign/v2 v2.0.7/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= -github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= -github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= +github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= +github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= +github.com/sanposhiho/wastedassign/v2 v2.1.0 h1:crurBF7fJKIORrV85u9UUpePDYGWnwvv3+A96WvwXT0= +github.com/sanposhiho/wastedassign/v2 v2.1.0/go.mod h1:+oSmSC+9bQ+VUAxA66nBb0Z7N8CK7mscKTDYC6aIek4= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw= github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= -github.com/sashamelentyev/usestdlibvars v1.27.0 h1:t/3jZpSXtRPRf2xr0m63i32ZrusyurIGT9E5wAvXQnI= -github.com/sashamelentyev/usestdlibvars v1.27.0/go.mod h1:9nl0jgOfHKWNFS43Ojw0i7aRoS4j6EBye3YBhmAIRF8= -github.com/securego/gosec/v2 v2.21.4 h1:Le8MSj0PDmOnHJgUATjD96PaXRvCpKC+DGJvwyy0Mlk= -github.com/securego/gosec/v2 v2.21.4/go.mod h1:Jtb/MwRQfRxCXyCm1rfM1BEiiiTfUOdyzzAhlr6lUTA= -github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU= -github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= +github.com/sashamelentyev/usestdlibvars v1.29.0 h1:8J0MoRrw4/NAXtjQqTHrbW9NN+3iMf7Knkq057v4XOQ= +github.com/sashamelentyev/usestdlibvars v1.29.0/go.mod h1:8PpnjHMk5VdeWlVb4wCdrB8PNbLqZ3wBZTZWkrpZZL8= +github.com/securego/gosec/v2 v2.24.7 h1:3k5yJnrhT1TTdsG0ZsnenlfCcT+7Y/+zeCPHbL7QAn8= +github.com/securego/gosec/v2 v2.24.7/go.mod h1:AdDJbjcG/XxFgVv7pW19vMNYlFM6+Q6Qy3t6lWAUcEY= +github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= +github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE= github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4= -github.com/sivchari/tenv v1.12.1 h1:+E0QzjktdnExv/wwsnnyk4oqZBUfuh89YMQT1cyuvSY= -github.com/sivchari/tenv v1.12.1/go.mod h1:1LjSOUCc25snIr5n3DtGGrENhX3LuWefcplwVGC24mw= -github.com/sonatard/noctx v0.1.0 h1:JjqOc2WN16ISWAjAk8M5ej0RfExEXtkEyExl2hLW+OM= -github.com/sonatard/noctx v0.1.0/go.mod h1:0RvBxqY8D4j9cTTTWE8ylt2vqj2EPI8fHmrxHdsaZ2c= +github.com/sonatard/noctx v0.5.0 h1:e/jdaqAsuWVOKQ0P6NWiIdDNHmHT5SwuuSfojFjzwrw= +github.com/sonatard/noctx v0.5.0/go.mod h1:64XdbzFb18XL4LporKXp8poqZtPKbCrqQ402CV+kJas= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0= github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= -github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= -github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= -github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= -github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= -github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= +github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= +github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= +github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= -github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= +github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0= github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= -github.com/stbenjam/no-sprintf-host-port v0.1.1 h1:tYugd/yrm1O0dV+ThCbaKZh195Dfm07ysF0U6JQXczc= -github.com/stbenjam/no-sprintf-host-port v0.1.1/go.mod h1:TLhvtIvONRzdmkFiio4O8LHsN9N74I+PhRquPsxpL0I= +github.com/stbenjam/no-sprintf-host-port v0.3.1 h1:AyX7+dxI4IdLBPtDbsGAyqiTSLpCP9hWRrXQDU4Cm/g= +github.com/stbenjam/no-sprintf-host-port v0.3.1/go.mod h1:ODbZesTCHMVKthBHskvUUexdcNHAQRXk9NpSsL8p/HQ= github.com/stoewer/go-strcase v1.3.1 h1:iS0MdW+kVTxgMoE1LAZyMiYJFKlOzLooE4MxjirtkAs= github.com/stoewer/go-strcase v1.3.1/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -535,8 +575,6 @@ github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= @@ -545,14 +583,12 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/tdakkota/asciicheck v0.2.0 h1:o8jvnUANo0qXtnslk2d3nMKTFNlOnJjRrNcj0j9qkHM= -github.com/tdakkota/asciicheck v0.2.0/go.mod h1:Qb7Y9EgjCLJGup51gDHFzbI08/gbGhL/UVhYIPWG2rg= github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA= github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= -github.com/tetafro/godot v1.4.18 h1:ouX3XGiziKDypbpXqShBfnNLTSjR8r3/HVzrtJ+bHlI= -github.com/tetafro/godot v1.4.18/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio= +github.com/tetafro/godot v1.5.4 h1:u1ww+gqpRLiIA16yF2PV1CV1n/X3zhyezbNXC3E14Sg= +github.com/tetafro/godot v1.5.4/go.mod h1:eOkMrVQurDui411nBY2FA05EYH01r14LuWY/NrVDVcU= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= @@ -561,26 +597,28 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= -github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 h1:quvGphlmUVU+nhpFa4gg4yJyTRJ13reZMDHrKwYw53M= -github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966/go.mod h1:27bSVNWSBOHm+qRp1T9qzaIpsWEP6TbUnei/43HK+PQ= -github.com/timonwong/loggercheck v0.10.1 h1:uVZYClxQFpw55eh+PIoqM7uAOHMrhVcDoWDery9R8Lg= -github.com/timonwong/loggercheck v0.10.1/go.mod h1:HEAWU8djynujaAVX7QI65Myb8qgfcZ1uKbdpg3ZzKl8= -github.com/tomarrell/wrapcheck/v2 v2.9.0 h1:801U2YCAjLhdN8zhZ/7tdjB3EnAoRlJHt/s+9hijLQ4= -github.com/tomarrell/wrapcheck/v2 v2.9.0/go.mod h1:g9vNIyhb5/9TQgumxQyOEqDHsmGYcGsVMOx/xGkqdMo= +github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 h1:9LPGD+jzxMlnk5r6+hJnar67cgpDIz/iyD+rfl5r2Vk= +github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67/go.mod h1:mkjARE7Yr8qU23YcGMSALbIxTQ9r9QBVahQOBRfU460= +github.com/timonwong/loggercheck v0.11.0 h1:jdaMpYBl+Uq9mWPXv1r8jc5fC3gyXx4/WGwTnnNKn4M= +github.com/timonwong/loggercheck v0.11.0/go.mod h1:HEAWU8djynujaAVX7QI65Myb8qgfcZ1uKbdpg3ZzKl8= +github.com/tomarrell/wrapcheck/v2 v2.12.0 h1:H/qQ1aNWz/eeIhxKAFvkfIA+N7YDvq6TWVFL27Of9is= +github.com/tomarrell/wrapcheck/v2 v2.12.0/go.mod h1:AQhQuZd0p7b6rfW+vUwHm5OMCGgp63moQ9Qr/0BpIWo= github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw= github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= -github.com/ultraware/funlen v0.1.0 h1:BuqclbkY6pO+cvxoq7OsktIXZpgBSkYTQtmwhAK81vI= -github.com/ultraware/funlen v0.1.0/go.mod h1:XJqmOQja6DpxarLj6Jj1U7JuoS8PvL4nEqDaQhy22p4= -github.com/ultraware/whitespace v0.1.1 h1:bTPOGejYFulW3PkcrqkeQwOd6NKOOXvmGD9bo/Gk8VQ= -github.com/ultraware/whitespace v0.1.1/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8= -github.com/uudashr/gocognit v1.1.3 h1:l+a111VcDbKfynh+airAy/DJQKaXh2m9vkoysMPSZyM= -github.com/uudashr/gocognit v1.1.3/go.mod h1:aKH8/e8xbTRBwjbCkwZ8qt4l2EpKXl31KMHgSS+lZ2U= -github.com/uudashr/iface v1.2.1 h1:vHHyzAUmWZ64Olq6NZT3vg/z1Ws56kyPdBOd5kTXDF8= -github.com/uudashr/iface v1.2.1/go.mod h1:4QvspiRd3JLPAEXBQ9AiZpLbJlrWWgRChOKDJEuQTdg= +github.com/ultraware/funlen v0.2.0 h1:gCHmCn+d2/1SemTdYMiKLAHFYxTYz7z9VIDRaTGyLkI= +github.com/ultraware/funlen v0.2.0/go.mod h1:ZE0q4TsJ8T1SQcjmkhN/w+MceuatI6pBFSxxyteHIJA= +github.com/ultraware/whitespace v0.2.0 h1:TYowo2m9Nfj1baEQBjuHzvMRbp19i+RCcRYrSWoFa+g= +github.com/ultraware/whitespace v0.2.0/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8= +github.com/uudashr/gocognit v1.2.1 h1:CSJynt5txTnORn/DkhiB4mZjwPuifyASC8/6Q0I/QS4= +github.com/uudashr/gocognit v1.2.1/go.mod h1:acaubQc6xYlXFEMb9nWX2dYBzJ/bIjEkc1zzvyIZg5Q= +github.com/uudashr/iface v1.4.1 h1:J16Xl1wyNX9ofhpHmQ9h9gk5rnv2A6lX/2+APLTo0zU= +github.com/uudashr/iface v1.4.1/go.mod h1:pbeBPlbuU2qkNDn0mmfrxP2X+wjPMIQAy+r1MBXSXtg= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= -github.com/xen0n/gosmopolitan v1.2.2 h1:/p2KTnMzwRexIW8GlKawsTWOxn7UHA+jCMF/V8HHtvU= -github.com/xen0n/gosmopolitan v1.2.2/go.mod h1:7XX7Mj61uLYrj0qmeN0zi7XDon9JRAEhYQqAPLVNTeg= +github.com/xen0n/gosmopolitan v1.3.0 h1:zAZI1zefvo7gcpbCOrPSHJZJYA9ZgLfJqtKzZ5pHqQM= +github.com/xen0n/gosmopolitan v1.3.0/go.mod h1:rckfr5T6o4lBtM1ga7mLGKZmLxswUoH1zxHgNXOsEt4= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM= github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= github.com/yeya24/promlinter v0.3.0 h1:JVDbMp08lVCP7Y6NP3qHroGAO6z2yGKQtS5JsjqtoFs= @@ -588,7 +626,6 @@ github.com/yeya24/promlinter v0.3.0/go.mod h1:cDfJQQYv9uYciW60QT0eeHlFodotkYZlL+ github.com/ykadowak/zerologlint v0.1.5 h1:Gy/fMz1dFQN9JZTPjv1hxEk+sRWm05row04Yoolgdiw= github.com/ykadowak/zerologlint v0.1.5/go.mod h1:KaUskqF3e/v59oPmdq1U1DnKcuHokl2/K1U4pmIELKg= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= @@ -598,32 +635,34 @@ gitlab.com/bosi/decorder v0.4.2 h1:qbQaV3zgwnBZ4zPMhGLW4KZe7A7NwxEhJx39R3shffo= gitlab.com/bosi/decorder v0.4.2/go.mod h1:muuhHoaJkA9QLcYHq4Mj8FJUwDZ+EirSHRiaTcTf6T8= go-simpler.org/assert v0.9.0 h1:PfpmcSvL7yAnWyChSjOz6Sp6m9j5lyK8Ok9pEL31YkQ= go-simpler.org/assert v0.9.0/go.mod h1:74Eqh5eI6vCK6Y5l3PI8ZYFXG4Sa+tkr70OIPJAUr28= -go-simpler.org/musttag v0.13.0 h1:Q/YAW0AHvaoaIbsPj3bvEI5/QFP7w696IMUpnKXQfCE= -go-simpler.org/musttag v0.13.0/go.mod h1:FTzIGeK6OkKlUDVpj0iQUXZLUO1Js9+mvykDQy9C5yM= -go-simpler.org/sloglint v0.7.2 h1:Wc9Em/Zeuu7JYpl+oKoYOsQSy2X560aVueCW/m6IijY= -go-simpler.org/sloglint v0.7.2/go.mod h1:US+9C80ppl7VsThQclkM7BkCHQAzuz8kHLsW3ppuluo= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go-simpler.org/musttag v0.14.0 h1:XGySZATqQYSEV3/YTy+iX+aofbZZllJaqwFWs+RTtSo= +go-simpler.org/musttag v0.14.0/go.mod h1:uP8EymctQjJ4Z1kUnjX0u2l60WfUdQxCwSNKzE1JEOE= +go-simpler.org/sloglint v0.11.1 h1:xRbPepLT/MHPTCA6TS/wNfZrDzkGvCCqUv4Bdwc3H7s= +go-simpler.org/sloglint v0.11.1/go.mod h1:2PowwiCOK8mjiF+0KGifVOT8ZsCNiFzvfyJeJOIt8MQ= +go.augendre.info/arangolint v0.4.0 h1:xSCZjRoS93nXazBSg5d0OGCi9APPLNMmmLrC995tR50= +go.augendre.info/arangolint v0.4.0/go.mod h1:l+f/b4plABuFISuKnTGD4RioXiCCgghv2xqst/xOvAA= +go.augendre.info/fatcontext v0.9.0 h1:Gt5jGD4Zcj8CDMVzjOJITlSb9cEch54hjRRlN3qDojE= +go.augendre.info/fatcontext v0.9.0/go.mod h1:L94brOAT1OOUNue6ph/2HnwxoNlds9aXDF2FcUntbNw= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY= -go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= -go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= +go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= -go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= -go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= -go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= -go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= -go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= -go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= -go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= -go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4= go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= -go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= -go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= @@ -640,28 +679,27 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= -golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= -golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b h1:DXr+pvt3nC887026GRP39Ej11UATqWDmWuS99x26cD0= -golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= +golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= +golang.org/x/exp v0.0.0-20250911091902-df9299821621 h1:2id6c1/gto0kaHYyrixvknJ8tUK/Qs5IsmBtrc+FtgU= +golang.org/x/exp v0.0.0-20250911091902-df9299821621/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/exp/typeparams v0.0.0-20241108190413-2d47ceb2692f h1:WTyX8eCCyfdqiPYkRGm0MqElSfYFH3yR1+rl/mct9sA= -golang.org/x/exp/typeparams v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/exp/typeparams v0.0.0-20260209203927-2842357ff358 h1:qWFG1Dj7TBjOjOvhEOkmyGPVoquqUKnIU0lEVLp8xyk= +golang.org/x/exp/typeparams v0.0.0-20260209203927-2842357ff358/go.mod h1:4Mzdyp/6jzw9auFDJ3OMF5qksa7UvPnzKqTVGcb04ms= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= -golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= +golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -671,14 +709,14 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= -golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= -golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= -golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= +golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -686,6 +724,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -693,7 +733,6 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -702,61 +741,49 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= -golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= +golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= -golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= -golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= -golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190321232350-e250d351ecad/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= -golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= -golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= -golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= +golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM= @@ -765,8 +792,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= -gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= +gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0= +gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/genproto/googleapis/api v0.0.0-20250826171959-ef028d996bc1 h1:APHvLLYBhtZvsbnpkfknDZ7NyH4z5+ub/I0u8L3Oz6g= @@ -775,8 +802,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1 h1: google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og= google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4= google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= -google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= -google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= @@ -788,8 +815,8 @@ gopkg.in/gcfg.v1 v1.2.3 h1:m8OOJ4ccYHnx2f4gQwpno8nAX5OGOh7RLaaz0pj3Ogs= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= -gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.1 h1:tVBILHy0R6e4wkYOn3XmiITt/hEVH4TFMYvAX2Ytz6k= +gopkg.in/ini.v1 v1.67.1/go.mod h1:x/cyOwCgZqOkJoDIJ3c1KNHMo10+nLGAhh+kn3Zizss= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= @@ -800,52 +827,54 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.5.1 h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I= -honnef.co/go/tools v0.5.1/go.mod h1:e9irvo83WDG9/irijV44wr3tbhcFeRnfpVlRqVwpzMs= -k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= -k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= -k8s.io/apiextensions-apiserver v0.34.3 h1:p10fGlkDY09eWKOTeUSioxwLukJnm+KuDZdrW71y40g= -k8s.io/apiextensions-apiserver v0.34.3/go.mod h1:aujxvqGFRdb/cmXYfcRTeppN7S2XV/t7WMEc64zB5A0= -k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= -k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/apiserver v0.34.3 h1:uGH1qpDvSiYG4HVFqc6A3L4CKiX+aBWDrrsxHYK0Bdo= -k8s.io/apiserver v0.34.3/go.mod h1:QPnnahMO5C2m3lm6fPW3+JmyQbvHZQ8uudAu/493P2w= -k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= -k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= -k8s.io/cloud-provider-aws v1.34.1-0.20250912204608-8a0025b4efb1 h1:yXrYREaxoMix9I+xfgZxwgvRhr7vs0iZJGrvELXYpik= -k8s.io/cloud-provider-aws v1.34.1-0.20250912204608-8a0025b4efb1/go.mod h1:a8p1e6RHviJmZ/ZJK9S26CpZ07uv/jCZa93opvKSDA8= -k8s.io/cloud-provider-vsphere v1.34.0 h1:XVn67iOmwld6pQI6DGCxwiA515VsHofIOUIwaVN8VLo= -k8s.io/cloud-provider-vsphere v1.34.0/go.mod h1:W+o/i/LjkiXU3yNt8fXcoY97zroeOUfCk0vWtXfUJAQ= -k8s.io/component-base v0.34.3 h1:zsEgw6ELqK0XncCQomgO9DpUIzlrYuZYA0Cgo+JWpVk= -k8s.io/component-base v0.34.3/go.mod h1:5iIlD8wPfWE/xSHTRfbjuvUul2WZbI2nOUK65XL0E/c= -k8s.io/controller-manager v0.34.0 h1:oCHoqS8dcFp7zDSu7HUvTpakq3isSxil3GprGGlJMsE= -k8s.io/controller-manager v0.34.0/go.mod h1:XFto21U+Mm9BT8r/Jd5E4tHCGtwjKAUFOuDcqaj2VK0= -k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= -k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-aggregator v0.34.1 h1:WNLV0dVNoFKmuyvdWLd92iDSyD/TSTjqwaPj0U9XAEU= -k8s.io/kube-aggregator v0.34.1/go.mod h1:RU8j+5ERfp0h+gIvWtxRPfsa5nK7rboDm8RST8BJfYQ= +honnef.co/go/tools v0.7.0 h1:w6WUp1VbkqPEgLz4rkBzH/CSU6HkoqNLp6GstyTx3lU= +honnef.co/go/tools v0.7.0/go.mod h1:pm29oPxeP3P82ISxZDgIYeOaf9ta6Pi0EWvCFoLG2vc= +k8s.io/api v0.35.1 h1:0PO/1FhlK/EQNVK5+txc4FuhQibV25VLSdLMmGpDE/Q= +k8s.io/api v0.35.1/go.mod h1:28uR9xlXWml9eT0uaGo6y71xK86JBELShLy4wR1XtxM= +k8s.io/apiextensions-apiserver v0.35.1 h1:p5vvALkknlOcAqARwjS20kJffgzHqwyQRM8vHLwgU7w= +k8s.io/apiextensions-apiserver v0.35.1/go.mod h1:2CN4fe1GZ3HMe4wBr25qXyJnJyZaquy4nNlNmb3R7AQ= +k8s.io/apimachinery v0.35.1 h1:yxO6gV555P1YV0SANtnTjXYfiivaTPvCTKX6w6qdDsU= +k8s.io/apimachinery v0.35.1/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns= +k8s.io/apiserver v0.35.1 h1:potxdhhTL4i6AYAa2QCwtlhtB1eCdWQFvJV6fXgJzxs= +k8s.io/apiserver v0.35.1/go.mod h1:BiL6Dd3A2I/0lBnteXfWmCFobHM39vt5+hJQd7Lbpi4= +k8s.io/client-go v0.35.1 h1:+eSfZHwuo/I19PaSxqumjqZ9l5XiTEKbIaJ+j1wLcLM= +k8s.io/client-go v0.35.1/go.mod h1:1p1KxDt3a0ruRfc/pG4qT/3oHmUj1AhSHEcxNSGg+OA= +k8s.io/cloud-provider-aws v1.35.1 h1:alBjzyitPhOeeHebdt6NbI64tm4MKrj7+Uo/CzYOx1U= +k8s.io/cloud-provider-aws v1.35.1/go.mod h1:6R9TIgQ/ecysPukSmEUs4kZIwqvju80+FjMAhtJ22Q0= +k8s.io/code-generator v0.35.1 h1:yLKR2la7Z9cWT5qmk67ayx8xXLM4RRKQMnC8YPvTWRI= +k8s.io/code-generator v0.35.1/go.mod h1:F2Fhm7aA69tC/VkMXLDokdovltXEF026Tb9yfQXQWKg= +k8s.io/component-base v0.35.1 h1:XgvpRf4srp037QWfGBLFsYMUQJkE5yMa94UsJU7pmcE= +k8s.io/component-base v0.35.1/go.mod h1:HI/6jXlwkiOL5zL9bqA3en1Ygv60F03oEpnuU1G56Bs= +k8s.io/controller-manager v0.35.1 h1:AKMrGk8sCDa0WtLh+8yfcKck3r/AVw60FOmpak/4fB0= +k8s.io/controller-manager v0.35.1/go.mod h1:ifoFum/gxonT7duRuSrNQxU7bctlStGMXraZP5xbaso= +k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b h1:gMplByicHV/TJBizHd9aVEsTYoJBnnUAT5MHlTkbjhQ= +k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b/go.mod h1:CgujABENc3KuTrcsdpGmrrASjtQsWCT7R99mEV4U/fM= +k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc= +k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0= +k8s.io/kube-aggregator v0.35.1 h1:LN+btMJ3yp7biqVgT/0LF6SKIKLyfPU0R+JJ1mycs2I= +k8s.io/kube-aggregator v0.35.1/go.mod h1:HQSjPQfOFRzcv7biQ7jV3cEfKHG+bczpLCfh4QfvxZU= k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE= k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= -k8s.io/utils v0.0.0-20260108192941-914a6e750570 h1:JT4W8lsdrGENg9W+YwwdLJxklIuKWdRm+BC+xt33FOY= -k8s.io/utils v0.0.0-20260108192941-914a6e750570/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= -mvdan.cc/gofumpt v0.7.0 h1:bg91ttqXmi9y2xawvkuMXyvAA/1ZGJqYAEGjXuP0JXU= -mvdan.cc/gofumpt v0.7.0/go.mod h1:txVFJy/Sc/mvaycET54pV8SW8gWxTlUuGHVEcncmNUo= -mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f h1:lMpcwN6GxNbWtbpI1+xzFLSW8XzX0u72NttUGVFjO3U= -mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f/go.mod h1:RSLa7mKKCNeTTMHBw5Hsy2rfJmd6O2ivt9Dw9ZqCQpQ= +k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 h1:AZYQSJemyQB5eRxqcPky+/7EdBj0xi3g0ZcxxJ7vbWU= +k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= +mvdan.cc/gofumpt v0.9.2 h1:zsEMWL8SVKGHNztrx6uZrXdp7AX8r421Vvp23sz7ik4= +mvdan.cc/gofumpt v0.9.2/go.mod h1:iB7Hn+ai8lPvofHd9ZFGVg2GOr8sBUw1QUWjNbmIL/s= +mvdan.cc/unparam v0.0.0-20251027182757-5beb8c8f8f15 h1:ssMzja7PDPJV8FStj7hq9IKiuiKhgz9ErWw+m68e7DI= +mvdan.cc/unparam v0.0.0-20251027182757-5beb8c8f8f15/go.mod h1:4M5MMXl2kW6fivUT6yRGpLLPNfuGtU2Z0cPvFquGDYU= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.33.0 h1:qPrZsv1cwQiFeieFlRqT627fVZ+tyfou/+S5S0H5ua0= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.33.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= -sigs.k8s.io/cloud-provider-azure v1.34.1 h1:FnzU4vMtbMVqbPG9kuXNv7e18sb+JT3TwyBoDBiexK4= -sigs.k8s.io/cloud-provider-azure v1.34.1/go.mod h1:5h1gnWhmxmQuIx2F85Bqo7HYOgR3nSq8kWuYA9Piulg= -sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.9.2 h1:7vEaYwdsvOz1OBAtEm6vyc4KCTsIZ8P9WN9OFfTAlTg= -sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.9.2/go.mod h1:BgPOvGEdPTyaIWREF7pywm6teBhO3fNVQ+CTPYyr/5w= -sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.8.4 h1:Sy+dyfxemdQaz/UfJYWzALlbLdEaZ7IoKn93JXTqWYs= -sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.8.4/go.mod h1:RgIi9n/PhULbvPjYZGsjP2zWJf1ZEd1qyA0CYUuSgcE= -sigs.k8s.io/controller-runtime v0.22.5 h1:v3nfSUMowX/2WMp27J9slwGFyAt7IV0YwBxAkrUr0GE= -sigs.k8s.io/controller-runtime v0.22.5/go.mod h1:pc5SoYWnWI6I+cBHYYdZ7B6YHZVY5xNfll88JB+vniI= +sigs.k8s.io/cloud-provider-azure v1.35.1 h1:7dntYGWYP9UE6OZprSLYc8GqFdYlGQGPOA9rWAx7BqQ= +sigs.k8s.io/cloud-provider-azure v1.35.1/go.mod h1:euktxdcotbaPbP7NAsbVEkCF52CjI+W81jBRva+z5CE= +sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.13.0 h1:MmCsEs5tx/5W1uRV8+Iv0tD7taBv40gjZ5SJZxxqUUY= +sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.13.0/go.mod h1:zIU1j1Q/+kHoYXtww3j8qDm3bPeeRYLD9JRipBR+HZQ= +sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.11.0 h1:xbQUC6pfgnxPE1pKiYIRmR5HkyZ7StB7fnZwQ6pr0eE= +sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.11.0/go.mod h1:9lQ7K/C/ms3OEDRlzLg2zyJVieNjV/7WfsQmOSnDaOQ= +sigs.k8s.io/controller-runtime v0.23.2 h1:Oh3FliXaA2CS1chpUXvjVNJtsvGZYUxQH8s7bvR7aXk= +sigs.k8s.io/controller-runtime v0.23.2/go.mod h1:B6COOxKptp+YaUT5q4l6LqUJTRpizbgf9KSRNdQGns0= sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20251103140007-7a1b16d039d2 h1:xLNIemrdP6o6uyzoBQEf83zPX9nO1G10t7sttZ3qz20= sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20251103140007-7a1b16d039d2/go.mod h1:sWEAaKdjIb8+pUyzfpeClTvbK2vTRdeF39lz/ee4EMU= -sigs.k8s.io/controller-tools v0.17.1 h1:bQ+dKCS7jY9AgpefenBDtm6geJZCHVKbegpLynxgyus= -sigs.k8s.io/controller-tools v0.17.1/go.mod h1:3QXAdrmdxYuQ4MifvbCAFD9wLXn7jylnfBPYS4yVDdc= +sigs.k8s.io/controller-tools v0.20.1 h1:gkfMt9YodI0K85oT8rVi80NTXO/kDmabKR5Ajn5GYxs= +sigs.k8s.io/controller-tools v0.20.1/go.mod h1:b4qPmjGU3iZwqn34alUU5tILhNa9+VXK+J3QV0fT/uU= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/kube-storage-version-migrator v0.0.6-0.20230721195810-5c8923c5ff96 h1:PFWFSkpArPNJxFX4ZKWAk9NSeRoZaXschn+ULa4xVek= diff --git a/tools/tools.go b/tools/tools.go index 9fd2e1079..13b01ecc6 100644 --- a/tools/tools.go +++ b/tools/tools.go @@ -4,7 +4,7 @@ package tools import ( - _ "github.com/golangci/golangci-lint/cmd/golangci-lint" + _ "github.com/golangci/golangci-lint/v2/cmd/golangci-lint" _ "github.com/onsi/ginkgo/v2/ginkgo" _ "sigs.k8s.io/controller-runtime/tools/setup-envtest" _ "sigs.k8s.io/controller-tools/cmd/controller-gen" From 4982c32f184460f6ef499091a1d0f5c048ebcfaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radek=20Ma=C5=88=C3=A1k?= Date: Tue, 17 Mar 2026 15:42:47 +0100 Subject: [PATCH 2/3] Vendor --- .../checkcompilerdirectives.go | 11 +- .../checknoglobals/check_no_globals.go | 14 - .../chavacava/garif/.gitignore | 0 .../chavacava/garif/LICENSE | 0 .../chavacava/garif/README.md | 2 +- .../chavacava/garif/constructors.go | 0 .../chavacava/garif/decorators.go | 0 .../chavacava/garif/doc.go | 2 +- .../chavacava/garif/enums.go | 0 .../chavacava/garif/io.go | 0 .../chavacava/garif/models.go | 16 +- .../polyfloyd/go-errorlint/LICENSE | 0 .../go-errorlint/errorlint/allowed.go | 0 .../go-errorlint/errorlint/analysis.go | 2 +- .../polyfloyd/go-errorlint/errorlint/lint.go | 908 + .../go-errorlint/errorlint/options.go | 12 + .../go-errorlint/errorlint/printf.go | 0 .../go/exhaustruct/v4}/LICENSE | 0 .../go/exhaustruct/v4}/analyzer/analyzer.go | 289 +- .../go/exhaustruct/v4/analyzer/config.go | 127 + .../exhaustruct/v4}/internal/comment/cache.go | 0 .../v4}/internal/comment/directive.go | 0 .../exhaustruct/v4/internal/pattern/list.go | 91 + .../v4}/internal/structure/fields-cache.go | 0 .../v4}/internal/structure/fields.go | 0 vendor/dev.gaijin.team/go/golib/LICENSE | 21 + vendor/dev.gaijin.team/go/golib/e/doc.go | 46 + vendor/dev.gaijin.team/go/golib/e/err.go | 140 + vendor/dev.gaijin.team/go/golib/e/log.go | 33 + .../dev.gaijin.team/go/golib/fields/dict.go | 69 + vendor/dev.gaijin.team/go/golib/fields/doc.go | 32 + .../dev.gaijin.team/go/golib/fields/field.go | 82 + .../dev.gaijin.team/go/golib/fields/list.go | 69 + vendor/github.com/4meepo/tagalign/.gitignore | 1 + .../4meepo/tagalign/.goreleaser.yml | 4 +- vendor/github.com/4meepo/tagalign/options.go | 7 - vendor/github.com/4meepo/tagalign/tagalign.go | 189 +- vendor/github.com/Abirdcfly/dupword/README.md | 6 +- .../github.com/Abirdcfly/dupword/dupword.go | 94 +- .../github.com/AdminBenni/iota-mixing/LICENSE | 21 + .../iota-mixing/pkg/analyzer/analyzer.go | 118 + .../iota-mixing/pkg/analyzer/flags/flags.go | 23 + .../github.com/AlwxSin/noinlineerr/.gitignore | 33 + .../AlwxSin/noinlineerr/.golangci.yml | 168 + .../AlwxSin/noinlineerr/.goreleaser.yml | 25 + .../tenv => AlwxSin/noinlineerr}/LICENSE | 2 +- .../github.com/AlwxSin/noinlineerr/README.md | 54 + .../AlwxSin/noinlineerr/noinlineerr.go | 154 + .../errname/pkg/analyzer/analyzer.go | 14 +- .../Antonboom/nilnil/pkg/analyzer/analyzer.go | 78 +- .../testifylint/analyzer/analyzer.go | 23 +- .../testifylint/analyzer/checkers_factory.go | 1 + .../internal/checkers/bool_compare.go | 8 +- .../internal/checkers/call_meta.go | 2 +- .../testifylint/internal/checkers/checker.go | 2 +- .../internal/checkers/checkers_registry.go | 4 +- .../testifylint/internal/checkers/empty.go | 73 +- .../internal/checkers/equal_values.go | 59 + .../internal/checkers/error_is_as.go | 50 +- .../internal/checkers/error_nil.go | 6 +- .../internal/checkers/expected_actual.go | 12 +- .../internal/checkers/formatter.go | 120 +- .../internal/checkers/go_require.go | 8 +- .../internal/checkers/helpers_basic_type.go | 42 +- .../internal/checkers/helpers_bool.go | 6 +- .../internal/checkers/helpers_comparison.go | 2 +- .../internal/checkers/helpers_context.go | 2 +- .../internal/checkers/helpers_diagnostic.go | 26 +- .../internal/checkers/helpers_http.go | 2 +- .../internal/checkers/helpers_len.go | 26 - .../testifylint/internal/checkers/len.go | 102 +- .../internal/checkers/negative_positive.go | 35 +- .../internal/checkers/require_error.go | 4 +- .../checkers/suite_method_signature.go | 71 + .../internal/checkers/suite_thelper.go | 6 +- .../internal/checkers/useless_assert.go | 97 +- .../testifylint/internal/config/config.go | 7 +- .../azure-sdk-for-go/sdk/azcore/CHANGELOG.md | 22 + .../internal/resource/resource_identifier.go | 26 +- .../sdk/azcore/internal/exported/exported.go | 2 +- .../sdk/azcore/internal/shared/constants.go | 2 +- .../sdk/azcore/runtime/pager.go | 11 +- .../sdk/azcore/runtime/poller.go | 2 +- .../sdk/azidentity/CHANGELOG.md | 41 + .../azure-sdk-for-go/sdk/azidentity/README.md | 3 +- .../sdk/azidentity/TOKEN_CACHING.MD | 1 + .../sdk/azidentity/TROUBLESHOOTING.md | 39 +- .../sdk/azidentity/assets.json | 2 +- .../sdk/azidentity/azure_cli_credential.go | 106 +- .../azure_developer_cli_credential.go | 108 +- .../azidentity/azure_powershell_credential.go | 234 + .../azure-sdk-for-go/sdk/azidentity/ci.yml | 3 - .../azidentity/default_azure_credential.go | 46 +- .../azidentity/developer_credential_util.go | 64 +- .../developer_credential_util_nonwindows.go | 17 + .../developer_credential_util_windows.go | 22 + .../azure-sdk-for-go/sdk/azidentity/errors.go | 2 + .../azidentity/managed-identity-matrix.json | 5 +- .../sdk/azidentity/test-resources-post.ps1 | 38 +- .../sdk/azidentity/test-resources.bicep | 164 +- .../sdk/azidentity/version.go | 2 +- .../storage/armstorage/autorest.md | 15 - .../storage/armstorage/{ => v2}/CHANGELOG.md | 31 + .../storage/armstorage/{ => v2}/LICENSE.txt | 0 .../storage/armstorage/{ => v2}/README.md | 2 +- .../armstorage/{ => v2}/accounts_client.go | 84 +- .../storage/armstorage/{ => v2}/assets.json | 0 .../storage/armstorage/v2/autorest.md | 15 + .../{ => v2}/blobcontainers_client.go | 58 +- .../{ => v2}/blobinventorypolicies_client.go | 16 +- .../{ => v2}/blobservices_client.go | 12 +- .../storage/armstorage/{ => v2}/build.go | 0 .../storage/armstorage/{ => v2}/ci.yml | 0 .../armstorage/{ => v2}/client_factory.go | 0 .../storage/armstorage/{ => v2}/constants.go | 42 +- .../{ => v2}/deletedaccounts_client.go | 8 +- .../{ => v2}/encryptionscopes_client.go | 16 +- .../{ => v2}/fileservices_client.go | 20 +- .../armstorage/{ => v2}/fileshares_client.go | 28 +- .../armstorage/{ => v2}/localusers_client.go | 24 +- .../{ => v2}/managementpolicies_client.go | 12 +- .../storage/armstorage/{ => v2}/models.go | 186 +- .../armstorage/{ => v2}/models_serde.go | 285 +- ...ksecurityperimeterconfigurations_client.go | 14 +- .../objectreplicationpolicies_client.go | 16 +- .../armstorage/{ => v2}/operations_client.go | 4 +- .../storage/armstorage/{ => v2}/options.go | 0 .../privateendpointconnections_client.go | 16 +- .../{ => v2}/privatelinkresources_client.go | 4 +- .../armstorage/{ => v2}/queue_client.go | 20 +- .../{ => v2}/queueservices_client.go | 12 +- .../storage/armstorage/{ => v2}/responses.go | 0 .../armstorage/{ => v2}/skus_client.go | 4 +- .../armstorage/{ => v2}/table_client.go | 20 +- .../{ => v2}/tableservices_client.go | 12 +- .../taskassignmentinstancesreport_client.go | 4 +- .../{ => v2}/taskassignments_client.go | 26 +- .../taskassignmentsinstancesreport_client.go | 4 +- .../armstorage/{ => v2}/time_rfc1123.go | 0 .../armstorage/{ => v2}/time_rfc3339.go | 0 .../armstorage/{ => v2}/usages_client.go | 4 +- .../storage/armstorage/v2/version.go | 10 + .../apps/confidential/confidential.go | 103 +- .../apps/internal/base/base.go | 47 +- .../apps/internal/base/storage/items.go | 17 +- .../apps/internal/base/storage/storage.go | 51 +- .../oauth/ops/accesstokens/accesstokens.go | 17 + .../internal/oauth/ops/authority/authority.go | 84 +- .../apps/public/public.go | 4 +- vendor/github.com/BurntSushi/toml/README.md | 4 +- vendor/github.com/BurntSushi/toml/decode.go | 32 +- vendor/github.com/BurntSushi/toml/encode.go | 125 +- vendor/github.com/BurntSushi/toml/error.go | 2 +- vendor/github.com/BurntSushi/toml/lex.go | 149 +- vendor/github.com/BurntSushi/toml/meta.go | 3 - vendor/github.com/BurntSushi/toml/parse.go | 49 +- .../fatcontext/pkg/analyzer/analyzer.go | 224 - .../github.com/Djarvur/go-err113/.travis.yml | 16 +- .../Djarvur/go-err113/comparison.go | 32 +- vendor/github.com/Djarvur/go-err113/err113.go | 10 +- .../v3/internal/pattern/list.go | 82 - .../MirrexOne/unqueryvet/.gitignore | 56 + .../MirrexOne/unqueryvet/.golangci.yml | 20 + .../unqueryvet/.unqueryvet.example.yaml | 165 + .../MirrexOne/unqueryvet/CONTRIBUTING.md | 341 + .../MirrexOne/unqueryvet/Dockerfile | 42 + .../MirrexOne/unqueryvet}/LICENSE | 12 +- .../github.com/MirrexOne/unqueryvet/README.md | 900 + .../MirrexOne/unqueryvet/RELEASE.md | 203 + .../MirrexOne/unqueryvet/Taskfile.yml | 398 + .../MirrexOne/unqueryvet/action.yml | 92 + .../MirrexOne/unqueryvet/analyzer.go | 27 + .../github.com/MirrexOne/unqueryvet/config.go | 11 + .../unqueryvet/internal/analyzer/analyzer.go | 414 + .../unqueryvet/internal/analyzer/concat.go | 100 + .../unqueryvet/internal/analyzer/filter.go | 176 + .../unqueryvet/internal/analyzer/fixes.go | 126 + .../unqueryvet/internal/analyzer/format.go | 217 + .../internal/analyzer/n1detector.go | 546 + .../internal/analyzer/sqlbuilders/bun.go | 146 + .../internal/analyzer/sqlbuilders/ent.go | 87 + .../internal/analyzer/sqlbuilders/goqu.go | 120 + .../internal/analyzer/sqlbuilders/gorm.go | 190 + .../analyzer/sqlbuilders/interface.go | 156 + .../internal/analyzer/sqlbuilders/jet.go | 184 + .../internal/analyzer/sqlbuilders/pgx.go | 82 + .../internal/analyzer/sqlbuilders/reform.go | 238 + .../internal/analyzer/sqlbuilders/rel.go | 227 + .../analyzer/sqlbuilders/sqlboiler.go | 135 + .../internal/analyzer/sqlbuilders/sqlc.go | 87 + .../internal/analyzer/sqlbuilders/sqlx.go | 90 + .../internal/analyzer/sqlbuilders/squirrel.go | 214 + .../internal/analyzer/sqli_scanner.go | 750 + .../internal/analyzer/tx_leak_detector.go | 1665 ++ .../MirrexOne/unqueryvet/pkg/config/config.go | 187 + .../MirrexOne/unqueryvet/schema.json | 270 + .../OpenPeeDeeP/depguard/v2/README.md | 30 +- .../OpenPeeDeeP/depguard/v2/depguard.go | 6 +- .../OpenPeeDeeP/depguard/v2/settings.go | 14 +- .../chroma/v2}/.editorconfig | 17 +- .../alecthomas/chroma/v2/.gitignore | 28 + .../alecthomas/chroma/v2/.golangci.yml | 89 + .../alecthomas/chroma/v2/.goreleaser.yml | 34 + .../github.com/alecthomas/chroma/v2/AGENTS.md | 11 + .../github.com/alecthomas/chroma/v2/Bitfile | 24 + .../github.com/alecthomas/chroma/v2/COPYING | 19 + .../alecthomas/chroma/v2/Dockerfile | 64 + .../github.com/alecthomas/chroma/v2/Justfile | 55 + .../github.com/alecthomas/chroma/v2/README.md | 307 + .../alecthomas/chroma/v2/biome.json | 6 + .../alecthomas/chroma/v2/chroma.jpg | Bin 0 -> 80950 bytes .../alecthomas/chroma/v2/coalesce.go | 35 + .../github.com/alecthomas/chroma/v2/colour.go | 192 + .../alecthomas/chroma/v2/delegate.go | 161 + vendor/github.com/alecthomas/chroma/v2/doc.go | 7 + .../alecthomas/chroma/v2/emitters.go | 233 + .../alecthomas/chroma/v2/formatter.go | 43 + .../alecthomas/chroma/v2/formatters/api.go | 57 + .../chroma/v2/formatters/html/html.go | 648 + .../alecthomas/chroma/v2/formatters/json.go | 39 + .../v2/formatters/svg/font_liberation_mono.go | 51 + .../chroma/v2/formatters/svg/svg.go | 222 + .../alecthomas/chroma/v2/formatters/tokens.go | 18 + .../chroma/v2/formatters/tty_indexed.go | 284 + .../chroma/v2/formatters/tty_truecolour.go | 76 + .../alecthomas/chroma/v2/iterator.go | 93 + .../github.com/alecthomas/chroma/v2/lexer.go | 179 + .../alecthomas/chroma/v2/lexers/README.md | 46 + .../alecthomas/chroma/v2/lexers/caddyfile.go | 275 + .../alecthomas/chroma/v2/lexers/cl.go | 243 + .../alecthomas/chroma/v2/lexers/dns.go | 17 + .../alecthomas/chroma/v2/lexers/emacs.go | 533 + .../chroma/v2/lexers/embedded/abap.xml | 154 + .../chroma/v2/lexers/embedded/abnf.xml | 66 + .../v2/lexers/embedded/actionscript.xml | 68 + .../v2/lexers/embedded/actionscript_3.xml | 163 + .../chroma/v2/lexers/embedded/ada.xml | 321 + .../chroma/v2/lexers/embedded/agda.xml | 66 + .../chroma/v2/lexers/embedded/al.xml | 75 + .../chroma/v2/lexers/embedded/alloy.xml | 58 + .../chroma/v2/lexers/embedded/angular2.xml | 109 + .../chroma/v2/lexers/embedded/antlr.xml | 317 + .../chroma/v2/lexers/embedded/apacheconf.xml | 74 + .../chroma/v2/lexers/embedded/apl.xml | 59 + .../chroma/v2/lexers/embedded/applescript.xml | 151 + .../v2/lexers/embedded/arangodb_aql.xml | 174 + .../chroma/v2/lexers/embedded/arduino.xml | 322 + .../chroma/v2/lexers/embedded/armasm.xml | 126 + .../chroma/v2/lexers/embedded/atl.xml | 165 + .../chroma/v2/lexers/embedded/autohotkey.xml | 78 + .../chroma/v2/lexers/embedded/autoit.xml | 70 + .../chroma/v2/lexers/embedded/awk.xml | 95 + .../chroma/v2/lexers/embedded/ballerina.xml | 97 + .../chroma/v2/lexers/embedded/bash.xml | 222 + .../v2/lexers/embedded/bash_session.xml | 25 + .../chroma/v2/lexers/embedded/batchfile.xml | 660 + .../chroma/v2/lexers/embedded/beef.xml | 120 + .../chroma/v2/lexers/embedded/bibtex.xml | 152 + .../chroma/v2/lexers/embedded/bicep.xml | 84 + .../chroma/v2/lexers/embedded/blitzbasic.xml | 141 + .../chroma/v2/lexers/embedded/bnf.xml | 28 + .../chroma/v2/lexers/embedded/bqn.xml | 83 + .../chroma/v2/lexers/embedded/brainfuck.xml | 51 + .../chroma/v2/lexers/embedded/c#.xml | 121 + .../chroma/v2/lexers/embedded/c++.xml | 331 + .../chroma/v2/lexers/embedded/c.xml | 260 + .../chroma/v2/lexers/embedded/c3.xml | 374 + .../chroma/v2/lexers/embedded/cap_n_proto.xml | 122 + .../v2/lexers/embedded/cassandra_cql.xml | 137 + .../chroma/v2/lexers/embedded/ceylon.xml | 151 + .../chroma/v2/lexers/embedded/cfengine3.xml | 197 + .../chroma/v2/lexers/embedded/cfstatement.xml | 92 + .../chroma/v2/lexers/embedded/chaiscript.xml | 134 + .../chroma/v2/lexers/embedded/chapel.xml | 143 + .../chroma/v2/lexers/embedded/cheetah.xml | 55 + .../chroma/v2/lexers/embedded/clojure.xml | 71 + .../chroma/v2/lexers/embedded/cmake.xml | 90 + .../chroma/v2/lexers/embedded/cobol.xml | 90 + .../v2/lexers/embedded/coffeescript.xml | 210 + .../chroma/v2/lexers/embedded/common_lisp.xml | 184 + .../chroma/v2/lexers/embedded/coq.xml | 136 + .../chroma/v2/lexers/embedded/core.xml | 79 + .../chroma/v2/lexers/embedded/crystal.xml | 762 + .../chroma/v2/lexers/embedded/css.xml | 323 + .../chroma/v2/lexers/embedded/csv.xml | 53 + .../chroma/v2/lexers/embedded/cue.xml | 85 + .../chroma/v2/lexers/embedded/cython.xml | 372 + .../chroma/v2/lexers/embedded/d.xml | 133 + .../chroma/v2/lexers/embedded/dart.xml | 213 + .../chroma/v2/lexers/embedded/dax.xml | 39 + .../v2/lexers/embedded/desktop_entry.xml | 17 + .../chroma/v2/lexers/embedded/devicetree.xml | 251 + .../chroma/v2/lexers/embedded/diff.xml | 52 + .../v2/lexers/embedded/django_jinja.xml | 153 + .../chroma/v2/lexers/embedded/dns.xml | 44 + .../chroma/v2/lexers/embedded/docker.xml | 68 + .../chroma/v2/lexers/embedded/dtd.xml | 168 + .../chroma/v2/lexers/embedded/dylan.xml | 176 + .../chroma/v2/lexers/embedded/ebnf.xml | 90 + .../chroma/v2/lexers/embedded/elixir.xml | 744 + .../chroma/v2/lexers/embedded/elm.xml | 119 + .../chroma/v2/lexers/embedded/emacslisp.xml | 132 + .../chroma/v2/lexers/embedded/erlang.xml | 166 + .../chroma/v2/lexers/embedded/factor.xml | 412 + .../chroma/v2/lexers/embedded/fennel.xml | 68 + .../chroma/v2/lexers/embedded/fish.xml | 159 + .../chroma/v2/lexers/embedded/forth.xml | 78 + .../chroma/v2/lexers/embedded/fortran.xml | 102 + .../v2/lexers/embedded/fortranfixed.xml | 71 + .../chroma/v2/lexers/embedded/fsharp.xml | 245 + .../chroma/v2/lexers/embedded/gas.xml | 150 + .../chroma/v2/lexers/embedded/gdscript.xml | 259 + .../chroma/v2/lexers/embedded/gdscript3.xml | 270 + .../chroma/v2/lexers/embedded/gherkin.xml | 263 + .../chroma/v2/lexers/embedded/gleam.xml | 100 + .../chroma/v2/lexers/embedded/glsl.xml | 65 + .../chroma/v2/lexers/embedded/gnuplot.xml | 289 + .../chroma/v2/lexers/embedded/go_template.xml | 114 + .../chroma/v2/lexers/embedded/graphql.xml | 88 + .../chroma/v2/lexers/embedded/groff.xml | 90 + .../chroma/v2/lexers/embedded/groovy.xml | 135 + .../chroma/v2/lexers/embedded/handlebars.xml | 147 + .../chroma/v2/lexers/embedded/hare.xml | 98 + .../chroma/v2/lexers/embedded/haskell.xml | 275 + .../chroma/v2/lexers/embedded/hcl.xml | 143 + .../chroma/v2/lexers/embedded/hexdump.xml | 189 + .../chroma/v2/lexers/embedded/hlb.xml | 131 + .../chroma/v2/lexers/embedded/hlsl.xml | 110 + .../chroma/v2/lexers/embedded/holyc.xml | 252 + .../chroma/v2/lexers/embedded/html.xml | 159 + .../chroma/v2/lexers/embedded/hy.xml | 104 + .../chroma/v2/lexers/embedded/idris.xml | 216 + .../chroma/v2/lexers/embedded/igor.xml | 47 + .../chroma/v2/lexers/embedded/ini.xml | 52 + .../chroma/v2/lexers/embedded/io.xml | 71 + .../chroma/v2/lexers/embedded/iscdhcpd.xml | 96 + .../chroma/v2/lexers/embedded/j.xml | 157 + .../chroma/v2/lexers/embedded/janet.xml | 48 + .../chroma/v2/lexers/embedded/java.xml | 193 + .../chroma/v2/lexers/embedded/javascript.xml | 160 + .../chroma/v2/lexers/embedded/json.xml | 112 + .../chroma/v2/lexers/embedded/jsonata.xml | 83 + .../chroma/v2/lexers/embedded/jsonnet.xml | 138 + .../chroma/v2/lexers/embedded/julia.xml | 400 + .../chroma/v2/lexers/embedded/jungle.xml | 98 + .../chroma/v2/lexers/embedded/kakoune.xml | 96 + .../chroma/v2/lexers/embedded/kdl.xml | 75 + .../chroma/v2/lexers/embedded/kotlin.xml | 234 + .../chroma/v2/lexers/embedded/lean.xml | 56 + .../embedded/lighttpd_configuration_file.xml | 42 + .../chroma/v2/lexers/embedded/llvm.xml | 73 + .../chroma/v2/lexers/embedded/lox.xml | 78 + .../chroma/v2/lexers/embedded/lua.xml | 160 + .../chroma/v2/lexers/embedded/makefile.xml | 131 + .../chroma/v2/lexers/embedded/mako.xml | 120 + .../chroma/v2/lexers/embedded/mason.xml | 89 + .../embedded/materialize_sql_dialect.xml | 155 + .../chroma/v2/lexers/embedded/mathematica.xml | 60 + .../chroma/v2/lexers/embedded/matlab.xml | 114 + .../chroma/v2/lexers/embedded/mcfunction.xml | 138 + .../chroma/v2/lexers/embedded/meson.xml | 85 + .../chroma/v2/lexers/embedded/metal.xml | 270 + .../chroma/v2/lexers/embedded/microcad.xml | 139 + .../chroma/v2/lexers/embedded/minizinc.xml | 82 + .../chroma/v2/lexers/embedded/mlir.xml | 73 + .../chroma/v2/lexers/embedded/modelica.xml | 106 + .../chroma/v2/lexers/embedded/modula-2.xml | 245 + .../chroma/v2/lexers/embedded/mojo.xml | 228 + .../chroma/v2/lexers/embedded/monkeyc.xml | 153 + .../chroma/v2/lexers/embedded/moonbit.xml | 75 + .../chroma/v2/lexers/embedded/moonscript.xml | 83 + .../v2/lexers/embedded/morrowindscript.xml | 90 + .../chroma/v2/lexers/embedded/myghty.xml | 77 + .../chroma/v2/lexers/embedded/mysql.xml | 121 + .../chroma/v2/lexers/embedded/nasm.xml | 126 + .../chroma/v2/lexers/embedded/natural.xml | 143 + .../chroma/v2/lexers/embedded/ndisasm.xml | 123 + .../chroma/v2/lexers/embedded/newspeak.xml | 121 + .../embedded/nginx_configuration_file.xml | 101 + .../chroma/v2/lexers/embedded/nim.xml | 211 + .../chroma/v2/lexers/embedded/nix.xml | 258 + .../chroma/v2/lexers/embedded/nsis.xml | 59 + .../chroma/v2/lexers/embedded/nu.xml | 121 + .../chroma/v2/lexers/embedded/objective-c.xml | 510 + .../v2/lexers/embedded/objectpascal.xml | 142 + .../chroma/v2/lexers/embedded/ocaml.xml | 153 + .../chroma/v2/lexers/embedded/octave.xml | 101 + .../chroma/v2/lexers/embedded/odin.xml | 127 + .../v2/lexers/embedded/onesenterprise.xml | 92 + .../v2/lexers/embedded/openedge_abl.xml | 101 + .../chroma/v2/lexers/embedded/openscad.xml | 96 + .../chroma/v2/lexers/embedded/org_mode.xml | 329 + .../chroma/v2/lexers/embedded/pacmanconf.xml | 37 + .../chroma/v2/lexers/embedded/perl.xml | 400 + .../chroma/v2/lexers/embedded/php.xml | 212 + .../chroma/v2/lexers/embedded/pig.xml | 105 + .../chroma/v2/lexers/embedded/pkgconfig.xml | 73 + .../chroma/v2/lexers/embedded/pl_pgsql.xml | 119 + .../chroma/v2/lexers/embedded/plaintext.xml | 21 + .../chroma/v2/lexers/embedded/plutus_core.xml | 105 + .../chroma/v2/lexers/embedded/pony.xml | 135 + .../embedded/postgresql_sql_dialect.xml | 155 + .../chroma/v2/lexers/embedded/postscript.xml | 89 + .../chroma/v2/lexers/embedded/povray.xml | 58 + .../chroma/v2/lexers/embedded/powerquery.xml | 51 + .../chroma/v2/lexers/embedded/powershell.xml | 230 + .../chroma/v2/lexers/embedded/prolog.xml | 115 + .../chroma/v2/lexers/embedded/promela.xml | 119 + .../chroma/v2/lexers/embedded/promql.xml | 123 + .../chroma/v2/lexers/embedded/properties.xml | 45 + .../v2/lexers/embedded/protocol_buffer.xml | 118 + .../chroma/v2/lexers/embedded/prql.xml | 161 + .../chroma/v2/lexers/embedded/psl.xml | 213 + .../chroma/v2/lexers/embedded/puppet.xml | 100 + .../chroma/v2/lexers/embedded/python.xml | 595 + .../chroma/v2/lexers/embedded/python_2.xml | 356 + .../chroma/v2/lexers/embedded/qbasic.xml | 173 + .../chroma/v2/lexers/embedded/qml.xml | 113 + .../chroma/v2/lexers/embedded/r.xml | 128 + .../chroma/v2/lexers/embedded/racket.xml | 260 + .../chroma/v2/lexers/embedded/ragel.xml | 149 + .../chroma/v2/lexers/embedded/react.xml | 236 + .../chroma/v2/lexers/embedded/reasonml.xml | 147 + .../chroma/v2/lexers/embedded/reg.xml | 68 + .../chroma/v2/lexers/embedded/rego.xml | 94 + .../chroma/v2/lexers/embedded/rexx.xml | 127 + .../chroma/v2/lexers/embedded/rgbasm.xml | 239 + .../chroma/v2/lexers/embedded/ring.xml | 74 + .../chroma/v2/lexers/embedded/rpgle.xml | 176 + .../chroma/v2/lexers/embedded/rpm_spec.xml | 58 + .../chroma/v2/lexers/embedded/ruby.xml | 724 + .../chroma/v2/lexers/embedded/rust.xml | 375 + .../chroma/v2/lexers/embedded/sas.xml | 191 + .../chroma/v2/lexers/embedded/sass.xml | 362 + .../chroma/v2/lexers/embedded/scala.xml | 274 + .../chroma/v2/lexers/embedded/scheme.xml | 106 + .../chroma/v2/lexers/embedded/scilab.xml | 98 + .../chroma/v2/lexers/embedded/scss.xml | 373 + .../chroma/v2/lexers/embedded/sed.xml | 92 + .../chroma/v2/lexers/embedded/sieve.xml | 61 + .../chroma/v2/lexers/embedded/smali.xml | 73 + .../chroma/v2/lexers/embedded/smalltalk.xml | 294 + .../chroma/v2/lexers/embedded/smarty.xml | 79 + .../chroma/v2/lexers/embedded/snbt.xml | 58 + .../chroma/v2/lexers/embedded/snobol.xml | 95 + .../chroma/v2/lexers/embedded/solidity.xml | 291 + .../chroma/v2/lexers/embedded/sourcepawn.xml | 59 + .../chroma/v2/lexers/embedded/sparql.xml | 160 + .../chroma/v2/lexers/embedded/sql.xml | 90 + .../chroma/v2/lexers/embedded/squidconf.xml | 63 + .../chroma/v2/lexers/embedded/standard_ml.xml | 548 + .../chroma/v2/lexers/embedded/stas.xml | 85 + .../chroma/v2/lexers/embedded/stylus.xml | 132 + .../chroma/v2/lexers/embedded/swift.xml | 207 + .../chroma/v2/lexers/embedded/systemd.xml | 63 + .../v2/lexers/embedded/systemverilog.xml | 181 + .../chroma/v2/lexers/embedded/tablegen.xml | 69 + .../chroma/v2/lexers/embedded/tal.xml | 43 + .../chroma/v2/lexers/embedded/tasm.xml | 135 + .../chroma/v2/lexers/embedded/tcl.xml | 272 + .../chroma/v2/lexers/embedded/tcsh.xml | 121 + .../chroma/v2/lexers/embedded/termcap.xml | 75 + .../chroma/v2/lexers/embedded/terminfo.xml | 84 + .../chroma/v2/lexers/embedded/terraform.xml | 149 + .../chroma/v2/lexers/embedded/tex.xml | 113 + .../chroma/v2/lexers/embedded/thrift.xml | 154 + .../chroma/v2/lexers/embedded/toml.xml | 45 + .../chroma/v2/lexers/embedded/tradingview.xml | 81 + .../v2/lexers/embedded/transact-sql.xml | 137 + .../chroma/v2/lexers/embedded/turing.xml | 82 + .../chroma/v2/lexers/embedded/turtle.xml | 170 + .../chroma/v2/lexers/embedded/twig.xml | 155 + .../chroma/v2/lexers/embedded/txtpb.xml | 162 + .../chroma/v2/lexers/embedded/typescript.xml | 302 + .../chroma/v2/lexers/embedded/typoscript.xml | 178 + .../v2/lexers/embedded/typoscriptcssdata.xml | 52 + .../v2/lexers/embedded/typoscripthtmldata.xml | 52 + .../chroma/v2/lexers/embedded/typst.xml | 108 + .../chroma/v2/lexers/embedded/ucode.xml | 147 + .../chroma/v2/lexers/embedded/v.xml | 355 + .../chroma/v2/lexers/embedded/v_shell.xml | 365 + .../chroma/v2/lexers/embedded/vala.xml | 72 + .../chroma/v2/lexers/embedded/vb_net.xml | 162 + .../chroma/v2/lexers/embedded/verilog.xml | 158 + .../chroma/v2/lexers/embedded/vhdl.xml | 171 + .../chroma/v2/lexers/embedded/vhs.xml | 48 + .../chroma/v2/lexers/embedded/viml.xml | 85 + .../chroma/v2/lexers/embedded/vue.xml | 295 + .../chroma/v2/lexers/embedded/wat.xml | 149 + .../chroma/v2/lexers/embedded/wdte.xml | 43 + .../embedded/webgpu_shading_language.xml | 142 + .../chroma/v2/lexers/embedded/webvtt.xml | 283 + .../chroma/v2/lexers/embedded/whiley.xml | 57 + .../chroma/v2/lexers/embedded/xml.xml | 95 + .../chroma/v2/lexers/embedded/xorg.xml | 35 + .../chroma/v2/lexers/embedded/yaml.xml | 122 + .../chroma/v2/lexers/embedded/yang.xml | 99 + .../v2/lexers/embedded/z80_assembly.xml | 74 + .../chroma/v2/lexers/embedded/zed.xml | 51 + .../chroma/v2/lexers/embedded/zig.xml | 187 + .../alecthomas/chroma/v2/lexers/gemtext.go | 37 + .../alecthomas/chroma/v2/lexers/genshi.go | 118 + .../alecthomas/chroma/v2/lexers/go.go | 81 + .../alecthomas/chroma/v2/lexers/haxe.go | 647 + .../alecthomas/chroma/v2/lexers/html.go | 8 + .../alecthomas/chroma/v2/lexers/http.go | 131 + .../alecthomas/chroma/v2/lexers/lexers.go | 85 + .../alecthomas/chroma/v2/lexers/markdown.go | 46 + .../alecthomas/chroma/v2/lexers/markless.go | 168 + .../alecthomas/chroma/v2/lexers/mysql.go | 33 + .../alecthomas/chroma/v2/lexers/php.go | 37 + .../alecthomas/chroma/v2/lexers/raku.go | 1712 ++ .../alecthomas/chroma/v2/lexers/rst.go | 89 + .../alecthomas/chroma/v2/lexers/svelte.go | 70 + .../alecthomas/chroma/v2/lexers/typoscript.go | 85 + .../alecthomas/chroma/v2/lexers/zed.go | 24 + .../alecthomas/chroma/v2/mutators.go | 201 + .../alecthomas/chroma/v2/pygments-lexers.txt | 605 + .../alecthomas/chroma/v2/quick/quick.go | 44 + .../github.com/alecthomas/chroma/v2/regexp.go | 530 + .../alecthomas/chroma/v2/registry.go | 228 + .../github.com/alecthomas/chroma/v2/remap.go | 94 + .../alecthomas/chroma/v2/renovate.json5 | 24 + .../alecthomas/chroma/v2/serialise.go | 483 + .../github.com/alecthomas/chroma/v2/style.go | 481 + .../alecthomas/chroma/v2/styles/abap.xml | 11 + .../alecthomas/chroma/v2/styles/algol.xml | 18 + .../alecthomas/chroma/v2/styles/algol_nu.xml | 18 + .../alecthomas/chroma/v2/styles/api.go | 65 + .../alecthomas/chroma/v2/styles/arduino.xml | 18 + .../alecthomas/chroma/v2/styles/ashen.xml | 69 + .../chroma/v2/styles/aura-theme-dark-soft.xml | 107 + .../chroma/v2/styles/aura-theme-dark.xml | 107 + .../alecthomas/chroma/v2/styles/autumn.xml | 36 + .../alecthomas/chroma/v2/styles/average.xml | 74 + .../chroma/v2/styles/base16-snazzy.xml | 74 + .../alecthomas/chroma/v2/styles/borland.xml | 26 + .../alecthomas/chroma/v2/styles/bw.xml | 23 + .../chroma/v2/styles/catppuccin-frappe.xml | 83 + .../chroma/v2/styles/catppuccin-latte.xml | 83 + .../chroma/v2/styles/catppuccin-macchiato.xml | 83 + .../chroma/v2/styles/catppuccin-mocha.xml | 83 + .../alecthomas/chroma/v2/styles/colorful.xml | 52 + .../alecthomas/chroma/v2/styles/compat.go | 66 + .../alecthomas/chroma/v2/styles/doom-one.xml | 51 + .../alecthomas/chroma/v2/styles/doom-one2.xml | 64 + .../alecthomas/chroma/v2/styles/dracula.xml | 74 + .../alecthomas/chroma/v2/styles/emacs.xml | 44 + .../chroma/v2/styles/evergarden.xml | 33 + .../alecthomas/chroma/v2/styles/friendly.xml | 44 + .../alecthomas/chroma/v2/styles/fruity.xml | 19 + .../chroma/v2/styles/github-dark.xml | 45 + .../alecthomas/chroma/v2/styles/github.xml | 39 + .../chroma/v2/styles/gruvbox-light.xml | 33 + .../alecthomas/chroma/v2/styles/gruvbox.xml | 33 + .../chroma/v2/styles/hr_high_contrast.xml | 12 + .../alecthomas/chroma/v2/styles/hrdark.xml | 10 + .../alecthomas/chroma/v2/styles/igor.xml | 9 + .../alecthomas/chroma/v2/styles/lovelace.xml | 53 + .../alecthomas/chroma/v2/styles/manni.xml | 44 + .../chroma/v2/styles/modus-operandi.xml | 13 + .../chroma/v2/styles/modus-vivendi.xml | 13 + .../alecthomas/chroma/v2/styles/monokai.xml | 29 + .../chroma/v2/styles/monokailight.xml | 26 + .../alecthomas/chroma/v2/styles/murphy.xml | 52 + .../alecthomas/chroma/v2/styles/native.xml | 35 + .../alecthomas/chroma/v2/styles/nord.xml | 46 + .../alecthomas/chroma/v2/styles/nordic.xml | 46 + .../alecthomas/chroma/v2/styles/onedark.xml | 25 + .../chroma/v2/styles/onesenterprise.xml | 10 + .../chroma/v2/styles/paraiso-dark.xml | 37 + .../chroma/v2/styles/paraiso-light.xml | 37 + .../alecthomas/chroma/v2/styles/pastie.xml | 45 + .../alecthomas/chroma/v2/styles/perldoc.xml | 37 + .../alecthomas/chroma/v2/styles/pygments.xml | 42 + .../chroma/v2/styles/rainbow_dash.xml | 40 + .../chroma/v2/styles/rose-pine-dawn.xml | 29 + .../chroma/v2/styles/rose-pine-moon.xml | 29 + .../alecthomas/chroma/v2/styles/rose-pine.xml | 29 + .../alecthomas/chroma/v2/styles/rpgle.xml | 30 + .../alecthomas/chroma/v2/styles/rrt.xml | 19 + .../chroma/v2/styles/solarized-dark.xml | 39 + .../chroma/v2/styles/solarized-dark256.xml | 41 + .../chroma/v2/styles/solarized-light.xml | 17 + .../alecthomas/chroma/v2/styles/swapoff.xml | 18 + .../alecthomas/chroma/v2/styles/tango.xml | 72 + .../chroma/v2/styles/tokyonight-day.xml | 83 + .../chroma/v2/styles/tokyonight-moon.xml | 83 + .../chroma/v2/styles/tokyonight-night.xml | 83 + .../chroma/v2/styles/tokyonight-storm.xml | 83 + .../alecthomas/chroma/v2/styles/trac.xml | 35 + .../alecthomas/chroma/v2/styles/vim.xml | 29 + .../alecthomas/chroma/v2/styles/vs.xml | 16 + .../alecthomas/chroma/v2/styles/vulcan.xml | 74 + .../chroma/v2/styles/witchhazel.xml | 31 + .../chroma/v2/styles/xcode-dark.xml | 31 + .../alecthomas/chroma/v2/styles/xcode.xml | 22 + .../github.com/alecthomas/chroma/v2/table.py | 31 + .../alecthomas/chroma/v2/tokentype_enumer.go | 583 + .../github.com/alecthomas/chroma/v2/types.go | 355 + .../alecthomas/go-check-sumtype/.golangci.yml | 92 + .../alecthomas/go-check-sumtype/README.md | 6 + .../alecthomas/go-check-sumtype/check.go | 10 +- .../alecthomas/go-check-sumtype/config.go | 3 + .../alecthomas/go-check-sumtype/def.go | 30 +- .../alexkohler/nakedret/v2/README.md | 2 +- .../alexkohler/nakedret/v2/nakedret.go | 15 +- .../github.com/alexkohler/prealloc/pkg/cmp.go | 297 + .../alexkohler/prealloc/pkg/math.go | 163 + .../alexkohler/prealloc/pkg/prealloc.go | 986 +- .../github.com/alfatraining/structtag/LICENSE | 60 + .../alfatraining/structtag/README.md | 92 + .../github.com/alfatraining/structtag/tags.go | 138 + .../nilnesserr}/.gitignore | 27 +- .../alingse/nilnesserr/.golangci.yaml | 75 + .../LICENSE.md => alingse/nilnesserr/LICENSE} | 12 +- .../github.com/alingse/nilnesserr/README.md | 89 + .../internal/typeparams/coretype.go | 122 + .../internal/typeparams/normalize.go | 200 + .../internal/typeparams/termlist.go | 163 + .../internal/typeparams/typeterm.go | 166 + .../github.com/alingse/nilnesserr/linter.go | 50 + .../github.com/alingse/nilnesserr/nilerr.go | 192 + .../github.com/alingse/nilnesserr/nilness.go | 374 + .../ashanbrown/forbidigo/{ => v2}/LICENSE | 0 .../{ => v2}/forbidigo/config_options.go | 0 .../forbidigo/{ => v2}/forbidigo/forbidigo.go | 21 +- .../forbidigo/{ => v2}/forbidigo/patterns.go | 28 +- .../ashanbrown/makezero/{ => v2}/LICENSE | 0 .../makezero/{ => v2}/makezero/makezero.go | 0 .../aws-sdk-go-v2/aws/go_module_metadata.go | 2 +- .../aws/middleware/user_agent.go | 2 + .../endpoints/awsrulesfn/partitions.go | 11 +- .../endpoints/awsrulesfn/partitions.json | 8 +- .../aymanbagabas/go-osc52/v2/LICENSE | 21 + .../aymanbagabas/go-osc52/v2/README.md | 83 + .../aymanbagabas/go-osc52/v2/osc52.go | 305 + .../github.com/bombsimon/wsl/v4/.golangci.yml | 91 +- vendor/github.com/bombsimon/wsl/v4/README.md | 14 +- .../github.com/bombsimon/wsl/v4/analyzer.go | 31 +- vendor/github.com/bombsimon/wsl/v4/wsl.go | 90 +- vendor/github.com/bombsimon/wsl/v5/.gitignore | 70 + .../github.com/bombsimon/wsl/v5/.golangci.yml | 87 + vendor/github.com/bombsimon/wsl/v5/CHECKS.md | 1546 ++ vendor/github.com/bombsimon/wsl/v5/LICENSE | 21 + vendor/github.com/bombsimon/wsl/v5/README.md | 187 + .../github.com/bombsimon/wsl/v5/analyzer.go | 198 + vendor/github.com/bombsimon/wsl/v5/config.go | 286 + vendor/github.com/bombsimon/wsl/v5/cursor.go | 88 + .../github.com/bombsimon/wsl/v5/renovate.json | 4 + vendor/github.com/bombsimon/wsl/v5/wsl.go | 1585 ++ .../butuzov/ireturn/analyzer/analyzer.go | 25 +- .../ireturn/analyzer/internal/config/allow.go | 2 +- .../ireturn/analyzer/internal/config/new.go | 1 - .../analyzer/internal/config/reject.go | 2 +- .../ireturn/analyzer/internal/types/iface.go | 2 +- .../butuzov/ireturn/analyzer/std.go | 11 + .../github.com/butuzov/mirror/MIRROR_FUNCS.md | 254 +- vendor/github.com/butuzov/mirror/Makefile | 19 +- vendor/github.com/butuzov/mirror/analyzer.go | 4 +- .../butuzov/mirror/checkers_maphash.go | 87 +- .../mirror/internal/checker/checker.go | 6 +- .../mirror/internal/checker/violation.go | 6 +- vendor/github.com/butuzov/mirror/readme.md | 13 +- .../perfsprint/analyzer/analyzer.go | 819 +- .../perfsprint/analyzer/diagnostic.go | 24 + .../ccojocar/zxcvbn-go/.golangci.yml | 53 +- .../ccojocar/zxcvbn-go/.goreleaser.yml | 2 +- .../zxcvbn-go/matching/dateMatchers.go | 3 +- .../ccojocar/zxcvbn-go/matching/leet.go | 4 +- .../ccojocar/zxcvbn-go/scoring/scoring.go | 2 +- .../charithe/durationcheck/README.md | 2 +- .../charithe/durationcheck/durationcheck.go | 51 +- .../charmbracelet/colorprofile/.golangci.yml | 41 + .../colorprofile/.goreleaser.yml | 6 + .../charmbracelet/colorprofile/LICENSE | 21 + .../charmbracelet/colorprofile/README.md | 103 + .../charmbracelet/colorprofile/doc.go | 4 + .../charmbracelet/colorprofile/env.go | 293 + .../charmbracelet/colorprofile/env_other.go | 8 + .../charmbracelet/colorprofile/env_windows.go | 45 + .../charmbracelet/colorprofile/profile.go | 399 + .../charmbracelet/colorprofile/writer.go | 169 + .../charmbracelet/lipgloss/.gitignore | 2 + .../charmbracelet/lipgloss/.golangci.yml | 41 + .../charmbracelet/lipgloss/.goreleaser.yml | 5 + .../github.com/charmbracelet/lipgloss/LICENSE | 21 + .../charmbracelet/lipgloss/README.md | 815 + .../charmbracelet/lipgloss/Taskfile.yaml | 19 + .../charmbracelet/lipgloss/align.go | 83 + .../charmbracelet/lipgloss/ansi_unix.go | 7 + .../charmbracelet/lipgloss/ansi_windows.go | 22 + .../charmbracelet/lipgloss/borders.go | 490 + .../charmbracelet/lipgloss/color.go | 172 + .../github.com/charmbracelet/lipgloss/get.go | 556 + .../github.com/charmbracelet/lipgloss/join.go | 175 + .../charmbracelet/lipgloss/position.go | 154 + .../charmbracelet/lipgloss/ranges.go | 48 + .../charmbracelet/lipgloss/renderer.go | 181 + .../charmbracelet/lipgloss/runes.go | 43 + .../github.com/charmbracelet/lipgloss/set.go | 799 + .../github.com/charmbracelet/lipgloss/size.go | 41 + .../charmbracelet/lipgloss/style.go | 588 + .../charmbracelet/lipgloss/unset.go | 331 + .../charmbracelet/lipgloss/whitespace.go | 83 + .../github.com/charmbracelet/x/ansi/LICENSE | 21 + .../github.com/charmbracelet/x/ansi/ansi.go | 11 + .../github.com/charmbracelet/x/ansi/ascii.go | 8 + .../charmbracelet/x/ansi/background.go | 178 + vendor/github.com/charmbracelet/x/ansi/c0.go | 79 + vendor/github.com/charmbracelet/x/ansi/c1.go | 72 + .../charmbracelet/x/ansi/charset.go | 55 + .../charmbracelet/x/ansi/clipboard.go | 75 + .../github.com/charmbracelet/x/ansi/color.go | 784 + .../github.com/charmbracelet/x/ansi/ctrl.go | 156 + .../github.com/charmbracelet/x/ansi/cursor.go | 635 + vendor/github.com/charmbracelet/x/ansi/cwd.go | 26 + vendor/github.com/charmbracelet/x/ansi/doc.go | 7 + .../charmbracelet/x/ansi/finalterm.go | 67 + .../github.com/charmbracelet/x/ansi/focus.go | 9 + .../charmbracelet/x/ansi/graphics.go | 62 + .../charmbracelet/x/ansi/hyperlink.go | 28 + .../github.com/charmbracelet/x/ansi/iterm2.go | 18 + .../github.com/charmbracelet/x/ansi/keypad.go | 28 + .../github.com/charmbracelet/x/ansi/kitty.go | 90 + .../github.com/charmbracelet/x/ansi/method.go | 172 + .../github.com/charmbracelet/x/ansi/mode.go | 847 + .../github.com/charmbracelet/x/ansi/modes.go | 65 + .../github.com/charmbracelet/x/ansi/mouse.go | 172 + .../charmbracelet/x/ansi/notification.go | 13 + .../github.com/charmbracelet/x/ansi/parser.go | 417 + .../charmbracelet/x/ansi/parser/const.go | 79 + .../charmbracelet/x/ansi/parser/seq.go | 136 + .../x/ansi/parser/transition_table.go | 273 + .../charmbracelet/x/ansi/parser_decode.go | 524 + .../charmbracelet/x/ansi/parser_handler.go | 60 + .../charmbracelet/x/ansi/parser_sync.go | 29 + .../charmbracelet/x/ansi/passthrough.go | 60 + .../github.com/charmbracelet/x/ansi/paste.go | 7 + .../github.com/charmbracelet/x/ansi/reset.go | 11 + .../github.com/charmbracelet/x/ansi/screen.go | 410 + vendor/github.com/charmbracelet/x/ansi/sgr.go | 79 + .../github.com/charmbracelet/x/ansi/status.go | 168 + .../github.com/charmbracelet/x/ansi/style.go | 673 + .../charmbracelet/x/ansi/termcap.go | 41 + .../github.com/charmbracelet/x/ansi/title.go | 48 + .../charmbracelet/x/ansi/truncate.go | 299 + .../github.com/charmbracelet/x/ansi/util.go | 92 + .../github.com/charmbracelet/x/ansi/width.go | 113 + .../github.com/charmbracelet/x/ansi/winop.go | 53 + .../github.com/charmbracelet/x/ansi/wrap.go | 474 + .../github.com/charmbracelet/x/ansi/xterm.go | 138 + .../charmbracelet/x/cellbuf/LICENSE | 21 + .../charmbracelet/x/cellbuf/buffer.go | 473 + .../charmbracelet/x/cellbuf/cell.go | 508 + .../charmbracelet/x/cellbuf/errors.go | 6 + .../charmbracelet/x/cellbuf/geom.go | 21 + .../charmbracelet/x/cellbuf/hardscroll.go | 272 + .../charmbracelet/x/cellbuf/hashmap.go | 301 + .../charmbracelet/x/cellbuf/link.go | 14 + .../charmbracelet/x/cellbuf/screen.go | 1457 ++ .../charmbracelet/x/cellbuf/sequence.go | 131 + .../charmbracelet/x/cellbuf/style.go | 31 + .../charmbracelet/x/cellbuf/tabstop.go | 137 + .../charmbracelet/x/cellbuf/utils.go | 38 + .../charmbracelet/x/cellbuf/wrap.go | 185 + .../charmbracelet/x/cellbuf/writer.go | 339 + .../github.com/charmbracelet/x/term/LICENSE | 21 + .../github.com/charmbracelet/x/term/term.go | 49 + .../charmbracelet/x/term/term_other.go | 39 + .../charmbracelet/x/term/term_unix.go | 96 + .../charmbracelet/x/term/term_unix_bsd.go | 11 + .../charmbracelet/x/term/term_unix_other.go | 11 + .../charmbracelet/x/term/term_windows.go | 87 + .../charmbracelet/x/term/terminal.go | 12 + .../github.com/charmbracelet/x/term/util.go | 47 + .../ckaznocha/intrange/.golangci.yml | 30 +- vendor/github.com/ckaznocha/intrange/go.work | 4 +- .../github.com/ckaznocha/intrange/intrange.go | 263 +- .../curioswitch/go-reassign/.golangci.yml | 5 +- .../curioswitch/go-reassign/README.md | 7 +- .../go-reassign/internal/analyzer/analyzer.go | 24 +- .../daixiang0/gci/pkg/config/config.go | 5 +- .../gci/pkg/section/standard_list.go | 350 +- vendor/github.com/dave/dst/.gitignore | 4 + vendor/github.com/dave/dst/.travis.yml | 15 + vendor/github.com/dave/dst/LICENSE | 51 + vendor/github.com/dave/dst/README.md | 706 + vendor/github.com/dave/dst/README.md.tpl | 239 + vendor/github.com/dave/dst/clone-generated.go | 1628 ++ vendor/github.com/dave/dst/clone.go | 11 + vendor/github.com/dave/dst/contributing.md | 78 + .../dave/dst/decorations-node-generated.go | 273 + .../dave/dst/decorations-types-generated.go | 659 + vendor/github.com/dave/dst/decorations.go | 61 + .../decorator/decorator-fragment-generated.go | 1547 ++ .../dave/dst/decorator/decorator-fragment.go | 620 + .../dst/decorator/decorator-node-generated.go | 2379 +++ .../dave/dst/decorator/decorator.go | 560 + .../github.com/dave/dst/decorator/helpers.go | 64 + vendor/github.com/dave/dst/decorator/load.go | 119 + vendor/github.com/dave/dst/decorator/map.go | 42 + .../decorator/resolver/gopackages/resolver.go | 61 + .../decorator/resolver/gotypes/resolver.go | 64 + .../dave/dst/decorator/resolver/resolver.go | 26 + .../dave/dst/decorator/restorer-generated.go | 1956 ++ .../github.com/dave/dst/decorator/restorer.go | 823 + vendor/github.com/dave/dst/dst.go | 664 + .../dave/dst/dstutil/decorations-generated.go | 369 + .../dave/dst/dstutil/decorations.go | 14 + vendor/github.com/dave/dst/dstutil/rewrite.go | 465 + vendor/github.com/dave/dst/dstutil/util.go | 14 + vendor/github.com/dave/dst/print.go | 245 + vendor/github.com/dave/dst/readme.go | 4 + vendor/github.com/dave/dst/resolve.go | 170 + vendor/github.com/dave/dst/scope.go | 112 + vendor/github.com/dave/dst/walk.go | 354 + vendor/github.com/dlclark/regexp2/.gitignore | 27 + vendor/github.com/dlclark/regexp2/.travis.yml | 7 + vendor/github.com/dlclark/regexp2/ATTRIB | 133 + .../go-diff => dlclark/regexp2}/LICENSE | 3 +- vendor/github.com/dlclark/regexp2/README.md | 174 + .../github.com/dlclark/regexp2/fastclock.go | 141 + vendor/github.com/dlclark/regexp2/match.go | 349 + vendor/github.com/dlclark/regexp2/regexp.go | 395 + vendor/github.com/dlclark/regexp2/replace.go | 177 + vendor/github.com/dlclark/regexp2/runner.go | 1613 ++ .../dlclark/regexp2/syntax/charclass.go | 865 + .../github.com/dlclark/regexp2/syntax/code.go | 274 + .../dlclark/regexp2/syntax/escape.go | 94 + .../github.com/dlclark/regexp2/syntax/fuzz.go | 20 + .../dlclark/regexp2/syntax/parser.go | 2262 +++ .../dlclark/regexp2/syntax/prefix.go | 896 + .../dlclark/regexp2/syntax/replacerdata.go | 87 + .../github.com/dlclark/regexp2/syntax/tree.go | 654 + .../dlclark/regexp2/syntax/writer.go | 500 + vendor/github.com/dlclark/regexp2/testoutput1 | 7061 +++++++ .../nonamedreturns/analyzer/analyzer.go | 8 +- .../ghostiam/protogetter/.goreleaser.yaml | 3 +- .../github.com/ghostiam/protogetter/README.md | 26 +- .../ghostiam/protogetter/flake.lock | 61 + .../github.com/ghostiam/protogetter/flake.nix | 70 + .../ghostiam/protogetter/processor.go | 133 +- .../ghostiam/protogetter/protogetter.go | 58 +- .../go-critic/checkers/badCond_checker.go | 3 +- .../go-critic/checkers/badRegexp_checker.go | 16 +- .../go-critic/go-critic/checkers/checkers.go | 2 +- .../checkers/commentedOutCode_checker.go | 30 +- .../checkers/deprecatedComment_checker.go | 25 +- .../go-critic/checkers/dupOption_checker.go | 118 + .../go-critic/checkers/embedded_rules.go | 64 +- .../checkers/exitAfterDefer_checker.go | 6 + .../go-critic/checkers/hugeParam_checker.go | 1 + .../go-critic/checkers/rulesdata/rulesdata.go | 696 +- .../go-critic/checkers/sqlQuery_checker.go | 7 + .../go-critic/go-critic/checkers/utils.go | 339 +- .../go-critic/go-critic/linter/linter.go | 4 +- .../go-viper/mapstructure/v2/.editorconfig | 6 + .../go-viper/mapstructure/v2/.envrc | 11 +- .../go-viper/mapstructure/v2/.gitignore | 10 +- .../go-viper/mapstructure/v2/.golangci.yaml | 55 +- .../go-viper/mapstructure/v2/README.md | 7 +- .../go-viper/mapstructure/v2/decode_hooks.go | 234 +- .../go-viper/mapstructure/v2/devenv.lock | 103 + .../go-viper/mapstructure/v2/devenv.nix | 14 + .../go-viper/mapstructure/v2/devenv.yaml | 4 + .../go-viper/mapstructure/v2/errors.go | 244 + .../go-viper/mapstructure/v2/flake.lock | 472 - .../go-viper/mapstructure/v2/flake.nix | 39 - .../go-viper/mapstructure/v2/mapstructure.go | 634 +- vendor/github.com/go-xmlfmt/xmlfmt/xmlfmt.go | 18 +- .../github.com/godoc-lint/godoc-lint/LICENSE | 21 + .../godoc-lint/pkg/analysis/analyzer.go | 108 + .../pkg/check/deprecated/deprecated.go | 114 + .../godoc-lint/pkg/check/max_len/max_len.go | 155 + .../check/no_unused_link/no_unused_link.go | 69 + .../godoc-lint/pkg/check/pkg_doc/pkg_doc.go | 206 + .../godoc-lint/pkg/check/registry.go | 66 + .../pkg/check/require_doc/require_doc.go | 179 + .../godoc-lint/pkg/check/shared/deprecated.go | 29 + .../check/start_with_name/start_with_name.go | 140 + .../pkg/check/stdlib_doclink/data.go | 27 + .../pkg/check/stdlib_doclink/internal/type.go | 30 + .../pkg/check/stdlib_doclink/stdlib.json | 1 + .../check/stdlib_doclink/stdlib_doclink.go | 315 + .../godoc-lint/pkg/compose/compose.go | 53 + .../godoc-lint/pkg/config/builder.go | 327 + .../godoc-lint/pkg/config/config.go | 73 + .../godoc-lint/pkg/config/default.go | 28 + .../godoc-lint/pkg/config/default.yaml | 17 + .../godoc-lint/godoc-lint/pkg/config/doc.go | 2 + .../godoc-lint/godoc-lint/pkg/config/once.go | 59 + .../godoc-lint/pkg/config/parser.go | 42 + .../godoc-lint/godoc-lint/pkg/config/plain.go | 98 + .../godoc-lint/pkg/inspect/inspector.go | 340 + .../godoc-lint/pkg/model/analyzer.go | 11 + .../godoc-lint/pkg/model/checker.go | 24 + .../godoc-lint/godoc-lint/pkg/model/config.go | 125 + .../godoc-lint/godoc-lint/pkg/model/doc.go | 2 + .../godoc-lint/pkg/model/inspector.go | 217 + .../godoc-lint/pkg/model/registry.go | 14 + .../godoc-lint/godoc-lint/pkg/model/rule.go | 40 + .../godoc-lint/pkg/model/ruleset.go | 97 + .../godoc-lint/godoc-lint/pkg/util/ast.go | 66 + .../godoc-lint/godoc-lint/pkg/util/doc.go | 2 + .../godoc-lint/godoc-lint/pkg/util/path.go | 16 + vendor/github.com/gofrs/flock/.golangci.yml | 150 +- vendor/github.com/gofrs/flock/LICENSE | 2 +- vendor/github.com/gofrs/flock/flock.go | 20 +- vendor/github.com/gofrs/flock/flock_others.go | 5 + vendor/github.com/gofrs/flock/flock_unix.go | 3 +- .../gofrs/flock/flock_unix_fcntl.go | 2 +- .../github.com/gofrs/flock/flock_windows.go | 4 +- vendor/github.com/gogo/protobuf/AUTHORS | 15 - vendor/github.com/gogo/protobuf/CONTRIBUTORS | 23 - vendor/github.com/gogo/protobuf/LICENSE | 35 - .../github.com/gogo/protobuf/proto/Makefile | 43 - .../github.com/gogo/protobuf/proto/clone.go | 258 - .../gogo/protobuf/proto/custom_gogo.go | 39 - .../github.com/gogo/protobuf/proto/decode.go | 427 - .../gogo/protobuf/proto/deprecated.go | 63 - .../github.com/gogo/protobuf/proto/discard.go | 350 - .../gogo/protobuf/proto/duration.go | 100 - .../gogo/protobuf/proto/duration_gogo.go | 49 - .../github.com/gogo/protobuf/proto/encode.go | 205 - .../gogo/protobuf/proto/encode_gogo.go | 33 - .../github.com/gogo/protobuf/proto/equal.go | 300 - .../gogo/protobuf/proto/extensions.go | 605 - .../gogo/protobuf/proto/extensions_gogo.go | 389 - vendor/github.com/gogo/protobuf/proto/lib.go | 973 - .../gogo/protobuf/proto/lib_gogo.go | 50 - .../gogo/protobuf/proto/message_set.go | 181 - .../gogo/protobuf/proto/pointer_reflect.go | 357 - .../protobuf/proto/pointer_reflect_gogo.go | 59 - .../gogo/protobuf/proto/pointer_unsafe.go | 308 - .../protobuf/proto/pointer_unsafe_gogo.go | 56 - .../gogo/protobuf/proto/properties.go | 610 - .../gogo/protobuf/proto/properties_gogo.go | 36 - .../gogo/protobuf/proto/skip_gogo.go | 119 - .../gogo/protobuf/proto/table_marshal.go | 3009 --- .../gogo/protobuf/proto/table_marshal_gogo.go | 388 - .../gogo/protobuf/proto/table_merge.go | 676 - .../gogo/protobuf/proto/table_unmarshal.go | 2249 --- .../protobuf/proto/table_unmarshal_gogo.go | 385 - vendor/github.com/gogo/protobuf/proto/text.go | 930 - .../gogo/protobuf/proto/text_gogo.go | 57 - .../gogo/protobuf/proto/text_parser.go | 1018 -- .../gogo/protobuf/proto/timestamp.go | 113 - .../gogo/protobuf/proto/timestamp_gogo.go | 49 - .../gogo/protobuf/proto/wrappers.go | 1888 -- .../gogo/protobuf/proto/wrappers_gogo.go | 113 - .../gogo/protobuf/sortkeys/sortkeys.go | 101 - .../asciicheck}/.gitignore | 12 +- .../golangci/asciicheck/.golangci.yml | 87 + .../{tdakkota => golangci}/asciicheck/LICENSE | 0 .../github.com/golangci/asciicheck/Makefile | 15 + .../asciicheck/README.md | 22 +- .../asciicheck/ascii.go | 0 .../golangci/asciicheck/asciicheck.go | 104 + vendor/github.com/golangci/dupl/.travis.yml | 5 - vendor/github.com/golangci/dupl/README.md | 63 - .../golangci/dupl/{main.go => lib/lib.go} | 66 +- .../github.com/golangci/dupl/printer/html.go | 14 +- .../golangci/dupl/printer/issuer.go | 56 + .../golangci/dupl/printer/plumbing.go | 44 +- .../golangci/dupl/suffixtree/suffixtree.go | 2 +- .../github.com/golangci/dupl/syntax/syntax.go | 20 +- .../pkg/analyzer/analyzer.go | 34 +- .../github.com/golangci/gofmt/gofmt/gofmt.go | 2 +- .../golangci/gofmt/gofmt/golangci.go | 39 +- .../github.com/golangci/gofmt/gofmt/readme.md | 3 +- .../golangci/gofmt/goimports/goimports.go | 88 - .../golangci/gofmt/goimports/golangci.go | 35 - .../golangci/gofmt/goimports/readme.md | 10 - .../internal/go/robustio/readme.md | 11 - .../golangci-lint/pkg/commands/help.go | 142 - .../golangci-lint/pkg/config/config.go | 112 - .../golangci-lint/pkg/config/issues.go | 246 - .../golangci-lint/pkg/config/linters.go | 65 - .../golangci-lint/pkg/config/loader.go | 479 - .../golangci-lint/pkg/config/output.go | 117 - .../golangci-lint/pkg/fsutils/files.go | 33 - .../golangci-lint/pkg/goanalysis/runners.go | 114 - .../pkg/golinters/asasalint/asasalint.go | 31 - .../pkg/golinters/asciicheck/asciicheck.go | 19 - .../pkg/golinters/bidichk/bidichk.go | 59 - .../pkg/golinters/bodyclose/bodyclose.go | 19 - .../canonicalheader/canonicalheader.go | 19 - .../golinters/containedctx/containedctx.go | 19 - .../golinters/contextcheck/contextcheck.go | 22 - .../pkg/golinters/copyloopvar/copyloopvar.go | 29 - .../pkg/golinters/cyclop/cyclop.go | 37 - .../pkg/golinters/depguard/depguard.go | 50 - .../pkg/golinters/dogsled/dogsled.go | 110 - .../golangci-lint/pkg/golinters/dupl/dupl.go | 96 - .../pkg/golinters/dupword/dupword.go | 30 - .../golinters/durationcheck/durationcheck.go | 19 - .../pkg/golinters/err113/err113.go | 19 - .../pkg/golinters/errcheck/errcheck.go | 271 - .../pkg/golinters/errchkjson/errchkjson.go | 31 - .../pkg/golinters/errname/errname.go | 19 - .../pkg/golinters/errorlint/errorlint.go | 54 - .../pkg/golinters/exhaustive/exhaustive.go | 37 - .../pkg/golinters/exhaustruct/exhaustruct.go | 30 - .../golinters/exportloopref/exportloopref.go | 19 - .../pkg/golinters/fatcontext/fatcontext.go | 19 - .../pkg/golinters/forbidigo/forbidigo.go | 103 - .../forcetypeassert/forcetypeassert.go | 19 - .../pkg/golinters/funlen/funlen.go | 75 - .../golangci-lint/pkg/golinters/gci/gci.go | 250 - .../golinters/ginkgolinter/ginkgolinter.go | 40 - .../gocheckcompilerdirectives.go | 19 - .../gochecknoglobals/gochecknoglobals.go | 26 - .../gochecknoinits/gochecknoinits.go | 75 - .../gochecksumtype/gochecksumtype.go | 82 - .../pkg/golinters/gocognit/gocognit.go | 80 - .../pkg/golinters/goconst/goconst.go | 98 - .../pkg/golinters/gocyclo/gocyclo.go | 76 - .../pkg/golinters/godot/godot.go | 101 - .../pkg/golinters/godox/godox.go | 75 - .../pkg/golinters/gofmt/gofmt.go | 98 - .../pkg/golinters/gofumpt/gofumpt.go | 132 - .../pkg/golinters/goheader/goheader.go | 115 - .../pkg/golinters/goimports/goimports.go | 94 - .../gomoddirectives/gomoddirectives.go | 64 - .../pkg/golinters/gomodguard/gomodguard.go | 94 - .../goprintffuncname/goprintffuncname.go | 19 - .../pkg/golinters/gosimple/gosimple.go | 22 - .../golinters/gosmopolitan/gosmopolitan.go | 32 - .../pkg/golinters/importas/importas.go | 67 - .../pkg/golinters/inamedparam/inamedparam.go | 30 - .../pkg/golinters/ineffassign/ineffassign.go | 19 - .../interfacebloat/interfacebloat.go | 29 - .../pkg/golinters/internal/diff.go | 264 - .../pkg/golinters/internal/util.go | 33 - .../pkg/golinters/intrange/intrange.go | 19 - .../pkg/golinters/ireturn/ireturn.go | 31 - .../golangci-lint/pkg/golinters/lll/lll.go | 157 - .../pkg/golinters/maintidx/maintidx.go | 30 - .../pkg/golinters/makezero/makezero.go | 74 - .../pkg/golinters/mirror/mirror.go | 70 - .../golangci-lint/pkg/golinters/mnd/mnd.go | 42 - .../pkg/golinters/musttag/musttag.go | 29 - .../pkg/golinters/nakedret/nakedret.go | 25 - .../pkg/golinters/nestif/nestif.go | 78 - .../pkg/golinters/nilerr/nilerr.go | 19 - .../pkg/golinters/nilnil/nilnil.go | 31 - .../pkg/golinters/nlreturn/nlreturn.go | 27 - .../pkg/golinters/noctx/noctx.go | 19 - .../nolintlint/internal/nolintlint.go | 311 - .../pkg/golinters/nolintlint/nolintlint.go | 104 - .../nonamedreturns/nonamedreturns.go | 29 - .../nosprintfhostport/nosprintfhostport.go | 19 - .../golinters/paralleltest/paralleltest.go | 34 - .../pkg/golinters/perfsprint/perfsprint.go | 32 - .../pkg/golinters/prealloc/prealloc.go | 65 - .../pkg/golinters/predeclared/predeclared.go | 26 - .../pkg/golinters/promlinter/promlinter.go | 77 - .../pkg/golinters/protogetter/protogetter.go | 74 - .../pkg/golinters/reassign/reassign.go | 32 - .../pkg/golinters/recvcheck/recvcheck.go | 19 - .../golinters/rowserrcheck/rowserrcheck.go | 25 - .../pkg/golinters/spancheck/spancheck.go | 33 - .../golinters/sqlclosecheck/sqlclosecheck.go | 19 - .../pkg/golinters/staticcheck/staticcheck.go | 22 - .../pkg/golinters/stylecheck/stylecheck.go | 31 - .../pkg/golinters/tagalign/tagalign.go | 75 - .../pkg/golinters/tagliatelle/tagliatelle.go | 35 - .../golangci-lint/pkg/golinters/tenv/tenv.go | 29 - .../testableexamples/testableexamples.go | 19 - .../pkg/golinters/testpackage/testpackage.go | 28 - .../pkg/golinters/tparallel/tparallel.go | 18 - .../golangci-lint/pkg/golinters/typecheck.go | 24 - .../pkg/golinters/unconvert/unconvert.go | 62 - .../pkg/golinters/unparam/unparam.go | 90 - .../golinters/usestdlibvars/usestdlibvars.go | 38 - .../golinters/wastedassign/wastedassign.go | 19 - .../pkg/golinters/whitespace/whitespace.go | 102 - .../golangci-lint/pkg/golinters/wsl/wsl.go | 40 - .../pkg/golinters/zerologlint/zerologlint.go | 19 - .../golangci/golangci-lint/pkg/goutil/env.go | 63 - .../pkg/lint/lintersdb/builder_linter.go | 856 - .../golangci-lint/pkg/logutils/logutils.go | 117 - .../golangci-lint/pkg/printers/codeclimate.go | 59 - .../pkg/printers/githubaction.go | 52 - .../golangci-lint/pkg/printers/json.go | 38 - .../golangci-lint/pkg/printers/printer.go | 145 - .../processors/autogenerated_exclude.go | 177 - .../pkg/result/processors/base_rule.go | 68 - .../pkg/result/processors/cgo.go | 59 - .../pkg/result/processors/exclude.go | 55 - .../pkg/result/processors/exclude_rules.go | 105 - .../pkg/result/processors/fixer.go | 260 - .../result/processors/identifier_marker.go | 154 - .../pkg/result/processors/issues.go | 69 - .../pkg/result/processors/path_prefixer.go | 36 - .../pkg/result/processors/path_prettifier.go | 40 - .../pkg/result/processors/severity.go | 116 - .../pkg/result/processors/skip_dirs.go | 172 - .../pkg/result/processors/skip_files.go | 59 - .../golangci/golangci-lint/{ => v2}/LICENSE | 0 .../{ => v2}/cmd/golangci-lint/main.go | 29 +- .../{ => v2}/cmd/golangci-lint/plugins.go | 0 .../{ => v2}/internal/cache/cache.go | 14 +- .../{ => v2}/internal/errorutil/errors.go | 0 .../v2/internal/go}/LICENSE | 0 .../v2/internal/go/base/error_notunix.go | 12 + .../v2/internal/go/base/error_unix.go | 16 + .../v2/internal/go/base/readme.md | 10 + .../{ => v2}/internal/go/cache/cache.go | 145 +- .../{ => v2}/internal/go/cache/cache_gcil.go | 0 .../{ => v2}/internal/go/cache/default.go | 26 +- .../internal/go/cache/default_gcil.go | 0 .../{ => v2}/internal/go/cache/hash.go | 2 +- .../{ => v2}/internal/go/cache/hash_gcil.go | 0 .../{ => v2}/internal/go/cache/prog.go | 151 +- .../{ => v2}/internal/go/cache/readme.md | 2 + .../v2/internal/go/cacheprog/cacheprog.go | 137 + .../v2/internal/go/cacheprog/readme.md | 9 + .../{ => v2}/internal/go/mmap/mmap.go | 7 +- .../{ => v2}/internal/go/mmap/mmap_other.go | 0 .../{ => v2}/internal/go/mmap/mmap_unix.go | 0 .../{ => v2}/internal/go/mmap/mmap_windows.go | 8 +- .../{ => v2}/internal/go/mmap/readme.md | 2 + .../{ => v2}/internal/go/quoted/quoted.go | 0 .../{ => v2}/internal/go/quoted/readme.md | 2 + .../golangci-lint/v2/internal/x}/LICENSE | 4 +- .../internal/x/tools/analysisflags/readme.md | 11 + .../v2/internal/x/tools/analysisflags/url.go | 33 + .../x/tools/analysisinternal/analysis.go | 43 + .../x/tools/analysisinternal/readme.md | 11 + .../v2/internal/x/tools/diff/diff.go | 177 + .../v2/internal/x/tools/diff/lcs/common.go | 179 + .../v2/internal/x/tools/diff/lcs/doc.go | 156 + .../v2/internal/x/tools/diff/lcs/git.sh | 33 + .../v2/internal/x/tools/diff/lcs/labels.go | 55 + .../v2/internal/x/tools/diff/lcs/old.go | 478 + .../v2/internal/x/tools/diff/lcs/sequence.go | 113 + .../v2/internal/x/tools/diff/ndiff.go | 99 + .../v2/internal/x/tools/diff/readme.md | 11 + .../v2/internal/x/tools/diff/unified.go | 251 + .../{ => v2}/pkg/commands/cache.go | 8 +- .../{ => v2}/pkg/commands/config.go | 57 +- .../{ => v2}/pkg/commands/config_verify.go | 120 +- .../{ => v2}/pkg/commands/custom.go | 34 +- .../{ => v2}/pkg/commands/flagsets.go | 152 +- .../golangci-lint/v2/pkg/commands/fmt.go | 145 + .../v2/pkg/commands/formatters.go | 137 + .../golangci-lint/v2/pkg/commands/help.go | 101 + .../v2/pkg/commands/help_formatters.go | 123 + .../v2/pkg/commands/help_linters.go | 156 + .../{ => v2}/pkg/commands/internal/builder.go | 46 +- .../pkg/commands/internal/configuration.go | 2 +- .../v2/pkg/commands/internal/dirhash.go | 93 + .../{ => v2}/pkg/commands/internal/imports.go | 0 .../internal/migrate/fakeloader/config.go | 22 + .../internal/migrate/fakeloader/fakeloader.go | 48 + .../pkg/commands/internal/migrate/migrate.go | 19 + .../internal/migrate/migrate_formatters.go | 105 + .../internal/migrate/migrate_issues.go | 20 + .../internal/migrate/migrate_linter_names.go | 966 + .../internal/migrate/migrate_linters.go | 31 + .../migrate/migrate_linters_exclusions.go | 144 + .../migrate/migrate_linters_settings.go | 1037 ++ .../internal/migrate/migrate_output.go | 103 + .../commands/internal/migrate/migrate_run.go | 34 + .../internal/migrate/migrate_severity.go | 33 + .../internal/migrate/parser/parser.go | 87 + .../pkg/commands/internal/migrate/ptr/ptr.go | 12 + .../internal/migrate/versionone/base_rule.go | 9 + .../internal/migrate/versionone/config.go | 18 + .../internal/migrate/versionone/doc.go | 4 + .../internal/migrate/versionone/issues.go | 32 + .../internal/migrate/versionone/linters.go | 11 + .../migrate/versionone/linters_settings.go | 865 + .../internal/migrate/versionone/output.go | 37 + .../internal/migrate/versionone/run.go | 25 + .../internal/migrate/versionone/severity.go | 12 + .../internal/migrate/versiontwo/base_rule.go | 13 + .../internal/migrate/versiontwo/config.go | 18 + .../internal/migrate/versiontwo/formatters.go | 15 + .../migrate/versiontwo/formatters_settings.go | 48 + .../internal/migrate/versiontwo/issues.go | 17 + .../internal/migrate/versiontwo/linters.go | 14 + .../migrate/versiontwo/linters_exclusions.go | 16 + .../migrate/versiontwo/linters_settings.go | 801 + .../internal/migrate/versiontwo/output.go | 11 + .../migrate/versiontwo/output_formats.go | 37 + .../internal/migrate/versiontwo/run.go | 26 + .../internal/migrate/versiontwo/severity.go | 13 + .../{ => v2}/pkg/commands/internal/vibra.go | 0 .../{ => v2}/pkg/commands/linters.go | 47 +- .../golangci-lint/v2/pkg/commands/migrate.go | 243 + .../{ => v2}/pkg/commands/root.go | 10 +- .../{ => v2}/pkg/commands/run.go | 164 +- .../{ => v2}/pkg/commands/version.go | 59 +- .../v2/pkg/config/base_loader.go | 232 + .../golangci-lint/v2/pkg/config/base_rule.go | 75 + .../golangci-lint/v2/pkg/config/config.go | 201 + .../golangci-lint/v2/pkg/config/formatters.go | 28 + .../v2/pkg/config/formatters_settings.go | 61 + .../golangci-lint/v2/pkg/config/issues.go | 15 + .../golangci-lint/v2/pkg/config/linters.go | 53 + .../v2/pkg/config/linters_exclusions.go | 61 + .../{ => v2}/pkg/config/linters_settings.go | 771 +- .../golangci-lint/v2/pkg/config/loader.go | 275 + .../golangci-lint/v2/pkg/config/output.go | 62 + .../v2/pkg/config/output_formats.go | 57 + .../v2/pkg/config/placeholders.go | 18 + .../golangci-lint/{ => v2}/pkg/config/run.go | 27 +- .../{ => v2}/pkg/config/severity.go | 7 +- .../{ => v2}/pkg/exitcodes/exitcodes.go | 0 .../golangci-lint/v2/pkg/fsutils/basepath.go | 77 + .../{ => v2}/pkg/fsutils/filecache.go | 2 +- .../{ => v2}/pkg/fsutils/fsutils.go | 14 +- .../v2/pkg/fsutils/fsutils_unix.go | 9 + .../v2/pkg/fsutils/fsutils_windows.go | 39 + .../{ => v2}/pkg/fsutils/linecache.go | 0 .../{ => v2}/pkg/fsutils/path_unix.go | 0 .../{ => v2}/pkg/fsutils/path_windows.go | 0 .../{ => v2}/pkg/goanalysis/issue.go | 12 +- .../{ => v2}/pkg/goanalysis/linter.go | 58 +- .../{ => v2}/pkg/goanalysis/load/guard.go | 0 .../{ => v2}/pkg/goanalysis/metalinter.go | 10 +- .../pkg/goanalysis/pkgerrors/errors.go | 21 +- .../pkg/goanalysis/pkgerrors/extract.go | 23 + .../pkg/goanalysis/pkgerrors/parse.go | 6 +- .../v2/pkg/goanalysis/position.go | 50 + .../{ => v2}/pkg/goanalysis/runner.go | 88 +- .../{ => v2}/pkg/goanalysis/runner_action.go | 30 +- .../pkg/goanalysis/runner_action_cache.go | 43 +- .../pkg/goanalysis/runner_checker.go} | 253 +- .../pkg/goanalysis/runner_loadingpackage.go | 117 +- .../v2/pkg/goanalysis/runners.go | 156 + .../{ => v2}/pkg/goanalysis/runners_cache.go | 65 +- .../golangci-lint/v2/pkg/goformat/runner.go | 297 + .../v2/pkg/goformatters/analyzer.go | 55 + .../v2/pkg/goformatters/formatters.go | 6 + .../v2/pkg/goformatters/gci/gci.go | 74 + .../v2/pkg/goformatters/gci/internal/LICENSE | 29 + .../gci/internal/config/config.go | 108 + .../gci/internal/section/parser.go | 51 + .../gci/internal/section/section.go | 7 + .../gci/internal/section/standard.go | 30 + .../gci/internal/section/standard_list.go | 189 + .../v2/pkg/goformatters/gofmt/gofmt.go | 35 + .../v2/pkg/goformatters/gofumpt/gofumpt.go | 41 + .../pkg/goformatters/goimports/goimports.go | 30 + .../v2/pkg/goformatters/golines/golines.go | 39 + .../v2/pkg/goformatters/internal/commons.go | 6 + .../v2/pkg/goformatters/internal/diff.go | 271 + .../v2/pkg/goformatters/meta_formatter.go | 95 + .../v2/pkg/goformatters/swaggo/swaggo.go | 23 + .../v2/pkg/golinters/arangolint/arangolint.go | 13 + .../v2/pkg/golinters/asasalint/asasalint.go | 29 + .../v2/pkg/golinters/asciicheck/asciicheck.go | 13 + .../v2/pkg/golinters/bidichk/bidichk.go | 55 + .../v2/pkg/golinters/bodyclose/bodyclose.go | 13 + .../canonicalheader/canonicalheader.go | 13 + .../golinters/containedctx/containedctx.go | 13 + .../golinters/contextcheck/contextcheck.go | 26 + .../pkg/golinters/copyloopvar/copyloopvar.go | 23 + .../v2/pkg/golinters/cyclop/cyclop.go | 30 + .../pkg/golinters/decorder/decorder.go | 17 +- .../v2/pkg/golinters/depguard/depguard.go | 54 + .../v2/pkg/golinters/dogsled/dogsled.go | 67 + .../v2/pkg/golinters/dupl/dupl.go | 90 + .../v2/pkg/golinters/dupword/dupword.go | 28 + .../golinters/durationcheck/durationcheck.go | 13 + .../embeddedstructfieldcheck.go | 24 + .../v2/pkg/golinters/err113/err113.go | 14 + .../v2/pkg/golinters/errcheck/errcheck.go | 115 + .../v2/pkg/golinters/errchkjson/errchkjson.go | 26 + .../v2/pkg/golinters/errname/errname.go | 13 + .../v2/pkg/golinters/errorlint/errorlint.go | 49 + .../v2/pkg/golinters/exhaustive/exhaustive.go | 32 + .../pkg/golinters/exhaustruct/exhaustruct.go | 30 + .../v2/pkg/golinters/exptostd/exptostd.go | 13 + .../v2/pkg/golinters/fatcontext/fatcontext.go | 23 + .../v2/pkg/golinters/forbidigo/forbidigo.go | 85 + .../forcetypeassert/forcetypeassert.go | 14 + .../v2/pkg/golinters/funcorder/funcorder.go | 25 + .../v2/pkg/golinters/funlen/funlen.go | 27 + .../golangci-lint/v2/pkg/golinters/gci/gci.go | 28 + .../golinters/ginkgolinter/ginkgolinter.go | 37 + .../gocheckcompilerdirectives.go | 13 + .../gochecknoglobals/gochecknoglobals.go | 14 + .../gochecknoinits/gochecknoinits.go | 44 + .../gochecksumtype/gochecksumtype.go | 82 + .../v2/pkg/golinters/gocognit/gocognit.go | 76 + .../v2/pkg/golinters/goconst/goconst.go | 113 + .../v2/pkg/golinters/gocritic/gocritic.go | 166 + .../golinters/gocritic/gocritic_settings.go} | 453 +- .../v2/pkg/golinters/gocyclo/gocyclo.go | 72 + .../v2/pkg/golinters/godoclint/godoclint.go | 119 + .../v2/pkg/golinters/godot/godot.go | 76 + .../v2/pkg/golinters/godox/godox.go | 60 + .../v2/pkg/golinters/gofmt/gofmt.go | 21 + .../v2/pkg/golinters/gofumpt/gofumpt.go | 21 + .../v2/pkg/golinters/goheader/goheader.go | 126 + .../v2/pkg/golinters/goimports/goimports.go | 21 + .../v2/pkg/golinters/golines/golines.go | 21 + .../gomoddirectives/gomoddirectives.go | 87 + .../v2/pkg/golinters/gomodguard/gomodguard.go | 89 + .../goprintffuncname/goprintffuncname.go | 13 + .../{ => v2}/pkg/golinters/gosec/gosec.go | 65 +- .../golinters/gosmopolitan/gosmopolitan.go | 30 + .../{ => v2}/pkg/golinters/govet/govet.go | 38 +- .../{ => v2}/pkg/golinters/grouper/grouper.go | 22 +- .../{ => v2}/pkg/golinters/iface/iface.go | 12 +- .../v2/pkg/golinters/importas/importas.go | 67 + .../pkg/golinters/inamedparam/inamedparam.go | 23 + .../pkg/golinters/ineffassign/ineffassign.go | 23 + .../interfacebloat/interfacebloat.go | 23 + .../pkg/golinters/internal/commons.go | 2 +- .../v2/pkg/golinters/internal/util.go | 33 + .../v2/pkg/golinters/intrange/intrange.go | 13 + .../v2/pkg/golinters/iotamixing/iotamixing.go | 26 + .../v2/pkg/golinters/ireturn/ireturn.go | 27 + .../golangci-lint/v2/pkg/golinters/lll/lll.go | 126 + .../pkg/golinters/loggercheck/loggercheck.go | 18 +- .../v2/pkg/golinters/maintidx/maintidx.go | 23 + .../v2/pkg/golinters/makezero/makezero.go | 48 + .../v2/pkg/golinters/mirror/mirror.go | 23 + .../pkg/golinters/misspell/misspell.go | 139 +- .../golangci-lint/v2/pkg/golinters/mnd/mnd.go | 33 + .../v2/pkg/golinters/modernize/modernize.go | 34 + .../v2/pkg/golinters/musttag/musttag.go | 26 + .../v2/pkg/golinters/nakedret/nakedret.go | 21 + .../v2/pkg/golinters/nestif/nestif.go | 52 + .../v2/pkg/golinters/nilerr/nilerr.go | 14 + .../v2/pkg/golinters/nilnesserr/nilnesserr.go | 19 + .../v2/pkg/golinters/nilnil/nilnil.go | 29 + .../v2/pkg/golinters/nlreturn/nlreturn.go | 23 + .../v2/pkg/golinters/noctx/noctx.go | 14 + .../pkg/golinters/noinlineerr/noinlineerr.go | 13 + .../golinters/nolintlint/internal/README.md | 0 .../golinters/nolintlint/internal/issues.go | 41 + .../nolintlint/internal/nolintlint.go | 232 + .../v2/pkg/golinters/nolintlint/nolintlint.go | 63 + .../nonamedreturns/nonamedreturns.go | 23 + .../nosprintfhostport/nosprintfhostport.go | 13 + .../golinters/paralleltest/paralleltest.go | 29 + .../v2/pkg/golinters/perfsprint/perfsprint.go | 40 + .../v2/pkg/golinters/prealloc/prealloc.go | 23 + .../pkg/golinters/predeclared/predeclared.go | 26 + .../v2/pkg/golinters/promlinter/promlinter.go | 73 + .../pkg/golinters/protogetter/protogetter.go | 25 + .../v2/pkg/golinters/reassign/reassign.go | 26 + .../v2/pkg/golinters/recvcheck/recvcheck.go | 21 + .../{ => v2}/pkg/golinters/revive/revive.go | 387 +- .../golinters/rowserrcheck/rowserrcheck.go | 21 + .../pkg/golinters/sloglint/sloglint.go | 11 +- .../v2/pkg/golinters/spancheck/spancheck.go | 30 + .../golinters/sqlclosecheck/sqlclosecheck.go | 13 + .../pkg/golinters/staticcheck/staticcheck.go} | 138 +- .../v2/pkg/golinters/swaggo/swaggo.go | 20 + .../v2/pkg/golinters/tagalign/tagalign.go | 29 + .../pkg/golinters/tagliatelle/tagliatelle.go | 67 + .../testableexamples/testableexamples.go | 13 + .../pkg/golinters/testifylint/testifylint.go | 33 +- .../pkg/golinters/testpackage/testpackage.go | 26 + .../{ => v2}/pkg/golinters/thelper/thelper.go | 42 +- .../v2/pkg/golinters/tparallel/tparallel.go | 13 + .../v2/pkg/golinters/typecheck.go | 17 + .../v2/pkg/golinters/unconvert/unconvert.go | 61 + .../v2/pkg/golinters/unparam/unparam.go | 60 + .../v2/pkg/golinters/unqueryvet/unqueryvet.go | 63 + .../{ => v2}/pkg/golinters/unused/unused.go | 16 +- .../golinters/usestdlibvars/usestdlibvars.go | 35 + .../v2/pkg/golinters/usetesting/usetesting.go | 29 + .../pkg/golinters/varnamelen/varnamelen.go | 28 +- .../golinters/wastedassign/wastedassign.go | 14 + .../v2/pkg/golinters/whitespace/whitespace.go | 22 + .../pkg/golinters/wrapcheck/wrapcheck.go | 20 +- .../golangci-lint/v2/pkg/golinters/wsl/wsl.go | 105 + .../v2/pkg/golinters/wsl/wsl_v5.go | 34 + .../pkg/golinters/zerologlint/zerologlint.go | 13 + .../golangci-lint/v2/pkg/goutil/env.go | 49 + .../{ => v2}/pkg/goutil/version.go | 4 +- .../{ => v2}/pkg/lint/context.go | 20 +- .../{ => v2}/pkg/lint/linter/config.go | 134 +- .../{ => v2}/pkg/lint/linter/context.go | 16 +- .../{ => v2}/pkg/lint/linter/linter.go | 8 +- .../v2/pkg/lint/lintersdb/builder_linter.go | 741 + .../pkg/lint/lintersdb/builder_plugin_go.go | 23 +- .../lint/lintersdb/builder_plugin_module.go | 12 +- .../{ => v2}/pkg/lint/lintersdb/manager.go | 166 +- .../{ => v2}/pkg/lint/lintersdb/validator.go | 28 +- .../{ => v2}/pkg/lint/package.go | 27 +- .../golangci-lint/{ => v2}/pkg/lint/runner.go | 132 +- .../{ => v2}/pkg/logutils/log.go | 0 .../golangci-lint/v2/pkg/logutils/logutils.go | 138 + .../{ => v2}/pkg/logutils/mock.go | 0 .../{ => v2}/pkg/logutils/out.go | 0 .../{ => v2}/pkg/logutils/stderr_log.go | 38 +- .../{ => v2}/pkg/printers/checkstyle.go | 86 +- .../v2/pkg/printers/codeclimate.go | 73 + .../{ => v2}/pkg/printers/html.go | 20 +- .../golangci-lint/v2/pkg/printers/json.go | 39 + .../{ => v2}/pkg/printers/junitxml.go | 101 +- .../golangci-lint/v2/pkg/printers/printer.go | 241 + .../{ => v2}/pkg/printers/sarif.go | 125 +- .../{ => v2}/pkg/printers/tab.go | 24 +- .../{ => v2}/pkg/printers/teamcity.go | 50 +- .../{ => v2}/pkg/printers/text.go | 32 +- .../golangci-lint/{ => v2}/pkg/report/data.go | 12 +- .../golangci-lint/{ => v2}/pkg/report/log.go | 5 +- .../{ => v2}/pkg/result/issue.go | 29 +- .../v2/pkg/result/processors/base_rule.go | 102 + .../v2/pkg/result/processors/cgo.go | 52 + .../{ => v2}/pkg/result/processors/diff.go | 38 +- .../exclusion_generated_file_filter.go | 77 + .../exclusion_generated_file_matcher.go | 107 + .../pkg/result/processors/exclusion_paths.go | 118 + .../result/processors/exclusion_presets.go | 138 + .../pkg/result/processors/exclusion_rules.go | 123 + .../result/processors/filename_unadjuster.go | 48 +- .../v2/pkg/result/processors/fixer.go | 306 + .../pkg/result/processors/invalid_issue.go | 9 +- .../v2/pkg/result/processors/issues.go | 69 + .../pkg/result/processors/max_from_linter.go | 14 +- .../processors/max_per_file_from_linter.go | 18 +- .../pkg/result/processors/max_same_issues.go | 15 +- .../pkg/result/processors/nolint_filter.go} | 65 +- .../pkg/result/processors/path_absoluter.go | 44 + .../pkg/result/processors/path_prettifier.go | 51 + .../pkg/result/processors/path_relativity.go | 60 + .../pkg/result/processors/path_shortener.go | 8 +- .../pkg/result/processors/processor.go | 4 +- .../v2/pkg/result/processors/severity.go | 86 + .../pkg/result/processors/sort_results.go | 29 +- .../pkg/result/processors/source_code.go | 15 +- .../pkg/result/processors/uniq_by_line.go | 20 +- .../{ => v2}/pkg/timeutils/stopwatch.go | 2 +- vendor/github.com/golangci/golines/LICENSE | 22 + .../golangci/golines/shorten/.gitattributes | 3 + .../golangci/golines/shorten/annotations.go | 65 + .../golangci/golines/shorten/format.go | 347 + .../shorten/internal/annotation/annotation.go | 94 + .../shorten/internal/comments/comments.go | 104 + .../golines/shorten/internal/graph/graph.go | 132 + .../shorten/internal/graph/graph_generated.go | 596 + .../golangci/golines/shorten/internal/line.go | 16 + .../golines/shorten/internal/tags/filler.go | 42 + .../golines/shorten/internal/tags/tags.go | 222 + .../golangci/golines/shorten/log.go | 9 + .../golangci/golines/shorten/shortener.go | 206 + .../golangci/misspell/.golangci.yml | 161 +- .../golangci/misspell/CONTRIBUTING.md | 29 + vendor/github.com/golangci/misspell/Makefile | 5 +- vendor/github.com/golangci/misspell/README.md | 72 +- vendor/github.com/golangci/misspell/ascii.go | 9 +- vendor/github.com/golangci/misspell/case.go | 3 +- .../golangci/misspell/install-misspell.sh | 26 +- vendor/github.com/golangci/misspell/legal.go | 4 +- vendor/github.com/golangci/misspell/mime.go | 7 + .../github.com/golangci/misspell/notwords.go | 4 + .../github.com/golangci/misspell/replace.go | 137 +- .../golangci/misspell/stringreplacer.go | 113 +- vendor/github.com/golangci/misspell/words.go | 3495 +--- .../github.com/golangci/misspell/words_uk.go | 1484 ++ .../github.com/golangci/misspell/words_us.go | 1625 ++ vendor/github.com/golangci/modinfo/.gitignore | 1 - .../github.com/golangci/modinfo/.golangci.yml | 157 - vendor/github.com/golangci/modinfo/Makefile | 12 - vendor/github.com/golangci/modinfo/module.go | 157 - vendor/github.com/golangci/modinfo/readme.md | 73 - .../golangci/plugin-module-register/LICENSE | 875 +- .../github.com/golangci/revgrep/.golangci.yml | 71 +- vendor/github.com/golangci/revgrep/README.md | 10 +- vendor/github.com/golangci/revgrep/issue.go | 37 + vendor/github.com/golangci/revgrep/patch.go | 195 + vendor/github.com/golangci/revgrep/revgrep.go | 311 +- .../github.com/golangci/swaggoswag/.gitignore | 24 + .../golangci/swaggoswag/formatter.go | 180 + vendor/github.com/golangci/swaggoswag/license | 21 + .../github.com/golangci/swaggoswag/parser.go | 48 + .../github.com/golangci/swaggoswag/readme.md | 26 + .../github.com/golangci/unconvert/golangci.go | 15 +- .../golangci/unconvert/unconvert.go | 5 +- .../pkg/ineffassign/ineffassign.go | 60 +- .../gostaticanalysis/comment/.tagpr | 35 + .../gostaticanalysis/comment/CHANGELOG.md | 34 + .../gostaticanalysis/comment/comment.go | 23 +- .../gostaticanalysis/comment/version.txt | 1 + .../gostaticanalysis/forcetypeassert/.tagpr | 35 + .../forcetypeassert/CHANGELOG.md | 19 + .../forcetypeassert/forcetypeassert.go | 29 +- .../forcetypeassert/version.txt | 1 + .../gostaticanalysis/nilerr/README.md | 6 + .../gostaticanalysis/nilerr/nilerr.go | 40 +- .../go-immutable-radix/v2/.gitignore | 24 + .../go-immutable-radix/v2/CHANGELOG.md | 27 + .../{hcl => go-immutable-radix/v2}/LICENSE | 303 +- .../hashicorp/go-immutable-radix/v2/README.md | 73 + .../hashicorp/go-immutable-radix/v2/edges.go | 21 + .../hashicorp/go-immutable-radix/v2/iradix.go | 679 + .../hashicorp/go-immutable-radix/v2/iter.go | 205 + .../hashicorp/go-immutable-radix/v2/node.go | 326 + .../go-immutable-radix/v2/path_iter.go | 59 + .../go-immutable-radix/v2/raw_iter.go | 78 + .../go-immutable-radix/v2/reverse_iter.go | 240 + .../github.com/hashicorp/go-version/LICENSE | 2 +- .../github.com/hashicorp/go-version/README.md | 5 +- .../hashicorp/go-version/constraint.go | 73 +- .../hashicorp/go-version/version.go | 64 +- .../go-version/version_collection.go | 2 +- .../hashicorp/golang-lru/v2/LICENSE | 364 + .../hashicorp/golang-lru/v2/internal/list.go | 142 + .../golang-lru/v2/simplelru/LICENSE_list} | 2 + .../hashicorp/golang-lru/v2/simplelru/lru.go | 177 + .../golang-lru/v2/simplelru/lru_interface.go | 46 + vendor/github.com/hashicorp/hcl/.gitignore | 9 - vendor/github.com/hashicorp/hcl/.travis.yml | 13 - vendor/github.com/hashicorp/hcl/Makefile | 18 - vendor/github.com/hashicorp/hcl/README.md | 125 - vendor/github.com/hashicorp/hcl/appveyor.yml | 19 - vendor/github.com/hashicorp/hcl/decoder.go | 729 - vendor/github.com/hashicorp/hcl/hcl.go | 11 - .../github.com/hashicorp/hcl/hcl/ast/ast.go | 219 - .../github.com/hashicorp/hcl/hcl/ast/walk.go | 52 - .../hashicorp/hcl/hcl/parser/error.go | 17 - .../hashicorp/hcl/hcl/parser/parser.go | 532 - .../hashicorp/hcl/hcl/printer/nodes.go | 789 - .../hashicorp/hcl/hcl/printer/printer.go | 66 - .../hashicorp/hcl/hcl/scanner/scanner.go | 652 - .../hashicorp/hcl/hcl/strconv/quote.go | 241 - .../hashicorp/hcl/hcl/token/position.go | 46 - .../hashicorp/hcl/hcl/token/token.go | 219 - .../hashicorp/hcl/json/parser/flatten.go | 117 - .../hashicorp/hcl/json/parser/parser.go | 313 - .../hashicorp/hcl/json/scanner/scanner.go | 451 - .../hashicorp/hcl/json/token/position.go | 46 - .../hashicorp/hcl/json/token/token.go | 118 - vendor/github.com/hashicorp/hcl/lex.go | 38 - vendor/github.com/hashicorp/hcl/parse.go | 39 - .../github.com/jgautheron/goconst/.gitignore | 1 + .../github.com/jgautheron/goconst/README.md | 50 +- vendor/github.com/jgautheron/goconst/api.go | 233 +- .../github.com/jgautheron/goconst/parser.go | 843 +- .../github.com/jgautheron/goconst/visitor.go | 166 +- .../github.com/jjti/go-spancheck/.gitignore | 3 + .../jjti/go-spancheck/.golangci.yml | 12 +- vendor/github.com/jjti/go-spancheck/README.md | 6 + vendor/github.com/jjti/go-spancheck/go.work | 2 +- .../github.com/jjti/go-spancheck/go.work.sum | 7 + .../github.com/jjti/go-spancheck/spancheck.go | 85 +- vendor/github.com/julz/importas/Makefile | 17 + vendor/github.com/julz/importas/analyzer.go | 16 +- vendor/github.com/julz/importas/config.go | 18 +- vendor/github.com/julz/importas/flags.go | 21 +- .../karamaru-alpha/copyloopvar/copyloopvar.go | 46 +- .../kisielk/errcheck/errcheck/errcheck.go | 6 +- .../kisielk/errcheck/errcheck/excludes.go | 3 + .../kisielk/errcheck/errcheck/tags.go | 12 - .../kisielk/errcheck/errcheck/tags_compat.go | 13 - .../kkHAIKE/contextcheck/contextcheck.go | 8 + .../kulti/thelper/pkg/analyzer/analyzer.go | 114 +- .../kulti/thelper/pkg/analyzer/report.go | 5 +- .../pkg/paralleltest/paralleltest.go | 389 +- .../kyoh86/exportloopref/.golangci.yml | 4 - .../kyoh86/exportloopref/.goreleaser.yml | 51 - .../github.com/kyoh86/exportloopref/LICENSE | 21 - .../github.com/kyoh86/exportloopref/Makefile | 16 - .../github.com/kyoh86/exportloopref/README.md | 223 - .../kyoh86/exportloopref/exportloopref.go | 334 - vendor/github.com/ldez/exptostd/.gitignore | 2 + vendor/github.com/ldez/exptostd/.golangci.yml | 79 + vendor/github.com/ldez/exptostd/LICENSE | 190 + vendor/github.com/ldez/exptostd/Makefile | 15 + vendor/github.com/ldez/exptostd/exptostd.go | 482 + vendor/github.com/ldez/exptostd/readme.md | 116 + .../ldez/gomoddirectives/.golangci.yml | 174 +- .../github.com/ldez/gomoddirectives/LICENSE | 2 +- .../ldez/gomoddirectives/gomoddirectives.go | 219 +- .../github.com/ldez/gomoddirectives/module.go | 35 +- .../github.com/ldez/gomoddirectives/readme.md | 240 +- vendor/github.com/ldez/grignotin/LICENSE | 201 + .../github.com/ldez/grignotin/goenv/goenv.go | 51 + .../github.com/ldez/grignotin/goenv/names.go | 276 + .../github.com/ldez/grignotin/gomod/gomod.go | 85 + .../modinfo => ldez/structtags}/LICENSE | 0 .../github.com/ldez/structtags/parser/tag.go | 115 + .../ldez/structtags/parser/value.go | 83 + .../github.com/ldez/tagliatelle/.golangci.yml | 143 +- .../github.com/ldez/tagliatelle/converter.go | 119 + vendor/github.com/ldez/tagliatelle/readme.md | 212 +- .../ldez/tagliatelle/tagliatelle.go | 244 +- vendor/github.com/ldez/usetesting/.gitignore | 2 + .../github.com/ldez/usetesting/.golangci.yml | 78 + vendor/github.com/ldez/usetesting/LICENSE | 190 + vendor/github.com/ldez/usetesting/Makefile | 15 + vendor/github.com/ldez/usetesting/readme.md | 213 + vendor/github.com/ldez/usetesting/report.go | 200 + .../github.com/ldez/usetesting/usetesting.go | 267 + .../lucasb-eyer/go-colorful/.gitignore | 101 + .../lucasb-eyer/go-colorful/CHANGELOG.md | 42 + .../lucasb-eyer/go-colorful/LICENSE | 7 + .../lucasb-eyer/go-colorful/README.md | 482 + .../lucasb-eyer/go-colorful/colorgens.go | 55 + .../lucasb-eyer/go-colorful/colors.go | 979 + .../go-colorful/happy_palettegen.go | 25 + .../lucasb-eyer/go-colorful/hexcolor.go | 67 + .../go-colorful/hsluv-snapshot-rev4.json | 1 + .../lucasb-eyer/go-colorful/hsluv.go | 207 + .../go-colorful/soft_palettegen.go | 185 + .../go-colorful/warm_palettegen.go | 25 + .../macabu/inamedparam/.golangci.yml | 16 +- .../github.com/macabu/inamedparam/README.md | 10 +- .../macabu/inamedparam/inamedparam.go | 7 +- .../magiconair/properties/.gitignore | 6 - .../magiconair/properties/CHANGELOG.md | 205 - .../magiconair/properties/LICENSE.md | 24 - .../magiconair/properties/README.md | 128 - .../magiconair/properties/decode.go | 289 - .../github.com/magiconair/properties/doc.go | 155 - .../magiconair/properties/integrate.go | 35 - .../github.com/magiconair/properties/lex.go | 395 - .../github.com/magiconair/properties/load.go | 293 - .../magiconair/properties/parser.go | 86 - .../magiconair/properties/properties.go | 848 - .../magiconair/properties/rangecheck.go | 31 - .../embeddedstructfieldcheck/LICENSE | 201 + .../analyzer/analyzer.go | 64 + .../embeddedstructfieldcheck/internal/diag.go | 48 + .../internal/structanalyzer.go | 88 + .../github.com/manuelarte/funcorder/LICENSE | 201 + .../manuelarte/funcorder/analyzer/analyzer.go | 97 + .../manuelarte/funcorder/internal/astutils.go | 93 + .../manuelarte/funcorder/internal/diag.go | 69 + .../manuelarte/funcorder/internal/features.go | 17 + .../funcorder/internal/file_processor.go | 82 + .../funcorder/internal/struct_constructor.go | 37 + .../funcorder/internal/structholder.go | 141 + .../pkg/testableexamples/testableexamples.go | 2 +- .../pkg/testpackage/testpackage.go | 12 +- vendor/github.com/matoous/godox/.golangci.yml | 39 +- vendor/github.com/matoous/godox/.revive.toml | 1 + vendor/github.com/matoous/godox/Makefile | 20 + vendor/github.com/matoous/godox/godox.go | 43 +- .../mattn/go-colorable/colorable_appengine.go | 38 - .../mattn/go-colorable/colorable_others.go | 4 +- .../mattn/go-colorable/colorable_windows.go | 22 +- .../mgechev/revive/config/config.go | 108 +- .../mgechev/revive/formatter/checkstyle.go | 8 +- .../mgechev/revive/formatter/default.go | 15 +- .../mgechev/revive/formatter/friendly.go | 140 +- .../mgechev/revive/formatter/json.go | 9 +- .../mgechev/revive/formatter/ndjson.go | 4 +- .../mgechev/revive/formatter/plain.go | 17 +- .../mgechev/revive/formatter/sarif.go | 17 +- .../mgechev/revive/formatter/stylish.go | 64 +- .../mgechev/revive/formatter/unix.go | 17 +- .../revive/internal/astutils/ast_utils.go | 221 + .../mgechev/revive/internal/ifelse/args.go | 9 +- .../mgechev/revive/internal/ifelse/branch.go | 53 +- .../revive/internal/ifelse/branch_kind.go | 51 +- .../mgechev/revive/internal/ifelse/chain.go | 12 +- .../mgechev/revive/internal/ifelse/doc.go | 8 +- .../mgechev/revive/internal/ifelse/func.go | 10 +- .../mgechev/revive/internal/ifelse/rule.go | 115 +- .../mgechev/revive/internal/ifelse/target.go | 7 +- .../mgechev/revive/internal/rule/name.go | 135 + .../revive/internal/syncset/syncset.go | 44 + .../revive/internal/typeparams/typeparams.go | 20 +- .../internal/typeparams/typeparams_go117.go | 12 - .../internal/typeparams/typeparams_go118.go | 20 - .../github.com/mgechev/revive/lint/config.go | 19 +- .../github.com/mgechev/revive/lint/failure.go | 92 +- vendor/github.com/mgechev/revive/lint/file.go | 98 +- .../mgechev/revive/lint/filefilter.go | 41 +- .../mgechev/revive/lint/formatter.go | 4 +- .../github.com/mgechev/revive/lint/linter.go | 61 +- vendor/github.com/mgechev/revive/lint/name.go | 133 +- .../github.com/mgechev/revive/lint/package.go | 181 +- vendor/github.com/mgechev/revive/lint/rule.go | 8 +- .../mgechev/revive/logging/logger.go | 50 + .../mgechev/revive/rule/add_constant.go | 139 +- .../mgechev/revive/rule/argument_limit.go | 77 +- .../github.com/mgechev/revive/rule/atomic.go | 7 +- .../mgechev/revive/rule/banned_characters.go | 33 +- .../mgechev/revive/rule/bare_return.go | 10 +- .../mgechev/revive/rule/blank_imports.go | 9 +- .../revive/rule/bool_literal_in_expr.go | 31 +- .../mgechev/revive/rule/call_to_gc.go | 31 +- .../revive/rule/cognitive_complexity.go | 74 +- .../mgechev/revive/rule/comment_spacings.go | 21 +- .../mgechev/revive/rule/comments_density.go | 19 +- .../mgechev/revive/rule/confusing_naming.go | 27 +- .../mgechev/revive/rule/confusing_results.go | 73 +- .../revive/rule/constant_logical_expr.go | 10 +- .../revive/rule/context_as_argument.go | 115 +- .../mgechev/revive/rule/context_keys_type.go | 18 +- .../mgechev/revive/rule/cyclomatic.go | 66 +- .../mgechev/revive/rule/datarace.go | 84 +- .../mgechev/revive/rule/deep_exit.go | 70 +- .../github.com/mgechev/revive/rule/defer.go | 89 +- .../mgechev/revive/rule/dot_imports.go | 37 +- .../mgechev/revive/rule/duplicated_imports.go | 4 +- .../mgechev/revive/rule/early_return.go | 72 +- .../mgechev/revive/rule/empty_block.go | 8 +- .../mgechev/revive/rule/empty_lines.go | 4 +- .../mgechev/revive/rule/enforce_map_style.go | 30 +- .../rule/enforce_repeated_arg_type_style.go | 101 +- .../revive/rule/enforce_slice_style.go | 27 +- .../revive/rule/enforce_switch_style.go | 142 + .../mgechev/revive/rule/epoch_naming.go | 149 + .../mgechev/revive/rule/error_naming.go | 18 +- .../mgechev/revive/rule/error_return.go | 73 +- .../mgechev/revive/rule/error_strings.go | 77 +- .../github.com/mgechev/revive/rule/errorf.go | 9 +- .../mgechev/revive/rule/exported.go | 465 +- .../mgechev/revive/rule/file_header.go | 28 +- .../mgechev/revive/rule/file_length_limit.go | 35 +- .../mgechev/revive/rule/filename_format.go | 35 +- .../mgechev/revive/rule/flag_param.go | 85 +- .../revive/rule/forbidden_call_in_wg_go.go | 113 + .../mgechev/revive/rule/function_length.go | 156 +- .../revive/rule/function_result_limit.go | 94 +- .../mgechev/revive/rule/get_return.go | 60 +- .../mgechev/revive/rule/identical_branches.go | 72 +- .../rule/identical_ifelseif_branches.go | 186 + .../rule/identical_ifelseif_condition.go | 148 + .../revive/rule/identical_switch_branches.go | 94 + .../rule/identical_switch_conditions.go | 78 + .../mgechev/revive/rule/if_return.go | 8 +- .../revive/rule/import_alias_naming.go | 60 +- .../mgechev/revive/rule/import_shadowing.go | 43 +- .../mgechev/revive/rule/imports_blocklist.go | 23 +- .../revive/rule/increment_decrement.go | 4 +- .../mgechev/revive/rule/indent_error_flow.go | 53 +- .../revive/rule/inefficient_map_lookup.go | 174 + .../mgechev/revive/rule/line_length_limit.go | 22 +- .../revive/rule/max_control_nesting.go | 24 +- .../mgechev/revive/rule/max_public_structs.go | 27 +- .../mgechev/revive/rule/modifies_param.go | 69 +- .../revive/rule/modifies_value_receiver.go | 177 +- .../mgechev/revive/rule/nested_structs.go | 2 +- .../revive/rule/optimize_operands_order.go | 21 +- .../mgechev/revive/rule/package_comments.go | 12 +- .../revive/rule/package_directory_mismatch.go | 194 + .../mgechev/revive/rule/package_naming.go | 315 + .../github.com/mgechev/revive/rule/range.go | 5 +- .../mgechev/revive/rule/range_val_address.go | 10 +- .../revive/rule/range_val_in_closure.go | 4 +- .../mgechev/revive/rule/receiver_naming.go | 158 +- .../revive/rule/redefines_builtin_id.go | 6 +- .../revive/rule/redundant_build_tag.go | 41 + .../revive/rule/redundant_import_alias.go | 6 +- .../revive/rule/redundant_test_main_exit.go | 84 + .../mgechev/revive/rule/string_format.go | 165 +- .../mgechev/revive/rule/string_of_int.go | 2 +- .../mgechev/revive/rule/struct_tag.go | 1054 +- .../mgechev/revive/rule/superfluous_else.go | 51 +- .../mgechev/revive/rule/time_date.go | 482 + .../mgechev/revive/rule/time_equal.go | 7 +- .../mgechev/revive/rule/time_naming.go | 4 +- .../revive/rule/unchecked_type_assertion.go | 47 +- .../revive/rule/unconditional_recursion.go | 89 +- .../mgechev/revive/rule/unexported_naming.go | 2 +- .../mgechev/revive/rule/unexported_return.go | 114 +- .../mgechev/revive/rule/unhandled_error.go | 34 +- .../mgechev/revive/rule/unnecessary_format.go | 129 + .../mgechev/revive/rule/unnecessary_if.go | 202 + .../mgechev/revive/rule/unnecessary_stmt.go | 2 +- .../mgechev/revive/rule/unreachable_code.go | 3 +- .../revive/rule/unsecure_url_scheme.go | 91 + .../mgechev/revive/rule/unused_param.go | 66 +- .../mgechev/revive/rule/unused_receiver.go | 130 +- .../github.com/mgechev/revive/rule/use_any.go | 4 +- .../mgechev/revive/rule/use_errors_new.go | 61 + .../mgechev/revive/rule/use_fmt_print.go | 108 + .../mgechev/revive/rule/use_slices_sort.go | 94 + .../mgechev/revive/rule/use_waitgroup_go.go | 158 + .../mgechev/revive/rule/useless_break.go | 51 +- .../revive/rule/useless_fallthrough.go | 92 + .../github.com/mgechev/revive/rule/utils.go | 194 +- .../mgechev/revive/rule/var_declarations.go | 50 +- .../mgechev/revive/rule/var_naming.go | 242 +- .../mgechev/revive/rule/waitgroup_by_value.go | 18 +- .../mitchellh/mapstructure/CHANGELOG.md | 96 - .../mitchellh/mapstructure/README.md | 46 - .../mitchellh/mapstructure/decode_hooks.go | 279 - .../mitchellh/mapstructure/error.go | 50 - .../mitchellh/mapstructure/mapstructure.go | 1540 -- .../tenv => muesli/termenv}/.gitignore | 2 - .../muesli/termenv/.golangci-soft.yml | 43 + .../github.com/muesli/termenv/.golangci.yml | 28 + vendor/github.com/muesli/termenv/LICENSE | 21 + vendor/github.com/muesli/termenv/README.md | 431 + .../github.com/muesli/termenv/ansi_compat.md | 65 + .../github.com/muesli/termenv/ansicolors.go | 281 + vendor/github.com/muesli/termenv/color.go | 205 + .../muesli/termenv/constants_linux.go | 8 + .../muesli/termenv/constants_solaris.go | 8 + .../muesli/termenv/constants_unix.go | 13 + .../muesli/termenv/constants_zos.go | 8 + vendor/github.com/muesli/termenv/copy.go | 37 + vendor/github.com/muesli/termenv/hyperlink.go | 11 + .../github.com/muesli/termenv/notification.go | 11 + vendor/github.com/muesli/termenv/output.go | 205 + vendor/github.com/muesli/termenv/profile.go | 112 + vendor/github.com/muesli/termenv/screen.go | 590 + vendor/github.com/muesli/termenv/style.go | 126 + .../muesli/termenv/templatehelper.go | 88 + vendor/github.com/muesli/termenv/termenv.go | 115 + .../muesli/termenv/termenv_other.go | 30 + .../muesli/termenv/termenv_posix.go | 17 + .../muesli/termenv/termenv_solaris.go | 22 + .../github.com/muesli/termenv/termenv_unix.go | 301 + .../muesli/termenv/termenv_windows.go | 140 + .../nunnatsa/ginkgolinter/.gitignore | 3 +- .../nunnatsa/ginkgolinter/.golangci.yml | 21 +- .../github.com/nunnatsa/ginkgolinter/Makefile | 11 +- .../nunnatsa/ginkgolinter/README.md | 73 +- .../nunnatsa/ginkgolinter/analyzer.go | 51 +- .../ginkgolinter/{types => config}/config.go | 61 +- .../github.com/nunnatsa/ginkgolinter/doc.go | 21 +- .../internal/expression/actual/actual.go | 18 +- .../internal/expression/actual/actualarg.go | 23 +- .../expression/actual/asyncfuncarg.go | 13 +- .../expression/actual/comparisonAsserion.go | 1 - .../internal/expression/expression.go | 57 +- .../expression/matcher/errormatchers.go | 6 +- .../internal/expression/matcher/matcher.go | 50 +- .../expression/matcher/matcherinfo.go | 9 +- .../expression/matcher/matcherwithnest.go | 4 +- .../expression/matcher/multiplematchers.go | 12 +- .../internal/expression/value/value.go | 12 +- .../internal/ginkgohandler/dothandler.go | 4 +- .../internal/ginkgohandler/handler.go | 11 +- .../internal/ginkgohandler/handling.go | 8 +- .../internal/ginkgohandler/namehandler.go | 6 +- .../internal/ginkgoinfo/ginkgoinfo.go | 26 + .../internal/gomegahandler/dothandler.go | 103 - .../internal/gomegahandler/handler.go | 274 +- .../internal/gomegahandler/namedhandler.go | 115 - .../internal/gomegainfo/gomegainfo.go | 57 +- .../internal/intervals/intervals.go | 204 +- .../rules/assertiondescriptionrule.go | 39 + .../internal/rules/asyncfunccallrule.go | 30 +- .../internal/rules/asyncsucceedrule.go | 12 +- .../internal/rules/asynctimeintervalsrule.go | 40 +- .../ginkgolinter/internal/rules/caprule.go | 34 +- .../internal/rules/comparepointerrule.go | 22 +- .../internal/rules/comparisonrule.go | 17 +- .../internal/rules/doublenegativerule.go | 14 +- .../internal/rules/equalboolrule.go | 14 +- .../internal/rules/equaldifferenttypesrule.go | 24 +- .../internal/rules/equalnilrule.go | 20 +- .../internal/rules/errorequalnilrule.go | 17 +- .../internal/rules/forceexpecttorule.go | 16 +- .../ginkgolinter/internal/rules/havelen0.go | 20 +- .../internal/rules/haveoccurredrule.go | 27 +- .../ginkgolinter/internal/rules/lenrule.go | 34 +- .../internal/rules/matcheronlyrule.go | 4 + .../internal/rules/matcherrorrule.go | 9 +- .../internal/rules/missingassertionrule.go | 21 +- .../internal/rules/nilcomparerule.go | 29 +- .../ginkgolinter/internal/rules/rule.go | 14 +- .../internal/rules/simplify_not.go | 21 + .../internal/rules/succeedrule.go | 40 +- .../{interfaces => typecheck}/interfaces.go | 43 +- .../ginkgolinter/linter/ginkgo_linter.go | 15 +- .../nunnatsa/ginkgolinter/types/boolean.go | 32 - .../olekukonko/tablewriter/.travis.yml | 22 - .../olekukonko/tablewriter/README.md | 431 - .../github.com/olekukonko/tablewriter/csv.go | 52 - .../olekukonko/tablewriter/table.go | 967 - .../tablewriter/table_with_color.go | 136 - .../github.com/olekukonko/tablewriter/util.go | 93 - .../github.com/olekukonko/tablewriter/wrap.go | 99 - .../openshift/api/.ci-operator.yaml | 2 +- .../github.com/openshift/api/.golangci.yaml | 3 + vendor/github.com/openshift/api/AGENTS.md | 14 + .../github.com/openshift/api/Dockerfile.ocp | 2 +- .../types_compatibilityrequirement.go | 8 +- .../zz_generated.swagger_doc_generated.go | 2 +- .../openshift/api/apps/v1/generated.pb.go | 871 +- .../api/apps/v1/generated.protomessage.pb.go | 52 + .../github.com/openshift/api/apps/v1/types.go | 12 +- .../v1/zz_prerelease_lifecycle_generated.go | 12 +- .../api/authorization/v1/generated.pb.go | 1155 +- .../v1/generated.protomessage.pb.go | 76 + .../openshift/api/build/v1/generated.pb.go | 2051 +-- .../api/build/v1/generated.protomessage.pb.go | 126 + .../api/cloudnetwork/v1/generated.pb.go | 171 +- .../v1/generated.protomessage.pb.go | 14 + .../api/config/v1/types_authentication.go | 55 +- .../openshift/api/config/v1/types_ingress.go | 1 + ...1_authentications-CustomNoUpgrade.crd.yaml | 52 +- ...erator_01_authentications-Default.crd.yaml | 23 +- ...thentications-DevPreviewNoUpgrade.crd.yaml | 52 +- ...g-operator_01_authentications-OKD.crd.yaml | 23 +- ...hentications-TechPreviewNoUpgrade.crd.yaml | 52 +- ...0_10_config-operator_01_ingresses.crd.yaml | 3 + ...tsdatagathers-DevPreviewNoUpgrade.crd.yaml | 234 - ...sdatagathers-TechPreviewNoUpgrade.crd.yaml | 234 - ...-operator_01_insightsdatagathers.crd.yaml} | 1 - ...00_10_config-operator_01_networks.crd.yaml | 6 +- ...hift-controller-manager_01_builds.crd.yaml | 3 +- .../v1/zz_generated.swagger_doc_generated.go | 8 +- .../openshift/api/config/v1alpha1/register.go | 2 + .../v1alpha1/types_cluster_monitoring.go | 59 + .../api/config/v1alpha1/types_insights.go | 1 + .../api/config/v1alpha1/types_pki.go | 274 + .../config/v1alpha1/zz_generated.deepcopy.go | 246 + ..._generated.featuregated-crd-manifests.yaml | 23 + .../zz_generated.swagger_doc_generated.go | 117 + vendor/github.com/openshift/api/features.md | 17 +- .../openshift/api/features/features.go | 393 +- .../github.com/openshift/api/features/util.go | 157 +- .../openshift/api/image/v1/generated.pb.go | 1317 +- .../api/image/v1/generated.protomessage.pb.go | 82 + .../openshift/api/network/v1/generated.pb.go | 436 +- .../network/v1/generated.protomessage.pb.go | 30 + .../api/networkoperator/v1/generated.pb.go | 375 +- .../v1/generated.protomessage.pb.go | 26 + .../openshift/api/oauth/v1/generated.pb.go | 511 +- .../api/oauth/v1/generated.protomessage.pb.go | 34 + ..._50_ingress_00_ingresscontrollers.crd.yaml | 3 +- .../0000_70_dns_00_dnses.crd.yaml | 3 +- .../api/operator/v1alpha1/types_clusterapi.go | 7 +- .../zz_generated.swagger_doc_generated.go | 2 +- .../openshift/api/project/v1/generated.pb.go | 205 +- .../project/v1/generated.protomessage.pb.go | 16 + .../openshift/api/quota/v1/generated.pb.go | 308 +- .../api/quota/v1/generated.protomessage.pb.go | 22 + .../openshift/api/route/v1/generated.pb.go | 578 +- .../api/route/v1/generated.protomessage.pb.go | 38 + .../openshift/api/samples/v1/generated.pb.go | 222 +- .../samples/v1/generated.protomessage.pb.go | 16 + .../openshift/api/security/v1/generated.pb.go | 684 +- .../security/v1/generated.protomessage.pb.go | 44 + .../openshift/api/template/v1/generated.pb.go | 520 +- .../template/v1/generated.protomessage.pb.go | 34 + .../openshift/api/user/v1/generated.pb.go | 310 +- .../api/user/v1/generated.protomessage.pb.go | 22 + .../config/v1/acceptrisk.go | 27 + .../config/v1/alibabacloudplatformstatus.go | 11 +- .../config/v1/alibabacloudresourcetag.go | 6 +- .../config/v1/apiserver.go | 58 +- .../config/v1/apiserverencryption.go | 26 +- .../config/v1/apiservernamedservingcert.go | 11 +- .../config/v1/apiserverservingcerts.go | 3 + .../config/v1/apiserverspec.go | 30 +- .../applyconfigurations/config/v1/audit.go | 26 +- .../config/v1/auditcustomrule.go | 18 +- .../config/v1/authentication.go | 57 +- .../config/v1/authenticationspec.go | 44 +- .../config/v1/authenticationstatus.go | 16 +- .../config/v1/awsdnsspec.go | 5 + .../config/v1/awsingressspec.go | 18 + .../config/v1/awskmsconfig.go | 10 + .../config/v1/awsplatformspec.go | 6 + .../config/v1/awsplatformstatus.go | 28 +- .../config/v1/awsresourcetag.go | 12 +- .../config/v1/awsserviceendpoint.go | 11 +- .../config/v1/azureplatformstatus.go | 37 +- .../config/v1/azureresourcetag.go | 9 +- .../v1/baremetalplatformloadbalancer.go | 11 + .../config/v1/baremetalplatformspec.go | 29 +- .../config/v1/baremetalplatformstatus.go | 59 +- .../config/v1/basicauthidentityprovider.go | 3 + .../applyconfigurations/config/v1/build.go | 54 +- .../config/v1/builddefaults.go | 25 +- .../config/v1/buildoverrides.go | 18 +- .../config/v1/buildspec.go | 12 +- .../config/v1/cloudcontrollermanagerstatus.go | 11 + .../config/v1/cloudloadbalancerconfig.go | 21 +- .../config/v1/cloudloadbalancerips.go | 22 +- .../config/v1/clustercondition.go | 10 +- .../config/v1/clusterimagepolicy.go | 56 +- .../config/v1/clusterimagepolicyspec.go | 17 +- .../config/v1/clusterimagepolicystatus.go | 1 + .../config/v1/clusternetworkentry.go | 8 +- .../config/v1/clusteroperator.go | 58 +- .../config/v1/clusteroperatorstatus.go | 20 +- .../v1/clusteroperatorstatuscondition.go | 20 +- .../config/v1/clusterversion.go | 59 +- .../v1/clusterversioncapabilitiesspec.go | 15 +- .../v1/clusterversioncapabilitiesstatus.go | 7 +- .../config/v1/clusterversionspec.go | 66 +- .../config/v1/clusterversionstatus.go | 77 +- .../config/v1/componentoverride.go | 19 +- .../config/v1/componentroutespec.go | 21 +- .../config/v1/componentroutestatus.go | 43 +- .../config/v1/conditionalupdate.go | 36 +- .../config/v1/conditionalupdaterisk.go | 47 +- .../config/v1/configmapfilereference.go | 6 +- .../config/v1/configmapnamereference.go | 4 + .../applyconfigurations/config/v1/console.go | 58 +- .../config/v1/consoleauthentication.go | 12 + .../config/v1/consolespec.go | 2 + .../config/v1/consolestatus.go | 4 + .../applyconfigurations/config/v1/custom.go | 8 + .../config/v1/customfeaturegates.go | 4 +- .../config/v1/customtlsprofile.go | 3 + .../v1/deprecatedwebhooktokenauthenticator.go | 10 + .../applyconfigurations/config/v1/dns.go | 56 +- .../config/v1/dnsplatformspec.go | 13 +- .../applyconfigurations/config/v1/dnsspec.go | 31 +- .../applyconfigurations/config/v1/dnszone.go | 19 +- .../config/v1/equinixmetalplatformstatus.go | 10 +- .../config/v1/externalipconfig.go | 16 +- .../config/v1/externalippolicy.go | 9 +- .../config/v1/externalplatformspec.go | 4 + .../config/v1/externalplatformstatus.go | 5 + .../config/v1/extramapping.go | 32 +- .../config/v1/featuregate.go | 56 +- .../config/v1/featuregateattributes.go | 1 + .../config/v1/featuregatedetails.go | 7 +- .../config/v1/featuregateselection.go | 7 +- .../config/v1/featuregatestatus.go | 12 +- .../config/v1/gatherconfig.go | 17 +- .../config/v1/gathererconfig.go | 15 +- .../config/v1/gatherers.go | 12 +- .../config/v1/gcpplatformstatus.go | 25 +- .../config/v1/gcpresourcelabel.go | 10 +- .../config/v1/gcpresourcetag.go | 19 +- .../config/v1/githubidentityprovider.go | 32 +- .../config/v1/gitlabidentityprovider.go | 23 +- .../config/v1/googleidentityprovider.go | 12 +- .../config/v1/htpasswdidentityprovider.go | 7 + .../config/v1/hubsource.go | 8 +- .../config/v1/hubsourcestatus.go | 9 +- .../config/v1/ibmcloudplatformspec.go | 10 + .../config/v1/ibmcloudplatformstatus.go | 27 +- .../config/v1/ibmcloudserviceendpoint.go | 15 +- .../config/v1/identityprovider.go | 10 +- .../config/v1/identityproviderconfig.go | 30 +- .../applyconfigurations/config/v1/image.go | 61 +- .../config/v1/imagecontentpolicy.go | 52 +- .../config/v1/imagecontentpolicyspec.go | 20 + .../config/v1/imagedigestmirrors.go | 37 +- .../config/v1/imagedigestmirrorset.go | 57 +- .../config/v1/imagedigestmirrorsetspec.go | 27 + .../config/v1/imagelabel.go | 4 +- .../config/v1/imagepolicy.go | 58 +- ...imagepolicyfulciocawithrekorrootoftrust.go | 11 +- .../config/v1/imagepolicypkirootoftrust.go | 12 +- .../v1/imagepolicypublickeyrootoftrust.go | 8 +- .../config/v1/imagepolicyspec.go | 17 +- .../config/v1/imagepolicystatus.go | 2 + .../v1/imagesigstoreverificationpolicy.go | 10 +- .../config/v1/imagespec.go | 39 +- .../config/v1/imagestatus.go | 24 +- .../config/v1/imagetagmirrors.go | 39 +- .../config/v1/imagetagmirrorset.go | 57 +- .../config/v1/imagetagmirrorsetspec.go | 27 + .../config/v1/infrastructure.go | 56 +- .../config/v1/infrastructurespec.go | 20 +- .../config/v1/infrastructurestatus.go | 58 +- .../applyconfigurations/config/v1/ingress.go | 57 +- .../config/v1/ingressplatformspec.go | 14 +- .../config/v1/ingressspec.go | 55 +- .../config/v1/ingressstatus.go | 18 +- .../config/v1/insightsdatagather.go | 51 +- .../config/v1/insightsdatagatherspec.go | 3 + .../config/v1/keystoneidentityprovider.go | 6 +- .../config/v1/kmsconfig.go | 12 +- .../config/v1/kubevirtplatformstatus.go | 10 +- .../config/v1/ldapattributemapping.go | 19 +- .../config/v1/ldapidentityprovider.go | 36 +- .../config/v1/loadbalancer.go | 4 + .../config/v1/maxagepolicy.go | 10 +- .../config/v1/mtumigration.go | 4 + .../config/v1/mtumigrationvalues.go | 6 +- .../applyconfigurations/config/v1/network.go | 60 +- .../config/v1/networkdiagnostics.go | 15 +- .../v1/networkdiagnosticssourceplacement.go | 16 +- .../v1/networkdiagnosticstargetplacement.go | 16 +- .../config/v1/networkmigration.go | 10 +- .../config/v1/networkspec.go | 43 +- .../config/v1/networkstatus.go | 22 +- .../applyconfigurations/config/v1/node.go | 56 +- .../applyconfigurations/config/v1/nodespec.go | 22 +- .../config/v1/nodestatus.go | 1 + .../config/v1/nutanixfailuredomain.go | 18 +- .../config/v1/nutanixplatformloadbalancer.go | 11 + .../config/v1/nutanixplatformspec.go | 21 +- .../config/v1/nutanixplatformstatus.go | 46 +- .../config/v1/nutanixprismelementendpoint.go | 10 +- .../config/v1/nutanixprismendpoint.go | 6 +- .../config/v1/nutanixresourceidentifier.go | 9 +- .../applyconfigurations/config/v1/oauth.go | 58 +- .../config/v1/oauthremoteconnectioninfo.go | 30 +- .../config/v1/oauthspec.go | 10 +- .../config/v1/oauthtemplates.go | 26 +- .../config/v1/objectreference.go | 12 +- .../config/v1/oidcclientconfig.go | 39 +- .../config/v1/oidcclientreference.go | 16 +- .../config/v1/oidcclientstatus.go | 34 +- .../config/v1/oidcprovider.go | 37 +- .../config/v1/openidclaims.go | 19 +- .../config/v1/openididentityprovider.go | 33 +- .../v1/openstackplatformloadbalancer.go | 11 + .../config/v1/openstackplatformspec.go | 29 +- .../config/v1/openstackplatformstatus.go | 61 +- .../config/v1/operandversion.go | 6 +- .../config/v1/operatorhub.go | 52 +- .../config/v1/operatorhubspec.go | 17 +- .../config/v1/operatorhubstatus.go | 5 + .../config/v1/ovirtplatformloadbalancer.go | 11 + .../config/v1/ovirtplatformstatus.go | 49 +- .../v1/persistentvolumeclaimreference.go | 5 + .../config/v1/persistentvolumeconfig.go | 12 +- .../config/v1/pkicertificatesubject.go | 9 +- .../config/v1/platformspec.go | 58 +- .../config/v1/platformstatus.go | 55 +- .../config/v1/policyfulciosubject.go | 11 +- .../config/v1/policyidentity.go | 16 +- .../config/v1/policymatchexactrepository.go | 3 + .../config/v1/policymatchremapidentity.go | 13 +- .../config/v1/policyrootoftrust.go | 21 +- .../config/v1/powervsplatformspec.go | 5 + .../config/v1/powervsplatformstatus.go | 26 +- .../config/v1/powervsserviceendpoint.go | 13 +- .../config/v1/prefixedclaimmapping.go | 18 +- .../config/v1/profilecustomizations.go | 10 + .../applyconfigurations/config/v1/project.go | 56 +- .../config/v1/projectspec.go | 8 +- .../config/v1/promqlclustercondition.go | 7 + .../applyconfigurations/config/v1/proxy.go | 56 +- .../config/v1/proxyspec.go | 40 +- .../config/v1/proxystatus.go | 9 +- .../config/v1/registrylocation.go | 10 +- .../config/v1/registrysources.go | 18 +- .../applyconfigurations/config/v1/release.go | 27 +- .../config/v1/repositorydigestmirrors.go | 20 +- .../v1/requestheaderidentityprovider.go | 46 +- .../config/v1/requiredhstspolicy.go | 33 +- .../config/v1/scheduler.go | 57 +- .../config/v1/schedulerspec.go | 51 +- .../config/v1/secretnamereference.go | 4 + .../config/v1/signaturestore.go | 16 +- .../applyconfigurations/config/v1/storage.go | 12 +- .../config/v1/templatereference.go | 4 + .../config/v1/tlsprofilespec.go | 18 +- .../config/v1/tlssecurityprofile.go | 86 +- .../config/v1/tokenclaimmapping.go | 24 + .../config/v1/tokenclaimmappings.go | 27 +- .../v1/tokenclaimorexpressionmapping.go | 20 +- .../config/v1/tokenclaimvalidationcelrule.go | 37 + .../config/v1/tokenclaimvalidationrule.go | 27 +- .../config/v1/tokenconfig.go | 23 +- .../config/v1/tokenissuer.go | 34 +- .../config/v1/tokenrequiredclaim.go | 10 +- .../config/v1/tokenuservalidationrule.go | 43 + .../applyconfigurations/config/v1/update.go | 53 +- .../config/v1/updatehistory.go | 39 +- .../config/v1/usernameclaimmapping.go | 51 +- .../config/v1/usernameprefix.go | 6 + .../v1/vspherefailuredomainhostgroup.go | 17 +- .../v1/vspherefailuredomainregionaffinity.go | 7 + .../v1/vspherefailuredomainzoneaffinity.go | 15 +- .../v1/vsphereplatformfailuredomainspec.go | 32 +- .../config/v1/vsphereplatformloadbalancer.go | 11 + .../v1/vsphereplatformnodenetworking.go | 4 + .../v1/vsphereplatformnodenetworkingspec.go | 22 +- .../config/v1/vsphereplatformspec.go | 51 +- .../config/v1/vsphereplatformstatus.go | 57 +- .../config/v1/vsphereplatformtopology.go | 51 +- .../config/v1/vsphereplatformvcenterspec.go | 19 +- .../config/v1/webhooktokenauthenticator.go | 13 + .../config/v1alpha1/alertmanagerconfig.go | 16 +- .../v1alpha1/alertmanagercustomconfig.go | 94 +- .../config/v1alpha1/audit.go | 11 + .../config/v1alpha1/backup.go | 56 +- .../config/v1alpha1/backupspec.go | 1 + .../config/v1alpha1/certificateconfig.go | 29 + .../config/v1alpha1/clusterimagepolicy.go | 56 +- .../config/v1alpha1/clusterimagepolicyspec.go | 17 +- .../v1alpha1/clusterimagepolicystatus.go | 1 + .../config/v1alpha1/clustermonitoring.go | 56 +- .../config/v1alpha1/clustermonitoringspec.go | 47 +- .../config/v1alpha1/containerresource.go | 16 +- .../v1alpha1/criocredentialproviderconfig.go | 285 + .../criocredentialproviderconfigspec.go | 72 + .../criocredentialproviderconfigstatus.go | 41 + .../config/v1alpha1/custompkipolicy.go | 51 + .../v1alpha1/defaultcertificateconfig.go | 30 + .../config/v1alpha1/ecdsakeyconfig.go | 40 + .../config/v1alpha1/etcdbackupspec.go | 22 +- .../config/v1alpha1/gatherconfig.go | 22 +- .../config/v1alpha1/imagepolicy.go | 58 +- ...imagepolicyfulciocawithrekorrootoftrust.go | 11 +- .../v1alpha1/imagepolicypkirootoftrust.go | 12 +- .../imagepolicypublickeyrootoftrust.go | 8 +- .../config/v1alpha1/imagepolicyspec.go | 17 +- .../config/v1alpha1/imagepolicystatus.go | 1 + .../imagesigstoreverificationpolicy.go | 8 +- .../config/v1alpha1/insightsdatagather.go | 56 +- .../config/v1alpha1/insightsdatagatherspec.go | 1 + .../config/v1alpha1/keyconfig.go | 59 + .../config/v1alpha1/metricsserverconfig.go | 71 +- .../persistentvolumeclaimreference.go | 4 + .../config/v1alpha1/persistentvolumeconfig.go | 12 +- .../config/v1alpha1/pki.go | 262 + .../v1alpha1/pkicertificatemanagement.go | 65 + .../config/v1alpha1/pkicertificatesubject.go | 9 +- .../config/v1alpha1/pkiprofile.go | 68 + .../config/v1alpha1/pkispec.go | 28 + .../config/v1alpha1/policyfulciosubject.go | 8 +- .../config/v1alpha1/policyidentity.go | 16 +- .../v1alpha1/policymatchexactrepository.go | 2 + .../v1alpha1/policymatchremapidentity.go | 11 +- .../config/v1alpha1/policyrootoftrust.go | 17 +- ...rometheusoperatoradmissionwebhookconfig.go | 78 + .../v1alpha1/prometheusoperatorconfig.go | 136 + .../config/v1alpha1/retentionnumberconfig.go | 5 + .../config/v1alpha1/retentionpolicy.go | 13 +- .../config/v1alpha1/retentionsizeconfig.go | 5 + .../config/v1alpha1/rsakeyconfig.go | 27 + .../config/v1alpha1/storage.go | 12 +- .../config/v1alpha1/userdefinedmonitoring.go | 7 + .../config/v1alpha2/custom.go | 8 + .../config/v1alpha2/gatherconfig.go | 15 +- .../config/v1alpha2/gathererconfig.go | 15 +- .../config/v1alpha2/gatherers.go | 12 +- .../config/v1alpha2/insightsdatagather.go | 56 +- .../config/v1alpha2/insightsdatagatherspec.go | 1 + .../persistentvolumeclaimreference.go | 4 + .../config/v1alpha2/persistentvolumeconfig.go | 12 +- .../config/v1alpha2/storage.go | 12 +- .../applyconfigurations/internal/internal.go | 280 +- .../typed/config/v1alpha1/config_client.go | 10 + .../v1alpha1/criocredentialproviderconfig.go | 62 + .../config/v1alpha1/generated_expansion.go | 4 + .../versioned/typed/config/v1alpha1/pki.go | 54 + .../externalversions/config/v1/apiserver.go | 4 +- .../config/v1/authentication.go | 4 +- .../externalversions/config/v1/build.go | 4 +- .../config/v1/clusterimagepolicy.go | 4 +- .../config/v1/clusteroperator.go | 4 +- .../config/v1/clusterversion.go | 4 +- .../externalversions/config/v1/console.go | 4 +- .../externalversions/config/v1/dns.go | 4 +- .../externalversions/config/v1/featuregate.go | 4 +- .../externalversions/config/v1/image.go | 4 +- .../config/v1/imagecontentpolicy.go | 4 +- .../config/v1/imagedigestmirrorset.go | 4 +- .../externalversions/config/v1/imagepolicy.go | 4 +- .../config/v1/imagetagmirrorset.go | 4 +- .../config/v1/infrastructure.go | 4 +- .../externalversions/config/v1/ingress.go | 4 +- .../config/v1/insightsdatagather.go | 4 +- .../externalversions/config/v1/network.go | 4 +- .../externalversions/config/v1/node.go | 4 +- .../externalversions/config/v1/oauth.go | 4 +- .../externalversions/config/v1/operatorhub.go | 4 +- .../externalversions/config/v1/project.go | 4 +- .../externalversions/config/v1/proxy.go | 4 +- .../externalversions/config/v1/scheduler.go | 4 +- .../config/v1alpha1/backup.go | 4 +- .../config/v1alpha1/clusterimagepolicy.go | 4 +- .../config/v1alpha1/clustermonitoring.go | 4 +- .../v1alpha1/criocredentialproviderconfig.go | 85 + .../config/v1alpha1/imagepolicy.go | 4 +- .../config/v1alpha1/insightsdatagather.go | 4 +- .../config/v1alpha1/interface.go | 14 + .../externalversions/config/v1alpha1/pki.go | 85 + .../config/v1alpha2/insightsdatagather.go | 4 +- .../informers/externalversions/factory.go | 3 +- .../informers/externalversions/generic.go | 4 + .../v1alpha1/criocredentialproviderconfig.go | 32 + .../config/v1alpha1/expansion_generated.go | 8 + .../config/listers/config/v1alpha1/pki.go | 32 + .../applyconfigurations/internal/internal.go | 93 + .../operator/v1/accesslogging.go | 42 +- .../v1/additionalnetworkdefinition.go | 21 +- .../v1/additionalroutingcapabilities.go | 7 + .../operator/v1/addpage.go | 4 + .../operator/v1/authentication.go | 50 +- .../operator/v1/authenticationstatus.go | 1 + .../v1/awsclassicloadbalancerparameters.go | 25 +- .../operator/v1/awscsidriverconfigspec.go | 8 +- .../operator/v1/awsefsvolumemetrics.go | 11 +- .../awsefsvolumemetricsrecursivewalkconfig.go | 12 +- .../operator/v1/awsloadbalancerparameters.go | 23 +- .../v1/awsnetworkloadbalancerparameters.go | 31 +- .../operator/v1/awssubnets.go | 16 +- .../operator/v1/azurecsidriverconfigspec.go | 4 + .../operator/v1/azurediskencryptionset.go | 23 +- .../v1/bootimageskewenforcementconfig.go | 20 +- .../v1/bootimageskewenforcementstatus.go | 28 +- .../operator/v1/capability.go | 7 +- .../operator/v1/capabilityvisibility.go | 5 + .../operator/v1/clienttls.go | 25 +- .../operator/v1/cloudcredential.go | 50 +- .../operator/v1/cloudcredentialspec.go | 13 +- .../operator/v1/cloudcredentialstatus.go | 2 + .../operator/v1/clusterbootimageautomatic.go | 15 +- .../operator/v1/clusterbootimagemanual.go | 24 +- .../operator/v1/clustercsidriver.go | 58 +- .../operator/v1/clustercsidriverspec.go | 18 +- .../operator/v1/clustercsidriverstatus.go | 2 + .../operator/v1/clusternetworkentry.go | 5 + .../applyconfigurations/operator/v1/config.go | 57 +- .../operator/v1/configmapfilereference.go | 13 +- .../operator/v1/console.go | 50 +- .../operator/v1/consoleconfigroute.go | 15 +- .../operator/v1/consolecustomization.go | 61 +- .../operator/v1/consoleproviders.go | 4 + .../operator/v1/consolespec.go | 29 +- .../operator/v1/consolestatus.go | 2 + .../containerloggingdestinationparameters.go | 8 + .../operator/v1/csidriverconfigspec.go | 24 +- .../operator/v1/csisnapshotcontroller.go | 56 +- .../operator/v1/csisnapshotcontrollerspec.go | 2 + .../v1/csisnapshotcontrollerstatus.go | 2 + .../operator/v1/defaultnetworkdefinition.go | 12 +- .../v1/developerconsolecatalogcategory.go | 6 +- .../v1/developerconsolecatalogcategorymeta.go | 13 +- .../developerconsolecatalogcustomization.go | 7 +- .../v1/developerconsolecatalogtypes.go | 20 +- .../applyconfigurations/operator/v1/dns.go | 62 +- .../operator/v1/dnscache.go | 20 + .../operator/v1/dnsnodeplacement.go | 25 +- .../operator/v1/dnsovertlsconfig.go | 17 +- .../operator/v1/dnsspec.go | 64 +- .../operator/v1/dnsstatus.go | 32 +- .../operator/v1/dnstransportconfig.go | 23 +- .../operator/v1/egressipconfig.go | 9 + .../operator/v1/endpointpublishingstrategy.go | 68 +- .../applyconfigurations/operator/v1/etcd.go | 50 +- .../operator/v1/etcdspec.go | 13 +- .../operator/v1/exportnetworkflows.go | 7 +- .../operator/v1/featuresmigration.go | 10 +- .../operator/v1/filereferencesource.go | 10 +- .../operator/v1/forwardplugin.go | 44 +- .../operator/v1/gatewayconfig.go | 23 +- .../operator/v1/gathererstatus.go | 12 +- .../operator/v1/gatherstatus.go | 13 +- .../operator/v1/gcpcsidriverconfigspec.go | 4 + .../operator/v1/gcpkmskeyreference.go | 22 +- .../operator/v1/gcploadbalancerparameters.go | 18 + .../operator/v1/generationstatus.go | 20 +- .../operator/v1/healthcheck.go | 18 +- .../operator/v1/hostnetworkstrategy.go | 57 +- .../operator/v1/httpcompressionpolicy.go | 16 + .../operator/v1/hybridoverlayconfig.go | 7 +- .../v1/ibmcloudcsidriverconfigspec.go | 4 + .../operator/v1/ibmloadbalancerparameters.go | 22 + .../operator/v1/ingress.go | 19 +- .../operator/v1/ingresscontroller.go | 70 +- .../v1/ingresscontrollercapturehttpcookie.go | 11 +- ...ingresscontrollercapturehttpcookieunion.go | 20 +- .../v1/ingresscontrollercapturehttpheader.go | 13 +- .../v1/ingresscontrollercapturehttpheaders.go | 11 +- .../v1/ingresscontrollerhttpheader.go | 12 +- .../v1/ingresscontrollerhttpheaderactions.go | 24 +- .../ingresscontrollerhttpheaderactionunion.go | 10 +- .../v1/ingresscontrollerhttpheaders.go | 76 +- ...gresscontrollerhttpuniqueidheaderpolicy.go | 16 +- .../operator/v1/ingresscontrollerlogging.go | 5 + .../v1/ingresscontrollersethttpheader.go | 10 + .../operator/v1/ingresscontrollerspec.go | 291 +- .../operator/v1/ingresscontrollerstatus.go | 61 +- .../v1/ingresscontrollertuningoptions.go | 214 +- .../operator/v1/insightsoperator.go | 56 +- .../operator/v1/insightsoperatorstatus.go | 8 +- .../operator/v1/insightsreport.go | 10 +- .../operator/v1/ipamconfig.go | 7 +- .../operator/v1/ipfixconfig.go | 1 + .../operator/v1/ipsecconfig.go | 13 +- .../operator/v1/ipsecfullmodeconfig.go | 10 + .../operator/v1/ipv4gatewayconfig.go | 11 + .../operator/v1/ipv4ovnkubernetesconfig.go | 19 +- .../operator/v1/ipv6gatewayconfig.go | 11 + .../operator/v1/ipv6ovnkubernetesconfig.go | 21 +- .../v1/irreconcilablevalidationoverrides.go | 11 + .../operator/v1/kubeapiserver.go | 56 +- .../operator/v1/kubeapiserverspec.go | 10 +- .../operator/v1/kubeapiserverstatus.go | 7 +- .../operator/v1/kubecontrollermanager.go | 56 +- .../operator/v1/kubecontrollermanagerspec.go | 7 +- .../operator/v1/kubescheduler.go | 56 +- .../operator/v1/kubestorageversionmigrator.go | 50 +- .../operator/v1/loadbalancerstrategy.go | 33 +- .../operator/v1/loggingdestination.go | 29 +- .../applyconfigurations/operator/v1/logo.go | 13 +- .../operator/v1/machineconfiguration.go | 56 +- .../operator/v1/machineconfigurationspec.go | 32 +- .../operator/v1/machineconfigurationstatus.go | 20 +- .../operator/v1/machinemanager.go | 17 +- .../operator/v1/machinemanagerselector.go | 12 +- .../operator/v1/managedbootimages.go | 2 + .../operator/v1/mtumigration.go | 8 + .../operator/v1/mtumigrationvalues.go | 6 +- .../operator/v1/netflowconfig.go | 2 + .../operator/v1/network.go | 51 +- .../operator/v1/networkmigration.go | 26 +- .../operator/v1/networkspec.go | 73 +- .../operator/v1/networkstatus.go | 3 + .../v1/nodedisruptionpolicyclusterstatus.go | 10 +- .../operator/v1/nodedisruptionpolicyconfig.go | 12 +- .../v1/nodedisruptionpolicyspecaction.go | 12 +- .../v1/nodedisruptionpolicyspecfile.go | 13 +- .../v1/nodedisruptionpolicyspecsshkey.go | 9 + .../v1/nodedisruptionpolicyspecunit.go | 16 +- .../operator/v1/nodedisruptionpolicystatus.go | 1 + .../v1/nodedisruptionpolicystatusaction.go | 12 +- .../v1/nodedisruptionpolicystatusfile.go | 13 +- .../v1/nodedisruptionpolicystatussshkey.go | 9 + .../v1/nodedisruptionpolicystatusunit.go | 16 +- .../operator/v1/nodeplacement.go | 35 +- .../operator/v1/nodeportstrategy.go | 26 + .../operator/v1/nodestatus.go | 31 +- .../operator/v1/oauthapiserverstatus.go | 2 + .../applyconfigurations/operator/v1/olm.go | 56 +- .../operator/v1/openshiftapiserver.go | 56 +- .../operator/v1/openshiftcontrollermanager.go | 50 +- .../operator/v1/openshiftsdnconfig.go | 21 +- .../v1/openstackloadbalancerparameters.go | 11 + .../operator/v1/operatorcondition.go | 20 +- .../operator/v1/operatorspec.go | 31 +- .../operator/v1/operatorstatus.go | 18 +- .../operator/v1/ovnkubernetesconfig.go | 65 +- .../operator/v1/partialselector.go | 3 + .../operator/v1/perspective.go | 15 +- .../operator/v1/perspectivevisibility.go | 6 +- .../operator/v1/pinnedresourcereference.go | 17 +- .../operator/v1/policyauditconfig.go | 24 +- .../operator/v1/privatestrategy.go | 27 + .../operator/v1/projectaccess.go | 4 + .../v1/providerloadbalancerparameters.go | 34 +- .../operator/v1/proxyconfig.go | 16 +- .../operator/v1/quickstarts.go | 3 + .../operator/v1/reloadservice.go | 6 + .../v1/resourceattributesaccessreview.go | 8 +- .../operator/v1/restartservice.go | 6 + .../operator/v1/routeadmissionpolicy.go | 30 +- .../applyconfigurations/operator/v1/server.go | 13 +- .../operator/v1/serviceaccountissuerstatus.go | 6 +- .../operator/v1/serviceca.go | 56 +- .../operator/v1/servicecatalogapiserver.go | 51 +- .../v1/servicecatalogcontrollermanager.go | 51 +- .../operator/v1/sflowconfig.go | 1 + .../operator/v1/simplemacvlanconfig.go | 14 +- .../operator/v1/staticipamaddresses.go | 4 + .../operator/v1/staticipamconfig.go | 9 +- .../operator/v1/staticipamdns.go | 9 +- .../operator/v1/staticipamroutes.go | 7 +- .../operator/v1/staticpodoperatorspec.go | 15 +- .../operator/v1/staticpodoperatorstatus.go | 9 +- .../operator/v1/statuspageprovider.go | 3 + .../operator/v1/storage.go | 56 +- .../operator/v1/storagespec.go | 10 +- .../operator/v1/storagestatus.go | 2 + .../v1/syslogloggingdestinationparameters.go | 21 +- .../applyconfigurations/operator/v1/theme.go | 16 +- .../operator/v1/upstream.go | 23 +- .../operator/v1/upstreamresolvers.go | 48 +- .../operator/v1/vspherecsidriverconfigspec.go | 38 +- .../testutils/Makefile | 14 +- .../testutils/cleanup.go | 1 + .../testutils/conditions.go | 2 +- .../testutils/matchers.go | 4 +- .../testutils/resourcebuilder/core/v1/node.go | 32 +- .../testutils/tools.go | 3 +- .../pelletier/go-toml/v2/.goreleaser.yaml | 2 +- .../pelletier/go-toml/v2/unmarshaler.go | 2 +- .../polyfloyd/go-errorlint/errorlint/lint.go | 385 - .../prometheus/common/expfmt/decode.go | 14 +- .../common/expfmt/openmetrics_create.go | 59 +- .../prometheus/common/expfmt/text_create.go | 58 +- .../prometheus/common/expfmt/text_parse.go | 102 +- .../prometheus/procfs/.golangci.yml | 28 +- vendor/github.com/prometheus/procfs/Makefile | 2 +- .../prometheus/procfs/Makefile.common | 2 +- vendor/github.com/prometheus/procfs/arp.go | 9 +- .../github.com/prometheus/procfs/buddyinfo.go | 10 +- .../github.com/prometheus/procfs/cmdline.go | 2 +- .../github.com/prometheus/procfs/cpuinfo.go | 2 +- .../prometheus/procfs/cpuinfo_armx.go | 2 +- .../prometheus/procfs/cpuinfo_loong64.go | 2 +- .../prometheus/procfs/cpuinfo_mipsx.go | 2 +- .../prometheus/procfs/cpuinfo_others.go | 2 +- .../prometheus/procfs/cpuinfo_ppcx.go | 2 +- .../prometheus/procfs/cpuinfo_riscvx.go | 2 +- .../prometheus/procfs/cpuinfo_s390x.go | 2 +- .../prometheus/procfs/cpuinfo_x86.go | 2 +- vendor/github.com/prometheus/procfs/crypto.go | 2 +- vendor/github.com/prometheus/procfs/doc.go | 2 +- vendor/github.com/prometheus/procfs/fs.go | 2 +- .../prometheus/procfs/fs_statfs_notype.go | 2 +- .../prometheus/procfs/fs_statfs_type.go | 2 +- .../github.com/prometheus/procfs/fscache.go | 9 +- .../prometheus/procfs/internal/fs/fs.go | 2 +- .../prometheus/procfs/internal/util/parse.go | 2 +- .../procfs/internal/util/readfile.go | 2 +- .../procfs/internal/util/sysreadfile.go | 2 +- .../internal/util/sysreadfile_compat.go | 2 +- .../procfs/internal/util/valueparser.go | 2 +- vendor/github.com/prometheus/procfs/ipvs.go | 2 +- .../prometheus/procfs/kernel_hung.go | 45 + .../prometheus/procfs/kernel_random.go | 2 +- .../github.com/prometheus/procfs/loadavg.go | 2 +- vendor/github.com/prometheus/procfs/mdstat.go | 118 +- .../github.com/prometheus/procfs/meminfo.go | 4 +- .../github.com/prometheus/procfs/mountinfo.go | 23 +- .../prometheus/procfs/mountstats.go | 4 +- .../prometheus/procfs/net_conntrackstat.go | 2 +- .../github.com/prometheus/procfs/net_dev.go | 2 +- .../prometheus/procfs/net_dev_snmp6.go | 7 +- .../prometheus/procfs/net_ip_socket.go | 2 +- .../prometheus/procfs/net_protocols.go | 4 +- .../github.com/prometheus/procfs/net_route.go | 2 +- .../prometheus/procfs/net_sockstat.go | 5 +- .../prometheus/procfs/net_softnet.go | 2 +- .../github.com/prometheus/procfs/net_tcp.go | 2 +- .../prometheus/procfs/net_tls_stat.go | 2 +- .../github.com/prometheus/procfs/net_udp.go | 2 +- .../github.com/prometheus/procfs/net_unix.go | 2 +- .../prometheus/procfs/net_wireless.go | 2 +- .../github.com/prometheus/procfs/net_xfrm.go | 2 +- .../github.com/prometheus/procfs/netstat.go | 2 +- .../prometheus/procfs/nfnetlink_queue.go | 85 + vendor/github.com/prometheus/procfs/proc.go | 4 +- .../prometheus/procfs/proc_cgroup.go | 2 +- .../prometheus/procfs/proc_cgroups.go | 8 +- .../prometheus/procfs/proc_environ.go | 2 +- .../prometheus/procfs/proc_fdinfo.go | 13 +- .../prometheus/procfs/proc_interrupts.go | 2 +- .../github.com/prometheus/procfs/proc_io.go | 2 +- .../prometheus/procfs/proc_limits.go | 7 +- .../github.com/prometheus/procfs/proc_maps.go | 2 +- .../prometheus/procfs/proc_netstat.go | 2 +- .../github.com/prometheus/procfs/proc_ns.go | 2 +- .../github.com/prometheus/procfs/proc_psi.go | 2 +- .../prometheus/procfs/proc_smaps.go | 2 +- .../github.com/prometheus/procfs/proc_snmp.go | 2 +- .../prometheus/procfs/proc_snmp6.go | 2 +- .../github.com/prometheus/procfs/proc_stat.go | 2 +- .../prometheus/procfs/proc_statm.go | 4 +- .../prometheus/procfs/proc_status.go | 9 +- .../github.com/prometheus/procfs/proc_sys.go | 2 +- .../github.com/prometheus/procfs/schedstat.go | 2 +- vendor/github.com/prometheus/procfs/slab.go | 2 +- .../github.com/prometheus/procfs/softirqs.go | 2 +- vendor/github.com/prometheus/procfs/stat.go | 5 +- vendor/github.com/prometheus/procfs/swaps.go | 2 +- vendor/github.com/prometheus/procfs/thread.go | 2 +- vendor/github.com/prometheus/procfs/vm.go | 2 +- .../github.com/prometheus/procfs/zoneinfo.go | 8 +- .../quasilyte/go-ruleguard/dsl/dsl.go | 6 +- .../go-ruleguard/ruleguard/irconv/irconv.go | 34 +- .../github.com/raeperd/recvcheck/.gitignore | 3 +- .../raeperd/recvcheck/.golangci.yml | 10 + vendor/github.com/raeperd/recvcheck/Makefile | 14 +- vendor/github.com/raeperd/recvcheck/README.md | 6 +- .../github.com/raeperd/recvcheck/analyzer.go | 122 +- .../go-internal}/diff/diff.go | 9 +- .../go-internal}/robustio/robustio.go | 0 .../go-internal}/robustio/robustio_darwin.go | 0 .../go-internal}/robustio/robustio_flaky.go | 0 .../go-internal}/robustio/robustio_other.go | 0 .../go-internal}/robustio/robustio_windows.go | 8 +- .../ryancurrah/gomodguard/.golangci.yml | 2 +- .../ryancurrah/gomodguard/README.md | 4 +- .../ryancurrah/gomodguard/processor.go | 4 - .../github.com/sagikazarmark/locafero/.envrc | 4 +- .../sagikazarmark/locafero/finder.go | 6 +- .../sagikazarmark/locafero/flake.lock | 303 +- .../sagikazarmark/locafero/flake.nix | 21 +- .../github.com/sagikazarmark/locafero/glob.go | 5 + .../sagikazarmark/locafero/glob_windows.go | 8 + .../github.com/sagikazarmark/slog-shim/.envrc | 4 - .../sagikazarmark/slog-shim/.gitignore | 4 - .../sagikazarmark/slog-shim/README.md | 81 - .../sagikazarmark/slog-shim/attr.go | 74 - .../sagikazarmark/slog-shim/attr_120.go | 75 - .../sagikazarmark/slog-shim/flake.lock | 273 - .../sagikazarmark/slog-shim/flake.nix | 57 - .../sagikazarmark/slog-shim/handler.go | 45 - .../sagikazarmark/slog-shim/handler_120.go | 45 - .../sagikazarmark/slog-shim/json_handler.go | 23 - .../slog-shim/json_handler_120.go | 24 - .../sagikazarmark/slog-shim/level.go | 61 - .../sagikazarmark/slog-shim/level_120.go | 61 - .../sagikazarmark/slog-shim/logger.go | 98 - .../sagikazarmark/slog-shim/logger_120.go | 99 - .../sagikazarmark/slog-shim/record.go | 31 - .../sagikazarmark/slog-shim/record_120.go | 32 - .../sagikazarmark/slog-shim/text_handler.go | 23 - .../slog-shim/text_handler_120.go | 24 - .../sagikazarmark/slog-shim/value.go | 109 - .../sagikazarmark/slog-shim/value_120.go | 110 - .../santhosh-tekuri/jsonschema/v5/.gitignore | 4 - .../santhosh-tekuri/jsonschema/v5/README.md | 220 - .../santhosh-tekuri/jsonschema/v5/compiler.go | 812 - .../santhosh-tekuri/jsonschema/v5/content.go | 29 - .../santhosh-tekuri/jsonschema/v5/doc.go | 49 - .../santhosh-tekuri/jsonschema/v5/draft.go | 1454 -- .../santhosh-tekuri/jsonschema/v5/errors.go | 129 - .../jsonschema/v5/extension.go | 116 - .../santhosh-tekuri/jsonschema/v5/format.go | 567 - .../jsonschema/v5/httploader/httploader.go | 38 - .../santhosh-tekuri/jsonschema/v5/loader.go | 60 - .../santhosh-tekuri/jsonschema/v5/output.go | 77 - .../santhosh-tekuri/jsonschema/v5/resource.go | 280 - .../santhosh-tekuri/jsonschema/v5/schema.go | 900 - .../jsonschema/{v5 => v6}/.gitmodules | 1 + .../jsonschema/v6/.golangci.yml | 7 + .../jsonschema/v6/.pre-commit-hooks.yaml | 7 + .../santhosh-tekuri/jsonschema/v6/.swp | Bin 0 -> 20480 bytes .../jsonschema/{v5 => v6}/LICENSE | 0 .../santhosh-tekuri/jsonschema/v6/README.md | 88 + .../santhosh-tekuri/jsonschema/v6/compiler.go | 332 + .../santhosh-tekuri/jsonschema/v6/content.go | 51 + .../santhosh-tekuri/jsonschema/v6/draft.go | 360 + .../santhosh-tekuri/jsonschema/v6/format.go | 708 + .../santhosh-tekuri/jsonschema/v6/go.work | 8 + .../santhosh-tekuri/jsonschema/v6/go.work.sum | 4 + .../jsonschema/v6/kind/kind.go | 651 + .../santhosh-tekuri/jsonschema/v6/loader.go | 266 + .../jsonschema/v6/metaschemas/draft-04/schema | 151 + .../jsonschema/v6/metaschemas/draft-06/schema | 150 + .../jsonschema/v6/metaschemas/draft-07/schema | 172 + .../metaschemas/draft/2019-09/meta/applicator | 55 + .../v6/metaschemas/draft/2019-09/meta/content | 15 + .../v6/metaschemas/draft/2019-09/meta/core | 56 + .../v6/metaschemas/draft/2019-09/meta/format | 13 + .../metaschemas/draft/2019-09/meta/meta-data | 35 + .../metaschemas/draft/2019-09/meta/validation | 97 + .../v6/metaschemas/draft/2019-09/schema | 41 + .../metaschemas/draft/2020-12/meta/applicator | 47 + .../v6/metaschemas/draft/2020-12/meta/content | 15 + .../v6/metaschemas/draft/2020-12/meta/core | 50 + .../draft/2020-12/meta/format-annotation | 13 + .../draft/2020-12/meta/format-assertion | 13 + .../metaschemas/draft/2020-12/meta/meta-data | 35 + .../draft/2020-12/meta/unevaluated | 14 + .../metaschemas/draft/2020-12/meta/validation | 97 + .../v6/metaschemas/draft/2020-12/schema | 57 + .../jsonschema/v6/objcompiler.go | 549 + .../santhosh-tekuri/jsonschema/v6/output.go | 216 + .../santhosh-tekuri/jsonschema/v6/position.go | 142 + .../santhosh-tekuri/jsonschema/v6/root.go | 202 + .../santhosh-tekuri/jsonschema/v6/roots.go | 286 + .../santhosh-tekuri/jsonschema/v6/schema.go | 254 + .../santhosh-tekuri/jsonschema/v6/util.go | 464 + .../jsonschema/v6/validator.go | 975 + .../santhosh-tekuri/jsonschema/v6/vocab.go | 111 + .../usestdlibvars/pkg/analyzer/analyzer.go | 57 +- .../pkg/analyzer/internal/mapping/mapping.go | 15 + .../github.com/securego/gosec/v2/.gitignore | 2 + .../securego/gosec/v2/.golangci.yml | 76 +- .../securego/gosec/v2/.goreleaser.yml | 5 +- .../securego/gosec/v2/DEVELOPMENT.md | 435 + vendor/github.com/securego/gosec/v2/Makefile | 34 +- vendor/github.com/securego/gosec/v2/README.md | 397 +- vendor/github.com/securego/gosec/v2/RULES.md | 184 + vendor/github.com/securego/gosec/v2/USERS.md | 1 + .../github.com/securego/gosec/v2/action.yml | 22 +- .../github.com/securego/gosec/v2/analyzer.go | 794 +- .../gosec/v2/analyzers/analyzerslist.go | 90 + .../gosec/v2/analyzers/commandinjection.go | 60 + .../gosec/v2/analyzers/context_propagation.go | 922 + .../gosec/v2/analyzers/conversion_overflow.go | 596 +- .../gosec/v2/analyzers/cors_bypass_pattern.go | 206 + .../gosec/v2/analyzers/form_parsing_limits.go | 521 + .../gosec/v2/analyzers/hardcodedNonce.go | 246 - .../gosec/v2/analyzers/hardcoded_nonce.go | 878 + .../gosec/v2/analyzers/loginjection.go | 88 + .../gosec/v2/analyzers/pathtraversal.go | 100 + .../gosec/v2/analyzers/range_analyzer.go | 1480 ++ .../analyzers/redirect_header_propagation.go | 266 + .../gosec/v2/analyzers/request_smuggling.go | 303 + .../gosec/v2/analyzers/slice_bounds.go | 807 +- .../gosec/v2/analyzers/smtpinjection.go | 67 + .../gosec/v2/analyzers/sqlinjection.go | 73 + .../gosec/v2/analyzers/ssh_callback.go | 381 + .../securego/gosec/v2/analyzers/ssrf.go | 81 + .../v2/analyzers/tls_resumption_verifypeer.go | 385 + .../securego/gosec/v2/analyzers/util.go | 601 +- .../gosec/v2/analyzers/walk_symlink_race.go | 326 + .../securego/gosec/v2/analyzers/xss.go | 115 + vendor/github.com/securego/gosec/v2/config.go | 39 +- .../github.com/securego/gosec/v2/cwe/data.go | 25 + .../securego/gosec/v2/gosec_cache.go | 81 + .../github.com/securego/gosec/v2/helpers.go | 190 +- .../ssautil/package_analysis_cache.go | 40 + .../gosec/v2/internal/ssautil/ssa_result.go | 37 + .../securego/gosec/v2/issue/issue.go | 41 +- .../securego/gosec/v2/path_filter.go | 213 + .../securego/gosec/v2/regex_cache.go | 21 + .../github.com/securego/gosec/v2/resolve.go | 6 + .../securego/gosec/v2/rules/archive.go | 88 +- .../securego/gosec/v2/rules/base.go | 39 + .../securego/gosec/v2/rules/bind.go | 32 +- .../securego/gosec/v2/rules/blocklist.go | 10 +- .../gosec/v2/rules/decompression-bomb.go | 111 - .../gosec/v2/rules/decompression_bomb.go | 107 + ...ry-traversal.go => directory_traversal.go} | 15 +- .../securego/gosec/v2/rules/errors.go | 12 +- .../securego/gosec/v2/rules/fileperms.go | 60 +- .../gosec/v2/rules/hardcoded_credentials.go | 142 +- .../securego/gosec/v2/rules/http_serve.go | 30 +- .../gosec/v2/rules/implicit_aliasing.go | 81 +- .../gosec/v2/rules/integer_overflow.go | 68 +- .../securego/gosec/v2/rules/math_big_rat.go | 45 - .../securego/gosec/v2/rules/pprof.go | 12 +- .../securego/gosec/v2/rules/rand.go | 44 +- .../securego/gosec/v2/rules/readfile.go | 239 +- .../github.com/securego/gosec/v2/rules/rsa.go | 28 +- .../securego/gosec/v2/rules/rulelist.go | 3 +- .../gosec/v2/rules/secret_serialization.go | 455 + .../securego/gosec/v2/rules/slowloris.go | 12 +- .../github.com/securego/gosec/v2/rules/sql.go | 402 +- .../github.com/securego/gosec/v2/rules/ssh.go | 29 +- .../securego/gosec/v2/rules/ssrf.go | 20 +- .../securego/gosec/v2/rules/subproc.go | 81 +- .../securego/gosec/v2/rules/tempfiles.go | 41 +- .../securego/gosec/v2/rules/templates.go | 37 +- .../github.com/securego/gosec/v2/rules/tls.go | 324 +- .../securego/gosec/v2/rules/tls_config.go | 12 +- .../securego/gosec/v2/rules/trojansource.go | 87 + .../securego/gosec/v2/rules/unsafe.go | 30 +- .../securego/gosec/v2/rules/weakcrypto.go | 42 +- .../securego/gosec/v2/rules/weakcryptohash.go | 55 - .../v2/rules/weakdepricatedcryptohash.go | 57 - .../securego/gosec/v2/taint/analyzer.go | 147 + .../securego/gosec/v2/taint/taint.go | 1435 ++ .../shazow/go-diff/difflib/differ.go | 39 - .../github.com/sirupsen/logrus/.golangci.yml | 95 +- .../github.com/sirupsen/logrus/CHANGELOG.md | 4 +- vendor/github.com/sirupsen/logrus/README.md | 126 +- .../github.com/sirupsen/logrus/appveyor.yml | 16 +- vendor/github.com/sirupsen/logrus/entry.go | 25 +- vendor/github.com/sirupsen/logrus/hooks.go | 8 +- vendor/github.com/sirupsen/logrus/logger.go | 34 +- vendor/github.com/sirupsen/logrus/logrus.go | 20 +- .../sirupsen/logrus/terminal_check_bsd.go | 2 +- .../sirupsen/logrus/terminal_check_unix.go | 2 + .../sirupsen/logrus/terminal_check_wasi.go | 8 + .../sirupsen/logrus/terminal_check_wasip1.go | 8 + .../sirupsen/logrus/text_formatter.go | 3 +- vendor/github.com/sivchari/tenv/.golangci.yml | 38 - vendor/github.com/sivchari/tenv/README.md | 107 - .../github.com/sivchari/tenv/goreleaser.yaml | 26 - vendor/github.com/sivchari/tenv/tenv.go | 223 - vendor/github.com/sivchari/tenv/tenv.png | Bin 247119 -> 0 bytes .../github.com/sonatard/noctx/.golangci.yml | 61 +- .../github.com/sonatard/noctx/.goreleaser.yml | 4 +- vendor/github.com/sonatard/noctx/Makefile | 18 +- vendor/github.com/sonatard/noctx/README.md | 167 +- .../github.com/sonatard/noctx/ngfunc/main.go | 62 - .../sonatard/noctx/ngfunc/report.go | 29 - vendor/github.com/sonatard/noctx/noctx.go | 93 +- .../sonatard/noctx/reqwithoutctx/main.go | 14 - .../sonatard/noctx/reqwithoutctx/report.go | 26 - .../sonatard/noctx/reqwithoutctx/ssa.go | 184 - .../sonatard/noctx/{ngfunc => }/types.go | 22 +- vendor/github.com/spf13/afero/.editorconfig | 3 + vendor/github.com/spf13/afero/.golangci.yaml | 62 +- vendor/github.com/spf13/afero/README.md | 644 +- .../github.com/spf13/afero/copyOnWriteFs.go | 9 +- vendor/github.com/spf13/afero/iofs.go | 9 +- vendor/github.com/spf13/afero/lstater.go | 4 +- vendor/github.com/spf13/afero/mem/file.go | 22 +- vendor/github.com/spf13/afero/unionFile.go | 5 +- vendor/github.com/spf13/afero/util.go | 4 +- vendor/github.com/spf13/cast/README.md | 2 +- vendor/github.com/spf13/cast/caste.go | 98 +- vendor/github.com/spf13/cobra/.golangci.yml | 35 +- vendor/github.com/spf13/cobra/README.md | 24 +- vendor/github.com/spf13/cobra/SECURITY.md | 105 + vendor/github.com/spf13/cobra/command.go | 23 +- vendor/github.com/spf13/cobra/completions.go | 19 +- vendor/github.com/spf13/pflag/flag.go | 14 +- vendor/github.com/spf13/viper/.envrc | 4 +- vendor/github.com/spf13/viper/.golangci.yaml | 3 - vendor/github.com/spf13/viper/README.md | 21 +- vendor/github.com/spf13/viper/UPDATES.md | 126 + vendor/github.com/spf13/viper/encoding.go | 181 + vendor/github.com/spf13/viper/experimental.go | 8 + vendor/github.com/spf13/viper/file.go | 54 +- vendor/github.com/spf13/viper/file_finder.go | 38 - vendor/github.com/spf13/viper/finder.go | 55 + vendor/github.com/spf13/viper/flake.lock | 303 +- vendor/github.com/spf13/viper/flake.nix | 2 +- .../spf13/viper/internal/encoding/decoder.go | 61 - .../spf13/viper/internal/encoding/encoder.go | 60 - .../spf13/viper/internal/encoding/error.go | 7 - .../viper/internal/encoding/hcl/codec.go | 40 - .../viper/internal/encoding/ini/codec.go | 99 - .../viper/internal/encoding/ini/map_utils.go | 74 - .../internal/encoding/javaproperties/codec.go | 86 - .../encoding/javaproperties/map_utils.go | 74 - .../spf13/viper/internal/features/finder.go | 5 + .../viper/internal/features/finder_default.go | 5 + vendor/github.com/spf13/viper/logger.go | 39 +- vendor/github.com/spf13/viper/remote.go | 256 + vendor/github.com/spf13/viper/util.go | 11 +- vendor/github.com/spf13/viper/viper.go | 557 +- .../pkg/analyzer/analyzer.go | 29 +- .../tdakkota/asciicheck/asciicheck.go | 49 - vendor/github.com/tetafro/godot/.golangci.yml | 3 +- .../github.com/tetafro/godot/.goreleaser.yml | 2 + vendor/github.com/tetafro/godot/README.md | 1 + vendor/github.com/tetafro/godot/checks.go | 63 +- vendor/github.com/tetafro/godot/comment.go | 19 + .../tetafro/godot/{getters.go => file.go} | 89 +- vendor/github.com/tetafro/godot/godot.go | 12 +- vendor/github.com/tetafro/godot/settings.go | 2 + .../bodyclose/passes/bodyclose/bodyclose.go | 62 +- .../timonwong/loggercheck/.golangci.yml | 140 +- .../timonwong/loggercheck/README.md | 6 +- .../internal/checkers/printf/printf.go | 13 +- .../loggercheck/internal/rules/rules.go | 16 +- .../timonwong/loggercheck/loggercheck.go | 19 +- .../wrapcheck/v2/wrapcheck/wrapcheck.go | 42 +- .../github.com/ultraware/funlen/.golangci.yml | 2 + vendor/github.com/ultraware/funlen/README.md | 20 + vendor/github.com/ultraware/funlen/funlen.go | 115 + vendor/github.com/ultraware/funlen/main.go | 124 - .../github.com/ultraware/whitespace/README.md | 2 +- .../ultraware/whitespace/whitespace.go | 149 +- vendor/github.com/uudashr/gocognit/README.md | 119 +- vendor/github.com/uudashr/gocognit/doc.go | 3 +- .../github.com/uudashr/gocognit/gocognit.go | 204 +- .../github.com/uudashr/gocognit/rangeiter.go | 47 + vendor/github.com/uudashr/gocognit/recv.go | 1 + .../uudashr/gocognit/recv_pre118.go | 1 + vendor/github.com/uudashr/iface/LICENSE | 2 +- .../github.com/uudashr/iface/identical/doc.go | 4 +- .../uudashr/iface/identical/identical.go | 33 +- .../iface/internal/directive/directive.go | 2 +- vendor/github.com/uudashr/iface/opaque/doc.go | 4 +- .../github.com/uudashr/iface/opaque/opaque.go | 43 +- .../uudashr/iface/unexported/doc.go | 4 + .../uudashr/iface/unexported/unexported.go | 214 + vendor/github.com/uudashr/iface/unused/doc.go | 4 +- .../github.com/uudashr/iface/unused/unused.go | 54 +- .../xen0n/gosmopolitan/.golangci.yml | 6 +- vendor/github.com/xo/terminfo/.gitignore | 9 + .../mapstructure => xo/terminfo}/LICENSE | 10 +- vendor/github.com/xo/terminfo/README.md | 139 + vendor/github.com/xo/terminfo/caps.go | 31 + vendor/github.com/xo/terminfo/capvals.go | 1525 ++ vendor/github.com/xo/terminfo/color.go | 88 + vendor/github.com/xo/terminfo/dec.go | 245 + vendor/github.com/xo/terminfo/load.go | 64 + vendor/github.com/xo/terminfo/param.go | 405 + vendor/github.com/xo/terminfo/stack.go | 48 + vendor/github.com/xo/terminfo/terminfo.go | 479 + vendor/go-simpler.org/musttag/.golangci.yaml | 18 + vendor/go-simpler.org/musttag/.golangci.yml | 23 - vendor/go-simpler.org/musttag/README.md | 10 +- vendor/go-simpler.org/musttag/builtins.go | 8 +- vendor/go-simpler.org/musttag/musttag.go | 57 +- vendor/go-simpler.org/sloglint/.golangci.yaml | 18 + vendor/go-simpler.org/sloglint/.golangci.yml | 22 - vendor/go-simpler.org/sloglint/README.md | 23 +- vendor/go-simpler.org/sloglint/sloglint.go | 270 +- vendor/go.augendre.info/arangolint/LICENSE | 21 + .../arangolint/pkg/analyzer/analyzer.go | 1336 ++ .../fatcontext/LICENSE | 0 .../fatcontext/pkg/analyzer/analyzer.go | 395 + .../auto/sdk/internal/telemetry/id.go | 2 +- .../auto/sdk/internal/telemetry/number.go | 2 +- .../auto/sdk/internal/telemetry/span.go | 70 +- .../auto/sdk/internal/telemetry/status.go | 10 +- .../auto/sdk/internal/telemetry/traces.go | 4 +- .../auto/sdk/internal/telemetry/value.go | 14 +- vendor/go.opentelemetry.io/auto/sdk/span.go | 25 +- vendor/go.opentelemetry.io/auto/sdk/tracer.go | 29 +- .../go.opentelemetry.io/otel/.codespellignore | 2 + vendor/go.opentelemetry.io/otel/.golangci.yml | 31 +- vendor/go.opentelemetry.io/otel/.lycheeignore | 7 + vendor/go.opentelemetry.io/otel/CHANGELOG.md | 161 +- vendor/go.opentelemetry.io/otel/CODEOWNERS | 2 +- .../go.opentelemetry.io/otel/CONTRIBUTING.md | 511 +- vendor/go.opentelemetry.io/otel/LICENSE | 30 + vendor/go.opentelemetry.io/otel/Makefile | 10 +- vendor/go.opentelemetry.io/otel/README.md | 16 +- vendor/go.opentelemetry.io/otel/RELEASING.md | 54 +- .../otel/SECURITY-INSIGHTS.yml | 203 + vendor/go.opentelemetry.io/otel/VERSIONING.md | 2 +- .../otel/attribute/encoder.go | 14 +- .../otel/attribute/filter.go | 8 +- .../otel/attribute/hash.go | 92 + .../otel/attribute/internal/attribute.go | 16 +- .../otel/attribute/internal/xxhash/xxhash.go | 64 + .../otel/attribute/iterator.go | 7 +- .../go.opentelemetry.io/otel/attribute/key.go | 2 +- .../go.opentelemetry.io/otel/attribute/kv.go | 2 +- .../go.opentelemetry.io/otel/attribute/set.go | 151 +- .../otel/attribute/type_string.go | 5 +- .../otel/attribute/value.go | 8 +- .../otel/baggage/baggage.go | 16 +- .../go.opentelemetry.io/otel/codes/codes.go | 4 +- .../otel/dependencies.Dockerfile | 4 +- .../otel/internal/global/internal_logging.go | 8 +- .../otel/internal/global/meter.go | 2 +- .../otel/internal/global/trace.go | 1 + vendor/go.opentelemetry.io/otel/metric.go | 2 +- .../go.opentelemetry.io/otel/metric/LICENSE | 30 + .../go.opentelemetry.io/otel/metric/config.go | 38 +- .../otel/propagation/baggage.go | 6 +- .../otel/propagation/propagation.go | 4 +- .../otel/propagation/trace_context.go | 8 +- vendor/go.opentelemetry.io/otel/sdk/LICENSE | 30 + .../otel/sdk/internal/x/features.go | 39 + .../otel/sdk/internal/x/x.go | 48 +- .../otel/sdk/resource/builtin.go | 4 +- .../otel/sdk/resource/container.go | 4 +- .../otel/sdk/resource/env.go | 2 +- .../otel/sdk/resource/host_id.go | 4 +- .../otel/sdk/resource/host_id_bsd.go | 1 - .../otel/sdk/resource/host_id_linux.go | 1 - .../otel/sdk/resource/host_id_unsupported.go | 1 - .../otel/sdk/resource/host_id_windows.go | 1 - .../otel/sdk/resource/os.go | 6 +- .../otel/sdk/resource/os_release_unix.go | 7 +- .../otel/sdk/resource/os_unix.go | 1 - .../otel/sdk/resource/os_unsupported.go | 1 - .../otel/sdk/resource/process.go | 18 +- .../otel/sdk/resource/resource.go | 4 +- .../otel/sdk/trace/batch_span_processor.go | 55 +- .../go.opentelemetry.io/otel/sdk/trace/doc.go | 3 + .../otel/sdk/trace/id_generator.go | 4 +- .../otel/sdk/{ => trace}/internal/env/env.go | 2 +- .../internal/observ/batch_span_processor.go | 119 + .../otel/sdk/trace/internal/observ/doc.go | 6 + .../internal/observ/simple_span_processor.go | 97 + .../otel/sdk/trace/internal/observ/tracer.go | 223 + .../otel/sdk/trace/provider.go | 14 +- .../otel/sdk/trace/sampling.go | 8 +- .../otel/sdk/trace/simple_span_processor.go | 37 +- .../otel/sdk/trace/snapshot.go | 2 +- .../otel/sdk/trace/span.go | 30 +- .../otel/sdk/trace/span_limits.go | 2 +- .../otel/sdk/trace/tracer.go | 32 +- .../otel/sdk/trace/version.go | 9 - .../go.opentelemetry.io/otel/sdk/version.go | 2 +- .../otel/semconv/v1.26.0/README.md | 3 - .../otel/semconv/v1.26.0/attribute_group.go | 8996 --------- .../otel/semconv/v1.26.0/metric.go | 1307 -- .../otel/semconv/v1.34.0/attribute_group.go | 210 + .../otel/semconv/v1.34.0/error_type.go | 31 + .../otel/semconv/v1.34.0/httpconv/metric.go | 25 +- .../otel/semconv/v1.37.0/MIGRATION.md | 41 + .../otel/semconv/v1.37.0/README.md | 3 + .../otel/semconv/v1.37.0/attribute_group.go | 15193 ++++++++++++++++ .../otel/semconv/{v1.26.0 => v1.37.0}/doc.go | 4 +- .../otel/semconv/v1.37.0/error_type.go | 56 + .../semconv/{v1.26.0 => v1.37.0}/exception.go | 2 +- .../otel/semconv/v1.37.0/otelconv/metric.go | 2264 +++ .../semconv/{v1.26.0 => v1.37.0}/schema.go | 4 +- vendor/go.opentelemetry.io/otel/trace/LICENSE | 30 + vendor/go.opentelemetry.io/otel/trace/auto.go | 6 +- .../go.opentelemetry.io/otel/trace/config.go | 49 +- vendor/go.opentelemetry.io/otel/trace/hex.go | 38 + .../otel/trace/internal/telemetry/attr.go | 2 +- .../otel/trace/internal/telemetry/id.go | 6 +- .../otel/trace/internal/telemetry/value.go | 4 +- vendor/go.opentelemetry.io/otel/trace/noop.go | 4 +- .../otel/trace/noop/noop.go | 2 +- vendor/go.opentelemetry.io/otel/trace/span.go | 4 + .../go.opentelemetry.io/otel/trace/trace.go | 156 +- .../otel/trace/tracestate.go | 6 +- vendor/go.opentelemetry.io/otel/version.go | 2 +- vendor/go.opentelemetry.io/otel/versions.yaml | 27 +- .../automaxprocs/internal/cgroups/cgroup.go | 79 - .../automaxprocs/internal/cgroups/cgroups.go | 118 - .../automaxprocs/internal/cgroups/cgroups2.go | 176 - .../automaxprocs/internal/cgroups/doc.go | 23 - .../automaxprocs/internal/cgroups/errors.go | 52 - .../internal/cgroups/mountpoint.go | 171 - .../automaxprocs/internal/cgroups/subsys.go | 103 - .../internal/runtime/cpu_quota_linux.go | 75 - .../internal/runtime/cpu_quota_unsupported.go | 31 - .../automaxprocs/internal/runtime/runtime.go | 40 - .../automaxprocs/maxprocs/maxprocs.go | 139 - .../automaxprocs/maxprocs/version.go | 24 - .../x/exp/constraints/constraints.go | 54 - vendor/golang.org/x/exp/maps/maps.go | 86 - vendor/golang.org/x/exp/slog/attr.go | 102 - vendor/golang.org/x/exp/slog/doc.go | 316 - vendor/golang.org/x/exp/slog/handler.go | 577 - .../x/exp/slog/internal/buffer/buffer.go | 84 - .../x/exp/slog/internal/ignorepc.go | 9 - vendor/golang.org/x/exp/slog/json_handler.go | 336 - vendor/golang.org/x/exp/slog/level.go | 201 - vendor/golang.org/x/exp/slog/logger.go | 343 - vendor/golang.org/x/exp/slog/noplog.bench | 36 - vendor/golang.org/x/exp/slog/record.go | 207 - vendor/golang.org/x/exp/slog/text_handler.go | 161 - vendor/golang.org/x/exp/slog/value.go | 456 - vendor/golang.org/x/exp/slog/value_119.go | 53 - vendor/golang.org/x/exp/slog/value_120.go | 39 - vendor/golang.org/x/exp/typeparams/common.go | 2 +- vendor/golang.org/x/mod/sumdb/dirhash/hash.go | 135 + vendor/golang.org/x/net/html/iter.go | 2 - vendor/golang.org/x/net/html/node.go | 1 + .../golang.org/x/net/html/nodetype_string.go | 31 + .../x/net/http2/client_priority_go126.go | 20 + .../x/net/http2/client_priority_go127.go | 13 + vendor/golang.org/x/net/http2/frame.go | 188 +- vendor/golang.org/x/net/http2/http2.go | 2 + vendor/golang.org/x/net/http2/server.go | 86 +- vendor/golang.org/x/net/http2/transport.go | 7 +- .../net/http2/writesched_priority_rfc7540.go | 4 + .../x/net/internal/httpsfv/httpsfv.go | 665 + vendor/golang.org/x/oauth2/deviceauth.go | 31 +- vendor/golang.org/x/oauth2/oauth2.go | 5 +- vendor/golang.org/x/oauth2/pkce.go | 2 +- vendor/golang.org/x/oauth2/token.go | 2 +- vendor/golang.org/x/oauth2/transport.go | 2 +- vendor/golang.org/x/sys/unix/ioctl_signed.go | 11 +- .../golang.org/x/sys/unix/ioctl_unsigned.go | 11 +- .../golang.org/x/sys/unix/syscall_solaris.go | 8 - vendor/golang.org/x/sys/unix/syscall_unix.go | 10 +- .../x/sys/windows/syscall_windows.go | 1 + .../golang.org/x/sys/windows/types_windows.go | 85 + .../x/sys/windows/zsyscall_windows.go | 7 + vendor/golang.org/x/text/cases/cases.go | 162 + vendor/golang.org/x/text/cases/context.go | 376 + vendor/golang.org/x/text/cases/fold.go | 34 + vendor/golang.org/x/text/cases/icu.go | 61 + vendor/golang.org/x/text/cases/info.go | 82 + vendor/golang.org/x/text/cases/map.go | 816 + .../golang.org/x/text/cases/tables15.0.0.go | 2527 +++ .../golang.org/x/text/cases/tables17.0.0.go | 2642 +++ vendor/golang.org/x/text/cases/trieval.go | 217 + .../x/text/message/catalog/catalog.go | 2 +- .../golang.org/x/text/message/catalog/dict.go | 6 +- .../golang.org/x/text/message/catalog/go19.go | 15 - .../x/text/message/catalog/gopre19.go | 23 - .../x/text/secure/bidirule/bidirule.go | 4 + .../x/text/secure/bidirule/bidirule10.0.0.go | 11 - .../x/text/secure/bidirule/bidirule9.0.0.go | 14 - .../x/text/unicode/bidi/tables10.0.0.go | 1815 -- .../x/text/unicode/bidi/tables11.0.0.go | 1887 -- .../x/text/unicode/bidi/tables12.0.0.go | 1923 -- .../x/text/unicode/bidi/tables13.0.0.go | 1955 -- .../x/text/unicode/bidi/tables15.0.0.go | 2 +- .../x/text/unicode/bidi/tables17.0.0.go | 2135 +++ .../x/text/unicode/bidi/tables9.0.0.go | 1781 -- .../x/text/unicode/norm/forminfo.go | 26 +- .../x/text/unicode/norm/tables10.0.0.go | 7657 -------- .../x/text/unicode/norm/tables11.0.0.go | 7693 -------- .../x/text/unicode/norm/tables12.0.0.go | 7710 -------- .../x/text/unicode/norm/tables15.0.0.go | 2820 +-- .../norm/{tables13.0.0.go => tables17.0.0.go} | 6716 +++---- .../x/text/unicode/norm/tables9.0.0.go | 7637 -------- .../golang.org/x/text/width/tables10.0.0.go | 1328 -- .../golang.org/x/text/width/tables11.0.0.go | 1340 -- .../golang.org/x/text/width/tables12.0.0.go | 1360 -- .../golang.org/x/text/width/tables15.0.0.go | 2 +- .../{tables13.0.0.go => tables17.0.0.go} | 533 +- vendor/golang.org/x/text/width/tables9.0.0.go | 1296 -- vendor/golang.org/x/time/rate/rate.go | 2 +- .../go/analysis/passes/hostport/hostport.go | 210 + .../go/analysis/passes/httpmux/httpmux.go | 184 + .../tools/go/analysis/passes/modernize/any.go | 53 + .../go/analysis/passes/modernize/bloop.go | 244 + .../tools/go/analysis/passes/modernize/doc.go | 541 + .../analysis/passes/modernize/errorsastype.go | 243 + .../analysis/passes/modernize/fmtappendf.go | 112 + .../go/analysis/passes/modernize/forvar.go | 113 + .../go/analysis/passes/modernize/maps.go | 296 + .../go/analysis/passes/modernize/minmax.go | 436 + .../go/analysis/passes/modernize/modernize.go | 146 + .../go/analysis/passes/modernize/newexpr.go | 202 + .../go/analysis/passes/modernize/omitzero.go | 132 + .../go/analysis/passes/modernize/plusbuild.go | 86 + .../go/analysis/passes/modernize/rangeint.go | 369 + .../go/analysis/passes/modernize/reflect.go | 196 + .../go/analysis/passes/modernize/slices.go | 292 + .../passes/modernize/slicescontains.go | 433 + .../analysis/passes/modernize/slicesdelete.go | 177 + .../go/analysis/passes/modernize/sortslice.go | 121 + .../analysis/passes/modernize/stditerators.go | 409 + .../passes/modernize/stringsbuilder.go | 382 + .../analysis/passes/modernize/stringscut.go | 591 + .../passes/modernize/stringscutprefix.go | 257 + .../analysis/passes/modernize/stringsseq.go | 140 + .../passes/modernize/testingcontext.go | 250 + .../analysis/passes/modernize/unsafefuncs.go | 210 + .../go/analysis/passes/modernize/waitgroup.go | 174 + .../tools/go/analysis/passes/printf/printf.go | 2 +- .../analysis/passes/stdversion/stdversion.go | 136 + .../tools/go/analysis/passes/waitgroup/doc.go | 34 + .../go/analysis/passes/waitgroup/waitgroup.go | 91 + .../x/tools/go/ast/inspector/cursor.go | 34 +- .../x/tools/go/ast/inspector/inspector.go | 4 +- .../x/tools/go/ast/inspector/iter.go | 36 +- .../x/tools/go/callgraph/callgraph.go | 124 + .../x/tools/go/callgraph/cha/cha.go | 77 + .../go/callgraph/internal/chautil/lazy.go | 96 + .../golang.org/x/tools/go/callgraph/util.go | 180 + .../x/tools/go/packages/packages.go | 15 +- vendor/golang.org/x/tools/go/ssa/subst.go | 15 +- .../x/tools/go/types/objectpath/objectpath.go | 16 +- .../x/tools/internal/aliases/aliases.go | 30 +- .../x/tools/internal/aliases/aliases_go122.go | 80 - .../internal/analysis/analyzerutil/version.go | 8 +- .../x/tools/internal/astutil/util.go | 87 +- .../x/tools/internal/event/core/event.go | 23 +- .../x/tools/internal/event/keys/keys.go | 439 +- .../x/tools/internal/event/label/label.go | 11 +- .../x/tools/internal/gcimporter/iexport.go | 11 +- .../x/tools/internal/gcimporter/iimport.go | 4 +- .../tools/internal/gcimporter/ureader_yes.go | 4 +- .../x/tools/internal/goplsexport/export.go | 17 + .../x/tools/internal/refactor/delete.go | 10 +- .../x/tools/internal/stdlib/deps.go | 2 +- .../x/tools/internal/typeparams/free.go | 4 +- .../typesinternal/typeindex/typeindex.go | 8 +- .../x/tools/internal/typesinternal/types.go | 3 +- .../gomodules.xyz/jsonpatch/v2/jsonpatch.go | 17 +- .../internal/editionssupport/editions.go | 2 +- .../protobuf/internal/encoding/tag/tag.go | 11 +- .../protobuf/internal/encoding/text/decode.go | 115 +- .../protobuf/internal/filedesc/desc.go | 53 +- .../protobuf/internal/filedesc/desc_init.go | 14 + .../protobuf/internal/filedesc/desc_lazy.go | 42 +- .../protobuf/internal/filedesc/editions.go | 12 +- .../protobuf/internal/genid/descriptor_gen.go | 1 + .../protobuf/internal/impl/codec_map.go | 6 + .../protobuf/internal/impl/decode.go | 3 +- .../protobuf/internal/impl/validate.go | 26 + .../protobuf/internal/version/version.go | 2 +- .../protobuf/proto/decode.go | 10 +- .../protobuf/reflect/protodesc/desc.go | 29 +- .../protobuf/reflect/protodesc/desc_init.go | 2 + .../protobuf/reflect/protodesc/editions.go | 4 +- .../protobuf/reflect/protodesc/proto.go | 37 +- .../types/descriptorpb/descriptor.pb.go | 13 +- .../types/known/timestamppb/timestamp.pb.go | 13 +- vendor/gopkg.in/ini.v1/.golangci.yml | 51 +- vendor/gopkg.in/ini.v1/README.md | 10 +- vendor/gopkg.in/ini.v1/key.go | 4 +- vendor/gopkg.in/ini.v1/parser.go | 14 +- .../go/tools/analysis/callcheck/callcheck.go | 6 +- .../honnef.co/go/tools/analysis/code/code.go | 12 +- .../honnef.co/go/tools/analysis/code/visit.go | 102 + .../analysis/facts/deprecated/deprecated.go | 8 +- .../analysis/facts/directives/directives.go | 4 +- .../analysis/facts/generated/generated.go | 4 +- .../tools/analysis/facts/nilness/nilness.go | 4 +- .../go/tools/analysis/facts/purity/purity.go | 8 +- .../tools/analysis/facts/tokenfile/token.go | 4 +- .../analysis/facts/typedness/typedness.go | 4 +- .../honnef.co/go/tools/analysis/lint/lint.go | 6 +- .../go/tools/analysis/report/report.go | 2 +- vendor/honnef.co/go/tools/config/config.go | 20 +- vendor/honnef.co/go/tools/config/example.conf | 1 + vendor/honnef.co/go/tools/go/ir/UPSTREAM | 2 +- vendor/honnef.co/go/tools/go/ir/builder.go | 37 +- vendor/honnef.co/go/tools/go/ir/create.go | 4 + vendor/honnef.co/go/tools/go/ir/dom.go | 4 +- vendor/honnef.co/go/tools/go/ir/emit.go | 23 +- vendor/honnef.co/go/tools/go/ir/exits.go | 369 - vendor/honnef.co/go/tools/go/ir/html.go | 57 +- .../honnef.co/go/tools/go/ir/irutil/util.go | 8 +- vendor/honnef.co/go/tools/go/ir/lift.go | 6 +- vendor/honnef.co/go/tools/go/ir/methods.go | 6 +- vendor/honnef.co/go/tools/go/ir/mode.go | 2 +- vendor/honnef.co/go/tools/go/ir/print.go | 4 +- vendor/honnef.co/go/tools/go/ir/sanity.go | 38 +- vendor/honnef.co/go/tools/go/ir/ssa.go | 18 +- vendor/honnef.co/go/tools/go/ir/util.go | 2 +- vendor/honnef.co/go/tools/go/ir/wrappers.go | 3 +- .../go/tools/go/types/typeutil/typeparams.go | 8 +- .../go/tools/go/types/typeutil/upstream.go | 2 +- .../go/tools/go/types/typeutil/util.go | 2 +- .../analysisinternal/typeindex/typeindex.go | 33 + .../tools/internal/passes/buildir/buildir.go | 36 +- .../go/tools/internal/sharedcheck/lint.go | 4 +- .../typesinternal/typeindex/typeindex.go | 226 + .../go/tools/knowledge/deprecated.go | 61 +- vendor/honnef.co/go/tools/pattern/convert.go | 90 +- vendor/honnef.co/go/tools/pattern/lexer.go | 76 +- vendor/honnef.co/go/tools/pattern/match.go | 52 +- vendor/honnef.co/go/tools/pattern/parser.go | 534 +- vendor/honnef.co/go/tools/pattern/pattern.go | 37 +- vendor/honnef.co/go/tools/printf/fuzz.go | 1 - vendor/honnef.co/go/tools/printf/printf.go | 4 +- .../honnef.co/go/tools/quickfix/analysis.go | 34 + vendor/honnef.co/go/tools/quickfix/doc.go | 9 + .../go/tools/quickfix/qf1001/qf1001.go | 123 + .../go/tools/quickfix/qf1002/qf1002.go | 146 + .../go/tools/quickfix/qf1003/qf1003.go | 205 + .../go/tools/quickfix/qf1004/qf1004.go | 65 + .../go/tools/quickfix/qf1005/qf1005.go | 111 + .../go/tools/quickfix/qf1006/qf1006.go | 61 + .../go/tools/quickfix/qf1007/qf1007.go | 92 + .../go/tools/quickfix/qf1008/qf1008.go | 147 + .../go/tools/quickfix/qf1009/qf1009.go | 51 + .../go/tools/quickfix/qf1010/qf1010.go | 75 + .../go/tools/quickfix/qf1011/qf1011.go | 21 + .../go/tools/quickfix/qf1012/qf1012.go | 128 + .../honnef.co/go/tools/simple/s1000/s1000.go | 2 +- .../honnef.co/go/tools/simple/s1001/s1001.go | 27 +- .../honnef.co/go/tools/simple/s1002/s1002.go | 4 +- .../honnef.co/go/tools/simple/s1003/s1003.go | 4 +- .../honnef.co/go/tools/simple/s1004/s1004.go | 17 +- .../honnef.co/go/tools/simple/s1005/s1005.go | 12 +- .../honnef.co/go/tools/simple/s1006/s1006.go | 2 +- .../honnef.co/go/tools/simple/s1007/s1007.go | 45 +- .../honnef.co/go/tools/simple/s1008/s1008.go | 35 +- .../honnef.co/go/tools/simple/s1009/s1009.go | 143 +- .../honnef.co/go/tools/simple/s1010/s1010.go | 20 +- .../honnef.co/go/tools/simple/s1011/s1011.go | 25 +- .../honnef.co/go/tools/simple/s1012/s1012.go | 19 +- .../honnef.co/go/tools/simple/s1016/s1016.go | 14 +- .../honnef.co/go/tools/simple/s1017/s1017.go | 2 +- .../honnef.co/go/tools/simple/s1018/s1018.go | 20 +- .../honnef.co/go/tools/simple/s1019/s1019.go | 2 +- .../honnef.co/go/tools/simple/s1020/s1020.go | 20 +- .../honnef.co/go/tools/simple/s1021/s1021.go | 4 +- .../honnef.co/go/tools/simple/s1023/s1023.go | 2 +- .../honnef.co/go/tools/simple/s1024/s1024.go | 30 +- .../honnef.co/go/tools/simple/s1025/s1025.go | 36 +- .../honnef.co/go/tools/simple/s1028/s1028.go | 21 +- .../honnef.co/go/tools/simple/s1030/s1030.go | 16 +- .../honnef.co/go/tools/simple/s1031/s1031.go | 20 +- .../honnef.co/go/tools/simple/s1032/s1032.go | 2 +- .../honnef.co/go/tools/simple/s1033/s1033.go | 19 +- .../honnef.co/go/tools/simple/s1034/s1034.go | 14 +- .../honnef.co/go/tools/simple/s1035/s1035.go | 38 +- .../honnef.co/go/tools/simple/s1036/s1036.go | 20 +- .../honnef.co/go/tools/simple/s1037/s1037.go | 32 +- .../honnef.co/go/tools/simple/s1038/s1038.go | 8 +- .../honnef.co/go/tools/simple/s1039/s1039.go | 15 +- .../honnef.co/go/tools/simple/s1040/s1040.go | 2 +- .../go/tools/staticcheck/fakejson/encode.go | 10 +- .../go/tools/staticcheck/fakexml/marshal.go | 7 +- .../go/tools/staticcheck/fakexml/typeinfo.go | 11 +- .../go/tools/staticcheck/sa1001/sa1001.go | 33 +- .../go/tools/staticcheck/sa1003/sa1003.go | 2 +- .../go/tools/staticcheck/sa1004/sa1004.go | 20 +- .../go/tools/staticcheck/sa1005/sa1005.go | 25 +- .../go/tools/staticcheck/sa1006/sa1006.go | 68 +- .../go/tools/staticcheck/sa1008/sa1008.go | 6 +- .../go/tools/staticcheck/sa1012/sa1012.go | 23 +- .../go/tools/staticcheck/sa1013/sa1013.go | 19 +- .../go/tools/staticcheck/sa1015/sa1015.go | 2 +- .../go/tools/staticcheck/sa1016/sa1016.go | 29 +- .../go/tools/staticcheck/sa1019/sa1019.go | 2 +- .../go/tools/staticcheck/sa1023/sa1023.go | 2 +- .../go/tools/staticcheck/sa1025/sa1025.go | 2 +- .../go/tools/staticcheck/sa1026/sa1026.go | 6 +- .../go/tools/staticcheck/sa2000/sa2000.go | 14 +- .../go/tools/staticcheck/sa2001/sa2001.go | 2 +- .../go/tools/staticcheck/sa2002/sa2002.go | 2 +- .../go/tools/staticcheck/sa2003/sa2003.go | 2 +- .../go/tools/staticcheck/sa3000/sa3000.go | 2 +- .../go/tools/staticcheck/sa3001/sa3001.go | 28 +- .../go/tools/staticcheck/sa4000/sa4000.go | 103 +- .../go/tools/staticcheck/sa4001/sa4001.go | 2 +- .../go/tools/staticcheck/sa4003/sa4003.go | 17 +- .../go/tools/staticcheck/sa4004/sa4004.go | 2 +- .../go/tools/staticcheck/sa4005/sa4005.go | 2 +- .../go/tools/staticcheck/sa4006/sa4006.go | 2 +- .../go/tools/staticcheck/sa4008/sa4008.go | 2 +- .../go/tools/staticcheck/sa4009/sa4009.go | 2 +- .../go/tools/staticcheck/sa4010/sa4010.go | 2 +- .../go/tools/staticcheck/sa4011/sa4011.go | 2 +- .../go/tools/staticcheck/sa4012/sa4012.go | 2 +- .../go/tools/staticcheck/sa4013/sa4013.go | 16 +- .../go/tools/staticcheck/sa4014/sa4014.go | 2 +- .../go/tools/staticcheck/sa4016/sa4016.go | 2 +- .../go/tools/staticcheck/sa4017/sa4017.go | 5 +- .../go/tools/staticcheck/sa4018/sa4018.go | 2 +- .../go/tools/staticcheck/sa4019/sa4019.go | 4 +- .../go/tools/staticcheck/sa4020/sa4020.go | 6 +- .../go/tools/staticcheck/sa4021/sa4021.go | 14 +- .../go/tools/staticcheck/sa4022/sa4022.go | 14 +- .../go/tools/staticcheck/sa4023/sa4023.go | 4 +- .../go/tools/staticcheck/sa4024/sa4024.go | 14 +- .../go/tools/staticcheck/sa4025/sa4025.go | 14 +- .../go/tools/staticcheck/sa4026/sa4026.go | 18 +- .../go/tools/staticcheck/sa4027/sa4027.go | 17 +- .../go/tools/staticcheck/sa4028/sa4028.go | 14 +- .../go/tools/staticcheck/sa4029/sa4029.go | 19 +- .../go/tools/staticcheck/sa4030/sa4030.go | 32 +- .../go/tools/staticcheck/sa4031/sa4031.go | 2 +- .../go/tools/staticcheck/sa4032/sa4032.go | 7 +- .../go/tools/staticcheck/sa5000/sa5000.go | 2 +- .../go/tools/staticcheck/sa5001/sa5001.go | 2 +- .../go/tools/staticcheck/sa5002/sa5002.go | 2 +- .../go/tools/staticcheck/sa5003/sa5003.go | 2 +- .../go/tools/staticcheck/sa5004/sa5004.go | 26 +- .../go/tools/staticcheck/sa5005/sa5005.go | 2 +- .../go/tools/staticcheck/sa5007/sa5007.go | 2 +- .../go/tools/staticcheck/sa5008/jsonv2.go | 288 + .../go/tools/staticcheck/sa5008/sa5008.go | 63 +- .../go/tools/staticcheck/sa5009/sa5009.go | 4 +- .../go/tools/staticcheck/sa5010/sa5010.go | 29 +- .../go/tools/staticcheck/sa5011/sa5011.go | 2 +- .../go/tools/staticcheck/sa5012/sa5012.go | 2 +- .../go/tools/staticcheck/sa6001/sa6001.go | 2 +- .../go/tools/staticcheck/sa6005/sa6005.go | 17 +- .../go/tools/staticcheck/sa6006/sa6006.go | 15 +- .../go/tools/staticcheck/sa9001/sa9001.go | 2 +- .../go/tools/staticcheck/sa9002/sa9002.go | 4 +- .../go/tools/staticcheck/sa9003/sa9003.go | 2 +- .../go/tools/staticcheck/sa9004/sa9004.go | 6 +- .../go/tools/staticcheck/sa9006/sa9006.go | 12 +- .../go/tools/staticcheck/sa9007/sa9007.go | 4 +- .../go/tools/staticcheck/sa9008/sa9008.go | 20 +- .../go/tools/stylecheck/st1000/st1000.go | 2 +- .../go/tools/stylecheck/st1001/st1001.go | 2 +- .../go/tools/stylecheck/st1003/st1003.go | 6 +- .../go/tools/stylecheck/st1005/st1005.go | 8 +- .../go/tools/stylecheck/st1006/st1006.go | 2 +- .../go/tools/stylecheck/st1008/st1008.go | 2 +- .../go/tools/stylecheck/st1011/st1011.go | 2 +- .../go/tools/stylecheck/st1012/st1012.go | 2 +- .../go/tools/stylecheck/st1013/st1013.go | 44 +- .../go/tools/stylecheck/st1015/st1015.go | 2 +- .../go/tools/stylecheck/st1016/st1016.go | 2 +- .../go/tools/stylecheck/st1017/st1017.go | 19 +- .../go/tools/stylecheck/st1018/st1018.go | 2 +- .../go/tools/stylecheck/st1019/st1019.go | 21 +- .../go/tools/stylecheck/st1020/st1020.go | 2 +- .../go/tools/stylecheck/st1021/st1021.go | 2 +- .../go/tools/stylecheck/st1022/st1022.go | 2 +- .../honnef.co/go/tools/unused/implements.go | 6 +- vendor/honnef.co/go/tools/unused/serialize.go | 2 +- vendor/honnef.co/go/tools/unused/unused.go | 105 +- vendor/k8s.io/api/admission/v1/doc.go | 2 + .../k8s.io/api/admission/v1/generated.pb.go | 175 +- .../k8s.io/api/admission/v1/generated.proto | 47 +- .../admission/v1/generated.protomessage.pb.go | 28 + vendor/k8s.io/api/admission/v1/types.go | 47 +- .../v1/types_swagger_doc_generated.go | 46 +- .../admission/v1/zz_generated.model_name.go | 37 + vendor/k8s.io/api/admission/v1beta1/doc.go | 1 + .../api/admission/v1beta1/generated.pb.go | 175 +- .../api/admission/v1beta1/generated.proto | 47 +- .../v1beta1/generated.protomessage.pb.go | 28 + vendor/k8s.io/api/admission/v1beta1/types.go | 47 +- .../v1beta1/types_swagger_doc_generated.go | 46 +- .../v1beta1/zz_generated.model_name.go | 37 + .../api/admissionregistration/v1/doc.go | 2 + .../admissionregistration/v1/generated.pb.go | 937 +- .../v1/generated.protomessage.pb.go | 76 + .../api/admissionregistration/v1/types.go | 9 +- .../v1/zz_generated.model_name.go | 157 + .../api/admissionregistration/v1alpha1/doc.go | 2 + .../v1alpha1/generated.pb.go | 890 +- .../v1alpha1/generated.protomessage.pb.go | 74 + .../admissionregistration/v1alpha1/types.go | 3 +- .../v1alpha1/zz_generated.model_name.go | 152 + .../api/admissionregistration/v1beta1/doc.go | 2 + .../v1beta1/generated.pb.go | 1149 +- .../v1beta1/generated.proto | 1 - .../v1beta1/generated.protomessage.pb.go | 90 + .../admissionregistration/v1beta1/types.go | 12 +- .../v1beta1/zz_generated.model_name.go | 192 + vendor/k8s.io/api/apidiscovery/v2/doc.go | 2 + .../api/apidiscovery/v2/generated.pb.go | 215 +- .../v2/generated.protomessage.pb.go | 32 + .../v2/zz_generated.model_name.go | 47 + vendor/k8s.io/api/apidiscovery/v2beta1/doc.go | 1 + .../api/apidiscovery/v2beta1/generated.pb.go | 216 +- .../v2beta1/generated.protomessage.pb.go | 32 + .../v2beta1/zz_generated.model_name.go | 47 + .../api/apiserverinternal/v1alpha1/doc.go | 1 + .../v1alpha1/generated.pb.go | 248 +- .../v1alpha1/generated.protomessage.pb.go | 34 + .../v1alpha1/zz_generated.model_name.go | 52 + vendor/k8s.io/api/apps/v1/doc.go | 1 + vendor/k8s.io/api/apps/v1/generated.pb.go | 1032 +- vendor/k8s.io/api/apps/v1/generated.proto | 10 +- .../api/apps/v1/generated.protomessage.pb.go | 82 + vendor/k8s.io/api/apps/v1/types.go | 12 +- .../apps/v1/types_swagger_doc_generated.go | 6 +- .../api/apps/v1/zz_generated.model_name.go | 172 + vendor/k8s.io/api/apps/v1beta1/doc.go | 1 + .../k8s.io/api/apps/v1beta1/generated.pb.go | 829 +- .../k8s.io/api/apps/v1beta1/generated.proto | 16 +- .../apps/v1beta1/generated.protomessage.pb.go | 68 + vendor/k8s.io/api/apps/v1beta1/types.go | 16 +- .../v1beta1/types_swagger_doc_generated.go | 6 +- .../apps/v1beta1/zz_generated.model_name.go | 137 + vendor/k8s.io/api/apps/v1beta2/doc.go | 1 + .../k8s.io/api/apps/v1beta2/generated.pb.go | 1134 +- .../k8s.io/api/apps/v1beta2/generated.proto | 18 +- .../apps/v1beta2/generated.protomessage.pb.go | 88 + vendor/k8s.io/api/apps/v1beta2/types.go | 20 +- .../v1beta2/types_swagger_doc_generated.go | 8 +- .../apps/v1beta2/zz_generated.model_name.go | 187 + vendor/k8s.io/api/authentication/v1/doc.go | 1 + .../api/authentication/v1/generated.pb.go | 411 +- .../v1/generated.protomessage.pb.go | 44 + .../v1/zz_generated.model_name.go | 72 + .../k8s.io/api/authentication/v1alpha1/doc.go | 1 + .../authentication/v1alpha1/generated.pb.go | 106 +- .../v1alpha1/generated.protomessage.pb.go | 26 + .../v1alpha1/zz_generated.model_name.go | 32 + .../k8s.io/api/authentication/v1beta1/doc.go | 1 + .../authentication/v1beta1/generated.pb.go | 280 +- .../v1beta1/generated.protomessage.pb.go | 36 + .../v1beta1/zz_generated.model_name.go | 52 + vendor/k8s.io/api/authorization/v1/doc.go | 2 + .../api/authorization/v1/generated.pb.go | 573 +- .../v1/generated.protomessage.pb.go | 54 + .../v1/zz_generated.model_name.go | 97 + .../k8s.io/api/authorization/v1beta1/doc.go | 1 + .../api/authorization/v1beta1/generated.pb.go | 512 +- .../v1beta1/generated.protomessage.pb.go | 50 + .../v1beta1/zz_generated.model_name.go | 87 + vendor/k8s.io/api/autoscaling/v1/doc.go | 1 + .../k8s.io/api/autoscaling/v1/generated.pb.go | 734 +- .../v1/generated.protomessage.pb.go | 64 + .../autoscaling/v1/zz_generated.model_name.go | 127 + vendor/k8s.io/api/autoscaling/v2/doc.go | 1 + .../k8s.io/api/autoscaling/v2/generated.pb.go | 830 +- .../k8s.io/api/autoscaling/v2/generated.proto | 6 +- .../v2/generated.protomessage.pb.go | 70 + vendor/k8s.io/api/autoscaling/v2/types.go | 6 +- .../v2/types_swagger_doc_generated.go | 4 +- .../autoscaling/v2/zz_generated.model_name.go | 142 + vendor/k8s.io/api/autoscaling/v2beta1/doc.go | 1 + .../api/autoscaling/v2beta1/generated.pb.go | 644 +- .../v2beta1/generated.protomessage.pb.go | 58 + .../v2beta1/zz_generated.model_name.go | 112 + vendor/k8s.io/api/autoscaling/v2beta2/doc.go | 1 + .../api/autoscaling/v2beta2/generated.pb.go | 829 +- .../v2beta2/generated.protomessage.pb.go | 70 + .../v2beta2/zz_generated.model_name.go | 142 + vendor/k8s.io/api/batch/v1/doc.go | 2 + vendor/k8s.io/api/batch/v1/generated.pb.go | 631 +- vendor/k8s.io/api/batch/v1/generated.proto | 4 +- .../api/batch/v1/generated.protomessage.pb.go | 56 + vendor/k8s.io/api/batch/v1/types.go | 4 +- .../batch/v1/types_swagger_doc_generated.go | 2 +- .../api/batch/v1/zz_generated.model_name.go | 107 + vendor/k8s.io/api/batch/v1beta1/doc.go | 1 + .../k8s.io/api/batch/v1beta1/generated.pb.go | 218 +- .../v1beta1/generated.protomessage.pb.go | 32 + .../batch/v1beta1/zz_generated.model_name.go | 47 + vendor/k8s.io/api/certificates/v1/doc.go | 2 + .../api/certificates/v1/generated.pb.go | 262 +- .../api/certificates/v1/generated.proto | 3 +- .../v1/generated.protomessage.pb.go | 34 + vendor/k8s.io/api/certificates/v1/types.go | 3 +- .../v1/zz_generated.model_name.go | 47 + .../k8s.io/api/certificates/v1alpha1/doc.go | 1 + .../api/certificates/v1alpha1/generated.pb.go | 1949 +- .../api/certificates/v1alpha1/generated.proto | 205 - .../v1alpha1/generated.protomessage.pb.go | 28 + .../api/certificates/v1alpha1/register.go | 2 - .../k8s.io/api/certificates/v1alpha1/types.go | 231 - .../v1alpha1/types_swagger_doc_generated.go | 52 - .../v1alpha1/zz_generated.deepcopy.go | 128 - .../v1alpha1/zz_generated.model_name.go | 37 + .../zz_generated.prerelease-lifecycle.go | 36 - vendor/k8s.io/api/certificates/v1beta1/doc.go | 1 + .../api/certificates/v1beta1/generated.pb.go | 3082 +++- .../api/certificates/v1beta1/generated.proto | 220 +- .../v1beta1/generated.protomessage.pb.go | 48 + .../api/certificates/v1beta1/register.go | 2 + .../k8s.io/api/certificates/v1beta1/types.go | 251 +- .../v1beta1/types_swagger_doc_generated.go | 53 + .../v1beta1/zz_generated.deepcopy.go | 135 + .../v1beta1/zz_generated.model_name.go | 82 + .../zz_generated.prerelease-lifecycle.go | 36 + vendor/k8s.io/api/coordination/v1/doc.go | 1 + .../api/coordination/v1/generated.pb.go | 148 +- .../v1/generated.protomessage.pb.go | 28 + .../v1/zz_generated.model_name.go | 37 + .../k8s.io/api/coordination/v1alpha2/doc.go | 1 + .../api/coordination/v1alpha2/generated.pb.go | 147 +- .../v1alpha2/generated.protomessage.pb.go | 28 + .../v1alpha2/zz_generated.model_name.go | 37 + vendor/k8s.io/api/coordination/v1beta1/doc.go | 1 + .../api/coordination/v1beta1/generated.pb.go | 246 +- .../v1beta1/generated.protomessage.pb.go | 34 + .../v1beta1/zz_generated.model_name.go | 52 + vendor/k8s.io/api/core/v1/doc.go | 2 + vendor/k8s.io/api/core/v1/generated.pb.go | 9343 ++-------- vendor/k8s.io/api/core/v1/generated.proto | 113 +- .../api/core/v1/generated.protomessage.pb.go | 498 + vendor/k8s.io/api/core/v1/toleration.go | 57 +- vendor/k8s.io/api/core/v1/types.go | 171 +- .../core/v1/types_swagger_doc_generated.go | 62 +- .../api/core/v1/zz_generated.deepcopy.go | 45 + .../api/core/v1/zz_generated.model_name.go | 1212 ++ vendor/k8s.io/api/discovery/v1/doc.go | 2 + .../k8s.io/api/discovery/v1/generated.pb.go | 320 +- .../k8s.io/api/discovery/v1/generated.proto | 2 - .../discovery/v1/generated.protomessage.pb.go | 38 + vendor/k8s.io/api/discovery/v1/types.go | 2 - .../v1/types_swagger_doc_generated.go | 2 +- .../discovery/v1/zz_generated.model_name.go | 62 + vendor/k8s.io/api/discovery/v1beta1/doc.go | 2 + .../api/discovery/v1beta1/generated.pb.go | 318 +- .../api/discovery/v1beta1/generated.proto | 2 - .../v1beta1/generated.protomessage.pb.go | 38 + vendor/k8s.io/api/discovery/v1beta1/types.go | 2 - .../v1beta1/types_swagger_doc_generated.go | 2 +- .../v1beta1/zz_generated.model_name.go | 62 + vendor/k8s.io/api/events/v1/doc.go | 2 + vendor/k8s.io/api/events/v1/generated.pb.go | 159 +- .../events/v1/generated.protomessage.pb.go | 28 + .../api/events/v1/zz_generated.model_name.go | 37 + vendor/k8s.io/api/events/v1beta1/doc.go | 1 + .../k8s.io/api/events/v1beta1/generated.pb.go | 159 +- .../v1beta1/generated.protomessage.pb.go | 28 + .../events/v1beta1/zz_generated.model_name.go | 37 + vendor/k8s.io/api/extensions/v1beta1/doc.go | 1 + .../api/extensions/v1beta1/generated.pb.go | 1521 +- .../api/extensions/v1beta1/generated.proto | 4 +- .../v1beta1/generated.protomessage.pb.go | 112 + vendor/k8s.io/api/extensions/v1beta1/types.go | 4 +- .../v1beta1/types_swagger_doc_generated.go | 4 +- .../v1beta1/zz_generated.model_name.go | 247 + .../v1beta1/zz_generated.validations.go | 24 +- vendor/k8s.io/api/flowcontrol/v1/doc.go | 1 + .../k8s.io/api/flowcontrol/v1/generated.pb.go | 791 +- .../v1/generated.protomessage.pb.go | 68 + .../flowcontrol/v1/zz_generated.model_name.go | 137 + vendor/k8s.io/api/flowcontrol/v1beta1/doc.go | 1 + .../api/flowcontrol/v1beta1/generated.pb.go | 792 +- .../v1beta1/generated.protomessage.pb.go | 68 + .../v1beta1/zz_generated.model_name.go | 137 + vendor/k8s.io/api/flowcontrol/v1beta2/doc.go | 1 + .../api/flowcontrol/v1beta2/generated.pb.go | 793 +- .../v1beta2/generated.protomessage.pb.go | 68 + .../v1beta2/zz_generated.model_name.go | 137 + vendor/k8s.io/api/flowcontrol/v1beta3/doc.go | 1 + .../api/flowcontrol/v1beta3/generated.pb.go | 792 +- .../v1beta3/generated.protomessage.pb.go | 68 + .../v1beta3/zz_generated.model_name.go | 137 + vendor/k8s.io/api/imagepolicy/v1alpha1/doc.go | 1 + .../api/imagepolicy/v1alpha1/generated.pb.go | 191 +- .../v1alpha1/generated.protomessage.pb.go | 30 + .../v1alpha1/zz_generated.model_name.go | 42 + vendor/k8s.io/api/networking/v1/doc.go | 2 + .../k8s.io/api/networking/v1/generated.pb.go | 1157 +- .../v1/generated.protomessage.pb.go | 92 + .../networking/v1/zz_generated.model_name.go | 197 + vendor/k8s.io/api/networking/v1beta1/doc.go | 2 + .../api/networking/v1beta1/generated.pb.go | 841 +- .../v1beta1/generated.protomessage.pb.go | 72 + .../v1beta1/zz_generated.model_name.go | 147 + vendor/k8s.io/api/node/v1/doc.go | 2 + vendor/k8s.io/api/node/v1/generated.pb.go | 193 +- .../api/node/v1/generated.protomessage.pb.go | 30 + .../api/node/v1/zz_generated.model_name.go | 42 + vendor/k8s.io/api/node/v1alpha1/doc.go | 1 + .../k8s.io/api/node/v1alpha1/generated.pb.go | 224 +- .../v1alpha1/generated.protomessage.pb.go | 32 + .../node/v1alpha1/zz_generated.model_name.go | 47 + vendor/k8s.io/api/node/v1beta1/doc.go | 1 + .../k8s.io/api/node/v1beta1/generated.pb.go | 193 +- .../node/v1beta1/generated.protomessage.pb.go | 30 + .../node/v1beta1/zz_generated.model_name.go | 42 + vendor/k8s.io/api/policy/v1/doc.go | 1 + vendor/k8s.io/api/policy/v1/generated.pb.go | 229 +- .../policy/v1/generated.protomessage.pb.go | 32 + .../api/policy/v1/zz_generated.model_name.go | 47 + vendor/k8s.io/api/policy/v1beta1/doc.go | 1 + .../k8s.io/api/policy/v1beta1/generated.pb.go | 229 +- .../v1beta1/generated.protomessage.pb.go | 32 + .../policy/v1beta1/zz_generated.model_name.go | 47 + vendor/k8s.io/api/rbac/v1/doc.go | 2 + vendor/k8s.io/api/rbac/v1/generated.pb.go | 422 +- vendor/k8s.io/api/rbac/v1/generated.proto | 4 + .../api/rbac/v1/generated.protomessage.pb.go | 46 + vendor/k8s.io/api/rbac/v1/types.go | 4 + .../api/rbac/v1/zz_generated.model_name.go | 82 + vendor/k8s.io/api/rbac/v1alpha1/doc.go | 1 + .../k8s.io/api/rbac/v1alpha1/generated.pb.go | 424 +- .../k8s.io/api/rbac/v1alpha1/generated.proto | 4 + .../v1alpha1/generated.protomessage.pb.go | 46 + vendor/k8s.io/api/rbac/v1alpha1/types.go | 4 + .../rbac/v1alpha1/zz_generated.model_name.go | 82 + vendor/k8s.io/api/rbac/v1beta1/doc.go | 1 + .../k8s.io/api/rbac/v1beta1/generated.pb.go | 422 +- .../k8s.io/api/rbac/v1beta1/generated.proto | 4 + .../rbac/v1beta1/generated.protomessage.pb.go | 46 + vendor/k8s.io/api/rbac/v1beta1/types.go | 4 + .../rbac/v1beta1/zz_generated.model_name.go | 82 + vendor/k8s.io/api/resource/v1/doc.go | 1 + vendor/k8s.io/api/resource/v1/generated.pb.go | 1493 +- vendor/k8s.io/api/resource/v1/generated.proto | 166 +- .../resource/v1/generated.protomessage.pb.go | 108 + vendor/k8s.io/api/resource/v1/types.go | 225 +- .../v1/types_swagger_doc_generated.go | 24 +- .../resource/v1/zz_generated.model_name.go | 237 + vendor/k8s.io/api/resource/v1alpha3/doc.go | 2 + .../api/resource/v1alpha3/generated.pb.go | 516 +- .../api/resource/v1alpha3/generated.proto | 59 +- .../v1alpha3/generated.protomessage.pb.go | 38 + vendor/k8s.io/api/resource/v1alpha3/types.go | 80 +- .../v1alpha3/types_swagger_doc_generated.go | 24 +- .../v1alpha3/zz_generated.deepcopy.go | 37 +- .../v1alpha3/zz_generated.model_name.go | 62 + vendor/k8s.io/api/resource/v1beta1/doc.go | 2 + .../api/resource/v1beta1/generated.pb.go | 1493 +- .../api/resource/v1beta1/generated.proto | 164 +- .../v1beta1/generated.protomessage.pb.go | 108 + vendor/k8s.io/api/resource/v1beta1/types.go | 221 +- .../v1beta1/types_swagger_doc_generated.go | 22 +- .../v1beta1/zz_generated.model_name.go | 237 + vendor/k8s.io/api/resource/v1beta2/doc.go | 2 + .../api/resource/v1beta2/generated.pb.go | 1493 +- .../api/resource/v1beta2/generated.proto | 166 +- .../v1beta2/generated.protomessage.pb.go | 108 + vendor/k8s.io/api/resource/v1beta2/types.go | 225 +- .../v1beta2/types_swagger_doc_generated.go | 24 +- .../v1beta2/zz_generated.model_name.go | 237 + vendor/k8s.io/api/scheduling/v1/doc.go | 2 + .../k8s.io/api/scheduling/v1/generated.pb.go | 113 +- .../v1/generated.protomessage.pb.go | 26 + .../scheduling/v1/zz_generated.model_name.go | 32 + vendor/k8s.io/api/scheduling/v1alpha1/doc.go | 1 + .../api/scheduling/v1alpha1/generated.pb.go | 1596 +- .../api/scheduling/v1alpha1/generated.proto | 115 + .../v1alpha1/generated.protomessage.pb.go | 42 + .../api/scheduling/v1alpha1/register.go | 2 + .../k8s.io/api/scheduling/v1alpha1/types.go | 127 + .../v1alpha1/types_swagger_doc_generated.go | 78 + .../v1alpha1/zz_generated.deepcopy.go | 179 + .../v1alpha1/zz_generated.model_name.go | 72 + vendor/k8s.io/api/scheduling/v1beta1/doc.go | 1 + .../api/scheduling/v1beta1/generated.pb.go | 114 +- .../v1beta1/generated.protomessage.pb.go | 26 + .../v1beta1/zz_generated.model_name.go | 32 + vendor/k8s.io/api/storage/v1/doc.go | 1 + vendor/k8s.io/api/storage/v1/generated.pb.go | 797 +- vendor/k8s.io/api/storage/v1/generated.proto | 26 + .../storage/v1/generated.protomessage.pb.go | 64 + vendor/k8s.io/api/storage/v1/types.go | 26 + .../storage/v1/types_swagger_doc_generated.go | 1 + .../api/storage/v1/zz_generated.deepcopy.go | 5 + .../api/storage/v1/zz_generated.model_name.go | 127 + vendor/k8s.io/api/storage/v1alpha1/doc.go | 1 + .../api/storage/v1alpha1/generated.pb.go | 391 +- .../v1alpha1/generated.protomessage.pb.go | 42 + .../v1alpha1/zz_generated.model_name.go | 72 + vendor/k8s.io/api/storage/v1beta1/doc.go | 1 + .../api/storage/v1beta1/generated.pb.go | 797 +- .../api/storage/v1beta1/generated.proto | 26 + .../v1beta1/generated.protomessage.pb.go | 64 + vendor/k8s.io/api/storage/v1beta1/types.go | 26 + .../v1beta1/types_swagger_doc_generated.go | 1 + .../storage/v1beta1/zz_generated.deepcopy.go | 5 + .../v1beta1/zz_generated.model_name.go | 127 + .../storagemigration/v1alpha1/generated.pb.go | 1688 -- .../{v1alpha1 => v1beta1}/doc.go | 4 +- .../storagemigration/v1beta1/generated.pb.go | 904 + .../{v1alpha1 => v1beta1}/generated.proto | 53 +- .../v1beta1/generated.protomessage.pb.go | 30 + .../{v1alpha1 => v1beta1}/register.go | 4 +- .../{v1alpha1 => v1beta1}/types.go | 52 +- .../types_swagger_doc_generated.go | 31 +- .../zz_generated.deepcopy.go | 38 +- .../v1beta1/zz_generated.model_name.go | 42 + .../zz_generated.prerelease-lifecycle.go | 14 +- .../pkg/apis/apiextensions/types.go | 11 + .../pkg/apis/apiextensions/v1/doc.go | 2 + .../pkg/apis/apiextensions/v1/generated.pb.go | 1074 +- .../pkg/apis/apiextensions/v1/generated.proto | 12 + .../v1/generated.protomessage.pb.go | 76 + .../pkg/apis/apiextensions/v1/types.go | 11 + .../v1/zz_generated.conversion.go | 4 + .../v1/zz_generated.model_name.go | 157 + .../pkg/apis/apiextensions/v1beta1/doc.go | 2 + .../apiextensions/v1beta1/generated.pb.go | 1048 +- .../apiextensions/v1beta1/generated.proto | 12 + .../v1beta1/generated.protomessage.pb.go | 74 + .../pkg/apis/apiextensions/v1beta1/types.go | 10 + .../v1beta1/zz_generated.conversion.go | 4 + .../v1beta1/zz_generated.model_name.go | 152 + .../v1/customresourcecolumndefinition.go | 24 +- .../v1/customresourceconversion.go | 9 +- .../v1/customresourcedefinition.go | 14 +- .../v1/customresourcedefinitioncondition.go | 30 +- .../v1/customresourcedefinitionnames.go | 24 +- .../v1/customresourcedefinitionspec.go | 34 +- .../v1/customresourcedefinitionstatus.go | 27 +- .../v1/customresourcedefinitionversion.go | 38 +- .../v1/customresourcesubresources.go | 11 +- .../v1/customresourcesubresourcescale.go | 24 +- .../v1/customresourcevalidation.go | 3 + .../apiextensions/v1/externaldocumentation.go | 2 + .../apiextensions/v1/jsonschemaprops.go | 179 +- .../apiextensions/v1/selectablefield.go | 10 + .../apiextensions/v1/servicereference.go | 16 +- .../apiextensions/v1/validationrule.go | 120 +- .../apiextensions/v1/webhookclientconfig.go | 39 +- .../apiextensions/v1/webhookconversion.go | 13 +- .../v1beta1/customresourcecolumndefinition.go | 24 +- .../v1beta1/customresourceconversion.go | 21 +- .../v1beta1/customresourcedefinition.go | 15 +- .../customresourcedefinitioncondition.go | 30 +- .../v1beta1/customresourcedefinitionnames.go | 24 +- .../v1beta1/customresourcedefinitionspec.go | 67 +- .../v1beta1/customresourcedefinitionstatus.go | 27 +- .../customresourcedefinitionversion.go | 43 +- .../v1beta1/customresourcesubresources.go | 9 +- .../v1beta1/customresourcesubresourcescale.go | 24 +- .../v1beta1/customresourcevalidation.go | 3 + .../v1beta1/externaldocumentation.go | 2 + .../apiextensions/v1beta1/jsonschemaprops.go | 179 +- .../apiextensions/v1beta1/selectablefield.go | 10 + .../apiextensions/v1beta1/servicereference.go | 16 +- .../apiextensions/v1beta1/validationrule.go | 120 +- .../v1beta1/webhookclientconfig.go | 39 +- .../apimachinery/pkg/api/errors/errors.go | 3 +- .../pkg/api/resource/generated.pb.go | 93 +- .../pkg/api/resource/generated.proto | 2 + .../api/resource/generated.protomessage.pb.go | 26 + .../apimachinery/pkg/api/resource/quantity.go | 2 + .../pkg/api/resource/quantity_proto.go | 4 - .../api/resource/zz_generated.model_name.go | 32 + .../pkg/api/validate/content/decimal_int.go | 62 + .../pkg/api/validate/content/dns.go | 101 + .../pkg/api/validate/content/errors.go | 27 + .../pkg/api/validate/content/identifier.go | 35 + .../pkg/api/validate/content/kube.go | 101 + .../apimachinery/pkg/api/validate/each.go | 15 + .../apimachinery/pkg/api/validate/enum.go | 48 +- .../pkg/api/validate/immutable.go | 42 +- .../apimachinery/pkg/api/validate/item.go | 25 +- .../apimachinery/pkg/api/validate/limits.go | 20 + .../apimachinery/pkg/api/validate/options.go | 35 + .../apimachinery/pkg/api/validate/strfmt.go | 290 + .../apimachinery/pkg/api/validate/subfield.go | 19 +- .../apimachinery/pkg/api/validate/union.go | 55 +- .../apimachinery/pkg/api/validate/update.go | 160 + .../pkg/api/validate/zeroorone.go | 9 +- .../pkg/api/validation/generic.go | 6 + .../pkg/api/validation/objectmeta.go | 86 +- .../internalversion/validation/validation.go | 76 + .../apimachinery/pkg/apis/meta/v1/doc.go | 1 + .../pkg/apis/meta/v1/generated.pb.go | 1520 +- .../pkg/apis/meta/v1/generated.proto | 2 +- .../apis/meta/v1/generated.protomessage.pb.go | 112 + .../apimachinery/pkg/apis/meta/v1/types.go | 1 - .../pkg/apis/meta/v1/validation/validation.go | 4 +- .../apis/meta/v1/zz_generated.model_name.go | 267 + .../apimachinery/pkg/apis/meta/v1beta1/doc.go | 1 + .../pkg/apis/meta/v1beta1/generated.pb.go | 72 +- .../meta/v1beta1/generated.protomessage.pb.go | 24 + .../pkg/apis/meta/v1beta1/types.go | 1 + .../meta/v1beta1/zz_generated.model_name.go | 27 + .../apimachinery/pkg/labels/selector.go | 4 +- vendor/k8s.io/apimachinery/pkg/runtime/doc.go | 2 + .../apimachinery/pkg/runtime/generated.pb.go | 135 +- .../pkg/runtime/generated.protomessage.pb.go | 28 + .../pkg/runtime/schema/generated.pb.go | 38 - .../schema/generated.protomessage.pb.go | 22 + .../k8s.io/apimachinery/pkg/runtime/scheme.go | 10 + .../serializer/protobuf/collections.go | 8 +- .../runtime/serializer/protobuf/protobuf.go | 39 +- .../apimachinery/pkg/runtime/types_proto.go | 10 + .../pkg/runtime/zz_generated.model_name.go | 92 + .../pkg/util/httpstream/httpstream.go | 30 +- .../pkg/util/intstr/generated.pb.go | 72 +- .../pkg/util/intstr/generated.proto | 1 + .../util/intstr/generated.protomessage.pb.go | 24 + .../apimachinery/pkg/util/intstr/intstr.go | 1 + .../util/intstr/zz_generated.model_name.go | 27 + .../k8s.io/apimachinery/pkg/util/sets/set.go | 19 +- .../pkg/util/strategicpatch/meta.go | 2 +- .../util/validation/field/error_matcher.go | 135 +- .../pkg/util/validation/field/errors.go | 8 + .../pkg/util/validation/validation.go | 105 +- vendor/k8s.io/apimachinery/pkg/version/doc.go | 2 + .../pkg/version/zz_generated.model_name.go | 27 + .../apis/apiserver/validation/validation.go | 2 +- .../k8s.io/apiserver/pkg/apis/audit/types.go | 11 + .../k8s.io/apiserver/pkg/apis/audit/v1/doc.go | 1 + .../pkg/apis/audit/v1/generated.pb.go | 482 +- .../pkg/apis/audit/v1/generated.proto | 11 + .../audit/v1/generated.protomessage.pb.go | 38 + .../apiserver/pkg/apis/audit/v1/types.go | 10 + .../apis/audit/v1/zz_generated.conversion.go | 32 + .../apis/audit/v1/zz_generated.deepcopy.go | 21 + .../apis/audit/v1/zz_generated.model_name.go | 62 + .../pkg/apis/audit/zz_generated.deepcopy.go | 21 + vendor/k8s.io/apiserver/pkg/audit/context.go | 27 +- vendor/k8s.io/apiserver/pkg/audit/request.go | 4 +- .../pkg/authentication/cel/compile.go | 2 +- .../headerrequest/requestheader_controller.go | 2 +- .../authorization/authorizer/interfaces.go | 14 + .../pkg/authorization/cel/compile.go | 2 +- .../apiserver/pkg/cel/environment/base.go | 46 +- .../apiserver/pkg/cel/library/quantity.go | 4 +- .../apiserver/pkg/cel/library/semverlib.go | 5 +- .../apiserver/pkg/features/kube_features.go | 86 +- .../configmap_cafile_content.go | 2 +- .../server/egressselector/egress_selector.go | 10 +- .../apiserver/pkg/util/webhook/webhook.go | 1 + .../v1/auditannotation.go | 34 +- .../v1/expressionwarning.go | 10 +- .../v1/matchcondition.go | 26 +- .../v1/matchresources.go | 84 +- .../v1/mutatingwebhook.go | 153 +- .../v1/mutatingwebhookconfiguration.go | 48 +- .../v1/namedrulewithoperations.go | 6 +- .../admissionregistration/v1/paramkind.go | 9 +- .../admissionregistration/v1/paramref.go | 49 +- .../admissionregistration/v1/rule.go | 40 +- .../v1/rulewithoperations.go | 11 +- .../v1/servicereference.go | 17 +- .../admissionregistration/v1/typechecking.go | 4 + .../v1/validatingadmissionpolicy.go | 56 +- .../v1/validatingadmissionpolicybinding.go | 58 +- .../validatingadmissionpolicybindingspec.go | 59 +- .../v1/validatingadmissionpolicyspec.go | 66 +- .../v1/validatingadmissionpolicystatus.go | 12 +- .../v1/validatingwebhook.go | 136 +- .../v1/validatingwebhookconfiguration.go | 48 +- .../admissionregistration/v1/validation.go | 74 +- .../admissionregistration/v1/variable.go | 9 +- .../v1/webhookclientconfig.go | 40 +- .../v1alpha1/applyconfiguration.go | 42 + .../v1alpha1/auditannotation.go | 34 +- .../v1alpha1/expressionwarning.go | 10 +- .../v1alpha1/jsonpatch.go | 66 + .../v1alpha1/matchcondition.go | 24 +- .../v1alpha1/matchresources.go | 87 +- .../v1alpha1/mutatingadmissionpolicy.go | 48 +- .../mutatingadmissionpolicybinding.go | 58 +- .../mutatingadmissionpolicybindingspec.go | 22 +- .../v1alpha1/mutatingadmissionpolicyspec.go | 74 +- .../v1alpha1/mutation.go | 17 +- .../v1alpha1/namedrulewithoperations.go | 6 +- .../v1alpha1/paramkind.go | 9 +- .../v1alpha1/paramref.go | 44 +- .../v1alpha1/typechecking.go | 4 + .../v1alpha1/validatingadmissionpolicy.go | 56 +- .../validatingadmissionpolicybinding.go | 58 +- .../validatingadmissionpolicybindingspec.go | 59 +- .../v1alpha1/validatingadmissionpolicyspec.go | 66 +- .../validatingadmissionpolicystatus.go | 12 +- .../v1alpha1/validation.go | 74 +- .../v1alpha1/variable.go | 9 +- .../v1beta1/applyconfiguration.go | 42 + .../v1beta1/auditannotation.go | 34 +- .../v1beta1/expressionwarning.go | 10 +- .../v1beta1/jsonpatch.go | 66 + .../v1beta1/matchcondition.go | 26 +- .../v1beta1/matchresources.go | 86 +- .../v1beta1/mutatingadmissionpolicy.go | 48 +- .../v1beta1/mutatingadmissionpolicybinding.go | 58 +- .../mutatingadmissionpolicybindingspec.go | 22 +- .../v1beta1/mutatingadmissionpolicyspec.go | 74 +- .../v1beta1/mutatingwebhook.go | 154 +- .../v1beta1/mutatingwebhookconfiguration.go | 49 +- .../admissionregistration/v1beta1/mutation.go | 17 +- .../v1beta1/namedrulewithoperations.go | 6 +- .../v1beta1/paramkind.go | 9 +- .../admissionregistration/v1beta1/paramref.go | 49 +- .../v1beta1/servicereference.go | 17 +- .../v1beta1/typechecking.go | 4 + .../v1beta1/validatingadmissionpolicy.go | 56 +- .../validatingadmissionpolicybinding.go | 58 +- .../validatingadmissionpolicybindingspec.go | 59 +- .../v1beta1/validatingadmissionpolicyspec.go | 66 +- .../validatingadmissionpolicystatus.go | 12 +- .../v1beta1/validatingwebhook.go | 137 +- .../v1beta1/validatingwebhookconfiguration.go | 49 +- .../v1beta1/validation.go | 74 +- .../admissionregistration/v1beta1/variable.go | 9 +- .../v1beta1/webhookclientconfig.go | 40 +- .../v1alpha1/serverstorageversion.go | 16 +- .../v1alpha1/storageversion.go | 54 +- .../v1alpha1/storageversioncondition.go | 20 +- .../v1alpha1/storageversionstatus.go | 15 +- .../apps/v1/controllerrevision.go | 60 +- .../applyconfigurations/apps/v1/daemonset.go | 61 +- .../apps/v1/daemonsetcondition.go | 18 +- .../apps/v1/daemonsetspec.go | 30 +- .../apps/v1/daemonsetstatus.go | 45 +- .../apps/v1/daemonsetupdatestrategy.go | 10 +- .../applyconfigurations/apps/v1/deployment.go | 62 +- .../apps/v1/deploymentcondition.go | 20 +- .../apps/v1/deploymentspec.go | 38 +- .../apps/v1/deploymentstatus.go | 36 +- .../apps/v1/deploymentstrategy.go | 10 +- .../applyconfigurations/apps/v1/replicaset.go | 69 +- .../apps/v1/replicasetcondition.go | 17 +- .../apps/v1/replicasetspec.go | 24 +- .../apps/v1/replicasetstatus.go | 27 +- .../apps/v1/rollingupdatedaemonset.go | 36 +- .../apps/v1/rollingupdatedeployment.go | 25 +- .../v1/rollingupdatestatefulsetstrategy.go | 15 +- .../apps/v1/statefulset.go | 69 +- .../apps/v1/statefulsetcondition.go | 17 +- .../apps/v1/statefulsetordinals.go | 11 + ...setpersistentvolumeclaimretentionpolicy.go | 14 +- .../apps/v1/statefulsetspec.go | 76 +- .../apps/v1/statefulsetstatus.go | 39 +- .../apps/v1/statefulsetupdatestrategy.go | 9 +- .../apps/v1beta1/controllerrevision.go | 62 +- .../apps/v1beta1/deployment.go | 57 +- .../apps/v1beta1/deploymentcondition.go | 20 +- .../apps/v1beta1/deploymentspec.go | 41 +- .../apps/v1beta1/deploymentstatus.go | 36 +- .../apps/v1beta1/deploymentstrategy.go | 10 +- .../apps/v1beta1/rollbackconfig.go | 3 + .../apps/v1beta1/rollingupdatedeployment.go | 25 +- .../rollingupdatestatefulsetstrategy.go | 15 +- .../apps/v1beta1/statefulset.go | 61 +- .../apps/v1beta1/statefulsetcondition.go | 17 +- .../apps/v1beta1/statefulsetordinals.go | 11 + ...setpersistentvolumeclaimretentionpolicy.go | 14 +- .../apps/v1beta1/statefulsetspec.go | 75 +- .../apps/v1beta1/statefulsetstatus.go | 39 +- .../apps/v1beta1/statefulsetupdatestrategy.go | 8 +- .../apps/v1beta2/controllerrevision.go | 62 +- .../apps/v1beta2/daemonset.go | 63 +- .../apps/v1beta2/daemonsetcondition.go | 18 +- .../apps/v1beta2/daemonsetspec.go | 30 +- .../apps/v1beta2/daemonsetstatus.go | 45 +- .../apps/v1beta2/daemonsetupdatestrategy.go | 10 +- .../apps/v1beta2/deployment.go | 57 +- .../apps/v1beta2/deploymentcondition.go | 20 +- .../apps/v1beta2/deploymentspec.go | 38 +- .../apps/v1beta2/deploymentstatus.go | 36 +- .../apps/v1beta2/deploymentstrategy.go | 10 +- .../apps/v1beta2/replicaset.go | 64 +- .../apps/v1beta2/replicasetcondition.go | 17 +- .../apps/v1beta2/replicasetspec.go | 24 +- .../apps/v1beta2/replicasetstatus.go | 27 +- .../apps/v1beta2/rollingupdatedaemonset.go | 36 +- .../apps/v1beta2/rollingupdatedeployment.go | 25 +- .../rollingupdatestatefulsetstrategy.go | 15 +- .../applyconfigurations/apps/v1beta2/scale.go | 12 +- .../apps/v1beta2/statefulset.go | 67 +- .../apps/v1beta2/statefulsetcondition.go | 17 +- .../apps/v1beta2/statefulsetordinals.go | 11 + ...setpersistentvolumeclaimretentionpolicy.go | 14 +- .../apps/v1beta2/statefulsetspec.go | 76 +- .../apps/v1beta2/statefulsetstatus.go | 39 +- .../apps/v1beta2/statefulsetupdatestrategy.go | 9 +- .../v1/crossversionobjectreference.go | 9 +- .../autoscaling/v1/horizontalpodautoscaler.go | 55 +- .../v1/horizontalpodautoscalerspec.go | 20 +- .../v1/horizontalpodautoscalerstatus.go | 19 +- .../autoscaling/v1/scale.go | 12 +- .../autoscaling/v1/scalespec.go | 3 + .../autoscaling/v1/scalestatus.go | 9 +- .../v2/containerresourcemetricsource.go | 17 +- .../v2/containerresourcemetricstatus.go | 15 +- .../v2/crossversionobjectreference.go | 9 +- .../autoscaling/v2/externalmetricsource.go | 8 +- .../autoscaling/v2/externalmetricstatus.go | 7 +- .../autoscaling/v2/horizontalpodautoscaler.go | 59 +- .../v2/horizontalpodautoscalerbehavior.go | 14 +- .../v2/horizontalpodautoscalercondition.go | 20 +- .../v2/horizontalpodautoscalerspec.go | 32 +- .../v2/horizontalpodautoscalerstatus.go | 24 +- .../autoscaling/v2/hpascalingpolicy.go | 13 +- .../autoscaling/v2/hpascalingrules.go | 44 +- .../autoscaling/v2/metricidentifier.go | 8 +- .../autoscaling/v2/metricspec.go | 35 +- .../autoscaling/v2/metricstatus.go | 34 +- .../autoscaling/v2/metrictarget.go | 18 +- .../autoscaling/v2/metricvaluestatus.go | 14 +- .../autoscaling/v2/objectmetricsource.go | 10 +- .../autoscaling/v2/objectmetricstatus.go | 10 +- .../autoscaling/v2/podsmetricsource.go | 9 +- .../autoscaling/v2/podsmetricstatus.go | 7 +- .../autoscaling/v2/resourcemetricsource.go | 12 +- .../autoscaling/v2/resourcemetricstatus.go | 10 +- .../v2beta1/containerresourcemetricsource.go | 24 +- .../v2beta1/containerresourcemetricstatus.go | 25 +- .../v2beta1/crossversionobjectreference.go | 9 +- .../v2beta1/externalmetricsource.go | 20 +- .../v2beta1/externalmetricstatus.go | 17 +- .../v2beta1/horizontalpodautoscaler.go | 59 +- .../horizontalpodautoscalercondition.go | 20 +- .../v2beta1/horizontalpodautoscalerspec.go | 24 +- .../v2beta1/horizontalpodautoscalerstatus.go | 24 +- .../autoscaling/v2beta1/metricspec.go | 35 +- .../autoscaling/v2beta1/metricstatus.go | 34 +- .../autoscaling/v2beta1/objectmetricsource.go | 21 +- .../autoscaling/v2beta1/objectmetricstatus.go | 21 +- .../autoscaling/v2beta1/podsmetricsource.go | 17 +- .../autoscaling/v2beta1/podsmetricstatus.go | 15 +- .../v2beta1/resourcemetricsource.go | 21 +- .../v2beta1/resourcemetricstatus.go | 22 +- .../v2beta2/containerresourcemetricsource.go | 17 +- .../v2beta2/containerresourcemetricstatus.go | 15 +- .../v2beta2/crossversionobjectreference.go | 9 +- .../v2beta2/externalmetricsource.go | 8 +- .../v2beta2/externalmetricstatus.go | 7 +- .../v2beta2/horizontalpodautoscaler.go | 59 +- .../horizontalpodautoscalerbehavior.go | 14 +- .../horizontalpodautoscalercondition.go | 20 +- .../v2beta2/horizontalpodautoscalerspec.go | 32 +- .../v2beta2/horizontalpodautoscalerstatus.go | 24 +- .../autoscaling/v2beta2/hpascalingpolicy.go | 13 +- .../autoscaling/v2beta2/hpascalingrules.go | 23 +- .../autoscaling/v2beta2/metricidentifier.go | 8 +- .../autoscaling/v2beta2/metricspec.go | 35 +- .../autoscaling/v2beta2/metricstatus.go | 34 +- .../autoscaling/v2beta2/metrictarget.go | 18 +- .../autoscaling/v2beta2/metricvaluestatus.go | 14 +- .../autoscaling/v2beta2/objectmetricsource.go | 9 +- .../autoscaling/v2beta2/objectmetricstatus.go | 7 +- .../autoscaling/v2beta2/podsmetricsource.go | 9 +- .../autoscaling/v2beta2/podsmetricstatus.go | 7 +- .../v2beta2/resourcemetricsource.go | 12 +- .../v2beta2/resourcemetricstatus.go | 10 +- .../applyconfigurations/batch/v1/cronjob.go | 58 +- .../batch/v1/cronjobspec.go | 43 +- .../batch/v1/cronjobstatus.go | 11 +- .../applyconfigurations/batch/v1/job.go | 58 +- .../batch/v1/jobcondition.go | 20 +- .../applyconfigurations/batch/v1/jobspec.go | 149 +- .../applyconfigurations/batch/v1/jobstatus.go | 94 +- .../batch/v1/jobtemplatespec.go | 8 +- .../batch/v1/podfailurepolicy.go | 7 + .../podfailurepolicyonexitcodesrequirement.go | 34 +- .../podfailurepolicyonpodconditionspattern.go | 12 +- .../batch/v1/podfailurepolicyrule.go | 24 +- .../batch/v1/successpolicy.go | 8 + .../batch/v1/successpolicyrule.go | 26 +- .../batch/v1/uncountedterminatedpods.go | 7 +- .../batch/v1beta1/cronjob.go | 58 +- .../batch/v1beta1/cronjobspec.go | 45 +- .../batch/v1beta1/cronjobstatus.go | 11 +- .../batch/v1beta1/jobtemplatespec.go | 8 +- .../v1/certificatesigningrequest.go | 68 +- .../v1/certificatesigningrequestcondition.go | 37 +- .../v1/certificatesigningrequestspec.go | 81 +- .../v1/certificatesigningrequeststatus.go | 34 +- .../v1alpha1/clustertrustbundle.go | 62 +- .../v1alpha1/clustertrustbundlespec.go | 33 +- .../v1beta1/certificatesigningrequest.go | 52 +- .../certificatesigningrequestcondition.go | 23 +- .../v1beta1/certificatesigningrequestspec.go | 85 +- .../certificatesigningrequeststatus.go | 6 +- .../v1beta1/clustertrustbundle.go | 62 +- .../v1beta1/clustertrustbundlespec.go | 33 +- .../podcertificaterequest.go | 68 +- .../podcertificaterequestspec.go | 108 +- .../podcertificaterequeststatus.go | 60 +- .../coordination/v1/lease.go | 49 +- .../coordination/v1/leasespec.go | 33 +- .../coordination/v1alpha2/leasecandidate.go | 50 +- .../v1alpha2/leasecandidatespec.go | 36 +- .../coordination/v1beta1/lease.go | 49 +- .../coordination/v1beta1/leasecandidate.go | 50 +- .../v1beta1/leasecandidatespec.go | 38 +- .../coordination/v1beta1/leasespec.go | 31 +- .../applyconfigurations/core/v1/affinity.go | 9 +- .../core/v1/apparmorprofile.go | 15 +- .../core/v1/attachedvolume.go | 8 +- .../v1/awselasticblockstorevolumesource.go | 28 +- .../core/v1/azurediskvolumesource.go | 21 +- .../v1/azurefilepersistentvolumesource.go | 14 +- .../core/v1/azurefilevolumesource.go | 10 +- .../core/v1/capabilities.go | 6 +- .../core/v1/cephfspersistentvolumesource.go | 27 +- .../core/v1/cephfsvolumesource.go | 27 +- .../core/v1/cinderpersistentvolumesource.go | 22 +- .../core/v1/cindervolumesource.go | 22 +- .../core/v1/clientipconfig.go | 5 + .../core/v1/clustertrustbundleprojection.go | 27 +- .../core/v1/componentcondition.go | 18 +- .../core/v1/componentstatus.go | 50 +- .../applyconfigurations/core/v1/configmap.go | 68 +- .../core/v1/configmapenvsource.go | 10 +- .../core/v1/configmapkeyselector.go | 9 +- .../core/v1/configmapnodeconfigsource.go | 23 +- .../core/v1/configmapprojection.go | 20 +- .../core/v1/configmapvolumesource.go | 28 +- .../applyconfigurations/core/v1/container.go | 179 +- .../v1/containerextendedresourcerequest.go | 10 +- .../core/v1/containerimage.go | 9 +- .../core/v1/containerport.go | 24 +- .../core/v1/containerresizepolicy.go | 8 +- .../core/v1/containerrestartrule.go | 8 +- .../v1/containerrestartruleonexitcodes.go | 13 +- .../core/v1/containerstate.go | 11 +- .../core/v1/containerstaterunning.go | 3 + .../core/v1/containerstateterminated.go | 23 +- .../core/v1/containerstatewaiting.go | 6 +- .../core/v1/containerstatus.go | 78 +- .../core/v1/containeruser.go | 4 + .../core/v1/csipersistentvolumesource.go | 55 +- .../core/v1/csivolumesource.go | 24 +- .../core/v1/daemonendpoint.go | 3 + .../core/v1/downwardapiprojection.go | 5 + .../core/v1/downwardapivolumefile.go | 18 +- .../core/v1/downwardapivolumesource.go | 16 +- .../core/v1/emptydirvolumesource.go | 17 +- .../core/v1/endpointaddress.go | 15 +- .../core/v1/endpointport.go | 34 +- .../applyconfigurations/core/v1/endpoints.go | 72 +- .../core/v1/endpointsubset.go | 26 +- .../core/v1/envfromsource.go | 10 +- .../applyconfigurations/core/v1/envvar.go | 18 +- .../core/v1/envvarsource.go | 18 +- .../core/v1/ephemeralcontainer.go | 21 +- .../core/v1/ephemeralcontainercommon.go | 137 +- .../core/v1/ephemeralvolumesource.go | 23 + .../applyconfigurations/core/v1/event.go | 96 +- .../core/v1/eventseries.go | 7 +- .../core/v1/eventsource.go | 6 +- .../applyconfigurations/core/v1/execaction.go | 7 + .../core/v1/fcvolumesource.go | 22 +- .../core/v1/filekeyselector.go | 21 +- .../core/v1/flexpersistentvolumesource.go | 23 +- .../core/v1/flexvolumesource.go | 23 +- .../core/v1/flockervolumesource.go | 7 + .../core/v1/gcepersistentdiskvolumesource.go | 30 +- .../core/v1/gitrepovolumesource.go | 18 +- .../v1/glusterfspersistentvolumesource.go | 19 +- .../core/v1/glusterfsvolumesource.go | 13 +- .../applyconfigurations/core/v1/grpcaction.go | 9 +- .../applyconfigurations/core/v1/hostalias.go | 7 +- .../applyconfigurations/core/v1/hostip.go | 3 + .../core/v1/hostpathvolumesource.go | 11 +- .../core/v1/httpgetaction.go | 19 +- .../applyconfigurations/core/v1/httpheader.go | 7 +- .../core/v1/imagevolumesource.go | 15 +- .../core/v1/iscsipersistentvolumesource.go | 47 +- .../core/v1/iscsivolumesource.go | 47 +- .../applyconfigurations/core/v1/keytopath.go | 17 +- .../applyconfigurations/core/v1/lifecycle.go | 26 +- .../core/v1/lifecyclehandler.go | 15 +- .../applyconfigurations/core/v1/limitrange.go | 50 +- .../core/v1/limitrangeitem.go | 18 +- .../core/v1/limitrangespec.go | 3 + .../core/v1/linuxcontaineruser.go | 9 +- .../core/v1/loadbalanceringress.go | 23 +- .../core/v1/loadbalancerstatus.go | 4 + .../core/v1/localobjectreference.go | 20 + .../core/v1/localvolumesource.go | 10 +- .../core/v1/modifyvolumestatus.go | 17 +- .../applyconfigurations/core/v1/namespace.go | 57 +- .../core/v1/namespacecondition.go | 17 +- .../core/v1/namespacespec.go | 4 + .../core/v1/namespacestatus.go | 7 +- .../core/v1/nfsvolumesource.go | 16 +- .../applyconfigurations/core/v1/node.go | 59 +- .../core/v1/nodeaddress.go | 8 +- .../core/v1/nodeaffinity.go | 18 +- .../core/v1/nodecondition.go | 20 +- .../core/v1/nodeconfigsource.go | 4 + .../core/v1/nodeconfigstatus.go | 43 +- .../core/v1/nodedaemonendpoints.go | 3 + .../core/v1/nodefeatures.go | 5 + .../core/v1/noderuntimehandler.go | 7 +- .../core/v1/noderuntimehandlerfeatures.go | 6 +- .../core/v1/nodeselector.go | 5 + .../core/v1/nodeselectorrequirement.go | 15 +- .../core/v1/nodeselectorterm.go | 8 +- .../applyconfigurations/core/v1/nodespec.go | 27 +- .../applyconfigurations/core/v1/nodestatus.go | 64 +- .../core/v1/nodeswapstatus.go | 3 + .../core/v1/nodesysteminfo.go | 39 +- .../core/v1/objectfieldselector.go | 6 +- .../core/v1/objectreference.go | 50 +- .../core/v1/persistentvolume.go | 61 +- .../core/v1/persistentvolumeclaim.go | 59 +- .../core/v1/persistentvolumeclaimcondition.go | 25 +- .../core/v1/persistentvolumeclaimspec.go | 75 +- .../core/v1/persistentvolumeclaimstatus.go | 81 +- .../core/v1/persistentvolumeclaimtemplate.go | 12 +- .../v1/persistentvolumeclaimvolumesource.go | 11 +- .../core/v1/persistentvolumesource.go | 105 +- .../core/v1/persistentvolumespec.go | 50 +- .../core/v1/persistentvolumestatus.go | 17 +- .../v1/photonpersistentdiskvolumesource.go | 8 +- .../applyconfigurations/core/v1/pod.go | 72 +- .../core/v1/podaffinity.go | 20 +- .../core/v1/podaffinityterm.go | 49 +- .../core/v1/podantiaffinity.go | 20 +- .../core/v1/podcertificateprojection.go | 84 +- .../core/v1/podcondition.go | 27 +- .../core/v1/poddnsconfig.go | 19 +- .../core/v1/poddnsconfigoption.go | 7 +- .../core/v1/podextendedresourceclaimstatus.go | 12 +- .../applyconfigurations/core/v1/podip.go | 3 + .../applyconfigurations/core/v1/podos.go | 6 + .../core/v1/podreadinessgate.go | 3 + .../core/v1/podresourceclaim.go | 33 +- .../core/v1/podresourceclaimstatus.go | 13 +- .../core/v1/podschedulinggate.go | 4 + .../core/v1/podsecuritycontext.go | 120 +- .../applyconfigurations/core/v1/podspec.go | 305 +- .../applyconfigurations/core/v1/podstatus.go | 145 +- .../core/v1/podtemplate.go | 50 +- .../core/v1/podtemplatespec.go | 8 +- .../applyconfigurations/core/v1/portstatus.go | 17 +- .../core/v1/portworxvolumesource.go | 12 +- .../core/v1/preferredschedulingterm.go | 7 +- .../applyconfigurations/core/v1/probe.go | 37 +- .../core/v1/probehandler.go | 13 +- .../core/v1/projectedvolumesource.go | 14 +- .../core/v1/quobytevolumesource.go | 25 +- .../core/v1/rbdpersistentvolumesource.go | 44 +- .../core/v1/rbdvolumesource.go | 44 +- .../core/v1/replicationcontroller.go | 68 +- .../core/v1/replicationcontrollercondition.go | 17 +- .../core/v1/replicationcontrollerspec.go | 26 +- .../core/v1/replicationcontrollerstatus.go | 22 +- .../core/v1/resourceclaim.go | 10 +- .../core/v1/resourcefieldselector.go | 11 +- .../core/v1/resourcehealth.go | 18 +- .../core/v1/resourcequota.go | 58 +- .../core/v1/resourcequotaspec.go | 13 +- .../core/v1/resourcequotastatus.go | 5 + .../core/v1/resourcerequirements.go | 21 +- .../core/v1/resourcestatus.go | 11 +- .../core/v1/scaleiopersistentvolumesource.go | 39 +- .../core/v1/scaleiovolumesource.go | 39 +- .../v1/scopedresourceselectorrequirement.go | 16 +- .../core/v1/scopeselector.go | 4 + .../core/v1/seccompprofile.go | 17 +- .../applyconfigurations/core/v1/secret.go | 69 +- .../core/v1/secretenvsource.go | 10 +- .../core/v1/secretkeyselector.go | 9 +- .../core/v1/secretprojection.go | 19 +- .../core/v1/secretreference.go | 7 +- .../core/v1/secretvolumesource.go | 31 +- .../core/v1/securitycontext.go | 82 +- .../core/v1/selinuxoptions.go | 12 +- .../applyconfigurations/core/v1/service.go | 62 +- .../core/v1/serviceaccount.go | 74 +- .../core/v1/serviceaccounttokenprojection.go | 23 +- .../core/v1/serviceport.go | 54 +- .../core/v1/servicespec.go | 214 +- .../core/v1/servicestatus.go | 7 +- .../core/v1/sessionaffinityconfig.go | 3 + .../core/v1/sleepaction.go | 3 + .../v1/storageospersistentvolumesource.go | 27 +- .../core/v1/storageosvolumesource.go | 27 +- .../applyconfigurations/core/v1/sysctl.go | 6 +- .../applyconfigurations/core/v1/taint.go | 17 +- .../core/v1/tcpsocketaction.go | 8 +- .../applyconfigurations/core/v1/toleration.go | 28 +- .../v1/topologyselectorlabelrequirement.go | 8 +- .../core/v1/topologyselectorterm.go | 7 + .../core/v1/topologyspreadconstraint.go | 108 +- .../core/v1/typedlocalobjectreference.go | 26 +- .../core/v1/typedobjectreference.go | 16 +- .../applyconfigurations/core/v1/volume.go | 10 +- .../core/v1/volumedevice.go | 6 +- .../core/v1/volumemount.go | 47 +- .../core/v1/volumemountstatus.go | 14 +- .../core/v1/volumenodeaffinity.go | 3 + .../core/v1/volumeprojection.go | 64 +- .../core/v1/volumeresourcerequirements.go | 10 +- .../core/v1/volumesource.go | 174 +- .../core/v1/vspherevirtualdiskvolumesource.go | 14 +- .../core/v1/weightedpodaffinityterm.go | 7 +- .../core/v1/windowssecuritycontextoptions.go | 20 +- .../core/v1/workloadreference.go | 74 + .../discovery/v1/endpoint.go | 43 +- .../discovery/v1/endpointconditions.go | 19 +- .../discovery/v1/endpointhints.go | 6 + .../discovery/v1/endpointport.go | 39 +- .../discovery/v1/endpointslice.go | 74 +- .../discovery/v1/fornode.go | 3 + .../discovery/v1/forzone.go | 3 + .../discovery/v1beta1/endpoint.go | 45 +- .../discovery/v1beta1/endpointconditions.go | 18 +- .../discovery/v1beta1/endpointhints.go | 6 + .../discovery/v1beta1/endpointport.go | 29 +- .../discovery/v1beta1/endpointslice.go | 67 +- .../discovery/v1beta1/fornode.go | 3 + .../discovery/v1beta1/forzone.go | 3 + .../applyconfigurations/events/v1/event.go | 104 +- .../events/v1/eventseries.go | 9 +- .../events/v1beta1/event.go | 103 +- .../events/v1beta1/eventseries.go | 7 +- .../extensions/v1beta1/daemonset.go | 63 +- .../extensions/v1beta1/daemonsetcondition.go | 18 +- .../extensions/v1beta1/daemonsetspec.go | 34 +- .../extensions/v1beta1/daemonsetstatus.go | 45 +- .../v1beta1/daemonsetupdatestrategy.go | 15 +- .../extensions/v1beta1/deployment.go | 63 +- .../extensions/v1beta1/deploymentcondition.go | 20 +- .../extensions/v1beta1/deploymentspec.go | 43 +- .../extensions/v1beta1/deploymentstatus.go | 36 +- .../extensions/v1beta1/deploymentstrategy.go | 10 +- .../extensions/v1beta1/httpingresspath.go | 30 +- .../v1beta1/httpingressrulevalue.go | 7 + .../extensions/v1beta1/ingress.go | 62 +- .../extensions/v1beta1/ingressbackend.go | 13 +- .../v1beta1/ingressloadbalanceringress.go | 11 +- .../v1beta1/ingressloadbalancerstatus.go | 3 + .../extensions/v1beta1/ingressportstatus.go | 17 +- .../extensions/v1beta1/ingressrule.go | 33 +- .../extensions/v1beta1/ingressrulevalue.go | 11 + .../extensions/v1beta1/ingressspec.go | 31 +- .../extensions/v1beta1/ingressstatus.go | 3 + .../extensions/v1beta1/ingresstls.go | 15 +- .../extensions/v1beta1/ipblock.go | 12 +- .../extensions/v1beta1/networkpolicy.go | 50 +- .../v1beta1/networkpolicyegressrule.go | 17 +- .../v1beta1/networkpolicyingressrule.go | 15 +- .../extensions/v1beta1/networkpolicypeer.go | 20 +- .../extensions/v1beta1/networkpolicyport.go | 18 +- .../extensions/v1beta1/networkpolicyspec.go | 39 +- .../extensions/v1beta1/replicaset.go | 70 +- .../extensions/v1beta1/replicasetcondition.go | 17 +- .../extensions/v1beta1/replicasetspec.go | 24 +- .../extensions/v1beta1/replicasetstatus.go | 27 +- .../extensions/v1beta1/rollbackconfig.go | 3 + .../v1beta1/rollingupdatedaemonset.go | 37 +- .../v1beta1/rollingupdatedeployment.go | 25 +- .../extensions/v1beta1/scale.go | 12 +- .../v1/exemptprioritylevelconfiguration.go | 28 +- .../flowcontrol/v1/flowdistinguishermethod.go | 5 + .../flowcontrol/v1/flowschema.go | 57 +- .../flowcontrol/v1/flowschemacondition.go | 20 +- .../flowcontrol/v1/flowschemaspec.go | 20 +- .../flowcontrol/v1/flowschemastatus.go | 3 + .../flowcontrol/v1/groupsubject.go | 6 + .../v1/limitedprioritylevelconfiguration.go | 55 +- .../flowcontrol/v1/limitresponse.go | 13 +- .../flowcontrol/v1/nonresourcepolicyrule.go | 18 +- .../flowcontrol/v1/policyruleswithsubjects.go | 18 +- .../v1/prioritylevelconfiguration.go | 56 +- .../v1/prioritylevelconfigurationcondition.go | 20 +- .../v1/prioritylevelconfigurationreference.go | 4 + .../v1/prioritylevelconfigurationspec.go | 22 +- .../v1/prioritylevelconfigurationstatus.go | 3 + .../flowcontrol/v1/queuingconfiguration.go | 27 +- .../flowcontrol/v1/resourcepolicyrule.go | 44 +- .../flowcontrol/v1/serviceaccountsubject.go | 8 +- .../flowcontrol/v1/subject.go | 14 +- .../flowcontrol/v1/usersubject.go | 4 + .../exemptprioritylevelconfiguration.go | 28 +- .../v1beta1/flowdistinguishermethod.go | 5 + .../flowcontrol/v1beta1/flowschema.go | 57 +- .../v1beta1/flowschemacondition.go | 20 +- .../flowcontrol/v1beta1/flowschemaspec.go | 20 +- .../flowcontrol/v1beta1/flowschemastatus.go | 3 + .../flowcontrol/v1beta1/groupsubject.go | 6 + .../limitedprioritylevelconfiguration.go | 51 +- .../flowcontrol/v1beta1/limitresponse.go | 13 +- .../v1beta1/nonresourcepolicyrule.go | 18 +- .../v1beta1/policyruleswithsubjects.go | 18 +- .../v1beta1/prioritylevelconfiguration.go | 56 +- .../prioritylevelconfigurationcondition.go | 20 +- .../prioritylevelconfigurationreference.go | 4 + .../v1beta1/prioritylevelconfigurationspec.go | 22 +- .../prioritylevelconfigurationstatus.go | 3 + .../v1beta1/queuingconfiguration.go | 27 +- .../flowcontrol/v1beta1/resourcepolicyrule.go | 44 +- .../v1beta1/serviceaccountsubject.go | 8 +- .../flowcontrol/v1beta1/subject.go | 14 +- .../flowcontrol/v1beta1/usersubject.go | 4 + .../exemptprioritylevelconfiguration.go | 28 +- .../v1beta2/flowdistinguishermethod.go | 5 + .../flowcontrol/v1beta2/flowschema.go | 57 +- .../v1beta2/flowschemacondition.go | 20 +- .../flowcontrol/v1beta2/flowschemaspec.go | 20 +- .../flowcontrol/v1beta2/flowschemastatus.go | 3 + .../flowcontrol/v1beta2/groupsubject.go | 6 + .../limitedprioritylevelconfiguration.go | 51 +- .../flowcontrol/v1beta2/limitresponse.go | 13 +- .../v1beta2/nonresourcepolicyrule.go | 18 +- .../v1beta2/policyruleswithsubjects.go | 18 +- .../v1beta2/prioritylevelconfiguration.go | 56 +- .../prioritylevelconfigurationcondition.go | 20 +- .../prioritylevelconfigurationreference.go | 4 + .../v1beta2/prioritylevelconfigurationspec.go | 22 +- .../prioritylevelconfigurationstatus.go | 3 + .../v1beta2/queuingconfiguration.go | 27 +- .../flowcontrol/v1beta2/resourcepolicyrule.go | 44 +- .../v1beta2/serviceaccountsubject.go | 8 +- .../flowcontrol/v1beta2/subject.go | 14 +- .../flowcontrol/v1beta2/usersubject.go | 4 + .../exemptprioritylevelconfiguration.go | 28 +- .../v1beta3/flowdistinguishermethod.go | 5 + .../flowcontrol/v1beta3/flowschema.go | 57 +- .../v1beta3/flowschemacondition.go | 20 +- .../flowcontrol/v1beta3/flowschemaspec.go | 20 +- .../flowcontrol/v1beta3/flowschemastatus.go | 3 + .../flowcontrol/v1beta3/groupsubject.go | 6 + .../limitedprioritylevelconfiguration.go | 51 +- .../flowcontrol/v1beta3/limitresponse.go | 13 +- .../v1beta3/nonresourcepolicyrule.go | 18 +- .../v1beta3/policyruleswithsubjects.go | 18 +- .../v1beta3/prioritylevelconfiguration.go | 56 +- .../prioritylevelconfigurationcondition.go | 20 +- .../prioritylevelconfigurationreference.go | 4 + .../v1beta3/prioritylevelconfigurationspec.go | 22 +- .../prioritylevelconfigurationstatus.go | 3 + .../v1beta3/queuingconfiguration.go | 27 +- .../flowcontrol/v1beta3/resourcepolicyrule.go | 44 +- .../v1beta3/serviceaccountsubject.go | 8 +- .../flowcontrol/v1beta3/subject.go | 14 +- .../flowcontrol/v1beta3/usersubject.go | 4 + .../imagepolicy/v1alpha1/imagereview.go | 54 +- .../v1alpha1/imagereviewcontainerspec.go | 3 + .../imagepolicy/v1alpha1/imagereviewspec.go | 13 +- .../imagepolicy/v1alpha1/imagereviewstatus.go | 14 +- .../applyconfigurations/internal/internal.go | 398 +- .../applyconfigurations/meta/v1/condition.go | 46 +- .../meta/v1/deleteoptions.go | 52 +- .../v1/groupresource.go} | 28 +- .../meta/v1/labelselector.go | 15 +- .../meta/v1/labelselectorrequirement.go | 14 +- .../meta/v1/managedfieldsentry.go | 39 +- .../applyconfigurations/meta/v1/objectmeta.go | 129 +- .../meta/v1/ownerreference.go | 32 +- .../meta/v1/preconditions.go | 8 +- .../applyconfigurations/meta/v1/typemeta.go | 15 +- .../networking/v1/httpingresspath.go | 29 +- .../networking/v1/httpingressrulevalue.go | 7 + .../networking/v1/ingress.go | 61 +- .../networking/v1/ingressbackend.go | 10 +- .../networking/v1/ingressclass.go | 54 +- .../v1/ingressclassparametersreference.go | 21 +- .../networking/v1/ingressclassspec.go | 13 +- .../v1/ingressloadbalanceringress.go | 11 +- .../v1/ingressloadbalancerstatus.go | 3 + .../networking/v1/ingressportstatus.go | 17 +- .../networking/v1/ingressrule.go | 33 +- .../networking/v1/ingressrulevalue.go | 5 + .../networking/v1/ingressservicebackend.go | 8 +- .../networking/v1/ingressspec.go | 31 +- .../networking/v1/ingressstatus.go | 3 + .../networking/v1/ingresstls.go | 15 +- .../networking/v1/ipaddress.go | 56 +- .../networking/v1/ipaddressspec.go | 4 + .../networking/v1/ipblock.go | 11 +- .../networking/v1/networkpolicy.go | 49 +- .../networking/v1/networkpolicyegressrule.go | 16 +- .../networking/v1/networkpolicyingressrule.go | 15 +- .../networking/v1/networkpolicypeer.go | 21 +- .../networking/v1/networkpolicyport.go | 18 +- .../networking/v1/networkpolicyspec.go | 40 +- .../networking/v1/parentreference.go | 12 +- .../networking/v1/servicebackendport.go | 10 +- .../networking/v1/servicecidr.go | 57 +- .../networking/v1/servicecidrspec.go | 5 + .../networking/v1/servicecidrstatus.go | 4 + .../networking/v1beta1/httpingresspath.go | 30 +- .../v1beta1/httpingressrulevalue.go | 7 + .../networking/v1beta1/ingress.go | 61 +- .../networking/v1beta1/ingressbackend.go | 13 +- .../networking/v1beta1/ingressclass.go | 54 +- .../ingressclassparametersreference.go | 21 +- .../networking/v1beta1/ingressclassspec.go | 13 +- .../v1beta1/ingressloadbalanceringress.go | 11 +- .../v1beta1/ingressloadbalancerstatus.go | 3 + .../networking/v1beta1/ingressportstatus.go | 17 +- .../networking/v1beta1/ingressrule.go | 33 +- .../networking/v1beta1/ingressrulevalue.go | 5 + .../networking/v1beta1/ingressspec.go | 31 +- .../networking/v1beta1/ingressstatus.go | 3 + .../networking/v1beta1/ingresstls.go | 15 +- .../networking/v1beta1/ipaddress.go | 56 +- .../networking/v1beta1/ipaddressspec.go | 4 + .../networking/v1beta1/parentreference.go | 12 +- .../networking/v1beta1/servicecidr.go | 57 +- .../networking/v1beta1/servicecidrspec.go | 5 + .../networking/v1beta1/servicecidrstatus.go | 4 + .../applyconfigurations/node/v1/overhead.go | 3 + .../node/v1/runtimeclass.go | 74 +- .../applyconfigurations/node/v1/scheduling.go | 15 +- .../node/v1alpha1/overhead.go | 3 + .../node/v1alpha1/runtimeclass.go | 55 +- .../node/v1alpha1/runtimeclassspec.go | 28 +- .../node/v1alpha1/scheduling.go | 15 +- .../node/v1beta1/overhead.go | 3 + .../node/v1beta1/runtimeclass.go | 74 +- .../node/v1beta1/scheduling.go | 15 +- .../applyconfigurations/policy/v1/eviction.go | 50 +- .../policy/v1/poddisruptionbudget.go | 56 +- .../policy/v1/poddisruptionbudgetspec.go | 42 +- .../policy/v1/poddisruptionbudgetstatus.go | 46 +- .../policy/v1beta1/eviction.go | 50 +- .../policy/v1beta1/poddisruptionbudget.go | 56 +- .../policy/v1beta1/poddisruptionbudgetspec.go | 43 +- .../v1beta1/poddisruptionbudgetstatus.go | 46 +- .../rbac/v1/aggregationrule.go | 4 + .../rbac/v1/clusterrole.go | 53 +- .../rbac/v1/clusterrolebinding.go | 54 +- .../applyconfigurations/rbac/v1/policyrule.go | 23 +- .../applyconfigurations/rbac/v1/role.go | 48 +- .../rbac/v1/rolebinding.go | 55 +- .../applyconfigurations/rbac/v1/roleref.go | 9 +- .../applyconfigurations/rbac/v1/subject.go | 17 +- .../rbac/v1alpha1/aggregationrule.go | 4 + .../rbac/v1alpha1/clusterrole.go | 54 +- .../rbac/v1alpha1/clusterrolebinding.go | 54 +- .../rbac/v1alpha1/policyrule.go | 23 +- .../applyconfigurations/rbac/v1alpha1/role.go | 49 +- .../rbac/v1alpha1/rolebinding.go | 55 +- .../rbac/v1alpha1/roleref.go | 9 +- .../rbac/v1alpha1/subject.go | 17 +- .../rbac/v1beta1/aggregationrule.go | 4 + .../rbac/v1beta1/clusterrole.go | 54 +- .../rbac/v1beta1/clusterrolebinding.go | 54 +- .../rbac/v1beta1/policyrule.go | 24 +- .../applyconfigurations/rbac/v1beta1/role.go | 49 +- .../rbac/v1beta1/rolebinding.go | 55 +- .../rbac/v1beta1/roleref.go | 9 +- .../rbac/v1beta1/subject.go | 17 +- .../resource/v1/allocateddevicestatus.go | 41 +- .../resource/v1/allocationresult.go | 16 +- .../resource/v1/capacityrequestpolicy.go | 35 +- .../resource/v1/capacityrequestpolicyrange.go | 26 +- .../resource/v1/capacityrequirements.go | 24 + .../resource/v1/celdeviceselector.go | 54 + .../resource/v1/counter.go | 3 + .../resource/v1/counterset.go | 17 +- .../applyconfigurations/resource/v1/device.go | 99 +- .../v1/deviceallocationconfiguration.go | 15 +- .../resource/v1/deviceallocationresult.go | 12 +- .../resource/v1/deviceattribute.go | 13 +- .../resource/v1/devicecapacity.go | 18 +- .../resource/v1/deviceclaim.go | 15 +- .../resource/v1/deviceclaimconfiguration.go | 8 + .../resource/v1/deviceclass.go | 61 +- .../resource/v1/deviceclassconfiguration.go | 2 + .../resource/v1/deviceclassspec.go | 25 +- .../resource/v1/deviceconfiguration.go | 5 + .../resource/v1/deviceconstraint.go | 37 +- .../resource/v1/devicecounterconsumption.go | 12 +- .../resource/v1/devicerequest.go | 38 +- .../v1/devicerequestallocationresult.go | 78 +- .../resource/v1/deviceselector.go | 3 + .../resource/v1/devicesubrequest.go | 91 +- .../resource/v1/devicetaint.go | 24 +- .../resource/v1/devicetoleration.go | 31 +- .../resource/v1/exactdevicerequest.go | 89 +- .../resource/v1/networkdevicedata.go | 23 +- .../resource/v1/opaquedeviceconfiguration.go | 19 +- .../resource/v1/resourceclaim.go | 63 +- .../v1/resourceclaimconsumerreference.go | 18 +- .../resource/v1/resourceclaimspec.go | 3 + .../resource/v1/resourceclaimstatus.go | 30 +- .../resource/v1/resourceclaimtemplate.go | 55 +- .../resource/v1/resourceclaimtemplatespec.go | 10 +- .../resource/v1/resourcepool.go | 30 +- .../resource/v1/resourceslice.go | 73 +- .../resource/v1/resourceslicespec.go | 65 +- .../resource/v1alpha3/celdeviceselector.go | 39 - .../resource/v1alpha3/deviceselector.go | 39 - .../resource/v1alpha3/devicetaint.go | 24 +- .../resource/v1alpha3/devicetaintrule.go | 64 +- .../resource/v1alpha3/devicetaintrulespec.go | 9 +- .../v1alpha3/devicetaintrulestatus.go | 70 + .../resource/v1alpha3/devicetaintselector.go | 48 +- .../resource/v1beta1/allocateddevicestatus.go | 41 +- .../resource/v1beta1/allocationresult.go | 16 +- .../resource/v1beta1/basicdevice.go | 94 +- .../resource/v1beta1/capacityrequestpolicy.go | 35 +- .../v1beta1/capacityrequestpolicyrange.go | 26 +- .../resource/v1beta1/capacityrequirements.go | 24 + .../resource/v1beta1/celdeviceselector.go | 54 + .../resource/v1beta1/counter.go | 3 + .../resource/v1beta1/counterset.go | 17 +- .../resource/v1beta1/device.go | 8 +- .../v1beta1/deviceallocationconfiguration.go | 15 +- .../v1beta1/deviceallocationresult.go | 12 +- .../resource/v1beta1/deviceattribute.go | 13 +- .../resource/v1beta1/devicecapacity.go | 18 +- .../resource/v1beta1/deviceclaim.go | 15 +- .../v1beta1/deviceclaimconfiguration.go | 8 + .../resource/v1beta1/deviceclass.go | 61 +- .../v1beta1/deviceclassconfiguration.go | 2 + .../resource/v1beta1/deviceclassspec.go | 25 +- .../resource/v1beta1/deviceconfiguration.go | 5 + .../resource/v1beta1/deviceconstraint.go | 37 +- .../v1beta1/devicecounterconsumption.go | 12 +- .../resource/v1beta1/devicerequest.go | 133 +- .../v1beta1/devicerequestallocationresult.go | 78 +- .../resource/v1beta1/deviceselector.go | 3 + .../resource/v1beta1/devicesubrequest.go | 92 +- .../resource/v1beta1/devicetaint.go | 24 +- .../resource/v1beta1/devicetoleration.go | 31 +- .../resource/v1beta1/networkdevicedata.go | 25 +- .../v1beta1/opaquedeviceconfiguration.go | 19 +- .../resource/v1beta1/resourceclaim.go | 63 +- .../v1beta1/resourceclaimconsumerreference.go | 18 +- .../resource/v1beta1/resourceclaimspec.go | 3 + .../resource/v1beta1/resourceclaimstatus.go | 30 +- .../resource/v1beta1/resourceclaimtemplate.go | 55 +- .../v1beta1/resourceclaimtemplatespec.go | 10 +- .../resource/v1beta1/resourcepool.go | 30 +- .../resource/v1beta1/resourceslice.go | 73 +- .../resource/v1beta1/resourceslicespec.go | 65 +- .../resource/v1beta2/allocateddevicestatus.go | 41 +- .../resource/v1beta2/allocationresult.go | 16 +- .../resource/v1beta2/capacityrequestpolicy.go | 35 +- .../v1beta2/capacityrequestpolicyrange.go | 26 +- .../resource/v1beta2/capacityrequirements.go | 24 + .../resource/v1beta2/celdeviceselector.go | 54 + .../resource/v1beta2/counter.go | 3 + .../resource/v1beta2/counterset.go | 17 +- .../resource/v1beta2/device.go | 99 +- .../v1beta2/deviceallocationconfiguration.go | 15 +- .../v1beta2/deviceallocationresult.go | 12 +- .../resource/v1beta2/deviceattribute.go | 13 +- .../resource/v1beta2/devicecapacity.go | 18 +- .../resource/v1beta2/deviceclaim.go | 15 +- .../v1beta2/deviceclaimconfiguration.go | 8 + .../resource/v1beta2/deviceclass.go | 61 +- .../v1beta2/deviceclassconfiguration.go | 2 + .../resource/v1beta2/deviceclassspec.go | 25 +- .../resource/v1beta2/deviceconfiguration.go | 5 + .../resource/v1beta2/deviceconstraint.go | 37 +- .../v1beta2/devicecounterconsumption.go | 12 +- .../resource/v1beta2/devicerequest.go | 38 +- .../v1beta2/devicerequestallocationresult.go | 78 +- .../resource/v1beta2/deviceselector.go | 3 + .../resource/v1beta2/devicesubrequest.go | 91 +- .../resource/v1beta2/devicetaint.go | 24 +- .../resource/v1beta2/devicetoleration.go | 31 +- .../resource/v1beta2/exactdevicerequest.go | 89 +- .../resource/v1beta2/networkdevicedata.go | 23 +- .../v1beta2/opaquedeviceconfiguration.go | 19 +- .../resource/v1beta2/resourceclaim.go | 63 +- .../v1beta2/resourceclaimconsumerreference.go | 18 +- .../resource/v1beta2/resourceclaimspec.go | 3 + .../resource/v1beta2/resourceclaimstatus.go | 30 +- .../resource/v1beta2/resourceclaimtemplate.go | 55 +- .../v1beta2/resourceclaimtemplatespec.go | 10 +- .../resource/v1beta2/resourcepool.go | 30 +- .../resource/v1beta2/resourceslice.go | 73 +- .../resource/v1beta2/resourceslicespec.go | 65 +- .../scheduling/v1/priorityclass.go | 67 +- .../v1alpha1/gangschedulingpolicy.go | 44 + .../scheduling/v1alpha1/podgroup.go | 53 + .../scheduling/v1alpha1/podgrouppolicy.go | 58 + .../scheduling/v1alpha1/priorityclass.go | 68 +- .../v1alpha1/typedlocalobjectreference.go | 67 + .../scheduling/v1alpha1/workload.go | 279 + .../scheduling/v1alpha1/workloadspec.go | 61 + .../scheduling/v1beta1/priorityclass.go | 68 +- .../storage/v1/csidriver.go | 59 +- .../storage/v1/csidriverspec.go | 170 +- .../applyconfigurations/storage/v1/csinode.go | 57 +- .../storage/v1/csinodedriver.go | 34 +- .../storage/v1/csinodespec.go | 4 + .../storage/v1/csistoragecapacity.go | 113 +- .../storage/v1/storageclass.go | 80 +- .../storage/v1/tokenrequest.go | 10 +- .../storage/v1/volumeattachment.go | 60 +- .../storage/v1/volumeattachmentsource.go | 16 +- .../storage/v1/volumeattachmentspec.go | 12 +- .../storage/v1/volumeattachmentstatus.go | 24 +- .../storage/v1/volumeattributesclass.go | 67 +- .../storage/v1/volumeerror.go | 15 +- .../storage/v1/volumenoderesources.go | 6 + .../storage/v1alpha1/csistoragecapacity.go | 113 +- .../storage/v1alpha1/volumeattachment.go | 60 +- .../v1alpha1/volumeattachmentsource.go | 16 +- .../storage/v1alpha1/volumeattachmentspec.go | 12 +- .../v1alpha1/volumeattachmentstatus.go | 24 +- .../storage/v1alpha1/volumeattributesclass.go | 67 +- .../storage/v1alpha1/volumeerror.go | 15 +- .../storage/v1beta1/csidriver.go | 62 +- .../storage/v1beta1/csidriverspec.go | 170 +- .../storage/v1beta1/csinode.go | 58 +- .../storage/v1beta1/csinodedriver.go | 33 +- .../storage/v1beta1/csinodespec.go | 4 + .../storage/v1beta1/csistoragecapacity.go | 113 +- .../storage/v1beta1/storageclass.go | 80 +- .../storage/v1beta1/tokenrequest.go | 10 +- .../storage/v1beta1/volumeattachment.go | 60 +- .../storage/v1beta1/volumeattachmentsource.go | 16 +- .../storage/v1beta1/volumeattachmentspec.go | 12 +- .../storage/v1beta1/volumeattachmentstatus.go | 24 +- .../storage/v1beta1/volumeattributesclass.go | 67 +- .../storage/v1beta1/volumeerror.go | 15 +- .../storage/v1beta1/volumenoderesources.go | 6 + .../v1alpha1/migrationcondition.go | 81 - .../storageversionmigration.go | 65 +- .../storageversionmigrationspec.go | 24 +- .../storageversionmigrationstatus.go | 18 +- .../client-go/applyconfigurations/utils.go | 56 +- .../client-go/discovery/discovery_client.go | 30 +- vendor/k8s.io/client-go/features/features.go | 43 +- .../client-go/features/known_features.go | 46 +- vendor/k8s.io/client-go/gentype/type.go | 8 +- .../v1/mutatingwebhookconfiguration.go | 4 +- .../v1/validatingadmissionpolicy.go | 4 +- .../v1/validatingadmissionpolicybinding.go | 4 +- .../v1/validatingwebhookconfiguration.go | 4 +- .../v1alpha1/mutatingadmissionpolicy.go | 4 +- .../mutatingadmissionpolicybinding.go | 4 +- .../v1alpha1/validatingadmissionpolicy.go | 4 +- .../validatingadmissionpolicybinding.go | 4 +- .../v1beta1/mutatingadmissionpolicy.go | 4 +- .../v1beta1/mutatingadmissionpolicybinding.go | 4 +- .../v1beta1/mutatingwebhookconfiguration.go | 4 +- .../v1beta1/validatingadmissionpolicy.go | 4 +- .../validatingadmissionpolicybinding.go | 4 +- .../v1beta1/validatingwebhookconfiguration.go | 4 +- .../v1alpha1/storageversion.go | 4 +- .../informers/apps/v1/controllerrevision.go | 4 +- .../client-go/informers/apps/v1/daemonset.go | 4 +- .../client-go/informers/apps/v1/deployment.go | 4 +- .../client-go/informers/apps/v1/replicaset.go | 4 +- .../informers/apps/v1/statefulset.go | 4 +- .../apps/v1beta1/controllerrevision.go | 4 +- .../informers/apps/v1beta1/deployment.go | 4 +- .../informers/apps/v1beta1/statefulset.go | 4 +- .../apps/v1beta2/controllerrevision.go | 4 +- .../informers/apps/v1beta2/daemonset.go | 4 +- .../informers/apps/v1beta2/deployment.go | 4 +- .../informers/apps/v1beta2/replicaset.go | 4 +- .../informers/apps/v1beta2/statefulset.go | 4 +- .../autoscaling/v1/horizontalpodautoscaler.go | 4 +- .../autoscaling/v2/horizontalpodautoscaler.go | 4 +- .../v2beta1/horizontalpodautoscaler.go | 4 +- .../v2beta2/horizontalpodautoscaler.go | 4 +- .../client-go/informers/batch/v1/cronjob.go | 4 +- .../client-go/informers/batch/v1/job.go | 4 +- .../informers/batch/v1beta1/cronjob.go | 4 +- .../v1/certificatesigningrequest.go | 4 +- .../v1alpha1/clustertrustbundle.go | 4 +- .../certificates/v1alpha1/interface.go | 7 - .../v1beta1/certificatesigningrequest.go | 4 +- .../v1beta1/clustertrustbundle.go | 4 +- .../certificates/v1beta1/interface.go | 7 + .../podcertificaterequest.go | 28 +- .../informers/coordination/v1/lease.go | 4 +- .../coordination/v1alpha2/leasecandidate.go | 4 +- .../informers/coordination/v1beta1/lease.go | 4 +- .../coordination/v1beta1/leasecandidate.go | 4 +- .../informers/core/v1/componentstatus.go | 4 +- .../client-go/informers/core/v1/configmap.go | 4 +- .../client-go/informers/core/v1/endpoints.go | 4 +- .../client-go/informers/core/v1/event.go | 4 +- .../client-go/informers/core/v1/limitrange.go | 4 +- .../client-go/informers/core/v1/namespace.go | 4 +- .../client-go/informers/core/v1/node.go | 4 +- .../informers/core/v1/persistentvolume.go | 4 +- .../core/v1/persistentvolumeclaim.go | 4 +- .../k8s.io/client-go/informers/core/v1/pod.go | 4 +- .../informers/core/v1/podtemplate.go | 4 +- .../core/v1/replicationcontroller.go | 4 +- .../informers/core/v1/resourcequota.go | 4 +- .../client-go/informers/core/v1/secret.go | 4 +- .../client-go/informers/core/v1/service.go | 4 +- .../informers/core/v1/serviceaccount.go | 4 +- .../informers/discovery/v1/endpointslice.go | 4 +- .../discovery/v1beta1/endpointslice.go | 4 +- .../client-go/informers/events/v1/event.go | 4 +- .../informers/events/v1beta1/event.go | 4 +- .../informers/extensions/v1beta1/daemonset.go | 4 +- .../extensions/v1beta1/deployment.go | 4 +- .../informers/extensions/v1beta1/ingress.go | 4 +- .../extensions/v1beta1/networkpolicy.go | 4 +- .../extensions/v1beta1/replicaset.go | 4 +- vendor/k8s.io/client-go/informers/factory.go | 3 +- .../informers/flowcontrol/v1/flowschema.go | 4 +- .../v1/prioritylevelconfiguration.go | 4 +- .../flowcontrol/v1beta1/flowschema.go | 4 +- .../v1beta1/prioritylevelconfiguration.go | 4 +- .../flowcontrol/v1beta2/flowschema.go | 4 +- .../v1beta2/prioritylevelconfiguration.go | 4 +- .../flowcontrol/v1beta3/flowschema.go | 4 +- .../v1beta3/prioritylevelconfiguration.go | 4 +- vendor/k8s.io/client-go/informers/generic.go | 14 +- .../informers/networking/v1/ingress.go | 4 +- .../informers/networking/v1/ingressclass.go | 4 +- .../informers/networking/v1/ipaddress.go | 4 +- .../informers/networking/v1/networkpolicy.go | 4 +- .../informers/networking/v1/servicecidr.go | 4 +- .../informers/networking/v1beta1/ingress.go | 4 +- .../networking/v1beta1/ingressclass.go | 4 +- .../informers/networking/v1beta1/ipaddress.go | 4 +- .../networking/v1beta1/servicecidr.go | 4 +- .../informers/node/v1/runtimeclass.go | 4 +- .../informers/node/v1alpha1/runtimeclass.go | 4 +- .../informers/node/v1beta1/runtimeclass.go | 4 +- .../policy/v1/poddisruptionbudget.go | 4 +- .../policy/v1beta1/poddisruptionbudget.go | 4 +- .../informers/rbac/v1/clusterrole.go | 4 +- .../informers/rbac/v1/clusterrolebinding.go | 4 +- .../client-go/informers/rbac/v1/role.go | 4 +- .../informers/rbac/v1/rolebinding.go | 4 +- .../informers/rbac/v1alpha1/clusterrole.go | 4 +- .../rbac/v1alpha1/clusterrolebinding.go | 4 +- .../client-go/informers/rbac/v1alpha1/role.go | 4 +- .../informers/rbac/v1alpha1/rolebinding.go | 4 +- .../informers/rbac/v1beta1/clusterrole.go | 4 +- .../rbac/v1beta1/clusterrolebinding.go | 4 +- .../client-go/informers/rbac/v1beta1/role.go | 4 +- .../informers/rbac/v1beta1/rolebinding.go | 4 +- .../informers/resource/v1/deviceclass.go | 4 +- .../informers/resource/v1/resourceclaim.go | 4 +- .../resource/v1/resourceclaimtemplate.go | 4 +- .../informers/resource/v1/resourceslice.go | 4 +- .../resource/v1alpha3/devicetaintrule.go | 4 +- .../informers/resource/v1beta1/deviceclass.go | 4 +- .../resource/v1beta1/resourceclaim.go | 4 +- .../resource/v1beta1/resourceclaimtemplate.go | 4 +- .../resource/v1beta1/resourceslice.go | 4 +- .../informers/resource/v1beta2/deviceclass.go | 4 +- .../resource/v1beta2/resourceclaim.go | 4 +- .../resource/v1beta2/resourceclaimtemplate.go | 4 +- .../resource/v1beta2/resourceslice.go | 4 +- .../informers/scheduling/v1/priorityclass.go | 4 +- .../scheduling/v1alpha1/interface.go | 7 + .../scheduling/v1alpha1/priorityclass.go | 4 +- .../informers/scheduling/v1alpha1/workload.go | 102 + .../scheduling/v1beta1/priorityclass.go | 4 +- .../informers/storage/v1/csidriver.go | 4 +- .../client-go/informers/storage/v1/csinode.go | 4 +- .../storage/v1/csistoragecapacity.go | 4 +- .../informers/storage/v1/storageclass.go | 4 +- .../informers/storage/v1/volumeattachment.go | 4 +- .../storage/v1/volumeattributesclass.go | 4 +- .../storage/v1alpha1/csistoragecapacity.go | 4 +- .../storage/v1alpha1/volumeattachment.go | 4 +- .../storage/v1alpha1/volumeattributesclass.go | 4 +- .../informers/storage/v1beta1/csidriver.go | 4 +- .../informers/storage/v1beta1/csinode.go | 4 +- .../storage/v1beta1/csistoragecapacity.go | 4 +- .../informers/storage/v1beta1/storageclass.go | 4 +- .../storage/v1beta1/volumeattachment.go | 4 +- .../storage/v1beta1/volumeattributesclass.go | 4 +- .../informers/storagemigration/interface.go | 12 +- .../{v1alpha1 => v1beta1}/interface.go | 2 +- .../storageversionmigration.go | 28 +- .../k8s.io/client-go/kubernetes/clientset.go | 16 +- .../client-go/kubernetes/scheme/register.go | 4 +- .../v1alpha1/certificates_client.go | 5 - .../v1alpha1/generated_expansion.go | 2 - .../v1beta1/certificates_client.go | 5 + .../v1beta1/generated_expansion.go | 2 + .../podcertificaterequest.go | 38 +- .../resource/v1alpha3/devicetaintrule.go | 4 + .../v1alpha1/generated_expansion.go | 2 + .../scheduling/v1alpha1/scheduling_client.go | 5 + .../typed/scheduling/v1alpha1/workload.go | 71 + .../{v1alpha1 => v1beta1}/doc.go | 2 +- .../generated_expansion.go | 2 +- .../storagemigration_client.go | 36 +- .../storageversionmigration.go | 38 +- .../v1alpha1/expansion_generated.go | 8 - .../v1beta1/expansion_generated.go | 8 + .../podcertificaterequest.go | 18 +- .../v1alpha1/expansion_generated.go | 8 + .../listers/scheduling/v1alpha1/workload.go | 70 + .../expansion_generated.go | 2 +- .../storageversionmigration.go | 12 +- .../pkg/apis/clientauthentication/v1/doc.go | 1 + .../v1/zz_generated.model_name.go | 42 + .../apis/clientauthentication/v1beta1/doc.go | 1 + .../v1beta1/zz_generated.model_name.go | 42 + .../plugin/pkg/client/auth/exec/exec.go | 157 +- .../plugin/pkg/client/auth/exec/metrics.go | 16 + vendor/k8s.io/client-go/rest/.mockery.yaml | 11 +- vendor/k8s.io/client-go/rest/urlbackoff.go | 4 +- vendor/k8s.io/client-go/rest/warnings.go | 7 +- vendor/k8s.io/client-go/testing/fixture.go | 11 + .../client-go/tools/cache/controller.go | 127 +- .../client-go/tools/cache/delta_fifo.go | 2 +- .../tools/cache/expiration_cache_fakes.go | 2 +- vendor/k8s.io/client-go/tools/cache/fifo.go | 17 + vendor/k8s.io/client-go/tools/cache/index.go | 4 +- .../k8s.io/client-go/tools/cache/listwatch.go | 30 + .../k8s.io/client-go/tools/cache/reflector.go | 30 +- .../client-go/tools/cache/shared_informer.go | 7 + vendor/k8s.io/client-go/tools/cache/store.go | 71 + .../client-go/tools/cache/the_real_fifo.go | 120 +- .../tools/cache/thread_safe_store.go | 81 +- .../client-go/tools/clientcmd/api/types.go | 49 + .../api/v1/zz_generated.conversion.go | 1 + .../clientcmd/api/zz_generated.deepcopy.go | 38 + .../tools/clientcmd/client_config.go | 15 + .../client-go/tools/clientcmd/loader.go | 5 +- .../client-go/tools/clientcmd/validation.go | 5 + .../tools/events/event_broadcaster.go | 2 +- .../tools/leaderelection/leaderelection.go | 48 +- .../tools/leaderelection/leasecandidate.go | 15 +- .../k8s.io/client-go/tools/metrics/metrics.go | 17 + vendor/k8s.io/client-go/tools/record/event.go | 2 +- .../client-go/tools/record/events_cache.go | 4 +- .../k8s.io/client-go/tools/reference/ref.go | 5 +- .../client-go/util/watchlist/watch_list.go | 99 + .../k8s.io/client-go/util/workqueue/queue.go | 44 +- vendor/k8s.io/code-generator/LICENSE | 202 + .../cmd/applyconfiguration-gen/args/args.go | 88 + .../args/externaltypes.go | 122 + .../generators/applyconfiguration.go | 565 + .../generators/internal.go | 98 + .../generators/jsontagutil.go | 99 + .../generators/openapi.go | 196 + .../generators/refgraph.go | 175 + .../generators/targets.go | 320 + .../generators/types.go | 37 + .../applyconfiguration-gen/generators/util.go | 177 + .../client-gen/generators/util/gvpackages.go | 30 + .../cmd/client-gen/generators/util/tags.go | 344 + .../cmd/client-gen/types/helpers.go | 121 + .../cmd/client-gen/types/types.go | 109 + .../code-generator/pkg/util/comments.go | 92 + .../pkg/util/plural_exceptions.go | 37 + .../component-base/compatibility/OWNERS | 1 + .../component-base/compatibility/registry.go | 120 +- .../featuregate/feature_gate.go | 386 +- .../k8s.io/component-base/metrics/counter.go | 36 +- vendor/k8s.io/component-base/metrics/desc.go | 20 +- vendor/k8s.io/component-base/metrics/gauge.go | 19 + .../component-base/metrics/histogram.go | 24 +- .../metrics/legacyregistry/registry.go | 5 + .../k8s.io/component-base/metrics/metric.go | 42 +- .../k8s.io/component-base/metrics/registry.go | 59 +- .../k8s.io/component-base/metrics/summary.go | 8 +- .../component-base/tracing/api/v1/doc.go | 2 + .../tracing/api/v1/zz_generated.model_name.go | 27 + vendor/k8s.io/component-base/version/base.go | 2 +- .../pkg/features/kube_features.go | 8 + vendor/k8s.io/gengo/v2/LICENSE | 202 + vendor/k8s.io/gengo/v2/Makefile | 14 + vendor/k8s.io/gengo/v2/README.md | 53 + vendor/k8s.io/gengo/v2/codetags/extractor.go | 85 + vendor/k8s.io/gengo/v2/codetags/parser.go | 407 + vendor/k8s.io/gengo/v2/codetags/scanner.go | 228 + vendor/k8s.io/gengo/v2/codetags/types.go | 169 + vendor/k8s.io/gengo/v2/comments.go | 194 + vendor/k8s.io/gengo/v2/execute.go | 98 + vendor/k8s.io/gengo/v2/generator/doc.go | 31 + .../gengo/v2/generator/error_tracker.go | 50 + vendor/k8s.io/gengo/v2/generator/execute.go | 308 + vendor/k8s.io/gengo/v2/generator/generator.go | 214 + .../k8s.io/gengo/v2/generator/go_generator.go | 61 + .../gengo/v2/generator/import_tracker.go | 96 + .../gengo/v2/generator/simple_target.go | 77 + .../gengo/v2/generator/snippet_writer.go | 188 + vendor/k8s.io/gengo/v2/namer/doc.go | 31 + .../k8s.io/gengo/v2/namer/import_tracker.go | 121 + vendor/k8s.io/gengo/v2/namer/namer.go | 402 + vendor/k8s.io/gengo/v2/namer/order.go | 72 + vendor/k8s.io/gengo/v2/namer/plural_namer.go | 120 + vendor/k8s.io/gengo/v2/parser/doc.go | 19 + vendor/k8s.io/gengo/v2/parser/parse.go | 1003 + vendor/k8s.io/gengo/v2/parser/parse_122.go | 38 + .../k8s.io/gengo/v2/parser/parse_pre_122.go | 34 + vendor/k8s.io/gengo/v2/types/doc.go | 19 + vendor/k8s.io/gengo/v2/types/types.go | 575 + vendor/k8s.io/klog/v2/README.md | 2 - .../klog/v2/internal/serialize/keyvalues.go | 232 +- .../internal/serialize/keyvalues_no_slog.go | 10 +- .../v2/internal/serialize/keyvalues_slog.go | 12 +- vendor/k8s.io/klog/v2/klog.go | 87 +- vendor/k8s.io/klog/v2/klogr.go | 4 +- vendor/k8s.io/klog/v2/klogr_slog.go | 11 +- vendor/k8s.io/klog/v2/textlogger/options.go | 18 + .../k8s.io/klog/v2/textlogger/textlogger.go | 53 +- .../pkg/apis/apiregistration/v1/doc.go | 4 +- .../apis/apiregistration/v1/generated.pb.go | 251 +- .../v1/generated.protomessage.pb.go | 34 + .../v1/zz_generated.model_name.go | 52 + .../pkg/apis/apiregistration/v1beta1/doc.go | 4 +- .../apiregistration/v1beta1/generated.pb.go | 252 +- .../v1beta1/generated.protomessage.pb.go | 34 + .../v1beta1/zz_generated.model_name.go | 52 + vendor/k8s.io/kube-openapi/pkg/util/trie.go | 79 + vendor/k8s.io/kube-openapi/pkg/util/util.go | 126 + vendor/modules.txt | 1128 +- vendor/mvdan.cc/gofumpt/format/format.go | 83 +- vendor/mvdan.cc/gofumpt/format/rewrite.go | 4 +- .../internal/govendor/go/doc/comment/std.go | 1 + .../internal/govendor/go/format/internal.go | 8 +- .../internal/govendor/go/printer/nodes.go | 20 +- .../internal/govendor/go/printer/printer.go | 24 +- .../gofumpt/internal/version/version.go | 54 +- vendor/mvdan.cc/unparam/check/check.go | 34 +- .../pkg/azclient/.golangci.yml | 80 +- .../pkg/azclient/Makefile | 2 +- .../pkg/azclient/accountclient/custom.go | 2 +- .../pkg/azclient/accountclient/interface.go | 4 +- .../mock_accountclient/interface.go | 2 +- .../accountclient/zz_generated_client.go | 2 +- .../azclient/blobcontainerclient/custom.go | 8 +- .../azclient/blobcontainerclient/interface.go | 4 +- .../mock_blobcontainerclient/interface.go | 2 +- .../zz_generated_client.go | 2 +- .../blobservicepropertiesclient/custom.go | 6 +- .../blobservicepropertiesclient/interface.go | 4 +- .../interface.go | 2 +- .../zz_generated_client.go | 2 +- .../pkg/azclient/deploymentclient/custom.go | 4 +- .../pkg/azclient/factory_conf.go | 2 +- .../fileservicepropertiesclient/custom.go | 6 +- .../fileservicepropertiesclient/interface.go | 4 +- .../interface.go | 2 +- .../zz_generated_client.go | 2 +- .../pkg/azclient/fileshareclient/custom.go | 4 +- .../pkg/azclient/fileshareclient/interface.go | 4 +- .../mock_fileshareclient/interface.go | 2 +- .../fileshareclient/zz_generated_client.go | 2 +- .../pkg/azclient/interfaceclient/custom.go | 2 +- .../azclient/loadbalancerclient/interface.go | 2 +- .../loadbalancerclient/zz_generated_client.go | 2 +- .../pkg/azclient/providerclient/custom.go | 4 +- .../azclient/resourcegroupclient/custom.go | 2 +- .../pkg/azclient/snapshotclient/custom.go | 2 +- .../azclient/utils/armbalancer/transport.go | 2 +- .../azclient/virtualmachineclient/custom.go | 6 +- .../virtualmachinescalesetvmclient/custom.go | 4 +- .../cloud-provider-azure/pkg/consts/consts.go | 2 + .../pkg/consts/helpers.go | 2 +- .../controller-runtime/.golangci.yml | 17 +- .../controller-runtime/.gomodcheck.yaml | 4 + .../sigs.k8s.io/controller-runtime/Makefile | 12 +- .../sigs.k8s.io/controller-runtime/README.md | 1 + .../sigs.k8s.io/controller-runtime/alias.go | 17 +- .../pkg/builder/controller.go | 2 +- .../controller-runtime/pkg/builder/webhook.go | 178 +- .../controller-runtime/pkg/cache/cache.go | 4 +- .../pkg/cache/delegating_by_gvk_cache.go | 6 +- .../pkg/cache/informer_cache.go | 29 +- .../pkg/cache/internal/cache_reader.go | 16 +- .../pkg/cache/internal/informers.go | 25 +- .../pkg/client/apiutil/apimachinery.go | 2 +- .../pkg/client/apiutil/errors.go | 4 +- .../controller-runtime/pkg/client/client.go | 60 + .../pkg/client/config/config.go | 6 - .../controller-runtime/pkg/client/dryrun.go | 4 + .../pkg/client/fake/client.go | 339 +- .../pkg/client/fake/versioned_tracker.go | 368 + .../pkg/client/fieldowner.go | 4 + .../pkg/client/fieldvalidation.go | 7 + .../pkg/client/interceptor/intercept.go | 8 + .../pkg/client/interfaces.go | 3 + .../pkg/client/namespaced_client.go | 49 +- .../controller-runtime/pkg/client/options.go | 19 + .../controller-runtime/pkg/client/patch.go | 11 +- .../pkg/client/typed_client.go | 33 + .../pkg/client/unstructured_client.go | 32 + .../controller-runtime/pkg/cluster/cluster.go | 28 +- .../pkg/cluster/internal.go | 5 + .../pkg/config/controller.go | 2 +- .../pkg/controller/controller.go | 6 +- .../controllerutil/controllerutil.go | 16 +- .../controller/priorityqueue/priorityqueue.go | 385 +- .../pkg/envtest/komega/equalobject.go | 10 +- .../controller-runtime/pkg/healthz/healthz.go | 4 +- .../pkg/internal/controller/controller.go | 29 +- .../internal/controller/metrics/metrics.go | 10 + .../pkg/internal/flock/flock_other.go | 2 +- .../pkg/internal/flock/flock_unix.go | 1 - .../pkg/internal/metrics/workqueue.go | 48 +- .../pkg/internal/recorder/recorder.go | 106 +- .../pkg/internal/source/event_handler.go | 6 +- .../pkg/internal/source/kind.go | 11 +- .../pkg/internal/testing/addr/manager.go | 8 +- .../pkg/internal/testing/process/arguments.go | 8 +- .../testing/process/procattr_other.go | 1 - .../internal/testing/process/procattr_unix.go | 1 - .../pkg/leaderelection/leader_election.go | 11 +- .../controller-runtime/pkg/log/deleg.go | 10 +- .../controller-runtime/pkg/log/log.go | 2 +- .../controller-runtime/pkg/log/null.go | 6 +- .../pkg/manager/internal.go | 24 +- .../controller-runtime/pkg/manager/manager.go | 36 +- .../pkg/manager/signals/signal_posix.go | 1 - .../pkg/reconcile/reconcile.go | 7 +- .../pkg/recorder/recorder.go | 7 +- .../pkg/webhook/admission/decode.go | 2 +- .../pkg/webhook/admission/defaulter_custom.go | 73 +- .../pkg/webhook/admission/validator_custom.go | 60 +- .../controller-runtime/pkg/webhook/alias.go | 8 +- .../pkg/webhook/conversion/conversion.go | 17 +- .../webhook/conversion/conversion_hubspoke.go | 173 + .../webhook/conversion/conversion_registry.go | 57 + .../pkg/webhook/internal/metrics/metrics.go | 1 + .../cmd/controller-gen/main.go | 29 +- .../pkg/applyconfiguration/doc.go | 18 + .../pkg/applyconfiguration/gen.go | 254 + .../zz_generated.markerhelp.go | 41 + .../controller-tools/pkg/crd/conv.go | 6 +- .../controller-tools/pkg/crd/desc_visitor.go | 8 +- .../controller-tools/pkg/crd/flatten.go | 59 +- .../controller-tools/pkg/crd/gen.go | 35 +- .../controller-tools/pkg/crd/known_types.go | 58 +- .../controller-tools/pkg/crd/markers/crd.go | 51 +- .../pkg/crd/markers/register.go | 2 +- .../pkg/crd/markers/topology.go | 32 +- .../pkg/crd/markers/validation.go | 314 +- .../crd/markers/zz_generated.markerhelp.go | 61 +- .../controller-tools/pkg/crd/parser.go | 31 +- .../controller-tools/pkg/crd/schema.go | 188 +- .../pkg/crd/schema_visitor.go | 14 +- .../controller-tools/pkg/crd/spec.go | 27 +- .../controller-tools/pkg/deepcopy/gen.go | 4 +- .../controller-tools/pkg/deepcopy/traverse.go | 68 +- .../controller-tools/pkg/genall/genall.go | 25 +- .../pkg/genall/help/pretty/help.go | 10 +- .../pkg/genall/help/pretty/print.go | 2 +- .../pkg/genall/help/pretty/table.go | 8 +- .../controller-tools/pkg/genall/help/sort.go | 14 +- .../controller-tools/pkg/genall/help/types.go | 16 +- .../controller-tools/pkg/genall/options.go | 16 +- .../controller-tools/pkg/genall/output.go | 6 + .../controller-tools/pkg/internal/crd/crd.go | 23 + .../controller-tools/pkg/loader/errors.go | 4 +- .../controller-tools/pkg/loader/loader.go | 10 +- .../controller-tools/pkg/markers/collect.go | 6 +- .../controller-tools/pkg/markers/parse.go | 45 +- .../controller-tools/pkg/markers/reg.go | 2 +- .../controller-tools/pkg/markers/zip.go | 2 +- .../controller-tools/pkg/rbac/parser.go | 39 +- .../pkg/rbac/zz_generated.markerhelp.go | 4 + .../controller-tools/pkg/schemapatcher/gen.go | 15 +- .../schemapatcher/internal/yaml/convert.go | 2 +- .../controller-tools/pkg/webhook/parser.go | 58 +- .../pkg/webhook/zz_generated.markerhelp.go | 12 + 5115 files changed, 335265 insertions(+), 204461 deletions(-) rename vendor/{github.com => codeberg.org}/chavacava/garif/.gitignore (100%) rename vendor/{github.com => codeberg.org}/chavacava/garif/LICENSE (100%) rename vendor/{github.com => codeberg.org}/chavacava/garif/README.md (97%) rename vendor/{github.com => codeberg.org}/chavacava/garif/constructors.go (100%) rename vendor/{github.com => codeberg.org}/chavacava/garif/decorators.go (100%) rename vendor/{github.com => codeberg.org}/chavacava/garif/doc.go (90%) rename vendor/{github.com => codeberg.org}/chavacava/garif/enums.go (100%) rename vendor/{github.com => codeberg.org}/chavacava/garif/io.go (100%) rename vendor/{github.com => codeberg.org}/chavacava/garif/models.go (98%) rename vendor/{github.com => codeberg.org}/polyfloyd/go-errorlint/LICENSE (100%) rename vendor/{github.com => codeberg.org}/polyfloyd/go-errorlint/errorlint/allowed.go (100%) rename vendor/{github.com => codeberg.org}/polyfloyd/go-errorlint/errorlint/analysis.go (94%) create mode 100644 vendor/codeberg.org/polyfloyd/go-errorlint/errorlint/lint.go rename vendor/{github.com => codeberg.org}/polyfloyd/go-errorlint/errorlint/options.go (56%) rename vendor/{github.com => codeberg.org}/polyfloyd/go-errorlint/errorlint/printf.go (100%) rename vendor/{github.com/GaijinEntertainment/go-exhaustruct/v3 => dev.gaijin.team/go/exhaustruct/v4}/LICENSE (100%) rename vendor/{github.com/GaijinEntertainment/go-exhaustruct/v3 => dev.gaijin.team/go/exhaustruct/v4}/analyzer/analyzer.go (52%) create mode 100644 vendor/dev.gaijin.team/go/exhaustruct/v4/analyzer/config.go rename vendor/{github.com/GaijinEntertainment/go-exhaustruct/v3 => dev.gaijin.team/go/exhaustruct/v4}/internal/comment/cache.go (100%) rename vendor/{github.com/GaijinEntertainment/go-exhaustruct/v3 => dev.gaijin.team/go/exhaustruct/v4}/internal/comment/directive.go (100%) create mode 100644 vendor/dev.gaijin.team/go/exhaustruct/v4/internal/pattern/list.go rename vendor/{github.com/GaijinEntertainment/go-exhaustruct/v3 => dev.gaijin.team/go/exhaustruct/v4}/internal/structure/fields-cache.go (100%) rename vendor/{github.com/GaijinEntertainment/go-exhaustruct/v3 => dev.gaijin.team/go/exhaustruct/v4}/internal/structure/fields.go (100%) create mode 100644 vendor/dev.gaijin.team/go/golib/LICENSE create mode 100644 vendor/dev.gaijin.team/go/golib/e/doc.go create mode 100644 vendor/dev.gaijin.team/go/golib/e/err.go create mode 100644 vendor/dev.gaijin.team/go/golib/e/log.go create mode 100644 vendor/dev.gaijin.team/go/golib/fields/dict.go create mode 100644 vendor/dev.gaijin.team/go/golib/fields/doc.go create mode 100644 vendor/dev.gaijin.team/go/golib/fields/field.go create mode 100644 vendor/dev.gaijin.team/go/golib/fields/list.go create mode 100644 vendor/github.com/AdminBenni/iota-mixing/LICENSE create mode 100644 vendor/github.com/AdminBenni/iota-mixing/pkg/analyzer/analyzer.go create mode 100644 vendor/github.com/AdminBenni/iota-mixing/pkg/analyzer/flags/flags.go create mode 100644 vendor/github.com/AlwxSin/noinlineerr/.gitignore create mode 100644 vendor/github.com/AlwxSin/noinlineerr/.golangci.yml create mode 100644 vendor/github.com/AlwxSin/noinlineerr/.goreleaser.yml rename vendor/github.com/{sivchari/tenv => AlwxSin/noinlineerr}/LICENSE (97%) create mode 100644 vendor/github.com/AlwxSin/noinlineerr/README.md create mode 100644 vendor/github.com/AlwxSin/noinlineerr/noinlineerr.go create mode 100644 vendor/github.com/Antonboom/testifylint/internal/checkers/equal_values.go create mode 100644 vendor/github.com/Antonboom/testifylint/internal/checkers/suite_method_signature.go create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azure_powershell_credential.go create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/developer_credential_util_nonwindows.go create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/developer_credential_util_windows.go delete mode 100644 vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/autorest.md rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/CHANGELOG.md (89%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/LICENSE.txt (100%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/README.md (99%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/accounts_client.go (97%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/assets.json (100%) create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/autorest.md rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/blobcontainers_client.go (98%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/blobinventorypolicies_client.go (98%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/blobservices_client.go (98%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/build.go (100%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/ci.yml (100%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/client_factory.go (100%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/constants.go (97%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/deletedaccounts_client.go (97%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/encryptionscopes_client.go (98%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/fileservices_client.go (97%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/fileshares_client.go (98%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/localusers_client.go (97%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/managementpolicies_client.go (98%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/models.go (95%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/models_serde.go (96%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/networksecurityperimeterconfigurations_client.go (98%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/objectreplicationpolicies_client.go (98%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/operations_client.go (97%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/options.go (100%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/privateendpointconnections_client.go (98%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/privatelinkresources_client.go (98%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/queue_client.go (97%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/queueservices_client.go (98%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/responses.go (100%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/skus_client.go (97%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/table_client.go (97%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/tableservices_client.go (98%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/taskassignmentinstancesreport_client.go (98%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/taskassignments_client.go (97%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/taskassignmentsinstancesreport_client.go (98%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/time_rfc1123.go (100%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/time_rfc3339.go (100%) rename vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/{ => v2}/usages_client.go (98%) create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/version.go delete mode 100644 vendor/github.com/Crocmagnon/fatcontext/pkg/analyzer/analyzer.go delete mode 100644 vendor/github.com/GaijinEntertainment/go-exhaustruct/v3/internal/pattern/list.go create mode 100644 vendor/github.com/MirrexOne/unqueryvet/.gitignore create mode 100644 vendor/github.com/MirrexOne/unqueryvet/.golangci.yml create mode 100644 vendor/github.com/MirrexOne/unqueryvet/.unqueryvet.example.yaml create mode 100644 vendor/github.com/MirrexOne/unqueryvet/CONTRIBUTING.md create mode 100644 vendor/github.com/MirrexOne/unqueryvet/Dockerfile rename vendor/{go.uber.org/automaxprocs => github.com/MirrexOne/unqueryvet}/LICENSE (87%) create mode 100644 vendor/github.com/MirrexOne/unqueryvet/README.md create mode 100644 vendor/github.com/MirrexOne/unqueryvet/RELEASE.md create mode 100644 vendor/github.com/MirrexOne/unqueryvet/Taskfile.yml create mode 100644 vendor/github.com/MirrexOne/unqueryvet/action.yml create mode 100644 vendor/github.com/MirrexOne/unqueryvet/analyzer.go create mode 100644 vendor/github.com/MirrexOne/unqueryvet/config.go create mode 100644 vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/analyzer.go create mode 100644 vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/concat.go create mode 100644 vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/filter.go create mode 100644 vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/fixes.go create mode 100644 vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/format.go create mode 100644 vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/n1detector.go create mode 100644 vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/bun.go create mode 100644 vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/ent.go create mode 100644 vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/goqu.go create mode 100644 vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/gorm.go create mode 100644 vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/interface.go create mode 100644 vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/jet.go create mode 100644 vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/pgx.go create mode 100644 vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/reform.go create mode 100644 vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/rel.go create mode 100644 vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/sqlboiler.go create mode 100644 vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/sqlc.go create mode 100644 vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/sqlx.go create mode 100644 vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/squirrel.go create mode 100644 vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqli_scanner.go create mode 100644 vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/tx_leak_detector.go create mode 100644 vendor/github.com/MirrexOne/unqueryvet/pkg/config/config.go create mode 100644 vendor/github.com/MirrexOne/unqueryvet/schema.json rename vendor/github.com/{sagikazarmark/slog-shim => alecthomas/chroma/v2}/.editorconfig (73%) create mode 100644 vendor/github.com/alecthomas/chroma/v2/.gitignore create mode 100644 vendor/github.com/alecthomas/chroma/v2/.golangci.yml create mode 100644 vendor/github.com/alecthomas/chroma/v2/.goreleaser.yml create mode 100644 vendor/github.com/alecthomas/chroma/v2/AGENTS.md create mode 100644 vendor/github.com/alecthomas/chroma/v2/Bitfile create mode 100644 vendor/github.com/alecthomas/chroma/v2/COPYING create mode 100644 vendor/github.com/alecthomas/chroma/v2/Dockerfile create mode 100644 vendor/github.com/alecthomas/chroma/v2/Justfile create mode 100644 vendor/github.com/alecthomas/chroma/v2/README.md create mode 100644 vendor/github.com/alecthomas/chroma/v2/biome.json create mode 100644 vendor/github.com/alecthomas/chroma/v2/chroma.jpg create mode 100644 vendor/github.com/alecthomas/chroma/v2/coalesce.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/colour.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/delegate.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/doc.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/emitters.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/formatter.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/formatters/api.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/formatters/html/html.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/formatters/json.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/formatters/svg/font_liberation_mono.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/formatters/svg/svg.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/formatters/tokens.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/formatters/tty_indexed.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/formatters/tty_truecolour.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/iterator.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexer.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/README.md create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/caddyfile.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/cl.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/dns.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/emacs.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/abap.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/abnf.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/actionscript.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/actionscript_3.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ada.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/agda.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/al.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/alloy.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/angular2.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/antlr.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/apacheconf.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/apl.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/applescript.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/arangodb_aql.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/arduino.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/armasm.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/atl.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/autohotkey.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/autoit.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/awk.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ballerina.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bash.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bash_session.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/batchfile.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/beef.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bibtex.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bicep.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/blitzbasic.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bnf.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bqn.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/brainfuck.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/c#.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/c++.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/c.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/c3.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cap_n_proto.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cassandra_cql.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ceylon.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cfengine3.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cfstatement.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/chaiscript.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/chapel.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cheetah.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/clojure.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cmake.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cobol.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/coffeescript.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/common_lisp.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/coq.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/core.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/crystal.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/css.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/csv.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cue.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cython.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/d.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dart.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dax.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/desktop_entry.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/devicetree.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/diff.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/django_jinja.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dns.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/docker.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dtd.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dylan.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ebnf.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/elixir.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/elm.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/emacslisp.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/erlang.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/factor.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/fennel.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/fish.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/forth.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/fortran.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/fortranfixed.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/fsharp.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gas.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gdscript.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gdscript3.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gherkin.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gleam.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/glsl.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gnuplot.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/go_template.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/graphql.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/groff.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/groovy.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/handlebars.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hare.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/haskell.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hcl.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hexdump.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hlb.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hlsl.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/holyc.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/html.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hy.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/idris.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/igor.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ini.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/io.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/iscdhcpd.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/j.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/janet.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/java.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/javascript.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/json.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/jsonata.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/jsonnet.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/julia.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/jungle.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/kakoune.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/kdl.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/kotlin.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lean.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lighttpd_configuration_file.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/llvm.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lox.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lua.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/makefile.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mako.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mason.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/materialize_sql_dialect.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mathematica.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/matlab.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mcfunction.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/meson.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/metal.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/microcad.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/minizinc.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mlir.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/modelica.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/modula-2.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mojo.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/monkeyc.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/moonbit.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/moonscript.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/morrowindscript.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/myghty.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mysql.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nasm.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/natural.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ndisasm.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/newspeak.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nginx_configuration_file.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nim.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nix.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nsis.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nu.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/objective-c.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/objectpascal.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ocaml.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/octave.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/odin.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/onesenterprise.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/openedge_abl.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/openscad.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/org_mode.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/pacmanconf.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/perl.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/php.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/pig.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/pkgconfig.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/pl_pgsql.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/plaintext.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/plutus_core.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/pony.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/postgresql_sql_dialect.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/postscript.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/povray.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/powerquery.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/powershell.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/prolog.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/promela.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/promql.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/properties.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/protocol_buffer.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/prql.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/psl.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/puppet.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/python.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/python_2.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/qbasic.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/qml.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/r.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/racket.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ragel.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/react.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/reasonml.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/reg.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rego.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rexx.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rgbasm.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ring.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rpgle.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rpm_spec.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ruby.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rust.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sas.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sass.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/scala.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/scheme.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/scilab.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/scss.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sed.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sieve.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/smali.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/smalltalk.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/smarty.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/snbt.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/snobol.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/solidity.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sourcepawn.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sparql.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sql.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/squidconf.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/standard_ml.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/stas.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/stylus.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/swift.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/systemd.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/systemverilog.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tablegen.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tal.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tasm.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tcl.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tcsh.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/termcap.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/terminfo.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/terraform.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tex.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/thrift.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/toml.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tradingview.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/transact-sql.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/turing.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/turtle.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/twig.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/txtpb.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/typescript.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/typoscript.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/typoscriptcssdata.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/typoscripthtmldata.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/typst.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ucode.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/v.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/v_shell.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/vala.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/vb_net.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/verilog.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/vhdl.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/vhs.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/viml.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/vue.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/wat.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/wdte.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/webgpu_shading_language.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/webvtt.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/whiley.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/xml.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/xorg.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/yaml.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/yang.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/z80_assembly.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/zed.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/zig.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/gemtext.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/genshi.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/go.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/haxe.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/html.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/http.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/lexers.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/markdown.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/markless.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/mysql.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/php.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/raku.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/rst.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/svelte.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/typoscript.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/zed.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/mutators.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/pygments-lexers.txt create mode 100644 vendor/github.com/alecthomas/chroma/v2/quick/quick.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/regexp.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/registry.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/remap.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/renovate.json5 create mode 100644 vendor/github.com/alecthomas/chroma/v2/serialise.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/style.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/abap.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/algol.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/algol_nu.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/api.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/arduino.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/ashen.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/aura-theme-dark-soft.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/aura-theme-dark.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/autumn.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/average.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/base16-snazzy.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/borland.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/bw.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/catppuccin-frappe.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/catppuccin-latte.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/catppuccin-macchiato.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/catppuccin-mocha.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/colorful.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/compat.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/doom-one.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/doom-one2.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/dracula.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/emacs.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/evergarden.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/friendly.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/fruity.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/github-dark.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/github.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/gruvbox-light.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/gruvbox.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/hr_high_contrast.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/hrdark.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/igor.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/lovelace.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/manni.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/modus-operandi.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/modus-vivendi.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/monokai.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/monokailight.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/murphy.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/native.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/nord.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/nordic.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/onedark.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/onesenterprise.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/paraiso-dark.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/paraiso-light.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/pastie.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/perldoc.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/pygments.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/rainbow_dash.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/rose-pine-dawn.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/rose-pine-moon.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/rose-pine.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/rpgle.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/rrt.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/solarized-dark.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/solarized-dark256.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/solarized-light.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/swapoff.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/tango.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/tokyonight-day.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/tokyonight-moon.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/tokyonight-night.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/tokyonight-storm.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/trac.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/vim.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/vs.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/vulcan.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/witchhazel.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/xcode-dark.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/styles/xcode.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/table.py create mode 100644 vendor/github.com/alecthomas/chroma/v2/tokentype_enumer.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/types.go create mode 100644 vendor/github.com/alecthomas/go-check-sumtype/.golangci.yml create mode 100644 vendor/github.com/alexkohler/prealloc/pkg/cmp.go create mode 100644 vendor/github.com/alexkohler/prealloc/pkg/math.go create mode 100644 vendor/github.com/alfatraining/structtag/LICENSE create mode 100644 vendor/github.com/alfatraining/structtag/README.md create mode 100644 vendor/github.com/alfatraining/structtag/tags.go rename vendor/github.com/{tdakkota/asciicheck => alingse/nilnesserr}/.gitignore (51%) create mode 100644 vendor/github.com/alingse/nilnesserr/.golangci.yaml rename vendor/github.com/{olekukonko/tablewriter/LICENSE.md => alingse/nilnesserr/LICENSE} (88%) create mode 100644 vendor/github.com/alingse/nilnesserr/README.md create mode 100644 vendor/github.com/alingse/nilnesserr/internal/typeparams/coretype.go create mode 100644 vendor/github.com/alingse/nilnesserr/internal/typeparams/normalize.go create mode 100644 vendor/github.com/alingse/nilnesserr/internal/typeparams/termlist.go create mode 100644 vendor/github.com/alingse/nilnesserr/internal/typeparams/typeterm.go create mode 100644 vendor/github.com/alingse/nilnesserr/linter.go create mode 100644 vendor/github.com/alingse/nilnesserr/nilerr.go create mode 100644 vendor/github.com/alingse/nilnesserr/nilness.go rename vendor/github.com/ashanbrown/forbidigo/{ => v2}/LICENSE (100%) rename vendor/github.com/ashanbrown/forbidigo/{ => v2}/forbidigo/config_options.go (100%) rename vendor/github.com/ashanbrown/forbidigo/{ => v2}/forbidigo/forbidigo.go (94%) rename vendor/github.com/ashanbrown/forbidigo/{ => v2}/forbidigo/patterns.go (79%) rename vendor/github.com/ashanbrown/makezero/{ => v2}/LICENSE (100%) rename vendor/github.com/ashanbrown/makezero/{ => v2}/makezero/makezero.go (100%) create mode 100644 vendor/github.com/aymanbagabas/go-osc52/v2/LICENSE create mode 100644 vendor/github.com/aymanbagabas/go-osc52/v2/README.md create mode 100644 vendor/github.com/aymanbagabas/go-osc52/v2/osc52.go create mode 100644 vendor/github.com/bombsimon/wsl/v5/.gitignore create mode 100644 vendor/github.com/bombsimon/wsl/v5/.golangci.yml create mode 100644 vendor/github.com/bombsimon/wsl/v5/CHECKS.md create mode 100644 vendor/github.com/bombsimon/wsl/v5/LICENSE create mode 100644 vendor/github.com/bombsimon/wsl/v5/README.md create mode 100644 vendor/github.com/bombsimon/wsl/v5/analyzer.go create mode 100644 vendor/github.com/bombsimon/wsl/v5/config.go create mode 100644 vendor/github.com/bombsimon/wsl/v5/cursor.go create mode 100644 vendor/github.com/bombsimon/wsl/v5/renovate.json create mode 100644 vendor/github.com/bombsimon/wsl/v5/wsl.go create mode 100644 vendor/github.com/catenacyber/perfsprint/analyzer/diagnostic.go create mode 100644 vendor/github.com/charmbracelet/colorprofile/.golangci.yml create mode 100644 vendor/github.com/charmbracelet/colorprofile/.goreleaser.yml create mode 100644 vendor/github.com/charmbracelet/colorprofile/LICENSE create mode 100644 vendor/github.com/charmbracelet/colorprofile/README.md create mode 100644 vendor/github.com/charmbracelet/colorprofile/doc.go create mode 100644 vendor/github.com/charmbracelet/colorprofile/env.go create mode 100644 vendor/github.com/charmbracelet/colorprofile/env_other.go create mode 100644 vendor/github.com/charmbracelet/colorprofile/env_windows.go create mode 100644 vendor/github.com/charmbracelet/colorprofile/profile.go create mode 100644 vendor/github.com/charmbracelet/colorprofile/writer.go create mode 100644 vendor/github.com/charmbracelet/lipgloss/.gitignore create mode 100644 vendor/github.com/charmbracelet/lipgloss/.golangci.yml create mode 100644 vendor/github.com/charmbracelet/lipgloss/.goreleaser.yml create mode 100644 vendor/github.com/charmbracelet/lipgloss/LICENSE create mode 100644 vendor/github.com/charmbracelet/lipgloss/README.md create mode 100644 vendor/github.com/charmbracelet/lipgloss/Taskfile.yaml create mode 100644 vendor/github.com/charmbracelet/lipgloss/align.go create mode 100644 vendor/github.com/charmbracelet/lipgloss/ansi_unix.go create mode 100644 vendor/github.com/charmbracelet/lipgloss/ansi_windows.go create mode 100644 vendor/github.com/charmbracelet/lipgloss/borders.go create mode 100644 vendor/github.com/charmbracelet/lipgloss/color.go create mode 100644 vendor/github.com/charmbracelet/lipgloss/get.go create mode 100644 vendor/github.com/charmbracelet/lipgloss/join.go create mode 100644 vendor/github.com/charmbracelet/lipgloss/position.go create mode 100644 vendor/github.com/charmbracelet/lipgloss/ranges.go create mode 100644 vendor/github.com/charmbracelet/lipgloss/renderer.go create mode 100644 vendor/github.com/charmbracelet/lipgloss/runes.go create mode 100644 vendor/github.com/charmbracelet/lipgloss/set.go create mode 100644 vendor/github.com/charmbracelet/lipgloss/size.go create mode 100644 vendor/github.com/charmbracelet/lipgloss/style.go create mode 100644 vendor/github.com/charmbracelet/lipgloss/unset.go create mode 100644 vendor/github.com/charmbracelet/lipgloss/whitespace.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/LICENSE create mode 100644 vendor/github.com/charmbracelet/x/ansi/ansi.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/ascii.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/background.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/c0.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/c1.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/charset.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/clipboard.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/color.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/ctrl.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/cursor.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/cwd.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/doc.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/finalterm.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/focus.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/graphics.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/hyperlink.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/iterm2.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/keypad.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/kitty.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/method.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/mode.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/modes.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/mouse.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/notification.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/parser.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/parser/const.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/parser/seq.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/parser/transition_table.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/parser_decode.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/parser_handler.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/parser_sync.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/passthrough.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/paste.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/reset.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/screen.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/sgr.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/status.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/style.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/termcap.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/title.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/truncate.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/util.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/width.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/winop.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/wrap.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/xterm.go create mode 100644 vendor/github.com/charmbracelet/x/cellbuf/LICENSE create mode 100644 vendor/github.com/charmbracelet/x/cellbuf/buffer.go create mode 100644 vendor/github.com/charmbracelet/x/cellbuf/cell.go create mode 100644 vendor/github.com/charmbracelet/x/cellbuf/errors.go create mode 100644 vendor/github.com/charmbracelet/x/cellbuf/geom.go create mode 100644 vendor/github.com/charmbracelet/x/cellbuf/hardscroll.go create mode 100644 vendor/github.com/charmbracelet/x/cellbuf/hashmap.go create mode 100644 vendor/github.com/charmbracelet/x/cellbuf/link.go create mode 100644 vendor/github.com/charmbracelet/x/cellbuf/screen.go create mode 100644 vendor/github.com/charmbracelet/x/cellbuf/sequence.go create mode 100644 vendor/github.com/charmbracelet/x/cellbuf/style.go create mode 100644 vendor/github.com/charmbracelet/x/cellbuf/tabstop.go create mode 100644 vendor/github.com/charmbracelet/x/cellbuf/utils.go create mode 100644 vendor/github.com/charmbracelet/x/cellbuf/wrap.go create mode 100644 vendor/github.com/charmbracelet/x/cellbuf/writer.go create mode 100644 vendor/github.com/charmbracelet/x/term/LICENSE create mode 100644 vendor/github.com/charmbracelet/x/term/term.go create mode 100644 vendor/github.com/charmbracelet/x/term/term_other.go create mode 100644 vendor/github.com/charmbracelet/x/term/term_unix.go create mode 100644 vendor/github.com/charmbracelet/x/term/term_unix_bsd.go create mode 100644 vendor/github.com/charmbracelet/x/term/term_unix_other.go create mode 100644 vendor/github.com/charmbracelet/x/term/term_windows.go create mode 100644 vendor/github.com/charmbracelet/x/term/terminal.go create mode 100644 vendor/github.com/charmbracelet/x/term/util.go create mode 100644 vendor/github.com/dave/dst/.gitignore create mode 100644 vendor/github.com/dave/dst/.travis.yml create mode 100644 vendor/github.com/dave/dst/LICENSE create mode 100644 vendor/github.com/dave/dst/README.md create mode 100644 vendor/github.com/dave/dst/README.md.tpl create mode 100644 vendor/github.com/dave/dst/clone-generated.go create mode 100644 vendor/github.com/dave/dst/clone.go create mode 100644 vendor/github.com/dave/dst/contributing.md create mode 100644 vendor/github.com/dave/dst/decorations-node-generated.go create mode 100644 vendor/github.com/dave/dst/decorations-types-generated.go create mode 100644 vendor/github.com/dave/dst/decorations.go create mode 100644 vendor/github.com/dave/dst/decorator/decorator-fragment-generated.go create mode 100644 vendor/github.com/dave/dst/decorator/decorator-fragment.go create mode 100644 vendor/github.com/dave/dst/decorator/decorator-node-generated.go create mode 100644 vendor/github.com/dave/dst/decorator/decorator.go create mode 100644 vendor/github.com/dave/dst/decorator/helpers.go create mode 100644 vendor/github.com/dave/dst/decorator/load.go create mode 100644 vendor/github.com/dave/dst/decorator/map.go create mode 100644 vendor/github.com/dave/dst/decorator/resolver/gopackages/resolver.go create mode 100644 vendor/github.com/dave/dst/decorator/resolver/gotypes/resolver.go create mode 100644 vendor/github.com/dave/dst/decorator/resolver/resolver.go create mode 100644 vendor/github.com/dave/dst/decorator/restorer-generated.go create mode 100644 vendor/github.com/dave/dst/decorator/restorer.go create mode 100644 vendor/github.com/dave/dst/dst.go create mode 100644 vendor/github.com/dave/dst/dstutil/decorations-generated.go create mode 100644 vendor/github.com/dave/dst/dstutil/decorations.go create mode 100644 vendor/github.com/dave/dst/dstutil/rewrite.go create mode 100644 vendor/github.com/dave/dst/dstutil/util.go create mode 100644 vendor/github.com/dave/dst/print.go create mode 100644 vendor/github.com/dave/dst/readme.go create mode 100644 vendor/github.com/dave/dst/resolve.go create mode 100644 vendor/github.com/dave/dst/scope.go create mode 100644 vendor/github.com/dave/dst/walk.go create mode 100644 vendor/github.com/dlclark/regexp2/.gitignore create mode 100644 vendor/github.com/dlclark/regexp2/.travis.yml create mode 100644 vendor/github.com/dlclark/regexp2/ATTRIB rename vendor/github.com/{shazow/go-diff => dlclark/regexp2}/LICENSE (96%) create mode 100644 vendor/github.com/dlclark/regexp2/README.md create mode 100644 vendor/github.com/dlclark/regexp2/fastclock.go create mode 100644 vendor/github.com/dlclark/regexp2/match.go create mode 100644 vendor/github.com/dlclark/regexp2/regexp.go create mode 100644 vendor/github.com/dlclark/regexp2/replace.go create mode 100644 vendor/github.com/dlclark/regexp2/runner.go create mode 100644 vendor/github.com/dlclark/regexp2/syntax/charclass.go create mode 100644 vendor/github.com/dlclark/regexp2/syntax/code.go create mode 100644 vendor/github.com/dlclark/regexp2/syntax/escape.go create mode 100644 vendor/github.com/dlclark/regexp2/syntax/fuzz.go create mode 100644 vendor/github.com/dlclark/regexp2/syntax/parser.go create mode 100644 vendor/github.com/dlclark/regexp2/syntax/prefix.go create mode 100644 vendor/github.com/dlclark/regexp2/syntax/replacerdata.go create mode 100644 vendor/github.com/dlclark/regexp2/syntax/tree.go create mode 100644 vendor/github.com/dlclark/regexp2/syntax/writer.go create mode 100644 vendor/github.com/dlclark/regexp2/testoutput1 create mode 100644 vendor/github.com/ghostiam/protogetter/flake.lock create mode 100644 vendor/github.com/ghostiam/protogetter/flake.nix create mode 100644 vendor/github.com/go-critic/go-critic/checkers/dupOption_checker.go create mode 100644 vendor/github.com/go-viper/mapstructure/v2/devenv.lock create mode 100644 vendor/github.com/go-viper/mapstructure/v2/devenv.nix create mode 100644 vendor/github.com/go-viper/mapstructure/v2/devenv.yaml create mode 100644 vendor/github.com/go-viper/mapstructure/v2/errors.go delete mode 100644 vendor/github.com/go-viper/mapstructure/v2/flake.lock delete mode 100644 vendor/github.com/go-viper/mapstructure/v2/flake.nix create mode 100644 vendor/github.com/godoc-lint/godoc-lint/LICENSE create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/analysis/analyzer.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/check/deprecated/deprecated.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/check/max_len/max_len.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/check/no_unused_link/no_unused_link.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/check/pkg_doc/pkg_doc.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/check/registry.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/check/require_doc/require_doc.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/check/shared/deprecated.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/check/start_with_name/start_with_name.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/check/stdlib_doclink/data.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/check/stdlib_doclink/internal/type.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/check/stdlib_doclink/stdlib.json create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/check/stdlib_doclink/stdlib_doclink.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/compose/compose.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/config/builder.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/config/config.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/config/default.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/config/default.yaml create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/config/doc.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/config/once.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/config/parser.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/config/plain.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/inspect/inspector.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/model/analyzer.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/model/checker.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/model/config.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/model/doc.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/model/inspector.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/model/registry.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/model/rule.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/model/ruleset.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/util/ast.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/util/doc.go create mode 100644 vendor/github.com/godoc-lint/godoc-lint/pkg/util/path.go delete mode 100644 vendor/github.com/gogo/protobuf/AUTHORS delete mode 100644 vendor/github.com/gogo/protobuf/CONTRIBUTORS delete mode 100644 vendor/github.com/gogo/protobuf/LICENSE delete mode 100644 vendor/github.com/gogo/protobuf/proto/Makefile delete mode 100644 vendor/github.com/gogo/protobuf/proto/clone.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/custom_gogo.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/decode.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/deprecated.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/discard.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/duration.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/duration_gogo.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/encode.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/encode_gogo.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/equal.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/extensions.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/extensions_gogo.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/lib.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/lib_gogo.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/message_set.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/pointer_reflect.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/pointer_reflect_gogo.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/pointer_unsafe.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/properties.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/properties_gogo.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/skip_gogo.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/table_marshal.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/table_marshal_gogo.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/table_merge.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/table_unmarshal.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/table_unmarshal_gogo.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/text.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/text_gogo.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/text_parser.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/timestamp.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/timestamp_gogo.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/wrappers.go delete mode 100644 vendor/github.com/gogo/protobuf/proto/wrappers_gogo.go delete mode 100644 vendor/github.com/gogo/protobuf/sortkeys/sortkeys.go rename vendor/github.com/{olekukonko/tablewriter => golangci/asciicheck}/.gitignore (58%) create mode 100644 vendor/github.com/golangci/asciicheck/.golangci.yml rename vendor/github.com/{tdakkota => golangci}/asciicheck/LICENSE (100%) create mode 100644 vendor/github.com/golangci/asciicheck/Makefile rename vendor/github.com/{tdakkota => golangci}/asciicheck/README.md (75%) rename vendor/github.com/{tdakkota => golangci}/asciicheck/ascii.go (100%) create mode 100644 vendor/github.com/golangci/asciicheck/asciicheck.go delete mode 100644 vendor/github.com/golangci/dupl/.travis.yml delete mode 100644 vendor/github.com/golangci/dupl/README.md rename vendor/github.com/golangci/dupl/{main.go => lib/lib.go} (51%) create mode 100644 vendor/github.com/golangci/dupl/printer/issuer.go delete mode 100644 vendor/github.com/golangci/gofmt/goimports/goimports.go delete mode 100644 vendor/github.com/golangci/gofmt/goimports/golangci.go delete mode 100644 vendor/github.com/golangci/gofmt/goimports/readme.md delete mode 100644 vendor/github.com/golangci/golangci-lint/internal/go/robustio/readme.md delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/commands/help.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/config/config.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/config/issues.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/config/linters.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/config/loader.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/config/output.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/fsutils/files.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/goanalysis/runners.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/asasalint/asasalint.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/asciicheck/asciicheck.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/bidichk/bidichk.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/bodyclose/bodyclose.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/canonicalheader/canonicalheader.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/containedctx/containedctx.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/contextcheck/contextcheck.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/copyloopvar/copyloopvar.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/cyclop/cyclop.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/depguard/depguard.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/dogsled/dogsled.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/dupl/dupl.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/dupword/dupword.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/durationcheck/durationcheck.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/err113/err113.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/errcheck/errcheck.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/errchkjson/errchkjson.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/errname/errname.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/errorlint/errorlint.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/exhaustive/exhaustive.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/exhaustruct/exhaustruct.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/exportloopref/exportloopref.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/fatcontext/fatcontext.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/forbidigo/forbidigo.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/forcetypeassert/forcetypeassert.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/funlen/funlen.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/gci/gci.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/ginkgolinter/ginkgolinter.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/gocheckcompilerdirectives/gocheckcompilerdirectives.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/gochecknoglobals/gochecknoglobals.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/gochecknoinits/gochecknoinits.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/gochecksumtype/gochecksumtype.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/gocognit/gocognit.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/goconst/goconst.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/gocyclo/gocyclo.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/godot/godot.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/godox/godox.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt/gofmt.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/gofumpt/gofumpt.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/goheader/goheader.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/goimports/goimports.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/gomoddirectives/gomoddirectives.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/gomodguard/gomodguard.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/goprintffuncname/goprintffuncname.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/gosimple/gosimple.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/gosmopolitan/gosmopolitan.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/importas/importas.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/inamedparam/inamedparam.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/ineffassign/ineffassign.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/interfacebloat/interfacebloat.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/internal/diff.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/internal/util.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/intrange/intrange.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/ireturn/ireturn.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/lll/lll.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/maintidx/maintidx.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/makezero/makezero.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/mirror/mirror.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/mnd/mnd.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/musttag/musttag.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/nakedret/nakedret.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/nestif/nestif.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/nilerr/nilerr.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/nilnil/nilnil.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/nlreturn/nlreturn.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/noctx/noctx.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/nolintlint/internal/nolintlint.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/nolintlint/nolintlint.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/nonamedreturns/nonamedreturns.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/nosprintfhostport/nosprintfhostport.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/paralleltest/paralleltest.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/perfsprint/perfsprint.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/prealloc/prealloc.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/predeclared/predeclared.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/promlinter/promlinter.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/protogetter/protogetter.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/reassign/reassign.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/recvcheck/recvcheck.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/rowserrcheck/rowserrcheck.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/spancheck/spancheck.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/sqlclosecheck/sqlclosecheck.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/staticcheck/staticcheck.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/stylecheck/stylecheck.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/tagalign/tagalign.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/tagliatelle/tagliatelle.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/tenv/tenv.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/testableexamples/testableexamples.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/testpackage/testpackage.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/tparallel/tparallel.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/typecheck.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/unconvert/unconvert.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/unparam/unparam.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/usestdlibvars/usestdlibvars.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/wastedassign/wastedassign.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/whitespace/whitespace.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/wsl/wsl.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/zerologlint/zerologlint.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/goutil/env.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/builder_linter.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/logutils/logutils.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/printers/codeclimate.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/printers/githubaction.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/printers/json.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/printers/printer.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/result/processors/autogenerated_exclude.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/result/processors/base_rule.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/result/processors/cgo.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/result/processors/exclude.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/result/processors/exclude_rules.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/result/processors/fixer.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/result/processors/identifier_marker.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/result/processors/issues.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_prefixer.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_prettifier.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/result/processors/severity.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/result/processors/skip_dirs.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/result/processors/skip_files.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/LICENSE (100%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/cmd/golangci-lint/main.go (66%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/cmd/golangci-lint/plugins.go (100%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/internal/cache/cache.go (95%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/internal/errorutil/errors.go (100%) rename vendor/github.com/golangci/{gofmt/goimports => golangci-lint/v2/internal/go}/LICENSE (100%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/internal/go/base/error_notunix.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/internal/go/base/error_unix.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/internal/go/base/readme.md rename vendor/github.com/golangci/golangci-lint/{ => v2}/internal/go/cache/cache.go (83%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/internal/go/cache/cache_gcil.go (100%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/internal/go/cache/default.go (80%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/internal/go/cache/default_gcil.go (100%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/internal/go/cache/hash.go (99%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/internal/go/cache/hash_gcil.go (100%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/internal/go/cache/prog.go (66%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/internal/go/cache/readme.md (97%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/internal/go/cacheprog/cacheprog.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/internal/go/cacheprog/readme.md rename vendor/github.com/golangci/golangci-lint/{ => v2}/internal/go/mmap/mmap.go (84%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/internal/go/mmap/mmap_other.go (100%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/internal/go/mmap/mmap_unix.go (100%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/internal/go/mmap/mmap_windows.go (74%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/internal/go/mmap/readme.md (85%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/internal/go/quoted/quoted.go (100%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/internal/go/quoted/readme.md (81%) rename vendor/github.com/{sagikazarmark/slog-shim => golangci/golangci-lint/v2/internal/x}/LICENSE (92%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/analysisflags/readme.md create mode 100644 vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/analysisflags/url.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/analysisinternal/analysis.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/analysisinternal/readme.md create mode 100644 vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/diff.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/lcs/common.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/lcs/doc.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/lcs/git.sh create mode 100644 vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/lcs/labels.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/lcs/old.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/lcs/sequence.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/ndiff.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/readme.md create mode 100644 vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/unified.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/commands/cache.go (89%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/commands/config.go (66%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/commands/config_verify.go (55%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/commands/custom.go (60%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/commands/flagsets.go (50%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/fmt.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/formatters.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/help.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/help_formatters.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/help_linters.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/commands/internal/builder.go (82%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/commands/internal/configuration.go (99%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/dirhash.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/commands/internal/imports.go (100%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/fakeloader/config.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/fakeloader/fakeloader.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_formatters.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_issues.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_linter_names.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_linters.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_linters_exclusions.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_linters_settings.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_output.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_run.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_severity.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/parser/parser.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/ptr/ptr.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/base_rule.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/config.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/doc.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/issues.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/linters.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/linters_settings.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/output.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/run.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/severity.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/base_rule.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/config.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/formatters.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/formatters_settings.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/issues.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/linters.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/linters_exclusions.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/linters_settings.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/output.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/output_formats.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/run.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/severity.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/commands/internal/vibra.go (100%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/commands/linters.go (63%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/commands/migrate.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/commands/root.go (92%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/commands/run.go (80%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/commands/version.go (63%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/config/base_loader.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/config/base_rule.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/config/config.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/config/formatters.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/config/formatters_settings.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/config/issues.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/config/linters.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/config/linters_exclusions.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/config/linters_settings.go (50%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/config/loader.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/config/output.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/config/output_formats.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/config/placeholders.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/config/run.go (54%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/config/severity.go (77%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/exitcodes/exitcodes.go (100%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/fsutils/basepath.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/fsutils/filecache.go (95%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/fsutils/fsutils.go (83%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/fsutils/fsutils_unix.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/fsutils/fsutils_windows.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/fsutils/linecache.go (100%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/fsutils/path_unix.go (100%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/fsutils/path_windows.go (100%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/goanalysis/issue.go (65%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/goanalysis/linter.go (79%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/goanalysis/load/guard.go (100%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/goanalysis/metalinter.go (89%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/goanalysis/pkgerrors/errors.go (65%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/goanalysis/pkgerrors/extract.go (78%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/goanalysis/pkgerrors/parse.go (88%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/position.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/goanalysis/runner.go (82%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/goanalysis/runner_action.go (64%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/goanalysis/runner_action_cache.go (63%) rename vendor/github.com/golangci/golangci-lint/{pkg/goanalysis/runner_base.go => v2/pkg/goanalysis/runner_checker.go} (51%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/goanalysis/runner_loadingpackage.go (84%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/runners.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/goanalysis/runners_cache.go (73%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/goformat/runner.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/analyzer.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/formatters.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/gci.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/LICENSE create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/config/config.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/section/parser.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/section/section.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/section/standard.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/section/standard_list.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gofmt/gofmt.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gofumpt/gofumpt.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/goimports/goimports.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/golines/golines.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/internal/commons.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/internal/diff.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/meta_formatter.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/swaggo/swaggo.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/arangolint/arangolint.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/asasalint/asasalint.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/asciicheck/asciicheck.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/bidichk/bidichk.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/bodyclose/bodyclose.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/canonicalheader/canonicalheader.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/containedctx/containedctx.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/contextcheck/contextcheck.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/copyloopvar/copyloopvar.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/cyclop/cyclop.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/golinters/decorder/decorder.go (76%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/depguard/depguard.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/dogsled/dogsled.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/dupl/dupl.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/dupword/dupword.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/durationcheck/durationcheck.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/embeddedstructfieldcheck/embeddedstructfieldcheck.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/err113/err113.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/errcheck/errcheck.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/errchkjson/errchkjson.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/errname/errname.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/errorlint/errorlint.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/exhaustive/exhaustive.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/exhaustruct/exhaustruct.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/exptostd/exptostd.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/fatcontext/fatcontext.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/forbidigo/forbidigo.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/forcetypeassert/forcetypeassert.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/funcorder/funcorder.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/funlen/funlen.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gci/gci.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/ginkgolinter/ginkgolinter.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gocheckcompilerdirectives/gocheckcompilerdirectives.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gochecknoglobals/gochecknoglobals.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gochecknoinits/gochecknoinits.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gochecksumtype/gochecksumtype.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gocognit/gocognit.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/goconst/goconst.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gocritic/gocritic.go rename vendor/github.com/golangci/golangci-lint/{pkg/golinters/gocritic/gocritic.go => v2/pkg/golinters/gocritic/gocritic_settings.go} (57%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gocyclo/gocyclo.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/godoclint/godoclint.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/godot/godot.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/godox/godox.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gofmt/gofmt.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gofumpt/gofumpt.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/goheader/goheader.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/goimports/goimports.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/golines/golines.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gomoddirectives/gomoddirectives.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gomodguard/gomodguard.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/goprintffuncname/goprintffuncname.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/golinters/gosec/gosec.go (78%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gosmopolitan/gosmopolitan.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/golinters/govet/govet.go (86%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/golinters/grouper/grouper.go (64%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/golinters/iface/iface.go (80%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/importas/importas.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/inamedparam/inamedparam.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/ineffassign/ineffassign.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/interfacebloat/interfacebloat.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/golinters/internal/commons.go (73%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/internal/util.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/intrange/intrange.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/iotamixing/iotamixing.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/ireturn/ireturn.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/lll/lll.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/golinters/loggercheck/loggercheck.go (68%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/maintidx/maintidx.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/makezero/makezero.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/mirror/mirror.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/golinters/misspell/misspell.go (50%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/mnd/mnd.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/modernize/modernize.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/musttag/musttag.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nakedret/nakedret.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nestif/nestif.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nilerr/nilerr.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nilnesserr/nilnesserr.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nilnil/nilnil.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nlreturn/nlreturn.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/noctx/noctx.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/noinlineerr/noinlineerr.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/golinters/nolintlint/internal/README.md (100%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nolintlint/internal/issues.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nolintlint/internal/nolintlint.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nolintlint/nolintlint.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nonamedreturns/nonamedreturns.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nosprintfhostport/nosprintfhostport.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/paralleltest/paralleltest.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/perfsprint/perfsprint.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/prealloc/prealloc.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/predeclared/predeclared.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/promlinter/promlinter.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/protogetter/protogetter.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/reassign/reassign.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/recvcheck/recvcheck.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/golinters/revive/revive.go (54%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/rowserrcheck/rowserrcheck.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/golinters/sloglint/sloglint.go (75%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/spancheck/spancheck.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/sqlclosecheck/sqlclosecheck.go rename vendor/github.com/golangci/golangci-lint/{pkg/golinters/internal/staticcheck_common.go => v2/pkg/golinters/staticcheck/staticcheck.go} (60%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/swaggo/swaggo.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/tagalign/tagalign.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/tagliatelle/tagliatelle.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/testableexamples/testableexamples.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/golinters/testifylint/testifylint.go (55%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/testpackage/testpackage.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/golinters/thelper/thelper.go (50%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/tparallel/tparallel.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/typecheck.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/unconvert/unconvert.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/unparam/unparam.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/unqueryvet/unqueryvet.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/golinters/unused/unused.go (88%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/usestdlibvars/usestdlibvars.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/usetesting/usetesting.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/golinters/varnamelen/varnamelen.go (58%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/wastedassign/wastedassign.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/whitespace/whitespace.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/golinters/wrapcheck/wrapcheck.go (64%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/wsl/wsl.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/wsl/wsl_v5.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/zerologlint/zerologlint.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/goutil/env.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/goutil/version.go (96%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/lint/context.go (67%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/lint/linter/config.go (55%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/lint/linter/context.go (65%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/lint/linter/linter.go (78%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/lint/lintersdb/builder_linter.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/lint/lintersdb/builder_plugin_go.go (84%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/lint/lintersdb/builder_plugin_module.go (86%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/lint/lintersdb/manager.go (66%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/lint/lintersdb/validator.go (76%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/lint/package.go (91%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/lint/runner.go (61%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/logutils/log.go (100%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/logutils/logutils.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/logutils/mock.go (100%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/logutils/out.go (100%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/logutils/stderr_log.go (90%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/printers/checkstyle.go (54%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/printers/codeclimate.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/printers/html.go (90%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/printers/json.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/printers/junitxml.go (58%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/printers/printer.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/printers/sarif.go (68%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/printers/tab.go (62%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/printers/teamcity.go (72%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/printers/text.go (70%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/report/data.go (53%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/report/log.go (93%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/result/issue.go (77%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/base_rule.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/cgo.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/result/processors/diff.go (59%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/exclusion_generated_file_filter.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/exclusion_generated_file_matcher.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/exclusion_paths.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/exclusion_presets.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/exclusion_rules.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/result/processors/filename_unadjuster.go (74%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/fixer.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/result/processors/invalid_issue.go (78%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/issues.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/result/processors/max_from_linter.go (73%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/result/processors/max_per_file_from_linter.go (65%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/result/processors/max_same_issues.go (78%) rename vendor/github.com/golangci/golangci-lint/{pkg/result/processors/nolint.go => v2/pkg/result/processors/nolint_filter.go} (79%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/path_absoluter.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/path_prettifier.go create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/path_relativity.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/result/processors/path_shortener.go (65%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/result/processors/processor.go (52%) create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/severity.go rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/result/processors/sort_results.go (79%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/result/processors/source_code.go (61%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/result/processors/uniq_by_line.go (64%) rename vendor/github.com/golangci/golangci-lint/{ => v2}/pkg/timeutils/stopwatch.go (98%) create mode 100644 vendor/github.com/golangci/golines/LICENSE create mode 100644 vendor/github.com/golangci/golines/shorten/.gitattributes create mode 100644 vendor/github.com/golangci/golines/shorten/annotations.go create mode 100644 vendor/github.com/golangci/golines/shorten/format.go create mode 100644 vendor/github.com/golangci/golines/shorten/internal/annotation/annotation.go create mode 100644 vendor/github.com/golangci/golines/shorten/internal/comments/comments.go create mode 100644 vendor/github.com/golangci/golines/shorten/internal/graph/graph.go create mode 100644 vendor/github.com/golangci/golines/shorten/internal/graph/graph_generated.go create mode 100644 vendor/github.com/golangci/golines/shorten/internal/line.go create mode 100644 vendor/github.com/golangci/golines/shorten/internal/tags/filler.go create mode 100644 vendor/github.com/golangci/golines/shorten/internal/tags/tags.go create mode 100644 vendor/github.com/golangci/golines/shorten/log.go create mode 100644 vendor/github.com/golangci/golines/shorten/shortener.go create mode 100644 vendor/github.com/golangci/misspell/CONTRIBUTING.md create mode 100644 vendor/github.com/golangci/misspell/words_uk.go create mode 100644 vendor/github.com/golangci/misspell/words_us.go delete mode 100644 vendor/github.com/golangci/modinfo/.gitignore delete mode 100644 vendor/github.com/golangci/modinfo/.golangci.yml delete mode 100644 vendor/github.com/golangci/modinfo/Makefile delete mode 100644 vendor/github.com/golangci/modinfo/module.go delete mode 100644 vendor/github.com/golangci/modinfo/readme.md create mode 100644 vendor/github.com/golangci/revgrep/issue.go create mode 100644 vendor/github.com/golangci/revgrep/patch.go create mode 100644 vendor/github.com/golangci/swaggoswag/.gitignore create mode 100644 vendor/github.com/golangci/swaggoswag/formatter.go create mode 100644 vendor/github.com/golangci/swaggoswag/license create mode 100644 vendor/github.com/golangci/swaggoswag/parser.go create mode 100644 vendor/github.com/golangci/swaggoswag/readme.md create mode 100644 vendor/github.com/gostaticanalysis/comment/.tagpr create mode 100644 vendor/github.com/gostaticanalysis/comment/CHANGELOG.md create mode 100644 vendor/github.com/gostaticanalysis/comment/version.txt create mode 100644 vendor/github.com/gostaticanalysis/forcetypeassert/.tagpr create mode 100644 vendor/github.com/gostaticanalysis/forcetypeassert/CHANGELOG.md create mode 100644 vendor/github.com/gostaticanalysis/forcetypeassert/version.txt create mode 100644 vendor/github.com/hashicorp/go-immutable-radix/v2/.gitignore create mode 100644 vendor/github.com/hashicorp/go-immutable-radix/v2/CHANGELOG.md rename vendor/github.com/hashicorp/{hcl => go-immutable-radix/v2}/LICENSE (50%) create mode 100644 vendor/github.com/hashicorp/go-immutable-radix/v2/README.md create mode 100644 vendor/github.com/hashicorp/go-immutable-radix/v2/edges.go create mode 100644 vendor/github.com/hashicorp/go-immutable-radix/v2/iradix.go create mode 100644 vendor/github.com/hashicorp/go-immutable-radix/v2/iter.go create mode 100644 vendor/github.com/hashicorp/go-immutable-radix/v2/node.go create mode 100644 vendor/github.com/hashicorp/go-immutable-radix/v2/path_iter.go create mode 100644 vendor/github.com/hashicorp/go-immutable-radix/v2/raw_iter.go create mode 100644 vendor/github.com/hashicorp/go-immutable-radix/v2/reverse_iter.go create mode 100644 vendor/github.com/hashicorp/golang-lru/v2/LICENSE create mode 100644 vendor/github.com/hashicorp/golang-lru/v2/internal/list.go rename vendor/github.com/{golangci/golangci-lint/internal/go/LICENSE => hashicorp/golang-lru/v2/simplelru/LICENSE_list} (97%) create mode 100644 vendor/github.com/hashicorp/golang-lru/v2/simplelru/lru.go create mode 100644 vendor/github.com/hashicorp/golang-lru/v2/simplelru/lru_interface.go delete mode 100644 vendor/github.com/hashicorp/hcl/.gitignore delete mode 100644 vendor/github.com/hashicorp/hcl/.travis.yml delete mode 100644 vendor/github.com/hashicorp/hcl/Makefile delete mode 100644 vendor/github.com/hashicorp/hcl/README.md delete mode 100644 vendor/github.com/hashicorp/hcl/appveyor.yml delete mode 100644 vendor/github.com/hashicorp/hcl/decoder.go delete mode 100644 vendor/github.com/hashicorp/hcl/hcl.go delete mode 100644 vendor/github.com/hashicorp/hcl/hcl/ast/ast.go delete mode 100644 vendor/github.com/hashicorp/hcl/hcl/ast/walk.go delete mode 100644 vendor/github.com/hashicorp/hcl/hcl/parser/error.go delete mode 100644 vendor/github.com/hashicorp/hcl/hcl/parser/parser.go delete mode 100644 vendor/github.com/hashicorp/hcl/hcl/printer/nodes.go delete mode 100644 vendor/github.com/hashicorp/hcl/hcl/printer/printer.go delete mode 100644 vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go delete mode 100644 vendor/github.com/hashicorp/hcl/hcl/strconv/quote.go delete mode 100644 vendor/github.com/hashicorp/hcl/hcl/token/position.go delete mode 100644 vendor/github.com/hashicorp/hcl/hcl/token/token.go delete mode 100644 vendor/github.com/hashicorp/hcl/json/parser/flatten.go delete mode 100644 vendor/github.com/hashicorp/hcl/json/parser/parser.go delete mode 100644 vendor/github.com/hashicorp/hcl/json/scanner/scanner.go delete mode 100644 vendor/github.com/hashicorp/hcl/json/token/position.go delete mode 100644 vendor/github.com/hashicorp/hcl/json/token/token.go delete mode 100644 vendor/github.com/hashicorp/hcl/lex.go delete mode 100644 vendor/github.com/hashicorp/hcl/parse.go create mode 100644 vendor/github.com/jgautheron/goconst/.gitignore create mode 100644 vendor/github.com/julz/importas/Makefile delete mode 100644 vendor/github.com/kisielk/errcheck/errcheck/tags.go delete mode 100644 vendor/github.com/kisielk/errcheck/errcheck/tags_compat.go delete mode 100644 vendor/github.com/kyoh86/exportloopref/.golangci.yml delete mode 100644 vendor/github.com/kyoh86/exportloopref/.goreleaser.yml delete mode 100644 vendor/github.com/kyoh86/exportloopref/LICENSE delete mode 100644 vendor/github.com/kyoh86/exportloopref/Makefile delete mode 100644 vendor/github.com/kyoh86/exportloopref/README.md delete mode 100644 vendor/github.com/kyoh86/exportloopref/exportloopref.go create mode 100644 vendor/github.com/ldez/exptostd/.gitignore create mode 100644 vendor/github.com/ldez/exptostd/.golangci.yml create mode 100644 vendor/github.com/ldez/exptostd/LICENSE create mode 100644 vendor/github.com/ldez/exptostd/Makefile create mode 100644 vendor/github.com/ldez/exptostd/exptostd.go create mode 100644 vendor/github.com/ldez/exptostd/readme.md create mode 100644 vendor/github.com/ldez/grignotin/LICENSE create mode 100644 vendor/github.com/ldez/grignotin/goenv/goenv.go create mode 100644 vendor/github.com/ldez/grignotin/goenv/names.go create mode 100644 vendor/github.com/ldez/grignotin/gomod/gomod.go rename vendor/github.com/{golangci/modinfo => ldez/structtags}/LICENSE (100%) create mode 100644 vendor/github.com/ldez/structtags/parser/tag.go create mode 100644 vendor/github.com/ldez/structtags/parser/value.go create mode 100644 vendor/github.com/ldez/tagliatelle/converter.go create mode 100644 vendor/github.com/ldez/usetesting/.gitignore create mode 100644 vendor/github.com/ldez/usetesting/.golangci.yml create mode 100644 vendor/github.com/ldez/usetesting/LICENSE create mode 100644 vendor/github.com/ldez/usetesting/Makefile create mode 100644 vendor/github.com/ldez/usetesting/readme.md create mode 100644 vendor/github.com/ldez/usetesting/report.go create mode 100644 vendor/github.com/ldez/usetesting/usetesting.go create mode 100644 vendor/github.com/lucasb-eyer/go-colorful/.gitignore create mode 100644 vendor/github.com/lucasb-eyer/go-colorful/CHANGELOG.md create mode 100644 vendor/github.com/lucasb-eyer/go-colorful/LICENSE create mode 100644 vendor/github.com/lucasb-eyer/go-colorful/README.md create mode 100644 vendor/github.com/lucasb-eyer/go-colorful/colorgens.go create mode 100644 vendor/github.com/lucasb-eyer/go-colorful/colors.go create mode 100644 vendor/github.com/lucasb-eyer/go-colorful/happy_palettegen.go create mode 100644 vendor/github.com/lucasb-eyer/go-colorful/hexcolor.go create mode 100644 vendor/github.com/lucasb-eyer/go-colorful/hsluv-snapshot-rev4.json create mode 100644 vendor/github.com/lucasb-eyer/go-colorful/hsluv.go create mode 100644 vendor/github.com/lucasb-eyer/go-colorful/soft_palettegen.go create mode 100644 vendor/github.com/lucasb-eyer/go-colorful/warm_palettegen.go delete mode 100644 vendor/github.com/magiconair/properties/.gitignore delete mode 100644 vendor/github.com/magiconair/properties/CHANGELOG.md delete mode 100644 vendor/github.com/magiconair/properties/LICENSE.md delete mode 100644 vendor/github.com/magiconair/properties/README.md delete mode 100644 vendor/github.com/magiconair/properties/decode.go delete mode 100644 vendor/github.com/magiconair/properties/doc.go delete mode 100644 vendor/github.com/magiconair/properties/integrate.go delete mode 100644 vendor/github.com/magiconair/properties/lex.go delete mode 100644 vendor/github.com/magiconair/properties/load.go delete mode 100644 vendor/github.com/magiconair/properties/parser.go delete mode 100644 vendor/github.com/magiconair/properties/properties.go delete mode 100644 vendor/github.com/magiconair/properties/rangecheck.go create mode 100644 vendor/github.com/manuelarte/embeddedstructfieldcheck/LICENSE create mode 100644 vendor/github.com/manuelarte/embeddedstructfieldcheck/analyzer/analyzer.go create mode 100644 vendor/github.com/manuelarte/embeddedstructfieldcheck/internal/diag.go create mode 100644 vendor/github.com/manuelarte/embeddedstructfieldcheck/internal/structanalyzer.go create mode 100644 vendor/github.com/manuelarte/funcorder/LICENSE create mode 100644 vendor/github.com/manuelarte/funcorder/analyzer/analyzer.go create mode 100644 vendor/github.com/manuelarte/funcorder/internal/astutils.go create mode 100644 vendor/github.com/manuelarte/funcorder/internal/diag.go create mode 100644 vendor/github.com/manuelarte/funcorder/internal/features.go create mode 100644 vendor/github.com/manuelarte/funcorder/internal/file_processor.go create mode 100644 vendor/github.com/manuelarte/funcorder/internal/struct_constructor.go create mode 100644 vendor/github.com/manuelarte/funcorder/internal/structholder.go create mode 100644 vendor/github.com/matoous/godox/Makefile delete mode 100644 vendor/github.com/mattn/go-colorable/colorable_appengine.go create mode 100644 vendor/github.com/mgechev/revive/internal/astutils/ast_utils.go create mode 100644 vendor/github.com/mgechev/revive/internal/rule/name.go create mode 100644 vendor/github.com/mgechev/revive/internal/syncset/syncset.go delete mode 100644 vendor/github.com/mgechev/revive/internal/typeparams/typeparams_go117.go delete mode 100644 vendor/github.com/mgechev/revive/internal/typeparams/typeparams_go118.go create mode 100644 vendor/github.com/mgechev/revive/logging/logger.go create mode 100644 vendor/github.com/mgechev/revive/rule/enforce_switch_style.go create mode 100644 vendor/github.com/mgechev/revive/rule/epoch_naming.go create mode 100644 vendor/github.com/mgechev/revive/rule/forbidden_call_in_wg_go.go create mode 100644 vendor/github.com/mgechev/revive/rule/identical_ifelseif_branches.go create mode 100644 vendor/github.com/mgechev/revive/rule/identical_ifelseif_condition.go create mode 100644 vendor/github.com/mgechev/revive/rule/identical_switch_branches.go create mode 100644 vendor/github.com/mgechev/revive/rule/identical_switch_conditions.go create mode 100644 vendor/github.com/mgechev/revive/rule/inefficient_map_lookup.go create mode 100644 vendor/github.com/mgechev/revive/rule/package_directory_mismatch.go create mode 100644 vendor/github.com/mgechev/revive/rule/package_naming.go create mode 100644 vendor/github.com/mgechev/revive/rule/redundant_build_tag.go create mode 100644 vendor/github.com/mgechev/revive/rule/redundant_test_main_exit.go create mode 100644 vendor/github.com/mgechev/revive/rule/time_date.go create mode 100644 vendor/github.com/mgechev/revive/rule/unnecessary_format.go create mode 100644 vendor/github.com/mgechev/revive/rule/unnecessary_if.go create mode 100644 vendor/github.com/mgechev/revive/rule/unsecure_url_scheme.go create mode 100644 vendor/github.com/mgechev/revive/rule/use_errors_new.go create mode 100644 vendor/github.com/mgechev/revive/rule/use_fmt_print.go create mode 100644 vendor/github.com/mgechev/revive/rule/use_slices_sort.go create mode 100644 vendor/github.com/mgechev/revive/rule/use_waitgroup_go.go create mode 100644 vendor/github.com/mgechev/revive/rule/useless_fallthrough.go delete mode 100644 vendor/github.com/mitchellh/mapstructure/CHANGELOG.md delete mode 100644 vendor/github.com/mitchellh/mapstructure/README.md delete mode 100644 vendor/github.com/mitchellh/mapstructure/decode_hooks.go delete mode 100644 vendor/github.com/mitchellh/mapstructure/error.go delete mode 100644 vendor/github.com/mitchellh/mapstructure/mapstructure.go rename vendor/github.com/{sivchari/tenv => muesli/termenv}/.gitignore (97%) create mode 100644 vendor/github.com/muesli/termenv/.golangci-soft.yml create mode 100644 vendor/github.com/muesli/termenv/.golangci.yml create mode 100644 vendor/github.com/muesli/termenv/LICENSE create mode 100644 vendor/github.com/muesli/termenv/README.md create mode 100644 vendor/github.com/muesli/termenv/ansi_compat.md create mode 100644 vendor/github.com/muesli/termenv/ansicolors.go create mode 100644 vendor/github.com/muesli/termenv/color.go create mode 100644 vendor/github.com/muesli/termenv/constants_linux.go create mode 100644 vendor/github.com/muesli/termenv/constants_solaris.go create mode 100644 vendor/github.com/muesli/termenv/constants_unix.go create mode 100644 vendor/github.com/muesli/termenv/constants_zos.go create mode 100644 vendor/github.com/muesli/termenv/copy.go create mode 100644 vendor/github.com/muesli/termenv/hyperlink.go create mode 100644 vendor/github.com/muesli/termenv/notification.go create mode 100644 vendor/github.com/muesli/termenv/output.go create mode 100644 vendor/github.com/muesli/termenv/profile.go create mode 100644 vendor/github.com/muesli/termenv/screen.go create mode 100644 vendor/github.com/muesli/termenv/style.go create mode 100644 vendor/github.com/muesli/termenv/templatehelper.go create mode 100644 vendor/github.com/muesli/termenv/termenv.go create mode 100644 vendor/github.com/muesli/termenv/termenv_other.go create mode 100644 vendor/github.com/muesli/termenv/termenv_posix.go create mode 100644 vendor/github.com/muesli/termenv/termenv_solaris.go create mode 100644 vendor/github.com/muesli/termenv/termenv_unix.go create mode 100644 vendor/github.com/muesli/termenv/termenv_windows.go rename vendor/github.com/nunnatsa/ginkgolinter/{types => config}/config.go (58%) create mode 100644 vendor/github.com/nunnatsa/ginkgolinter/internal/ginkgoinfo/ginkgoinfo.go delete mode 100644 vendor/github.com/nunnatsa/ginkgolinter/internal/gomegahandler/dothandler.go delete mode 100644 vendor/github.com/nunnatsa/ginkgolinter/internal/gomegahandler/namedhandler.go create mode 100644 vendor/github.com/nunnatsa/ginkgolinter/internal/rules/assertiondescriptionrule.go create mode 100644 vendor/github.com/nunnatsa/ginkgolinter/internal/rules/simplify_not.go rename vendor/github.com/nunnatsa/ginkgolinter/internal/{interfaces => typecheck}/interfaces.go (59%) delete mode 100644 vendor/github.com/nunnatsa/ginkgolinter/types/boolean.go delete mode 100644 vendor/github.com/olekukonko/tablewriter/.travis.yml delete mode 100644 vendor/github.com/olekukonko/tablewriter/README.md delete mode 100644 vendor/github.com/olekukonko/tablewriter/csv.go delete mode 100644 vendor/github.com/olekukonko/tablewriter/table.go delete mode 100644 vendor/github.com/olekukonko/tablewriter/table_with_color.go delete mode 100644 vendor/github.com/olekukonko/tablewriter/util.go delete mode 100644 vendor/github.com/olekukonko/tablewriter/wrap.go create mode 100644 vendor/github.com/openshift/api/apps/v1/generated.protomessage.pb.go create mode 100644 vendor/github.com/openshift/api/authorization/v1/generated.protomessage.pb.go create mode 100644 vendor/github.com/openshift/api/build/v1/generated.protomessage.pb.go create mode 100644 vendor/github.com/openshift/api/cloudnetwork/v1/generated.protomessage.pb.go delete mode 100644 vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_insightsdatagathers-DevPreviewNoUpgrade.crd.yaml delete mode 100644 vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_insightsdatagathers-TechPreviewNoUpgrade.crd.yaml rename vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/{0000_10_config-operator_01_insightsdatagathers-CustomNoUpgrade.crd.yaml => 0000_10_config-operator_01_insightsdatagathers.crd.yaml} (99%) create mode 100644 vendor/github.com/openshift/api/config/v1alpha1/types_pki.go create mode 100644 vendor/github.com/openshift/api/image/v1/generated.protomessage.pb.go create mode 100644 vendor/github.com/openshift/api/network/v1/generated.protomessage.pb.go create mode 100644 vendor/github.com/openshift/api/networkoperator/v1/generated.protomessage.pb.go create mode 100644 vendor/github.com/openshift/api/oauth/v1/generated.protomessage.pb.go create mode 100644 vendor/github.com/openshift/api/project/v1/generated.protomessage.pb.go create mode 100644 vendor/github.com/openshift/api/quota/v1/generated.protomessage.pb.go create mode 100644 vendor/github.com/openshift/api/route/v1/generated.protomessage.pb.go create mode 100644 vendor/github.com/openshift/api/samples/v1/generated.protomessage.pb.go create mode 100644 vendor/github.com/openshift/api/security/v1/generated.protomessage.pb.go create mode 100644 vendor/github.com/openshift/api/template/v1/generated.protomessage.pb.go create mode 100644 vendor/github.com/openshift/api/user/v1/generated.protomessage.pb.go create mode 100644 vendor/github.com/openshift/client-go/config/applyconfigurations/config/v1/acceptrisk.go create mode 100644 vendor/github.com/openshift/client-go/config/applyconfigurations/config/v1/tokenclaimvalidationcelrule.go create mode 100644 vendor/github.com/openshift/client-go/config/applyconfigurations/config/v1/tokenuservalidationrule.go create mode 100644 vendor/github.com/openshift/client-go/config/applyconfigurations/config/v1alpha1/certificateconfig.go create mode 100644 vendor/github.com/openshift/client-go/config/applyconfigurations/config/v1alpha1/criocredentialproviderconfig.go create mode 100644 vendor/github.com/openshift/client-go/config/applyconfigurations/config/v1alpha1/criocredentialproviderconfigspec.go create mode 100644 vendor/github.com/openshift/client-go/config/applyconfigurations/config/v1alpha1/criocredentialproviderconfigstatus.go create mode 100644 vendor/github.com/openshift/client-go/config/applyconfigurations/config/v1alpha1/custompkipolicy.go create mode 100644 vendor/github.com/openshift/client-go/config/applyconfigurations/config/v1alpha1/defaultcertificateconfig.go create mode 100644 vendor/github.com/openshift/client-go/config/applyconfigurations/config/v1alpha1/ecdsakeyconfig.go create mode 100644 vendor/github.com/openshift/client-go/config/applyconfigurations/config/v1alpha1/keyconfig.go create mode 100644 vendor/github.com/openshift/client-go/config/applyconfigurations/config/v1alpha1/pki.go create mode 100644 vendor/github.com/openshift/client-go/config/applyconfigurations/config/v1alpha1/pkicertificatemanagement.go create mode 100644 vendor/github.com/openshift/client-go/config/applyconfigurations/config/v1alpha1/pkiprofile.go create mode 100644 vendor/github.com/openshift/client-go/config/applyconfigurations/config/v1alpha1/pkispec.go create mode 100644 vendor/github.com/openshift/client-go/config/applyconfigurations/config/v1alpha1/prometheusoperatoradmissionwebhookconfig.go create mode 100644 vendor/github.com/openshift/client-go/config/applyconfigurations/config/v1alpha1/prometheusoperatorconfig.go create mode 100644 vendor/github.com/openshift/client-go/config/applyconfigurations/config/v1alpha1/rsakeyconfig.go create mode 100644 vendor/github.com/openshift/client-go/config/clientset/versioned/typed/config/v1alpha1/criocredentialproviderconfig.go create mode 100644 vendor/github.com/openshift/client-go/config/clientset/versioned/typed/config/v1alpha1/pki.go create mode 100644 vendor/github.com/openshift/client-go/config/informers/externalversions/config/v1alpha1/criocredentialproviderconfig.go create mode 100644 vendor/github.com/openshift/client-go/config/informers/externalversions/config/v1alpha1/pki.go create mode 100644 vendor/github.com/openshift/client-go/config/listers/config/v1alpha1/criocredentialproviderconfig.go create mode 100644 vendor/github.com/openshift/client-go/config/listers/config/v1alpha1/pki.go delete mode 100644 vendor/github.com/polyfloyd/go-errorlint/errorlint/lint.go create mode 100644 vendor/github.com/prometheus/procfs/kernel_hung.go create mode 100644 vendor/github.com/prometheus/procfs/nfnetlink_queue.go create mode 100644 vendor/github.com/raeperd/recvcheck/.golangci.yml rename vendor/github.com/{golangci/gofmt/gofmt/internal => rogpeppe/go-internal}/diff/diff.go (98%) rename vendor/github.com/{golangci/golangci-lint/internal/go => rogpeppe/go-internal}/robustio/robustio.go (100%) rename vendor/github.com/{golangci/golangci-lint/internal/go => rogpeppe/go-internal}/robustio/robustio_darwin.go (100%) rename vendor/github.com/{golangci/golangci-lint/internal/go => rogpeppe/go-internal}/robustio/robustio_flaky.go (100%) rename vendor/github.com/{golangci/golangci-lint/internal/go => rogpeppe/go-internal}/robustio/robustio_other.go (100%) rename vendor/github.com/{golangci/golangci-lint/internal/go => rogpeppe/go-internal}/robustio/robustio_windows.go (70%) create mode 100644 vendor/github.com/sagikazarmark/locafero/glob.go create mode 100644 vendor/github.com/sagikazarmark/locafero/glob_windows.go delete mode 100644 vendor/github.com/sagikazarmark/slog-shim/.envrc delete mode 100644 vendor/github.com/sagikazarmark/slog-shim/.gitignore delete mode 100644 vendor/github.com/sagikazarmark/slog-shim/README.md delete mode 100644 vendor/github.com/sagikazarmark/slog-shim/attr.go delete mode 100644 vendor/github.com/sagikazarmark/slog-shim/attr_120.go delete mode 100644 vendor/github.com/sagikazarmark/slog-shim/flake.lock delete mode 100644 vendor/github.com/sagikazarmark/slog-shim/flake.nix delete mode 100644 vendor/github.com/sagikazarmark/slog-shim/handler.go delete mode 100644 vendor/github.com/sagikazarmark/slog-shim/handler_120.go delete mode 100644 vendor/github.com/sagikazarmark/slog-shim/json_handler.go delete mode 100644 vendor/github.com/sagikazarmark/slog-shim/json_handler_120.go delete mode 100644 vendor/github.com/sagikazarmark/slog-shim/level.go delete mode 100644 vendor/github.com/sagikazarmark/slog-shim/level_120.go delete mode 100644 vendor/github.com/sagikazarmark/slog-shim/logger.go delete mode 100644 vendor/github.com/sagikazarmark/slog-shim/logger_120.go delete mode 100644 vendor/github.com/sagikazarmark/slog-shim/record.go delete mode 100644 vendor/github.com/sagikazarmark/slog-shim/record_120.go delete mode 100644 vendor/github.com/sagikazarmark/slog-shim/text_handler.go delete mode 100644 vendor/github.com/sagikazarmark/slog-shim/text_handler_120.go delete mode 100644 vendor/github.com/sagikazarmark/slog-shim/value.go delete mode 100644 vendor/github.com/sagikazarmark/slog-shim/value_120.go delete mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/.gitignore delete mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/README.md delete mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/compiler.go delete mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/content.go delete mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/doc.go delete mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/draft.go delete mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/errors.go delete mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/extension.go delete mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/format.go delete mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/httploader/httploader.go delete mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/loader.go delete mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/output.go delete mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/resource.go delete mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v5/schema.go rename vendor/github.com/santhosh-tekuri/jsonschema/{v5 => v6}/.gitmodules (91%) create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/.golangci.yml create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/.pre-commit-hooks.yaml create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/.swp rename vendor/github.com/santhosh-tekuri/jsonschema/{v5 => v6}/LICENSE (100%) create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/README.md create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/compiler.go create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/content.go create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/draft.go create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/format.go create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/go.work create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/go.work.sum create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/kind/kind.go create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/loader.go create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft-04/schema create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft-06/schema create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft-07/schema create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2019-09/meta/applicator create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2019-09/meta/content create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2019-09/meta/core create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2019-09/meta/format create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2019-09/meta/meta-data create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2019-09/meta/validation create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2019-09/schema create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2020-12/meta/applicator create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2020-12/meta/content create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2020-12/meta/core create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2020-12/meta/format-annotation create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2020-12/meta/format-assertion create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2020-12/meta/meta-data create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2020-12/meta/unevaluated create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2020-12/meta/validation create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2020-12/schema create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/objcompiler.go create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/output.go create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/position.go create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/root.go create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/roots.go create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/schema.go create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/util.go create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/validator.go create mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/vocab.go create mode 100644 vendor/github.com/securego/gosec/v2/DEVELOPMENT.md create mode 100644 vendor/github.com/securego/gosec/v2/RULES.md create mode 100644 vendor/github.com/securego/gosec/v2/analyzers/commandinjection.go create mode 100644 vendor/github.com/securego/gosec/v2/analyzers/context_propagation.go create mode 100644 vendor/github.com/securego/gosec/v2/analyzers/cors_bypass_pattern.go create mode 100644 vendor/github.com/securego/gosec/v2/analyzers/form_parsing_limits.go delete mode 100644 vendor/github.com/securego/gosec/v2/analyzers/hardcodedNonce.go create mode 100644 vendor/github.com/securego/gosec/v2/analyzers/hardcoded_nonce.go create mode 100644 vendor/github.com/securego/gosec/v2/analyzers/loginjection.go create mode 100644 vendor/github.com/securego/gosec/v2/analyzers/pathtraversal.go create mode 100644 vendor/github.com/securego/gosec/v2/analyzers/range_analyzer.go create mode 100644 vendor/github.com/securego/gosec/v2/analyzers/redirect_header_propagation.go create mode 100644 vendor/github.com/securego/gosec/v2/analyzers/request_smuggling.go create mode 100644 vendor/github.com/securego/gosec/v2/analyzers/smtpinjection.go create mode 100644 vendor/github.com/securego/gosec/v2/analyzers/sqlinjection.go create mode 100644 vendor/github.com/securego/gosec/v2/analyzers/ssh_callback.go create mode 100644 vendor/github.com/securego/gosec/v2/analyzers/ssrf.go create mode 100644 vendor/github.com/securego/gosec/v2/analyzers/tls_resumption_verifypeer.go create mode 100644 vendor/github.com/securego/gosec/v2/analyzers/walk_symlink_race.go create mode 100644 vendor/github.com/securego/gosec/v2/analyzers/xss.go create mode 100644 vendor/github.com/securego/gosec/v2/gosec_cache.go create mode 100644 vendor/github.com/securego/gosec/v2/internal/ssautil/package_analysis_cache.go create mode 100644 vendor/github.com/securego/gosec/v2/internal/ssautil/ssa_result.go create mode 100644 vendor/github.com/securego/gosec/v2/path_filter.go create mode 100644 vendor/github.com/securego/gosec/v2/regex_cache.go create mode 100644 vendor/github.com/securego/gosec/v2/rules/base.go delete mode 100644 vendor/github.com/securego/gosec/v2/rules/decompression-bomb.go create mode 100644 vendor/github.com/securego/gosec/v2/rules/decompression_bomb.go rename vendor/github.com/securego/gosec/v2/rules/{directory-traversal.go => directory_traversal.go} (81%) delete mode 100644 vendor/github.com/securego/gosec/v2/rules/math_big_rat.go create mode 100644 vendor/github.com/securego/gosec/v2/rules/secret_serialization.go create mode 100644 vendor/github.com/securego/gosec/v2/rules/trojansource.go delete mode 100644 vendor/github.com/securego/gosec/v2/rules/weakcryptohash.go delete mode 100644 vendor/github.com/securego/gosec/v2/rules/weakdepricatedcryptohash.go create mode 100644 vendor/github.com/securego/gosec/v2/taint/analyzer.go create mode 100644 vendor/github.com/securego/gosec/v2/taint/taint.go delete mode 100644 vendor/github.com/shazow/go-diff/difflib/differ.go create mode 100644 vendor/github.com/sirupsen/logrus/terminal_check_wasi.go create mode 100644 vendor/github.com/sirupsen/logrus/terminal_check_wasip1.go delete mode 100644 vendor/github.com/sivchari/tenv/.golangci.yml delete mode 100644 vendor/github.com/sivchari/tenv/README.md delete mode 100644 vendor/github.com/sivchari/tenv/goreleaser.yaml delete mode 100644 vendor/github.com/sivchari/tenv/tenv.go delete mode 100644 vendor/github.com/sivchari/tenv/tenv.png delete mode 100644 vendor/github.com/sonatard/noctx/ngfunc/main.go delete mode 100644 vendor/github.com/sonatard/noctx/ngfunc/report.go delete mode 100644 vendor/github.com/sonatard/noctx/reqwithoutctx/main.go delete mode 100644 vendor/github.com/sonatard/noctx/reqwithoutctx/report.go delete mode 100644 vendor/github.com/sonatard/noctx/reqwithoutctx/ssa.go rename vendor/github.com/sonatard/noctx/{ngfunc => }/types.go (62%) create mode 100644 vendor/github.com/spf13/cobra/SECURITY.md create mode 100644 vendor/github.com/spf13/viper/UPDATES.md create mode 100644 vendor/github.com/spf13/viper/encoding.go create mode 100644 vendor/github.com/spf13/viper/experimental.go delete mode 100644 vendor/github.com/spf13/viper/file_finder.go create mode 100644 vendor/github.com/spf13/viper/finder.go delete mode 100644 vendor/github.com/spf13/viper/internal/encoding/decoder.go delete mode 100644 vendor/github.com/spf13/viper/internal/encoding/encoder.go delete mode 100644 vendor/github.com/spf13/viper/internal/encoding/error.go delete mode 100644 vendor/github.com/spf13/viper/internal/encoding/hcl/codec.go delete mode 100644 vendor/github.com/spf13/viper/internal/encoding/ini/codec.go delete mode 100644 vendor/github.com/spf13/viper/internal/encoding/ini/map_utils.go delete mode 100644 vendor/github.com/spf13/viper/internal/encoding/javaproperties/codec.go delete mode 100644 vendor/github.com/spf13/viper/internal/encoding/javaproperties/map_utils.go create mode 100644 vendor/github.com/spf13/viper/internal/features/finder.go create mode 100644 vendor/github.com/spf13/viper/internal/features/finder_default.go create mode 100644 vendor/github.com/spf13/viper/remote.go delete mode 100644 vendor/github.com/tdakkota/asciicheck/asciicheck.go create mode 100644 vendor/github.com/tetafro/godot/comment.go rename vendor/github.com/tetafro/godot/{getters.go => file.go} (79%) create mode 100644 vendor/github.com/ultraware/funlen/.golangci.yml create mode 100644 vendor/github.com/ultraware/funlen/funlen.go delete mode 100644 vendor/github.com/ultraware/funlen/main.go create mode 100644 vendor/github.com/uudashr/gocognit/rangeiter.go create mode 100644 vendor/github.com/uudashr/iface/unexported/doc.go create mode 100644 vendor/github.com/uudashr/iface/unexported/unexported.go create mode 100644 vendor/github.com/xo/terminfo/.gitignore rename vendor/github.com/{mitchellh/mapstructure => xo/terminfo}/LICENSE (88%) create mode 100644 vendor/github.com/xo/terminfo/README.md create mode 100644 vendor/github.com/xo/terminfo/caps.go create mode 100644 vendor/github.com/xo/terminfo/capvals.go create mode 100644 vendor/github.com/xo/terminfo/color.go create mode 100644 vendor/github.com/xo/terminfo/dec.go create mode 100644 vendor/github.com/xo/terminfo/load.go create mode 100644 vendor/github.com/xo/terminfo/param.go create mode 100644 vendor/github.com/xo/terminfo/stack.go create mode 100644 vendor/github.com/xo/terminfo/terminfo.go create mode 100644 vendor/go-simpler.org/musttag/.golangci.yaml delete mode 100644 vendor/go-simpler.org/musttag/.golangci.yml create mode 100644 vendor/go-simpler.org/sloglint/.golangci.yaml delete mode 100644 vendor/go-simpler.org/sloglint/.golangci.yml create mode 100644 vendor/go.augendre.info/arangolint/LICENSE create mode 100644 vendor/go.augendre.info/arangolint/pkg/analyzer/analyzer.go rename vendor/{github.com/Crocmagnon => go.augendre.info}/fatcontext/LICENSE (100%) create mode 100644 vendor/go.augendre.info/fatcontext/pkg/analyzer/analyzer.go create mode 100644 vendor/go.opentelemetry.io/otel/SECURITY-INSIGHTS.yml create mode 100644 vendor/go.opentelemetry.io/otel/attribute/hash.go create mode 100644 vendor/go.opentelemetry.io/otel/attribute/internal/xxhash/xxhash.go create mode 100644 vendor/go.opentelemetry.io/otel/sdk/internal/x/features.go rename vendor/go.opentelemetry.io/otel/sdk/{ => trace}/internal/env/env.go (98%) create mode 100644 vendor/go.opentelemetry.io/otel/sdk/trace/internal/observ/batch_span_processor.go create mode 100644 vendor/go.opentelemetry.io/otel/sdk/trace/internal/observ/doc.go create mode 100644 vendor/go.opentelemetry.io/otel/sdk/trace/internal/observ/simple_span_processor.go create mode 100644 vendor/go.opentelemetry.io/otel/sdk/trace/internal/observ/tracer.go delete mode 100644 vendor/go.opentelemetry.io/otel/sdk/trace/version.go delete mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.26.0/README.md delete mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.26.0/attribute_group.go delete mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.26.0/metric.go create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.34.0/error_type.go create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.37.0/MIGRATION.md create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.37.0/README.md create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.37.0/attribute_group.go rename vendor/go.opentelemetry.io/otel/semconv/{v1.26.0 => v1.37.0}/doc.go (80%) create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.37.0/error_type.go rename vendor/go.opentelemetry.io/otel/semconv/{v1.26.0 => v1.37.0}/exception.go (74%) create mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.37.0/otelconv/metric.go rename vendor/go.opentelemetry.io/otel/semconv/{v1.26.0 => v1.37.0}/schema.go (71%) create mode 100644 vendor/go.opentelemetry.io/otel/trace/hex.go delete mode 100644 vendor/go.uber.org/automaxprocs/internal/cgroups/cgroup.go delete mode 100644 vendor/go.uber.org/automaxprocs/internal/cgroups/cgroups.go delete mode 100644 vendor/go.uber.org/automaxprocs/internal/cgroups/cgroups2.go delete mode 100644 vendor/go.uber.org/automaxprocs/internal/cgroups/doc.go delete mode 100644 vendor/go.uber.org/automaxprocs/internal/cgroups/errors.go delete mode 100644 vendor/go.uber.org/automaxprocs/internal/cgroups/mountpoint.go delete mode 100644 vendor/go.uber.org/automaxprocs/internal/cgroups/subsys.go delete mode 100644 vendor/go.uber.org/automaxprocs/internal/runtime/cpu_quota_linux.go delete mode 100644 vendor/go.uber.org/automaxprocs/internal/runtime/cpu_quota_unsupported.go delete mode 100644 vendor/go.uber.org/automaxprocs/internal/runtime/runtime.go delete mode 100644 vendor/go.uber.org/automaxprocs/maxprocs/maxprocs.go delete mode 100644 vendor/go.uber.org/automaxprocs/maxprocs/version.go delete mode 100644 vendor/golang.org/x/exp/constraints/constraints.go delete mode 100644 vendor/golang.org/x/exp/maps/maps.go delete mode 100644 vendor/golang.org/x/exp/slog/attr.go delete mode 100644 vendor/golang.org/x/exp/slog/doc.go delete mode 100644 vendor/golang.org/x/exp/slog/handler.go delete mode 100644 vendor/golang.org/x/exp/slog/internal/buffer/buffer.go delete mode 100644 vendor/golang.org/x/exp/slog/internal/ignorepc.go delete mode 100644 vendor/golang.org/x/exp/slog/json_handler.go delete mode 100644 vendor/golang.org/x/exp/slog/level.go delete mode 100644 vendor/golang.org/x/exp/slog/logger.go delete mode 100644 vendor/golang.org/x/exp/slog/noplog.bench delete mode 100644 vendor/golang.org/x/exp/slog/record.go delete mode 100644 vendor/golang.org/x/exp/slog/text_handler.go delete mode 100644 vendor/golang.org/x/exp/slog/value.go delete mode 100644 vendor/golang.org/x/exp/slog/value_119.go delete mode 100644 vendor/golang.org/x/exp/slog/value_120.go create mode 100644 vendor/golang.org/x/mod/sumdb/dirhash/hash.go create mode 100644 vendor/golang.org/x/net/html/nodetype_string.go create mode 100644 vendor/golang.org/x/net/http2/client_priority_go126.go create mode 100644 vendor/golang.org/x/net/http2/client_priority_go127.go create mode 100644 vendor/golang.org/x/net/internal/httpsfv/httpsfv.go create mode 100644 vendor/golang.org/x/text/cases/cases.go create mode 100644 vendor/golang.org/x/text/cases/context.go create mode 100644 vendor/golang.org/x/text/cases/fold.go create mode 100644 vendor/golang.org/x/text/cases/icu.go create mode 100644 vendor/golang.org/x/text/cases/info.go create mode 100644 vendor/golang.org/x/text/cases/map.go create mode 100644 vendor/golang.org/x/text/cases/tables15.0.0.go create mode 100644 vendor/golang.org/x/text/cases/tables17.0.0.go create mode 100644 vendor/golang.org/x/text/cases/trieval.go delete mode 100644 vendor/golang.org/x/text/message/catalog/go19.go delete mode 100644 vendor/golang.org/x/text/message/catalog/gopre19.go delete mode 100644 vendor/golang.org/x/text/secure/bidirule/bidirule10.0.0.go delete mode 100644 vendor/golang.org/x/text/secure/bidirule/bidirule9.0.0.go delete mode 100644 vendor/golang.org/x/text/unicode/bidi/tables10.0.0.go delete mode 100644 vendor/golang.org/x/text/unicode/bidi/tables11.0.0.go delete mode 100644 vendor/golang.org/x/text/unicode/bidi/tables12.0.0.go delete mode 100644 vendor/golang.org/x/text/unicode/bidi/tables13.0.0.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/tables17.0.0.go delete mode 100644 vendor/golang.org/x/text/unicode/bidi/tables9.0.0.go delete mode 100644 vendor/golang.org/x/text/unicode/norm/tables10.0.0.go delete mode 100644 vendor/golang.org/x/text/unicode/norm/tables11.0.0.go delete mode 100644 vendor/golang.org/x/text/unicode/norm/tables12.0.0.go rename vendor/golang.org/x/text/unicode/norm/{tables13.0.0.go => tables17.0.0.go} (53%) delete mode 100644 vendor/golang.org/x/text/unicode/norm/tables9.0.0.go delete mode 100644 vendor/golang.org/x/text/width/tables10.0.0.go delete mode 100644 vendor/golang.org/x/text/width/tables11.0.0.go delete mode 100644 vendor/golang.org/x/text/width/tables12.0.0.go rename vendor/golang.org/x/text/width/{tables13.0.0.go => tables17.0.0.go} (74%) delete mode 100644 vendor/golang.org/x/text/width/tables9.0.0.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/hostport/hostport.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/httpmux/httpmux.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/any.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/bloop.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/doc.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/errorsastype.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/fmtappendf.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/forvar.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/maps.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/minmax.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/modernize.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/newexpr.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/omitzero.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/plusbuild.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/rangeint.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/reflect.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/slices.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/slicescontains.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/slicesdelete.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/sortslice.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/stditerators.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/stringsbuilder.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/stringscut.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/stringscutprefix.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/stringsseq.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/testingcontext.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/unsafefuncs.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/waitgroup.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/stdversion/stdversion.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/waitgroup/doc.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/waitgroup/waitgroup.go create mode 100644 vendor/golang.org/x/tools/go/callgraph/callgraph.go create mode 100644 vendor/golang.org/x/tools/go/callgraph/cha/cha.go create mode 100644 vendor/golang.org/x/tools/go/callgraph/internal/chautil/lazy.go create mode 100644 vendor/golang.org/x/tools/go/callgraph/util.go delete mode 100644 vendor/golang.org/x/tools/internal/aliases/aliases_go122.go create mode 100644 vendor/golang.org/x/tools/internal/goplsexport/export.go delete mode 100644 vendor/honnef.co/go/tools/go/ir/exits.go create mode 100644 vendor/honnef.co/go/tools/internal/analysisinternal/typeindex/typeindex.go create mode 100644 vendor/honnef.co/go/tools/internal/typesinternal/typeindex/typeindex.go create mode 100644 vendor/honnef.co/go/tools/quickfix/analysis.go create mode 100644 vendor/honnef.co/go/tools/quickfix/doc.go create mode 100644 vendor/honnef.co/go/tools/quickfix/qf1001/qf1001.go create mode 100644 vendor/honnef.co/go/tools/quickfix/qf1002/qf1002.go create mode 100644 vendor/honnef.co/go/tools/quickfix/qf1003/qf1003.go create mode 100644 vendor/honnef.co/go/tools/quickfix/qf1004/qf1004.go create mode 100644 vendor/honnef.co/go/tools/quickfix/qf1005/qf1005.go create mode 100644 vendor/honnef.co/go/tools/quickfix/qf1006/qf1006.go create mode 100644 vendor/honnef.co/go/tools/quickfix/qf1007/qf1007.go create mode 100644 vendor/honnef.co/go/tools/quickfix/qf1008/qf1008.go create mode 100644 vendor/honnef.co/go/tools/quickfix/qf1009/qf1009.go create mode 100644 vendor/honnef.co/go/tools/quickfix/qf1010/qf1010.go create mode 100644 vendor/honnef.co/go/tools/quickfix/qf1011/qf1011.go create mode 100644 vendor/honnef.co/go/tools/quickfix/qf1012/qf1012.go create mode 100644 vendor/honnef.co/go/tools/staticcheck/sa5008/jsonv2.go create mode 100644 vendor/k8s.io/api/admission/v1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/admission/v1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/admission/v1beta1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/admission/v1beta1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/admissionregistration/v1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/admissionregistration/v1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/admissionregistration/v1alpha1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/admissionregistration/v1alpha1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/admissionregistration/v1beta1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/admissionregistration/v1beta1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/apidiscovery/v2/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/apidiscovery/v2/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/apidiscovery/v2beta1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/apidiscovery/v2beta1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/apiserverinternal/v1alpha1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/apiserverinternal/v1alpha1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/apps/v1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/apps/v1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/apps/v1beta1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/apps/v1beta1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/apps/v1beta2/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/apps/v1beta2/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/authentication/v1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/authentication/v1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/authentication/v1alpha1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/authentication/v1alpha1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/authentication/v1beta1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/authentication/v1beta1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/authorization/v1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/authorization/v1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/authorization/v1beta1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/authorization/v1beta1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/autoscaling/v1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/autoscaling/v1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/autoscaling/v2/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/autoscaling/v2/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/autoscaling/v2beta1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/autoscaling/v2beta1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/autoscaling/v2beta2/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/autoscaling/v2beta2/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/batch/v1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/batch/v1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/batch/v1beta1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/batch/v1beta1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/certificates/v1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/certificates/v1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/certificates/v1alpha1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/certificates/v1alpha1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/certificates/v1beta1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/certificates/v1beta1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/coordination/v1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/coordination/v1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/coordination/v1alpha2/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/coordination/v1alpha2/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/coordination/v1beta1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/coordination/v1beta1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/core/v1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/core/v1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/discovery/v1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/discovery/v1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/discovery/v1beta1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/discovery/v1beta1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/events/v1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/events/v1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/events/v1beta1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/events/v1beta1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/extensions/v1beta1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/extensions/v1beta1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/flowcontrol/v1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/flowcontrol/v1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/flowcontrol/v1beta1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/flowcontrol/v1beta1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/flowcontrol/v1beta2/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/flowcontrol/v1beta2/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/flowcontrol/v1beta3/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/flowcontrol/v1beta3/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/imagepolicy/v1alpha1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/imagepolicy/v1alpha1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/networking/v1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/networking/v1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/networking/v1beta1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/networking/v1beta1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/node/v1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/node/v1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/node/v1alpha1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/node/v1alpha1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/node/v1beta1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/node/v1beta1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/policy/v1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/policy/v1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/policy/v1beta1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/policy/v1beta1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/rbac/v1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/rbac/v1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/rbac/v1alpha1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/rbac/v1alpha1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/rbac/v1beta1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/rbac/v1beta1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/resource/v1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/resource/v1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/resource/v1alpha3/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/resource/v1alpha3/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/resource/v1beta1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/resource/v1beta1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/resource/v1beta2/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/resource/v1beta2/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/scheduling/v1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/scheduling/v1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/scheduling/v1alpha1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/scheduling/v1alpha1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/scheduling/v1beta1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/scheduling/v1beta1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/storage/v1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/storage/v1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/storage/v1alpha1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/storage/v1alpha1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/api/storage/v1beta1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/api/storage/v1beta1/zz_generated.model_name.go delete mode 100644 vendor/k8s.io/api/storagemigration/v1alpha1/generated.pb.go rename vendor/k8s.io/api/storagemigration/{v1alpha1 => v1beta1}/doc.go (89%) create mode 100644 vendor/k8s.io/api/storagemigration/v1beta1/generated.pb.go rename vendor/k8s.io/api/storagemigration/{v1alpha1 => v1beta1}/generated.proto (64%) create mode 100644 vendor/k8s.io/api/storagemigration/v1beta1/generated.protomessage.pb.go rename vendor/k8s.io/api/storagemigration/{v1alpha1 => v1beta1}/register.go (97%) rename vendor/k8s.io/api/storagemigration/{v1alpha1 => v1beta1}/types.go (57%) rename vendor/k8s.io/api/storagemigration/{v1alpha1 => v1beta1}/types_swagger_doc_generated.go (68%) rename vendor/k8s.io/api/storagemigration/{v1alpha1 => v1beta1}/zz_generated.deepcopy.go (78%) create mode 100644 vendor/k8s.io/api/storagemigration/v1beta1/zz_generated.model_name.go rename vendor/k8s.io/api/storagemigration/{v1alpha1 => v1beta1}/zz_generated.prerelease-lifecycle.go (96%) create mode 100644 vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/resource/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/resource/zz_generated.model_name.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/validate/content/decimal_int.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/validate/content/dns.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/validate/content/identifier.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/validate/content/kube.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/validate/options.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/validate/strfmt.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/validate/update.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/validation/validation.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1beta1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1beta1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/schema/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/zz_generated.model_name.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/intstr/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/intstr/zz_generated.model_name.go create mode 100644 vendor/k8s.io/apimachinery/pkg/version/zz_generated.model_name.go create mode 100644 vendor/k8s.io/apiserver/pkg/apis/audit/v1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/apiserver/pkg/apis/audit/v1/zz_generated.model_name.go rename vendor/k8s.io/client-go/applyconfigurations/certificates/{v1alpha1 => v1beta1}/podcertificaterequest.go (85%) rename vendor/k8s.io/client-go/applyconfigurations/certificates/{v1alpha1 => v1beta1}/podcertificaterequestspec.go (53%) rename vendor/k8s.io/client-go/applyconfigurations/certificates/{v1alpha1 => v1beta1}/podcertificaterequeststatus.go (56%) create mode 100644 vendor/k8s.io/client-go/applyconfigurations/core/v1/workloadreference.go rename vendor/k8s.io/client-go/applyconfigurations/{storagemigration/v1alpha1/groupversionresource.go => meta/v1/groupresource.go} (54%) delete mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha3/celdeviceselector.go delete mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha3/deviceselector.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha3/devicetaintrulestatus.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/scheduling/v1alpha1/gangschedulingpolicy.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/scheduling/v1alpha1/podgroup.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/scheduling/v1alpha1/podgrouppolicy.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/scheduling/v1alpha1/typedlocalobjectreference.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/scheduling/v1alpha1/workload.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/scheduling/v1alpha1/workloadspec.go delete mode 100644 vendor/k8s.io/client-go/applyconfigurations/storagemigration/v1alpha1/migrationcondition.go rename vendor/k8s.io/client-go/applyconfigurations/storagemigration/{v1alpha1 => v1beta1}/storageversionmigration.go (85%) rename vendor/k8s.io/client-go/applyconfigurations/storagemigration/{v1alpha1 => v1beta1}/storageversionmigrationspec.go (66%) rename vendor/k8s.io/client-go/applyconfigurations/storagemigration/{v1alpha1 => v1beta1}/storageversionmigrationstatus.go (76%) rename vendor/k8s.io/client-go/informers/certificates/{v1alpha1 => v1beta1}/podcertificaterequest.go (77%) create mode 100644 vendor/k8s.io/client-go/informers/scheduling/v1alpha1/workload.go rename vendor/k8s.io/client-go/informers/storagemigration/{v1alpha1 => v1beta1}/interface.go (98%) rename vendor/k8s.io/client-go/informers/storagemigration/{v1alpha1 => v1beta1}/storageversionmigration.go (77%) rename vendor/k8s.io/client-go/kubernetes/typed/certificates/{v1alpha1 => v1beta1}/podcertificaterequest.go (58%) create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1/workload.go rename vendor/k8s.io/client-go/kubernetes/typed/storagemigration/{v1alpha1 => v1beta1}/doc.go (97%) rename vendor/k8s.io/client-go/kubernetes/typed/storagemigration/{v1alpha1 => v1beta1}/generated_expansion.go (97%) rename vendor/k8s.io/client-go/kubernetes/typed/storagemigration/{v1alpha1 => v1beta1}/storagemigration_client.go (62%) rename vendor/k8s.io/client-go/kubernetes/typed/storagemigration/{v1alpha1 => v1beta1}/storageversionmigration.go (57%) rename vendor/k8s.io/client-go/listers/certificates/{v1alpha1 => v1beta1}/podcertificaterequest.go (79%) create mode 100644 vendor/k8s.io/client-go/listers/scheduling/v1alpha1/workload.go rename vendor/k8s.io/client-go/listers/storagemigration/{v1alpha1 => v1beta1}/expansion_generated.go (97%) rename vendor/k8s.io/client-go/listers/storagemigration/{v1alpha1 => v1beta1}/storageversionmigration.go (78%) create mode 100644 vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1beta1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/client-go/util/watchlist/watch_list.go create mode 100644 vendor/k8s.io/code-generator/LICENSE create mode 100644 vendor/k8s.io/code-generator/cmd/applyconfiguration-gen/args/args.go create mode 100644 vendor/k8s.io/code-generator/cmd/applyconfiguration-gen/args/externaltypes.go create mode 100644 vendor/k8s.io/code-generator/cmd/applyconfiguration-gen/generators/applyconfiguration.go create mode 100644 vendor/k8s.io/code-generator/cmd/applyconfiguration-gen/generators/internal.go create mode 100644 vendor/k8s.io/code-generator/cmd/applyconfiguration-gen/generators/jsontagutil.go create mode 100644 vendor/k8s.io/code-generator/cmd/applyconfiguration-gen/generators/openapi.go create mode 100644 vendor/k8s.io/code-generator/cmd/applyconfiguration-gen/generators/refgraph.go create mode 100644 vendor/k8s.io/code-generator/cmd/applyconfiguration-gen/generators/targets.go create mode 100644 vendor/k8s.io/code-generator/cmd/applyconfiguration-gen/generators/types.go create mode 100644 vendor/k8s.io/code-generator/cmd/applyconfiguration-gen/generators/util.go create mode 100644 vendor/k8s.io/code-generator/cmd/client-gen/generators/util/gvpackages.go create mode 100644 vendor/k8s.io/code-generator/cmd/client-gen/generators/util/tags.go create mode 100644 vendor/k8s.io/code-generator/cmd/client-gen/types/helpers.go create mode 100644 vendor/k8s.io/code-generator/cmd/client-gen/types/types.go create mode 100644 vendor/k8s.io/code-generator/pkg/util/comments.go create mode 100644 vendor/k8s.io/code-generator/pkg/util/plural_exceptions.go create mode 100644 vendor/k8s.io/component-base/tracing/api/v1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/gengo/v2/LICENSE create mode 100644 vendor/k8s.io/gengo/v2/Makefile create mode 100644 vendor/k8s.io/gengo/v2/README.md create mode 100644 vendor/k8s.io/gengo/v2/codetags/extractor.go create mode 100644 vendor/k8s.io/gengo/v2/codetags/parser.go create mode 100644 vendor/k8s.io/gengo/v2/codetags/scanner.go create mode 100644 vendor/k8s.io/gengo/v2/codetags/types.go create mode 100644 vendor/k8s.io/gengo/v2/comments.go create mode 100644 vendor/k8s.io/gengo/v2/execute.go create mode 100644 vendor/k8s.io/gengo/v2/generator/doc.go create mode 100644 vendor/k8s.io/gengo/v2/generator/error_tracker.go create mode 100644 vendor/k8s.io/gengo/v2/generator/execute.go create mode 100644 vendor/k8s.io/gengo/v2/generator/generator.go create mode 100644 vendor/k8s.io/gengo/v2/generator/go_generator.go create mode 100644 vendor/k8s.io/gengo/v2/generator/import_tracker.go create mode 100644 vendor/k8s.io/gengo/v2/generator/simple_target.go create mode 100644 vendor/k8s.io/gengo/v2/generator/snippet_writer.go create mode 100644 vendor/k8s.io/gengo/v2/namer/doc.go create mode 100644 vendor/k8s.io/gengo/v2/namer/import_tracker.go create mode 100644 vendor/k8s.io/gengo/v2/namer/namer.go create mode 100644 vendor/k8s.io/gengo/v2/namer/order.go create mode 100644 vendor/k8s.io/gengo/v2/namer/plural_namer.go create mode 100644 vendor/k8s.io/gengo/v2/parser/doc.go create mode 100644 vendor/k8s.io/gengo/v2/parser/parse.go create mode 100644 vendor/k8s.io/gengo/v2/parser/parse_122.go create mode 100644 vendor/k8s.io/gengo/v2/parser/parse_pre_122.go create mode 100644 vendor/k8s.io/gengo/v2/types/doc.go create mode 100644 vendor/k8s.io/gengo/v2/types/types.go create mode 100644 vendor/k8s.io/kube-aggregator/pkg/apis/apiregistration/v1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/kube-aggregator/pkg/apis/apiregistration/v1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1/generated.protomessage.pb.go create mode 100644 vendor/k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1/zz_generated.model_name.go create mode 100644 vendor/k8s.io/kube-openapi/pkg/util/trie.go create mode 100644 vendor/k8s.io/kube-openapi/pkg/util/util.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/versioned_tracker.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/conversion_hubspoke.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/conversion_registry.go create mode 100644 vendor/sigs.k8s.io/controller-tools/pkg/applyconfiguration/doc.go create mode 100644 vendor/sigs.k8s.io/controller-tools/pkg/applyconfiguration/gen.go create mode 100644 vendor/sigs.k8s.io/controller-tools/pkg/applyconfiguration/zz_generated.markerhelp.go create mode 100644 vendor/sigs.k8s.io/controller-tools/pkg/internal/crd/crd.go diff --git a/vendor/4d63.com/gocheckcompilerdirectives/checkcompilerdirectives/checkcompilerdirectives.go b/vendor/4d63.com/gocheckcompilerdirectives/checkcompilerdirectives/checkcompilerdirectives.go index 19948c454..e719155d9 100644 --- a/vendor/4d63.com/gocheckcompilerdirectives/checkcompilerdirectives/checkcompilerdirectives.go +++ b/vendor/4d63.com/gocheckcompilerdirectives/checkcompilerdirectives/checkcompilerdirectives.go @@ -72,12 +72,11 @@ func isKnown(directive string) bool { return false } +// Found by running the following command on the source of go. +// git grep -o -E -h '//go:[a-z_-]+' -- ':!**/*_test.go' ':!test/' ':!**/testdata/**' | sort -u +// See https://pkg.go.dev/cmd/compile@go1.24#hdr-Compiler_Directives var known = []string{ - // Found by running the following command on the source of go. - // git grep -o -E -h '//go:[a-z_]+' -- ':!**/*_test.go' ':!test/' ':!**/testdata/**' | sort -u - "binary", "build", - "buildsomethingelse", "cgo_dynamic_linker", "cgo_export_dynamic", "cgo_export_static", @@ -85,10 +84,10 @@ var known = []string{ "cgo_import_static", "cgo_ldflag", "cgo_unsafe_args", + "debug", "embed", "generate", "linkname", - "name", "nocheckptr", "noescape", "noinline", @@ -101,5 +100,7 @@ var known = []string{ "systemstack", "uintptrescapes", "uintptrkeepalive", + "wasmimport", + "wasmexport", "yeswritebarrierrec", } diff --git a/vendor/4d63.com/gochecknoglobals/checknoglobals/check_no_globals.go b/vendor/4d63.com/gochecknoglobals/checknoglobals/check_no_globals.go index edf9193ec..c17c6acca 100644 --- a/vendor/4d63.com/gochecknoglobals/checknoglobals/check_no_globals.go +++ b/vendor/4d63.com/gochecknoglobals/checknoglobals/check_no_globals.go @@ -1,7 +1,6 @@ package checknoglobals import ( - "flag" "fmt" "go/ast" "go/token" @@ -37,18 +36,10 @@ func Analyzer() *analysis.Analyzer { Name: "gochecknoglobals", Doc: Doc, Run: checkNoGlobals, - Flags: flags(), RunDespiteErrors: true, } } -func flags() flag.FlagSet { - flags := flag.NewFlagSet("", flag.ExitOnError) - flags.Bool("t", false, "Include tests") - - return *flags -} - func isAllowed(cm ast.CommentMap, v ast.Node, ti *types.Info) bool { switch i := v.(type) { case *ast.GenDecl: @@ -138,16 +129,11 @@ func hasEmbedComment(cm ast.CommentMap, n ast.Node) bool { } func checkNoGlobals(pass *analysis.Pass) (interface{}, error) { - includeTests := pass.Analyzer.Flags.Lookup("t").Value.(flag.Getter).Get().(bool) - for _, file := range pass.Files { filename := pass.Fset.Position(file.Pos()).Filename if !strings.HasSuffix(filename, ".go") { continue } - if !includeTests && strings.HasSuffix(filename, "_test.go") { - continue - } fileCommentMap := ast.NewCommentMap(pass.Fset, file, file.Comments) diff --git a/vendor/github.com/chavacava/garif/.gitignore b/vendor/codeberg.org/chavacava/garif/.gitignore similarity index 100% rename from vendor/github.com/chavacava/garif/.gitignore rename to vendor/codeberg.org/chavacava/garif/.gitignore diff --git a/vendor/github.com/chavacava/garif/LICENSE b/vendor/codeberg.org/chavacava/garif/LICENSE similarity index 100% rename from vendor/github.com/chavacava/garif/LICENSE rename to vendor/codeberg.org/chavacava/garif/LICENSE diff --git a/vendor/github.com/chavacava/garif/README.md b/vendor/codeberg.org/chavacava/garif/README.md similarity index 97% rename from vendor/github.com/chavacava/garif/README.md rename to vendor/codeberg.org/chavacava/garif/README.md index 6a19c6147..c1cc80d3b 100644 --- a/vendor/github.com/chavacava/garif/README.md +++ b/vendor/codeberg.org/chavacava/garif/README.md @@ -1,6 +1,6 @@ # garif -A GO package to create and manipulate SARIF logs. +A Go package to create and manipulate SARIF logs. SARIF, from _Static Analysis Results Interchange Format_, is a standard JSON-based format for the output of static analysis tools defined and promoted by [OASIS](https://www.oasis-open.org/). diff --git a/vendor/github.com/chavacava/garif/constructors.go b/vendor/codeberg.org/chavacava/garif/constructors.go similarity index 100% rename from vendor/github.com/chavacava/garif/constructors.go rename to vendor/codeberg.org/chavacava/garif/constructors.go diff --git a/vendor/github.com/chavacava/garif/decorators.go b/vendor/codeberg.org/chavacava/garif/decorators.go similarity index 100% rename from vendor/github.com/chavacava/garif/decorators.go rename to vendor/codeberg.org/chavacava/garif/decorators.go diff --git a/vendor/github.com/chavacava/garif/doc.go b/vendor/codeberg.org/chavacava/garif/doc.go similarity index 90% rename from vendor/github.com/chavacava/garif/doc.go rename to vendor/codeberg.org/chavacava/garif/doc.go index 50fa6dfe5..5ac5a156a 100644 --- a/vendor/github.com/chavacava/garif/doc.go +++ b/vendor/codeberg.org/chavacava/garif/doc.go @@ -1,4 +1,4 @@ -// Package garif defines all the GO structures required to model a SARIF log file. +// Package garif defines all the Go structures required to model a SARIF log file. // These structures were created using the JSON-schema sarif-schema-2.1.0.json of SARIF logfiles // available at https://github.com/oasis-tcs/sarif-spec/tree/master/Schemata. // diff --git a/vendor/github.com/chavacava/garif/enums.go b/vendor/codeberg.org/chavacava/garif/enums.go similarity index 100% rename from vendor/github.com/chavacava/garif/enums.go rename to vendor/codeberg.org/chavacava/garif/enums.go diff --git a/vendor/github.com/chavacava/garif/io.go b/vendor/codeberg.org/chavacava/garif/io.go similarity index 100% rename from vendor/github.com/chavacava/garif/io.go rename to vendor/codeberg.org/chavacava/garif/io.go diff --git a/vendor/github.com/chavacava/garif/models.go b/vendor/codeberg.org/chavacava/garif/models.go similarity index 98% rename from vendor/github.com/chavacava/garif/models.go rename to vendor/codeberg.org/chavacava/garif/models.go index f16a86136..ed18b04a5 100644 --- a/vendor/github.com/chavacava/garif/models.go +++ b/vendor/codeberg.org/chavacava/garif/models.go @@ -273,7 +273,7 @@ type ExternalProperties struct { // An array of graph objects that will be merged with a separate run. Graphs []*Graph `json:"graphs,omitempty"` - // A stable, unique identifer for this external properties object, in the form of a GUID. + // A stable, unique identifier for this external properties object, in the form of a GUID. Guid string `json:"guid,omitempty"` // Describes the invocation of the analysis tool that will be merged with a separate run. @@ -291,7 +291,7 @@ type ExternalProperties struct { // An array of result objects that will be merged with a separate run. Results []*Result `json:"results,omitempty"` - // A stable, unique identifer for the run associated with this external properties object, in the form of a GUID. + // A stable, unique identifier for the run associated with this external properties object, in the form of a GUID. RunGuid string `json:"runGuid,omitempty"` // The URI of the JSON schema corresponding to the version of the external property file format. @@ -319,7 +319,7 @@ type ExternalProperties struct { // ExternalPropertyFileReference Contains information that enables a SARIF consumer to locate the external property file that contains the value of an externalized property associated with the run. type ExternalPropertyFileReference struct { - // A stable, unique identifer for the external property file in the form of a GUID. + // A stable, unique identifier for the external property file in the form of a GUID. Guid string `json:"guid,omitempty"` // A non-negative integer specifying the number of items contained in the external property file. @@ -835,7 +835,7 @@ type ReportingDescriptor struct { // A description of the report. Should, as far as possible, provide details sufficient to enable resolution of any problem indicated by the result. FullDescription *MultiformatMessageString `json:"fullDescription,omitempty"` - // A unique identifer for the reporting descriptor in the form of a GUID. + // A unique identifier for the reporting descriptor in the form of a GUID. Guid string `json:"guid,omitempty"` // Provides the primary documentation for the report, useful when there is no online documentation. @@ -928,7 +928,7 @@ type Result struct { // An array of zero or more unique graph objects associated with the result. Graphs []*Graph `json:"graphs,omitempty"` - // A stable, unique identifer for the result in the form of a GUID. + // A stable, unique identifier for the result in the form of a GUID. Guid string `json:"guid,omitempty"` // An absolute URI at which the result can be viewed. @@ -1114,7 +1114,7 @@ type RunAutomationDetails struct { // A description of the identity and role played within the engineering system by this object's containing run object. Description *Message `json:"description,omitempty"` - // A stable, unique identifer for this object's containing run object in the form of a GUID. + // A stable, unique identifier for this object's containing run object in the form of a GUID. Guid string `json:"guid,omitempty"` // A hierarchical string that uniquely identifies this object's containing run object. @@ -1169,7 +1169,7 @@ type StackFrame struct { // Suppression A suppression that is relevant to a result. type Suppression struct { - // A stable, unique identifer for the supression in the form of a GUID. + // A stable, unique identifier for the suppression in the form of a GUID. Guid string `json:"guid,omitempty"` // A string representing the justification for the suppression. @@ -1293,7 +1293,7 @@ type ToolComponent struct { // A dictionary, each of whose keys is a resource identifier and each of whose values is a multiformatMessageString object, which holds message strings in plain text and (optionally) Markdown format. The strings can include placeholders, which can be used to construct a message in combination with an arbitrary number of additional string arguments. GlobalMessageStrings map[string]*MultiformatMessageString `json:"globalMessageStrings,omitempty"` - // A unique identifer for the tool component in the form of a GUID. + // A unique identifier for the tool component in the form of a GUID. Guid string `json:"guid,omitempty"` // The absolute URI at which information about this version of the tool component can be found. diff --git a/vendor/github.com/polyfloyd/go-errorlint/LICENSE b/vendor/codeberg.org/polyfloyd/go-errorlint/LICENSE similarity index 100% rename from vendor/github.com/polyfloyd/go-errorlint/LICENSE rename to vendor/codeberg.org/polyfloyd/go-errorlint/LICENSE diff --git a/vendor/github.com/polyfloyd/go-errorlint/errorlint/allowed.go b/vendor/codeberg.org/polyfloyd/go-errorlint/errorlint/allowed.go similarity index 100% rename from vendor/github.com/polyfloyd/go-errorlint/errorlint/allowed.go rename to vendor/codeberg.org/polyfloyd/go-errorlint/errorlint/allowed.go diff --git a/vendor/github.com/polyfloyd/go-errorlint/errorlint/analysis.go b/vendor/codeberg.org/polyfloyd/go-errorlint/errorlint/analysis.go similarity index 94% rename from vendor/github.com/polyfloyd/go-errorlint/errorlint/analysis.go rename to vendor/codeberg.org/polyfloyd/go-errorlint/errorlint/analysis.go index 84ebd6cf8..a26067bbf 100644 --- a/vendor/github.com/polyfloyd/go-errorlint/errorlint/analysis.go +++ b/vendor/codeberg.org/polyfloyd/go-errorlint/errorlint/analysis.go @@ -17,7 +17,7 @@ func NewAnalyzer(opts ...Option) *analysis.Analyzer { a := &analysis.Analyzer{ Name: "errorlint", - Doc: "Source code linter for Go software that can be used to find code that will cause problems with the error wrapping scheme introduced in Go 1.13.", + Doc: "Linter for error wrapping issues.", Run: run, } diff --git a/vendor/codeberg.org/polyfloyd/go-errorlint/errorlint/lint.go b/vendor/codeberg.org/polyfloyd/go-errorlint/errorlint/lint.go new file mode 100644 index 000000000..b7d3cbd5f --- /dev/null +++ b/vendor/codeberg.org/polyfloyd/go-errorlint/errorlint/lint.go @@ -0,0 +1,908 @@ +package errorlint + +import ( + "bytes" + "fmt" + "go/ast" + "go/constant" + "go/printer" + "go/token" + "go/types" + "strings" + + "golang.org/x/tools/go/analysis" +) + +type ByPosition []analysis.Diagnostic + +func (l ByPosition) Len() int { return len(l) } +func (l ByPosition) Swap(i, j int) { l[i], l[j] = l[j], l[i] } +func (l ByPosition) Less(i, j int) bool { + return l[i].Pos < l[j].Pos +} + +func LintFmtErrorfCalls(fset *token.FileSet, info types.Info, multipleWraps bool) []analysis.Diagnostic { + var lints []analysis.Diagnostic + + for expr, t := range info.Types { + // Search for error expressions that are the result of fmt.Errorf + // invocations. + if t.Type.String() != "error" { + continue + } + call, ok := isFmtErrorfCallExpr(info, expr) + if !ok { + continue + } + + // Find all % fields in the format string. + formatVerbs, ok := printfFormatStringVerbs(info, call) + if !ok { + continue + } + + // For any arguments that are errors, check whether the wrapping verb is used. %w may occur + // for multiple errors in one Errorf invocation, unless multipleWraps is true. We raise an + // issue if at least one error does not have a corresponding wrapping verb. + args := call.Args[1:] + if !multipleWraps { + wrapCount := 0 + for i := 0; i < len(args) && i < len(formatVerbs); i++ { + arg := args[i] + if !implementsError(info.Types[arg].Type) { + continue + } + verb := formatVerbs[i] + + if verb.format == "w" { + wrapCount++ + if wrapCount > 1 { + lints = append(lints, analysis.Diagnostic{ + Message: "only one %w verb is permitted per format string", + Pos: arg.Pos(), + }) + break + } + } + + if wrapCount == 0 { + lints = append(lints, analysis.Diagnostic{ + Message: "non-wrapping format verb for fmt.Errorf. Use `%w` to format errors", + Pos: args[i].Pos(), + }) + break + } + } + + } else { + var lint *analysis.Diagnostic + argIndex := 0 + for _, verb := range formatVerbs { + if verb.index != -1 { + argIndex = verb.index + } else { + argIndex++ + } + + if verb.format == "w" || verb.format == "T" { + continue + } + if argIndex-1 >= len(args) { + continue + } + arg := args[argIndex-1] + if !implementsError(info.Types[arg].Type) { + continue + } + + strStart := call.Args[0].Pos() + if lint == nil { + lint = &analysis.Diagnostic{ + Message: "non-wrapping format verb for fmt.Errorf. Use `%w` to format errors", + Pos: arg.Pos(), + } + } + fixMessage := "Use `%w` to format errors" + if len(lint.SuggestedFixes) > 0 { + fixMessage += fmt.Sprintf(" (%d)", len(lint.SuggestedFixes)+1) + } + lint.SuggestedFixes = append(lint.SuggestedFixes, analysis.SuggestedFix{ + Message: fixMessage, + TextEdits: []analysis.TextEdit{{ + Pos: strStart + token.Pos(verb.formatOffset) + 1, + End: strStart + token.Pos(verb.formatOffset) + 2, + NewText: []byte("w"), + }}, + }) + } + if lint != nil { + lints = append(lints, *lint) + } + } + } + return lints +} + +// printfFormatStringVerbs returns a normalized list of all the verbs that are used per argument to +// the printf function. The index of each returned element corresponds to the index of the +// respective argument. +func printfFormatStringVerbs(info types.Info, call *ast.CallExpr) ([]verb, bool) { + if len(call.Args) <= 1 { + return nil, false + } + strLit, ok := call.Args[0].(*ast.BasicLit) + if !ok { + // Ignore format strings that are not literals. + return nil, false + } + formatString := constant.StringVal(info.Types[strLit].Value) + + pp := printfParser{str: formatString} + verbs, err := pp.ParseAllVerbs() + if err != nil { + return nil, false + } + + return verbs, true +} + +func isFmtErrorfCallExpr(info types.Info, expr ast.Expr) (*ast.CallExpr, bool) { + call, ok := expr.(*ast.CallExpr) + if !ok { + return nil, false + } + fn, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + // TODO: Support fmt.Errorf variable aliases? + return nil, false + } + obj := info.Uses[fn.Sel] + + pkg := obj.Pkg() + if pkg != nil && pkg.Name() == "fmt" && obj.Name() == "Errorf" { + return call, true + } + return nil, false +} + +func LintErrorComparisons(info *TypesInfoExt) []analysis.Diagnostic { + var lints []analysis.Diagnostic + + // Check for error comparisons. + for expr := range info.TypesInfo.Types { + // Find == and != operations. + binExpr, ok := expr.(*ast.BinaryExpr) + if !ok { + continue + } + if binExpr.Op != token.EQL && binExpr.Op != token.NEQ { + continue + } + // Comparing errors with nil is okay. + if isNil(binExpr.X) || isNil(binExpr.Y) { + continue + } + // Find comparisons of which one side is a of type error. + if !isErrorType(info.TypesInfo, binExpr.X) && !isErrorType(info.TypesInfo, binExpr.Y) { + continue + } + // Some errors that are returned from some functions are exempt. + if isAllowedErrorComparison(info, binExpr.X, binExpr.Y) { + continue + } + // Comparisons that happen in `func (type) Is(error) bool` are okay. + if isNodeInErrorIsFunc(info, binExpr) { + continue + } + + diagnostic := analysis.Diagnostic{ + Message: fmt.Sprintf("comparing with %s will fail on wrapped errors. Use errors.Is to check for a specific error", binExpr.Op), + Pos: binExpr.Pos(), + } + + // Add suggested fix. + var errVar, targetErr ast.Expr + // Identify which side is the error variable and which is the sentinel error. + if isErrorType(info.TypesInfo, binExpr.Y) && !isErrorType(info.TypesInfo, binExpr.X) { + // Y is error, X is not + errVar = binExpr.Y + targetErr = binExpr.X + } else { + // X is error (or both are errors) + errVar = binExpr.X + targetErr = binExpr.Y + } + + negated := binExpr.Op == token.NEQ + + // Build the suggested fix - preserve the original order of parameters. + replacement := fmt.Sprintf("errors.Is(%s, %s)", exprToString(errVar), exprToString(targetErr)) + if negated { + replacement = "!" + replacement + } + + diagnostic.SuggestedFixes = []analysis.SuggestedFix{{ + Message: "Use errors.Is() to compare errors", + TextEdits: []analysis.TextEdit{{ + Pos: binExpr.Pos(), + End: binExpr.End(), + NewText: []byte(replacement), + }}, + }} + + lints = append(lints, diagnostic) + } + + // Check for error comparisons in switch statements. + for scope := range info.TypesInfo.Scopes { + // Find value switch blocks. + switchStmt, ok := scope.(*ast.SwitchStmt) + if !ok { + continue + } + // Check whether the switch operates on an error type. + if !isErrorType(info.TypesInfo, switchStmt.Tag) { + continue + } + + var problematicCaseClause *ast.CaseClause + outer: + for _, stmt := range switchStmt.Body.List { + caseClause := stmt.(*ast.CaseClause) + for _, caseExpr := range caseClause.List { + if isNil(caseExpr) { + continue + } + // Some errors that are returned from some functions are exempt. + if !isAllowedErrorComparison(info, switchStmt.Tag, caseExpr) { + problematicCaseClause = caseClause + break outer + } + } + } + if problematicCaseClause == nil { + continue + } + + // Comparisons that happen in `func (type) Is(error) bool` are okay. + if isNodeInErrorIsFunc(info, switchStmt) { + continue + } + + if !switchComparesNonNil(switchStmt) { + continue + } + + diagnostic := analysis.Diagnostic{ + Message: "switch on an error will fail on wrapped errors. Use errors.Is to check for specific errors", + Pos: problematicCaseClause.Pos(), + } + + // Create a simpler version of the fix for switch statements + // We'll transform: switch err { case ErrX: ... } + // To: switch { case errors.Is(err, ErrX): ... } + + // Create a new switch statement with an empty tag + newSwitchStmt := &ast.SwitchStmt{ + Init: switchStmt.Init, + Tag: nil, // Empty tag for the switch. + Body: &ast.BlockStmt{ + List: make([]ast.Stmt, len(switchStmt.Body.List)), + }, + } + + // Convert each case to use errors.Is. + switchTagExpr := switchStmt.Tag // The error variable being checked. + for i, stmt := range switchStmt.Body.List { + origCaseClause := stmt.(*ast.CaseClause) + + // Create a new case clause. + newCaseClause := &ast.CaseClause{ + Body: origCaseClause.Body, + } + + // If this is a default case (no expressions), keep it as-is. + if len(origCaseClause.List) == 0 { + newCaseClause.List = nil // Default case. + newSwitchStmt.Body.List[i] = newCaseClause + continue + } + + newCaseClause.List = make([]ast.Expr, 0, len(origCaseClause.List)) + + // Convert each case expression. + for _, caseExpr := range origCaseClause.List { + if isNil(caseExpr) { + // Keep nil checks as is: case err == nil: + newCaseClause.List = append(newCaseClause.List, + &ast.BinaryExpr{ + X: switchTagExpr, + Op: token.EQL, + Y: caseExpr, + }) + continue + } + // Replace err == ErrX with errors.Is(err, ErrX). + newCaseClause.List = append(newCaseClause.List, + &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: ast.NewIdent("errors"), + Sel: ast.NewIdent("Is"), + }, + Args: []ast.Expr{switchTagExpr, caseExpr}, + }) + } + + newSwitchStmt.Body.List[i] = newCaseClause + } + + // Print the modified AST to get the fix text. + var buf bytes.Buffer + printer.Fprint(&buf, token.NewFileSet(), newSwitchStmt) + fixText := buf.String() + + diagnostic.SuggestedFixes = []analysis.SuggestedFix{{ + Message: "Convert to errors.Is() for error comparisons", + TextEdits: []analysis.TextEdit{{ + Pos: switchStmt.Pos(), + End: switchStmt.End(), + NewText: []byte(fixText), + }}, + }} + + lints = append(lints, diagnostic) + } + + return lints +} + +// exprToString converts an expression to its string representation. +func exprToString(expr ast.Expr) string { + switch e := expr.(type) { + case *ast.Ident: + return e.Name + case *ast.SelectorExpr: + return exprToString(e.X) + "." + e.Sel.Name + case *ast.StarExpr: + return "*" + exprToString(e.X) + case *ast.UnaryExpr: + return e.Op.String() + exprToString(e.X) + case *ast.BinaryExpr: + return exprToString(e.X) + " " + e.Op.String() + " " + exprToString(e.Y) + case *ast.CallExpr: + var args []string + for _, arg := range e.Args { + args = append(args, exprToString(arg)) + } + return exprToString(e.Fun) + "(" + strings.Join(args, ", ") + ")" + case *ast.ParenExpr: + return "(" + exprToString(e.X) + ")" + case *ast.IndexExpr: + return exprToString(e.X) + "[" + exprToString(e.Index) + "]" + case *ast.BasicLit: + return e.Value + case *ast.TypeAssertExpr: + return exprToString(e.X) + ".(" + exprToString(e.Type) + ")" + default: + // If we can't handle the expression type, return a placeholder. + return "/* complex expression */" + } +} + +func isNil(ex ast.Expr) bool { + ident, ok := ex.(*ast.Ident) + return ok && ident.Name == "nil" +} + +func isErrorType(info *types.Info, ex ast.Expr) bool { + t := info.Types[ex].Type + return t != nil && t.String() == "error" +} + +func isNodeInErrorIsFunc(info *TypesInfoExt, node ast.Node) bool { + funcDecl := info.ContainingFuncDecl(node) + if funcDecl == nil { + return false + } + // Check if the function name is Is. + if funcDecl.Name.Name != "Is" { + return false + } + // Check if the function has a receiver. + if funcDecl.Recv == nil { + return false + } + // There should be 1 argument of type error. + if params := funcDecl.Type.Params.List; len(params) != 1 || info.TypesInfo.Types[params[0].Type].Type.String() != "error" { + return false + } + // The return type should be bool. + if params := funcDecl.Type.Results.List; len(params) != 1 || info.TypesInfo.Types[params[0].Type].Type.String() != "bool" { + return false + } + return true +} + +// switchComparesNonNil returns true if one of its clauses compares by value. +func switchComparesNonNil(switchStmt *ast.SwitchStmt) bool { + for _, caseBlock := range switchStmt.Body.List { + caseClause, ok := caseBlock.(*ast.CaseClause) + if !ok { + continue + } + for _, clause := range caseClause.List { + switch clause := clause.(type) { + case nil: + // default label is safe. + continue + case *ast.Ident: + // `case nil` is safe. + if clause.Name == "nil" { + continue + } + } + // anything else (including an Ident other than nil) isn't safe. + return true + } + } + return false +} + +func LintErrorTypeAssertions(fset *token.FileSet, info *TypesInfoExt) []analysis.Diagnostic { + var lints []analysis.Diagnostic + + for expr := range info.TypesInfo.Types { + // Find type assertions. + typeAssert, ok := expr.(*ast.TypeAssertExpr) + if !ok { + continue + } + + // Find type assertions that operate on values of type error. + if !isErrorTypeAssertion(*info.TypesInfo, typeAssert) { + continue + } + + if isNodeInErrorIsFunc(info, typeAssert) { + continue + } + + // If the asserted type is not an error, allow the expression. + if !implementsError(info.TypesInfo.Types[typeAssert.Type].Type) { + continue + } + + diagnostic := analysis.Diagnostic{ + Message: "type assertion on error will fail on wrapped errors. Use errors.As to check for specific errors", + Pos: typeAssert.Pos(), + } + + // Create suggested fix for type assertion + targetType := exprToString(typeAssert.Type) + errExpr := exprToString(typeAssert.X) + + // Check if the type is a pointer type + baseType, isPointerType := strings.CutPrefix(targetType, "*") + + parent := info.NodeParent[typeAssert] + + // For assignment statements like: targetErr, ok := err.(*SomeError) + if assign, ok := parent.(*ast.AssignStmt); ok && len(assign.Lhs) == 2 { + if id, ok := assign.Lhs[0].(*ast.Ident); ok { + // Generate a suitable variable name, handling underscore case + // Example: _, ok := err.(*MyError) -> myError := &MyError{}; ok := errors.As(err, &myError) + varName := generateErrorVarName(id.Name, baseType) + + // If this is part of an if statement initialization + ifParent, isIfInit := info.NodeParent[assign].(*ast.IfStmt) + if isIfInit && ifParent.Init == assign { + // Handle special case for if statements + // Replace: if targetErr, ok := err.(*SomeError); ok { + // With: targetErr := &SomeError{} + // if errors.As(err, &targetErr) { + var varDecl string + if isPointerType { + varDecl = fmt.Sprintf("%s := &%s{}", varName, baseType) + } else { + varDecl = fmt.Sprintf("var %s %s", varName, baseType) + } + condition := fmt.Sprintf("if errors.As(%s, &%s)", errExpr, varName) + + replacement := fmt.Sprintf("%s\n%s", + varDecl, condition) + + diagnostic.SuggestedFixes = []analysis.SuggestedFix{{ + Message: "Use errors.As() for type assertions on errors", + TextEdits: []analysis.TextEdit{{ + // Replace both the if statement's initialization and condition + Pos: ifParent.Pos(), + End: ifParent.Body.Pos(), + NewText: []byte(replacement), + }}, + }} + lints = append(lints, diagnostic) + continue + } + + // Regular assignment outside of if statement. + // Replace: targetErr, ok := err.(*SomeError) or err.(SomeError) + // With: targetErr := &SomeError{} or var targetErr SomeError + // ok := errors.As(err, &targetErr) + var varDecl string + if isPointerType { + varDecl = fmt.Sprintf("%s := &%s{}", varName, baseType) + } else { + varDecl = fmt.Sprintf("var %s %s", varName, baseType) + } + + // Preserve the original name of the "ok" variable + // Example: myErr, wasFound := err.(*MyError) + // Should use "wasFound" in the transformed code, not just "ok" + okName := "ok" // Default + if len(assign.Lhs) > 1 { + if okIdent, okOk := assign.Lhs[1].(*ast.Ident); okOk && okIdent.Name != "_" { + okName = okIdent.Name + } + } + + // Align with golden file format + replacement := fmt.Sprintf("%s\n%s := errors.As(%s, &%s)", + varDecl, okName, errExpr, varName) + + diagnostic.SuggestedFixes = []analysis.SuggestedFix{{ + Message: "Use errors.As() for type assertions on errors", + TextEdits: []analysis.TextEdit{{ + Pos: assign.Pos(), + End: assign.End(), + NewText: []byte(replacement), + }}, + }} + lints = append(lints, diagnostic) + continue + } + } + + if _, ok := parent.(*ast.IfStmt); ok { + // For if statements without initialization but with direct type assertion in condition + varName := generateErrorVarName("target", baseType) + var varDecl string + if isPointerType { + varDecl = fmt.Sprintf("%s := &%s{}", varName, baseType) + } else { + varDecl = fmt.Sprintf("var %s %s", varName, baseType) + } + replacement := fmt.Sprintf("%s\nif errors.As(%s, &%s)", + varDecl, errExpr, varName) + + diagnostic.SuggestedFixes = []analysis.SuggestedFix{{ + Message: "Use errors.As() for type assertions on errors", + TextEdits: []analysis.TextEdit{{ + Pos: typeAssert.Pos(), + End: typeAssert.End(), + NewText: []byte(replacement), + }}, + }} + lints = append(lints, diagnostic) + continue + } + + // Handle standalone type assertions without assignment + // Example: _ = err.(*MyError) + // Transforms to: _ = func() *MyError { var target *MyError; _ = errors.As(err, &target); return target }() + varName := generateErrorVarName("target", baseType) + var targetDecl string + if isPointerType { + targetDecl = fmt.Sprintf("%s := &%s{}", varName, baseType) + } else { + targetDecl = fmt.Sprintf("var %s %s", varName, baseType) + } + + replacement := fmt.Sprintf("func() %s {\n\t%s\n\t_ = errors.As(%s, &%s)\n\treturn %s\n}()", + targetType, targetDecl, errExpr, varName, varName) + + diagnostic.SuggestedFixes = []analysis.SuggestedFix{{ + Message: "Use errors.As() for type assertions on errors", + TextEdits: []analysis.TextEdit{{ + Pos: typeAssert.Pos(), + End: typeAssert.End(), + NewText: []byte(replacement), + }}, + }} + lints = append(lints, diagnostic) + } + + for scope := range info.TypesInfo.Scopes { + // Find type switches. + typeSwitch, ok := scope.(*ast.TypeSwitchStmt) + if !ok { + continue + } + + // Find the type assertion in the type switch. + var typeAssert *ast.TypeAssertExpr + switch t := typeSwitch.Assign.(type) { + case *ast.ExprStmt: + typeAssert = t.X.(*ast.TypeAssertExpr) + case *ast.AssignStmt: + typeAssert = t.Rhs[0].(*ast.TypeAssertExpr) + } + + // Check whether the type switch is on a value of type error. + if !isErrorTypeAssertion(*info.TypesInfo, typeAssert) { + continue + } + + if isNodeInErrorIsFunc(info, typeSwitch) { + continue + } + + diagnostic := analysis.Diagnostic{ + Message: "type switch on error will fail on wrapped errors. Use errors.As to check for specific errors", + Pos: typeAssert.Pos(), + } + + // Transform type switch into a switch statement with errors.As in each case + // e.g., switch err.(type) { case *MyError: ... } becomes: + // var myError *MyError; switch { case errors.As(err, &myError): ... } + + // Get the error variable being type-switched on + errExpr := typeAssert.X + + // a flag to know if we can fix the issue with a [analysis.SuggestedFix] + canFix := true + + // Determine if this is a type switch with assignment (switch e := err.(type)) + var assignIdent *ast.Ident + var useShadowVar bool + if assignStmt, ok := typeSwitch.Assign.(*ast.AssignStmt); ok { + // This is a type switch with assignment like: switch e := err.(type) + if len(assignStmt.Lhs) == 1 { + if id, ok := assignStmt.Lhs[0].(*ast.Ident); ok { + if exprToString(errExpr) == id.Name { + // the switch with assignment is like switch err := err.(type) + // we cannot reuse err, otherwise it would lead to errors(err, &err) + canFix = false + + // TODO - suggest a fix with a new variable name instead? + // the issue is with the fact each branch should have a new variable name + } else { + // the variable names are different, we can reuse the assigned variable + assignIdent = id + useShadowVar = true + } + } + } + } + + // Create variable declarations for each type + varDecls := []ast.Stmt{} + + // Create a map of type expressions to variable names + typeToVar := make(map[ast.Expr]string) + + // First collect all unique types from cases + caseTypes := []ast.Expr{} + for _, stmt := range typeSwitch.Body.List { + caseClause := stmt.(*ast.CaseClause) + for _, typeExpr := range caseClause.List { + // Skip default case (empty list) and nil comparisons. + if typeExpr != nil && !isNil(typeExpr) { + caseTypes = append(caseTypes, typeExpr) + } + } + } + + // Create variable declarations for each type. + for i, typeExpr := range caseTypes { + // Create variable declarations for each type. + // generate a default and unique name + varName := fmt.Sprintf("errCase%d", i) + + // then try to find a better one. + if useShadowVar || (assignIdent != nil && i == 0) { + // If we have an assignment identifier, use it for all variables in a switch with assignment. + // Otherwise, if we have an assignment but not shadowing, use it for the first variable. + varName = assignIdent.Name + } + + // Ensure we don't create duplicate variables with the same name. + var duplicate bool + for j := 0; j < i; j++ { + if typeToVar[caseTypes[j]] == varName { + duplicate = true + break + } + } + + if duplicate { + // Use a different name to avoid duplicate variable declarations. + varName = fmt.Sprintf("%s%d", varName, i) + } + + typeToVar[typeExpr] = varName + + // Create a variable declaration. + varDecl := &ast.DeclStmt{ + Decl: &ast.GenDecl{ + Tok: token.VAR, + Specs: []ast.Spec{ + &ast.ValueSpec{ + Names: []*ast.Ident{ast.NewIdent(varName)}, + Type: typeExpr, + }, + }, + }, + } + + varDecls = append(varDecls, varDecl) + } + + // Create a new switch statement with empty tag. + newSwitchStmt := &ast.SwitchStmt{ + Body: &ast.BlockStmt{ + List: make([]ast.Stmt, len(typeSwitch.Body.List)), + }, + } + + // Create a block statement to hold both variable declarations and the switch. + blockStmt := &ast.BlockStmt{ + List: append(varDecls, newSwitchStmt), + } + + // Process each case. + for i, stmt := range typeSwitch.Body.List { + caseClause := stmt.(*ast.CaseClause) + + // Create a new case clause. + newCaseClause := &ast.CaseClause{ + Body: caseClause.Body, + } + + // If this is a default case, keep it as-is. + if len(caseClause.List) == 0 { + // This is the default case. + newCaseClause.List = nil + newSwitchStmt.Body.List[i] = newCaseClause + continue + } + + // For other cases, create errors.As calls for each type. + newCaseClause.List = make([]ast.Expr, len(caseClause.List)) + + for j, typeExpr := range caseClause.List { + // Nil cases should become err == nil. + if isNil(typeExpr) { + newCaseClause.List[j] = &ast.BinaryExpr{ + X: errExpr, + Op: token.EQL, + Y: typeExpr, + } + continue + } + + // Get the previously declared variable for this type. + varName := typeToVar[typeExpr] + + // Create errors.As(err, &varName) call. + newCaseClause.List[j] = &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: ast.NewIdent("errors"), + Sel: ast.NewIdent("As"), + }, + Args: []ast.Expr{ + errExpr, + &ast.UnaryExpr{ + Op: token.AND, + X: ast.NewIdent(varName), + }, + }, + } + } + + // If this is a switch with assignment, we need to update the variable + // names used in the body of each case to match our renamed variables. + if assignIdent != nil && len(caseClause.List) > 0 { + typeExpr := caseClause.List[0] + oldVarName := assignIdent.Name + newVarName := typeToVar[typeExpr] + + if oldVarName != newVarName { + // Create a visitor to replace all mentions of the original variable + // with our renamed variable in this case's body. + visitor := func(n ast.Node) bool { + if ident, ok := n.(*ast.Ident); ok && ident.Name == oldVarName { + ident.Name = newVarName + } + return true + } + + // Apply the visitor to the case body + for _, bodyStmt := range newCaseClause.Body { + ast.Inspect(bodyStmt, visitor) + } + } + } + + // Add this case to the switch. + newSwitchStmt.Body.List[i] = newCaseClause + } + + if canFix { + // Print the resulting block to get the fix text. + var buf bytes.Buffer + printer.Fprint(&buf, token.NewFileSet(), blockStmt) + fixText := buf.String() + + diagnostic.SuggestedFixes = []analysis.SuggestedFix{{ + Message: "Convert type switch to use errors.As", + TextEdits: []analysis.TextEdit{{ + Pos: typeSwitch.Pos(), + End: typeSwitch.End(), + NewText: []byte(fixText), + }}, + }} + } + lints = append(lints, diagnostic) + } + + return lints +} + +func isErrorTypeAssertion(info types.Info, typeAssert *ast.TypeAssertExpr) bool { + t := info.Types[typeAssert.X] + return t.Type.String() == "error" +} + +func implementsError(t types.Type) bool { + mset := types.NewMethodSet(t) + + for i := 0; i < mset.Len(); i++ { + if mset.At(i).Kind() != types.MethodVal { + continue + } + + obj := mset.At(i).Obj() + if obj.Name() == "Error" && obj.Type().String() == "func() string" { + return true + } + } + + return false +} + +// generateErrorVarName creates an appropriate variable name for error type assertions. +// If originalName is "_" or a generic placeholder, it generates a more meaningful name +// based on the error type, following Go naming conventions: +// +// Examples: +// - originalName="_", typeName="MyError" → "myError" (camelCase conversion) +// - originalName="_", typeName="pkg.CustomError" → "customError" (package prefix removed) +// - originalName="existingName" → "existingName" (original name preserved) +// - originalName="_", typeName="" → "myErr" (fallback for unknown types) +// +// This helps ensure code readability when converting type assertions to errors.As calls, +// particularly when dealing with underscore identifiers that can't be referenced. +func generateErrorVarName(originalName, typeName string) string { + // If the original name is not an underscore, use it + if originalName != "_" { + return originalName + } + + // Handle underscore case by generating a name based on the type + // Strip any package prefix like "pkg." + if lastDot := strings.LastIndex(typeName, "."); lastDot >= 0 { + typeName = typeName[lastDot+1:] + } + + // Convert first letter to lowercase for camelCase + if len(typeName) > 0 { + firstChar := strings.ToLower(typeName[:1]) + if len(typeName) > 1 { + return firstChar + typeName[1:] + } + return firstChar + } + + // If we couldn't determine a good name, use default. + return "anErr" +} diff --git a/vendor/github.com/polyfloyd/go-errorlint/errorlint/options.go b/vendor/codeberg.org/polyfloyd/go-errorlint/errorlint/options.go similarity index 56% rename from vendor/github.com/polyfloyd/go-errorlint/errorlint/options.go rename to vendor/codeberg.org/polyfloyd/go-errorlint/errorlint/options.go index 4d7c742d8..64d4352f4 100644 --- a/vendor/github.com/polyfloyd/go-errorlint/errorlint/options.go +++ b/vendor/codeberg.org/polyfloyd/go-errorlint/errorlint/options.go @@ -13,3 +13,15 @@ func WithAllowedWildcard(ap []AllowPair) Option { allowedWildcardAppend(ap) } } + +func WithComparison(enabled bool) Option { + return func() { + checkComparison = enabled + } +} + +func WithAsserts(enabled bool) Option { + return func() { + checkAsserts = enabled + } +} diff --git a/vendor/github.com/polyfloyd/go-errorlint/errorlint/printf.go b/vendor/codeberg.org/polyfloyd/go-errorlint/errorlint/printf.go similarity index 100% rename from vendor/github.com/polyfloyd/go-errorlint/errorlint/printf.go rename to vendor/codeberg.org/polyfloyd/go-errorlint/errorlint/printf.go diff --git a/vendor/github.com/GaijinEntertainment/go-exhaustruct/v3/LICENSE b/vendor/dev.gaijin.team/go/exhaustruct/v4/LICENSE similarity index 100% rename from vendor/github.com/GaijinEntertainment/go-exhaustruct/v3/LICENSE rename to vendor/dev.gaijin.team/go/exhaustruct/v4/LICENSE diff --git a/vendor/github.com/GaijinEntertainment/go-exhaustruct/v3/analyzer/analyzer.go b/vendor/dev.gaijin.team/go/exhaustruct/v4/analyzer/analyzer.go similarity index 52% rename from vendor/github.com/GaijinEntertainment/go-exhaustruct/v3/analyzer/analyzer.go rename to vendor/dev.gaijin.team/go/exhaustruct/v4/analyzer/analyzer.go index ec75fd409..a235de385 100644 --- a/vendor/github.com/GaijinEntertainment/go-exhaustruct/v3/analyzer/analyzer.go +++ b/vendor/dev.gaijin.team/go/exhaustruct/v4/analyzer/analyzer.go @@ -12,14 +12,12 @@ import ( "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/ast/inspector" - "github.com/GaijinEntertainment/go-exhaustruct/v3/internal/comment" - "github.com/GaijinEntertainment/go-exhaustruct/v3/internal/pattern" - "github.com/GaijinEntertainment/go-exhaustruct/v3/internal/structure" + "dev.gaijin.team/go/exhaustruct/v4/internal/comment" + "dev.gaijin.team/go/exhaustruct/v4/internal/structure" ) type analyzer struct { - include pattern.List `exhaustruct:"optional"` - exclude pattern.List `exhaustruct:"optional"` + config Config structFields structure.FieldsCache `exhaustruct:"optional"` comments comment.Cache `exhaustruct:"optional"` @@ -28,22 +26,16 @@ type analyzer struct { typeProcessingNeedMu sync.RWMutex `exhaustruct:"optional"` } -func NewAnalyzer(include, exclude []string) (*analysis.Analyzer, error) { - a := analyzer{ - typeProcessingNeed: make(map[string]bool), - comments: comment.Cache{}, - } - - var err error - - a.include, err = pattern.NewList(include...) +func NewAnalyzer(config Config) (*analysis.Analyzer, error) { + err := config.Prepare() if err != nil { - return nil, err //nolint:wrapcheck + return nil, err } - a.exclude, err = pattern.NewList(exclude...) - if err != nil { - return nil, err //nolint:wrapcheck + a := analyzer{ + config: config, + typeProcessingNeed: make(map[string]bool), + comments: comment.Cache{}, } return &analysis.Analyzer{ //nolint:exhaustruct @@ -51,27 +43,10 @@ func NewAnalyzer(include, exclude []string) (*analysis.Analyzer, error) { Doc: "Checks if all structure fields are initialized", Run: a.run, Requires: []*analysis.Analyzer{inspect.Analyzer}, - Flags: a.newFlagSet(), + Flags: *a.config.BindToFlagSet(flag.NewFlagSet("", flag.PanicOnError)), }, nil } -func (a *analyzer) newFlagSet() flag.FlagSet { - fs := flag.NewFlagSet("", flag.PanicOnError) - - fs.Var(&a.include, "i", `Regular expression to match type names, can receive multiple flags. -Anonymous structs can be matched by '' alias. -4ex: - github.com/GaijinEntertainment/go-exhaustruct/v3/analyzer\. - github.com/GaijinEntertainment/go-exhaustruct/v3/analyzer\.TypeInfo`) - fs.Var(&a.exclude, "e", `Regular expression to exclude type names, can receive multiple flags. -Anonymous structs can be matched by '' alias. -4ex: - github.com/GaijinEntertainment/go-exhaustruct/v3/analyzer\. - github.com/GaijinEntertainment/go-exhaustruct/v3/analyzer\.TypeInfo`) - - return *fs -} - func (a *analyzer) run(pass *analysis.Pass) (any, error) { insp := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) //nolint:forcetypeassert @@ -98,14 +73,8 @@ func (a *analyzer) newVisitor(pass *analysis.Pass) func(n ast.Node, push bool, s return true } - if len(lit.Elts) == 0 { - if ret, ok := stackParentIsReturn(stack); ok { - if returnContainsNonNilError(pass, ret, n) { - // it is okay to return uninitialized structure in case struct's direct parent is - // a return statement containing non-nil error - return true - } - } + if len(lit.Elts) == 0 && a.checkEmptyStructAllowed(pass, stack, typeInfo) { + return true } file := a.comments.Get(pass.Fset, stack[0].(*ast.File)) //nolint:forcetypeassert @@ -113,11 +82,155 @@ func (a *analyzer) newVisitor(pass *analysis.Pass) func(n ast.Node, push bool, s pos, msg := a.processStruct(pass, lit, structTyp, typeInfo, rc) if pos != nil { - pass.Reportf(*pos, msg) + pass.Reportf(*pos, "%s", msg) + } + + return true + } +} + +func (a *analyzer) checkEmptyStructAllowed(pass *analysis.Pass, stack []ast.Node, typeInfo *TypeInfo) bool { + // empty structs are globally allowed + if a.config.AllowEmpty { + return true + } + + // some structs are allowed to be empty, basing on pattern + if a.config.allowEmptyPatterns.MatchFullString(typeInfo.String()) { + return true + } + + if ret, ok := getParentReturnStmt(stack); ok { + // empty structures are allowed in all return statements + if a.config.AllowEmptyReturns { + return true + } + + // empty structures are allowed in error returns + if isErrorReturnStatement(pass, ret, stack[len(stack)-1]) { + return true } + } + // empty structures are allowed in variable declarations + if isChildOfVariableDeclaration(stack) && a.config.AllowEmptyDeclarations { return true } + + return false +} + +// isPartOfVariableDeclaration checks if the node is direct part of variable +// declaration, meaning that it is a first-level RHS child of `:=` or `var` +// declaration. +func isChildOfVariableDeclaration(stack []ast.Node) bool { + if len(stack) < 2 { //nolint:mnd // stack for sure contains at leas current node and its parent (file) + return false + } + + // Start from composite literal and go up the stack + for i := len(stack) - 1; i > 0; i-- { + parent := stack[i-1] + + switch p := parent.(type) { + case *ast.AssignStmt: + if p.Tok == token.DEFINE { + return true + } + + case *ast.ValueSpec: + return true + + case *ast.UnaryExpr: + // Only allow pointer taking (&) + if p.Op == token.AND { + continue + } + + return false + + default: + return false + } + } + + return false +} + +// getParentReturnStmt checks if the direct parent of the current node is a +// return statement and returns it if so. +func getParentReturnStmt(stack []ast.Node) (*ast.ReturnStmt, bool) { + if len(stack) < 2 { //nolint:mnd // stack for sure contains at leas current node and its parent (file) + return nil, false + } + + // Start from composite literal and go up the stack + for i := len(stack) - 1; i > 0; i-- { + parent := stack[i-1] + + switch p := parent.(type) { + case *ast.ReturnStmt: + return p, true + + case *ast.UnaryExpr: + // Only allow pointer taking (&) + if p.Op == token.AND { + continue + } + + return nil, false + + default: + return nil, false + } + } + + return nil, false +} + +// errorIface is an interface type of the [error] interface. +// +//nolint:forcetypeassert,gochecknoglobals +var errorIface = types.Universe.Lookup("error").Type().Underlying().(*types.Interface) + +// isErrorReturnStatement checks if the return statement is an error return +// statement, meaning that it contains a non-nil value that implements [error]. +func isErrorReturnStatement(pass *analysis.Pass, n *ast.ReturnStmt, currentNode ast.Node) bool { + if len(n.Results) == 0 { + return false + } + + // iterate backwards, since idiomatic position of error is at the end + for i := len(n.Results) - 1; i >= 0; i-- { + ri := n.Results[i] + + // Skip the current node, since it is already being checked + if ri == currentNode { + continue + } + + switch ri := ri.(type) { + case *ast.Ident: + // Skip nil values + if ri.Name == "nil" { + continue + } + + case *ast.UnaryExpr: + // Current node might be under the unary expression + if ri.X == currentNode { + continue + } + } + + // Check if the type implements error interface + resultType := pass.TypesInfo.TypeOf(ri) + if resultType != nil && types.Implements(resultType, errorIface) { + return true + } + } + + return false } // getCompositeLitRelatedComments returns all comments that are related to checked node. We @@ -129,16 +242,23 @@ func getCompositeLitRelatedComments(stack []ast.Node, cm ast.CommentMap) []*ast. for i := len(stack) - 1; i >= 0; i-- { node := stack[i] - switch node.(type) { - case *ast.CompositeLit, // stack[len(stack)-1] - *ast.ReturnStmt, // return ... - *ast.IndexExpr, // map[enum]...{...}[key] - *ast.CallExpr, // myfunc(map...) - *ast.UnaryExpr, // &map... - *ast.AssignStmt, // variable assignment (without var keyword) - *ast.DeclStmt, // var declaration, parent of *ast.GenDecl - *ast.GenDecl, // var declaration, parent of *ast.ValueSpec - *ast.ValueSpec: // var declaration + switch tn := node.(type) { + case *ast.CompositeLit: + // comments on the lines prior to literal + comments = append(comments, cm[node]...) + // comments on the same line as literal type definition + // worth noting that event "typeless" literals have a type + comments = append(comments, cm[tn.Type]...) + + case *ast.ReturnStmt, // return ... + *ast.IndexExpr, // map[enum]...{...}[key] + *ast.CallExpr, // myfunc(map...) + *ast.UnaryExpr, // &map... + *ast.AssignStmt, // variable assignment (without var keyword) + *ast.DeclStmt, // var declaration, parent of *ast.GenDecl + *ast.GenDecl, // var declaration, parent of *ast.ValueSpec + *ast.ValueSpec, // var declaration + *ast.KeyValueExpr: // field declaration comments = append(comments, cm[node]...) default: @@ -150,7 +270,7 @@ func getCompositeLitRelatedComments(stack []ast.Node, cm ast.CommentMap) []*ast. } func getStructType(pass *analysis.Pass, lit *ast.CompositeLit) (*types.Struct, *TypeInfo, bool) { - switch typ := pass.TypesInfo.TypeOf(lit).(type) { + switch typ := types.Unalias(pass.TypesInfo.TypeOf(lit)).(type) { case *types.Named: // named type if structTyp, ok := typ.Underlying().(*types.Struct); ok { pkg := typ.Obj().Pkg() @@ -179,56 +299,6 @@ func getStructType(pass *analysis.Pass, lit *ast.CompositeLit) (*types.Struct, * } } -func stackParentIsReturn(stack []ast.Node) (*ast.ReturnStmt, bool) { - // it is safe to skip boundary check, since stack always has at least one element - // we also have no reason to check the first element, since it is always a file - for i := len(stack) - 2; i > 0; i-- { - switch st := stack[i].(type) { - case *ast.ReturnStmt: - return st, true - - case *ast.UnaryExpr: - // in case we're dealing with pointers - it is still viable to check pointer's - // parent for return statement - continue - - default: - return nil, false - } - } - - return nil, false -} - -// errorIface is a type that represents [error] interface and all types will be -// compared against. -var errorIface = types.Universe.Lookup("error").Type().Underlying().(*types.Interface) - -func returnContainsNonNilError(pass *analysis.Pass, ret *ast.ReturnStmt, except ast.Node) bool { - // errors are mostly located at the end of return statement, so we're starting - // from the end. - for i := len(ret.Results) - 1; i >= 0; i-- { - ri := ret.Results[i] - - // skip current node - if ri == except { - continue - } - - if un, ok := ri.(*ast.UnaryExpr); ok { - if un.X == except { - continue - } - } - - if types.Implements(pass.TypesInfo.TypeOf(ri), errorIface) { - return true - } - } - - return false -} - func (a *analyzer) processStruct( pass *analysis.Pass, lit *ast.CompositeLit, @@ -266,7 +336,7 @@ func (a *analyzer) processStruct( // shouldProcessType returns true if type should be processed basing off include // and exclude patterns, defined though constructor and\or flags. func (a *analyzer) shouldProcessType(info *TypeInfo) bool { - if len(a.include) == 0 && len(a.exclude) == 0 { + if len(a.config.includePatterns) == 0 && len(a.config.excludePatterns) == 0 { return true } @@ -278,13 +348,14 @@ func (a *analyzer) shouldProcessType(info *TypeInfo) bool { if !ok { a.typeProcessingNeedMu.Lock() + res = true - if a.include != nil && !a.include.MatchFullString(name) { + if a.config.includePatterns != nil && !a.config.includePatterns.MatchFullString(name) { res = false } - if res && a.exclude != nil && a.exclude.MatchFullString(name) { + if res && a.config.excludePatterns != nil && a.config.excludePatterns.MatchFullString(name) { res = false } diff --git a/vendor/dev.gaijin.team/go/exhaustruct/v4/analyzer/config.go b/vendor/dev.gaijin.team/go/exhaustruct/v4/analyzer/config.go new file mode 100644 index 000000000..0c39cbed8 --- /dev/null +++ b/vendor/dev.gaijin.team/go/exhaustruct/v4/analyzer/config.go @@ -0,0 +1,127 @@ +package analyzer + +import ( + "flag" + "strings" + + "dev.gaijin.team/go/golib/e" + + "dev.gaijin.team/go/exhaustruct/v4/internal/pattern" +) + +type Config struct { + // IncludeRx is a list of regular expressions to match type names that should be + // processed. Anonymous structs can be matched by '' alias. + // + // Each regular expression must match the full type name, including package path. + // For example, to match type `net/http.Cookie` regular expression should be + // `.*/http\.Cookie`, but not `http\.Cookie`. + IncludeRx []string `exhaustruct:"optional"` + includePatterns pattern.List `exhaustruct:"optional"` + + // ExcludeRx is a list of regular expressions to match type names that should be + // excluded from processing. Anonymous structs can be matched by '' + // alias. + // + // Has precedence over IncludeRx. + // + // Each regular expression must match the full type name, including package path. + // For example, to match type `net/http.Cookie` regular expression should be + // `.*/http\.Cookie`, but not `http\.Cookie`. + ExcludeRx []string `exhaustruct:"optional"` + excludePatterns pattern.List `exhaustruct:"optional"` + + // AllowEmpty allows empty structures, effectively excluding them from the check. + AllowEmpty bool `exhaustruct:"optional"` + + // AllowEmptyRx is a list of regular expressions to match type names that should + // be allowed to be empty. Anonymous structs can be matched by '' + // alias. + // + // Each regular expression must match the full type name, including package path. + // For example, to match type `net/http.Cookie` regular expression should be + // `.*/http\.Cookie`, but not `http\.Cookie`. + AllowEmptyRx []string `exhaustruct:"optional"` + allowEmptyPatterns pattern.List `exhaustruct:"optional"` + + // AllowEmptyReturns allows empty structures in return statements. + AllowEmptyReturns bool `exhaustruct:"optional"` + + // AllowEmptyDeclarations allows empty structures in variable declarations. + AllowEmptyDeclarations bool `exhaustruct:"optional"` +} + +// Prepare compiles all regular expression patterns into pattern lists for +// efficient matching. +func (c *Config) Prepare() error { + var err error + + c.includePatterns, err = pattern.NewList(c.IncludeRx...) + if err != nil { + return e.NewFrom("compile include patterns", err) + } + + c.excludePatterns, err = pattern.NewList(c.ExcludeRx...) + if err != nil { + return e.NewFrom("compile exclude patterns", err) + } + + c.allowEmptyPatterns, err = pattern.NewList(c.AllowEmptyRx...) + if err != nil { + return e.NewFrom("compile allow empty patterns", err) + } + + return nil +} + +// stringSliceFlag implements flag.Value interface for []string fields. +type stringSliceFlag struct { + slice *[]string +} + +func (s stringSliceFlag) String() string { + if s.slice == nil { + return "" + } + + return strings.Join(*s.slice, ",") +} + +func (s stringSliceFlag) Set(value string) error { + *s.slice = append(*s.slice, value) + return nil +} + +// BindToFlagSet binds the config fields to the provided flag set. +func (c *Config) BindToFlagSet(fs *flag.FlagSet) *flag.FlagSet { + fs.Var(stringSliceFlag{&c.IncludeRx}, "include-rx", + "Regular expression to match type names that should be processed. "+ + "Anonymous structs can be matched by '' alias. "+ + "Each regex must match the full type name including package path. "+ + "Example: `.*/http\\.Cookie`. Can be used multiple times.") + fs.Var(stringSliceFlag{&c.IncludeRx}, "i", "Short form of -include-rx") + + fs.Var(stringSliceFlag{&c.ExcludeRx}, "exclude-rx", + "Regular expression to exclude type names from processing, has precedence over -include. "+ + "Anonymous structs can be matched by '' alias. "+ + "Each regex must match the full type name including package path. "+ + "Example: `.*/http\\.Cookie`. Can be used multiple times.") + fs.Var(stringSliceFlag{&c.ExcludeRx}, "e", "Short form of -exclude-rx") + + fs.BoolVar(&c.AllowEmpty, "allow-empty", c.AllowEmpty, + "Allow empty structures, effectively excluding them from the check") + + fs.Var(stringSliceFlag{&c.AllowEmptyRx}, "allow-empty-rx", + "Regular expression to match type names that should be allowed to be empty. "+ + "Anonymous structs can be matched by '' alias. "+ + "Each regex must match the full type name including package path. "+ + "Example: `.*/http\\.Cookie`. Can be used multiple times.") + + fs.BoolVar(&c.AllowEmptyReturns, "allow-empty-returns", c.AllowEmptyReturns, + "Allow empty structures in return statements") + + fs.BoolVar(&c.AllowEmptyDeclarations, "allow-empty-declarations", c.AllowEmptyDeclarations, + "Allow empty structures in variable declarations") + + return fs +} diff --git a/vendor/github.com/GaijinEntertainment/go-exhaustruct/v3/internal/comment/cache.go b/vendor/dev.gaijin.team/go/exhaustruct/v4/internal/comment/cache.go similarity index 100% rename from vendor/github.com/GaijinEntertainment/go-exhaustruct/v3/internal/comment/cache.go rename to vendor/dev.gaijin.team/go/exhaustruct/v4/internal/comment/cache.go diff --git a/vendor/github.com/GaijinEntertainment/go-exhaustruct/v3/internal/comment/directive.go b/vendor/dev.gaijin.team/go/exhaustruct/v4/internal/comment/directive.go similarity index 100% rename from vendor/github.com/GaijinEntertainment/go-exhaustruct/v3/internal/comment/directive.go rename to vendor/dev.gaijin.team/go/exhaustruct/v4/internal/comment/directive.go diff --git a/vendor/dev.gaijin.team/go/exhaustruct/v4/internal/pattern/list.go b/vendor/dev.gaijin.team/go/exhaustruct/v4/internal/pattern/list.go new file mode 100644 index 000000000..26b8ac20d --- /dev/null +++ b/vendor/dev.gaijin.team/go/exhaustruct/v4/internal/pattern/list.go @@ -0,0 +1,91 @@ +package pattern + +import ( + "regexp" + "strings" + + "dev.gaijin.team/go/golib/e" + "dev.gaijin.team/go/golib/fields" +) + +// List represents a collection of compiled regular expressions that can be used +// for pattern matching against strings. It implements the flag.Value interface +// to support command-line flag binding. +type List []*regexp.Regexp //nolint:recvcheck + +// NewList creates a new List from the provided regular expression patterns. +// Each pattern string is compiled into a regular expression. If any pattern +// is empty or fails to compile, an error is returned. +func NewList(patterns ...string) (List, error) { + if len(patterns) == 0 { + return nil, nil + } + + list := make(List, 0, len(patterns)) + + for _, pattern := range patterns { + re, err := parseRx(pattern) + if err != nil { + return nil, err + } + + list = append(list, re) + } + + return list, nil +} + +// MatchFullString checks if any of the regular expressions in the list matches +// the entire input string. A match is considered successful only if the regex +// matches the complete string from start to end, not just a substring. +// +// For example, if a List contains the pattern "test", it will match "test" +// but not "testing" or "contest". +func (l List) MatchFullString(str string) bool { + for i := 0; i < len(l); i++ { + if m := l[i].FindStringSubmatch(str); len(m) > 0 && m[0] == str { + return true + } + } + + return false +} + +// String returns a string representation of the List by joining all regex patterns +// with commas. This method implements the flag.Value interface and is used when +// the List is displayed or serialized. +func (l List) String() string { + patterns := make([]string, len(l)) + for i, re := range l { + patterns[i] = re.String() + } + + return strings.Join(patterns, ",") +} + +// Set adds a new regex pattern to the List by compiling the provided string. +// This method implements the flag.Value interface and is called when the flag +// is set from command-line arguments or programmatically. +func (l *List) Set(value string) error { + re, err := parseRx(value) + if err != nil { + return err + } + + *l = append(*l, re) + + return nil +} + +func parseRx(str string) (*regexp.Regexp, error) { + if str == "" { + return nil, e.New("empty regular expression is not allowed") + } + + re, err := regexp.Compile(str) + if err != nil { + return nil, e.NewFrom("failed to compile regular expression", err, fields.F("pattern", str)) + } + + return re, nil +} diff --git a/vendor/github.com/GaijinEntertainment/go-exhaustruct/v3/internal/structure/fields-cache.go b/vendor/dev.gaijin.team/go/exhaustruct/v4/internal/structure/fields-cache.go similarity index 100% rename from vendor/github.com/GaijinEntertainment/go-exhaustruct/v3/internal/structure/fields-cache.go rename to vendor/dev.gaijin.team/go/exhaustruct/v4/internal/structure/fields-cache.go diff --git a/vendor/github.com/GaijinEntertainment/go-exhaustruct/v3/internal/structure/fields.go b/vendor/dev.gaijin.team/go/exhaustruct/v4/internal/structure/fields.go similarity index 100% rename from vendor/github.com/GaijinEntertainment/go-exhaustruct/v3/internal/structure/fields.go rename to vendor/dev.gaijin.team/go/exhaustruct/v4/internal/structure/fields.go diff --git a/vendor/dev.gaijin.team/go/golib/LICENSE b/vendor/dev.gaijin.team/go/golib/LICENSE new file mode 100644 index 000000000..05a82fec2 --- /dev/null +++ b/vendor/dev.gaijin.team/go/golib/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Gaijin Entertainment + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/dev.gaijin.team/go/golib/e/doc.go b/vendor/dev.gaijin.team/go/golib/e/doc.go new file mode 100644 index 000000000..a1582f5c1 --- /dev/null +++ b/vendor/dev.gaijin.team/go/golib/e/doc.go @@ -0,0 +1,46 @@ +// Package e provides a custom error type with support for error chaining and +// structured metadata fields. +// +// The main type, Err, enables convenient error wrapping and the attachment of +// key-value metadata fields (fields.Field). Errors can be wrapped to add context +// and enriched with fields for structured logging or diagnostics. +// +// Example: Wrapping errors with context +// +// var ErrJSONParseFailed = e.New("JSON parse failed") +// var val any +// if err := json.Unmarshal([]byte(`["invalid", "json]`), &val); err != nil { +// return ErrJSONParseFailed.Wrap(err) +// // Output: "JSON parse failed: unexpected end of JSON input" +// } +// +// Example: Enriching errors with fields +// +// err := e.New("operation failed").WithField("user_id", 42) +// // Output: "operation failed (user_id=42)" +// +// err = err.Wrap(e.New("db error").WithFields(fields.F("query", "SELECT *"))) +// // Output: "operation failed (user_id=42): db error (query=SELECT *)" +// +// Any error can be converted to an Err using the From function. This does not +// wrap the error; unwrapping will not return the original error. +// +// e.From(errors.New("error")) // "error" +// errors.Unwrap(e.From(errors.New("error"))) // nil +// +// The Err string format is: +// +// (fields...): +// +// Fields are always enclosed in parentheses, and wrapped errors are separated by +// a colon and space. +// +// All methods that return errors create new instances; errors are immutable. +// +// Deprecated methods Unwrap, Is, and As are present for compatibility with the +// errors package, but should not be used directly. Use the errors package +// functions instead. +// +// The Log function logs errors using our logger abstraction - logger.Logger, +// extracting reason, wrapped error, and fields, logging them appropriately. +package e diff --git a/vendor/dev.gaijin.team/go/golib/e/err.go b/vendor/dev.gaijin.team/go/golib/e/err.go new file mode 100644 index 000000000..334dc563c --- /dev/null +++ b/vendor/dev.gaijin.team/go/golib/e/err.go @@ -0,0 +1,140 @@ +package e + +import ( + "errors" + "slices" + "strings" + + "dev.gaijin.team/go/golib/fields" +) + +// Err represents a custom error type that supports error chaining and structured metadata fields. +type Err struct { + errs []error + fields fields.List +} + +// New returns a new Err with the given reason and optional fields. +// The returned error can be further wrapped or annotated with additional fields. +func New(reason string, f ...fields.Field) *Err { + return From(errors.New(reason), f...) //nolint:err113 +} + +// NewFrom returns a new Err with the given reason, wrapping the provided error, and optional fields. +// If wrapped is nil, it behaves like New. +func NewFrom(reason string, wrapped error, f ...fields.Field) *Err { + if wrapped == nil { + return New(reason, f...) + } + + return &Err{ + errs: []error{errors.New(reason), wrapped}, //nolint:err113 + fields: f, + } +} + +// From converts any error to an Err, optionally adding fields. This is not true wrapping; +// unwrapping will not return the original error. Passing nil results in an Err with reason "error(nil)". +func From(origin error, f ...fields.Field) *Err { + if origin == nil { + origin = errors.New("error(nil)") //nolint:err113 + } + + return &Err{ + errs: []error{origin}, + fields: f, + } +} + +// Wrap returns a new Err that wraps the provided error with the current Err as context. +// Additional fields can be attached. If err is nil, it is replaced with an Err for "error(nil)". +func (e *Err) Wrap(err error, f ...fields.Field) *Err { + if err == nil { + err = errors.New("error(nil)") //nolint:err113 + } + + return &Err{ + errs: []error{e, err}, + fields: f, + } +} + +// Error returns the string representation of the Err, including reason, fields, and wrapped errors. +func (e *Err) Error() string { + b := &strings.Builder{} + writeTo(b, e) + + return b.String() +} + +func writeTo(b *strings.Builder, err error) { + if b.Len() > 0 { + b.WriteString(": ") + } + + ee, ok := err.(*Err) //nolint:errorlint + if !ok { + b.WriteString(err.Error()) + + return + } + + b.WriteString(ee.Reason()) + + if ee == nil { + return + } + + if len(ee.fields) > 0 { + b.WriteRune(' ') + ee.fields.WriteTo(b) + } + + if len(ee.errs) > 1 { + writeTo(b, ee.errs[1]) + } +} + +// Clone returns a new Err with the same error, wrapped error, and a cloned fields container. +func (e *Err) Clone() *Err { + return &Err{ + errs: slices.Clone(e.errs), + fields: slices.Clone(e.fields), + } +} + +// WithFields returns a new Err with the same error and the provided fields. +func (e *Err) WithFields(f ...fields.Field) *Err { + return From(e, f...) +} + +// WithField returns a new Err with the same error and a single additional field. +func (e *Err) WithField(key string, val any) *Err { + return e.WithFields(fields.F(key, val)) +} + +// Fields returns the metadata fields attached to the Err. +func (e *Err) Fields() fields.List { + return e.fields +} + +// Reason returns the reason string of the Err, without fields or wrapped errors. +// If the Err is nil, returns "(*e.Err)(nil)". If empty, returns "(*e.Err)(empty)". +func (e *Err) Reason() string { + if e == nil { + return "(*e.Err)(nil)" + } + + if len(e.errs) == 0 { + return "(*e.Err)(empty)" + } + + return e.errs[0].Error() +} + +// Unwrap returns the underlying errors for compatibility with errors.Is and errors.As. +// +// Deprecated: This method is for internal use only. Prefer using the errors package directly. +func (e *Err) Unwrap() []error { + return e.errs +} diff --git a/vendor/dev.gaijin.team/go/golib/e/log.go b/vendor/dev.gaijin.team/go/golib/e/log.go new file mode 100644 index 000000000..0caafaab0 --- /dev/null +++ b/vendor/dev.gaijin.team/go/golib/e/log.go @@ -0,0 +1,33 @@ +package e + +import ( + "dev.gaijin.team/go/golib/fields" +) + +// ErrorLogger defines a function that logs an error message, an error, and optional fields. +type ErrorLogger func(msg string, err error, fs ...fields.Field) + +// Log logs the provided error using the given ErrorLogger function. +// +// If err is nil, Log does nothing. If err is of type Err, its reason is used as the log message, +// the wrapped error is passed as the error, and its fields are passed as log fields. +// For other error types, err.Error() is used as the message and nil is passed as the error. +func Log(err error, f ErrorLogger) { + if err == nil { + return + } + + // We're not interested in wrapped error, therefore we're only typecasting it. + if e, ok := err.(*Err); ok { //nolint:errorlint + var wrapped error + if len(e.errs) > 1 { + wrapped = e.errs[1] + } + + f(e.Reason(), wrapped, e.fields...) + + return + } + + f(err.Error(), nil) +} diff --git a/vendor/dev.gaijin.team/go/golib/fields/dict.go b/vendor/dev.gaijin.team/go/golib/fields/dict.go new file mode 100644 index 000000000..cd025089f --- /dev/null +++ b/vendor/dev.gaijin.team/go/golib/fields/dict.go @@ -0,0 +1,69 @@ +package fields + +import ( + "iter" + "strings" +) + +const CollectionSep = ", " + +// Dict is a map-based collection of unique fields, keyed by string. +// It provides efficient lookup and overwrites duplicate keys. +type Dict map[string]any + +// Add inserts or updates fields in the Dict, overwriting existing keys if present. +// +// Example: +// +// d := fields.Dict{"foo": "bar"} +// d.Add(fields.F("baz", 42), fields.F("foo", "qux")) // d["foo"] == "qux" +func (d Dict) Add(fields ...Field) { + for _, f := range fields { + d[f.K] = f.V + } +} + +// ToList converts the Dict to a List, with order unspecified. +// Each key-value pair becomes a Field in the resulting List. +func (d Dict) ToList() List { + s := make(List, 0, len(d)) + + for k, v := range d { + s = append(s, Field{k, v}) + } + + return s +} + +// All returns an iterator over all key-value pairs in the Dict as iter.Seq2[string, any]. +// +// Example: +// +// for k, v := range d.All() { +// fmt.Println(k, v) +// } +func (d Dict) All() iter.Seq2[string, any] { + return func(yield func(string, any) bool) { + for k, v := range d { + if !yield(k, v) { + return + } + } + } +} + +// WriteTo writes the Dict as a string in the format "(key1=val1, key2=val2)" to the provided builder. +// If the Dict is empty, nothing is written. The order of fields is unspecified. +func (d Dict) WriteTo(b *strings.Builder) { + WriteTo(b, d.All()) +} + +// String returns the Dict as a string in the format "(key1=val1, key2=val2)". +// Returns an empty string if the Dict is empty. The order of fields is unspecified. +func (d Dict) String() string { + b := strings.Builder{} + + d.WriteTo(&b) + + return b.String() +} diff --git a/vendor/dev.gaijin.team/go/golib/fields/doc.go b/vendor/dev.gaijin.team/go/golib/fields/doc.go new file mode 100644 index 000000000..1ef4ee56d --- /dev/null +++ b/vendor/dev.gaijin.team/go/golib/fields/doc.go @@ -0,0 +1,32 @@ +// Package fields provides types and functions to work with key-value pairs. +// +// The package offers three primary abstractions: +// +// - Field: A key-value pair where the key is a string and the value can be any type. +// - Dict: A map-based collection of unique fields, providing efficient key-based lookup. +// - List: An ordered collection of fields that preserves insertion order. +// +// Fields can be created using the F constructor, and both Dict and List provide +// conversion methods between the two collection types. All types implement String() +// for consistent string representation. +// +// Example usage: +// +// // Create fields +// f1 := fields.F("status", "success") +// f2 := fields.F("code", 200) +// +// // Working with a List (ordered collection) +// var list fields.List +// list.Add(f1, f2) +// fmt.Println(list) // "(status=success, code=200)" +// +// // Working with a Dict (unique key collection) +// dict := fields.Dict{} +// dict.Add(f1, f2, fields.F("status", "updated")) // overwrites "status" +// fmt.Println(dict) // "(status=updated, code=200)" (order may vary) +// +// // Converting between types +// list2 := dict.ToList() // order unspecified +// dict2 := list.ToDict() // last occurrence of each key wins +package fields diff --git a/vendor/dev.gaijin.team/go/golib/fields/field.go b/vendor/dev.gaijin.team/go/golib/fields/field.go new file mode 100644 index 000000000..324b2970f --- /dev/null +++ b/vendor/dev.gaijin.team/go/golib/fields/field.go @@ -0,0 +1,82 @@ +// Package fields provides types and functions for working with key-value fields. +package fields + +import ( + "fmt" + "iter" + "strings" +) + +// Field represents a key-value pair, where the key is a string and the value can be any type. +type Field struct { + // Key of the field + K string + // Value of the field + V any +} + +// F creates a new Field with the given key and value. +// +// Example: +// +// f := fields.F("user", "alice") +func F(key string, value any) Field { + return Field{K: key, V: value} +} + +// writeKVTo writes a key-value pair to the given builder in the format "key=value". +func writeKVTo(b *strings.Builder, key string, value any) { + b.WriteString(key) + b.WriteRune('=') + + switch val := value.(type) { + case string: + b.WriteString(val) + + case fmt.Stringer: + b.WriteString(val.String()) + + case error: + b.WriteString(val.Error()) + + default: + _, _ = fmt.Fprintf(b, "%v", value) + } +} + +// WriteTo writes the Field as a string in the format "key=value" to the provided builder. +func (f Field) WriteTo(b *strings.Builder) { + writeKVTo(b, f.K, f.V) +} + +// String returns the Field as a string in the format "key=value". +func (f Field) String() string { + b := &strings.Builder{} + f.WriteTo(b) + + return b.String() +} + +// WriteTo writes key-value pairs from an iter.Seq2[string, any] to the builder in the format "(key1=val1, key2=val2)". +// If no fields are present, nothing is written. +func WriteTo(b *strings.Builder, seq iter.Seq2[string, any]) { + first := true + + for k, v := range seq { + if first { + first = false + + b.WriteString("(") + } else { + b.WriteString(", ") + } + + writeKVTo(b, k, v) + } + + // means that we've written at least one field, and, therefore, + // can close the parenthesis + if !first { + b.WriteString(")") + } +} diff --git a/vendor/dev.gaijin.team/go/golib/fields/list.go b/vendor/dev.gaijin.team/go/golib/fields/list.go new file mode 100644 index 000000000..5a881f77e --- /dev/null +++ b/vendor/dev.gaijin.team/go/golib/fields/list.go @@ -0,0 +1,69 @@ +package fields + +import ( + "iter" + "strings" +) + +// List is an ordered collection of Field values, preserving insertion order. +// Such collection do not check for duplicate keys. +type List []Field //nolint:recvcheck //we need Add to be a pointer receiver to modify original value. + +// Add one or more fields to the List, modifying it. +// +// Example: +// +// var l fields.List +// l.Add(fields.F("foo", "bar"), fields.F("baz", 42)) +func (l *List) Add(fields ...Field) { + *l = append(*l, fields...) +} + +// ToDict converts the List to a Dict, overwriting duplicate keys with the last occurrence. +// +// Example: +// +// l := fields.List{fields.F("foo", 1), fields.F("foo", 2)} +// d := l.ToDict() // d["foo"] == 2 +func (l List) ToDict() Dict { + d := make(Dict, len(l)) + + for i := range l { + d[l[i].K] = l[i].V + } + + return d +} + +// All returns an iterator over all key-value pairs in the List as iter.Seq2[string, any]. +// +// Example: +// +// for k, v := range l.All() { +// fmt.Println(k, v) +// } +func (l List) All() iter.Seq2[string, any] { + return func(yield func(string, any) bool) { + for i := 0; i < len(l); i++ { + if !yield(l[i].K, l[i].V) { + return + } + } + } +} + +// WriteTo writes the List as a string in the format "(key1=val1, key2=val2)" to the provided builder. +// If the List is empty, nothing is written. +func (l List) WriteTo(b *strings.Builder) { + WriteTo(b, l.All()) +} + +// String returns the List as a string in the format "(key1=val1, key2=val2)". +// Returns an empty string if the List is empty. +func (l List) String() string { + b := strings.Builder{} + + l.WriteTo(&b) + + return b.String() +} diff --git a/vendor/github.com/4meepo/tagalign/.gitignore b/vendor/github.com/4meepo/tagalign/.gitignore index e37bb52e4..1c6218ee2 100644 --- a/vendor/github.com/4meepo/tagalign/.gitignore +++ b/vendor/github.com/4meepo/tagalign/.gitignore @@ -17,6 +17,7 @@ *.test .vscode +.idea/ # Output of the go coverage tool, specifically when used with LiteIDE *.out diff --git a/vendor/github.com/4meepo/tagalign/.goreleaser.yml b/vendor/github.com/4meepo/tagalign/.goreleaser.yml index e7b6f6800..37dfec7c8 100644 --- a/vendor/github.com/4meepo/tagalign/.goreleaser.yml +++ b/vendor/github.com/4meepo/tagalign/.goreleaser.yml @@ -1,4 +1,4 @@ ---- +version: 2 project_name: tagalign release: @@ -29,4 +29,4 @@ builds: goarch: 386 - goos: freebsd goarch: arm64 - main: ./cmd/tagalign/ \ No newline at end of file + main: ./cmd/tagalign/ diff --git a/vendor/github.com/4meepo/tagalign/options.go b/vendor/github.com/4meepo/tagalign/options.go index ddec98da7..2a7859246 100644 --- a/vendor/github.com/4meepo/tagalign/options.go +++ b/vendor/github.com/4meepo/tagalign/options.go @@ -2,13 +2,6 @@ package tagalign type Option func(*Helper) -// WithMode specify the mode of tagalign. -func WithMode(mode Mode) Option { - return func(h *Helper) { - h.mode = mode - } -} - // WithSort enable tags sort. // fixedOrder specify the order of tags, the other tags will be sorted by name. // Sory is disabled by default. diff --git a/vendor/github.com/4meepo/tagalign/tagalign.go b/vendor/github.com/4meepo/tagalign/tagalign.go index 4734b5666..612aefb0b 100644 --- a/vendor/github.com/4meepo/tagalign/tagalign.go +++ b/vendor/github.com/4meepo/tagalign/tagalign.go @@ -1,27 +1,19 @@ package tagalign import ( + "cmp" "fmt" "go/ast" "go/token" - "log" "reflect" - "sort" + "slices" "strconv" "strings" - "github.com/fatih/structtag" - + "github.com/alfatraining/structtag" "golang.org/x/tools/go/analysis" ) -type Mode int - -const ( - StandaloneMode Mode = iota - GolangciLintMode -) - type Style int const ( @@ -44,11 +36,14 @@ func NewAnalyzer(options ...Option) *analysis.Analyzer { } } -func Run(pass *analysis.Pass, options ...Option) []Issue { - var issues []Issue +func Run(pass *analysis.Pass, options ...Option) { for _, f := range pass.Files { + filename := getFilename(pass.Fset, f) + if !strings.HasSuffix(filename, ".go") { + continue + } + h := &Helper{ - mode: StandaloneMode, style: DefaultStyle, align: true, } @@ -63,22 +58,19 @@ func Run(pass *analysis.Pass, options ...Option) []Issue { if !h.align && !h.sort { // do nothing - return nil + return } ast.Inspect(f, func(n ast.Node) bool { h.find(pass, n) return true }) + h.Process(pass) - issues = append(issues, h.issues...) } - return issues } type Helper struct { - mode Mode - style Style align bool // whether enable tags align. @@ -87,19 +79,6 @@ type Helper struct { singleFields []*ast.Field consecutiveFieldsGroups [][]*ast.Field // fields in this group, must be consecutive in struct. - issues []Issue -} - -// Issue is used to integrate with golangci-lint's inline auto fix. -type Issue struct { - Pos token.Position - Message string - InlineFix InlineFix -} -type InlineFix struct { - StartCol int // zero-based - Length int - NewString string } func (w *Helper) find(pass *analysis.Pass, n ast.Node) { @@ -159,42 +138,28 @@ func (w *Helper) find(pass *analysis.Pass, n ast.Node) { split() } -func (w *Helper) report(pass *analysis.Pass, field *ast.Field, startCol int, msg, replaceStr string) { - if w.mode == GolangciLintMode { - iss := Issue{ - Pos: pass.Fset.Position(field.Tag.Pos()), - Message: msg, - InlineFix: InlineFix{ - StartCol: startCol, - Length: len(field.Tag.Value), - NewString: replaceStr, - }, - } - w.issues = append(w.issues, iss) - } - - if w.mode == StandaloneMode { - pass.Report(analysis.Diagnostic{ - Pos: field.Tag.Pos(), - End: field.Tag.End(), - Message: msg, - SuggestedFixes: []analysis.SuggestedFix{ - { - Message: msg, - TextEdits: []analysis.TextEdit{ - { - Pos: field.Tag.Pos(), - End: field.Tag.End(), - NewText: []byte(replaceStr), - }, +func (w *Helper) report(pass *analysis.Pass, field *ast.Field, msg, replaceStr string) { + pass.Report(analysis.Diagnostic{ + Pos: field.Tag.Pos(), + End: field.Tag.End(), + Message: msg, + SuggestedFixes: []analysis.SuggestedFix{ + { + Message: msg, + TextEdits: []analysis.TextEdit{ + { + Pos: field.Tag.Pos(), + End: field.Tag.End(), + NewText: []byte(replaceStr), }, }, }, - }) - } + }, + }) } -func (w *Helper) Process(pass *analysis.Pass) { //nolint:gocognit +//nolint:gocognit,gocyclo,nestif +func (w *Helper) Process(pass *analysis.Pass) { // process grouped fields for _, fields := range w.consecutiveFieldsGroups { offsets := make([]int, len(fields)) @@ -220,7 +185,7 @@ func (w *Helper) Process(pass *analysis.Pass) { //nolint:gocognit tag, err := strconv.Unquote(field.Tag.Value) if err != nil { // if tag value is not a valid string, report it directly - w.report(pass, field, column, errTagValueSyntax, field.Tag.Value) + w.report(pass, field, errTagValueSyntax, field.Tag.Value) fields = removeField(fields, i) continue } @@ -228,7 +193,7 @@ func (w *Helper) Process(pass *analysis.Pass) { //nolint:gocognit tags, err := structtag.Parse(tag) if err != nil { // if tag value is not a valid struct tag, report it directly - w.report(pass, field, column, err.Error(), field.Tag.Value) + w.report(pass, field, err.Error(), field.Tag.Value) fields = removeField(fields, i) continue } @@ -241,7 +206,7 @@ func (w *Helper) Process(pass *analysis.Pass) { //nolint:gocognit cp[i] = tag } notSortedTagsGroup = append(notSortedTagsGroup, cp) - sortBy(w.fixedTagOrder, tags) + sortTags(w.fixedTagOrder, tags) } for _, t := range tags.Tags() { addKey(t.Key) @@ -252,7 +217,7 @@ func (w *Helper) Process(pass *analysis.Pass) { //nolint:gocognit } if w.sort && StrictStyle == w.style { - sortAllKeys(w.fixedTagOrder, uniqueKeys) + sortKeys(w.fixedTagOrder, uniqueKeys) maxTagNum = len(uniqueKeys) } @@ -340,27 +305,26 @@ func (w *Helper) Process(pass *analysis.Pass) { //nolint:gocognit msg := "tag is not aligned, should be: " + unquoteTag - w.report(pass, field, offsets[i], msg, newTagValue) + w.report(pass, field, msg, newTagValue) } } // process single fields for _, field := range w.singleFields { - column := pass.Fset.Position(field.Tag.Pos()).Column - 1 tag, err := strconv.Unquote(field.Tag.Value) if err != nil { - w.report(pass, field, column, errTagValueSyntax, field.Tag.Value) + w.report(pass, field, errTagValueSyntax, field.Tag.Value) continue } tags, err := structtag.Parse(tag) if err != nil { - w.report(pass, field, column, err.Error(), field.Tag.Value) + w.report(pass, field, err.Error(), field.Tag.Value) continue } originalTags := append([]*structtag.Tag(nil), tags.Tags()...) if w.sort { - sortBy(w.fixedTagOrder, tags) + sortTags(w.fixedTagOrder, tags) } newTagValue := fmt.Sprintf("`%s`", tags.String()) @@ -371,85 +335,47 @@ func (w *Helper) Process(pass *analysis.Pass) { //nolint:gocognit msg := "tag is not aligned , should be: " + tags.String() - w.report(pass, field, column, msg, newTagValue) + w.report(pass, field, msg, newTagValue) } } -// Issues returns all issues found by the analyzer. -// It is used to integrate with golangci-lint. -func (w *Helper) Issues() []Issue { - log.Println("tagalign 's Issues() should only be called in golangci-lint mode") - return w.issues -} - -// sortBy sorts tags by fixed order. +// sortTags sorts tags by fixed order. // If a tag is not in the fixed order, it will be sorted by name. -func sortBy(fixedOrder []string, tags *structtag.Tags) { - // sort by fixed order - sort.Slice(tags.Tags(), func(i, j int) bool { - ti := tags.Tags()[i] - tj := tags.Tags()[j] - - oi := findIndex(fixedOrder, ti.Key) - oj := findIndex(fixedOrder, tj.Key) - - if oi == -1 && oj == -1 { - return ti.Key < tj.Key - } - - if oi == -1 { - return false - } - - if oj == -1 { - return true - } - - return oi < oj +func sortTags(fixedOrder []string, tags *structtag.Tags) { + slices.SortFunc(tags.Tags(), func(a, b *structtag.Tag) int { + return compareByFixedOrder(fixedOrder)(a.Key, b.Key) }) } -func sortAllKeys(fixedOrder []string, keys []string) { - sort.Slice(keys, func(i, j int) bool { - oi := findIndex(fixedOrder, keys[i]) - oj := findIndex(fixedOrder, keys[j]) +func sortKeys(fixedOrder []string, keys []string) { + slices.SortFunc(keys, compareByFixedOrder(fixedOrder)) +} + +func compareByFixedOrder(fixedOrder []string) func(a, b string) int { + return func(a, b string) int { + oi := slices.Index(fixedOrder, a) + oj := slices.Index(fixedOrder, b) if oi == -1 && oj == -1 { - return keys[i] < keys[j] + return strings.Compare(a, b) } if oi == -1 { - return false + return 1 } if oj == -1 { - return true + return -1 } - return oi < oj - }) -} - -func findIndex(s []string, e string) int { - for i, a := range s { - if a == e { - return i - } + return cmp.Compare(oi, oj) } - return -1 } func alignFormat(length int) string { return "%" + fmt.Sprintf("-%ds", length) } -func max(a, b int) int { - if a > b { - return a - } - return b -} - func removeField(fields []*ast.Field, index int) []*ast.Field { if index < 0 || index >= len(fields) { return fields @@ -457,3 +383,12 @@ func removeField(fields []*ast.Field, index int) []*ast.Field { return append(fields[:index], fields[index+1:]...) } + +func getFilename(fset *token.FileSet, file *ast.File) string { + filename := fset.PositionFor(file.Pos(), true).Filename + if !strings.HasSuffix(filename, ".go") { + return fset.PositionFor(file.Pos(), false).Filename + } + + return filename +} diff --git a/vendor/github.com/Abirdcfly/dupword/README.md b/vendor/github.com/Abirdcfly/dupword/README.md index e6c5b919f..a3db4c503 100644 --- a/vendor/github.com/Abirdcfly/dupword/README.md +++ b/vendor/github.com/Abirdcfly/dupword/README.md @@ -101,10 +101,14 @@ Flags: no effect (deprecated) -c int display offending line with this many lines of context (default -1) + -comments-only + check only comments, skip strings -cpuprofile string write CPU profile to this file -debug string debug flags, any subset of "fpstv" + -diff + with -fix, don't update the files, but print a unified diff -fix apply all suggested fixes -flags @@ -130,7 +134,7 @@ Flags: ### 5. my advice -use `--keyword=the,and,a` and `-fix` together. I think that specifying only commonly repeated prepositions can effectively avoid false positives. +use `--keyword=the,and,a` and `-fix` together. I think that specifying only commonly repeated prepositions can effectively avoid false positives. see [dupword#4](https://github.com/Abirdcfly/dupword/issues/4) for real code example. diff --git a/vendor/github.com/Abirdcfly/dupword/dupword.go b/vendor/github.com/Abirdcfly/dupword/dupword.go index 6838d7e75..a3eaced8a 100644 --- a/vendor/github.com/Abirdcfly/dupword/dupword.go +++ b/vendor/github.com/Abirdcfly/dupword/dupword.go @@ -20,8 +20,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -// Package dupword defines an Analyzer that checks that duplicate words -// int the source code. +// Package dupword defines an Analyzer that checks those duplicate words in the source code. package dupword import ( @@ -49,54 +48,45 @@ This analyzer checks miswritten duplicate words in comments or package doc or st CommentPrefix = `//` ) -var ( - defaultWord = []string{} - // defaultWord = []string{"the", "and", "a"} - ignoreWord = map[string]bool{} -) - -type analyzer struct { - KeyWord []string -} +type keywords []string -func (a *analyzer) String() string { - return strings.Join(a.KeyWord, ",") +func (a keywords) String() string { + return strings.Join(a, ",") } -func (a *analyzer) Set(w string) error { +func (a *keywords) Set(w string) error { if len(w) != 0 { - a.KeyWord = make([]string, 0) - a.KeyWord = append(a.KeyWord, strings.Split(w, ",")...) + *a = append(*a, strings.Split(w, ",")...) } + return nil } -type ignore struct { -} +type ignore map[string]bool -func (a *ignore) String() string { - t := make([]string, 0, len(ignoreWord)) - for k := range ignoreWord { +func (a ignore) String() string { + var t []string + + for k := range a { t = append(t, k) } + return strings.Join(t, ",") } -func (a *ignore) Set(w string) error { +func (a ignore) Set(w string) error { for _, k := range strings.Split(w, ",") { - ignoreWord[k] = true + a[k] = true } - return nil -} -// for test only -func ClearIgnoreWord() { - ignoreWord = map[string]bool{} + return nil } func NewAnalyzer() *analysis.Analyzer { - ignore := &ignore{} - analyzer := &analyzer{KeyWord: defaultWord} + analyzer := &analyzer{ + ignoreWords: map[string]bool{}, + } + a := &analysis.Analyzer{ Name: Name, Doc: Doc, @@ -104,17 +94,29 @@ func NewAnalyzer() *analysis.Analyzer { Run: analyzer.run, RunDespiteErrors: true, } + a.Flags.Init(Name, flag.ExitOnError) - a.Flags.Var(analyzer, "keyword", "keywords for detecting duplicate words") - a.Flags.Var(ignore, "ignore", "ignore words") + a.Flags.Var(&analyzer.keywords, "keyword", "keywords for detecting duplicate words") + a.Flags.Var(&analyzer.ignoreWords, "ignore", "ignore words") + a.Flags.BoolVar(&analyzer.commentsOnly, "comments-only", false, "check only comments, skip strings") a.Flags.Var(version{}, "V", "print version and exit") + return a } +type analyzer struct { + keywords keywords + ignoreWords ignore + commentsOnly bool +} + func (a *analyzer) run(pass *analysis.Pass) (interface{}, error) { for _, file := range pass.Files { a.fixDuplicateWordInComment(pass, file) } + if a.commentsOnly { + return nil, nil + } inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) nodeFilter := []ast.Node{ (*ast.BasicLit)(nil), @@ -208,8 +210,8 @@ func (a *analyzer) fixDuplicateWordInString(pass *analysis.Pass, lit *ast.BasicL } // CheckOneKey use to check there is a defined duplicate word in a string. -// raw is checked line. key is the keyword to check. empty means just check duplicate word. -func CheckOneKey(raw, key string) (new string, findWord string, find bool) { +// `raw` is the checked line. key is the keyword to check. empty means just check duplicate word. +func (a *analyzer) checkOneKey(raw, key string) (new string, findWord string, find bool) { if key == "" { has := false fields := strings.Fields(raw) @@ -249,7 +251,7 @@ func CheckOneKey(raw, key string) (new string, findWord string, find bool) { */ symbol := raw[spaceStart:i] if ((key != "" && curWord == key) || key == "") && curWord == preWord && curWord != "" { - if !ExcludeWords(curWord) { + if !a.excludeWords(cutTrailingCommas(curWord)) { find = true findWordMap[curWord] = true newLine.WriteString(lastSpace) @@ -270,7 +272,7 @@ func CheckOneKey(raw, key string) (new string, findWord string, find bool) { // last position word := raw[wordStart:] if ((key != "" && word == key) || key == "") && word == preWord { - if !ExcludeWords(word) { + if !a.excludeWords(cutTrailingCommas(word)) { find = true findWordMap[word] = true } @@ -296,8 +298,8 @@ func CheckOneKey(raw, key string) (new string, findWord string, find bool) { } func (a *analyzer) Check(raw string) (update string, keyword string, find bool) { - for _, key := range a.KeyWord { - updateOne, _, findOne := CheckOneKey(raw, key) + for _, key := range a.keywords { + updateOne, _, findOne := a.checkOneKey(raw, key) if findOne { raw = updateOne find = findOne @@ -309,8 +311,8 @@ func (a *analyzer) Check(raw string) (update string, keyword string, find bool) } } } - if len(a.KeyWord) == 0 { - return CheckOneKey(raw, "") + if len(a.keywords) == 0 { + return a.checkOneKey(raw, "") } return } @@ -318,7 +320,7 @@ func (a *analyzer) Check(raw string) (update string, keyword string, find bool) // ExcludeWords determines whether duplicate words should be reported, // // e.g. %s, should not be reported. -func ExcludeWords(word string) (exclude bool) { +func (a *analyzer) excludeWords(word string) (exclude bool) { firstRune, _ := utf8.DecodeRuneInString(word) if unicode.IsDigit(firstRune) { return true @@ -329,7 +331,7 @@ func ExcludeWords(word string) (exclude bool) { if unicode.IsSymbol(firstRune) { return true } - if _, exist := ignoreWord[word]; exist { + if _, exist := a.ignoreWords[word]; exist { return true } return false @@ -341,3 +343,11 @@ func isExampleOutputStart(comment string) bool { strings.HasPrefix(comment, "// Unordered output:") || strings.HasPrefix(comment, "// unordered output:") } + +// cutTrailingCommas is used to remove trailing commas of words. +// The excludeWords are provided as comma-separated list, so it is +// impossible to ignore "[word], [word]," matches otherwise +func cutTrailingCommas(s string) string { + result, _ := strings.CutSuffix(s, ",") + return result +} diff --git a/vendor/github.com/AdminBenni/iota-mixing/LICENSE b/vendor/github.com/AdminBenni/iota-mixing/LICENSE new file mode 100644 index 000000000..06e009ffa --- /dev/null +++ b/vendor/github.com/AdminBenni/iota-mixing/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Benedikt Aron Þjóðbjargarson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/AdminBenni/iota-mixing/pkg/analyzer/analyzer.go b/vendor/github.com/AdminBenni/iota-mixing/pkg/analyzer/analyzer.go new file mode 100644 index 000000000..4c56ebdde --- /dev/null +++ b/vendor/github.com/AdminBenni/iota-mixing/pkg/analyzer/analyzer.go @@ -0,0 +1,118 @@ +package analyzer + +import ( + "go/ast" + "go/token" + "log" + "strings" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/ast/inspector" + + "github.com/AdminBenni/iota-mixing/pkg/analyzer/flags" +) + +func GetIotaMixingAnalyzer() *analysis.Analyzer { + return &analysis.Analyzer{ + Name: "iotamixing", + Doc: "checks if iotas are being used in const blocks with other non-iota declarations.", + Run: run, + Requires: []*analysis.Analyzer{inspect.Analyzer}, + } +} + +func run(pass *analysis.Pass) (interface{}, error) { + ASTInspector := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) //nolint:forcetypeassert // will always be correct type + + // we only need to check Generic Declarations + nodeFilter := []ast.Node{ + (*ast.GenDecl)(nil), + } + + ASTInspector.Preorder(nodeFilter, func(node ast.Node) { checkGenericDeclaration(node, pass) }) + + return interface{}(nil), nil +} + +func checkGenericDeclaration(node ast.Node, pass *analysis.Pass) { + decl := node.(*ast.GenDecl) //nolint:forcetypeassert // filtered for this node, will always be this type + + if decl.Tok != token.CONST { + return + } + + checkConstDeclaration(decl, pass) +} + +func checkConstDeclaration(decl *ast.GenDecl, pass *analysis.Pass) { + iotaFound := false + valued := make([]*ast.ValueSpec, 0, len(decl.Specs)) + + // traverse specs inside const block + for _, spec := range decl.Specs { + if specVal, ok := spec.(*ast.ValueSpec); ok { + iotaFound, valued = checkValueSpec(specVal, iotaFound, valued) + } + } + + if !iotaFound { + return + } + + // there was an iota, now depending on the report-individual flag we must either + // report the const block or all regular valued specs that are mixing with the iota + switch flags.ReportIndividualFlag() { + case flags.TrueString: + for _, value := range valued { + pass.Reportf( + value.Pos(), + "%s is a const with r-val in same const block as iota. keep iotas in separate const blocks", + getName(value), + ) + } + default: //nolint:gocritic // default logs error and falls through to "false" case, simplest in this order + log.Printf( + "warning: unsupported value '%s' for flag %s, assuming value 'false'.", + flags.ReportIndividualFlag(), flags.ReportIndividualFlagName, + ) + + fallthrough + case flags.FalseString: + if len(valued) == 0 { + return + } + + pass.Reportf(decl.Pos(), "iota mixing. keep iotas in separate blocks to consts with r-val") + } +} + +func checkValueSpec(spec *ast.ValueSpec, iotaFound bool, valued []*ast.ValueSpec) (bool, []*ast.ValueSpec) { + // traverse through values (r-val) of spec and look for iota + for _, expr := range spec.Values { + if idn, ok := expr.(*ast.Ident); ok && idn.Name == "iota" { + return true, valued + } + } + + // iota wasn't found, add to valued spec list if there is an r-val + if len(spec.Values) > 0 { + return iotaFound, append(valued, spec) + } + + return iotaFound, valued +} + +func getName(spec *ast.ValueSpec) string { + sb := strings.Builder{} + + for i, ident := range spec.Names { + sb.WriteString(ident.Name) + + if i < len(spec.Names)-1 { + sb.WriteString(", ") + } + } + + return sb.String() +} diff --git a/vendor/github.com/AdminBenni/iota-mixing/pkg/analyzer/flags/flags.go b/vendor/github.com/AdminBenni/iota-mixing/pkg/analyzer/flags/flags.go new file mode 100644 index 000000000..8f9b73b64 --- /dev/null +++ b/vendor/github.com/AdminBenni/iota-mixing/pkg/analyzer/flags/flags.go @@ -0,0 +1,23 @@ +package flags + +import "flag" + +const ( + TrueString = "true" + FalseString = "false" + + ReportIndividualFlagName = "report-individual" + reportIndividualFlagUsage = "whether or not to report individual consts rather than just the const block." +) + +var ( + reportIndividualFlag *string //nolint:gochecknoglobals // only used in this file, not too plussed +) + +func SetupFlags(flags *flag.FlagSet) { + reportIndividualFlag = flags.String(ReportIndividualFlagName, FalseString, reportIndividualFlagUsage) +} + +func ReportIndividualFlag() string { + return *reportIndividualFlag +} diff --git a/vendor/github.com/AlwxSin/noinlineerr/.gitignore b/vendor/github.com/AlwxSin/noinlineerr/.gitignore new file mode 100644 index 000000000..15573eff6 --- /dev/null +++ b/vendor/github.com/AlwxSin/noinlineerr/.gitignore @@ -0,0 +1,33 @@ +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work +go.work.sum + +# env file +.env +.envrc + +# ide +.idea +.vscode + +# OS specific +.DS_Store diff --git a/vendor/github.com/AlwxSin/noinlineerr/.golangci.yml b/vendor/github.com/AlwxSin/noinlineerr/.golangci.yml new file mode 100644 index 000000000..36b315589 --- /dev/null +++ b/vendor/github.com/AlwxSin/noinlineerr/.golangci.yml @@ -0,0 +1,168 @@ +version: "2" + +linters: + default: all + disable: + - decorder + - depguard + - err113 + - exhaustruct + - nlreturn + - nonamedreturns + - paralleltest + - recvcheck + - testpackage + - varnamelen + - wrapcheck + + settings: + cyclop: + max-complexity: 30 + dogsled: + max-blank-identifiers: 2 + dupl: + threshold: 150 + errcheck: + check-type-assertions: false + check-blank: true + exclude-functions: + - fmt.Print + - fmt.Printf + - fmt.Println + - fmt.Fprint(*bytes.Buffer) + - fmt.Fprintf(*bytes.Buffer) + - fmt.Fprintln(*bytes.Buffer) + - fmt.Fprint(*strings.Builder) + - fmt.Fprintf(*strings.Builder) + - fmt.Fprintln(*strings.Builder) + - fmt.Fprint(os.Stderr) + - fmt.Fprintf(os.Stderr) + - fmt.Fprintln(os.Stderr) + - io/ioutil.ReadFile + - io/ioutil.ReadDir + gocognit: + min-complexity: 30 + goconst: + min-len: 3 + min-occurrences: 3 + gocritic: + disabled-checks: + - regexpMust + - rangeValCopy + - importShadow + - docStub + enabled-tags: + - performance + - style + - diagnostic + - experimental + - opinionated + settings: + captLocal: + paramsOnly: true + hugeParam: + sizeThreshold: 1024 + gocyclo: + min-complexity: 30 + godox: + keywords: + - FIXME + govet: + enable: + - atomicalign + disable: + - shadow + enable-all: false + disable-all: false + ireturn: + allow: + - anon + - error + - empty + - stdlib + - generic + lll: + line-length: 160 + misspell: + locale: US + mnd: + ignored-functions: + - ^strings\.SplitN + nakedret: + max-func-lines: 30 + perfsprint: + strconcat: false + prealloc: + simple: true + range-loops: true + for-loops: false + staticcheck: + checks: + - '*' + - -ST1003 + - -QF1008 + unparam: + check-exported: false + unused: + field-writes-are-uses: true + post-statements-are-reads: false + exported-fields-are-used: true + parameters-are-used: true + local-variables-are-used: true + generated-is-used: true + usetesting: + context-background: true + context-todo: true + os-chdir: true + os-mkdir-temp: true + os-setenv: true + os-temp-dir: false + os-create-temp: true + varnamelen: + min-name-length: 2 + whitespace: + multi-if: false + multi-func: false + + exclusions: + presets: + - comments + - common-false-positives + - std-error-handling + rules: + - path: _test\.go + linters: + - bodyclose + - containedctx + - contextcheck + - dogsled + - errcheck + - errchkjson + - errorlint + - forcetypeassert + - funlen + - gosec + - lll + - mnd + - musttag + - nilnil + - unparam + - gosmopolitan + + +formatters: + enable: + - gci + - gofumpt + - goimports + settings: + gci: + sections: + - standard + - default + - localmodule + - blank + - dot + gofumpt: + extra-rules: true + diff --git a/vendor/github.com/AlwxSin/noinlineerr/.goreleaser.yml b/vendor/github.com/AlwxSin/noinlineerr/.goreleaser.yml new file mode 100644 index 000000000..a36e47cdc --- /dev/null +++ b/vendor/github.com/AlwxSin/noinlineerr/.goreleaser.yml @@ -0,0 +1,25 @@ +project_name: noinlineerr +builds: + - main: ./cmd/noinlineerr/main.go + binary: noinlineerr + goos: + - linux + - darwin + - windows + goarch: + - amd64 + - arm64 + +archives: + - formats: [ 'tar.gz' ] + files: + - LICENSE + - README.md + +checksum: + name_template: 'checksums.txt' + +release: + github: + owner: AlwxSin + name: noinlineerr diff --git a/vendor/github.com/sivchari/tenv/LICENSE b/vendor/github.com/AlwxSin/noinlineerr/LICENSE similarity index 97% rename from vendor/github.com/sivchari/tenv/LICENSE rename to vendor/github.com/AlwxSin/noinlineerr/LICENSE index 5185ec09a..03a52166d 100644 --- a/vendor/github.com/sivchari/tenv/LICENSE +++ b/vendor/github.com/AlwxSin/noinlineerr/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021 sivchari +Copyright (c) 2025 Alwx Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/github.com/AlwxSin/noinlineerr/README.md b/vendor/github.com/AlwxSin/noinlineerr/README.md new file mode 100644 index 000000000..c0a9cb386 --- /dev/null +++ b/vendor/github.com/AlwxSin/noinlineerr/README.md @@ -0,0 +1,54 @@ +# noinlineerr + +A Go linter that forbids inline error handling using `if err := ...; err != nil`. + +--- + +## Why? +Inline error handling in Go can hurt readability by hiding the actual function call behind error plumbing. +We believe errors and functions deserve their own spotlight. + +Instead of: +```go +if err := doSomething(); err != nil { + return err +} +``` +Prefer the more explicit and readable: +```go +err := doSomething() +if err != nil { + return err +} +``` + +--- + +## Install +```bash +go install github.com/AlwxSin/noinlineerr/cmd/noinlineerr@latest +``` + +--- + +## Usage +### As a standalone tool +```bash +noinlineerr ./... +``` + +⚠️ Note: The linter detects inline error assignments only when the error variable is explicitly typed or deducible. It doesn't handle dynamically typed interfaces (e.g., `foo().Err()` where `Err()` returns an error via an interface). + +--- + +## Development +Run tests: +```bash +go test ./... +``` +Test data lives under `testdata/src/...` + +--- + +## Contributing +PRs are welcome. Let's make Go code cleaner, one `err` at a time. diff --git a/vendor/github.com/AlwxSin/noinlineerr/noinlineerr.go b/vendor/github.com/AlwxSin/noinlineerr/noinlineerr.go new file mode 100644 index 000000000..9bf562320 --- /dev/null +++ b/vendor/github.com/AlwxSin/noinlineerr/noinlineerr.go @@ -0,0 +1,154 @@ +package noinlineerr + +import ( + "bytes" + "go/ast" + "go/printer" + "go/types" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/ast/inspector" +) + +const errMessage = "avoid inline error handling using `if err := ...; err != nil`; use plain assignment `err := ...`" + +func NewAnalyzer() *analysis.Analyzer { + return &analysis.Analyzer{ + Name: "noinlineerr", + Doc: "Disallows inline error handling (`if err := ...; err != nil {`)", + Run: run, + Requires: []*analysis.Analyzer{inspect.Analyzer}, + } +} + +func run(pass *analysis.Pass) (any, error) { + insp, ok := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + if !ok { + return nil, nil //nolint:nilnil // nothing to return + } + + nodeFilter := []ast.Node{ + (*ast.IfStmt)(nil), + } + + insp.Preorder(nodeFilter, inlineErrorInspector(pass)) + + return nil, nil //nolint:nilnil // nothing to return +} + +func inlineErrorInspector(pass *analysis.Pass) func(n ast.Node) { + return func(n ast.Node) { + ifStmt, ok := n.(*ast.IfStmt) + if !ok || ifStmt.Init == nil { + return + } + + // check if the init clause is an assignment + assignStmt, ok := ifStmt.Init.(*ast.AssignStmt) + if !ok { + return + } + + // iterate over left-hand side variables of the assignment + for _, lhs := range assignStmt.Lhs { + ident, ok := lhs.(*ast.Ident) + if !ok { + continue + } + + // confirm type is error and it is used in condition + obj := pass.TypesInfo.ObjectOf(ident) + if !isError(obj) || ident.Name == "_" || !errorUsedInCondition(ifStmt.Cond, ident.Name) { + continue + } + + // if there are more than 1 assignment + // or there are any variables with same name + // then we can make a shadow conflict with other variables + // so don't do anything beside simple error message + if len(assignStmt.Lhs) != 1 || shadowVarsExists(ident.Name, pass.TypesInfo.Scopes[ifStmt]) { + pass.Reportf(ident.Pos(), errMessage) + return + } + + // else we know there is a simple err assignment like + // if err := func(); err != nil {} + // and we can autofix that + + var buf bytes.Buffer + + _ = printer.Fprint(&buf, pass.Fset, assignStmt) + assignText := buf.String() + + // report usage of inline error assignment + pass.Report(analysis.Diagnostic{ + Pos: ident.Pos(), + End: ident.End(), + Message: errMessage, + SuggestedFixes: []analysis.SuggestedFix{ + { + Message: "move err assignment outside if", + TextEdits: []analysis.TextEdit{ + { + // insert err := ... before if + Pos: ifStmt.Pos(), + End: ifStmt.Pos(), + NewText: []byte(assignText + "\n"), + }, + { + // delete Init part + Pos: assignStmt.Pos(), + End: assignStmt.End() + 1, // +1 for ; + NewText: nil, + }, + }, + }, + }, + }) + } + } +} + +func isError(obj types.Object) bool { + if obj == nil { + return false + } + + errorType := types.Universe.Lookup("error").Type() + + return types.AssignableTo(obj.Type(), errorType) +} + +func shadowVarsExists(name string, scope *types.Scope) bool { + if scope == nil { + return false + } + + parentScope := scope.Parent() + if parentScope == nil { + return false + } + + return parentScope.Lookup(name) != nil +} + +func errorUsedInCondition(cond ast.Expr, errIdentName string) bool { + used := false + + ast.Inspect(cond, func(n ast.Node) bool { + ident, ok := n.(*ast.Ident) + if !ok { + return true + } + + if ident.Name == errIdentName { + used = true + return false + } + + return true + }) + + return used +} diff --git a/vendor/github.com/Antonboom/errname/pkg/analyzer/analyzer.go b/vendor/github.com/Antonboom/errname/pkg/analyzer/analyzer.go index 2b8794dc2..669edcc20 100644 --- a/vendor/github.com/Antonboom/errname/pkg/analyzer/analyzer.go +++ b/vendor/github.com/Antonboom/errname/pkg/analyzer/analyzer.go @@ -21,7 +21,7 @@ func New() *analysis.Analyzer { } } -func run(pass *analysis.Pass) (interface{}, error) { +func run(pass *analysis.Pass) (any, error) { insp := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) insp.Nodes([]ast.Node{ @@ -72,12 +72,12 @@ func run(pass *analysis.Pass) (interface{}, error) { return true }) - return nil, nil //nolint:nilnil + return nil, nil //nolint:nilnil // Integration interface of analysis.Analyzer. } func reportAboutErrorType(pass *analysis.Pass, typePos token.Pos, typeName string) { var form string - if unicode.IsLower([]rune(typeName)[0]) { + if startsWithLower(typeName) { form = "xxxError" } else { form = "XxxError" @@ -88,7 +88,7 @@ func reportAboutErrorType(pass *analysis.Pass, typePos token.Pos, typeName strin func reportAboutArrayErrorType(pass *analysis.Pass, typePos token.Pos, typeName string) { var forms string - if unicode.IsLower([]rune(typeName)[0]) { + if startsWithLower(typeName) { forms = "`xxxErrors` or `xxxError`" } else { forms = "`XxxErrors` or `XxxError`" @@ -99,10 +99,14 @@ func reportAboutArrayErrorType(pass *analysis.Pass, typePos token.Pos, typeName func reportAboutSentinelError(pass *analysis.Pass, pos token.Pos, varName string) { var form string - if unicode.IsLower([]rune(varName)[0]) { + if startsWithLower(varName) { form = "errXxx" } else { form = "ErrXxx" } pass.Reportf(pos, "the sentinel error name `%s` should conform to the `%s` format", varName, form) } + +func startsWithLower(n string) bool { + return unicode.IsLower([]rune(n)[0]) //nolint:gocritic // Source code is Unicode text encoded in UTF-8. +} diff --git a/vendor/github.com/Antonboom/nilnil/pkg/analyzer/analyzer.go b/vendor/github.com/Antonboom/nilnil/pkg/analyzer/analyzer.go index 5507d9546..443d53714 100644 --- a/vendor/github.com/Antonboom/nilnil/pkg/analyzer/analyzer.go +++ b/vendor/github.com/Antonboom/nilnil/pkg/analyzer/analyzer.go @@ -31,7 +31,9 @@ func New() *analysis.Analyzer { } a.Flags.Var(&n.checkedTypes, "checked-types", "comma separated list of return types to check") a.Flags.BoolVar(&n.detectOpposite, "detect-opposite", false, - "in addition, detect opposite situation (simultaneous return of non-nil error and valid value)") + "in addition, to detect opposite situation (simultaneous return of non-nil error and valid value)") + a.Flags.BoolVar(&n.onlyTwo, "only-two", true, + "to check functions with only two return values") return a } @@ -39,12 +41,14 @@ func New() *analysis.Analyzer { type nilNil struct { checkedTypes checkedTypes detectOpposite bool + onlyTwo bool } func newNilNil() *nilNil { return &nilNil{ checkedTypes: newDefaultCheckedTypes(), detectOpposite: false, + onlyTwo: true, } } @@ -54,7 +58,7 @@ var funcAndReturns = []ast.Node{ (*ast.ReturnStmt)(nil), } -func (n *nilNil) run(pass *analysis.Pass) (interface{}, error) { +func (n *nilNil) run(pass *analysis.Pass) (any, error) { insp := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) var fs funcTypeStack @@ -77,44 +81,54 @@ func (n *nilNil) run(pass *analysis.Pass) (interface{}, error) { case *ast.ReturnStmt: ft := fs.Top() // Current function. - if !push || len(v.Results) != 2 || ft == nil || ft.Results == nil || len(ft.Results.List) != 2 { + if !push { return false } - - fRes1Type := pass.TypesInfo.TypeOf(ft.Results.List[0].Type) - if fRes1Type == nil { + if len(v.Results) < 2 { return false } - - fRes2Type := pass.TypesInfo.TypeOf(ft.Results.List[1].Type) - if fRes2Type == nil { + if (ft == nil) || (ft.Results == nil) || (len(ft.Results.List) != len(v.Results)) { + // Unreachable. return false } - ok, zv := n.isDangerNilType(fRes1Type) - if !(ok && implementsError(fRes2Type)) { - return false + lastIdx := len(ft.Results.List) - 1 + if n.onlyTwo { + lastIdx = 1 } - retVal, retErr := v.Results[0], v.Results[1] - - if ((zv == zeroValueNil) && isNil(pass, retVal) && isNil(pass, retErr)) || - ((zv == zeroValueZero) && isZero(retVal) && isNil(pass, retErr)) { - pass.Reportf(v.Pos(), nilNilReportMsg) + lastFtRes := ft.Results.List[lastIdx] + if !implementsError(pass.TypesInfo.TypeOf(lastFtRes.Type)) { return false } - if n.detectOpposite && (((zv == zeroValueNil) && !isNil(pass, retVal) && !isNil(pass, retErr)) || - ((zv == zeroValueZero) && !isZero(retVal) && !isNil(pass, retErr))) { - pass.Reportf(v.Pos(), notNilNotNilReportMsg) - return false + retErr := v.Results[lastIdx] + for i := range lastIdx { + retVal := v.Results[i] + + zv, ok := n.isDangerNilType(pass.TypesInfo.TypeOf(ft.Results.List[i].Type)) + if !ok { + continue + } + + if ((zv == zeroValueNil) && isNil(pass, retVal) && isNil(pass, retErr)) || + ((zv == zeroValueZero) && isZero(retVal) && isNil(pass, retErr)) { + pass.Reportf(v.Pos(), nilNilReportMsg) + return false + } + + if n.detectOpposite && (((zv == zeroValueNil) && !isNil(pass, retVal) && !isNil(pass, retErr)) || + ((zv == zeroValueZero) && !isZero(retVal) && !isNil(pass, retErr))) { + pass.Reportf(v.Pos(), notNilNotNilReportMsg) + return false + } } } return true }) - return nil, nil //nolint:nilnil + return nil, nil //nolint:nilnil // Integration interface of analysis.Analyzer. } type zeroValue int @@ -124,35 +138,35 @@ const ( zeroValueZero ) -func (n *nilNil) isDangerNilType(t types.Type) (bool, zeroValue) { - switch v := t.(type) { +func (n *nilNil) isDangerNilType(t types.Type) (zeroValue, bool) { + switch v := types.Unalias(t).(type) { case *types.Pointer: - return n.checkedTypes.Contains(ptrType), zeroValueNil + return zeroValueNil, n.checkedTypes.Contains(ptrType) case *types.Signature: - return n.checkedTypes.Contains(funcType), zeroValueNil + return zeroValueNil, n.checkedTypes.Contains(funcType) case *types.Interface: - return n.checkedTypes.Contains(ifaceType), zeroValueNil + return zeroValueNil, n.checkedTypes.Contains(ifaceType) case *types.Map: - return n.checkedTypes.Contains(mapType), zeroValueNil + return zeroValueNil, n.checkedTypes.Contains(mapType) case *types.Chan: - return n.checkedTypes.Contains(chanType), zeroValueNil + return zeroValueNil, n.checkedTypes.Contains(chanType) case *types.Basic: if v.Kind() == types.Uintptr { - return n.checkedTypes.Contains(uintptrType), zeroValueZero + return zeroValueZero, n.checkedTypes.Contains(uintptrType) } if v.Kind() == types.UnsafePointer { - return n.checkedTypes.Contains(unsafeptrType), zeroValueNil + return zeroValueNil, n.checkedTypes.Contains(unsafeptrType) } case *types.Named: return n.isDangerNilType(v.Underlying()) } - return false, 0 + return 0, false } var errorIface = types.Universe.Lookup("error").Type().Underlying().(*types.Interface) diff --git a/vendor/github.com/Antonboom/testifylint/analyzer/analyzer.go b/vendor/github.com/Antonboom/testifylint/analyzer/analyzer.go index a9e41b0a8..711179714 100644 --- a/vendor/github.com/Antonboom/testifylint/analyzer/analyzer.go +++ b/vendor/github.com/Antonboom/testifylint/analyzer/analyzer.go @@ -5,9 +5,9 @@ import ( "go/ast" "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/ast/inspector" - "github.com/Antonboom/testifylint/internal/analysisutil" "github.com/Antonboom/testifylint/internal/checkers" "github.com/Antonboom/testifylint/internal/config" "github.com/Antonboom/testifylint/internal/testify" @@ -24,9 +24,10 @@ func New() *analysis.Analyzer { cfg := config.NewDefault() analyzer := &analysis.Analyzer{ - Name: name, - Doc: doc, - URL: url, + Name: name, + Doc: doc, + URL: url, + Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: func(pass *analysis.Pass) (any, error) { regularCheckers, advancedCheckers, err := newCheckers(cfg) if err != nil { @@ -51,16 +52,14 @@ type testifyLint struct { } func (tl *testifyLint) run(pass *analysis.Pass) (any, error) { - filesToAnalysis := make([]*ast.File, 0, len(pass.Files)) - for _, f := range pass.Files { - if !analysisutil.Imports(f, testify.AssertPkgPath, testify.RequirePkgPath, testify.SuitePkgPath) { - continue - } - filesToAnalysis = append(filesToAnalysis, f) + // NOTE(a.telyshev): There are no premature optimizations like "scan only _test.go" or + // "scan only files with testify imports", since it could lead to skip files + // with assertions (etc. test helpers in regular Go files or suite methods). + insp, ok := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + if !ok { + return nil, nil } - insp := inspector.New(filesToAnalysis) - // Regular checkers. insp.Preorder([]ast.Node{(*ast.CallExpr)(nil)}, func(node ast.Node) { tl.regularCheck(pass, node.(*ast.CallExpr)) diff --git a/vendor/github.com/Antonboom/testifylint/analyzer/checkers_factory.go b/vendor/github.com/Antonboom/testifylint/analyzer/checkers_factory.go index df04dfdc5..274ce85ce 100644 --- a/vendor/github.com/Antonboom/testifylint/analyzer/checkers_factory.go +++ b/vendor/github.com/Antonboom/testifylint/analyzer/checkers_factory.go @@ -58,6 +58,7 @@ func newCheckers(cfg config.Config) ([]checkers.RegularChecker, []checkers.Advan case *checkers.Formatter: c.SetCheckFormatString(cfg.Formatter.CheckFormatString) c.SetRequireFFuncs(cfg.Formatter.RequireFFuncs) + c.SetRequireStringMsg(cfg.Formatter.RequireStringMsg) case *checkers.GoRequire: c.SetIgnoreHTTPHandlers(cfg.GoRequire.IgnoreHTTPHandlers) diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/bool_compare.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/bool_compare.go index 67959b633..4bcd5304f 100644 --- a/vendor/github.com/Antonboom/testifylint/internal/checkers/bool_compare.go +++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/bool_compare.go @@ -43,7 +43,7 @@ func (checker BoolCompare) Check(pass *analysis.Pass, call *CallMeta) *analysis. } newUseFnDiagnostic := func(proposed string, survivingArg ast.Expr, replaceStart, replaceEnd token.Pos) *analysis.Diagnostic { - if !isBuiltinBool(pass, survivingArg) { + if !hasBoolType(pass, survivingArg) { if checker.ignoreCustomTypes { return nil } @@ -65,7 +65,7 @@ func (checker BoolCompare) Check(pass *analysis.Pass, call *CallMeta) *analysis. } newNeedSimplifyDiagnostic := func(survivingArg ast.Expr, replaceStart, replaceEnd token.Pos) *analysis.Diagnostic { - if !isBuiltinBool(pass, survivingArg) { + if !hasBoolType(pass, survivingArg) { if checker.ignoreCustomTypes { return nil } @@ -103,7 +103,7 @@ func (checker BoolCompare) Check(pass *analysis.Pass, call *CallMeta) *analysis. switch { case xor(t1, t2): survivingArg, _ := anyVal([]bool{t1, t2}, arg2, arg1) - if call.Fn.NameFTrimmed == "Exactly" && !isBuiltinBool(pass, survivingArg) { + if call.Fn.NameFTrimmed == "Exactly" && !hasBoolType(pass, survivingArg) { // NOTE(a.telyshev): `Exactly` assumes no type conversion. return nil } @@ -111,7 +111,7 @@ func (checker BoolCompare) Check(pass *analysis.Pass, call *CallMeta) *analysis. case xor(f1, f2): survivingArg, _ := anyVal([]bool{f1, f2}, arg2, arg1) - if call.Fn.NameFTrimmed == "Exactly" && !isBuiltinBool(pass, survivingArg) { + if call.Fn.NameFTrimmed == "Exactly" && !hasBoolType(pass, survivingArg) { // NOTE(a.telyshev): `Exactly` assumes no type conversion. return nil } diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/call_meta.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/call_meta.go index 96b5b19b0..3d9c3428a 100644 --- a/vendor/github.com/Antonboom/testifylint/internal/checkers/call_meta.go +++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/call_meta.go @@ -93,7 +93,7 @@ func NewCallMeta(pass *analysis.Pass, ce *ast.CallExpr) *CallMeta { isAssert := analysisutil.IsPkg(initiatorPkg, testify.AssertPkgName, testify.AssertPkgPath) isRequire := analysisutil.IsPkg(initiatorPkg, testify.RequirePkgName, testify.RequirePkgPath) - if !(isAssert || isRequire) { + if !isAssert && !isRequire { return nil } diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/checker.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/checker.go index ac23af6f6..0d8e9d2f4 100644 --- a/vendor/github.com/Antonboom/testifylint/internal/checkers/checker.go +++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/checker.go @@ -19,5 +19,5 @@ type RegularChecker interface { // AdvancedChecker implements complex Check logic different from trivial CallMeta check. type AdvancedChecker interface { Checker - Check(pass *analysis.Pass, inspector *inspector.Inspector) []analysis.Diagnostic + Check(pass *analysis.Pass, insp *inspector.Inspector) []analysis.Diagnostic } diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/checkers_registry.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/checkers_registry.go index f881be4f2..264e18b6d 100644 --- a/vendor/github.com/Antonboom/testifylint/internal/checkers/checkers_registry.go +++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/checkers_registry.go @@ -10,7 +10,6 @@ var registry = checkersRegistry{ {factory: asCheckerFactory(NewFloatCompare), enabledByDefault: true}, {factory: asCheckerFactory(NewBoolCompare), enabledByDefault: true}, {factory: asCheckerFactory(NewEmpty), enabledByDefault: true}, - {factory: asCheckerFactory(NewLen), enabledByDefault: true}, {factory: asCheckerFactory(NewNegativePositive), enabledByDefault: true}, {factory: asCheckerFactory(NewCompares), enabledByDefault: true}, {factory: asCheckerFactory(NewContains), enabledByDefault: true}, @@ -19,6 +18,8 @@ var registry = checkersRegistry{ {factory: asCheckerFactory(NewErrorIsAs), enabledByDefault: true}, {factory: asCheckerFactory(NewEncodedCompare), enabledByDefault: true}, {factory: asCheckerFactory(NewExpectedActual), enabledByDefault: true}, + {factory: asCheckerFactory(NewLen), enabledByDefault: true}, + {factory: asCheckerFactory(NewEqualValues), enabledByDefault: true}, {factory: asCheckerFactory(NewRegexp), enabledByDefault: true}, {factory: asCheckerFactory(NewSuiteExtraAssertCall), enabledByDefault: true}, {factory: asCheckerFactory(NewSuiteDontUsePkg), enabledByDefault: true}, @@ -29,6 +30,7 @@ var registry = checkersRegistry{ {factory: asCheckerFactory(NewGoRequire), enabledByDefault: true}, {factory: asCheckerFactory(NewRequireError), enabledByDefault: true}, {factory: asCheckerFactory(NewSuiteBrokenParallel), enabledByDefault: true}, + {factory: asCheckerFactory(NewSuiteMethodSignature), enabledByDefault: true}, {factory: asCheckerFactory(NewSuiteSubtestRun), enabledByDefault: true}, {factory: asCheckerFactory(NewSuiteTHelper), enabledByDefault: false}, } diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/empty.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/empty.go index 71657fe11..854421e6a 100644 --- a/vendor/github.com/Antonboom/testifylint/internal/checkers/empty.go +++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/empty.go @@ -11,31 +11,41 @@ import ( // Empty detects situations like // -// assert.Len(t, arr, 0) -// assert.Equal(t, 0, len(arr)) -// assert.EqualValues(t, 0, len(arr)) -// assert.Exactly(t, 0, len(arr)) -// assert.LessOrEqual(t, len(arr), 0) -// assert.GreaterOrEqual(t, 0, len(arr)) -// assert.Less(t, len(arr), 0) -// assert.Greater(t, 0, len(arr)) -// assert.Less(t, len(arr), 1) -// assert.Greater(t, 1, len(arr)) -// assert.Zero(t, len(arr)) -// assert.Empty(t, len(arr)) +// assert.Len(t, arr, 0) +// assert.Zero(t, str) +// assert.Zero(t, len(arr)) +// assert.Equal(t, 0, len(arr)) +// assert.EqualValues(t, 0, len(arr)) +// assert.Exactly(t, 0, len(arr)) +// assert.LessOrEqual(t, len(arr), 0) +// assert.GreaterOrEqual(t, 0, len(arr)) +// assert.Less(t, len(arr), 1) +// assert.Greater(t, 1, len(arr)) +// assert.Equal(t, "", str) +// assert.EqualValues(t, "", str) +// assert.Exactly(t, "", str) +// assert.Equal(t, “, str) +// assert.EqualValues(t, “, str) +// assert.Exactly(t, “, str) // -// assert.NotEqual(t, 0, len(arr)) -// assert.NotEqualValues(t, 0, len(arr)) -// assert.Less(t, 0, len(arr)) -// assert.Greater(t, len(arr), 0) -// assert.Positive(t, len(arr)) -// assert.NotZero(t, len(arr)) -// assert.NotEmpty(t, len(arr)) +// assert.Positive(t, len(arr)) +// assert.NotZero(t, str) +// assert.NotZero(t, len(arr)) +// assert.NotEqual(t, 0, len(arr)) +// assert.NotEqualValues(t, 0, len(arr)) +// assert.Greater(t, len(arr), 0) +// assert.Less(t, 0, len(arr)) +// assert.NotEqual(t, "", str) +// assert.NotEqualValues(t, "", str) +// assert.NotEqual(t, “, str) +// assert.NotEqualValues(t, “, str) // // and requires // // assert.Empty(t, arr) // assert.NotEmpty(t, arr) +// +// Also Empty removes extra `len` call. type Empty struct{} // NewEmpty constructs Empty checker. @@ -49,7 +59,7 @@ func (checker Empty) Check(pass *analysis.Pass, call *CallMeta) *analysis.Diagno return checker.checkNotEmpty(pass, call) } -func (checker Empty) checkEmpty(pass *analysis.Pass, call *CallMeta) *analysis.Diagnostic { //nolint:gocognit +func (checker Empty) checkEmpty(pass *analysis.Pass, call *CallMeta) *analysis.Diagnostic { //nolint:gocognit // It is ok. newUseEmptyDiagnostic := func(replaceStart, replaceEnd token.Pos, replaceWith ast.Expr) *analysis.Diagnostic { const proposed = "Empty" return newUseFunctionDiagnostic(checker.Name(), call, proposed, @@ -67,6 +77,9 @@ func (checker Empty) checkEmpty(pass *analysis.Pass, call *CallMeta) *analysis.D switch call.Fn.NameFTrimmed { case "Zero": + if hasStringType(pass, a) { + return newUseEmptyDiagnostic(a.Pos(), a.End(), a) + } if lenArg, ok := isBuiltinLenCall(pass, a); ok { return newUseEmptyDiagnostic(a.Pos(), a.End(), lenArg) } @@ -89,6 +102,10 @@ func (checker Empty) checkEmpty(pass *analysis.Pass, call *CallMeta) *analysis.D } case "Equal", "EqualValues", "Exactly": + if isEmptyStringLit(a) { + return newUseEmptyDiagnostic(a.Pos(), b.End(), b) + } + arg1, ok1 := isLenCallAndZero(pass, a, b) arg2, ok2 := isLenCallAndZero(pass, b, a) @@ -119,7 +136,7 @@ func (checker Empty) checkEmpty(pass *analysis.Pass, call *CallMeta) *analysis.D return nil } -func (checker Empty) checkNotEmpty(pass *analysis.Pass, call *CallMeta) *analysis.Diagnostic { //nolint:gocognit +func (checker Empty) checkNotEmpty(pass *analysis.Pass, call *CallMeta) *analysis.Diagnostic { //nolint:gocognit // It is ok. newUseNotEmptyDiagnostic := func(replaceStart, replaceEnd token.Pos, replaceWith ast.Expr) *analysis.Diagnostic { const proposed = "NotEmpty" return newUseFunctionDiagnostic(checker.Name(), call, proposed, @@ -136,7 +153,15 @@ func (checker Empty) checkNotEmpty(pass *analysis.Pass, call *CallMeta) *analysi a := call.Args[0] switch call.Fn.NameFTrimmed { - case "NotZero", "Positive": + case "Positive": + if lenArg, ok := isBuiltinLenCall(pass, a); ok { + return newUseNotEmptyDiagnostic(a.Pos(), a.End(), lenArg) + } + + case "NotZero": + if hasStringType(pass, a) { + return newUseNotEmptyDiagnostic(a.Pos(), a.End(), a) + } if lenArg, ok := isBuiltinLenCall(pass, a); ok { return newUseNotEmptyDiagnostic(a.Pos(), a.End(), lenArg) } @@ -154,6 +179,10 @@ func (checker Empty) checkNotEmpty(pass *analysis.Pass, call *CallMeta) *analysi switch call.Fn.NameFTrimmed { case "NotEqual", "NotEqualValues": + if isEmptyStringLit(a) { + return newUseNotEmptyDiagnostic(a.Pos(), b.End(), b) + } + arg1, ok1 := isLenCallAndZero(pass, a, b) arg2, ok2 := isLenCallAndZero(pass, b, a) diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/equal_values.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/equal_values.go new file mode 100644 index 000000000..c8f305c3e --- /dev/null +++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/equal_values.go @@ -0,0 +1,59 @@ +package checkers + +import ( + "go/types" + "strings" + + "golang.org/x/tools/go/analysis" +) + +// EqualValues detects situations like +// +// assert.EqualValues(t, 42, result.IntField) +// assert.NotEqualValues(t, 42, result.IntField) +// ... +// +// and requires +// +// assert.Equal(t, 42, result.IntField) +// assert.NotEqual(t, 42, result.IntField) +type EqualValues struct{} + +// NewEqualValues constructs EqualValues checker. +func NewEqualValues() EqualValues { return EqualValues{} } +func (EqualValues) Name() string { return "equal-values" } + +func (checker EqualValues) Check(pass *analysis.Pass, call *CallMeta) *analysis.Diagnostic { + assrn := call.Fn.NameFTrimmed + switch assrn { + default: + return nil + case "EqualValues", "NotEqualValues": + } + + if len(call.Args) < 2 { + return nil + } + first, second := call.Args[0], call.Args[1] + + if isFunc(pass, first) || isFunc(pass, second) { + // NOTE(a.telyshev): EqualValues for funcs is ok, but not Equal: + // https://github.com/stretchr/testify/issues/1524 + return nil + } + + ft, st := pass.TypesInfo.TypeOf(first), pass.TypesInfo.TypeOf(second) + if !types.Identical(ft, st) { + return nil + } + + // Type of one of arguments is equivalent to any. + if isEmptyInterfaceType(ft) || isEmptyInterfaceType(st) { + // EqualValues is ok here. + // Equal would check their types and would fail. + return nil + } + + proposed := strings.TrimSuffix(assrn, "Values") + return newUseFunctionDiagnostic(checker.Name(), call, proposed) +} diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/error_is_as.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/error_is_as.go index f2812c939..ac9d968b8 100644 --- a/vendor/github.com/Antonboom/testifylint/internal/checkers/error_is_as.go +++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/error_is_as.go @@ -6,21 +6,30 @@ import ( "go/types" "golang.org/x/tools/go/analysis" + + "github.com/Antonboom/testifylint/internal/analysisutil" + "github.com/Antonboom/testifylint/internal/testify" ) // ErrorIsAs detects situations like // // assert.Error(t, err, errSentinel) // assert.NoError(t, err, errSentinel) +// assert.IsType(t, err, errSentinel) +// assert.IsType(t, (*http.MaxBytesError)(nil), err) +// assert.IsNotType(t, err, errSentinel) +// assert.IsNotType(t, store.NotFoundError{}, err) // assert.True(t, errors.Is(err, errSentinel)) // assert.False(t, errors.Is(err, errSentinel)) // assert.True(t, errors.As(err, &target)) +// assert.False(t, errors.As(err, &target)) // // and requires // // assert.ErrorIs(t, err, errSentinel) // assert.NotErrorIs(t, err, errSentinel) // assert.ErrorAs(t, err, &target) +// assert.NotErrorAs(t, err, &target) // // Also ErrorIsAs repeats go vet's "errorsas" check logic. type ErrorIsAs struct{} @@ -32,7 +41,7 @@ func (ErrorIsAs) Name() string { return "error-is-as" } func (checker ErrorIsAs) Check(pass *analysis.Pass, call *CallMeta) *analysis.Diagnostic { switch call.Fn.NameFTrimmed { case "Error": - if len(call.Args) >= 2 && isError(pass, call.Args[1]) { + if len(call.Args) >= 2 && isError(pass, call.Args[1]) && !isAssertCollectT(pass, call.Selector.X) { const proposed = "ErrorIs" msg := fmt.Sprintf("invalid usage of %[1]s.Error, use %[1]s.%[2]s instead", call.SelectorXStr, proposed) return newDiagnostic(checker.Name(), call, msg, newSuggestedFuncReplacement(call, proposed)) @@ -45,6 +54,18 @@ func (checker ErrorIsAs) Check(pass *analysis.Pass, call *CallMeta) *analysis.Di return newDiagnostic(checker.Name(), call, msg, newSuggestedFuncReplacement(call, proposed)) } + case "IsType": + if len(call.Args) >= 2 && isError(pass, call.Args[0]) || isError(pass, call.Args[1]) { + msg := fmt.Sprintf("use %[1]s.ErrorIs or %[1]s.ErrorAs depending on the case", call.SelectorXStr) + return newDiagnostic(checker.Name(), call, msg) + } + + case "IsNotType": + if len(call.Args) >= 2 && isError(pass, call.Args[0]) || isError(pass, call.Args[1]) { + msg := fmt.Sprintf("use %[1]s.NotErrorIs or %[1]s.NotErrorAs depending on the case", call.SelectorXStr) + return newDiagnostic(checker.Name(), call, msg) + } + case "True": if len(call.Args) < 1 { return nil @@ -87,8 +108,14 @@ func (checker ErrorIsAs) Check(pass *analysis.Pass, call *CallMeta) *analysis.Di return nil } - if isErrorsIsCall(pass, ce) { - const proposed = "NotErrorIs" + var proposed string + switch { + case isErrorsIsCall(pass, ce): + proposed = "NotErrorIs" + case isErrorsAsCall(pass, ce): + proposed = "NotErrorAs" + } + if proposed != "" { return newUseFunctionDiagnostic(checker.Name(), call, proposed, analysis.TextEdit{ Pos: ce.Pos(), @@ -97,7 +124,7 @@ func (checker ErrorIsAs) Check(pass *analysis.Pass, call *CallMeta) *analysis.Di }) } - case "ErrorAs": + case "ErrorAs", "NotErrorAs": if len(call.Args) < 2 { return nil } @@ -138,3 +165,18 @@ func (checker ErrorIsAs) Check(pass *analysis.Pass, call *CallMeta) *analysis.Di } return nil } + +func isAssertCollectT(pass *analysis.Pass, e ast.Expr) bool { + ptr, ok := pass.TypesInfo.TypeOf(e).(*types.Pointer) + if !ok { + return false + } + + named, ok := ptr.Elem().(*types.Named) + if !ok { + return false + } + + collectT := analysisutil.ObjectOf(pass.Pkg, testify.AssertPkgPath, "CollectT") + return named.Obj() == collectT +} diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/error_nil.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/error_nil.go index b9f28df21..b7ced9a8d 100644 --- a/vendor/github.com/Antonboom/testifylint/internal/checkers/error_nil.go +++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/error_nil.go @@ -18,6 +18,7 @@ import ( // assert.EqualValues(t, nil, err) // assert.Exactly(t, nil, err) // assert.ErrorIs(t, err, nil) +// assert.IsType(t, err, nil) // // assert.NotNil(t, err) // assert.NotEmpty(t, err) @@ -25,6 +26,7 @@ import ( // assert.NotEqual(t, nil, err) // assert.NotEqualValues(t, nil, err) // assert.NotErrorIs(t, err, nil) +// assert.IsNotType(t, err, nil) // // and requires // @@ -54,7 +56,7 @@ func (checker ErrorNil) Check(pass *analysis.Pass, call *CallMeta) *analysis.Dia return errorFn, call.Args[0], call.Args[0].End() } - case "Equal", "EqualValues", "Exactly", "ErrorIs": + case "Equal", "EqualValues", "Exactly", "ErrorIs", "IsType": if len(call.Args) < 2 { return "", nil, token.NoPos } @@ -67,7 +69,7 @@ func (checker ErrorNil) Check(pass *analysis.Pass, call *CallMeta) *analysis.Dia return noErrorFn, b, b.End() } - case "NotEqual", "NotEqualValues", "NotErrorIs": + case "NotEqual", "NotEqualValues", "NotErrorIs", "IsNotType": if len(call.Args) < 2 { return "", nil, token.NoPos } diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/expected_actual.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/expected_actual.go index 351d675ce..e0467ac70 100644 --- a/vendor/github.com/Antonboom/testifylint/internal/checkers/expected_actual.go +++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/expected_actual.go @@ -17,6 +17,8 @@ var DefaultExpectedVarPattern = regexp.MustCompile( // ExpectedActual detects situations like // // assert.Equal(t, result, expected) +// assert.Equal(t, result, len(expected)) +// assert.Equal(t, len(resultFields), len(expectedFields)) // assert.EqualExportedValues(t, resultObj, User{Name: "Anton"}) // assert.EqualValues(t, result, 42) // assert.Exactly(t, result, int64(42)) @@ -37,6 +39,8 @@ var DefaultExpectedVarPattern = regexp.MustCompile( // and requires // // assert.Equal(t, expected, result) +// assert.Equal(t, len(expected), result) +// assert.Equal(t, len(expectedFields), len(resultFields)) // assert.EqualExportedValues(t, User{Name: "Anton"}, resultObj) // assert.EqualValues(t, 42, result) // ... @@ -69,6 +73,7 @@ func (checker ExpectedActual) Check(pass *analysis.Pass, call *CallMeta) *analys "InDeltaSlice", "InEpsilon", "InEpsilonSlice", + "IsNotType", "IsType", "JSONEq", "NotEqual", @@ -116,12 +121,17 @@ func (checker ExpectedActual) isExpectedValueCandidate(pass *analysis.Pass, expr return checker.isExpectedValueCandidate(pass, v.X) case *ast.UnaryExpr: - return (v.Op == token.AND) && checker.isExpectedValueCandidate(pass, v.X) // &value + if v.Op == token.AND || v.Op == token.SUB { // &value, -value + return checker.isExpectedValueCandidate(pass, v.X) + } case *ast.CompositeLit: return true case *ast.CallExpr: + if lv, ok := isBuiltinLenCall(pass, expr); ok { + return isIdentNamedAfterPattern(checker.expVarPattern, lv) + } return isParenExpr(v) || isCastedBasicLitOrExpectedValue(v, checker.expVarPattern) || isExpectedValueFactory(pass, v, checker.expVarPattern) diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/formatter.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/formatter.go index 7ff4de470..572e88f96 100644 --- a/vendor/github.com/Antonboom/testifylint/internal/checkers/formatter.go +++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/formatter.go @@ -1,8 +1,10 @@ package checkers import ( + "fmt" "go/types" "strconv" + "strings" "golang.org/x/tools/go/analysis" @@ -25,9 +27,15 @@ import ( // assert.Errorf(t, err, "Profile %s should not be valid", test.profile) // assert.Errorf(t, err, "test %s", test.testName) // assert.Truef(t, targetTs.Equal(ts), "the timestamp should be as expected (%s) but was %s", targetTs, ts) +// +// It also checks that there are no arguments in `msgAndArgs` if the message is not a string, +// and additionally checks that the first argument of `msgAndArgs` is a not empty string. +// +// Finally, it checks that failure message in Fail and FailNow is not used as a format string (which won't work). type Formatter struct { checkFormatString bool requireFFuncs bool + requireStringMsg bool } // NewFormatter constructs Formatter checker. @@ -35,6 +43,7 @@ func NewFormatter() *Formatter { return &Formatter{ checkFormatString: true, requireFFuncs: false, + requireStringMsg: true, } } @@ -50,6 +59,11 @@ func (checker *Formatter) SetRequireFFuncs(v bool) *Formatter { return checker } +func (checker *Formatter) SetRequireStringMsg(v bool) *Formatter { + checker.requireStringMsg = v + return checker +} + func (checker Formatter) Check(pass *analysis.Pass, call *CallMeta) (result *analysis.Diagnostic) { if call.Fn.IsFmt { return checker.checkFmtAssertion(pass, call) @@ -63,21 +77,64 @@ func (checker Formatter) checkNotFmtAssertion(pass *analysis.Pass, call *CallMet return nil } - fFunc := call.Fn.Name + "f" + lastArgPos := len(call.ArgsRaw) - 1 + isSingleMsgAndArgElem := msgAndArgsPos == lastArgPos + msgAndArgs := call.ArgsRaw[msgAndArgsPos] - if msgAndArgsPos == len(call.ArgsRaw)-1 { - msgAndArgs := call.ArgsRaw[msgAndArgsPos] - if args, ok := isFmtSprintfCall(pass, msgAndArgs); ok { - if checker.requireFFuncs { - return newRemoveFnAndUseDiagnostic(pass, checker.Name(), call, fFunc, - "fmt.Sprintf", msgAndArgs, args...) - } - return newRemoveSprintfDiagnostic(pass, checker.Name(), call, msgAndArgs, args) + if name := call.Fn.NameFTrimmed; name == "Fail" || name == "FailNow" { + failureMsg, err := strconv.Unquote(analysisutil.NodeString(pass.Fset, call.Args[0])) + if err != nil { + return nil + } + if strings.Contains(failureMsg, "%") { + return newDiagnostic(checker.Name(), call, + "failure message is not a format string, use msgAndArgs instead") } } - if checker.requireFFuncs { - return newUseFunctionDiagnostic(checker.Name(), call, fFunc) + if args, ok := isFmtSprintfCall(pass, msgAndArgs); ok && isSingleMsgAndArgElem { + if checker.requireFFuncs { + return newRemoveFnAndUseDiagnostic(pass, checker.Name(), call, call.Fn.Name+"f", + "fmt.Sprintf", msgAndArgs, args...) + } + return newRemoveSprintfDiagnostic(pass, checker.Name(), call, msgAndArgs, args) + } + + if hasStringType(pass, msgAndArgs) { //nolint:nestif // This is the best option of code organization :( + format, err := strconv.Unquote(analysisutil.NodeString(pass.Fset, msgAndArgs)) + if nil == err && format == "" { // Unquote failed for not string literals. + var fixes []analysis.SuggestedFix + if isSingleMsgAndArgElem { + fixes = append(fixes, analysis.SuggestedFix{ + Message: "Remove empty message", + TextEdits: []analysis.TextEdit{newRemoveLastArgTextEdit(pass, call.Args)}, + }) + } + return newDiagnostic(checker.Name(), call, "empty message", fixes...) + } + if checker.requireFFuncs { + return newUseFunctionDiagnostic(checker.Name(), call, call.Fn.Name+"f") + } + } else { + if isSingleMsgAndArgElem { //nolint:revive // Better without early-return. + if checker.requireStringMsg { + return newDiagnostic(checker.Name(), call, + "do not use non-string value as first element (msg) of msgAndArgs", + analysis.SuggestedFix{ + Message: `Introduce "%+v" as the message`, + TextEdits: []analysis.TextEdit{ + { + Pos: msgAndArgs.Pos(), + End: msgAndArgs.End(), + NewText: []byte(`"%+v", ` + analysisutil.NodeString(pass.Fset, msgAndArgs)), + }, + }, + }) + } + } else { + return newDiagnostic(checker.Name(), call, + "using msgAndArgs with non-string first element (msg) causes panic") + } } return nil } @@ -88,14 +145,35 @@ func (checker Formatter) checkFmtAssertion(pass *analysis.Pass, call *CallMeta) return nil } + lastArgPos := len(call.ArgsRaw) - 1 msg := call.ArgsRaw[formatPos] + noFormatArgs := formatPos == lastArgPos - if formatPos == len(call.ArgsRaw)-1 { + if formatPos == lastArgPos { if args, ok := isFmtSprintfCall(pass, msg); ok { return newRemoveSprintfDiagnostic(pass, checker.Name(), call, msg, args) } } + format, err := strconv.Unquote(analysisutil.NodeString(pass.Fset, msg)) + if err != nil { + // Unreachable, because msg is a string literal in formatted assertion. + return nil + } + if format == "" { + var fixes []analysis.SuggestedFix + if noFormatArgs { + fixes = append(fixes, analysis.SuggestedFix{ + Message: fmt.Sprintf("Remove empty message and use `%s`", call.Fn.NameFTrimmed), + TextEdits: []analysis.TextEdit{ + newReplaceFnTextEdit(call.Fn, call.Fn.NameFTrimmed), + newRemoveLastArgTextEdit(pass, call.Args), + }, + }) + } + return newDiagnostic(checker.Name(), call, "empty message", fixes...) + } + if checker.checkFormatString { report := pass.Report defer func() { pass.Report = report }() @@ -103,23 +181,22 @@ func (checker Formatter) checkFmtAssertion(pass *analysis.Pass, call *CallMeta) pass.Report = func(d analysis.Diagnostic) { result = newDiagnostic(checker.Name(), call, d.Message) } - - format, err := strconv.Unquote(analysisutil.NodeString(pass.Fset, msg)) - if err != nil { - return nil - } printf.CheckPrintf(pass, call.Call, call.String(), format, formatPos) } return result } func isPrintfLikeCall(pass *analysis.Pass, call *CallMeta) (int, bool) { + if call.Call.Ellipsis.IsValid() { + return -1, false + } + msgAndArgsPos := getMsgAndArgsPosition(call.Fn.Signature) if msgAndArgsPos <= 0 { return -1, false } - if !(len(call.ArgsRaw) > msgAndArgsPos && hasStringType(pass, call.ArgsRaw[msgAndArgsPos])) { + if msgAndArgsPos >= len(call.ArgsRaw) { return -1, false } @@ -153,7 +230,7 @@ func assertHasFormattedAnalogue(pass *analysis.Pass, call *CallMeta) bool { if !ok { return false } - for i := 0; i < suite.NumMethods(); i++ { + for i := range suite.NumMethods() { if suite.Method(i).Name() == call.Fn.Name+"f" { return true } @@ -179,10 +256,11 @@ func getMsgAndArgsPosition(sig *types.Signature) int { } func getMsgPosition(sig *types.Signature) int { - for i := 0; i < sig.Params().Len(); i++ { + for i := range sig.Params().Len() { param := sig.Params().At(i) - if b, ok := param.Type().(*types.Basic); ok && b.Kind() == types.String && param.Name() == "msg" { + if b, ok := param.Type().(*types.Basic); ok && b.Kind() == types.String && (param.Name() == "msg" || + param.Name() == "format") { // NOTE(a.telyshev): assert.CollectT case. return i } } diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/go_require.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/go_require.go index 8b0d39999..4a0eb294e 100644 --- a/vendor/github.com/Antonboom/testifylint/internal/checkers/go_require.go +++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/go_require.go @@ -57,9 +57,9 @@ func (checker *GoRequire) SetIgnoreHTTPHandlers(v bool) *GoRequire { // Other test functions called in the test function are also analyzed to make a verdict about the current function. // This leads to recursion, which the cache of processed functions (processedFuncs) helps reduce the impact of. // Also, because of this, we have to pre-collect a list of test function declarations (testsDecls). -func (checker GoRequire) Check(pass *analysis.Pass, inspector *inspector.Inspector) (diagnostics []analysis.Diagnostic) { +func (checker GoRequire) Check(pass *analysis.Pass, insp *inspector.Inspector) (diagnostics []analysis.Diagnostic) { testsDecls := make(funcDeclarations) - inspector.Preorder([]ast.Node{(*ast.FuncDecl)(nil)}, func(node ast.Node) { + insp.Preorder([]ast.Node{(*ast.FuncDecl)(nil)}, func(node ast.Node) { fd := node.(*ast.FuncDecl) if isTestingFuncOrMethod(pass, fd) { @@ -78,7 +78,7 @@ func (checker GoRequire) Check(pass *analysis.Pass, inspector *inspector.Inspect (*ast.GoStmt)(nil), (*ast.CallExpr)(nil), } - inspector.Nodes(nodesFilter, func(node ast.Node, push bool) bool { + insp.Nodes(nodesFilter, func(node ast.Node, push bool) bool { if fd, ok := node.(*ast.FuncDecl); ok { if !isTestingFuncOrMethod(pass, fd) { return false @@ -171,7 +171,7 @@ func (checker GoRequire) Check(pass *analysis.Pass, inspector *inspector.Inspect }) if !checker.ignoreHTTPHandlers { - diagnostics = append(diagnostics, checker.checkHTTPHandlers(pass, inspector)...) + diagnostics = append(diagnostics, checker.checkHTTPHandlers(pass, insp)...) } return diagnostics diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_basic_type.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_basic_type.go index b4bb56321..a716cb0e2 100644 --- a/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_basic_type.go +++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_basic_type.go @@ -37,7 +37,7 @@ func isTypedUnsignedIntNumber(e ast.Expr, v int) bool { return isTypedIntNumber(e, v, "uint", "uint8", "uint16", "uint32", "uint64") } -func isTypedIntNumber(e ast.Expr, v int, types ...string) bool { +func isTypedIntNumber(e ast.Expr, v int, goTypes ...string) bool { ce, ok := e.(*ast.CallExpr) if !ok || len(ce.Args) != 1 { return false @@ -48,7 +48,7 @@ func isTypedIntNumber(e ast.Expr, v int, types ...string) bool { return false } - for _, t := range types { + for _, t := range goTypes { if fn.Name == t { return isIntNumber(ce.Args[0], v) } @@ -61,27 +61,23 @@ func isIntNumber(e ast.Expr, rhs int) bool { return ok && (lhs == rhs) } -func isNegativeIntNumber(e ast.Expr) bool { - v, ok := isIntBasicLit(e) - return ok && v < 0 -} - -func isPositiveIntNumber(e ast.Expr) bool { - v, ok := isIntBasicLit(e) - return ok && v > 0 -} - -func isEmptyStringLit(e ast.Expr) bool { +func isStringLit(e ast.Expr) bool { bl, ok := e.(*ast.BasicLit) - return ok && bl.Kind == token.STRING && bl.Value == `""` + return ok && bl.Kind == token.STRING } -func isNotEmptyStringLit(e ast.Expr) bool { +func isEmptyStringLit(e ast.Expr) bool { bl, ok := e.(*ast.BasicLit) - return ok && bl.Kind == token.STRING && bl.Value != `""` + return ok && bl.Kind == token.STRING && (bl.Value == `""` || bl.Value == "``") } func isBasicLit(e ast.Expr) bool { + if un, ok := e.(*ast.UnaryExpr); ok { + if un.Op == token.SUB { + return isBasicLit(un.X) + } + } + _, ok := e.(*ast.BasicLit) return ok } @@ -144,6 +140,11 @@ func isPointer(pass *analysis.Pass, e ast.Expr) (types.Type, bool) { return ptr.Elem(), true } +func isFunc(pass *analysis.Pass, e ast.Expr) bool { + _, ok := pass.TypesInfo.TypeOf(e).(*types.Signature) + return ok +} + // isByteArray returns true if expression is `[]byte` itself. func isByteArray(e ast.Expr) bool { at, ok := e.(*ast.ArrayType) @@ -171,12 +172,3 @@ func hasStringType(pass *analysis.Pass, e ast.Expr) bool { basicType, ok := pass.TypesInfo.TypeOf(e).(*types.Basic) return ok && basicType.Kind() == types.String } - -// untype returns v from type(v) expression or v itself if there is no type conversion. -func untype(e ast.Expr) ast.Expr { - ce, ok := e.(*ast.CallExpr) - if !ok || len(ce.Args) != 1 { - return e - } - return ce.Args[0] -} diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_bool.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_bool.go index 13e579a2b..613f2fd30 100644 --- a/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_bool.go +++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_bool.go @@ -14,6 +14,10 @@ var ( trueObj = types.Universe.Lookup("true") ) +func isUntypedBool(pass *analysis.Pass, e ast.Expr) bool { + return isUntypedTrue(pass, e) || isUntypedFalse(pass, e) +} + func isUntypedTrue(pass *analysis.Pass, e ast.Expr) bool { return analysisutil.IsObj(pass.TypesInfo, e, trueObj) } @@ -22,7 +26,7 @@ func isUntypedFalse(pass *analysis.Pass, e ast.Expr) bool { return analysisutil.IsObj(pass.TypesInfo, e, falseObj) } -func isBuiltinBool(pass *analysis.Pass, e ast.Expr) bool { +func hasBoolType(pass *analysis.Pass, e ast.Expr) bool { basicType, ok := pass.TypesInfo.TypeOf(e).(*types.Basic) return ok && basicType.Kind() == types.Bool } diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_comparison.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_comparison.go index ac11d7399..e62844307 100644 --- a/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_comparison.go +++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_comparison.go @@ -55,7 +55,7 @@ func isStrictComparisonWith( lhs predicate, op token.Token, rhs predicate, -) (ast.Expr, ast.Expr, bool) { +) (leftOperand ast.Expr, rightOperand ast.Expr, fact bool) { be, ok := e.(*ast.BinaryExpr) if !ok { return nil, nil, false diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_context.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_context.go index e8505fad0..2ad0ae4a3 100644 --- a/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_context.go +++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_context.go @@ -54,7 +54,7 @@ func findSurroundingFunc(pass *analysis.Pass, stack []ast.Node) *funcID { isHTTPHandler = true } - if i >= 2 { //nolint:nestif + if i >= 2 { //nolint:nestif // Already clear code. if ce, ok := stack[i-1].(*ast.CallExpr); ok { if se, ok := ce.Fun.(*ast.SelectorExpr); ok { isTestCleanup = implementsTestingT(pass, se.X) && se.Sel != nil && (se.Sel.Name == "Cleanup") diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_diagnostic.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_diagnostic.go index f12d87aa3..c1364f274 100644 --- a/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_diagnostic.go +++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_diagnostic.go @@ -131,13 +131,23 @@ func newSuggestedFuncReplacement( proposedFn += "f" } return analysis.SuggestedFix{ - Message: fmt.Sprintf("Replace `%s` with `%s`", call.Fn.Name, proposedFn), - TextEdits: append([]analysis.TextEdit{ - { - Pos: call.Fn.Pos(), - End: call.Fn.End(), - NewText: []byte(proposedFn), - }, - }, additionalEdits...), + Message: fmt.Sprintf("Replace `%s` with `%s`", call.Fn.Name, proposedFn), + TextEdits: append([]analysis.TextEdit{newReplaceFnTextEdit(call.Fn, proposedFn)}, additionalEdits...), + } +} + +func newReplaceFnTextEdit(callFn analysis.Range, proposedFn string) analysis.TextEdit { + return analysis.TextEdit{ + Pos: callFn.Pos(), + End: callFn.End(), + NewText: []byte(proposedFn), + } +} + +func newRemoveLastArgTextEdit(pass *analysis.Pass, callArgs []ast.Expr) analysis.TextEdit { + return analysis.TextEdit{ + Pos: callArgs[0].Pos(), + End: callArgs[len(callArgs)-1].End(), + NewText: formatAsCallArgs(pass, callArgs[0:len(callArgs)-1]...), } } diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_http.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_http.go index 9dabb02a9..4aa19c1bb 100644 --- a/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_http.go +++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_http.go @@ -24,7 +24,7 @@ func mimicHTTPHandler(pass *analysis.Pass, fType *ast.FuncType) bool { return false } - for i := 0; i < sig.Params().Len(); i++ { + for i := range sig.Params().Len() { lhs := sig.Params().At(i).Type() rhs := pass.TypesInfo.TypeOf(fType.Params.List[i].Type) if !types.Identical(lhs, rhs) { diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_len.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_len.go index 904950ff3..6afa5849a 100644 --- a/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_len.go +++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/helpers_len.go @@ -2,7 +2,6 @@ package checkers import ( "go/ast" - "go/token" "go/types" "golang.org/x/tools/go/analysis" @@ -12,31 +11,6 @@ import ( var lenObj = types.Universe.Lookup("len") -func isLenEquality(pass *analysis.Pass, e ast.Expr) (ast.Expr, ast.Expr, bool) { - be, ok := e.(*ast.BinaryExpr) - if !ok { - return nil, nil, false - } - - if be.Op != token.EQL { - return nil, nil, false - } - return xorLenCall(pass, be.X, be.Y) -} - -func xorLenCall(pass *analysis.Pass, a, b ast.Expr) (lenArg ast.Expr, expectedLen ast.Expr, ok bool) { - arg1, ok1 := isBuiltinLenCall(pass, a) - arg2, ok2 := isBuiltinLenCall(pass, b) - - if xor(ok1, ok2) { - if ok1 { - return arg1, b, true - } - return arg2, a, true - } - return nil, nil, false -} - func isLenCallAndZero(pass *analysis.Pass, a, b ast.Expr) (ast.Expr, bool) { lenArg, ok := isBuiltinLenCall(pass, a) return lenArg, ok && isZero(b) diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/len.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/len.go index c240a6174..51a883b14 100644 --- a/vendor/github.com/Antonboom/testifylint/internal/checkers/len.go +++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/len.go @@ -1,19 +1,42 @@ package checkers import ( + "go/ast" + "go/token" + "golang.org/x/tools/go/analysis" ) // Len detects situations like // -// assert.Equal(t, 3, len(arr)) -// assert.EqualValues(t, 3, len(arr)) -// assert.Exactly(t, 3, len(arr)) -// assert.True(t, len(arr) == 3) +// assert.Equal(t, 42, len(arr)) +// assert.Equal(t, len(arr), 42) +// assert.EqualValues(t, 42, len(arr)) +// assert.EqualValues(t, len(arr), 42) +// assert.Exactly(t, 42, len(arr)) +// assert.Exactly(t, len(arr), 42) +// assert.True(t, 42 == len(arr)) +// assert.True(t, len(arr) == 42) +// +// assert.Equal(t, value, len(arr)) +// assert.EqualValues(t, value, len(arr)) +// assert.Exactly(t, value, len(arr)) +// assert.True(t, len(arr) == value) +// +// assert.Equal(t, len(expArr), len(arr)) +// assert.EqualValues(t, len(expArr), len(arr)) +// assert.Exactly(t, len(expArr), len(arr)) +// assert.True(t, len(arr) == len(expArr)) // // and requires // -// assert.Len(t, arr, 3) +// assert.Len(t, arr, 42) +// assert.Len(t, arr, value) +// assert.Len(t, arr, len(expArr)) +// +// The checker ignores assertions in which length checking is not a priority, e.g +// +// assert.Equal(t, len(arr), value) type Len struct{} // NewLen constructs Len checker. @@ -21,45 +44,62 @@ func NewLen() Len { return Len{} } func (Len) Name() string { return "len" } func (checker Len) Check(pass *analysis.Pass, call *CallMeta) *analysis.Diagnostic { - const proposedFn = "Len" - switch call.Fn.NameFTrimmed { case "Equal", "EqualValues", "Exactly": if len(call.Args) < 2 { return nil } - a, b := call.Args[0], call.Args[1] - if lenArg, expectedLen, ok := xorLenCall(pass, a, b); ok { - if _, ok := isIntBasicLit(expectedLen); (expectedLen == b) && !ok { - // https://github.com/Antonboom/testifylint/issues/9 - return nil - } - return newUseFunctionDiagnostic(checker.Name(), call, proposedFn, - analysis.TextEdit{ - Pos: a.Pos(), - End: b.End(), - NewText: formatAsCallArgs(pass, lenArg, expectedLen), - }) - } + a, b := call.Args[0], call.Args[1] + return checker.checkArgs(call, pass, a, b, false) case "True": if len(call.Args) < 1 { return nil } - expr := call.Args[0] - if lenArg, expectedLen, ok := isLenEquality(pass, expr); ok { - if _, ok := isIntBasicLit(expectedLen); !ok { - return nil - } - return newUseFunctionDiagnostic(checker.Name(), call, proposedFn, - analysis.TextEdit{ - Pos: expr.Pos(), - End: expr.End(), - NewText: formatAsCallArgs(pass, lenArg, expectedLen), - }) + be, ok := call.Args[0].(*ast.BinaryExpr) + if !ok { + return nil + } + if be.Op != token.EQL { + return nil + } + return checker.checkArgs(call, pass, be.Y, be.X, true) // In True, the actual value is usually first. + } + return nil +} + +func (checker Len) checkArgs(call *CallMeta, pass *analysis.Pass, a, b ast.Expr, inverted bool) *analysis.Diagnostic { + newUseLenDiagnostic := func(lenArg, expectedLen ast.Expr) *analysis.Diagnostic { + const proposedFn = "Len" + start, end := a.Pos(), b.End() + if inverted { + start, end = b.Pos(), a.End() + } + return newUseFunctionDiagnostic(checker.Name(), call, proposedFn, + analysis.TextEdit{ + Pos: start, + End: end, + NewText: formatAsCallArgs(pass, lenArg, expectedLen), + }) + } + + arg1, firstIsLen := isBuiltinLenCall(pass, a) + arg2, secondIsLen := isBuiltinLenCall(pass, b) + + switch { + case firstIsLen && secondIsLen: + return newUseLenDiagnostic(arg2, a) + + case firstIsLen: + if _, secondIsNum := isIntBasicLit(b); secondIsNum { + return newUseLenDiagnostic(arg1, b) } + + case secondIsLen: + return newUseLenDiagnostic(arg2, a) } + return nil } diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/negative_positive.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/negative_positive.go index a61bbdfcb..f15dc4981 100644 --- a/vendor/github.com/Antonboom/testifylint/internal/checkers/negative_positive.go +++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/negative_positive.go @@ -55,7 +55,7 @@ func (checker NegativePositive) checkNegative(pass *analysis.Pass, call *CallMet }) } - // NOTE(a.telyshev): We ignore uint-asserts as being no sense for assert.Negative. + // NOTE(a.telyshev): We ignore uint and len asserts as being no sense for assert.Negative. switch call.Fn.NameFTrimmed { case "Less": @@ -64,8 +64,8 @@ func (checker NegativePositive) checkNegative(pass *analysis.Pass, call *CallMet } a, b := call.Args[0], call.Args[1] - if isSignedNotZero(pass, a) && isZeroOrSignedZero(b) { - return newUseNegativeDiagnostic(a.Pos(), b.End(), untype(a)) + if canBeNegative(pass, a) && isZeroOrSignedZero(b) { + return newUseNegativeDiagnostic(a.Pos(), b.End(), a) } case "Greater": @@ -74,8 +74,8 @@ func (checker NegativePositive) checkNegative(pass *analysis.Pass, call *CallMet } a, b := call.Args[0], call.Args[1] - if isZeroOrSignedZero(a) && isSignedNotZero(pass, b) { - return newUseNegativeDiagnostic(a.Pos(), b.End(), untype(b)) + if isZeroOrSignedZero(a) && canBeNegative(pass, b) { + return newUseNegativeDiagnostic(a.Pos(), b.End(), b) } case "True": @@ -84,12 +84,12 @@ func (checker NegativePositive) checkNegative(pass *analysis.Pass, call *CallMet } expr := call.Args[0] - a, _, ok1 := isStrictComparisonWith(pass, expr, isSignedNotZero, token.LSS, p(isZeroOrSignedZero)) // a < 0 - _, b, ok2 := isStrictComparisonWith(pass, expr, p(isZeroOrSignedZero), token.GTR, isSignedNotZero) // 0 > a + a, _, ok1 := isStrictComparisonWith(pass, expr, canBeNegative, token.LSS, p(isZeroOrSignedZero)) // a < 0 + _, b, ok2 := isStrictComparisonWith(pass, expr, p(isZeroOrSignedZero), token.GTR, canBeNegative) // 0 > a survivingArg, ok := anyVal([]bool{ok1, ok2}, a, b) if ok { - return newUseNegativeDiagnostic(expr.Pos(), expr.End(), untype(survivingArg)) + return newUseNegativeDiagnostic(expr.Pos(), expr.End(), survivingArg) } case "False": @@ -98,12 +98,12 @@ func (checker NegativePositive) checkNegative(pass *analysis.Pass, call *CallMet } expr := call.Args[0] - a, _, ok1 := isStrictComparisonWith(pass, expr, isSignedNotZero, token.GEQ, p(isZeroOrSignedZero)) // a >= 0 - _, b, ok2 := isStrictComparisonWith(pass, expr, p(isZeroOrSignedZero), token.LEQ, isSignedNotZero) // 0 <= a + a, _, ok1 := isStrictComparisonWith(pass, expr, canBeNegative, token.GEQ, p(isZeroOrSignedZero)) // a >= 0 + _, b, ok2 := isStrictComparisonWith(pass, expr, p(isZeroOrSignedZero), token.LEQ, canBeNegative) // 0 <= a survivingArg, ok := anyVal([]bool{ok1, ok2}, a, b) if ok { - return newUseNegativeDiagnostic(expr.Pos(), expr.End(), untype(survivingArg)) + return newUseNegativeDiagnostic(expr.Pos(), expr.End(), survivingArg) } } return nil @@ -128,7 +128,7 @@ func (checker NegativePositive) checkPositive(pass *analysis.Pass, call *CallMet a, b := call.Args[0], call.Args[1] if isNotAnyZero(a) && isAnyZero(b) { - return newUsePositiveDiagnostic(a.Pos(), b.End(), untype(a)) + return newUsePositiveDiagnostic(a.Pos(), b.End(), a) } case "Less": @@ -138,7 +138,7 @@ func (checker NegativePositive) checkPositive(pass *analysis.Pass, call *CallMet a, b := call.Args[0], call.Args[1] if isAnyZero(a) && isNotAnyZero(b) { - return newUsePositiveDiagnostic(a.Pos(), b.End(), untype(b)) + return newUsePositiveDiagnostic(a.Pos(), b.End(), b) } case "True": @@ -152,7 +152,7 @@ func (checker NegativePositive) checkPositive(pass *analysis.Pass, call *CallMet survivingArg, ok := anyVal([]bool{ok1, ok2}, a, b) if ok { - return newUsePositiveDiagnostic(expr.Pos(), expr.End(), untype(survivingArg)) + return newUsePositiveDiagnostic(expr.Pos(), expr.End(), survivingArg) } case "False": @@ -166,8 +166,13 @@ func (checker NegativePositive) checkPositive(pass *analysis.Pass, call *CallMet survivingArg, ok := anyVal([]bool{ok1, ok2}, a, b) if ok { - return newUsePositiveDiagnostic(expr.Pos(), expr.End(), untype(survivingArg)) + return newUsePositiveDiagnostic(expr.Pos(), expr.End(), survivingArg) } } return nil } + +func canBeNegative(pass *analysis.Pass, e ast.Expr) bool { + _, isLen := isBuiltinLenCall(pass, e) + return isSignedNotZero(pass, e) && !isLen +} diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/require_error.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/require_error.go index e4e30aaf4..e96516310 100644 --- a/vendor/github.com/Antonboom/testifylint/internal/checkers/require_error.go +++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/require_error.go @@ -50,12 +50,12 @@ func (checker *RequireError) SetFnPattern(p *regexp.Regexp) *RequireError { return checker } -func (checker RequireError) Check(pass *analysis.Pass, inspector *inspector.Inspector) []analysis.Diagnostic { +func (checker RequireError) Check(pass *analysis.Pass, insp *inspector.Inspector) []analysis.Diagnostic { callsByFunc := make(map[funcID][]*callMeta) // Stage 1. Collect meta information about any calls inside functions. - inspector.WithStack([]ast.Node{(*ast.CallExpr)(nil)}, func(node ast.Node, push bool, stack []ast.Node) bool { + insp.WithStack([]ast.Node{(*ast.CallExpr)(nil)}, func(node ast.Node, push bool, stack []ast.Node) bool { if !push { return false } diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/suite_method_signature.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/suite_method_signature.go new file mode 100644 index 000000000..9ceba5db7 --- /dev/null +++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/suite_method_signature.go @@ -0,0 +1,71 @@ +package checkers + +import ( + "fmt" + "go/ast" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/ast/inspector" + + "github.com/Antonboom/testifylint/internal/analysisutil" + "github.com/Antonboom/testifylint/internal/testify" +) + +// SuiteMethodSignature warns, when +// - suite's test methods have arguments or returning values; +// - suite's custom (user) methods conflicts with (shadows/overrides) suite functionality methods. +type SuiteMethodSignature struct{} + +// NewSuiteMethodSignature constructs SuiteMethodSignature checker. +func NewSuiteMethodSignature() SuiteMethodSignature { return SuiteMethodSignature{} } +func (SuiteMethodSignature) Name() string { return "suite-method-signature" } + +func (checker SuiteMethodSignature) Check(pass *analysis.Pass, insp *inspector.Inspector) (diags []analysis.Diagnostic) { + insp.Preorder([]ast.Node{(*ast.FuncDecl)(nil)}, func(node ast.Node) { + fd := node.(*ast.FuncDecl) + if !isSuiteMethod(pass, fd) { + return + } + + methodName := fd.Name.Name + rcv := fd.Recv.List[0] + + if isSuiteTestMethod(methodName) { + if fd.Type.Params.NumFields() > 0 || fd.Type.Results.NumFields() > 0 { + const msg = "test method should not have any arguments or returning values" + diags = append(diags, *newDiagnostic(checker.Name(), fd, msg)) + return + } + } + + iface, ok := suiteMethodToInterface[methodName] + if !ok { + return + } + ifaceObj := analysisutil.ObjectOf(pass.Pkg, testify.SuitePkgPath, iface) + if ifaceObj == nil { + return + } + if !implements(pass, rcv.Type, ifaceObj) { + msg := fmt.Sprintf("method conflicts with %s.%s interface", testify.SuitePkgName, iface) + diags = append(diags, *newDiagnostic(checker.Name(), fd, msg)) + } + }) + return diags +} + +// https://github.com/stretchr/testify/blob/master/suite/interfaces.go +var suiteMethodToInterface = map[string]string{ + // NOTE(a.telyshev): We ignore suite.TestingSuite interface, because + // - suite.Run will not work for suite-types that do not implement it; + // - this interface has several methods, which may cause a false positive for one of the methods in the suite-type. + "SetupSuite": "SetupAllSuite", + "SetupTest": "SetupTestSuite", + "TearDownSuite": "TearDownAllSuite", + "TearDownTest": "TearDownTestSuite", + "BeforeTest": "BeforeTest", + "AfterTest": "AfterTest", + "HandleStats": "WithStats", + "SetupSubTest": "SetupSubTest", + "TearDownSubTest": "TearDownSubTest", +} diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/suite_thelper.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/suite_thelper.go index ef8d82132..074de4f76 100644 --- a/vendor/github.com/Antonboom/testifylint/internal/checkers/suite_thelper.go +++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/suite_thelper.go @@ -22,8 +22,8 @@ type SuiteTHelper struct{} func NewSuiteTHelper() SuiteTHelper { return SuiteTHelper{} } func (SuiteTHelper) Name() string { return "suite-thelper" } -func (checker SuiteTHelper) Check(pass *analysis.Pass, inspector *inspector.Inspector) (diagnostics []analysis.Diagnostic) { - inspector.Preorder([]ast.Node{(*ast.FuncDecl)(nil)}, func(node ast.Node) { +func (checker SuiteTHelper) Check(pass *analysis.Pass, insp *inspector.Inspector) (diagnostics []analysis.Diagnostic) { + insp.Preorder([]ast.Node{(*ast.FuncDecl)(nil)}, func(node ast.Node) { fd := node.(*ast.FuncDecl) if !isSuiteMethod(pass, fd) { return @@ -43,7 +43,7 @@ func (checker SuiteTHelper) Check(pass *analysis.Pass, inspector *inspector.Insp } rcvName := rcv.Names[0].Name - helperCallStr := fmt.Sprintf("%s.T().Helper()", rcvName) + helperCallStr := rcvName + ".T().Helper()" firstStmt := fd.Body.List[0] if analysisutil.NodeString(pass.Fset, firstStmt) == helperCallStr { diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/useless_assert.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/useless_assert.go index 045706e5d..15de9c6c5 100644 --- a/vendor/github.com/Antonboom/testifylint/internal/checkers/useless_assert.go +++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/useless_assert.go @@ -30,20 +30,38 @@ import ( // assert.False(t, num == num) // assert.False(t, num != num) // -// assert.Empty(t, "") -// assert.False(t, false) +// assert.Empty(t, "value") // Any string literal. +// assert.Error(t, nil) +// assert.False(t, false) // Any bool literal. // assert.Implements(t, (*any)(nil), new(Conn)) -// assert.Negative(t, -42) +// assert.Negative(t, 42) // Any int literal. // assert.Nil(t, nil) // assert.NoError(t, nil) -// assert.NotEmpty(t, "value") -// assert.NotZero(t, 42) -// assert.NotZero(t, "value") -// assert.Positive(t, 42) -// assert.True(t, true) -// assert.Zero(t, 0) -// assert.Zero(t, "") +// assert.NotEmpty(t, "value") // Any string literal. +// assert.NotImplements(t, (*any)(nil), new(Conn)) +// assert.NotNil(t, nil) +// assert.NotZero(t, 42) // Any int literal. +// assert.NotZero(t, "value") // Any string literal. +// assert.NotZero(t, nil) +// assert.NotZero(t, false) // Any bool literal. +// assert.Positive(t, 42) // Any int literal. +// assert.True(t, true) // Any bool literal. +// assert.Zero(t, 42) // Any int literal. +// assert.Zero(t, "value") // Any string literal. // assert.Zero(t, nil) +// assert.Zero(t, false) // Any bool literal. +// +// assert.Negative(len(x)) +// assert.Less(len(x), 0) +// assert.Greater(0, len(x)) +// assert.GreaterOrEqual(len(x), 0) +// assert.LessOrEqual(0, len(x)) +// +// assert.Negative(uintVal) +// assert.Less(uintVal, 0) +// assert.Greater(0, uintVal) +// assert.GreaterOrEqual(uintVal, 0) +// assert.LessOrEqual(0, uintVal) type UselessAssert struct{} // NewUselessAssert constructs UselessAssert checker. @@ -57,13 +75,13 @@ func (checker UselessAssert) Check(pass *analysis.Pass, call *CallMeta) *analysi var isMeaningless bool switch call.Fn.NameFTrimmed { - case "Empty": - isMeaningless = (len(call.Args) >= 1) && isEmptyStringLit(call.Args[0]) + case "False", "True": + isMeaningless = (len(call.Args) >= 1) && isUntypedBool(pass, call.Args[0]) - case "False": - isMeaningless = (len(call.Args) >= 1) && isUntypedFalse(pass, call.Args[0]) + case "GreaterOrEqual", "Less": + isMeaningless = (len(call.Args) >= 2) && isAnyZero(call.Args[1]) && canNotBeNegative(pass, call.Args[0]) - case "Implements": + case "Implements", "NotImplements": if len(call.Args) < 2 { return nil } @@ -71,29 +89,34 @@ func (checker UselessAssert) Check(pass *analysis.Pass, call *CallMeta) *analysi elem, ok := isPointer(pass, call.Args[0]) isMeaningless = ok && isEmptyInterfaceType(elem) - case "Negative": - isMeaningless = (len(call.Args) >= 1) && isNegativeIntNumber(call.Args[0]) - - case "Nil", "NoError": - isMeaningless = (len(call.Args) >= 1) && isNil(call.Args[0]) + case "LessOrEqual", "Greater": + isMeaningless = (len(call.Args) >= 2) && isAnyZero(call.Args[0]) && canNotBeNegative(pass, call.Args[1]) - case "NotEmpty": - isMeaningless = (len(call.Args) >= 1) && isNotEmptyStringLit(call.Args[0]) + case "Positive": + if len(call.Args) < 1 { + return nil + } + _, isMeaningless = isIntBasicLit(call.Args[0]) - case "NotZero": - isMeaningless = (len(call.Args) >= 1) && - (isNotEmptyStringLit(call.Args[0]) || - isNegativeIntNumber(call.Args[0]) || isPositiveIntNumber(call.Args[0])) + case "Negative": + if len(call.Args) < 1 { + return nil + } + _, isInt := isIntBasicLit(call.Args[0]) + isMeaningless = isInt || canNotBeNegative(pass, call.Args[0]) - case "Positive": - isMeaningless = (len(call.Args) >= 1) && isPositiveIntNumber(call.Args[0]) + case "Error", "Nil", "NoError", "NotNil": + isMeaningless = (len(call.Args) >= 1) && isNil(call.Args[0]) - case "True": - isMeaningless = (len(call.Args) >= 1) && isUntypedTrue(pass, call.Args[0]) + case "Empty", "NotEmpty": + isMeaningless = (len(call.Args) >= 1) && isStringLit(call.Args[0]) - case "Zero": - isMeaningless = (len(call.Args) >= 1) && - (isZero(call.Args[0]) || isEmptyStringLit(call.Args[0]) || isNil(call.Args[0])) + case "NotZero", "Zero": + if len(call.Args) < 1 { + return nil + } + _, isInt := isIntBasicLit(call.Args[0]) + isMeaningless = isInt || isStringLit(call.Args[0]) || isNil(call.Args[0]) || isUntypedBool(pass, call.Args[0]) } if isMeaningless { @@ -123,12 +146,15 @@ func (checker UselessAssert) checkSameVars(pass *analysis.Pass, call *CallMeta) "InDeltaSlice", "InEpsilon", "InEpsilonSlice", + "IsNotType", "IsType", "JSONEq", "Less", "LessOrEqual", + "NotElementsMatch", "NotEqual", "NotEqualValues", + "NotErrorAs", "NotErrorIs", "NotRegexp", "NotSame", @@ -163,3 +189,8 @@ func (checker UselessAssert) checkSameVars(pass *analysis.Pass, call *CallMeta) } return nil } + +func canNotBeNegative(pass *analysis.Pass, e ast.Expr) bool { + _, isLen := isBuiltinLenCall(pass, e) + return isLen || isUnsigned(pass, e) +} diff --git a/vendor/github.com/Antonboom/testifylint/internal/config/config.go b/vendor/github.com/Antonboom/testifylint/internal/config/config.go index 23b673428..7b2587876 100644 --- a/vendor/github.com/Antonboom/testifylint/internal/config/config.go +++ b/vendor/github.com/Antonboom/testifylint/internal/config/config.go @@ -24,6 +24,7 @@ func NewDefault() Config { Formatter: FormatterConfig{ CheckFormatString: true, RequireFFuncs: false, + RequireStringMsg: true, }, GoRequire: GoRequireConfig{ IgnoreHTTPHandlers: false, @@ -66,6 +67,7 @@ type ExpectedActualConfig struct { type FormatterConfig struct { CheckFormatString bool RequireFFuncs bool + RequireStringMsg bool } // GoRequireConfig implements configuration of checkers.GoRequire. @@ -133,7 +135,10 @@ func BindToFlags(cfg *Config, fs *flag.FlagSet) { "to enable go vet's printf checks") fs.BoolVar(&cfg.Formatter.RequireFFuncs, "formatter.require-f-funcs", false, - "to require f-assertions (e.g. assert.Equalf) if format string is used, even if there are no variable-length variables.") + "to require f-assertions (e.g. assert.Equalf) if format string is used, even if there are no variable-length variables") + fs.BoolVar(&cfg.Formatter.RequireStringMsg, + "formatter.require-string-msg", true, + "to require that the first element of msgAndArgs (msg) has a string type") fs.BoolVar(&cfg.GoRequire.IgnoreHTTPHandlers, "go-require.ignore-http-handlers", false, diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/CHANGELOG.md b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/CHANGELOG.md index c73744e23..47d2b85fa 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/CHANGELOG.md +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/CHANGELOG.md @@ -1,5 +1,27 @@ # Release History +## 1.20.0 (2025-11-06) + +### Features Added + +* Added `runtime.FetcherForNextLinkOptions.HTTPVerb` to specify the HTTP verb when fetching the next page via next link. Defaults to `http.MethodGet`. + +### Bugs Fixed + +* Fixed potential panic when decoding base64 strings. +* Fixed an issue in resource identifier parsing which prevented it from returning an error for malformed resource IDs. + +## 1.19.1 (2025-09-11) + +### Bugs Fixed + +* Fixed resource identifier parsing for provider-specific resource hierarchies containing "resourceGroups" segments. + +### Other Changes + +* Improved error fall-back for improperly authored long-running operations. +* Upgraded dependencies. + ## 1.19.0 (2025-08-21) ### Features Added diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/internal/resource/resource_identifier.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/internal/resource/resource_identifier.go index a08d3d0ff..8a40ebe4d 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/internal/resource/resource_identifier.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/internal/resource/resource_identifier.go @@ -123,9 +123,9 @@ func newResourceIDWithProvider(parent *ResourceID, providerNamespace, resourceTy } func chooseResourceType(resourceTypeName string, parent *ResourceID) ResourceType { - if strings.EqualFold(resourceTypeName, resourceGroupsLowerKey) { + if strings.EqualFold(resourceTypeName, resourceGroupsLowerKey) && isSubscriptionResource(parent) { return ResourceGroupResourceType - } else if strings.EqualFold(resourceTypeName, subscriptionsKey) && parent != nil && parent.ResourceType.String() == TenantResourceType.String() { + } else if strings.EqualFold(resourceTypeName, subscriptionsKey) && isTenantResource(parent) { return SubscriptionResourceType } @@ -182,12 +182,12 @@ func appendNext(parent *ResourceID, parts []string, id string) (*ResourceID, err if len(parts) == 1 { // subscriptions and resourceGroups are not valid ids without their names - if strings.EqualFold(parts[0], subscriptionsKey) || strings.EqualFold(parts[0], resourceGroupsLowerKey) { + if strings.EqualFold(parts[0], subscriptionsKey) && isTenantResource(parent) || strings.EqualFold(parts[0], resourceGroupsLowerKey) && isSubscriptionResource(parent) { return nil, fmt.Errorf("invalid resource ID: %s", id) } // resourceGroup must contain either child or provider resource type - if parent.ResourceType.String() == ResourceGroupResourceType.String() { + if isResourceGroupResource(parent) { return nil, fmt.Errorf("invalid resource ID: %s", id) } @@ -196,7 +196,7 @@ func appendNext(parent *ResourceID, parts []string, id string) (*ResourceID, err if strings.EqualFold(parts[0], providersKey) && (len(parts) == 2 || strings.EqualFold(parts[2], providersKey)) { // provider resource can only be on a tenant or a subscription parent - if parent.ResourceType.String() != SubscriptionResourceType.String() && parent.ResourceType.String() != TenantResourceType.String() { + if !isSubscriptionResource(parent) && !isTenantResource(parent) { return nil, fmt.Errorf("invalid resource ID: %s", id) } @@ -217,6 +217,7 @@ func appendNext(parent *ResourceID, parts []string, id string) (*ResourceID, err func splitStringAndOmitEmpty(v, sep string) []string { r := make([]string, 0) for _, s := range strings.Split(v, sep) { + s = strings.TrimSpace(s) if len(s) == 0 { continue } @@ -225,3 +226,18 @@ func splitStringAndOmitEmpty(v, sep string) []string { return r } + +// isTenantResource returns true if the resourceID represents a tenant resource. The condition is resource ID matched with TenantResourceType and has no parent. +func isTenantResource(resourceID *ResourceID) bool { + return resourceID != nil && strings.EqualFold(resourceID.ResourceType.String(), TenantResourceType.String()) && resourceID.Parent == nil +} + +// isSubscriptionResource returns true if the resourceID represents a subscription resource. The condition is resource ID matched with SubscriptionResourceType and its parent is a tenant resource. +func isSubscriptionResource(resourceID *ResourceID) bool { + return resourceID != nil && strings.EqualFold(resourceID.ResourceType.String(), SubscriptionResourceType.String()) && isTenantResource(resourceID.Parent) +} + +// isResourceGroupResource returns true if the resourceID represents a resource group resource. The condition is resource ID matched with ResourceGroupResourceType and its parent is a subscription resource. +func isResourceGroupResource(resourceID *ResourceID) bool { + return resourceID != nil && strings.EqualFold(resourceID.ResourceType.String(), ResourceGroupResourceType.String()) && isSubscriptionResource(resourceID.Parent) +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/exported.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/exported.go index 460170034..612af11ac 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/exported.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/exported.go @@ -92,7 +92,7 @@ func DecodeByteArray(s string, v *[]byte, format Base64Encoding) error { return nil } payload := string(s) - if payload[0] == '"' { + if len(payload) >= 2 && payload[0] == '"' && payload[len(payload)-1] == '"' { // remove surrounding quotes payload = payload[1 : len(payload)-1] } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/constants.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/constants.go index 9fb41a405..f15200091 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/constants.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/constants.go @@ -40,5 +40,5 @@ const ( Module = "azcore" // Version is the semantic version (see http://semver.org) of this module. - Version = "v1.19.0" + Version = "v1.20.0" ) diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/pager.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/pager.go index c66fc0a90..edb4a3cd4 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/pager.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/pager.go @@ -99,6 +99,11 @@ type FetcherForNextLinkOptions struct { // StatusCodes contains additional HTTP status codes indicating success. // The default value is http.StatusOK. StatusCodes []int + + // HTTPVerb specifies the HTTP verb to use when fetching the next page. + // The default value is http.MethodGet. + // This field is only used when NextReq is not specified. + HTTPVerb string } // FetcherForNextLink is a helper containing boilerplate code to simplify creating a PagingHandler[T].Fetcher from a next link URL. @@ -119,7 +124,11 @@ func FetcherForNextLink(ctx context.Context, pl Pipeline, nextLink string, first if options.NextReq != nil { req, err = options.NextReq(ctx, nextLink) } else { - req, err = NewRequest(ctx, http.MethodGet, nextLink) + verb := http.MethodGet + if options.HTTPVerb != "" { + verb = options.HTTPVerb + } + req, err = NewRequest(ctx, verb, nextLink) } } if err != nil { diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/poller.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/poller.go index 4f90e4474..a89ae9b7b 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/poller.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/poller.go @@ -91,7 +91,7 @@ func NewPoller[T any](resp *http.Response, pl exported.Pipeline, options *NewPol // this is a back-stop in case the swagger is incorrect (i.e. missing one or more status codes for success). // ideally the codegen should return an error if the initial response failed and not even create a poller. if !poller.StatusCodeValid(resp) { - return nil, errors.New("the operation failed or was cancelled") + return nil, exported.NewResponseError(resp) } // determine the polling method diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/CHANGELOG.md b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/CHANGELOG.md index 9e68cf670..4a6349e16 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/CHANGELOG.md +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/CHANGELOG.md @@ -1,5 +1,46 @@ # Release History +## 1.13.1 (2025-11-10) + +### Bugs Fixed + +- `AzureCLICredential` quoted arguments incorrectly on Windows + +## 1.13.0 (2025-10-07) + +### Features Added + +- Added `AzurePowerShellCredential`, which authenticates as the identity logged in to Azure PowerShell + (thanks [ArmaanMcleod](https://github.com/ArmaanMcleod)) +- When `AZURE_TOKEN_CREDENTIALS` is set to `ManagedIdentityCredential`, `DefaultAzureCredential` behaves the same as + does `ManagedIdentityCredential` when used directly. It doesn't apply special retry configuration or attempt to + determine whether IMDS is available. ([#25265](https://github.com/Azure/azure-sdk-for-go/issues/25265)) + +### Breaking Changes + +* Removed the `WorkloadIdentityCredential` support for identity binding mode added in v1.13.0-beta.1. + It will return in v1.14.0-beta.1 + +## 1.13.0-beta.1 (2025-09-17) + +### Features Added + +- Added `AzurePowerShellCredential`, which authenticates as the identity logged in to Azure PowerShell + (thanks [ArmaanMcleod](https://github.com/ArmaanMcleod)) +- `WorkloadIdentityCredential` supports identity binding mode ([#25056](https://github.com/Azure/azure-sdk-for-go/issues/25056)) + +## 1.12.0 (2025-09-16) + +### Features Added +- Added `DefaultAzureCredentialOptions.RequireAzureTokenCredentials`. `NewDefaultAzureCredential` returns an + error when this option is true and the environment variable `AZURE_TOKEN_CREDENTIALS` has no value. + +### Other Changes +- `AzureDeveloperCLICredential` no longer hangs when AZD_DEBUG is set +- `GetToken` methods of `AzureCLICredential` and `AzureDeveloperCLICredential` return an error when + `TokenRequestOptions.Claims` has a value because these credentials can't acquire a token in that + case. The error messages describe the action required to get a token. + ## 1.11.0 (2025-08-05) ### Other Changes diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/README.md b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/README.md index 069bc688d..127c25b72 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/README.md +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/README.md @@ -1,6 +1,6 @@ # Azure Identity Client Module for Go -The Azure Identity module provides Microsoft Entra ID ([formerly Azure Active Directory](https://learn.microsoft.com/entra/fundamentals/new-name)) token authentication support across the Azure SDK. It includes a set of `TokenCredential` implementations, which can be used with Azure SDK clients supporting token authentication. +The Azure Identity module provides [Microsoft Entra ID](https://learn.microsoft.com/entra/fundamentals/whatis) token-based authentication support across the Azure SDK. It includes a set of `TokenCredential` implementations, which can be used with Azure SDK clients supporting token authentication. [![PkgGoDev](https://pkg.go.dev/badge/github.com/Azure/azure-sdk-for-go/sdk/azidentity)](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity) | [Microsoft Entra ID documentation](https://learn.microsoft.com/entra/identity/) @@ -153,6 +153,7 @@ client := armresources.NewResourceGroupsClient("subscription ID", chain, nil) |-|- |[AzureCLICredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#AzureCLICredential)|Authenticate as the user signed in to the Azure CLI |[AzureDeveloperCLICredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#AzureDeveloperCLICredential)|Authenticates as the user signed in to the Azure Developer CLI +|[AzurePowerShellCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#AzurePowerShellCredential)|Authenticates as the user signed in to Azure PowerShell ## Environment Variables diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TOKEN_CACHING.MD b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TOKEN_CACHING.MD index da2094e36..8bdaf8165 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TOKEN_CACHING.MD +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TOKEN_CACHING.MD @@ -40,6 +40,7 @@ The following table indicates the state of in-memory and persistent caching in e | ------------------------------ | ------------------------------------------------------------------- | ------------------------ | | `AzureCLICredential` | Not Supported | Not Supported | | `AzureDeveloperCLICredential` | Not Supported | Not Supported | +| `AzurePowerShellCredential` | Not Supported | Not Supported | | `AzurePipelinesCredential` | Supported | Supported | | `ClientAssertionCredential` | Supported | Supported | | `ClientCertificateCredential` | Supported | Supported | diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TROUBLESHOOTING.md b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TROUBLESHOOTING.md index 6ac513846..517006a42 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TROUBLESHOOTING.md +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TROUBLESHOOTING.md @@ -12,13 +12,13 @@ This troubleshooting guide covers failure investigation techniques, common error - [Troubleshoot AzureCLICredential authentication issues](#troubleshoot-azureclicredential-authentication-issues) - [Troubleshoot AzureDeveloperCLICredential authentication issues](#troubleshoot-azuredeveloperclicredential-authentication-issues) - [Troubleshoot AzurePipelinesCredential authentication issues](#troubleshoot-azurepipelinescredential-authentication-issues) +- [Troubleshoot AzurePowerShellCredential authentication issues](#troubleshoot-azurepowershellcredential-authentication-issues) - [Troubleshoot ClientCertificateCredential authentication issues](#troubleshoot-clientcertificatecredential-authentication-issues) - [Troubleshoot ClientSecretCredential authentication issues](#troubleshoot-clientsecretcredential-authentication-issues) - [Troubleshoot DefaultAzureCredential authentication issues](#troubleshoot-defaultazurecredential-authentication-issues) - [Troubleshoot EnvironmentCredential authentication issues](#troubleshoot-environmentcredential-authentication-issues) - [Troubleshoot ManagedIdentityCredential authentication issues](#troubleshoot-managedidentitycredential-authentication-issues) - [Azure App Service and Azure Functions managed identity](#azure-app-service-and-azure-functions-managed-identity) - - [Azure Kubernetes Service managed identity](#azure-kubernetes-service-managed-identity) - [Azure Virtual Machine managed identity](#azure-virtual-machine-managed-identity) - [Troubleshoot WorkloadIdentityCredential authentication issues](#troubleshoot-workloadidentitycredential-authentication-issues) - [Get additional help](#get-additional-help) @@ -120,7 +120,6 @@ azlog.SetEvents(azidentity.EventAuthentication) |---|---|---| |Azure Virtual Machines and Scale Sets|[Configuration](https://learn.microsoft.com/entra/identity/managed-identities-azure-resources/qs-configure-portal-windows-vm)|[Troubleshooting](#azure-virtual-machine-managed-identity)| |Azure App Service and Azure Functions|[Configuration](https://learn.microsoft.com/azure/app-service/overview-managed-identity)|[Troubleshooting](#azure-app-service-and-azure-functions-managed-identity)| -|Azure Kubernetes Service|[Configuration](https://azure.github.io/aad-pod-identity/docs/)|[Troubleshooting](#azure-kubernetes-service-managed-identity)| |Azure Arc|[Configuration](https://learn.microsoft.com/azure/azure-arc/servers/managed-identity-authentication)|| |Azure Service Fabric|[Configuration](https://learn.microsoft.com/azure/service-fabric/concepts-managed-identity)|| @@ -159,14 +158,6 @@ curl "$IDENTITY_ENDPOINT?resource=https://management.core.windows.net&api-versio > This command's output will contain an access token and SHOULD NOT BE SHARED, to avoid compromising account security. -### Azure Kubernetes Service managed identity - -#### Pod Identity - -| Error Message |Description| Mitigation | -|---|---|---| -|"no azure identity found for request clientID"|The application attempted to authenticate before an identity was assigned to its pod|Verify the pod is labeled correctly. This also occurs when a correctly labeled pod authenticates before the identity is ready. To prevent initialization races, configure NMI to set the Retry-After header in its responses as described in [Pod Identity documentation](https://azure.github.io/aad-pod-identity/docs/configure/feature_flags/#set-retry-after-header-in-nmi-response). - ## Troubleshoot AzureCLICredential authentication issues @@ -215,6 +206,34 @@ azd auth token --output json --scope https://management.core.windows.net/.defaul ``` >Note that output of this command will contain a valid access token, and SHOULD NOT BE SHARED to avoid compromising account security. + +## Troubleshoot `AzurePowerShellCredential` authentication issues + +| Error Message |Description| Mitigation | +|---|---|---| +|executable not found on path|No local installation of PowerShell was found.|Ensure that PowerShell is properly installed on the machine. Instructions for installing PowerShell can be found [here](https://learn.microsoft.com/powershell/scripting/install/installing-powershell).| +|Az.Accounts module not found|The Az.Account module needed for authentication in Azure PowerShell isn't installed.|Install the latest Az.Account module. Installation instructions can be found [here](https://learn.microsoft.com/powershell/azure/install-az-ps).| +|Please run "Connect-AzAccount" to set up account.|No account is currently logged into Azure PowerShell.|
  • Log in to Azure PowerShell using the `Connect-AzAccount` command. More instructions for authenticating Azure PowerShell can be found at [Sign in with Azure PowerShell](https://learn.microsoft.com/powershell/azure/authenticate-azureps).
  • Validate that Azure PowerShell can obtain tokens. For instructions, see [Verify Azure PowerShell can obtain tokens](#verify-azure-powershell-can-obtain-tokens).
| + +#### __Verify Azure PowerShell can obtain tokens__ + +You can manually verify that Azure PowerShell is authenticated and can obtain tokens. First, use the `Get-AzContext` command to verify the account that is currently logged in to Azure PowerShell. + +``` +PS C:\> Get-AzContext + +Name Account SubscriptionName Environment TenantId +---- ------- ---------------- ----------- -------- +Subscription1 (xxxxxxxx-xxxx-xxxx-xxx... test@outlook.com Subscription1 AzureCloud xxxxxxxx-x... +``` + +Once you've verified Azure PowerShell is using correct account, validate that it's able to obtain tokens for this account: + +```bash +Get-AzAccessToken -ResourceUrl "https://management.core.windows.net" +``` +>Note that output of this command will contain a valid access token, and SHOULD NOT BE SHARED to avoid compromising account security. + ## Troubleshoot `WorkloadIdentityCredential` authentication issues diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/assets.json b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/assets.json index 4118f99ef..1646ff911 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/assets.json +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "go", "TagPrefix": "go/azidentity", - "Tag": "go/azidentity_191110b0dd" + "Tag": "go/azidentity_530ea4279b" } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azure_cli_credential.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azure_cli_credential.go index 0fd03f456..6944152c9 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azure_cli_credential.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azure_cli_credential.go @@ -7,14 +7,11 @@ package azidentity import ( - "bytes" "context" + "encoding/base64" "encoding/json" "errors" "fmt" - "os" - "os/exec" - "runtime" "strings" "sync" "time" @@ -26,8 +23,6 @@ import ( const credNameAzureCLI = "AzureCLICredential" -type azTokenProvider func(ctx context.Context, scopes []string, tenant, subscription string) ([]byte, error) - // AzureCLICredentialOptions contains optional parameters for AzureCLICredential. type AzureCLICredentialOptions struct { // AdditionallyAllowedTenants specifies tenants to which the credential may authenticate, in addition to @@ -45,15 +40,8 @@ type AzureCLICredentialOptions struct { // inDefaultChain is true when the credential is part of DefaultAzureCredential inDefaultChain bool - // tokenProvider is used by tests to fake invoking az - tokenProvider azTokenProvider -} - -// init returns an instance of AzureCLICredentialOptions initialized with default values. -func (o *AzureCLICredentialOptions) init() { - if o.tokenProvider == nil { - o.tokenProvider = defaultAzTokenProvider - } + // exec is used by tests to fake invoking az + exec executor } // AzureCLICredential authenticates as the identity logged in to the Azure CLI. @@ -80,7 +68,9 @@ func NewAzureCLICredential(options *AzureCLICredentialOptions) (*AzureCLICredent if cp.TenantID != "" && !validTenantID(cp.TenantID) { return nil, errInvalidTenantID } - cp.init() + if cp.exec == nil { + cp.exec = shellExec + } cp.AdditionallyAllowedTenants = resolveAdditionalTenants(cp.AdditionallyAllowedTenants) return &AzureCLICredential{mu: &sync.Mutex{}, opts: cp}, nil } @@ -99,14 +89,37 @@ func (c *AzureCLICredential) GetToken(ctx context.Context, opts policy.TokenRequ if err != nil { return at, err } + // pass the CLI a Microsoft Entra ID v1 resource because we don't know which CLI version is installed and older ones don't support v2 scopes + resource := strings.TrimSuffix(opts.Scopes[0], defaultSuffix) + command := "az account get-access-token -o json --resource " + resource + tenantArg := "" + if tenant != "" { + tenantArg = " --tenant " + tenant + command += tenantArg + } + if c.opts.Subscription != "" { + // subscription needs quotes because it may contain spaces + command += ` --subscription "` + c.opts.Subscription + `"` + } + if opts.Claims != "" { + encoded := base64.StdEncoding.EncodeToString([]byte(opts.Claims)) + return at, fmt.Errorf( + "%s.GetToken(): Azure CLI requires multifactor authentication or additional claims. Run this command then retry the operation: az login%s --claims-challenge %s", + credNameAzureCLI, + tenantArg, + encoded, + ) + } + c.mu.Lock() defer c.mu.Unlock() - b, err := c.opts.tokenProvider(ctx, opts.Scopes, tenant, c.opts.Subscription) + + b, err := c.opts.exec(ctx, credNameAzureCLI, command) if err == nil { at, err = c.createAccessToken(b) } if err != nil { - err = unavailableIfInChain(err, c.opts.inDefaultChain) + err = unavailableIfInDAC(err, c.opts.inDefaultChain) return at, err } msg := fmt.Sprintf("%s.GetToken() acquired a token for scope %q", credNameAzureCLI, strings.Join(opts.Scopes, ", ")) @@ -114,63 +127,6 @@ func (c *AzureCLICredential) GetToken(ctx context.Context, opts policy.TokenRequ return at, nil } -// defaultAzTokenProvider invokes the Azure CLI to acquire a token. It assumes -// callers have verified that all string arguments are safe to pass to the CLI. -var defaultAzTokenProvider azTokenProvider = func(ctx context.Context, scopes []string, tenantID, subscription string) ([]byte, error) { - // pass the CLI a Microsoft Entra ID v1 resource because we don't know which CLI version is installed and older ones don't support v2 scopes - resource := strings.TrimSuffix(scopes[0], defaultSuffix) - // set a default timeout for this authentication iff the application hasn't done so already - var cancel context.CancelFunc - if _, hasDeadline := ctx.Deadline(); !hasDeadline { - ctx, cancel = context.WithTimeout(ctx, cliTimeout) - defer cancel() - } - commandLine := "az account get-access-token -o json --resource " + resource - if tenantID != "" { - commandLine += " --tenant " + tenantID - } - if subscription != "" { - // subscription needs quotes because it may contain spaces - commandLine += ` --subscription "` + subscription + `"` - } - var cliCmd *exec.Cmd - if runtime.GOOS == "windows" { - dir := os.Getenv("SYSTEMROOT") - if dir == "" { - return nil, newCredentialUnavailableError(credNameAzureCLI, "environment variable 'SYSTEMROOT' has no value") - } - cliCmd = exec.CommandContext(ctx, "cmd.exe", "/c", commandLine) - cliCmd.Dir = dir - } else { - cliCmd = exec.CommandContext(ctx, "/bin/sh", "-c", commandLine) - cliCmd.Dir = "/bin" - } - cliCmd.Env = os.Environ() - var stderr bytes.Buffer - cliCmd.Stderr = &stderr - cliCmd.WaitDelay = 100 * time.Millisecond - - stdout, err := cliCmd.Output() - if errors.Is(err, exec.ErrWaitDelay) && len(stdout) > 0 { - // The child process wrote to stdout and exited without closing it. - // Swallow this error and return stdout because it may contain a token. - return stdout, nil - } - if err != nil { - msg := stderr.String() - var exErr *exec.ExitError - if errors.As(err, &exErr) && exErr.ExitCode() == 127 || strings.HasPrefix(msg, "'az' is not recognized") { - msg = "Azure CLI not found on path" - } - if msg == "" { - msg = err.Error() - } - return nil, newCredentialUnavailableError(credNameAzureCLI, msg) - } - - return stdout, nil -} - func (c *AzureCLICredential) createAccessToken(tk []byte) (azcore.AccessToken, error) { t := struct { AccessToken string `json:"accessToken"` diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azure_developer_cli_credential.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azure_developer_cli_credential.go index 1bd3720b6..f97bf95df 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azure_developer_cli_credential.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azure_developer_cli_credential.go @@ -7,14 +7,11 @@ package azidentity import ( - "bytes" "context" + "encoding/base64" "encoding/json" "errors" "fmt" - "os" - "os/exec" - "runtime" "strings" "sync" "time" @@ -24,9 +21,10 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/internal/log" ) -const credNameAzureDeveloperCLI = "AzureDeveloperCLICredential" - -type azdTokenProvider func(ctx context.Context, scopes []string, tenant string) ([]byte, error) +const ( + credNameAzureDeveloperCLI = "AzureDeveloperCLICredential" + mfaRequired = "Azure Developer CLI requires multifactor authentication or additional claims" +) // AzureDeveloperCLICredentialOptions contains optional parameters for AzureDeveloperCLICredential. type AzureDeveloperCLICredentialOptions struct { @@ -41,8 +39,8 @@ type AzureDeveloperCLICredentialOptions struct { // inDefaultChain is true when the credential is part of DefaultAzureCredential inDefaultChain bool - // tokenProvider is used by tests to fake invoking azd - tokenProvider azdTokenProvider + // exec is used by tests to fake invoking azd + exec executor } // AzureDeveloperCLICredential authenticates as the identity logged in to the [Azure Developer CLI]. @@ -62,8 +60,8 @@ func NewAzureDeveloperCLICredential(options *AzureDeveloperCLICredentialOptions) if cp.TenantID != "" && !validTenantID(cp.TenantID) { return nil, errInvalidTenantID } - if cp.tokenProvider == nil { - cp.tokenProvider = defaultAzdTokenProvider + if cp.exec == nil { + cp.exec = shellExec } return &AzureDeveloperCLICredential{mu: &sync.Mutex{}, opts: cp}, nil } @@ -75,23 +73,52 @@ func (c *AzureDeveloperCLICredential) GetToken(ctx context.Context, opts policy. if len(opts.Scopes) == 0 { return at, errors.New(credNameAzureDeveloperCLI + ": GetToken() requires at least one scope") } + command := "azd auth token -o json --no-prompt" for _, scope := range opts.Scopes { if !validScope(scope) { return at, fmt.Errorf("%s.GetToken(): invalid scope %q", credNameAzureDeveloperCLI, scope) } + command += " --scope " + scope } tenant, err := resolveTenant(c.opts.TenantID, opts.TenantID, credNameAzureDeveloperCLI, c.opts.AdditionallyAllowedTenants) if err != nil { return at, err } + if tenant != "" { + command += " --tenant-id " + tenant + } + commandNoClaims := command + if opts.Claims != "" { + encoded := base64.StdEncoding.EncodeToString([]byte(opts.Claims)) + command += " --claims " + encoded + } + c.mu.Lock() defer c.mu.Unlock() - b, err := c.opts.tokenProvider(ctx, opts.Scopes, tenant) + + b, err := c.opts.exec(ctx, credNameAzureDeveloperCLI, command) if err == nil { at, err = c.createAccessToken(b) } if err != nil { - err = unavailableIfInChain(err, c.opts.inDefaultChain) + msg := err.Error() + switch { + case strings.Contains(msg, "unknown flag: --claims"): + err = newAuthenticationFailedError( + credNameAzureDeveloperCLI, + mfaRequired+", however the installed version doesn't support this. Upgrade to version 1.18.1 or later", + nil, + ) + case opts.Claims != "": + err = newAuthenticationFailedError( + credNameAzureDeveloperCLI, + mfaRequired+". Run this command then retry the operation: "+commandNoClaims, + nil, + ) + case strings.Contains(msg, "azd auth login"): + err = newCredentialUnavailableError(credNameAzureDeveloperCLI, `please run "azd auth login" from a command prompt to authenticate before using this credential`) + } + err = unavailableIfInDAC(err, c.opts.inDefaultChain) return at, err } msg := fmt.Sprintf("%s.GetToken() acquired a token for scope %q", credNameAzureDeveloperCLI, strings.Join(opts.Scopes, ", ")) @@ -99,61 +126,6 @@ func (c *AzureDeveloperCLICredential) GetToken(ctx context.Context, opts policy. return at, nil } -// defaultAzTokenProvider invokes the Azure Developer CLI to acquire a token. It assumes -// callers have verified that all string arguments are safe to pass to the CLI. -var defaultAzdTokenProvider azdTokenProvider = func(ctx context.Context, scopes []string, tenant string) ([]byte, error) { - // set a default timeout for this authentication iff the application hasn't done so already - var cancel context.CancelFunc - if _, hasDeadline := ctx.Deadline(); !hasDeadline { - ctx, cancel = context.WithTimeout(ctx, cliTimeout) - defer cancel() - } - commandLine := "azd auth token -o json" - if tenant != "" { - commandLine += " --tenant-id " + tenant - } - for _, scope := range scopes { - commandLine += " --scope " + scope - } - var cliCmd *exec.Cmd - if runtime.GOOS == "windows" { - dir := os.Getenv("SYSTEMROOT") - if dir == "" { - return nil, newCredentialUnavailableError(credNameAzureDeveloperCLI, "environment variable 'SYSTEMROOT' has no value") - } - cliCmd = exec.CommandContext(ctx, "cmd.exe", "/c", commandLine) - cliCmd.Dir = dir - } else { - cliCmd = exec.CommandContext(ctx, "/bin/sh", "-c", commandLine) - cliCmd.Dir = "/bin" - } - cliCmd.Env = os.Environ() - var stderr bytes.Buffer - cliCmd.Stderr = &stderr - cliCmd.WaitDelay = 100 * time.Millisecond - - stdout, err := cliCmd.Output() - if errors.Is(err, exec.ErrWaitDelay) && len(stdout) > 0 { - // The child process wrote to stdout and exited without closing it. - // Swallow this error and return stdout because it may contain a token. - return stdout, nil - } - if err != nil { - msg := stderr.String() - var exErr *exec.ExitError - if errors.As(err, &exErr) && exErr.ExitCode() == 127 || strings.HasPrefix(msg, "'azd' is not recognized") { - msg = "Azure Developer CLI not found on path" - } else if strings.Contains(msg, "azd auth login") { - msg = `please run "azd auth login" from a command prompt to authenticate before using this credential` - } - if msg == "" { - msg = err.Error() - } - return nil, newCredentialUnavailableError(credNameAzureDeveloperCLI, msg) - } - return stdout, nil -} - func (c *AzureDeveloperCLICredential) createAccessToken(tk []byte) (azcore.AccessToken, error) { t := struct { AccessToken string `json:"token"` diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azure_powershell_credential.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azure_powershell_credential.go new file mode 100644 index 000000000..082965554 --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azure_powershell_credential.go @@ -0,0 +1,234 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package azidentity + +import ( + "context" + "encoding/base64" + "encoding/binary" + "encoding/json" + "errors" + "fmt" + "os/exec" + "runtime" + "strings" + "sync" + "time" + "unicode/utf16" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" + "github.com/Azure/azure-sdk-for-go/sdk/internal/log" +) + +const ( + credNameAzurePowerShell = "AzurePowerShellCredential" + noAzAccountModule = "Az.Accounts module not found" +) + +// AzurePowerShellCredentialOptions contains optional parameters for AzurePowerShellCredential. +type AzurePowerShellCredentialOptions struct { + // AdditionallyAllowedTenants specifies tenants to which the credential may authenticate, in addition to + // TenantID. When TenantID is empty, this option has no effect and the credential will authenticate to + // any requested tenant. Add the wildcard value "*" to allow the credential to authenticate to any tenant. + AdditionallyAllowedTenants []string + + // TenantID identifies the tenant the credential should authenticate in. + // Defaults to Azure PowerShell's default tenant, which is typically the home tenant of the logged in user. + TenantID string + + // inDefaultChain is true when the credential is part of DefaultAzureCredential + inDefaultChain bool + + // exec is used by tests to fake invoking Azure PowerShell + exec executor +} + +// AzurePowerShellCredential authenticates as the identity logged in to Azure PowerShell. +type AzurePowerShellCredential struct { + mu *sync.Mutex + opts AzurePowerShellCredentialOptions +} + +// NewAzurePowerShellCredential constructs an AzurePowerShellCredential. Pass nil to accept default options. +func NewAzurePowerShellCredential(options *AzurePowerShellCredentialOptions) (*AzurePowerShellCredential, error) { + cp := AzurePowerShellCredentialOptions{} + + if options != nil { + cp = *options + } + + if cp.TenantID != "" && !validTenantID(cp.TenantID) { + return nil, errInvalidTenantID + } + + if cp.exec == nil { + cp.exec = shellExec + } + + cp.AdditionallyAllowedTenants = resolveAdditionalTenants(cp.AdditionallyAllowedTenants) + + return &AzurePowerShellCredential{mu: &sync.Mutex{}, opts: cp}, nil +} + +// GetToken requests a token from Azure PowerShell. This credential doesn't cache tokens, so every call invokes Azure PowerShell. +// This method is called automatically by Azure SDK clients. +func (c *AzurePowerShellCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) { + at := azcore.AccessToken{} + + if len(opts.Scopes) != 1 { + return at, errors.New(credNameAzurePowerShell + ": GetToken() requires exactly one scope") + } + + if !validScope(opts.Scopes[0]) { + return at, fmt.Errorf("%s.GetToken(): invalid scope %q", credNameAzurePowerShell, opts.Scopes[0]) + } + + tenant, err := resolveTenant(c.opts.TenantID, opts.TenantID, credNameAzurePowerShell, c.opts.AdditionallyAllowedTenants) + if err != nil { + return at, err + } + + // Always pass a Microsoft Entra ID v1 resource URI (not a v2 scope) because Get-AzAccessToken only supports v1 resource URIs. + resource := strings.TrimSuffix(opts.Scopes[0], defaultSuffix) + + tenantArg := "" + if tenant != "" { + tenantArg = fmt.Sprintf(" -TenantId '%s'", tenant) + } + + if opts.Claims != "" { + encoded := base64.StdEncoding.EncodeToString([]byte(opts.Claims)) + return at, fmt.Errorf( + "%s.GetToken(): Azure PowerShell requires multifactor authentication or additional claims. Run this command then retry the operation: Connect-AzAccount%s -ClaimsChallenge '%s'", + credNameAzurePowerShell, + tenantArg, + encoded, + ) + } + + // Inline script to handle Get-AzAccessToken differences between Az.Accounts versions with SecureString handling and minimum version requirement + script := fmt.Sprintf(` +$ErrorActionPreference = 'Stop' +[version]$minimumVersion = '2.2.0' + +$mod = Import-Module Az.Accounts -MinimumVersion $minimumVersion -PassThru -ErrorAction SilentlyContinue + +if (-not $mod) { + Write-Error '%s' +} + +$params = @{ + ResourceUrl = '%s' + WarningAction = 'Ignore' +} + +# Only force AsSecureString for Az.Accounts versions > 2.17.0 and < 5.0.0 which return plain text token by default. +# Newer Az.Accounts versions return SecureString token by default and no longer use AsSecureString parameter. +if ($mod.Version -ge [version]'2.17.0' -and $mod.Version -lt [version]'5.0.0') { + $params['AsSecureString'] = $true +} + +$tenantId = '%s' +if ($tenantId.Length -gt 0) { + $params['TenantId'] = '%s' +} + +$token = Get-AzAccessToken @params + +$customToken = New-Object -TypeName psobject + +# The following .NET interop pattern is supported in all PowerShell versions and safely converts SecureString to plain text. +if ($token.Token -is [System.Security.SecureString]) { + $ssPtr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($token.Token) + try { + $plainToken = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($ssPtr) + } finally { + [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ssPtr) + } + $customToken | Add-Member -MemberType NoteProperty -Name Token -Value $plainToken +} else { + $customToken | Add-Member -MemberType NoteProperty -Name Token -Value $token.Token +} +$customToken | Add-Member -MemberType NoteProperty -Name ExpiresOn -Value $token.ExpiresOn.ToUnixTimeSeconds() + +$jsonToken = $customToken | ConvertTo-Json +return $jsonToken +`, noAzAccountModule, resource, tenant, tenant) + + // Windows: prefer pwsh.exe (PowerShell Core), fallback to powershell.exe (Windows PowerShell) + // Unix: only support pwsh (PowerShell Core) + exe := "pwsh" + if runtime.GOOS == "windows" { + if _, err := exec.LookPath("pwsh.exe"); err == nil { + exe = "pwsh.exe" + } else { + exe = "powershell.exe" + } + } + + command := exe + " -NoProfile -NonInteractive -OutputFormat Text -EncodedCommand " + base64EncodeUTF16LE(script) + + c.mu.Lock() + defer c.mu.Unlock() + + b, err := c.opts.exec(ctx, credNameAzurePowerShell, command) + if err == nil { + at, err = c.createAccessToken(b) + } + + if err != nil { + err = unavailableIfInDAC(err, c.opts.inDefaultChain) + return at, err + } + + msg := fmt.Sprintf("%s.GetToken() acquired a token for scope %q", credNameAzurePowerShell, strings.Join(opts.Scopes, ", ")) + log.Write(EventAuthentication, msg) + + return at, nil +} + +func (c *AzurePowerShellCredential) createAccessToken(tk []byte) (azcore.AccessToken, error) { + t := struct { + Token string `json:"Token"` + ExpiresOn int64 `json:"ExpiresOn"` + }{} + + err := json.Unmarshal(tk, &t) + if err != nil { + return azcore.AccessToken{}, err + } + + converted := azcore.AccessToken{ + Token: t.Token, + ExpiresOn: time.Unix(t.ExpiresOn, 0).UTC(), + } + + return converted, nil +} + +// Encodes a string to Base64 using UTF-16LE encoding +func base64EncodeUTF16LE(text string) string { + u16 := utf16.Encode([]rune(text)) + buf := make([]byte, len(u16)*2) + for i, v := range u16 { + binary.LittleEndian.PutUint16(buf[i*2:], v) + } + return base64.StdEncoding.EncodeToString(buf) +} + +// Decodes a Base64 UTF-16LE string back to string +func base64DecodeUTF16LE(encoded string) (string, error) { + data, err := base64.StdEncoding.DecodeString(encoded) + if err != nil { + return "", err + } + u16 := make([]uint16, len(data)/2) + for i := range u16 { + u16[i] = binary.LittleEndian.Uint16(data[i*2:]) + } + return string(utf16.Decode(u16)), nil +} + +var _ azcore.TokenCredential = (*AzurePowerShellCredential)(nil) diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/ci.yml b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/ci.yml index 38445e853..51dd97939 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/ci.yml +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/ci.yml @@ -41,6 +41,3 @@ extends: GenerateVMJobs: true Path: sdk/azidentity/managed-identity-matrix.json Selection: sparse - MatrixReplace: - - Pool=.*LINUXPOOL.*/azsdk-pool-mms-ubuntu-2204-identitymsi - - OSVmImage=.*LINUXVMIMAGE.*/azsdk-pool-mms-ubuntu-2204-1espt diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/default_azure_credential.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/default_azure_credential.go index 2b94270a8..aaaabc5c2 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/default_azure_credential.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/default_azure_credential.go @@ -26,6 +26,7 @@ const ( managedIdentity az azd + azurePowerShell ) // DefaultAzureCredentialOptions contains optional parameters for DefaultAzureCredential. @@ -48,6 +49,10 @@ type DefaultAzureCredentialOptions struct { // the application responsible for ensuring the configured authority is valid and trustworthy. DisableInstanceDiscovery bool + // RequireAzureTokenCredentials determines whether NewDefaultAzureCredential returns an error when the environment + // variable AZURE_TOKEN_CREDENTIALS has no value. + RequireAzureTokenCredentials bool + // TenantID sets the default tenant for authentication via the Azure CLI, Azure Developer CLI, and workload identity. TenantID string } @@ -67,6 +72,7 @@ type DefaultAzureCredentialOptions struct { // - [ManagedIdentityCredential] // - [AzureCLICredential] // - [AzureDeveloperCLICredential] +// - [AzurePowerShellCredential] // // Consult the documentation for these credential types for more information on how they authenticate. // Once a credential has successfully authenticated, DefaultAzureCredential will use that credential for @@ -79,9 +85,13 @@ type DefaultAzureCredentialOptions struct { // Valid values for AZURE_TOKEN_CREDENTIALS are the name of any single type in the above chain, for example // "EnvironmentCredential" or "AzureCLICredential", and these special values: // -// - "dev": try [AzureCLICredential] and [AzureDeveloperCLICredential], in that order +// - "dev": try [AzureCLICredential], [AzureDeveloperCLICredential], and [AzurePowerShellCredential], in that order // - "prod": try [EnvironmentCredential], [WorkloadIdentityCredential], and [ManagedIdentityCredential], in that order // +// [DefaultAzureCredentialOptions].RequireAzureTokenCredentials controls whether AZURE_TOKEN_CREDENTIALS must be set. +// NewDefaultAzureCredential returns an error when RequireAzureTokenCredentials is true and AZURE_TOKEN_CREDENTIALS +// has no value. +// // [DefaultAzureCredential overview]: https://aka.ms/azsdk/go/identity/credential-chains#defaultazurecredential-overview type DefaultAzureCredential struct { chain *ChainedTokenCredential @@ -89,16 +99,20 @@ type DefaultAzureCredential struct { // NewDefaultAzureCredential creates a DefaultAzureCredential. Pass nil for options to accept defaults. func NewDefaultAzureCredential(options *DefaultAzureCredentialOptions) (*DefaultAzureCredential, error) { + if options == nil { + options = &DefaultAzureCredentialOptions{} + } + var ( creds []azcore.TokenCredential errorMessages []string - selected = env | workloadIdentity | managedIdentity | az | azd + selected = env | workloadIdentity | managedIdentity | az | azd | azurePowerShell ) if atc, ok := os.LookupEnv(azureTokenCredentials); ok { switch { case atc == "dev": - selected = az | azd + selected = az | azd | azurePowerShell case atc == "prod": selected = env | workloadIdentity | managedIdentity case strings.EqualFold(atc, credNameEnvironment): @@ -111,14 +125,15 @@ func NewDefaultAzureCredential(options *DefaultAzureCredentialOptions) (*Default selected = az case strings.EqualFold(atc, credNameAzureDeveloperCLI): selected = azd + case strings.EqualFold(atc, credNameAzurePowerShell): + selected = azurePowerShell default: return nil, fmt.Errorf(`invalid %s value %q. Valid values are "dev", "prod", or the name of any credential type in the default chain. See https://aka.ms/azsdk/go/identity/docs#DefaultAzureCredential for more information`, azureTokenCredentials, atc) } + } else if options.RequireAzureTokenCredentials { + return nil, fmt.Errorf("%s must be set when RequireAzureTokenCredentials is true. See https://aka.ms/azsdk/go/identity/docs#DefaultAzureCredential for more information", azureTokenCredentials) } - if options == nil { - options = &DefaultAzureCredentialOptions{} - } additionalTenants := options.AdditionallyAllowedTenants if len(additionalTenants) == 0 { if tenants := os.Getenv(azureAdditionallyAllowedTenants); tenants != "" { @@ -153,7 +168,11 @@ func NewDefaultAzureCredential(options *DefaultAzureCredentialOptions) (*Default } } if selected&managedIdentity != 0 { - o := &ManagedIdentityCredentialOptions{ClientOptions: options.ClientOptions, dac: true} + o := &ManagedIdentityCredentialOptions{ + ClientOptions: options.ClientOptions, + // enable special DefaultAzureCredential behavior (IMDS probing) only when the chain contains another credential + dac: selected^managedIdentity != 0, + } if ID, ok := os.LookupEnv(azureClientID); ok { o.ID = ClientID(ID) } @@ -191,6 +210,19 @@ func NewDefaultAzureCredential(options *DefaultAzureCredentialOptions) (*Default creds = append(creds, &defaultCredentialErrorReporter{credType: credNameAzureDeveloperCLI, err: err}) } } + if selected&azurePowerShell != 0 { + azurePowerShellCred, err := NewAzurePowerShellCredential(&AzurePowerShellCredentialOptions{ + AdditionallyAllowedTenants: additionalTenants, + TenantID: options.TenantID, + inDefaultChain: true, + }) + if err == nil { + creds = append(creds, azurePowerShellCred) + } else { + errorMessages = append(errorMessages, credNameAzurePowerShell+": "+err.Error()) + creds = append(creds, &defaultCredentialErrorReporter{credType: credNameAzurePowerShell, err: err}) + } + } if len(errorMessages) > 0 { log.Writef(EventAuthentication, "NewDefaultAzureCredential failed to initialize some credentials:\n\t%s", strings.Join(errorMessages, "\n\t")) diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/developer_credential_util.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/developer_credential_util.go index be963d3a2..cb7dbe2e4 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/developer_credential_util.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/developer_credential_util.go @@ -7,22 +7,72 @@ package azidentity import ( + "bytes" + "context" "errors" + "os" + "os/exec" + "strings" "time" ) // cliTimeout is the default timeout for authentication attempts via CLI tools const cliTimeout = 10 * time.Second -// unavailableIfInChain returns err or, if the credential was invoked by DefaultAzureCredential, a +// executor runs a command and returns its output or an error +type executor func(ctx context.Context, credName, command string) ([]byte, error) + +var shellExec = func(ctx context.Context, credName, command string) ([]byte, error) { + // set a default timeout for this authentication iff the caller hasn't done so already + var cancel context.CancelFunc + if _, hasDeadline := ctx.Deadline(); !hasDeadline { + ctx, cancel = context.WithTimeout(ctx, cliTimeout) + defer cancel() + } + cmd, err := buildCmd(ctx, credName, command) + if err != nil { + return nil, err + } + cmd.Env = os.Environ() + stderr := bytes.Buffer{} + cmd.Stderr = &stderr + cmd.WaitDelay = 100 * time.Millisecond + + stdout, err := cmd.Output() + if errors.Is(err, exec.ErrWaitDelay) && len(stdout) > 0 { + // The child process wrote to stdout and exited without closing it. + // Swallow this error and return stdout because it may contain a token. + return stdout, nil + } + if err != nil { + msg := stderr.String() + var exErr *exec.ExitError + if errors.As(err, &exErr) && exErr.ExitCode() == 127 || strings.Contains(msg, "' is not recognized") { + return nil, newCredentialUnavailableError(credName, "executable not found on path") + } + if credName == credNameAzurePowerShell { + if strings.Contains(msg, "Connect-AzAccount") { + msg = `Please run "Connect-AzAccount" to set up an account` + } + if strings.Contains(msg, noAzAccountModule) { + msg = noAzAccountModule + } + } + if msg == "" { + msg = err.Error() + } + return nil, newAuthenticationFailedError(credName, msg, nil) + } + + return stdout, nil +} + +// unavailableIfInDAC returns err or, if the credential was invoked by DefaultAzureCredential, a // credentialUnavailableError having the same message. This ensures DefaultAzureCredential will try // the next credential in its chain (another developer credential). -func unavailableIfInChain(err error, inDefaultChain bool) error { - if err != nil && inDefaultChain { - var unavailableErr credentialUnavailable - if !errors.As(err, &unavailableErr) { - err = newCredentialUnavailableError(credNameAzureDeveloperCLI, err.Error()) - } +func unavailableIfInDAC(err error, inDefaultChain bool) error { + if err != nil && inDefaultChain && !errors.As(err, new(credentialUnavailable)) { + err = NewCredentialUnavailableError(err.Error()) } return err } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/developer_credential_util_nonwindows.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/developer_credential_util_nonwindows.go new file mode 100644 index 000000000..681fcd0cf --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/developer_credential_util_nonwindows.go @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +//go:build !windows + +package azidentity + +import ( + "context" + "os/exec" +) + +func buildCmd(ctx context.Context, _, command string) (*exec.Cmd, error) { + cmd := exec.CommandContext(ctx, "/bin/sh", "-c", command) + cmd.Dir = "/bin" + return cmd, nil +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/developer_credential_util_windows.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/developer_credential_util_windows.go new file mode 100644 index 000000000..09c7a1a97 --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/developer_credential_util_windows.go @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package azidentity + +import ( + "context" + "os" + "os/exec" + "syscall" +) + +func buildCmd(ctx context.Context, credName, command string) (*exec.Cmd, error) { + dir := os.Getenv("SYSTEMROOT") + if dir == "" { + return nil, newCredentialUnavailableError(credName, `environment variable "SYSTEMROOT" has no value`) + } + cmd := exec.CommandContext(ctx, "cmd.exe") + cmd.Dir = dir + cmd.SysProcAttr = &syscall.SysProcAttr{CmdLine: "/c " + command} + return cmd, nil +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/errors.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/errors.go index a6d7c6cbc..33cb63be0 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/errors.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/errors.go @@ -99,6 +99,8 @@ func (e *AuthenticationFailedError) Error() string { anchor = "apc" case credNameCert: anchor = "client-cert" + case credNameAzurePowerShell: + anchor = "azure-pwsh" case credNameSecret: anchor = "client-secret" case credNameManagedIdentity: diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/managed-identity-matrix.json b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/managed-identity-matrix.json index f92245533..063325c69 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/managed-identity-matrix.json +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/managed-identity-matrix.json @@ -10,8 +10,7 @@ }, "GoVersion": [ "env:GO_VERSION_PREVIOUS" - ], - "IDENTITY_IMDS_AVAILABLE": "1" + ] } ] -} +} \ No newline at end of file diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/test-resources-post.ps1 b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/test-resources-post.ps1 index 874d4ef37..c5634cd21 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/test-resources-post.ps1 +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/test-resources-post.ps1 @@ -41,7 +41,7 @@ if ($CI) { az account set --subscription $SubscriptionId } -Write-Host "Building container" +Write-Host "##[group]Building container" $image = "$($DeploymentOutputs['AZIDENTITY_ACR_LOGIN_SERVER'])/azidentity-managed-id-test" Set-Content -Path "$PSScriptRoot/Dockerfile" -Value @" FROM mcr.microsoft.com/oss/go/microsoft/golang:latest AS builder @@ -62,11 +62,34 @@ CMD ["./managed-id-test"] docker build -t $image "$PSScriptRoot" az acr login -n $DeploymentOutputs['AZIDENTITY_ACR_NAME'] docker push $image +Write-Host "##[endgroup]" $rg = $DeploymentOutputs['AZIDENTITY_RESOURCE_GROUP'] +Write-Host "##[group]Deploying to VM" +# az will return 0 when the script fails on the VM, so the script prints a UUID to indicate all commands succeeded +$uuid = [guid]::NewGuid().ToString() +$vmScript = @" +az acr login -n $($DeploymentOutputs['AZIDENTITY_ACR_NAME']) && \ +sudo docker run \ +-e AZIDENTITY_STORAGE_NAME=$($DeploymentOutputs['AZIDENTITY_STORAGE_NAME']) \ +-e AZIDENTITY_STORAGE_NAME_USER_ASSIGNED=$($DeploymentOutputs['AZIDENTITY_STORAGE_NAME_USER_ASSIGNED']) \ +-e AZIDENTITY_USER_ASSIGNED_IDENTITY=$($DeploymentOutputs['AZIDENTITY_USER_ASSIGNED_IDENTITY']) \ +-e AZIDENTITY_USER_ASSIGNED_IDENTITY_CLIENT_ID=$($DeploymentOutputs['AZIDENTITY_USER_ASSIGNED_IDENTITY_CLIENT_ID']) \ +-e AZIDENTITY_USER_ASSIGNED_IDENTITY_OBJECT_ID=$($DeploymentOutputs['AZIDENTITY_USER_ASSIGNED_IDENTITY_OBJECT_ID']) \ +-p 80:8080 -d \ +$image && \ +/usr/bin/echo $uuid +"@ +$output = az vm run-command invoke -g $rg -n $DeploymentOutputs['AZIDENTITY_VM_NAME'] --command-id RunShellScript --scripts "$vmScript" | Out-String +Write-Host $output +if (-not $output.Contains($uuid)) { + throw "couldn't start container on VM" +} +Write-Host "##[endgroup]" + # ACI is easier to provision here than in the bicep file because the image isn't available before now -Write-Host "Deploying Azure Container Instance" +Write-Host "##[group]Deploying Azure Container Instance" $aciName = "azidentity-test" az container create -g $rg -n $aciName --image $image ` --acr-identity $($DeploymentOutputs['AZIDENTITY_USER_ASSIGNED_IDENTITY']) ` @@ -85,23 +108,27 @@ az container create -g $rg -n $aciName --image $image ` FUNCTIONS_CUSTOMHANDLER_PORT=80 $aciIP = az container show -g $rg -n $aciName --query ipAddress.ip --output tsv Write-Host "##vso[task.setvariable variable=AZIDENTITY_ACI_IP;]$aciIP" +Write-Host "##[endgroup]" # Azure Functions deployment: copy the Windows binary from the Docker image, deploy it in a zip -Write-Host "Deploying to Azure Functions" +Write-Host "##[group]Deploying to Azure Functions" $container = docker create $image docker cp ${container}:managed-id-test.exe "$PSScriptRoot/testdata/managed-id-test/" docker rm -v $container Compress-Archive -Path "$PSScriptRoot/testdata/managed-id-test/*" -DestinationPath func.zip -Force az functionapp deploy -g $rg -n $DeploymentOutputs['AZIDENTITY_FUNCTION_NAME'] --src-path func.zip --type zip +Write-Host "##[endgroup]" -Write-Host "Creating federated identity" +Write-Host "##[group]Creating federated identity" $aksName = $DeploymentOutputs['AZIDENTITY_AKS_NAME'] $idName = $DeploymentOutputs['AZIDENTITY_USER_ASSIGNED_IDENTITY_NAME'] $issuer = az aks show -g $rg -n $aksName --query "oidcIssuerProfile.issuerUrl" -otsv $podName = "azidentity-test" $serviceAccountName = "workload-identity-sa" az identity federated-credential create -g $rg --identity-name $idName --issuer $issuer --name $idName --subject system:serviceaccount:default:$serviceAccountName --audiences api://AzureADTokenExchange -Write-Host "Deploying to AKS" +Write-Host "##[endgroup]" + +Write-Host "##[group]Deploying to AKS" az aks get-credentials -g $rg -n $aksName az aks update --attach-acr $DeploymentOutputs['AZIDENTITY_ACR_NAME'] -g $rg -n $aksName Set-Content -Path "$PSScriptRoot/k8s.yaml" -Value @" @@ -138,3 +165,4 @@ spec: "@ kubectl apply -f "$PSScriptRoot/k8s.yaml" Write-Host "##vso[task.setvariable variable=AZIDENTITY_POD_NAME;]$podName" +Write-Host "##[endgroup]" diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/test-resources.bicep b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/test-resources.bicep index 135feb017..cb3b5f4df 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/test-resources.bicep +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/test-resources.bicep @@ -19,7 +19,10 @@ param location string = resourceGroup().location // https://learn.microsoft.com/azure/role-based-access-control/built-in-roles var acrPull = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d') -var blobReader = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1') +var blobReader = subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' +) resource sa 'Microsoft.Storage/storageAccounts@2021-08-01' = if (deployResources) { kind: 'StorageV2' @@ -60,6 +63,16 @@ resource acrPullContainerInstance 'Microsoft.Authorization/roleAssignments@2022- scope: containerRegistry } +resource acrPullVM 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (deployResources) { + name: guid(resourceGroup().id, acrPull, 'vm') + properties: { + principalId: deployResources ? vm.identity.principalId : '' + principalType: 'ServicePrincipal' + roleDefinitionId: acrPull + } + scope: containerRegistry +} + resource blobRoleUserAssigned 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (deployResources) { scope: saUserAssigned name: guid(resourceGroup().id, blobReader, usermgdid.id) @@ -80,6 +93,16 @@ resource blobRoleFunc 'Microsoft.Authorization/roleAssignments@2022-04-01' = if scope: sa } +resource blobRoleVM 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (deployResources) { + scope: sa + name: guid(resourceGroup().id, blobReader, 'vm') + properties: { + principalId: deployResources ? vm.identity.principalId : '' + roleDefinitionId: blobReader + principalType: 'ServicePrincipal' + } +} + resource containerRegistry 'Microsoft.ContainerRegistry/registries@2023-01-01-preview' = if (deployResources) { location: location name: uniqueString(resourceGroup().id) @@ -215,6 +238,143 @@ resource aks 'Microsoft.ContainerService/managedClusters@2023-06-01' = if (deplo } } +resource publicIP 'Microsoft.Network/publicIPAddresses@2023-05-01' = if (deployResources) { + name: '${baseName}PublicIP' + location: location + sku: { + name: 'Standard' + } + properties: { + publicIPAllocationMethod: 'Static' + } +} + +resource nsg 'Microsoft.Network/networkSecurityGroups@2024-07-01' = if (deployResources) { + name: '${baseName}NSG' + location: location + properties: { + securityRules: [ + { + name: 'AllowHTTP' + properties: { + description: 'Allow HTTP traffic on port 80' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '80' + sourceAddressPrefix: '*' + destinationAddressPrefix: '*' + access: 'Allow' + priority: 1000 + direction: 'Inbound' + } + } + ] + } +} + +resource vnet 'Microsoft.Network/virtualNetworks@2024-07-01' = if (deployResources) { + name: '${baseName}vnet' + location: location + properties: { + addressSpace: { + addressPrefixes: [ + '10.0.0.0/16' + ] + } + subnets: [ + { + name: '${baseName}subnet' + properties: { + addressPrefix: '10.0.0.0/24' + defaultOutboundAccess: false + networkSecurityGroup: { + id: deployResources ? nsg.id : '' + } + } + } + ] + } +} + +resource nic 'Microsoft.Network/networkInterfaces@2024-07-01' = if (deployResources) { + name: '${baseName}NIC' + location: location + properties: { + ipConfigurations: [ + { + name: 'myIPConfig' + properties: { + privateIPAllocationMethod: 'Dynamic' + publicIPAddress: { + id: deployResources ? publicIP.id : '' + } + subnet: { + id: deployResources ? vnet.properties.subnets[0].id : '' + } + } + } + ] + } +} + +resource vm 'Microsoft.Compute/virtualMachines@2024-07-01' = if (deployResources) { + name: '${baseName}vm' + location: location + identity: { + type: 'SystemAssigned, UserAssigned' + userAssignedIdentities: { + '${deployResources ? usermgdid.id: ''}': {} + } + } + properties: { + hardwareProfile: { + vmSize: 'Standard_DS1_v2' + } + osProfile: { + adminUsername: adminUser + computerName: '${baseName}vm' + customData: base64(''' +#cloud-config +package_update: true +packages: + - docker.io +runcmd: + - curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash + - az login --identity --allow-no-subscriptions +''') + linuxConfiguration: { + disablePasswordAuthentication: true + ssh: { + publicKeys: [ + { + path: '/home/${adminUser}/.ssh/authorized_keys' + keyData: sshPubKey + } + ] + } + } + } + networkProfile: { + networkInterfaces: [ + { + id: deployResources ? nic.id : '' + } + ] + } + storageProfile: { + imageReference: { + publisher: 'Canonical' + offer: 'ubuntu-24_04-lts' + sku: 'server' + version: 'latest' + } + osDisk: { + createOption: 'FromImage' + } + } + } +} + output AZIDENTITY_ACR_LOGIN_SERVER string = deployResources ? containerRegistry.properties.loginServer : '' output AZIDENTITY_ACR_NAME string = deployResources ? containerRegistry.name : '' output AZIDENTITY_AKS_NAME string = deployResources ? aks.name : '' @@ -226,3 +386,5 @@ output AZIDENTITY_USER_ASSIGNED_IDENTITY string = deployResources ? usermgdid.id output AZIDENTITY_USER_ASSIGNED_IDENTITY_CLIENT_ID string = deployResources ? usermgdid.properties.clientId : '' output AZIDENTITY_USER_ASSIGNED_IDENTITY_NAME string = deployResources ? usermgdid.name : '' output AZIDENTITY_USER_ASSIGNED_IDENTITY_OBJECT_ID string = deployResources ? usermgdid.properties.principalId : '' +output AZIDENTITY_VM_NAME string = deployResources ? vm.name : '' +output AZIDENTITY_VM_IP string = deployResources ? publicIP.properties.ipAddress : '' diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/version.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/version.go index c3a70c4f2..041f11658 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/version.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/version.go @@ -14,5 +14,5 @@ const ( module = "github.com/Azure/azure-sdk-for-go/sdk/" + component // Version is the semantic version (see http://semver.org) of this module. - version = "v1.11.0" + version = "v1.13.1" ) diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/autorest.md b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/autorest.md deleted file mode 100644 index cb90d76db..000000000 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/autorest.md +++ /dev/null @@ -1,15 +0,0 @@ -### AutoRest Configuration - -> see https://aka.ms/autorest - -``` yaml -azure-arm: true -require: -- https://github.com/Azure/azure-rest-api-specs/blob/86c6306649b02e542117adb46c61e8019dbd78e9/specification/storage/resource-manager/readme.md -- https://github.com/Azure/azure-rest-api-specs/blob/86c6306649b02e542117adb46c61e8019dbd78e9/specification/storage/resource-manager/readme.go.md -license-header: MICROSOFT_MIT_NO_VERSION -module-version: 1.8.1 -modelerfour: - seal-single-value-enum-by-default: true -tag: package-2024-01 -``` diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/CHANGELOG.md b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/CHANGELOG.md similarity index 89% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/CHANGELOG.md rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/CHANGELOG.md index 7be78103b..9b6ea5440 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/CHANGELOG.md +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/CHANGELOG.md @@ -1,5 +1,36 @@ # Release History +## 2.0.0 (2025-09-25) +### Breaking Changes + +- Type of `TriggerParameters.IntervalUnit` has been changed from `*string` to `*IntervalUnit` +- Type of `TriggerParametersUpdate.IntervalUnit` has been changed from `*string` to `*IntervalUnit` + +### Features Added + +- New enum type `IntervalUnit` with values `IntervalUnitDays` +- New enum type `ZonePlacementPolicy` with values `ZonePlacementPolicyAny`, `ZonePlacementPolicyNone` +- New struct `AccountIPv6Endpoints` +- New struct `DualStackEndpointPreference` +- New struct `EncryptionInTransit` +- New struct `NfsSetting` +- New struct `Placement` +- New struct `SKUInformationLocationInfoItem` +- New struct `SmbOAuthSettings` +- New field `Placement`, `Zones` in struct `Account` +- New field `Placement`, `Zones` in struct `AccountCreateParameters` +- New field `DualStackEndpointPreference` in struct `AccountProperties` +- New field `DualStackEndpointPreference` in struct `AccountPropertiesCreateParameters` +- New field `DualStackEndpointPreference` in struct `AccountPropertiesUpdateParameters` +- New field `Placement`, `Zones` in struct `AccountUpdateParameters` +- New field `SmbOAuthSettings` in struct `AzureFilesIdentityBasedAuthentication` +- New field `IPv6Endpoints` in struct `Endpoints` +- New field `IPv6Rules` in struct `NetworkRuleSet` +- New field `Nfs` in struct `ProtocolSettings` +- New field `LocationInfo` in struct `SKUInformation` +- New field `EncryptionInTransit` in struct `SmbSetting` + + ## 1.8.1 (2025-06-30) ### Other Changes diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/LICENSE.txt b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/LICENSE.txt similarity index 100% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/LICENSE.txt rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/LICENSE.txt diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/README.md b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/README.md similarity index 99% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/README.md rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/README.md index 9724799d2..913f0d30d 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/README.md +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/README.md @@ -18,7 +18,7 @@ This project uses [Go modules](https://github.com/golang/go/wiki/Modules) for ve Install the Azure Storage module: ```sh -go get github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage +go get github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2 ``` ## Authorization diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/accounts_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/accounts_client.go similarity index 97% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/accounts_client.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/accounts_client.go index 4597afade..f8a54413f 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/accounts_client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/accounts_client.go @@ -43,7 +43,7 @@ func NewAccountsClient(subscriptionID string, credential azcore.TokenCredential, // BeginAbortHierarchicalNamespaceMigration - Abort live Migration of storage account to enable Hns // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -70,7 +70,7 @@ func (client *AccountsClient) BeginAbortHierarchicalNamespaceMigration(ctx conte // AbortHierarchicalNamespaceMigration - Abort live Migration of storage account to enable Hns // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 func (client *AccountsClient) abortHierarchicalNamespaceMigration(ctx context.Context, resourceGroupName string, accountName string, options *AccountsClientBeginAbortHierarchicalNamespaceMigrationOptions) (*http.Response, error) { var err error const operationName = "AccountsClient.BeginAbortHierarchicalNamespaceMigration" @@ -112,7 +112,7 @@ func (client *AccountsClient) abortHierarchicalNamespaceMigrationCreateRequest(c return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -121,7 +121,7 @@ func (client *AccountsClient) abortHierarchicalNamespaceMigrationCreateRequest(c // CheckNameAvailability - Checks that the storage account name is valid and is not already in use. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. // - options - AccountsClientCheckNameAvailabilityOptions contains the optional parameters for the AccountsClient.CheckNameAvailability @@ -160,7 +160,7 @@ func (client *AccountsClient) checkNameAvailabilityCreateRequest(ctx context.Con return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, accountName); err != nil { @@ -184,7 +184,7 @@ func (client *AccountsClient) checkNameAvailabilityHandleResponse(resp *http.Res // set of properties, the request will succeed. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -213,7 +213,7 @@ func (client *AccountsClient) BeginCreate(ctx context.Context, resourceGroupName // set of properties, the request will succeed. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 func (client *AccountsClient) create(ctx context.Context, resourceGroupName string, accountName string, parameters AccountCreateParameters, options *AccountsClientBeginCreateOptions) (*http.Response, error) { var err error const operationName = "AccountsClient.BeginCreate" @@ -255,7 +255,7 @@ func (client *AccountsClient) createCreateRequest(ctx context.Context, resourceG return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, parameters); err != nil { @@ -270,7 +270,7 @@ func (client *AccountsClient) createCreateRequest(ctx context.Context, resourceG // synchronously across three Azure availability zones in the primary region. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -301,7 +301,7 @@ func (client *AccountsClient) BeginCustomerInitiatedMigration(ctx context.Contex // synchronously across three Azure availability zones in the primary region. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 func (client *AccountsClient) customerInitiatedMigration(ctx context.Context, resourceGroupName string, accountName string, parameters AccountMigration, options *AccountsClientBeginCustomerInitiatedMigrationOptions) (*http.Response, error) { var err error const operationName = "AccountsClient.BeginCustomerInitiatedMigration" @@ -343,7 +343,7 @@ func (client *AccountsClient) customerInitiatedMigrationCreateRequest(ctx contex return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, parameters); err != nil { @@ -355,7 +355,7 @@ func (client *AccountsClient) customerInitiatedMigrationCreateRequest(ctx contex // Delete - Deletes a storage account in Microsoft Azure. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -401,7 +401,7 @@ func (client *AccountsClient) deleteCreateRequest(ctx context.Context, resourceG return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() return req, nil } @@ -417,7 +417,7 @@ func (client *AccountsClient) deleteCreateRequest(ctx context.Context, resourceG // 'Planned'. Learn more about the failover options here- https://learn.microsoft.com/azure/storage/common/storage-disaster-recovery-guidance // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -451,7 +451,7 @@ func (client *AccountsClient) BeginFailover(ctx context.Context, resourceGroupNa // 'Planned'. Learn more about the failover options here- https://learn.microsoft.com/azure/storage/common/storage-disaster-recovery-guidance // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 func (client *AccountsClient) failover(ctx context.Context, resourceGroupName string, accountName string, options *AccountsClientBeginFailoverOptions) (*http.Response, error) { var err error const operationName = "AccountsClient.BeginFailover" @@ -493,7 +493,7 @@ func (client *AccountsClient) failoverCreateRequest(ctx context.Context, resourc return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") if options != nil && options.FailoverType != nil { reqQP.Set("failoverType", "Planned") } @@ -504,7 +504,7 @@ func (client *AccountsClient) failoverCreateRequest(ctx context.Context, resourc // GetCustomerInitiatedMigration - Gets the status of the ongoing migration for the specified storage account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -557,7 +557,7 @@ func (client *AccountsClient) getCustomerInitiatedMigrationCreateRequest(ctx con return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -576,7 +576,7 @@ func (client *AccountsClient) getCustomerInitiatedMigrationHandleResponse(resp * // and account status. The ListKeys operation should be used to retrieve storage keys. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -626,7 +626,7 @@ func (client *AccountsClient) getPropertiesCreateRequest(ctx context.Context, re if options != nil && options.Expand != nil { reqQP.Set("$expand", string(*options.Expand)) } - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -644,7 +644,7 @@ func (client *AccountsClient) getPropertiesHandleResponse(resp *http.Response) ( // BeginHierarchicalNamespaceMigration - Live Migration of storage account to enable Hns // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -674,7 +674,7 @@ func (client *AccountsClient) BeginHierarchicalNamespaceMigration(ctx context.Co // HierarchicalNamespaceMigration - Live Migration of storage account to enable Hns // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 func (client *AccountsClient) hierarchicalNamespaceMigration(ctx context.Context, resourceGroupName string, accountName string, requestType string, options *AccountsClientBeginHierarchicalNamespaceMigrationOptions) (*http.Response, error) { var err error const operationName = "AccountsClient.BeginHierarchicalNamespaceMigration" @@ -716,7 +716,7 @@ func (client *AccountsClient) hierarchicalNamespaceMigrationCreateRequest(ctx co return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") reqQP.Set("requestType", requestType) req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} @@ -726,7 +726,7 @@ func (client *AccountsClient) hierarchicalNamespaceMigrationCreateRequest(ctx co // NewListPager - Lists all the storage accounts available under the subscription. Note that storage keys are not returned; // use the ListKeys operation for this. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - options - AccountsClientListOptions contains the optional parameters for the AccountsClient.NewListPager method. func (client *AccountsClient) NewListPager(options *AccountsClientListOptions) *runtime.Pager[AccountsClientListResponse] { return runtime.NewPager(runtime.PagingHandler[AccountsClientListResponse]{ @@ -763,7 +763,7 @@ func (client *AccountsClient) listCreateRequest(ctx context.Context, _ *Accounts return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -781,7 +781,7 @@ func (client *AccountsClient) listHandleResponse(resp *http.Response) (AccountsC // ListAccountSAS - List SAS credentials of a storage account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -829,7 +829,7 @@ func (client *AccountsClient) listAccountSASCreateRequest(ctx context.Context, r return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, parameters); err != nil { @@ -850,7 +850,7 @@ func (client *AccountsClient) listAccountSASHandleResponse(resp *http.Response) // NewListByResourceGroupPager - Lists all the storage accounts available under the given resource group. Note that storage // keys are not returned; use the ListKeys operation for this. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - options - AccountsClientListByResourceGroupOptions contains the optional parameters for the AccountsClient.NewListByResourceGroupPager // method. @@ -893,7 +893,7 @@ func (client *AccountsClient) listByResourceGroupCreateRequest(ctx context.Conte return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -911,7 +911,7 @@ func (client *AccountsClient) listByResourceGroupHandleResponse(resp *http.Respo // ListKeys - Lists the access keys or Kerberos keys (if active directory enabled) for the specified storage account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -961,7 +961,7 @@ func (client *AccountsClient) listKeysCreateRequest(ctx context.Context, resourc if options != nil && options.Expand != nil { reqQP.Set("$expand", "kerb") } - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -979,7 +979,7 @@ func (client *AccountsClient) listKeysHandleResponse(resp *http.Response) (Accou // ListServiceSAS - List service SAS credentials of a specific resource. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -1027,7 +1027,7 @@ func (client *AccountsClient) listServiceSASCreateRequest(ctx context.Context, r return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, parameters); err != nil { @@ -1048,7 +1048,7 @@ func (client *AccountsClient) listServiceSASHandleResponse(resp *http.Response) // RegenerateKey - Regenerates one of the access keys or Kerberos keys for the specified storage account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -1096,7 +1096,7 @@ func (client *AccountsClient) regenerateKeyCreateRequest(ctx context.Context, re return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, regenerateKey); err != nil { @@ -1117,7 +1117,7 @@ func (client *AccountsClient) regenerateKeyHandleResponse(resp *http.Response) ( // BeginRestoreBlobRanges - Restore blobs in the specified blob ranges // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -1145,7 +1145,7 @@ func (client *AccountsClient) BeginRestoreBlobRanges(ctx context.Context, resour // RestoreBlobRanges - Restore blobs in the specified blob ranges // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 func (client *AccountsClient) restoreBlobRanges(ctx context.Context, resourceGroupName string, accountName string, parameters BlobRestoreParameters, options *AccountsClientBeginRestoreBlobRangesOptions) (*http.Response, error) { var err error const operationName = "AccountsClient.BeginRestoreBlobRanges" @@ -1187,7 +1187,7 @@ func (client *AccountsClient) restoreBlobRangesCreateRequest(ctx context.Context return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, parameters); err != nil { @@ -1199,7 +1199,7 @@ func (client *AccountsClient) restoreBlobRangesCreateRequest(ctx context.Context // RevokeUserDelegationKeys - Revoke user delegation keys. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -1246,7 +1246,7 @@ func (client *AccountsClient) revokeUserDelegationKeysCreateRequest(ctx context. return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() return req, nil } @@ -1260,7 +1260,7 @@ func (client *AccountsClient) revokeUserDelegationKeysCreateRequest(ctx context. // location and name of the storage account cannot be changed after creation. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -1308,7 +1308,7 @@ func (client *AccountsClient) updateCreateRequest(ctx context.Context, resourceG return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, parameters); err != nil { diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/assets.json b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/assets.json similarity index 100% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/assets.json rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/assets.json diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/autorest.md b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/autorest.md new file mode 100644 index 000000000..6bbac5a2c --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/autorest.md @@ -0,0 +1,15 @@ +### AutoRest Configuration + +> see https://aka.ms/autorest + +``` yaml +azure-arm: true +require: +- https://github.com/Azure/azure-rest-api-specs/blob/260ed6a52537921f53a18ffaf4020e3b4d510367/specification/storage/resource-manager/readme.md +- https://github.com/Azure/azure-rest-api-specs/blob/260ed6a52537921f53a18ffaf4020e3b4d510367/specification/storage/resource-manager/readme.go.md +license-header: MICROSOFT_MIT_NO_VERSION +module-version: 2.0.0 +modelerfour: + seal-single-value-enum-by-default: true +tag: package-2025-01 +``` diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/blobcontainers_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/blobcontainers_client.go similarity index 98% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/blobcontainers_client.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/blobcontainers_client.go index b01dc92d1..f60a79d58 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/blobcontainers_client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/blobcontainers_client.go @@ -44,7 +44,7 @@ func NewBlobContainersClient(subscriptionID string, credential azcore.TokenCrede // clears out only the specified tags in the request. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -100,7 +100,7 @@ func (client *BlobContainersClient) clearLegalHoldCreateRequest(ctx context.Cont return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, legalHold); err != nil { @@ -123,7 +123,7 @@ func (client *BlobContainersClient) clearLegalHoldHandleResponse(resp *http.Resp // contained by the container. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -178,7 +178,7 @@ func (client *BlobContainersClient) createCreateRequest(ctx context.Context, res return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, blobContainer); err != nil { @@ -200,7 +200,7 @@ func (client *BlobContainersClient) createHandleResponse(resp *http.Response) (B // but not required for this operation. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -256,7 +256,7 @@ func (client *BlobContainersClient) createOrUpdateImmutabilityPolicyCreateReques return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if options != nil && options.IfMatch != nil { @@ -286,7 +286,7 @@ func (client *BlobContainersClient) createOrUpdateImmutabilityPolicyHandleRespon // Delete - Deletes specified container under its account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -339,7 +339,7 @@ func (client *BlobContainersClient) deleteCreateRequest(ctx context.Context, res return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() return req, nil } @@ -350,7 +350,7 @@ func (client *BlobContainersClient) deleteCreateRequest(ctx context.Context, res // container. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -409,7 +409,7 @@ func (client *BlobContainersClient) deleteImmutabilityPolicyCreateRequest(ctx co return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} req.Raw().Header["If-Match"] = []string{ifMatch} @@ -432,7 +432,7 @@ func (client *BlobContainersClient) deleteImmutabilityPolicyHandleResponse(resp // allowed on a Locked policy will be this action. ETag in If-Match is required for this operation. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -490,7 +490,7 @@ func (client *BlobContainersClient) extendImmutabilityPolicyCreateRequest(ctx co return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} req.Raw().Header["If-Match"] = []string{ifMatch} @@ -518,7 +518,7 @@ func (client *BlobContainersClient) extendImmutabilityPolicyHandleResponse(resp // Get - Gets properties of a specified container. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -572,7 +572,7 @@ func (client *BlobContainersClient) getCreateRequest(ctx context.Context, resour return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -591,7 +591,7 @@ func (client *BlobContainersClient) getHandleResponse(resp *http.Response) (Blob // body. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -647,7 +647,7 @@ func (client *BlobContainersClient) getImmutabilityPolicyCreateRequest(ctx conte return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if options != nil && options.IfMatch != nil { @@ -672,7 +672,7 @@ func (client *BlobContainersClient) getImmutabilityPolicyHandleResponse(resp *ht // can be 15 to 60 seconds, or can be infinite. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -726,7 +726,7 @@ func (client *BlobContainersClient) leaseCreateRequest(ctx context.Context, reso return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if options != nil && options.Parameters != nil { @@ -750,7 +750,7 @@ func (client *BlobContainersClient) leaseHandleResponse(resp *http.Response) (Bl // NewListPager - Lists all containers and does not support a prefix like data plane. Also SRP today does not return continuation // token. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -807,7 +807,7 @@ func (client *BlobContainersClient) listCreateRequest(ctx context.Context, resou if options != nil && options.Maxpagesize != nil { reqQP.Set("$maxpagesize", *options.Maxpagesize) } - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -826,7 +826,7 @@ func (client *BlobContainersClient) listHandleResponse(resp *http.Response) (Blo // action. ETag in If-Match is required for this operation. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -884,7 +884,7 @@ func (client *BlobContainersClient) lockImmutabilityPolicyCreateRequest(ctx cont return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} req.Raw().Header["If-Match"] = []string{ifMatch} @@ -908,7 +908,7 @@ func (client *BlobContainersClient) lockImmutabilityPolicyHandleResponse(resp *h // unlocked state, Account level versioning must be enabled and there should be no Legal hold on the container. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -940,7 +940,7 @@ func (client *BlobContainersClient) BeginObjectLevelWorm(ctx context.Context, re // unlocked state, Account level versioning must be enabled and there should be no Legal hold on the container. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 func (client *BlobContainersClient) objectLevelWorm(ctx context.Context, resourceGroupName string, accountName string, containerName string, options *BlobContainersClientBeginObjectLevelWormOptions) (*http.Response, error) { var err error const operationName = "BlobContainersClient.BeginObjectLevelWorm" @@ -986,7 +986,7 @@ func (client *BlobContainersClient) objectLevelWormCreateRequest(ctx context.Con return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -996,7 +996,7 @@ func (client *BlobContainersClient) objectLevelWormCreateRequest(ctx context.Con // pattern and does not clear out the existing tags that are not specified in the request. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -1052,7 +1052,7 @@ func (client *BlobContainersClient) setLegalHoldCreateRequest(ctx context.Contex return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, legalHold); err != nil { @@ -1074,7 +1074,7 @@ func (client *BlobContainersClient) setLegalHoldHandleResponse(resp *http.Respon // Update fails if the specified container doesn't already exist. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -1129,7 +1129,7 @@ func (client *BlobContainersClient) updateCreateRequest(ctx context.Context, res return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, blobContainer); err != nil { diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/blobinventorypolicies_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/blobinventorypolicies_client.go similarity index 98% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/blobinventorypolicies_client.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/blobinventorypolicies_client.go index d8cd8d27e..e2842b82c 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/blobinventorypolicies_client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/blobinventorypolicies_client.go @@ -43,7 +43,7 @@ func NewBlobInventoryPoliciesClient(subscriptionID string, credential azcore.Tok // CreateOrUpdate - Sets the blob inventory policy to the specified storage account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -97,7 +97,7 @@ func (client *BlobInventoryPoliciesClient) createOrUpdateCreateRequest(ctx conte return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, properties); err != nil { @@ -118,7 +118,7 @@ func (client *BlobInventoryPoliciesClient) createOrUpdateHandleResponse(resp *ht // Delete - Deletes the blob inventory policy associated with the specified storage account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -170,7 +170,7 @@ func (client *BlobInventoryPoliciesClient) deleteCreateRequest(ctx context.Conte return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -179,7 +179,7 @@ func (client *BlobInventoryPoliciesClient) deleteCreateRequest(ctx context.Conte // Get - Gets the blob inventory policy associated with the specified storage account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -232,7 +232,7 @@ func (client *BlobInventoryPoliciesClient) getCreateRequest(ctx context.Context, return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -249,7 +249,7 @@ func (client *BlobInventoryPoliciesClient) getHandleResponse(resp *http.Response // NewListPager - Gets the blob inventory policy associated with the specified storage account. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -299,7 +299,7 @@ func (client *BlobInventoryPoliciesClient) listCreateRequest(ctx context.Context return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/blobservices_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/blobservices_client.go similarity index 98% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/blobservices_client.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/blobservices_client.go index 21a7346bc..009273985 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/blobservices_client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/blobservices_client.go @@ -44,7 +44,7 @@ func NewBlobServicesClient(subscriptionID string, credential azcore.TokenCredent // and CORS (Cross-Origin Resource Sharing) rules. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -93,7 +93,7 @@ func (client *BlobServicesClient) getServicePropertiesCreateRequest(ctx context. return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -110,7 +110,7 @@ func (client *BlobServicesClient) getServicePropertiesHandleResponse(resp *http. // NewListPager - List blob services of storage account. It returns a collection of one object named default. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -159,7 +159,7 @@ func (client *BlobServicesClient) listCreateRequest(ctx context.Context, resourc return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -178,7 +178,7 @@ func (client *BlobServicesClient) listHandleResponse(resp *http.Response) (BlobS // and CORS (Cross-Origin Resource Sharing) rules. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -229,7 +229,7 @@ func (client *BlobServicesClient) setServicePropertiesCreateRequest(ctx context. return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, parameters); err != nil { diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/build.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/build.go similarity index 100% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/build.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/build.go diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/ci.yml b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/ci.yml similarity index 100% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/ci.yml rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/ci.yml diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/client_factory.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/client_factory.go similarity index 100% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/client_factory.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/client_factory.go diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/constants.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/constants.go similarity index 97% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/constants.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/constants.go index 24a0bd0dd..c9aa130a5 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/constants.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/constants.go @@ -5,11 +5,6 @@ package armstorage -const ( - moduleName = "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage" - moduleVersion = "v1.8.1" -) - // AccessTier - Required for storage accounts where kind = BlobStorage. The access tier is used for billing. The 'Premium' // access tier is the default value for premium block blobs storage account type and it cannot // be changed for the premium block blobs storage account type. @@ -70,7 +65,10 @@ func PossibleAccountStatusValues() []AccountStatus { } } -// ActiveDirectoryPropertiesAccountType - Specifies the Active Directory account type for Azure Storage. +// ActiveDirectoryPropertiesAccountType - Specifies the Active Directory account type for Azure Storage. If directoryServiceOptions +// is set to AD (AD DS authentication), this property is optional. If provided, samAccountName should also be +// provided. For directoryServiceOptions AADDS (Entra DS authentication) or AADKERB (Entra authentication), this property +// can be omitted. type ActiveDirectoryPropertiesAccountType string const ( @@ -470,6 +468,22 @@ func PossibleImmutabilityPolicyUpdateTypeValues() []ImmutabilityPolicyUpdateType } } +// IntervalUnit - Run interval unit of task execution. This is a required field when ExecutionTrigger.properties.type is 'OnSchedule'; +// this property should not be present when ExecutionTrigger.properties.type is +// 'RunOnce' +type IntervalUnit string + +const ( + IntervalUnitDays IntervalUnit = "Days" +) + +// PossibleIntervalUnitValues returns the possible values for the IntervalUnit const type. +func PossibleIntervalUnitValues() []IntervalUnit { + return []IntervalUnit{ + IntervalUnitDays, + } +} + // InventoryRuleType - The valid value is Inventory type InventoryRuleType string @@ -1454,3 +1468,19 @@ func PossibleUsageUnitValues() []UsageUnit { UsageUnitSeconds, } } + +// ZonePlacementPolicy - The availability zone pinning policy for the storage account. +type ZonePlacementPolicy string + +const ( + ZonePlacementPolicyAny ZonePlacementPolicy = "Any" + ZonePlacementPolicyNone ZonePlacementPolicy = "None" +) + +// PossibleZonePlacementPolicyValues returns the possible values for the ZonePlacementPolicy const type. +func PossibleZonePlacementPolicyValues() []ZonePlacementPolicy { + return []ZonePlacementPolicy{ + ZonePlacementPolicyAny, + ZonePlacementPolicyNone, + } +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/deletedaccounts_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/deletedaccounts_client.go similarity index 97% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/deletedaccounts_client.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/deletedaccounts_client.go index ec49f1385..a5d6216e1 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/deletedaccounts_client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/deletedaccounts_client.go @@ -43,7 +43,7 @@ func NewDeletedAccountsClient(subscriptionID string, credential azcore.TokenCred // Get - Get properties of specified deleted account resource. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - deletedAccountName - Name of the deleted storage account. // - location - The location of the deleted storage account. // - options - DeletedAccountsClientGetOptions contains the optional parameters for the DeletedAccountsClient.Get method. @@ -89,7 +89,7 @@ func (client *DeletedAccountsClient) getCreateRequest(ctx context.Context, delet return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -106,7 +106,7 @@ func (client *DeletedAccountsClient) getHandleResponse(resp *http.Response) (Del // NewListPager - Lists deleted accounts under the subscription. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - options - DeletedAccountsClientListOptions contains the optional parameters for the DeletedAccountsClient.NewListPager // method. func (client *DeletedAccountsClient) NewListPager(options *DeletedAccountsClientListOptions) *runtime.Pager[DeletedAccountsClientListResponse] { @@ -144,7 +144,7 @@ func (client *DeletedAccountsClient) listCreateRequest(ctx context.Context, _ *D return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/encryptionscopes_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/encryptionscopes_client.go similarity index 98% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/encryptionscopes_client.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/encryptionscopes_client.go index 71e798515..f1dd4fdc5 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/encryptionscopes_client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/encryptionscopes_client.go @@ -44,7 +44,7 @@ func NewEncryptionScopesClient(subscriptionID string, credential azcore.TokenCre // Get - Returns the properties for the specified encryption scope. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -98,7 +98,7 @@ func (client *EncryptionScopesClient) getCreateRequest(ctx context.Context, reso return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -115,7 +115,7 @@ func (client *EncryptionScopesClient) getHandleResponse(resp *http.Response) (En // NewListPager - Lists all the encryption scopes available under the specified storage account. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -173,7 +173,7 @@ func (client *EncryptionScopesClient) listCreateRequest(ctx context.Context, res if options != nil && options.Maxpagesize != nil { reqQP.Set("$maxpagesize", strconv.FormatInt(int64(*options.Maxpagesize), 10)) } - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -192,7 +192,7 @@ func (client *EncryptionScopesClient) listHandleResponse(resp *http.Response) (E // does not already exist. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -247,7 +247,7 @@ func (client *EncryptionScopesClient) patchCreateRequest(ctx context.Context, re return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, encryptionScope); err != nil { @@ -270,7 +270,7 @@ func (client *EncryptionScopesClient) patchHandleResponse(resp *http.Response) ( // encryption scope properties will be updated per the specified request. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -325,7 +325,7 @@ func (client *EncryptionScopesClient) putCreateRequest(ctx context.Context, reso return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, encryptionScope); err != nil { diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/fileservices_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/fileservices_client.go similarity index 97% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/fileservices_client.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/fileservices_client.go index 0ce4ce544..3a3ed1d42 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/fileservices_client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/fileservices_client.go @@ -45,7 +45,7 @@ func NewFileServicesClient(subscriptionID string, credential azcore.TokenCredent // Sharing) rules. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -94,7 +94,7 @@ func (client *FileServicesClient) getServicePropertiesCreateRequest(ctx context. return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -113,7 +113,7 @@ func (client *FileServicesClient) getServicePropertiesHandleResponse(resp *http. // used in recommendations and bursting formula. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -163,7 +163,7 @@ func (client *FileServicesClient) getServiceUsageCreateRequest(ctx context.Conte return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -181,7 +181,7 @@ func (client *FileServicesClient) getServiceUsageHandleResponse(resp *http.Respo // List - List all file services in storage accounts // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -228,7 +228,7 @@ func (client *FileServicesClient) listCreateRequest(ctx context.Context, resourc return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -245,7 +245,7 @@ func (client *FileServicesClient) listHandleResponse(resp *http.Response) (FileS // NewListServiceUsagesPager - Gets the usages of file service in storage account. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -298,7 +298,7 @@ func (client *FileServicesClient) listServiceUsagesCreateRequest(ctx context.Con if options != nil && options.Maxpagesize != nil { reqQP.Set("$maxpagesize", strconv.FormatInt(int64(*options.Maxpagesize), 10)) } - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -317,7 +317,7 @@ func (client *FileServicesClient) listServiceUsagesHandleResponse(resp *http.Res // Sharing) rules. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -367,7 +367,7 @@ func (client *FileServicesClient) setServicePropertiesCreateRequest(ctx context. return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, parameters); err != nil { diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/fileshares_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/fileshares_client.go similarity index 98% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/fileshares_client.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/fileshares_client.go index a063e282f..17a758997 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/fileshares_client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/fileshares_client.go @@ -45,7 +45,7 @@ func NewFileSharesClient(subscriptionID string, credential azcore.TokenCredentia // the share. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -103,7 +103,7 @@ func (client *FileSharesClient) createCreateRequest(ctx context.Context, resourc if options != nil && options.Expand != nil { reqQP.Set("$expand", *options.Expand) } - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, fileShare); err != nil { @@ -124,7 +124,7 @@ func (client *FileSharesClient) createHandleResponse(resp *http.Response) (FileS // Delete - Deletes specified share under its account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -180,7 +180,7 @@ func (client *FileSharesClient) deleteCreateRequest(ctx context.Context, resourc if options != nil && options.Include != nil { reqQP.Set("$include", *options.Include) } - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if options != nil && options.XMSSnapshot != nil { @@ -192,7 +192,7 @@ func (client *FileSharesClient) deleteCreateRequest(ctx context.Context, resourc // Get - Gets properties of a specified share. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -249,7 +249,7 @@ func (client *FileSharesClient) getCreateRequest(ctx context.Context, resourceGr if options != nil && options.Expand != nil { reqQP.Set("$expand", *options.Expand) } - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if options != nil && options.XMSSnapshot != nil { @@ -271,7 +271,7 @@ func (client *FileSharesClient) getHandleResponse(resp *http.Response) (FileShar // be 15 to 60 seconds, or can be infinite. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -325,7 +325,7 @@ func (client *FileSharesClient) leaseCreateRequest(ctx context.Context, resource return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if options != nil && options.XMSSnapshot != nil { @@ -354,7 +354,7 @@ func (client *FileSharesClient) leaseHandleResponse(resp *http.Response) (FileSh // NewListPager - Lists all shares. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -411,7 +411,7 @@ func (client *FileSharesClient) listCreateRequest(ctx context.Context, resourceG if options != nil && options.Maxpagesize != nil { reqQP.Set("$maxpagesize", *options.Maxpagesize) } - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -429,7 +429,7 @@ func (client *FileSharesClient) listHandleResponse(resp *http.Response) (FileSha // Restore - Restore a file share within a valid retention days if share soft delete is enabled // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -482,7 +482,7 @@ func (client *FileSharesClient) restoreCreateRequest(ctx context.Context, resour return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, deletedShare); err != nil { @@ -495,7 +495,7 @@ func (client *FileSharesClient) restoreCreateRequest(ctx context.Context, resour // Update fails if the specified share does not already exist. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -550,7 +550,7 @@ func (client *FileSharesClient) updateCreateRequest(ctx context.Context, resourc return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, fileShare); err != nil { diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/localusers_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/localusers_client.go similarity index 97% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/localusers_client.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/localusers_client.go index 35c35f50f..2201e3ecc 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/localusers_client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/localusers_client.go @@ -45,7 +45,7 @@ func NewLocalUsersClient(subscriptionID string, credential azcore.TokenCredentia // enablement and extended groups cannot be set with other properties. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -100,7 +100,7 @@ func (client *LocalUsersClient) createOrUpdateCreateRequest(ctx context.Context, return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, properties); err != nil { @@ -121,7 +121,7 @@ func (client *LocalUsersClient) createOrUpdateHandleResponse(resp *http.Response // Delete - Deletes the local user associated with the specified storage account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -173,7 +173,7 @@ func (client *LocalUsersClient) deleteCreateRequest(ctx context.Context, resourc return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -182,7 +182,7 @@ func (client *LocalUsersClient) deleteCreateRequest(ctx context.Context, resourc // Get - Get the local user of the storage account by username. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -235,7 +235,7 @@ func (client *LocalUsersClient) getCreateRequest(ctx context.Context, resourceGr return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -252,7 +252,7 @@ func (client *LocalUsersClient) getHandleResponse(resp *http.Response) (LocalUse // NewListPager - List the local users associated with the storage account. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -310,7 +310,7 @@ func (client *LocalUsersClient) listCreateRequest(ctx context.Context, resourceG if options != nil && options.Maxpagesize != nil { reqQP.Set("$maxpagesize", strconv.FormatInt(int64(*options.Maxpagesize), 10)) } - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -328,7 +328,7 @@ func (client *LocalUsersClient) listHandleResponse(resp *http.Response) (LocalUs // ListKeys - List SSH authorized keys and shared key of the local user. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -381,7 +381,7 @@ func (client *LocalUsersClient) listKeysCreateRequest(ctx context.Context, resou return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -399,7 +399,7 @@ func (client *LocalUsersClient) listKeysHandleResponse(resp *http.Response) (Loc // RegeneratePassword - Regenerate the local user SSH password. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -453,7 +453,7 @@ func (client *LocalUsersClient) regeneratePasswordCreateRequest(ctx context.Cont return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/managementpolicies_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/managementpolicies_client.go similarity index 98% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/managementpolicies_client.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/managementpolicies_client.go index ca9da9f0a..f4715d478 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/managementpolicies_client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/managementpolicies_client.go @@ -43,7 +43,7 @@ func NewManagementPoliciesClient(subscriptionID string, credential azcore.TokenC // CreateOrUpdate - Sets the managementpolicy to the specified storage account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -97,7 +97,7 @@ func (client *ManagementPoliciesClient) createOrUpdateCreateRequest(ctx context. return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, properties); err != nil { @@ -118,7 +118,7 @@ func (client *ManagementPoliciesClient) createOrUpdateHandleResponse(resp *http. // Delete - Deletes the managementpolicy associated with the specified storage account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -170,7 +170,7 @@ func (client *ManagementPoliciesClient) deleteCreateRequest(ctx context.Context, return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() return req, nil } @@ -178,7 +178,7 @@ func (client *ManagementPoliciesClient) deleteCreateRequest(ctx context.Context, // Get - Gets the managementpolicy associated with the specified storage account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -230,7 +230,7 @@ func (client *ManagementPoliciesClient) getCreateRequest(ctx context.Context, re return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/models.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/models.go similarity index 95% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/models.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/models.go index 15a62038b..4eed2d7ef 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/models.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/models.go @@ -29,12 +29,18 @@ type Account struct { // The identity of the resource. Identity *Identity + // Optional. Gets or sets the zonal placement details for the storage account. + Placement *Placement + // Properties of the storage account. Properties *AccountProperties // Resource tags. Tags map[string]*string + // Optional. Gets or sets the pinned logical availability zone for the storage account. + Zones []*string + // READ-ONLY; Fully qualified resource ID for the resource. Ex - /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName} ID *string @@ -81,6 +87,9 @@ type AccountCreateParameters struct { // The identity of the resource. Identity *Identity + // Optional. Gets or sets the zonal placement details for the storage account. + Placement *Placement + // The parameters used to create the storage account. Properties *AccountPropertiesCreateParameters @@ -89,6 +98,37 @@ type AccountCreateParameters struct { // resource. Each tag must have a key with a length no greater than 128 characters and a value with a length no greater than // 256 characters. Tags map[string]*string + + // Optional. Gets or sets the pinned logical availability zone for the storage account. + Zones []*string +} + +// AccountIPv6Endpoints - The URIs that are used to perform a retrieval of a public blob, queue, table, web or dfs object +// via an IPv6 endpoint. +type AccountIPv6Endpoints struct { + // Gets the internet routing storage endpoints + InternetEndpoints *AccountInternetEndpoints + + // Gets the microsoft routing storage endpoints. + MicrosoftEndpoints *AccountMicrosoftEndpoints + + // READ-ONLY; Gets the blob endpoint. + Blob *string + + // READ-ONLY; Gets the dfs endpoint. + Dfs *string + + // READ-ONLY; Gets the file endpoint. + File *string + + // READ-ONLY; Gets the queue endpoint. + Queue *string + + // READ-ONLY; Gets the table endpoint. + Table *string + + // READ-ONLY; Gets the web endpoint. + Web *string } // AccountImmutabilityPolicyProperties - This defines account-level immutability policy properties. @@ -196,7 +236,7 @@ type AccountMicrosoftEndpoints struct { // AccountMigration - The parameters or status associated with an ongoing or enqueued storage account migration in order to // update its current SKU or region. type AccountMigration struct { - // REQUIRED; The properties of a storage account’s ongoing or enqueued migration. + // REQUIRED; The properties of a storage account's ongoing or enqueued migration. StorageAccountMigrationDetails *AccountMigrationProperties // current value is 'default' for customer initiated migration @@ -209,7 +249,7 @@ type AccountMigration struct { ID *string } -// AccountMigrationProperties - The properties of a storage account’s ongoing or enqueued migration. +// AccountMigrationProperties - The properties of a storage account's ongoing or enqueued migration. type AccountMigrationProperties struct { // REQUIRED; Target sku name for the account TargetSKUName *SKUName @@ -255,6 +295,9 @@ type AccountProperties struct { // for this property. DefaultToOAuthAuthentication *bool + // Maintains information about the Internet protocol opted by the user. + DualStackEndpointPreference *DualStackEndpointPreference + // Enables extended group support with local users feature, if set to true EnableExtendedGroups *bool @@ -408,6 +451,9 @@ type AccountPropertiesCreateParameters struct { // for this property. DefaultToOAuthAuthentication *bool + // Maintains information about the Internet protocol opted by the user. + DualStackEndpointPreference *DualStackEndpointPreference + // Enables extended group support with local users feature, if set to true EnableExtendedGroups *bool @@ -498,6 +544,9 @@ type AccountPropertiesUpdateParameters struct { // for this property. DefaultToOAuthAuthentication *bool + // Maintains information about the Internet protocol opted by the user. + DualStackEndpointPreference *DualStackEndpointPreference + // Enables extended group support with local users feature, if set to true EnableExtendedGroups *bool @@ -601,6 +650,9 @@ type AccountUpdateParameters struct { // Optional. Indicates the type of storage account. Currently only StorageV2 value supported by server. Kind *Kind + // Optional. Gets or sets the zonal placement details for the storage account. + Placement *Placement + // The parameters used when updating a storage account. Properties *AccountPropertiesUpdateParameters @@ -612,6 +664,9 @@ type AccountUpdateParameters struct { // resource (across resource groups). A maximum of 15 tags can be provided for a // resource. Each tag must have a key no greater in length than 128 characters and a value no greater in length than 256 characters. Tags map[string]*string + + // Optional. Gets or sets the pinned logical availability zone for the storage account. + Zones []*string } // AccountUsage - Usage of provisioned storage, IOPS, bandwidth and number of file shares across all live shares and soft-deleted @@ -644,28 +699,47 @@ type AccountUsageElements struct { // ActiveDirectoryProperties - Settings properties for Active Directory (AD). type ActiveDirectoryProperties struct { - // REQUIRED; Specifies the domain GUID. - DomainGUID *string - - // REQUIRED; Specifies the primary domain that the AD DNS server is authoritative for. - DomainName *string - - // Specifies the Active Directory account type for Azure Storage. + // Specifies the Active Directory account type for Azure Storage. If directoryServiceOptions is set to AD (AD DS authentication), + // this property is optional. If provided, samAccountName should also be + // provided. For directoryServiceOptions AADDS (Entra DS authentication) or AADKERB (Entra authentication), this property + // can be omitted. AccountType *ActiveDirectoryPropertiesAccountType - // Specifies the security identifier (SID) for Azure Storage. + // Specifies the security identifier (SID) for Azure Storage. If directoryServiceOptions is set to AD (AD DS authentication), + // this property is required. Otherwise, it can be omitted. AzureStorageSid *string - // Specifies the security identifier (SID). + // Specifies the domain GUID. If directoryServiceOptions is set to AD (AD DS authentication), this property is required. If + // directoryServiceOptions is set to AADDS (Entra DS authentication), this + // property can be omitted. If directoryServiceOptions is set to AADKERB (Entra authentication), this property is optional; + // it is needed to support configuration of directory- and file-level permissions + // via Windows File Explorer, but is not required for authentication. + DomainGUID *string + + // Specifies the primary domain that the AD DNS server is authoritative for. This property is required if directoryServiceOptions + // is set to AD (AD DS authentication). If directoryServiceOptions is set to + // AADDS (Entra DS authentication), providing this property is optional, as it will be inferred automatically if omitted. + // If directoryServiceOptions is set to AADKERB (Entra authentication), this + // property is optional; it is needed to support configuration of directory- and file-level permissions via Windows File Explorer, + // but is not required for authentication. + DomainName *string + + // Specifies the security identifier (SID) of the AD domain. If directoryServiceOptions is set to AD (AD DS authentication), + // this property is required. Otherwise, it can be omitted. DomainSid *string - // Specifies the Active Directory forest to get. + // Specifies the Active Directory forest to get. If directoryServiceOptions is set to AD (AD DS authentication), this property + // is required. Otherwise, it can be omitted. ForestName *string - // Specifies the NetBIOS domain name. + // Specifies the NetBIOS domain name. If directoryServiceOptions is set to AD (AD DS authentication), this property is required. + // Otherwise, it can be omitted. NetBiosDomainName *string - // Specifies the Active Directory SAMAccountName for Azure Storage. + // Specifies the Active Directory SAMAccountName for Azure Storage. If directoryServiceOptions is set to AD (AD DS authentication), + // this property is optional. If provided, accountType should also be + // provided. For directoryServiceOptions AADDS (Entra DS authentication) or AADKERB (Entra authentication), this property + // can be omitted. SamAccountName *string } @@ -689,11 +763,16 @@ type AzureFilesIdentityBasedAuthentication struct { // REQUIRED; Indicates the directory service used. Note that this enum may be extended in the future. DirectoryServiceOptions *DirectoryServiceOptions - // Required if directoryServiceOptions are AD, optional if they are AADKERB. + // Additional information about the directory service. Required if directoryServiceOptions is AD (AD DS authentication). Optional + // for directoryServiceOptions AADDS (Entra DS authentication) and AADKERB + // (Entra authentication). ActiveDirectoryProperties *ActiveDirectoryProperties // Default share permission for users using Kerberos authentication if RBAC role is not assigned. DefaultSharePermission *DefaultSharePermission + + // Required for Managed Identities access using OAuth over SMB. + SmbOAuthSettings *SmbOAuthSettings } // BlobContainer - Properties of the blob container, including Id, resource name, resource type, Etag. @@ -1188,6 +1267,12 @@ type Dimension struct { Name *string } +// DualStackEndpointPreference - Dual-stack endpoint preference defines whether IPv6 endpoints are going to be published. +type DualStackEndpointPreference struct { + // A boolean flag which indicates whether IPv6 storage endpoints are to be published. + PublishIPv6Endpoint *bool +} + // Encryption - The encryption settings on the storage account. type Encryption struct { // The identity to be used with service-side encryption at rest. @@ -1217,6 +1302,12 @@ type EncryptionIdentity struct { EncryptionUserAssignedIdentity *string } +// EncryptionInTransit - Encryption in transit setting. +type EncryptionInTransit struct { + // Indicates whether encryption in transit is required + Required *bool +} + // EncryptionScope - The Encryption Scope resource. type EncryptionScope struct { // Properties of the encryption scope. @@ -1312,6 +1403,9 @@ type EncryptionServices struct { // Endpoints - The URIs that are used to perform a retrieval of a public blob, queue, table, web or dfs object. type Endpoints struct { + // Gets the IPv6 storage endpoints. + IPv6Endpoints *AccountIPv6Endpoints + // Gets the internet routing storage endpoints InternetEndpoints *AccountInternetEndpoints @@ -1737,7 +1831,7 @@ type IPRule struct { // Field has constant value "Allow", any specified value is ignored. Action *string - // REQUIRED; Specifies the IP or IP range in CIDR format. Only IPV4 address is allowed. + // REQUIRED; Specifies the IP or IP range in CIDR format. IPAddressOrRange *string } @@ -2339,6 +2433,9 @@ type NetworkRuleSet struct { // Sets the IP ACL rules IPRules []*IPRule + // Sets the IPv6 ACL rules. + IPv6Rules []*IPRule + // Sets the resource access rules ResourceAccessRules []*ResourceAccessRule @@ -2430,6 +2527,12 @@ type NetworkSecurityPerimeterConfigurationPropertiesResourceAssociation struct { Name *string } +// NfsSetting - Setting for NFS protocol +type NfsSetting struct { + // Encryption in transit setting. + EncryptionInTransit *EncryptionInTransit +} + // NspAccessRule - Information of Access Rule in Network Security Perimeter profile type NspAccessRule struct { // Name of the resource @@ -2593,6 +2696,12 @@ type PermissionScope struct { Service *string } +// Placement - The complex type of the zonal placement details. +type Placement struct { + // The availability zone pinning policy for the storage account. + ZonePlacementPolicy *ZonePlacementPolicy +} + // PrivateEndpoint - The Private Endpoint resource. type PrivateEndpoint struct { // READ-ONLY; The ARM identifier for Private Endpoint @@ -2691,6 +2800,9 @@ type ProtectedAppendWritesHistory struct { // ProtocolSettings - Protocol settings for file service type ProtocolSettings struct { + // Setting for NFS protocol + Nfs *NfsSetting + // Setting for SMB protocol Smb *SmbSetting } @@ -2895,7 +3007,8 @@ type SKUCapability struct { type SKUInformation struct { // REQUIRED; The SKU name. Required for account creation; optional for update. Note that in older versions, SKU name was called // accountType. - Name *SKUName + Name *SKUName + LocationInfo []*SKUInformationLocationInfoItem // The restrictions because of which SKU cannot be used. This is empty if there are no restrictions. Restrictions []*Restriction @@ -2918,6 +3031,14 @@ type SKUInformation struct { Tier *SKUTier } +type SKUInformationLocationInfoItem struct { + // READ-ONLY; Describes the location for the product where storage account resource can be created. + Location *string + + // READ-ONLY; Describes the available zones for the product where storage account resource can be created. + Zones []*string +} + // SKUListResult - The response from the List Storage SKUs operation. type SKUListResult struct { // READ-ONLY; Get the list result of storage SKUs and their properties. @@ -3017,6 +3138,12 @@ type SignedIdentifier struct { ID *string } +// SmbOAuthSettings - Setting property for Managed Identity access over SMB using OAuth +type SmbOAuthSettings struct { + // Specifies if managed identities can access SMB shares using OAuth. The default interpretation is false for this property. + IsSmbOAuthEnabled *bool +} + // SmbSetting - Setting for SMB protocol type SmbSetting struct { // SMB authentication methods supported by server. Valid values are NTLMv2, Kerberos. Should be passed as a string with delimiter @@ -3027,6 +3154,9 @@ type SmbSetting struct { // a string with delimiter ';'. ChannelEncryption *string + // Encryption in transit setting. + EncryptionInTransit *EncryptionInTransit + // Kerberos ticket encryption supported by server. Valid values are RC4-HMAC, AES-256. Should be passed as a string with delimiter // ';' KerberosTicketEncryption *string @@ -3371,12 +3501,6 @@ type TrackedResource struct { // TriggerParameters - The trigger parameters update for the storage task assignment execution type TriggerParameters struct { - // CONSTANT; Run interval unit of task execution. This is a required field when ExecutionTrigger.properties.type is 'OnSchedule'; - // this property should not be present when ExecutionTrigger.properties.type is - // 'RunOnce' - // Field has constant value "Days", any specified value is ignored. - IntervalUnit *string - // When to end task execution. This is a required field when ExecutionTrigger.properties.type is 'OnSchedule'; this property // should not be present when ExecutionTrigger.properties.type is 'RunOnce' EndBy *time.Time @@ -3385,6 +3509,11 @@ type TriggerParameters struct { // should not be present when ExecutionTrigger.properties.type is 'RunOnce' Interval *int32 + // Run interval unit of task execution. This is a required field when ExecutionTrigger.properties.type is 'OnSchedule'; this + // property should not be present when ExecutionTrigger.properties.type is + // 'RunOnce' + IntervalUnit *IntervalUnit + // When to start task execution. This is a required field when ExecutionTrigger.properties.type is 'OnSchedule'; this property // should not be present when ExecutionTrigger.properties.type is 'RunOnce' StartFrom *time.Time @@ -3396,12 +3525,6 @@ type TriggerParameters struct { // TriggerParametersUpdate - The trigger parameters update for the storage task assignment execution type TriggerParametersUpdate struct { - // CONSTANT; Run interval unit of task execution. This is a mutable field when ExecutionTrigger.properties.type is 'OnSchedule'; - // this property should not be present when ExecutionTrigger.properties.type is - // 'RunOnce' - // Field has constant value "Days", any specified value is ignored. - IntervalUnit *string - // When to end task execution. This is a mutable field when ExecutionTrigger.properties.type is 'OnSchedule'; this property // should not be present when ExecutionTrigger.properties.type is 'RunOnce' EndBy *time.Time @@ -3410,6 +3533,11 @@ type TriggerParametersUpdate struct { // should not be present when ExecutionTrigger.properties.type is 'RunOnce' Interval *int32 + // Run interval unit of task execution. This is a mutable field when ExecutionTrigger.properties.type is 'OnSchedule'; this + // property should not be present when ExecutionTrigger.properties.type is + // 'RunOnce' + IntervalUnit *IntervalUnit + // When to start task execution. This is a mutable field when ExecutionTrigger.properties.type is 'OnSchedule'; this property // should not be present when ExecutionTrigger.properties.type is 'RunOnce' StartFrom *time.Time diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/models_serde.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/models_serde.go similarity index 96% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/models_serde.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/models_serde.go index 3840973ee..c6ba017ac 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/models_serde.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/models_serde.go @@ -56,10 +56,12 @@ func (a Account) MarshalJSON() ([]byte, error) { populate(objectMap, "kind", a.Kind) populate(objectMap, "location", a.Location) populate(objectMap, "name", a.Name) + populate(objectMap, "placement", a.Placement) populate(objectMap, "properties", a.Properties) populate(objectMap, "sku", a.SKU) populate(objectMap, "tags", a.Tags) populate(objectMap, "type", a.Type) + populate(objectMap, "zones", a.Zones) return json.Marshal(objectMap) } @@ -90,6 +92,9 @@ func (a *Account) UnmarshalJSON(data []byte) error { case "name": err = unpopulate(val, "Name", &a.Name) delete(rawMsg, key) + case "placement": + err = unpopulate(val, "Placement", &a.Placement) + delete(rawMsg, key) case "properties": err = unpopulate(val, "Properties", &a.Properties) delete(rawMsg, key) @@ -102,6 +107,9 @@ func (a *Account) UnmarshalJSON(data []byte) error { case "type": err = unpopulate(val, "Type", &a.Type) delete(rawMsg, key) + case "zones": + err = unpopulate(val, "Zones", &a.Zones) + delete(rawMsg, key) } if err != nil { return fmt.Errorf("unmarshalling type %T: %v", a, err) @@ -148,9 +156,11 @@ func (a AccountCreateParameters) MarshalJSON() ([]byte, error) { populate(objectMap, "identity", a.Identity) populate(objectMap, "kind", a.Kind) populate(objectMap, "location", a.Location) + populate(objectMap, "placement", a.Placement) populate(objectMap, "properties", a.Properties) populate(objectMap, "sku", a.SKU) populate(objectMap, "tags", a.Tags) + populate(objectMap, "zones", a.Zones) return json.Marshal(objectMap) } @@ -175,6 +185,9 @@ func (a *AccountCreateParameters) UnmarshalJSON(data []byte) error { case "location": err = unpopulate(val, "Location", &a.Location) delete(rawMsg, key) + case "placement": + err = unpopulate(val, "Placement", &a.Placement) + delete(rawMsg, key) case "properties": err = unpopulate(val, "Properties", &a.Properties) delete(rawMsg, key) @@ -184,6 +197,64 @@ func (a *AccountCreateParameters) UnmarshalJSON(data []byte) error { case "tags": err = unpopulate(val, "Tags", &a.Tags) delete(rawMsg, key) + case "zones": + err = unpopulate(val, "Zones", &a.Zones) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", a, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type AccountIPv6Endpoints. +func (a AccountIPv6Endpoints) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "blob", a.Blob) + populate(objectMap, "dfs", a.Dfs) + populate(objectMap, "file", a.File) + populate(objectMap, "internetEndpoints", a.InternetEndpoints) + populate(objectMap, "microsoftEndpoints", a.MicrosoftEndpoints) + populate(objectMap, "queue", a.Queue) + populate(objectMap, "table", a.Table) + populate(objectMap, "web", a.Web) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type AccountIPv6Endpoints. +func (a *AccountIPv6Endpoints) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", a, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "blob": + err = unpopulate(val, "Blob", &a.Blob) + delete(rawMsg, key) + case "dfs": + err = unpopulate(val, "Dfs", &a.Dfs) + delete(rawMsg, key) + case "file": + err = unpopulate(val, "File", &a.File) + delete(rawMsg, key) + case "internetEndpoints": + err = unpopulate(val, "InternetEndpoints", &a.InternetEndpoints) + delete(rawMsg, key) + case "microsoftEndpoints": + err = unpopulate(val, "MicrosoftEndpoints", &a.MicrosoftEndpoints) + delete(rawMsg, key) + case "queue": + err = unpopulate(val, "Queue", &a.Queue) + delete(rawMsg, key) + case "table": + err = unpopulate(val, "Table", &a.Table) + delete(rawMsg, key) + case "web": + err = unpopulate(val, "Web", &a.Web) + delete(rawMsg, key) } if err != nil { return fmt.Errorf("unmarshalling type %T: %v", a, err) @@ -542,6 +613,7 @@ func (a AccountProperties) MarshalJSON() ([]byte, error) { populate(objectMap, "customDomain", a.CustomDomain) populate(objectMap, "dnsEndpointType", a.DNSEndpointType) populate(objectMap, "defaultToOAuthAuthentication", a.DefaultToOAuthAuthentication) + populate(objectMap, "dualStackEndpointPreference", a.DualStackEndpointPreference) populate(objectMap, "enableExtendedGroups", a.EnableExtendedGroups) populate(objectMap, "supportsHttpsTrafficOnly", a.EnableHTTPSTrafficOnly) populate(objectMap, "isNfsV3Enabled", a.EnableNfsV3) @@ -619,6 +691,9 @@ func (a *AccountProperties) UnmarshalJSON(data []byte) error { case "defaultToOAuthAuthentication": err = unpopulate(val, "DefaultToOAuthAuthentication", &a.DefaultToOAuthAuthentication) delete(rawMsg, key) + case "dualStackEndpointPreference": + err = unpopulate(val, "DualStackEndpointPreference", &a.DualStackEndpointPreference) + delete(rawMsg, key) case "enableExtendedGroups": err = unpopulate(val, "EnableExtendedGroups", &a.EnableExtendedGroups) delete(rawMsg, key) @@ -726,6 +801,7 @@ func (a AccountPropertiesCreateParameters) MarshalJSON() ([]byte, error) { populate(objectMap, "customDomain", a.CustomDomain) populate(objectMap, "dnsEndpointType", a.DNSEndpointType) populate(objectMap, "defaultToOAuthAuthentication", a.DefaultToOAuthAuthentication) + populate(objectMap, "dualStackEndpointPreference", a.DualStackEndpointPreference) populate(objectMap, "enableExtendedGroups", a.EnableExtendedGroups) populate(objectMap, "supportsHttpsTrafficOnly", a.EnableHTTPSTrafficOnly) populate(objectMap, "isNfsV3Enabled", a.EnableNfsV3) @@ -780,6 +856,9 @@ func (a *AccountPropertiesCreateParameters) UnmarshalJSON(data []byte) error { case "defaultToOAuthAuthentication": err = unpopulate(val, "DefaultToOAuthAuthentication", &a.DefaultToOAuthAuthentication) delete(rawMsg, key) + case "dualStackEndpointPreference": + err = unpopulate(val, "DualStackEndpointPreference", &a.DualStackEndpointPreference) + delete(rawMsg, key) case "enableExtendedGroups": err = unpopulate(val, "EnableExtendedGroups", &a.EnableExtendedGroups) delete(rawMsg, key) @@ -845,6 +924,7 @@ func (a AccountPropertiesUpdateParameters) MarshalJSON() ([]byte, error) { populate(objectMap, "customDomain", a.CustomDomain) populate(objectMap, "dnsEndpointType", a.DNSEndpointType) populate(objectMap, "defaultToOAuthAuthentication", a.DefaultToOAuthAuthentication) + populate(objectMap, "dualStackEndpointPreference", a.DualStackEndpointPreference) populate(objectMap, "enableExtendedGroups", a.EnableExtendedGroups) populate(objectMap, "supportsHttpsTrafficOnly", a.EnableHTTPSTrafficOnly) populate(objectMap, "encryption", a.Encryption) @@ -897,6 +977,9 @@ func (a *AccountPropertiesUpdateParameters) UnmarshalJSON(data []byte) error { case "defaultToOAuthAuthentication": err = unpopulate(val, "DefaultToOAuthAuthentication", &a.DefaultToOAuthAuthentication) delete(rawMsg, key) + case "dualStackEndpointPreference": + err = unpopulate(val, "DualStackEndpointPreference", &a.DualStackEndpointPreference) + delete(rawMsg, key) case "enableExtendedGroups": err = unpopulate(val, "EnableExtendedGroups", &a.EnableExtendedGroups) delete(rawMsg, key) @@ -1070,9 +1153,11 @@ func (a AccountUpdateParameters) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) populate(objectMap, "identity", a.Identity) populate(objectMap, "kind", a.Kind) + populate(objectMap, "placement", a.Placement) populate(objectMap, "properties", a.Properties) populate(objectMap, "sku", a.SKU) populate(objectMap, "tags", a.Tags) + populate(objectMap, "zones", a.Zones) return json.Marshal(objectMap) } @@ -1091,6 +1176,9 @@ func (a *AccountUpdateParameters) UnmarshalJSON(data []byte) error { case "kind": err = unpopulate(val, "Kind", &a.Kind) delete(rawMsg, key) + case "placement": + err = unpopulate(val, "Placement", &a.Placement) + delete(rawMsg, key) case "properties": err = unpopulate(val, "Properties", &a.Properties) delete(rawMsg, key) @@ -1100,6 +1188,9 @@ func (a *AccountUpdateParameters) UnmarshalJSON(data []byte) error { case "tags": err = unpopulate(val, "Tags", &a.Tags) delete(rawMsg, key) + case "zones": + err = unpopulate(val, "Zones", &a.Zones) + delete(rawMsg, key) } if err != nil { return fmt.Errorf("unmarshalling type %T: %v", a, err) @@ -1278,6 +1369,7 @@ func (a AzureFilesIdentityBasedAuthentication) MarshalJSON() ([]byte, error) { populate(objectMap, "activeDirectoryProperties", a.ActiveDirectoryProperties) populate(objectMap, "defaultSharePermission", a.DefaultSharePermission) populate(objectMap, "directoryServiceOptions", a.DirectoryServiceOptions) + populate(objectMap, "smbOAuthSettings", a.SmbOAuthSettings) return json.Marshal(objectMap) } @@ -1299,6 +1391,9 @@ func (a *AzureFilesIdentityBasedAuthentication) UnmarshalJSON(data []byte) error case "directoryServiceOptions": err = unpopulate(val, "DirectoryServiceOptions", &a.DirectoryServiceOptions) delete(rawMsg, key) + case "smbOAuthSettings": + err = unpopulate(val, "SmbOAuthSettings", &a.SmbOAuthSettings) + delete(rawMsg, key) } if err != nil { return fmt.Errorf("unmarshalling type %T: %v", a, err) @@ -2434,6 +2529,33 @@ func (d *Dimension) UnmarshalJSON(data []byte) error { return nil } +// MarshalJSON implements the json.Marshaller interface for type DualStackEndpointPreference. +func (d DualStackEndpointPreference) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "publishIpv6Endpoint", d.PublishIPv6Endpoint) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type DualStackEndpointPreference. +func (d *DualStackEndpointPreference) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", d, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "publishIpv6Endpoint": + err = unpopulate(val, "PublishIPv6Endpoint", &d.PublishIPv6Endpoint) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", d, err) + } + } + return nil +} + // MarshalJSON implements the json.Marshaller interface for type Encryption. func (e Encryption) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) @@ -2508,6 +2630,33 @@ func (e *EncryptionIdentity) UnmarshalJSON(data []byte) error { return nil } +// MarshalJSON implements the json.Marshaller interface for type EncryptionInTransit. +func (e EncryptionInTransit) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "required", e.Required) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type EncryptionInTransit. +func (e *EncryptionInTransit) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", e, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "required": + err = unpopulate(val, "Required", &e.Required) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", e, err) + } + } + return nil +} + // MarshalJSON implements the json.Marshaller interface for type EncryptionScope. func (e EncryptionScope) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) @@ -2740,6 +2889,7 @@ func (e Endpoints) MarshalJSON() ([]byte, error) { populate(objectMap, "blob", e.Blob) populate(objectMap, "dfs", e.Dfs) populate(objectMap, "file", e.File) + populate(objectMap, "ipv6Endpoints", e.IPv6Endpoints) populate(objectMap, "internetEndpoints", e.InternetEndpoints) populate(objectMap, "microsoftEndpoints", e.MicrosoftEndpoints) populate(objectMap, "queue", e.Queue) @@ -2766,6 +2916,9 @@ func (e *Endpoints) UnmarshalJSON(data []byte) error { case "file": err = unpopulate(val, "File", &e.File) delete(rawMsg, key) + case "ipv6Endpoints": + err = unpopulate(val, "IPv6Endpoints", &e.IPv6Endpoints) + delete(rawMsg, key) case "internetEndpoints": err = unpopulate(val, "InternetEndpoints", &e.InternetEndpoints) delete(rawMsg, key) @@ -5319,6 +5472,7 @@ func (n NetworkRuleSet) MarshalJSON() ([]byte, error) { populate(objectMap, "bypass", n.Bypass) populate(objectMap, "defaultAction", n.DefaultAction) populate(objectMap, "ipRules", n.IPRules) + populate(objectMap, "ipv6Rules", n.IPv6Rules) populate(objectMap, "resourceAccessRules", n.ResourceAccessRules) populate(objectMap, "virtualNetworkRules", n.VirtualNetworkRules) return json.Marshal(objectMap) @@ -5342,6 +5496,9 @@ func (n *NetworkRuleSet) UnmarshalJSON(data []byte) error { case "ipRules": err = unpopulate(val, "IPRules", &n.IPRules) delete(rawMsg, key) + case "ipv6Rules": + err = unpopulate(val, "IPv6Rules", &n.IPv6Rules) + delete(rawMsg, key) case "resourceAccessRules": err = unpopulate(val, "ResourceAccessRules", &n.ResourceAccessRules) delete(rawMsg, key) @@ -5582,6 +5739,33 @@ func (n *NetworkSecurityPerimeterConfigurationPropertiesResourceAssociation) Unm return nil } +// MarshalJSON implements the json.Marshaller interface for type NfsSetting. +func (n NfsSetting) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "encryptionInTransit", n.EncryptionInTransit) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type NfsSetting. +func (n *NfsSetting) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", n, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "encryptionInTransit": + err = unpopulate(val, "EncryptionInTransit", &n.EncryptionInTransit) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", n, err) + } + } + return nil +} + // MarshalJSON implements the json.Marshaller interface for type NspAccessRule. func (n NspAccessRule) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) @@ -6060,6 +6244,33 @@ func (p *PermissionScope) UnmarshalJSON(data []byte) error { return nil } +// MarshalJSON implements the json.Marshaller interface for type Placement. +func (p Placement) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "zonePlacementPolicy", p.ZonePlacementPolicy) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type Placement. +func (p *Placement) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "zonePlacementPolicy": + err = unpopulate(val, "ZonePlacementPolicy", &p.ZonePlacementPolicy) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + } + return nil +} + // MarshalJSON implements the json.Marshaller interface for type PrivateEndpoint. func (p PrivateEndpoint) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) @@ -6358,6 +6569,7 @@ func (p *ProtectedAppendWritesHistory) UnmarshalJSON(data []byte) error { // MarshalJSON implements the json.Marshaller interface for type ProtocolSettings. func (p ProtocolSettings) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) + populate(objectMap, "nfs", p.Nfs) populate(objectMap, "smb", p.Smb) return json.Marshal(objectMap) } @@ -6371,6 +6583,9 @@ func (p *ProtocolSettings) UnmarshalJSON(data []byte) error { for key, val := range rawMsg { var err error switch key { + case "nfs": + err = unpopulate(val, "Nfs", &p.Nfs) + delete(rawMsg, key) case "smb": err = unpopulate(val, "Smb", &p.Smb) delete(rawMsg, key) @@ -6939,6 +7154,7 @@ func (s SKUInformation) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) populate(objectMap, "capabilities", s.Capabilities) populate(objectMap, "kind", s.Kind) + populate(objectMap, "locationInfo", s.LocationInfo) populate(objectMap, "locations", s.Locations) populate(objectMap, "name", s.Name) populate(objectMap, "resourceType", s.ResourceType) @@ -6962,6 +7178,9 @@ func (s *SKUInformation) UnmarshalJSON(data []byte) error { case "kind": err = unpopulate(val, "Kind", &s.Kind) delete(rawMsg, key) + case "locationInfo": + err = unpopulate(val, "LocationInfo", &s.LocationInfo) + delete(rawMsg, key) case "locations": err = unpopulate(val, "Locations", &s.Locations) delete(rawMsg, key) @@ -6985,6 +7204,37 @@ func (s *SKUInformation) UnmarshalJSON(data []byte) error { return nil } +// MarshalJSON implements the json.Marshaller interface for type SKUInformationLocationInfoItem. +func (s SKUInformationLocationInfoItem) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "location", s.Location) + populate(objectMap, "zones", s.Zones) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type SKUInformationLocationInfoItem. +func (s *SKUInformationLocationInfoItem) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", s, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "location": + err = unpopulate(val, "Location", &s.Location) + delete(rawMsg, key) + case "zones": + err = unpopulate(val, "Zones", &s.Zones) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", s, err) + } + } + return nil +} + // MarshalJSON implements the json.Marshaller interface for type SKUListResult. func (s SKUListResult) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) @@ -7227,11 +7477,39 @@ func (s *SignedIdentifier) UnmarshalJSON(data []byte) error { return nil } +// MarshalJSON implements the json.Marshaller interface for type SmbOAuthSettings. +func (s SmbOAuthSettings) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "isSmbOAuthEnabled", s.IsSmbOAuthEnabled) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type SmbOAuthSettings. +func (s *SmbOAuthSettings) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", s, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "isSmbOAuthEnabled": + err = unpopulate(val, "IsSmbOAuthEnabled", &s.IsSmbOAuthEnabled) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", s, err) + } + } + return nil +} + // MarshalJSON implements the json.Marshaller interface for type SmbSetting. func (s SmbSetting) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) populate(objectMap, "authenticationMethods", s.AuthenticationMethods) populate(objectMap, "channelEncryption", s.ChannelEncryption) + populate(objectMap, "encryptionInTransit", s.EncryptionInTransit) populate(objectMap, "kerberosTicketEncryption", s.KerberosTicketEncryption) populate(objectMap, "multichannel", s.Multichannel) populate(objectMap, "versions", s.Versions) @@ -7253,6 +7531,9 @@ func (s *SmbSetting) UnmarshalJSON(data []byte) error { case "channelEncryption": err = unpopulate(val, "ChannelEncryption", &s.ChannelEncryption) delete(rawMsg, key) + case "encryptionInTransit": + err = unpopulate(val, "EncryptionInTransit", &s.EncryptionInTransit) + delete(rawMsg, key) case "kerberosTicketEncryption": err = unpopulate(val, "KerberosTicketEncryption", &s.KerberosTicketEncryption) delete(rawMsg, key) @@ -8109,7 +8390,7 @@ func (t TriggerParameters) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) populateDateTimeRFC3339(objectMap, "endBy", t.EndBy) populate(objectMap, "interval", t.Interval) - objectMap["intervalUnit"] = "Days" + populate(objectMap, "intervalUnit", t.IntervalUnit) populateDateTimeRFC3339(objectMap, "startFrom", t.StartFrom) populateDateTimeRFC3339(objectMap, "startOn", t.StartOn) return json.Marshal(objectMap) @@ -8152,7 +8433,7 @@ func (t TriggerParametersUpdate) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) populateDateTimeRFC3339(objectMap, "endBy", t.EndBy) populate(objectMap, "interval", t.Interval) - objectMap["intervalUnit"] = "Days" + populate(objectMap, "intervalUnit", t.IntervalUnit) populateDateTimeRFC3339(objectMap, "startFrom", t.StartFrom) populateDateTimeRFC3339(objectMap, "startOn", t.StartOn) return json.Marshal(objectMap) diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/networksecurityperimeterconfigurations_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/networksecurityperimeterconfigurations_client.go similarity index 98% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/networksecurityperimeterconfigurations_client.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/networksecurityperimeterconfigurations_client.go index b4773da4f..d856daf80 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/networksecurityperimeterconfigurations_client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/networksecurityperimeterconfigurations_client.go @@ -43,7 +43,7 @@ func NewNetworkSecurityPerimeterConfigurationsClient(subscriptionID string, cred // Get - Gets effective NetworkSecurityPerimeterConfiguration for association // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -96,7 +96,7 @@ func (client *NetworkSecurityPerimeterConfigurationsClient) getCreateRequest(ctx return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -113,7 +113,7 @@ func (client *NetworkSecurityPerimeterConfigurationsClient) getHandleResponse(re // NewListPager - Gets list of effective NetworkSecurityPerimeterConfiguration for storage account // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -163,7 +163,7 @@ func (client *NetworkSecurityPerimeterConfigurationsClient) listCreateRequest(ct return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -181,7 +181,7 @@ func (client *NetworkSecurityPerimeterConfigurationsClient) listHandleResponse(r // BeginReconcile - Refreshes any information about the association. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -209,7 +209,7 @@ func (client *NetworkSecurityPerimeterConfigurationsClient) BeginReconcile(ctx c // Reconcile - Refreshes any information about the association. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 func (client *NetworkSecurityPerimeterConfigurationsClient) reconcile(ctx context.Context, resourceGroupName string, accountName string, networkSecurityPerimeterConfigurationName string, options *NetworkSecurityPerimeterConfigurationsClientBeginReconcileOptions) (*http.Response, error) { var err error const operationName = "NetworkSecurityPerimeterConfigurationsClient.BeginReconcile" @@ -255,7 +255,7 @@ func (client *NetworkSecurityPerimeterConfigurationsClient) reconcileCreateReque return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/objectreplicationpolicies_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/objectreplicationpolicies_client.go similarity index 98% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/objectreplicationpolicies_client.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/objectreplicationpolicies_client.go index c10b4c2a0..360f6fa08 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/objectreplicationpolicies_client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/objectreplicationpolicies_client.go @@ -43,7 +43,7 @@ func NewObjectReplicationPoliciesClient(subscriptionID string, credential azcore // CreateOrUpdate - Create or update the object replication policy of the storage account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -99,7 +99,7 @@ func (client *ObjectReplicationPoliciesClient) createOrUpdateCreateRequest(ctx c return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, properties); err != nil { @@ -120,7 +120,7 @@ func (client *ObjectReplicationPoliciesClient) createOrUpdateHandleResponse(resp // Delete - Deletes the object replication policy associated with the specified storage account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -174,7 +174,7 @@ func (client *ObjectReplicationPoliciesClient) deleteCreateRequest(ctx context.C return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -183,7 +183,7 @@ func (client *ObjectReplicationPoliciesClient) deleteCreateRequest(ctx context.C // Get - Get the object replication policy of the storage account by policy ID. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -238,7 +238,7 @@ func (client *ObjectReplicationPoliciesClient) getCreateRequest(ctx context.Cont return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -255,7 +255,7 @@ func (client *ObjectReplicationPoliciesClient) getHandleResponse(resp *http.Resp // NewListPager - List the object replication policies associated with the storage account. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -305,7 +305,7 @@ func (client *ObjectReplicationPoliciesClient) listCreateRequest(ctx context.Con return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/operations_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/operations_client.go similarity index 97% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/operations_client.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/operations_client.go index 93d7185dc..33f8e6eda 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/operations_client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/operations_client.go @@ -36,7 +36,7 @@ func NewOperationsClient(credential azcore.TokenCredential, options *arm.ClientO // NewListPager - Lists all of the available Storage Rest API operations. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - options - OperationsClientListOptions contains the optional parameters for the OperationsClient.NewListPager method. func (client *OperationsClient) NewListPager(options *OperationsClientListOptions) *runtime.Pager[OperationsClientListResponse] { return runtime.NewPager(runtime.PagingHandler[OperationsClientListResponse]{ @@ -70,7 +70,7 @@ func (client *OperationsClient) listCreateRequest(ctx context.Context, _ *Operat return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/options.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/options.go similarity index 100% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/options.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/options.go diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/privateendpointconnections_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/privateendpointconnections_client.go similarity index 98% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/privateendpointconnections_client.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/privateendpointconnections_client.go index f64ed6884..df3e32d29 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/privateendpointconnections_client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/privateendpointconnections_client.go @@ -43,7 +43,7 @@ func NewPrivateEndpointConnectionsClient(subscriptionID string, credential azcor // Delete - Deletes the specified private endpoint connection associated with the storage account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -95,7 +95,7 @@ func (client *PrivateEndpointConnectionsClient) deleteCreateRequest(ctx context. return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -104,7 +104,7 @@ func (client *PrivateEndpointConnectionsClient) deleteCreateRequest(ctx context. // Get - Gets the specified private endpoint connection associated with the storage account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -157,7 +157,7 @@ func (client *PrivateEndpointConnectionsClient) getCreateRequest(ctx context.Con return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -174,7 +174,7 @@ func (client *PrivateEndpointConnectionsClient) getHandleResponse(resp *http.Res // NewListPager - List all the private endpoint connections associated with the storage account. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -224,7 +224,7 @@ func (client *PrivateEndpointConnectionsClient) listCreateRequest(ctx context.Co return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -242,7 +242,7 @@ func (client *PrivateEndpointConnectionsClient) listHandleResponse(resp *http.Re // Put - Update the state of specified private endpoint connection associated with the storage account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -296,7 +296,7 @@ func (client *PrivateEndpointConnectionsClient) putCreateRequest(ctx context.Con return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, properties); err != nil { diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/privatelinkresources_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/privatelinkresources_client.go similarity index 98% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/privatelinkresources_client.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/privatelinkresources_client.go index bd1a24c77..cb6f64e92 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/privatelinkresources_client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/privatelinkresources_client.go @@ -43,7 +43,7 @@ func NewPrivateLinkResourcesClient(subscriptionID string, credential azcore.Toke // ListByStorageAccount - Gets the private link resources that need to be created for a storage account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -91,7 +91,7 @@ func (client *PrivateLinkResourcesClient) listByStorageAccountCreateRequest(ctx return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/queue_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/queue_client.go similarity index 97% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/queue_client.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/queue_client.go index d1b4ed83f..90d6c5a54 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/queue_client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/queue_client.go @@ -43,7 +43,7 @@ func NewQueueClient(subscriptionID string, credential azcore.TokenCredential, op // Create - Creates a new queue with the specified queue name, under the specified account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -98,7 +98,7 @@ func (client *QueueClient) createCreateRequest(ctx context.Context, resourceGrou return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, queue); err != nil { @@ -119,7 +119,7 @@ func (client *QueueClient) createHandleResponse(resp *http.Response) (QueueClien // Delete - Deletes the queue with the specified queue name, under the specified account if it exists. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -172,7 +172,7 @@ func (client *QueueClient) deleteCreateRequest(ctx context.Context, resourceGrou return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -181,7 +181,7 @@ func (client *QueueClient) deleteCreateRequest(ctx context.Context, resourceGrou // Get - Gets the queue with the specified queue name, under the specified account if it exists. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -235,7 +235,7 @@ func (client *QueueClient) getCreateRequest(ctx context.Context, resourceGroupNa return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -252,7 +252,7 @@ func (client *QueueClient) getHandleResponse(resp *http.Response) (QueueClientGe // NewListPager - Gets a list of all the queues under the specified storage account // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -306,7 +306,7 @@ func (client *QueueClient) listCreateRequest(ctx context.Context, resourceGroupN if options != nil && options.Maxpagesize != nil { reqQP.Set("$maxpagesize", *options.Maxpagesize) } - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -324,7 +324,7 @@ func (client *QueueClient) listHandleResponse(resp *http.Response) (QueueClientL // Update - Creates a new queue with the specified queue name, under the specified account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -379,7 +379,7 @@ func (client *QueueClient) updateCreateRequest(ctx context.Context, resourceGrou return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, queue); err != nil { diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/queueservices_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/queueservices_client.go similarity index 98% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/queueservices_client.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/queueservices_client.go index 72c431c6b..304cb6c77 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/queueservices_client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/queueservices_client.go @@ -44,7 +44,7 @@ func NewQueueServicesClient(subscriptionID string, credential azcore.TokenCreden // and CORS (Cross-Origin Resource Sharing) rules. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -93,7 +93,7 @@ func (client *QueueServicesClient) getServicePropertiesCreateRequest(ctx context return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -111,7 +111,7 @@ func (client *QueueServicesClient) getServicePropertiesHandleResponse(resp *http // List - List all queue services for the storage account // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -158,7 +158,7 @@ func (client *QueueServicesClient) listCreateRequest(ctx context.Context, resour return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -177,7 +177,7 @@ func (client *QueueServicesClient) listHandleResponse(resp *http.Response) (Queu // and CORS (Cross-Origin Resource Sharing) rules. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -228,7 +228,7 @@ func (client *QueueServicesClient) setServicePropertiesCreateRequest(ctx context return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, parameters); err != nil { diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/responses.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/responses.go similarity index 100% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/responses.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/responses.go diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/skus_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/skus_client.go similarity index 97% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/skus_client.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/skus_client.go index f6404ce16..8c0ba7c21 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/skus_client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/skus_client.go @@ -42,7 +42,7 @@ func NewSKUsClient(subscriptionID string, credential azcore.TokenCredential, opt // NewListPager - Lists the available SKUs supported by Microsoft.Storage for given subscription. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - options - SKUsClientListOptions contains the optional parameters for the SKUsClient.NewListPager method. func (client *SKUsClient) NewListPager(options *SKUsClientListOptions) *runtime.Pager[SKUsClientListResponse] { return runtime.NewPager(runtime.PagingHandler[SKUsClientListResponse]{ @@ -80,7 +80,7 @@ func (client *SKUsClient) listCreateRequest(ctx context.Context, _ *SKUsClientLi return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/table_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/table_client.go similarity index 97% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/table_client.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/table_client.go index 0dc4d6100..af4d579b4 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/table_client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/table_client.go @@ -43,7 +43,7 @@ func NewTableClient(subscriptionID string, credential azcore.TokenCredential, op // Create - Creates a new table with the specified table name, under the specified account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -96,7 +96,7 @@ func (client *TableClient) createCreateRequest(ctx context.Context, resourceGrou return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if options != nil && options.Parameters != nil { @@ -120,7 +120,7 @@ func (client *TableClient) createHandleResponse(resp *http.Response) (TableClien // Delete - Deletes the table with the specified table name, under the specified account if it exists. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -172,7 +172,7 @@ func (client *TableClient) deleteCreateRequest(ctx context.Context, resourceGrou return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -181,7 +181,7 @@ func (client *TableClient) deleteCreateRequest(ctx context.Context, resourceGrou // Get - Gets the table with the specified table name, under the specified account if it exists. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -234,7 +234,7 @@ func (client *TableClient) getCreateRequest(ctx context.Context, resourceGroupNa return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -251,7 +251,7 @@ func (client *TableClient) getHandleResponse(resp *http.Response) (TableClientGe // NewListPager - Gets a list of all the tables under the specified storage account // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -299,7 +299,7 @@ func (client *TableClient) listCreateRequest(ctx context.Context, resourceGroupN return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -317,7 +317,7 @@ func (client *TableClient) listHandleResponse(resp *http.Response) (TableClientL // Update - Creates a new table with the specified table name, under the specified account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -370,7 +370,7 @@ func (client *TableClient) updateCreateRequest(ctx context.Context, resourceGrou return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if options != nil && options.Parameters != nil { diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/tableservices_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/tableservices_client.go similarity index 98% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/tableservices_client.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/tableservices_client.go index 2905d9110..706fcf517 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/tableservices_client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/tableservices_client.go @@ -44,7 +44,7 @@ func NewTableServicesClient(subscriptionID string, credential azcore.TokenCreden // and CORS (Cross-Origin Resource Sharing) rules. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -93,7 +93,7 @@ func (client *TableServicesClient) getServicePropertiesCreateRequest(ctx context return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -111,7 +111,7 @@ func (client *TableServicesClient) getServicePropertiesHandleResponse(resp *http // List - List all table services for the storage account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -158,7 +158,7 @@ func (client *TableServicesClient) listCreateRequest(ctx context.Context, resour return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -177,7 +177,7 @@ func (client *TableServicesClient) listHandleResponse(resp *http.Response) (Tabl // and CORS (Cross-Origin Resource Sharing) rules. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group within the user's subscription. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -228,7 +228,7 @@ func (client *TableServicesClient) setServicePropertiesCreateRequest(ctx context return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, parameters); err != nil { diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/taskassignmentinstancesreport_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/taskassignmentinstancesreport_client.go similarity index 98% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/taskassignmentinstancesreport_client.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/taskassignmentinstancesreport_client.go index 19bc76fae..9f0836bc7 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/taskassignmentinstancesreport_client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/taskassignmentinstancesreport_client.go @@ -43,7 +43,7 @@ func NewTaskAssignmentInstancesReportClient(subscriptionID string, credential az // NewListPager - Fetch the report summary of a single storage task assignment's instances // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -104,7 +104,7 @@ func (client *TaskAssignmentInstancesReportClient) listCreateRequest(ctx context if options != nil && options.Maxpagesize != nil { reqQP.Set("$maxpagesize", strconv.FormatInt(int64(*options.Maxpagesize), 10)) } - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/taskassignments_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/taskassignments_client.go similarity index 97% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/taskassignments_client.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/taskassignments_client.go index f35781731..38883628c 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/taskassignments_client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/taskassignments_client.go @@ -48,7 +48,7 @@ func NewTaskAssignmentsClient(subscriptionID string, credential azcore.TokenCred // set of properties, the request will succeed. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -82,7 +82,7 @@ func (client *TaskAssignmentsClient) BeginCreate(ctx context.Context, resourceGr // set of properties, the request will succeed. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 func (client *TaskAssignmentsClient) create(ctx context.Context, resourceGroupName string, accountName string, storageTaskAssignmentName string, parameters TaskAssignment, options *TaskAssignmentsClientBeginCreateOptions) (*http.Response, error) { var err error const operationName = "TaskAssignmentsClient.BeginCreate" @@ -128,7 +128,7 @@ func (client *TaskAssignmentsClient) createCreateRequest(ctx context.Context, re return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, parameters); err != nil { @@ -140,7 +140,7 @@ func (client *TaskAssignmentsClient) createCreateRequest(ctx context.Context, re // BeginDelete - Delete the storage task assignment sub-resource // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -169,7 +169,7 @@ func (client *TaskAssignmentsClient) BeginDelete(ctx context.Context, resourceGr // Delete - Delete the storage task assignment sub-resource // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 func (client *TaskAssignmentsClient) deleteOperation(ctx context.Context, resourceGroupName string, accountName string, storageTaskAssignmentName string, options *TaskAssignmentsClientBeginDeleteOptions) (*http.Response, error) { var err error const operationName = "TaskAssignmentsClient.BeginDelete" @@ -215,7 +215,7 @@ func (client *TaskAssignmentsClient) deleteCreateRequest(ctx context.Context, re return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -224,7 +224,7 @@ func (client *TaskAssignmentsClient) deleteCreateRequest(ctx context.Context, re // Get - Get the storage task assignment properties // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -277,7 +277,7 @@ func (client *TaskAssignmentsClient) getCreateRequest(ctx context.Context, resou return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -294,7 +294,7 @@ func (client *TaskAssignmentsClient) getHandleResponse(resp *http.Response) (Tas // NewListPager - List all the storage task assignments in an account // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -346,7 +346,7 @@ func (client *TaskAssignmentsClient) listCreateRequest(ctx context.Context, reso if options != nil && options.Maxpagesize != nil { reqQP.Set("$maxpagesize", strconv.FormatInt(int64(*options.Maxpagesize), 10)) } - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil @@ -364,7 +364,7 @@ func (client *TaskAssignmentsClient) listHandleResponse(resp *http.Response) (Ta // BeginUpdate - Update storage task assignment properties // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -394,7 +394,7 @@ func (client *TaskAssignmentsClient) BeginUpdate(ctx context.Context, resourceGr // Update - Update storage task assignment properties // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 func (client *TaskAssignmentsClient) update(ctx context.Context, resourceGroupName string, accountName string, storageTaskAssignmentName string, parameters TaskAssignmentUpdateParameters, options *TaskAssignmentsClientBeginUpdateOptions) (*http.Response, error) { var err error const operationName = "TaskAssignmentsClient.BeginUpdate" @@ -440,7 +440,7 @@ func (client *TaskAssignmentsClient) updateCreateRequest(ctx context.Context, re return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} if err := runtime.MarshalAsJSON(req, parameters); err != nil { diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/taskassignmentsinstancesreport_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/taskassignmentsinstancesreport_client.go similarity index 98% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/taskassignmentsinstancesreport_client.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/taskassignmentsinstancesreport_client.go index f0600dbee..ac1453ffa 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/taskassignmentsinstancesreport_client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/taskassignmentsinstancesreport_client.go @@ -43,7 +43,7 @@ func NewTaskAssignmentsInstancesReportClient(subscriptionID string, credential a // NewListPager - Fetch the report summary of all the storage task assignments and instances in an account // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - resourceGroupName - The name of the resource group. The name is case insensitive. // - accountName - The name of the storage account within the specified resource group. Storage account names must be between // 3 and 24 characters in length and use numbers and lower-case letters only. @@ -98,7 +98,7 @@ func (client *TaskAssignmentsInstancesReportClient) listCreateRequest(ctx contex if options != nil && options.Maxpagesize != nil { reqQP.Set("$maxpagesize", strconv.FormatInt(int64(*options.Maxpagesize), 10)) } - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/time_rfc1123.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/time_rfc1123.go similarity index 100% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/time_rfc1123.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/time_rfc1123.go diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/time_rfc3339.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/time_rfc3339.go similarity index 100% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/time_rfc3339.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/time_rfc3339.go diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/usages_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/usages_client.go similarity index 98% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/usages_client.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/usages_client.go index a37623746..155622b0c 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/usages_client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/usages_client.go @@ -42,7 +42,7 @@ func NewUsagesClient(subscriptionID string, credential azcore.TokenCredential, o // NewListByLocationPager - Gets the current usage count and the limit for the resources of the location under the subscription. // -// Generated from API version 2024-01-01 +// Generated from API version 2025-01-01 // - location - The location of the Azure Storage resource. // - options - UsagesClientListByLocationOptions contains the optional parameters for the UsagesClient.NewListByLocationPager // method. @@ -86,7 +86,7 @@ func (client *UsagesClient) listByLocationCreateRequest(ctx context.Context, loc return nil, err } reqQP := req.Raw().URL.Query() - reqQP.Set("api-version", "2024-01-01") + reqQP.Set("api-version", "2025-01-01") req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["Accept"] = []string{"application/json"} return req, nil diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/version.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/version.go new file mode 100644 index 000000000..560980b42 --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage/v2/version.go @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package armstorage + +const ( + moduleName = "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage" + moduleVersion = "v2.0.0" +) diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential/confidential.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential/confidential.go index 549d68ab9..29c004320 100644 --- a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential/confidential.go +++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential/confidential.go @@ -596,6 +596,11 @@ func (cca Client) AcquireTokenSilent(ctx context.Context, scopes []string, opts return AuthResult{}, errors.New("call another AcquireToken method to request a new token having these claims") } + // For service principal scenarios, require WithSilentAccount for public API + if o.account.IsZero() { + return AuthResult{}, errors.New("WithSilentAccount option is required") + } + silentParameters := base.AcquireTokenSilentParameters{ Scopes: scopes, Account: o.account, @@ -604,8 +609,15 @@ func (cca Client) AcquireTokenSilent(ctx context.Context, scopes []string, opts IsAppCache: o.account.IsZero(), TenantID: o.tenantID, AuthnScheme: o.authnScheme, + Claims: o.claims, } + return cca.acquireTokenSilentInternal(ctx, silentParameters) +} + +// acquireTokenSilentInternal is the internal implementation shared by AcquireTokenSilent and AcquireTokenByCredential +func (cca Client) acquireTokenSilentInternal(ctx context.Context, silentParameters base.AcquireTokenSilentParameters) (AuthResult, error) { + return cca.base.AcquireTokenSilent(ctx, silentParameters) } @@ -708,8 +720,10 @@ func (cca Client) AcquireTokenByAuthCode(ctx context.Context, code string, redir // acquireTokenByCredentialOptions contains optional configuration for AcquireTokenByCredential type acquireTokenByCredentialOptions struct { - claims, tenantID string - authnScheme AuthenticationScheme + claims, tenantID string + authnScheme AuthenticationScheme + extraBodyParameters map[string]string + cacheKeyComponents map[string]string } // AcquireByCredentialOption is implemented by options for AcquireTokenByCredential @@ -719,7 +733,7 @@ type AcquireByCredentialOption interface { // AcquireTokenByCredential acquires a security token from the authority, using the client credentials grant. // -// Options: [WithClaims], [WithTenantID] +// Options: [WithClaims], [WithTenantID], [WithFMIPath], [WithAttribute] func (cca Client) AcquireTokenByCredential(ctx context.Context, scopes []string, opts ...AcquireByCredentialOption) (AuthResult, error) { o := acquireTokenByCredentialOptions{} err := options.ApplyOptions(&o, opts) @@ -736,6 +750,29 @@ func (cca Client) AcquireTokenByCredential(ctx context.Context, scopes []string, if o.authnScheme != nil { authParams.AuthnScheme = o.authnScheme } + authParams.ExtraBodyParameters = o.extraBodyParameters + authParams.CacheKeyComponents = o.cacheKeyComponents + if o.claims == "" { + silentParameters := base.AcquireTokenSilentParameters{ + Scopes: scopes, + Account: Account{}, // empty account for app token + RequestType: accesstokens.ATConfidential, + Credential: cca.cred, + IsAppCache: true, + TenantID: o.tenantID, + AuthnScheme: o.authnScheme, + Claims: o.claims, + ExtraBodyParameters: o.extraBodyParameters, + CacheKeyComponents: o.cacheKeyComponents, + } + + // Use internal method with empty account (service principal scenario) + cache, err := cca.acquireTokenSilentInternal(ctx, silentParameters) + if err == nil { + return cache, nil + } + } + token, err := cca.base.Token.Credential(ctx, authParams, cca.cred) if err != nil { return AuthResult{}, err @@ -781,3 +818,63 @@ func (cca Client) Account(ctx context.Context, accountID string) (Account, error func (cca Client) RemoveAccount(ctx context.Context, account Account) error { return cca.base.RemoveAccount(ctx, account) } + +// WithFMIPath specifies the path to a federated managed identity. +// The path should point to a valid FMI configuration file that contains the necessary +// identity information for authentication. +func WithFMIPath(path string) interface { + AcquireByCredentialOption + options.CallOption +} { + return struct { + AcquireByCredentialOption + options.CallOption + }{ + CallOption: options.NewCallOption( + func(a any) error { + switch t := a.(type) { + case *acquireTokenByCredentialOptions: + if t.extraBodyParameters == nil { + t.extraBodyParameters = make(map[string]string) + } + if t.cacheKeyComponents == nil { + t.cacheKeyComponents = make(map[string]string) + } + t.cacheKeyComponents["fmi_path"] = path + t.extraBodyParameters["fmi_path"] = path + default: + return fmt.Errorf("unexpected options type %T", a) + } + return nil + }, + ), + } +} + +// WithAttribute specifies an identity attribute to include in the token request. +// The attribute is sent as "attributes" in the request body and returned as "xmc_attr" +// in the access token claims. This is sometimes used withFMIPath +func WithAttribute(attrValue string) interface { + AcquireByCredentialOption + options.CallOption +} { + return struct { + AcquireByCredentialOption + options.CallOption + }{ + CallOption: options.NewCallOption( + func(a any) error { + switch t := a.(type) { + case *acquireTokenByCredentialOptions: + if t.extraBodyParameters == nil { + t.extraBodyParameters = make(map[string]string) + } + t.extraBodyParameters["attributes"] = attrValue + default: + return fmt.Errorf("unexpected options type %T", a) + } + return nil + }, + ), + } +} diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/base.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/base.go index 61c1c4cec..abf54f7e5 100644 --- a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/base.go +++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/base.go @@ -46,16 +46,18 @@ type accountManager interface { // AcquireTokenSilentParameters contains the parameters to acquire a token silently (from cache). type AcquireTokenSilentParameters struct { - Scopes []string - Account shared.Account - RequestType accesstokens.AppType - Credential *accesstokens.Credential - IsAppCache bool - TenantID string - UserAssertion string - AuthorizationType authority.AuthorizeType - Claims string - AuthnScheme authority.AuthenticationScheme + Scopes []string + Account shared.Account + RequestType accesstokens.AppType + Credential *accesstokens.Credential + IsAppCache bool + TenantID string + UserAssertion string + AuthorizationType authority.AuthorizeType + Claims string + AuthnScheme authority.AuthenticationScheme + ExtraBodyParameters map[string]string + CacheKeyComponents map[string]string } // AcquireTokenAuthCodeParameters contains the parameters required to acquire an access token using the auth code flow. @@ -327,7 +329,12 @@ func (b Client) AcquireTokenSilent(ctx context.Context, silent AcquireTokenSilen if silent.AuthnScheme != nil { authParams.AuthnScheme = silent.AuthnScheme } - + if silent.CacheKeyComponents != nil { + authParams.CacheKeyComponents = silent.CacheKeyComponents + } + if silent.ExtraBodyParameters != nil { + authParams.ExtraBodyParameters = silent.ExtraBodyParameters + } m := b.pmanager if authParams.AuthorizationType != authority.ATOnBehalfOf { authParams.AuthorizationType = authority.ATRefreshToken @@ -367,8 +374,19 @@ func (b Client) AcquireTokenSilent(ctx context.Context, silent AcquireTokenSilen // If the token is not same, we don't need to refresh it. // Which means it refreshed. if str, err := m.Read(ctx, authParams); err == nil && str.AccessToken.Secret == ar.AccessToken { - if tr, er := b.Token.Credential(ctx, authParams, silent.Credential); er == nil { - return b.AuthResultFromToken(ctx, authParams, tr) + switch silent.RequestType { + case accesstokens.ATConfidential: + if tr, er := b.Token.Credential(ctx, authParams, silent.Credential); er == nil { + return b.AuthResultFromToken(ctx, authParams, tr) + } + case accesstokens.ATPublic: + token, err := b.Token.Refresh(ctx, silent.RequestType, authParams, silent.Credential, storageTokenResponse.RefreshToken) + if err != nil { + return ar, err + } + return b.AuthResultFromToken(ctx, authParams, token) + case accesstokens.ATUnknown: + return ar, errors.New("silent request type cannot be ATUnknown") } } } @@ -446,6 +464,9 @@ func (b Client) AcquireTokenOnBehalfOf(ctx context.Context, onBehalfOfParams Acq authParams.Claims = onBehalfOfParams.Claims authParams.Scopes = onBehalfOfParams.Scopes authParams.UserAssertion = onBehalfOfParams.UserAssertion + if authParams.ExtraBodyParameters != nil { + authParams.ExtraBodyParameters = silentParameters.ExtraBodyParameters + } token, err := b.Token.OnBehalfOf(ctx, authParams, onBehalfOfParams.Credential) if err == nil { ar, err = b.AuthResultFromToken(ctx, authParams, token) diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/storage/items.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/storage/items.go index 7379e2233..b7d1a670b 100644 --- a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/storage/items.go +++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/storage/items.go @@ -79,6 +79,7 @@ type AccessToken struct { UserAssertionHash string `json:"user_assertion_hash,omitempty"` TokenType string `json:"token_type,omitempty"` AuthnSchemeKeyID string `json:"keyid,omitempty"` + ExtCacheKey string `json:"ext_cache_key,omitempty"` AdditionalFields map[string]interface{} } @@ -105,15 +106,21 @@ func NewAccessToken(homeID, env, realm, clientID string, cachedAt, refreshOn, ex // Key outputs the key that can be used to uniquely look up this entry in a map. func (a AccessToken) Key() string { ks := []string{a.HomeAccountID, a.Environment, a.CredentialType, a.ClientID, a.Realm, a.Scopes} - key := strings.Join( - ks, - shared.CacheKeySeparator, - ) + // add token type to key for new access tokens types. skip for bearer token type to // preserve fwd and back compat between a common cache and msal clients if !strings.EqualFold(a.TokenType, authority.AccessTokenTypeBearer) { - key = strings.Join([]string{key, a.TokenType}, shared.CacheKeySeparator) + ks = append(ks, a.TokenType) } + // add extra body param hash to key if present + if a.ExtCacheKey != "" { + ks[2] = "atext" // if the there is extra cache we add "atext" to the key replacing accesstoken + ks = append(ks, a.ExtCacheKey) + } + key := strings.Join( + ks, + shared.CacheKeySeparator, + ) return strings.ToLower(key) } diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/storage/storage.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/storage/storage.go index 84a234967..825d8a0f6 100644 --- a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/storage/storage.go +++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/storage/storage.go @@ -135,7 +135,8 @@ func (m *Manager) Read(ctx context.Context, authParameters authority.AuthParams) aliases = metadata.Aliases } - accessToken := m.readAccessToken(homeAccountID, aliases, realm, clientID, scopes, tokenType, authnSchemeKeyID) + accessToken := m.readAccessToken(homeAccountID, aliases, realm, clientID, scopes, tokenType, authnSchemeKeyID, authParameters.CacheExtKeyGenerator()) + tr.AccessToken = accessToken if homeAccountID == "" { @@ -203,6 +204,7 @@ func (m *Manager) Write(authParameters authority.AuthParams, tokenResponse acces authnSchemeKeyID, ) + accessToken.ExtCacheKey = authParameters.CacheExtKeyGenerator() // Since we have a valid access token, cache it before moving on. if err := accessToken.Validate(); err == nil { if err := m.writeAccessToken(accessToken); err != nil { @@ -291,26 +293,49 @@ func (m *Manager) aadMetadata(ctx context.Context, authorityInfo authority.Info) return m.aadCache[authorityInfo.Host], nil } -func (m *Manager) readAccessToken(homeID string, envAliases []string, realm, clientID string, scopes []string, tokenType, authnSchemeKeyID string) AccessToken { +func (m *Manager) readAccessToken(homeID string, envAliases []string, realm, clientID string, scopes []string, tokenType, authnSchemeKeyID, extCacheKey string) AccessToken { m.contractMu.RLock() - // TODO: linear search (over a map no less) is slow for a large number (thousands) of tokens. - // this shows up as the dominating node in a profile. for real-world scenarios this likely isn't - // an issue, however if it does become a problem then we know where to look. - for k, at := range m.contract.AccessTokens { + + tokensToSearch := m.contract.AccessTokens + + for k, at := range tokensToSearch { + // TODO: linear search (over a map no less) is slow for a large number (thousands) of tokens. + // this shows up as the dominating node in a profile. for real-world scenarios this likely isn't + // an issue, however if it does become a problem then we know where to look. if at.HomeAccountID == homeID && at.Realm == realm && at.ClientID == clientID { - if (strings.EqualFold(at.TokenType, tokenType) && at.AuthnSchemeKeyID == authnSchemeKeyID) || (at.TokenType == "" && (tokenType == "" || tokenType == "Bearer")) { - if checkAlias(at.Environment, envAliases) && isMatchingScopes(scopes, at.Scopes) { - m.contractMu.RUnlock() - if needsUpgrade(k) { - m.contractMu.Lock() - defer m.contractMu.Unlock() - at = upgrade(m.contract.AccessTokens, k) + // Match token type and authentication scheme + tokenTypeMatch := (strings.EqualFold(at.TokenType, tokenType) && at.AuthnSchemeKeyID == authnSchemeKeyID) || + (at.TokenType == "" && (tokenType == "" || tokenType == "Bearer")) + environmentAndScopesMatch := checkAlias(at.Environment, envAliases) && isMatchingScopes(scopes, at.Scopes) + + if tokenTypeMatch && environmentAndScopesMatch { + // For hashed tokens, check that the key contains the hash + if extCacheKey != "" { + if !strings.Contains(k, extCacheKey) { + continue // Skip this token if the key doesn't contain the hash + } + } else { + // If no extCacheKey is provided, only match tokens that also have no extCacheKey + if at.ExtCacheKey != "" { + continue // Skip tokens that require a hash when no hash is provided } + } + // Handle token upgrade if needed + if needsUpgrade(k) { + m.contractMu.RUnlock() + m.contractMu.Lock() + at = upgrade(tokensToSearch, k) + m.contractMu.Unlock() return at } + + m.contractMu.RUnlock() + return at } } } + + // No token found, unlock and return empty token m.contractMu.RUnlock() return AccessToken{} } diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens/accesstokens.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens/accesstokens.go index d738c7591..481f9e434 100644 --- a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens/accesstokens.go +++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens/accesstokens.go @@ -281,6 +281,9 @@ func (c Client) FromClientSecret(ctx context.Context, authParameters authority.A qv.Set(clientID, authParameters.ClientID) addScopeQueryParam(qv, authParameters) + // Add extra body parameters if provided + addExtraBodyParameters(ctx, qv, authParameters) + return c.doTokenResp(ctx, authParameters, qv) } @@ -296,6 +299,9 @@ func (c Client) FromAssertion(ctx context.Context, authParameters authority.Auth qv.Set(clientInfo, clientInfoVal) addScopeQueryParam(qv, authParameters) + // Add extra body parameters if provided + addExtraBodyParameters(ctx, qv, authParameters) + return c.doTokenResp(ctx, authParameters, qv) } @@ -329,6 +335,8 @@ func (c Client) FromUserAssertionClientCertificate(ctx context.Context, authPara qv.Set("requested_token_use", "on_behalf_of") addScopeQueryParam(qv, authParameters) + // Add extra body parameters if provided + addExtraBodyParameters(ctx, qv, authParameters) return c.doTokenResp(ctx, authParameters, qv) } @@ -466,3 +474,12 @@ func addScopeQueryParam(queryParams url.Values, authParameters authority.AuthPar scopes := AppendDefaultScopes(authParameters) queryParams.Set("scope", strings.Join(scopes, " ")) } + +// addExtraBodyParameters evaluates and adds extra body parameters to the request +func addExtraBodyParameters(ctx context.Context, v url.Values, ap authority.AuthParams) { + for key, value := range ap.ExtraBodyParameters { + if value != "" { + v.Set(key, value) + } + } +} diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority/authority.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority/authority.go index 3f4037464..debd465db 100644 --- a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority/authority.go +++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority/authority.go @@ -15,6 +15,7 @@ import ( "net/url" "os" "path" + "sort" "strings" "time" @@ -47,6 +48,8 @@ type jsonCaller interface { } // For backward compatibility, accept both old and new China endpoints for a transition period. +// This list is derived from the AAD instance discovery metadata and represents all known trusted hosts +// across different Azure clouds (Public, China, Germany, US Government, etc.) var aadTrustedHostList = map[string]bool{ "login.windows.net": true, // Microsoft Azure Worldwide - Used in validation scenarios where host is not this list "login.partner.microsoftonline.cn": true, // Microsoft Azure China (new) @@ -55,6 +58,9 @@ var aadTrustedHostList = map[string]bool{ "login-us.microsoftonline.com": true, // Microsoft Azure US Government - Legacy "login.microsoftonline.us": true, // Microsoft Azure US Government "login.microsoftonline.com": true, // Microsoft Azure Worldwide + "login.microsoft.com": true, + "sts.windows.net": true, + "login.usgovcloudapi.net": true, } // TrustedHost checks if an AAD host is trusted/valid. @@ -103,36 +109,46 @@ func (r *TenantDiscoveryResponse) Validate() error { // ValidateIssuerMatchesAuthority validates that the issuer in the TenantDiscoveryResponse matches the authority. // This is used to identity security or configuration issues in authorities and the OIDC endpoint func (r *TenantDiscoveryResponse) ValidateIssuerMatchesAuthority(authorityURI string, aliases map[string]bool) error { - if authorityURI == "" { return errors.New("TenantDiscoveryResponse: empty authorityURI provided for validation") } + if r.Issuer == "" { + return errors.New("TenantDiscoveryResponse: empty issuer in response") + } - // Parse the issuer URL issuerURL, err := url.Parse(r.Issuer) if err != nil { return fmt.Errorf("TenantDiscoveryResponse: failed to parse issuer URL: %w", err) } + authorityURL, err := url.Parse(authorityURI) + if err != nil { + return fmt.Errorf("TenantDiscoveryResponse: failed to parse authority URL: %w", err) + } + + // Fast path: exact scheme + host match + if issuerURL.Scheme == authorityURL.Scheme && issuerURL.Host == authorityURL.Host { + return nil + } - // Even if it doesn't match the authority, issuers from known and trusted hosts are valid + // Alias-based acceptance if aliases != nil && aliases[issuerURL.Host] { return nil } - // Parse the authority URL for comparison - authorityURL, err := url.Parse(authorityURI) - if err != nil { - return fmt.Errorf("TenantDiscoveryResponse: failed to parse authority URL: %w", err) + issuerHost := issuerURL.Host + authorityHost := authorityURL.Host + + // Accept if issuer host is trusted + if TrustedHost(issuerHost) { + return nil } - // Check if the scheme and host match (paths can be ignored when validating the issuer) - if issuerURL.Scheme == authorityURL.Scheme && issuerURL.Host == authorityURL.Host { + // Accept if authority is a regional variant ending with "." + if strings.HasSuffix(authorityHost, "."+issuerHost) { return nil } - // If we get here, validation failed - return fmt.Errorf("TenantDiscoveryResponse: issuer from OIDC discovery '%s' does not match authority '%s' or a known pattern", - r.Issuer, authorityURI) + return fmt.Errorf("TenantDiscoveryResponse: issuer '%s' does not match authority '%s' or any trusted/alias rule", r.Issuer, authorityURI) } type InstanceDiscoveryMetadata struct { @@ -256,6 +272,12 @@ type AuthParams struct { DomainHint string // AuthnScheme is an optional scheme for formatting access tokens AuthnScheme AuthenticationScheme + // ExtraBodyParameters are additional parameters to include in token requests. + // The functions are evaluated at request time to get the parameter values. + // These parameters are also included in the cache key. + ExtraBodyParameters map[string]string + // CacheKeyComponents are additional components to include in the cache key. + CacheKeyComponents map[string]string } // NewAuthParams creates an authorization parameters object. @@ -642,8 +664,42 @@ func (a *AuthParams) AssertionHash() string { } func (a *AuthParams) AppKey() string { + baseKey := a.ClientID + "_" if a.AuthorityInfo.Tenant != "" { - return fmt.Sprintf("%s_%s_AppTokenCache", a.ClientID, a.AuthorityInfo.Tenant) + baseKey += a.AuthorityInfo.Tenant + } + + // Include extra body parameters in the cache key + paramHash := a.CacheExtKeyGenerator() + if paramHash != "" { + baseKey = fmt.Sprintf("%s_%s", baseKey, paramHash) + } + + return baseKey + "_AppTokenCache" +} + +// CacheExtKeyGenerator computes a hash of the Cache key components key and values +// to include in the cache key. This ensures tokens acquired with different +// parameters are cached separately. +func (a *AuthParams) CacheExtKeyGenerator() string { + if len(a.CacheKeyComponents) == 0 { + return "" + } + + // Sort keys to ensure consistent hashing + keys := make([]string, 0, len(a.CacheKeyComponents)) + for k := range a.CacheKeyComponents { + keys = append(keys, k) } - return fmt.Sprintf("%s__AppTokenCache", a.ClientID) + sort.Strings(keys) + + // Create a string by concatenating key+value pairs + keyStr := "" + for _, key := range keys { + // Append key followed by its value with no separator + keyStr += key + a.CacheKeyComponents[key] + } + + hash := sha256.Sum256([]byte(keyStr)) + return strings.ToLower(base64.RawURLEncoding.EncodeToString(hash[:])) } diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/public/public.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/public/public.go index 7beed2617..797c086cb 100644 --- a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/public/public.go +++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/public/public.go @@ -368,9 +368,9 @@ type AcquireByUsernamePasswordOption interface { acquireByUsernamePasswordOption() } -// AcquireTokenByUsernamePassword acquires a security token from the authority, via Username/Password Authentication. -// NOTE: this flow is NOT recommended. +// Deprecated: This API will be removed in a future release. Use a more secure flow instead. Follow this migration guide: https://aka.ms/msal-ropc-migration // +// AcquireTokenByUsernamePassword acquires a security token from the authority, via Username/Password Authentication. // Options: [WithClaims], [WithTenantID] func (pca Client) AcquireTokenByUsernamePassword(ctx context.Context, scopes []string, username, password string, opts ...AcquireByUsernamePasswordOption) (AuthResult, error) { o := acquireTokenByUsernamePasswordOptions{} diff --git a/vendor/github.com/BurntSushi/toml/README.md b/vendor/github.com/BurntSushi/toml/README.md index 639e6c399..1101d206d 100644 --- a/vendor/github.com/BurntSushi/toml/README.md +++ b/vendor/github.com/BurntSushi/toml/README.md @@ -1,9 +1,9 @@ TOML stands for Tom's Obvious, Minimal Language. This Go package provides a reflection interface similar to Go's standard library `json` and `xml` packages. -Compatible with TOML version [v1.0.0](https://toml.io/en/v1.0.0). +Compatible with TOML version [v1.1.0](https://toml.io/en/v1.1.0). -Documentation: https://godocs.io/github.com/BurntSushi/toml +Documentation: https://pkg.go.dev/github.com/BurntSushi/toml See the [releases page](https://github.com/BurntSushi/toml/releases) for a changelog; this information is also in the git tag annotations (e.g. `git show diff --git a/vendor/github.com/BurntSushi/toml/decode.go b/vendor/github.com/BurntSushi/toml/decode.go index c05a0b7e5..ed884840f 100644 --- a/vendor/github.com/BurntSushi/toml/decode.go +++ b/vendor/github.com/BurntSushi/toml/decode.go @@ -196,6 +196,26 @@ func (md *MetaData) PrimitiveDecode(primValue Primitive, v any) error { return md.unify(primValue.undecoded, rvalue(v)) } +// markDecodedRecursive is a helper to mark any key under the given tmap as +// decoded, recursing as needed +func markDecodedRecursive(md *MetaData, tmap map[string]any) { + for key := range tmap { + md.decoded[md.context.add(key).String()] = struct{}{} + if tmap, ok := tmap[key].(map[string]any); ok { + md.context = append(md.context, key) + markDecodedRecursive(md, tmap) + md.context = md.context[0 : len(md.context)-1] + } + if tarr, ok := tmap[key].([]map[string]any); ok { + for _, elm := range tarr { + md.context = append(md.context, key) + markDecodedRecursive(md, elm) + md.context = md.context[0 : len(md.context)-1] + } + } + } +} + // unify performs a sort of type unification based on the structure of `rv`, // which is the client representation. // @@ -222,6 +242,16 @@ func (md *MetaData) unify(data any, rv reflect.Value) error { if err != nil { return md.parseErr(err) } + // Assume the Unmarshaler decoded everything, so mark all keys under + // this table as decoded. + if tmap, ok := data.(map[string]any); ok { + markDecodedRecursive(md, tmap) + } + if aot, ok := data.([]map[string]any); ok { + for _, tmap := range aot { + markDecodedRecursive(md, tmap) + } + } return nil } if v, ok := rvi.(encoding.TextUnmarshaler); ok { @@ -400,7 +430,7 @@ func (md *MetaData) unifyString(data any, rv reflect.Value) error { if i, ok := data.(int64); ok { rv.SetString(strconv.FormatInt(i, 10)) } else if f, ok := data.(float64); ok { - rv.SetString(strconv.FormatFloat(f, 'f', -1, 64)) + rv.SetString(strconv.FormatFloat(f, 'g', -1, 64)) } else { return md.badtype("string", data) } diff --git a/vendor/github.com/BurntSushi/toml/encode.go b/vendor/github.com/BurntSushi/toml/encode.go index 73366c0d9..bd7aa1865 100644 --- a/vendor/github.com/BurntSushi/toml/encode.go +++ b/vendor/github.com/BurntSushi/toml/encode.go @@ -228,9 +228,9 @@ func (enc *Encoder) eElement(rv reflect.Value) { } switch v.Location() { default: - enc.wf(v.Format(format)) + enc.write(v.Format(format)) case internal.LocalDatetime, internal.LocalDate, internal.LocalTime: - enc.wf(v.In(time.UTC).Format(format)) + enc.write(v.In(time.UTC).Format(format)) } return case Marshaler: @@ -279,40 +279,40 @@ func (enc *Encoder) eElement(rv reflect.Value) { case reflect.String: enc.writeQuoted(rv.String()) case reflect.Bool: - enc.wf(strconv.FormatBool(rv.Bool())) + enc.write(strconv.FormatBool(rv.Bool())) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - enc.wf(strconv.FormatInt(rv.Int(), 10)) + enc.write(strconv.FormatInt(rv.Int(), 10)) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - enc.wf(strconv.FormatUint(rv.Uint(), 10)) + enc.write(strconv.FormatUint(rv.Uint(), 10)) case reflect.Float32: f := rv.Float() if math.IsNaN(f) { if math.Signbit(f) { - enc.wf("-") + enc.write("-") } - enc.wf("nan") + enc.write("nan") } else if math.IsInf(f, 0) { if math.Signbit(f) { - enc.wf("-") + enc.write("-") } - enc.wf("inf") + enc.write("inf") } else { - enc.wf(floatAddDecimal(strconv.FormatFloat(f, 'f', -1, 32))) + enc.write(floatAddDecimal(strconv.FormatFloat(f, 'g', -1, 32))) } case reflect.Float64: f := rv.Float() if math.IsNaN(f) { if math.Signbit(f) { - enc.wf("-") + enc.write("-") } - enc.wf("nan") + enc.write("nan") } else if math.IsInf(f, 0) { if math.Signbit(f) { - enc.wf("-") + enc.write("-") } - enc.wf("inf") + enc.write("inf") } else { - enc.wf(floatAddDecimal(strconv.FormatFloat(f, 'f', -1, 64))) + enc.write(floatAddDecimal(strconv.FormatFloat(f, 'g', -1, 64))) } case reflect.Array, reflect.Slice: enc.eArrayOrSliceElement(rv) @@ -330,27 +330,32 @@ func (enc *Encoder) eElement(rv reflect.Value) { // By the TOML spec, all floats must have a decimal with at least one number on // either side. func floatAddDecimal(fstr string) string { - if !strings.Contains(fstr, ".") { - return fstr + ".0" + for _, c := range fstr { + if c == 'e' { // Exponent syntax + return fstr + } + if c == '.' { + return fstr + } } - return fstr + return fstr + ".0" } func (enc *Encoder) writeQuoted(s string) { - enc.wf("\"%s\"", dblQuotedReplacer.Replace(s)) + enc.write(`"` + dblQuotedReplacer.Replace(s) + `"`) } func (enc *Encoder) eArrayOrSliceElement(rv reflect.Value) { length := rv.Len() - enc.wf("[") + enc.write("[") for i := 0; i < length; i++ { elem := eindirect(rv.Index(i)) enc.eElement(elem) if i != length-1 { - enc.wf(", ") + enc.write(", ") } } - enc.wf("]") + enc.write("]") } func (enc *Encoder) eArrayOfTables(key Key, rv reflect.Value) { @@ -363,7 +368,7 @@ func (enc *Encoder) eArrayOfTables(key Key, rv reflect.Value) { continue } enc.newline() - enc.wf("%s[[%s]]", enc.indentStr(key), key) + enc.writef("%s[[%s]]", enc.indentStr(key), key) enc.newline() enc.eMapOrStruct(key, trv, false) } @@ -376,7 +381,7 @@ func (enc *Encoder) eTable(key Key, rv reflect.Value) { enc.newline() } if len(key) > 0 { - enc.wf("%s[%s]", enc.indentStr(key), key) + enc.writef("%s[%s]", enc.indentStr(key), key) enc.newline() } enc.eMapOrStruct(key, rv, false) @@ -402,47 +407,44 @@ func (enc *Encoder) eMap(key Key, rv reflect.Value, inline bool) { // Sort keys so that we have deterministic output. And write keys directly // underneath this key first, before writing sub-structs or sub-maps. - var mapKeysDirect, mapKeysSub []string + var mapKeysDirect, mapKeysSub []reflect.Value for _, mapKey := range rv.MapKeys() { - k := mapKey.String() if typeIsTable(tomlTypeOfGo(eindirect(rv.MapIndex(mapKey)))) { - mapKeysSub = append(mapKeysSub, k) + mapKeysSub = append(mapKeysSub, mapKey) } else { - mapKeysDirect = append(mapKeysDirect, k) + mapKeysDirect = append(mapKeysDirect, mapKey) } } - var writeMapKeys = func(mapKeys []string, trailC bool) { - sort.Strings(mapKeys) + writeMapKeys := func(mapKeys []reflect.Value, trailC bool) { + sort.Slice(mapKeys, func(i, j int) bool { return mapKeys[i].String() < mapKeys[j].String() }) for i, mapKey := range mapKeys { - val := eindirect(rv.MapIndex(reflect.ValueOf(mapKey))) + val := eindirect(rv.MapIndex(mapKey)) if isNil(val) { continue } if inline { - enc.writeKeyValue(Key{mapKey}, val, true) + enc.writeKeyValue(Key{mapKey.String()}, val, true) if trailC || i != len(mapKeys)-1 { - enc.wf(", ") + enc.write(", ") } } else { - enc.encode(key.add(mapKey), val) + enc.encode(key.add(mapKey.String()), val) } } } if inline { - enc.wf("{") + enc.write("{") } writeMapKeys(mapKeysDirect, len(mapKeysSub) > 0) writeMapKeys(mapKeysSub, false) if inline { - enc.wf("}") + enc.write("}") } } -const is32Bit = (32 << (^uint(0) >> 63)) == 32 - func pointerTo(t reflect.Type) reflect.Type { if t.Kind() == reflect.Ptr { return pointerTo(t.Elem()) @@ -477,15 +479,14 @@ func (enc *Encoder) eStruct(key Key, rv reflect.Value, inline bool) { frv := eindirect(rv.Field(i)) - if is32Bit { - // Copy so it works correct on 32bit archs; not clear why this - // is needed. See #314, and https://www.reddit.com/r/golang/comments/pnx8v4 - // This also works fine on 64bit, but 32bit archs are somewhat - // rare and this is a wee bit faster. - copyStart := make([]int, len(start)) - copy(copyStart, start) - start = copyStart - } + // Need to make a copy because ... ehm, I don't know why... I guess + // allocating a new array can cause it to fail(?) + // + // Done for: https://github.com/BurntSushi/toml/issues/430 + // Previously only on 32bit for: https://github.com/BurntSushi/toml/issues/314 + copyStart := make([]int, len(start)) + copy(copyStart, start) + start = copyStart // Treat anonymous struct fields with tag names as though they are // not anonymous, like encoding/json does. @@ -507,7 +508,7 @@ func (enc *Encoder) eStruct(key Key, rv reflect.Value, inline bool) { } addFields(rt, rv, nil) - writeFields := func(fields [][]int) { + writeFields := func(fields [][]int, totalFields int) { for _, fieldIndex := range fields { fieldType := rt.FieldByIndex(fieldIndex) fieldVal := rv.FieldByIndex(fieldIndex) @@ -537,8 +538,8 @@ func (enc *Encoder) eStruct(key Key, rv reflect.Value, inline bool) { if inline { enc.writeKeyValue(Key{keyName}, fieldVal, true) - if fieldIndex[0] != len(fields)-1 { - enc.wf(", ") + if fieldIndex[0] != totalFields-1 { + enc.write(", ") } } else { enc.encode(key.add(keyName), fieldVal) @@ -547,12 +548,14 @@ func (enc *Encoder) eStruct(key Key, rv reflect.Value, inline bool) { } if inline { - enc.wf("{") + enc.write("{") } - writeFields(fieldsDirect) - writeFields(fieldsSub) + + l := len(fieldsDirect) + len(fieldsSub) + writeFields(fieldsDirect, l) + writeFields(fieldsSub, l) if inline { - enc.wf("}") + enc.write("}") } } @@ -702,7 +705,7 @@ func isEmpty(rv reflect.Value) bool { func (enc *Encoder) newline() { if enc.hasWritten { - enc.wf("\n") + enc.write("\n") } } @@ -724,14 +727,22 @@ func (enc *Encoder) writeKeyValue(key Key, val reflect.Value, inline bool) { enc.eElement(val) return } - enc.wf("%s%s = ", enc.indentStr(key), key.maybeQuoted(len(key)-1)) + enc.writef("%s%s = ", enc.indentStr(key), key.maybeQuoted(len(key)-1)) enc.eElement(val) if !inline { enc.newline() } } -func (enc *Encoder) wf(format string, v ...any) { +func (enc *Encoder) write(s string) { + _, err := enc.w.WriteString(s) + if err != nil { + encPanic(err) + } + enc.hasWritten = true +} + +func (enc *Encoder) writef(format string, v ...any) { _, err := fmt.Fprintf(enc.w, format, v...) if err != nil { encPanic(err) diff --git a/vendor/github.com/BurntSushi/toml/error.go b/vendor/github.com/BurntSushi/toml/error.go index 1dd523211..b7077d3ae 100644 --- a/vendor/github.com/BurntSushi/toml/error.go +++ b/vendor/github.com/BurntSushi/toml/error.go @@ -69,7 +69,7 @@ type Position struct { Line int // Line number, starting at 1. Col int // Error column, starting at 1. Start int // Start of error, as byte offset starting at 0. - Len int // Lenght of the error in bytes. + Len int // Length of the error in bytes. } func (p Position) withCol(tomlFile string) Position { diff --git a/vendor/github.com/BurntSushi/toml/lex.go b/vendor/github.com/BurntSushi/toml/lex.go index 6878d9d69..9f4396a0f 100644 --- a/vendor/github.com/BurntSushi/toml/lex.go +++ b/vendor/github.com/BurntSushi/toml/lex.go @@ -13,7 +13,6 @@ type itemType int const ( itemError itemType = iota - itemNIL // used in the parser to indicate no type itemEOF itemText itemString @@ -47,14 +46,13 @@ func (p Position) String() string { } type lexer struct { - input string - start int - pos int - line int - state stateFn - items chan item - tomlNext bool - esc bool + input string + start int + pos int + line int + state stateFn + items chan item + esc bool // Allow for backing up up to 4 runes. This is necessary because TOML // contains 3-rune tokens (""" and '''). @@ -90,14 +88,13 @@ func (lx *lexer) nextItem() item { } } -func lex(input string, tomlNext bool) *lexer { +func lex(input string) *lexer { lx := &lexer{ - input: input, - state: lexTop, - items: make(chan item, 10), - stack: make([]stateFn, 0, 10), - line: 1, - tomlNext: tomlNext, + input: input, + state: lexTop, + items: make(chan item, 10), + stack: make([]stateFn, 0, 10), + line: 1, } return lx } @@ -108,7 +105,7 @@ func (lx *lexer) push(state stateFn) { func (lx *lexer) pop() stateFn { if len(lx.stack) == 0 { - return lx.errorf("BUG in lexer: no states to pop") + panic("BUG in lexer: no states to pop") } last := lx.stack[len(lx.stack)-1] lx.stack = lx.stack[0 : len(lx.stack)-1] @@ -275,7 +272,9 @@ func (lx *lexer) errorPos(start, length int, err error) stateFn { func (lx *lexer) errorf(format string, values ...any) stateFn { if lx.atEOF { pos := lx.getPos() - pos.Line-- + if lx.pos >= 1 && lx.input[lx.pos-1] == '\n' { + pos.Line-- + } pos.Len = 1 pos.Start = lx.pos - 1 lx.items <- item{typ: itemError, pos: pos, err: fmt.Errorf(format, values...)} @@ -303,6 +302,8 @@ func lexTop(lx *lexer) stateFn { return lexTableStart case eof: if lx.pos > lx.start { + // TODO: never reached? I think this can only occur on a bug in the + // lexer(?) return lx.errorf("unexpected EOF") } lx.emit(itemEOF) @@ -390,8 +391,6 @@ func lexTableNameStart(lx *lexer) stateFn { func lexTableNameEnd(lx *lexer) stateFn { lx.skip(isWhitespace) switch r := lx.next(); { - case isWhitespace(r): - return lexTableNameEnd case r == '.': lx.ignore() return lexTableNameStart @@ -410,7 +409,7 @@ func lexTableNameEnd(lx *lexer) stateFn { // Lexes only one part, e.g. only 'a' inside 'a.b'. func lexBareName(lx *lexer) stateFn { r := lx.next() - if isBareKeyChar(r, lx.tomlNext) { + if isBareKeyChar(r) { return lexBareName } lx.backup() @@ -418,23 +417,23 @@ func lexBareName(lx *lexer) stateFn { return lx.pop() } -// lexBareName lexes one part of a key or table. -// -// It assumes that at least one valid character for the table has already been -// read. +// lexQuotedName lexes one part of a quoted key or table name. It assumes that +// it starts lexing at the quote itself (" or '). // // Lexes only one part, e.g. only '"a"' inside '"a".b'. func lexQuotedName(lx *lexer) stateFn { r := lx.next() switch { - case isWhitespace(r): - return lexSkip(lx, lexValue) case r == '"': lx.ignore() // ignore the '"' return lexString case r == '\'': lx.ignore() // ignore the "'" return lexRawString + + // TODO: I don't think any of the below conditions can ever be reached? + case isWhitespace(r): + return lexSkip(lx, lexValue) case r == eof: return lx.errorf("unexpected EOF; expected value") default: @@ -462,17 +461,19 @@ func lexKeyStart(lx *lexer) stateFn { func lexKeyNameStart(lx *lexer) stateFn { lx.skip(isWhitespace) switch r := lx.peek(); { - case r == '=' || r == eof: - return lx.errorf("unexpected '='") - case r == '.': - return lx.errorf("unexpected '.'") + default: + lx.push(lexKeyEnd) + return lexBareName case r == '"' || r == '\'': lx.ignore() lx.push(lexKeyEnd) return lexQuotedName - default: - lx.push(lexKeyEnd) - return lexBareName + + // TODO: I think these can never be reached? + case r == '=' || r == eof: + return lx.errorf("unexpected '='") + case r == '.': + return lx.errorf("unexpected '.'") } } @@ -483,7 +484,7 @@ func lexKeyEnd(lx *lexer) stateFn { switch r := lx.next(); { case isWhitespace(r): return lexSkip(lx, lexKeyEnd) - case r == eof: + case r == eof: // TODO: never reached return lx.errorf("unexpected EOF; expected key separator '='") case r == '.': lx.ignore() @@ -626,10 +627,7 @@ func lexInlineTableValue(lx *lexer) stateFn { case isWhitespace(r): return lexSkip(lx, lexInlineTableValue) case isNL(r): - if lx.tomlNext { - return lexSkip(lx, lexInlineTableValue) - } - return lx.errorPrevLine(errLexInlineTableNL{}) + return lexSkip(lx, lexInlineTableValue) case r == '#': lx.push(lexInlineTableValue) return lexCommentStart @@ -651,10 +649,7 @@ func lexInlineTableValueEnd(lx *lexer) stateFn { case isWhitespace(r): return lexSkip(lx, lexInlineTableValueEnd) case isNL(r): - if lx.tomlNext { - return lexSkip(lx, lexInlineTableValueEnd) - } - return lx.errorPrevLine(errLexInlineTableNL{}) + return lexSkip(lx, lexInlineTableValueEnd) case r == '#': lx.push(lexInlineTableValueEnd) return lexCommentStart @@ -662,10 +657,7 @@ func lexInlineTableValueEnd(lx *lexer) stateFn { lx.ignore() lx.skip(isWhitespace) if lx.peek() == '}' { - if lx.tomlNext { - return lexInlineTableValueEnd - } - return lx.errorf("trailing comma not allowed in inline tables") + return lexInlineTableValueEnd } return lexInlineTableValue case r == '}': @@ -853,9 +845,6 @@ func lexStringEscape(lx *lexer) stateFn { r := lx.next() switch r { case 'e': - if !lx.tomlNext { - return lx.error(errLexEscape{r}) - } fallthrough case 'b': fallthrough @@ -876,9 +865,6 @@ func lexStringEscape(lx *lexer) stateFn { case '\\': return lx.pop() case 'x': - if !lx.tomlNext { - return lx.error(errLexEscape{r}) - } return lexHexEscape case 'u': return lexShortUnicodeEscape @@ -926,19 +912,9 @@ func lexLongUnicodeEscape(lx *lexer) stateFn { // lexBaseNumberOrDate can differentiate base prefixed integers from other // types. func lexNumberOrDateStart(lx *lexer) stateFn { - r := lx.next() - switch r { - case '0': + if lx.next() == '0' { return lexBaseNumberOrDate } - - if !isDigit(r) { - // The only way to reach this state is if the value starts - // with a digit, so specifically treat anything else as an - // error. - return lx.errorf("expected a digit but got %q", r) - } - return lexNumberOrDate } @@ -1117,7 +1093,7 @@ func lexBaseNumberOrDate(lx *lexer) stateFn { case 'x': r = lx.peek() if !isHex(r) { - lx.errorf("not a hexidecimal number: '%s%c'", lx.current(), r) + lx.errorf("not a hexadecimal number: '%s%c'", lx.current(), r) } return lexHexInteger } @@ -1194,13 +1170,13 @@ func lexSkip(lx *lexer, nextState stateFn) stateFn { } func (s stateFn) String() string { + if s == nil { + return "" + } name := runtime.FuncForPC(reflect.ValueOf(s).Pointer()).Name() if i := strings.LastIndexByte(name, '.'); i > -1 { name = name[i+1:] } - if s == nil { - name = "" - } return name + "()" } @@ -1208,8 +1184,6 @@ func (itype itemType) String() string { switch itype { case itemError: return "Error" - case itemNIL: - return "NIL" case itemEOF: return "EOF" case itemText: @@ -1224,18 +1198,22 @@ func (itype itemType) String() string { return "Float" case itemDatetime: return "DateTime" + case itemArray: + return "Array" + case itemArrayEnd: + return "ArrayEnd" case itemTableStart: return "TableStart" case itemTableEnd: return "TableEnd" + case itemArrayTableStart: + return "ArrayTableStart" + case itemArrayTableEnd: + return "ArrayTableEnd" case itemKeyStart: return "KeyStart" case itemKeyEnd: return "KeyEnd" - case itemArray: - return "Array" - case itemArrayEnd: - return "ArrayEnd" case itemCommentStart: return "CommentStart" case itemInlineTableStart: @@ -1264,24 +1242,7 @@ func isDigit(r rune) bool { return r >= '0' && r <= '9' } func isBinary(r rune) bool { return r == '0' || r == '1' } func isOctal(r rune) bool { return r >= '0' && r <= '7' } func isHex(r rune) bool { return (r >= '0' && r <= '9') || (r|0x20 >= 'a' && r|0x20 <= 'f') } -func isBareKeyChar(r rune, tomlNext bool) bool { - if tomlNext { - return (r >= 'A' && r <= 'Z') || - (r >= 'a' && r <= 'z') || - (r >= '0' && r <= '9') || - r == '_' || r == '-' || - r == 0xb2 || r == 0xb3 || r == 0xb9 || (r >= 0xbc && r <= 0xbe) || - (r >= 0xc0 && r <= 0xd6) || (r >= 0xd8 && r <= 0xf6) || (r >= 0xf8 && r <= 0x037d) || - (r >= 0x037f && r <= 0x1fff) || - (r >= 0x200c && r <= 0x200d) || (r >= 0x203f && r <= 0x2040) || - (r >= 0x2070 && r <= 0x218f) || (r >= 0x2460 && r <= 0x24ff) || - (r >= 0x2c00 && r <= 0x2fef) || (r >= 0x3001 && r <= 0xd7ff) || - (r >= 0xf900 && r <= 0xfdcf) || (r >= 0xfdf0 && r <= 0xfffd) || - (r >= 0x10000 && r <= 0xeffff) - } - - return (r >= 'A' && r <= 'Z') || - (r >= 'a' && r <= 'z') || - (r >= '0' && r <= '9') || - r == '_' || r == '-' +func isBareKeyChar(r rune) bool { + return (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') || + (r >= '0' && r <= '9') || r == '_' || r == '-' } diff --git a/vendor/github.com/BurntSushi/toml/meta.go b/vendor/github.com/BurntSushi/toml/meta.go index e61453730..0d337026c 100644 --- a/vendor/github.com/BurntSushi/toml/meta.go +++ b/vendor/github.com/BurntSushi/toml/meta.go @@ -135,9 +135,6 @@ func (k Key) maybeQuoted(i int) string { // Like append(), but only increase the cap by 1. func (k Key) add(piece string) Key { - if cap(k) > len(k) { - return append(k, piece) - } newKey := make(Key, len(k)+1) copy(newKey, k) newKey[len(k)] = piece diff --git a/vendor/github.com/BurntSushi/toml/parse.go b/vendor/github.com/BurntSushi/toml/parse.go index 3f2c090c8..b474247ae 100644 --- a/vendor/github.com/BurntSushi/toml/parse.go +++ b/vendor/github.com/BurntSushi/toml/parse.go @@ -3,7 +3,6 @@ package toml import ( "fmt" "math" - "os" "strconv" "strings" "time" @@ -17,7 +16,6 @@ type parser struct { context Key // Full key for the current hash in scope. currentKey string // Base key name for everything except hashes. pos Position // Current position in the TOML file. - tomlNext bool ordered []Key // List of keys in the order that they appear in the TOML data. @@ -32,8 +30,6 @@ type keyInfo struct { } func parse(data string) (p *parser, err error) { - _, tomlNext := os.LookupEnv("BURNTSUSHI_TOML_110") - defer func() { if r := recover(); r != nil { if pErr, ok := r.(ParseError); ok { @@ -50,7 +46,6 @@ func parse(data string) (p *parser, err error) { // it anyway. if strings.HasPrefix(data, "\xff\xfe") || strings.HasPrefix(data, "\xfe\xff") { // UTF-16 data = data[2:] - //lint:ignore S1017 https://github.com/dominikh/go-tools/issues/1447 } else if strings.HasPrefix(data, "\xef\xbb\xbf") { // UTF-8 data = data[3:] } @@ -74,10 +69,9 @@ func parse(data string) (p *parser, err error) { p = &parser{ keyInfo: make(map[string]keyInfo), mapping: make(map[string]any), - lx: lex(data, tomlNext), + lx: lex(data), ordered: make([]Key, 0), implicits: make(map[string]struct{}), - tomlNext: tomlNext, } for { item := p.next() @@ -351,17 +345,14 @@ func (p *parser) valueFloat(it item) (any, tomlType) { var dtTypes = []struct { fmt string zone *time.Location - next bool }{ - {time.RFC3339Nano, time.Local, false}, - {"2006-01-02T15:04:05.999999999", internal.LocalDatetime, false}, - {"2006-01-02", internal.LocalDate, false}, - {"15:04:05.999999999", internal.LocalTime, false}, - - // tomlNext - {"2006-01-02T15:04Z07:00", time.Local, true}, - {"2006-01-02T15:04", internal.LocalDatetime, true}, - {"15:04", internal.LocalTime, true}, + {time.RFC3339Nano, time.Local}, + {"2006-01-02T15:04:05.999999999", internal.LocalDatetime}, + {"2006-01-02", internal.LocalDate}, + {"15:04:05.999999999", internal.LocalTime}, + {"2006-01-02T15:04Z07:00", time.Local}, + {"2006-01-02T15:04", internal.LocalDatetime}, + {"15:04", internal.LocalTime}, } func (p *parser) valueDatetime(it item) (any, tomlType) { @@ -372,9 +363,6 @@ func (p *parser) valueDatetime(it item) (any, tomlType) { err error ) for _, dt := range dtTypes { - if dt.next && !p.tomlNext { - continue - } t, err = time.ParseInLocation(dt.fmt, it.val, dt.zone) if err == nil { if missingLeadingZero(it.val, dt.fmt) { @@ -529,7 +517,7 @@ func numUnderscoresOK(s string) bool { } } - // isHexis a superset of all the permissable characters surrounding an + // isHex is a superset of all the permissible characters surrounding an // underscore. accept = isHex(r) } @@ -645,6 +633,11 @@ func (p *parser) setValue(key string, value any) { // Note that since it has already been defined (as a hash), we don't // want to overwrite it. So our business is done. if p.isArray(keyContext) { + if !p.isImplicit(keyContext) { + if _, ok := hash[key]; ok { + p.panicf("Key '%s' has already been defined.", keyContext) + } + } p.removeImplicit(keyContext) hash[key] = value return @@ -803,10 +796,8 @@ func (p *parser) replaceEscapes(it item, str string) string { b.WriteByte(0x0d) skip = 1 case 'e': - if p.tomlNext { - b.WriteByte(0x1b) - skip = 1 - } + b.WriteByte(0x1b) + skip = 1 case '"': b.WriteByte(0x22) skip = 1 @@ -816,11 +807,9 @@ func (p *parser) replaceEscapes(it item, str string) string { // The lexer guarantees the correct number of characters are present; // don't need to check here. case 'x': - if p.tomlNext { - escaped := p.asciiEscapeToUnicode(it, str[i+2:i+4]) - b.WriteRune(escaped) - skip = 3 - } + escaped := p.asciiEscapeToUnicode(it, str[i+2:i+4]) + b.WriteRune(escaped) + skip = 3 case 'u': escaped := p.asciiEscapeToUnicode(it, str[i+2:i+6]) b.WriteRune(escaped) diff --git a/vendor/github.com/Crocmagnon/fatcontext/pkg/analyzer/analyzer.go b/vendor/github.com/Crocmagnon/fatcontext/pkg/analyzer/analyzer.go deleted file mode 100644 index 7b88bf56e..000000000 --- a/vendor/github.com/Crocmagnon/fatcontext/pkg/analyzer/analyzer.go +++ /dev/null @@ -1,224 +0,0 @@ -package analyzer - -import ( - "bytes" - "errors" - "fmt" - "go/ast" - "go/printer" - "go/token" - "go/types" - - "golang.org/x/tools/go/analysis" - "golang.org/x/tools/go/analysis/passes/inspect" - "golang.org/x/tools/go/ast/inspector" -) - -var Analyzer = &analysis.Analyzer{ - Name: "fatcontext", - Doc: "detects nested contexts in loops and function literals", - Run: run, - Requires: []*analysis.Analyzer{inspect.Analyzer}, -} - -var errUnknown = errors.New("unknown node type") - -func run(pass *analysis.Pass) (interface{}, error) { - inspctr := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) - - nodeFilter := []ast.Node{ - (*ast.ForStmt)(nil), - (*ast.RangeStmt)(nil), - (*ast.FuncLit)(nil), - } - - inspctr.Preorder(nodeFilter, func(node ast.Node) { - body, err := getBody(node) - if err != nil { - return - } - - assignStmt := findNestedContext(pass, node, body.List) - if assignStmt == nil { - return - } - - suggestedStmt := ast.AssignStmt{ - Lhs: assignStmt.Lhs, - TokPos: assignStmt.TokPos, - Tok: token.DEFINE, - Rhs: assignStmt.Rhs, - } - suggested, err := render(pass.Fset, &suggestedStmt) - - var fixes []analysis.SuggestedFix - if err == nil { - fixes = append(fixes, analysis.SuggestedFix{ - Message: "replace `=` with `:=`", - TextEdits: []analysis.TextEdit{ - { - Pos: assignStmt.Pos(), - End: assignStmt.End(), - NewText: suggested, - }, - }, - }) - } - - pass.Report(analysis.Diagnostic{ - Pos: assignStmt.Pos(), - Message: getReportMessage(node), - SuggestedFixes: fixes, - }) - }) - - return nil, nil -} - -func getReportMessage(node ast.Node) string { - switch node.(type) { - case *ast.ForStmt, *ast.RangeStmt: - return "nested context in loop" - case *ast.FuncLit: - return "nested context in function literal" - default: - return "unsupported nested context type" - } -} - -func getBody(node ast.Node) (*ast.BlockStmt, error) { - forStmt, ok := node.(*ast.ForStmt) - if ok { - return forStmt.Body, nil - } - - rangeStmt, ok := node.(*ast.RangeStmt) - if ok { - return rangeStmt.Body, nil - } - - funcLit, ok := node.(*ast.FuncLit) - if ok { - return funcLit.Body, nil - } - - return nil, errUnknown -} - -func findNestedContext(pass *analysis.Pass, node ast.Node, stmts []ast.Stmt) *ast.AssignStmt { - for _, stmt := range stmts { - // Recurse if necessary - if inner, ok := stmt.(*ast.BlockStmt); ok { - found := findNestedContext(pass, node, inner.List) - if found != nil { - return found - } - } - - if inner, ok := stmt.(*ast.IfStmt); ok { - found := findNestedContext(pass, node, inner.Body.List) - if found != nil { - return found - } - } - - if inner, ok := stmt.(*ast.SwitchStmt); ok { - found := findNestedContext(pass, node, inner.Body.List) - if found != nil { - return found - } - } - - if inner, ok := stmt.(*ast.CaseClause); ok { - found := findNestedContext(pass, node, inner.Body) - if found != nil { - return found - } - } - - if inner, ok := stmt.(*ast.SelectStmt); ok { - found := findNestedContext(pass, node, inner.Body.List) - if found != nil { - return found - } - } - - if inner, ok := stmt.(*ast.CommClause); ok { - found := findNestedContext(pass, node, inner.Body) - if found != nil { - return found - } - } - - // Actually check for nested context - assignStmt, ok := stmt.(*ast.AssignStmt) - if !ok { - continue - } - - t := pass.TypesInfo.TypeOf(assignStmt.Lhs[0]) - if t == nil { - continue - } - - if t.String() != "context.Context" { - continue - } - - if assignStmt.Tok == token.DEFINE { - continue - } - - // allow assignment to non-pointer children of values defined within the loop - if lhs := getRootIdent(pass, assignStmt.Lhs[0]); lhs != nil { - if obj := pass.TypesInfo.ObjectOf(lhs); obj != nil { - if checkObjectScopeWithinNode(obj.Parent(), node) { - continue // definition is within the loop - } - } - } - - return assignStmt - } - - return nil -} - -func checkObjectScopeWithinNode(scope *types.Scope, node ast.Node) bool { - if scope == nil { - return false - } - - if scope.Pos() >= node.Pos() && scope.End() <= node.End() { - return true - } - - return false -} - -func getRootIdent(pass *analysis.Pass, node ast.Node) *ast.Ident { - for { - switch n := node.(type) { - case *ast.Ident: - return n - case *ast.IndexExpr: - node = n.X - case *ast.SelectorExpr: - if sel, ok := pass.TypesInfo.Selections[n]; ok && sel.Indirect() { - return nil // indirected (pointer) roots don't imply a (safe) copy - } - node = n.X - default: - return nil - } - } -} - -// render returns the pretty-print of the given node -func render(fset *token.FileSet, x interface{}) ([]byte, error) { - var buf bytes.Buffer - if err := printer.Fprint(&buf, fset, x); err != nil { - return nil, fmt.Errorf("printing node: %w", err) - } - return buf.Bytes(), nil -} diff --git a/vendor/github.com/Djarvur/go-err113/.travis.yml b/vendor/github.com/Djarvur/go-err113/.travis.yml index 44fe77d53..142be3e8b 100644 --- a/vendor/github.com/Djarvur/go-err113/.travis.yml +++ b/vendor/github.com/Djarvur/go-err113/.travis.yml @@ -1,18 +1,14 @@ language: go go: - - "1.13" - - "1.14" + - "1.23" + - "1.24" + - "1.25" - tip -env: - - GO111MODULE=on - before_install: - - go get github.com/axw/gocov/gocov - - go get github.com/mattn/goveralls - - go get golang.org/x/tools/cmd/cover - - go get golang.org/x/tools/cmd/goimports + - go install github.com/mattn/goveralls@v0.0.12 + - go install golang.org/x/tools/cmd/goimports@v0.36.0 - wget -O - -q https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh script: @@ -21,4 +17,4 @@ script: - go test -v -race ./... after_success: - - test "$TRAVIS_GO_VERSION" = "1.14" && goveralls -service=travis-ci + - test "$TRAVIS_GO_VERSION" = "1.25" && goveralls -service=travis-ci diff --git a/vendor/github.com/Djarvur/go-err113/comparison.go b/vendor/github.com/Djarvur/go-err113/comparison.go index 8a8555783..a267ebdce 100644 --- a/vendor/github.com/Djarvur/go-err113/comparison.go +++ b/vendor/github.com/Djarvur/go-err113/comparison.go @@ -7,9 +7,10 @@ import ( "go/types" "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/ast/inspector" ) -func inspectComparision(pass *analysis.Pass, n ast.Node) bool { // nolint: unparam +func inspectComparision(file *ast.File, pass *analysis.Pass, n ast.Node) bool { // nolint: unparam // check whether the call expression matches time.Now().Sub() be, ok := n.(*ast.BinaryExpr) if !ok { @@ -25,6 +26,18 @@ func inspectComparision(pass *analysis.Pass, n ast.Node) bool { // nolint: unpar return true } + root := inspector.New([]*ast.File{file}).Root() + c, ok := root.FindNode(n) + if !ok { + panic(fmt.Errorf("could not find node %T in inspector for file %q", n, file.Name.Name)) + } + + for cur := c.Parent(); cur != root; cur = cur.Parent() { + if isMethodNamed(cur, pass, "Is") { + return true + } + } + oldExpr := render(pass.Fset, be) negate := "" @@ -56,6 +69,23 @@ func inspectComparision(pass *analysis.Pass, n ast.Node) bool { // nolint: unpar return true } +var errorType = types.Universe.Lookup("error").Type().Underlying().(*types.Interface) + +func isMethodNamed(cur inspector.Cursor, pass *analysis.Pass, name string) bool { + funcNode, ok := cur.Node().(*ast.FuncDecl) + + if !ok || funcNode.Name == nil || funcNode.Name.Name != name { + return false + } + + if funcNode.Recv == nil && len(funcNode.Recv.List) != 1 { + return false + } + + typ := pass.TypesInfo.Types[funcNode.Recv.List[0].Type] + return typ.Type != nil && types.Implements(typ.Type, errorType) +} + func isError(v ast.Expr, info *types.Info) bool { if intf, ok := info.TypeOf(v).Underlying().(*types.Interface); ok { return intf.NumMethods() == 1 && intf.Method(0).FullName() == "(error).Error" diff --git a/vendor/github.com/Djarvur/go-err113/err113.go b/vendor/github.com/Djarvur/go-err113/err113.go index ec4f52ac7..190a7ded9 100644 --- a/vendor/github.com/Djarvur/go-err113/err113.go +++ b/vendor/github.com/Djarvur/go-err113/err113.go @@ -2,10 +2,10 @@ package err113 import ( - "bytes" "go/ast" "go/printer" "go/token" + "strings" "golang.org/x/tools/go/analysis" ) @@ -19,14 +19,14 @@ func NewAnalyzer() *analysis.Analyzer { } } -func run(pass *analysis.Pass) (interface{}, error) { +func run(pass *analysis.Pass) (any, error) { for _, file := range pass.Files { tlds := enumerateFileDecls(file) ast.Inspect( file, func(n ast.Node) bool { - return inspectComparision(pass, n) && + return inspectComparision(file, pass, n) && inspectDefinition(pass, tlds, n) }, ) @@ -36,8 +36,8 @@ func run(pass *analysis.Pass) (interface{}, error) { } // render returns the pretty-print of the given node. -func render(fset *token.FileSet, x interface{}) string { - var buf bytes.Buffer +func render(fset *token.FileSet, x any) string { + var buf strings.Builder if err := printer.Fprint(&buf, fset, x); err != nil { panic(err) } diff --git a/vendor/github.com/GaijinEntertainment/go-exhaustruct/v3/internal/pattern/list.go b/vendor/github.com/GaijinEntertainment/go-exhaustruct/v3/internal/pattern/list.go deleted file mode 100644 index a16e5058d..000000000 --- a/vendor/github.com/GaijinEntertainment/go-exhaustruct/v3/internal/pattern/list.go +++ /dev/null @@ -1,82 +0,0 @@ -package pattern - -import ( - "fmt" - "regexp" - "strings" -) - -var ( - ErrEmptyPattern = fmt.Errorf("pattern can't be empty") - ErrCompilationFailed = fmt.Errorf("pattern compilation failed") -) - -// List is a list of regular expressions. -type List []*regexp.Regexp - -// NewList parses slice of strings to a slice of compiled regular expressions. -func NewList(strs ...string) (List, error) { - if len(strs) == 0 { - return nil, nil - } - - l := make(List, 0, len(strs)) - - for _, str := range strs { - re, err := strToRe(str) - if err != nil { - return nil, err - } - - l = append(l, re) - } - - return l, nil -} - -// MatchFullString matches provided string against all regexps in a slice and returns -// true if any of them matches whole string. -func (l List) MatchFullString(str string) bool { - for i := 0; i < len(l); i++ { - if m := l[i].FindStringSubmatch(str); len(m) > 0 && m[0] == str { - return true - } - } - - return false -} - -func (l *List) Set(value string) error { - re, err := strToRe(value) - if err != nil { - return err - } - - *l = append(*l, re) - - return nil -} - -func (l *List) String() string { - res := make([]string, 0, len(*l)) - - for _, re := range *l { - res = append(res, `"`+re.String()+`"`) - } - - return strings.Join(res, ", ") -} - -// strToRe parses string to a compiled regular expression that matches full string. -func strToRe(str string) (*regexp.Regexp, error) { - if str == "" { - return nil, ErrEmptyPattern - } - - re, err := regexp.Compile(str) - if err != nil { - return nil, fmt.Errorf("%w: %s: %w", ErrCompilationFailed, str, err) - } - - return re, nil -} diff --git a/vendor/github.com/MirrexOne/unqueryvet/.gitignore b/vendor/github.com/MirrexOne/unqueryvet/.gitignore new file mode 100644 index 000000000..23f505c0f --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/.gitignore @@ -0,0 +1,56 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +/unqueryvet + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool +*.out +coverage.html + +# Dependency directories +vendor/ + +# Go workspace file +go.work +go.work.sum + +# IDE files +.idea/ +.vscode/ +*.swp +*.swo +*~ + +# OS files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Temporary files +*.tmp +*.log +go.work +.golangci.local.yml + +# Build tools (downloaded by Taskfile/Gradle) +.tools/ +.task/ + +# VS Code extension build artifacts +extensions/vscode/node_modules/ +extensions/vscode/out/ +extensions/vscode/*.vsix +*.vsix + +# Claude Code +.claude/ diff --git a/vendor/github.com/MirrexOne/unqueryvet/.golangci.yml b/vendor/github.com/MirrexOne/unqueryvet/.golangci.yml new file mode 100644 index 000000000..d604d323f --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/.golangci.yml @@ -0,0 +1,20 @@ +version: "2" + +formatters: + enable: + - gofumpt + - goimports + settings: + gofumpt: + extra-rules: true + +linters: + exclusions: + warn-unused: true + presets: + - comments + - std-error-handling + +issues: + max-issues-per-linter: 0 + max-same-issues: 0 diff --git a/vendor/github.com/MirrexOne/unqueryvet/.unqueryvet.example.yaml b/vendor/github.com/MirrexOne/unqueryvet/.unqueryvet.example.yaml new file mode 100644 index 000000000..e3327ee7e --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/.unqueryvet.example.yaml @@ -0,0 +1,165 @@ +# Unqueryvet Configuration File +# This is an example configuration showing all available options +# +# JSON Schema validation is automatically provided by SchemaStore.org +# for editors that support it (VS Code, GoLand, Neovim, etc.) + +# ============================================================================== +# LEVEL 1: Simple Configuration (quick setup) +# ============================================================================== + +# Built-in rules severity configuration +# Available rules: select-star, n1-queries, sql-injection, tx-leak +# Severity values: error, warning, info, ignore +rules: + select-star: warning + n1-queries: warning + sql-injection: error + tx-leak: warning + +# Files to ignore (glob patterns) +ignore: + - "*_test.go" + - "testdata/**" + - "vendor/**" + +# SQL patterns to whitelist (won't trigger warnings) +allow: + - "COUNT(*)" + - "information_schema.*" + +# ============================================================================== +# LEVEL 2: Detailed Configuration (existing options) +# ============================================================================== + +# Enable/disable SQL builder checking (default: true) +check-sql-builders: true + +# Enable/disable aliased wildcard detection like SELECT t.* (default: true) +check-aliased-wildcard: true + +# Enable/disable string concatenation analysis (default: true) +check-string-concat: true + +# Enable/disable format string analysis like fmt.Sprintf (default: true) +check-format-strings: true + +# Enable/disable strings.Builder analysis (default: true) +check-string-builder: true + +# Enable/disable subquery analysis (default: true) +check-subqueries: true + +# Diagnostic severity: "error" or "warning" (default: "warning") +severity: warning + +# SQL builder libraries to check (all enabled by default) +sql-builders: + squirrel: true + gorm: true + sqlx: true + ent: true + pgx: true + bun: true + sqlboiler: true + jet: true + sqlc: true + goqu: true + rel: true + reform: true + +# Legacy: Patterns for files to ignore (use 'ignore' instead) +# ignored-files: +# - "*_test.go" + +# Legacy: Functions to ignore (regex patterns) +# ignored-functions: +# - "debug\\..*" +# - "test.*" + +# Legacy: Regex patterns to allow (use 'allow' instead) +# allowed-patterns: +# - "SELECT \\* FROM temp_.*" + +# ============================================================================== +# LEVEL 3: Custom Rules with DSL (advanced) +# ============================================================================== + +# Define your own analysis rules using patterns and conditions +custom-rules: + # Example 1: Allow SELECT * for temporary tables + - id: allow-temp-tables + pattern: SELECT * FROM $TABLE + when: isTempTable(table) + action: allow + + # Example 2: Detect N+1 queries in loops + - id: n1-in-loop + pattern: $DB.Query($QUERY) + when: in_loop && !contains(function, "batch") + message: "Potential N+1 query detected in loop" + severity: warning + fix: "Consider using batch query or preloading" + + # Example 3: Require WHERE clause for DELETE/UPDATE + - id: require-where + patterns: + - DELETE FROM $TABLE + - UPDATE $TABLE SET $COLS + when: "!has_where" + message: "Dangerous query without WHERE clause" + severity: error + + # Example 4: Context-aware rules (strict in prod code, relaxed in tests) + - id: strict-select-star + pattern: SELECT * FROM $TABLE + when: | + !matches(file, "_test.go$") && + !matches(file, "testdata/") && + !isSystemTable(table) && + !isTempTable(table) + message: "Avoid SELECT * in production code - specify columns explicitly" + severity: error + +# ============================================================================== +# DSL Reference +# ============================================================================== +# +# Pattern Metavariables: +# $TABLE - matches table name (with optional schema) +# $VAR - matches identifier/variable +# $QUERY - matches string literal +# $COLS - matches column list +# $EXPR - matches any expression +# $DB - matches database object +# +# Condition Variables: +# file - current file path +# package - current package name +# function - current function name +# query - SQL query text +# query_type - SELECT, INSERT, UPDATE, DELETE +# table - primary table name +# tables - list of all tables +# columns - list of columns +# has_join - true if query has JOIN +# has_where - true if query has WHERE +# in_loop - true if inside a loop +# loop_depth - nesting depth of loops +# builder - SQL builder type (gorm, squirrel, etc.) +# +# Built-in Functions: +# contains(str, substr) - check if string contains substring +# matches(str, regex) - check if string matches regex +# startsWith(str, prefix) - check if string starts with prefix +# endsWith(str, suffix) - check if string ends with suffix +# isSystemTable(table) - check if table is system/catalog table +# isTempTable(table) - check if table looks like temp table +# isAggregate(query) - check if query has aggregate functions +# +# Operators: +# =~ - regex match (e.g., file =~ "_test.go$") +# !~ - regex not match +# && - logical AND +# || - logical OR +# ! - logical NOT diff --git a/vendor/github.com/MirrexOne/unqueryvet/CONTRIBUTING.md b/vendor/github.com/MirrexOne/unqueryvet/CONTRIBUTING.md new file mode 100644 index 000000000..dacc30734 --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/CONTRIBUTING.md @@ -0,0 +1,341 @@ +# Contributing to unqueryvet + +Thank you for your interest in contributing to unqueryvet! This document provides guidelines and instructions for contributing. + +## Table of Contents + +- [Getting Started](#getting-started) +- [Development Setup](#development-setup) +- [Project Structure](#project-structure) +- [Running Tests](#running-tests) +- [Code Style](#code-style) +- [Pull Request Process](#pull-request-process) +- [Adding New SQL Builders](#adding-new-sql-builders) +- [Reporting Issues](#reporting-issues) + +--- + +## Getting Started + +1. Fork the repository on GitHub +2. Clone your fork locally: + ```bash + git clone https://github.com/YOUR_USERNAME/unqueryvet.git + cd unqueryvet + ``` +3. Add the upstream remote: + ```bash + git remote add upstream https://github.com/MirrexOne/unqueryvet.git + ``` +4. Create a new branch for your feature: + ```bash + git checkout -b feature/your-feature-name + ``` + +--- + +## Development Setup + +### Prerequisites + +- Go 1.24 or later +- [Task](https://taskfile.dev/) (optional, but recommended) +- golangci-lint (for linting) + +### Install Dependencies + +```bash +go mod download +``` + +### Build + +Using Task: +```bash +task build # Build CLI +task build:lsp # Build LSP server +task build:all # Build both +``` + +Using Go directly: +```bash +go build ./cmd/unqueryvet +go build ./cmd/unqueryvet-lsp +``` + +### Install Locally + +```bash +task install:all +# or +go install ./cmd/unqueryvet +go install ./cmd/unqueryvet-lsp +``` + +--- + +## Project Structure + +``` +unqueryvet/ +├── cmd/ +│ ├── unqueryvet/ # CLI entry point +│ └── unqueryvet-lsp/ # LSP server entry point +├── internal/ +│ ├── analyzer/ # Core analysis engine +│ │ ├── sqlbuilders/ # SQL builder support (12 builders) +│ │ ├── n1detector.go # N+1 query detection +│ │ └── sqli_scanner.go # SQL injection scanner +│ ├── cli/ # CLI output utilities +│ ├── configloader/ # Configuration loading +│ ├── dsl/ # Custom Rules DSL engine +│ ├── lsp/ # LSP server implementation +│ ├── messages/ # Error messages +│ ├── runner/ # Analysis runner +│ ├── tui/ # Interactive TUI (Bubble Tea) +│ └── version/ # Version information +├── pkg/ +│ └── config/ # Public configuration API +├── extensions/ +│ ├── goland/ # GoLand/IntelliJ plugin (Kotlin) +│ └── vscode/ # VS Code extension (TypeScript) +├── docs/ # Documentation +├── _examples/ # Example configurations +└── testdata/ # Test fixtures +``` + +### Key Packages + +| Package | Description | +|---------|-------------| +| `internal/analyzer` | Core detection logic (SELECT *, N+1, SQL Injection) | +| `internal/analyzer/sqlbuilders` | Support for 12 SQL builder libraries | +| `internal/dsl` | Custom rules DSL using expr-lang | +| `internal/lsp` | Language Server Protocol implementation | +| `internal/tui` | Interactive terminal UI with Bubble Tea | +| `pkg/config` | Configuration with default rules | + +> **Note**: All three detection rules (SELECT *, N+1, SQL Injection) are enabled by default. + +--- + +## Running Tests + +Using Task: +```bash +task test # Run all tests +task test:race # Run with race detection (requires CGO) +task test:short # Run short tests only +task test:unit # Run unit tests only +task test:integration # Run integration tests +task coverage # Generate coverage report +``` + +Using Go directly: +```bash +go test ./... +go test -v -race ./... +go test -coverprofile=coverage.out ./... +``` + +### Running Benchmarks + +```bash +task bench +# or +go test -bench=. -benchmem ./internal/analyzer +``` + +--- + +## Code Style + +### Formatting + +```bash +task fmt # Format code +task fmt:check # Check formatting +``` + +### Linting + +```bash +task lint # Run golangci-lint +task lint:fix # Run with auto-fix +task vet # Run go vet +``` + +### All Checks + +```bash +task check:all # fmt:check + vet + lint + test +``` + +### Guidelines + +1. **Follow Go conventions** - Use `gofmt`, follow [Effective Go](https://go.dev/doc/effective_go) +2. **Write tests** - All new features should have tests +3. **Document exports** - All exported functions/types need documentation comments +4. **Keep it simple** - Prefer simple, readable code over clever solutions +5. **No breaking changes** - Maintain backward compatibility for public APIs + +--- + +## Pull Request Process + +1. **Sync with upstream** + ```bash + git fetch upstream + git rebase upstream/main + ``` + +2. **Ensure tests pass** + ```bash + task check:all + ``` + +3. **Write meaningful commit messages** + ``` + feat: add support for new SQL builder XYZ + + - Add XYZ builder detection in internal/analyzer/sqlbuilders/ + - Add tests for common XYZ patterns + - Update documentation + ``` + +4. **Push and create PR** + ```bash + git push origin feature/your-feature-name + ``` + +5. **PR Requirements** + - Clear description of changes + - Tests for new functionality + - Documentation updates if needed + - Passing CI checks + +--- + +## Adding New SQL Builders + +To add support for a new SQL builder library: + +### 1. Create Builder File + +Create `internal/analyzer/sqlbuilders/yourbuilder.go`: + +```go +package sqlbuilders + +import ( + "go/ast" +) + +// YourBuilderChecker checks for SELECT * in YourBuilder queries. +type YourBuilderChecker struct { + BaseChecker +} + +// NewYourBuilderChecker creates a new checker for YourBuilder. +func NewYourBuilderChecker() *YourBuilderChecker { + return &YourBuilderChecker{ + BaseChecker: BaseChecker{ + name: "yourbuilder", + packagePath: "github.com/example/yourbuilder", + }, + } +} + +func (c *YourBuilderChecker) Name() string { + return c.name +} + +func (c *YourBuilderChecker) IsApplicable(call *ast.CallExpr) bool { + // Check if this call is from yourbuilder package + return c.isPackageCall(call, "yourbuilder") +} + +func (c *YourBuilderChecker) CheckSelectStar(call *ast.CallExpr) *Violation { + // Implement SELECT * detection logic + return nil +} + +func (c *YourBuilderChecker) CheckChainedCalls(call *ast.CallExpr) []*Violation { + // Check method chains for SELECT * + return nil +} +``` + +### 2. Register in Registry + +Update `internal/analyzer/sqlbuilders/interface.go`: + +```go +func NewRegistry(cfg *config.SQLBuildersConfig) *Registry { + r := &Registry{checkers: make([]SQLBuilderChecker, 0)} + + // ... existing builders ... + + if cfg.YourBuilder { + r.checkers = append(r.checkers, NewYourBuilderChecker()) + } + + return r +} +``` + +### 3. Add Configuration + +Update `pkg/config/config.go`: + +```go +type SQLBuildersConfig struct { + // ... existing fields ... + YourBuilder bool `yaml:"yourbuilder"` +} + +func DefaultSQLBuildersConfig() SQLBuildersConfig { + return SQLBuildersConfig{ + // ... existing defaults ... + YourBuilder: true, + } +} +``` + +### 4. Write Tests + +Create `internal/analyzer/sqlbuilders/yourbuilder_test.go` with test cases. + +### 5. Update Documentation + +- Add to README.md SQL builders table +- Add example in `
` block +- Update `.unqueryvet.example.yaml` + +--- + +## Reporting Issues + +### Bug Reports + +Please include: +- Go version (`go version`) +- unqueryvet version (`unqueryvet -version`) +- Operating system +- Minimal reproducible example +- Expected vs actual behavior + +### Feature Requests + +Please include: +- Use case description +- Proposed solution (if any) +- Examples of desired behavior + +--- + +## Questions? + +- Open a [GitHub Issue](https://github.com/MirrexOne/unqueryvet/issues) + +Thank you for contributing! diff --git a/vendor/github.com/MirrexOne/unqueryvet/Dockerfile b/vendor/github.com/MirrexOne/unqueryvet/Dockerfile new file mode 100644 index 000000000..58383d2d1 --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/Dockerfile @@ -0,0 +1,42 @@ +# Build stage +FROM golang:1.24-alpine AS builder + +RUN apk add --no-cache git gcc musl-dev + +WORKDIR /app + +# Copy go mod files +COPY go.mod go.sum ./ +RUN go mod download + +# Copy source +COPY . . + +# Build binaries +RUN CGO_ENABLED=1 go build -ldflags="-s -w" -o /unqueryvet ./cmd/unqueryvet +RUN CGO_ENABLED=1 go build -ldflags="-s -w" -o /unqueryvet-lsp ./cmd/unqueryvet-lsp + +# Final stage +FROM alpine:3.19 + +RUN apk add --no-cache ca-certificates tzdata + +# Create non-root user +RUN adduser -D -u 1000 unqueryvet +USER unqueryvet + +WORKDIR /workspace + +# Copy binaries +COPY --from=builder /unqueryvet /usr/local/bin/ +COPY --from=builder /unqueryvet-lsp /usr/local/bin/ + +# Default command +ENTRYPOINT ["unqueryvet"] +CMD ["./..."] + +# Labels +LABEL org.opencontainers.image.title="Unqueryvet" +LABEL org.opencontainers.image.description="SQL SELECT * linter for Go" +LABEL org.opencontainers.image.source="https://github.com/MirrexOne/unqueryvet" +LABEL org.opencontainers.image.licenses="MIT" diff --git a/vendor/go.uber.org/automaxprocs/LICENSE b/vendor/github.com/MirrexOne/unqueryvet/LICENSE similarity index 87% rename from vendor/go.uber.org/automaxprocs/LICENSE rename to vendor/github.com/MirrexOne/unqueryvet/LICENSE index 20dcf51d9..278a61152 100644 --- a/vendor/go.uber.org/automaxprocs/LICENSE +++ b/vendor/github.com/MirrexOne/unqueryvet/LICENSE @@ -1,4 +1,6 @@ -Copyright (c) 2017 Uber Technologies, Inc. +MIT License + +Copyright (c) 2024 MirrexOne Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -7,13 +9,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/MirrexOne/unqueryvet/README.md b/vendor/github.com/MirrexOne/unqueryvet/README.md new file mode 100644 index 000000000..faa5e7b66 --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/README.md @@ -0,0 +1,900 @@ +# unqueryvet + +[![Go Report Card](https://goreportcard.com/badge/github.com/MirrexOne/unqueryvet)](https://goreportcard.com/report/github.com/MirrexOne/unqueryvet) +[![Go Reference](https://pkg.go.dev/badge/github.com/MirrexOne/unqueryvet.svg)](https://pkg.go.dev/github.com/MirrexOne/unqueryvet) +[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) + +[![JetBrains Plugins](https://img.shields.io/jetbrains/plugin/v/29733-unqueryvet.svg)](https://plugins.jetbrains.com/plugin/29733-unqueryvet) +[![JetBrains Plugins Downloads](https://img.shields.io/jetbrains/plugin/d/29733-unqueryvet.svg)](https://plugins.jetbrains.com/plugin/29733-unqueryvet) + +[![VS Code Marketplace](https://vsmarketplacebadges.dev/version-short/mirrexdev.unqueryvet.svg)](https://marketplace.visualstudio.com/items?itemName=mirrexdev.unqueryvet) +[![VS Code Installs](https://vsmarketplacebadges.dev/installs-short/mirrexdev.unqueryvet.svg)](https://marketplace.visualstudio.com/items?itemName=mirrexdev.unqueryvet) + +[![Get from Marketplace](https://img.shields.io/badge/JetBrains-Get%20Plugin-000000?style=for-the-badge&logo=jetbrains)](https://plugins.jetbrains.com/plugin/29733-unqueryvet) +[![Get from VS Code Marketplace](https://img.shields.io/badge/VS%20Code-Install%20Extension-007ACC?style=for-the-badge&logo=visualstudiocode)](https://marketplace.visualstudio.com/items?itemName=mirrexdev.unqueryvet) + +**unqueryvet** is a comprehensive Go linter for SQL queries. It detects `SELECT *` usage, N+1 query problems, SQL injection vulnerabilities, and provides suggestions for query optimization. + +## Key Features + +| Feature | Description | +| ----------------------------- | ---------------------------------------------------------------------------- | +| **SELECT \* Detection** | Finds `SELECT *` in raw SQL, SQL builders, and templates | +| **N+1 Query Detection** | Identifies queries inside loops | +| **SQL Injection Scanner** | Detects `fmt.Sprintf` and string concatenation vulnerabilities | +| **Transaction Leak Detection**| Detects unclosed transactions and improper lifecycle management | +| **12 SQL Builder Support** | Squirrel, GORM, SQLx, Ent, PGX, Bun, SQLBoiler, Jet, sqlc, goqu, rel, reform | +| **Custom Rules DSL** | Define your own analysis rules | +| **LSP Server** | Real-time IDE integration | +| **Interactive TUI** | Fix issues interactively | + +--- + +## Installation + +### Standalone Tool + +```bash +go install github.com/MirrexOne/unqueryvet/cmd/unqueryvet@latest +``` + +### LSP Server (for IDE integration) + +```bash +go install github.com/MirrexOne/unqueryvet/cmd/unqueryvet-lsp@latest +``` + +### Docker + +```bash +docker pull ghcr.io/mirrexone/unqueryvet:latest +docker run --rm -v $(pwd):/app ghcr.io/mirrexone/unqueryvet /app/... +``` + +### With golangci-lint + +Add to your `.golangci.yml`: + +```yaml +version: "2" + +linters: + enable: + - unqueryvet + + settings: + unqueryvet: + check-sql-builders: true +``` + +--- + +## Quick Start + +### Basic Usage + +```bash +# Analyze all packages (all rules enabled by default) +unqueryvet ./... + +# Verbose output with explanations +unqueryvet -verbose ./... + +# Quiet mode (errors only) for CI/CD +unqueryvet -quiet ./... + +# Show statistics +unqueryvet -stats ./... + +# Interactive fix mode +unqueryvet -fix ./... + +# Show version +unqueryvet -version +``` + +### Default Rules + +All detection rules are **enabled by default**: + +| Rule | Default Severity | Description | +|------|-----------------|-------------| +| `select-star` | warning | Detects `SELECT *` usage | +| `n1-queries` | warning | Detects N+1 query patterns (queries in loops) | +| `sql-injection` | error | Detects SQL injection vulnerabilities | +| `tx-leak` | warning | Detects unclosed SQL transactions | + +To disable a rule, set its severity to `ignore` in your `.unqueryvet.yaml`: + +```yaml +rules: + n1-queries: ignore # Disable N+1 detection +``` + +### CLI Flags + +| Flag | Description | +|------|-------------| +| `-version` | Print version information | +| `-verbose` | Enable verbose output with detailed explanations | +| `-quiet` | Quiet mode (only errors) | +| `-stats` | Show analysis statistics | +| `-no-color` | Disable colored output | +| `-n1` | Force enable N+1 detection (overrides config) | +| `-sqli` | Force enable SQL injection detection (overrides config) | +| `-tx-leak` | Force enable transaction leak detection (overrides config) | +| `-fix` | Interactive fix mode - step through issues and apply fixes | + +### With Configuration File + +```bash +# Create config file +cat > .unqueryvet.yaml << 'EOF' +severity: warning +check-sql-builders: true + +# Rules are enabled by default - configure severity if needed +rules: + select-star: warning + n1-queries: warning + sql-injection: error + +ignore: + - "*_test.go" + - "vendor/**" +EOF + +# Run (auto-loads config) +unqueryvet ./... +``` + +--- + +## Detection Examples + +### 1. SELECT \* Detection + +**Bad code:** + +```go +// Direct SELECT * +query := "SELECT * FROM users" + +// Aliased wildcard +query := "SELECT t.* FROM users t" + +// In subquery +query := "SELECT id FROM (SELECT * FROM users)" + +// String concatenation +query := "SELECT * " + "FROM users" + +// Format string +query := fmt.Sprintf("SELECT * FROM %s", table) + +// SQL builders +squirrel.Select("*").From("users") +db.Model(&User{}).Select("*") +goqu.From("users").Select(goqu.Star()) +``` + +**Good code:** + +```go +// Explicit columns +query := "SELECT id, name, email FROM users" + +// SQL builders +squirrel.Select("id", "name", "email").From("users") +db.Model(&User{}).Select("id", "name", "email") +goqu.From("users").Select("id", "name", "email") +``` + +### 2. N+1 Query Detection + +**Bad code (triggers warning):** + +```go +users, _ := db.Query("SELECT id, name FROM users") +for users.Next() { + var user User + users.Scan(&user.ID, &user.Name) + + // N+1 problem: query inside loop + orders, _ := db.Query("SELECT * FROM orders WHERE user_id = ?", user.ID) +} +``` + +**Good code:** + +```go +// Use JOIN +query := ` + SELECT u.id, u.name, o.id, o.total + FROM users u + LEFT JOIN orders o ON u.id = o.user_id +` + +// Or use IN clause +userIDs := []int{1, 2, 3, 4, 5} +query := "SELECT * FROM orders WHERE user_id IN (?)" +db.Query(query, userIDs) +``` + +### 3. SQL Injection Detection + +**Bad code (triggers warning):** + +```go +// String concatenation with user input +query := "SELECT * FROM users WHERE name = '" + userName + "'" + +// fmt.Sprintf with user input +query := fmt.Sprintf("SELECT * FROM users WHERE id = %s", userID) +``` + +**Good code:** + +```go +// Parameterized query +query := "SELECT id, name FROM users WHERE name = ?" +db.Query(query, userName) + +// Named parameters +query := "SELECT id, name FROM users WHERE id = :id" +db.NamedQuery(query, map[string]interface{}{"id": userID}) +``` + +### 4. Transaction Leak Detection + +Detects unclosed SQL transactions using 19-phase AST analysis. Supports multiple transaction begin methods across different libraries. + +**Supported Begin Methods:** + +| Library | Methods | +|---------|---------| +| database/sql | `Begin`, `BeginTx` | +| sqlx | `Beginx`, `BeginTxx`, `MustBegin`, `MustBeginTx` | +| pgx | `BeginFunc`, `BeginTxFunc` | +| bun | `RunInTx` | +| ent | `Tx`, `NewTx` | + +**Detection Patterns:** + +| Violation Type | Severity | Description | +|----------------|----------|-------------| +| `no_commit_rollback` | critical | Transaction has neither Commit() nor Rollback() | +| `no_rollback` | high | Transaction has Commit() but no Rollback() for error paths | +| `no_commit` | medium | Transaction has Rollback() but no Commit() | +| `early_return` | high | Early return paths bypass Commit() without defer | +| `defer_in_loop` | high | Defer inside loop - defers pile up until function returns | +| `shadowed_transaction` | high | Transaction variable shadowed in inner scope | +| `goroutine_capture` | high | Transaction captured by goroutine without defer | +| `variable_reassignment` | high | Transaction variable reassigned - previous tx may leak | +| `fatal_without_defer` | high | Transaction may leak if os.Exit/log.Fatal called | +| `panic_without_defer` | medium | Transaction may leak if panic() called | +| `conditional_commit` | medium | Commit() inside conditional - may not execute | +| `commit_in_switch` | medium | Commit() in switch/case - may not execute in all cases | +| `commit_in_select` | medium | Commit() in select/case - may not execute | +| `commit_in_loop` | medium | Commit() in loop - may not execute if loop doesn't iterate | +| `deferred_commit` | medium | Using defer Commit() is an antipattern | +| `commit_error_ignored` | low | Commit() error ignored with blank identifier | +| `rollback_error_ignored` | low | Rollback() error ignored with blank identifier | + +**Bad code (triggers error):** + +```go +func createUser(db *sql.DB, name string) error { + tx, err := db.Begin() + if err != nil { + return err + } + // Missing defer tx.Rollback() and missing tx.Commit()! + + _, err = tx.Exec("INSERT INTO users (name) VALUES (?)", name) + if err != nil { + return err // Transaction leaked! + } + return nil +} + +func deferInLoop(db *sql.DB, items []string) error { + for _, item := range items { + tx, _ := db.Begin() + defer tx.Rollback() // Defers pile up until function returns! + tx.Exec("INSERT...", item) + tx.Commit() + } + return nil +} +``` + +**Good code:** + +```go +func createUser(db *sql.DB, name string) error { + tx, err := db.Begin() + if err != nil { + return err + } + defer tx.Rollback() // Safe: called after Commit() is a no-op + + _, err = tx.Exec("INSERT INTO users (name) VALUES (?)", name) + if err != nil { + return err // Rollback will be called via defer + } + + return tx.Commit() +} + +// Using callback pattern (automatically handled) +func createUserCallback(db *pgx.Conn, name string) error { + return db.BeginFunc(ctx, func(tx pgx.Tx) error { + _, err := tx.Exec(ctx, "INSERT INTO users (name) VALUES ($1)", name) + return err // Commit/Rollback handled automatically + }) +} +``` + +--- + +## Configuration + +### Full Configuration File (.unqueryvet.yaml) + +```yaml +# Built-in rules severity (all enabled by default) +# Available values: error, warning, info, ignore +rules: + select-star: warning # SELECT * detection + n1-queries: warning # N+1 query detection + sql-injection: error # SQL injection scanning + tx-leak: warning # Transaction leak detection + +# Diagnostic severity for legacy options: "error" or "warning" +severity: warning + +# Core analysis options +check-sql-builders: true +check-aliased-wildcard: true +check-string-concat: true +check-format-strings: true +check-string-builder: true +check-subqueries: true + +# SQL builder libraries to check +sql-builders: + squirrel: true + gorm: true + sqlx: true + ent: true + pgx: true + bun: true + sqlboiler: true + jet: true + sqlc: true + goqu: true + rel: true + reform: true + +# File patterns to ignore (glob) +ignored-files: + - "*_test.go" + - "testdata/**" + - "vendor/**" + - "mock_*.go" + +# Function patterns to ignore (regex) +ignored-functions: + - "debug\\..*" + - "test.*" + +# Allowed SELECT * patterns (regex) +allowed-patterns: + - "SELECT \\* FROM information_schema\\..*" + - "SELECT \\* FROM pg_catalog\\..*" + - "SELECT \\* FROM temp_.*" +``` + +--- + +## Custom Rules DSL + +Define your own analysis rules using a powerful DSL with three levels of complexity. + +### Level 1: Simple Configuration + +```yaml +# .unqueryvet.yaml +rules: + select-star: error # Built-in rule severity + n1-queries: warning + sql-injection: error + +ignore: + - "*_test.go" + - "testdata/**" + +allow: + - "COUNT(*)" + - "information_schema.*" +``` + +### Level 2: Pattern Matching + +```yaml +custom-rules: + - id: allow-temp-tables + pattern: SELECT * FROM $TABLE + when: isTempTable(table) + action: allow + + - id: dangerous-delete + pattern: DELETE FROM $TABLE + when: "!has_where" + message: "DELETE without WHERE clause" + severity: error + + - id: require-tx-timeout + pattern: db.BeginTx($CTX, $OPTS) + when: "!contains(opts, 'Timeout')" + message: "Transaction should have timeout set" + severity: warning +``` + +### Level 3: Advanced Conditions + +```yaml +custom-rules: + - id: n1-detection + pattern: $DB.Query($QUERY) + when: | + in_loop && + !contains(function, "batch") && + !matches(file, "_test.go$") + message: "N+1 query in loop" + severity: warning + fix: "Use batch query or preloading" +``` + +### DSL Reference + +| **Metavariables** | **Description** | +|-------------------|-----------------| +| `$TABLE` | Table name (with optional schema) | +| `$VAR` | Identifier/variable | +| `$QUERY` | String literal | +| `$COLS` | Column list | +| `$DB` | Database object | + +| **Variables** | **Description** | +|---------------|-----------------| +| `file`, `package`, `function` | Code context | +| `query`, `query_type`, `table` | SQL context | +| `has_where`, `has_join` | Query structure | +| `in_loop`, `loop_depth` | Loop context | +| `builder` | SQL builder type | + +| **Functions** | **Description** | +|---------------|-----------------| +| `contains(s, sub)` | String contains | +| `matches(s, regex)` | Regex match | +| `isSystemTable(t)` | System table check | +| `isTempTable(t)` | Temp table check | +| `isAggregate(q)` | Aggregate function check | + +| **Operators** | **Description** | +|---------------|-----------------| +| `=~`, `!~` | Regex match/not match | +| `&&`, `\|\|`, `!` | Logical operators | + +Full documentation: [docs/DSL.md](docs/DSL.md) + +--- + +## LSP Server (IDE Integration) + +The LSP server provides real-time analysis in your IDE. + +### Starting the Server + +```bash +unqueryvet-lsp +``` + +### VS Code Setup + +Install the extension from `extensions/vscode/` or configure manually: + +```json +// .vscode/settings.json +{ + "unqueryvet.enable": true, + "unqueryvet.path": "unqueryvet-lsp", + // All rules enabled by default, args optional + "unqueryvet.trace.server": "verbose" +} +``` + +### Features + +- **Real-time diagnostics** - See issues as you type +- **Hover information** - Explanations on hover +- **Quick fixes** - One-click fixes for SELECT \* +- **Code completion** - Column name suggestions + +### GoLand/IntelliJ Setup + +1. Build the plugin: `cd extensions/goland && ./gradlew buildPlugin` +2. Install from disk: Settings → Plugins → Install from disk +3. Configure: Settings → Tools → unqueryvet + +--- + +## Interactive TUI Mode + +Fix issues interactively with a terminal UI. + +```bash +unqueryvet -fix ./... +``` + +### Controls + +| Category | Key | Action | +|----------|-----|--------| +| **Navigation** | `↑/k` | Previous issue | +| | `↓/j` | Next issue | +| | `g` | Go to first issue | +| | `G` | Go to last issue | +| **Actions** | `Enter/a` | Apply fix | +| | `s` | Skip issue | +| | `u` | Undo last action | +| | `p` | Toggle preview | +| **Batch** | `A` | Apply all remaining | +| | `S` | Skip all remaining | +| | `R` | Reset all actions | +| **Other** | `e` | Export results to JSON | +| | `?` | Toggle help | +| | `q/Esc` | Quit | + +### Example Session + +``` +Found 15 issues. Review each one: + +[1/15] internal/api/users.go:42:15 +───────────────────────────────────── + 41 | func getUsers(db *sql.DB) { + 42 | query := "SELECT * FROM users" + | ^^^^^^^^^^^^^^^^^^^^^ avoid SELECT * + 43 | rows, _ := db.Query(query) + +Suggestions: + 1. SELECT id, username, email, created_at (from struct User) + 2. SELECT id, username, email + 3. Skip this issue + 4. Edit manually + +Your choice [1-4]: _ +``` + +--- + +## Supported SQL Builders + +### Full Support (12 builders) + +| Builder | Package | Patterns Detected | +| ------------- | ----------------------------------- | -------------------------------------------- | +| **Squirrel** | `github.com/Masterminds/squirrel` | `Select("*")`, `Columns("*")` | +| **GORM** | `gorm.io/gorm` | `Select("*")`, `Find(&users)` without Select | +| **SQLx** | `github.com/jmoiron/sqlx` | `Select()`, raw queries | +| **Ent** | `entgo.io/ent` | Query builder patterns | +| **PGX** | `github.com/jackc/pgx` | `Query()`, `QueryRow()` | +| **Bun** | `github.com/uptrace/bun` | `NewSelect()`, raw queries | +| **SQLBoiler** | `github.com/volatiletech/sqlboiler` | Generated query methods | +| **Jet** | `github.com/go-jet/jet` | `SELECT()`, `STAR` | +| **sqlc** | Generated code | SELECT \* in .sql files | +| **goqu** | `github.com/doug-martin/goqu` | `Select(goqu.Star())`, `SelectAll()` | +| **rel** | `github.com/go-rel/rel` | `Find()`, `FindAll()` without Select | +| **reform** | `gopkg.in/reform.v1` | `FindByPrimaryKeyFrom()`, `SelectAllFrom()` | + +### Examples by Builder + +
+Squirrel + +```go +// Bad +sq.Select("*").From("users") +sq.Select().Columns("*").From("users") + +// Good +sq.Select("id", "name", "email").From("users") +``` + +
+ +
+GORM + +```go +// Bad +db.Select("*").Find(&users) +db.Table("users").Find(&users) // implicit SELECT * + +// Good +db.Select("id", "name", "email").Find(&users) +``` + +
+ +
+goqu + +```go +// Bad +goqu.From("users").Select(goqu.Star()) +goqu.From("users").SelectAll() + +// Good +goqu.From("users").Select("id", "name", "email") +``` + +
+ +
+rel + +```go +// Bad +repo.Find(ctx, &user) // loads all columns +repo.FindAll(ctx, &users) + +// Good +repo.Find(ctx, &user, rel.Select("id", "name", "email")) +``` + +
+ +
+reform + +```go +// Bad +db.FindByPrimaryKeyFrom(UserTable, id, &user) +db.FindAllFrom(UserTable, "status", "active") + +// Good +db.SelectOneFrom(UserTable, "id, name, email WHERE id = ?", id) +``` + +
+ +
+SQLx + +```go +// Bad +db.Select(&users, "SELECT * FROM users") +db.Get(&user, "SELECT * FROM users WHERE id = ?", id) + +// Good +db.Select(&users, "SELECT id, name, email FROM users") +db.Get(&user, "SELECT id, name, email FROM users WHERE id = ?", id) +``` + +
+ +
+Ent + +```go +// Bad - implicit SELECT * +users, err := client.User.Query().All(ctx) + +// Good - explicit column selection +users, err := client.User.Query(). + Select(user.FieldID, user.FieldName, user.FieldEmail). + All(ctx) +``` + +
+ +
+PGX + +```go +// Bad +rows, err := conn.Query(ctx, "SELECT * FROM users") + +// Good +rows, err := conn.Query(ctx, "SELECT id, name, email FROM users") +``` + +
+ +
+Bun + +```go +// Bad +db.NewSelect().Model(&users).Scan(ctx) +db.NewSelect().TableExpr("users").Scan(ctx, &users) + +// Good +db.NewSelect().Model(&users).Column("id", "name", "email").Scan(ctx) +``` + +
+ +
+SQLBoiler + +```go +// Bad - loads all columns +users, err := models.Users().All(ctx, db) +user, err := models.FindUser(ctx, db, userID) + +// Good - explicit column selection +users, err := models.Users( + qm.Select("id", "name", "email"), +).All(ctx, db) +``` + +
+ +
+Jet + +```go +// Bad +stmt := SELECT(User.AllColumns).FROM(User) + +// Good +stmt := SELECT(User.ID, User.Name, User.Email).FROM(User) +``` + +
+ +
+sqlc + +```sql +-- Bad (in .sql file) +-- name: GetUsers :many +SELECT * FROM users; + +-- Good +-- name: GetUsers :many +SELECT id, name, email FROM users; +``` + +
+ +--- + +## Docker & CI/CD + +### Dockerfile + +```dockerfile +FROM golang:1.24-alpine AS builder +RUN go install github.com/MirrexOne/unqueryvet/cmd/unqueryvet@latest + +FROM alpine:latest +COPY --from=builder /go/bin/unqueryvet /usr/local/bin/ +ENTRYPOINT ["unqueryvet"] +``` + +### GitHub Actions + +```yaml +name: SQL Lint + +on: [push, pull_request] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v6 + with: + go-version: '1.24' + + - name: Install unqueryvet + run: go install github.com/MirrexOne/unqueryvet/cmd/unqueryvet@latest + + - name: Run unqueryvet + run: unqueryvet -n1 -sqli -tx-leak ./... +``` + +### GitLab CI + +```yaml +sql-lint: + image: ghcr.io/mirrexone/unqueryvet:latest + script: + - unqueryvet -quiet -n1 -sqli -tx-leak ./... + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" +``` + +--- + +## Exit Codes + +| Code | Meaning | +|------|---------| +| 0 | No issues found | +| 1 | Warnings found | +| 2 | Errors found | +| 3 | Analysis failed | + +--- + +## Documentation + +- [CLI Features Guide](docs/CLI_FEATURES.md) +- [Custom Rules DSL](docs/DSL.md) +- [IDE Integration Guide](docs/IDE_INTEGRATION.md) + +--- + +## Development + +### Build + +```bash +go build ./cmd/unqueryvet +go build ./cmd/unqueryvet-lsp +``` + +### Test + +```bash +go test ./... +``` + +### Install locally + +```bash +go install ./cmd/unqueryvet +go install ./cmd/unqueryvet-lsp +``` + +--- + +## Contributing + +```bash +git clone https://github.com/MirrexOne/unqueryvet.git +cd unqueryvet +go mod download +go test ./... +go build ./... +``` + +See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines. + +--- + +## License + +MIT License - see [LICENSE](LICENSE) file for details. + +--- + +## Acknowledgments + +- Built on [golang.org/x/tools/go/analysis](https://pkg.go.dev/golang.org/x/tools/go/analysis) +- TUI powered by [Bubbletea](https://github.com/charmbracelet/bubbletea) + +--- + +## Support + +- **Bug Reports**: [GitHub Issues](https://github.com/MirrexOne/unqueryvet/issues) diff --git a/vendor/github.com/MirrexOne/unqueryvet/RELEASE.md b/vendor/github.com/MirrexOne/unqueryvet/RELEASE.md new file mode 100644 index 000000000..e1a797ede --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/RELEASE.md @@ -0,0 +1,203 @@ +# Release Process + +This document describes how to create a new release of Unqueryvet and its VS Code extension. + +## Prerequisites + +- Push access to the repository +- Go 1.21+ installed +- Node.js 20+ installed +- Git configured + +## Release Workflow + +### Option 1: Fully Automated (Recommended) + +1. **Create a Git tag:** + ```bash + git tag -a v1.0.0 -m "Release v1.0.0" + git push origin v1.0.0 + ``` + +2. **Create GitHub Release:** + - Go to https://github.com/MirrexOne/unqueryvet/releases/new + - Select the tag you just pushed (v1.0.0) + - Title: `v1.0.0` + - Description: List of changes + - Click "Publish release" + +3. **What happens automatically:** + - ✅ GitHub Actions builds LSP binaries for all platforms + - ✅ Binaries are attached to the release + - ✅ Checksums file is generated + - ✅ VS Code extension is built + - ✅ VS Code extension is published to Marketplace + - ✅ Extension .vsix is attached to the release + +4. **Wait 5-10 minutes** for workflows to complete + +5. **Verify:** + - Check release has all LSP binaries attached + - Check VS Code Marketplace: https://marketplace.visualstudio.com/items?itemName=mirrexdev.unqueryvet + - Test automatic LSP download in a fresh VS Code instance + +### Option 2: Manual Build + +If you need to build locally: + +1. **Build LSP binaries:** + ```bash + # Using Task + task build:lsp:release + + # Or using script directly + ./scripts/build-lsp.sh v1.0.0 # Linux/macOS + # OR + powershell ./scripts/build-lsp.ps1 -Version v1.0.0 # Windows + ``` + +2. **Check dist/ folder:** + ```bash + ls -lh dist/ + ``` + + You should see: + - unqueryvet-lsp-windows-amd64.exe + - unqueryvet-lsp-windows-arm64.exe + - unqueryvet-lsp-linux-amd64 + - unqueryvet-lsp-linux-arm64 + - unqueryvet-lsp-darwin-amd64 + - unqueryvet-lsp-darwin-arm64 + - checksums.txt + +3. **Upload to GitHub Release manually:** + - Create release on GitHub + - Upload all files from dist/ + +4. **Build VS Code extension:** + ```bash + cd extensions/vscode + npm install + npm run compile + npx @vscode/vsce package + ``` + +5. **Publish VS Code extension:** + ```bash + npx @vscode/vsce publish -p YOUR_PAT_TOKEN + ``` + +## Platform Support + +LSP binaries are built for: + +| Platform | Architecture | File | +|----------|-------------|------| +| Windows | amd64 | unqueryvet-lsp-windows-amd64.exe | +| Windows | arm64 | unqueryvet-lsp-windows-arm64.exe | +| Linux | amd64 | unqueryvet-lsp-linux-amd64 | +| Linux | arm64 | unqueryvet-lsp-linux-arm64 | +| macOS | amd64 | unqueryvet-lsp-darwin-amd64 | +| macOS | arm64 (M1+) | unqueryvet-lsp-darwin-arm64 | + +## Version Numbering + +Follow Semantic Versioning (semver): + +- **Major** (v2.0.0): Breaking changes +- **Minor** (v1.1.0): New features, backward compatible +- **Patch** (v1.0.1): Bug fixes, backward compatible + +## Checklist Before Release + +- [ ] All tests passing (`task test`) +- [ ] Code formatted (`task fmt`) +- [ ] Linter passing (`task lint`) +- [ ] CHANGELOG.md updated +- [ ] Version bumped in: + - [ ] extensions/vscode/package.json + - [ ] extensions/vscode/CHANGELOG.md +- [ ] README.md up to date +- [ ] All PRs merged +- [ ] No breaking changes (or documented) + +## Post-Release + +1. **Test installation:** + ```bash + # Test Go installation + go install github.com/MirrexOne/unqueryvet/cmd/unqueryvet@latest + + # Test LSP installation + go install github.com/MirrexOne/unqueryvet/cmd/unqueryvet-lsp@latest + ``` + +2. **Test VS Code extension:** + - Install from Marketplace + - Open a Go file + - Verify automatic LSP download works + - Verify diagnostics appear + +3. **Update documentation** if needed + +4. **Announce release:** + - Twitter/X + - Reddit r/golang + - LinkedIn + - Discord communities + +## Troubleshooting + +### GitHub Actions fails + +- Check workflow logs: https://github.com/MirrexOne/unqueryvet/actions +- Common issues: + - VSCE_PAT expired → regenerate in Azure DevOps + - Build error → test locally first + - Permission error → check GITHUB_TOKEN permissions + +### VS Code extension not publishing + +- Verify VSCE_PAT secret is set in GitHub +- Check publisher ID matches in package.json (mirrexdev) +- Ensure version number is incremented + +### LSP binaries missing + +- Check GitHub Actions workflow completed +- Verify tag was pushed correctly +- Check release was published (not draft) + +## Emergency Rollback + +If a release has critical bugs: + +1. **Mark as pre-release** on GitHub +2. **Unpublish VS Code extension:** + ```bash + npx @vscode/vsce unpublish mirrexdev.unqueryvet@VERSION + ``` +3. **Fix issues** and create new patch release +4. **Communicate** to users about the issue + +## Files Modified Per Release + +- `extensions/vscode/package.json` - bump version +- `extensions/vscode/CHANGELOG.md` - add release notes +- `CHANGELOG.md` - add release notes (if exists) +- Git tag - create new tag + +## Automation Scripts + +| Script | Purpose | +|--------|---------| +| `scripts/build-lsp.sh` | Build LSP for all platforms (Unix) | +| `scripts/build-lsp.ps1` | Build LSP for all platforms (Windows) | +| `.github/workflows/release-lsp.yml` | Auto-build LSP on release | +| `.github/workflows/publish-vscode-extension.yml` | Auto-publish VS Code extension | + +## Support + +For issues with releases: +- GitHub Issues: https://github.com/MirrexOne/unqueryvet/issues +- GitHub Discussions: https://github.com/MirrexOne/unqueryvet/discussions diff --git a/vendor/github.com/MirrexOne/unqueryvet/Taskfile.yml b/vendor/github.com/MirrexOne/unqueryvet/Taskfile.yml new file mode 100644 index 000000000..b93402fe4 --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/Taskfile.yml @@ -0,0 +1,398 @@ +# https://taskfile.dev +version: "3" + +vars: + VERSION: + sh: git describe --tags --always --dirty 2>/dev/null || echo "dev" + COMMIT: + sh: git rev-parse --short HEAD 2>/dev/null || echo "unknown" + DATE: + sh: date -u +"%Y-%m-%dT%H:%M:%SZ" + BUILT_BY: + sh: echo "$(whoami)@$(hostname)" + LDFLAGS: >- + -X 'github.com/MirrexOne/unqueryvet/internal/version.Version={{.VERSION}}' + -X 'github.com/MirrexOne/unqueryvet/internal/version.Commit={{.COMMIT}}' + -X 'github.com/MirrexOne/unqueryvet/internal/version.Date={{.DATE}}' + -X 'github.com/MirrexOne/unqueryvet/internal/version.BuiltBy={{.BUILT_BY}}' + BINARY_NAME: unqueryvet + BINARY_EXT: + sh: if [ "$(go env GOOS)" = "windows" ]; then echo ".exe"; fi + +tasks: + default: + desc: Format, test, and build + cmds: + - task: fmt + - task: test + - task: build + + # ============================================================================ + # BUILD TASKS + # ============================================================================ + + build: + desc: Build the unqueryvet binary + cmds: + - echo "Building {{.BINARY_NAME}}..." + - go build -v -ldflags "{{.LDFLAGS}}" -o {{.BINARY_NAME}}{{.BINARY_EXT}} ./cmd/unqueryvet + sources: + - "**/*.go" + - go.mod + - go.sum + generates: + - "{{.BINARY_NAME}}{{.BINARY_EXT}}" + + build:lsp: + desc: Build the LSP server binary + cmds: + - echo "Building unqueryvet-lsp..." + - go build -v -ldflags "{{.LDFLAGS}}" -o unqueryvet-lsp{{.BINARY_EXT}} ./cmd/unqueryvet-lsp + sources: + - "**/*.go" + - go.mod + generates: + - "unqueryvet-lsp{{.BINARY_EXT}}" + + build:all: + desc: Build all binaries + cmds: + - task: build + - task: build:lsp + + build:lsp:all: + desc: Build LSP server for all platforms (cross-compile) + cmds: + - echo "Building LSP for all platforms..." + - | + if [ "$(go env GOOS)" = "windows" ]; then + powershell -ExecutionPolicy Bypass -File ./scripts/build-lsp.ps1 -Version "{{.VERSION}}" + else + chmod +x ./scripts/build-lsp.sh + ./scripts/build-lsp.sh "{{.VERSION}}" + fi + - echo "Binaries available in dist/" + + build:lsp:release: + desc: Build LSP for all platforms with release optimizations + cmds: + - echo "Building LSP release binaries..." + - | + if [ "$(go env GOOS)" = "windows" ]; then + powershell -ExecutionPolicy Bypass -File ./scripts/build-lsp.ps1 -Version "{{.VERSION}}" + else + chmod +x ./scripts/build-lsp.sh + ./scripts/build-lsp.sh "{{.VERSION}}" + fi + - cd dist && sha256sum * > checksums.txt + - echo "Release binaries with checksums in dist/" + + install: + desc: Install unqueryvet binary to GOPATH/bin + cmds: + - echo "Installing unqueryvet..." + - go install -ldflags "{{.LDFLAGS}}" ./cmd/unqueryvet + + install:all: + desc: Install all binaries to GOPATH/bin + cmds: + - echo "Installing all binaries..." + - go install -ldflags "{{.LDFLAGS}}" ./cmd/unqueryvet + - go install -ldflags "{{.LDFLAGS}}" ./cmd/unqueryvet-lsp + + # ============================================================================ + # TEST TASKS + # ============================================================================ + + test: + desc: Run tests with race detection (requires CGO on Windows) + cmds: + - echo "Running tests..." + - go test -v -coverprofile=coverage.out ./... + + test:race: + desc: Run tests with race detection (requires CGO_ENABLED=1) + cmds: + - echo "Running tests with race detection..." + - go test -v -race -coverprofile=coverage.out ./... + + test:short: + desc: Run short tests (skip long-running tests) + cmds: + - echo "Running short tests..." + - go test -v -short ./... + + test:unit: + desc: Run unit tests only + cmds: + - echo "Running unit tests..." + - go test -v ./internal/... + + test:integration: + desc: Run integration tests + cmds: + - echo "Running integration tests..." + - go test -v -tags=integration ./... + + bench: + desc: Run benchmarks + cmds: + - echo "Running benchmarks..." + - go test -bench=. -benchmem ./internal/analyzer + + bench:all: + desc: Run all benchmarks with comparison + cmds: + - echo "Running all benchmarks..." + - go test -bench=. -benchmem -count=5 ./... | tee bench.txt + + coverage: + desc: Generate coverage report + deps: [test] + cmds: + - echo "Generating coverage report..." + - go tool cover -html=coverage.out -o coverage.html + - echo "Coverage report generated - coverage.html" + + coverage:func: + desc: Show function coverage + deps: [test] + cmds: + - go tool cover -func=coverage.out + + # ============================================================================ + # FORMAT & LINT TASKS + # ============================================================================ + + fmt: + desc: Format all Go files + cmds: + - echo "Formatting code..." + - gofmt -s -w . + - go fmt ./... + + fmt:check: + desc: Check if code is formatted + cmds: + - echo "Checking code formatting..." + - | + UNFORMATTED=$(gofmt -s -l .) + if [ -n "$UNFORMATTED" ]; then + echo "The following files need formatting:" + echo "$UNFORMATTED" + exit 1 + else + echo "All files are properly formatted" + fi + + lint: + desc: Run golangci-lint + cmds: + - echo "Running linter..." + - golangci-lint run ./... + + lint:fix: + desc: Run golangci-lint with auto-fix + cmds: + - echo "Running linter with auto-fix..." + - golangci-lint run --fix ./... + + vet: + desc: Run go vet + cmds: + - echo "Running go vet..." + - go vet ./... + + check: + desc: Run unqueryvet on the project itself + cmds: + - echo "Running unqueryvet on project..." + - go run ./cmd/unqueryvet ./... + + check:all: + desc: Run all checks (fmt, vet, lint, test) + cmds: + - task: fmt:check + - task: vet + - task: lint + - task: test + + # ============================================================================ + # DEPENDENCY TASKS + # ============================================================================ + + deps: + desc: Update and verify dependencies + cmds: + - echo "Updating dependencies..." + - go mod tidy + - go mod verify + + deps:download: + desc: Download all dependencies + cmds: + - echo "Downloading dependencies..." + - go mod download + + deps:upgrade: + desc: Upgrade all dependencies to latest + cmds: + - echo "Upgrading dependencies..." + - go get -u ./... + - go mod tidy + + deps:graph: + desc: Show dependency graph + cmds: + - go mod graph + + # ============================================================================ + # DOCKER TASKS + # ============================================================================ + + docker:build: + desc: Build Docker image + cmds: + - echo "Building Docker image..." + - docker build -t unqueryvet:{{.VERSION}} -t unqueryvet:latest . + + docker:run: + desc: Run unqueryvet in Docker + cmds: + - docker run --rm -v $(pwd):/app unqueryvet:latest /app/... + + docker:push: + desc: Push Docker image to registry + vars: + REGISTRY: '{{.REGISTRY | default "ghcr.io/mirrexone"}}' + cmds: + - docker tag unqueryvet:{{.VERSION}} {{.REGISTRY}}/unqueryvet:{{.VERSION}} + - docker tag unqueryvet:latest {{.REGISTRY}}/unqueryvet:latest + - docker push {{.REGISTRY}}/unqueryvet:{{.VERSION}} + - docker push {{.REGISTRY}}/unqueryvet:latest + + # ============================================================================ + # RELEASE TASKS + # ============================================================================ + + release:snapshot: + desc: Create a snapshot release (no publish) + cmds: + - echo "Creating snapshot release..." + - goreleaser release --snapshot --clean + + release: + desc: Create and publish a release + cmds: + - echo "Creating release..." + - goreleaser release --clean + preconditions: + - sh: test -n "$GITHUB_TOKEN" + msg: "GITHUB_TOKEN is required" + + # ============================================================================ + # DEVELOPMENT TASKS + # ============================================================================ + + dev: + desc: Run in development mode with watch + cmds: + - echo "Starting development mode..." + - go run ./cmd/unqueryvet -watch ./... + + dev:lsp: + desc: Run LSP server in development mode + cmds: + - echo "Starting LSP server..." + - go run ./cmd/unqueryvet-lsp + + generate: + desc: Run go generate + cmds: + - echo "Running go generate..." + - go generate ./... + + # ============================================================================ + # CLEAN TASKS + # ============================================================================ + + clean: + desc: Remove build artifacts + cmds: + - echo "Cleaning..." + - rm -f {{.BINARY_NAME}}{{.BINARY_EXT}} + - rm -f unqueryvet-lsp{{.BINARY_EXT}} + - rm -f coverage.out coverage.html + - rm -f bench.txt + - rm -rf dist/ + - go clean + + clean:cache: + desc: Clean Go build cache + cmds: + - echo "Cleaning Go cache..." + - go clean -cache + + clean:testcache: + desc: Clean Go test cache + cmds: + - echo "Cleaning test cache..." + - go clean -testcache + + clean:all: + desc: Clean everything + cmds: + - task: clean + - task: clean:cache + - task: clean:testcache + + # ============================================================================ + # EXTENSION TASKS + # ============================================================================ + + ext:vscode:build: + desc: Build VS Code extension + dir: extensions/vscode + cmds: + - echo "Building VS Code extension..." + - npm install + - npm run compile + + ext:vscode:package: + desc: Package VS Code extension + dir: extensions/vscode + cmds: + - echo "Packaging VS Code extension..." + - npm run package + + ext:goland:build: + desc: Build GoLand plugin + dir: extensions/goland + cmds: + - echo "Building GoLand plugin..." + - ./gradlew buildPlugin + + # ============================================================================ + # DOCUMENTATION TASKS + # ============================================================================ + + docs:serve: + desc: Serve documentation locally + cmds: + - echo "Serving docs on http://localhost:8000" + - python -m http.server 8000 --directory docs + + docs:godoc: + desc: Run godoc server + cmds: + - echo "Starting godoc on http://localhost:6060" + - godoc -http=:6060 + + # ============================================================================ + # HELP + # ============================================================================ + + help: + desc: Show all available tasks + cmds: + - task --list-all diff --git a/vendor/github.com/MirrexOne/unqueryvet/action.yml b/vendor/github.com/MirrexOne/unqueryvet/action.yml new file mode 100644 index 000000000..d01b9ae95 --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/action.yml @@ -0,0 +1,92 @@ +name: "Unqueryvet" +description: "Detect inconsistencies in Go SQL queries" +author: "MirrexOne" + +branding: + icon: "search" + color: "blue" + +inputs: + version: + description: "Version of unqueryvet to use" + required: false + default: "latest" + working-directory: + description: "Working directory" + required: false + default: "." + args: + description: "Arguments to pass to unqueryvet" + required: false + default: "./..." + fail-on-issues: + description: "Fail the action if issues are found" + required: false + default: "true" + check-n1: + description: "Enable N+1 query detection" + required: false + default: "false" + check-sqli: + description: "Enable SQL injection detection" + required: false + default: "false" + +outputs: + issues-found: + description: "Number of issues found" + value: ${{ steps.run.outputs.issues }} + exit-code: + description: "Exit code from unqueryvet" + value: ${{ steps.run.outputs.exit_code }} + +runs: + using: "composite" + steps: + - name: Install unqueryvet + shell: bash + run: | + if [ "${{ inputs.version }}" = "latest" ]; then + go install github.com/MirrexOne/unqueryvet/cmd/unqueryvet@latest + else + go install github.com/MirrexOne/unqueryvet/cmd/unqueryvet@${{ inputs.version }} + fi + + - name: Run unqueryvet + id: run + shell: bash + working-directory: ${{ inputs.working-directory }} + run: | + set +e + + ARGS="${{ inputs.args }}" + + if [ "${{ inputs.check-n1 }}" = "true" ]; then + ARGS="-n1 $ARGS" + fi + + if [ "${{ inputs.check-sqli }}" = "true" ]; then + ARGS="-sqli $ARGS" + fi + + OUTPUT=$(unqueryvet $ARGS 2>&1) + EXIT_CODE=$? + + echo "$OUTPUT" + + # Count issues (lines with file:line:column pattern) + ISSUES=$(echo "$OUTPUT" | grep -c ":[0-9]*:[0-9]*:" || true) + + echo "issues=$ISSUES" >> $GITHUB_OUTPUT + echo "exit_code=$EXIT_CODE" >> $GITHUB_OUTPUT + + if [ "${{ inputs.fail-on-issues }}" = "true" ] && [ $EXIT_CODE -ne 0 ]; then + echo "::error::Unqueryvet found $ISSUES issues" + exit 1 + fi + + if [ $ISSUES -eq 0 ]; then + echo "::notice::No SELECT * issues found!" + else + echo "::warning::Found $ISSUES SELECT * issues" + fi diff --git a/vendor/github.com/MirrexOne/unqueryvet/analyzer.go b/vendor/github.com/MirrexOne/unqueryvet/analyzer.go new file mode 100644 index 000000000..28c3ba6e8 --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/analyzer.go @@ -0,0 +1,27 @@ +// Package unqueryvet provides a Go static analysis tool that detects SELECT * usage +package unqueryvet + +import ( + "golang.org/x/tools/go/analysis" + + "github.com/MirrexOne/unqueryvet/internal/analyzer" + "github.com/MirrexOne/unqueryvet/pkg/config" +) + +// Analyzer is the main unqueryvet analyzer instance +// This is the primary export that golangci-lint will use +var Analyzer = analyzer.NewAnalyzer() + +// New creates a new instance of the unqueryvet analyzer +func New() *analysis.Analyzer { + return Analyzer +} + +// NewWithConfig creates a new analyzer instance with custom configuration +// This is the recommended way to use unqueryvet with custom settings +func NewWithConfig(cfg *config.UnqueryvetSettings) *analysis.Analyzer { + if cfg == nil { + return Analyzer + } + return analyzer.NewAnalyzerWithSettings(*cfg) +} diff --git a/vendor/github.com/MirrexOne/unqueryvet/config.go b/vendor/github.com/MirrexOne/unqueryvet/config.go new file mode 100644 index 000000000..03626ad38 --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/config.go @@ -0,0 +1,11 @@ +package unqueryvet + +import "github.com/MirrexOne/unqueryvet/pkg/config" + +// Settings is a type alias for UnqueryvetSettings from the config package. +type Settings = config.UnqueryvetSettings + +// DefaultSettings returns the default configuration for Unqueryvet. +func DefaultSettings() Settings { + return config.DefaultSettings() +} diff --git a/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/analyzer.go b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/analyzer.go new file mode 100644 index 000000000..b10e9657c --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/analyzer.go @@ -0,0 +1,414 @@ +// Package analyzer provides the SQL static analysis implementation for detecting SELECT * usage. +package analyzer + +import ( + "go/ast" + "go/token" + "regexp" + "strconv" + "strings" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/ast/inspector" + + "github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders" + "github.com/MirrexOne/unqueryvet/pkg/config" +) + +const ( + // defaultWarningMessage is the standard warning for SELECT * usage + defaultWarningMessage = "avoid SELECT * - explicitly specify needed columns for better performance, maintainability and stability" +) + +// Precompiled regex patterns for performance +var ( + // aliasedWildcardPattern matches SELECT alias.* patterns like "SELECT t.*", "SELECT u.*, o.*" + aliasedWildcardPattern = regexp.MustCompile(`(?i)SELECT\s+(?:[A-Za-z_][A-Za-z0-9_]*\s*\.\s*\*\s*,?\s*)+`) + + // subquerySelectStarPattern matches SELECT * in subqueries like "(SELECT * FROM ...)" + subquerySelectStarPattern = regexp.MustCompile(`(?i)\(\s*SELECT\s+\*`) +) + +// NewAnalyzer creates the Unqueryvet analyzer with enhanced logic for production use +func NewAnalyzer() *analysis.Analyzer { + return NewAnalyzerWithSettings(config.DefaultSettings()) +} + +// NewAnalyzerWithSettings creates analyzer with provided settings for golangci-lint integration +func NewAnalyzerWithSettings(s config.UnqueryvetSettings) *analysis.Analyzer { + return &analysis.Analyzer{ + Name: "unqueryvet", + Doc: "detects SELECT * in SQL queries and SQL builders, preventing performance issues and encouraging explicit column selection", + Run: func(pass *analysis.Pass) (any, error) { + return RunWithConfig(pass, &s) + }, + Requires: []*analysis.Analyzer{inspect.Analyzer}, + } +} + +// analysisContext holds the context for AST analysis +type analysisContext struct { + pass *analysis.Pass + cfg *config.UnqueryvetSettings + filter *FilterContext + builderRegistry *sqlbuilders.Registry +} + +// RunWithConfig performs analysis with provided configuration +// This is the main entry point for configured analysis +func RunWithConfig(pass *analysis.Pass, cfg *config.UnqueryvetSettings) (any, error) { + insp := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + + // Use provided configuration or default if nil + if cfg == nil { + defaultSettings := config.DefaultSettings() + cfg = &defaultSettings + } + + // Create filter context for efficient filtering + filter, err := NewFilterContext(cfg) + if err != nil { + // If filter creation fails, continue without filtering + filter = nil + } + + // Check if current file should be ignored + if filter != nil && len(pass.Files) > 0 { + fileName := pass.Fset.File(pass.Files[0].Pos()).Name() + if filter.IsIgnoredFile(fileName) { + return nil, nil + } + } + + // Create SQL builder registry for checking SQL builder patterns + var builderRegistry *sqlbuilders.Registry + if cfg.CheckSQLBuilders { + builderRegistry = sqlbuilders.NewRegistry(&cfg.SQLBuilders) + } + + ctx := &analysisContext{ + pass: pass, + cfg: cfg, + filter: filter, + builderRegistry: builderRegistry, + } + + // Define AST node types we're interested in + nodeFilter := []ast.Node{ + (*ast.CallExpr)(nil), // Function/method calls + (*ast.File)(nil), // Files (for SQL builder analysis) + (*ast.AssignStmt)(nil), // Assignment statements for standalone literals + (*ast.GenDecl)(nil), // General declarations (const, var, type) + (*ast.BinaryExpr)(nil), // Binary expressions for string concatenation + } + + // Walk through all AST nodes and analyze them + insp.Preorder(nodeFilter, ctx.handleNode) + + return nil, nil +} + +// handleNode dispatches AST node to appropriate handler +func (ctx *analysisContext) handleNode(n ast.Node) { + switch node := n.(type) { + case *ast.File: + ctx.handleFileNode(node) + case *ast.AssignStmt: + // Check assignment statements for standalone SQL literals + checkAssignStmt(ctx.pass, node, ctx.cfg) + case *ast.GenDecl: + // Check constant and variable declarations + checkGenDecl(ctx.pass, node, ctx.cfg) + case *ast.CallExpr: + ctx.handleCallExpr(node) + // Analyze function calls for SQL with SELECT * usage + case *ast.BinaryExpr: + ctx.handleBinaryExpr(node) + } +} + +// handleFileNode processes file-level analysis +func (ctx *analysisContext) handleFileNode(node *ast.File) { + // Note: SQL builder analysis with type checking is done by Registry.Check() in handleCallExpr. + // The old analyzeSQLBuilders() function was removed because it didn't use type checking + // and caused false positives (issue #5). + + if ctx.cfg.N1DetectionEnabled { + AnalyzeN1(ctx.pass, node) + } + if ctx.cfg.SQLInjectionDetectionEnabled { + AnalyzeSQLInjection(ctx.pass, node) + } + if ctx.cfg.TxLeakDetectionEnabled { + AnalyzeTxLeaks(ctx.pass, node) + } +} + +// handleCallExpr processes function/method call expressions +func (ctx *analysisContext) handleCallExpr(node *ast.CallExpr) { + if ctx.filter != nil && ctx.filter.IsIgnoredFunction(node) { + return + } + + if ctx.cfg.CheckFormatStrings && CheckFormatFunction(ctx.pass, node, ctx.cfg) { + ctx.pass.Report(analysis.Diagnostic{ + Pos: node.Pos(), + Message: getDetailedWarningMessage("format_string"), + }) + return + } + + if ctx.builderRegistry != nil && ctx.builderRegistry.HasCheckers() { + violations := ctx.builderRegistry.Check(ctx.pass.TypesInfo, node) + for _, v := range violations { + ctx.pass.Report(analysis.Diagnostic{ + Pos: v.Pos, + End: v.End, + Message: v.Message, + }) + } + if len(violations) > 0 { + return + } + } + + checkCallExpr(ctx.pass, node, ctx.cfg) +} + +// handleBinaryExpr processes binary expressions (string concatenation) +func (ctx *analysisContext) handleBinaryExpr(node *ast.BinaryExpr) { + if ctx.cfg.CheckStringConcat && CheckConcatenation(ctx.pass, node, ctx.cfg) { + ctx.pass.Report(analysis.Diagnostic{ + Pos: node.Pos(), + Message: getDetailedWarningMessage("concat"), + }) + } +} + +// checkAssignStmt checks assignment statements for standalone SQL literals +func checkAssignStmt(pass *analysis.Pass, stmt *ast.AssignStmt, cfg *config.UnqueryvetSettings) { + // Check right-hand side expressions for string literals with SELECT * + for _, expr := range stmt.Rhs { + // Only check direct string literals, not function calls + if lit, ok := expr.(*ast.BasicLit); ok && lit.Kind == token.STRING { + content := normalizeSQLQuery(lit.Value) + if isSelectStarQuery(content, cfg) { + pass.Report(analysis.Diagnostic{ + Pos: lit.Pos(), + Message: getWarningMessage(), + }) + } + } + } +} + +// checkGenDecl checks general declarations (const, var) for SELECT * in SQL queries +func checkGenDecl(pass *analysis.Pass, decl *ast.GenDecl, cfg *config.UnqueryvetSettings) { + // Only check const and var declarations + if decl.Tok != token.CONST && decl.Tok != token.VAR { + return + } + + // Iterate through all specifications in the declaration + for _, spec := range decl.Specs { + // Type assert to ValueSpec (const/var specifications) + valueSpec, ok := spec.(*ast.ValueSpec) + if !ok { + continue + } + + // Check all values in the specification + for _, value := range valueSpec.Values { + // Only check direct string literals + if lit, ok := value.(*ast.BasicLit); ok && lit.Kind == token.STRING { + content := normalizeSQLQuery(lit.Value) + if isSelectStarQuery(content, cfg) { + pass.Report(analysis.Diagnostic{ + Pos: lit.Pos(), + Message: getWarningMessage(), + }) + } + } + } + } +} + +// checkCallExpr analyzes function calls for SQL with SELECT * usage +// Note: SQL builder checking with type verification is done by Registry.Check() in handleCallExpr. +// This function only checks raw SQL strings in function arguments. +func checkCallExpr(pass *analysis.Pass, call *ast.CallExpr, cfg *config.UnqueryvetSettings) { + // Check function call arguments for strings with SELECT * + for _, arg := range call.Args { + if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { + content := normalizeSQLQuery(lit.Value) + if isSelectStarQuery(content, cfg) { + pass.Report(analysis.Diagnostic{ + Pos: lit.Pos(), + Message: getWarningMessage(), + }) + } + } + } +} + +// NormalizeSQLQuery normalizes SQL query for analysis with advanced escape sequence handling. +// Exported for testing purposes. +func NormalizeSQLQuery(query string) string { + return normalizeSQLQuery(query) +} + +func normalizeSQLQuery(query string) string { + if len(query) < 2 { + return query + } + + first, last := query[0], query[len(query)-1] + + // 1. Handle different quote types with escape sequence processing + if first == '"' && last == '"' { + // For regular strings check for escape sequences + if !strings.Contains(query, "\\") { + query = trimQuotes(query) + } else if unquoted, err := strconv.Unquote(query); err == nil { + // Use standard Go unquoting for proper escape sequence handling + query = unquoted + } else { + // Fallback: simple quote removal + query = trimQuotes(query) + } + } else if first == '`' && last == '`' { + // Raw strings - simply remove backticks + query = trimQuotes(query) + } + + // 2. Process comments line by line before normalization + lines := strings.Split(query, "\n") + var processedParts []string + + for _, line := range lines { + // Remove comments from current line + if idx := strings.Index(line, "--"); idx != -1 { + line = line[:idx] + } + + // Add non-empty lines + if trimmed := strings.TrimSpace(line); trimmed != "" { + processedParts = append(processedParts, trimmed) + } + } + + // 3. Reassemble query and normalize + query = strings.Join(processedParts, " ") + query = strings.ToUpper(query) + query = strings.ReplaceAll(query, "\t", " ") + query = regexp.MustCompile(`\s+`).ReplaceAllString(query, " ") + + return strings.TrimSpace(query) +} + +// trimQuotes removes first and last character (quotes) +func trimQuotes(query string) string { + return query[1 : len(query)-1] +} + +// IsSelectStarQuery determines if query contains SELECT * with enhanced allowed patterns support. +// Exported for testing purposes. +func IsSelectStarQuery(query string, cfg *config.UnqueryvetSettings) bool { + return isSelectStarQuery(query, cfg) +} + +func isSelectStarQuery(query string, cfg *config.UnqueryvetSettings) bool { + // Check allowed patterns first - if query matches an allowed pattern, ignore it + for _, pattern := range cfg.AllowedPatterns { + if matched, _ := regexp.MatchString(pattern, query); matched { + return false + } + } + + upperQuery := strings.ToUpper(query) + + // Check for SELECT * in query (case-insensitive) + if strings.Contains(upperQuery, "SELECT *") { //nolint:unqueryvet + // Ensure this is actually an SQL query by checking for SQL keywords + sqlKeywords := []string{"FROM", "WHERE", "JOIN", "GROUP", "ORDER", "HAVING", "UNION", "LIMIT"} + for _, keyword := range sqlKeywords { + if strings.Contains(upperQuery, keyword) { + return true + } + } + + // Also check if it's just "SELECT *" without other keywords (still problematic) + trimmed := strings.TrimSpace(upperQuery) + if trimmed == "SELECT *" { + return true + } + } + + // Check for SELECT alias.* patterns (e.g., SELECT t.*, SELECT u.*, o.*) + if cfg.CheckAliasedWildcard && isSelectAliasStarQuery(query) { + return true + } + + // Check for SELECT * in subqueries (e.g., (SELECT * FROM ...)) + if cfg.CheckSubqueries && isSelectStarInSubquery(query) { + return true + } + + return false +} + +// isSelectAliasStarQuery detects SELECT alias.* patterns like "SELECT t.*", "SELECT u.*, o.*" +func isSelectAliasStarQuery(query string) bool { + return aliasedWildcardPattern.MatchString(query) +} + +// isSelectStarInSubquery detects SELECT * in subqueries like "(SELECT * FROM ...)" +func isSelectStarInSubquery(query string) bool { + return subquerySelectStarPattern.MatchString(query) +} + +// getWarningMessage returns informative warning message +func getWarningMessage() string { + return defaultWarningMessage +} + +// getDetailedWarningMessage returns context-specific warning message +func getDetailedWarningMessage(context string) string { + switch context { + case "sql_builder": + return "avoid SELECT * in SQL builder - explicitly specify columns to prevent unnecessary data transfer and schema change issues" + case "nested": + return "avoid SELECT * in subquery - can cause performance issues and unexpected results when schema changes" + case "empty_select": + return "SQL builder Select() without columns defaults to SELECT * - add specific columns with .Columns() method" + case "aliased_wildcard": + return "avoid SELECT alias.* - explicitly specify columns like alias.id, alias.name for better maintainability" + case "subquery": + return "avoid SELECT * in subquery - specify columns explicitly to prevent issues when schema changes" + case "concat": + return "avoid SELECT * in concatenated query - explicitly specify needed columns" + case "format_string": + return "avoid SELECT * in format string - explicitly specify needed columns" + default: + return defaultWarningMessage + } +} + +// IsRuleEnabledExported checks if a rule is enabled in the configuration. +// A rule is enabled if it exists in the Rules map and its severity is not "ignore". +func IsRuleEnabledExported(rules config.RuleSeverity, ruleID string) bool { + if rules == nil { + return false + } + severity, exists := rules[ruleID] + if !exists { + return false + } + return severity != "ignore" +} + +// isRuleEnabled is an internal helper for checking rule enablement. +func isRuleEnabled(rules config.RuleSeverity, ruleID string) bool { + return IsRuleEnabledExported(rules, ruleID) +} diff --git a/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/concat.go b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/concat.go new file mode 100644 index 000000000..c4635ec84 --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/concat.go @@ -0,0 +1,100 @@ +// Package analyzer provides the SQL static analysis implementation for detecting SELECT * usage. +package analyzer + +import ( + "go/ast" + "go/token" + "strings" + + "golang.org/x/tools/go/analysis" + + "github.com/MirrexOne/unqueryvet/pkg/config" +) + +// StringConcatAnalyzer analyzes string concatenation expressions for SELECT * patterns. +// It traverses binary expressions to combine string parts and check for SELECT * usage. +type StringConcatAnalyzer struct { + pass *analysis.Pass + cfg *config.UnqueryvetSettings +} + +// NewStringConcatAnalyzer creates a new StringConcatAnalyzer. +func NewStringConcatAnalyzer(pass *analysis.Pass, cfg *config.UnqueryvetSettings) *StringConcatAnalyzer { + return &StringConcatAnalyzer{ + pass: pass, + cfg: cfg, + } +} + +// AnalyzeBinaryExpr analyzes a binary expression for string concatenation with SELECT *. +// Returns true if SELECT * was detected in the concatenated string. +func (sca *StringConcatAnalyzer) AnalyzeBinaryExpr(expr *ast.BinaryExpr) bool { + // Only analyze string concatenation (+ operator) + if expr.Op != token.ADD { + return false + } + + // Extract all string parts from the concatenation chain + parts := sca.extractStringParts(expr) + if len(parts) == 0 { + return false + } + + // Combine parts and check for SELECT * + combined := strings.Join(parts, "") + if combined == "" { + return false + } + + // Normalize and check for SELECT * + normalized := normalizeSQLQuery("\"" + combined + "\"") + return isSelectStarQuery(normalized, sca.cfg) +} + +// extractStringParts recursively extracts all string literal parts from a concatenation chain. +// For expressions like: "SELECT * " + "FROM " + tableName + " WHERE id = 1" +// It extracts: ["SELECT * ", "FROM ", " WHERE id = 1"] +func (sca *StringConcatAnalyzer) extractStringParts(expr ast.Expr) []string { + var parts []string + + switch e := expr.(type) { + case *ast.BasicLit: + // String literal + if e.Kind == token.STRING { + // Remove quotes from the string + value := strings.Trim(e.Value, "`\"") + parts = append(parts, value) + } + case *ast.BinaryExpr: + // Concatenation - recurse into both sides + if e.Op == token.ADD { + parts = append(parts, sca.extractStringParts(e.X)...) + parts = append(parts, sca.extractStringParts(e.Y)...) + } + case *ast.Ident: + // Variable reference - we can't know the value at compile time + // but we can check if it's a constant + if e.Obj != nil && e.Obj.Kind == ast.Con { + if valueSpec, ok := e.Obj.Decl.(*ast.ValueSpec); ok { + for _, value := range valueSpec.Values { + if lit, ok := value.(*ast.BasicLit); ok && lit.Kind == token.STRING { + strValue := strings.Trim(lit.Value, "`\"") + parts = append(parts, strValue) + } + } + } + } + case *ast.ParenExpr: + // Parenthesized expression - unwrap + parts = append(parts, sca.extractStringParts(e.X)...) + } + + return parts +} + +// CheckConcatenation is a convenience function to check a binary expression for SELECT *. +// It creates an analyzer and performs the check in one call. +func CheckConcatenation(pass *analysis.Pass, expr *ast.BinaryExpr, cfg *config.UnqueryvetSettings) bool { + analyzer := NewStringConcatAnalyzer(pass, cfg) + return analyzer.AnalyzeBinaryExpr(expr) +} diff --git a/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/filter.go b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/filter.go new file mode 100644 index 000000000..5ad13b62f --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/filter.go @@ -0,0 +1,176 @@ +// Package analyzer provides the SQL static analysis implementation for detecting SELECT * usage. +package analyzer + +import ( + "go/ast" + "path/filepath" + "regexp" + "strings" + + "github.com/MirrexOne/unqueryvet/pkg/config" +) + +// FilterContext holds precompiled patterns for filtering files, functions, and queries. +// It provides efficient filtering by compiling regex patterns once during initialization. +type FilterContext struct { + ignoredFuncPatterns []*regexp.Regexp + ignoredFilePatterns []string + allowedPatterns []*regexp.Regexp +} + +// NewFilterContext creates a new FilterContext from settings. +// It precompiles all regex patterns for efficient filtering. +// Returns an error if any pattern is invalid. +func NewFilterContext(cfg *config.UnqueryvetSettings) (*FilterContext, error) { + fc := &FilterContext{ + ignoredFilePatterns: cfg.IgnoredFiles, + } + + // Compile ignored function patterns + for _, pattern := range cfg.IgnoredFunctions { + re, err := regexp.Compile(pattern) + if err != nil { + return nil, err + } + fc.ignoredFuncPatterns = append(fc.ignoredFuncPatterns, re) + } + + // Compile allowed query patterns + for _, pattern := range cfg.AllowedPatterns { + re, err := regexp.Compile(pattern) + if err != nil { + return nil, err + } + fc.allowedPatterns = append(fc.allowedPatterns, re) + } + + return fc, nil +} + +// IsIgnoredFunction checks if a function call should be ignored based on configured patterns. +// It extracts the full function name (package.function or receiver.method) and matches against patterns. +func (fc *FilterContext) IsIgnoredFunction(call *ast.CallExpr) bool { + if len(fc.ignoredFuncPatterns) == 0 { + return false + } + + funcName := extractFunctionName(call) + if funcName == "" { + return false + } + + for _, pattern := range fc.ignoredFuncPatterns { + if pattern.MatchString(funcName) { + return true + } + } + + return false +} + +// IsIgnoredFile checks if a file path matches any of the ignored file patterns. +// Supports glob patterns like "*_test.go", "testdata/**", "mock_*.go". +func (fc *FilterContext) IsIgnoredFile(filePath string) bool { + if len(fc.ignoredFilePatterns) == 0 { + return false + } + + // Normalize path separators for cross-platform support + normalizedPath := filepath.ToSlash(filePath) + baseName := filepath.Base(filePath) + + for _, pattern := range fc.ignoredFilePatterns { + // Try matching against full path + if matched, _ := filepath.Match(pattern, normalizedPath); matched { + return true + } + // Try matching against base name only + if matched, _ := filepath.Match(pattern, baseName); matched { + return true + } + // Handle ** patterns (recursive matching) + if strings.Contains(pattern, "**") { + if matchDoubleStarPattern(pattern, normalizedPath) { + return true + } + } + } + + return false +} + +// IsAllowedPattern checks if a query matches any of the allowed patterns. +// Returns true if the query should be allowed (not reported as a violation). +func (fc *FilterContext) IsAllowedPattern(query string) bool { + for _, pattern := range fc.allowedPatterns { + if pattern.MatchString(query) { + return true + } + } + return false +} + +// extractFunctionName extracts the full function name from a call expression. +// Returns formats like "pkg.Function", "receiver.Method", or just "Function". +func extractFunctionName(call *ast.CallExpr) string { + switch fun := call.Fun.(type) { + case *ast.SelectorExpr: + // Method call: obj.Method() or pkg.Function() + switch x := fun.X.(type) { + case *ast.Ident: + // pkg.Function() or receiver.Method() + return x.Name + "." + fun.Sel.Name + case *ast.SelectorExpr: + // Nested: pkg.subpkg.Function() + if ident, ok := x.X.(*ast.Ident); ok { + return ident.Name + "." + x.Sel.Name + "." + fun.Sel.Name + } + case *ast.CallExpr: + // Chained call: obj.Method1().Method2() + return fun.Sel.Name + } + return fun.Sel.Name + case *ast.Ident: + // Direct function call: Function() + return fun.Name + } + return "" +} + +// matchDoubleStarPattern handles glob patterns with ** (recursive matching). +// Example: "testdata/**" matches "testdata/foo/bar.go" +func matchDoubleStarPattern(pattern, path string) bool { + // Split pattern by ** + parts := strings.Split(pattern, "**") + if len(parts) != 2 { + return false + } + + prefix := strings.TrimSuffix(parts[0], "/") + suffix := strings.TrimPrefix(parts[1], "/") + + // Check if path starts with prefix + if prefix != "" && !strings.HasPrefix(path, prefix) { + return false + } + + // Check if path ends with suffix (if suffix exists) + if suffix != "" { + // Get the part after prefix + remainingPath := strings.TrimPrefix(path, prefix) + remainingPath = strings.TrimPrefix(remainingPath, "/") + + // Match suffix at the end or as a pattern + if matched, _ := filepath.Match(suffix, filepath.Base(path)); matched { + return true + } + if strings.HasSuffix(remainingPath, suffix) { + return true + } + } else { + // No suffix, just check prefix + return strings.HasPrefix(path, prefix) + } + + return false +} diff --git a/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/fixes.go b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/fixes.go new file mode 100644 index 000000000..f059f063e --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/fixes.go @@ -0,0 +1,126 @@ +// Package analyzer provides the SQL static analysis implementation for detecting SELECT * usage. +package analyzer + +import ( + "go/token" + "regexp" + "strings" + + "golang.org/x/tools/go/analysis" +) + +// SuggestedFixGenerator generates auto-fix suggestions for SELECT * violations. +type SuggestedFixGenerator struct { + fset *token.FileSet +} + +// NewSuggestedFixGenerator creates a new SuggestedFixGenerator. +func NewSuggestedFixGenerator(fset *token.FileSet) *SuggestedFixGenerator { + return &SuggestedFixGenerator{ + fset: fset, + } +} + +// selectStarPattern matches SELECT * patterns for replacement +var selectStarFixPattern = regexp.MustCompile(`(?i)(SELECT\s+)\*(\s+FROM)`) + +// aliasedStarPattern matches SELECT alias.* patterns for replacement +var aliasedStarFixPattern = regexp.MustCompile(`(?i)(SELECT\s+)([A-Za-z_][A-Za-z0-9_]*)\s*\.\s*\*`) + +// GenerateFix creates a SuggestedFix for a SELECT * violation. +func (sfg *SuggestedFixGenerator) GenerateFix( + pos token.Pos, + end token.Pos, + originalText string, + violationType string, +) *analysis.SuggestedFix { + var newText string + var message string + + switch violationType { + case "select_star": + // Replace SELECT * with placeholder columns + newText = selectStarFixPattern.ReplaceAllString(originalText, "${1}id, /* TODO: specify columns */ ${2}") + message = "Replace SELECT * with explicit columns" + + case "aliased_wildcard": + // Replace SELECT t.* with placeholder + newText = aliasedStarFixPattern.ReplaceAllStringFunc(originalText, func(match string) string { + // Extract the alias + parts := aliasedStarFixPattern.FindStringSubmatch(match) + if len(parts) >= 3 { + alias := parts[2] + return parts[1] + alias + ".id, " + alias + "./* TODO: specify columns */" + } + return match + }) + message = "Replace SELECT alias.* with explicit columns" + + case "sql_builder_star": + // For SQL builder Select("*") -> Select("id", /* TODO */) + newText = strings.Replace(originalText, `"*"`, `"id", /* TODO: specify columns */`, 1) + message = "Replace \"*\" with explicit column names" + + case "empty_select": + // For empty Select() -> Select("id", /* TODO */) + newText = strings.Replace(originalText, "Select()", `Select("id", /* TODO: specify columns */)`, 1) + message = "Add column names to Select()" + + default: + // Generic replacement + newText = selectStarFixPattern.ReplaceAllString(originalText, "${1}id, /* TODO: specify columns */ ${2}") + message = "Replace SELECT * with explicit columns" + } + + // If no change was made, don't suggest a fix + if newText == originalText { + return nil + } + + return &analysis.SuggestedFix{ + Message: message, + TextEdits: []analysis.TextEdit{ + { + Pos: pos, + End: end, + NewText: []byte(newText), + }, + }, + } +} + +// GenerateColumnPlaceholder returns a placeholder string for explicit columns. +func (sfg *SuggestedFixGenerator) GenerateColumnPlaceholder() string { + return "id, /* TODO: specify columns */" +} + +// GenerateAliasedColumnPlaceholder returns a placeholder with table alias. +func (sfg *SuggestedFixGenerator) GenerateAliasedColumnPlaceholder(alias string) string { + return alias + ".id, " + alias + "./* TODO: specify columns */" +} + +// CreateDiagnosticWithFix creates a Diagnostic with an optional SuggestedFix. +func CreateDiagnosticWithFix( + pos token.Pos, + end token.Pos, + message string, + originalText string, + violationType string, + fset *token.FileSet, +) analysis.Diagnostic { + diagnostic := analysis.Diagnostic{ + Pos: pos, + End: end, + Message: message, + } + + // Generate fix if we have enough information + if originalText != "" && fset != nil { + generator := NewSuggestedFixGenerator(fset) + if fix := generator.GenerateFix(pos, end, originalText, violationType); fix != nil { + diagnostic.SuggestedFixes = []analysis.SuggestedFix{*fix} + } + } + + return diagnostic +} diff --git a/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/format.go b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/format.go new file mode 100644 index 000000000..c96636706 --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/format.go @@ -0,0 +1,217 @@ +// Package analyzer provides the SQL static analysis implementation for detecting SELECT * usage. +package analyzer + +import ( + "go/ast" + "go/token" + "strings" + + "golang.org/x/tools/go/analysis" + + "github.com/MirrexOne/unqueryvet/pkg/config" +) + +// formatFunctions maps package.function names to the index of the format string argument. +// Index -1 means the format string is the last argument (for variadic functions). +var formatFunctions = map[string]int{ + // fmt package + "fmt.Sprintf": 0, + "fmt.Printf": 0, + "fmt.Fprintf": 1, // first arg is io.Writer + "fmt.Errorf": 0, + "fmt.Fscanf": 1, + "fmt.Sscanf": 1, + "Sprintf": 0, // direct call after import + "Printf": 0, + "Errorf": 0, + + // log package + "log.Printf": 0, + "log.Fatalf": 0, + "log.Panicf": 0, + "log.Logf": 1, // first arg is log level + "Logger.Printf": 0, + "Logger.Fatalf": 0, + "Logger.Panicf": 0, + + // testing package + "testing.T.Logf": 0, + "testing.T.Errorf": 0, + "testing.T.Fatalf": 0, + "testing.T.Skipf": 0, + "testing.B.Logf": 0, + "testing.B.Errorf": 0, + "testing.B.Fatalf": 0, + "T.Logf": 0, + "T.Errorf": 0, + "T.Fatalf": 0, + "B.Logf": 0, + "B.Errorf": 0, + "B.Fatalf": 0, + + // errors package + "errors.Errorf": 0, + "errors.Wrapf": 1, // first arg is error + + // pkg/errors + "errors.WithMessagef": 1, + + // logrus + "logrus.Infof": 0, + "logrus.Warnf": 0, + "logrus.Errorf": 0, + "logrus.Debugf": 0, + "logrus.Fatalf": 0, + "logrus.Panicf": 0, + "logrus.Tracef": 0, + "logrus.Printf": 0, + "Entry.Infof": 0, + "Entry.Warnf": 0, + "Entry.Errorf": 0, + "Entry.Debugf": 0, + + // zap + "zap.S.Infof": 0, + "zap.S.Warnf": 0, + "zap.S.Errorf": 0, + "zap.S.Debugf": 0, + "zap.S.Fatalf": 0, + "zap.S.Panicf": 0, + "SugaredLogger.Infof": 0, + "SugaredLogger.Warnf": 0, + "SugaredLogger.Errorf": 0, + "SugaredLogger.Debugf": 0, +} + +// FormatStringAnalyzer analyzes format functions like fmt.Sprintf for SELECT * patterns. +type FormatStringAnalyzer struct { + pass *analysis.Pass + cfg *config.UnqueryvetSettings +} + +// NewFormatStringAnalyzer creates a new FormatStringAnalyzer. +func NewFormatStringAnalyzer(pass *analysis.Pass, cfg *config.UnqueryvetSettings) *FormatStringAnalyzer { + return &FormatStringAnalyzer{ + pass: pass, + cfg: cfg, + } +} + +// AnalyzeFormatCall analyzes a function call for format string patterns with SELECT *. +// Returns true if SELECT * was detected in the format string. +func (fsa *FormatStringAnalyzer) AnalyzeFormatCall(call *ast.CallExpr) bool { + // Get the function name + funcName := fsa.getFunctionName(call) + if funcName == "" { + return false + } + + // Check if this is a known format function + argIndex, ok := formatFunctions[funcName] + if !ok { + return false + } + + // Extract the format string + formatStr, ok := fsa.extractFormatString(call, argIndex) + if !ok { + return false + } + + // Check if the format string contains SELECT * + normalized := normalizeSQLQuery("\"" + formatStr + "\"") + return isSelectStarQuery(normalized, fsa.cfg) +} + +// getFunctionName extracts the function name from a call expression. +// Returns formats like "fmt.Sprintf", "log.Printf", or just "Sprintf". +func (fsa *FormatStringAnalyzer) getFunctionName(call *ast.CallExpr) string { + switch fun := call.Fun.(type) { + case *ast.SelectorExpr: + // Method call: pkg.Func() or obj.Method() + switch x := fun.X.(type) { + case *ast.Ident: + // pkg.Func() like fmt.Sprintf + return x.Name + "." + fun.Sel.Name + case *ast.SelectorExpr: + // Nested: pkg.subpkg.Func() or receiver.Type.Method() + if ident, ok := x.X.(*ast.Ident); ok { + return ident.Name + "." + x.Sel.Name + "." + fun.Sel.Name + } + // obj.Field.Method() + return x.Sel.Name + "." + fun.Sel.Name + case *ast.CallExpr: + // Chained: something().Method() + return fun.Sel.Name + } + return fun.Sel.Name + case *ast.Ident: + // Direct function call: Sprintf() (after import . "fmt") + return fun.Name + } + return "" +} + +// extractFormatString extracts the format string from a function call. +// argIndex specifies which argument contains the format string. +func (fsa *FormatStringAnalyzer) extractFormatString(call *ast.CallExpr, argIndex int) (string, bool) { + if argIndex < 0 || argIndex >= len(call.Args) { + return "", false + } + + arg := call.Args[argIndex] + + // Direct string literal + if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { + return strings.Trim(lit.Value, "`\""), true + } + + // Identifier (constant or variable) + if ident, ok := arg.(*ast.Ident); ok { + if ident.Obj != nil && ident.Obj.Kind == ast.Con { + // It's a constant - try to get its value + if valueSpec, ok := ident.Obj.Decl.(*ast.ValueSpec); ok { + for _, value := range valueSpec.Values { + if lit, ok := value.(*ast.BasicLit); ok && lit.Kind == token.STRING { + return strings.Trim(lit.Value, "`\""), true + } + } + } + } + } + + return "", false +} + +// CheckFormatFunction is a convenience function to check a call expression for SELECT *. +// It creates an analyzer and performs the check in one call. +func CheckFormatFunction(pass *analysis.Pass, call *ast.CallExpr, cfg *config.UnqueryvetSettings) bool { + analyzer := NewFormatStringAnalyzer(pass, cfg) + return analyzer.AnalyzeFormatCall(call) +} + +// IsFormatFunction checks if a call expression is a known format function. +func IsFormatFunction(call *ast.CallExpr) bool { + var funcName string + + switch fun := call.Fun.(type) { + case *ast.SelectorExpr: + switch x := fun.X.(type) { + case *ast.Ident: + funcName = x.Name + "." + fun.Sel.Name + case *ast.SelectorExpr: + if ident, ok := x.X.(*ast.Ident); ok { + funcName = ident.Name + "." + x.Sel.Name + "." + fun.Sel.Name + } else { + funcName = x.Sel.Name + "." + fun.Sel.Name + } + default: + funcName = fun.Sel.Name + } + case *ast.Ident: + funcName = fun.Name + } + + _, ok := formatFunctions[funcName] + return ok +} diff --git a/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/n1detector.go b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/n1detector.go new file mode 100644 index 000000000..cf0331129 --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/n1detector.go @@ -0,0 +1,546 @@ +package analyzer + +import ( + "go/ast" + "go/token" + "strings" + + "golang.org/x/tools/go/analysis" +) + +// N1Detector detects potential N+1 query problems. +// An N+1 query problem occurs when a SQL query is executed inside a loop, +// causing one query per iteration instead of a single batch query. +type N1Detector struct { + // loopDepth tracks how deeply nested we are in loops + loopDepth int + // queryMethods are method names that typically execute SQL queries + queryMethods map[string]bool + // ormMethods are ORM-specific methods that indicate queries + ormMethods map[string]bool + // transactionMethods are methods that indicate transaction usage + transactionMethods map[string]bool + // functionCallsInLoop tracks function calls made inside loops for indirect N+1 detection + functionCallsInLoop map[string]bool + // knownQueryFunctions are user-defined functions known to execute queries + knownQueryFunctions map[string]bool +} + +// NewN1Detector creates a new N+1 query detector. +func NewN1Detector() *N1Detector { + return &N1Detector{ + queryMethods: map[string]bool{ + // Standard database/sql + "Query": true, + "QueryRow": true, + "Exec": true, + "ExecContext": true, + "QueryContext": true, + "QueryRowContext": true, + // SQLx + "QueryRowx": true, + "Queryx": true, + "SelectContext": true, + "GetContext": true, + "NamedQuery": true, + "NamedQueryContext": true, + "NamedExec": true, + "NamedExecContext": true, + // General + "Select": true, + "Get": true, + "Find": true, + "First": true, + "Where": true, + "Raw": true, + }, + ormMethods: map[string]bool{ + // GORM + "Preload": true, + "Association": true, + "Related": true, + "Model": true, + "Table": true, + "Joins": true, + "InnerJoins": true, + "Pluck": true, + "Count": true, + "Take": true, + "Last": true, + "Scan": true, + "Row": true, + "Rows": true, + // Bun + "NewSelect": true, + "NewInsert": true, + "NewUpdate": true, + "NewDelete": true, + "Column": true, + "ColumnExpr": true, + "Relation": true, + // Ent + "Only": true, + "OnlyX": true, + "AllX": true, + "FirstX": true, + // SQLBoiler + "One": true, + "OneP": true, + "AllP": true, + "Exists": true, + "ExistsP": true, + // PGX + "SendBatch": true, + }, + transactionMethods: map[string]bool{ + "Begin": true, + "BeginTx": true, + "BeginTxx": true, + "Transaction": true, + "WithContext": true, + "RunInTransaction": true, + "Tx": true, + "NewTx": true, + }, + functionCallsInLoop: make(map[string]bool), + knownQueryFunctions: make(map[string]bool), + } +} + +// N1Severity represents the severity level of an N+1 violation. +type N1Severity string + +const ( + N1SeverityCritical N1Severity = "critical" // Direct query in loop + N1SeverityHigh N1Severity = "high" // ORM method in loop + N1SeverityMedium N1Severity = "medium" // Indirect query via function call + N1SeverityLow N1Severity = "low" // Potential issue, needs review +) + +// N1Violation represents a detected N+1 query problem. +type N1Violation struct { + Pos token.Pos + End token.Pos + Message string + LoopType string // "for", "range", or "while-like" + QueryType string // The method name that was called + Severity N1Severity // Severity level + Suggestion string // Suggested fix + IsIndirect bool // True if detected via function call + FunctionName string // Name of the function if indirect +} + +// CheckN1Queries analyzes the file for N+1 query patterns. +func (d *N1Detector) CheckN1Queries(pass *analysis.Pass, file *ast.File) []N1Violation { + var violations []N1Violation + + ast.Inspect(file, func(n ast.Node) bool { + switch node := n.(type) { + case *ast.ForStmt: + // Entering a for loop + d.loopDepth++ + defer func() { d.loopDepth-- }() + + // Check the body for queries + if node.Body != nil { + violations = append(violations, d.checkBlockForQueries(pass, node.Body, "for")...) + } + return true + + case *ast.RangeStmt: + // Entering a range loop + d.loopDepth++ + defer func() { d.loopDepth-- }() + + // Check the body for queries + if node.Body != nil { + violations = append(violations, d.checkBlockForQueries(pass, node.Body, "range")...) + } + return true + } + return true + }) + + return violations +} + +// checkBlockForQueries checks a block statement for SQL query calls. +func (d *N1Detector) checkBlockForQueries(pass *analysis.Pass, block *ast.BlockStmt, loopType string) []N1Violation { + var violations []N1Violation + + ast.Inspect(block, func(n ast.Node) bool { + // Skip nested loops - they'll be handled separately + switch n.(type) { + case *ast.ForStmt, *ast.RangeStmt: + return false + } + + call, ok := n.(*ast.CallExpr) + if !ok { + return true + } + + methodName := d.getMethodName(call) + if methodName == "" { + return true + } + + // Check 1: Direct query method call + if d.queryMethods[methodName] { + if v := d.checkDirectQueryCall(call, methodName, loopType); v != nil { + violations = append(violations, *v) + } + return true + } + + // Check 2: ORM-specific method call + if d.ormMethods[methodName] { + if v := d.checkORMMethodCall(call, methodName, loopType); v != nil { + violations = append(violations, *v) + } + return true + } + + // Check 3: Transaction method in loop (potential issue) + if d.transactionMethods[methodName] { + violations = append(violations, N1Violation{ + Pos: call.Pos(), + End: call.End(), + Message: "transaction started inside loop - consider batching operations", + LoopType: loopType, + QueryType: methodName, + Severity: N1SeverityMedium, + Suggestion: "Move transaction outside the loop and batch operations, or use a single transaction for all iterations", + }) + return true + } + + // Check 4: Indirect query via function call + if v := d.checkIndirectQueryCall(call, methodName, loopType); v != nil { + violations = append(violations, *v) + } + + return true + }) + + return violations +} + +// checkDirectQueryCall checks for direct database query calls. +func (d *N1Detector) checkDirectQueryCall(call *ast.CallExpr, methodName, loopType string) *N1Violation { + // Check if any argument contains SELECT or other SQL keywords + hasSQLKeyword := false + for _, arg := range call.Args { + if lit, ok := arg.(*ast.BasicLit); ok { + if lit.Kind == token.STRING { + value := strings.ToUpper(lit.Value) + if strings.Contains(value, "SELECT") || strings.Contains(value, "INSERT") || + strings.Contains(value, "UPDATE") || strings.Contains(value, "DELETE") { + hasSQLKeyword = true + break + } + } + } + } + + // Also check if it's a method on a database variable + if !hasSQLKeyword { + hasSQLKeyword = d.mightBeQueryCall(call) + } + + if hasSQLKeyword { + return &N1Violation{ + Pos: call.Pos(), + End: call.End(), + Message: n1Message(methodName, loopType), + LoopType: loopType, + QueryType: methodName, + Severity: N1SeverityCritical, + Suggestion: n1Suggestion(loopType), + } + } + + return nil +} + +// checkORMMethodCall checks for ORM-specific method calls that might cause N+1. +func (d *N1Detector) checkORMMethodCall(call *ast.CallExpr, methodName, loopType string) *N1Violation { + // ORM methods like Preload, Association, Related are often N+1 sources + suspiciousMethods := map[string]bool{ + "Preload": true, + "Association": true, + "Related": true, + "Relation": true, + } + + if suspiciousMethods[methodName] { + return &N1Violation{ + Pos: call.Pos(), + End: call.End(), + Message: "ORM relation loading inside loop: " + methodName + "() - this causes N+1 queries", + LoopType: loopType, + QueryType: methodName, + Severity: N1SeverityHigh, + Suggestion: "Use eager loading (Preload) before the loop, or fetch all related data in a single query with JOIN", + } + } + + // Check for query execution methods + executionMethods := map[string]bool{ + "Find": true, "First": true, "Take": true, "Last": true, + "One": true, "All": true, "Only": true, "Scan": true, + } + + if executionMethods[methodName] && d.mightBeQueryCall(call) { + return &N1Violation{ + Pos: call.Pos(), + End: call.End(), + Message: "ORM query execution inside loop: " + methodName + "() - potential N+1 problem", + LoopType: loopType, + QueryType: methodName, + Severity: N1SeverityHigh, + Suggestion: "Collect IDs first, then use WHERE IN clause or batch loading", + } + } + + return nil +} + +// checkIndirectQueryCall checks for function calls that might execute queries. +func (d *N1Detector) checkIndirectQueryCall(call *ast.CallExpr, methodName, loopType string) *N1Violation { + // Check for suspicious function names that might contain queries + lowerName := strings.ToLower(methodName) + suspiciousPatterns := []string{ + "get", "fetch", "find", "load", "query", "select", + "retrieve", "lookup", "read", "search", + } + + for _, pattern := range suspiciousPatterns { + if strings.Contains(lowerName, pattern) { + // Check if it's called on a repository/store/dao object + if d.isRepositoryCall(call) { + return &N1Violation{ + Pos: call.Pos(), + End: call.End(), + Message: "potential N+1: function " + methodName + "() called inside loop may execute database query", + LoopType: loopType, + QueryType: methodName, + Severity: N1SeverityMedium, + Suggestion: "Review this function - if it executes a query, consider batch loading or caching", + IsIndirect: true, + FunctionName: methodName, + } + } + } + } + + return nil +} + +// isRepositoryCall checks if the call is on a repository-like object. +func (d *N1Detector) isRepositoryCall(call *ast.CallExpr) bool { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return false + } + + if ident, ok := sel.X.(*ast.Ident); ok { + name := strings.ToLower(ident.Name) + repositoryPatterns := []string{ + "repo", "repository", "store", "dao", "service", + "handler", "manager", "provider", "client", + } + for _, pattern := range repositoryPatterns { + if strings.Contains(name, pattern) { + return true + } + } + } + + return false +} + +// n1Suggestion generates a suggestion based on loop type. +func n1Suggestion(loopType string) string { + switch loopType { + case "range": + return "Collect all IDs before the loop, then use a single query with IN clause:\n" + + " ids := make([]int, 0, len(items))\n" + + " for _, item := range items { ids = append(ids, item.ID) }\n" + + " db.Query(\"SELECT * FROM table WHERE id IN (?)\", ids)" + case "for": + return "Consider using batch query with IN clause or JOIN instead of querying in each iteration" + default: + return "Refactor to execute a single batch query instead of multiple queries in loop" + } +} + +// getMethodName extracts the method name from a call expression. +func (d *N1Detector) getMethodName(call *ast.CallExpr) string { + switch fun := call.Fun.(type) { + case *ast.SelectorExpr: + return fun.Sel.Name + case *ast.Ident: + return fun.Name + } + return "" +} + +// mightBeQueryCall checks if a call might be a database query. +func (d *N1Detector) mightBeQueryCall(call *ast.CallExpr) bool { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return false + } + + // Check for common database variable names + if ident, ok := sel.X.(*ast.Ident); ok { + name := strings.ToLower(ident.Name) + return name == "db" || name == "conn" || name == "tx" || + strings.Contains(name, "database") || + strings.Contains(name, "repo") || + strings.Contains(name, "store") + } + + return false +} + +// n1Message generates a helpful message for N+1 detection. +func n1Message(methodName, loopType string) string { + suggestion := "" + switch loopType { + case "range": + suggestion = "Consider using a batch query with IN clause or JOIN" + case "for": + suggestion = "Consider collecting IDs first, then executing a single query with IN clause" + } + + return "potential N+1 query: " + methodName + "() called inside loop - " + suggestion +} + +// AnalyzeN1 is a convenience function to run N+1 detection on a file. +func AnalyzeN1(pass *analysis.Pass, file *ast.File) { + detector := NewN1Detector() + violations := detector.CheckN1Queries(pass, file) + + for _, v := range violations { + message := v.Message + if v.Suggestion != "" { + message += "\n Suggestion: " + v.Suggestion + } + if v.Severity != "" { + message = "[" + string(v.Severity) + "] " + message + } + + pass.Report(analysis.Diagnostic{ + Pos: v.Pos, + End: v.End, + Message: message, + }) + } +} + +// GetN1Violations returns all N+1 violations for external use. +func GetN1Violations(pass *analysis.Pass, file *ast.File) []N1Violation { + detector := NewN1Detector() + return detector.CheckN1Queries(pass, file) +} + +// CheckN1QueriesNoPass is a method to check for N+1 queries without analysis.Pass. +// This is useful for testing. +func (d *N1Detector) CheckN1QueriesNoPass(file *ast.File) []N1Violation { + return DetectN1InAST(nil, file) +} + +// DetectN1InAST detects N+1 query problems in an AST file without analysis.Pass. +// This is designed for use in LSP server where we don't have a full analysis pass. +func DetectN1InAST(fset *token.FileSet, file *ast.File) []N1Violation { + detector := NewN1Detector() + var violations []N1Violation + + ast.Inspect(file, func(n ast.Node) bool { + switch node := n.(type) { + case *ast.ForStmt: + detector.loopDepth++ + defer func() { detector.loopDepth-- }() + + if node.Body != nil { + violations = append(violations, detector.checkBlockForQueriesNoPass(node.Body, "for")...) + } + return true + + case *ast.RangeStmt: + detector.loopDepth++ + defer func() { detector.loopDepth-- }() + + if node.Body != nil { + violations = append(violations, detector.checkBlockForQueriesNoPass(node.Body, "range")...) + } + return true + } + return true + }) + + return violations +} + +// checkBlockForQueriesNoPass checks a block statement for SQL query calls without analysis.Pass. +func (d *N1Detector) checkBlockForQueriesNoPass(block *ast.BlockStmt, loopType string) []N1Violation { + var violations []N1Violation + + ast.Inspect(block, func(n ast.Node) bool { + switch n.(type) { + case *ast.ForStmt, *ast.RangeStmt: + return false + } + + call, ok := n.(*ast.CallExpr) + if !ok { + return true + } + + methodName := d.getMethodName(call) + if methodName == "" { + return true + } + + // Check 1: Direct query method call + if d.queryMethods[methodName] { + if v := d.checkDirectQueryCall(call, methodName, loopType); v != nil { + violations = append(violations, *v) + } + return true + } + + // Check 2: ORM-specific method call + if d.ormMethods[methodName] { + if v := d.checkORMMethodCall(call, methodName, loopType); v != nil { + violations = append(violations, *v) + } + return true + } + + // Check 3: Transaction method in loop + if d.transactionMethods[methodName] { + violations = append(violations, N1Violation{ + Pos: call.Pos(), + End: call.End(), + Message: "transaction started inside loop - consider batching operations", + LoopType: loopType, + QueryType: methodName, + Severity: N1SeverityMedium, + Suggestion: "Move transaction outside the loop and batch operations, or use a single transaction for all iterations", + }) + return true + } + + // Check 4: Indirect query via function call + if v := d.checkIndirectQueryCall(call, methodName, loopType); v != nil { + violations = append(violations, *v) + } + + return true + }) + + return violations +} diff --git a/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/bun.go b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/bun.go new file mode 100644 index 000000000..a25f559a1 --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/bun.go @@ -0,0 +1,146 @@ +// Package sqlbuilders provides SQL builder library-specific checkers for SELECT * detection. +package sqlbuilders + +import ( + "go/ast" + "go/token" + "go/types" + "strings" +) + +const bunPkgPath = "github.com/uptrace/bun" + +// BunChecker checks github.com/uptrace/bun for SELECT * patterns. +type BunChecker struct{} + +// NewBunChecker creates a new BunChecker. +func NewBunChecker() *BunChecker { + return &BunChecker{} +} + +// Name returns the name of this checker. +func (c *BunChecker) Name() string { + return "bun" +} + +// IsApplicable checks if the call is from bun using type information. +func (c *BunChecker) IsApplicable(info *types.Info, call *ast.CallExpr) bool { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return false + } + + // Check if the receiver type is from bun package + return IsTypeFromPackage(info, sel.X, bunPkgPath) +} + +// CheckSelectStar checks for SELECT * in bun calls. +func (c *BunChecker) CheckSelectStar(call *ast.CallExpr) *SelectStarViolation { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return nil + } + + methodName := sel.Sel.Name + + // Check ColumnExpr("*") + if methodName == "ColumnExpr" || methodName == "Column" { + for _, arg := range call.Args { + if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { + value := strings.Trim(lit.Value, "`\"") + if value == "*" { + return &SelectStarViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "bun " + methodName + "(\"*\") - explicitly specify columns", + Builder: "bun", + Context: "explicit_star", + } + } + } + } + } + + // Check NewRaw or Raw with SELECT * + if methodName == "NewRaw" || methodName == "Raw" { + for _, arg := range call.Args { + if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { + value := strings.Trim(lit.Value, "`\"") + upperValue := strings.ToUpper(value) + if strings.Contains(upperValue, "SELECT *") { + return &SelectStarViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "bun Raw() with SELECT * - specify columns explicitly", + Builder: "bun", + Context: "raw_select_star", + } + } + } + } + } + + return nil +} + +// CheckChainedCalls checks method chains for SELECT * patterns. +func (c *BunChecker) CheckChainedCalls(call *ast.CallExpr) []*SelectStarViolation { + var violations []*SelectStarViolation + + // Track chain state + hasNewSelect := false + hasColumn := false + var selectCall *ast.CallExpr + + // Traverse the call chain + current := call + for current != nil { + sel, ok := current.Fun.(*ast.SelectorExpr) + if !ok { + break + } + + switch sel.Sel.Name { + case "NewSelect": + hasNewSelect = true + selectCall = current + case "Column", "ColumnExpr": + hasColumn = true + // Check for "*" argument + for _, arg := range current.Args { + if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { + value := strings.Trim(lit.Value, "`\"") + if value == "*" { + violations = append(violations, &SelectStarViolation{ + Pos: current.Pos(), + End: current.End(), + Message: "bun Column(\"*\") in chain - specify columns explicitly", + Builder: "bun", + Context: "chained_star", + }) + } + } + } + case "Scan", "Exec": + // Terminal methods - check if we have NewSelect without Column + if hasNewSelect && !hasColumn && selectCall != nil { + violations = append(violations, &SelectStarViolation{ + Pos: selectCall.Pos(), + End: current.End(), + Message: "bun NewSelect() with Scan/Exec without Column() defaults to SELECT *", + Builder: "bun", + Context: "implicit_star", + }) + } + } + + // Move to the next call in the chain + if innerCall, ok := sel.X.(*ast.CallExpr); ok { + current = innerCall + } else { + break + } + } + + return violations +} diff --git a/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/ent.go b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/ent.go new file mode 100644 index 000000000..c3f184894 --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/ent.go @@ -0,0 +1,87 @@ +// Package sqlbuilders provides SQL builder library-specific checkers for SELECT * detection. +package sqlbuilders + +import ( + "go/ast" + "go/types" +) + +const entPkgPath = "entgo.io/ent" + +// EntChecker checks entgo.io/ent for SELECT * patterns. +type EntChecker struct{} + +// NewEntChecker creates a new EntChecker. +func NewEntChecker() *EntChecker { + return &EntChecker{} +} + +// Name returns the name of this checker. +func (c *EntChecker) Name() string { + return "ent" +} + +// IsApplicable checks if the call is from ent using type information. +func (c *EntChecker) IsApplicable(info *types.Info, call *ast.CallExpr) bool { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return false + } + + // Check if the receiver type is from ent package + return IsTypeFromPackage(info, sel.X, entPkgPath) +} + +// CheckSelectStar checks for SELECT * in ent calls. +func (c *EntChecker) CheckSelectStar(call *ast.CallExpr) *SelectStarViolation { + // ent typically doesn't have explicit SELECT * patterns + // The implicit SELECT * happens when Query().All() is called without Select() + return nil +} + +// CheckChainedCalls checks method chains for SELECT * patterns. +func (c *EntChecker) CheckChainedCalls(call *ast.CallExpr) []*SelectStarViolation { + var violations []*SelectStarViolation + + // Track chain state + hasQuery := false + hasSelect := false + var queryCall *ast.CallExpr + + // Traverse the call chain + current := call + for current != nil { + sel, ok := current.Fun.(*ast.SelectorExpr) + if !ok { + break + } + + switch sel.Sel.Name { + case "Query": + hasQuery = true + queryCall = current + case "Select": + hasSelect = true + case "All", "Only", "OnlyX", "First", "FirstX": + // Terminal methods - check if we have Query without Select + if hasQuery && !hasSelect && queryCall != nil { + violations = append(violations, &SelectStarViolation{ + Pos: queryCall.Pos(), + End: current.End(), + Message: "ent Query() with All/Only without Select() fetches all columns - use Select() to specify columns", + Builder: "ent", + Context: "implicit_star", + }) + } + } + + // Move to the next call in the chain + if innerCall, ok := sel.X.(*ast.CallExpr); ok { + current = innerCall + } else { + break + } + } + + return violations +} diff --git a/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/goqu.go b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/goqu.go new file mode 100644 index 000000000..a923c1f19 --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/goqu.go @@ -0,0 +1,120 @@ +package sqlbuilders + +import ( + "go/ast" + "go/token" + "go/types" + "strings" +) + +const goquPkgPath = "github.com/doug-martin/goqu" + +// GoquChecker checks for SELECT * in goqu queries. +type GoquChecker struct{} + +// NewGoquChecker creates a new goqu checker. +func NewGoquChecker() *GoquChecker { + return &GoquChecker{} +} + +// Name returns the checker name. +func (c *GoquChecker) Name() string { + return "goqu" +} + +// IsApplicable checks if the call is from goqu using type information. +func (c *GoquChecker) IsApplicable(info *types.Info, call *ast.CallExpr) bool { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return false + } + + // Check if the receiver type is from goqu package + if IsTypeFromPackage(info, sel.X, goquPkgPath) { + return true + } + + // Check for package-level function calls like goqu.From() + if ident, ok := sel.X.(*ast.Ident); ok { + if info != nil { + if obj := info.Uses[ident]; obj != nil { + if pkgName, ok := obj.(*types.PkgName); ok { + pkgPath := pkgName.Imported().Path() + if len(pkgPath) >= len(goquPkgPath) && pkgPath[:len(goquPkgPath)] == goquPkgPath { + return true + } + } + } + } + } + + return false +} + +// CheckSelectStar checks for SELECT * patterns in goqu. +func (c *GoquChecker) CheckSelectStar(call *ast.CallExpr) *SelectStarViolation { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return nil + } + + methodName := sel.Sel.Name + + // goqu.From("table").SelectAll() - this selects all columns + if methodName == "SelectAll" { + return &SelectStarViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "goqu SelectAll() selects all columns - use Select() with explicit column names", + } + } + + // goqu.From("table").Select("*") + if methodName == "Select" { + for _, arg := range call.Args { + if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { + value := strings.Trim(lit.Value, "`\"'") + if value == "*" { + return &SelectStarViolation{ + Pos: lit.Pos(), + End: lit.End(), + Message: "goqu Select(\"*\") - specify columns explicitly", + } + } + } + } + + // goqu.From("table").Select() without arguments also selects all + if len(call.Args) == 0 { + return &SelectStarViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "goqu Select() without arguments selects all columns", + } + } + } + + return nil +} + +// CheckChainedCalls checks chained method calls. +func (c *GoquChecker) CheckChainedCalls(call *ast.CallExpr) []*SelectStarViolation { + var violations []*SelectStarViolation + + // Walk up the chain + current := call + for current != nil { + if v := c.CheckSelectStar(current); v != nil { + violations = append(violations, v) + } + + // Move to the receiver if it's also a call + sel, ok := current.Fun.(*ast.SelectorExpr) + if !ok { + break + } + current, _ = sel.X.(*ast.CallExpr) + } + + return violations +} diff --git a/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/gorm.go b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/gorm.go new file mode 100644 index 000000000..6275eaf5e --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/gorm.go @@ -0,0 +1,190 @@ +// Package sqlbuilders provides SQL builder library-specific checkers for SELECT * detection. +package sqlbuilders + +import ( + "go/ast" + "go/token" + "go/types" + "strings" +) + +const gormPkgPath = "gorm.io/gorm" + +// GORMChecker checks gorm.io/gorm for SELECT * patterns. +type GORMChecker struct{} + +// NewGORMChecker creates a new GORMChecker. +func NewGORMChecker() *GORMChecker { + return &GORMChecker{} +} + +// Name returns the name of this checker. +func (c *GORMChecker) Name() string { + return "gorm" +} + +// IsApplicable checks if the call is from GORM using type information. +func (c *GORMChecker) IsApplicable(info *types.Info, call *ast.CallExpr) bool { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return false + } + + // Check if the receiver type is from gorm package + return IsTypeFromPackage(info, sel.X, gormPkgPath) +} + +// CheckSelectStar checks for SELECT * in GORM calls. +func (c *GORMChecker) CheckSelectStar(call *ast.CallExpr) *SelectStarViolation { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return nil + } + + switch sel.Sel.Name { + case "Select": + return c.checkSelectMethod(call) + case "Raw": + return c.checkRawMethod(call, "GORM Raw() with SELECT * - specify columns explicitly") + case "Exec": + return c.checkRawMethod(call, "GORM Exec() with SELECT * - specify columns explicitly") + } + + return nil +} + +// checkSelectMethod checks db.Select() for star patterns +func (c *GORMChecker) checkSelectMethod(call *ast.CallExpr) *SelectStarViolation { + for _, arg := range call.Args { + lit, ok := arg.(*ast.BasicLit) + if !ok || lit.Kind != token.STRING { + continue + } + + value := strings.Trim(lit.Value, "`\"") + if value == "*" { + return &SelectStarViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "GORM Select(\"*\") - explicitly specify columns", + Builder: "gorm", + Context: "explicit_star", + } + } + + if strings.Contains(strings.ToUpper(value), "SELECT *") { + return &SelectStarViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "GORM Select() contains SELECT * - specify columns explicitly", + Builder: "gorm", + Context: "raw_select_star", + } + } + } + return nil +} + +// checkRawMethod checks db.Raw() or db.Exec() for SELECT * patterns +func (c *GORMChecker) checkRawMethod(call *ast.CallExpr, message string) *SelectStarViolation { + for _, arg := range call.Args { + lit, ok := arg.(*ast.BasicLit) + if !ok || lit.Kind != token.STRING { + continue + } + + value := strings.Trim(lit.Value, "`\"") + if strings.Contains(strings.ToUpper(value), "SELECT *") { + return &SelectStarViolation{ + Pos: call.Pos(), + End: call.End(), + Message: message, + Builder: "gorm", + Context: "raw_select_star", + } + } + } + return nil +} + +// CheckChainedCalls checks method chains for SELECT * patterns. +// gormChainState tracks state while traversing GORM call chain +type gormChainState struct { + hasModel bool + hasSelect bool + modelCall *ast.CallExpr +} + +func (c *GORMChecker) CheckChainedCalls(call *ast.CallExpr) []*SelectStarViolation { + var violations []*SelectStarViolation + state := &gormChainState{} + + current := call + for current != nil { + sel, ok := current.Fun.(*ast.SelectorExpr) + if !ok { + break + } + + if v := c.processGormChainMethod(sel.Sel.Name, current, state); v != nil { + violations = append(violations, v) + } + + if innerCall, ok := sel.X.(*ast.CallExpr); ok { + current = innerCall + } else { + break + } + } + + return violations +} + +// processGormChainMethod processes a single method in the GORM call chain +func (c *GORMChecker) processGormChainMethod(methodName string, current *ast.CallExpr, state *gormChainState) *SelectStarViolation { + switch methodName { + case "Model", "Table": + state.hasModel = true + state.modelCall = current + case "Select": + state.hasSelect = true + return c.checkGormSelectArgs(current) + case "Find", "First", "Last", "Take", "Scan": + return c.checkGormTerminalMethod(current, state) + } + return nil +} + +// checkGormSelectArgs checks Select() arguments for "*" +func (c *GORMChecker) checkGormSelectArgs(current *ast.CallExpr) *SelectStarViolation { + for _, arg := range current.Args { + lit, ok := arg.(*ast.BasicLit) + if !ok || lit.Kind != token.STRING { + continue + } + if strings.Trim(lit.Value, "`\"") == "*" { + return &SelectStarViolation{ + Pos: current.Pos(), + End: current.End(), + Message: "GORM Select(\"*\") in chain - specify columns explicitly", + Builder: "gorm", + Context: "chained_star", + } + } + } + return nil +} + +// checkGormTerminalMethod checks terminal methods (Find, First, etc.) for implicit SELECT * +func (c *GORMChecker) checkGormTerminalMethod(current *ast.CallExpr, state *gormChainState) *SelectStarViolation { + if state.hasModel && !state.hasSelect && state.modelCall != nil { + return &SelectStarViolation{ + Pos: state.modelCall.Pos(), + End: current.End(), + Message: "GORM Model() with Find/First without Select() defaults to SELECT *", + Builder: "gorm", + Context: "implicit_star", + } + } + return nil +} diff --git a/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/interface.go b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/interface.go new file mode 100644 index 000000000..4670d6155 --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/interface.go @@ -0,0 +1,156 @@ +// Package sqlbuilders provides SQL builder library-specific checkers for SELECT * detection. +package sqlbuilders + +import ( + "go/ast" + "go/token" + "go/types" + + "github.com/MirrexOne/unqueryvet/pkg/config" +) + +// SelectStarViolation represents a detected SELECT * usage in SQL builder code. +type SelectStarViolation struct { + // Pos is the position in source code where the violation was detected + Pos token.Pos + // End is the end position of the violation + End token.Pos + // Message is the human-readable description of the violation + Message string + // Builder is the name of the SQL builder library + Builder string + // Context provides additional context about the violation type + Context string +} + +// SQLBuilderChecker is the interface for SQL builder library-specific checkers. +// Each SQL builder library (GORM, sqlx, etc.) implements this interface. +type SQLBuilderChecker interface { + // Name returns the name of the SQL builder library + Name() string + + // IsApplicable checks if the call expression is from this SQL builder. + // It uses type information to verify the receiver type belongs to the correct package. + IsApplicable(info *types.Info, call *ast.CallExpr) bool + + // CheckSelectStar checks a single call expression for SELECT * usage + CheckSelectStar(call *ast.CallExpr) *SelectStarViolation + + // CheckChainedCalls analyzes method chains for SELECT * patterns + CheckChainedCalls(call *ast.CallExpr) []*SelectStarViolation +} + +// Registry holds all registered SQL builder checkers and provides a unified interface. +type Registry struct { + checkers []SQLBuilderChecker +} + +// NewRegistry creates a new Registry with checkers based on the configuration. +func NewRegistry(cfg *config.SQLBuildersConfig) *Registry { + r := &Registry{ + checkers: make([]SQLBuilderChecker, 0), + } + + // Register enabled checkers + if cfg.Squirrel { + r.checkers = append(r.checkers, NewSquirrelChecker()) + } + if cfg.GORM { + r.checkers = append(r.checkers, NewGORMChecker()) + } + if cfg.SQLx { + r.checkers = append(r.checkers, NewSQLxChecker()) + } + if cfg.Ent { + r.checkers = append(r.checkers, NewEntChecker()) + } + if cfg.PGX { + r.checkers = append(r.checkers, NewPGXChecker()) + } + if cfg.Bun { + r.checkers = append(r.checkers, NewBunChecker()) + } + if cfg.SQLBoiler { + r.checkers = append(r.checkers, NewSQLBoilerChecker()) + } + if cfg.Jet { + r.checkers = append(r.checkers, NewJetChecker()) + } + if cfg.Sqlc { + r.checkers = append(r.checkers, NewSQLCChecker()) + } + if cfg.Goqu { + r.checkers = append(r.checkers, NewGoquChecker()) + } + if cfg.Rel { + r.checkers = append(r.checkers, NewRelChecker()) + } + if cfg.Reform { + r.checkers = append(r.checkers, NewReformChecker()) + } + + return r +} + +// Check analyzes a call expression against all registered checkers. +// Returns all violations found across all applicable checkers. +// The info parameter provides type information for accurate type checking. +func (r *Registry) Check(info *types.Info, call *ast.CallExpr) []*SelectStarViolation { + var violations []*SelectStarViolation + + for _, checker := range r.checkers { + if !checker.IsApplicable(info, call) { + continue + } + + // Check for direct SELECT * usage + if v := checker.CheckSelectStar(call); v != nil { + violations = append(violations, v) + } + + // Check for SELECT * in method chains + chainViolations := checker.CheckChainedCalls(call) + violations = append(violations, chainViolations...) + } + + return violations +} + +// HasCheckers returns true if at least one checker is registered. +func (r *Registry) HasCheckers() bool { + return len(r.checkers) > 0 +} + +// IsTypeFromPackage checks if the type of an expression belongs to a package +// with the given path prefix. This is used to verify that a method call +// is actually from the expected SQL builder library. +func IsTypeFromPackage(info *types.Info, expr ast.Expr, pkgPathPrefix string) bool { + if info == nil { + return false + } + + typ := info.TypeOf(expr) + if typ == nil { + return false + } + + return isTypeFromPackageRecursive(typ, pkgPathPrefix) +} + +// isTypeFromPackageRecursive recursively checks if a type belongs to a package. +func isTypeFromPackageRecursive(typ types.Type, pkgPathPrefix string) bool { + switch t := typ.(type) { + case *types.Named: + if obj := t.Obj(); obj != nil { + if pkg := obj.Pkg(); pkg != nil { + pkgPath := pkg.Path() + if len(pkgPath) >= len(pkgPathPrefix) && pkgPath[:len(pkgPathPrefix)] == pkgPathPrefix { + return true + } + } + } + case *types.Pointer: + return isTypeFromPackageRecursive(t.Elem(), pkgPathPrefix) + } + return false +} diff --git a/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/jet.go b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/jet.go new file mode 100644 index 000000000..9e28021be --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/jet.go @@ -0,0 +1,184 @@ +// Package sqlbuilders provides SQL builder library-specific checkers for SELECT * detection. +package sqlbuilders + +import ( + "go/ast" + "go/token" + "go/types" + "slices" + "strings" +) + +const jetPkgPath = "github.com/go-jet/jet" + +// JetChecker checks github.com/go-jet/jet for SELECT * patterns. +type JetChecker struct{} + +// NewJetChecker creates a new JetChecker. +func NewJetChecker() *JetChecker { + return &JetChecker{} +} + +// Name returns the name of this checker. +func (c *JetChecker) Name() string { + return "jet" +} + +// IsApplicable checks if the call is from jet using type information. +func (c *JetChecker) IsApplicable(info *types.Info, call *ast.CallExpr) bool { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + // Check for direct SELECT call - verify via type info + if ident, ok := call.Fun.(*ast.Ident); ok { + if info != nil { + if obj := info.Uses[ident]; obj != nil { + if pkg := obj.Pkg(); pkg != nil { + pkgPath := pkg.Path() + if len(pkgPath) >= len(jetPkgPath) && pkgPath[:len(jetPkgPath)] == jetPkgPath { + return true + } + } + } + } + } + return false + } + + // Check if the receiver type is from jet package + return IsTypeFromPackage(info, sel.X, jetPkgPath) +} + +// CheckSelectStar checks for SELECT * in jet calls. +func (c *JetChecker) CheckSelectStar(call *ast.CallExpr) *SelectStarViolation { + // Check for direct function calls (SELECT, RawStatement) + if ident, ok := call.Fun.(*ast.Ident); ok { + return c.checkIdentCall(call, ident) + } + + // Check for selector calls (table.AllColumns, pkg.Star, etc.) + if sel, ok := call.Fun.(*ast.SelectorExpr); ok { + return c.checkSelectorCall(call, sel) + } + + return nil +} + +// checkIdentCall handles direct function calls like SELECT() or RawStatement() +func (c *JetChecker) checkIdentCall(call *ast.CallExpr, ident *ast.Ident) *SelectStarViolation { + switch ident.Name { + case "SELECT": + if slices.ContainsFunc(call.Args, c.isAllColumnsOrStar) { + return &SelectStarViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "Jet SELECT with AllColumns/STAR - specify columns explicitly", + Builder: "jet", + Context: "explicit_star", + } + } + case "RawStatement": + return c.checkRawStatementArgs(call, "Jet RawStatement with SELECT * - specify columns explicitly") + } + return nil +} + +// checkSelectorCall handles selector calls like table.AllColumns or pkg.Star +func (c *JetChecker) checkSelectorCall(call *ast.CallExpr, sel *ast.SelectorExpr) *SelectStarViolation { + methodName := sel.Sel.Name + + switch methodName { + case "AllColumns": + return &SelectStarViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "Jet AllColumns fetches all columns (SELECT *) - specify columns explicitly", + Builder: "jet", + Context: "all_columns", + } + case "Star": + return &SelectStarViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "Jet Star() - avoid SELECT * and specify columns explicitly", + Builder: "jet", + Context: "explicit_star", + } + case "RawStatement", "Raw": + return c.checkRawStatementArgs(call, "Jet Raw/RawStatement with SELECT * - specify columns explicitly") + } + + return nil +} + +// checkRawStatementArgs checks for SELECT * in raw statement arguments +func (c *JetChecker) checkRawStatementArgs(call *ast.CallExpr, message string) *SelectStarViolation { + for _, arg := range call.Args { + if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { + value := strings.Trim(lit.Value, "`\"") + if strings.Contains(strings.ToUpper(value), "SELECT *") { + return &SelectStarViolation{ + Pos: call.Pos(), + End: call.End(), + Message: message, + Builder: "jet", + Context: "raw_select_star", + } + } + } + } + return nil +} + +// CheckChainedCalls checks method chains for SELECT * patterns. +func (c *JetChecker) CheckChainedCalls(call *ast.CallExpr) []*SelectStarViolation { + var violations []*SelectStarViolation + + // Traverse the call chain looking for SELECT with AllColumns + current := call + for current != nil { + // Check arguments for AllColumns + for _, arg := range current.Args { + if c.isAllColumnsOrStar(arg) { + violations = append(violations, &SelectStarViolation{ + Pos: current.Pos(), + End: current.End(), + Message: "Jet SELECT chain contains AllColumns/STAR - specify columns explicitly", + Builder: "jet", + Context: "chained_star", + }) + } + } + + // Move to the next call in the chain + sel, ok := current.Fun.(*ast.SelectorExpr) + if !ok { + break + } + + if innerCall, ok := sel.X.(*ast.CallExpr); ok { + current = innerCall + } else { + break + } + } + + return violations +} + +// isAllColumnsOrStar checks if an expression represents AllColumns or STAR. +func (c *JetChecker) isAllColumnsOrStar(expr ast.Expr) bool { + switch e := expr.(type) { + case *ast.SelectorExpr: + // table.AllColumns or package.STAR + return e.Sel.Name == "AllColumns" || e.Sel.Name == "STAR" + case *ast.CallExpr: + // Check if it's a call to AllColumns() or Star() + if sel, ok := e.Fun.(*ast.SelectorExpr); ok { + return sel.Sel.Name == "AllColumns" || sel.Sel.Name == "Star" + } + case *ast.Ident: + // Direct STAR identifier + return e.Name == "STAR" || e.Name == "AllColumns" + } + return false +} diff --git a/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/pgx.go b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/pgx.go new file mode 100644 index 000000000..394cd6596 --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/pgx.go @@ -0,0 +1,82 @@ +// Package sqlbuilders provides SQL builder library-specific checkers for SELECT * detection. +package sqlbuilders + +import ( + "go/ast" + "go/token" + "go/types" + "strings" +) + +const pgxPkgPath = "github.com/jackc/pgx" + +// PGXChecker checks github.com/jackc/pgx for SELECT * patterns. +type PGXChecker struct{} + +// NewPGXChecker creates a new PGXChecker. +func NewPGXChecker() *PGXChecker { + return &PGXChecker{} +} + +// Name returns the name of this checker. +func (c *PGXChecker) Name() string { + return "pgx" +} + +// IsApplicable checks if the call is from pgx using type information. +func (c *PGXChecker) IsApplicable(info *types.Info, call *ast.CallExpr) bool { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return false + } + + // Check if the receiver type is from pgx package + return IsTypeFromPackage(info, sel.X, pgxPkgPath) +} + +// CheckSelectStar checks for SELECT * in pgx calls. +func (c *PGXChecker) CheckSelectStar(call *ast.CallExpr) *SelectStarViolation { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return nil + } + + methodName := sel.Sel.Name + + // pgx methods where the SQL query is typically the second argument (after context) + // conn.Query(ctx, sql, args...), conn.QueryFunc(ctx, sql, args, func...) + switch methodName { + case "Query", "QueryRow", "Exec", "Prepare", "QueryFunc": + // supported methods + default: + return nil + } + + const queryArgIndex = 1 + if queryArgIndex >= len(call.Args) { + return nil + } + + arg := call.Args[queryArgIndex] + if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { + value := strings.Trim(lit.Value, "`\"") + upperValue := strings.ToUpper(value) + if strings.Contains(upperValue, "SELECT *") { + return &SelectStarViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "pgx " + methodName + "() with SELECT * - specify columns explicitly", + Builder: "pgx", + Context: "raw_select_star", + } + } + } + + return nil +} + +// CheckChainedCalls checks method chains for SELECT * patterns. +func (c *PGXChecker) CheckChainedCalls(call *ast.CallExpr) []*SelectStarViolation { + // pgx doesn't have significant chaining patterns + return nil +} diff --git a/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/reform.go b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/reform.go new file mode 100644 index 000000000..ff7a139c0 --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/reform.go @@ -0,0 +1,238 @@ +package sqlbuilders + +import ( + "go/ast" + "go/token" + "go/types" + "strings" + + "golang.org/x/tools/go/analysis" +) + +const reformPkgPath = "gopkg.in/reform.v1" + +// ReformChecker detects SELECT * patterns in gopkg.in/reform.v1 queries. +// https://github.com/go-reform/reform +type ReformChecker struct{} + +// NewReformChecker creates a new reform checker. +func NewReformChecker() *ReformChecker { + return &ReformChecker{} +} + +// Name returns the name of the SQL builder. +func (c *ReformChecker) Name() string { + return "reform" +} + +// IsApplicable checks if the call is from reform using type information. +func (c *ReformChecker) IsApplicable(info *types.Info, call *ast.CallExpr) bool { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return false + } + + // Check if the receiver type is from reform package + return IsTypeFromPackage(info, sel.X, reformPkgPath) +} + +// CheckSelectStar checks a single call expression for SELECT * usage. +func (c *ReformChecker) CheckSelectStar(call *ast.CallExpr) *SelectStarViolation { + v := c.checkCall(call) + if v == nil { + return nil + } + + return &SelectStarViolation{ + Pos: v.Pos, + End: v.End, + Message: v.Message, + Builder: "reform", + Context: v.Method, + } +} + +// CheckChainedCalls analyzes method chains for SELECT * patterns. +func (c *ReformChecker) CheckChainedCalls(call *ast.CallExpr) []*SelectStarViolation { + // reform doesn't typically use method chaining for SELECT * + return nil +} + +// Check analyzes a file for reform SELECT * patterns. +func (c *ReformChecker) Check(pass *analysis.Pass, file *ast.File) { + ast.Inspect(file, func(n ast.Node) bool { + call, ok := n.(*ast.CallExpr) + if !ok { + return true + } + + if v := c.checkCall(call); v != nil { + pass.Report(analysis.Diagnostic{ + Pos: v.Pos, + End: v.End, + Message: v.Message, + }) + } + + return true + }) +} + +// ReformViolation represents a reform SELECT * violation. +type ReformViolation struct { + Pos token.Pos + End token.Pos + Message string + Method string +} + +// checkCall checks a call expression for reform SELECT * patterns. +func (c *ReformChecker) checkCall(call *ast.CallExpr) *ReformViolation { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return nil + } + + method := sel.Sel.Name + + // reform patterns that load all columns: + // - db.FindByPrimaryKeyFrom(table, pk, &record) + // - db.FindOneFrom(table, column, value, &record) + // - db.FindAllFrom(table, column, values...) + // - db.SelectOneFrom(table, tail, args...) - if tail doesn't specify columns + // - db.SelectAllFrom(table, tail, args...) - if tail doesn't specify columns + // - querier.SelectRows(tail, args...) - may need column specification + + switch method { + case "FindByPrimaryKeyFrom", "FindOneFrom", "FindAllFrom": + // These methods always load all columns + if c.isReformDB(sel.X) { + return &ReformViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "reform: " + method + " loads all columns - consider using SelectAllFrom with specific columns", + Method: method, + } + } + + case "SelectOneFrom", "SelectAllFrom": + // Check if the tail argument specifies columns + if c.isReformDB(sel.X) && !c.hasColumnSpecification(call) { + return &ReformViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "reform: " + method + " should specify columns in the tail argument", + Method: method, + } + } + + case "SelectRows": + // Check querier.SelectRows + if c.isQuerier(sel.X) && !c.hasSelectClause(call) { + return &ReformViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "reform: SelectRows query may select all columns - verify column specification", + Method: method, + } + } + } + + return nil +} + +// isReformDB checks if the expression is a reform DB. +func (c *ReformChecker) isReformDB(expr ast.Expr) bool { + if ident, ok := expr.(*ast.Ident); ok { + name := ident.Name + return name == "db" || name == "DB" || name == "querier" || + name == "tx" || name == "Tx" + } + + if sel, ok := expr.(*ast.SelectorExpr); ok { + return sel.Sel.Name == "DB" || sel.Sel.Name == "Querier" + } + + return false +} + +// isQuerier checks if the expression is a reform Querier. +func (c *ReformChecker) isQuerier(expr ast.Expr) bool { + if ident, ok := expr.(*ast.Ident); ok { + name := ident.Name + return name == "querier" || name == "q" || name == "db" || name == "tx" + } + + return false +} + +// hasColumnSpecification checks if the call specifies columns. +func (c *ReformChecker) hasColumnSpecification(call *ast.CallExpr) bool { + // The tail argument (usually second) should specify columns + // e.g., "WHERE id = ? ORDER BY name" doesn't specify columns + // but "id, name WHERE id = ?" does + + // Find the tail argument (string) + for _, arg := range call.Args { + if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { + tail := strings.Trim(lit.Value, "`\"") + tailUpper := strings.ToUpper(tail) + + // Check if tail starts with column names (not WHERE, ORDER BY, etc.) + if strings.HasPrefix(tailUpper, "WHERE") || + strings.HasPrefix(tailUpper, "ORDER") || + strings.HasPrefix(tailUpper, "LIMIT") || + strings.HasPrefix(tailUpper, "GROUP") || + strings.HasPrefix(tailUpper, "HAVING") || + tail == "" { + return false + } + + // If it doesn't start with common clauses, assume it has columns + return true + } + } + + return false +} + +// hasSelectClause checks if a SelectRows call has a proper SELECT clause. +func (c *ReformChecker) hasSelectClause(call *ast.CallExpr) bool { + for _, arg := range call.Args { + if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { + query := strings.ToUpper(strings.Trim(lit.Value, "`\"")) + + // Check if query has SELECT with specific columns (not *) + if strings.Contains(query, "SELECT") { + if strings.Contains(query, "SELECT *") || + strings.Contains(query, "SELECT\t*") || + strings.Contains(query, "SELECT\n*") { + return false + } + return true + } + } + } + + return false +} + +// CheckFile checks a file and returns violations. +func (c *ReformChecker) CheckFile(file *ast.File, fset *token.FileSet) []ReformViolation { + var violations []ReformViolation + + ast.Inspect(file, func(n ast.Node) bool { + call, ok := n.(*ast.CallExpr) + if !ok { + return true + } + + if v := c.checkCall(call); v != nil { + violations = append(violations, *v) + } + + return true + }) + + return violations +} diff --git a/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/rel.go b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/rel.go new file mode 100644 index 000000000..bf98bc8b9 --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/rel.go @@ -0,0 +1,227 @@ +package sqlbuilders + +import ( + "go/ast" + "go/token" + "go/types" + + "golang.org/x/tools/go/analysis" +) + +const relPkgPath = "github.com/go-rel/rel" + +// RelChecker detects SELECT * patterns in go-rel/rel queries. +// https://github.com/go-rel/rel +type RelChecker struct{} + +// NewRelChecker creates a new rel checker. +func NewRelChecker() *RelChecker { + return &RelChecker{} +} + +// Name returns the name of the SQL builder. +func (c *RelChecker) Name() string { + return "rel" +} + +// IsApplicable checks if the call is from rel using type information. +func (c *RelChecker) IsApplicable(info *types.Info, call *ast.CallExpr) bool { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return false + } + + // Check if the receiver type is from rel package + return IsTypeFromPackage(info, sel.X, relPkgPath) +} + +// CheckSelectStar checks a single call expression for SELECT * usage. +func (c *RelChecker) CheckSelectStar(call *ast.CallExpr) *SelectStarViolation { + if !c.isSelectAllPattern(call) { + return nil + } + + sel := call.Fun.(*ast.SelectorExpr) + return &SelectStarViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "rel: query loads all columns - consider using Select() to specify columns", + Builder: "rel", + Context: sel.Sel.Name, + } +} + +// CheckChainedCalls analyzes method chains for SELECT * patterns. +func (c *RelChecker) CheckChainedCalls(call *ast.CallExpr) []*SelectStarViolation { + // rel doesn't typically use method chaining for SELECT * + return nil +} + +// Check analyzes a file for rel SELECT * patterns. +func (c *RelChecker) Check(pass *analysis.Pass, file *ast.File) { + ast.Inspect(file, func(n ast.Node) bool { + call, ok := n.(*ast.CallExpr) + if !ok { + return true + } + + // Check for rel patterns that load all columns + if c.isSelectAllPattern(call) { + pass.Report(analysis.Diagnostic{ + Pos: call.Pos(), + End: call.End(), + Message: "rel: query loads all columns - consider using Select() to specify columns", + }) + } + + return true + }) +} + +// isSelectAllPattern checks if a call represents a SELECT * pattern in rel. +func (c *RelChecker) isSelectAllPattern(call *ast.CallExpr) bool { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return false + } + + method := sel.Sel.Name + + // rel patterns that load all columns by default: + // - repo.Find(ctx, &user) - loads all columns + // - repo.FindAll(ctx, &users) - loads all columns + // - repo.FindAndCountAll(ctx, &users) - loads all columns + // - rel.From("users").All(ctx, &users) - loads all columns without Select() + + switch method { + case "Find", "FindAll", "FindAndCountAll": + // These methods load all columns unless combined with Select() + // Check if this is a call on a rel repository + if c.isRelRepository(sel.X) { + // Check if the query chain includes Select() + if !c.hasSelectInChain(call) { + return true + } + } + + case "All", "One": + // Check if this is part of a query builder chain without Select() + if c.isQueryBuilderWithoutSelect(sel.X) { + return true + } + } + + return false +} + +// isRelRepository checks if the expression is a rel repository. +func (c *RelChecker) isRelRepository(expr ast.Expr) bool { + // Check for common rel repository variable names + if ident, ok := expr.(*ast.Ident); ok { + name := ident.Name + return name == "repo" || name == "repository" || + name == "r" || name == "db" + } + + // Check for selector on repo + if sel, ok := expr.(*ast.SelectorExpr); ok { + return c.isRelRepository(sel.X) + } + + return false +} + +// hasSelectInChain checks if Select() is used in the query chain. +func (c *RelChecker) hasSelectInChain(call *ast.CallExpr) bool { + // Walk up the chain looking for Select() + current := call.Fun + for { + sel, ok := current.(*ast.SelectorExpr) + if !ok { + break + } + + if sel.Sel.Name == "Select" { + return true + } + + // Check if the receiver is a call expression (method chain) + if callExpr, ok := sel.X.(*ast.CallExpr); ok { + if innerSel, ok := callExpr.Fun.(*ast.SelectorExpr); ok { + if innerSel.Sel.Name == "Select" { + return true + } + } + current = callExpr.Fun + } else { + break + } + } + + return false +} + +// isQueryBuilderWithoutSelect checks if an expression is a query builder without Select(). +func (c *RelChecker) isQueryBuilderWithoutSelect(expr ast.Expr) bool { + // Walk the call chain looking for From() without Select() + hasFrom := false + hasSelect := false + + current := expr + for { + call, ok := current.(*ast.CallExpr) + if !ok { + break + } + + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + break + } + + switch sel.Sel.Name { + case "From": + hasFrom = true + case "Select": + hasSelect = true + } + + current = sel.X + } + + return hasFrom && !hasSelect +} + +// RelViolation represents a rel SELECT * violation. +type RelViolation struct { + Pos token.Pos + End token.Pos + Message string + Method string +} + +// CheckFile checks a file and returns violations. +func (c *RelChecker) CheckFile(file *ast.File, fset *token.FileSet) []RelViolation { + var violations []RelViolation + + ast.Inspect(file, func(n ast.Node) bool { + call, ok := n.(*ast.CallExpr) + if !ok { + return true + } + + if c.isSelectAllPattern(call) { + sel := call.Fun.(*ast.SelectorExpr) + violations = append(violations, RelViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "rel: query loads all columns - consider using Select()", + Method: sel.Sel.Name, + }) + } + + return true + }) + + return violations +} diff --git a/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/sqlboiler.go b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/sqlboiler.go new file mode 100644 index 000000000..1ecbe1e3d --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/sqlboiler.go @@ -0,0 +1,135 @@ +// Package sqlbuilders provides SQL builder library-specific checkers for SELECT * detection. +package sqlbuilders + +import ( + "go/ast" + "go/token" + "go/types" + "strings" +) + +const sqlboilerPkgPath = "github.com/volatiletech/sqlboiler" + +// SQLBoilerChecker checks github.com/volatiletech/sqlboiler for SELECT * patterns. +type SQLBoilerChecker struct{} + +// NewSQLBoilerChecker creates a new SQLBoilerChecker. +func NewSQLBoilerChecker() *SQLBoilerChecker { + return &SQLBoilerChecker{} +} + +// Name returns the name of this checker. +func (c *SQLBoilerChecker) Name() string { + return "sqlboiler" +} + +// IsApplicable checks if the call is from sqlboiler using type information. +func (c *SQLBoilerChecker) IsApplicable(info *types.Info, call *ast.CallExpr) bool { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return false + } + + // Check if the receiver type is from sqlboiler package + if IsTypeFromPackage(info, sel.X, sqlboilerPkgPath) { + return true + } + + // Check for qm (query mods) package - verify via type info + if ident, ok := sel.X.(*ast.Ident); ok { + if info != nil { + if obj := info.Uses[ident]; obj != nil { + // For package-level function calls like qm.Select(), obj is *types.PkgName + if pkgName, ok := obj.(*types.PkgName); ok { + pkgPath := pkgName.Imported().Path() + if len(pkgPath) >= len(sqlboilerPkgPath) && pkgPath[:len(sqlboilerPkgPath)] == sqlboilerPkgPath { + return true + } + } + } + } + } + + return false +} + +// CheckSelectStar checks for SELECT * in sqlboiler calls. +func (c *SQLBoilerChecker) CheckSelectStar(call *ast.CallExpr) *SelectStarViolation { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return nil + } + + methodName := sel.Sel.Name + + // Check qm.Select("*") + if methodName == "Select" { + // Check if caller is qm package + if ident, ok := sel.X.(*ast.Ident); ok && ident.Name == "qm" { + for _, arg := range call.Args { + if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { + value := strings.Trim(lit.Value, "`\"") + if value == "*" { + return &SelectStarViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "SQLBoiler qm.Select(\"*\") - explicitly specify columns", + Builder: "sqlboiler", + Context: "explicit_star", + } + } + } + } + } + } + + return nil +} + +// CheckChainedCalls checks method chains for SELECT * patterns. +func (c *SQLBoilerChecker) CheckChainedCalls(call *ast.CallExpr) []*SelectStarViolation { + var violations []*SelectStarViolation + + // SQLBoiler uses query mods passed to model methods + // Example: models.Users(qm.Select("*")).All(ctx, db) + + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return violations + } + + // Check terminal methods + if sel.Sel.Name == "All" || sel.Sel.Name == "One" { + // Look for the model call that might have query mods + if innerCall, ok := sel.X.(*ast.CallExpr); ok { + // Check if there's a qm.Select in the arguments + // Note: qm.Select("*") is already detected by CheckSelectStar when + // the analyzer visits that CallExpr, so we only check for hasSelect here + hasSelect := false + for _, arg := range innerCall.Args { + if callExpr, ok := arg.(*ast.CallExpr); ok { + if innerSel, ok := callExpr.Fun.(*ast.SelectorExpr); ok { + if innerSel.Sel.Name == "Select" { + hasSelect = true + break + } + } + } + } + + // If no Select query mod, it defaults to SELECT * + if !hasSelect && len(innerCall.Args) == 0 { + // Model().All() without query mods = SELECT * + violations = append(violations, &SelectStarViolation{ + Pos: innerCall.Pos(), + End: call.End(), + Message: "SQLBoiler model().All() without qm.Select() defaults to SELECT *", + Builder: "sqlboiler", + Context: "implicit_star", + }) + } + } + } + + return violations +} diff --git a/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/sqlc.go b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/sqlc.go new file mode 100644 index 000000000..d98a52bd4 --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/sqlc.go @@ -0,0 +1,87 @@ +package sqlbuilders + +import ( + "go/ast" + "go/token" + "go/types" + "strings" +) + +// sqlc generates code, so we check if the package path contains "sqlc" +const sqlcPkgPath = "sqlc" + +// SQLCChecker checks for SELECT * in sqlc generated code. +type SQLCChecker struct{} + +// NewSQLCChecker creates a new sqlc checker. +func NewSQLCChecker() *SQLCChecker { + return &SQLCChecker{} +} + +// Name returns the checker name. +func (c *SQLCChecker) Name() string { + return "sqlc" +} + +// IsApplicable checks if the call is from sqlc generated code using type information. +func (c *SQLCChecker) IsApplicable(info *types.Info, call *ast.CallExpr) bool { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return false + } + + // sqlc generates code, check if receiver type's package contains "sqlc" + if info != nil { + typ := info.TypeOf(sel.X) + if typ != nil { + if named, ok := typ.(*types.Named); ok { + if obj := named.Obj(); obj != nil { + if pkg := obj.Pkg(); pkg != nil { + if strings.Contains(pkg.Path(), sqlcPkgPath) { + return true + } + } + } + } + // Check pointer types + if ptr, ok := typ.(*types.Pointer); ok { + if named, ok := ptr.Elem().(*types.Named); ok { + if obj := named.Obj(); obj != nil { + if pkg := obj.Pkg(); pkg != nil { + if strings.Contains(pkg.Path(), sqlcPkgPath) { + return true + } + } + } + } + } + } + } + + return false +} + +// CheckSelectStar checks for SELECT * in the call. +func (c *SQLCChecker) CheckSelectStar(call *ast.CallExpr) *SelectStarViolation { + // sqlc doesn't typically have SELECT * visible in Go code + // but we can check string arguments + for _, arg := range call.Args { + if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { + value := strings.ToUpper(lit.Value) + if strings.Contains(value, "SELECT *") || strings.Contains(value, "SELECT\t*") { + return &SelectStarViolation{ + Pos: lit.Pos(), + End: lit.End(), + Message: "sqlc query contains SELECT * - specify columns explicitly in your .sql file", + } + } + } + } + return nil +} + +// CheckChainedCalls checks chained method calls. +func (c *SQLCChecker) CheckChainedCalls(call *ast.CallExpr) []*SelectStarViolation { + // sqlc doesn't typically use chained calls + return nil +} diff --git a/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/sqlx.go b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/sqlx.go new file mode 100644 index 000000000..1daf4c6ca --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/sqlx.go @@ -0,0 +1,90 @@ +// Package sqlbuilders provides SQL builder library-specific checkers for SELECT * detection. +package sqlbuilders + +import ( + "go/ast" + "go/token" + "go/types" + "strings" +) + +const sqlxPkgPath = "github.com/jmoiron/sqlx" + +// SQLxChecker checks github.com/jmoiron/sqlx for SELECT * patterns. +type SQLxChecker struct{} + +// NewSQLxChecker creates a new SQLxChecker. +func NewSQLxChecker() *SQLxChecker { + return &SQLxChecker{} +} + +// Name returns the name of this checker. +func (c *SQLxChecker) Name() string { + return "sqlx" +} + +// IsApplicable checks if the call is from sqlx using type information. +func (c *SQLxChecker) IsApplicable(info *types.Info, call *ast.CallExpr) bool { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return false + } + + // Check if the receiver type is from sqlx package + return IsTypeFromPackage(info, sel.X, sqlxPkgPath) +} + +// CheckSelectStar checks for SELECT * in sqlx calls. +func (c *SQLxChecker) CheckSelectStar(call *ast.CallExpr) *SelectStarViolation { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return nil + } + + methodName := sel.Sel.Name + + // Methods where the SQL query is typically the first or second argument + queryArgIndex := 0 + switch methodName { + case "Select", "Get": + // db.Select(&dest, query, args...) + // db.Get(&dest, query, args...) + queryArgIndex = 1 + case "Queryx", "QueryRowx", "MustExec", "NamedExec": + // db.Queryx(query, args...) + queryArgIndex = 0 + case "NamedQuery": + // db.NamedQuery(query, arg) + queryArgIndex = 0 + default: + return nil + } + + if queryArgIndex >= len(call.Args) { + return nil + } + + arg := call.Args[queryArgIndex] + if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { + value := strings.Trim(lit.Value, "`\"") + upperValue := strings.ToUpper(value) + if strings.Contains(upperValue, "SELECT *") { + return &SelectStarViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "sqlx " + methodName + "() with SELECT * - specify columns explicitly", + Builder: "sqlx", + Context: "raw_select_star", + } + } + } + + return nil +} + +// CheckChainedCalls checks method chains for SELECT * patterns. +func (c *SQLxChecker) CheckChainedCalls(call *ast.CallExpr) []*SelectStarViolation { + // sqlx doesn't have significant chaining patterns like GORM + // Most queries are single method calls + return nil +} diff --git a/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/squirrel.go b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/squirrel.go new file mode 100644 index 000000000..33f1f9069 --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqlbuilders/squirrel.go @@ -0,0 +1,214 @@ +// Package sqlbuilders provides SQL builder library-specific checkers for SELECT * detection. +package sqlbuilders + +import ( + "go/ast" + "go/token" + "go/types" + "strings" +) + +const squirrelPkgPath = "github.com/Masterminds/squirrel" + +// SquirrelChecker checks github.com/Masterminds/squirrel for SELECT * patterns. +type SquirrelChecker struct{} + +// NewSquirrelChecker creates a new SquirrelChecker. +func NewSquirrelChecker() *SquirrelChecker { + return &SquirrelChecker{} +} + +// Name returns the name of this checker. +func (c *SquirrelChecker) Name() string { + return "squirrel" +} + +// IsApplicable checks if the call is from Squirrel using type information. +func (c *SquirrelChecker) IsApplicable(info *types.Info, call *ast.CallExpr) bool { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return false + } + + // Check if the receiver type is from squirrel package + if IsTypeFromPackage(info, sel.X, squirrelPkgPath) { + return true + } + + // Check for package-level function calls like squirrel.Select() + if ident, ok := sel.X.(*ast.Ident); ok { + if info != nil { + if obj := info.Uses[ident]; obj != nil { + if pkgName, ok := obj.(*types.PkgName); ok { + pkgPath := pkgName.Imported().Path() + if len(pkgPath) >= len(squirrelPkgPath) && pkgPath[:len(squirrelPkgPath)] == squirrelPkgPath { + return true + } + } + } + } + } + + return false +} + +// CheckSelectStar checks for SELECT * in Squirrel calls. +func (c *SquirrelChecker) CheckSelectStar(call *ast.CallExpr) *SelectStarViolation { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return nil + } + + methodName := sel.Sel.Name + + // Check squirrel.Select("*") or builder.Select("*") + if methodName == "Select" { + // Empty Select() means SELECT * + if len(call.Args) == 0 { + return &SelectStarViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "Squirrel Select() without columns defaults to SELECT * - add specific columns", + Builder: "squirrel", + Context: "empty_select", + } + } + + // Check for "*" in arguments + for _, arg := range call.Args { + if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { + value := strings.Trim(lit.Value, "`\"") + if value == "*" || value == "" { + return &SelectStarViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "Squirrel Select(\"*\") - explicitly specify columns", + Builder: "squirrel", + Context: "explicit_star", + } + } + } + } + } + + // Check Columns("*") or Column("*") + if methodName == "Columns" || methodName == "Column" { + for _, arg := range call.Args { + if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { + value := strings.Trim(lit.Value, "`\"") + if value == "*" { + return &SelectStarViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "Squirrel Columns(\"*\") - explicitly specify columns", + Builder: "squirrel", + Context: "explicit_star", + } + } + } + } + } + + return nil +} + +// CheckChainedCalls checks method chains for SELECT * patterns. +// squirrelChainState tracks state while traversing call chain +type squirrelChainState struct { + hasSelect bool + hasColumns bool + selectCall *ast.CallExpr +} + +func (c *SquirrelChecker) CheckChainedCalls(call *ast.CallExpr) []*SelectStarViolation { + var violations []*SelectStarViolation + state := &squirrelChainState{} + + current := call + for current != nil { + sel, ok := current.Fun.(*ast.SelectorExpr) + if !ok { + break + } + + if v := c.processChainMethod(sel.Sel.Name, current, state); v != nil { + violations = append(violations, v) + } + + if innerCall, ok := sel.X.(*ast.CallExpr); ok { + current = innerCall + } else { + break + } + } + + return violations +} + +// processChainMethod processes a single method in the call chain +func (c *SquirrelChecker) processChainMethod(methodName string, current *ast.CallExpr, state *squirrelChainState) *SelectStarViolation { + switch methodName { + case "Select": + return c.handleSelectMethod(current, state) + case "Columns", "Column": + return c.handleColumnsMethod(current, state) + case "From", "Where", "Join", "LeftJoin", "RightJoin", "InnerJoin": + return c.handleTerminalMethod(state) + } + return nil +} + +// handleSelectMethod handles Select() calls in chain +func (c *SquirrelChecker) handleSelectMethod(current *ast.CallExpr, state *squirrelChainState) *SelectStarViolation { + state.hasSelect = true + state.selectCall = current + + if len(current.Args) == 0 { + return nil + } + + state.hasColumns = true + if v := c.checkArgsForStar(current, "Squirrel Select(\"*\") in chain - specify columns explicitly"); v != nil { + return v + } + return nil +} + +// handleColumnsMethod handles Columns()/Column() calls in chain +func (c *SquirrelChecker) handleColumnsMethod(current *ast.CallExpr, state *squirrelChainState) *SelectStarViolation { + state.hasColumns = true + return c.checkArgsForStar(current, "Squirrel Columns(\"*\") in chain - specify columns explicitly") +} + +// handleTerminalMethod handles terminal methods (From, Where, Join, etc.) +func (c *SquirrelChecker) handleTerminalMethod(state *squirrelChainState) *SelectStarViolation { + if state.hasSelect && !state.hasColumns && state.selectCall != nil && len(state.selectCall.Args) == 0 { + return &SelectStarViolation{ + Pos: state.selectCall.Pos(), + End: state.selectCall.End(), + Message: "Squirrel Select() without columns in chain defaults to SELECT *", + Builder: "squirrel", + Context: "empty_select_chain", + } + } + return nil +} + +// checkArgsForStar checks if any argument is "*" +func (c *SquirrelChecker) checkArgsForStar(call *ast.CallExpr, message string) *SelectStarViolation { + for _, arg := range call.Args { + if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { + value := strings.Trim(lit.Value, "`\"") + if value == "*" { + return &SelectStarViolation{ + Pos: call.Pos(), + End: call.End(), + Message: message, + Builder: "squirrel", + Context: "chained_star", + } + } + } + } + return nil +} diff --git a/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqli_scanner.go b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqli_scanner.go new file mode 100644 index 000000000..7f3d1fe79 --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/sqli_scanner.go @@ -0,0 +1,750 @@ +package analyzer + +import ( + "fmt" + "go/ast" + "go/token" + "go/types" + "regexp" + "strings" + + "golang.org/x/tools/go/analysis" +) + +// SQLISeverity represents the severity level of SQL injection vulnerability. +type SQLISeverity string + +const ( + SQLISeverityCritical SQLISeverity = "critical" // Direct user input in query + SQLISeverityHigh SQLISeverity = "high" // Format string with variables + SQLISeverityMedium SQLISeverity = "medium" // String concatenation + SQLISeverityLow SQLISeverity = "low" // Potential issue, needs review +) + +// SQLInjectionScanner detects potential SQL injection vulnerabilities. +type SQLInjectionScanner struct { + // dangerousFuncs are functions that format strings (potential SQL injection vectors) + dangerousFuncs map[string]map[string]bool // package -> function -> bool + // queryFuncs are database query functions + queryFuncs map[string]bool + // ormQueryMethods are ORM-specific query methods + ormQueryMethods map[string]bool + // taintedVariables tracks variables that might contain user input + taintedVariables map[string]bool + // userInputPatterns are variable name patterns that suggest user input + userInputPatterns []string + // httpInputFuncs are functions that read HTTP input + httpInputFuncs map[string]map[string]bool + // pass is the current analysis pass + pass *analysis.Pass +} + +// SQLInjectionViolation represents a detected SQL injection vulnerability. +type SQLInjectionViolation struct { + Pos token.Pos + End token.Pos + Message string + Severity SQLISeverity + VulnType string // "concat", "sprintf", "exec", "tainted", "orm_raw" + Suggestion string + CodeFix string // Suggested code fix +} + +// NewSQLInjectionScanner creates a new SQL injection scanner. +func NewSQLInjectionScanner() *SQLInjectionScanner { + return &SQLInjectionScanner{ + dangerousFuncs: map[string]map[string]bool{ + "fmt": { + "Sprintf": true, + "Fprintf": true, + "Printf": true, + "Errorf": true, + "Sscanf": true, + }, + "strings": { + "Join": true, + "Replace": true, + "ReplaceAll": true, + "Builder": true, + }, + "strconv": { + "Itoa": true, + "FormatInt": true, + }, + }, + queryFuncs: map[string]bool{ + // Standard database/sql + "Query": true, + "QueryRow": true, + "Exec": true, + "ExecContext": true, + "QueryContext": true, + "QueryRowContext": true, + "Prepare": true, + "PrepareContext": true, + // SQLx + "QueryRowx": true, + "Queryx": true, + "MustExec": true, + "NamedExec": true, + "NamedQuery": true, + "NamedExecContext": true, + "NamedQueryContext": true, + "Get": true, + "Select": true, + "GetContext": true, + "SelectContext": true, + // GORM + "Raw": true, + "Where": true, + "Having": true, + "Order": true, + "Group": true, + "Joins": true, + // Bun + "NewRaw": true, + "ColumnExpr": true, + "WhereOr": true, + // PGX + "SendBatch": true, + }, + ormQueryMethods: map[string]bool{ + // GORM dangerous methods when used with string concat + "Raw": true, + "Exec": true, + "Where": true, + "Or": true, + "Not": true, + "Having": true, + "Order": true, + "Group": true, + "Joins": true, + // Bun + "NewRaw": true, + "WhereOr": true, + "ColumnExpr": true, + "TableExpr": true, + }, + taintedVariables: make(map[string]bool), + userInputPatterns: []string{ + "user", "input", "param", "query", "search", "filter", + "id", "name", "email", "password", "username", "request", + "body", "form", "data", "value", "arg", "args", + "term", "keyword", "text", "content", + }, + httpInputFuncs: map[string]map[string]bool{ + "http": { + "Request": true, + }, + "gin": { + "Param": true, + "Query": true, + "PostForm": true, + "DefaultQuery": true, + "GetQuery": true, + "BindJSON": true, + "ShouldBind": true, + }, + "echo": { + "Param": true, + "QueryParam": true, + "FormValue": true, + "Bind": true, + }, + "fiber": { + "Params": true, + "Query": true, + "FormValue": true, + "BodyParser": true, + }, + "chi": { + "URLParam": true, + }, + "mux": { + "Vars": true, + }, + }, + } +} + +// SQL pattern for identifying SQL-like strings +var sqlPattern = regexp.MustCompile(`(?i)(SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|TRUNCATE)\s+`) + +// Placeholder patterns for parameterized queries +var placeholderPattern = regexp.MustCompile(`(\?|\$\d+|:\w+|@\w+)`) + +// ScanFile scans a file for SQL injection vulnerabilities. +func (s *SQLInjectionScanner) ScanFile(pass *analysis.Pass, file *ast.File) []SQLInjectionViolation { + s.pass = pass + var violations []SQLInjectionViolation + + ast.Inspect(file, func(n ast.Node) bool { + switch node := n.(type) { + case *ast.CallExpr: + // Check for dangerous patterns + if v := s.checkCallExpr(node); v != nil { + violations = append(violations, *v) + } + case *ast.BinaryExpr: + // Check for string concatenation in SQL context + if v := s.checkBinaryExpr(node); v != nil { + violations = append(violations, *v) + } + } + return true + }) + + return violations +} + +// checkCallExpr checks a function call for SQL injection patterns. +func (s *SQLInjectionScanner) checkCallExpr(call *ast.CallExpr) *SQLInjectionViolation { + // Check if this is a query function call + methodName := s.getMethodName(call) + if !s.queryFuncs[methodName] && !s.ormQueryMethods[methodName] { + return nil + } + + // Ignore *sql.Stmt calls since they don't take queries + if s.isStmtMethod(call) { + return nil + } + + // If this is a parameterized query (first arg is string literal with placeholders, + // subsequent args are parameters), it's safe + if s.isParameterizedQuery(call) { + return nil + } + + // Determine which argument is the query string + queryIdx := 0 + if strings.HasSuffix(methodName, "Context") { + queryIdx = 1 + } + + if len(call.Args) <= queryIdx { + return nil + } + + // Only check the query argument for dangerous patterns + arg := call.Args[queryIdx] + + // Pattern 1: fmt.Sprintf result used as query + if innerCall, ok := arg.(*ast.CallExpr); ok { + if s.isDangerousFormatCall(innerCall) { + if s.containsUserInput(innerCall) { + return &SQLInjectionViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "SQL INJECTION: fmt.Sprintf with user input passed to " + methodName + "()", + Severity: SQLISeverityCritical, + VulnType: "sprintf", + Suggestion: "Use parameterized queries with placeholders (?, $1, :name)", + CodeFix: s.generateParameterizedFix(methodName, arg), + } + } + // Even without detected user input, format strings are suspicious + return &SQLInjectionViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "potential SQL injection: fmt.Sprintf result passed to " + methodName + "() - use parameterized queries", + Severity: SQLISeverityHigh, + VulnType: "sprintf", + Suggestion: "Replace fmt.Sprintf with parameterized query using placeholders", + CodeFix: s.generateParameterizedFix(methodName, arg), + } + } + // Check for HTTP input functions + if s.isHTTPInputCall(innerCall) { + return &SQLInjectionViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "SQL INJECTION: HTTP input directly used in " + methodName + "()", + Severity: SQLISeverityCritical, + VulnType: "tainted", + Suggestion: "Never use HTTP input directly in SQL - always use parameterized queries", + } + } + } + + // Pattern 2: String concatenation used as query + if binExpr, ok := arg.(*ast.BinaryExpr); ok { + if binExpr.Op == token.ADD { + if s.containsTaintedVariable(binExpr) { + return &SQLInjectionViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "SQL INJECTION: string concatenation with user input in " + methodName + "()", + Severity: SQLISeverityCritical, + VulnType: "concat", + Suggestion: "Use parameterized queries instead of string concatenation", + CodeFix: "Replace: db." + methodName + "(\"SELECT * FROM users WHERE id = \" + id)\nWith: db." + methodName + "(\"SELECT * FROM users WHERE id = ?\", id)", + } + } + if s.containsStringVariable(binExpr) { + return &SQLInjectionViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "potential SQL injection: string concatenation in " + methodName + "()", + Severity: SQLISeverityHigh, + VulnType: "concat", + Suggestion: "Use parameterized queries instead of string concatenation", + } + } + } + } + + // Pattern 3: Tainted variable used directly + if ident := getIdent(arg); ident != nil { + if s.isTaintedVariable(ident.Name) && !s.isConstant(arg) { + return &SQLInjectionViolation{ + Pos: call.Pos(), + End: call.End(), + Message: fmt.Sprintf("SQL INJECTION: potentially tainted variable '%s' used in %s ()", ident.Name, methodName), + Severity: SQLISeverityHigh, + VulnType: "tainted", + Suggestion: fmt.Sprintf("Validate and sanitize '%s' or use parameterized queries", ident.Name), + } + } + if s.mightBeDynamicQuery(ident) && !s.isConstant(arg) { + return &SQLInjectionViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "review SQL query in " + methodName + "(): ensure '" + ident.Name + "' is not built with user input", + Severity: SQLISeverityMedium, + VulnType: "variable", + Suggestion: "Audit the construction of '" + ident.Name + "' to ensure it doesn't contain user input", + } + } + } + + // Pattern 4: ORM Raw methods with string variables + if s.ormQueryMethods[methodName] { + if v := s.checkORMRawMethod(call, methodName); v != nil { + return v + } + } + + return nil +} + +// checkORMRawMethod checks ORM-specific raw SQL methods. +func (s *SQLInjectionScanner) checkORMRawMethod(call *ast.CallExpr, methodName string) *SQLInjectionViolation { + // Methods like db.Raw(), db.Where() with string concatenation + if len(call.Args) == 0 { + return nil + } + + firstArg := call.Args[0] + + // Check if first argument is a string literal (safe) or variable (needs review) + if _, ok := firstArg.(*ast.BasicLit); !ok { + // Not a string literal - might be dangerous + if ident := getIdent(firstArg); ident != nil { + if s.isTaintedVariable(ident.Name) && !s.isConstant(firstArg) { + return &SQLInjectionViolation{ + Pos: call.Pos(), + End: call.End(), + Message: "SQL INJECTION risk: " + methodName + "() with potentially tainted variable", + Severity: SQLISeverityHigh, + VulnType: "orm_raw", + Suggestion: "Use parameterized syntax: db." + methodName + "(\"field = ?\", value)", + } + } + } + } + + return nil +} + +// generateParameterizedFix generates a suggested fix for sprintf patterns. +func (s *SQLInjectionScanner) generateParameterizedFix(methodName string, arg ast.Expr) string { + return "Replace fmt.Sprintf with parameterized query:\n" + + " Before: db." + methodName + "(fmt.Sprintf(\"SELECT * FROM users WHERE id = %d\", id))\n" + + " After: db." + methodName + "(\"SELECT * FROM users WHERE id = ?\", id)" +} + +// isHTTPInputCall checks if a call is reading HTTP input. +func (s *SQLInjectionScanner) isHTTPInputCall(call *ast.CallExpr) bool { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return false + } + + methodName := sel.Sel.Name + + // Check for common HTTP input methods + httpMethods := map[string]bool{ + "Param": true, "Query": true, "PostForm": true, + "FormValue": true, "QueryParam": true, "Params": true, + "GetQuery": true, "DefaultQuery": true, "BodyParser": true, + "Bind": true, "BindJSON": true, "ShouldBind": true, + "URLParam": true, "Vars": true, + } + + return httpMethods[methodName] +} + +// isConstant checks if an expression refers to a constant. +func (s *SQLInjectionScanner) isConstant(expr ast.Expr) bool { + if expr == nil { + return false + } + if s.pass != nil && s.pass.TypesInfo != nil { + if ident := getIdent(expr); ident != nil { + if obj := s.pass.TypesInfo.ObjectOf(ident); obj != nil { + _, ok := obj.(*types.Const) + return ok + } + } + } + if ident, ok := expr.(*ast.Ident); ok { + if ident.Obj != nil && ident.Obj.Kind == ast.Con { + return true + } + } + return false +} + +// getIdent extracts an identifier from an expression (Ident or SelectorExpr). +func getIdent(expr ast.Expr) *ast.Ident { + switch e := expr.(type) { + case *ast.Ident: + return e + case *ast.SelectorExpr: + return e.Sel + default: + return nil + } +} + +// getConstantValue attempts to get the string value of a constant expression. +func (s *SQLInjectionScanner) getConstantValue(expr ast.Expr) (string, bool) { + if expr == nil { + return "", false + } + if s.pass != nil && s.pass.TypesInfo != nil { + if ident := getIdent(expr); ident != nil { + if obj := s.pass.TypesInfo.ObjectOf(ident); obj != nil { + if c, ok := obj.(*types.Const); ok { + val := c.Val().ExactString() + // Remove quotes if it's a string constant + if strings.HasPrefix(val, "\"") && strings.HasSuffix(val, "\"") { + return val[1 : len(val)-1], true + } + return val, true + } + } + } + } + if ident, ok := expr.(*ast.Ident); ok { + if ident.Obj != nil && ident.Obj.Kind == ast.Con { + if vs, ok := ident.Obj.Decl.(*ast.ValueSpec); ok { + for i, name := range vs.Names { + if name.Name == ident.Name && i < len(vs.Values) { + if lit, ok := vs.Values[i].(*ast.BasicLit); ok && lit.Kind == token.STRING { + val := lit.Value + if strings.HasPrefix(val, "\"") && strings.HasSuffix(val, "\"") { + return val[1 : len(val)-1], true + } + return val, true + } + } + } + } + } + } + return "", false +} + +// isTaintedVariable checks if a variable name suggests user input. +func (s *SQLInjectionScanner) isTaintedVariable(name string) bool { + lowerName := strings.ToLower(name) + for _, pattern := range s.userInputPatterns { + if strings.Contains(lowerName, pattern) { + return true + } + } + return s.taintedVariables[name] +} + +// containsTaintedVariable checks if an expression contains tainted variables. +func (s *SQLInjectionScanner) containsTaintedVariable(expr ast.Expr) bool { + hasTainted := false + + ast.Inspect(expr, func(n ast.Node) bool { + if ident, ok := n.(*ast.Ident); ok { + if s.isTaintedVariable(ident.Name) && !s.isConstant(ident) { + hasTainted = true + return false + } + } + return true + }) + + return hasTainted +} + +// MarkVariableAsTainted marks a variable as containing user input. +func (s *SQLInjectionScanner) MarkVariableAsTainted(name string) { + s.taintedVariables[name] = true +} + +// isStmtMethod checks if a call is a method on a prepared statement (e.g., *sql.Stmt). +func (s *SQLInjectionScanner) isStmtMethod(call *ast.CallExpr) bool { + if sel, ok := call.Fun.(*ast.SelectorExpr); ok { + if s.pass != nil && s.pass.TypesInfo != nil { + if selObj := s.pass.TypesInfo.Uses[sel.Sel]; selObj != nil { + if sig, ok := selObj.Type().(*types.Signature); ok { + if recv := sig.Recv(); recv != nil { + recvType := recv.Type().String() + if strings.Contains(recvType, "sql.Stmt") || strings.Contains(recvType, "sqlx.Stmt") || strings.Contains(recvType, "NamedStmt") { + return true + } + } + } + } + } else { + // Fallback heuristic: if the receiver is named "stmt", assume it's a statement + if ident, ok := sel.X.(*ast.Ident); ok { + name := strings.ToLower(ident.Name) + if strings.Contains(name, "stmt") { + return true + } + } + } + } + return false +} + +// isParameterizedQuery checks if a call uses parameterized query syntax. +// A parameterized query has a string literal or constant with placeholders (?, $1, :name, @param) +// as the query argument, with subsequent arguments providing the values. +func (s *SQLInjectionScanner) isParameterizedQuery(call *ast.CallExpr) bool { + methodName := s.getMethodName(call) + queryIdx := 0 + // Context-aware methods usually have the query as the second argument + if strings.HasSuffix(methodName, "Context") { + queryIdx = 1 + } + + if len(call.Args) <= queryIdx+1 { + return false + } + + // Query argument should be a string literal or constant + queryArg := call.Args[queryIdx] + var queryStr string + if lit, ok := queryArg.(*ast.BasicLit); ok && lit.Kind == token.STRING { + queryStr = lit.Value + } else if val, ok := s.getConstantValue(queryArg); ok { + queryStr = val + } + + if queryStr == "" { + return false + } + + // Check if the string contains placeholder patterns + return placeholderPattern.MatchString(queryStr) +} + +// checkBinaryExpr checks string concatenation for SQL injection. +func (s *SQLInjectionScanner) checkBinaryExpr(expr *ast.BinaryExpr) *SQLInjectionViolation { + if expr.Op != token.ADD { + return nil + } + + // Check if this looks like SQL concatenation + if s.isSQLStringConcat(expr) && s.containsStringVariable(expr) { + return &SQLInjectionViolation{ + Pos: expr.Pos(), + End: expr.End(), + Message: "potential SQL injection: string concatenation with SQL keywords - use parameterized queries", + Severity: SQLISeverityMedium, + VulnType: "concat", + } + } + + return nil +} + +// getMethodName extracts the method name from a call expression. +func (s *SQLInjectionScanner) getMethodName(call *ast.CallExpr) string { + switch fun := call.Fun.(type) { + case *ast.SelectorExpr: + return fun.Sel.Name + case *ast.Ident: + return fun.Name + } + return "" +} + +// isDangerousFormatCall checks if a call is to a dangerous format function. +func (s *SQLInjectionScanner) isDangerousFormatCall(call *ast.CallExpr) bool { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return false + } + + pkgIdent, ok := sel.X.(*ast.Ident) + if !ok { + return false + } + + if funcs, ok := s.dangerousFuncs[pkgIdent.Name]; ok { + return funcs[sel.Sel.Name] + } + + return false +} + +// containsUserInput checks if a format call might contain user input. +func (s *SQLInjectionScanner) containsUserInput(call *ast.CallExpr) bool { + if len(call.Args) < 2 { + return false + } + + // Check if any argument is a variable (not a literal) + for i, arg := range call.Args { + if i == 0 { + // Skip format string + continue + } + // If argument is not a literal, it might be user input + if _, ok := arg.(*ast.BasicLit); !ok { + // Check if it's a constant (including exported constants from other packages) + if s.isConstant(arg) { + continue + } + return true + } + } + + return false +} + +// containsStringVariable checks if an expression contains string variables. +func (s *SQLInjectionScanner) containsStringVariable(expr ast.Expr) bool { + hasVariable := false + + ast.Inspect(expr, func(n ast.Node) bool { + switch node := n.(type) { + case *ast.Ident: + // Check if this is a variable (not a constant) + if s.isConstant(node) { + return true + } + if node.Obj != nil { + hasVariable = true + return false + } + case *ast.CallExpr: + // Function call results are considered dynamic + hasVariable = true + return false + } + return true + }) + + return hasVariable +} + +// isSQLStringConcat checks if a binary expression looks like SQL concatenation. +func (s *SQLInjectionScanner) isSQLStringConcat(expr *ast.BinaryExpr) bool { + // Check left operand + if s.isQueryString(expr.X) { + return true + } + // Check right operand + if s.isQueryString(expr.Y) { + return true + } + return false +} + +// isQueryString checks if an expression looks like a SQL query string. +func (s *SQLInjectionScanner) isQueryString(expr ast.Expr) bool { + var val string + if lit, ok := expr.(*ast.BasicLit); ok && lit.Kind == token.STRING { + val = lit.Value + } else if v, ok := s.getConstantValue(expr); ok { + val = v + } + + if val == "" { + return false + } + + value := strings.ToUpper(val) + return sqlPattern.MatchString(value) +} + +// mightBeDynamicQuery checks if an identifier might be a dynamically built query. +func (s *SQLInjectionScanner) mightBeDynamicQuery(ident *ast.Ident) bool { + name := strings.ToLower(ident.Name) + return strings.Contains(name, "query") || + strings.Contains(name, "sql") || + strings.Contains(name, "stmt") +} + +// AnalyzeSQLInjection is a convenience function to run SQL injection scanning. +func AnalyzeSQLInjection(pass *analysis.Pass, file *ast.File) { + scanner := NewSQLInjectionScanner() + violations := scanner.ScanFile(pass, file) + + for _, v := range violations { + message := v.Message + if v.Suggestion != "" { + message += "\n Suggestion: " + v.Suggestion + } + if v.CodeFix != "" { + message += "\n Fix: " + v.CodeFix + } + if v.Severity != "" { + message = "[" + string(v.Severity) + "] " + message + } + + pass.Report(analysis.Diagnostic{ + Pos: v.Pos, + End: v.End, + Message: message, + }) + } +} + +// GetSQLInjectionViolations returns all SQL injection violations for external use. +func GetSQLInjectionViolations(pass *analysis.Pass, file *ast.File) []SQLInjectionViolation { + scanner := NewSQLInjectionScanner() + return scanner.ScanFile(pass, file) +} + +// ScanFileAST scans a file for SQL injection vulnerabilities without analysis.Pass. +// This is designed for use in LSP server where we don't have a full analysis pass. +func ScanFileAST(fset *token.FileSet, file *ast.File) []SQLInjectionViolation { + scanner := NewSQLInjectionScanner() + return scanner.ScanFileNoPass(fset, file) +} + +// ScanFileNoPass scans a file for SQL injection vulnerabilities without analysis.Pass. +// This is a method version for testing purposes. +func (s *SQLInjectionScanner) ScanFileNoPass(fset *token.FileSet, file *ast.File) []SQLInjectionViolation { + s.pass = nil + var violations []SQLInjectionViolation + + ast.Inspect(file, func(n ast.Node) bool { + switch node := n.(type) { + case *ast.CallExpr: + if v := s.checkCallExpr(node); v != nil { + violations = append(violations, *v) + } + case *ast.BinaryExpr: + if v := s.checkBinaryExpr(node); v != nil { + violations = append(violations, *v) + } + } + return true + }) + + return violations +} diff --git a/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/tx_leak_detector.go b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/tx_leak_detector.go new file mode 100644 index 000000000..afa3b68a4 --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/internal/analyzer/tx_leak_detector.go @@ -0,0 +1,1665 @@ +package analyzer + +import ( + "fmt" + "go/ast" + "go/token" + "strings" + + "golang.org/x/tools/go/analysis" +) + +// TxLeakSeverity represents the severity level of a transaction leak. +type TxLeakSeverity string + +const ( + TxLeakSeverityCritical TxLeakSeverity = "critical" // Begin without any Commit/Rollback + TxLeakSeverityHigh TxLeakSeverity = "high" // Begin with Commit but no Rollback in error path + TxLeakSeverityMedium TxLeakSeverity = "medium" // Begin with Rollback but no Commit + TxLeakSeverityLow TxLeakSeverity = "low" // Informational - potential issue +) + +// TxLeakViolation represents a detected unclosed transaction. +type TxLeakViolation struct { + Pos token.Pos + End token.Pos + Message string + Severity TxLeakSeverity + ViolationType string // violation type identifier + TxVarName string // Name of the transaction variable + Suggestion string +} + +// TxState tracks the state of a transaction variable within a function. +type TxState struct { + VarName string + BeginPos token.Pos + BeginEnd token.Pos + HasCommit bool + HasRollback bool + HasDefer bool // Rollback/Commit in defer + HasDeferredCommit bool // Commit() is in defer - antipattern + IsReturned bool // Transaction returned to caller + IsReturnedInClosure bool // Transaction captured by returned closure + IsCallback bool // Transaction used in callback pattern + IsPassedToFunc bool // Transaction passed to another function + IsSentToChannel bool // Transaction sent through channel (ch <- tx) + IsStoredInStruct bool // Transaction stored in struct field + IsStoredInCollection bool // Transaction stored in map or slice + IsCapturedByGoroutine bool // Transaction captured by goroutine + IsShadowed bool // Variable is shadowed in inner scope + ShadowedBy token.Pos // Position where shadowing occurs + HasPanicPath bool // Function has panic() without deferred rollback + HasFatalPath bool // Function has os.Exit/log.Fatal without deferred rollback + HasEarlyReturn bool // Has return before commit without defer + CommitInConditional bool // Commit is inside conditional block + CommitInSwitch bool // Commit is inside switch/case that might not execute + CommitInSelect bool // Commit is inside select/case that might not execute + CommitInLoop bool // Commit is inside loop that might not iterate + IsReassigned bool // Transaction variable is reassigned + CommitErrorIgnored bool // Commit() error is ignored with blank identifier + RollbackErrorIgnored bool // Rollback() error is ignored with blank identifier + HasDeferInLoop bool // Transaction has defer inside a loop (antipattern) + Scope int // Scope depth where transaction was created +} + +// TxLeakDetector detects unclosed SQL transactions. +type TxLeakDetector struct { + // beginMethods are methods that start a transaction + beginMethods map[string]bool + // commitMethods are methods that commit a transaction + commitMethods map[string]bool + // rollbackMethods are methods that rollback a transaction + rollbackMethods map[string]bool + // callbackMethods are methods that handle tx lifecycle automatically + callbackMethods map[string]bool + // txStates tracks all transaction states in current function + txStates map[string]*TxState + // scopeDepth tracks current scope depth for shadowing detection + scopeDepth int + // txScopes maps variable names to their scope depths for shadowing detection + txScopes map[string][]int +} + +// NewTxLeakDetector creates a new transaction leak detector. +func NewTxLeakDetector() *TxLeakDetector { + return &TxLeakDetector{ + beginMethods: map[string]bool{ + // database/sql + "Begin": true, + "BeginTx": true, + // sqlx + "BeginTxx": true, + "Beginx": true, + "MustBegin": true, + "MustBeginTx": true, + // pgx + "BeginFunc": true, // callback pattern - also in callbackMethods + // bun + "RunInTx": true, // callback pattern - also in callbackMethods + // ent ORM + "Tx": true, + // General + "NewTx": true, + }, + commitMethods: map[string]bool{ + "Commit": true, + }, + rollbackMethods: map[string]bool{ + "Rollback": true, + }, + callbackMethods: map[string]bool{ + // These handle tx lifecycle automatically + "Transaction": true, + "RunInTransaction": true, + "BeginFunc": true, + "BeginTxFunc": true, // pgx conn.BeginTxFunc + "RunInTx": true, + "WithTx": true, + "InTransaction": true, + "Transactional": true, + "ExecTx": true, + "DoInTx": true, + }, + txStates: make(map[string]*TxState), + txScopes: make(map[string][]int), + } +} + +// CheckTxLeaks analyzes a file for unclosed transaction patterns. +func (d *TxLeakDetector) CheckTxLeaks(pass *analysis.Pass, file *ast.File) []TxLeakViolation { + var violations []TxLeakViolation + + // Analyze each function declaration + for _, decl := range file.Decls { + funcDecl, ok := decl.(*ast.FuncDecl) + if !ok || funcDecl.Body == nil { + continue + } + + // Skip test functions (TestXxx, BenchmarkXxx, FuzzXxx, ExampleXxx) + if isTestFunction(funcDecl) { + continue + } + + // Skip test helper functions (functions with *testing.T as first param) + if isTestHelperFunction(funcDecl) { + continue + } + + violations = append(violations, d.analyzeFunction(funcDecl)...) + } + + return violations +} + +// isTestFunction checks if a function declaration is a test function. +// A test function has a name starting with Test/Benchmark/Fuzz/Example AND +// the appropriate parameter signature (or no params for Example). +func isTestFunction(funcDecl *ast.FuncDecl) bool { + name := funcDecl.Name.Name + + // Check for Example functions (no required parameters) + if strings.HasPrefix(name, "Example") { + return true + } + + // Check for Test, Benchmark, Fuzz functions + isTestPrefix := strings.HasPrefix(name, "Test") || + strings.HasPrefix(name, "Benchmark") || + strings.HasPrefix(name, "Fuzz") + + if !isTestPrefix { + return false + } + + // Must have at least one parameter + if funcDecl.Type.Params == nil || len(funcDecl.Type.Params.List) == 0 { + return false + } + + // Check first parameter type + firstParam := funcDecl.Type.Params.List[0] + if firstParam.Type == nil { + return false + } + + // Check for *testing.T, *testing.B, *testing.F + starExpr, ok := firstParam.Type.(*ast.StarExpr) + if !ok { + return false + } + + selExpr, ok := starExpr.X.(*ast.SelectorExpr) + if !ok { + return false + } + + ident, ok := selExpr.X.(*ast.Ident) + if !ok { + return false + } + + if ident.Name != "testing" { + return false + } + + expectedType := "" + if strings.HasPrefix(name, "Test") { + expectedType = "T" + } else if strings.HasPrefix(name, "Benchmark") { + expectedType = "B" + } else if strings.HasPrefix(name, "Fuzz") { + expectedType = "F" + } + + return selExpr.Sel.Name == expectedType +} + +// isTestHelperFunction checks if a function is a test helper by looking at its parameters. +// Test helpers typically take *testing.T, *testing.B, or *testing.F as the first parameter. +func isTestHelperFunction(funcDecl *ast.FuncDecl) bool { + if funcDecl.Type.Params == nil || len(funcDecl.Type.Params.List) == 0 { + return false + } + + // Check first parameter + firstParam := funcDecl.Type.Params.List[0] + if firstParam.Type == nil { + return false + } + + // Check for *testing.T, *testing.B, *testing.F + starExpr, ok := firstParam.Type.(*ast.StarExpr) + if !ok { + return false + } + + selExpr, ok := starExpr.X.(*ast.SelectorExpr) + if !ok { + return false + } + + ident, ok := selExpr.X.(*ast.Ident) + if !ok { + return false + } + + if ident.Name == "testing" { + switch selExpr.Sel.Name { + case "T", "B", "F", "M": + return true + } + } + + return false +} + +// analyzeFunction analyzes a single function for transaction leaks. +func (d *TxLeakDetector) analyzeFunction(funcDecl *ast.FuncDecl) []TxLeakViolation { + // Reset state for each function + d.txStates = make(map[string]*TxState) + d.txScopes = make(map[string][]int) + d.scopeDepth = 0 + + // Phase 1: Find transaction Begin points with scope tracking + d.findTransactionBeginsWithScope(funcDecl) + + if len(d.txStates) == 0 { + return nil + } + + // Phase 2: Check for callback patterns (handled automatically) + d.detectCallbackPatterns(funcDecl) + + // Phase 3: Track Commit/Rollback calls + d.trackCommitRollback(funcDecl) + + // Phase 4: Check for returned transactions + d.checkReturnStatements(funcDecl) + + // Phase 5: Check for transactions passed to other functions + d.checkFunctionParameters(funcDecl) + + // Phase 6: Check for transactions stored in struct fields + d.checkStructFieldStorage(funcDecl) + + // Phase 6.5: Check for transactions sent through channels + d.checkChannelSend(funcDecl) + + // Phase 7: Check for goroutine captures + d.checkGoroutineCaptures(funcDecl) + + // Phase 8: Check for panic paths without defer + d.checkPanicPaths(funcDecl) + + // Phase 9: Check for early returns without defer + d.checkEarlyReturns(funcDecl) + + // Phase 10: Check for conditional commits + d.checkConditionalCommits(funcDecl) + + // Phase 11: Check for switch/case commits + d.checkSwitchCaseCommits(funcDecl) + + // Phase 12: Check for select/case commits + d.checkSelectCaseCommits(funcDecl) + + // Phase 13: Check for os.Exit/log.Fatal paths + d.checkFatalPaths(funcDecl) + + // Phase 14: Check for commit in loops + d.checkLoopCommits(funcDecl) + + // Phase 15: Check for variable reassignment + d.checkVariableReassignment(funcDecl) + + // Phase 16: Check for ignored commit errors + d.checkCommitErrorIgnored(funcDecl) + + // Phase 17: Check for ignored rollback errors + d.checkRollbackErrorIgnored(funcDecl) + + // Phase 18: Check for defer inside loop (antipattern) + d.checkDeferInLoop(funcDecl) + + // Phase 19: Generate violations + return d.generateViolations() +} + +// findTransactionBeginsWithScope finds all transaction Begin calls with scope tracking. +func (d *TxLeakDetector) findTransactionBeginsWithScope(funcDecl *ast.FuncDecl) { + // First pass: find all transaction begins and their scopes + d.findBeginsRecursive(funcDecl.Body, 0) +} + +// findBeginsRecursive recursively finds Begin calls with scope tracking. +func (d *TxLeakDetector) findBeginsRecursive(node ast.Node, depth int) { + if node == nil { + return + } + + ast.Inspect(node, func(n ast.Node) bool { + switch stmt := n.(type) { + case *ast.BlockStmt: + // Process block with increased depth + for _, s := range stmt.List { + d.findBeginsRecursive(s, depth+1) + } + return false // Don't recurse further, we handled it + + case *ast.IfStmt: + // Process if statement parts with proper scoping + // The if body creates a new scope + if stmt.Init != nil { + d.findBeginsRecursive(stmt.Init, depth) + } + d.findBeginsRecursive(stmt.Body, depth+1) // if body is a new scope + if stmt.Else != nil { + d.findBeginsRecursive(stmt.Else, depth+1) // else is also a new scope + } + return false + + case *ast.ForStmt: + if stmt.Init != nil { + d.findBeginsRecursive(stmt.Init, depth) + } + d.findBeginsRecursive(stmt.Body, depth+1) // for body is a new scope + return false + + case *ast.RangeStmt: + d.findBeginsRecursive(stmt.Body, depth+1) // range body is a new scope + return false + + case *ast.AssignStmt: + d.processAssignmentWithDepth(stmt, depth) + return true + } + return true + }) +} + +// processAssignmentWithDepth processes an assignment with explicit depth. +func (d *TxLeakDetector) processAssignmentWithDepth(assignStmt *ast.AssignStmt, depth int) { + for i, rhs := range assignStmt.Rhs { + call, ok := rhs.(*ast.CallExpr) + if !ok { + continue + } + + if d.isBeginCall(call) { + // Skip if this is a callback pattern method + if d.isCallbackMethod(call) { + continue + } + + // Extract variable name from LHS + if i < len(assignStmt.Lhs) { + if ident, ok := assignStmt.Lhs[i].(*ast.Ident); ok { + // Skip error variables + if ident.Name == "err" || ident.Name == "_" { + continue + } + + varName := ident.Name + + // Check for shadowing - if variable exists in outer scope + if existingScopes, exists := d.txScopes[varName]; exists { + for _, existingScope := range existingScopes { + if existingScope < depth { + // This is shadowing - mark the outer transaction + // Find the state for the outer variable + for key, state := range d.txStates { + if state.VarName == varName && state.Scope == existingScope { + state.IsShadowed = true + state.ShadowedBy = assignStmt.Pos() + _ = key // used in iteration + break + } + } + } + } + } + + // Track scope for this variable + d.txScopes[varName] = append(d.txScopes[varName], depth) + + // Create unique key for this transaction + key := d.createTxKey(varName, depth, assignStmt.Pos()) + d.txStates[key] = &TxState{ + VarName: varName, + BeginPos: assignStmt.Pos(), + BeginEnd: assignStmt.End(), + Scope: depth, + } + } + } + } + } +} + +// createTxKey creates a unique key for a transaction state. +func (d *TxLeakDetector) createTxKey(varName string, scope int, pos token.Pos) string { + // Use position to create unique key for shadowed variables + return fmt.Sprintf("%s_%d_%d", varName, scope, pos) +} + +// isBeginCall checks if a call expression is a transaction Begin method. +func (d *TxLeakDetector) isBeginCall(call *ast.CallExpr) bool { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return false + } + return d.beginMethods[sel.Sel.Name] +} + +// isCallbackMethod checks if a call expression is a callback-based transaction method. +func (d *TxLeakDetector) isCallbackMethod(call *ast.CallExpr) bool { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return false + } + return d.callbackMethods[sel.Sel.Name] +} + +// detectCallbackPatterns marks transactions that are used in callback patterns. +func (d *TxLeakDetector) detectCallbackPatterns(funcDecl *ast.FuncDecl) { + ast.Inspect(funcDecl.Body, func(n ast.Node) bool { + call, ok := n.(*ast.CallExpr) + if !ok { + return true + } + + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return true + } + + // Check if this is a callback transaction method + if d.callbackMethods[sel.Sel.Name] { + // Mark any tx parameters in the callback as handled + for _, arg := range call.Args { + if funcLit, ok := arg.(*ast.FuncLit); ok { + // Check parameters of the callback function + for _, param := range funcLit.Type.Params.List { + for _, name := range param.Names { + d.markAllStatesWithName(name.Name, func(s *TxState) { + s.IsCallback = true + }) + } + } + } + } + } + + return true + }) +} + +// markAllStatesWithName applies a function to all states with the given variable name. +func (d *TxLeakDetector) markAllStatesWithName(varName string, fn func(*TxState)) { + for _, state := range d.txStates { + if state.VarName == varName { + fn(state) + } + } +} + +// trackCommitRollback scans for Commit and Rollback calls on tracked transaction variables. +func (d *TxLeakDetector) trackCommitRollback(funcDecl *ast.FuncDecl) { + ast.Inspect(funcDecl.Body, func(n ast.Node) bool { + switch node := n.(type) { + case *ast.GoStmt: + // Skip goroutines - defers inside goroutines don't protect the main function + // We track goroutine captures separately in checkGoroutineCaptures + return false + + case *ast.DeferStmt: + // Check defer statements + d.checkDeferStatement(node) + return true + + case *ast.CallExpr: + // Check direct Commit/Rollback calls + d.checkCommitRollbackCall(node, false) + return true + } + return true + }) +} + +// checkDeferStatement checks a defer statement for Commit/Rollback calls. +func (d *TxLeakDetector) checkDeferStatement(deferStmt *ast.DeferStmt) { + call := deferStmt.Call + // Check for direct defer tx.Rollback() + d.checkCommitRollbackCall(call, true) + + // Check for defer func() { ... }() + if funcLit, ok := call.Fun.(*ast.FuncLit); ok { + d.checkDeferredClosure(funcLit) + } + + // Check for defer someFunc(tx) - function call with tx as argument + d.checkDeferredFunctionCall(call) +} + +// checkDeferredFunctionCall checks if a deferred function call takes a transaction as argument. +// This handles patterns like: defer cleanup(tx) where cleanup() might do Rollback. +func (d *TxLeakDetector) checkDeferredFunctionCall(call *ast.CallExpr) { + // Check each argument to see if it's a tracked transaction variable + for _, arg := range call.Args { + switch a := arg.(type) { + case *ast.Ident: + // Direct variable: defer cleanup(tx) + d.markAllStatesWithName(a.Name, func(s *TxState) { + s.HasDefer = true + // We assume the function handles rollback since tx is passed to deferred call + }) + case *ast.UnaryExpr: + // Pointer: defer cleanup(&tx) + if ident, ok := a.X.(*ast.Ident); ok { + d.markAllStatesWithName(ident.Name, func(s *TxState) { + s.HasDefer = true + }) + } + } + } +} + +// checkDeferredClosure checks a deferred closure for Commit/Rollback calls. +func (d *TxLeakDetector) checkDeferredClosure(funcLit *ast.FuncLit) { + ast.Inspect(funcLit.Body, func(n ast.Node) bool { + if call, ok := n.(*ast.CallExpr); ok { + d.checkCommitRollbackCall(call, true) + } + return true + }) +} + +// checkCommitRollbackCall checks if a call is Commit or Rollback on a tracked transaction. +func (d *TxLeakDetector) checkCommitRollbackCall(call *ast.CallExpr, inDefer bool) { + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return + } + + methodName := sel.Sel.Name + + // Get the variable name being called on + var varName string + if ident, ok := sel.X.(*ast.Ident); ok { + varName = ident.Name + } + + if varName == "" { + return + } + + // Mark all states with this variable name + d.markAllStatesWithName(varName, func(state *TxState) { + if d.commitMethods[methodName] { + state.HasCommit = true + // Deferred commit is an antipattern + if inDefer { + state.HasDeferredCommit = true + } + } + + if d.rollbackMethods[methodName] { + state.HasRollback = true + if inDefer { + state.HasDefer = true + } + } + }) +} + +// checkReturnStatements checks if any transaction variable is returned. +func (d *TxLeakDetector) checkReturnStatements(funcDecl *ast.FuncDecl) { + ast.Inspect(funcDecl.Body, func(n ast.Node) bool { + retStmt, ok := n.(*ast.ReturnStmt) + if !ok { + return true + } + + for _, result := range retStmt.Results { + switch r := result.(type) { + case *ast.Ident: + d.markAllStatesWithName(r.Name, func(s *TxState) { + s.IsReturned = true + }) + case *ast.UnaryExpr: + // Handle &tx case (returning pointer) + if ident, ok := r.X.(*ast.Ident); ok { + d.markAllStatesWithName(ident.Name, func(s *TxState) { + s.IsReturned = true + }) + } + case *ast.FuncLit: + // Handle closure return: return func() { tx.Commit() } + // Check if closure captures any tracked tx variables + d.checkClosureCaptures(r) + } + } + return true + }) +} + +// checkClosureCaptures checks if a closure captures any tracked transaction variables. +func (d *TxLeakDetector) checkClosureCaptures(funcLit *ast.FuncLit) { + ast.Inspect(funcLit.Body, func(inner ast.Node) bool { + if ident, ok := inner.(*ast.Ident); ok { + d.markAllStatesWithName(ident.Name, func(s *TxState) { + s.IsReturnedInClosure = true + }) + } + return true + }) +} + +// checkFunctionParameters checks if transaction is passed to another function. +func (d *TxLeakDetector) checkFunctionParameters(funcDecl *ast.FuncDecl) { + ast.Inspect(funcDecl.Body, func(n ast.Node) bool { + call, ok := n.(*ast.CallExpr) + if !ok { + return true + } + + // Skip if this is a Commit/Rollback call + if sel, ok := call.Fun.(*ast.SelectorExpr); ok { + if d.commitMethods[sel.Sel.Name] || d.rollbackMethods[sel.Sel.Name] { + return true + } + } + + // Check each argument + for _, arg := range call.Args { + switch a := arg.(type) { + case *ast.Ident: + d.markAllStatesWithName(a.Name, func(s *TxState) { + s.IsPassedToFunc = true + }) + case *ast.UnaryExpr: + if ident, ok := a.X.(*ast.Ident); ok { + d.markAllStatesWithName(ident.Name, func(s *TxState) { + s.IsPassedToFunc = true + }) + } + } + } + return true + }) +} + +// checkStructFieldStorage checks if transaction is stored in a struct field. +func (d *TxLeakDetector) checkStructFieldStorage(funcDecl *ast.FuncDecl) { + ast.Inspect(funcDecl.Body, func(n ast.Node) bool { + assignStmt, ok := n.(*ast.AssignStmt) + if !ok { + return true + } + + for i, lhs := range assignStmt.Lhs { + // Check for struct field assignment: s.tx = tx + if sel, ok := lhs.(*ast.SelectorExpr); ok { + _ = sel // We have a selector on the left side + if i < len(assignStmt.Rhs) { + if ident, ok := assignStmt.Rhs[i].(*ast.Ident); ok { + d.markAllStatesWithName(ident.Name, func(s *TxState) { + s.IsStoredInStruct = true + }) + } + } + } + + // Check for map/slice assignment: txMap[key] = tx or txSlice[i] = tx + if indexExpr, ok := lhs.(*ast.IndexExpr); ok { + _ = indexExpr + if i < len(assignStmt.Rhs) { + if ident, ok := assignStmt.Rhs[i].(*ast.Ident); ok { + d.markAllStatesWithName(ident.Name, func(s *TxState) { + s.IsStoredInCollection = true + }) + } + } + } + } + + // Check for append: txSlice = append(txSlice, tx) + for _, rhs := range assignStmt.Rhs { + if call, ok := rhs.(*ast.CallExpr); ok { + if ident, ok := call.Fun.(*ast.Ident); ok && ident.Name == "append" { + // Check arguments after the first one + for j := 1; j < len(call.Args); j++ { + if argIdent, ok := call.Args[j].(*ast.Ident); ok { + d.markAllStatesWithName(argIdent.Name, func(s *TxState) { + s.IsStoredInCollection = true + }) + } + } + } + } + } + + return true + }) +} + +// checkChannelSend checks if transaction is sent through a channel. +func (d *TxLeakDetector) checkChannelSend(funcDecl *ast.FuncDecl) { + ast.Inspect(funcDecl.Body, func(n ast.Node) bool { + sendStmt, ok := n.(*ast.SendStmt) + if !ok { + return true + } + + // Check if value being sent is a tracked transaction: ch <- tx + if ident, ok := sendStmt.Value.(*ast.Ident); ok { + d.markAllStatesWithName(ident.Name, func(s *TxState) { + s.IsSentToChannel = true + }) + } + + // Also check for pointer: ch <- &tx + if unary, ok := sendStmt.Value.(*ast.UnaryExpr); ok { + if ident, ok := unary.X.(*ast.Ident); ok { + d.markAllStatesWithName(ident.Name, func(s *TxState) { + s.IsSentToChannel = true + }) + } + } + + return true + }) +} + +// checkGoroutineCaptures checks if transaction is captured by a goroutine. +func (d *TxLeakDetector) checkGoroutineCaptures(funcDecl *ast.FuncDecl) { + ast.Inspect(funcDecl.Body, func(n ast.Node) bool { + goStmt, ok := n.(*ast.GoStmt) + if !ok { + return true + } + + // Check what variables the goroutine captures + ast.Inspect(goStmt.Call, func(inner ast.Node) bool { + if ident, ok := inner.(*ast.Ident); ok { + d.markAllStatesWithName(ident.Name, func(s *TxState) { + s.IsCapturedByGoroutine = true + }) + } + return true + }) + + return true + }) +} + +// checkPanicPaths checks if function has panic() without deferred rollback. +func (d *TxLeakDetector) checkPanicPaths(funcDecl *ast.FuncDecl) { + hasPanic := false + ast.Inspect(funcDecl.Body, func(n ast.Node) bool { + call, ok := n.(*ast.CallExpr) + if !ok { + return true + } + + if ident, ok := call.Fun.(*ast.Ident); ok { + if ident.Name == "panic" { + hasPanic = true + } + } + return true + }) + + if hasPanic { + for _, state := range d.txStates { + if !state.HasDefer { + state.HasPanicPath = true + } + } + } +} + +// checkEarlyReturns checks for early returns before commit without defer. +func (d *TxLeakDetector) checkEarlyReturns(funcDecl *ast.FuncDecl) { + // Track position of each tx Begin + txPositions := make(map[string]token.Pos) + for name, state := range d.txStates { + txPositions[name] = state.BeginPos + } + + var returnPositions []token.Pos + var commitPositions []token.Pos + + ast.Inspect(funcDecl.Body, func(n ast.Node) bool { + switch node := n.(type) { + case *ast.ReturnStmt: + returnPositions = append(returnPositions, node.Pos()) + case *ast.CallExpr: + if sel, ok := node.Fun.(*ast.SelectorExpr); ok { + if d.commitMethods[sel.Sel.Name] { + commitPositions = append(commitPositions, node.Pos()) + } + } + } + return true + }) + + // Check if there are returns before any commit + for _, state := range d.txStates { + if state.HasDefer { + continue // Defer handles early returns + } + + for _, retPos := range returnPositions { + // If return is after Begin but before Commit + hasCommitBefore := false + for _, commitPos := range commitPositions { + if commitPos < retPos { + hasCommitBefore = true + break + } + } + if retPos > state.BeginPos && !hasCommitBefore { + state.HasEarlyReturn = true + break + } + } + } +} + +// checkSwitchCaseCommits checks if Commit is inside switch/case that might not execute. +func (d *TxLeakDetector) checkSwitchCaseCommits(funcDecl *ast.FuncDecl) { + ast.Inspect(funcDecl.Body, func(n ast.Node) bool { + switchStmt, ok := n.(*ast.SwitchStmt) + if !ok { + return true + } + + // Count cases with commit + casesWithCommit := 0 + totalCases := 0 + hasDefault := false + + for _, stmt := range switchStmt.Body.List { + caseClause, ok := stmt.(*ast.CaseClause) + if !ok { + continue + } + totalCases++ + + if caseClause.List == nil { + hasDefault = true + } + + hasCommitInCase := false + ast.Inspect(caseClause, func(inner ast.Node) bool { + if call, ok := inner.(*ast.CallExpr); ok { + if sel, ok := call.Fun.(*ast.SelectorExpr); ok { + if d.commitMethods[sel.Sel.Name] { + hasCommitInCase = true + } + } + } + return true + }) + + if hasCommitInCase { + casesWithCommit++ + } + } + + // If commit is not in all cases (including default), it's problematic + if casesWithCommit > 0 && (casesWithCommit < totalCases || !hasDefault) { + for _, state := range d.txStates { + if state.HasCommit && !state.HasDefer { + state.CommitInSwitch = true + } + } + } + + return true + }) +} + +// checkSelectCaseCommits checks if Commit is inside select/case that might not execute. +func (d *TxLeakDetector) checkSelectCaseCommits(funcDecl *ast.FuncDecl) { + ast.Inspect(funcDecl.Body, func(n ast.Node) bool { + selectStmt, ok := n.(*ast.SelectStmt) + if !ok { + return true + } + + // Count cases with commit + casesWithCommit := 0 + totalCases := 0 + hasDefault := false + + for _, stmt := range selectStmt.Body.List { + commClause, ok := stmt.(*ast.CommClause) + if !ok { + continue + } + totalCases++ + + if commClause.Comm == nil { + hasDefault = true + } + + hasCommitInCase := false + for _, bodyStmt := range commClause.Body { + ast.Inspect(bodyStmt, func(inner ast.Node) bool { + if call, ok := inner.(*ast.CallExpr); ok { + if sel, ok := call.Fun.(*ast.SelectorExpr); ok { + if d.commitMethods[sel.Sel.Name] { + hasCommitInCase = true + } + } + } + return true + }) + } + + if hasCommitInCase { + casesWithCommit++ + } + } + + // If commit is not in all cases (including default), it's problematic + if casesWithCommit > 0 && (casesWithCommit < totalCases || !hasDefault) { + for _, state := range d.txStates { + if state.HasCommit && !state.HasDefer { + state.CommitInSelect = true + } + } + } + + return true + }) +} + +// checkFatalPaths checks if function has os.Exit or log.Fatal without deferred rollback. +func (d *TxLeakDetector) checkFatalPaths(funcDecl *ast.FuncDecl) { + hasFatal := false + ast.Inspect(funcDecl.Body, func(n ast.Node) bool { + call, ok := n.(*ast.CallExpr) + if !ok { + return true + } + + // Check for os.Exit + if sel, ok := call.Fun.(*ast.SelectorExpr); ok { + if ident, ok := sel.X.(*ast.Ident); ok { + // os.Exit, log.Fatal, log.Fatalf, log.Fatalln + if (ident.Name == "os" && sel.Sel.Name == "Exit") || + (ident.Name == "log" && strings.HasPrefix(sel.Sel.Name, "Fatal")) { + hasFatal = true + } + } + } + + return true + }) + + if hasFatal { + for _, state := range d.txStates { + if !state.HasDefer { + state.HasFatalPath = true + } + } + } +} + +// checkLoopCommits checks if Commit is inside a loop that might not iterate. +func (d *TxLeakDetector) checkLoopCommits(funcDecl *ast.FuncDecl) { + ast.Inspect(funcDecl.Body, func(n ast.Node) bool { + var loopBody *ast.BlockStmt + + switch stmt := n.(type) { + case *ast.ForStmt: + loopBody = stmt.Body + case *ast.RangeStmt: + loopBody = stmt.Body + default: + return true + } + + if loopBody == nil { + return true + } + + // Check if Commit is inside the loop body + hasCommitInLoop := false + ast.Inspect(loopBody, func(inner ast.Node) bool { + if call, ok := inner.(*ast.CallExpr); ok { + if sel, ok := call.Fun.(*ast.SelectorExpr); ok { + if d.commitMethods[sel.Sel.Name] { + hasCommitInLoop = true + } + } + } + return true + }) + + if hasCommitInLoop { + for _, state := range d.txStates { + if state.HasCommit && !state.HasDefer { + state.CommitInLoop = true + } + } + } + + return true + }) +} + +// checkVariableReassignment checks if transaction variable is reassigned. +func (d *TxLeakDetector) checkVariableReassignment(funcDecl *ast.FuncDecl) { + // Track all Begin calls per variable name + beginCounts := make(map[string]int) + + ast.Inspect(funcDecl.Body, func(n ast.Node) bool { + assignStmt, ok := n.(*ast.AssignStmt) + if !ok { + return true + } + + for i, rhs := range assignStmt.Rhs { + call, ok := rhs.(*ast.CallExpr) + if !ok { + continue + } + + if d.isBeginCall(call) { + if i < len(assignStmt.Lhs) { + if ident, ok := assignStmt.Lhs[i].(*ast.Ident); ok { + if ident.Name != "err" && ident.Name != "_" { + beginCounts[ident.Name]++ + } + } + } + } + } + return true + }) + + // Mark variables that have multiple Begin calls as reassigned + for varName, count := range beginCounts { + if count > 1 { + d.markAllStatesWithName(varName, func(s *TxState) { + s.IsReassigned = true + }) + } + } +} + +// checkCommitErrorIgnored checks if Commit() error is ignored with blank identifier. +func (d *TxLeakDetector) checkCommitErrorIgnored(funcDecl *ast.FuncDecl) { + ast.Inspect(funcDecl.Body, func(n ast.Node) bool { + assignStmt, ok := n.(*ast.AssignStmt) + if !ok { + return true + } + + // Look for: _ = tx.Commit() or result, _ := tx.Commit() + for i, rhs := range assignStmt.Rhs { + call, ok := rhs.(*ast.CallExpr) + if !ok { + continue + } + + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + continue + } + + if d.commitMethods[sel.Sel.Name] { + // Check if the error is ignored + // For single assignment: _ = tx.Commit() + if len(assignStmt.Lhs) == 1 { + if ident, ok := assignStmt.Lhs[0].(*ast.Ident); ok && ident.Name == "_" { + if varIdent, ok := sel.X.(*ast.Ident); ok { + d.markAllStatesWithName(varIdent.Name, func(s *TxState) { + s.CommitErrorIgnored = true + }) + } + } + } + // For tuple assignment: result, _ := someFunc() - check if error position is _ + if len(assignStmt.Lhs) > i+1 { + if ident, ok := assignStmt.Lhs[i+1].(*ast.Ident); ok && ident.Name == "_" { + if varIdent, ok := sel.X.(*ast.Ident); ok { + d.markAllStatesWithName(varIdent.Name, func(s *TxState) { + s.CommitErrorIgnored = true + }) + } + } + } + } + } + return true + }) +} + +// checkRollbackErrorIgnored checks if Rollback() error is ignored with blank identifier. +func (d *TxLeakDetector) checkRollbackErrorIgnored(funcDecl *ast.FuncDecl) { + ast.Inspect(funcDecl.Body, func(n ast.Node) bool { + assignStmt, ok := n.(*ast.AssignStmt) + if !ok { + return true + } + + // Look for: _ = tx.Rollback() or result, _ := tx.Rollback() + for i, rhs := range assignStmt.Rhs { + call, ok := rhs.(*ast.CallExpr) + if !ok { + continue + } + + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + continue + } + + if d.rollbackMethods[sel.Sel.Name] { + // Check if the error is ignored + // For single assignment: _ = tx.Rollback() + if len(assignStmt.Lhs) == 1 { + if ident, ok := assignStmt.Lhs[0].(*ast.Ident); ok && ident.Name == "_" { + if varIdent, ok := sel.X.(*ast.Ident); ok { + d.markAllStatesWithName(varIdent.Name, func(s *TxState) { + s.RollbackErrorIgnored = true + }) + } + } + } + // For tuple assignment: result, _ := someFunc() - check if error position is _ + if len(assignStmt.Lhs) > i+1 { + if ident, ok := assignStmt.Lhs[i+1].(*ast.Ident); ok && ident.Name == "_" { + if varIdent, ok := sel.X.(*ast.Ident); ok { + d.markAllStatesWithName(varIdent.Name, func(s *TxState) { + s.RollbackErrorIgnored = true + }) + } + } + } + } + } + return true + }) +} + +// checkDeferInLoop checks if defer with transaction is inside a loop (antipattern). +func (d *TxLeakDetector) checkDeferInLoop(funcDecl *ast.FuncDecl) { + // We need to track loop depth manually since ast.Inspect doesn't give us exit notification + var processNode func(n ast.Node, loopDepth int) + processNode = func(n ast.Node, loopDepth int) { + if n == nil { + return + } + + switch node := n.(type) { + case *ast.ForStmt: + // Enter for loop - process body with increased depth + if node.Body != nil { + for _, stmt := range node.Body.List { + processNode(stmt, loopDepth+1) + } + } + case *ast.RangeStmt: + // Enter range loop - process body with increased depth + if node.Body != nil { + for _, stmt := range node.Body.List { + processNode(stmt, loopDepth+1) + } + } + case *ast.DeferStmt: + if loopDepth > 0 { + // Defer is inside a loop - check if it involves a tracked transaction + call := node.Call + if sel, ok := call.Fun.(*ast.SelectorExpr); ok { + if d.rollbackMethods[sel.Sel.Name] || d.commitMethods[sel.Sel.Name] { + if ident, ok := sel.X.(*ast.Ident); ok { + d.markAllStatesWithName(ident.Name, func(s *TxState) { + s.HasDeferInLoop = true + }) + } + } + } + // Also check defer func() { tx.Rollback() }() + if funcLit, ok := call.Fun.(*ast.FuncLit); ok { + ast.Inspect(funcLit.Body, func(inner ast.Node) bool { + if innerCall, ok := inner.(*ast.CallExpr); ok { + if sel, ok := innerCall.Fun.(*ast.SelectorExpr); ok { + if d.rollbackMethods[sel.Sel.Name] || d.commitMethods[sel.Sel.Name] { + if ident, ok := sel.X.(*ast.Ident); ok { + d.markAllStatesWithName(ident.Name, func(s *TxState) { + s.HasDeferInLoop = true + }) + } + } + } + } + return true + }) + } + } + case *ast.BlockStmt: + for _, stmt := range node.List { + processNode(stmt, loopDepth) + } + case *ast.IfStmt: + if node.Init != nil { + processNode(node.Init, loopDepth) + } + processNode(node.Body, loopDepth) + if node.Else != nil { + processNode(node.Else, loopDepth) + } + case *ast.SwitchStmt: + processNode(node.Body, loopDepth) + case *ast.TypeSwitchStmt: + processNode(node.Body, loopDepth) + case *ast.SelectStmt: + processNode(node.Body, loopDepth) + case *ast.CaseClause: + for _, stmt := range node.Body { + processNode(stmt, loopDepth) + } + case *ast.CommClause: + for _, stmt := range node.Body { + processNode(stmt, loopDepth) + } + } + } + + if funcDecl.Body != nil { + for _, stmt := range funcDecl.Body.List { + processNode(stmt, 0) + } + } +} + +// checkConditionalCommits checks if Commit is inside a conditional block. +func (d *TxLeakDetector) checkConditionalCommits(funcDecl *ast.FuncDecl) { + ast.Inspect(funcDecl.Body, func(n ast.Node) bool { + ifStmt, ok := n.(*ast.IfStmt) + if !ok { + return true + } + + // Check if Commit is inside the if body + hasCommitInIf := false + ast.Inspect(ifStmt.Body, func(inner ast.Node) bool { + if call, ok := inner.(*ast.CallExpr); ok { + if sel, ok := call.Fun.(*ast.SelectorExpr); ok { + if d.commitMethods[sel.Sel.Name] { + hasCommitInIf = true + } + } + } + return true + }) + + // Check if Commit is NOT in else (meaning it might not execute) + hasCommitInElse := false + if ifStmt.Else != nil { + ast.Inspect(ifStmt.Else, func(inner ast.Node) bool { + if call, ok := inner.(*ast.CallExpr); ok { + if sel, ok := call.Fun.(*ast.SelectorExpr); ok { + if d.commitMethods[sel.Sel.Name] { + hasCommitInElse = true + } + } + } + return true + }) + } + + // If commit is only in one branch, it's conditional + if hasCommitInIf != hasCommitInElse { + for _, state := range d.txStates { + if state.HasCommit && !state.HasDefer { + state.CommitInConditional = true + } + } + } + + return true + }) +} + +// generateViolations creates violations for unclosed transactions. +func (d *TxLeakDetector) generateViolations() []TxLeakViolation { + var violations []TxLeakViolation + + for _, state := range d.txStates { + // Skip if transaction is returned to caller + if state.IsReturned { + continue + } + + // Skip if transaction is returned in a closure (lifecycle managed by caller) + if state.IsReturnedInClosure { + continue + } + + // Skip if transaction is sent through a channel (lifecycle managed by receiver) + if state.IsSentToChannel { + continue + } + + // Skip if using callback pattern + if state.IsCallback { + continue + } + + // Skip if passed to another function (can't track inter-procedural) + // But warn if there's no defer as a safety net + if state.IsPassedToFunc && state.HasDefer { + continue + } + + // Skip if stored in struct (can't track field lifecycle) + // But warn if there's no defer as a safety net + if state.IsStoredInStruct && state.HasDefer { + continue + } + + // Skip if stored in collection (map/slice) with defer + // But warn if there's no defer as a safety net + if state.IsStoredInCollection && state.HasDefer { + continue + } + + // Handle shadowing - this is always a problem + if state.IsShadowed { + violations = append(violations, TxLeakViolation{ + Pos: state.BeginPos, + End: state.BeginEnd, + Message: "transaction " + state.VarName + " is shadowed by another transaction in inner scope", + Severity: TxLeakSeverityHigh, + ViolationType: "shadowed_transaction", + TxVarName: state.VarName, + Suggestion: "Use different variable names for nested transactions to avoid shadowing", + }) + continue + } + + // Handle goroutine capture - warn about potential issues + if state.IsCapturedByGoroutine && !state.HasDefer { + violations = append(violations, TxLeakViolation{ + Pos: state.BeginPos, + End: state.BeginEnd, + Message: "transaction " + state.VarName + " is captured by goroutine without defer", + Severity: TxLeakSeverityHigh, + ViolationType: "goroutine_capture", + TxVarName: state.VarName, + Suggestion: "Ensure transaction is properly handled in goroutine with defer Rollback()", + }) + continue + } + + // Handle panic paths + if state.HasPanicPath && !state.HasDefer { + violations = append(violations, TxLeakViolation{ + Pos: state.BeginPos, + End: state.BeginEnd, + Message: "transaction " + state.VarName + " may leak if panic() is called", + Severity: TxLeakSeverityMedium, + ViolationType: "panic_without_defer", + TxVarName: state.VarName, + Suggestion: "Add defer " + state.VarName + ".Rollback() to handle panic scenarios", + }) + } + + // Handle conditional commits + if state.CommitInConditional && !state.HasDefer { + violations = append(violations, TxLeakViolation{ + Pos: state.BeginPos, + End: state.BeginEnd, + Message: "transaction " + state.VarName + " Commit() is inside conditional - may not execute", + Severity: TxLeakSeverityMedium, + ViolationType: "conditional_commit", + TxVarName: state.VarName, + Suggestion: "Ensure Commit() is called on all success paths or use defer pattern", + }) + } + + // Handle switch/case commits + if state.CommitInSwitch && !state.HasDefer { + violations = append(violations, TxLeakViolation{ + Pos: state.BeginPos, + End: state.BeginEnd, + Message: "transaction " + state.VarName + " Commit() is inside switch/case - may not execute in all cases", + Severity: TxLeakSeverityMedium, + ViolationType: "commit_in_switch", + TxVarName: state.VarName, + Suggestion: "Ensure Commit() is called in all switch cases or use defer pattern", + }) + } + + // Handle select/case commits + if state.CommitInSelect && !state.HasDefer { + violations = append(violations, TxLeakViolation{ + Pos: state.BeginPos, + End: state.BeginEnd, + Message: "transaction " + state.VarName + " Commit() is inside select/case - may not execute in all cases", + Severity: TxLeakSeverityMedium, + ViolationType: "commit_in_select", + TxVarName: state.VarName, + Suggestion: "Ensure Commit() is called in all select cases or use defer pattern", + }) + } + + // Handle fatal paths (os.Exit, log.Fatal) + if state.HasFatalPath && !state.HasDefer { + violations = append(violations, TxLeakViolation{ + Pos: state.BeginPos, + End: state.BeginEnd, + Message: "transaction " + state.VarName + " may leak if os.Exit() or log.Fatal() is called", + Severity: TxLeakSeverityHigh, + ViolationType: "fatal_without_defer", + TxVarName: state.VarName, + Suggestion: "Add defer " + state.VarName + ".Rollback() to handle fatal exit scenarios (note: defers don't run on os.Exit)", + }) + } + + // Handle commit in loop + if state.CommitInLoop && !state.HasDefer { + violations = append(violations, TxLeakViolation{ + Pos: state.BeginPos, + End: state.BeginEnd, + Message: "transaction " + state.VarName + " Commit() is inside loop - may not execute if loop doesn't iterate", + Severity: TxLeakSeverityMedium, + ViolationType: "commit_in_loop", + TxVarName: state.VarName, + Suggestion: "Move Commit() outside loop or ensure loop always iterates at least once", + }) + } + + // Handle variable reassignment + if state.IsReassigned { + violations = append(violations, TxLeakViolation{ + Pos: state.BeginPos, + End: state.BeginEnd, + Message: "transaction variable " + state.VarName + " is reassigned - previous transaction may leak", + Severity: TxLeakSeverityHigh, + ViolationType: "variable_reassignment", + TxVarName: state.VarName, + Suggestion: "Commit or Rollback the first transaction before starting a new one, or use different variable names", + }) + } + + // Handle ignored commit error + if state.CommitErrorIgnored { + violations = append(violations, TxLeakViolation{ + Pos: state.BeginPos, + End: state.BeginEnd, + Message: "transaction " + state.VarName + " Commit() error is ignored with blank identifier", + Severity: TxLeakSeverityLow, + ViolationType: "commit_error_ignored", + TxVarName: state.VarName, + Suggestion: "Handle the Commit() error - if it fails, the transaction is rolled back automatically", + }) + } + + // Handle deferred commit - antipattern + if state.HasDeferredCommit { + violations = append(violations, TxLeakViolation{ + Pos: state.BeginPos, + End: state.BeginEnd, + Message: "transaction " + state.VarName + " uses defer Commit() - this is an antipattern", + Severity: TxLeakSeverityMedium, + ViolationType: "deferred_commit", + TxVarName: state.VarName, + Suggestion: "Use defer " + state.VarName + ".Rollback() and explicit Commit() at the end of the function", + }) + } + + // Handle ignored rollback error + if state.RollbackErrorIgnored { + violations = append(violations, TxLeakViolation{ + Pos: state.BeginPos, + End: state.BeginEnd, + Message: "transaction " + state.VarName + " Rollback() error is ignored with blank identifier", + Severity: TxLeakSeverityLow, + ViolationType: "rollback_error_ignored", + TxVarName: state.VarName, + Suggestion: "Consider logging Rollback() errors for debugging - silent failures can hide issues", + }) + } + + // Handle defer inside loop - antipattern + if state.HasDeferInLoop { + violations = append(violations, TxLeakViolation{ + Pos: state.BeginPos, + End: state.BeginEnd, + Message: "transaction " + state.VarName + " has defer inside loop - defers pile up until function returns", + Severity: TxLeakSeverityHigh, + ViolationType: "defer_in_loop", + TxVarName: state.VarName, + Suggestion: "Move transaction handling outside loop or use explicit Rollback()/Commit() in each iteration", + }) + } + + // Case 1: No Commit and no Rollback - Critical + if !state.HasCommit && !state.HasRollback { + msg := "unclosed transaction: " + state.VarName + " - missing both Commit() and Rollback()" + if state.IsPassedToFunc { + msg += " (passed to function - ensure it handles the transaction)" + } + if state.IsStoredInStruct { + msg += " (stored in struct - ensure lifecycle is managed)" + } + + violations = append(violations, TxLeakViolation{ + Pos: state.BeginPos, + End: state.BeginEnd, + Message: msg, + Severity: TxLeakSeverityCritical, + ViolationType: "no_commit_rollback", + TxVarName: state.VarName, + Suggestion: "Add defer " + state.VarName + ".Rollback() immediately after Begin(), then call Commit() on success", + }) + continue + } + + // Case 2: Has Commit but no Rollback - High + if state.HasCommit && !state.HasRollback { + violations = append(violations, TxLeakViolation{ + Pos: state.BeginPos, + End: state.BeginEnd, + Message: "transaction " + state.VarName + " has Commit() but no Rollback() for error paths", + Severity: TxLeakSeverityHigh, + ViolationType: "no_rollback", + TxVarName: state.VarName, + Suggestion: "Add defer " + state.VarName + ".Rollback() to handle errors - it's safe to call after Commit()", + }) + continue + } + + // Case 3: Has Rollback but no Commit - Medium + if state.HasRollback && !state.HasCommit { + violations = append(violations, TxLeakViolation{ + Pos: state.BeginPos, + End: state.BeginEnd, + Message: "transaction " + state.VarName + " has Rollback() but missing Commit()", + Severity: TxLeakSeverityMedium, + ViolationType: "no_commit", + TxVarName: state.VarName, + Suggestion: "Ensure Commit() is called on success path", + }) + } + + // Case 4: Early return without defer + if state.HasEarlyReturn && !state.HasDefer && state.HasCommit { + violations = append(violations, TxLeakViolation{ + Pos: state.BeginPos, + End: state.BeginEnd, + Message: "transaction " + state.VarName + " has early return paths that bypass Commit()", + Severity: TxLeakSeverityHigh, + ViolationType: "early_return", + TxVarName: state.VarName, + Suggestion: "Add defer " + state.VarName + ".Rollback() to handle early returns safely", + }) + } + } + + return violations +} + +// AnalyzeTxLeaks is a convenience function to run transaction leak detection on a file. +func AnalyzeTxLeaks(pass *analysis.Pass, file *ast.File) { + detector := NewTxLeakDetector() + violations := detector.CheckTxLeaks(pass, file) + + for _, v := range violations { + message := "[" + string(v.Severity) + "] " + v.Message + if v.Suggestion != "" { + message += "\n Suggestion: " + v.Suggestion + } + + pass.Report(analysis.Diagnostic{ + Pos: v.Pos, + End: v.End, + Message: message, + }) + } +} + +// GetTxLeakViolations returns all transaction leak violations for external use. +func GetTxLeakViolations(pass *analysis.Pass, file *ast.File) []TxLeakViolation { + detector := NewTxLeakDetector() + return detector.CheckTxLeaks(pass, file) +} + +// DetectTxLeaksInAST detects transaction leak problems in an AST file without analysis.Pass. +// This is designed for use in LSP server where we don't have a full analysis pass. +func DetectTxLeaksInAST(fset *token.FileSet, file *ast.File) []TxLeakViolation { + detector := NewTxLeakDetector() + var violations []TxLeakViolation + + // Analyze each function declaration + for _, decl := range file.Decls { + funcDecl, ok := decl.(*ast.FuncDecl) + if !ok || funcDecl.Body == nil { + continue + } + + // Skip test functions (TestXxx, BenchmarkXxx, FuzzXxx, ExampleXxx) + if isTestFunction(funcDecl) { + continue + } + + // Skip test helper functions (functions with *testing.T as first param) + if isTestHelperFunction(funcDecl) { + continue + } + + violations = append(violations, detector.analyzeFunction(funcDecl)...) + } + + return violations +} diff --git a/vendor/github.com/MirrexOne/unqueryvet/pkg/config/config.go b/vendor/github.com/MirrexOne/unqueryvet/pkg/config/config.go new file mode 100644 index 000000000..06b564f12 --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/pkg/config/config.go @@ -0,0 +1,187 @@ +// Package config provides configuration structures for Unqueryvet analyzer. +package config + +// CustomRule represents a user-defined DSL rule for SQL analysis. +type CustomRule struct { + // ID is a unique identifier for the rule. + ID string `mapstructure:"id" json:"id" yaml:"id"` + + // Pattern is the SQL or code pattern to match. + // Supports metavariables like $TABLE, $VAR, etc. + Pattern string `mapstructure:"pattern" json:"pattern" yaml:"pattern"` + + // Patterns allows multiple patterns for a single rule. + Patterns []string `mapstructure:"patterns" json:"patterns" yaml:"patterns,omitempty"` + + // When is an optional condition expression (evaluated with expr-lang). + // Available variables: file, package, function, query, table, in_loop, etc. + When string `mapstructure:"when" json:"when" yaml:"when,omitempty"` + + // Message is the diagnostic message shown when the rule triggers. + Message string `mapstructure:"message" json:"message" yaml:"message,omitempty"` + + // Severity is the severity level (error, warning, info, ignore). + Severity string `mapstructure:"severity" json:"severity" yaml:"severity,omitempty"` + + // Action determines what to do when the pattern matches (report, allow, ignore). + Action string `mapstructure:"action" json:"action" yaml:"action,omitempty"` + + // Fix is an optional suggested fix message. + Fix string `mapstructure:"fix" json:"fix" yaml:"fix,omitempty"` +} + +// RuleSeverity maps built-in rule IDs to their severity levels. +type RuleSeverity map[string]string + +// UnqueryvetSettings holds the configuration for the Unqueryvet analyzer. +type UnqueryvetSettings struct { + // CheckSQLBuilders enables checking SQL builders like Squirrel for SELECT * usage + CheckSQLBuilders bool `mapstructure:"check-sql-builders" json:"check-sql-builders" yaml:"check-sql-builders"` + + // AllowedPatterns is a list of regex patterns that are allowed to use SELECT * + // Example: ["SELECT \\* FROM temp_.*", "SELECT \\* FROM .*_backup"] + AllowedPatterns []string `mapstructure:"allowed-patterns" json:"allowed-patterns" yaml:"allowed-patterns"` + + // IgnoredFunctions is a list of function name patterns to ignore + // Example: ["debug.Query", "test.*", "mock.*"] + IgnoredFunctions []string `mapstructure:"ignored-functions" json:"ignored-functions" yaml:"ignored-functions"` + + // IgnoredFiles is a list of glob patterns for files to ignore + // Example: ["*_test.go", "testdata/**", "mock_*.go"] + IgnoredFiles []string `mapstructure:"ignored-files" json:"ignored-files" yaml:"ignored-files"` + + // Severity defines the diagnostic severity: "error" or "warning" (default: "warning") + Severity string `mapstructure:"severity" json:"severity" yaml:"severity"` + + // CheckAliasedWildcard enables detection of SELECT alias.* patterns (e.g., SELECT t.* FROM users t) + CheckAliasedWildcard bool `mapstructure:"check-aliased-wildcard" json:"check-aliased-wildcard" yaml:"check-aliased-wildcard"` + + // CheckStringConcat enables detection of SELECT * in string concatenation (e.g., "SELECT * " + "FROM users") + CheckStringConcat bool `mapstructure:"check-string-concat" json:"check-string-concat" yaml:"check-string-concat"` + + // CheckFormatStrings enables detection of SELECT * in format functions (e.g., fmt.Sprintf) + CheckFormatStrings bool `mapstructure:"check-format-strings" json:"check-format-strings" yaml:"check-format-strings"` + + // CheckStringBuilder enables detection of SELECT * in strings.Builder usage + CheckStringBuilder bool `mapstructure:"check-string-builder" json:"check-string-builder" yaml:"check-string-builder"` + + // CheckSubqueries enables detection of SELECT * in subqueries (e.g., SELECT * FROM (SELECT * FROM ...)) + CheckSubqueries bool `mapstructure:"check-subqueries" json:"check-subqueries" yaml:"check-subqueries"` + + // SQLBuilders defines which SQL builder libraries to check + SQLBuilders SQLBuildersConfig `mapstructure:"sql-builders" json:"sql-builders" yaml:"sql-builders"` + + // Rules is a map of built-in rule IDs to their severity (error, warning, info, ignore). + // Example: {"select-star": "error", "n1-queries": "warning"} + Rules RuleSeverity `mapstructure:"rules" json:"rules" yaml:"rules,omitempty"` + + // CustomRules is a list of user-defined DSL rules. + CustomRules []CustomRule `mapstructure:"custom-rules" json:"custom-rules" yaml:"custom-rules,omitempty"` + + // Allow is a list of SQL patterns to allow (whitelist). + // These patterns will not trigger any warnings. + Allow []string `mapstructure:"allow" json:"allow" yaml:"allow,omitempty"` + + // Ignore is a list of file patterns to ignore (in addition to IgnoredFiles). + Ignore []string `mapstructure:"ignore" json:"ignore" yaml:"ignore,omitempty"` + + // N1DetectionEnabled global flag for N+1 detection + N1DetectionEnabled bool `mapstructure:"check-n1-queries" json:"check-n1-queries" yaml:"check-n1-queries,omitempty"` + + // SQLInjectionDetectionEnabled global flag for SQL injection detection + SQLInjectionDetectionEnabled bool `mapstructure:"check-sql-injection" json:"check-sql-injection" yaml:"check-sql-injection,omitempty"` + + // TxLeakDetectionEnabled global flag for unclosed transaction detection + TxLeakDetectionEnabled bool `mapstructure:"check-tx-leaks" json:"check-tx-leaks" yaml:"check-tx-leaks,omitempty"` +} + +// SQLBuildersConfig defines which SQL builder libraries to analyze. +type SQLBuildersConfig struct { + // Squirrel enables checking github.com/Masterminds/squirrel + Squirrel bool `mapstructure:"squirrel" json:"squirrel" yaml:"squirrel"` + + // GORM enables checking gorm.io/gorm + GORM bool `mapstructure:"gorm" json:"gorm" yaml:"gorm"` + + // SQLx enables checking github.com/jmoiron/sqlx + SQLx bool `mapstructure:"sqlx" json:"sqlx" yaml:"sqlx"` + + // Ent enables checking entgo.io/ent + Ent bool `mapstructure:"ent" json:"ent" yaml:"ent"` + + // PGX enables checking github.com/jackc/pgx + PGX bool `mapstructure:"pgx" json:"pgx" yaml:"pgx"` + + // Bun enables checking github.com/uptrace/bun + Bun bool `mapstructure:"bun" json:"bun" yaml:"bun"` + + // SQLBoiler enables checking github.com/volatiletech/sqlboiler + SQLBoiler bool `mapstructure:"sqlboiler" json:"sqlboiler" yaml:"sqlboiler"` + + // Jet enables checking github.com/go-jet/jet + Jet bool `mapstructure:"jet" json:"jet" yaml:"jet"` + + // Sqlc enables checking github.com/sqlc-dev/sqlc generated code + Sqlc bool `mapstructure:"sqlc" json:"sqlc" yaml:"sqlc"` + + // Goqu enables checking github.com/doug-martin/goqu + Goqu bool `mapstructure:"goqu" json:"goqu" yaml:"goqu"` + + // Rel enables checking github.com/go-rel/rel + Rel bool `mapstructure:"rel" json:"rel" yaml:"rel"` + + // Reform enables checking gopkg.in/reform.v1 + Reform bool `mapstructure:"reform" json:"reform" yaml:"reform"` +} + +// DefaultSQLBuildersConfig returns the default SQL builders configuration with all checkers enabled. +func DefaultSQLBuildersConfig() SQLBuildersConfig { + return SQLBuildersConfig{ + Squirrel: true, + GORM: true, + SQLx: true, + Ent: true, + PGX: true, + Bun: true, + SQLBoiler: true, + Jet: true, + Sqlc: true, + Goqu: true, + Rel: true, + Reform: true, + } +} + +// DefaultSettings returns the default configuration for unqueryvet. +// By default, all detection features are enabled for maximum coverage. +func DefaultSettings() UnqueryvetSettings { + return UnqueryvetSettings{ + CheckSQLBuilders: true, + CheckAliasedWildcard: true, + CheckStringConcat: true, + CheckFormatStrings: true, + CheckStringBuilder: true, + CheckSubqueries: true, + N1DetectionEnabled: true, + SQLInjectionDetectionEnabled: true, + TxLeakDetectionEnabled: true, + Severity: "warning", + AllowedPatterns: []string{ + `(?i)COUNT\(\s*\*\s*\)`, + `(?i)MAX\(\s*\*\s*\)`, + `(?i)MIN\(\s*\*\s*\)`, + `(?i)SELECT \* FROM information_schema\..*`, + `(?i)SELECT \* FROM pg_catalog\..*`, + `(?i)SELECT \* FROM sys\..*`, + }, + IgnoredFunctions: []string{}, + IgnoredFiles: []string{}, + SQLBuilders: DefaultSQLBuildersConfig(), + Rules: RuleSeverity{ + "select-star": "warning", + "n1-queries": "warning", + "sql-injection": "error", + "tx-leak": "warning", + }, + } +} diff --git a/vendor/github.com/MirrexOne/unqueryvet/schema.json b/vendor/github.com/MirrexOne/unqueryvet/schema.json new file mode 100644 index 000000000..f4df7b18a --- /dev/null +++ b/vendor/github.com/MirrexOne/unqueryvet/schema.json @@ -0,0 +1,270 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/MirrexOne/unqueryvet/main/schema.json", + "title": "unqueryvet configuration", + "description": "Configuration schema for unqueryvet - a Go static analysis tool for SQL queries", + "type": "object", + "additionalProperties": false, + "properties": { + "rules": { + "type": "object", + "description": "Built-in rules severity configuration", + "additionalProperties": false, + "properties": { + "select-star": { + "$ref": "#/definitions/severity", + "description": "Severity for SELECT * detection" + }, + "n1-queries": { + "$ref": "#/definitions/severity", + "description": "Severity for N+1 query detection" + }, + "sql-injection": { + "$ref": "#/definitions/severity", + "description": "Severity for SQL injection detection" + }, + "tx-leak": { + "$ref": "#/definitions/severity", + "description": "Severity for transaction leak detection" + } + } + }, + "ignore": { + "type": "array", + "description": "File patterns to ignore (glob syntax)", + "items": { + "type": "string" + }, + "examples": [["*_test.go", "testdata/**", "vendor/**"]] + }, + "allow": { + "type": "array", + "description": "SQL patterns to whitelist (won't trigger warnings)", + "items": { + "type": "string" + }, + "examples": [["COUNT(*)", "information_schema.*"]] + }, + "severity": { + "$ref": "#/definitions/severityLevel", + "description": "Default diagnostic severity: 'error' or 'warning'", + "default": "warning" + }, + "check-sql-builders": { + "type": "boolean", + "description": "Enable SQL builder library checking", + "default": true + }, + "check-aliased-wildcard": { + "type": "boolean", + "description": "Enable aliased wildcard detection (e.g., SELECT t.*)", + "default": true + }, + "check-string-concat": { + "type": "boolean", + "description": "Enable string concatenation analysis", + "default": true + }, + "check-format-strings": { + "type": "boolean", + "description": "Enable format string analysis (e.g., fmt.Sprintf)", + "default": true + }, + "check-string-builder": { + "type": "boolean", + "description": "Enable strings.Builder analysis", + "default": true + }, + "check-subqueries": { + "type": "boolean", + "description": "Enable SELECT * detection in subqueries", + "default": true + }, + "sql-builders": { + "type": "object", + "description": "SQL builder libraries to check", + "additionalProperties": false, + "properties": { + "squirrel": { + "type": "boolean", + "description": "Check github.com/Masterminds/squirrel", + "default": true + }, + "gorm": { + "type": "boolean", + "description": "Check gorm.io/gorm", + "default": true + }, + "sqlx": { + "type": "boolean", + "description": "Check github.com/jmoiron/sqlx", + "default": true + }, + "ent": { + "type": "boolean", + "description": "Check entgo.io/ent", + "default": true + }, + "pgx": { + "type": "boolean", + "description": "Check github.com/jackc/pgx", + "default": true + }, + "bun": { + "type": "boolean", + "description": "Check github.com/uptrace/bun", + "default": true + }, + "sqlboiler": { + "type": "boolean", + "description": "Check github.com/volatiletech/sqlboiler", + "default": true + }, + "jet": { + "type": "boolean", + "description": "Check github.com/go-jet/jet", + "default": true + }, + "sqlc": { + "type": "boolean", + "description": "Check sqlc generated code", + "default": true + }, + "goqu": { + "type": "boolean", + "description": "Check github.com/doug-martin/goqu", + "default": true + }, + "rel": { + "type": "boolean", + "description": "Check github.com/go-rel/rel", + "default": true + }, + "reform": { + "type": "boolean", + "description": "Check gopkg.in/reform.v1", + "default": true + } + } + }, + "ignored-files": { + "type": "array", + "description": "Legacy: File patterns to ignore (use 'ignore' instead)", + "items": { + "type": "string" + }, + "deprecated": true + }, + "ignored-functions": { + "type": "array", + "description": "Function patterns to ignore (regex)", + "items": { + "type": "string" + }, + "examples": [["debug\\..*", "test.*"]] + }, + "allowed-patterns": { + "type": "array", + "description": "Legacy: Regex patterns to allow (use 'allow' instead)", + "items": { + "type": "string" + }, + "deprecated": true + }, + "custom-rules": { + "type": "array", + "description": "Custom analysis rules using DSL", + "items": { + "$ref": "#/definitions/customRule" + } + }, + "output": { + "type": "object", + "description": "Output configuration options", + "additionalProperties": false, + "properties": { + "format": { + "type": "string", + "enum": ["text", "json", "sarif"], + "description": "Output format", + "default": "text" + }, + "color": { + "type": "string", + "enum": ["auto", "always", "never"], + "description": "Color output mode", + "default": "auto" + }, + "verbose": { + "type": "boolean", + "description": "Enable verbose output", + "default": false + }, + "quiet": { + "type": "boolean", + "description": "Quiet mode (only errors)", + "default": false + } + } + } + }, + "definitions": { + "severity": { + "type": "string", + "enum": ["error", "warning", "info", "ignore"], + "description": "Severity level for a rule" + }, + "severityLevel": { + "type": "string", + "enum": ["error", "warning"], + "description": "Default severity level" + }, + "customRule": { + "type": "object", + "description": "Custom analysis rule definition", + "required": ["id"], + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "description": "Unique identifier for the rule", + "pattern": "^[a-z][a-z0-9-]*$" + }, + "pattern": { + "type": "string", + "description": "SQL/code pattern to match (supports metavariables: $TABLE, $VAR, $QUERY, $COLS, $DB, $EXPR)" + }, + "patterns": { + "type": "array", + "description": "Multiple patterns (any match triggers the rule)", + "items": { + "type": "string" + } + }, + "when": { + "type": "string", + "description": "Condition expression using expr-lang syntax. Available variables: file, package, function, query, query_type, table, tables, columns, has_join, has_where, in_loop, loop_depth, builder" + }, + "message": { + "type": "string", + "description": "Diagnostic message to display when rule matches" + }, + "severity": { + "$ref": "#/definitions/severity", + "description": "Severity level for this rule" + }, + "action": { + "type": "string", + "enum": ["report", "allow", "ignore"], + "description": "Action to take when rule matches", + "default": "report" + }, + "fix": { + "type": "string", + "description": "Suggested fix message" + } + }, + "oneOf": [{ "required": ["pattern"] }, { "required": ["patterns"] }] + } + } +} diff --git a/vendor/github.com/OpenPeeDeeP/depguard/v2/README.md b/vendor/github.com/OpenPeeDeeP/depguard/v2/README.md index 2ccfa22c5..0bf603b2b 100644 --- a/vendor/github.com/OpenPeeDeeP/depguard/v2/README.md +++ b/vendor/github.com/OpenPeeDeeP/depguard/v2/README.md @@ -7,7 +7,7 @@ allow specific packages within a repository. ## Install ```bash -go install github.com/OpenPeeDeeP/depguard@latest +go install github.com/OpenPeeDeeP/depguard/cmd/depguard@latest ``` ## Config @@ -49,7 +49,7 @@ the linter's output. - `files` - list of file globs that will match this list of settings to compare against - `allow` - list of allowed packages - `deny` - map of packages that are not allowed where the value is a suggestion -= `listMode` - the mode to use for package matching +- `listMode` - the mode to use for package matching Files are matched using [Globs](https://github.com/gobwas/glob). If the files list is empty, then all files will match that list. Prefixing a file @@ -153,11 +153,29 @@ would be allowed. ```yaml Main: deny: - - github.com/OpenPeeDeeP/depguard$ + github.com/OpenPeeDeeP/depguard$: Please use v2 ``` -## Golangci-lint +## golangci-lint This linter was built with -[Golangci-lint](https://github.com/golangci/golangci-lint) in mind. It is compatible -and read their docs to see how to implement all their linters, including this one. +[golangci-lint](https://github.com/golangci/golangci-lint) in mind, read the [linters docs](https://golangci-lint.run/usage/linters/#depguard) to see how to configure all their linters, including this one. + +The config is similar to the YAML depguard config documented above, however due to [golangci-lint limitation](https://github.com/golangci/golangci-lint/pull/4227) the `deny` value must be provided as a list, with `pkg` and `desc` keys (otherwise a [panic](https://github.com/OpenPeeDeeP/depguard/issues/74) may occur): + +```yaml +# golangci-lint config +linters-settings: + depguard: + rules: + prevent_unmaintained_packages: + list-mode: lax # allow unless explicitely denied + files: + - $all + - "!$test" + allow: + - $gostd + deny: + - pkg: io/ioutil + desc: "replaced by io and os packages since Go 1.16: https://tip.golang.org/doc/go1.16#ioutil" +``` diff --git a/vendor/github.com/OpenPeeDeeP/depguard/v2/depguard.go b/vendor/github.com/OpenPeeDeeP/depguard/v2/depguard.go index 2729091e8..af07b9bb6 100644 --- a/vendor/github.com/OpenPeeDeeP/depguard/v2/depguard.go +++ b/vendor/github.com/OpenPeeDeeP/depguard/v2/depguard.go @@ -47,12 +47,12 @@ func (ua *UncompiledAnalyzer) Compile() error { return nil } -func (settings LinterSettings) run(pass *analysis.Pass) (interface{}, error) { - s, err := settings.compile() +func (s LinterSettings) run(pass *analysis.Pass) (interface{}, error) { + settings, err := s.compile() if err != nil { return nil, err } - return s.run(pass) + return settings.run(pass) } func newAnalyzer(run func(*analysis.Pass) (interface{}, error)) *analysis.Analyzer { diff --git a/vendor/github.com/OpenPeeDeeP/depguard/v2/settings.go b/vendor/github.com/OpenPeeDeeP/depguard/v2/settings.go index 311cacc88..5bc74f8d0 100644 --- a/vendor/github.com/OpenPeeDeeP/depguard/v2/settings.go +++ b/vendor/github.com/OpenPeeDeeP/depguard/v2/settings.go @@ -202,9 +202,9 @@ func (l LinterSettings) compile() (linterSettings, error) { return li, nil } -func (ls linterSettings) whichLists(fileName string) []*list { +func (s linterSettings) whichLists(fileName string) []*list { var matches []*list - for _, l := range ls { + for _, l := range s { if l.fileMatch(fileName) { matches = append(matches, l) } @@ -236,5 +236,13 @@ func strInPrefixList(str string, prefixList []string) (bool, int) { if ioc[len(ioc)-1] == '$' { return str == ioc[:len(ioc)-1], idx } - return strings.HasPrefix(str, prefixList[idx]), idx + + // There is no sep chars in ioc so it is a GOROOT import that is being matched to the import (str) (see $gostd expander) + // AND the import contains a period which GOROOT cannot have. This eliminates the go.evil.me/pkg scenario + // BUT should still allow /os/exec and ./os/exec imports which are very uncommon + if !strings.ContainsAny(ioc, "./") && strings.ContainsRune(str, '.') { + return false, idx + } + + return strings.HasPrefix(str, ioc), idx } diff --git a/vendor/github.com/sagikazarmark/slog-shim/.editorconfig b/vendor/github.com/alecthomas/chroma/v2/.editorconfig similarity index 73% rename from vendor/github.com/sagikazarmark/slog-shim/.editorconfig rename to vendor/github.com/alecthomas/chroma/v2/.editorconfig index 1fb0e1bec..cfb2c669e 100644 --- a/vendor/github.com/sagikazarmark/slog-shim/.editorconfig +++ b/vendor/github.com/alecthomas/chroma/v2/.editorconfig @@ -1,18 +1,17 @@ root = true [*] -charset = utf-8 +indent_style = tab end_of_line = lf -indent_size = 4 -indent_style = space -insert_final_newline = true +charset = utf-8 trim_trailing_whitespace = true +insert_final_newline = true -[*.nix] +[*.xml] +indent_style = space indent_size = 2 +insert_final_newline = false -[{Makefile,*.mk}] -indent_style = tab - -[Taskfile.yaml] +[*.yml] +indent_style = space indent_size = 2 diff --git a/vendor/github.com/alecthomas/chroma/v2/.gitignore b/vendor/github.com/alecthomas/chroma/v2/.gitignore new file mode 100644 index 000000000..aedf83d99 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/.gitignore @@ -0,0 +1,28 @@ +# Binaries for programs and plugins +.git +.idea +.vscode +.hermit +*.exe +*.dll +*.so +*.dylib +/cmd/chroma/chroma + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 +.glide/ + +_models/ + +_examples/ +*.min.* +build/ + +cmd/chromad/static/chroma.wasm +cmd/chromad/static/wasm_exec.js diff --git a/vendor/github.com/alecthomas/chroma/v2/.golangci.yml b/vendor/github.com/alecthomas/chroma/v2/.golangci.yml new file mode 100644 index 000000000..91f313b1a --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/.golangci.yml @@ -0,0 +1,89 @@ +run: + tests: true + +output: + print-issued-lines: false + +linters: + enable-all: true + disable: + - lll + - gocyclo + - dupl + - gochecknoglobals + - funlen + - godox + - wsl + - gocognit + - nolintlint + - testpackage + - godot + - nestif + - paralleltest + - nlreturn + - cyclop + - gci + - gofumpt + - errorlint + - exhaustive + - wrapcheck + - stylecheck + - thelper + - nonamedreturns + - revive + - dupword + - exhaustruct + - varnamelen + - forcetypeassert + - ireturn + - maintidx + - govet + - testableexamples + - musttag + - depguard + - goconst + - perfsprint + - mnd + - predeclared + - recvcheck + - tenv + - err113 + +linters-settings: + gocyclo: + min-complexity: 10 + dupl: + threshold: 100 + goconst: + min-len: 8 + min-occurrences: 3 + forbidigo: + #forbid: + # - (Must)?NewLexer$ + exclude_godoc_examples: false + + +issues: + exclude-dirs: + - _examples + max-per-linter: 0 + max-same: 0 + exclude-use-default: false + exclude: + # Captured by errcheck. + - '^(G104|G204):' + # Very commonly not checked. + - 'Error return value of .(.*\.Help|.*\.MarkFlagRequired|(os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*printf?|os\.(Un)?Setenv). is not checked' + - 'exported method (.*\.MarshalJSON|.*\.UnmarshalJSON|.*\.EntityURN|.*\.GoString|.*\.Pos) should have comment or be unexported' + - 'composite literal uses unkeyed fields' + - 'declaration of "err" shadows declaration' + - 'should not use dot imports' + - 'Potential file inclusion via variable' + - 'should have comment or be unexported' + - 'comment on exported var .* should be of the form' + - 'at least one file in a package should have a package comment' + - 'string literal contains the Unicode' + - 'methods on the same type should have the same receiver name' + - '_TokenType_name should be _TokenTypeName' + - '`_TokenType_map` should be `_TokenTypeMap`' + - 'rewrite if-else to switch statement' diff --git a/vendor/github.com/alecthomas/chroma/v2/.goreleaser.yml b/vendor/github.com/alecthomas/chroma/v2/.goreleaser.yml new file mode 100644 index 000000000..f7c4f7d2d --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/.goreleaser.yml @@ -0,0 +1,34 @@ +project_name: chroma +release: + github: + owner: alecthomas + name: chroma +brews: + - install: bin.install "chroma" +env: + - CGO_ENABLED=0 +builds: + - goos: + - linux + - darwin + - windows + goarch: + - arm64 + - amd64 + - "386" + goarm: + - "6" + dir: ./cmd/chroma + main: . + ldflags: -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} + binary: chroma +archives: + - format: tar.gz + name_template: "{{ .Binary }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" + files: + - COPYING + - README* +snapshot: + name_template: SNAPSHOT-{{ .Commit }} +checksum: + name_template: "{{ .ProjectName }}-{{ .Version }}-checksums.txt" diff --git a/vendor/github.com/alecthomas/chroma/v2/AGENTS.md b/vendor/github.com/alecthomas/chroma/v2/AGENTS.md new file mode 100644 index 000000000..0d3b6ee49 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/AGENTS.md @@ -0,0 +1,11 @@ +Chroma is a syntax highlighting library, tool and web playground for Go. It is based on Pygments and includes importers for it, so most of the same concepts from Pygments apply to Chroma. + +This project is written in Go, uses Hermit to manage tooling, and Just for helper commands. Helper scripts are in ./scripts. + +Language definitions are XML files defined in ./lexers/embedded/*.xml. + +Styles/themes are defined in ./styles/*.xml. + +The CLI can be run with `chroma`. + +The web playground can be run with `chromad --csrf-key=moo`. It blocks, so should generally be run in the background. It also does not hot reload, so has to be manually restarted. The playground has two modes - for local development it uses the server itself to render, while for production running `just chromad` will compile ./cmd/libchromawasm into a WASM module that is bundled into `chromad`. diff --git a/vendor/github.com/alecthomas/chroma/v2/Bitfile b/vendor/github.com/alecthomas/chroma/v2/Bitfile new file mode 100644 index 000000000..bf158633a --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/Bitfile @@ -0,0 +1,24 @@ +VERSION = %(git describe --tags --dirty --always)% +export CGOENABLED = 0 + +tokentype_enumer.go: types.go + build: go generate + +# Regenerate the list of lexers in the README +README.md: lexers/*.go lexers/*/*.xml table.py + build: ./table.py + -clean + +implicit %{1}%{2}.min.%{3}: **/*.{css,js} + build: esbuild --bundle %{IN} --minify --outfile=%{OUT} + +implicit build/%{1}: cmd/* + cd cmd/%{1} + inputs: cmd/%{1}/**/* **/*.go + build: go build -ldflags="-X 'main.version=%{VERSION}'" -o ../../build/%{1} . + +#upload: chromad +# build: +# scp chromad root@swapoff.org: +# ssh root@swapoff.org 'install -m755 ./chromad /srv/http/swapoff.org/bin && service chromad restart' +# touch upload diff --git a/vendor/github.com/alecthomas/chroma/v2/COPYING b/vendor/github.com/alecthomas/chroma/v2/COPYING new file mode 100644 index 000000000..92dc39f70 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/COPYING @@ -0,0 +1,19 @@ +Copyright (C) 2017 Alec Thomas + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/alecthomas/chroma/v2/Dockerfile b/vendor/github.com/alecthomas/chroma/v2/Dockerfile new file mode 100644 index 000000000..c86b37932 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/Dockerfile @@ -0,0 +1,64 @@ +# Multi-stage Dockerfile for chromad Go application using Hermit-managed tools + +# Build stage +FROM ubuntu:24.04 AS builder + +# Install system dependencies +RUN apt-get update && apt-get install -y \ + curl \ + git \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# Set working directory +WORKDIR /app + +# Copy the entire project (including bin directory with Hermit tools) +COPY . . + +# Make Hermit tools executable and add to PATH +ENV PATH="/app/bin:${PATH}" + +# Set Go environment variables for static compilation +ENV CGO_ENABLED=0 +ENV GOOS=linux +ENV GOARCH=amd64 + +# Build the application using just +RUN just chromad + +# Runtime stage +FROM alpine:3.23 AS runtime + +# Install ca-certificates for HTTPS requests +RUN apk --no-cache add ca-certificates curl + +# Create a non-root user +RUN addgroup -g 1001 chromad && \ + adduser -D -s /bin/sh -u 1001 -G chromad chromad + +# Set working directory +WORKDIR /app + +# Copy the binary from build stage +COPY --from=builder /app/build/chromad /app/chromad + +# Change ownership to non-root user +RUN chown chromad:chromad /app/chromad + +# Switch to non-root user +USER chromad + +# Expose port (default is 8080, but can be overridden via PORT env var) +EXPOSE 8080 + +# Set default environment variables +ENV PORT=8080 +ENV CHROMA_CSRF_KEY="testtest" + +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD curl -fsSL http://127.0.0.1:8080/ > /dev/null + +# Run the application +CMD ["sh", "-c", "./chromad --csrf-key=$CHROMA_CSRF_KEY --bind=0.0.0.0:$PORT"] diff --git a/vendor/github.com/alecthomas/chroma/v2/Justfile b/vendor/github.com/alecthomas/chroma/v2/Justfile new file mode 100644 index 000000000..24e3816f1 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/Justfile @@ -0,0 +1,55 @@ +set positional-arguments := true +set shell := ["bash", "-c"] + +version := `git describe --tags --dirty --always` +export GOOS := env("GOOS", "linux") +export GOARCH := env("GOARCH", "amd64") + +_help: + @just -l + +# Generate README.md from lexer definitions +readme: + #!/usr/bin/env bash + GOOS= GOARCH= ./table.py + +# Generate tokentype_string.go +tokentype-string: + go generate + +# Format JavaScript files +format-js: + biome format --write cmd/chromad/static/index.js cmd/chromad/static/chroma.js + +# Build chromad binary +chromad: wasm-exec chroma-wasm + #!/usr/bin/env bash + rm -rf build + mk cmd/chromad/static/index.min.js : cmd/chromad/static/{index,chroma}.js -- \ + esbuild --platform=browser --format=esm --bundle cmd/chromad/static/index.js --minify --external:./wasm_exec.js --outfile=cmd/chromad/static/index.min.js + mk cmd/chromad/static/index.min.css : cmd/chromad/static/index.css -- \ + esbuild --bundle cmd/chromad/static/index.css --minify --outfile=cmd/chromad/static/index.min.css + cd cmd/chromad && CGOENABLED=0 go build -ldflags="-X 'main.version={{ version }}'" -o ../../build/chromad . + +# Copy wasm_exec.js from TinyGo +wasm-exec: + #!/usr/bin/env bash + tinygoroot=$(tinygo env TINYGOROOT) + mk cmd/chromad/static/wasm_exec.js : "$tinygoroot/targets/wasm_exec.js" -- \ + install -m644 "$tinygoroot/targets/wasm_exec.js" cmd/chromad/static/wasm_exec.js + +# Build WASM binary +chroma-wasm: + #!/usr/bin/env bash + if type tinygo > /dev/null 2>&1; then + mk cmd/chromad/static/chroma.wasm : cmd/libchromawasm/main.go -- \ + tinygo build -no-debug -target wasm -o cmd/chromad/static/chroma.wasm cmd/libchromawasm/main.go + else + mk cmd/chromad/static/chroma.wasm : cmd/libchromawasm/main.go -- \ + GOOS=js GOARCH=wasm go build -o cmd/chromad/static/chroma.wasm cmd/libchromawasm/main.go + fi + +# Upload chromad to server +upload: chromad + scp build/chromad root@swapoff.org: + ssh root@swapoff.org 'install -m755 ./chromad /srv/http/swapoff.org/bin && service chromad restart' diff --git a/vendor/github.com/alecthomas/chroma/v2/README.md b/vendor/github.com/alecthomas/chroma/v2/README.md new file mode 100644 index 000000000..4aeb54d97 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/README.md @@ -0,0 +1,307 @@ +![Chroma](chroma.jpg) + +# A general purpose syntax highlighter in pure Go + +[![Go Reference](https://pkg.go.dev/badge/github.com/alecthomas/chroma/v2.svg)](https://pkg.go.dev/github.com/alecthomas/chroma/v2) [![CI](https://github.com/alecthomas/chroma/actions/workflows/ci.yml/badge.svg)](https://github.com/alecthomas/chroma/actions/workflows/ci.yml) [![Slack chat](https://img.shields.io/static/v1?logo=slack&style=flat&label=slack&color=green&message=gophers)](https://invite.slack.golangbridge.org/) + + +Chroma takes source code and other structured text and converts it into syntax +highlighted HTML, ANSI-coloured text, etc. + +Chroma is based heavily on [Pygments](http://pygments.org/), and includes +translators for Pygments lexers and styles. + +## Table of Contents + + + +1. [Supported languages](#supported-languages) +2. [Try it](#try-it) +3. [Using the library](#using-the-library) + 1. [Quick start](#quick-start) + 2. [Identifying the language](#identifying-the-language) + 3. [Formatting the output](#formatting-the-output) + 4. [The HTML formatter](#the-html-formatter) +4. [More detail](#more-detail) + 1. [Lexers](#lexers) + 2. [Formatters](#formatters) + 3. [Styles](#styles) +5. [Command-line interface](#command-line-interface) +6. [Testing lexers](#testing-lexers) +7. [What's missing compared to Pygments?](#whats-missing-compared-to-pygments) + + + +## Supported languages + +| Prefix | Language +| :----: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +| A | ABAP, ABNF, ActionScript, ActionScript 3, Ada, Agda, AL, Alloy, Angular2, ANTLR, ApacheConf, APL, AppleScript, ArangoDB AQL, Arduino, ArmAsm, ATL, AutoHotkey, AutoIt, Awk +| B | Ballerina, Bash, Bash Session, Batchfile, Beef, BibTeX, Bicep, BlitzBasic, BNF, BQN, Brainfuck +| C | C, C#, C++, C3, Caddyfile, Caddyfile Directives, Cap'n Proto, Cassandra CQL, Ceylon, CFEngine3, cfstatement, ChaiScript, Chapel, Cheetah, Clojure, CMake, COBOL, CoffeeScript, Common Lisp, Coq, Core, Crystal, CSS, CSV, CUE, Cython +| D | D, Dart, Dax, Desktop file, Diff, Django/Jinja, dns, Docker, DTD, Dylan +| E | EBNF, Elixir, Elm, EmacsLisp, Erlang +| F | Factor, Fennel, Fish, Forth, Fortran, FortranFixed, FSharp +| G | GAS, GDScript, GDScript3, Gemtext, Genshi, Genshi HTML, Genshi Text, Gherkin, Gleam, GLSL, Gnuplot, Go, Go HTML Template, Go Template, Go Text Template, GraphQL, Groff, Groovy +| H | Handlebars, Hare, Haskell, Haxe, HCL, Hexdump, HLB, HLSL, HolyC, HTML, HTTP, Hy +| I | Idris, Igor, INI, Io, ISCdhcpd +| J | J, Janet, Java, JavaScript, JSON, JSONata, Jsonnet, Julia, Jungle +| K | Kakoune, Kotlin +| L | Lean4, Lighttpd configuration file, LLVM, lox, Lua +| M | Makefile, Mako, markdown, Markless, Mason, Materialize SQL dialect, Mathematica, Matlab, MCFunction, Meson, Metal, MiniZinc, MLIR, Modelica, Modula-2, Mojo, MonkeyC, MoonScript, MorrowindScript, Myghty, MySQL +| N | NASM, Natural, NDISASM, Newspeak, Nginx configuration file, Nim, Nix, NSIS, Nu +| O | Objective-C, ObjectPascal, OCaml, Octave, Odin, OnesEnterprise, OpenEdge ABL, OpenSCAD, Org Mode +| P | PacmanConf, Perl, PHP, PHTML, Pig, PkgConfig, PL/pgSQL, plaintext, Plutus Core, Pony, PostgreSQL SQL dialect, PostScript, POVRay, PowerQuery, PowerShell, Prolog, Promela, PromQL, properties, Protocol Buffer, Protocol Buffer Text Format, PRQL, PSL, Puppet, Python, Python 2 +| Q | QBasic, QML +| R | R, Racket, Ragel, Raku, react, ReasonML, reg, Rego, reStructuredText, Rexx, RGBDS Assembly, Ring, RPGLE, RPMSpec, Ruby, Rust +| S | SAS, Sass, Scala, Scheme, Scilab, SCSS, Sed, Sieve, Smali, Smalltalk, Smarty, SNBT, Snobol, Solidity, SourcePawn, SPARQL, SQL, SquidConf, Standard ML, stas, Stylus, Svelte, Swift, SYSTEMD, systemverilog +| T | TableGen, Tal, TASM, Tcl, Tcsh, Termcap, Terminfo, Terraform, TeX, Thrift, TOML, TradingView, Transact-SQL, Turing, Turtle, Twig, TypeScript, TypoScript, TypoScriptCssData, TypoScriptHtmlData, Typst +| U | ucode +| V | V, V shell, Vala, VB.net, verilog, VHDL, VHS, VimL, vue +| W | WDTE, WebAssembly Text Format, WebGPU Shading Language, WebVTT, Whiley +| X | XML, Xorg +| Y | YAML, YANG +| Z | Z80 Assembly, Zed, Zig + +_I will attempt to keep this section up to date, but an authoritative list can be +displayed with `chroma --list`._ + +## Try it + +Try out various languages and styles on the [Chroma Playground](https://swapoff.org/chroma/playground/). + +## Using the library + +This is version 2 of Chroma, use the import path: + +```go +import "github.com/alecthomas/chroma/v2" +``` + +Chroma, like Pygments, has the concepts of +[lexers](https://github.com/alecthomas/chroma/tree/master/lexers), +[formatters](https://github.com/alecthomas/chroma/tree/master/formatters) and +[styles](https://github.com/alecthomas/chroma/tree/master/styles). + +Lexers convert source text into a stream of tokens, styles specify how token +types are mapped to colours, and formatters convert tokens and styles into +formatted output. + +A package exists for each of these, containing a global `Registry` variable +with all of the registered implementations. There are also helper functions +for using the registry in each package, such as looking up lexers by name or +matching filenames, etc. + +In all cases, if a lexer, formatter or style can not be determined, `nil` will +be returned. In this situation you may want to default to the `Fallback` +value in each respective package, which provides sane defaults. + +### Quick start + +A convenience function exists that can be used to simply format some source +text, without any effort: + +```go +err := quick.Highlight(os.Stdout, someSourceCode, "go", "html", "monokai") +``` + +### Identifying the language + +To highlight code, you'll first have to identify what language the code is +written in. There are three primary ways to do that: + +1. Detect the language from its filename. + + ```go + lexer := lexers.Match("foo.go") + ``` + +2. Explicitly specify the language by its Chroma syntax ID (a full list is available from `lexers.Names()`). + + ```go + lexer := lexers.Get("go") + ``` + +3. Detect the language from its content. + + ```go + lexer := lexers.Analyse("package main\n\nfunc main()\n{\n}\n") + ``` + +In all cases, `nil` will be returned if the language can not be identified. + +```go +if lexer == nil { + lexer = lexers.Fallback +} +``` + +At this point, it should be noted that some lexers can be extremely chatty. To +mitigate this, you can use the coalescing lexer to coalesce runs of identical +token types into a single token: + +```go +lexer = chroma.Coalesce(lexer) +``` + +### Formatting the output + +Once a language is identified you will need to pick a formatter and a style (theme). + +```go +style := styles.Get("swapoff") +if style == nil { + style = styles.Fallback +} +formatter := formatters.Get("html") +if formatter == nil { + formatter = formatters.Fallback +} +``` + +Then obtain an iterator over the tokens: + +```go +contents, err := ioutil.ReadAll(r) +iterator, err := lexer.Tokenise(nil, string(contents)) +``` + +And finally, format the tokens from the iterator: + +```go +err := formatter.Format(w, style, iterator) +``` + +### The HTML formatter + +By default the `html` registered formatter generates standalone HTML with +embedded CSS. More flexibility is available through the `formatters/html` package. + +Firstly, the output generated by the formatter can be customised with the +following constructor options: + +- `Standalone()` - generate standalone HTML with embedded CSS. +- `WithClasses()` - use classes rather than inlined style attributes. +- `ClassPrefix(prefix)` - prefix each generated CSS class. +- `TabWidth(width)` - Set the rendered tab width, in characters. +- `WithLineNumbers()` - Render line numbers (style with `LineNumbers`). +- `WithLinkableLineNumbers()` - Make the line numbers linkable and be a link to themselves. +- `HighlightLines(ranges)` - Highlight lines in these ranges (style with `LineHighlight`). +- `LineNumbersInTable()` - Use a table for formatting line numbers and code, rather than spans. + +If `WithClasses()` is used, the corresponding CSS can be obtained from the formatter with: + +```go +formatter := html.New(html.WithClasses(true)) +err := formatter.WriteCSS(w, style) +``` + +## More detail + +### Lexers + +See the [Pygments documentation](http://pygments.org/docs/lexerdevelopment/) +for details on implementing lexers. Most concepts apply directly to Chroma, +but see existing lexer implementations for real examples. + +In many cases lexers can be automatically converted directly from Pygments by +using the included Python 3 script `pygments2chroma_xml.py`. I use something like +the following: + +```sh +uv run --script _tools/pygments2chroma_xml.py \ + pygments.lexers.jvm.KotlinLexer \ + > lexers/embedded/kotlin.xml +``` + +A list of all lexers available in Pygments can be found in [pygments-lexers.txt](https://github.com/alecthomas/chroma/blob/master/pygments-lexers.txt). + +### Formatters + +Chroma supports HTML output, as well as terminal output in 8 colour, 256 colour, and true-colour. + +A `noop` formatter is included that outputs the token text only, and a `tokens` +formatter outputs raw tokens. The latter is useful for debugging lexers. + +### Styles + +Chroma styles are defined in XML. The style entries use the +[same syntax](http://pygments.org/docs/styles/) as Pygments. + +All Pygments styles have been converted to Chroma using the `_tools/style.py` +script. + +When you work with one of [Chroma's styles](https://github.com/alecthomas/chroma/tree/master/styles), +know that the `Background` token type provides the default style for tokens. It does so +by defining a foreground color and background color. + +For example, this gives each token name not defined in the style a default color +of `#f8f8f8` and uses `#000000` for the highlighted code block's background: + +```xml + +``` + +Also, token types in a style file are hierarchical. For instance, when `CommentSpecial` is not defined, Chroma uses the token style from `Comment`. So when several comment tokens use the same color, you'll only need to define `Comment` and override the one that has a different color. + +For a quick overview of the available styles and how they look, check out the [Chroma Style Gallery](https://xyproto.github.io/splash/docs/). + +## Command-line interface + +A command-line interface to Chroma is included. + +Binaries are available to install from [the releases page](https://github.com/alecthomas/chroma/releases). + +The CLI can be used as a preprocessor to colorise output of `less(1)`, +see documentation for the `LESSOPEN` environment variable. + +The `--fail` flag can be used to suppress output and return with exit status +1 to facilitate falling back to some other preprocessor in case chroma +does not resolve a specific lexer to use for the given file. For example: + +```shell +export LESSOPEN='| p() { chroma --fail "$1" || cat "$1"; }; p "%s"' +``` + +Replace `cat` with your favourite fallback preprocessor. + +When invoked as `.lessfilter`, the `--fail` flag is automatically turned +on under the hood for easy integration with [lesspipe shipping with +Debian and derivatives](https://manpages.debian.org/lesspipe#USER_DEFINED_FILTERS); +for that setup the `chroma` executable can be just symlinked to `~/.lessfilter`. + +## Projects using Chroma + +* [`moor`](https://github.com/walles/moor) is a full-blown pager that colorizes + its input using Chroma +* [Hugo](https://gohugo.io/) is a static site generator that [uses Chroma for syntax + highlighting code examples](https://gohugo.io/content-management/syntax-highlighting/) + +## Testing lexers + +If you edit some lexers and want to try it, open a shell in `cmd/chromad` and run: + +```shell +go run . --csrf-key=securekey +``` + +A Link will be printed. Open it in your Browser. Now you can test on the Playground with your local changes. + +If you want to run the tests and the lexers, open a shell in the root directory and run: + +```shell +go test ./lexers +``` + +When updating or adding a lexer, please add tests. See [lexers/README.md](lexers/README.md) for more. + +## What's missing compared to Pygments? + +- Quite a few lexers, for various reasons (pull-requests welcome): + - Pygments lexers for complex languages often include custom code to + handle certain aspects, such as Raku's ability to nest code inside + regular expressions. These require time and effort to convert. + - I mostly only converted languages I had heard of, to reduce the porting cost. +- Some more esoteric features of Pygments are omitted for simplicity. +- Though the Chroma API supports content detection, very few languages support them. + I have plans to implement a statistical analyser at some point, but not enough time. diff --git a/vendor/github.com/alecthomas/chroma/v2/biome.json b/vendor/github.com/alecthomas/chroma/v2/biome.json new file mode 100644 index 000000000..a5bec2e19 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/biome.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.0.5/schema.json", + "formatter": { + "indentStyle": "space" + } +} diff --git a/vendor/github.com/alecthomas/chroma/v2/chroma.jpg b/vendor/github.com/alecthomas/chroma/v2/chroma.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a747dbf804db96473bffa217fb5aead7a18c3b7f GIT binary patch literal 80950 zcmeFXcUTkM*ESkzkotfiASEa$(xg2~XbD(AQ0YZMI!N!m2Bc$1=!%qxQWONFgOpH& z&;;p7hXA4X7D&R$ue|Sf{yEq6UFYv-C7JA*?9A+S&)RFvy4Sv(yj)}0xkW*K0Vu8mX#U*>0E{Sj{zx~PQ z{I@*$@BV+jfk^-WkbHz%N=8OHnc_cf3Q8)#$NxDlEhY7l;{TlSBjx{`ks9!k>VMi4 zfPC8j_WAck{@MJ4z&{B5gTOxs{DZ(h2>gSgE|a5)W# z0#N*0C@IKkI3*<|6*U!EsA;MHCA2`=e+%%xLicaE@-JcdU!nNdzo@8a$ZrNZTDt!| z{(s%LoF(V=DwnMQRyqoDi;ChVfRdGhik0H>C&ec+2|@Fp5&n-Fb3>YzO;s0Y<$3j{OavYKgXFx5wkv|NdV3t!UPJWPg#KQms0>nDhl!qqhbX>0VMuUK)1zQCao-wyg(?9<9h1KBGa=5*AfIYJuLN_ z!Q;4V%gjzb%=PZWIRurwixxcl^09f*$j3p=yC!k(nIhnkXE2lRSz!-HYQ&vWQ=~Bq z(t3}%`~VS%ri5O-zu}Kpx&Ztg2L)~2UYO#DO)c%r7B^*){o?ODs^IO2gq7^0dn+8V zekAB{N$(6}E{k@-D?BVJ$etrde$YJjs9dJ``IVI4ZOvY@GSV;Em^;=@WbNXooFcz2 zOl0*3j?Bb~F{??5T<9Qzhs!+V64C*!q9R<3lVO_%E#_*nnh77h!=;Tl6l@|?l?r^{ z;@SwJy+vB2Sy4~-7=mbb^n4L0nv+>C;Q?fkC_;K-b8rq5ZK;r631&1vQUG(EA6%E6 zg3!+Q7CrF~nVaz|Wf2ryS-#N!$&l0>w^S3KrDlD1_lFkEix_BESt;6PKv~rNhV~8- zI9w|D;R%B4K%T49X{rm@udWFf04vL$`IK@A@?f69qFvbokH=#YE8W-r2$%CFo83ns z4p!ua{1(O~s!g@;4Xx_}lXdoYhwBoQl(hQKrx%~m{o*!+N@}&Ye6CE8_w>`E;&t7O zIJyLY%RjVSCA8>MWGG9Mye+g|+&vrP0f_XR@XtEWwujsy7{>{bzW06q5l>i)S%Lca zQVB*pf7j0?RxJZB*GGh&l^_zX{$)eWoO1~nbkg{&@$w0MJ#HG(qv zQ!4yG5oTV)FC_UL{{0n>*QRdWnC(`#k4r{XCE4kXmpp-D(jgKu0AUd>ZJc<;6`M`XRumukJ5LdcK6}5&M z^w8aG)cX39%|py8Gp9IocH7AMQSaX<%%Jw+nSPx}D?>d(k%KR`hB1$(CvH{k_N=d;9TlGxeoxLGQc8%F zXh4C@u|@b_dULS>Q~sbVY7c)Of|!NZKx`m$#U3y$2!$E0D!*T-v|#Fh_dKKox?5nN zy>a7;B4TS+vt3)iR(KQhTJ%w6vePx5=jnqPi4p@c-f++CRFWWMtg-l&cxDe9TP9x| z4h1{JI4vAAtaHb^yc={21!LR?N~Uv33@pKB+;yFHdJT+pT-X(iwZb9Bq=VloMC)gj z?_mA*(a~y|8DU_AF`Kp(;Emk71l%s(Ity&SCmS>ei73+LW?hlWj`)(2DG!)aL>1Kfc+c z7O=|AKRhS(PGarAFCu@zlk&pV<+(Ogch82!tmX9N?nCtCu`_-pFAuVMCz)vp!MM6w z<+CqQ4z|{Y*{q{St^6?+>H1}?H^t2W`VEsJq#Z>>HcTPi?dHr4iiR6uJKjmOJSeA# zVb`}ebpBXm2?`4*ZzGnzH5Etp9m;XMa$9E0_e8Zfyc&Fv@Gv9vn_%*TBxV-g(@Ov} zT2xaG&>=`sPZD5JUEdIGdOfG6CV-Y_f^Q4>?Wj9>B-ic;bbUPd2%uXZZz$3^cDT87 z3Aj@@=GhQtM9t>?8&{xy^;T>9;(^8t&}Ibh^Tp=HpjPt}D|pyTY?0#+GAdiPXPLKZ z>6ByLaprlSW&rDdKb~M_kXcUhJ5N0#Y!0~kKiFKk1bpM8lkbhdjA9Xr6V8RU8rNDc z?z{Jpc7e!O*oFn;0qnOC^+~&9m!T8wNZ(Y?qNwzT;w1;&pMk-aeBUtOqjTd5(^vRu z(_etQ%z**|%HhZ5NCHQB6R5$Q8YSJ;4GF^6Ui&17S3mkLi;`EsDYl5?tDCKZp=)KX!XHrxHuIdI6lk-5TICb z8mk0@~U%!swqUjoD_F{$^HF#W-$BaWjvz*i0aVuhjxXGZ2ER)+C z6|V&^YJFO1)I9#IcPTe}&aZ3VQcY~?NT*WP)=dE~NEVr-sXhAg<$ae&bN#aI@pf*} z-dF2H!6%chKyVwF3B#>Cpb%EGG9H&>9Z;tpk6M}1=h{X5JjEXTy<`BITM$vYugD)M zzX3C+5r60$m~3fR$D`w3@~r;B@4o1P9qF3p zI9>$IB=h@#jZ0tvaAgO)z6P7(Fb+(#VLIfsAA5ooK%hxw$CeFgnGnCZ`(MR!bL7`2 zt?O5=a_XdA5#-^zPY1fQS+|+%9WhZLCDZSBEUwXp&23h&Pl!ErA{m%!9GTM*f-h{= zpV0Zg5M5K4(`xL{VZ*iTdc=F&%8~6jo39y^dt?8hE{*x9vMKs`$F6D zihWek)K|kpAvr+kaLehf_Jap^PV{w)YQnoW=$*H#~r}id_MWSDvc*&T4_5t!i zYA#+gEUF)tS*HIP=sD16=5Pob(M(nE*wIjqIFUopaNJ>Ojvd8Rq8Y;?n{7Q z^Oce=OsbZX?6dQy9f#`PMO(86i>6c=Ht-;FxZgBZzgg1r9_wPKw&fK78g3eCS4h)I z9DGBEn}Bpo9F;#yxt+l~eRoxGg%H4dAR94K6B6wdQsqFrN@J##0@Od)?RgEzu9fkU zC(3Uc3PrWthv%cD7i^K3gWcis?^7)b98G zw+;Y{v`y9`Qj;^id55w;XQ$y+Na|ejC*O__K23|4W-~>5HHoYb>Ys%fHcF-o90GtI zT_-}zK@mNhFK@iCUuCTC!nRE#F-XnLLa))}B+?5zq~iNXIBVocf!$#B7n^z?ZY3(D zmZA}MTP%)bHi!PHfRo34!1%ssoza?K+-)qnAhY|5BvX%^m!uNqudCW>WD?4*FxA6m7Tb@11$=_bx1C0TXV#1Bz_&0gW% z-X!slt#W?rtQc_qK7LmfygOI_w(e&XvLKZII!as@PqH%2eV(ZuiCHmdZJnOvJppx#j&lLBWVN66smZj(-rEFnbF2D zPXz3IG{PegguDcpl%zcpgCB^5`*Bz@>T9NMPa$+?;HrH|r&kVlcxp?0MY#)6SHoX25<;+^E zS|6@(sESuJ#sfrJtfs5cx>Lyo+7qRL$Ihk?;$O!2%TXyed~^QV^ML(i>01w&iX!5u zEG+OP0;t?jem8$-AgHQRz-CaH#arh#fNMejl+n_!a6da4Q(*5M{@85NZMN74sl*H& zJjhc8drlBeO5#3qcXHlre^jL80m)6b(x+obG>g7SI#S*sNJ;ZS(v}oiJ83PH14xFB zR$M&6^usaJ4tQE`5^O+BYwp+EZ7lnau}Cyuoq&G{)Gn;08A`u4-u9>7+_MXKSTcU@ z{$Azr?7#?O?A6dyBLjy9M|Q8b4xa&V>q5jYgj@uMW0Hw~L5{Uf6g>U>nrLZFy^^O% zdp`d!`a-sR!xh>Vbpi1aOLHRlYs#qL-T9zRSXIW8HtgP)ss895K*Bmam_KC6yU#h> zjn|&Tnl6rk#8D{`3v5`|dg|K5Xn(ZyL-1;UDVt)zpzktE`;SB!*=Fxl`0J{?sPNB7 z?NXm9(Z4oZg=`YmqO^0nN^Xbh?=>z-+p;zMGLTr4>GU`jEd%C!PeEuck;ZC z^&CaLgQI%$4}lp8JU0{~+uAl@;`+~8bcA}Ui_X8(YHWY_9^L`^0P*FPKR?|x^mwFV zg&=sskB>3sMNTPz<*?l^LiYSbX+rVnmhi{$mf2yZwltqjoo>9j5VQ7|LGs)zuk7v+ zf0`@1j!5Tu5MSrO6W6Bw>>?~pBwpsGY&!J5ihxbF=R96Nis!Ix076dqQR_xV_kHGi zV%i`LfFrJTtwaIeJ8E(^yx2%MEPH$?Nm5YWuxY5;URcQoa|9{{r)1^A8b`!uy%FFp zFeqI)#ek8DgX;SN;wLHFugvd&G@6neo~Q3O6gd$w!Y=<}J5Qr8FUYytRR0G4-I+h{ zGIJmx45Yd2%hPQeo$R3u?vr#=ZvHxvO2;5pi)VQ_kJ5HAmcBE4C(JMaOa%|KuJ8>8 zslI8wt=E#YlI7ohh5ED=qd#&97<*MK6xx`RNxv5$bm2K^{BR|S_WnC7ICC~BM_CNo zZE^e!AQ2fp14H4SPJ#4eI=*~n<1*{HGEJSF3*bd+!3u7+vq+~Pe(KU&*I#~<&LIcmzu`DyN2NsjND;a&w@hJ3?aHO;B zrv-3LdHunxLg^jeo)-E}@q(G&sCj`gcvAXEXk3+iR$d3_6EP^*0AyDm9V4Tx?xp=e zes_d>sknbu4I@#hPV*EF3E%>*UuH`d`>2 ziI%bKTfyEcr4DY$zB)`UmA$h)ux6aotbqfO%AVi+Y^U1C>pBo-Ej{UjD_SwOO)LUA zq%yRE-ZF=(DGukGzSamkIe^qd`v|KIw`6}r=uoaVU2SNk;%*%@ud!6wk``!tObzG1 zaylUL_If40GJA)hr2xw|f_qv&YPVcixCF5Bcg%D2C=}Ji#v49yx{;cWZn? z@3N)WO1TR7BtQOzTE z>j%^*w&DJRPBRrX>D(H$%H?k~fQnUX+SHcx`z52#K~JOJ8cD8OIJ{(ARcrt9YT18% z0QLvBa_>m8W0zgIu{3?N;Ae1zP)IB<1!l>)t$NdVs#685`livVVZmmC_xi?``_p_4 zE{d4>j)@2i`k*}N*Iw^8m%*YoYhLlt5=ybWADH(MX=>A5ls2O_<%J$j$Ca2SOwuLb z?yfjhmBShUh%61%4p(}X#Z>!o7GRN;0pyDirPVINeK^iXhE~p)K5e1xh|x{_$fA3W z(jgdh>06`#b-1Bki>Mv_`^_uWP>HeY`6lbaeBB~!WN=e)(>DFX%q)mG5RW(tZoYaE_yNU&*0VdfHBI} z)~dy-ZD;0$Pjvcwdx{k8aAT&5`FlS3Z)@2Yu_qn!mWZYcEH{=f9J*+%DlFTXAsIW} zo)afKV~?MBr^}xx8hwUK6>Zlsk}7LN3YXED2Qfz`G&@!PkT!OO1BJh0Ldd3jQMw z(NkjAnzn+t$X`{xvnI3K-zbgoo+%NdN)IX zfCW!P;3Ys=^y!O0xC%#9AeT!h7M~q)yl(F5bo0FJdCXwiS1no%IH|9M^qurAp)On&|9 zb48bO0InR0OF%eg3PK^-;?>x0RXS>FW>XI=4&XIR(qcLwA(hHPi58UW8)^zuAt z6?{%`Q;p3*E2*n-89edr2i~IysVC>2+X;uy{j5#&n7JEVo3LOEaDtDbd`O1CRGK%Y z&z7Pz{ZmfbU5x&li@MGgFc`;;6+~;|cbA$wG&dVpdrO!z@v*Z6WuVik`(IMfW{E>K z7Nv8~$kg4@r6z_Y+k}HaPl$)S;6>5*K^LF$A3fiZQ<#TXS%Srd($GO}JvS=&{;Isv zo@ee@n?(t&tn|zkX!)~*qa62D|3u>oOlYGv2#H^9+92J`H1F#!AKOdYW)I^)ekt>o z5o7#I8T`eH%XPB*WY>gK=Tq(0e%oNPu0YkbXR=uN^-I8bx%#_@oh?N+pDn)06xXS4 znoob;V1SIzXyAh`0i3|!7sdldDaAAolec$CT;-34e64uISO$f2#k#r{C5s_Q@qT&b zx!CF^?LM_X#slMR3)pgV?LtwNc6qZm$rAuZpVRf8^;hHXzU@BPxbPm}%qH{5InE^( z^P&ofZ~4iC^;94Bl~d!74fa_-{2pW#YdHdlo{~6bM`n(`+%k---Jx7T%n^ZK*Vli! zD_1AH=TWitOD4R;Jj<0PIsvO7=Er&*`-h>}L(mH5YpG*YzPHz-4k8BypKPuckbCVS6l-~S?YRjhVJp^;uB!8ER&Wn^Mq&=iO!Y@U z#f5wZ3v=V-*N2-G*m;zS&%Qk7o|t$rE-O|qZoEtl!i_|jYkb>y{Jvhk2d7Mgq*s+# zR7a)EfF=;1ny`BH^P|R%QSH;-%ZK8<=a1UZX}!y*CuMFn0~@11T;!;Y3?kviRdg>w z!bSzXS|yFSj?rEa^K>yc@U&Vhq-KQOtJV-(diysI2)Ea1dIh6d#ncFD@-*{tkZ%;c zqSgJeLe5IBwB?vl%umtaVM3Z|cqUcCsT5v37bjjJ!UeS?-nn4&6^<|y{xcBB%R2S> z{!ga*rDm3`Tdwd7q1CYN-lj3ZtH?&Pr_+`f{OOucErA?3YnkAX+rNJb(xk`X@IHmx z)}n+8HYiJhzFix@IMSGYGn8Bv6>c@+on?z`I9k;Ye_#z*HlG%V=GDTDI^W zQ~gT!X5%HGR6kxfZ2dfpBOXTyfeoki=kScwSSfTBzn*?2vU~*aDO7HqUVm{3a5MyS zaHmOe^oh)9eRXp5x8ctzP8QzPlkTScpzYRPDUTCF%)Vg=Gbrhv)|6_sG}s3~UXjxN z(tL~QOK4=b1ZZp8Iv(J@5K8pM|5BTiRvErV$KAlkqOCb!TQ|cgSjWEUY1xqKuUn*}ef*9zHW08u=-+mw;Az zSK*FRh4j{%ifCLqY2#xL_BZ``QR^k3^4;5zr{d}cMwKjer>0Lez1Kc^T2#Wma}ut~ zb-_5@1(9t=Z|(Dc@sytRms-^X7r} zg%|-cMj&?b%Pa{e2C6e#&6@P#jrtmcAA^R#7A#=XsI}rI3*+gf(gJ$-Czk+(MIOP1 zKzj*zqZ*=embC&wEC@b$liH1Zlp%>#Z5Uj&W2fnv%MNsrY`!NyWL&Y6_mHDNta=VfKI!ig{$?Fv&z3TQH5nQo4GhPI4%U=ShU5MY&um2RHboPi{ z<5R@ zx(oekio#v(FScANz;55aq;Id>dX4M`BXSj4ffj(T#X0%aVaBE)Y-TY5GU`Ln=92l8 z-0&_nb#un1P%JT2e!Eb5rf^uhm#)j1cn!Ufhu(Vxjke$scOwaeNY{}1C*I&uE>-c* z{_s)n!x`f0F^)hRi>|?Kv5V_xn1xul&>jl8Md}GK=yCREHlNy%PX2LUEQ3!@q(eA} z)YKOMy}9JVIUZoo+Gi$qA#z-2vmis*h>>L_X2nHzU{gr!EmOOirW%26$X|4>AuR#) zo~C}REi2GX*$KE$*_#X1EVUmOG)vJNe?=yRN}n5C8*c^c|MuG^!3x4G;B7{26B#^L zf!r9iOoXW1NW~E-eCDA$Zv#famkRDnrWlE0!^?xPWYmBp|`4Bo2e=chRzkEw;Zj+UCXcKMX} zUs_z%n9_}OUanR$XI^x<>)iqzYu1Nd1S?t)IbOo>-yufn(RXq>7 zW+X|G&X{W5qLIS5=MgU)plEz3#}M$YlY7o4zN1OANGrvt+W7c4aUL1Mw|NWYJE$##qP1y7D@8pxWj(uQVzYI2+>_q1iM;_ zWn7cdcr(L-cLA4g?*c&*0jJx*!or$8)1Q8ahom)(Fcs1EHu~O z7mFIQO@9~)3Urdb<>60n8XOF*sf)+N9OApx~`wA6LfL!aQ8Po?1hN-^!|$ubg>y zB&X*^UjlkE334-+fHsCpfD7>+zdcHmzG=m#L0Q@3bHbU;NhC3jBtjav1pFBaXw)A$ zrX91*v@vy9z4$GP&z$2dTsd7u5A~!6(5UgOSRF5+libflO=!-d7qf0z%$Ajwmnq*5 zMJ4ZchV3uZvd9d`j;YIaU6@$(=5Y}-PR(O`VP7*P&u3F@wV9k=V2mVY=akZBKD*_x ztd@5=hUPno*xfa#^rFM;A)uw6{&jkT1mTF^7hb`8%2Lj=Eea3W&NfyxIE*DuLscIW z5a?LUg+lS6LO4o)V3<^DW7G#yw=o3yI2XxJo z{U9-C+80s*jZ3)b*Za9BU#5a=@4qQDcddtrJG4?{pM5+rgJOg&yoFZBcEXrU14`P5 zB`0@v?lstTEilVK+|+-MW40o0wUhczWwPDOw5;B@3T7W;_$~qIFh^)bVXB?g1vKD} zO5>v-zAVWKY54gBx%|&{hU{do!lkd&7}#t#KsfS^$Ws+sAq}~<*Jau+Z|=0$G`9Iz z&To6KsPY(!yaHVazXa60sBrDpX4vG`Q$<<;15gV^2!e1hF|%wv_0Ox4?E^PUhg(8EfG5|`V==Zb!>9=YwYTCaO1YE_!*D(>+>Mo-nx0t zqBhWJPJG;YC`6IE?wuY*tq_lgx_QI;Oe)+s)0E@7=W6Qj^QOitq9ch4o{d|G+k+Y} zggB{fw~e@X?xo>UIZ)HFvzapyrOV+~y=ngTzg01#yvX20m1; z`LNQ1-P+3xt%R0_?(Xf9=-l^rO%NhA!3=MGrSZGKN>+iGc+Kabsu*WM+Q7uFgL({0p(r2UHAy^1$}r+)?hj?mc? zijl>>ve5i{g4jUTnDj6N_ODrgwpl2QTIkCP-fOsV?Li_cZ$=(RNFZDS&KfQ#37%)N z9$3tEyOZp!Fha)9=>=XwmD(Uk8RBBgoKC#B$-Wb8$fT_~Qq%WRye2DP$I7=&Lq`f~ zF7~I}z~dK2DytNf;{5xtBE;hT)RAL{R>leec^IGCI<@n@-C-h_1|O2a{6z3gb1AeVm62<`kc_0TCK; zt}iKeXeUm$Eq=Z0LjBq70x>E*ha_Uz{|JiM)~jgtqvzGzx=)}oytWh;u!OzxE4d3R z35(~1V>WbUMhc!E&3N`U5@UQGZ93Em8*B(In9G`aI$~h=(#hm?<))`YuEvyXI2Au| zFQQc-D0^(oW15Q0`eqi!klOZBbh>rnl6tkvJ&f+;>oOxr)ty9z(JU)SHX z7YfE5l=8f!y1y&SsCGsEP=S#$h;^DOVX1nT!_k;V`l5!vX~lCo61i7eU*qf?E_A4( zj+dj#wlC5`nc$u3UzUmo8x#f^M(50qvf_EU)nL7 zWHMe+ATgk?9E&jemv@zH7P|96KTw7hOkG~reFxOn6G($ioQ~|Q4O&t_ckPwo7K>Y@ zaTt5)zQ1+7oKF5op4q(nDL#Ke8N;-g7ibtOi|(_*hg1=x(T?BWBALv)JO}$mjxPc9 z)6nm*ZON)WcjjILtddtNzhW--pnM}-L-Muo{uh6_eb6x4B8*?}5`aSEMWN!CfVeCq zc}JI^y^?@EVI~$my~5dES^d7%Wd+82PD=0CoUcG`gBI%zYi3!t-VQzOuh?;GVuKB8 zlB%=Hxd~_Gif8G27wTt;iw)JGFJ*5=3du;)*qWn?I0Cepq-w<4IV!G2ZxP2Tu=XvY z_D3G~ob5&(d%qcCIfE5_E|AzF=o^ZO^rvpk%b?^hz>@Tq_;p)8r^CCsdk2uqSspma-xKX^XPYluJ#r?bc3G z@XAcmJW-I>PoN$33rEYzlQsnc8Ya(Cch%HewCJ!S)8)-x!)LiuPZGNFE#E-QDF&g7 z$Y+MYeW$(#ZbX-g4r@xuZ;*TA`NV>3YhT4tZ{D=xRBHvk$e|m^r=kqxgRz*b++$%? z6SRFx^#^Dy91F@%QrfdmP$8*}qP#hN^HN-+&NpnGLU z8!%f(51bfje!947nn@a=k9}e-PJ#yog-S8OwC49T-J=p0=KpL!uUkyV?KbIpOuU?q zxljnHfTI?{66?Qw#O+?)3s~ISf8OXL7Pp^P`7L_2$~Zg!Gu;--|KJJ9`z|>He~+p& z-0I&8U^?*?{$>6|euG7ILyT>cbj9q#raj)gt?}C0GCkOsmYm zdlz$@Q6=qZuZlaLmN%Y(V*7p)Y%T%s$ac6OXhL>C>ZDn3kv|JFjr_x3sCa!Tn|Qil zd+ID_cV2&7^4+t&@z7HpqH0-l}pP+xIUXt4kfCPYM$Q|c!GVgcHok8+|Db=75yt!ro5L_Fgi%27gA#5L;yV@^eG zI{t8pf#Db1O6krht@+$+L;2PSi6Q!R$c;q?Ci?F98@2nn`e9m~7kmSNP8ewZ+Dp5A zv%c;pxGVF>pA*MFn{IS0){7Bs&iis6EtU4BI8J}s3cJ-B;{A4snLn@$l2T-7Ejr|h zn8OjIv8f^P7cKdIpy4l8AKcS2Fyw0R#dvbd7;M8X${jwZ}pY(G%H;`IAhFQGQ9 zGMOc*vF-HWTCmwLKKM2{+UPyP7kga#G@uQyzd~^S;GyuUBi^bO0&kVOh2Z0MtuN%sEBoMj78X@Qf!9Ni0FbujH*BRWGB?&lF z!|HyRw|t+U7dQWgLJ$Cp4i#}H2R$Sao&QK|A&`}hI=Ug=^AdpcCr4yE@-Go*lE4VG zEsA+_DvE)ax8(oMpdlGEpgV(qsN}g4-5J&dex&k68uO7LcF@8%P(|1uD~a`4ABt+w z_jEf^IIEIvvuh|6q==0DTcoG+{^`m{Q69KAh z5LJ7zCu&yaq2pVs=xnjHBZg**#rdf#Yvjk>sL?%4?sVvMc1C!whG&ulF}5dA~YdX#gP74+6_fN&`MOvRLHxODTFeQ8Fucnx!bCB@FBY z3qo8?UX@{rxIvf0Bvy)POo3*zleoxgJ~wZ<$vIWTwTHA+%@9Z?aId)cS0m!FVldl% zIMG?SBLAhwGXw0GZS6U~NJAhUu;2+x*jUzNi*>ilp*B-Q>d{i(V3Af@N&NzIde)@B zgyb&_o}HwnV1w+|e-x7IsrMBmg5jVPzZ=j>D0cV^?&*}Kec`$c(`;rBVf1pcrFrWs z?#H-%TH5$xPX*&Nm~fL^YkK{|lLUC=ZvXq@R+ArmBnun^0*@o z;vHC<0&F3d6Map|#)h2mK2y849)GOZOedco?O)c3$^oRhzeze?Ccs@|d2 zehBV~cSx1P%f;1h8mIcZ#t(oCgrYk|xEF)`itFTRYyS!@Ja`lh7+B}JNwViS`TL7j zkSf1f$m8o$xRP63r*7Sq5GTLE!=rCJl57FNI*dmY-00s4Nv2>^MQQ9Bf8vMOA)|dsb-_Q7rD|F5+*@u-nW@0*5#37G9a|dEUGPupK1_+&izU4xK6+ zT71e(47~&t9hK)Vwg`3E)=%1acvmGhE3;%QwQzLU2iRS?NYC5V|I#ArWeP@*6#u>i zh=ZmCPdxTn+IP7&pv+Bnz;`fPsJ{&Su{YHr?_TcO*(D(SyQug4l5s`W^A^|p+8Ku6 zwspMmY5FCACX*QV_bz9Emj(ZsqBheP6Y(F24{=T1YgA@0v#AdHKZjT{3sKd;IH0VA zd(O@Zn>ubkC&gAG58YOReK4x{i4$$MP<{BB6R&nuV#VJnC-D;4`Q?ynS7mc;qQB~M z@V_DtSp1RE%=oEj0iotvO99Ijp)c{csMHn4t4a&ZQtF;t&fDdGs2@R;9s9WTvjSs# zWjoYUQxO4OVoT%))oaqzT;DUN)I(5Z0ffyRmdSI0Fvw)1te8agw8rU!C)nIs7EO`` z_R5##di43JWcT?X!}m+T{=1c`+OeB3i}^kE7p-TmSfzb(nIVengq5B+?yy(PS;ui^ zNVYtmhvaKqbS-%1n9C0SFy5Ji`sEV?%9jTj#4FA&{E!fYIXoUJ9y<&qZ8>v(jKYl}D8)job`&9V8X(=%#YHdTR$K|bl}kq@K~u!S6Qou)%4L|F^9FOdVI zq9D_nV}vf3gM6dpS_JzWSkzv#H0d5u8P=x!+2%r*pdf&|&#XPNH8?U|08>8OD-ZuX zH3mIOgE@wBO2@}X5duNwCHHW!carU|4tWm9C@xB<>QR?F3s_-xS_L zx@}&F&Mwxi9_KT_y(Y`IjZdKR#9RWu#wFnWy^nnv5IK@!W`5w$9!4F|~+H+l)ciu>NW1gNqRGKoE%G8P-mk4a=cY`q?(bupr@ zsr!rLT=lFQ;OHTn;0Wdm(nZ&IIs8TZvvH?w6Rt0pw@zMRI2F$81u=O&ls(eQ>$W?b ztI~Cc;Zt(_i(Ms83r^C+d_`;rY$~;F;+jH16lm%zw}Y)Ez@7^Ep0R{w(X;zVFyX?s z49q^v;N@-JqMd`4>3=32Aevo?wD~zG!+X~`=7cNm5)fT_i*u-G=rds%>cTQv(uuA* zP25qEC{-8Fu*=#?)y#Xb1yz9BC9BC%bV&At%YQL6Uh&z))ma)n=~lT2iu`@t;beZFL$9|V8u_RW*#-Th^vijXdh?a)&)r9kLD(*5_27BSU znolJ9ul^Q{!yCx-;R%O;Phc<=BnR9@`ul1Xj*F$DplY*OxpYd< z$>E?p_Mj8?z@lPs%PjCD5!xC?Uu8OLO`vW3VYTMvHN(pG2FB9f!a|IKFh4l>wQp)# z%OqR($Aw~p-NTMAi1@o5T_ZUexgZ3kgIrhrw)t1|#Jw*W!6_X~jOuA|zUOu5-^OjP z8*+rXtwlGf@i#!LABZ<$>K;4%?--Y*1~yfd4BZ!nhn2U9KFV?@Zp6$G)(hnT7n3#5 zTLYyE$eQ_d{Ic>G^he}(P-3X`cb~y^O)&hn0=?UT{I-R(Lh2X%#x5}oxcXwtHN-5? z+Ed0WJ7y{W)%Q)jzI>OmgN!HzKQCI%^7Osr+h zAU~9BWBO-Oq(|zs55#7=WeG<52{FP51zh8t=CjT z!{-xWbjQ0C0Wr9CehIkvZ&!yE!`t$@q~#&$i|&p(LnU787LA74Li0d>YDOwF@S_s0 zh}Za-OnlHlh^gDhM4^DX_WRR!ky&>?7zS{1%}P}H{ZSxvgFB25nz5VU4+F~1J9qSg zLdS#{6NuA4nR#0GkxXU6ed`4Y`RIUmQ^?>zkmn+Xcl?)Bx&xLt<91y$$DtH; zV2C_@jpk!CeTju9rNCVQKeFvYp*{CT9Y2gtvZ)G!nl#*B+24v`DLN<@8aW1|oSr*TpQRIiss8?fAmWm+TiHrkyb6TB)|ttuSkU+S|U$!579SLyO3?r)S1k z!VMaJi8tFKq-RR5BwBLdG)LpFmQqo%chvn&^3=@@PawU6qM`(t)5>?6|*b$#$x@ zDL()EcG)+W0&GtY#_-tDKR6)S?#T7gllo;IS5+|d`HJEannlUj1N-vgMcc&#LSL@; zB%`J0*`dWakidR*Q39DjkowX395v-vxvpO^IFHG4nI&zOTNJ;T*YRXi}uOufp)pO zw6topQ1XJ3(yj&yj}#F@K{w-FdtffHdEcTf0A4ou2&Uh`mO1pbE8d409 zbn|lkf4cdI&TltFMYs8MN-NdJ(DWhPuzltW&AqY|;IxuPFh}+O!_l?JGyVO4g`^9q zgj`lhZsnT$WtC5evO?~eTZE8H?zSYC+!jJES(5u@?w82i=RUbDgfT*Ho9i~)yWji! z`*V-&!S+7qye`k@^YuK|!5-ITy^QLZwG0WeZ7LDTxi)w1=LbEPZ&uwN{BZs8V~kQ- zFIcqOF=QGj=9`x^4gSJmKW zi3{7&)14r?nconqKi^YWfPqA|hiyI#R%(w&{ib$IMKid5g0(2FluDp}PeSwQH~S23 z_X>v}Vm4}k(|-xZFM{KXR9t$}PRY+O1(?kL|J+XKOSD$&VL@w*(@zUw}9Ta%QE+l~W@{VddL!Ac)(nBm7yt`wVTsqy%(!?;81;X3gDE2khmzQt7yOiWO zdYyA`ReFMZkbAV6aXUWKBC921&FY&Ssm`0~{x%RH(y10|ayXCo>cB0i{v9q48c%6{ z89pwOYPo1KEH!CBRyX}mM0$HzNB&E!E00iUS(^~ZMFFWmD4J|7`>vRXoKA;LUf12( zzooF)9z&ANe-;$PaLCZBJdPbn-Qg20*+u6gugsIZ#XBbN*HKelP7Y_4PTR<{hI^Ii z90WnRwJrj@Oo2V;VMJ-yT>B3xX+#X8Cc(K<=s_o~bX2CS$dIA*WfY_@zoHg8yC;#) z$G2`x_$Lgtt@UlL+q%4l7|&`rx4xrh6@F6EQ9N^k=-hJS;7WGRo4qoIZr>%#F4e(n zX0ciBKmVc%;+8$nuND6Gy|BVDGg{Qg@5#rIw!Mo3hbf9{?+E8*?_r|ib@kXAWwU*> zq;2_etTa>qk?{7#I*+e{)!b|FXUTRL=b*-t$&pa+m=UgjECv^ktFi=?vU5$!(oN(( z_3!WV9*!3meM`fodN+HczZBi&C%S+d*K}9489K#arim6qLUq*LEHh-W)_ltU!X{TGe_OD_VzvH>_bR8 z@4YP^DMsBl-4lF;R1=%`7dM4V6YF>-e5w~WOH?IE)36`T!g(}vy&|3JdyRB6wh|6# zKUQt<6(i-vfrP>8zcGL(aGGyyG}T(OT*bwHJ|FtF*}Cwq?ZV2fNMn8cZs8t(!7Ide z;exRQfARCK;Ox-Wh>MgT-~Eb4>~_Z(Qu;ea!IV8-v9AxoR8pK?(WY*qPO5i%E<~|R zyiQ^K=5qUOF;iV4h5j)!T~Tb`!DM%S;yep`teu*Bs<_ktpk!?)Jn>iQWT&c{Ff`Tq zSwfcSY^_{(aA7B!bATkvzt(y=I{L?FQSJ6BTdx;#ZNs% zTDPnu9e$VnD~-d0C&+l9bkTe&j!~ zk&EOO9%NTT$3X!=meH5S**&hu!|RxWeJm}{ZAisgZlWdhy*o) z!lmDCcdINHdHDW1ciSnT*e?rKwI*lP0Pa-tSU`>Zmse3nyKC{UyO0tu@3Q3I`B^{2 z=HB~3@IY6dt1i4J|IT>I6*&>s^B(VJzrSg08YqPEoM7sv?m=@vrNqo?XwA_h#OP(c zHty3(8_9Q+IPF6c#y(V9wV{JuxrKsH0UA&@2=yku8!JG~{0ooT(fw}4y7X7Q%-Ovd z6d0s^0Q;7bNd7Y=mA6JRk2rwSL6jPc@rpdMOvbB)&?hBE4ackj`)LDq`GbW&l1U?k zogfOdi_gRjJ9Ur@`Lw_BG)M$nIErlwRUw9^TwMt03aaB(@!$(+_=D71-plLqE1}5v zLR@v9J~uplzhQ&sx+Ya^@O!AP@V~HyQe^v6to!)*D8MZ^Z*=!>XyX{h=|2{4nmHy^ z8GMZMh$#`?=2$JqE|b2O7A&kMp0A`t4Tq7XDaxFQUGs^$a-746+F$w7@vjH$5<9h; z2@5UAGuZceQh_bPN+PlHHE^Y0On7u)1aIoF?8&cRTk+R}JfZBz2Pjn|HCWnvuc_9SO7ihJkF<{vEF3FJROj%(8 z_gdlvU@o3xBFB9Nxz8o-X#oRh?9Gg6qM^5>Jokn#? zFQVS59NsmAbWn3#fx+s(b?5u^ShkJTjvLsNWza5Gj+23F#vMPdezGrV$87(s&6PF% z{DZrlDKggonbjj<>3Og162cLZfoZ@x7RXX|jRJq^M@{?2Z>r7UA-35BTsoyZJw_~C zw{4Ef<~;_m!krM^jb4e9$y--`)b=04&7Q^!C7w8o&{|A9Z=rePc?8n_5yWEwT-v_s zHRMHZ#F*{Bx~RT?220@sp_Z@YC68H-{)<>%+-9Vz;w`}5mq!?7urr_VKMiyk7#7CT!E%=2>VDBy z?0dtDPa4WU8(s)NqO|CLu-~Z#a7v6lff>TcpdGwyYSCOUdiEoInLjToM&^=2hYTtk z(;%!xEx&rX_Do556p{%qB+T$yP0#rsv)E)6JTZrT=uHr&mQTDFn^8b)s%h@-BEUZ1 zWk$=LY=(GdeCg7-^}uyQ5gWxb%G&G6a<6`YL*ejoZpMWUN$5gJD4VLbZDt$Y+Y^M0 zoXT(A%kmv)yx*hkaIvzTgofFET4hJV&}5_4Q0#O=`=j^^`MvsWke%&K_#5gU!i0n@ z=qdzs(&a;%pgdT*FI^ufs`cSBK#lR1+?`>RLjHqNBvAh9X81vM0-oIRu{u-`zPklY zR&}9Na|YfC17R67`3Vm?#_AXfy3V+RTl+Ijp;O?5Y_u=b0JsAM6|XzSp$czEuW>Pi z^?K`&`j%xb;ffK?j0Zyq7e7XnY`NvX#YKJB8w6sE-nqy(N5|x*IRG-XX z7h)+j9+Iz5>0eb(w$^@g4Ci*pogjNY^iJak;pPk<^Te1RYJENK1CPq{h9H816>}#= zzi8nhHjCItloN1rjnzD;&>nq4QKNfl;*f-CG~EPhgM1#QBny51`Ci{i=Od?t^@knpW4kcV z;@^HwqWO)K?{};N(!&%5@OW^9h`heZeYB^ygCRzc;>RjJf7LXs`l#E?fAE79_a^{=~-)+rxfZJ#Xeq2GUGm^r!agfs#X z*7i;aR~);?xhheOd#qz9+N$)ZCaA7sr%-tp1sgYC3qG&kW#NDI7}Ym~ymU59Jt{in zxPI>p;TIa8nCc^}EA|A^ztI^HKL49;zVbR$yJP3*Q|5a*W=A_M%_C~X__NCDH^M41 zub~}2gC+9y|dR=o|&g^ng2jM?Mju`REv4r-5PxU$ZP`H2`RL%4!z-(Ix(c+UT82knljNH5cd}= zde8}x9Zi9VT~l7|%my(e@UC$Q9M%=e9@D8 zc^dm3LzTd`XD~EK1Bi4XvrehizyGkY1!}7hp5)7pR zaw=b-8LAmc?w8D?v5jw_Vb~l#f6J$b7d|(w#XF+fK(i*Ru*rPyv!CCXv!}|PXO_jn+b1Al6qg?OG0zH4o z1v{ie?9$9pJtpuoYUOL+wO*dER>{=6h2*O}K+;qsnX-sBD7)W~*CIADl;yoZ)u_ip z<|d2kwJDu?J)N{GVea(Lqd(6!WQ{aJKCE)k*8bPElMV3P)&q<4LV@M2{`HB{s>7d+9`x>AXh$87^VFK{4)msnm~T9#5EZIO-oBI4l_S-7?oReGh7Z)~>0eOF zZ%$I#6bCo6RonuAk&Uh;Iy64zs#iXBd5txZZA{rQPRqNmJ1ClQG2)uoXtOv)6Qm~xDXQ-u_q#qCE4=JE+GU__VD#*27;gjA z_ce@q3)#J?eTOo2T~1nvS#ZdKI=srd7EgFWgi&Sr;>s%)Bdo@1kA4|JmlwLwWp^BT z8Ey6X+Ii~AUpHm^-&(A!hP;7&*``fUW%_X|?8F`aod?4#>tl&^G!6lKg^f9zMk|?* zWL30;%QAv0qYQ1oy}bt zzD~0NvCQRko3xb(LaLwpKrizdF8|(q|F^_Dz13WMJ?lwB?gBSb^xC?1kZ}M@9W{x( zZA^Ywc;V3{4>ZIlkd_c#sLGJ0#xbiA0+@GzwA;74%NEqM8{>{BR<}O!t*ty(NT*af zU7c_kZyL7Y@`3~91{gz$&a}oO!;b3>cv$Vd06mmre3&$~k6EE9@|~|M!B$!yz~%u}gn;H)`1 zrOw#KHMxEjAC8y7<~sx6K{TSm#Un%YM4DasXA0nkCzkn#>d1UN2qOW#X7fErcvFIU z>bes(!F3|eY#$VDi!QEC0)3=-tZ<#CjaU@g^Z8Lf{A2ncfG~gj;lY)U%VRH05#DcL z4Ntb@w;#tfO&_bmlQ;V*xVzc=`+a2~SD0H#5h}1d*MIk^rvGLlOsm_`dKRY`B>I9& zO*p1qSWAnBS>BRZXj-016lGT`yH5Cx|Jx$sh(B5Lt^Nm}Alnyq76!IMiz@_DSc$Qu z-p?;6UF_W!dVaI5(FY4l2~Y(bTEquY8^c}2JtrX@YBb;R6}tHpoIUjF>({v#$I=H| zCM(#>>pLtHjea)#sv?p9U~ew=R0eY5otYENV2D@8#Yt)TLIH;SA^IC^tpVWFB6oOj z93Zn6*%x0nQ#?rhTymkGP-*DsGkSH10XB<83zM%2c@4)~_=sMe>yT&>wviUr!Z($x zX>#o!& z?{qmAkjl;5G=t4I^oGtotcFpV3 zZ-f35Hp_Z;C;U`gV9y?f0OU;<}^1m>V8_{mXefJ{10)o zHA}Oq*5elrYf{F>c*iVszm)n7ycYIO#FYo}+B?p44(@G7A})iIOf`!q5^}}mANZlf zkCGTGJ5S&<>5OwV3-40aMKq{GuP+hVThrYJ8zIWJ4-taWv{TF^hI+cK?0Be&A9t#~ z+fR=)V^veo^3*h+2Tf#1Pd}Fbr zyy;GfR*>UiGss~wdDCWYko#M&u4#HaQRFYL*CMLI9K#a5H`f#8&8fyvSo+-TX}+T(NFA`>GIY#+L0{*U2)`zurk z9*eG#sS_@5UC*esraHDQ7uIqHc~BEj@xhB&k6*%5n2%WZe=KJ^7a~E+l#^qcs{qtlTUWVeO-ERgiT4j?`C~H$I>3~Hcd4> zmNIUZedc~64v|V%)_G*T6xi73_OxxL)|kk`@i^Gwo4AlmqIaeX`7QJqz`IxVzK>93*>7j`@tkxK9R9pv2FRcR&HqU}tVPzF&^85Vojvfk)&xP@FLT@>OkGPKKy%nT5+Tk>i2IP;PGcPBc+gJkZq9ECZ5Q8 ziw((f|E;-m?~C0jm^3rb8pZ_#ti20)w-`2=VjG&-fr`+R4kJ?*IJj$HvnwjebICrWQOm% zwZGB!TDBZXW;s1tS01j)p;|Veu5q&Os0C#YFPbMC2}1`d&J86zK*hube^mirfR`3$ zr_daZUxSxH$wn_s4Hxwe!-K%t3V+O7ic}to+reW(jGA}gb*xyDQgDK)hTTg;I?t1J zK69E7@i9sw(9!+bFQn?OLSaz4u{s{l!ePXY1jS0^{{ruYvbH`~9d4yEuEv{h??tfM zVOHkZC1f{mZu3kGpI-XjH{^n?Th$X?hxi^j=)4=V(=c2R>jDy-fD|#6|1qXeREOeO# zO7^$&LZ|%}I2wB0X%Rg_!s?$^Kz*{dI33VCfJG*~4wW5t{AskllndzXKP^y8fyLwu zm}f*AtZ1tFH(2?^=xe|bAS5$czPP0h@UFg!($0|;>o6-6yS~=#x{Ba1)2x2sYA0WV zh1gCoERgM{<;DZub6lx0+D{K-ZkdagY`sA-*~||@O4gMxD`#k9iVZ3|Ph~v&{YH+1 zmtl)+fAU&Bq#}@OSy9kt)}5fiA?_aM07d_gv@Am;P(J#$dZL+Ss9weFXWZ2H49TcJ z%#|aZhQqMbRuXNS68XNCfEek7s5(ZnCb9?+k?Qog1DRxb%AdZA*~}c$+a~^B$PZdf z_Z6?$FFK3YA1jA<&{;HC*FkyVJkn7x$}7<-G%4-rj`K@m=#&wIe0**4o;;j12-cD&_! z?Q;68Bej)T(cgV^Pw&bd%e_Zxt<7SMth8Xl0-;Oe9w77M<+9bor8m01xP>*~5n>tf z>l+l;tR|Sfs;tVm(Fl43!QaoH17}}V@*jK7MhcLG(97HK-@l*AQoH1UDuxW=xtR)i zJ<^=1j!ag4K{V|i*m%(=wqtY>CrZz8*X2L?IyJ>7^BMs)su)4cP zkEzGy`n|vPftZGUB03epLGm^3wExGlx!nuY(QmJPq?`f;deCpEztW&~>%+sKb(F#M z*&cU69YMeLO>0r{a5%IBz9ZHSt|>IB8x$>_msr&*rJVs^hj(Epe4Swm>8+wOXt)A_ zv53Vu-_$3KVn5)i5-~3T@fXU=cV~*IDUiELMOuhFUgq6BL^|UpxQ6gEsG%w_oF^o7 z)P%s#VRzEdN!0t40s#{o;Xco=n{Pr3g*d<6<2=2=SFFYnofwxlF-dNQfUu@5N6z`)e)brb*!-SluPalj>S z^!`C1@DV?bojRf0z(lv`c=eqQlutgz=&T3lltm8^BIX^av)$Q|qqjJKdscu9(y8xi z98tUV)fuGgy$5WU#DcbSQknSxo)pl5<>KInPARt_XOu8RTZxE&EEXHsRZ+0SfmSKv zY1e#U;IG@P(khEj7-@kqYy>j#K&~|@ zHz7aM^vZ{s#D&E9Pmo9?7=G)Md*)93bn@++xQOu11kM4fcbrFW%dMltmanLs($&-C zYDIT$!Y8yZ_cMeO8+L#S+|m@AQ%&p5XOM9$mtSZUMJh7mZRNDu^(fXVh9YPjQhX({ zC4a3^=5*9-Jj-2N71RA|V|`3-ZuE5)PFmEYP(Vqt&ZnQTyiT~eZPb(Xv7|PJG^tQ= zCQ^YvY1ur1 zycVe@Aeerp`z3X+(6pgMFXblmGq;{cXMrrX6;lx5o;pUtC--O>?dh znDTryuzdfrqljLE<6RiMJ1<|%Nlr!758SguG*A|?Nb<9~u8RPiZVDTqZX!FbGBEvws`BqYwF1QF!n)adC`v82x8<_ku#A9;Isvw4okt#o>hIgR)RN$jun$1(tOB zUOKECxw&$16$BJM*PD~);qGi*UyBNiwGA~x{OF3%7q5$!Z0q1c4cNmF774pENeea zi_eVlvcy!l+=P+N1IMvKN@sPS>6p1seY*}-14MoY`yDXc_uYY0ioVjJFLt7|;b+$J zAFQFY4`UfgH#j47w*^dpmjpZV4nfujFLOTr6hp zHr9+uP#HFUnK&mHU*auzVP`ifvBiaf%6FSqJYAHZbnj3~Pe6FL7w2f{#d5A-wwY6$ z<&1wX{tl8Wwa()_*kF83bKu%hY`YTg*S4iLgt#De@`$b)nfuFf7Ff0AiahsmnAoiM zaDRIpzW^UIXIxn64%lHhP(6z8igIrXipARD*h>HF*K3uh2VnjfD{u^|yksG!I_PVu z2_0K!y3-ZFSm<2|z1YfQ?czW4{7SHcxYDk`hFZ|Ax^L)0S%&-(_p!;R3LB$w6Cr%m z8_1`Z*y>_~!%_WZ;wMVhT7DImHo*;OnxE%c?_!tXNmNFI)2*Fie4!g)2Nq_PK3){9 zsh$UvTSY9$U+N}IX?l>jG<*QZxWqoIX|8c?3EA-k95^Xxdc$--#2m*i<)Q|5^_E*a zFY@Enhs5xPdoCvEY@Y~5&Pj?VpiYG zA1ECv9w;7I#MlO67VKkI{EHp*3eOjB_wn;G>!`k`|2QV$>W~-btClgJNwV*}Ydp^u zP0OunZ#1zM)=M9mk%{bL+WQQZ&Nx6(+jbPhW=1vbQpq%PW*|IcEGOvV@Nd(1Ilmop zoj0WE!sw{0o%zC&DqpsZzF7>#!9O6$rn2ugNwREst#^XU6Mj?Wg!p4YcI@34(W76Y zYj8}Pot^n0wk|y?-Igj{V!)^1S}sgKr~S7}F9WoTxx|p(P~}!k<526Ii2I8gZh6!( zk#^riAPSHX?x}@#KPW~>TK`0^5GZ=R-;-}Sx09>oU>`ljk%RK6gP?U=L$Uc!73Wgw zv>%_)*e3~rN{b`dK^a*o9qiAA0#O~8SVJ$RpS@M-mG!#iQ<|nD|5b})H1m~zEYnwC z9QNHffXE8>2|1E6jTAyO$xzcWRqUwjKU2c2GlG`tV(RVZN|M_?eCjBG8-1Yo)5CLX zN&8V@#^I0dJwiZ1~Bs9teb?lz-E08u`uxS}W6P!!38_3Y4sf?!a*5vY7^*g7=Xq^MKUKvCeB_^nA5^WW1MUxwzQLBn{+3_*kp`ReY=S_r> zR(vGZ0JuQ0YS>;Sy3%I|_o5@ICKZGNEE)k&z|m&$E0 zr)lb~TY0atN50k}$Ku#D_QgV3`ST`c2!}9<7in9#n~lDm#g)qOay;?}`+wc~d%RmG z!*@Drel?J+xO?0(1V8)!m6UxiFisU)MGDN5t)*lB{JfAYNh$k{Y&tuOygGmJQ$wt$ zV2wtD!0Df1()4NY_>IWi_E4+Y86s(n!kEpo$ONPqSiNobQf`gfvHq#1Bt|d}FxxN3 zV5dpEldl-y4C4y&q&VVK!c&6adk|pjeJJ?Glc`1zHgV*v)O68gMZ=N9bq~)OJdOv2 zL0}scR3O17Ah_a%XB7&-8%;2(Vha#;QDu+ZatViMzwm6oil|ZXVdc~_@`*&A%^6DB zizwy3c8L>wBV1E!RP#snu3{6TQ`RKEF5MDrm(9W*hCc6t!}(aRui7ZqpvE38KdA9P zmgln3$+HaE%9`3Ugw`A5KOIhwFU5RtY$S<-G&%ZYi)aB=wnH5rb-Sp`e_APC+4~xE zf~Ta26`Z6M!xFR5oE!;AH`ypOm;JFazvqT))YW>|Kfe1Oc@)eRs`K&7pA#s`61X3d zOz9%Lp7V!(H$V^&r(wlpHjOHBs^V7at{9^E3RQk zp?IzP6`)P74jgD#$3=>@9fie{OM?|L{dzy&RBVo)gXZ6jG=r=}fWZD}z8UYejWIKt zus{x1jx?wFSu>URuZsk~NgOQ~+5TAb+%GZ`b_2vD6dcRx+*fk zC9FXCf`vtl+m>#^eYC0reUCeZT{jpZWco6<^3GpqszsY-A=`cdBk$~t&=V(1i%lVnfw9J3Tk&Z- z&&T?}(+fUmTc}i=#R-V{Ce74wMT73KX~sR&!IjD#DsfPp^yI1($LSHjqQ)atPVTKY`=@$tBEG zZ`*J%VQCnhFyp#+QY0A_B%m1Maa-DX9fhK;$L*h#k7#rv*}7V9syf4ssdO@V_X zg9hqM6syzE&Z9fQK)c+J`!%A{qDVSx(w-w$OOc5YRZ&(5N}|OzS-xrG$BaUzaKNd2 zO6fre^<571r{9cqbIjt4!IwQsQp7VWIXNI{nkIEaN>4-k(5Q1P(_+SzNqXI`5v_&2 z3YX3#&ppeSUmq9MsDP(CZYdb44)0`(*_>cKzi_Xxo88lV?CC1fn9jivnxXvZ_4-bJ z8Y6R25$7Lr*dzTt8sK_MWl%i4*r#^KY3pd*A+k`3@%8@ec2NP5`E*2Toe=)V2NiK) zHAZBpKX?1^#SWQ=GQ1sHd1_*ZHcROj9mOaT4ZsC@62*lflteLE<3AS&&A1F^kk0zj+(I@mWJB*0iC)#S)@;@mAW*Zdg0bF_STB zsdLryK8RX)=`-l#qG}4C^YEWqtJ+m9x$Ui% zaC6esuIlz){Ag`**afXIGfHTy=#NMD{H`YYSo~w*wng?~DzT2z5&u|Dml~m7+1!;7 z;yPZaLp>ZqAYEmpeg7;;2&?ttXj|^!5ZWYJk5bS-$0ztq=;d~e*BL?KW(+$(iFFjQrK280d1{3C8vN&ZU(Zh)aqt0vZyZJNegYrh9zvHO|BV~y2tA(%3<{+_S0ef9(V$vT|Fyn6ZY%(bbDA?k>5*n=EsC1OZ8WSMaHGCwd$8ypE#R?*Qza%p z5dLm{@S4&IaH^Cs^eM~Oc!t*EfL+yE+QB3Cq2|({54YoO)N>MAyk~eR&=@2!{QKOG z3L7_iPWj6n{iRYp(a84ocA*gSy#|56n$D4h@BB)ZO{K0E={6LfVeZm6Vp*Kj=NCFW zQIRE*8rDY9J0$jxdIJ{YTRnmOU=CSF?w1A=V7rM29IW-~#1%sJ;Q?k10ij;G^fk}X z{p6>kGO?GahoLQgYvx2Sy0HIc2~t>p;;04!3`TNV;{@V%w`QIf5}X8Zi8krj@BjzP z4gayQf@6_LWwUyO>BB2*3TGlk7$~n@Dq#;~i`W1^aOA1&?g_mEom~{&{+SY%aZcJ4 zkUiIaIVW~ho&`CtL>E0$0&|~w3yiEsQbtikEhjcAHf!Tl8cg3Pv>Ln=uG;_8s+j0K zPK`=X1$`onXRZB`p>E{D(>hT;8*_=;Eo!AE%Wva;%%amX=%4dgz6Vb>7!*5tdU(7$ zJ6-x4v%cki_n#3`@cf$}N5V0fH)EpG44>?)D5dGqN}% zbS{X<6@t|C?+z;R${0OC%ix;LV`T*U;&|!iF;*^0<;(xWI7u~A#V-7l*p*EfQxaV; zUmekcJ$_vaOY?(5^7}k5wl#jCu($JTK)E|r2P{LEzBVvHr2n_e{uU@`BysjRfHepF z_1EAi`TP17F2coH(qMlAi-W$bohPptrW`{Zd<(>X=V3}ypHt`Epf$Jq)RV^&HO?}t zy}OaGq4l>~5&W(j8g6MTYpF^M?NFOHu>7^igR>aPCC}kq{J8l(cN92g=MU|Z9cOfk zMl+l=4S6SXKnJd+F}+?zYY&YP%tc$I~yDjtS$+ejO# zb+mnyWu0v!OaxS9E$+R>{=o=HB`%>aCGd8@2h*o^=c>D1pmBr zl%|0$-dd&myF~G*f_kdj!Vj)rp@#&?I(;H-G*UQd4QIvpN#+aRmxZhse_cxo3a_kI z=Hk^ta=pdoVSn)vm2h2;g*>{C5cbF1;`|*jrh40)&?Y zO=Yj~T{3?xx2XRad0Q!P!V*T;_{Z|Sa}QIJ_iYj39-lzowT10KBW0-)8;`*JRR2H? zLV4)=pWHB#Fb~pa!d|Z-Iq>VWd_!fx=O4?~8!glctTmWW@=}ZtN;(Zvf*o`usebW@ zmnMEWE$LfiuLH}n?nM`@uqxgPXr)}{>s3HM0HRkkFT^yQSb`pKVL26EB+qFzu(!Ty zJJGXIyf&8aVI^}g=+QwuCubhj%d*ly>N#uwOFjG6ufC(^H`DybBC@$M*6?fAlVjcI zIUag+Gz|2z`Qj?q0dM&G;iP?2?=*FNr-T!09L~nPFx@Q#h&h89u7Po(jugE(-|;}` zbpsD$*5{{T;?h4Bb-?pyyxF4h$pn&^e`4Q=Y;OAsN1_^Lbr;~=e+4po)c|*f{NXj* z7GI$p?8<1X-uq&!Y^zOK=5=O6=P6+9bfzAVjqL?WZsY#3ybp#LO?>IRR$ZG1ylJ6W zJ^XDKOSMUwm+b_z1vH7)1>7)mrWtYts&2vuycm~M+yYAiXY2p5bU*RR4i;9nG2g!` zqgjt97k49X!pW9`)xfRfJEkbA0eEwY@a?s5MiXYff1C?zJ&>-JuU|C`XcRB20F5@AR@_?af1xGV_AZf>=Yn`w~7s z;AD=i$NQC)DnGn(#{8|1X*}x;1GJ=Bqudkvt&;#knT({P6X&a+{+*%a)6fmbs@qAk zjC)k=#rvV~8B|IVPzC1eq=m8|1&9f}8@{3VYK;VacOf0ecxb=|VNz zd7(WJO5ZUs5PCJbZN3k+ra0LA3I#QDV=;h>VcN91DSP6alnn{v_GT&m7J`b9`L7`@ z;nhKsei`M>vhOf|XiJ#-(}L$L9!fN83Skla%O{~P{!kG4LD#LqK2BTxz5?F+*=piF zvf$)MJ;l_mX{l?W*}eK}s$RKPyN9a_(bP!=dw3lVxmN>wbe_&yvL zFF`225B+oCKM}TCufv)-FtKs#^&@rCL+ss~eDb#yM12H=JVf`)bvcgb2DTduj>YcS zt8hw+JJ)L$@)#(&_GgdQnC(Dgxv7${&ZBLP!0FDe0Pl;R1ZuOs{+b@0Qg-kv?HK~A zf+y2h&N{K=`6tOgv)uAt&4RaRYW)aPUCRWzp~PzJDRx4HrcQ;0&UYOzkMcI}Nkfw* z80yFgbO^+$#4j0Yd3#N$Ch>fb9M)rV6fY!E3Hxw<Dv$PM(lIg8T}lAam}YMDt2dopVoMO>a;#g6WJCc z6oA=gJ+P*lb95lziCm@zzwsLNqrRIB{}kWEu*n2WutYTU1nNB?!_c6*Ubl$tJAo-W z<0qjxr&nN5j(ncO-*CLW!kS8V9Py6*$0Ao*4a|}}$#H*nmZReKpv5hZ&=H^<|_JqRSlHb2o@@J)W}lTxjd z!XdEbAAA3Udi_{0qjXng(PdNp_4YKLINyOeX z3;$;IfctrC177a6Pm41*=QDS!>_X2z4WTAmW&Vwu-nC$y3;)NWVD&6?qV<0CbrGr3 zWUi1iex()B`Hw$1?p5fo{+v+?tOLEBp=4{pAitw$H)gf(X}Sh}+ZRK1De(6^ zqJafO{S%`b;7u$yuoxs&rg{eF{rs{IN8)wO;IJr?5+f#X*Ma(V#nnM`6bdg#20HVq zF%&wn^dLwt5JH~&`0BU7@UC1MkBlhL}UPoMcCZ8l>CRn6`f{?puAV(PhLBbET#}Xv$b(%1e3o5Xs|fTqltKUhw(Oo8hsXN9!^BPeDGHKOS@jIC8Iy)-t;ofLdm z0&xA%bcF~`OpVw|ekZ%M{|KF%~>o(;f5NWes7%$f}8_2O&4?>IkYWt3-PE? zY`DjTMN=r>Yp<9b=-8iGX=>EMX5yW$bH~{DNrhVx+~r75Yz-8ZOT~~KJK^Unqch4} zmD3dhj(ddLcmpHdh=jd_Z##qd8>m|th>L7?P&&zXe=s6EFDcNaV^eqN@iLl<#vaZY zYptaVOVwsz+VS195ApJOo&@J-JAlW#uk2gNp;}5DtI{1CdkoIHl`hD@g z($qw1L;h*xIYU3)Hd?3zDW{WePQQ{e2nJ(Uua$877T?|0}a%cD|zyy3Iitg@T)r@dA0m#u{ijDk=42I6ins{VV8yG`HFXw4&j|O@i%jy+8QQ z=OZk8+9@-J}WO=8M+7l zL;v^)Qx8vl)~dBl^W8>I;ovaoy+IKvC1R$g+THG7CH^PQfc`3L(W;lQbdWBU;D}`;_Z_ zV`U|?*Pm7`HCDA|8b?~*!{EJnJ@F1a)zE*F0MGdD8%a}2BT(Cp`T^cIr^>sT6MXN? z8E=zp*6#l_!lWMS8NB^!C~&VcAphYBQw8D~$mrL{sv@Zp0-{=O0y=G{31B%mT3!Tf zkLH@pHu1V$A0T?q&wGC zD%*}%=8CF9W-Hzjd_LS+r#&{-Gj!ao*qzDMo}d?kt?8;i@SCt1E*>hcLP|b{>7U`2 zkL|S8lIn$3Qi*RqN@lK;KsfVnMQl%#^nDfu2CfQ4n$|9vHxI z`JZJ*!Ef;`2b*Z{+c9w;PJgIhqSm+b9PG%jdzX{Hesq?U$M??nW4{!EmvM=c0aXXi=l45TSJoW&a(NWB6tw~0b!4CI>4+(1E&fg z0AK6dRU^Sp6`oy!+uTEU+A_tYCv&M;!9TLIfrV6u%(Zcqfpg2bw}6eUC>g<8IM61f znpu|z_OwQd(VtGx-i9sD5Q^4jrfY=91Qkv-r~yL$!had~mgBsSg-A2=6yRyvR&}-{ zu0V~+LE~loutYoFKl!|G_-A4Z0$f(t^!}?{Mi;#|=f2*=Us+)z>&m}{=1YZsVw0au z{EV`p2eZ+U5|1#8lY#E-;V<7+Yt`xG6w%Dqe zAO#oiMur1=Ya)UphB2=o`#aEFCYXoY1->L}Y{yhT8g{9L7YQ=g>DS{Ic~=8@8K8l_ zpwfHff+{t#FsdK}3^EE3(hGqZ z(cPPiW)zMnJ|j1J(9tdKuKD-Ue*&xTy*oQYNy2$%Fr@KmfliOMWv?XbsXp%+!;R$! z>vhM7iHQ2WeJCxiwj%gujY=Y8luj(<2R&9+j_J(hH=*t`!b2`NV$;PAUgs;Bo48 zhj+m?NJI7)&$H9D^H zcg8l931xs+`9632tBd(RlD<2f%K!ggQ4~=`WE?um-Vws7yzQdQ%wuNn%#L$HQo>1A zvXUJ-viGr%5hwFl*_`Zi%yT&B^u0g7-=AEra~=2n8qeqB`55%8wNAAKZCe66Nt9b3 zkJ>j3H2@!eE^U9i4f4_=q(&za_GD!*cEqiX+ogVd9Q+)2zXKUJ?UEIg;nHa9RegRr z^~tPGX6jmsY}i``(BLoP)#6JcwWW0{KC`*qazMTEA8q=^IRPW)ffzur6^e0)1?Pb_GF&UING^{`DIOg>3Lw!vX7}008DRQ%xNq1h%&Gv^vQhMzS+Y{i9#}GFHdbW z?p@M5(7AMDD;SAqJ`M&xT9=|<87kG{tC$=6a;Q@;p_*s+PxWsWFF@2fj|Dh0j4g}= zr;gvD_uA7OM~6Y5lYf0ehXijvKf@KrP+Ch7Z(F=HE;pkmHxHl)2voCKWjWr*$&fp2 z=5BtCV54K3X1#xOub9f&xAZk|+?xjGhHzH`$}9||8qg+5)W}^jx-w5fS){wvpLUS zWk*kN*^4b|dgxHx>#OL>uY?-nY|7o!oeez=R-|ZAV5GwDq%G_57V94X=(ojDv;QN6 zX^=XFsS-8guPZ@q`JN;B+l!iG@b}H-5 z9|k_MD%;Opz>sibkSfluhr|P&%OS9IU;q}mT6ZrXLSkR$n%t3GgH6{BDLfCF1Oo5E z?w1X9f4*d7z6ogd!XZCpNWwX}fD?Xby|MY9^#!Z1*fSyI5o%`A2al?Siy=CMkCbw| z;CDwlSn5tDSJ?s^5cX6UKJ$P zHdJh5L)_PtI2c=dgeY|1rE_g{@|07YOb+x??PvHd*RjTgD$MisWZs6meui#Ns31~- zE2|c`vbZwVNQX(f!QVrjjJO5fzUm^e+@!?U=Dxznvp&QYsSL9@U;u(+Ihye7`7bp8 z=TD}fEAHI_s$`rv1glT^{QhT3eXl&5;5DSt0J;kHz~GEcEN(~UHzohA$9EX`qZZ<~ zDrLIhldA8Wp*{nBiTPHJg!zpJ4^Mw+oejg2i(2>V`Evts15M(xp*U@ z$>QGxvs+g+1!v^qAK*dyG@pW(?vq1opNrH0lljAqogswoLZ!n;m>CHo>BKtHSu6sP zNm;3{g+aND)2s9)>?{Fswa6h`^pVQn7wDrU+GASrT~wyQ`zC*@ZX)im{7jhHNnp6E z&=xf;|9pRq6ngvy0bUV@gr!>h^fHd3Q&1#H&(`|)tJ+y-Kv}<44(si}XC>cirBLAhRumfg1uy)6Il(g9+(73gs}V)^u;w z2PvnR+BAU(jtzD77ZqP@ms+E0VbW|IMjVfFZl!k!=gym$pBTM{ z_(I+uYekfFfE`dLzf_1fNRzd4Y6C*ga)XZQma z9w}~o$dkONXz1S!;{8tl&@(`cxy04}YSuN8U58o36cQZ>?ZNKcUQ$tGKGRts?K1g; z-b)HK8~aBFUA<}}gAyc}+K3TUEn@A1im?4a1-3ftZksaAYZPEu`AS|swH!n2vg%hDF%agu3oXbyG+R`aqOI|w*+2B(n)x`mrM3Qp`|LsCP zMP;%L0gi+@juNx^Np}10I*7>WFR$6b%UVe1i?2kYY6O8Se*FkyD4Hs{SP*sR+=_3? zkw^&^dXPID6aPJunQLBFdGKDHryiGj$GXVZUdG3X%0s$I+Pi2u$uMpn5YQhle~o~% z7j-B7hpI9s>(Mk1Rtn)+@L%B!O*h&v}Mq|Uhele%8g#wsPg0Q*E2~uZAli8 za*cRWsPV9z<%G+wLrMMLe{@U9ke{F_-=%o;CBPH{#1P7UtZ==_?t?d8Xys&7)D_$I z95=<x2HXiClVivsA}PYqpZK>@mM3+|{vq~cykPz3+_!uHTmQZcJ?uYU7D~YH zAj{kVqndIP|9-uT_lb#FakN#);(HBs>xEbiDT1IqqFTB_#=!=d4wojN53hO_Z+Ipq zO5Ck5t}N5EUleC@$Z^$(5Dw1dk!%F|{1R8+YS+S)B|#Ig<~y?>=fi=|z2ZO+ ziGvv|G8!d!HBIIh7uQHgd^SRmo%;dc))>p>=1(f_vO>n}0vbjSrK*|Sf&q&|009E- ztEha^qm?ee9Q^%qBUCap_VHNIOGC(H0m3@cTJkrQV+ zQUm5YTgs-kHO&LZ$mS_GzMqeZD9Z|&3s4pq2MSO|BRq|B(>~BDMIe*!NS2s1C;XQb zw6$RmB^n&%x&W za$|)L@1WkC>`K()L*eTP^NfaVRgR?55?iPapEC=b6KlI^_=nB6&}k@Os5cbF%hN4a zTbg~B5HVPv{)>FRisvBV&j#|&qX`SImE1yDq6jy>%r)QeOI#H=sb9_CZ0fZ_+^g)V z^LfHKbjvNJkN@ia!_nB~@lgxOo|NgwSvVWEd=A*FFI0a2m9RDf*w<=+NgSJ}v?=7!(2e-`}u_?5+UGZx^bSv~4W zl!u6`rOkd)4L5!DpH;yK-Q_t^Org;Yl|R38g*zBoF@K1%xyb($%XbXW3$}2F zz)bdnelQ61QrTo(Vo5$QD`IOamq0V4oP@S#D3V<|f!Id>9q3;fJ_rfdaGUy%j;2e| zj6|=#Uh1I^pieD(bVHnheC5|Iaf4ZW^~!wS{B-oQ#ImYNtqa`zu|L%j*d^2V8dm-F z>nj^%I47mqEElSML3=QJmG|-T zQ-uDC*KRyxd%tjI)@xOJR*l>QkM@vy`*Ykh0ylsGnJ zXDtHZK|@YryxJLMJ|#DNSY_p^ML<-KO)pbK*|YuV-|;yaM-c2xroy>}TdqfwJSVh1&GAzKBJk*TCS`M?am%!5Fne&ZC9xFFT;#3RT^c8xmsn zy1NB@NPV)1zB|}OS;PaGa#bS(fOFews415~H(ye_6MjFQ=D`faBF6=QRkACKARvJQ zik^ZTRa1>=h(6~_CWD4R6FADXOp#^ZZZnhpnqc5J zOT6~ePu~00%m!3eoPT17yWas-ve4Wp`Cee}2nnhGjEwJfmf{jeK2Vh8Qcx8<1CDUv%EiI^-_YE>X_hU5A`$FT^n^K*;ZS%!{ zDC=pZ)<*dDY5{ri{*E43?Q$T&%L>7)htf>%bHfXCTkHc(-i1p)pSRs|7Xt?hpio8r zIXo*Xho~)sT^cZ21FUOeeuJ({PVtEx_ts{y#>!dj&7VV)EK{2iJLMGgyFCHrr7#_Y zyBVxC1>FyNi{@NRpy<>opD^%wsnb0}uGzh;>sy=XB|JD1lvYRbH-UOvHJ8ilFxJ1& zEy~KmSrH>xzATIMm;{|Yp8lJrCCrUYE&7h5IQG((`lcOgQU3D>MVfkQ~duB zwBMjP}|rLGU1|+$}Y@NWFKH z{Seh5Jbfm=BP7nmsh{|ZNX$!O&}eG1SKy(I1rd3(rv*RS0^fUq-HC(j`vka751vxk zimY?Abb26amytQXPw{Nrl%jy&NR?aYTMyV!OLZu z`-%`h+zC1?f`QCrE<<`||L(T9l-B+-FCagCbl&=VJycpznZI!r(BCM$Q3L0(C`zuV zlyQ#)d(zHt!r8v~3j}uGMNAb`Ht?uu&e$Ef4v<~?(vqgjsyEqYC62p&EEXd{2Abn8v`Y4+?q(N4#hE$iN(C{F_cTO^}ZghWuEmj(KX3F z-EV^U&_8w&f)Z(8%;cOug}fAuJW>ZB&<&_bkBy~%-Axs9^G3gsdTOf=s&9;0=Tc;+ z@!ip_ zS^t(7yQveHo{+8t~i2Buj4@j5T&XXC&_ULJO9#jP{?3#BD)iK?L1*1qM)lt~0cIl?|04 z^(=9EC8rb3H~`$Pms6K!QrW12v?!tpP2bDnJ8-!@{dHw($83%4=r~6yCOeiNZgBGEfIYbjYAiSIYJ0D=TqJfz6$1B7Oqt>97CM$%IqhXv!w&rjP?1 z(%sZz)EPGsRI@WSU?E)hqIlIZu47`n19QS{=UEr5C?N(xlF~wEvFpMPjs4iQ!(EB9 z`-$wd?g6R@IiIi{RSy`qUP1pAfSj5p<*`l}34s~?=j6lsPEHXJkH6)@iDGFle6EVW zW`zT`;sRlmgn&tal+lpgy-!EK4n8;mME@HVeJLNO?pGFvFmQAxLO=&`l+^aULTgi> zesRo;e)Nf>dhF_=Q|exFPW~5K8o*6hl7=h5z>&#x*215+-g0ewlJlCf9TKh;JZ+?7 zOBb%wL1ZceWKJF0rGo&Dm3tk>9Re;TW=0Q>Lx7mv4?-S(p1^5&_!gl<5+zqoV^SH( z3a8mW1*f!icT6U%p`?R&Ryt0HwjH=_>OZ%Nrr6JHC z!W`y^KHGD>vRq2T#vX)isO0Vkl2YsY?I1^#Z%HN zDrh>V+7x-BcKR}wc_#FOR*I2JiFHqq&*G}Qt~^suh-qI?K3_yg zhDsxMe{$*aVmv6k)KY|#RLC-RM`&q?{!vv@1(?Xbpa<55p|_h;6y{i>R8=o9;^L@l z_HxlP`6fTrYU!JzDbF=>a`ma{Z$oq1o~YK!o()JLIyC6z`#sEmRc+5+v6#kn8s$hy zjeUsE`#VOtI;1hX{WQy-1LNgQ&n=J@RQC9R@?pUXMwEVh-9;UJ5=DS3=VrW{v6T!i z@NdqK?ZOCzck$FvscjYJLdy$1?ku`Ed4xXT7Q0xEu3?zb>3H(!65eH^?T$wdw2$<% znx$$eO7+4!9ah9FzvpQ*wL;AXrbw_bj#GJTq1ra2D#-ZjF&Y8V?Xn=y16$)Bsar#c zHd@~X8eKOjBuR6QIXGma-FRO#+AC1k|I+{@y=An-ESaNnQ(|&r5^jwj%?nGSEcF5m zyyt4V{Z%g-D@md)W@cjsq2)N)p(K!y7q2n%33*?P!z zC2v+>))Vj-NC*m3^d*TxyJn9hKUTH1hc3=)K=f%?805f>3lOo>YH9GN!?!a?*`J-9 z4^sgtq1hM#G9m-2+)TT7&Zh>r_jztsg`3?7G3FhusN~eD8jh~>hgKZv9E=02Pe${9 zku6d47htw6}7`^YU?C~9Mi#vBq+znl~6=GS!w z7}z@HbxPX9LHG7i>uk18cWV8GE8Yue9=3B*_p-F-`RozBXfe?69LEjTE1ktSjyMF_ z6#w-~LqI#)<|SCo33qBXl`OU{^UMFh+v^CZdG+J}V{r&II;k`jJvHyvcsBgovJ+pT zJS<1Mh|VF(Y2;r%GQYnUEpP*{6v8YA$1HV5etK0>|Bo(Y&?ut{u?RSa909!vLpJGU zn?VX=5yWL9Ci}O}*jwbaz_ZtZ zdsK-tU>Y8!08{ejUA(Z@Z4FEjM`6&iLDg#3C$**f`Iw(V?@n>V^if9H9564-MbInl zOJM*fE)}_rWh(_{KB2COzwA=w0!?uw^JB6YsJ;mXa{3uH+te$szG2N^Rxkd12cSfm zv7jc=MjZ|gZ@Y}UOlGbiLvt{_X76SjGHCTT(n=d~yIZ ze^Hf`$8AK!j=a%n$2*8issd0)GqY6oha^xX0(2S-BZkLekJ${ zFhJS^1_DA9A{5VY_Jm@9Tn_2p6;5j2A+$f= zXiKH_$#uu09bXb3X6?F17yt70G9yx0FqesKsy;RqHhyaxcCCDP-=oS_5(9&VR5HB8 z6HwbSG^Si)m=sOPtxntMPbl`0XuE*gnpO&2ux zM;N#aCPT!31}tI9B0hNq?uTU>M$~D*Qz_UL4e25m!?rutlgCMj<9+XlA@Heddxn}B zAO3dQ_gco=G-VI80`>f%9%VRf(Uj;*J-Wtk-}Gxea&^6v|y&=wi=8g0VW*)5Wzk|FC1!=lrjSM`vmn zjR~sCVd(Hbx@uBYR9o`cAq6=YdPFsl?N=y6Fmf;fsY_OeGlwntC!lt8;^A7|1T6KD z@@#ak5~X(SX3Brro6L@FND{_5Lp6>tTlT<%OxIHm4>xKrGly2V#t z+##K+ajwt4#9GGQy3$T0v32GHR7F;IsIuoBTHG6P6H!uA&+JmxoW5LZlxoeF!|zTW)qTMt zy_`5ho{W8QEWNoaH8$F6phNgoC75JE&%~f|A7DVSg%6e9s$~iG87l3bVG<#b(ME@y zA%!2sEGC}+!E!_Lp0K;niHE~M_(B)OQbS;XKZz9W3B!UMpp>_6!4EGi<6#yLkTLYjt(eHv%>< zxmPF>^KZt}Vu$o|rQHd)wVxt{pja8o)#G+l`%Z}Qv)IPTP8##g6*BHnK?qO(6NQIf zD242l@78DEKGDiSCXjNyd%5?-tasy}U+3j8OHU1Zyo)qG_5<_D@r+&x5!=?A@E8Q_ zA6+oB^?S$#VE&BIb@=w@xiDNN@l)c>f+k=x2PXZ`946n;nfmo^uy2yi8!-7b_Tuq6 zI@jpNuc7k3zs<)bJnG7*1r$mA!b;bfmV2EKVw|Ks!t)AtV!^03cEX7zxJ6FKYO)&yN#UaM@xt2xtBkMSLBBoQoepTw2LO6)hAo2z=J4o^>#EL9({2q8)p77Cys=YV9ut4HX zZ`BCZ;pa=4+ljkoMM9>q!Oig8;idr8HD!cCH|A1gcjh4J;x0deDz zJEQ1Nd;1!qKP|_c&@!1FTKBSMz*7Xk2tMeLqxDWXP zDPJJn8qXyLYY5SWTLYt0$mC60&Mn_VH{xHQ6<(L1F;%rw{v*Bj<5iBEKoC!WPL`Ir z6#C1J5lqiX8C$x5t_{3Ba~Io8Ttf6(Ku1BR{~3h!_3=wE_Q=$Cekmv>dF?`UXXVDfPw<+h_STc20B0Lim%TL&^QiS-cu?iYgk@I8 z76I&#=AN1SInuYF6v=Nof}&{Nt&_{qeXH?A8iE?M7OuFjM+riy!|u{b@@SLGxa7R? z$D~_nLLH1gjC=w{qv%X~GMwWwIX>-ucHGuUumZJC)^Mos9Ym-DloJYw?25Oqh5j$D zqQei&{>i7H*S-9O5jfEy%5C6e_Nh#h@a^^_kCxF_4AB@3xbz1m3ZFey7A;hf7W(um{@S`vexk zR_5~Ah1y5c!5A$&^9U1nC|hJeI}{ZoFVn+(L;a{CP#}vNbAa07bMga6_8@?>hVZo4 zjdtt#ef*V*t?zU^{gSb#0KWQKg2uJr`9B1&`u%!d?;LQTL&X8QM-g0%Vyq=_YbIYx z=)Ps!YiDVMiJkqYqU}EUzgfxKE$48x;cPu0Vw1a{v}|8^prYQZ(m|0JUJMD7cLwZU z`UY5a9%75_Qcppk`>v_DVgS3tD1WJ!4odh(he`&D(Tr1>GvRlXH>_6k5)e`A~aIfwfsV=Pd&QZ#BG`hwBKNMkV z`Xbi?y_$$G_0OHz;-c7 zukSF#yYdANd!9g!hazY^gynjk@q-+Swie>b!i`$q!Pv3o^mOvDpfx>XK(r9+o;u04`IwjpMwR(NkCx6_Z6scpV( z_eiB}{Gmia`C^`5P;stTl1q~I6?PtXGE^9`Et z=w~4NoFuR=mS-F=W~tI|sIu`H3wjwxo7A`#diIEvxu`DFOA|*&(Q!{U0(F@d{qkkLa{nNH&JNT;bA!?1edq#FtQKe=Y zD#2}B$Y|QWDxloKNsC3)-{|@Su-h-=ta60z9ec_)#>ekfHJ=wV*%c$3qBP0$hy9c)^IV)k@&dqG)Ruw~m0U zO{pvr8|(i2N4GXUc_*D3UQsZ*pYR{;VBO@Vu$D8=vnbXuN`OWx)-VTV@1@+qQsA>0 zh^rSi?~YgUMP7a&+(@pHi+B3D+_=$2wk{aZ?P6l&*#V3zWIQO7UWK>P*4#dv=PngK zKj#FRY)haf@AAQa&x2wHR-fE&8_R8Frk|zG*B*p{+J0@my2=(vIY2^z{WOZM%I>a* z)ZB>ecv5ulb9Tk-AY=?R+U6R^UzG&_Ld5|TWCLN(PIxe#st%B>3&Cefz{AxRGhzvy z#<2MA7_C;ETI^(OYowB5fNtXh2cq-dO4y%zZQqLPfq%^Uw*ZM%v*Rn=(sUr;WR+uf zEDG#k#zUhx#J-6m)dJw=vhkT&IIZ0W?cUojQ#8Zu7CQBUeT(Q&CHchvC}TGYFa6Kk zk_WN)ZTJH*Zm1sEdQ3f4iCOFWc+fCfKuA6;>T%3pLu-}?SoMY@ip0?t?ehHqVN%mu z4Hi4@TH}Dg^d|6`5cd3FU2r8In~z4er-xXu4fh;uLFh^r=m%>=ter#-GVBRO zOeCj44P-+IUm;eQx`CfGhxn4;`54hBW;bj>Q?n0~8ym)=;?j9cUV~TpKucimzy8os z%r<|3$?{&uG@E4q`S_K*$Z@JhDrGqK#r?edZ#g@7dPC`GbisRxS_r*`%KtP%diJ7a z&o#dBlY<=hAX{OsoXRuVXTX$G*Yyw;dHQr%roIx93@Ll1(A29I?zCSfHFmzl9Uq(x z`XNs2qri2}Um%FW8bWlv^_=(kNofiiJ|q4{0s6~@Q|i$mzh=8a|MSx-266|U1;{f{ml z9U~Uftw$X%K&a4^KN*qqi?Zo1@v`eNynPzF0f3I>gO>z!Dbp5fUN86Jy|=~%COk2( za6KXM0M#us6{%u7&F7i~IDPc$hJa_j574@9%=|7`nCY>SsS)I&v@cH z;yulE4@BYkM3U)|iFOoTLS^}Yh0D~whHM?8c8t0#Z(3yRdXfPAJIYs6YOe>ilAWFq18J7NSnvlly_zz2sEB64|bI95(aZNb1=*N5b*8P-q8BhM}tpJqy8_P-}0 z9-F;~+lf~PwxecLbCbLfGEjmQ>ZpX2ta?nK(NZaI#rwg4hP>;=x#Fgq~Vg-x%O~tfLW%{%ppM!Wvk}; zYYy`X{?v$+m`Y8}c!qvU(l@hc+SIb9Elp8wbT&y-|O+C zIR7L?oEf+$a1Q?gVba{0cw^IqgAQ(KWCwgj)Mz10l`Jm45>9Gb;iSFFtupE^+c8X;pTz9UO zy$0<4H z->xgtXXfMjwdv6>GlJYxa&GRMQRhNw#B&b-jv5*Z!puvKqwel#c87NlN#~b1RnG#41tO$9V?{`jKwK29ZFWpENdae5m$qB zQHl&zwJ+`myg_h5i&s?xp$l^$eKm9A|DVDY*w1Yr7xo$v)X-Qw z_{l6|Twd#&Qskb@+Ls3Cj|)%x4?dpz19WSTFqXmyWpmo~RvrrQTsqwFHxM@{is1dB zd+*k;)S5`d<3tH^0qzBJS${Pno|~~)5a8U((3tfiUgX|XyYH3IaDm8XxanF?Pqw!> z(EMS*>#@(2ffT<4<~uhwTf78a$kG#lvhE*^Wy6gjISqHD{G`oxG(=2*ueo3Iv63Ox z^7)D%x9|#(Nbc##$pf16ZB$X#OYwh~>lH9vapzt)w} zuSOgmA;r;_TNFKnM!ED9njFxHU0*pV_dc|RV1DKtZZw+ikNt_HmM#l(J?jdSVXfeE zKj=qIzfRBR^=>q|WsZ$LqN+@zWsj4%-_73E3N-t9E6@Ivk zo`~|a_Iv~Kczk5nGVo|36mM&BdcY4UT-LWUR|ap-y&x6 zek4r5k|jH}#!DK*GRJo9p5&@@sY$(QUkQ9{r&Lft42(YU%5pGNdWtK=?!WYX1LE+W zedT6hNq6q78nbkW`n@nk+G=Aa_~hk5vj>Fp~XmRYcA$0Zh z{mc$4g_r;6(*L_Vi=0Lshc~>L9bAlHDGNH^tLBL2916^ul`Sa26*8n&yueN?-?-n` z;G~e~5>sq${zSQ+`R+tQZnS`yh7v*g{mRt`w5d^V8Gxp{FY7sx+bX{B(5waZL-NrxxiS*Rb?4$84Vcs7#F;oaUV30|lJT4X7{0J+*k8G(JtA%BRj$HS`s{?_JN14ZUgj*zo<=Acn zV|&|UE8q7r^Rn7Mq?sI-C1JjQcD5KYSvhRSqcDaFuF{?jF=hvPZpCHRS*pMH$vlDL_#3@ zKdSYrK0Q+U5l9Oy=M@cU`0uahv>N|6saddon<* z>n9SKyf+2sB+uXD5&z_ycgAX&*7=6LE}wn$VX|LE@@oTxG_VLfJ1*aiYbSI;WS6vM z;Xu7>drd+6nHg=r%z0nOQ2l>#@gCRceaQwlo`(KqbM)-X!osr|-Yvbm5fCf>kdIYm zFWQ1#bf8Q=As>jO!Wfc{3*-1G^Nx|&htWsavH2SC1NhQ`fZ;RKoNR@@A0Y}sy04$- z7pKb(Uez^LS$Qp&yJn-^nCIN$=jsl*2S`C9sAVH3+PB4rd75@b7(iBf6_Y215`H`* z{!xJ=O&n&L9HM#($(+#%x>lG$E85%ttS1cpvyO+t@-G_lA}bYZF*=LK%@jxm7>l5U0(wgg<<+0^<@vkHuBeCAFl?~{35Wz_765{G? z0BkLuI4t*tQe9=%ySEI8&^Goc90Sk4;etwx=J&q=Ya{aJK1>@IO9aXMI>Vl$&MR~v zW(NT#rt2{vy<<=!GG-HsdjxKXoYdXy4#<71C%{OHhK{`I4Qy6_f{;fOG%t$X>vp?z zmToT0I@O&@RoZ3wZWK-nCwO?fW=u$@7vN~;!!_Q;|chg+i1Rx?0u-EERkln;2!#6ksNFQMAjwOljeCavU+NdUf zKA=c>Jp`A;t*;p>AD%}uz?{62w)QEl&T964XnY|;6G||r%0Gw8k+k>yBkz1DwMt%4 zI?2HQy?uhhZ(+>0+k~?Pw1z|Qd^^I_R}rr)PI-F)$9UBa$XYr%A3#o6%U&Valmqhr zXcxdYYQjdf+0t0`L=u%(;cAXqCQO_W((@^US7&}xwzKL$ZC2Fp5Vu99oF7X@nXlHASY_&J-axLHg7DvBs}2$L8;kR$0FQ2{M3IMh*Uz z-2h??16}a256k>_zaIU3;@FzlnS^{7Ig19^;HCU$2%J<|wDvxPw? zvID8Gc-Ct3C-ySk*>h<+y0c>}xhEX69i%pi=Bap={alY>V{3m~q#lj(*k}820NQyT ztKLj4Bw?86+}13iwdIlAn=8p5?3uEej_n2%?|+U4*hsB;jeghrNmc&L4pM}O7W~rX2z*qx9dt!QH^izvva*FsC9wO<@sfh zxP`Mb`6QKoH?cv0a)JSz8EmOBJg(H@HUV9WE7Y9ne{|?8r~W-~#TBkQKX@-aGR@8| zCWB9X|L&Ms3^qg>xM%^@Z0QhZwSB`*kGo5Cr* z$n(X$1G`^goA5o2x&NQ`Bssb=qGl<4)&4WgM8$Za(>3x>>~GxB-6>H$Ak&r70z^C% z#FKhA7uyy{r6+7gY12Rk)du8T0bu_=V+X~}!4)w(n(s-D{-m~Qm%kf*G(?+(Rdr~x zS9i>_=xD4KP-A)yEguxT7VqPF)S~nVuS_x23P<)>XfDU=LdDyirXn%w$|ooVvrtHP8Y^@Z|W2^Az&Vh<3x1f<8=vgL;C#3=_*}IRG}G4|xJ{Vz5TN$+;UxM=$wX zp3+@^S``uQpNK9*0MxyzGhN_Bhl#9HmkMXg*iN*8h8UDv87G{}*5W!SK4&xI8W1_c z%7lRyTLFPcFGz1dOf6D3sE>BA8@XH1{w#kc49BmN({YR9UF05LTyyDCuYL~gaYLP3v!r#CB)_=;KrFHbbdyT1sLyTxNFpOsv%cKVV(9AF}d z(9Kc}dc!q=|2B!F!FIjGwdHAZ3y79{*NVhJWTbIoyPKsP0Xo34Wk}P&9wYZ#hu8iK z?j0*c)K)(2k`octUpWEjQ>ejPFPjv2ckcTwm9K%rQ6=Uo&=<$3<=S{-Q5~-`mcB50 z7S$Y#Km%$TJB2uoX(ANmFD}GuFU7ZkQeRRXxG8&Fm)Ym@2ZdsraQn~%9+nib7l#_6 zvp!S+zRDyZRNjWAtb`g@pX}_o0Y>@v3pddUXHa1$LE=NZsGn;05d!%IJ^lRZunY( ziEza&`+%CLT#b2eIF$$l z2-rRU(f-xH9bfEs{s>!-JC>nc7Q29@NExWa(Kb)I`Y#LQ-o0^;S&(uMWte5L%Asw% ztZT^>luSZC4aC5Z#X!Y2u#z_aBz4Gp5Ky?j^;=zmz74SK@-6FtjfF@^I)mgM%H@8} z%Ap+c@U&AjQayMW9-Cd9TZ;w%P^H<2M?dv)XZ&222CiDEQ}sXnM|Zkp@bZo_+1`jr zu4B=OKOAmG*38%*&6`4t#ToB$ghf6}PsXUf=X0Gqq#;I6wmD#T7ZM?i$uSVu`VT&# z8ZOOjFu)-R%e~r|?d^S%EX!;5(43K;TNx~zB~UzxE{0AGYJaAUA+FQ}+4gonT;E>P zNoNj%Je+Ui_#iIr;l49yvbzQ;g0Xkqem(5b@4oF#QaDW>L#*=N%=zkwl0Uv!y0M`6 zStM`6Vqak_j?#52WDp>gE$Z})lQJyaSz8El&^|PUQ=#+5F_^Aj}Enk60YMyr^%4S+rAAg+Zyl79o&0ghkPtmEwj%_A%4>=X@ZspZ1E_;`05Kn>7EV-SHpcy1w1d0iiIR>b|pnU4>0;A zm$)$6y!VdSR=6TDU8R@){m7|BZ3=?zyl#zY{heB|# z3kgjKvQV~eou&wb0Z>)*5znYe$S680;8HP$y9k|zIJJW0shK8Jk{{Jmy2hvm@l~ux zW+Uxe7FqFUX2Bgmmd2SJ>8J_R&q%oe>KL0!YZ~KA$?Q=Ixxn|4si7*PQttOf2%eLY zvNdV=rG{uD`zMDiHd@yMMasis4aV>%Ftc}$e=4VsMx%{yeR zX2l<3jcBz92mEs!Q133#i=bG2~g59`caeF4UvwCx}~padPZ54kglD~hP7n_07kgx2{jzd!Jypigwimh`No zKGebK2&(o9y=4uqf?LPm>29DrN6tgJE$xAC!yBzs&EvNzYdH!0h_*|KhBCF3SrxN&ifxMf5(*XDAsd9OSA zy}!SI{qcUd?{Qw|JkN8$XU+CE+BX@i2b2B1cStf7vZ?Rp7IZQvnrjih<{ih0Pc20( z*VG@GYZ{9cUPE?Bfd7#wt*qsVWfi84G^Bd#Zi?ZQu&zCP>s%l#;YAp7pfci}6mnsOYU;vhP zFL(qEce3Nye&OpSZ+b~^ELQgxGh73l2d+?<$g`t?h*6}hL+$gzFIXF{$GHKViH13j z-d$)otCZq@7xSKsy|wSeC@3Ue;4XE8T;DVkenX^t-s&j}re_BB;S{hA=#J}3n)(=Nw2Z1j&69>{mDR$89|8nlSjdV2`x zE_HOSz;-*80%3oe3{{gaZg}fuC-A9q%k7>Stk2}G{!>0Ux5sw7$Qp{24c+^XgrBpW z>Rt4@z@n>3Bk--5DwnUeL=#bHisjf`&1#%pJWR2>TzQ4_+MkFXFJxv-eMInWI<{Nz zAf}(JUO`t3q1Ay6NwjOs(M1j}hs@Cp9WZGILIPLqP{i>uBi4)$bO^!xZOP^9*_;`t z5aOO?ORT7E9KIg@)WPcY=~$&#O{S1|U@Fv6h;6)MvPD(ss(LEl=%6@S+H$J;Tw?=c zlDqUF&jETW0hG^O1qVT`ADGuPBb?>Ym;L{-G=>7z#&z&&@?!EMcls^j>3=LflA_w~ zsV?Nicmb#A$rA6GZk_Ll)3APge^!^R$ULk528EDVv*#xIMNJ*zGxpNO@?uaK_pSVA zT`@=Qc}=~QKOUfy-Aev@>hr#W!>?JrRL%GX|67IGXuKgoGjt&dewm_TPD=Sbk(-(S z>kO!KNZX7eVj1L7kx~}mEY8<{x%Kl{icLgmE>)z7E-L46x%6VI@44=7^z|xd`XOe% z0(9oUBo0#-TOS5LF9B1jwar(f*S3v3u(8ASu+3Q6fpqbP%wW2SHy@%*@&0b@k{g11 z7rhN)a-AZboSb>tt{i%Z(c_TH1k30q zHw<6*^{gqIavOg5soy&vQkkcaQKU3iFlQ_yt?lJq5pdmB z28t7TCV4jUkeR8*^|a_q%;0~zA&8iI+jj!u;Qoq2T`T8fvj;CLX5ulhqu!|17;<O#}du*hs6}iGDUd3s!~YRNY99Il|0s_!msOQNx4L z33=crC6}z<1`4tZctu{|Qo(5k(JP+arGDNz*&aOVPz5hWd6Vo^oi2a5VkON5Iu-cRY5i zy{Jd9Rn*+YA>&1xJFO}Tw*}JQ`t%I?)|o)R^DFt&vG)MQTGUdko@-HWU=mg67yiup z3K{a78MjwtPyy-{pbLb~BT5zq^-L)5oxN=EI-@?;y&gSTdwwe%}uuQBO!3H<)p zFHtojS?O0Z0$=;r9cVh2z{@d2A({r|{9!stZuTts=h*={073b6N3cW?Is;Fz-4jiL zOTg<^>B2~wAtij*+vLz?w6YcQQIRqBcBcP6oW1bNH|?=^TwU)b4$xancCxs{5LAma z>mL8iQ+K-BMqU%&M==ubUe=z9^S=PMGp!(}nku<>-LXTEa@ zpP|xnl-;N76)1Sioiwy+K?Y(ZT7@58<3Dx0y%6;}6sqM>@mAijDaZwQeU1@uc0O`?mN$Bx+aNkn=HSDeDef6;~T;-TM zKCl)2h5}|h9gx+n3U3+92(fhsvWy}Ou_70$T0m*H*}?4R$+<6=p67LljnPurpOhG1 zDzDI$mT2QcuGE6Mj>pR4G*v!(jt87V^voI{pbG;3OM33a)A_P{ipE>1;e~ zOv(||qgZ>N8_ioQF%2kLF3APTo6N?hc1vPP)0Z;cc|MR?cPRXu)_xj2V5B49Z(@Lk z=qWck&GKiv^my8yP40^7&-?L0`!+}Dzw8T^gwm`NcXOqCwgL>2$wWvBW#+w}GCJS+ zY9&Og?cz78HE3Au@*m%XZ&ZAh6;m1fm78*Hx&knj5F!Lgo!+0ncl-#zp)7JeRo4B| zz^|fYsj5JaDrZ-Wszaq%N-^)lhg{H`phuGXIVwZWXE3pm(%EzuK?;22GpH)+s(Dj& zV+ojXRUiS79|&i$TLrUH&Hg455ShFp|IPLTLMwe!$|CGU0+WLQT7sX4lgtP8G2II6 z`MbwH^-^HsY!|o$c7l>*rbD*>ZC~;p^9G@ai=Hci5#b${t5am7&ZnIe<(HF9t8B;y z-H83wSxg~D$e|K;t59EgDyL@a#I)W%dPhtH;6+{DWGfv3a8rPl(J_pPn+D%FtOD3m zLR&Us)vRfOS@SV#_kcyh!DdM9)mJT1+aFDP0-%Cos6Xw`egpREAr-`QvG-H&!1&>| z3am}plzgMzh20C<>zmsuIhg$p;F)` zps%M&35R(k(UE2N;irPgV za0%1YeApgE6;zPWqU!<6b#|eK@HB8aGbz}`^5)|0$wYcF+%gwLk7=vz_EvHLlrh?Y zrO8LP8w)d$r;YNib%3|8$Sf1o&bVm zc9`s0>jH_}N2=U(30xT?YybxkQ<IOYaZjxX?PD%C`>TD^vC?^oj{RtD1k%2>=V5ctOes=A1KC^5T__VzUISiXQ+_+g zlggGG0shp)Bj3NZi!VufDO1?oALmLuduxp6up&ric@5IeEp^@D{QJ-_`Se=O-LJqe z3<7-zz#5yM{OCGwSC+<%5`#{#&z^>x5uP3MH~sykbzcF z8!M3zscYz>7#~^EOJ)t>(M>U{+_1v)6v3P?UmFJUf_Fnl>XU2(_t6TJX43KaA_U8L z*r{gBvvQB5kG(3D#3>x5#-S*RxpN>F^qFh=f}T(2aV#&drq)Z#;;oU#kw|=?S3|5* zOht58&;Clj&8`QIs75EO)@im2S?c~>t6K0e*1j9=`0!sJ#0|w8@l6) zNmGcQR2->Kza^X|9c#4Y4SE3dgN(3(@z|(N%A*yKsKiGFQd>I_x$1GdhWE!8bzC@L z=5SkYM#ll@tcV*SG^7Xu*XLX-$ibR+Mo|wKT%D`Dpm(jcg~+7|)q`!!zKBz=iZ}`? z*`BM5kFY#*u&FqEEoo`8X)~I#x{mS~N|U~RQtB>8(>c73=80)8wt-2EaQCki!+_F5 zk2zVZwf;S6rm7F2(C;Up=5h=mw~Nzzo{L)BQS8*IrDSJ`yuxIFA#(DX94*UgzjGrC4YOE5$9?!iAo&3krWp74^EkDPf>ya1nV6Hp(hD-=hWYv#p4YD1W7dw>edR-~DTX0h9 z`ZuTv_GRcJAAy0^d=9@<%aWE@=k&CQ`wpp#_E#M4Zil6L5uA z2lCUo^zkGW9gE~O(?3-@y;XJBj$jR7r$U9(*k*}cFFu_+WAKC35Qca)XZ!l-~}WRyWmJ zc*&gfWU#l%ld+S9{=(i?wG{9=WDJ7)$0C4Yql3ol<8z7!JrAKm5k>)#b>i#q0L`Q& z^Dk4G`G?Z{`LFx-H=8xp^^ylLlEPU9HIu`c?6psrQYP|!=uMewZO<75CIEO~$Udd4 zpOFTABs|4RCfIWnfHSgd%hvzkmd2AiA(ZxGbL92~q39ttzwqQ^n0dOVK&DWZ5bF~B zjB0>V^5GIgWz+t4pJ&qFZIipZSaA`x8Jr03lz3ve?Y9aaZIA0`24~a{@S}ysEIW`~ zf7PgipHYz}dj_?Kl^FSNmU={h;Zfch=|XwrCXuSN$s9I-{B3v>SaJn$*A&E%Ob$#a zcBpebTZ=??Lc2NeXe|$&7j|_s;-+s<20c#nUAJpoW@F(BPdyEr-f&kqk&r(&Kh zQNu*PO!=Ej_KW};bWn;4H4yl*bAxv$E3Su)2a)u?tq<43ufnc0rinV-4x+vfbq;NS z1Dag4FGc=q%6lg%hHInikNqF^Hw~GOG>trfU0)Gk;P~{+6;A9+)>DL$SF<`+nC)GhfaG{@BIftO%vylvQWM%0Wjww>&%IrC zIs45{(P(AD=2ChSK+0ehJVX!1Hk>;ed1=}w!Xc&zKk=un7RV4wgz_$SzXdjDxY7@E zPA#mU07y%ewgt6~76|EWjmU<3xbVFUm_dhwZ=yot_Os)fN-|e(0aD$7BZ-!P0TbZR zeB}EYbm100VGalnxcoAued<|l?5={-H3XOoE_0x|z79cvN&3j7Ku^#qSBfX_19m#b ztGoijRL3>aRFLz@Wax|4BO95z4uLmOiF=T!6inl?NlaxVr|*pIY>3EP>)gR1naFH+PgY3FNvP|Di-?ZN_ zj6b~|B4DCTmdPz_@+wXLOpEYHnugrih%{eh7$^k)_fk3UOkm-ge=M3oUs}Ru;$Tm_ zpWNNUiM_9O*)DF%GKv8de!@~xS|+9V z=x)%9%}>D>rcX#mc38pND;HD>755Ln-2g|CuU*< z8>?`V64Uj^LuaU5)5g0T1l0*a?TNg_h3L!$`5iNp`@xY2$F6b}-B2|>BG zuN;2uoxM7GMkOQVQKE3osw3T#64*1ntIh?=cgUa12xjmw9`F10&)05HmxF1oqC%t8 z$zJ9x+y(OX&m0goMTuBgdRashc+^lQ87_1(HUKO#{;R8yh#Ibq1iK$bUF4HUzcPo& z7ekdezzykh*vguDXvFz*3NWKWhi~Jg32N&ApPa5t>9wNP;wiY2n8lDqyAR_NuuYH` zIE?z`G!`uD6y)}LWoyT~;u3#CR>)?dVdAk?{E*&BOdgVQ6W!f>OCh%K#&G4$$Z}@4 z)53%*LEE+bS{(&+@Pk>fc?9N!J{LL+)nhex;D!$zfNzk&nm9*AK|57T?MKGf>tz%} zrg9B|j@Ktpn-36HrnU=DyT6;Itady!RF+9kDpiVw>B$x55Gmuuz=7A%3$B^o_;x2} z2#jz%18dKuU#EMMh2!j1=iWYY7VN;8jId5o>8rduYXH|N2Eem=z-+s%Vu1&mXkm-A zWanW1M!5L?v@f6ISIYZevFysGk&P>9leps>K*{|N^v#L-Nl6hY*(VolE%Ae zB4OHBhpVM~~exqTr85k6NFujZjgu3O;l6NkeIvHlm zWeG_uDLVt|Q$`HHUT-_uzEygXZ20FEcT&YsG;ExulLwjn%20G?Cn}Xm*YtC5gOo$ zobx}gL0VPnZ_MEJ9LP4Of(rb4giLW{E^~Oj9^dKZ8#E23qW1NszNb_o4sc229C6t# z5>>K&s#1>`Qher!UYI(zkn9;Yz8gNiH)vq{a7}tdNy;m^aUE|s=-0(FTz^w_$!p2N zeV*9uZ>aa6)UEIM@V065ng-Ewnx`L8#7g>Nd@>&am`f%h|7O~*P}xMxrQ~loRJ$P^N->ABIYS@NJwsavlH>X50*##(b} zu+>{sW<>dArB&hCVqt$EeYgA$D(}{CMY7p7+`kc~#J&oxYf>#hcC+A$be(WSbe(ey zj!J}xtY3_lDao~Xvbx6FF$RG8O<;Tw$(35Z- zR-iv&U}M07Iu+$l;V|!(OfQoOT|kBx`55Y-dZZYj7diI%_dvoq!L_0(k;vI;`0-|% zJ~1Io)Iw>wMtVecWQA5VKGJ5*Ya{|hw5~3lNEJl93fiFr5}#em_Me?dMXb1L^{`=_ z5^I_*xfsrCg3igS$i3mOHK7VBJ*D~?oF5QvxKf#y%YjN0YTOHi)Shj?3m3-6^Mh4L z4!iOL6ys0aF}*T#0T>ZX7IzR4`-k+X)2?nB-0jWR`vqMe#h~&^b^Q^o+z=A_9Qk=i z4gDQ=^|l5RP_TZZl!ol;e0HVo<)^XH*(QJuF>SG;vIlqfn-YcVU|&cSGqnYd~VWfz~g1Goc?ayl8#yzQ>iQj(r zkL6@+|Tfk&rRrDxGR1VyZ{WXC+4TTA)Uu>)NZa-ei6LL_ED^TY`@0N z&vOH6l1K_;o_1Co!n;3o*R{_DpZOWEL6O+|91v}T^_!JJ!pbh+BH`tklZdrf>ce7+pifGC(( zIO~DAP^XclJF>tW_;t;h*>dcIM&8Gw4lMyxQ9+FIO-sPg(Ej9pNo*>`F}&{}W1FF_`;yldT+_S*S`j^9)az{F}@h z4Vj{pJ$%(*dQjp>gA zL83kI&h}hJ`t?Sz@U75Pgq7hLt;kYz+VdvXmrwPz^wFhY7wKAZqn?WfK!%MTDfWVw zdQ#9y_5Dil`Rpb5e^BpRlsx%HIwNicxn;yW+b|0ussZ9O-jWv)%mdHkk>A2UhvjpE zlwQeFfu`rRGMV-S`t3hrF^X|Hlkt)gmYmC3n-7`+3?G=cNZ;z4Mubh6`434i8I9|F zAWA=QZpNaRX(>fN*3DO0Yz*(O3!{FGe*D_3^`&H~LiBA{%5TS142$e>_-n?JDV?0` z{si?u3jj6{$>Lid*|JlgZRU5d3i7CWoGwcprDO)8MC`s&--(1H1jqL!0nU|Mt9!c) z)X*DH-X_ARK%7u3prOt8P0aRcSNm>7YLX(--Cu>TPuuh z=8pZdZ;2WW*a2AsBFKyv5n>Z)7t&#MpQfdfp`I?A2K_D~bGHCdSx!V69-z-}3ckC( z$h%BX2d+|91($o^cEQOCi5dqGn;`qXGIA?Ev*WwJMi>M`c^#0)!0~l6LCx4D>lrM`_xwl;)3X9 zB$M6e^w{9KCW>O%13tR~>c^C|o;9L*>KZ#v}`^V-0kq-vU1sz(;2=EzbJLiN;Q~mSyyx$!_ zf?g)vajtd*m@3#cRh{p~O7^*yw0lzM^#{Ay-O~NV zbaipi+khZN?Hi1SYo_yU7nfdK8gmvpe2J%6lG4e=VLf+0(WZzOS#~cWe)F z4F=kRQ^wQE9$8)CC-1Y8{s$08y%{Pvv(lO&Lay88e#GQs7%gNP`*7f>lGIu%MyqTq z5FtK1{ksFxJgPSsE#M1f9@SHX((;^}SwzQ=&hckY^9GE-HpYUCZU7zC&l*(pI zAB!g@@}++`zxyr#d{H+l0{H4E9+{@3QL?Jr7^?kI(n01+a!`VNxTL=mLI`X&fPaLV&3&b!~F+3p9i|?(ofw zZ?Hn|mZW9TRVj_7Rq-_)xGjcc1MLlM^FcJ&yiyTb7MNU3 z>w#I@+y!V1dtF=D4>Dn%r#wqOfNIS2l7em6rlW+rLh3t@eA0nA#mPy zrja@4b7!H<@sB3?6-CLd8teIyo5-hZhD>pDAtxzkeb8r-*Onv8tK?pE3)qEw(r{;? zp~!Q=>Yqf}Ru_qJ?ELmT=L0}1v9b4U6Pd(#ybtqBce4u9#F z$9h3ZKi?I;DXh%rnYxB~z$$*?8c*GRcVyw?Jgg9xUWq>46tGJWpZfW&pTdskw)bdX zY5iW^`R>GGj`PgX(4v+H))8r9_~1kCVT0!8RbTB1PN zuV+&MY#z$E58Wm?@&fO^Pp9b*>A@EBn&#a|hb41Umu6ani?eT*pR|vU!e4tuV4XYO zFXNpSlU+ehN)dWeN!brkh9lSGH=LzbdnGCE8h)|4#87vp3G+!jVv`txG1j~3hA2Od;t z`7zCsOe33h2}p_!6Mr^Za=E-eB)2@w4$;zZ2JA)sU}LDd|4;&&daHk@Gk(>Lhso#a zUah`t(iV7qD{@%uQn0y}#%*fCqP_P)m1%XgRZeC|R|JSk)!S zg=hQ$Px3ymzT}}Pdwu)FFhC(2!Ii@oEdNPQ+2=-{U(G5jB3xu&GiHQb6=9^bdm$tZ zBdsoar|}`uN0u7Mi>#ql3!hkmb;5zwBWt8H#dv4$bn`QzV|AeYFU(|QLxb=C&P3kp z!K5H5QXA*~H>aLYDJ2RL#xME-J3X2-X&#`S8=}3&_r}jW)>iKVZ{q>wfOcH>f$!Gx zWHQ+7@$vJIj@^%~yn;o)T&ISIpx0i&uH%;*ndi+DZqp)M#eENd!ru)ezy)yG*&DS( zP0mRx)Mv6GGz?^K67vN}6Qav#K6aPo?5NMlC~OO=1%`XT;vEBR5#sIQ75ka^-C&57 zt2LY^CVT9QsGxy41E%2kZXmu;bEy!CR-qTv z6PE9_zqo1V#`aQhYW&nO?fLhl9vA23(_UZIoeJ}J?>HjYWcj!1bP{|220+c_Onm%* zFyNP&&d{U^P^%u>fGZM^#-9_S-J8@Shw3-w&R069jkI?JSS{!re4Q>6qd0_Rr109H48Oj^g_TTWE3NX$s}Em4V`a=2T>bEXvyI_j0c zx!}C@(8X^_kL&zi&3i+rD@9@qMK*91Yz;WeonZ3VMTMkewT>j|6Lq9E)YJ}@Hr^5k zRy?qJ2BNul!|#fzj@z34u}k)LII}QS1+TVxZ?=FqnIaQzUY%h{@n!;ukP0QV^U=3f zsE_p@d3c>`u!}v_tgRgV_|~q9#U{I8d$=>}*Tbp-;jA>zs5zNlGJ!LuPsCE#^X8T_ z$61_M=7@W`(d~m`k8^u&Z=6Tu?gXP(M9fWQ27WOhtVT!s`y0ruTIM8pjy0{VyRZcx1w?k@*PnZqNMObG?Pcf{AvOm?xz({Siyf!<;P zn1w#&GGg!fe2!`1f;qLWCMHjYWiAYexr{1Yjn<3$rUqDjZ6`6$29lo3V)&o~g!5Qh z-m}JEw|4K!a1IkjmM3H>J&e>K^#krCV3A~(jQwac5QY(YvgD0K8=LSk5g?Mm+?!## z0wYyZCOehbHa4Ga-Q3$DA3pU9R2-oPm{xR=cZ4;uDnFKjP`Df2$7(>*Xbt$Qx)^AJ zDMIj{de&o}a+}HSu{~?~i=q4c+LIXJdpOZoUrK6CLhW9_%Gs#q*b zEF$@09|v}yZf&fs$xk9F~q!xcvP?HLWpJttEATSN-4*u6|M zq6&z%@uZCL8!`sc<#=x~xZ!-g?)AtLW**%{Ptr>3p+u)SE>~&F$t;!uw;PuQqN;%T zwIw$7o{WoGN^C#TE2H+vzIq*i3LGJQ*1TU{)l(z;QIPHYgrmQ;|6}0~J$JZ0b}0lk z>#T^R?v8coyW#Qz^AY|ls2$1g-|qyqXkh(OChG=#xPg_6iYln^&exkOtZ3g78M`lD zWSH&P5Mwa+nn@uawW1~V4#SYS`Qa>6dc&9@mHD_NUZCaXZ`G=1_C}M?x*SES~kBA^P?>8Q`nhL$O9ZCtK+at$wmnbNx-)scYr&C zr+IcJyRzHhPg@&nn`WUxDw&njCq@#BaUcb;i~*yXP&d9GtKqSWu|r|#U!<|}KSk`L z1q6UrzXm(AAEHTE%#Ot;!9+IO#p0RA8$CL&jtygipgTty&oP6IhX)k6_X08nkYCc} z;`=~{)49o#x@?(WdKwci1t^|x0tnBgU$8=%HV;$3m(|110D0gF04#%syTgeUPT!^g z+@*G!O&gZ(cTW>oX|?r-uGKT#_8kVRa-Q!t({EpO+4QBbbyh!85Os8uznX;o^HG7U zBLjfK(xCp#iCoz@T{gsA*?u+5Ef`4JAkr;;NFM1A&V-4l7t({P#h!+2O9=rBr>s@M zum%6%uOk+I>5xF}v;wW0F9yC-zInuK&uku4N%IDZDRP=Ay`HdhUUyJQ{e4;2tEu-q zLgw5V#rsPUz!p$mzjx`GT%4cQS*E#W7fnSYBWlhg`857y)z?|oXneh{uBD&|vPAp2 zsEXRDMlbRc5njaXnEw$EUPy5L$v5tidYjbrXoKd>UkDlgKIg`h)rwM$qBT!4*#qv3 zl{(+x6BZ7I#pd|`8lAFCK7QuaymYw#=Uhid{avvJot!9}Z`lvGY&9NzG*lB*r<#CQC(+&F z0(0q2`HH56`Xay(m~Y9pFymf-cH}6BOZ!mw1l_Z#E^WGcLIPV*c7?nS$sPZ+-fjUK zi|Kk$%$sy8EyDHDTc_RR)L$o|43-L|u$%psXRRVPqD~z4fbSF~Bs|sL3+$y~Swa{x zE=saQ>OERhkFLtNc4p6FxQuIa=2FbhS1FZBO(M>vddtHl)=QG1FE}!#?plhrMMPNK zQGVkpvQWEWMY@A1TYrkXDz~Vp%QmagcfdHKUYXCndh21glEuAdK~@CU9ayH{sYb?* zPU<;RCfpEjdJbV=VLxT&C#TZHZJfW@EDCoxZGFZ2`#8I>I&Ob4F-T-4bs)Z5H^ZmD z@amtB0d}hA`q-LrBEhWd4g!mw6zf32^KbEdzdXbHy*j*ZY-p*>w#J!{&aONFw?qUD zMy(iR?-p;t?7M`@v=+^?LgaS=<+-_aW9I$&?cT+&nb@1p#wJ$Q0+El#|32W?!)g@R znZ3Dk@{Z;GGLLcoBk5r8t0|){h9pZdLhgcdo?jm@QX7sVoJL`VnZxDRE62tiV`ZMC zWk|Yye+e6Ac0)+!;3QOSXuS9J(dq&sA&B!9BrKbmtH3gTI6@N!4lB2IR@kpe$&!Zp z^84N)50=P*`cb%a!n!NQct3U7lY$22wIx05$}p(rN?_a3^x zDX#OfV6xHAZ!$aQ6C#@E%0Pl*2w1mdQB*TnaG?o-Y%sMj7k7CIE^c?Di9rD`mYCMZ zUfFlFKZ*=oKTE9{KelvecRsms-!25bTTQtQ%yusrHSJsmf?vt!Jyc2WEbhL>sUNJO z+hq?d7slx#X!7d4T7AujpOWI9fXDhedhWQDtwZER*y4o(m%1Ix7mMhl%K$n`68JcH zM@Z5#QcUA!zyI<-mRIl(3R%Q{KkZEZX;fwfB?E}XUY+BidW=t=A`^BT%bEAaygiv* z{^Vdr?alO0eL`C2m)v$m*w+zvlU%lOaU1Y?KXKZ%x79UuRZImy|GyI`U-Cvf_~+|e zB3aK_PPT_q(rHhDy^yD;3jVVsan#WN(#?~}Tx$9-bM%73Vk2DubC^Vl5!U-O;8|9g zfNiNuq4IabTq3O*4NRp-rx4$G=8e`-=cPQ?Y%h&Nogb{)#pCOmpoMWEH@=T%N+}$C zT&;Vn1#SFsy>9y+pYK>bvg2(?@$`Lo{FTuRp09^+4m@6n;wMqk4*Blhnvul(`sAaL z>+}lt-nRsP6I_QRx{$dKUybWx$oz~Ku_s~pvZ-Wio0!+CMNx|?17gOq3vH0aC#fN} zXMD3ooIwCJ#x`-6Xxnue0l4n>ooD?OB-o=)uQ>k4BC!Y)o!`3TNA)=FxhA_*4o!{8mFMZ0&Af>0*GBBY_w`(v~G=04yRTsC=>jLIQsx3yI$ zTNmV92wRf@sj*)Q2E{Ev5dI(@LSUtBk8|0e)W|3MH0|x&Wwqzcdmuk1?^HCzgxR;- z1JitYN_F}cAh6GX<3%f$B=V(

)}55;`dud3IBER-AOu@p^kSE+y`sKT{`CH8iGB zffd5ZxhlZ7XQ4OdhwwL&8&b?U?kAO~8dm`EUj^|)Zhrc` z-llBzFvOW6)3n6el-zGM%&h2==aJupfDL%ZHV%@(Q~t7jT6SobEvTZdDUkhl_f zK`WRP;7g<}MN787gZ53k09x!6C+K%3*L6lyr2nV(m__@$51Sg^ow+ghl7{{GkHva4 z1pVjRU$VX2<2yOYrJChc6?(o+bm4>=;|9wF?7R%xiy+DWXRtzi1JGJlmo{Q9Yibow zHLTW?dh9q{V826ts;qY|MOf}7kOS7aldDUN)dIBN-(Cj`gFSZ=!6NO~XClqWPp53{ zXYO-0$4;wdTzlno?^OEqQFmk?ni9Ke^IdJ+>Sn}Y$2xtJW)iQd-{Bg``=)P9jpIK% zyKJ4dVVH^YUbS%l#&YZJjHS#MdD#19-g)WmZ%FpNRryQD`_ut)ha=lE_?HpS}*t8a3cOjcel4EdYl9vS;daH zj(DkS9w*KYD4z0%bZjR8uS7nhLC*ZcsTGc2u&7(bn=WV3DD_VBl6SOE186~(_zHc6IR;V4}n6gIc~(L z3XAZ3-^1qco>eoMDfn4DC>48CQK|P}^B>Cw-?7x?)rm-)YDH2fo$C)(0`qX!M|{u; zIjCec>G3;%y8SUK2-b0wI_UwE8rg>QBUVjbKc1%dsQqA_#GtwVK48wS&LiJ)n0!|> zNF7g?CF2@oDSD*r6itJ9`}+r=^LC6Z_h-_AY|w`p1U5u$`y$01xM5crWiUa&?U@o` z+URNaHU2%Pxxw#qs*S`U9ObkhJA0{{D*6;pUd?F)LPE<`~6E_$t%@ni$Kid+K4ZGv!RCk0dEV zD`A20Pg~F&n(pq6wch;z7a%URzG(Scs-ms1HMu@vRm4pkTq15A_LF!kR;Pz$AtYv< z5>&l#ixzzDM)36C;HLpaKF07e!EW37hQNlG4GAIJI)YxSLK?^LgNo%Z1e4_0D~pyU zR#zheFK`Gps4mSXFEPcI!Y$Xvw|L0TW~73xT+!n13b%xG>q`RrcBxrBII?`?6M6sU zq7#Y9#}~rI3U*ok$Ny*d6q6){#xIZ+00n2;tDT?mAs6(1R%)r{J6iUVEzSrv*qWWb zYfs$#1xSdw)FU+tO@B&ODZ~~>bgcbmz5E)U^^hoXzm=ZomjF3Sp zJZVT_V+2c;iFU(Guz%qfUQGCY9xJ&#I&x%_mSj|mS%VEGlf|!Qy0_jc=^HU}UxPcW zt$to&rkdLK6)_W1xwk;dWB{I*k*&{^!`QRjpsxtN~_bG&_}ni~>Z0!!)8w0^&A-7TWy z1(H*!Fuz9JZG1RS*-P-FW?5lsLA1xxoh5fGtUC>u(zo}(qCj4=r|U=GFMp-BxApA@ z-sM^OJcvpp2%%49bv#06{;)XlgW&Glj9Mo`!Xx$n)FDNZ{;^1z#67M>4XXN0k(c5e zfw03b`>fUKgJDTf_L&P*M@4gvA-zbKJdE!$qyn1P{ntX_HuUGI9iiemN|o;~yt0*7 zh<2$gtFT$QyRD~cy5|x;1Eq7mV8ZpkslNTqk^BRC`DXDgMg75z=E)CeL6AZ~7_gll zAC)C-4BPkIU;bd<5jUr${EQ&9N_~RjG<{~EussWIouIcRpa-P7_Os0aHG^9+pLYot z1Ap8+a{_;q4Kid}v0)hxPRmrD(-A*EtsoOPx4fo&=lHktCy&eCU7>&}*?*2a9UBt> ze-tKF*wg;-PKTq?o>ijRp}EB{0tL@brCm2Ev^Z|{3wwQ7H#|(k(G~W=zpx!B9y%|9 zp>-R=?x8pZ!S z?_vf2`+&cQSX$U|UWt(yM@T2a)VdfG6yZoZ{|+U+SKHztVNqYZdA&lL}9~HdnP+#>`Cp0eG`RxvD)h8Xf2?_orBe&Bt#_GZJAj#g!m`M`z(!E*9$7h!EmreUZsc#|?rISP`t^{{wIGr&8*#)7vDy zX6V&sNDeugxQ_S8opmo_EIK>BU_GVH)Na#aLFZJZXoagwz%a0m&pyajLK082th zUS0@!uY!QW?V`6VvAmVJCRuH$vR%3?eJ@gg?28lQr19b7wskj!`1RQtYyJ5ZH#G#W z0G1@j3eLcpo67ha)cd&7@=nAh^AkT`@FLo{RPaKF=-#gyuI^d>GJ|Vo=F;si#zyVm zm&I$?KiW_?SO_h9e7~vzTq}jzCa{4sWt*jB^r!%-atKb58z&YiaWpoRybsW9bzFME zRp5c9YbPDz&F$>0MFJ+|^I1n7-AZK-6b^7gz>*cP)>21h5R+T4|0=jdBtJ&Pq$^-!)F{qw#|w8!KVVap_b2+%vs)Zp&Z-3gW@YRwFwIjh}T2 za9=2psauT*yk1%46FYn9{{k8#<=pTFKZmlXh0GjXPitDHn|}6u%kD=JaLBH+50!uf z1tetk;~#((i+w7|zBc>JHyrR(b~w%sJ^FU7d#PrYKP^J;>xCaMUUSntblcdP=k+Uw zNCar0s8Fn+ZdL??(C7aE)nA)O5wZHDu=YlVjpCN@X1izNOJ@0PrCA8<$zp>q?h4oA2iqFC~AKEt;JYeZkWz}#`@G}qxYz}MrBJsD1U0lHf0Evyb zBn%9Gf8PebQ8uN9SMTs4^R)@^@hS`U@4vnyNfX`aLTN_=b7eku6x#UB_o7gKSr-ph3w zo(xc*k|f~tjwOvpJ&k^PNq6TvN?0>CN&GnGwDpe~YFeeJwv;GE!NB7q_5T1G;(YfQ zVc(7``)9;I5NUA-)hS^i%SMbXXWviJSpISPjVwHA;qdXbDshY;yGAO==wQ1-2Sbi9 zPC9y5Nv3KDF0E&burbRM6X}K@=dF40xFaBZqdt|V9peVfL~j1~^7gOGXFh1OZHIz{ z<1UG#`)2w$_by$K^Ub>h9IAow=sJ3U`SK#V}*D00%Vw+>lvEYjdS(CS?Hm z$jugi;2>hZl(0S?aaK{pGR<(+8`U}PmI?1?`F{O^n>N_fMkG!pC z8~*^A{)@%>=|yQ<19ZEa$Crj`Cx2^i{4f1UpT{6yLNc{<`fKTZJS z8zo_n(0@5%%{3|lXKdRJ@8K*ln8@(@WFXVkS{{RJl)MV5=fAISH=jFJ*wAU_N5(Wg*S(DTK z?^^y~e06q<;>*z|KfETsto^0G;Go|XKWUE`X`U(Z9i^_97LR8wrKP2*X#iQ=J27Ye zBeh3N3|GOr_PI8zs!6KMqjR?Ic|YO!SN6Vr$9Oz{1>o|iMZ&yVZaOrymY3VAKQ-VC zlDbP zt*%wsWmny}KOARwHTvh_zxX)=_Vv;9+e=%>G|QRo&_>gZ$nW@cAAqmmE-2tGCd6@7 zJpP3U)Px+Z9(1={tL|1msd$r$@+$l}l;t^Xcl(NOo-Q{1>8~90BD?^Hrd!HnUB!0QR#~R z05iXj-xY4Wcj8YFd`ox9@dl@PsSxLYmvXblzk(G5*b4jG_J#idg7p5-U$h5>H7^f% zi$S-wxYVp=)4tpGww73}=LH>5Y+M{M=bxusejWI$#?xxrXtMyKr~nM);A8p@EBepD zo;9J7aOO5R$_|b$QE`I0cWrN`%VqLEDa!Kvba;a{&GAWEv?r zCG#DD{VB6SwVvK$j{Evyr18z71zMuGO`&s-%_-CY9X*xE;{hupKZ6@Nc z9^<aWpcw-1|zS3ZlO`{oL zvF*>e72hxX9TWRp$cnOfYS|4;FZ#d`*0}K3A4ecJgzd zO5&WW1;8Jlrxo=aeVO3#`Tj2%fOn-iU3|~fDbv?&Iu&1Gz&z)vs@Q(~Vy}U@a7KSl zf5ML_?8Z5-isw3&9>!6Pj?j7U?N!V`p4}^DlPkMu#yH5Rj4h6P^yAW{OiqE0!H1$C2W#cVQqjOYCERV9yaKse&5NX}GDRs{URq3ci(Tx6V9t1E^FfyYc$Srz*Mjw@v& znpBLVv||-sMI~~1$KlennlX+llXJkuZ5DD)1r57b(~c>Oqpy0kAmj{mAIhsWXqn3; zWB=9u6ryZ56}e||vAEz@Fd2acv?G%kBZ~BA1D2fZdk=@aL~Nyx55ULiUelxar7ked zE(`I1ILG-F@_aWXPIHRstToAP+!byI0=|16lg6&AbL+C6AgPD6WwG`JuCH#08B~zK zxEvbyusJs`L*=tBA?8+0)YY|@pX65gItt`oRwskh)pxnvN2OOX0(Px^ zWehrmQb_o$P9@ZLW$o+;&+AvAeuQK2tcc3}M^FC%RcIqA0Q&XErFTLH6Pc$Rx$o^- zpK0Eku%Hi5O2A1QcgxSGYPT7{&Ux;C`rWIl5HXa_jwxFkn1C_Re@f7f=qi(w^~H0^ zG3&yCR@P@280*kiZ8}B{rH-912~{Sntoz??dFj@C)Is)}X`9esLL;WBRuyyN;;CN4_GNEiTA(A?mI z+v{1RXDJ;(yiM5a$6so2xq<%vFmwKY!nwtpI_)`HoqeUun-7 z#yS50KjBar+rOu$rDPkH85qd*q2~t<4+5pg=V;ey0JwX^B(y=3y z42pWXcE|MmDlT%=h0gm<)IvB^?OxH~?-M<}$}>s1e)mzIr$3c^<8L?$3UYRg16@Xw zek0lCzbn%om2s(K!pGoMNI0|f`@tSOit^b*xH;|DARg81c9*Wt=AqmO_aT?{>*?DS z`Jdq57yX7s-q{^Eudh4_p*;gZj(;CowvZ}gEs%e%27emMw=b|PNHB5LdLL}ot-jHM-3CZMd#6q~ z{Og^}^5vlPia1nkU@!d8qi%yagx=>SdV2o!2jAQt_d(_94Qhs*oIOprZ>5SA3 z0SUEZ1<(v0;CkoVHK-y{12F+gk@KlI!+ksZ9zAQ8Rcvn>sTs^XykM?A_yd9gJx3>x zTAn)zW^K@>`9qPla@}!^dvV^a{g}w=BjmXRY#jar`=+&0*X?9ROl27FLQV(FI`tmD z_y)M@VmWp@XjU?;thQ~BtawJj9UC0~02im@TEAqsYb~;psDX(2axun1{J#p-Huzkj z7~8p69i)yq$F@&7$4a=+%QH&wvw4r-%*X(PfPVIUKT7heVvkytQyxoZoSBjF8B!1) z5UCjJEDCA@1Ip@_`%mG-ODQq4`>%rjGt7(wQ z8UUMifWJDG=dlO+d)Jv)8)Ma=+A!@cM2^l*z&K&F000;qbgki~T(lUJ?DIhx7#SJk z9R4Sd>07Ybx6ASwNeO_sINrD&0O`kiyq39g`xoYuJ8{!*CvRMj%bM|Pth0U|ZWamHWbT({KYlhus*@9RT2g zQ8k!QtqS>jOLEJSGs!K}k`4#ATIeH;6jPP+I^^TqY4zZG{{W3TD53q-FDc68bP7pq zXM>!NPPzRn$HeA7XV~S?vN5BujV*TD#sOT6rg8wm`==^+^z`+qp@m|A&u|V^K2UO1 zz#DKEl1CUBt$(ulp%D~r3={<+iB@3P$UQ2@mWbOQ5^p~u?<0FRU^-(NuNtm6`y3V3 zjHiRmK4hTByll=wf`6uQpKn^0<3+P+ByTJR3&_VmC>==PkEgG-YCWyaq+Hp=UB%v+VFSbVq?+Ti#m!g;;htZZ{GL8Rz-*{AZA7_)yc1&=@6OTeTJqYXmHHh+-Zum* zL#mOL+FLl!0R4N{J>@z8ZleXZZW%rJI9|O^9@rJ#9K+1|3@rru7+VWM#iRvF{LTR? z{CwRw2LN%;YC#v;pdMj%=XcBVa(V22hXb`~i)m$$I_+m5yMlQQ!Qc;Xx+*hhj~?j? zn8E(wP|63($9=spIX<*YFg?l`HQ2A@Mqqf`=G&4<*o(Cj!FwGbU941M0BXIT~HaO{2 zj`#c)!vnsxL z^7f|g$`4)LK5ToOcQutTk&-!MP$X}k3OML9^v}ONI@XI4KdUasH>sH=aL(9P!6Xs) zdXv-C^&DckO++z`CUKVl6&>(>8;tfC{DpOziJD|GHgGnVVllLn{98{Ww*&8175hRb z+`xxXl{x3PJe*(-{Qi~IOBG@zhVnQI&9jd*uvROAf7Sg5T>k)`E5p2V;#i=-XWz77 z^MD3U0RI5>bgsAJ2agiO$qkDRe&K8q1Fm@f_qBYD;!hBH)4ZFv9>=e5rVrs?QJ-;vXxs$$`lfb1}FRV0vw+D|7O{{V$T(iL#c z(~-@61SO&I^%7>IO|+HHY3AnxVCJ#Bmp#Ml#_qvju_PA2)Xxc0?j2?*z}=qkd^xZ{nrgqhh&CfZ#7>u3P>=B_2t;dliz zj8{CfGT|d5ZC^}|~hD?0ULHS32>5TNR0Dt`_^BxS|`+6T*yqmlWK%Ay(L>W-S+15V!Q z@*MhnptjI4)Bgb1Su@$X43IkUUrK5|4uOj^fC$Oso}A;3F^cp3U&AjFoQw?qpZ$9E zu=%7We1>7dRj94BJW5y?oSb5*%O4>R99L<3rppl~UgIN<)q!&h4ad^Gs&!L7FB5}w z^f|{3f&liaETb9i?^{yG+qGs$yEz~IYU+bLYP9TSNEC8KSCMhS?V7y!8D->EHw-JL zC!aW<|JMEx)v@xLo+jgHJXKN2%{fR13)Jym!$+Q(sSJldHC~EdIrgk&Z1NB3Q^xol z_8lueLrBQqitwk(e(h*SsW5HdkJ7nibDS^XQ;8U{1EpgsF=pz!TQjd+VUw`JCXI-V~BCm0On) z{SP?&Dn0-U-lE((^*yO0A--aI3f>Vph<7;7J?lOZla7^kDBeyzyH}$|jr2z>>K74#>Cn}LEJi`-Kh7!k zb|90u{V`in*{L5lJ%<(a7)+w9?9wR&$)^RdM--WrBa%K` zaZ!1Jq}=^E7&R=4SLF1njqC>=-{W32Y%5(3h}F1~I{hjaQyM!fcPVKKZSYoiM&}Sm=7br^r^Qa zFU~o~(y5mxY5eH(AB9@xk}Bn~HU`3T^y!L_H#r#kiqGGYIK?VS!EXJHK@Ve2De$;F zQ{LB)+nTW$TrATCDTpoK5 zN`_+MY63|GDaha_2PdUxs{``^^A6QCZ}T5~U<#8NBWW%RFE}B(e^37aRcl*MgP*&{ zaa`0)RY)EG0M8YA31rUG$@HM*s|0#hm#9exJMc*8IL0g5d?Vu)fum_#APi@rvC7IAsQ&9o^vSMyO!Flx5x|8T$vc@x7z>kvI`#DY>ry-gcMXMpcpx&I zVEsQ1p0wB@gq+EqIQc;2bp1P4q%fU{^BD_dvBpWyZ(cvit}2xbJ*emmNQ%h&aq}F1 z5FIi)0x{pGV_KFGDj1IrS@(RscYAuA4mqfI7~F*n$Xk96IT+{H@cwnBZvv}>795hp zBdNj49=^u{Zow?u2DjwuQGh+V6=u;2oxAQ7L;itzCj z?0cAL>{qvh%o0{rkd!1kkCe80h4#-CdfwEt<}a041GQK)4afQMo_bT@i|oU8<=-9| zTVMyC3lZypaaPG?Mu9(eA8r9BAdF)TJwPAb{*BONmj_8*3HE8SjG^5~$SuZl1~HB}`VY>bF_fEQFk}U=i|TpljOU&^){@%9 zuom0Z0;+{8*m21@7{}0c&0E^m!zf>F)fi!bLky3*`0zW7{d_D&GRN5E^t4teqOplL zmXH-7d54z4=RJA?I`ydpamj$Od1{2QU$sMn)Kc?T@8+^|6;ey9GwpGOl1%i>Nb(Cv&M#H}VbvIl%cr zsfDu*(L#CWpkugq@7NxoR+JGuk;X3+I1+8o1GaP6exs*q^XlVIuE5gR$DN8Id1rcH;|$p>amdeJ znD6zdC4{0BSuv6$RvWTIWP%1c=il_L37}+9@?@XjM8U`$j-H%jJktcy#UshJaOuBv zgFLC{j1kXq>0A@VpId>2tYkEAHMv~nq)eVLGlA>Vo_#s4ds5TqYl8!Qz~k?7LF2JF z7ze2IuEC)B^W+C{!NwPoGm*zmIK~f3sd;M8{3ir%7y}4Y1Dxj_4h{uPJZ+xm)nOLL zg6ej@WI^qa4yPMQ>DO`e`VK3cx`88z&XFJ;cXECB9kIu3*Rkt1hExzbh=T#NjsR1Q zq;~7j1Jb4AF)EnA z=L3&Q>iXIB7yf5BI4gNeL%-1#k;60ALQM2cDg&{b=>6P)Q>STWFJV7-ASu3uFLE z=%c?K{e?N9Xxtc>;{l5|Kv%Hpai7w(%rSX$ouiiN zz$ErR-5CcMrS+4p6bh2zwmJsE1np0mf}V$hGwMnI0PEIl>n!QAPrld$sNM4u&H)~s zD_6{tMGT|&k}g?QxjU2ro}GTY)l0b5j`<|q4ta_{lmW@;!~X!S^{QBdquCfqGN@R0xtn#Gi5OraKf8QK>fAy=wJ|g(?-o(poXXS@G zv*lw8^y$-|Zk0pg7sWO5B(Q>Q%EKl2$0N7&?_VDHqr}Z4xQy)$$6Wg3{{YorTa#sV zDzzys50cNb%2;?f!Rj}~z9?JCiw6wDEIHgZ^~QhweuBJ9R@M#}diwi+o+&k5W6o@| z2IIfAaW^-Az|E7*ezBKeRXC+%@a*3=m1#CQ`tZ0Rc;^`v&d)yXoZ^yc_c?Lfx7Mld zJY%8#E9j`fMIRknr!yK~aKYp*GJnFNF8SU#&tXY}(x5DU@#K0}TuuohP3jNs&jeEv zQPFY5R?ZI{ds5^U=Z-VYT4pU1`N36j%MLj7r7{!Fb5#y8m8Divn|k84OwFR#nbmq` zlu7;GPj70XUwOuO#Xoi#bH+#VtrIYDFL~@&*R=*xe(nGVKZRzy=k9PQGXU9MhrMac zXJYuD?zg9Eva_6JPfzJs{$n148UBKUE*Bk#r8LFLYKwwT9WhPwvUdv2X$y~CzO>Ef z1dcr_t}7RO=f@qpcBUcSPzY~Col9Nh~JJJpzE!5HLrnb%1gFt7(3xUD#MIraT3G9BCd@y9i@XsG=?tCFOTTMrAG7V)w9 zdG`FPuF&*3btzI9M2QDnj7Ko0mG-;rOoKs(0t!_pYYbXq@PnSmuVL5ePj4fV-zx3|p!Cmg)9Fw<&GKUk zdMG%-Uf!4BEyj1E7L?agy~uAOgn3h)6S0oWW2aa)ss(HT)n?m@SL zLF4r1tMP;7gOS*OciXw+71c?&>W@CXD9u_+L&G)A2gpVU30$6f{$Jr> 8) + 4*g*g + (((767 - rmean) * b * b) >> 8))) +} + +// Brighten returns a copy of this colour with its brightness adjusted. +// +// If factor is negative, the colour is darkened. +// +// Uses approach described here (http://www.pvladov.com/2012/09/make-color-lighter-or-darker.html). +func (c Colour) Brighten(factor float64) Colour { + r := float64(c.Red()) + g := float64(c.Green()) + b := float64(c.Blue()) + + if factor < 0 { + factor++ + r *= factor + g *= factor + b *= factor + } else { + r = (255-r)*factor + r + g = (255-g)*factor + g + b = (255-b)*factor + b + } + return NewColour(uint8(r), uint8(g), uint8(b)) +} + +// BrightenOrDarken brightens a colour if it is < 0.5 brightness or darkens if > 0.5 brightness. +func (c Colour) BrightenOrDarken(factor float64) Colour { + if c.Brightness() < 0.5 { + return c.Brighten(factor) + } + return c.Brighten(-factor) +} + +// ClampBrightness returns a copy of this colour with its brightness adjusted such that +// it falls within the range [min, max] (or very close to it due to rounding errors). +// The supplied values use the same [0.0, 1.0] range as Brightness. +func (c Colour) ClampBrightness(min, max float64) Colour { + if !c.IsSet() { + return c + } + + min = math.Max(min, 0) + max = math.Min(max, 1) + current := c.Brightness() + target := math.Min(math.Max(current, min), max) + if current == target { + return c + } + + r := float64(c.Red()) + g := float64(c.Green()) + b := float64(c.Blue()) + rgb := r + g + b + if target > current { + // Solve for x: target == ((255-r)*x + r + (255-g)*x + g + (255-b)*x + b) / 255 / 3 + return c.Brighten((target*255*3 - rgb) / (255*3 - rgb)) + } + // Solve for x: target == (r*(x+1) + g*(x+1) + b*(x+1)) / 255 / 3 + return c.Brighten((target*255*3)/rgb - 1) +} + +// Brightness of the colour (roughly) in the range 0.0 to 1.0. +func (c Colour) Brightness() float64 { + return (float64(c.Red()) + float64(c.Green()) + float64(c.Blue())) / 255.0 / 3.0 +} + +// ParseColour in the forms #rgb, #rrggbb, #ansi, or #. +// Will return an "unset" colour if invalid. +func ParseColour(colour string) Colour { + colour = normaliseColour(colour) + n, err := strconv.ParseUint(colour, 16, 32) + if err != nil { + return 0 + } + return Colour(n + 1) //nolint:gosec +} + +// MustParseColour is like ParseColour except it panics if the colour is invalid. +// +// Will panic if colour is in an invalid format. +func MustParseColour(colour string) Colour { + parsed := ParseColour(colour) + if !parsed.IsSet() { + panic(fmt.Errorf("invalid colour %q", colour)) + } + return parsed +} + +// IsSet returns true if the colour is set. +func (c Colour) IsSet() bool { return c != 0 } + +func (c Colour) String() string { return fmt.Sprintf("#%06x", int(c-1)) } +func (c Colour) GoString() string { return fmt.Sprintf("Colour(0x%06x)", int(c-1)) } + +// Red component of colour. +func (c Colour) Red() uint8 { return uint8(((c - 1) >> 16) & 0xff) } //nolint:gosec + +// Green component of colour. +func (c Colour) Green() uint8 { return uint8(((c - 1) >> 8) & 0xff) } //nolint:gosec + +// Blue component of colour. +func (c Colour) Blue() uint8 { return uint8((c - 1) & 0xff) } //nolint:gosec + +// Colours is an orderable set of colours. +type Colours []Colour + +func (c Colours) Len() int { return len(c) } +func (c Colours) Swap(i, j int) { c[i], c[j] = c[j], c[i] } +func (c Colours) Less(i, j int) bool { return c[i] < c[j] } + +// Convert colours to #rrggbb. +func normaliseColour(colour string) string { + if ansi, ok := ANSI2RGB[colour]; ok { + return ansi + } + if strings.HasPrefix(colour, "#") { + colour = colour[1:] + if len(colour) == 3 { + return colour[0:1] + colour[0:1] + colour[1:2] + colour[1:2] + colour[2:3] + colour[2:3] + } + } + return colour +} diff --git a/vendor/github.com/alecthomas/chroma/v2/delegate.go b/vendor/github.com/alecthomas/chroma/v2/delegate.go new file mode 100644 index 000000000..298f2dbbd --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/delegate.go @@ -0,0 +1,161 @@ +package chroma + +import ( + "bytes" +) + +type delegatingLexer struct { + root Lexer + language Lexer +} + +// DelegatingLexer combines two lexers to handle the common case of a language embedded inside another, such as PHP +// inside HTML or PHP inside plain text. +// +// It takes two lexer as arguments: a root lexer and a language lexer. First everything is scanned using the language +// lexer, which must return "Other" for unrecognised tokens. Then all "Other" tokens are lexed using the root lexer. +// Finally, these two sets of tokens are merged. +// +// The lexers from the template lexer package use this base lexer. +func DelegatingLexer(root Lexer, language Lexer) Lexer { + return &delegatingLexer{ + root: root, + language: language, + } +} + +func (d *delegatingLexer) SetTracing(enable bool) { + if l, ok := d.language.(TracingLexer); ok { + l.SetTracing(enable) + } + if l, ok := d.root.(TracingLexer); ok { + l.SetTracing(enable) + } +} + +func (d *delegatingLexer) AnalyseText(text string) float32 { + return d.root.AnalyseText(text) +} + +func (d *delegatingLexer) SetAnalyser(analyser func(text string) float32) Lexer { + d.root.SetAnalyser(analyser) + return d +} + +func (d *delegatingLexer) SetRegistry(r *LexerRegistry) Lexer { + d.root.SetRegistry(r) + d.language.SetRegistry(r) + return d +} + +func (d *delegatingLexer) Config() *Config { + return d.language.Config() +} + +// An insertion is the character range where language tokens should be inserted. +type insertion struct { + start, end int + tokens []Token +} + +func (d *delegatingLexer) Tokenise(options *TokeniseOptions, text string) (Iterator, error) { // nolint: gocognit + tokens, err := Tokenise(Coalesce(d.language), options, text) + if err != nil { + return nil, err + } + // Compute insertions and gather "Other" tokens. + others := &bytes.Buffer{} + insertions := []*insertion{} + var insert *insertion + offset := 0 + var last Token + for _, t := range tokens { + if t.Type == Other { + if last != EOF && insert != nil && last.Type != Other { + insert.end = offset + } + others.WriteString(t.Value) + } else { + if last == EOF || last.Type == Other { + insert = &insertion{start: offset} + insertions = append(insertions, insert) + } + insert.tokens = append(insert.tokens, t) + } + last = t + offset += len(t.Value) + } + + if len(insertions) == 0 { + return d.root.Tokenise(options, text) + } + + // Lex the other tokens. + rootTokens, err := Tokenise(Coalesce(d.root), options, others.String()) + if err != nil { + return nil, err + } + + // Interleave the two sets of tokens. + var out []Token + offset = 0 // Offset into text. + tokenIndex := 0 + nextToken := func() Token { + if tokenIndex >= len(rootTokens) { + return EOF + } + t := rootTokens[tokenIndex] + tokenIndex++ + return t + } + insertionIndex := 0 + nextInsertion := func() *insertion { + if insertionIndex >= len(insertions) { + return nil + } + i := insertions[insertionIndex] + insertionIndex++ + return i + } + t := nextToken() + i := nextInsertion() + for t != EOF || i != nil { + // fmt.Printf("%d->%d:%q %d->%d:%q\n", offset, offset+len(t.Value), t.Value, i.start, i.end, Stringify(i.tokens...)) + if t == EOF || (i != nil && i.start < offset+len(t.Value)) { + var l Token + l, t = splitToken(t, i.start-offset) + if l != EOF { + out = append(out, l) + offset += len(l.Value) + } + out = append(out, i.tokens...) + offset += i.end - i.start + if t == EOF { + t = nextToken() + } + i = nextInsertion() + } else { + out = append(out, t) + offset += len(t.Value) + t = nextToken() + } + } + return Literator(out...), nil +} + +func splitToken(t Token, offset int) (l Token, r Token) { + if t == EOF { + return EOF, EOF + } + if offset == 0 { + return EOF, t + } + if offset == len(t.Value) { + return t, EOF + } + l = t.Clone() + r = t.Clone() + l.Value = l.Value[:offset] + r.Value = r.Value[offset:] + return +} diff --git a/vendor/github.com/alecthomas/chroma/v2/doc.go b/vendor/github.com/alecthomas/chroma/v2/doc.go new file mode 100644 index 000000000..4dde77c81 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/doc.go @@ -0,0 +1,7 @@ +// Package chroma takes source code and other structured text and converts it into syntax highlighted HTML, ANSI- +// coloured text, etc. +// +// Chroma is based heavily on Pygments, and includes translators for Pygments lexers and styles. +// +// For more information, go here: https://github.com/alecthomas/chroma +package chroma diff --git a/vendor/github.com/alecthomas/chroma/v2/emitters.go b/vendor/github.com/alecthomas/chroma/v2/emitters.go new file mode 100644 index 000000000..1097a7576 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/emitters.go @@ -0,0 +1,233 @@ +package chroma + +import ( + "fmt" +) + +// An Emitter takes group matches and returns tokens. +type Emitter interface { + // Emit tokens for the given regex groups. + Emit(groups []string, state *LexerState) Iterator +} + +// ValidatingEmitter is an Emitter that can validate against a compiled rule. +type ValidatingEmitter interface { + Emitter + ValidateEmitter(rule *CompiledRule) error +} + +// SerialisableEmitter is an Emitter that can be serialised and deserialised to/from JSON. +type SerialisableEmitter interface { + Emitter + EmitterKind() string +} + +// EmitterFunc is a function that is an Emitter. +type EmitterFunc func(groups []string, state *LexerState) Iterator + +// Emit tokens for groups. +func (e EmitterFunc) Emit(groups []string, state *LexerState) Iterator { + return e(groups, state) +} + +type Emitters []Emitter + +type byGroupsEmitter struct { + Emitters +} + +var _ ValidatingEmitter = (*byGroupsEmitter)(nil) + +// ByGroups emits a token for each matching group in the rule's regex. +func ByGroups(emitters ...Emitter) Emitter { + return &byGroupsEmitter{Emitters: emitters} +} + +func (b *byGroupsEmitter) EmitterKind() string { return "bygroups" } + +func (b *byGroupsEmitter) ValidateEmitter(rule *CompiledRule) error { + if len(rule.Regexp.GetGroupNumbers())-1 != len(b.Emitters) { + return fmt.Errorf("number of groups %d does not match number of emitters %d", len(rule.Regexp.GetGroupNumbers())-1, len(b.Emitters)) + } + return nil +} + +func (b *byGroupsEmitter) Emit(groups []string, state *LexerState) Iterator { + iterators := make([]Iterator, 0, len(groups)-1) + if len(b.Emitters) != len(groups)-1 { + iterators = append(iterators, Error.Emit(groups, state)) + // panic(errors.Errorf("number of groups %q does not match number of emitters %v", groups, emitters)) + } else { + for i, group := range groups[1:] { + if b.Emitters[i] != nil { + iterators = append(iterators, b.Emitters[i].Emit([]string{group}, state)) + } + } + } + return Concaterator(iterators...) +} + +// ByGroupNames emits a token for each named matching group in the rule's regex. +func ByGroupNames(emitters map[string]Emitter) Emitter { + return EmitterFunc(func(groups []string, state *LexerState) Iterator { + iterators := make([]Iterator, 0, len(state.NamedGroups)-1) + if len(state.NamedGroups)-1 == 0 { + if emitter, ok := emitters[`0`]; ok { + iterators = append(iterators, emitter.Emit(groups, state)) + } else { + iterators = append(iterators, Error.Emit(groups, state)) + } + } else { + ruleRegex := state.Rules[state.State][state.Rule].Regexp + for i := 1; i < len(state.NamedGroups); i++ { + groupName := ruleRegex.GroupNameFromNumber(i) + group := state.NamedGroups[groupName] + if emitter, ok := emitters[groupName]; ok { + if emitter != nil { + iterators = append(iterators, emitter.Emit([]string{group}, state)) + } + } else { + iterators = append(iterators, Error.Emit([]string{group}, state)) + } + } + } + return Concaterator(iterators...) + }) +} + +// UsingByGroup emits tokens for the matched groups in the regex using a +// sublexer. Used when lexing code blocks where the name of a sublexer is +// contained within the block, for example on a Markdown text block or SQL +// language block. +// +// An attempt to load the sublexer will be made using the captured value from +// the text of the matched sublexerNameGroup. If a sublexer matching the +// sublexerNameGroup is available, then tokens for the matched codeGroup will +// be emitted using the sublexer. Otherwise, if no sublexer is available, then +// tokens will be emitted from the passed emitter. +// +// Example: +// +// var Markdown = internal.Register(MustNewLexer( +// &Config{ +// Name: "markdown", +// Aliases: []string{"md", "mkd"}, +// Filenames: []string{"*.md", "*.mkd", "*.markdown"}, +// MimeTypes: []string{"text/x-markdown"}, +// }, +// Rules{ +// "root": { +// {"^(```)(\\w+)(\\n)([\\w\\W]*?)(^```$)", +// UsingByGroup( +// 2, 4, +// String, String, String, Text, String, +// ), +// nil, +// }, +// }, +// }, +// )) +// +// See the lexers/markdown.go for the complete example. +// +// Note: panic's if the number of emitters does not equal the number of matched +// groups in the regex. +func UsingByGroup(sublexerNameGroup, codeGroup int, emitters ...Emitter) Emitter { + return &usingByGroup{ + SublexerNameGroup: sublexerNameGroup, + CodeGroup: codeGroup, + Emitters: emitters, + } +} + +type usingByGroup struct { + SublexerNameGroup int `xml:"sublexer_name_group"` + CodeGroup int `xml:"code_group"` + Emitters Emitters `xml:"emitters"` +} + +func (u *usingByGroup) EmitterKind() string { return "usingbygroup" } +func (u *usingByGroup) Emit(groups []string, state *LexerState) Iterator { + // bounds check + if len(u.Emitters) != len(groups)-1 { + panic("UsingByGroup expects number of emitters to be the same as len(groups)-1") + } + + // grab sublexer + sublexer := state.Registry.Get(groups[u.SublexerNameGroup]) + + // build iterators + iterators := make([]Iterator, len(groups)-1) + for i, group := range groups[1:] { + if i == u.CodeGroup-1 && sublexer != nil { + var err error + iterators[i], err = sublexer.Tokenise(nil, groups[u.CodeGroup]) + if err != nil { + panic(err) + } + } else if u.Emitters[i] != nil { + iterators[i] = u.Emitters[i].Emit([]string{group}, state) + } + } + return Concaterator(iterators...) +} + +// UsingLexer returns an Emitter that uses a given Lexer for parsing and emitting. +// +// This Emitter is not serialisable. +func UsingLexer(lexer Lexer) Emitter { + return EmitterFunc(func(groups []string, _ *LexerState) Iterator { + it, err := lexer.Tokenise(&TokeniseOptions{State: "root", Nested: true}, groups[0]) + if err != nil { + panic(err) + } + return it + }) +} + +type usingEmitter struct { + Lexer string `xml:"lexer,attr"` +} + +func (u *usingEmitter) EmitterKind() string { return "using" } + +func (u *usingEmitter) Emit(groups []string, state *LexerState) Iterator { + if state.Registry == nil { + panic(fmt.Sprintf("no LexerRegistry available for Using(%q)", u.Lexer)) + } + lexer := state.Registry.Get(u.Lexer) + if lexer == nil { + panic(fmt.Sprintf("no such lexer %q", u.Lexer)) + } + it, err := lexer.Tokenise(&TokeniseOptions{State: "root", Nested: true}, groups[0]) + if err != nil { + panic(err) + } + return it +} + +// Using returns an Emitter that uses a given Lexer reference for parsing and emitting. +// +// The referenced lexer must be stored in the same LexerRegistry. +func Using(lexer string) Emitter { + return &usingEmitter{Lexer: lexer} +} + +type usingSelfEmitter struct { + State string `xml:"state,attr"` +} + +func (u *usingSelfEmitter) EmitterKind() string { return "usingself" } + +func (u *usingSelfEmitter) Emit(groups []string, state *LexerState) Iterator { + it, err := state.Lexer.Tokenise(&TokeniseOptions{State: u.State, Nested: true}, groups[0]) + if err != nil { + panic(err) + } + return it +} + +// UsingSelf is like Using, but uses the current Lexer. +func UsingSelf(stateName string) Emitter { + return &usingSelfEmitter{stateName} +} diff --git a/vendor/github.com/alecthomas/chroma/v2/formatter.go b/vendor/github.com/alecthomas/chroma/v2/formatter.go new file mode 100644 index 000000000..00dd5d8df --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/formatter.go @@ -0,0 +1,43 @@ +package chroma + +import ( + "io" +) + +// A Formatter for Chroma lexers. +type Formatter interface { + // Format returns a formatting function for tokens. + // + // If the iterator panics, the Formatter should recover. + Format(w io.Writer, style *Style, iterator Iterator) error +} + +// A FormatterFunc is a Formatter implemented as a function. +// +// Guards against iterator panics. +type FormatterFunc func(w io.Writer, style *Style, iterator Iterator) error + +func (f FormatterFunc) Format(w io.Writer, s *Style, it Iterator) (err error) { // nolint + defer func() { + if perr := recover(); perr != nil { + err = perr.(error) + } + }() + return f(w, s, it) +} + +type recoveringFormatter struct { + Formatter +} + +func (r recoveringFormatter) Format(w io.Writer, s *Style, it Iterator) (err error) { + defer func() { + if perr := recover(); perr != nil { + err = perr.(error) + } + }() + return r.Formatter.Format(w, s, it) +} + +// RecoveringFormatter wraps a formatter with panic recovery. +func RecoveringFormatter(formatter Formatter) Formatter { return recoveringFormatter{formatter} } diff --git a/vendor/github.com/alecthomas/chroma/v2/formatters/api.go b/vendor/github.com/alecthomas/chroma/v2/formatters/api.go new file mode 100644 index 000000000..9ca0d01dd --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/formatters/api.go @@ -0,0 +1,57 @@ +package formatters + +import ( + "io" + "sort" + + "github.com/alecthomas/chroma/v2" + "github.com/alecthomas/chroma/v2/formatters/html" + "github.com/alecthomas/chroma/v2/formatters/svg" +) + +var ( + // NoOp formatter. + NoOp = Register("noop", chroma.FormatterFunc(func(w io.Writer, s *chroma.Style, iterator chroma.Iterator) error { + for t := iterator(); t != chroma.EOF; t = iterator() { + if _, err := io.WriteString(w, t.Value); err != nil { + return err + } + } + return nil + })) + // Default HTML formatter outputs self-contained HTML. + htmlFull = Register("html", html.New(html.Standalone(true), html.WithClasses(true))) // nolint + SVG = Register("svg", svg.New(svg.EmbedFont("Liberation Mono", svg.FontLiberationMono, svg.WOFF))) +) + +// Fallback formatter. +var Fallback = NoOp + +// Registry of Formatters. +var Registry = map[string]chroma.Formatter{} + +// Names of registered formatters. +func Names() []string { + out := []string{} + for name := range Registry { + out = append(out, name) + } + sort.Strings(out) + return out +} + +// Get formatter by name. +// +// If the given formatter is not found, the Fallback formatter will be returned. +func Get(name string) chroma.Formatter { + if f, ok := Registry[name]; ok { + return f + } + return Fallback +} + +// Register a named formatter. +func Register(name string, formatter chroma.Formatter) chroma.Formatter { + Registry[name] = formatter + return formatter +} diff --git a/vendor/github.com/alecthomas/chroma/v2/formatters/html/html.go b/vendor/github.com/alecthomas/chroma/v2/formatters/html/html.go new file mode 100644 index 000000000..1aaafd0f4 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/formatters/html/html.go @@ -0,0 +1,648 @@ +package html + +import ( + "fmt" + "html" + "io" + "sort" + "strconv" + "strings" + "sync" + + "github.com/alecthomas/chroma/v2" +) + +// Option sets an option of the HTML formatter. +type Option func(f *Formatter) + +// Standalone configures the HTML formatter for generating a standalone HTML document. +func Standalone(b bool) Option { return func(f *Formatter) { f.standalone = b } } + +// ClassPrefix sets the CSS class prefix. +func ClassPrefix(prefix string) Option { return func(f *Formatter) { f.prefix = prefix } } + +// WithClasses emits HTML using CSS classes, rather than inline styles. +func WithClasses(b bool) Option { return func(f *Formatter) { f.Classes = b } } + +// WithAllClasses disables an optimisation that omits redundant CSS classes. +func WithAllClasses(b bool) Option { return func(f *Formatter) { f.allClasses = b } } + +// WithCustomCSS sets user's custom CSS styles. +func WithCustomCSS(css map[chroma.TokenType]string) Option { + return func(f *Formatter) { + f.customCSS = css + } +} + +// WithCSSComments adds prefixe comments to the css classes. Defaults to true. +func WithCSSComments(b bool) Option { return func(f *Formatter) { f.writeCSSComments = b } } + +// TabWidth sets the number of characters for a tab. Defaults to 8. +func TabWidth(width int) Option { return func(f *Formatter) { f.tabWidth = width } } + +// PreventSurroundingPre prevents the surrounding pre tags around the generated code. +func PreventSurroundingPre(b bool) Option { + return func(f *Formatter) { + f.preventSurroundingPre = b + + if b { + f.preWrapper = nopPreWrapper + } else { + f.preWrapper = defaultPreWrapper + } + } +} + +// InlineCode creates inline code wrapped in a code tag. +func InlineCode(b bool) Option { + return func(f *Formatter) { + f.inlineCode = b + f.preWrapper = preWrapper{ + start: func(code bool, styleAttr string) string { + if code { + return fmt.Sprintf(``, styleAttr) + } + + return `` + }, + end: func(code bool) string { + if code { + return `` + } + + return `` + }, + } + } +} + +// WithPreWrapper allows control of the surrounding pre tags. +func WithPreWrapper(wrapper PreWrapper) Option { + return func(f *Formatter) { + f.preWrapper = wrapper + } +} + +// WrapLongLines wraps long lines. +func WrapLongLines(b bool) Option { + return func(f *Formatter) { + f.wrapLongLines = b + } +} + +// WithLineNumbers formats output with line numbers. +func WithLineNumbers(b bool) Option { + return func(f *Formatter) { + f.lineNumbers = b + } +} + +// LineNumbersInTable will, when combined with WithLineNumbers, separate the line numbers +// and code in table td's, which make them copy-and-paste friendly. +func LineNumbersInTable(b bool) Option { + return func(f *Formatter) { + f.lineNumbersInTable = b + } +} + +// WithLinkableLineNumbers decorates the line numbers HTML elements with an "id" +// attribute so they can be linked. +func WithLinkableLineNumbers(b bool, prefix string) Option { + return func(f *Formatter) { + f.linkableLineNumbers = b + f.lineNumbersIDPrefix = prefix + } +} + +// HighlightLines higlights the given line ranges with the Highlight style. +// +// A range is the beginning and ending of a range as 1-based line numbers, inclusive. +func HighlightLines(ranges [][2]int) Option { + return func(f *Formatter) { + f.highlightRanges = ranges + sort.Sort(f.highlightRanges) + } +} + +// BaseLineNumber sets the initial number to start line numbering at. Defaults to 1. +func BaseLineNumber(n int) Option { + return func(f *Formatter) { + f.baseLineNumber = n + } +} + +// New HTML formatter. +func New(options ...Option) *Formatter { + f := &Formatter{ + baseLineNumber: 1, + preWrapper: defaultPreWrapper, + writeCSSComments: true, + } + f.styleCache = newStyleCache(f) + for _, option := range options { + option(f) + } + return f +} + +// PreWrapper defines the operations supported in WithPreWrapper. +type PreWrapper interface { + // Start is called to write a start

 element.
+	// The code flag tells whether this block surrounds
+	// highlighted code. This will be false when surrounding
+	// line numbers.
+	Start(code bool, styleAttr string) string
+
+	// End is called to write the end 
element. + End(code bool) string +} + +type preWrapper struct { + start func(code bool, styleAttr string) string + end func(code bool) string +} + +func (p preWrapper) Start(code bool, styleAttr string) string { + return p.start(code, styleAttr) +} + +func (p preWrapper) End(code bool) string { + return p.end(code) +} + +var ( + nopPreWrapper = preWrapper{ + start: func(code bool, styleAttr string) string { return "" }, + end: func(code bool) string { return "" }, + } + defaultPreWrapper = preWrapper{ + start: func(code bool, styleAttr string) string { + if code { + return fmt.Sprintf(``, styleAttr) + } + + return fmt.Sprintf(``, styleAttr) + }, + end: func(code bool) string { + if code { + return `` + } + + return `` + }, + } +) + +// Formatter that generates HTML. +type Formatter struct { + styleCache *styleCache + standalone bool + prefix string + Classes bool // Exported field to detect when classes are being used + allClasses bool + customCSS map[chroma.TokenType]string + writeCSSComments bool + preWrapper PreWrapper + inlineCode bool + preventSurroundingPre bool + tabWidth int + wrapLongLines bool + lineNumbers bool + lineNumbersInTable bool + linkableLineNumbers bool + lineNumbersIDPrefix string + highlightRanges highlightRanges + baseLineNumber int +} + +type highlightRanges [][2]int + +func (h highlightRanges) Len() int { return len(h) } +func (h highlightRanges) Swap(i, j int) { h[i], h[j] = h[j], h[i] } +func (h highlightRanges) Less(i, j int) bool { return h[i][0] < h[j][0] } + +func (f *Formatter) Format(w io.Writer, style *chroma.Style, iterator chroma.Iterator) (err error) { + return f.writeHTML(w, style, iterator.Tokens()) +} + +// We deliberately don't use html/template here because it is two orders of magnitude slower (benchmarked). +// +// OTOH we need to be super careful about correct escaping... +func (f *Formatter) writeHTML(w io.Writer, style *chroma.Style, tokens []chroma.Token) (err error) { // nolint: gocyclo + css := f.styleCache.get(style, true) + if f.standalone { + fmt.Fprint(w, "\n") + if f.Classes { + fmt.Fprint(w, "") + } + fmt.Fprintf(w, "\n", f.styleAttr(css, chroma.Background)) + } + + wrapInTable := f.lineNumbers && f.lineNumbersInTable + + lines := chroma.SplitTokensIntoLines(tokens) + lineDigits := len(strconv.Itoa(f.baseLineNumber + len(lines) - 1)) + highlightIndex := 0 + + if wrapInTable { + // List line numbers in its own + fmt.Fprintf(w, "\n", f.styleAttr(css, chroma.PreWrapper)) + fmt.Fprintf(w, "", f.styleAttr(css, chroma.LineTable)) + fmt.Fprintf(w, "\n", f.styleAttr(css, chroma.LineTableTD)) + fmt.Fprintf(w, "%s", f.preWrapper.Start(false, f.styleAttr(css, chroma.PreWrapper))) + for index := range lines { + line := f.baseLineNumber + index + highlight, next := f.shouldHighlight(highlightIndex, line) + if next { + highlightIndex++ + } + if highlight { + fmt.Fprintf(w, "", f.styleAttr(css, chroma.LineHighlight)) + } + + fmt.Fprintf(w, "%s\n", f.styleAttr(css, chroma.LineNumbersTable), f.lineIDAttribute(line), f.lineTitleWithLinkIfNeeded(css, lineDigits, line)) + + if highlight { + fmt.Fprintf(w, "") + } + } + fmt.Fprint(w, f.preWrapper.End(false)) + fmt.Fprint(w, "\n") + fmt.Fprintf(w, "\n", f.styleAttr(css, chroma.LineTableTD, "width:100%")) + } + + fmt.Fprintf(w, "%s", f.preWrapper.Start(true, f.styleAttr(css, chroma.PreWrapper))) + + highlightIndex = 0 + for index, tokens := range lines { + // 1-based line number. + line := f.baseLineNumber + index + highlight, next := f.shouldHighlight(highlightIndex, line) + if next { + highlightIndex++ + } + + if !(f.preventSurroundingPre || f.inlineCode) { + // Start of Line + fmt.Fprint(w, ``) + } else { + fmt.Fprintf(w, "%s>", f.styleAttr(css, chroma.Line)) + } + + // Line number + if f.lineNumbers && !wrapInTable { + fmt.Fprintf(w, "%s", f.styleAttr(css, chroma.LineNumbers), f.lineIDAttribute(line), f.lineTitleWithLinkIfNeeded(css, lineDigits, line)) + } + + fmt.Fprintf(w, ``, f.styleAttr(css, chroma.CodeLine)) + } + + for _, token := range tokens { + html := html.EscapeString(token.String()) + attr := f.styleAttr(css, token.Type) + if attr != "" { + html = fmt.Sprintf("%s", attr, html) + } + fmt.Fprint(w, html) + } + + if !(f.preventSurroundingPre || f.inlineCode) { + fmt.Fprint(w, ``) // End of CodeLine + + fmt.Fprint(w, ``) // End of Line + } + } + fmt.Fprintf(w, "%s", f.preWrapper.End(true)) + + if wrapInTable { + fmt.Fprint(w, "\n") + fmt.Fprint(w, "\n") + } + + if f.standalone { + fmt.Fprint(w, "\n\n") + fmt.Fprint(w, "\n") + } + + return nil +} + +func (f *Formatter) lineIDAttribute(line int) string { + if !f.linkableLineNumbers { + return "" + } + return fmt.Sprintf(" id=\"%s\"", f.lineID(line)) +} + +func (f *Formatter) lineTitleWithLinkIfNeeded(css map[chroma.TokenType]string, lineDigits, line int) string { + title := fmt.Sprintf("%*d", lineDigits, line) + if !f.linkableLineNumbers { + return title + } + return fmt.Sprintf("%s", f.styleAttr(css, chroma.LineLink), f.lineID(line), title) +} + +func (f *Formatter) lineID(line int) string { + return fmt.Sprintf("%s%d", f.lineNumbersIDPrefix, line) +} + +func (f *Formatter) shouldHighlight(highlightIndex, line int) (bool, bool) { + next := false + for highlightIndex < len(f.highlightRanges) && line > f.highlightRanges[highlightIndex][1] { + highlightIndex++ + next = true + } + if highlightIndex < len(f.highlightRanges) { + hrange := f.highlightRanges[highlightIndex] + if line >= hrange[0] && line <= hrange[1] { + return true, next + } + } + return false, next +} + +func (f *Formatter) class(t chroma.TokenType) string { + for t != 0 { + if cls, ok := chroma.StandardTypes[t]; ok { + if cls != "" { + return f.prefix + cls + } + return "" + } + t = t.Parent() + } + if cls := chroma.StandardTypes[t]; cls != "" { + return f.prefix + cls + } + return "" +} + +func (f *Formatter) styleAttr(styles map[chroma.TokenType]string, tt chroma.TokenType, extraCSS ...string) string { + if f.Classes { + cls := f.class(tt) + if cls == "" { + return "" + } + return fmt.Sprintf(` class="%s"`, cls) + } + if _, ok := styles[tt]; !ok { + tt = tt.SubCategory() + if _, ok := styles[tt]; !ok { + tt = tt.Category() + if _, ok := styles[tt]; !ok { + return "" + } + } + } + css := []string{styles[tt]} + css = append(css, extraCSS...) + return fmt.Sprintf(` style="%s"`, strings.Join(css, ";")) +} + +func (f *Formatter) tabWidthStyle() string { + if f.tabWidth != 0 && f.tabWidth != 8 { + return fmt.Sprintf("-moz-tab-size: %[1]d; -o-tab-size: %[1]d; tab-size: %[1]d;", f.tabWidth) + } + return "" +} + +func (f *Formatter) writeCSSRule(w io.Writer, comment string, selector string, styles string) error { + if styles == "" { + return nil + } + if f.writeCSSComments && comment != "" { + if _, err := fmt.Fprintf(w, "/* %s */ ", comment); err != nil { + return err + } + } + if _, err := fmt.Fprintf(w, "%s { %s }\n", selector, styles); err != nil { + return err + } + return nil +} + +// WriteCSS writes CSS style definitions (without any surrounding HTML). +func (f *Formatter) WriteCSS(w io.Writer, style *chroma.Style) error { + css := f.styleCache.get(style, false) + + // Special-case background as it is mapped to the outer ".chroma" class. + if err := f.writeCSSRule(w, chroma.Background.String(), fmt.Sprintf(".%sbg", f.prefix), css[chroma.Background]); err != nil { + return err + } + // Special-case PreWrapper as it is the ".chroma" class. + if err := f.writeCSSRule(w, chroma.PreWrapper.String(), fmt.Sprintf(".%schroma", f.prefix), css[chroma.PreWrapper]); err != nil { + return err + } + // Special-case code column of table to expand width. + if f.lineNumbers && f.lineNumbersInTable { + selector := fmt.Sprintf(".%schroma .%s:last-child", f.prefix, f.class(chroma.LineTableTD)) + if err := f.writeCSSRule(w, chroma.LineTableTD.String(), selector, "width: 100%;"); err != nil { + return err + } + } + // Special-case line number highlighting when targeted. + if f.lineNumbers || f.lineNumbersInTable { + targetedLineCSS := StyleEntryToCSS(style.Get(chroma.LineHighlight)) + for _, tt := range []chroma.TokenType{chroma.LineNumbers, chroma.LineNumbersTable} { + comment := fmt.Sprintf("%s targeted by URL anchor", tt) + selector := fmt.Sprintf(".%schroma .%s:target", f.prefix, f.class(tt)) + if err := f.writeCSSRule(w, comment, selector, targetedLineCSS); err != nil { + return err + } + } + } + tts := []int{} + for tt := range css { + tts = append(tts, int(tt)) + } + sort.Ints(tts) + for _, ti := range tts { + tt := chroma.TokenType(ti) + switch tt { + case chroma.Background, chroma.PreWrapper: + continue + } + class := f.class(tt) + if class == "" { + continue + } + if err := f.writeCSSRule(w, tt.String(), fmt.Sprintf(".%schroma .%s", f.prefix, class), css[tt]); err != nil { + return err + } + } + return nil +} + +func (f *Formatter) styleToCSS(style *chroma.Style) map[chroma.TokenType]string { + classes := map[chroma.TokenType]string{} + bg := style.Get(chroma.Background) + // Convert the style. + for t := range chroma.StandardTypes { + entry := style.Get(t) + if t != chroma.Background { + entry = entry.Sub(bg) + } + + // Inherit from custom CSS provided by user + tokenCategory := t.Category() + tokenSubCategory := t.SubCategory() + if t != tokenCategory { + if css, ok := f.customCSS[tokenCategory]; ok { + classes[t] = css + } + } + if tokenCategory != tokenSubCategory { + if css, ok := f.customCSS[tokenSubCategory]; ok { + classes[t] += css + } + } + // Add custom CSS provided by user + if css, ok := f.customCSS[t]; ok { + classes[t] += css + } + + if !f.allClasses && entry.IsZero() && classes[t] == `` { + continue + } + + styleEntryCSS := StyleEntryToCSS(entry) + if styleEntryCSS != `` && classes[t] != `` { + styleEntryCSS += `;` + } + classes[t] = styleEntryCSS + classes[t] + } + classes[chroma.Background] += `;` + f.tabWidthStyle() + classes[chroma.PreWrapper] += classes[chroma.Background] + classes[chroma.PreWrapper] += ` -webkit-text-size-adjust: none;` + // Make PreWrapper a grid to show highlight style with full width. + if len(f.highlightRanges) > 0 && f.customCSS[chroma.PreWrapper] == `` { + classes[chroma.PreWrapper] += `display: grid;` + } + // Make PreWrapper wrap long lines. + if f.wrapLongLines { + classes[chroma.PreWrapper] += `white-space: pre-wrap; word-break: break-word;` + } + lineNumbersStyle := `white-space: pre; -webkit-user-select: none; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;` + // All rules begin with default rules followed by user provided rules + classes[chroma.Line] = `display: flex;` + classes[chroma.Line] + classes[chroma.LineNumbers] = lineNumbersStyle + classes[chroma.LineNumbers] + classes[chroma.LineNumbersTable] = lineNumbersStyle + classes[chroma.LineNumbersTable] + classes[chroma.LineTable] = "border-spacing: 0; padding: 0; margin: 0; border: 0;" + classes[chroma.LineTable] + classes[chroma.LineTableTD] = "vertical-align: top; padding: 0; margin: 0; border: 0;" + classes[chroma.LineTableTD] + classes[chroma.LineLink] = "outline: none; text-decoration: none; color: inherit" + classes[chroma.LineLink] + return classes +} + +// StyleEntryToCSS converts a chroma.StyleEntry to CSS attributes. +func StyleEntryToCSS(e chroma.StyleEntry) string { + styles := []string{} + if e.Colour.IsSet() { + styles = append(styles, "color: "+e.Colour.String()) + } + if e.Background.IsSet() { + styles = append(styles, "background-color: "+e.Background.String()) + } + if e.Bold == chroma.Yes { + styles = append(styles, "font-weight: bold") + } + if e.Italic == chroma.Yes { + styles = append(styles, "font-style: italic") + } + if e.Underline == chroma.Yes { + styles = append(styles, "text-decoration: underline") + } + return strings.Join(styles, "; ") +} + +// Compress CSS attributes - remove spaces, transform 6-digit colours to 3. +func compressStyle(s string) string { + parts := strings.Split(s, ";") + out := []string{} + for _, p := range parts { + p = strings.Join(strings.Fields(p), " ") + p = strings.Replace(p, ": ", ":", 1) + if strings.Contains(p, "#") { + c := p[len(p)-6:] + if c[0] == c[1] && c[2] == c[3] && c[4] == c[5] { + p = p[:len(p)-6] + c[0:1] + c[2:3] + c[4:5] + } + } + out = append(out, p) + } + return strings.Join(out, ";") +} + +const styleCacheLimit = 32 + +type styleCacheEntry struct { + style *chroma.Style + compressed bool + cache map[chroma.TokenType]string +} + +type styleCache struct { + mu sync.Mutex + // LRU cache of compiled (and possibly compressed) styles. This is a slice + // because the cache size is small, and a slice is sufficiently fast for + // small N. + cache []styleCacheEntry + f *Formatter +} + +func newStyleCache(f *Formatter) *styleCache { + return &styleCache{f: f} +} + +func (l *styleCache) get(style *chroma.Style, compress bool) map[chroma.TokenType]string { + l.mu.Lock() + defer l.mu.Unlock() + + // Look for an existing entry. + for i := len(l.cache) - 1; i >= 0; i-- { + entry := l.cache[i] + if entry.style == style && entry.compressed == compress { + // Top of the cache, no need to adjust the order. + if i == len(l.cache)-1 { + return entry.cache + } + // Move this entry to the end of the LRU + copy(l.cache[i:], l.cache[i+1:]) + l.cache[len(l.cache)-1] = entry + return entry.cache + } + } + + // No entry, create one. + cached := l.f.styleToCSS(style) + if !l.f.Classes { + for t, style := range cached { + cached[t] = compressStyle(style) + } + } + if compress { + for t, style := range cached { + cached[t] = compressStyle(style) + } + } + // Evict the oldest entry. + if len(l.cache) >= styleCacheLimit { + l.cache = l.cache[0:copy(l.cache, l.cache[1:])] + } + l.cache = append(l.cache, styleCacheEntry{style: style, cache: cached, compressed: compress}) + return cached +} diff --git a/vendor/github.com/alecthomas/chroma/v2/formatters/json.go b/vendor/github.com/alecthomas/chroma/v2/formatters/json.go new file mode 100644 index 000000000..436d3ce8c --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/formatters/json.go @@ -0,0 +1,39 @@ +package formatters + +import ( + "encoding/json" + "fmt" + "io" + + "github.com/alecthomas/chroma/v2" +) + +// JSON formatter outputs the raw token structures as JSON. +var JSON = Register("json", chroma.FormatterFunc(func(w io.Writer, s *chroma.Style, it chroma.Iterator) error { + if _, err := fmt.Fprintln(w, "["); err != nil { + return err + } + i := 0 + for t := it(); t != chroma.EOF; t = it() { + if i > 0 { + if _, err := fmt.Fprintln(w, ","); err != nil { + return err + } + } + i++ + bytes, err := json.Marshal(t) + if err != nil { + return err + } + if _, err := fmt.Fprint(w, " "+string(bytes)); err != nil { + return err + } + } + if _, err := fmt.Fprintln(w); err != nil { + return err + } + if _, err := fmt.Fprintln(w, "]"); err != nil { + return err + } + return nil +})) diff --git a/vendor/github.com/alecthomas/chroma/v2/formatters/svg/font_liberation_mono.go b/vendor/github.com/alecthomas/chroma/v2/formatters/svg/font_liberation_mono.go new file mode 100644 index 000000000..70d692ec4 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/formatters/svg/font_liberation_mono.go @@ -0,0 +1,51 @@ +// Digitized data copyright (c) 2010 Google Corporation +// with Reserved Font Arimo, Tinos and Cousine. +// Copyright (c) 2012 Red Hat, Inc. +// with Reserved Font Name Liberation. +// +// This Font Software is licensed under the SIL Open Font License, Version 1.1. +// This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL +// +// ----------------------------------------------------------- +// SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +// ----------------------------------------------------------- +// +// PREAMBLE +// The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others. +// +// The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives. +// +// DEFINITIONS +// "Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation. +// +// "Reserved Font Name" refers to any names specified as such after the copyright statement(s). +// +// "Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s). +// +// "Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment. +// +// "Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software. +// +// PERMISSION & CONDITIONS +// Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions: +// +// 1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself. +// +// 2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user. +// +// 3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users. +// +// 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission. +// +// 5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software. +// +// TERMINATION +// This license becomes null and void if any of the above conditions are not met. +// +// DISCLAIMER +// THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. + +package svg + +// Liberation Mono as base64 encoded woff (SIL Open Font License)[https://en.wikipedia.org/wiki/Liberation_fonts] +var FontLiberationMono = `d09GRgABAAAAAqtYABIAAAAEycAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAKrPAAAABwAAAAcdooU5UdERUYAAp6sAAAAcAAAAIZxBHoIR1BPUwACoNwAAApfAAAzLnW/WuJHU1VCAAKfHAAAAb4AAALi0BntuE9TLzIAAAIQAAAAYAAAAGAAbrqGY21hcAAADmgAAARSAAAGPmw6RjVjdnQgAAAbpAAAAZ8AAAKuZwZtV2ZwZ20AABK8AAAEqQAAB7R+YbYRZ2FzcAACnpwAAAAQAAAAEAAYAAlnbHlmAAA0mAACOjQAA8hUF/4NBGhlYWQAAAGUAAAANgAAADYELjhMaGhlYQAAAcwAAAAhAAAAJAjCBstobXR4AAACcAAAC/UAACV4+gaVVWxvY2EAAB1EAAAXVAAAJXwSZmZ8bWF4cAAAAfAAAAAgAAAAIA3VBMBuYW1lAAJuzAAABTkAAAumb4o3f3Bvc3QAAnQIAAAqlAAAW+Bx9Ia5cHJlcAAAF2gAAAQ8AAAFesjzjI8AAQAAAAIAABUZ4O5fDzz1Ah8IAAAAAADIQ3qnAAAAANiiczX8Jf2ZBfEH2QAAAAgAAAABAAAAAHjaY2BkYGBb+XcmAwNr5B/VX1WsHxmAIsiAMw4AmuUGmAAAAAABAAAJXgEiAEgAWwAGAAIAEAAvAFwAAAO5AxEAAwABAAMEzQGQAAUAAAWaBTMAAAEdBZoFMwAAA2EAZgISCAUCBwQJAgIFAgQE4AAK/0AAeP8AAAABAAAAADFBU0MAQAAg/iME5/5+AAAGqQJnYAABv9/3AAAEOgVFAAAAIAAOeNqlWglwVdUZvuc1tBiVzYBCEJSGarG4UMMmU9lk0QhWBAybVGoEpGkfJNIqiokELVQibQVEFptQi4hKiTjEWrApWNbijB1gKkyhTq3aCAiU0Zq82+8/5zvJn+t7SRjfzDf/uffs//nPv92Xtj+YH+CXtt8j9rW0/aY9yr2BwXx/Dd6dA8YBd+D5M6AAZWk7CjiF59nAPODXwNPAY8D9pMuBNUAJ8JRrb6a6MeowBfgO5ysD4qSCKvW8B9jE8idAEct5EToayAGWAOkcN4sYiflXgs4BbeXWFX6B8i+53gqgGFjENQstBSpJC4FqtL8QdJpqX8G2p4HfAdvY5xagPfcoPP0V8D54fQnbzarnvZ2vL/l1I9usxVyyn67AX4H55P8o986ufTjfoa/pxb087dra85kLejnoP4EHgEygLSB7eLb+/L8EEzmLMnUOGpmK/1Gs5p6WRJDFPkvI92TIIG9LIiiN4BF1DlGIfOXzLDQGKxpwviiNc4xUtIznksmzL+P6mqJxrjsVLePaYkA2eVzaDHovcJh3pJDjVBNyXxY6amVXnv+unnuzvoy8jNIWpBU81+IkVM6rM/ucJt2rnkdT5lPRHN4bofeR7qKMVJ4HDXjnsni+vPf27kWokXvSH/foqNprGtAPGK/2lsk2/XjWxbxLoucmo+4Y6Mc8Q+HVDPJ1jzqHhdSVY9F+r+KlnwN3N/gW56lkvx8CL1JP/IP8yVB8kj2/5vZgywHf+31eCgxTuvhh4KfA89SfmCd2EdY6263B6qFcopcqB6o8Rt0RL3t+D809o5Ik981wb3GOp+9DdRJ5g44MFlPW9Zp9v8lKZ72dZJ6+1A3y/h5VX+bsQ919nU1e6b3OUevQ7U9zj4+ovUblW/i/Tt3zMspoLuf3Z6fXU9LIvfPUy/tB4EmueZhDGIJ+m7yaxvKrwAbgu7xnV9ImpHPOnyldIjxdwDVtYLvuwA28D143LFb2c5HS2ddxvkXUaQvJB6/DiznWNyjPlcrmwv8I9rOP4DjrphPYT5jg/JUcqy/lQ8pbFU47mM6R93I+oYOJ8cx/z/MaSR6UK3s+FLiJ5yR4SJ1TifId8rimh7iWLRwP6zYXRHjUi+hCPoNnYTXLw9T9ebneRpshwEAAZ2L2ATIuZNnI3n8EejH9N6w5FlOAnjEngN4OVpeJrD3oYDIdYteCfh94w/lt9vkuYBvxhUPdeBUK0rYn/UrxTyrJY/gi4Qd4xh00VwCyjz5AJ66nIAnmED04biblu4iyu8v5lwIZO/w38BHmhi42zzWEtX3Q1ea2IKitCYLEM8CWIKgZAvoJ3r0EeiQIwhdAPwIuRbkv6HzXLtwN5PL5CNs+p3AWmAiMBm4GpqDNE3C1v+fGDHOA2wHMn5Cx2gb2V/NfN5/MFT4L3Mq2f3T9E6uBSrcGP29ipVrzbj7/Bs8vg2LMxAfoX+76h0NBy0C7A8vRZiOeK9CoHeg6vFsFinHCNzjfxSgPB7I57gpgLXDS7a22A2gBxz/CcQscEh+CYswAewoH4Xk79zUmNRJbgTdR3uHWlTgMQMoTu4DjwGXk6XiUXwRex/ifA4XAKaV7FjtZNe85ubL3BPXhgXq/1pdD8amfUbGH2PGLWB6p/Fpvx9NV3PEE68r5PIs6XvRwS9IbqCf28LmIerCC85bz3UbqxZ+wfivbLGe7auqkVcAkYDv32oE+9ia+92P2ok9wN8f174tJs1m+3u098TB5IO+upj+YF/F3q5zOCs9Rn11NOzqWejif+qmMOmwC/Zd0+sh+vHzyrrfy0wtV/TJlG+OKz7fRJ4uTetse8NzitLV7VKwodcNJ17N9BvkYqDGO0W/z4w1RdetpX6Lxpo9VczimP/PH6E+IPR/H8Waw/Xi+u5HtfuH2aW1BB9oBQ7vgbaD46V/nvFuUHdExz2DaiCnc90q2n0TbPxPYxzh9GO2YtzvZnH8p7WCpinU7Uq6yuQ4fM8n8I2if2hM307dI5/j+Wfb1TT5fS34t47rac51F7DdG0a6E1A8gH69S88bpR+U7vWZ1x1qH2nehT6GPah5QsiR+/R183sh4+CzQh/t9hTz1se8QnsN67t3TNJVXGMDxttA/Evm/ixgTuT85yk+7JUKncLyWlJ2VinL9Ys+s7iK1Mu7Xut7ZQCunF1KutrPvdjVWkeOnjU1S+d/ej7mfdLry1zVfbld+T6WiqfzT8ZS/DMpQlPo1HqM8zqDc9mHckkW/2tN8rkP28gOei/Rrw7XLeltznHHqHDpQH01yuraOZ3kcz8aPQWDWA7BhBrIUywDdDPwZOADcxPJOYBPLgq6wRZNA48CfOIZvx3qzm+U463eq/jJuKeaDz2H6AeMc7PM6gm3lnX0/l2X4i2aE1MHv6ejrxfap8ijUP0UeSQ7pVD1/Y5BpI/bicXfe8hxM5V1Zyvet2K47dcMwxj6Fzt8MbmWOairrr3KyVge5YwdcG8ld1dkPOZff0m7s5z0UudtM27eLtnFrvY23OimbcUhnxj2PE3sZq/djPFFO/XMZqffjxXd/E/gUEF90Iuv2cIx0ygbahZ+jvg31xBH6sodoSxCzx6CrTDuUTzq/3PLsKAEbZi5xeVObozns+ob/cX6wzSn2dPZYqEVX4k5CfOkeLs8XPAqKfRjwy/Qn7cJ+r7k6yzdp19qt11xJH7uLW5NpyfEkbhjq2plupBn1beQcwyreIdyPELF0iBgs3EEb/inPah718TruX2RCxl/tEAyiXuxBHwf60oynTRA+lNNebHI8lrVYvVZE2Srk+N6GjqOsvUNAdk2ti4+sfitxsmB50p/50U6MZ14hejJ+Oux4YfmBsoHuNqKHjjNHNJ/rkPtyBu8GKZ5L7IK1mS0uP27jmoFEa8ZiZxmLSftrYKugMxILYKtK6Mu+DfxN0Xsdwh97fzqSD0iWo9N5yUXNpM3JV1axfTQ/GaU/p5/pn6P5SZ/HiVKdk4zkKC0tolxEqc/rpKJN5UuS8fF0ClrQjPxlsjxmMtrcHJn3ozz1ec2mqPcnNB2cOgdq59rGvoOdjFmZX9ZIblzowCbqm0Obkr2ZtA+p6qMyluqsRzIWakommqLnm4v2VOeik9GiJsB8TyJsiDDDwerTJAiHO5+y9q2GqMvXpYD0Cwey/buqb7mDveeNoEH/t5L0L06O8CUAOj6RRTzpYO13I0gc4fjw6WpXKN8gBRrM061+nkSuQx3fX1XxeoXaY7GKpcvV2F/1HM/nXDRKHM5r31mN7LuRtTfAGfoKZxiXtE2+7sQ51Peqp/b+9nAITzYiS4zlE7Cf4dxIn6gcrCb8M7/5Jv4AnHB8Cz92sL5dMv5c7+bx1OZuztBO4RceBK4ADsEm5/A77AYHyYtYSE5UvnVDH5nJwBLmkjcT4j++7mC/qRdyPMkJtvNg3oq52+AF0AlAvrOL1nfeJ/lN1acN0db1N/cBhj5kF/o+XemzxYlujImn0V/vSR85ULn9iYz7clTM25H9fYwVb5EbLMEe+N3C+pgdGL+nkY/3MI+x28mJ5GntuBfQh+/H3Db0lXnwy9SWZzA/N4MxXKHjg/3OPcrllm1uZZXzKW1Ozv7PAOsrYKxSwH2hHOviZEHOTcoCX9Y0CjPT1QkV6Lrzfd8cRO9dLC/ybq77Xmzz/9OZR2hNXrTmt+Q5vBfTKYPdHaxMZRIiIwPoZ+cxrha6oEWulZ9OEoeBlxKLrXBnatbwXNvzXuczF1+mbGA1bfA6ys1U5a/w25rp6O6ruZO5b8kBnxCobzOfeeD98wIX+9k8f7qLTW3cyhxMLB3x7uX0Iycw7vX5BB3XTmVuaT5lu6WibRQiMbN5lDEhdK9ZGomXW6k42cfISeJju95R7GdzbkFQI98BakFr3H90bC67Bel7rp0d+3/87rwTz3LPakDl/kMvJCQGLAU9SBwgFZ5WAdhD+C/PY76r4rcN+cZwkD5VUzatCV+gcdsdNPHjGtZQntZgXfuwxrtBjwLvcN2yt0N8d4jfDuSbwlhgHtv8RaGK9YJZ/PZQoUHfc4S6Y9CN4YfME3R038Hsd83reJ7+TD1EBqCPgx3A+wLRPf8H1ZqAPAAAAHja5dT7U1ZFGAfw73sOr+dEvspVkHzZPQf3pICIigiEpHIJK5QSMzURbzWaZnQzHTUtSjJSHLyDDmSFERUgApqXbExnzIwGS/Ey5p55z5pZUVlT885wOonDL03TH9Azs7vz/LA7z35mngeAjJ41CC5nR0CSk7lu5QEBkYBLchIFElZLyfJS+Xl5tbxeLpNr5DPuULfXfdJ93X3Teyq6Mnp39J8knHhJNskj08h0MpPMIqtIMzlOOshF8hO5SbqpQoNoONWpQRNoIk2iaTSdZtAsWkiX0pfoZrqfHqVdmlsL1SI0XTO0BG2SVqAVaiXaFm2vLul99P56iB6uR+lEH6rH6bn6XH1BjBQTFKMxMIn1ZUEsjEWyQWwwi2dJLJ0tZmtYCStlZayC1bB61sQOskPsODvNvmSdzDLSjXHGBKPImGc8biw2lsYviV+WEFGr1Zb5JX+yP92f4R/vz/JP7o6xbceEolpKkZ+TV8gljsEGeY/c7o5yb3K3u7u88HY7BtUEJJJQkkvybxvMJmtICzlBviGXyS/kd8egLw2hEY5BrGMwkqb2GixyDMppda/BgNsGedoUbaZjUN5rEOwYDNSjbxsU6fNvGdB/McjvNShn1ayu1+CUY3DeMUjrNVhgLHQMiuKLHYOI2lK/y+/1pzgG4/yZ/pxuatu2aX9qH7MP2wfsZnuf3WQ32g12nT3GHm7HXiPihrguvhOmuCquiMviorggOsV5cU58Lc6KDvGVaBdnxBfiM3FMfCKOikPigGgTrWKfaBKNol5UiFKxXCwUhWKqYCJYBAjJ+sP6zfrRardOWyesGmurVWLFWUMsahHLa0VZEVY/y+P72XfB1+kb60v0aWamOcFMNZPNUWaiOcw0TGJGmsG8m3/Pr3Ef5/wK7+Cf8xP8KD/CW3kTb+B7eRWfyHN4Nh/CDc54DNcujbiUcGHjnPI5sZ4WT5Wn0rPTs8Oz3bMt8GRPj/zPo48U+Pfhwj80XM6c6AnpP97ouSkjAG70ceaLijsQiDvRFx70Q38EIRghCEUYwjEAEYjEQEThLmcqeREN4nSiBh0xGAwGA3djCIYiFnGIxzAkYDgSMQIjMQpJGI1kjEEKUpGGe5COscjAvRiH8ZiATGQhGzm4D7mYiPvxAB5EHiZhMvLxEB7GFBRgKh7BNDyK6ZiBmXgMs1CI2SjCHKf+17AOr+MNVGA7dmMP3sLbeBfvoBbv4X3UoR4f4CN8iAY0Yh/2oxktaEMrDuFjHMYR5QqewXwswELlKl5EDZ7Gk2oUXsAiNQ2l2KmOxrPqWDUDT2CZOkxNVIfLxWoKFmOlPAN7cRBrMQ9PqUmuAjVVTcASrFI45uJlvIptrjBXuNKhnFUuKpeUc8p5HFBX4pgrTelSA5Ubyg9qq9qmfIvlSqdyWbmGEpThFbyJ9diIcmzCBmzBVueHm1GFXajEr9I6aReKpR3STqkSK6TdUpVU+heLM5/fAAB42nVVz1PbRhTeFQYMGCJTyjDVIatu7MJgl3SStkApbG3J2HXTYgwzK+hBIiZjeuKUQ6ad8a2MSP+XJ3IxOeXaQ/+HHNpbOSbX9L2VTSAz1Qhr3/d+7vfeLmr78CDQ+3vt3dbOTz8++qH5faO+XfO9auU7tbX57cY362urX3/15Rf3Vz4vlxY/KxbuyU/duwtzefvOzPTU5ER2fGw0M2JxVhLAQx9GCiJfi6Qvo3q5JPyFrlcu+bIWgogE4CdTlPW6gWQEIhRQxE90Aw5BoeWTDyxVaqmuLbktNtgGpZAC/vKk6PODlsb1H54MBFyZ9SOzzhSNMI2C66KHqYqqFT7UnnZjP8QaeTI1WZXV48lyiSWTU7icwhUsytOEL25ys7AW/fXEYtlpSos79aMO7LS07zmuG5RLDZiRnlGxqgkJY1UYNyHFCZXOzkVSehU/79vsKFzOdWQn+lnDSIS+8Ygfx79DfhmWpAdLz/5ewJ0fQ0l6PixT1ObudZ7m+5QcRgu2FPEbhtuRV//eRqIBMlaw3zBaglUFvqtdepwach3HNSlqcRhH/Xe9IylsGSe5XHzqI91sR2OI/ruX5w7Ungdgh12+Hgy2XtttwketQw1WoSa6ESL4bkl31XHz1zY7/6dmSAuSgwy7LtFw3lfsCAXotXQqC3bkXDC1shyAFZLm1VDz8T5pekPNtXsosbfNto4hU2h0pI+Mn0fQO8Lp+oUaI22Yeeu4Mp7Ni7WVwNgKrKrROREwWkSS0OumA84NucS2EWbepp8rBxMU87NiTWIYiuNLPxy8T7sLGEAg0fXldBD2NCgPFyoadMxP7q+gRxRiw04800xYkacwJyvX3aWy/JO2Ni4DN5irAgsfD7xgxTfnSvhx6KUlUCzZ0pfswbvXyUPhvHjAHrLAI+P5Kk5Z0Y915wncDZ0OnrsnQjsuqAA7HEh9HNDYIUNLrx0zHIGZlT3dbMtm60CvDgpJFRQuU/A/CCO1k4bBAYRsISu05YwEaGgjIGq4kJUN/IXxQhb/bCTcoDS4lQ2hucOG1lgGLAn/2BvYkXwr6CiNU7U+jDZGIsap1h03cNOnXLJQLQaJ0SNLpNaHKrymUJHF+azWDURcLtDQCy2PZSC7AtSOpr0RPYblARmG80Gv9m5JN8hCmpiL6qFAZEJt2blJLmwb+Vqsf6BuDNUizspmO6bgchCQYeUNYDTCajXvmLuADrTEu1fYeKTNgY4Tpegwd9cpiGx0YtnWG8Ya75PfnGeUa5Y1eXOvUi7h1VZJJD9rJYqftQ/0pc2YONvTFxa3qmElSO6hTl8KxpRBLUIJJEGQQJF2Ucgae+dSMdYz2owBjPy4z5nBskOMs8d9K8XsNFHRJFLMQk0m1aihdQaxbIr1DGaehBFlanJUZdWEylnTlpNwgi4QeckZm+DsRY5PcydBr10D93kvmVBOatFDC5VWeLb/PvX+gX6RY+hmfjFRhR4cl4UuNhv/rfiiQ4Pya9CNw4AOG5vH1uDLgctNbJPcxELGcjApjyswJSuEbxG+leJjhI/jiPJ5ju497P0OcJqAQ+3ikRSf/OnE9hV1KsBLJbb/Kf8HKfchKQAAAHjaPVTdTyNVFL9nBhZZ2L3lq3QFvPNCg1ZpKYsx2tJbdO8ioAx0xyxggBgS3yzJdJ9pkHUxUloFWU1IwNfdJR0ghME0pcofsPwBXVsR9cENoyY+mnqmgDf5nd855875mntnwm6IEID3iAajF/wB3CGNhIGGzJCHSTe8j/4hZHs/SIIQQA7g828iv4W2zT1wcyfOSLgTbhIHQiqjE3e6ST/4iUbiKAFx7u3COB96KUpAnHu96EUmCspphEQISqWsVUPnDhDNhNd2gja9uktKbDZcB+9gAhu9mOBtTNCH3Hdhh9Du5R9r5F/4R+1gf4sO9pd4hf0peljybOMsfSZHraQlHVqwaQGzpqyoJZPn/Ll09Q9RYr+futlvp0H26+lLjJ5C2y8ngtET4CfCyX4uCnZYfFosFGVe7H5dFIWLZaCR9EI91m3gtUFZKwSfaT8F8xoJ14MTO7LRhOOlUQKO1URUhIQvAW2o4xG5xJ5BXlPyaj6eN/IVNA/HTd1s6ih6NHckH/4IP6huNpsFJevL5rLybDaelWiGZSRvJpSJZtKZQqbyYMvNFNNnquasGTcrzVKOt5oNLwvHPij76n5839iviO8ZexLdDe1au7IJ17jnUT+LGylDMoyccWzI3nQoLW1uGVtSbut4S/I+CT2RNh5D7tHxIyl8DSjxw3Wcg6B0IBSEjFM4eBOo69Prs+vyt2tu9o1wM99D/lDCHnbXnK3C7qV67Xqd+G41wDbD1XCLBPCO3b5gAbd4xwz7uqXE6Gp69XBV5qttXYKvOltQ1FJBV7wroZW5FWulkn4PtSQKtVyRvkq42ZeREiukwJcClvKmpGhqLiWRpCOpJGW7qJJ0tQpl2bcsDSemEtGE7FsCusSWvEsyX3I0CMch1OAUNcSHkEs5qNlpVsSBrXDV0Si+mHezzwcCbPFBkD1YCLDPBkps4z44FpQF34Ls+xTm5oHPV9cKHc8nipfrE8SL4NJudLu0qm5Zu4InO417U4iDUhGqdphblBXOGlrF5Hg/+1B0sQnkceQGf71WCbJW4Zfxpr+w1xJgVIYDuAGunR7GTaTmDmHCVd6OCUfVFmaNlEYkPtLzhuAj7R3iqQqFIRgSbWxQ9DPVhBb+EQzgebyLjfUjbiPSAgrCElJcQDM0aU5/k1YHVHP4qSbhlwb4fbW2zDBGQ3SKztEKSr10mEZpkhZoiVaF0GdROUrwJwGbTqgEE1LbdyIez6BZVRodNKrVCQMWjfaILfnIuHFl0SDa+MTdbYDlsfuJBOlrGzT8kbvGdNvYoDGDCreVOCqOtm0n6RvTY3rsnud8wYWqE48nFkMuG+UdBPFcLrAN8OixmH7hwQi0Yp57ZenR9ctA+1lUCJbB9HqM2EExjw46sQmj7KIYDTFSDtNRXJbETJO6h0zqZXMSQzCDft7L/71N6ued6pcVy8v1H5x2ib942q2SvUucQRDGf7vvu+JHiCmMpYKFTVqrFHavhZwiprA48A6xOBGMQkI05usSgt9oJIhyghYenAqCh6JJFAPXRLQTIeA/kKCEoMEm576O5wkeImkyA7PPzsw+M8OO2TW7vDQe9wlnbI64DynhGfhHFzf/yA9dYttkm/iPkn95rLDJArN8E/Q+G+rnFXG+5qRvsc0iw2wQY4SqW2k/Cc+LDPpI6PbqKsFjupmTuu+E7wvNalA5hHlClHWp3eAuuykb4FAlSakCetUDPSE9THBgvrv7NwjHSdAudk1s7MKhjxnX1XTouOMxIBOGdUDcKaldz5wK0swb2qQLBEVyuCqdWvroFfT0esS8TS9T5P+RjgcYlU7a6CJIYzac1I7YEadcplliNeMbunqbN+906g2dfzbFB9E60VZaVZQZEjZip4kpT3mM2VP/J8+Np+u44/8yk+kTOgjQQg0//vWjslXF6TL/WP/lrltKod2TX8uKE+TeWYVsU7f/24btI8kpdktN3CRNih5CeVE3Qom7k9m4PftaZjyQvfjM7DkU4YO8AHjajdd33I512D/w73VdKqtSCSG7ImQWyczeI4SIjMyMsiqVShnJjWRkl+w9b3veNhHKjOy9V+bz9nv9/nr+enp1vK7r/J7HcXzGcZyX8w7h//1X4X/FKHE6hGjyEGJNQkhUO4THOovJITyeWLQK4YkUwvkTQ8RGcTuExAXF5RCSqEniOun5EJJ1DCF5duH6SflPiaddP91d7A0hRVGxLIRn0osdITzn+rndIaQcGMLzVcSqEFLhlMpn6nZCTZoyYn4IL8B7Qf+0KYX8dD7T+UwvPz28F/HK4CwDrAwHQ8iIaybXmXqK4yFkVp9ZfWa9s8DPAi9LrxCyys/mOtuREF7qE8LLhQWOr4wLIbv67M5yJBLycuD8quucrnPqm4u2XFtDyF0yhNd49Zp7efiYh395cwke5oObD5f8vMjvfgG4BfQpAK+ge6/DeP16CG84K6RnIZ9vZhI9Qiii91vxIRRtKCYIPhRTV0x+cRgl8C5BT8npgsZSzko9+nT/bXzf9r20WhaGMnDLwC+jZ1k4ZWcLvcqZbTn8y6ktB6M83PKPPs2lAp0VcKxgByoMFzyuwOuKtFW0M5XSCP5XglWJ1krmVZn+ynpVqSHgVIFTBU5VOqsiUlWPas6qOasutzrs6jCr01Yd35o8ram2ptqadNXUsxZva8mrZSdqwall794RtemvTVdt+LVxrs27OrTW6R9CXbl17XZdeHVxfhfnd+uF4P9QL6+wt/XsTz3+1bO79fGrbx/rq6tPa3119fnYIJvApwE+DfBpYLfesx/v8bEhHQ3paERHI7WN+NRIbaN1Qs/39Xyf5vf58T5+7+PXGH5jXBqbS2PzaKxnYxqb0NgElw/0aEpXU7qa8qWp+01hNoPRzG42w7uZumb2ornZNYfXAnYLvFvY5xbyW5jdh+byIV8+vBdCSxpa6tfSdUv+tcSjpfNW+rfWozVvW3s2WuvVGofWvG2DQxu629qBtri31RNEaMe7dri34107Oj+C1/5R4NiBhg7ud2ByBxw74NjBnnTkQ0c+dITREUZHGB1hdILRyXknmjs576Tfx64/du8Tz8An8D/h+yd8/oTPnXHtrHdn8+2sR2fz6WIHu+DfRe8untkutHXFs6u97dpc4NlVblfz6AavG1+6yevOq0/d/9RsPjOPz+zf57z9XM8e5vsF/l/g9CVvvzTrr1z3pK2n2q9x/MY8vuHLt7B70dcLxncM+o6n3+P+Pe29ed7bbPvwva8Z9OV9X+d97VY/un7Q7wd8+7v/o5ofaRyAV5zfioGuB7o/kBeDYA6GMRjHn5z/pMcQOD/T+DOuQ2kaap7D5A3HbTgNI3z/xflImkfqOwreaN9Hm9MYeGNwGcOTsb6PpW2cGC/nVxi/6fubvAm8+12PiTyeqOckGibhNgnHSfImeV4nm8lkHkzm/2Q9J9M2hf9T8JxiVlP0n2J+U+icgsdUvabiPtXZNLXT1E7j23S8Z/Brhnsz7NMM+DPxmWkGM+XOhDVL7SzzmGX/ZuE7W+1suufQMZe2ubjOVTcP5jxc5uGyAJeFuC5UvwjeIjWL4C3izyI7HW+/4+mNt4Pxfi/izTpez8W8X2w/FvvtXmwvF/sNWWJPlsBeYv+WmPcSnizlyVKeLMVnqVksxWUZLsvoWQZnmfplzpe7v0K/Fa5XurcSp1XwV/NlDX1rcVhrrms9L+voXAd/HT3reLCOpgTcEzwPCa4T+JPAy/Vq1uu53pw2+L5RzUbcN9O02ecWvbfC3iZ/u57bYf5Byw5ad9irnfj9qX6XXd6F826fe3DbA+8vfP/2fa9nei9++2jc7/5+dQfs9EE7cMhv9SF6/zGzw+4fsaNH1P7r3lFeHdPz2KNPMzuu1wm8Tuh7koaTOJ/C+ZT80/qdUX+G9rNmcM7v3Dk+neP5edgX7NYFc7no7BIPLuN0mf4rcK/CvKrnVXtyjZ7r8K7jdMOcbqi5qe9Ne3DL9S29buNwG8Z/sO/w6w5v7tq7u3Lu6X+fT/f1emB3H9rhh3Ie9g+RkEYMF/dCJNInRKJlxPkQie0IkUQNxekQeax7iHhnijw+W6wKkSfUJW4uOodIkrxislCTdHqIJGsXIslzhciTKULkKb28I0VSyHumSYg82zNEnusYIimrCH2e1yeVvFTqU7ufWl4afNIMDJEXEgnXaYOYECLp9Eq3TuwWx0MkfXYBKz1O6XF/Uc8XD4ZIBmcZegi9vS9FMuKSUZ+M8DJeDpFM2QTumfTMpFdmujLrnRm3zDRngZulhhgljoRIVvnepSJZ5WdzL1ttAe8lfF/C4+UKQu7LzrxbRbLLyb4xRHLomUNuDjy8X0VeTSnqCdpedT8n3Tn1yEl7Lppz4ZSLllzXQyR3YQEvN/zXSgr98+CZR30e9XnUG18kr7y8tOadHyL59MuHSz468tGVH35+XudXW0BtgYKCDwX2hkhB9wrqX/B2iLxO3+uthJ5vyHnDDrzhe6Hkgg+FhoitIWJ1I4WLCniF4RVW+6Zr73ORN5eFSBH6iuBapJdQX4T3b6UXrt9yXRSmd71IUb2K4VqML8XkFDef4jgX51EJ9SXMr4R9LEF7STMtyfuS6krSVIq3pZyVUltK/tu+v82z0nahNK2l7V9p+1qGT2XoLkt3WTlleVZWfTkcy7kuT0t5vleAW0GfivhUwbWKeVRxXjWTwNs7XaSaHtV4Uk1edfXV9aqhRw2+1IBVk66afK2JYy1z9C4XqYXHOzTUNo/aeNRxXsd1XVrr2pl3+V2P7/X0qA+7Pu71PT8N6GiAQwP9GsB/j/8N1TZ03lDfhmob4dDIXjVS+755eQeLeAeLNOZdE/2bqG+iXxPampjLBzh8wA/vX5EPeNnUzjR11tRZU/ebmof3sEgz95u538xz0ozW5p795jCbm28LPFro28Jufkjbh2bTEo+WMFvKaUlbS89mSzvRSm1rmtvQ18autZXfzm63w/0jc2vP+/Y0tze3Drzr4H5HWjrS0Mk+dTKnj+V5T4p84nnqbC6dnXVx1tV37zuRbu5140E3Grup7wanOx2f4vAZrp/R8hkOn7n3Of49xBcwv9DvS15+iedXcr6iuyceX5vx1zR9Y87fqu+lfy87/p05f4f39/r3lteH1315189M+sH6gc/91fY3qx+dD3A+QP8BPB7w6FrPONhxuMfhE4fPQL4M1GuQXoPUDYoXNA2mbTDsn/D8ia9D/K4OefTpbIi8ITz6meah/Bvq+1D4Q81jmH7D9B+m/3D74D0pMlzecL91I+SOoPUX30ea00g5o3AbBXOU3R5F1yg7PBrWaFijYY0259FqxtA1hp4x+I+RM5YXY9WM03uc6/Fm+qvc33j1G++9V0Um0Pc7X3/3DE3EY6LcSfpOxnEyzpPt1hQYU/SZqnbqo08cprk/DfdpaqZ5vqaZ03T3p/N3uvsznM/QcyYs70yRWbydpXY2vDly5vqtmmt35tI4j755OMyHM1+P+e7P12++ugW+L9RjIb4LaVxkVotwXMSPeDmL4SymbYk9WKqHd53IMrqWq1uh7wq/8Sv5vso8Vjtb4xlaq1cC/xLs6Hr4G9Rs9GxspGOTWW5yvclztZlfW3i41fU2XLfb9z/sxw4+79B7Bz079fvTzP6E/ae+u9Tvwm8XzD18/Msc//Z9r977+LUP5n6zP4DPAc/dQTt00PVBPA/Z33/wOezeEWf/8v8ojcf4chzmcX1OeH5O6nOS5lM0n+bHaXVn8DvDr7N0nYV5js/nxQWcL9JyifZL5nIZp8v6XTbXK3Rdweeqe9f0vwb3ut/r6/reoOOG+d00t5v634R9yy7elvuf35k7au/QeUfNHffvwrjn7B7v79u/B/bwgRk9xOvhxhANNcTeEI0MD1HvK9FobdFTzBbHQzSWRmQXhUUrMURMEPPF6RBN5H6iKqKHUJPoSIg+NlCMEzvEvRB9PK9oItQ+vi5En+geoomziXqij1gmzodokvSigtAryXShV9KUwllSNUl3h2gyvZI1F3olxzf55RB9EtZTeD91O0Sfxi1FJiEvBf7P4PlsrxB9zv2UKcTWEH1e/1TwU9GfWi/vStHUctIkFv1D9IWGol2IpnXtfSmaVo+0eKeFn1bPdPikOxii6fFNL//F5KKo0OtFOjLAzyAnwyjBgwx0ZMQn4/UQ9b4UzRQfopn55l0pmhlOZvwz05EFpywFBcwsML0zRbPinFW/rOqzwsoqL9uqEH1J3ktyXoLnvSn6MpyX6X9F7iswXoGdXb/sfM9OW3azyY5zDlxzyM9hxjnofzUIs30V5qv05XSeE89cZpgLfm6+5Taj3Hq/xpfX3MuTS+iZx1le3uXlST54+XDIr1d+e1HAbAu4LkhfQZxf1/cN2G/gU8hMC00WPC0Eo5AdKUxPYfreTCTwesvOFZVflMdF4Rejv5idKA6vuP4l8CpBZwkYJfUsaa4l6SvJj1LOS/l8216Vdl4G1zLulcWtLB+8t0TLuS4Po7yz8vIq2ImK5lFR34rqK8KpBLsyrpVhVDGHKrytQk8VuVVx814TreazGj7VzaIGnjX5WZOOWmprwX5Hz3fs7jv41Pb81IZfB0YdM6xLU1278C6sd/laj4f1eFWfzw30acCX99Q1NJtG7r9Pf2PcmtidJvh/oLapOXnXiDaD1dxcW6hrIf9Ds/8Qp5Z4t+wYoq1obcXz1mbX2mcbXNrwvy0t7fBpx4OPaGsvr73z9n4T2sPuoF8HHnTgQUdaOuLUCY9O+H+s/ydm1Vl0cdYVx274f+q5+ZQn3hmin9Pbw35/QeOXfmu+VPeV35qear/G7WuefiP/G7nfOu+Fz3f0f+9eb89Ubxz62KW+sPvJ6+f6B89+fx7/iPePrgfoH4f3wJIhOojuwTgPtlc/2echuP3Mj6F0D5Xr3/focPMf4XqEnF/gjeTfKJij9RtN9xjfx/BiDC1jeTdW/Vjn4+zKOPrHyxuv7684/krnb/An4DfB99/NZ6KdmAh7kplMhjXZczKFv1Ptx1QcptnXaa6n4zBdjn+PozNhznI9C9Zsnszm9xz655jvHLOeS9dcXOY6n0frPM/TPHOar/983vp3OTrfvfk4LMBrAa4L4CyAuQDXhbxb6GwhLxeqXQhzoXz/dkcXwVtkdxbpv8gMFuEU7zmMlx/vLN5ZvLnF671Y78VyF/NtsZktwXsJT5fQs4S2pXov1Xup3sv0WOb7MrXL+LfcXJbjvtweLOf5cruxQs4Kz/4K91e6v9L9le6vdH8lTStxX2mvVtGxSv4qeavlrZa3mpbVzld7Dlb7DVrD9zV6rTGDNfit4eUavNY8umdua3m4lqdraVpr9us8R+t8XycvQc8EtQn8TsA3gZb1nuH1tK7HZb2c9XxZj8sGfm1wvkHtBt5swHGD843yN9qDjfI38mYjjE2enU32cpPnbZPcTXI32avNsDc73+x8M8zNNGyWv4WGLXhs4esWvy9b9NnifKud28rnrfZqG8+2+e3YRv82fm/jyzY5281mO33b8drOu+1msJ3uP+j+w578wZM/zOMP+7QDzg65O+DvwGuHXdpB8058dzrfycOd8HbSvFOPP+3mnzj9CX+X/F082mUfdtOxmxe79d6Nx25e73G2B94e3PZ4zvfI+4tnf8H6y2/cX3j9TcPf9utvz9nfuP6t7147upcne/m319leXu21n/vMeh+t+/ixj0/78Nyv336e7Df//Wa8n6cH6Dxg5w/gd0DtAbUH5R3E7yBPDjo/6Pyg80P0HJJ7yG/JIWeHaPyHp//Q/Y+8f3A8jM9hHA87OyzvMI8Om/MROEdgH8HniPkcwf2I+n+d/+v8X+f/0v2v86N0HnV+1PlRuo7y/yi8o/ge0/+Y/sf4cswOHHPvmP32Thk97vw43ONwvV9Gj+N8AucTOJ9wdkKPEzBPmtdJ5yft3UnzOem34KS5nbSvJ/lyklen7OUpz9QpvE7x75Sz03id5s1pOKfdO43DafM6bYan7dIZfc/w7Yy5en+NnjHXs+bqPTZ61vlZPM7Scxbvs3iftQ9ncT+H+zk9z5nrOTM8x4Pzzs7bqfNmcN68zjs/j8d5Hp+3Gxc8exf0vqD3BX0v6HmB5gs0X6TtojPvytGLzi/CugjrIqyLPLxEwyX8L9F2Sc9LtF12dpnfl2FdhnXZ+WVYl2FdgXMF/yt0XaHrCl1XnV21r1fpv2r2V51f5e9VPlzF4Zrn6podvGY3r9FwTc9r+l3j/3X8rttN7+bR62Z+XT/v6NEbcm/w4IZ9v6HXTRpv8uWm+dzU/yaet/S8Zca39LtF0y14t+Xdxv+2+tt038bptvu3PYe3cfnPLv1H73/4/8eL//h7R80dNXfU3FFzR80dNXf0vKPnXffv4nkXz7t8ugv/rt+Ae+Zyz2/NPTX31NxTc0/NPTX31dzX876e992/z/v77t3H+4HdeGCeD+h7YBcfmNUDz8VDvykP8XvIy4fOHx4MsZBNDAmxSFHRSvQU08XeEIsGkUbkFRVEE9EnxGLOY91DLFEu0VD0F/HieIg9llJUET2EPo+tE3Aery22htgTvcR8ITdxCgE3cTsxSrifJJGAlwRWEhhJBorJIebvjFhS3JLql/RyiCXDK1lJodbfGrFksJK5lwxWsushljy9qCem//+g50lcn1wWYk+pfSq7KCxofmq42BhiT/Pi6eZigsAvhesU9KY4HWLP1BCwntkdYs/i8Sys5zIJup6j/7kdIZaSHyl9f15+Kvip9E6lPpXr1PxLDSM1fmloSQPzBZ8v0PjCbIFzWhj+lomlwysdD9PxIF1noUc6/qSH/6K6DLzNyLtMfMrs098ksaw4Z8P5ZZxePhJir/Axe2LhPAeOr54PsZw8yG12ueW9hlNe5/nU5qMln3v5b4dYgXshVtC91+W/gVchmIXpehOHN50VSS5cF8GrCC/fgvEWX/0dECvKl6L0FTPTYngW53Fxe1FCj5Jm4f0/VspZKfMo9ei7fm/r9bbepeWUNucy+pehr6w9KafG3wGx8vqVXxViFcqIcQI/fwvEKvpe0Twq0VqJv5V4X8kOVeZJZd5VhlOZniq8rEJLVVyr8rgqj/1dEKsGp5r+1XlQnU813K9BSw09auJVE4ea5lLLTtQyu3fUvkNzbR7XxrUOzXVorquurl51+f4uHfVc16O/Pn/r61EfXn2eNzDvBng30qs5zm3sYRvXbfD2rh9ry5u2atqqaaumLZ3t1LQz+4/MuoM97wDDe36so89OsD7Gxzt+rLP6Lvp0tXPdzLgb7d31786H7uo/xfVTWj5z/TmvPud9D/Vf8OoLM/rSPL/iRU/fv9b/a/2/6Rhi3+L5rXvf4u/dP9bLjnwH83vPXm+1veH1dt2HR33w6OusLw/7mk1fO9WPj/141M/z8QPfftDrB7Psz//+8vrL60/nj+79aN4DnPt7ITaAnjjY/m6IxXke4nCOcz8OXpxnJs7OxPE4zhzicB6obqC8ge4PxGcQHoNcD8JrkNkP8psxmLeDeTGYlp/0+onHQ3g1xG/MEFx/pulnGn/2fajvQ/k5FI9hcoapHQZvmNrhvBwub7h5DIc13NkI+CNcj+DhL343fqHzF36MxGMkn0fiMJL/o+COsrOj1Y/hy1h1Y/kxjv7xcsfjPB7H8XJ/5c+vdvE3e/ebnAl2YQLOv+Pzuz6/6zmRRxPlT+LPJF5MljNZ7ylypnhupvBqipop9E/VeyrMqXhNgzXNczGNj9NonC5/uh7TeTGd/hn4zIA/g+YZ+M6UPxPmTLOZaV6z8v4fwq7N9izM1mOO3nPwmGN/5nrW5sGdj/t8XBbgu4BvC81xke/xuMR7Bhab/WJ76G+Y2BKclvJ0mbNlOCy328vlr+DtCv6vlLNS71U8WIWfvz9iq/Vabe/WmNcautbwdC3Na3mwVu4639fhsY7+BPoScEyw8wnuJ/B9vV4b9NnA5421/wfAjkaUeNqMfQdglEX2+JSvbO81m2yyqUCAQJYkBIEsSgkgEEDKAiEBAQFFmoCASu+9ifQiIiD9IkVFsIOCXe9+clZsdzY8u2S//N/Mty0h5/2BTZZkvjdv3rx5bd57iwiagxCdR75HFMnIHzJISKaIarQilhAquFJwxWrDpaXWoDXYulXQGrDSgDUwh5J5CiKIfB+xkQmKAyFECIUvl8TOHE6zkJ3KMhEEjRZj+CbuGCrAgLKCfKsNlXoKGExrkMPEWTRIi4JOcmKj58WXn8er6Ok/n7l0CTGY2El70VPiZQ4zEDLJEqESww0hiSBUFgwWFCahx0BxcCtXN/lEca5q+gntReZE5hFYIkHFCAkrxC7Ih9LRidB4TVqqU3BorQaD1mY26QWd3e5wpftlQXILGHkFjyhKDkkXoClu6tF5MgIawWA0HAunYWMqslgtx8Jep3WOcY1xl5H2MVYZSR8r7mOtsv5gpdZQema50Wq0im471YmoIFgWtJWWFhTkV06unAzrzrcitvjod74AN3zn67C5S/mLvyssVL/D2mjAGaBZdvbKKgrCK2APUvYKws8Ddrr3NiwoXwy+d6Cy6Y5777j06W0/Yjl872B89+B7B78TCXXB42+jnZQX7lHG4kfY6x7c4R71nTL2HuUF3AHYAN1aN1V4SHwRZaPmqA06EBrjySikgsHZFLZQbGHTajQ5tlRfCx+yoaLi9GbOZlPDrY1NjVPDGU2bOqXUVI/TFcrIK3eFbO5yl8spFRokw9Qw0lq0IW2Ftlorsm+7tce117WiViutFbEoUsnDd7LSCq/JjCSesmBBfj7QB/iktIBTib2iOx1km82+2DjV3GzjHZLszCrKpiV+7LbmtSRFbYpLgKfgf3JLnGf1U+xgvzFh3Ib9vyMWHrr+yVxlSNdDKbuX+g/s6H71rblPvdriqGvuhMNbh7WsPV4wZMZD88m+klHL1m7ED+w9p92zx4TDOQ89KON/aZqOWDp80+Py/PnyuoOB8ffIysBm5cNmkpalvYLpeIc4OtLs1oGlWUpT7TSEgFXrfhZeF/sCdU0oBeWg1mhoqBhhs9Q8i1CaJWHBkJuW5jQYgoW+pqfCGb7TQzMK4LtX6zkVFrSnhwo2+C4TCQGdysry8/ORh31VzxAwiMotwegRzcLBnAyrQ8rKzAUq4Da5WZmS0+EKFhaLjf/4w3V034ba3di3ftWq9StxelmPXrfeenu324jmph+J3TXK8cePHj74+EHl+IwJ42fdN2niTzf9BFaaX/etsEfsxVd7Cxofuq1Y09yYa8/2paba/dRb6G7ZRmfUGNp36FKItYVYj7wWb4aXmmlLnbuNz+svpFrRYmnaN2yhgVKxtG8YiS5gEpU5mAxxl1YNrxxeWQlEcMd4gi1fzMzN42u05LTEsNBgocvpMGHZ5S4ucUuyHwcLS5xSbPnujoTCeJUOQqvuqwq3PP/KVZydkX92//pjfTb9beG6wTnrmk/PH9GkXU4rZVv17eGJHfaMbNOjZunflt8fetDQ9ZZlF09iw+b2W7os3bt2ds9po3t+tfPUJ/nfflYctCxxCd279h3Z794pnct61r722vcjXpm6tATkGsa/gmB6n8s1d0hLCRFEJqFghVHJqMoycjgqwvgzA5VBdDY8Y0SZIbNOrxcoSEXZZNYhwQeMERepqii02NxZucRqsZUEJUKshy48e+HxfS88e+EQsSnfKZ2//RY/jV3Yik9f/1a5jcOvAPjTYvD1Oh0VBBkhBp82Bp/IWcU2q4XkBV02Ou2xCxdePHDgxQsv7CUO5Wul27c/4nPYiA343I/XldsZfPQ7qaXviq/BKbgz1MpkNOqIjpgtRKeD7TdQraCZZlhkIBpJaxDkOfo1eqLXG8VJ8lx5rUzlM3UXTmkN5bJs5FTKrwSBWlAJnF8ZY30uEZiAsKn0y3GLblmP80pySkQg5S6saaF8eXbGw9tnnFO+boH1hqXCvrsWdv+zHJM6VP5798V346Ycz/tQjTBI2In0yBHSEoNRFI6Exb+hMn7gALA1yxooCsBsASc5tkEZjA9swAdItXIHPrweH1buWA+0pMom8iTOh/3NCFkowqAqBRGj7UMFvG0oUs9uTGnZAzD+INYql+ChhyPj2V70xm/Sh8gkeN4bMiDKnn0qXIAxRgWV6sPwYFHAiXuTVvjN3bvZM9eBha7yOd0hHShj4Ck2GSrIj/EUQxpf/wbnK+/BOqfAGQ1zHkwNGTBoZwKPUC9G0c2O4ufGQTyFFp2sfcMhfvJnBtPLFD0Az/YRhwCN3KBP7wi1TPEabDbJgCSUmmb2YLMn3UOMnpDZm+4lTur1Uq3WPDWslalzaph6gZhIPcdgC8BBTrkyHPRibE6mCDmHZWUyBg4U2mjsfbDQlgNyXejzx08//fw9qvvju9Or9u5ft2H3ro3K4G/Io8pRZRu+E9+BK/EQ5VFlP87EtA4pV5Vryh/YtPOPP2DdG4E048EOMKG2oTSjQcI6bIAjaLbI0tSwLFOdZMAIg9bysD3n2igYpaE7JmRh/yUhq6gwu4SxwQ58Okf5ZvFGLLfZj0eso5He922cf+eN29dxfloL87UHWqWi9qG0FISMplTZYXKk+Y1Gq1U3NWyVcQpKSZ6Pfy1IqLvonB1xSUeQaUx0yXkdMRdtkgzCLeBc2/qNk7tWLp87ZZXxjOP759/7/pHNr+8KkHemTfhw9ZxnBk28/8HJ1kOvXDg+9Yv7923rvp7jNRf2sCfg1QxND3XKy4bta57m98uSOzub7WN+8zyb1WadGjaDiKU2Gw2kpQUCgGdAptqp4RAcS8K+XIfTKbMt5dobJbAvZTvL97gRxW0r5Vo7KzM7r8QVKCwuAr2cj4uChY2sENS40LP2s/frkPupbGxeum3o9hFjRg5c02/RghkbDE86fnv+3W92Ltt8Gk956vLzz1j/fGhmz7tKtpeO7TZ+xqyJpiPPP/34jOOpgvUkMPhdsBejYe91IOW6hvIMolEiGi2hWMQmMxIMwtSwRjQb0g0FhokGwWDAeknCTO1ycRNMMkPccUnI5QGG904tDtCDNZEpZPYrzyhrFQP+GZcpz+GylXRW7dLV9LZIzwTdu6A0NDjUwuux250Oh0Y2upj5ne7wTg07HD6fZWrY5xOcTs/UsFMSgEs0GoHTOOngqITOr8cn7B+jrAmDEgTSBhlpOT3BdARDkSlEoef0a9te+k/GqdJvVx3Yv6L7Q2XHC2ggsiht2tHLN/AzK96eevhR51sH1j2ws2UJ+cc6ZdCQb5h22gx4lwO/uFAWWDCFVr9fMuj1bmCV7BwH8EWVAyOHxUF01OGA424CzjFgKwX7WqaBxKkPxtmCH/3K/GTusAajbAGHHQUz7DKgTpycE2S2DBOO6uryn979VsGa67is/+Giv2051Prk1Atfn96yoMfCnnsemrMZP/uugsO4Ax6GH1A+TT+s/PvG0KrvXl+7+7YZPR+5fIDz/07ghRawD1rUPOQES0zWg+uDdHoka2Sgt0TYvifZnTHFgqxZFpsdVIDQQsl75pf/RNLpGuGpyODI91gmIzCceooWAa26Aq18KBcVgv1T6nG20OUZU52ZRmMLyZkHRAu2QVaLlZhpOiUW0aPT5TTLAXM6J4darelMKtBWN4lK9TQFq1TDJ7HrDc5ULjd/mf3DKOfH0UNE40Zfhj3J/hO6/vHVZ3U7Z09aOvHVBcsu37N80vxtHy2ZM3vZ8gewkLV91dJtm9dvWItnnXn/7afmPekUfEcnjdw9OLxz9OSjLsF5Av8ycfKUeyfOUubeP2/FlCWrljNeWQXrL4vySlWorSxJaTaD2w1uQ3aOOWNq2GA2p5t3mY+ZfzDXmSUdNZup0wk85OSyhSl9Ehcq9VVFMKE746YIivG6rYTxPbP+gxmJ1YJMEcqUX39+7JX8w8Vnth4hTZ6/79wXNz7AH764e878hx+ee/uS3uS8sl9ZsmKb7zh2/zpkAqq78u5virDn0tEVa451mc19Ua5fhXbcF80L2SUqgpLVakRh21DRHFO1Kq5x55ZpXKpq3W+43qVmrn0ZvGplE7VF4bUKpRCMJVkQJUEC/1bYPlQjbhuKEbzMKGbt81VHuZABZZbD9W+URdx4UCHfWKyaENyO2Qp2zCFgtVtCGQIC/0GSNRgJAhHLpInSHIlKIZuzXKJmAvYJSDfVqupQEAwmqX97EQa55ryPXqvdT4eQW67gvVuV9cq6LWwN6D48WBhEv+VrGBi6RYATgEGgCuKRsFmYKKwRdgnHBDGFCiGbqxzc6iPhVrgCV+NJWKiAL3PxcfwmFs2qYcPVR0G+Kh6SEAAzB14MgzR6jQ7euFFBGzeiBmssDaXH1iiJhFCzgAVchiaiOYAcWyfbncpCWGbDFZYUaXERW+EQWOG1rVvwRHzvVmX4Fba+4SAjWgMfp6EA6hIKaAIBrd+P3B4rKOvMLK3W5/en7xjqd7t9PkdV2CdENXhBcpwjvmtR6QYK2wTGc0dS0pHEdF1xdrBQwMyyad28/7B7uzXFx0iLPlV339Zk19IlB01nUrD+jY8xiqx5gf67+5QRt1b0GFjSdWJlt949BpRMmLb+IcNL7z134y4WNSGoufKF8BjYde1Rd7Qm1M/jc3fwUbFFy84mk9iSFmWgvCJU1KNnWld91/fDMtXbQu+H3W6tE+ucNrM+XV+ln6ifoxf1yAZ2UQu9zaZvQVuXlma9Fy5FrZu9F24dZ3PwwmCpBdwTswaHMw5iAY1kmRl3Tt0xtyErswMuyeL6qaiNjekjd7AkSOGkwvktYr+XiJNZeuCw8VGkyGID8rhsYlQDWOB3NuGxx1auIVLm7N7jZ4x4/K5uQ11ixn13Nmnd+84PajZ+/sDXrw4/Orrb1H/MeOzG4q3Y/8zOfz2kjOx6S9n4TlN6TC8lPynvK7t2aPyD7754dg/2P9Z/yGZFfLvzYNzsD2zDA/6uzPpDeU1Z3XXwoDuHPI8nfI/9+Okfn1SefGb8hEU/LVS+eha34/wPf4TLoENksCf6h5rpCQXbURJBWYNrBg6U2SRjoidVYdCUQzS4pwYDd1IB5GBZIZiVlZXR8EYsIlYY5RSwgLkRHKABCg69FpsxvBN0yyNXlr2Ilf/Dv0S2G7psxm8cwQ8p88Uufz4tPJn3rhLGP6v2+V7Aay7gZURO5EcVoSZ6n4khZQejwoUElJ6ht6fYU6rCdrsgiraqMCDlqwoLtkbUTULccg2oahkhK2ANsHgCuNTgTeeDPGJKBb6DMSfMVb7/WWmCt+Prax94/LTy/ebNH3+Km/c9ebwW6449hh+ouSh2Uc7O2ue1ncTX7h6qVCvzptyvZM7kZ3oy6I7pXHeMDpVZLRZJlj3IYHB7kMliImZtupYYRRMcN6vVJCCplRSSKJIqpN3ScekT6bokGagkabW0Kqy1x84jsOhkbjzFVGfyiYwyGwlkgEYOgNHRkikR3O6J46P3le7apJxU/lC+IB7cf86BnB13PfEYOaj8oPywbF0nZSUej/uTE8qJTpMXKCwgujdqX2qQFTUJOUyCFohts4tGTmFTPQonPEALagp0y0DUwglZaBNGK1eUz5TVuAR3x7dd+OcPM/e++zo5rjypbAPCnVZqsObHGz9hHacXm3MkzKlHg0LFolaLqE4nIwqOq6YqnC4WiMQMX8rEKnGOeEz8WJTTqQiuIRaqwpgibVUY2Rr6Y5Pzo3GVeNjXGYi+9tLNkSZke2QU2MxdtitDtirB7aosfh7w6MDtqdtDBVgUJQ2RqE7P5jHjPrgKg4YqA+FKDRSHnE3LMRZlGVWBCBJt3NJSeQ6mn5KYnmk6NjHY2E48j+yLDDtPZwsHFdvOyDWYP8YvzBf1Ap+b3D6LqNc5dUhEKT7NmbrrIa/RWu5xV4U9HqLRwD7o9RqBAMcTe8wejc2M6pmijM9zwJgCnkAB1RKVgD2AU5j7L/T64l9/Kt9iDdbiIVOfqHjz4B48oPP6lspV/PGiLXgq7oGH4oHKk22/qlW+inzULANX7I7uVTO+V6CTZUoFDUJ6QW8wyiAjKmS8Wz7OLB9tQkaUFqi7UZoU44N9AIKwYDxYF3dHfj1/nujOk4mRdWKXyKuk+M+n+X68CnNhPldpKFWC/ZaBF7Vag1HQyMAZso3qkR52nya7nXHbJap8oxsP/m7gVVqivIjb117C7ZUXgfY3ftq+XTCqe3+87lv6AcxlAUvGY7LJPBJgtZmB482U6qqYX21Pcl/iWjFmseaVsNCcF8NM9IO3n33ictbTtmnht5RL+Be8762vTl5Inz4Xe6k2ymuMjq/xtZWHcjVarQ44Wc/oqRcMRpyht5YTWYeny4uBmliTRE01XpRMUJCzKlGxzInKpC39RvE+ClRt/6miIV3IQweVfCBtFdkTebH2Nzb/dzD/7TC/iNJDJjADRUkGDGjiLEUnYGeHnZ7vzpPdYpcbg7bDs/PgWeb/eQB3lwshj0a2W4xGk8nuoSleQa8328/UXQgZTNZyu0bjMlNTnBUAcTXM5U4YwCpDtCkD65Fm0dw8O1uF3eUuw3bgjoOUhtL3Ldtv6y3s/u6ssyCl+dlP6aglt456fYDSA59q+YvyTu12kCnuopNDVuJ/c9ZJ4lMj6hzKlQVBRHq9QTSYzPqVGM/CeBxYbBJdoMHTNHgMKDXEjjDTZ5Vl7EuwIcNil5OhhXOLGMt2jvxuOfQRsdgOC+MP96vdCJRZvXY+rWazEzQGzvMYHltyMhlq4bzkcmuBl7QCtVeFqb1RGaoe1WAhiFHQTDxWJIxRfvv9D+VPLER+w5pLyqvKxZ1bHt0IAvyYshGPwYNwXzDDH1MOEWfkG+U/cJ49/N6Jr7+K85cdtQmlGJBFkmQkOx2iBSQ5iDaNuSqsoVKy4Epac9QD52KrUJDbBGDtoBarZny4TvnqPL78PaYXlDO/KpueoCcefPHeiCJ2ee95JfLder5+5UFhMtd/Gei2UDY1mZDPqnEjZLLSQKbDWxV2CCY/kMFk10vV4So91iPVSwrGqBINiUddBQuJxb3ZQcslN1PppdNNF48uaV854OEXyq5+eTO1PlL2NH9oinGx6+CrLnwnDjVCNpVmW6I2R1WoCBmNWmwwUJPWBudSK7hdBmIDKdfHhs22MttE23nbDzbRQG02JIpWrh9VPq+nhlCw3lFNMFQWpy2PD4Fj25TbHfScsv778/izf/389A689nflTeU69qzZQsoiz4ldnqvZdDkl8gS98rHSbC7j8T7AZ2OBzs1Rj1ATScx0paUaEEp1iUKLlpkGL/VmVIfT0rwCBRUZAvuCSJIqwyqT1EZp0mFU913IyqBcmLGYFskDi5vfQrCLqKwMp8NP3H5BGKv89IdS0uNs6vENux7rNH5R5z3L+jX76dq7nzR/xrP2QeWLoqEzu6yYVdU5D0858zoekzNv2gNTug5um2VtduuAe3sceXrj8cCk0e+179k6w5ZV0L7fvWw9t0dtPhnlhmwyyHsCnhgSRIHRFtuSghn1IlcBJ3npWaWL0EY4eGOQcHA716mrgTZMl1tRTsiqlcxwAm12CwhYQ+L4BesdP8ZbXhy08pACnHKhw+e1P189P23rnvnP4n8rv/z0DcZ0Qu2Ry7v2vUu7sjnAehGe57G4wpCXgtksEa2O6PQGLaEDJNxZwhLCUbESn4xbbYXAAGAVY3apg4Pk0suKfAmH0ouaNMcdL4ldamcNfG7TfLoY5ojZ5240NNRaIxutFnBCHQ7BqBVcbp1W6/Z4hQJLH0uVhVosRpeWOozZRmzUgHkka/jcbH2gM6IBwPiS3aVJ4bZAlg7nmTCIXyZ4O4LgddncPhykf77Zo1d+WusZb75zboLFmpE/61iXPq2zxp7DDpxx4cFXlf6A7LkFf19eg89FlI/+iYfQ21T5mw14H+TyJxQKUAlpBQH8CKCORhRkjaAxGpCWSgLWCDam+soYfu7SJL0adbpAv2qZQsvi/4JkDO51RemF/3lFWa6suIL/qfS6QjsTHHkgUkY6RF4gz5GF8fkPcDu2YyjAptRI4E4TotNKNIQqUDWiZYy8WBZU1uLkqQzG2MtWWmiN8xhDIEhefEZJvYKn4/uukPLIGVJOIpEd5E4A0h3mWsDtxqJQiqAhWgpKW6eXo5xLQL2ApWpraKWUxqjfFLx3xsY4ICy48TItjLjp87Wv0xFrhJTtK258xu+2tiqD6DnwiWWmUcDAEhHSaLHwSxjWIP4SRr4kjRI/Hartg7eSLGUdnqgMkqet+GPPCk6fqXA+hsTuTghGFFNBBHfQW//uRAQmpftq3zhJi2KXJxibAJfWMVwEkPiyzCI+v4QBKfxfcGH2F7ywCfBYB/gMWiFVrfhdxWURfkroCvSTUOuQRxRAMRPwh6gka5h/ii2YYIGxSGVysgQ/R8AchJ0jehh8iqcewbNeww/gp2hW7Yd0Re00eLbuRl228FbdQlinM6SlIhiU6GmgGcg+zBGTge6i8P4/q6s53+L1wgnaTqwBu8gT0jNUwBFZORRtQGXxSyicUxR0O8mzyrsvXRNOfJn2gwN0B4uJLxV6o0xUgEaF2rUwe1Nsmry8jIwUM23V2takb9hmM6SavRO9H3t/8NZ5RT31elNTXRXhVIshqwJI1xfUssbg4pkE+YlrCNAi7CYi4VBE5XROTB1GIxGWnJJYLMbG1ArIsZzCjrgDi9U4HS6hV0qgc7dRQyWp04n5O3fjl78df9/0sbpnWuKZFy81i3xQvbHfs9Mf6BKeKE+yjJs0c/zhh3GlKNyyYOodg604++kTSsuKvtKwrf3CAml1Z79+o5ie/xus+VbgAycKsJuoVNFkMrrY7WuWw1sRtjosRqRz0nRYHOV337CmsrL64c9oQCUvC7RgFpO6VoccrB/7LBZufe3cz0OITI5KNYIw9Ce85KnZCzYtXbh5yUySqXyufHmm1VhD8UHhOyXcadjFyOVPLl396K1X31Ll0HzAsS3sSwoaG/IbkSxJdgdy+FIn2TGyW+zV9kn2ufYLdklLuc2a4fOX2+0ej6Ui7HFRXUU4XZ4jr5GpHIJfgAtgUe9uE9vDvL3JyV4XuBzMOlHVZWwJJW4TrBLNx+TnU9+mXrDMnb5zw4Yd96y2Pmuc8eLMX+oQ8cPJyDy20TR03ItXP7oyfoKhekcYZ6i23PK6LwUv0NkF3NUulOaW0pDJZJbMWdl2pwlpMirCeo2FplSAJxSjs0rsOKVVjuGhZeYButzBPEZqd1ZLED2OxB0LHd5678xXn8VLZz7ampAa6bAgRT6dsXj9yiWbltx/dFwVdmEPKR44cjN+9Ib9YLH5vnx8z0evvfPl3198HfDkdwZAawdQu0+oOViiRkn22u2ykfpSPQhI6tFZLM6KsMWioxXhj6UfJDIXlKSkc3GrpLJ+5KaBWeKKB9Si96hWJwZuDxB8656Vd21L2dn8m0e/Vf745pv/KDmLt4ukPBX/dur1cK8WDyzEudiG9Thd+Uz52IPfPrYFlzPeWM79mMvgxwRDKS4mdojRm6KzVoSZZheFirBLNGMnKkvK24htdNz4iBpHTrbbJpyGwRrpXAMGu/Tcp+WPN/OfLhg7vjX+hh6uvYMeXu29ctioWScaWo6t1K3me7tGGSz4hZ5wggpQ31C+QGkTa6Zbq023prdq7TM7cirCbofF1BxwMjmRXBHOEFoJRBCYkC1MMpqDST5bUpJDzC+1FmUlKAfb36a4JCiBjJBi9yhsUEdM7jpwOfWMdfKw30nro/e/fPrFy5Mfb0E1whPSu4GHFyybFbxnxIB5XZXBy+d5e/bFtzx/13hMgSd8WD9uhH+NofhQ7cvXvqBvPPfh+Y83H6uoOq2ewbNATca/DvCt3QKx2x06vUPvdDl0TtlcERZkC0KcyPVsMi4d7DGB4AV7WUXVmnX2SS0d9288/MlxUx/YVSNeVmbdsvyKsiBSQE4vXfjktsgqRlcex7oMOtmI2ofS9QYDZnsqggOo6x/WIw2QUmNGAoVdps64aq6nttRTEw0eFAXyWI7fv/ADtc3wfuU5/NPFi6tXr6b+1W9fuKCe02mgFzvDnBZYaXEo1epwIGSQDE6Xzdo/bENmU0XYbKZamDCmIev5gFzfqrGEItUGjU5KO3/yRp99LR6ePXe5Mo70vHgx9em3U6wrMxfOoC+ps2P0bXS9etQhlIZ1Wh6a0WrV2AwLJchYYwb1B8IaPJSyWJ5C8sWlGq9NDiKsV9YvrKnBV99RuuPX8U8jlYni5doRxKgURDYjEbw2JAyDOc2wYiu4PrDcHNGZAx5aHlf2LrfLnefOK6K3Ya+yenIbF1U+xu9hj7P0LsuLG8TVgqOrf7HQfvWNQAuXXVv13er7VH65E+COAjmSh7qEMl15eQhp09P9Zo1G69c2aZol2GHPUlxmu8VgTtfyBcGKgg3C9knB3kCcc6xt8kB1B/l1rFv9xn+q/prYW3cK9TkobZJI5tjegwfZSZOJA6aPOdC60629yNGtsy/si+yh/c81m9NqTGX1qPFDDr8FLAc/P3AAWA7w/hvjc8DbgwpCbiugizxajzcF+AAQdgC22ij1GyDaEEPwsII878tKR3EWlw5hQgkd9+ORQzEWZ3iIzUv7XHn6+UgB8B7Tc91hbpbPAlaZmsni8WrhfGktFGQuUw03xxwSWSn1NG73G999/Vvk65+/P7dsy7a1a9fuWk38yg+we9mgptywm/9Wvvz7u/945+2r7zM7QBkk3CpUwMxZzA7ws6V74ORl5zh9YAc4YeUaHwnASSd/ZQcEwAxwxUmg7lJ9tG5V7v91gCg8KR3DIJ4Ltz348vNPzVqwefHiTYtmkczIq2c0OxUwNg4VC8E7PeOqAONrnz139aP3Xn5V1aOAZ4rQg+vRopAvzemmBoPeqc/KtoEONdlceh8CLUqBncsKOZZJSKoES5KdWdaSmExNTkYk1nlbWxNZPCY9KZCinQ+8+ix5b+nGxTNnLdiwQugRrvLPMRR/fqMYnz5w92jsxU5SHPnk3Vcuf/zh5Q8YD/0HeMgJ++hETUMOkyTJstPlNtntpF/YbtGbJSfPoEzmH8Aqzju5eUHG1yRY6Back0btebnG532iiUYsrF5YNXYMfdj+n6cVgZy7/fU7l0+aNK7Iqp63x4F3skEH5aLeoWaylG5P8RrAEbBLQl6TdIOLutLAtEiZlEL0NCXFZWFmEZhCrlg0NJEPcXMsIR4ZzQADIy87ltGoGkdAsHTsJ0L2v15//e+BXfYHN2PTyNHK76tvf/fS8bdT9urvn/FL/2EzHl3TDxdtPTZvRfrAPk+E+ng79ZjYf8P+RXMc5T02ty93pTfpPU1dx7N11+kf4h1Au+KQT9RqicNhdrmtBuBBFzjEYICImFJ2HR0ssDam0u1FQbt6VcC2UrWvi6zPHmp3Pz6uVAwYsfjRg/v37gU9jlOUL1dH7utze+aylss2kl1RPQd0TBfaAemi5x97PNoUn9XphPPvdBmdGhCVjZ5/HI86cKOMxIx6K54w8qF5Dz8ZFQAdH5158jGhXaTf9pnHd5OptUdUGTCp8sRlErV3uwD/LAEcdCzqFw1JUKIjBr2WmONBCWeDoETcneJRiXRchsHffe09pc+r2GBtk5WHHZdg2lDRmWnTyfN8HifMc4avdUioJUY2s4lKot5G9VT2eDWyV/alUJNJL3u9Ho1stumn6RfpiV4EjPjcQTUkEUuQrn/ZmhSWoHkyD0rYnMUldhabaNORwBv65+U1pXkHXjt9sjKQZ1/y3PwMt8ZgoKOP47+/uiLyb8B1j/J7x93F+IAyaNw9/iFVA72kiuPN7sMnAN56ZhWwuLuMBXAu9ZIoEkrZPYZOwIJGNFNVVgfd9ZK/AD9VYKvhCP6P7lPOK+eex7uUqa/g5rjZJWUq3oefUTqT5sSkDMWPRX6OvM3mvhXkzzKY24FKQz6b1kRMOotVr9NZnS6TVitadGYkVsTd52B9wpSqG4QzVeOA7RB2uUvgqwnj7B6FuS37rGhlU5pdwJqhclNc/KzSNnxeGaRfIk2f11ooiDz0if9earvx8jfPcjpsADo0B1x4zEKmWEOAMXR6iQpgmQtmLDNbEzn/a8wiGAtZODeQg5E59PbIQPLGMpq7YlntBysA/jVYaw7YBlloYKjQkuXya/T+LK9IaXYOsIdG/iVs1hRo1mje0PygEa1Uo7FkWay/hMESzKwXQYgGUuMXufEMRsyOB8iUoo4YvhcHA04uBNVEIeb93oKdNHX+vvXz5q/buxBr3xtaMfeuMfMqhr6nDDq4GFfdfb+4TJw1Flcv279i8N3K/pGbvMSz4S7lsfFhwJ/YlUHkLI+PuEJanosK9mMii1jNXyH2/SyowsMYTI6C/fcvvuYhoSKtx0cz7GB9ZlBRzM7R+lJ9qbBoX4Fvje+Y7w3fDz7JSn0+O7LbfgnbGwZOGl+2W5VRTFBE86Os7Ma6KOrvu50mtnIp6/H3hvadO2bM3Iph72Htoj2MBPvmK4NWhMfjoWM2eoj34RF4yLghK/YvU3aPmwl0mDle2bPkAFvDPaSpUE3zYOfbhjLsssuNLEfCMgq5U8tRSGsoR/qQXa9n2THRqD0wRorHciU/vzCe1lvoVqP1agofj0kUFeOpYxZtGJQ9f0r7qQO6rOs+b/Bt93WaSPNaBh3DNjXLbZ7SomnBmjuAjHV1KPrHIgH1eV2O8iu5FM0zahGyg/dDWcQJIfDLpR1DZTM9g02Je4zksFPQnmV3ZhURHy/NIUdqu4udL11iMae6F4Su4p0oHc0KdbMD+2m1RsHtclEhzSgYMwIWMATS3XPca9zU7bZbZF0GxYhaaDWdROfSC1TSUkp1OtApFp1FpzFbsVWDCgoq1SqZ+JU9txwKKuuZEdbExb3q0bLKj1xS1MaWqPhQzQkye/IG6ynn+3vmvvnF11fm7ricdta6YNb2PQewcdI4w+ozphdeMGP719ex13bmjPHgStPQey6de/kS28e2wLIbxCGg0+8N3ZKLkMOeSX3phnRKNXZNXhO/Tq+bGvbBJhqoXk8tFvfUMM991FKHwyILmTRzajg3l3q4ko9WtNRLe2yQSZqIMkhZgaKOpAPOKgomK3uJucYBdtvBbqCFDYVnatcM6pbz1FP/d2XL5cyjrmm9Z93PKnnK+5PBt5Tqr1/f2rz35H6rVv/z+VdnTigtC0198B+rV8xd07yoiNtyO9GnQoEwFY5MHhoRCqaiTBMyNWlq83icWtFALCl2tzuFiILsdKYfD1ucrZzE7ITFOnWCIMs5x4Gno9sUjCVxooTpYmU/T07halOSV+KGxbhL3LLL6ZDdMivSyJPzSnJLkuInp3qPGnvnlJXLpowYW13Rb9SY0VOWrZkwbsyY3lv3TZuy/7Gp0/aRw8unjLprdL+KEeOqpy2B9+NG964YN27MlJVT9u+dft9jj8PetYG9e0TsAnbqkFCB3WYDT1mLBBfVGK0aykL+st6grw4LBmq2mKvDDmQxwF+N00Y10Ug28GC0OMsa3ye11Mim5ugA77HdiCYmFAVK4KVGuWtxJ2UenqPMO6kswA8SeB9SRr+Cx+EJr5DHVy9bW8cSwpetJjsjm8k47veCrCwFWXmUn8/ckBUOJ2J1cyISERZ8PB1fRSk5Nq2mFYIE3b+f7KO62l9vbKL62l/Y3u6qu0NoDnK0DeqEloe6lzlv8dzSvKBtka6wsHm639+8yJbj8dgESm3Nbbfe1tZUUNbU6SjILiDGAmwWCpzI58vsG0bp1elgsaan+5DcNywILMZQyAzWgiSDlWfTqAZH8oVv4m+0pE2Va4mgHpxScFF48pAz6fqfZ4HncSu3hH8FzyCPpfzC+I6Y3H/kPd8e07wJD85rP3H+hu0DZ4yaNPqrt9+6mrnHsWb5godD03a9cGj2uOqJ7+BPVxyfMO+WifNmLBEvg6Xbp2+4W6uubdKz+k/ve+fDnlbzhm48uGhFeuWQ6gFte7fNa7F9UnijP2PxwBXbal8rH9tUGn9H6+7FATJarUHsI7xAHxBn8/0pDmWAUJX5/mCE1w4VwCRFVegYOg/bFXL5o2mGDW/aQDIFWPzj/x6NvPOY8MIZ+MPztNJRrnCEx9CaoCK0MzS6FTJKdrtsM9oCTb0Bb3EJkizSXGmttFsSEX9DWXqTTkcvhS2uS2G73VKlw2Zdum6Obo3uB12dTjpuuWAhyGKxTLLMtQhaCgLWkpaT0/xiOAelBS+G095M0pMsgY9JWiZrWc1dXPLGrttiplth/SBiLhdO0Q0VHUTIysxmMpjlMdpkdhnPsvjYPTNePX18p+qsqW22jD9w9uSB/xs4JWVE6O5JNH218vuJE8ofa1Zj7fHjWLt6mFL71ear01Hdv/6FCbmx5UiPflnT77722qsfvRW4reue3deUswefwF0/+wx3feKQ8vTnuAXutk754qLynnKKRSQZ779OVtCI+Ah4qC3RyBCIaX0WShWaNbMhW0ErZ25G7udhmg8vakpNyTiDXSGbWYddVBcyWct1OpNJ/jxsOoNjdhsPT5ex2yyVNDcFCO1twJIsapNUrpBwfaJOSImagMwuEvDrNSfP19wxTL/Jdnz9lv3p+V5PYZutkpC/fszMZRv6de0y9dat86fTMdNmEyH/VOdeuvH3L16kfNiuvWa4cXev8JQHQz06TygOCvySkNXtrgJb4zDPNbsj1BRpNFQQJKy1Wg1GsxGDerXZ9YRIOozNkoQMFNEfhmrR98w7h8VEM32DsUhWrKIhKXaHizAranAGYm/oYeUo7ncSvtwRmagcxxUnlBO47yo8oQxPTVdWKuvSkt7Ga6nIf+BsNAnZsUAFSTYj0CMI/LEjYfo3zomWl/ktTTRhJocHv+jLtUfptRp8eH3k+bq6WD0U2DQs2CnEz40ZpaJmKIgeDHVxa5r6/bmtMjICac2a5ecGcjUWIE2borRA0/RW6RfDmQUXwyjTkknMgfQAKOpAq8zMVgEqGAz2i2EDElIuhoWkkxFPba1Utz5404mI5SOwg/EX/C/SpFQFO1VzJQuLhSN/yf/KR6/smYODqzePHfDhrqq+h05V3EH++OsTMA1XKMdp2UMTx8y2K3tJRZdy5Z0BdXV1N8T/CG9J/WwyuhUh6XUu07rRDLooWr8VZPktyCZJHi91HgsjiplxptWaj4W1QlICZb0LyViZQawwIxq+oYsOTp9+8PH77398wl09e941rnuPsUKHGfsPTJt2YP+M28eO79Fj/DieNw6bOEh4AeY3o7GhEjBGJUoFs94g6AUL8O+RsEEgprAsmswyNsvpcpU8UT4mn5fB6pdFdrtwJKwVz9Rd+JvdVS6CyFXjEZyTJufzNPJGUq+TKvdYRnmieo8llpMDyjS8Yh1erkxfFxm8jtdu4bYkSDeKq4DLOocyjSZTCvLJDuRI88MBM1JewPV52PoRK+D6PIw+rF/AleDqeAAs77/XcLlxO5I+954Rg7v16DxYs8i476EF64ZXLxzlwa8REryry9yet05p37Fn986aexbMmdRzcefKYYV3MxwLSR7dAjjmoIdC3TLTTSYRebxeSbSlp7M0yNy8TJPRZPw8XGWaaCIGU6qJaE0mmspK9Ao81Eg9ntRU5+fh1I+o5vNwiF0o0Y+TCi+SblGjht5f1XNl8DqMoja8lqu4sVIuumXbauWzjKW2fbvPdSitGNajW+c7pCXGHXPmbxw4ZOh46rtv7jXj0o3LJpR3at+layfDhPtnjOx5L5jW4xreL4MmlmSRrBwq1rtfLioJOkW8/tpLyrvCCccPaV8yk0uZIbQHH8jHciGtOqPRBH6Jx+RJTXObzSafZK8Ia6nkQvy2Sg2x1jdpWNACTJIs9c5YzWbj2aBq0IluJBph/Of95mYIwqlTWLPg+JOSfm/K1VC7/D7KCvGFyAPKC8+BxVd77HwzJhfnKM8IbcFGNYNFYRYliegI1mGLVTCbzGew5XRYlrGJSpi1DuDX1zdVIVmz+F/1EAac9PTClxYdeP6lI6Sb8NofP0rmP36kz549dPD8LOYT4ut4H7lK3rBJmiD3tWconfE1eGdHZaGAxWo1m0yCFk47cjithvVha8hoKbdaZTORV4XJJi4VC1QtGJUBSfUMATWmwvdaLgmyhPBryvelgcLsDR3K802d7s4bPlxRnhJGSgObNCOnRtH+aq5AGpytbeJ8ZEJFoVSjAUs6OPO8DPNzXob5T1aGmXyq6pVhqkkRoGKLwCRhxXc4C2u9OwffuSkw81sSvJuMLOw0oXtZJPVuJm8+A7vg32AX6MEraBEyWnl83+3Rmj8Pa0Hf11AHGAVgDzQS5G8o6dRYI/33ladOvfb66XMvb7p/yo/TJ0+bI9hOv/n+iVNvXjq3ebFybeX6RWzeu0FH3x7V0QND+eBwg1kvU4x1BovZpDVZuJa2guq2yLKBUmSWkPQ/tXS8oILryyxWvxLEQIDoG/LnSdxPAZ3Sr/adGvbuJO6zKg1PxPelK6vKlA3xt2q8wAey+IrYxZKnua78ipAlV76OkFXW/IQfiZwCve2mxOGhpMKJQ06YpdqCLSgDeMhaWcT/VYJPWcb8SoBlBVjHo7C+VWFdZ7B+xIcjNXBmjcTuaQgBHubP6jkefeHZ/9QF1Ge9CTwyQjZKmjE8CnCoABegUAxAfH6g9xblY+EeoZTX65SHWLGOJhDwWGGrkSczS6MJ+AIZO4YGzLGCnTO8uorLuLL/WrJT0oZJbVISNBE1G4RbwRJT+diZVbSl8Yod5Zc3Pq5DZPILfbpPGXFbH7Vgp2ufpIIdYculS2q8RrgsPW7LZVlXVhndVvco+gk5a4hJzCVn6h6tMdsEOQfnFyH4Fx9/ID5+OqpEPyN7SM8fqDRZE6NRI+PJEviBOt4M45HD1Oj4HfHxO+LjGXzkyWl0fGUcH1Z99hlyh4yUPUAJslnUJ9gj9Z6pjj4jkW10AHKFDJRkUUpoDKXEvrLb5ye4vHSi+aHbdUazA1sJiEsqmTQGg9NsNlIQ6S4Hrgpr9FXhdE2BhrAQaZmmSjNHc0zzsUZOpw6NQ2MWrLIgV4UFama5jGYbiqXNIu6oRv2hWMGdrTRRYFkafTHvn2bhRE1EwJolERogi5UTqw/gL8k25RjuppzFsyJXuwu95uNUvF0ZJXZ5ROn3sFLwiHDSotQqGzgdJiudWa0L0CGX024WHgnr1Z/CPp/boJKZj+M1HnwPm0R55CzsibMGG8RcfKZuR43RgnRJPNJw/HQ0VN1D/kCZwZwY3Rj8KI8AfCOH/3mNzdAI/Mo4/PHIAXvuPUUYfAJP/F5jMalPqLsOz/B6BD5H8+gajiWv4ThbA06ao+H46eiupDXcBWvA9dbQYHyCz/kiEKygsfGVcfhxvo0uAsEKcDLfAh/6ovU97IJvWKiN1+4xmzWCHTySFJ9JkqWqsKeMGaws6+m8/IMsGqgsg2Z1V4F9IZhvqrBirBZs6FpyDuM1QVlFQVYXhAOsKMjKq4MCsdqgJUvU6iAlTfl477uv//OHmTiglgiRAZvIUOW0Ela6gVGhw5oflU7RPWsm7YT1to6f6184fUyMPp4c0VCPPjwPn9OzMLpfh/h+EReXS4dq3CkSStqvhuOno5FRucEeGOnyJkY3Bj9JLrmZnEl1NTp+R3x8Qi4x+CijRaPjK+P4jEc0JpdcTC6RFI/6RHx/MdqBPhVaClNBF2WHzIJOpyFI0iCNwSjjk8jb4MIP/H8tLtFitxbLWrwDj1R2j8XD8fBxyl5cPUbZpWzHPfBIXH2XsgtXjVP2KbvH4RHKDhb3aVv3gbBenAT2lw9lonCo0JXu9gupDptZ1AgoVdY5rEiHsrLdfle6EPAaA1VhUWMzC9RiFKi3Kqxmoqv3XO7SaPQ14WtEe0hFyyJ4nJUn/fP4K22Th1mtNHa4cW5WBq+R+GDutOGrqrAQ+b+59w1fWX3Jr6A+jzy6MbLeT1CvLcpFtWJi+fZO546CndUXVy/e3unpQ8rH+6ZE+i3HHqzbfx85vEClO88d5/vaNso3u9RzbuPnfHeN3VWPbxqOn44GRs8te2CgzdlgXxuMTzrnds7HtkbHV8bhJ51zGz/nLkd9PoBneP4zn6N9FKfR0Tm0MMdorUHQJOZIqhcxgn1ZHEq16yRw6pAMdodorw7rbNVhUSfqpGjFiHrL0TCDg1eMOMGvcPKakVicoOq+qw8rX50/j40/YHJh375flS2Pk5q5r0xUxC7ffHR58abIhW1Izdm/JqwRL8PpHhgqkNINzW2ePFseSs8wgLFVGDQ099Bsmu2rCGejDCfLo6qWJklzJQr+nivu75XV46VEJnm8UqsARyO1udFAbcyd5RkUar8lmbdpcPuxsObZA09MIu22dhk2st+oYUNLi9sVLZ6wcUXNN18/++nkbs1unRGuwnmPHG69L5Bd1ee2cR1KHurXYVSLVncU9qrcvbeWCvTal3uWLh9d1j6zWZeK9g/zveG5wmIN7E1nZjug21YjJpVaWZlUmlTTuo2Z1Nv/huOn90JcarAHCloFE6NvHkuWfI+Q9zRpDUMzioF536wpbsUfqGwI/2D8mR2/I5QZMnH4rdrhjHbY0g4e/aCmXTf10crow/FnZ8dxGw+mtz+ko+xhSjLawHNv17QpjE4ZZdDYc5I+Puc2mJNLtiB7zlbcKiU9iaMpcsD4M0JvHmVuj5aFehgyW5cC2Vq3tuWlpqU1tUmy3A64pUPHYm+GtyJciirCztZ9w6XOUqc5OzPDnDoxlehpamqGhTY3N68IG7RmnntqVlknel0SveZSC5gZi/+Xtm3BWL4cdkZrb5lbfVMmNgsbsGsjm9UpJsKohOettsTkcbGmZ9iyvPOvM5dlttk0Yt483OPxUHmP2+QD9m2rjncbsGf/wVqxtDRUXTyrT9+WZGe/SorHaQfj36zKquHlLerQvbNm3btvJ8/UXjKx71Dr5lUrVihfKP/0XO43Krx5MEvWHkV6Hd36xA5G8/lgq7UVegPNu0Zttb6qrRZI9yFHwlZTe38wHipX+fME508f58+TNanpRns9/mw4fvpElT/ZAxN9/sTom8eSJbI6NhXGygFfI2Nnx+GO10R5xMd4RJOepo6O22dqzieD/ZOK9znGi3qss+biaj2u0AMzHqzRmyjmTBzn4YbPTR/LceLP3aEz0mSbrsFYskTHzwrWszksuMKCW1lgml9rLLroNA3nmR2fZ3xThApC6YRNRPBaE55rwpNMuNqEK0wYYCKTQdKqMCor44eHoAeBLr3Ff6AUsLnnhHoIssEsmCSTZPUQn88a8HiseU2MQprQQqDEYDNkGqhZMMhmQRCNyF8RZkUVFkRYNYSItE5nNktOMhmNWt6YLFjvWoVXmqq96irrp1bG9HOhOzdPBPXMMs9y3DKyOnlSYYMWfWTUsuEDlii1JR9MWPRWxRCsKXkH97zx69e//05SV23fsW7tuj2b6Du3vDBr6r3DB3XLvnXKPcOUd5SApNxQfsLkp58VxXThyNHzz548BnTkeZZcXvVV5ZVO3S8v7IE2q5XBnbRfPC+S71c/lSee4rzs4bz8dI03tYGubTh++miVP9kDoz2+enq/wViux9lYwIMgv6eRsQfjY3egBFyUWdDI2NlxHJi+53zvYXyPUlPqaXuK7kMfC4OEafx+T48GhIr0RMOasYiSaDRotEfDgsY0FIvAUEfDZozVWvZj+AdchyXgbjHeHw7F488NvEf1ApD3a2OXgNYDkafptchTB+izp08re9evV+acPq32bbgXcK8EOc3sQtY5p6hRuzA7J93ldwvegDFQodqFRla+ZqEguWPaXE0ttP5/WodFcetQVq3D4hxuHWZKQqVS+/vlOb1uv+NOjH9/b1Z574oR5wIK7bX2wJbIikwc6blp3zbiV64rH909qHPV6u+wBWeM6td5yLLfNlRFLlS994/1w0go/HeVP3iOH9/zwSo/7WX8hFOszDLcXuPze+r7IA3HTx+i8ip74I6UtMTom8dyfgLYPg77z5qMlEZhz47DZnzCPNgUK/dg/6zxp6pPJNmFPAeNzzFMxeduFR8nTHK306Ozxmcg6CzL6+U55RmoYyg9TUpJ8SGbzxbITAVv0eVwgAnmcBnMZloRNlvqXR0k1Z6otmGSLMA8sdeayPdlOf50aSyRN/I1T+yNpvrWCCQzmsNLeqkpvdE8X3kaq/dJrGl2fE3jRaRax05GCNHrVlcV1xNq7GZ4PD60HBGsT8SHzA3jSaqN0z9uqyy/mmSv/VzTOmqrNIgnHYzD3xLzU1X4Vm+j8BM225bvEvadHLwlAZ3BVqqFj8Uucdjb8UXYH/0pYmOV+AkdPlcZwOrRojDZuMnwC9NZROqeryktJdxmZPEb1quE+wm5UT9hYdRPAB8WT3enGOSb5GNbjmtXlX/GqPzDmBR0fdSMUHFVYR+MwQZ+dkT9dQ/AltLcfw07Jk9xKpPrAV8jsMfEYW9FfrQ1jrfV7W0U9uU47K2OBN5+X9pf4r0UWaN4M9jUm/4/8F5am4AtpmXVg837q3DYeSrsumsAG7jJxmMSL9c4UoSERqIove5L4Q04gyy3vikaFHI1zc7OzcvL90h+ZDZbJEuzfIczt+kZbAjZw7m5ZqQFiWrUWqjvpnIwVaTWy0RrWBqmFgc1XhuGi+xBJyWbWy8acej0M4+NXBirEFM6Vo6buGzRlLuqyWd9XnqClYllYT024qb1C8X+783rl8599CZeH8DZOconidj9aOBnCa2P17o9DOv1o2ZoVChPduXQlBTkSzeZfPnNwRt19w3ziz9ipx6PJQVZmlSE7RZWumfSGsotZn1mRVjWuwRnrKAon39Vezk2DFS51dRrvtSsetVxRayyK+gEnZdEAcHOlisml8gp7+LmNQtqj05fsmHFos2LZwqHa4N8uUAEM7aQfCDBjgU7diyIVP39hdevvvH8a/HY4/B4rHI5soH8iccRf6kx1o9VqnZw/7jNvJwk7GucWt9mVmEfjMNWZU8c9uc1ZncjsBP2+BYhAVvw5zYCe0wc9laAvTUB+4sag6kR2G/HYW8lUhw29aXVhw3yaiSXa02i8qqnKq8wyCunU6eLyqtFMK4rl2sqzO0dVammfF+TnS1HA86N0GFpQzqYHH9Jh6V/JPk8f9akZTXweXjPHg6/WTyGo8oIH5NtGSli/fg0r/Pj8Huosu03lc7MMZeKW1lTG8ifZNhbQA6osFMAtjYt53/A3vJbQn9IwVsagT0mDnsrWGNb47CtKamNwr4ch701CbbcqrA+bCXM+hhFYUuab1TvUkxJiwKNwZNQDJ7m+zoVXiHAMwbr00GN9zI65DegcTQeLujqxbB4naF0ELSMHyRlS15p6E/zeHxulyvFp9fpfA6anqGWHMrIoXP6PavDbv/KcIqb9RB6vTA/nndfr9w6foXy3woSsTMrL0vOKioJ1i9NJL+Pu0q+HqvsE7soL6k1ineT2byA65J41rFihYO1ZGRd2IRXxS5gM/MuDw7B4KZmM7IYZL1F7/G6TVVhl85mt1WHZWqvcOPd7uNu4ra77diit4mx7gksXpHozd9YU1V7NIkv6OQJPez6vYjZ9HtZ96Xdu89Hfj2/m46L/CrMexH+bKy1s45M9LuNyuqPPmLxuaJoHWcqGhZqqiFut8dsMoGN6Unze0xOMcWX0jcMHijS6+2gfPT4E/11PdFHG1/rzbzIM583g2I3B7F4S6KZWZzEPDP1ZjKz24SzT7ImkclEXrhQvLxjwUKVvL3IFk7eJwQWzI3fkeyM36nsgHX8Er+Dwa6sBncqqo9+MO7f71BtcB23wb+tcQRoY3cww+Pw47akCt9oaBR+/zj85Zok+D/V6HX0r++EtsRjxQw+AmneGPxEfGKLIxHLQEZnvVjGqyBLMZe5zVVZagRZehocRGsM62jcAsaN5jLgdnVcWzaOkFy7iSaPU3EdE8dV1Q9xWhhMybjCPnBceQ1K85BLLc/V6/5LYW5S6laiIje5GletxeVyYCTIuEVwnlgJzy0hP6F2m2ww2Ch1ue12s5m1c7PrWNs4HaW2uJ0Qa2KY6BoHZz0rJ1qHa41n+Y48f57sHFul/IivvPrMgbM5TznuYu0Ll6xZTrXba6ve+eLIS+nzprEcv39Ea2CYX+5CKag81AQEDyHUnZLi0llgdl+qEY6K0ecR3a2EaoHMFbBAY2VicJqj4ZjkTwiIIcY+cUQMWpPrhdmPvvtbjeMifqsmXjHsuCi0u/GyaLhw4e0bh2J1w2IOr1mGPTsOtGrKZWyLqIy9P3o+2N3FFre1QXxkGqzJw/hL8wOr0CBL7orev4Lsf43zUsu47Ofa+1iNwSzo43r5Wxin8lLv+uPOJY2L1TNH67QS9cwgWrQCjRc0i+ZoPXMwXs+cyOH/X+XM349U7hPaRb4kKbycGXDjPdE4LQpUX6hup2ozSNxmGFsjaZGQ5B8vZvXPoG+0sF/dQtkGo9Gs04kqI1stZsPKsFkT4vxMby40T/FYXs+v16zupnJzlgZGPomy+Mf4vSssIwz4XGi6utpxPe0rjjPQ83ZO9wKVnrooPd9JYMvyp/Qwbhine5/6dP+5Jh7hjNMgDk/WfIObi48jW0iHNRT/HAdZxmyxD3iNyWULwHyDjf0O7wOojr9hEB9n8KUE4LJGYYN82B65g1kIYyRNDFWOK4y7O44rjMO7YZz1BAaoD9foDAmhg/ln4tzO763KwVvQ6wXWnt6spVgnyAIxa1geBTVTDdEQJFLeLjB6gc0VJjgF7ENqgslVoEGrnFcCG5LjFlnju2m3nj6Pszsou8hu/GqHmdXk48jCzTPPKvfyPlOLozXwVtQn1ExEgsYoUK3WZtdRIxL0vL4GfCG9RbaA2WFBrHMhOCjJci0ea432P1LTmMExKeHzM26Q83hOMfnk047Kpyo/fBDCKcoRItP75k3eFzm6ejX+bvakXaRgdT27qXXUp5+VdE8+y2RtcE+uxlNrovFUNn4ZSkRUl3lTExHV+FlvxvextcpLn0Z56ZOaOGwOF8Z5ua3eVx33RXTc5zVxmOhmfMFWl5LwlSyuv8RX4rZ9DFvkC9SL/4owdr7YFXi07zjOz0oz8QDynMI+isG4OBO5EMMlmsfF6vhBJg4Qh4DHfVsoU5Yko9/pBNXocmXn+AMBa3U4IHipy9awK2SirteWaIQbLbKP14fcXOgfyLAKA/aeGLag44L8ri379LjvgVWnYhX/47EH3038yjvKjbLwqPZ5z3yK9yxbcHpL7TyhKlr/ryxQcQa5zHoPsE48fr/DyD7uyOGlmVluX0XY7TNaLKxUzaIxi/EK8kSnvVhF5c0NCJh6yStyq4iTpfV7Edw/s1dhxy5tx9EXGnQkqD24eaV2hVQ+lmYuXZicyzA8nvuQiLnx3Ae3q9E4fP94vDzm87J4OfZ6GsnbOBiHnYi3cdjewF/H+Pn4eCzel/VXOSFkJ24B9lciB6Mq1XvT3TuD3z8Onz0TqhfBn+L3NcjbIMhRd0N4SewJvks6mhnqYTG400STzeY22O1ukWYETFawWkx9TFUmWmZiidBrTLtMx0wfm2Sz6byJGFixtcNpd9irwoQ4bCkGvaEqrNHoaXIBXzRFTM3amVK/xQ6/IA9IsU8scSeSw3IKS6y56s/JiNKmdd9+h1G7IGmpTGG9vPDpyC3lqbkdHt20VcT98DA8HHeWHlHKH1ZKH1kpCQGpDinXle9YYiaLZ6UCbWp4P6YcsBInhm7RO31NEfL5vAHWJ7mZ1+Jt0bIp8GrTpkZ7rt/uB+512i00y5hVEdZrjYmmQcZo06DEzW0wvr4GfXDj5kCsAIi1nJJiES83uBlWZ456MFlr7tj17MVBfTv1Ni0v+/JU3/6ndxw4tPfpPgOO4rLI3X2GDh1waHg/fHv5QIo7ayrwb+de4fexp0/jALayDhknTkSe8+RdffPNq0r/t8iSI9ue2BGXdVs4rxZFZW15Eq9aXF7BWI9XeT8IzksD1HhrWJV1LpB1t7i8elQvhhJm/SujsEHeRqIR35dq4nDZuNdgnJPL5QGqjleuR60B5e2aGMybcSVL675TY5Vq/tSpGo8/ge3NuJKlDu7buLhv8xuM1tc/h7x/JYdfHKVFzPZsAXJ/fotWYv3xvE8Fhz9QpcVAlRZ5MMHAvGb1zm0D2GDXClHYLQG2Kdjir2GTJWYVdhOAbW6RVx+20pn13YzjPQvfrkY60lrHwKowYVy20DMKk40bGB2XHwOYRIcDcVyXxn08RgddQdH/wHWpmKCD2LT+XeLtsNdzOU+UqDxxLaqDP6vR6AUpzhPPKmHWOwPGDVLHiRxTk8uLTLHYDe/PyWlakhRTYzNrmC+qs0ThxfAcXXcdZBqzDwc9rtqH78MvuB1H2tbEIRcl9/40o66hLK3RKBGTCYuiTpIsVmQwgjAD85+1UdRqRaPab7vhJ+tF7wZjHd6tapiDZyDyHqHXrz97/braJ1QZvCmykdyzCR/YHu3HfBFwpeIdKA31CzVP84KvaDNpfNjksEj+9FSH01ERJharpSKcZrVKXqfb7TTrJZBIrlgPbmuwAT7cZ4uaciycEe8owkujGV7RXiP03URvkQMHDkS7jZAlC69F+4v8uhDnqC1HlKuJfLCd8fyxREyD+Ww4tWkDfafeEx6M3yvuwEl3ljdqsls3uFdU4Q+Pw0/ENDh8u61R+P3j8JmuToLvS2kU/sE4/Li+5vCRM61R+Il70S0oCf6fNWk5/wM+yy7biVqeJNjJLgo8Dk/5Wiee5MQWJ8yGnSSRc1eErCzXAt7E5uU5Suq826L3q2mx+9XYjWyS7mdz90yaeyduC2tL5OqN9zhvshfYPH3j62PPdETRG0x+lTs+I+3meZQBrL9tdB6JbL+Fn9cO7tjmMLgwpq3QLg53Ow6o8gdlZhqNCfmTuK9sp8rKulrV7/Vyv7e2xu/RJtvUvPcLx3eIKitrk+6pa4Eqsrfefqi5iAdjuYgJ+LoofLM2kY148x11DL6qRyI1PmfSLXUCfmU813E8nIdofqSW50ca9Sr8JPrxnq0cpw5R3TMmyoMMqTE6I67Pg7xfCsepUtU9AxJxtaE6I0rGX4U9JgYb/FxjNA7GYJt0hkZhX47BJlsjCdiCztAI7ANx2EuRLqorGGydwfbXeJOlOAFbNtgSsBHGa6P9EC0oLWSC/2usNtHAWpPyqrL8eIFrIJonGWt6yDoeJnU7FPonuhxy27ZdtE9oGmqKxoRaZjtkSlOJ30zMzfK9TlteRdhhc8lpKK1vWDCD/UvsFLx4wnJDdMZo+NhoITx8HGzQgaKxzoc8QlaUHEW21msympWcjdBuTg1urbyhNhaNNxqdQ3vPWrhp6aKHl8wUSzdsWLCOdRZ9O9FslP49Muaj1/754duXeN8lWvdhVH95wANrioaFWrrsfruA8vwao9EveMH6aJbvykvLS6sK5+nz9IIlV7SI1WELFfzJOfXxEo76n1zS4BOy2GeX8E//lNXiuejHmMRTbqM1uhnqx5is7HWrbZt122rcFl9f8+Djp587efyR/cce67t58+wHcXP2WSbCic7dWre1dmq/aLNydtajKbaT0/mnmZB32UebxO3Wjeyelj6Hknu/snvpbiGXCflFi8XoAU7PznGBy2l3WYyWM1gXMoSNWOekgXpdYNU76eQUEVtpw1awvA3XXzWDJR9F3o/2g43tVf1+sLuU33lD2MRGEdgHvg6e59wmlKKz2yXBBD91e3S2qrBOJ2ioYE/sSLTzbnILOHCJA9a8opyg2hk/l32ODOC1se7LyE87cU5bfOt/UN2FffuU93Bw33a87PTb9PRjgYuRVy9fmDlVaTJJ9fdKo/TzgPRqF/Kni1aryegFtHJy3alwINwWCyNb5n9tnttY91yO1V/SbC7Gwb+gGa2qCZyNttGNUQ2jQYDrMN7Pv30oDZw0qwXpLXq3xypZJZOWfZCNyc4/rUZo0JehAeX4RyOx9sQZ/BNJ1Cbz/4+07wCPqkrfv+e26XPvnd5rZiaQRjIJIbQMvUMS6lBMUERARLog0ovUoPQSpCtFmoZiRRRZURDBsq64a1t727WsheTyP+fcOy1Bd3/P/+EJEgxzv+/cc752vu99DdT6fY/ftSN0YD4YSNrET8XfxCc27myz/87jh8mDMJeiF0/pBAY0DhCPiJvA9E4PrQQCitdgXs7ksQG4epWxFoRO8Ho9Hiur0ClCYbOjOm7mBC/HelmvmuMCMHOm1VA+tbGZfGX8+WSumMY3kCRvwoQ6RVYJK8IcxjA2MrtOgcSuU/HDbold5+n7V9zfunNeTo+OTUh2zj0pkeyMV618hNth6NHvS4lsJ4lPLDIUzIaHxrw2gjEYBMGj9hLecIQxUB6DxxCkgvA8BS1KHTpOqriSwnCOvNSvd76pQs20wXDEVtyJnK5Ac2TiozMUy6YVFGfldC79Q4TiynnLtZv4Hv2uNQMqbt7LgW3infhe00V0iHmhJbTTJnjW3B4NNIC8rToum0B7mglsOsSYRjCUMnntQHOuoR9kM/emzDhk7phgHEo3bxnUQ+gcQhlz8DwU9HExn0LQEbQgqAiVxYqZOii1Qs3DrWNAo1EKqim7VBqzAwLTyIpKMOf+QBaCzUB/YMuImz+Azo0tqE2NP356k3ihbh+Iim/v2wdWPH0JbKv7/ZmrTzwwGbw7LRPrGdmFHjHezrNeQq+HJw3uazPPoS0gxHmgDEigz65mXT6Z3tBQVtQM+BnfZv0X6OfGd8h/sI9TCgn9edmmJujP9E7U1cPOawkmfnjxzc/eefl1JPsiGLchDFID4SE6xgJ2HSqOEhTJ6hivj7eg+iPFMjBrYlwkFJw0p7xes1okzwBU+pbQdG4BUCr2AtUNv5KKMf8Yf88QGal067p1tdvXkR6R8IjXlzwcPzZsxJsHUnCl1/72yrXX0Jm7W37nGvTGlTShYUlSQ2gQUTLiRiFUKNFUUQRoxiyV04TiNyrD2qOvuynQOIasa8ymNteBy9vAo3USFw1J3AXP+J3QfgrQW3aLBaH9Mmt0JhOjYWx2rbk6rhW0gpJSQv+jNFIc3HRN7WgzxkgjPM7IiCLGmBI/6Q8ogM/o94Dtff+2nVSLv/z6q3iDKjGJr18YA8pA0NT4sGYnPWnGfdCMIt6Y28HQCnDxUMM08NYX30h2aBSUcQETh3ZoUCzPTZmVnF4fCAbtrJJiwhHW6rA6auIBK8dZAxSh0UBZNTThgwtkbIo4kohcmrCaZ6FRG/hbVjo2uj9qThJ6WlmarPlO/PrkGvELwP7tpV97Hig5OmfJVnB7jx6vvnBiC1Dct32o+Ivp6qmlZwxdPtn7et0TnRZPmX3Xextmz528FPD9nt2FriDgHkS8HwZiSCxKCqiEwHGC0UQD5AUG0NU0xdHl9L00paVoROJF00qeJ6ApohC3lpLI4KdNUHmVlaXmGqXABNXFMVBEktZr7eIOVcFo1rgEu9fotVtMdcIO5gl8T/QVlCuPQYiK/WIRA2fUq7RKpc6o0+tJi1XLC3xlXEUIgKcEgdA5CWZanFAkQ5AmrWvyVJMMSmXFxF4c8Cv8VNAYLI2WdgTUmgGV2a37DuprcoJ8u3j1x/ofG5w33FlPMnHrcmOH6hWLbxTRry/esm2+zD/G5LKo23F4rMDNqG02qzXAIzBnKpKth1ZQrwxlQRtoU4ZsIURCBh2skia9KQqydAckeaW0AojkhpJMZE296R/Skj0zHTnUNr4eHQ9XXkHsZJ1Xt85kJ7sz6VFllrJIELGUoTPHwPX+C+Z/cROdY35Wa6ZUBs5GUZyK0igRO4fG4zWrCDW06U64jaX3Lq1rM+JHCW2yGGFuqkAUWBESSERG9sLTDeOmL+3XXaQugm1g00WR6jlgmdvZrq0rPzs7Xxy6fOqY2iX0vIZS6uKNxYvX3jl1eUOL6tmzq1sUlhTjszcenr0xGDeySyxo4LVa6Ce9gQCto7JCPs5gNisr4mZeD3RmAtl7ueSUuMTJqOLjoybhQsrXTHJAmEB2wnAfPNVrzJx27bt3G3LwoILqv272lOL2HUsOmvpt3wjiGyce3dy4iLkkzru/8Njjz4nbt0ybtZ58ujEqzpfvZtE9MovuZtM42oxETSxKQNGBCibzSkGnM5kVGJ6ORkhex3nKSPG8hlDiiwmNAXoGY3PqtibQgmnswAkqN1TUky5FcWEPU7pduSKRul25gmndxLFrREddHfhsDdiWxrU2nDARvWMhI1ADSjAYCMLEUxRtoi1mYDTyJEULkgWgCRSLRKWzh1c2ExnOICfBuLMguZPNCdo1/+GzW1Z37lxUNg+Rr/FkB3LaE2I5XbR2K7ffsEGcSJ5sPNnIEumY7SaiZywLyYUlQrKZaJPZkhCLU+qq4oj31nwrsf4XqXDjA5aq84J0NHd6nyRV42YZ0z39PrtvLMwrEYofTevQjTal0Wrg7tNqFTy+ywa3vMuW+7oy3x4C4sx8b+gy++pV6Sr7449RcwOVt6bxu9pa0rCGFGolnzQVylIFZTFCm9lSpTYgwARWo+VouEwkSfB6NWMyGzigpY1GHQ9YjVrHU2q8SnA5kOG0JhGp0S2/IC8SUADEM6cHIAjQ8Egkai2l8neB889faWHjWoofPwPOdTud/2yvE6130Dfa3+hEdpk8Nn984zzq1ee7zux2eX2ZJN9geG5nw73vJ7rG/GoVaTQaDCqfw+FUOQNBr8FhUFFWPaOvjvugPTISCYh6dFNVnjGHLVlIJiAPEArRNDhoCyIVxP3YEZbyLu/om9Fvy8q95RW9Ou/p0HPjHtVKZUfTY31HvH2dOthw1/aVix6kTjaMWPcgcFJ7b+yZde+ybVjWm69Be9gSY0qWxOw8Tav0hMlk1putNhPgKAU8kwoBs5fhhCIDDjFFgCfdBmOvl86Et3xBj6LcNtNkPrzj/RsM6zZq9uih60ux4kn9APiO2sBS41J3wsxwA0tvIRK8eZ8xC3H/Zs9YyM7qBMFMsITXh2kYVRpjTVyjoSQwAppyZRDpSQSYNv5CTiYbS4pXz2dsXQI3n9mksCiaE+ypfgV9Z1YNe2lP4FYse3EwTLxSPvWxCW9Nmn+kKdcezOEYCmO2+5GvcSG5LVDuQBBKy3H6qjjHqewYiN+bBsSfkrupxAlU/qTErCIDpCyBzw/WdKse9lLNbTQOfm8B0/9gl4WPTZj6ZGluKxT+IrR+JG+ROAzz8/EwY+sSC1gYmAs59Tqdk6FcboFXq0kNrTRiHw8zMz1y8hcSEku9sJkw76HUVWooiq5cIpj03gT/opSyLl3/8dc/XJ07BdyRU/9ofU6PmQ+umdcx3Kcar2tXcE+P2G8MG1XmiJ/daBSv+6B8YYyT3R/aIIRaFjSr9BTlIATBoaLcHiep1xs4XmOACRDP2irirAX+WHn5nwmIsKbSciAoJJCXspQKU9efLNta+e0P4NOqjVHQtmXj0kfWrNoYawOKxaFMecPBSC660yVb5Xg7/W5gpl55/52/Wqh8k5zfjsdnyoPQ1TQ8r3CyrMIKIzevz8lUx516p15hdCiNypq4kVKkGOyaRfUpzsUcJGx6cS+NfnH8fX9/+OzZRDlvqkTCWLcvScKYlugm2BjT57hQ/bULyj+yrCqV2kOoiZY5Tj9qD+H1pqq4HqhdZARmZ+R/rdP5kxhiyNV4geRrbs3YMOdghKFPrlvbOhJq034uXbR93oUXn561NMXacNtwNM7F9nt4s1L5qGmD+MNdo9GY198vSMwNJLFHPEfvx3eDVqJPLAzttgaVkGk0AKOhNTa7njSR0IDBLWtSmBQ0Q2EXfiEJU0A0cZaywVVhDkaEVoCh3VQgwcJ4UVz01dmzIPjlT8/uArvEBomHcd0m8Rz5qTic6bb1XP361x2NDD1NomKEvmAMtF2z4JnKJqpiLfUcRwSzsqArMrdo6VaHDUSQD5I6KhgMh2HOFDbCLWzQ1sQNdBp2UwqmrixTWlRYQFzrVEmx35eEotODNCgnmAFmjYlW797dbf4d7cRPxZ/yThd8+7ePvh986tiRRb0P71x/2FnfWyz7RfwJ3FM5/7beYd5X1Lf922/7H9/yzJHRD90eDne8ree0ObPmhcRtF7A+B6E+AboPEYH5YA7Ux0n4AwG1iTBlt3CqQwa/PxTyVMRDFkI/WU9qKKxQRdzAp8EtJltqy5ri7aVpFAxgjXwCVgiY0xFaD+YMXrau08T+OT9f9z7iuHYcbI3v+3VcTe2CpWvM2/1vvn7tU+DqeMeAWERwt2iXv26dZd4S8frg+wd3cAworxxeNTCwfOEW5GcmwnO6G9euB+Hz8IE4lNrIvI1rLANjep1CYbAThNdgCIUtrmegVYcx9s0XYiqVrqfFQnFU4Ayw1cehJVefAeon4pwrUXqTvU5OU87h4taZSKrQVaagVOV6ywf33rZsSbu2rYu7dVqwhuvgHDSuX/tWhe3bFbVqz1iG37llxe9vdO2je0S3dS3dqDHcNbiwffvCVu3bY54LKD/iufDBuIhHPBdeo8PB6r16f8ClhSLWx10WwYJKRbq44JKZLzDvxYVoE56jzJeSSX8h8LK3b90BNGfCaOzStU1R+9Yj+jYhxIDO8zNhl6Fzj7laiRkDIF4gfDcioNhDodWSPAAkaTBCR8MRNO7Hpsg045iAcE8338F0k4gIP1+VzOBmqq1E+9keWb7eHZatrkvjAnmP8BKdYlpOaTSSHo/N53fiZTHEnRZWUxVngQEvDoc5QSQAzvNN1kZal4yUtRlByLHVyzq3bpNf3qYJTcikLdv0B0y9+kxozhXSF9pkaU1yYxZeAQCn1RqMhJ7DJMHwi4Op0fmczFg6QRSSeLDU19CquH1R944LV0mtDb9/VdmXf0TYsJxpnehtqIXxSRaMq3AV1oTwuR2ERtC4oQeogZmvnqGdlIHSW1EdX84toxfSbj6SgUlHkAhHhOZ0qaA6PuyldQ+//e0nr58dv/zh6c9TN9z3DnxswtYX/GI/8ZefvwIkok99Y/uedxB9KpSrHtqY7+m28BQOijlBEEZNJpdCoTYFTaFwFuejK+I+i8utNp0B9pg27la71UqbmdMr0cuKlqeQ9tNrnuneNBVFpwnehF9l3JCZs1eerOo+7KU5y+XWxtiWSYe2IpaVHbNO7CSnidOD44Y/NmHjU4XiJqnDcdrwFN9K25tf0+vge0S5u59Ta1mPjbVRDrOf8meFPC5WhQYN7GqKMKRqZdKETtInyQg1RUUoBSCEYkMpizgdzKxs3kuKyUgJoreIWAxmniDH/ix+dHTvjNxXwCfLFj2+78ChxUvBJ6/kzth7VPzIDCMq43Og10RN3Ye3i78+/uEX37x/BChu/7BOc494+lnxG/G55J7AHNVOIi9mYymd1WqkYPRn5qvjZkSIokqJW55OZs+k5ScGXGVQRKQLVj0g49/9/ewD6yZt6DNgeNsiRZf+oFf5/JdNvzVSdzQcef7IdjAAeHfUqndoxS7il+KRv06W+G2ZPlAOI9E25uL0eh7xEWi1JrNOzfO0Vk9pDQQLZZFLouUyerFsHzBLq4zMjhFXEmytHQF9R/mkdoP6tSsotoiHZOZWXyvoovOiy7vlZzV+kqBwBdcH9E+eSebfePa0e4x3KZU6lcUCjavPqjKZ7Mhu8HETcCn1ekIlMbW4iFTIWZ66sY0mE03JfspcLdHWpXj0HYuqQLQtLbsXhVseqxEwawtfQXJ9gZC77N5FE6u69hwdFXsNlQhcGnIRf0v2G7E3KNWcWaMWdFxxY+S3z0oyJ7hnBWJkrFChZjUamD5wJKtlKY42GDmNXlMdVwuEUBOXgasJWm9ANC8IQTCRuqfVGNO6lwSDrAuqvSToXvzoqwT454DHwSDEVCvuAqPE9uJGavSNC2Cm+Cz5M6ivWyW2Wyrm1q0FH6VxzfyJjBVYxgosowbLaE5Q0fx/yLgfLAYmRE4jfgU84lTxffJKw10gJH5LjgfdV60QzywVH1u1AoyAMlrFIfQ0uI4uGGFmGwTWBRibSsW4SIFxe3Tm6rjOwDqhtWRZymBgoJlAd0NpokUzyp4JE6SSJKIJMwbYzgdJmoBwDgCrwU8Nv1HviwqgBro14o1HV15+qMOe8qeXHb/yxW+9yWfAd3W7Rasg/uu3x8WfN/Ras6TP2oVfXn75FfTeu0N5YUxDOIjesQgt2M2ESa3R2ExmgXG6HCYTqImbTGqLBSZwFkqvgKZdbUAOJf0ug2iWJwUDdBo6qA8aIyKETJEfUOW9vxNvvHJ66XMddg8Sv38FBsXvgAgAopJ6v+E38BOZ/8Gll95euqrPqX0w+yT/DQqc4NvddSJysAugr+uOuaLg2iqMwEpZtDodYbEaGYfTAs08adHCX7zNBiriNo5XV8R5V9PCcrQZI6gfJC8PpICRQBQqUFxa39gbrKjac2bPCiBknbA2/O29m8Q/z4qLqPHUEXHeQ8/t2Pdcg/aZ54mbf70CNHYw4bh0ljbDNR0H5cyGUWFuUGET9E6jNZsgrE7BpGBbtLTiNkCDzQY3arYt20aZqTAa6uHQwqbuajL3Z+oKhMU7oKQ4iaAtUyghColkNO8rpcdliz9eW/nX8YM3Hjw89aVzYExjLTVGnP7EqQErj68YXbx6OTB0vnP7ob4rRg6Y1D+nZWXb3h1WgZar7xOf1626r2piz5xAfqdWvaouYp3mwLNUCe2rH/N0+Sg35VCpoRux291uNU/BtM1P+GEmQhAuncteE3cZVKj7siauo5viyjY9dshlJU5eU6BsBcyq9KQCHUOorn8OOX7F8kVT1+jOmL596d2vJ2wUP/5p3jAr+VXDoOiLZ8VS8uf7FkycNHeKcPCVZ48sn7707IzJbdfNmPflBqzDLOirusG97iR6xMIK1iagYQzByDIutw36K5uNMllx57uJomBEkz6TkdERnna9aKLTOTvQRXKwBJeXi2i6m/ifr87+GngyuHHK+r1H91w/RU1pbOz6JQDghb/dePGwed6Mw5vWPQxerasTr36J5NsF5fPDfeNA8lnMGpSYqmjWDE+iBpowjcYAE4yKuMVisKhZBYutXHmqJ78Z3y2GS0mIZJaAx5M8etTEh3a+/BY1UnT0fvuLT66++FnoqGHLeKABw8eNActXrxaPPHb0xd2HtKOn4LVbCGUrZD6BmT+6eeThic3yWdVqH0+1zCECwUBl3KqLhIOcDu5sQdAlkXfOQ9+asY0TkkncJ1RT1hMyki9x/gilCMr6UmDw4B1L+rf85P2/fxfa6Xx0/dLlkb7T+syZX755y5M/U6dHD+yaawq36317bOdjS9d4h1YOqCksz/UZPQMXVk9bDEb0F4cuTtUu6AqY+zuI8pjOqmYYlidYwumirZJLpmlWh6Yo1TpewbGoFFQevcUFvcxywKCM32KOpuH+Cx1JunOt+Ffxk5MH1fSIz1+6/PTCObUPXf7wHnLaXvH7d8aJ7zCfjO998aevju279G7jj/2OvIftBamFAr6A5ztNp2WKMGhjLydw3BFOP6mtZy79XizxsEwlCGq4PA/qjekoglYQiDkd+gdUeb1clIba7ZcNB5i6/5H96CPwxwBiEXxOb1wTh/GmktZqBYCvWvB1Ck1oOJ6rjit5Av4idagIInEBNaECSjQmGyUuARkCWLrKXgRWHwW14lT0dVScDlaL02kWXBDbbhUvbRVrwK6toBjXc0moM3mR6WpgUVcV/IK5BP0Ou4ZQ4Y6PMDE7FrPrTWqVkqJYEgC/P+RlWNaXleV2e9V6OpKd5ffbOFt1PMBR3lDIrofOyqM3MEAFVo9QUbVxFUOU5yS6/LAGyT9k7suokD6mj9GqrNHSqFkRpHgSd4lYDIpEvwjwJ7jryPfGbSI3jDv86M8XL+6/f++5+GP3zqFtd0wj32t8HTwgXgZfivPBQna2ac4c01uNGnGveITptkT8ugGQv9z4EWjFYbW0s27ljY+IpP4vMVuT+s+IdUrX3+fL8kD9vcFgKOTB+ruzauJ+H/zi0CpwFFoAd8YCCGkLkKgZ5/x/6G5M0vaRp2Xdr2XqfgDUiK+AT8XtYCWzVFL85i0UX0LlrFrS8PYqpHfRzc/oy5hr2UvkECXE6lg/Hx/22Gz2hOoFBXlQ8/yi4qI8O8+0Li0qaFVQEW/F5UVzoxXxXLPbbAOGFhVxs4FHcz5qneWP1yCafvmZ3msvpJGapIoaqeUAcgk4HeMmXEJlQNwkV+c1eXXEEb7+3e6f+l2Pvl6S3MVsUTW07dq5TZtOnTuA15IrtUBeqRuvDS0HZmAnW7cbvBisvWF8Is82Bjzy8V/++vFbf/lLI5lcNJKIQ7t8H/RpDGba81KEhufNDEHDoEhZHTca9ToYslGAIqhUE0qybJNIxqL49JZKWW5QHlKPxPeANve17zGi31kwesf+e6uYbjeG1h2NLFuP5tO7v/uXbDSHFYd2dRbmnzHDuKxfzG7kLRqNnSB0ZoaHYZnVMnCElRAoSomsLBenXDw0MLxBr6uI67m0G4z0BDGdxDqNwxrIhCVRMz3r8tO3jxwyfOZc8U1w5cZHe0AdyD3pevaq5WHD0pnUy7U3LmBp0bi6NC9GQDnLsJxGwk0MjrXgNRojYbLbGYLyelzOirgLmGxWGxoTE/iBIwRCkhDL/QQUO1PUpr1Gt5QXcW4DDJWBFpUuQzIPHgFl/hw8c/JkY/uXGy+8+SaYkSb2tRdeuLGotpY+XkukvVsBY/hHVCTLKlCt2uH1Ym69oNsFzzllsFbHYfYDlJTCoMYeAFF3NHnJSecVooIw/UfeC0TDJMrBrUmZpVcPPv+NpdU7dgDAUvpdz7Upyi+u7LIZlD0MqJFe8aUysYzp2vCwA3QaAF7+/Vmzbrdx9Rq8Ja68Ia012hP34btfP+5HLEhKHnC7QwYDb1XQ4UgwMHBEkPF5K+I+DgmP2y1dagJdb8jiN9Ei+l8UyVj/oLz+GcqAr6V9M2P+B2DByZO3VMiNX0eKE50iBsr6oL3TkhgVywu4XG5TS7yDiJaMm87JDYTDcOuEeR9nckv7B/zp/omW39LkNNlDCR0yeccTfOP0fQllXgV3w/20o7RTjxG7Eeu4f/Kweye5MvT4/Sfy9IrF9XXSfO2x6jH1FxsLmnMiqPoApzzFijkRBOt/wZhb/gvGNyrE+EZ/q4+WcdSf4Y6kPl/C3uHMGvbWuCPK36TPp/DMhgbPbHxfrzPS5J9hp6fJj7HT7d7/MrO7PB1r0+n/MzzuNNkxvrbZqRD+dL5oeSbuojtov8V8kSIn8fnK38mx8H84YxxFopEZ+DuwmqVnSCMn6c9hJ0jP4cPEBEDwClUFDCVtt/zcG2mf65U+1+38w8+9lPm5xExi0R98bgMmBpQ+N4A/l7CZ/tfPRavzB5/b2Fxeu/d/lrfLzQ3y52IsLtQnQDpS80n4OVmZ601TpJkJw98Jo8wZkvEcCWO6Qtrz6DnffQt3Q8XNbwmR6BwT6LYxh6tn25jJBH/jDT3bouEwQaeH32m0PdtiCGv42WkA1vLHCwgfVZ6bbCqbiGXDs94C5g4xmZtxhzSRi9xGYLng/xSJjjGBKkFylSC5SpBcJUguDspVguQqkZC1kVQJ6G/00ekyYa4RPL+3XJ7fOyDP2qOzdcpmp/QZ+xljazNV8OcPoP2PJYE/TXWED4JJlyE7NSOE8cMuM8MJHzEh1sakcnpdNhvB6b0qPa2i/QHK4XTUxAmn1wPjWS/QUk4vx3mdFAsTleq4lmYt1XHWeAuSuvRBToSfIFUX0rqHzIn+QZ8x2TJYimH6cNfgggXJvkEwfJrcMLh2vngVFMCvD8CpRceSbYPiSbldsM/ti+7eJd2RjxWH0cPpPjBqLybujrXyeb35ykiIgzvYorSUtPb5XIQrAIMNJ8kUMhXxwkLCwGlyoKfQ8PYwET4D7E/GMftWUVqoKhNf3aLPI0moFkXUK2nYi8WtS6PQY0CFJfZkHNyV+kFxqme/IxhL3iRH//uls69emHIgj1TCl925j+vqud1/zTpZ8NT4WdZGLXmz58KKZXNnr66c3wMwfyFuAhYAoBg/2rNB0fpQw6Oj9j86e5pn0fDx5J4Zx0Y+e/7iU6OOpeHaHUjgw6XZToxr5w7+F+y55Z+k+ZUfoV9JIbol54hew5+fL3++TbK2Ek/LkXrOzGjSMHZwjxx7gNDAta2ItVADoJGggFQaWgODZU7HrR6hE2rjOpJUALVCTTMIPQo3gZ2Xb1bKM7kvU+wXaehAZDAiJwqZMEHi3H3iuC/I6+NxwxzTreELqVWO2f+9aeVKk+TLxMG4jwn7Mp4l67JknwX/vhees6+S/j5CpH4+gYXBR6T5WjTDGSBujYiR+Cx8RtFnhdEZRf8i7w9QMfBzisUh9EPsAT4MZrultUb/Q/kk8DDhBCb5KhgjVTH10AoNFBIz+/An3AL6CQnviTqRwHtKw1oxIGQYk0PBp2GVSvlvN5gHGmD+2zcWcVlgImFWExxNE2YH7XE7rFJDnI2hzE4nh/hkTLjb8o+y+7Q5pz9J4x/6s/SdPP7neXtTuQfHcjlaTTgsJqfZbjcRNO322C1WS03caqUZJD1DmRwOLLwxQ/jmhfVoelPXn+TiD/1hDn5L6ZN5JJXMvVHvWQ4xJta6ZVZ2i1DQZdLrOQvLcsFsOi83OxQOwSiXC7YIwCQ7YDaa9UDplSZI7M0mSG6RWwvpMIKh/0MeDa7+L+nzA/9j2py0T9uT9qkXOCXvSBhxgKlOz5/bJ2JmZ+nElMATU1lYnGadpBmIWXAfWFFXnAnm44ROB92hoLLZTZzUWyRYDJRg0FA1cU3yqly+iE6wq8I1ki4lU+3Wfp8d+LGl8QtR8q32PXrEton/EK+LV/buBYV7wcy1U6fVkssbR4jrwQTgaVzNdGt8lWyNeVng+RwP/a0eZuntYm6LimFYjmAJh5O1xCx0ddxiQJ5VpaXRcFKiSuSw8Zeb1T4JbOzwJBhqgESDu1RrwkCPf1nc+fHZM6B9/YQ3P3pJ/CleWwm2A+Nm6q6/iuPEF4eLv7Df7Rs2+rffwNDRh+5oONEeWMGYFG5TXQK3SdWTeFGy5UZsy7fV80Y2HR/kgjSLjLCYjBg7/QVsa+zY1uAaIp5DJ3ioK6ok7Y3FXG631+EgNKzFTBkUYY1GZWCsNkqgfXBxBIOgpCmFklLm5Xpdq+NePcNa2Oq41WJoURsXVKTBgEInk0rb02KwGGi9Plgb17+vVFD42Eaj6RM2cnOuzMKak8kfE5U6iFN/SGOPRM3EiE1NplikggpWAf8iTGH8Nms6t+ywoeC1F1c2Xl5xHlwdtfSeexd/btCHzKvBUw92noSw3YZ0alPapUtpm070M3eV3fgUdBGfo61ld8cn3St+2GJygXgCDDgMriDot69C+fmhcH4+rjtK8eRBIo9oS8SIvsS1WLxDx46xdlSoHZXdieiRHQgS2UGKbWNzCkVFrI3t198ZrYxzAW+gIEBZqEAMrlAgEApRlLd3LKdrbTwnZvf3zGm303nMCbOrmJPUEL0n9yYFqjdirFXperZD/xXs+L8xi4br6ezdrl1vJ5XfQZVvzq+IC3ozsinSchbAFSvAZCow0Ltt1Ci4vNIWxQuMp2wy5loTgxfRxJLjqVsFbQep5pdEB0ca2YpMuQ7fAUgQrcB1NzZ/Df2jJYBs2c7h79pjzAiW7XRi0SO7wIVvJkyfOU79bNYvha3QqxEfqdlQ9fzMB7rFx6JXMyr5ar4oHu5qL34o5ldUKibz4yfPnvD4JszAsnjaoGHClwWuYUXwhd0oGbmtCvGv3FFVNYa5w/Scu/5fyXeWjNEPJmJ0mK39nIatA5h6i51KPztSjF6fiNETPAJUBxijD+8QM0TSfhZzc+HP3iZ/9hgJ24AKwpTkzmC4Sf6LORvwZz8tffYY6bOz4GePyYqoiWbcjXVJ/Pk3SBfxE2E/RZE48z1z83S9xZie8cB/U41rDweSWPRvgA8xkgZFtpNSmVH1bUqk+kMTjP6jyedcg3mVxJVmx/UB4Zb1jaeTz7hGVmJbhB4Bn3C5vl00VeFI4kPXJfGh3yCzsB4kwnhH6B57600C0GTINA1jRB+QMaKRHj/JeoQlPdbWB306U8a/kZ5zNPmca+T9EpeYFdvIX+utHNA0w6F+OvmMazifRHqHUaUj7NGZMvSeius0dUnM1TfAj5l61EI9pFpNUqaFuFZzQMaIRbqTMrKJWUI2WVFv4GjyFtyHR5PPSb4PrAhh5W5ZD3o6+Yxr5GTJN5hxVeU/9WYdTTbDWatL4qy9QerlfeWX9tXB+kzUNPl99MJ6VDV5H8HE+/C5m/wb6TlHk89J7Ss/2ld++y3rTk8nn5F6H0H0PoLOJj8vYWbVJTGz3iBbZeqxHurB6DL1wLhZBxJ4XEk9SBg04PcxBf4bjbnZvtqK9SiR5ZoocRv6MTbXlXq/nWmOzfV08hnXyCVy3ORHqIl+u/T5TTB06pI4NolzTgK3tK9O1zusikxejbm4jnYgiTfzBhBlPUKSHuvrA167NuPfSM85mnxOal+50b5ym29Zq3s6+QzpfcB9FZKrdSG3XZuB1VWWjtVFfk5OkjBw+MLWmVhdZelYXamfY3NapWN19YU/l8LTSvs5RiswaXynz4tlaXha6c91eAEn/xzqbYB5XSGM7wLE0Fie2aLyadwakoO7lnCTFjqYhablfCqVWQN/kXaSqo6TdruhOm6n05uQUQiDQpKMe4NEExoPSrIIRHfHMiW5GdTtqPMEAYfQhQ1rwVBwW8vQcZjzjgVdV82ftqPj1sG/HFjy8j3tuscqwLjG78Sbj44GRS/3WpL94MNHJn33yL1TB00c8NDiEQfGj1jTs/0RqMs+mG/ydH8iTFTHzA5nlsav19NKwuT3E7STjmTrOaknOUujcejhL9pDMxKmAe3xWCviHv5/1SlkYmlZmQhLK0pQJ3kTonaoFX9GXCiKoCPomZdzl/jmtk/eX9x1zqypy0IHi9977tLbsbLSzp9sbHy59fZ+P+4o72svvs25oajytum9xk4cPNJf++DRwxW1JQWziTSM0gMJLPrm9fC0qkUKi/5ZPMtUGculjUaT3WYxO1xujVrtdthMjNfnsllsq0dYHLVxC6NB45IVcZpQwEU4LyVjybpFWgqWAIC+BTw6SJYwMlHowS9yCYPpKkoo6QXkaYySvoZ5SqpiAJxndID70EAUxKxapRLmwiqD0aSFb7AmrqfVFKHCIxXlTUopqM1WWno8SiE1vlPLpy4c/ESb+icO/+2ZQ+JQps8ja+/qd+NTpvvmw9c++/0kyrmz4F55Fc+8FhDtiAmxsizWHWhtMLTUBVpZrQEfS7fvEGjtppyUs6wi7nW6OGCKVsQNJhOlUuUh+j6eimSmrlL2XYaTsgtJzij5ni81h9yM6sTaWh6oQKCQKIzMpD2RtJPmfFflLRl3YseexycsySHJerJT+wWre87p/dSAnoMnzZ4oVsXvmTN+3P33jKD6l7UNd/T16FBcfvTuocAEbMAFHMNvnw3O3TDutD5438ApHZ/rev+MgzXvgcmfv3D1479deKlhQKtOblPFbWXS/kF3iNOYTUQE+qk7YsX5vIc1UVYqKyvitNJ8tppXR4tZkynH78+piTuc8Mvv8BM6IlITh1lrYU1cZ2x6mCRojeTgqCHVPoneomQLzOg/iBccTeuXSPyY5sRYBjptKegkH3n/9V9r5z28W/zqP43i94eWrFj46fsrFu+vXffIwytBpzO760498RioYjYxL+954ISVtpxZc+69d8+tetZEh+aOXrmZXkQPHBS/bf7sifOZhuUPrN6yaOEaSXcUy/VjrkHdi4nusVCONeRRU4WCQOlYp8eqKGmtc8BoKrsyThAKv8mUj1ioZGWLyqSGqrKmzYKS9KWZWobTtLRKlJ+JJKGkOB+QY+eurOzVa9Wc+ZMXbRFvfvGZuGXRvQvmrOrVq3LF3FWPbt+8eVuvVdSE5XMr5wWndD06ef5RH+29uPbtz79466G/wD8eXTD5aNcpwXmV8x5c/NiKHbv31A1d1R/17N4EdC2emYYZPUsRnFoNGIIxmQnWCNNXrbFZg+n5ZjSUha1K5RoLbreL4N3q70UVoZbchtfJgUs2CtsNPfo1fLmWdtStuvHx4nn9+gXQML3kd9bf1NDldNtbywCPl9GMZKiIU9z/VYb15EHUcts4BFxcv8y43dSjX+OiFVR41YqG9yZP6zEkUBgpb5+OOzc2GeMnuUjQ1Qmp4W4d419K3mFukyL8KI7wP6kvjDa5w9wjdk1xyvAIf3OmdL8E/z7JIcPLuJyJ2BDf5RQ1u2dyS/dMzgTab/o9E44R8b1eVeI+S0jc67U/RfvRdY4fJcoqo7GnH13p4O8MOn1PP4WYL+l0Vr/UFVPJLWS6mbpfwld3RCD/lvjDvXDshuVBeI+yPL0Jb8xIRWMqVc+ozCaY4B6ULpHSYuSxyRg59V5Q7qWx3jpGvpS8m91GpPET2Z3N8ZTT9Em7L8MJJOFy/4E+yfUlcVYrr2/RCcqdWFo3Wlr8HQ+X1i0pmBQgcUtWkoYZOCGBGSh/WgJHj9Bk8CMnMQmrEpiEiTsyDEoIrJm8ee+IQ6j/4D4KN9EpFtAKNoLQCwZWYD1ehN0EeJuWpii1ANTOirhO7ZLna/HAek4zInUhzT8h9yRkuKS7u7aTndCOSfNvB/uSnoe59Ps0m+Rqnp/x5BDm199WJD0MSSyH/vcyjNUiRBT5F16hUObbbMFIttsdUVLFJfkRG+XI8gf9Sn9hRdzv4qHjhXaWd+RUxh0OpYZTmiUI1oyuGuiA+QtCut9N62jNxD2XmyGa6Makq7YuNnjInTLgONlqXnzFnK7t5q6UdZ09EexK6koerZt9dE8Kg3zqiJOvNE6yLZ0taX+wZn7KuZLEwptfU68ygwi7hHbjs8BXqdNwDivDMeGIXTAIFXHSDYMLzqehSVJlMRk4rUUVrIirEtgbF6LSy8q0iUm816ZvLAn2akzXz9G18/wVUJ3nK5E6CeDXH6FWbX1d2xeXg7eS7+9gDdlFHrLriFQZNLxMurvoDs/GMhxH5cGMZFSsVZbSF422gDE3R5It8p1OqoWSblMmgMIcdF1pM+k1fEmEgaGTz0My+MYyHZcg2gxTJK3HxR8uybirRMGTIiqzOUo4dAocOqHJQRa/SnRL0BpaKqp039LpS+f0ujNAkrtIMnBnrznw+z1lFCN26dRj984eXcgfOvfcubt756Lb9gEKtEABU+eqKWC3WD2lqrP4mfhP8R1R3HdbEel59wp4Eux8669vvyOOFvtdltcBns9lGP++JdzRQ2K5AXsByfMRr0fIUSoFO9zSfi6vhasFTDMY0sUXhqyhirhRp7ZaBNefr0HqshZIjcOYuzIcCVrhbi5FdUgJS8AaLS5Nqg/4hPKHGKpsz6L7YCo62oeV940ecJOYuXhfKVT+tU69du5eTv6wfPfOnp3ptlB58XvxauM/uvefLPYAT03u14MMgAIgQMUb3712BewET4oDwAmxnzj6EsadvHlzNX0Jvn8dzDSsxORYO61Kp1QaLJyeIymKN1sBTCkMBpbQ6HR2iqZZ1gZIPYmK5Cotb6YVej1rUCsomkDE7tEL0s6GsaGMpg5SrVsGKWhMVGclfhXKD4KlQRC1GqMqMgpF5YBV4afVK8V7xPo9/foC8W/Dft8jPgLuaKjPB4ZSv7bbRweIm2CeqJ/OdPsezGz8tqEHaQR1e8ZE3jrcgM9ni5v30Ycxz1QWcU+sg9MFfYLPS9CkVqMxK5RKk9nMOUg6FGZVPr2XIxxK2mUjEI6FyWSzCdVxm5EOwDhKq6BpNPOaslGo04A/b7A2wadC4CD4zqY0jOH+SqMUGiiTeGSl2ZKIIggkQlny2wdI247J0/YcaRs8oNOLpkEbZRzAFxct2QOECHi/712H9585CdqTJ3o9I37ae2SnkKvh/RoMBXjHu1TR03MoTTkGACQxn85QPJsfIibGOrrcbp1Wa1FzCj/v9BFKUqlSWUhLOKJQ+zkfTziVjNtOmGvMJEeZzXa7oSJutzDQMul0Sob/Y2WRgSpIFNaxqqGwtGmNt9CVSujKguFb/vVhr/ZP1F5c6HtKExCfL62sWcidMn/4+PRhL9cCVR5oFchduyD+ECgBAvDyoFbsMOSAvmt+Y35w3ERt3dMhsTv12vE7yUPq53HceUeSrwXGnYivRUVoCa2eU+OIVwFD3qYsLQVp0FcG+T1h+Oxk6/q3K1eeBevFe+DhGllH9mt8sk6M1aXtIx4jyEQYllWpKK1Ox/MCScJHmcxGAs9nCgDuFEqvVVMsIoQ6jw6BFY8/NIMhSsx1oTnDIEDdoqVRRdTMlAap38RLz4vn94B/iN2oCQP3DMwWu61bRx8UVY39wZzGBkpHhuoefLDu++/ROhyD/tdD94G57+2xiM0aDefleghCl8uErWz7DtHSgIemWrRoBZ1QHjBQeXkteF4lwanyFOL2tNkkXFD8vqWh5ajUR5OR9wpJzNJAxIpnNaRXXADCkbT5lwKQT0pXJ0loNjzlQXs+f8Pf/SVnNyfMxWva3NVm27w1vbr045aWLZ2xYv6w2xduX9z7zVeffNO1h1s86f7prW7bvHZer2yQs/VR9TW3zeWf0q7ltv1Vg0Zbhw7rMGhQrMIRyO43qWLD9nmrTD379e6T375lKKtD79FwPQ7B9ZgK8xE30SVmJqx2t8btsNIer9vhdFTEnZwe9yFr4nqrDdo51O0r5yWJge20Qgnc3EUe4AVIO0ndfGiY8kFO4l56esfKzl0PuYt8xe2RUoX9u7XdFerav47c2LiearPKXFBxMejqOqVdoadNj3O5vlVU1qoVUMYo3rubCAtRGnNZEFYnoaWsNspcA1M1jtBoOE5ZE+cIPGiXwD4oSG/Y9gswbxYS91VZUR8hmEiFAJ4r7gMGHalfctBxMguo3gQMMN18n7TpwYILT82Y6d5/SvxZvPGV+IVSXIKw6qEcNPR1JqJNzG0iaJ4n1BTCi6qMA6Aj0ACXAloEXoZtvrUgcn0jrWImkJa1e++Zf9b1lOOvey9f37sZHH9oztKF5/Wbjlx7ae2rYfEC9LP+5Cy/hwgTc2M9OW2W1elU0l6tgSC0NpqOZDtYBVsTtyq4LEuWpTo+PwsQWb6sVllURda/skhOgQCHshRZtEoVRDiLtDMdATnFhzRqyhS5YnGLToQUEDLGk0pHQMa4z/6mKMjZCxeCuiQAcgO4HfokNUZB/uAjCQUZ9FxKzUrhHx9aeiwJgEwSGhhnvQj1RvW8HrGgg+c1nN1opEycyetzUJihQCDgwhuhcmYERiLPeiMDFk2akszRBNTWhgfphRLZnglRgOAW/Oj80R2WLv1nww9/X7z4LFn0vOjdvajx9eIZ5LdbJ4g///gloB7YSg5rPEAOu9F531uDb1+/sQvKU9Tw/byIsS764bhoz00fzIEvYW5JJ7E2NgR6SJq1mB12iiUVhMDrtCpWifAYaOhZjbTR5dZaGWt1nHea4HvReU0FJpKDv5Wbqk3zTcdMH5gUXuhnaZWCoQQbbauOkxJg2gUpbMLxA+KXyeBmSKOZkbjb5W2ogMGDIJnQIBVFU/Nm4EdTScYgeGf02tH7ya/a1rb13n7qffGjC2Tvhpug6JRoa3Hh+w8/ZLpBYyoO3yZG6ygKPHrjR3CZoInZ4jB6BI4dgjC3ySG2xob5srIES8AfCXOs3qoFRE5LO2vT6RCqqsJqs2W7XAqBys2zgkDLMKAptwmF/nDDVsRztJzabjH5fGoTr3eqYQKUop9Ry/Qz8lR6gQG1LZbJSuPGxvJm7e8ZugMqw+Ma0/yxYMYUNMYwdMPGEHT+5KP7S8ru2u54JPfrvSP7nl3719d++7p6wKnaK0+LoWV1DOBXFotbBi0EM/SlY8Av4lpjvF/eA0ss4hDw8YPgDqABXjvYLLZaIdbZwLVjW+HGE/OfGgf8Kx/u/4FUD0I8gDUYv7xnLEsD9eUJWk3bHZTBiJELjAqrFZ5lK6XQV8c1GkXahGUm6ltZBuZb+pigUCJDpVLvLVt27fnDl4LPGKaOvCr+BhTiRfAz+e2WE1c/f+IF74yFwH5yC3i2LhEfdcd4uC6iIpZlh4K5kGRuj8M+MO4ASL6KhHzQLXAKHW7cV7gykMGiaTSSabwcCSjPcNr0R2IChOoKSFFM8iiKy8D94niyzyuvkOOXikSCSRE0LgVd8MABSUwRhzI2Zjg8aQGEB2VTunUkaeGVfDBLT2l88DRpaIx6yDDwaFEYEi7lvTNBLKQV9AklKdjM0mgC/AMDVEukTPRD4m9j94ri9zD8UpwYv9TbpjRa0LZh5OHjW4cPOHZ4vzgU+N6qBpNBP1AJakb2+71zZRf9Hj1dhcCpZ1MdF8hx6BK4zu9Dn+IjclHNIqL0630+p1lpzst326ribpfAq7NQsYJnWlbEAZPZMZbTRPBQaQadttzUmg5dkt6PcQdNtn5k/usvgNo5u1qTSvqIok1puFVR7wcWrty8YtbsZVtXFi68ewSwAAvZeuidnvVMu28aJlZ20e7RblxPHn7z0qUPPjn/HmLRRXei2DehiaaIhaKUNA8IQTDodPBgO5w8ySIYZ4tCAX2PGWP8yliPabukyXCHjH6XpJKRfCWgElhRz4nrvju7Zw/4+MufntkBHvo1gRVFljeeI8s3kZPP1W+85Gg8TF1OYkUdQnexcK1d8KzZWJeZUan0arXL7TE7HGRV3MEroTuRLsYYnU5t4NTmNLobW3mTogN2hTikkKY4gwiuJhyJwoXvSEKLQpsnj1l0xgemiIvqH3jAaT+crWSKapZUjxtLbTLuX71OdIDP1nXr+/odKydPHl8iSDV4jdwTKUCPNy4W5Yy83qQzGASdRsmqtVqWJygGCAIDg2qzRUEbTBSMpGviesKgVrO8lmIxsSqUuSzh/VKoHbipKvlfzGpQJoHZIg8ANaD8JdFI1Ar9Aij106qnxS+/ePZL8ZszOy9vBWe2Xm48u0i8QfdeJz6EMDzA5HU3btxo3CFh24XgPj4M40gn3MlTYWTttbqsJrPBIsAsn3LStMfucjiA0+lSW2h/QKBdXspoMkqTxNDGmExKh4VT6iriSlfKgWfqIG0OKLAMKIn/KE/CI5tHIUR1yaCUAzQSTUWNfiNUxeg3UL898f2NLtPXxHsXhfMHrGplEG/+8MTGF1aD08ueb/ykxUzx7Dby03WNR44cHKh5kJ25sJDsuQ4MFg+DwQ0LJoEccRXSsRDa6jK4fwJEATEklpetNBq9dkcexzm8VKvCbENl3J5tz3YxLmgQXRYtzA6VWi3DEJVxJonPFW0GMJ0BImsMKEpwOiDX6XhGkYY1hs8vE9ADNyjtCBOH8MSMXiqxrdxLlS8++MrFlmQ40UlFvZbsmBL3JjqmxPefOQGuVVSyaQ1TKSx0J91b5khwe1kNATNeFsF0mWGo7ZIaWAPNG1gzweNDtzJF1mA4ko5UR40u2TH3tefAgwu3FUITdIxVHIE54fINy2bPWrp+1am77wQ2ZH7i1d4lbPTzxucHPNR7Ipj+1l8ufXD99fcSfBh0BcwNAigqNzAwkbfCLDeYZYb5i8HMc/AUU74/pHO4BZtDcUQaVP8jLgf2cfUfMzmQ4zePKJudTn6R4uxAvZUIaZhwMuGw1gcT8Nw8D9wlTg/Pm6vimHiixf+ZryMdIetPOSg2rOs8oG238m5/xkPxcu024VFz355TMgk8ALEK6tAJ7n0r4qIQDAYF3BQsYbMrBBjEWSz6iriFp1RpKJt/xEVByNMVyXQM2kof3Un89ceTX7heCP4dlK57BNMfPPDqHPAFGRH/Jb59dKP+PDh0/eUJ92hve2S4jP35GN0NyoPWdEAs16IWeD7L7W5hI5VqNjfPGYapegslSTsFJ0oPjDgvQ9sAwThfyJBQqv2nz9EiQFhUPw6XIA4HGePIbEItvD4EQV2EcESQ8B5Arj41V+1oM6dnqBqQP538yvtC4NNH1rnjn84HMIe/bWHXh4Y/NcR7n2mAPjQ6Pr1o5XeIzeHwFv35l69vrBo+4dOH65Zld825u3qUNyKdPWhH34V7xQmj6C6xgEsbMNA0YdFasluYgD6EOjx5lRfqobKQ9qo4mbCWfxjKQLdvB8FMJgI5oEm/bqffLer9iyKdiqAeBQMNExM8BOIdWpANCtLZCPb+dg5GA5Q5SUUg2Q4GMO/BbK0lisWQ7QiFDDbWlpPrNONdrlRm/4EBkQKypiFNhuglqEwooV7+NyoF4OzUvW272X/MprACZHMHzBsa2jVlVEB6yLNw0As7EYKHXqezEXaTSUEoXG4bURHX2/Q2Na0WKuLQoZkr4jT/X7kDJDoFIYOWVqa8XPr7t5//KH6z/8vcRxzb71qzS/zowa1ashezCfxiA3YQhif0B/Fb8fqSB/L6xV8/Ba4d3LntaBM5HUhOVqGwGwmbTWfUOV0me0XcxJpYXs1DCXkLSqTU/1VOkNbRI0lLCiUADUMZqBW7V8vZ0Dfib19//QO4DrOgxjMussup13HqI74nfif+LH4EPMBvE/OPbRXPSOtZcPMbhsH3BC2I8TFouhQBH5Gd7dRptSanz9kyxyKgYMAXD9hbENAI+rXwoLIsYaE8ag/c9p5m0ksjbDILaTSnKQ6dpAsuqklIl8ZSq1SYwnkHdK1kEIb5UnGuJEK+5ZhXPXKh5ZGc17eC4RVTLZrscIsOrYf06TeRo//5rtjntG7O7NnLKfLNhdOGDshbsEDc51jYtUv26nYb7s8uEf8jfkiW2+49c/ji0wPwveUxyV4aWGos/n4l/D6Ev/8cx6IlN79lFHA9ojBasjqcTgUb8PvNBS21BFFQKLBMcUluGC1IVrxQwPyHBX6/w6PIFRwOIVdBUx6PDTVuNTW50qJgPhqpMSenyURMqi4pz7hhFJ6SaGZZylqaKFriH0SGjrrjrRdOv8mfML09cfrk6TXDR00ef9sR75PmV/esfDqwwsUVFIU6BNrNGzxigcNfP3sB8K/df+CI/oPbRg2tWTOyf9WoS/yWg3eOtME1swrri2dPXlRqWom43G9+S/fDGM4R1HNCWHiXwu93eTQWJruFR4uxz7XakD1EI9RTO7Tjdr4pNQhR1gRkKAUvlFSMVWBTbjYpJNinoI8AXTrXLpq1etJMpMyCu4/ueg6QP7769fVZCya9tlD88SZBhjecq5kWrxoEFaiovnodqEFk18rj5abZU2/bMhBYpT7CSTAmbAtjpeIYQngkLDoLzN4xMoIabelTcTVrNSOgy/Lo+Sb3ltC6ScV0OV0vQYKjFnp/CTm/HrDi72n0bqK5lnq8YVCtPcXypq7FZ2utOIyhoc1FM5TDY/k0ReXxEatK5QnxoZLWTn9V3GlU6wphcE0X0oUwZ4eZpMXIEwpogJ1JaMQ0HC1bGjtTmitJFRQyriMTpHTSRTOfiD4kXci7DlxynRGmjPyVHPvvC6fPX5ryWB65bq0vXFpUFuv05KbFK+6PThw9eGF3cdjKhfY+laDdi1cBBW20E2jGjwaFD2+mNI8a+ne/8YDYhrpy7u9nP9h8rKL6dGrGiO5jYNGMkczplI3zO2gJzS4Fyen1Dhj6uD2Yv4EjOEYj4Vcz8O0wlj+whNIlWxEqUwj4krHYkFGhR66zJEjOBscGfDBHpGZ8tv7gP9xPcTMmbtq6bf+aCb+RbvG2br1JzwlAPvz4Zv3wCR+89db5LtclO1gI/ft2jMmH/EoWCSx6lqAMSpphlBTclyzqw6BMlAZooPXWuGgMkSoLmYmwnUABl8gxZLAqBHNmLY7I0R/4j9juMhgDJr0mtpo/9+4Jc62hX/r2iWSFIpuofY0s+XvDqH/MuGfBgnuyh498d+DylZX5xVFJTsXNL+gLdCcYo7Yh+sdMWbbiYtpPOHlnLlXWVuU3ZRdkS8mbQBfn5Hh0BZxHg6x0WvImFeUAzHmk4ps00QMFLs4HET1lNkWLMIBkBB9PyprUoBxQaKk5IBkjL1kO4EY6rja30DpMuh49Adn3oTZT/eXlwTzr4mgV0quicLE1L1jeMTC1zUN9R89oUWoxl2bPeMfcMtrX2qpVgW0U9UrNyHuLRpSUiFdve7hywqxZE4asHgValZSMKLp3ZM3QSZu7d998zzCpJlcP35EJviML0SpmVbEWzmiE2Y/VZnTxCo7SZoQtt8p5MpkEggLU586Oe2c/sb/+9nkLN52sp+mnJo9CUKaNVXWzj+8ip/3uBlvnS3sY96/Cs+xCuJy0QQszZqPBZXB7jC4zqYABH8dZoUXk+IwaVlNCrESUlMgI0ttVnwKubr1KOs9Lb1WlnwDZ/H5j7ZgmfarSeiAsMCRTCKHCQ5myskIug8EaosKRkNkMt6nZJYvmayaaHNFZ/1y6DLr7W4mZoLxvLmwG531CZlKeg0C9QGZiYCwHQfzQBh261bUaDQNHGEFTWg3uz2g15ApmoifhlsQaqHZJfvnOOxK5xpdfiufAj1LR8lBtLRiSKFfC9fzPze+paXB/6YlQTEeo1Ryvg5tKxykpXEJVpgyTBGiWHL9C44wlfvJUWak/tygPRlo/gRdAqLK7ZpcaZJMba+FnX0aDafCzNURhzMbQaGBbq0uoRmkIDTaEmZOmCWdklBHJUC32MhUVXwCxhsugXDxHt61t+Li2lvJI+yHBVeIjKmMtdXAJXbwg+AM2lYqEyaypIs46VfAX5/V6KuJeoOU5GL9wmQsrY0s2Q0aTrsOjeEPIsuANEYSmwCrxl/A+r4NdNLwmaJKW2uGIOBeRdw8qxXQmerag1dSpjMjW1pIdlK0Kxj3AgK8lP5mQG/EG3B4rcun1CoWKhRvDalCpvD5KbVVXxgmrzW6wV8atBqtBYUbAk+ZbM64knGUzeLcknWHaFglI7Hm4Cl+CvUiU/PDgQUkBZszShWMVSPp6RbTdJPK9hWIJ3DKvLb77jjnAXtuof7d9dDxc94/EodQaKL+eCMSE1L4BSqoqWTZLbhoGB7tpmwaUlZYWdMsTP0cPmlbZhdvDgWzmbG3qjC/FNYoxsSjl9RKs0804GRVMqwmrilD5/IKgI3Ae7WI8FHyxLtbBop40igMA33iWlyVBOJsiLyQHOhMxmtREIENwJmJRjM6JL4uFp+rJn8S1z707//N1z34ZOVH6yegNA57bUQXmN77KXBInPSFusInnVvxz4ZZN5lPVj43ecuYhsKhhINRjHIwBxsP9H0HZp89tASDMKRRqddhNZbeIKD0cHXQE4W40Gi0Oi07qwhKSLUgZlqoJljXMNwuAjA4RbGrmyacKO8UGHGQ3MoAMjOs/bKiRzL538MyxBwo7de6HMK23zXlhH1ndcOS5lvNbjR1VM2bC8MevIgewbc6BA+Q06R2Mg+/gDih7GGfOLjMAIYVGo1aHXFQkO6x0c3TADpNmvcFgtls0rv+D7ND6l/4X0R9TkME7u/2R4NBDBXc8EO9/C8EBcQeUewyMu1oRFbGWnFKpVVlatSKygx4PoaIKi/wh1MhocTiMubSRRmvPazlChaEiksAD0QzYquSYrz8TyskslUWTXYzN/QZplF8ESwbG90uqM2t2DPkPpBR5FKnUuBv1LKbeRcqN2JFm0I2Am6LEmwNz1rKY26FU6gyE3+APBB1uN1TDzZs5DYdiNOm+X7qPSbt2zVQgXVSpE1Oe2RiDnNqsWdi/yUjo4/995JDsghVbV0piPS91WF5+5sXGArjmiNPnV3xvVBpzMYRDgOfNEPBD0XSSaAazgqxKXsfdYn6EMSXtQ9MeUSwZbZ/RMTfWTvwcO900yaZt4PfpQTbVRvK3id5PKJkcv6DYiYexk0VD6PWcEk3Os4KB0nAMzyk5/N4zCN/kKqwKWKyoNhUEKD1HjT53gcvmEH3oMbE02684CHfjQE/vueSWGxfIZ9r2uL1T413wQYk+ZZRb01uxnW8Dv9+Fa5UBYmysjUdrpSibgTXTNGC1dDDLSlbGOSvQUFYrC+1ARdzIcc6KuIHjVTCAUagsLAV9mLlpZS3FgJ2TMd8iwbNKnjMtL8K4tjLUKWpIpG8XZ4JXGnd1WrTz0QO7O8ezyL5i3x0DRowYfLC6ipyySNy0tE818AEDTH4cwVblK8QXBn742ut/FwdegzoVQ5224DoPtg66LA8ARoXNZsyCtsFjMvnNNO+Hbtbpt5jViLYuDfIeA/GmcmTZOiRB7jFnkEQ3YUSNMTgVlae8CfJU//6Derz63PMXew7q338AUICcPZtGL7HZF4/YvgPkkv0mvHS8/vQXgBR//+eZJ4+/NIEEYr34tx8al81ZMlf8N4iAvrgfAnOUYkw4C+GGGUULq0nFcQ4WbhdeS2s9XpURETUpAAvfBMubHMABLR2QOIbS2DPKMwAf0BtAiZoQhquOcmmLQeAZwVgcjggdQchkscIMjtQ/dwWs3vfWS+L498ZNnTK+8ck7J0yENgtsswIYB4LfisBicZ5J/FpsFIk8cSz1l7+8amo4ably7swbLqqr4xKycWdufkNdh9vNTLSImfQsqzArLFa90QjPmNGiNbMov888Y4WtSlNkYujaI4jvp85MHrP7Qn36beA+4w/PgIbGLmk3gfLzML7IrZ8H/v+eR9XeOJH5PIRLibGUS2JGI8vqFQ4FTD1sNvhAm4XXYHoT3oX1TGv8ShYyStOJ0/BlM6o6pwRA1+PteohMfs3ikQmVb/Sv7KLfpQHZ4O6xd0YF7Et+gHKYcT1I1lthTurNaziF6xZ6g6T5anL72kRxahN8bMMIemzGnWvqmV6iKGa3aVlWELw+v83thg9FppRTVSXIZ5qa+OTDJbUVsjltKkab0tY5AW+++HUzcRofruyi28ew0J52TIkFgEu+q9YR7pheRxCsnqOhGHSiuUySAPkX3KMgF1+AC4ZUmvF3jRl37lmSBk5QYHzMfO09kSLkd0ydSHwmoVPo9JyKroKnTiLySn6mNFmILiJ9hB0ekOdeGDfmrvFABXzwAx69ftX8mFG8Jv4TxlskcQbKOQnuGx2Uq1csS6XVwi1CABi1GFjAWqwqHQcdEscBktRXwBRRA8xpF//NKaJkgKhg8sI/CIIwgC1CRTwwsR68+cwbc1eD0e+J9e8Dw/Xpd9Nt92yc/0hQ7ABOg9/F2mdGjpDyv4RcCkkurUql5JQKhVGNqOGMnAXNWrIVcaXSqDZxRgX0AeZU6aK5WII8xIgMZtBvB1H4C8+0BRGyzP0Tp10Xv3sf9H1P3Ll67pVnxbz6FSNGPiPWgt/BabFDYOf8DXuhLOgdPAb3WhbdhyhG0x8anjCwLM/neMOhkA3uv5LWthwqgMCCiPDkMKmhwuEAr1dWxfUuCvopg4FKAoVndJ42Y3rCEicaUM2m1N4s9ZBRH2pTyEqAdkh1LbMJOn4PRWd9+frpO+8vaxnIyhG/2qnrOm4S0N8+VhTX9Xvr4vFrjj26GbN+zuk/sVOnFVN6gZJtx9rtXKvdwyjgGZ7t7dDTd7i8wh7rfe+g9Y8unW/q1WtzflkYJoctut+DdL8Jt89LuKcoP6bmLBZSpbI7dAZsWnSAYHD2S2QmMtE0Po+OIP22E4VUYOmA0vZlrTs4N6+/O7ewc78+W8Shxl223MHj6LVHThoec45fcGNG/bG0Z/tQn6teIQhW4PX6A3r4FxVxwWc2O7AYZhcjkU0xIAVA2hy/OxTNECTRcCVL2QFu2k7ntjwyvBCJdOjQlu2ylOdWU/944jgWq6HH6u71xyRZQ/C8k1C+p+HZxGtj5Xk1RdkdWgUWSssTpj9ZG7mrR2ocgKsiJ35U8daH+vTpXJg7dM82W5visval4tDHT1O6xWOdjxkOHm3459ihubZdRnhWpopD8Nq4YNZUFfMwwSDv1mh4C0HwfHYLdOnIE0GGhumyzMeijpuAAoZKlMKVfplqS4xRCRlN2wzcYgXoHlLecdb0tZPv79CfyTNjZ0/qPqjybK85vVYtjHVNvFNxcKeCjr36l7VtXTj80Ixhdz7bYcqgmcttdE7iDfNtWlcPKOyEz9cJGGx8w4yBp75dzEKazQw89hYrieH/zQqFQAuow+fJuICg6s7fuokOBUdBSoJlT19Z6ptDbWeJFeB4gmoKHKgVPwOOWnK1zDLVODqdJ8xMtI5pEE+YyQQNDn7wHzODpT++CSGYuTkLmEx0hSeTblyXn063kWxfL8QpDu2NiwjBSCsSIAiby8+jriwXHY4ElHaHHT4eOBxaysWhrkveBEOKBIrVLTtnk3cAAgbIR/s9jc9JIiBIdNBawDjwy8mJE+WUAVc+774bbFi4SVTdTrcVC8BVsWBpo5Q1oELonKXgakOH47vcw+pmo/WbAeUfCuUvIMpjXrNOUHqzldlU0JlH5bUqDGlR0SOg4whbipM54wVm8jqVFJcm6grS/U9y0Dgi1WRkMhNUfibIsR+J/xoU9efkVD0Qv6dL18fW1h7o0nXSsAeqcnJ8xYPEH0yAeGv1zJ4xl7flqruGVk+fPmrn88/vHDV9evWwsataet0de81cfVVslGYX90I9utJtDSw1E+/NbtAnPQj1UhPZMaNKDQiWIklWTWm0lNrMorJcUXk0EyIbupkgHu4BQRK8DU68Kv4kFAcj4jcX6bYwDXqh9ekZMxs7EqgAQ9BncPzWMmbiOUpJOSini+J5lcNs1EofXgQ/vqwg2UqF4AyM1o4A/h6kyBJWQSF2XpOehH9489LaMnXR+tdOPzHKHzE+eG6Rz6rUaqk7j8P31+LVnIPgMnx6NVB23NVaHAYOjp/oGV49xN64G+vZFcqyivkE5ir5MatBpVdTenjcLCq9nhAwf5NGQEHA+dRcvCwPkK0CUhcmgcj5d/x/pH0FeFRXFvC97z4Zd41PJkYSCJmJYhncQ9AwuBfXFpfg0OLW4sUqlAolFCpAhbbQ0tJ2q7vdytZb6rLbknnzn3vfzGQmwO7/fz+QkfCunXvusXsEkwejPlv43Wfl/wyVmsmvnMeXgheEzxRXretvcis+SZvW8D3f6rvzdPzWMP5WgIUK5DmnIIq8SoVo4WKk1kiY5wXOqITfVTbxjfMpApVyn2LmRLn0TVyLR70uN8NnuRWyAf8SWiT3jMRxAx//GsawUS8Nq0mvtdkMFr3F7gAtkpmT9VYdaDQ6e6Jx7kY3QqV2eOycU2fdSHA3X1hQXprdsdVPIVc0tJu7OqdvR+0hHc5bHgntpud9e7iav4vdV1CLbIHDmqRBBt6UBoKs3WT3ZNqZry5x1tBwCasxyeQwgjCh0xgjuwAnXcmZ2qTWPY3OAl4XDVQowKKUWx6dXnamKCmXq5xm/LnRc9dtuCfUMvOucvmqEs0Rmsy1KBrX5UTvLmV3HT+w6Lb5C0YMaHtHZNZn+k4oLM9tDnBcCHBsz/wGewXygOVxNlHk3Ml6ISXVDVo76IDEQDSIOVqkcMkoOdF+HW+Hjb8DtiYaF+MuhLGnnkySl1/8eO77G96XnY9b96xbf/jMkX54fagn3+oxeZf7+st3fb7s/NO61fNePrqvfgteoeQDHMQvh3lmoHw0IlDmFtO5PIsFpXlBkOREdWGBnTopEALU1Kny6ng7sRMDMnj6BrWGFC6Duh41zvulBN8j5C+46dwlejcWxzZjC8C+8oiDV2Qp7dt1HLd4xwfL6kce3//0u5Yn7+1PV4MnnR79yNHu/eezZblCL62cXtF9ybq1nRf2uGPFzqoe+0/B2q4XTtrYqrRtD4rTq+HcFIMc4EStAmk6vROJVivSE5ebyp5ER3QgD6hpBfKoDnKjE6MSauNLKEtkUWJtzpZ0PnRk04EpdzqeTPv9zC8/ffsPLs3y7qX3zk8aa9hxRr4m//Yf+WOzvFQ5X4lz0TqRmeeRlrhdNlwTtOlsOqRSwTlT/Y+55HDmEsVkSKXcjEiBTa7H558u+XT749+mP+lYP1V++8ihziV4hRkbMHns38sf320YO0meculdS+hfylxYLR86l9Z0LtgBc3FoAS5OrNOpMJuHA9tqgtiY4JpQleiWQI0TcQipOMBJZm5q/GRwIZ2McEWebJZ/kUPR6eCdMB3Op8DmTsDFAMiKDtQ2kKpFoiCYzMjsdJlEk2jjbKBn2ThOBdrWDXl9EgMFrMypijq3KTYrFhORwd2J5ZNfZDyb9+6BvXvu/TjzvPPnJ2X5V9yfu/7AXsNF+W/yS/J5+crbur1P08o6iETribNcwW6gh1aT2+EQdSxbpiPgdKqJ2sAEWTUhViW9vyOxlGvSa3FWHV988XAfIrGa4dm0kkVj3fB/Y1WsZLg88YUmVcOPyccb64Vf+Mc/aA4rwKlWjB//i8lJC8PfU7sh8z2pCRQaU6RM5HDo0jNThLxm6Rq9hmqumo81oIdpNO5s5oJiUkI/E/Y5qoQ1KSUVdRegIkZGJIN0uYm58ZbEciYisqH7hkUzVqxe2Dogf7Nx3fz13c6F5evv/1q3YMa0H17/HTSDwq2na0f0rR628al+E4ZfpAlMPzuybcZ6W+aswRselD9HMd+HDwUCKxkVsKAMLkNK0mdnuy2cxOU1M9mp6JkSNGlRbk1Qn6QFMSFJ0GpTmS+E9ya+EKA9xgrrVTZebClKZbxbBEtrGnU/vbWHxL0TpPVzikqyCjqU38JTos+Stbpdpq6934pzmIA9Ow175mJ79j3Dte6RuiRWlIYy6f1jpsBx6S5zit6sz/JmpPcfmoEFt8lNsd8EfMNG+QayRqjvLQNT4iszMX8cxf6p3NlZqWCrLAwkc/uf+CdcIz/WZ8dtB89s239OvnjnoGFnerfv+8klvlVD1l3ZY/YF71qydDmpvl45ZYqrTWVFezH32WfZ/c508im7m4Vzq1Kro0m1tbxOz0kaLGE10RrFZDW7TYtdmDVmRI2EEKtxObvTwV41xq3x9FX19XL23/AZ2QfSmX4M3vpXCTkY+hW/yU2iuIHVzJbUCgkoM6DhMcidEmfEPDuJOGL2iBl/mrGqMby94bd6bjAsKGJPuVOuFQTml5BH41S8yam8xaI1J5ub5btygOC4HJYUlaEfJchUMUQmmpE9WqfG3zROBcf8hqI1zCMR/ZQS4Tj3Zc685ICf27a5nBUxP81zzFuceyfqIM73GDQOZ0YqmP95Cp95IOoxHvok6iSewE/S0dCAT29wpaTgVFBnUw0kw5OcjtL7Bl2IBwnJyKfzHI1P0et5RMypdrOmJmiOGAOUfKqJWfMTqrRZb8H9WGikt9SzGvtv4II0zKBefg3bsOZGdjh90e7dTeY/POA3GZPT03lkB7nWSDwZaaBm9Q0mExfI1kZXugvmT1wmk4sQpGNCaCOTvFne/4QVKIn9b8426SK4HjQo4ibs0y+/tnvR9Bt5qPzHot0sX/Y1li/bBac2G40LlLpVDq/XYkkzcOYsp91uVoHuYc+20uQQRjM2arUZjDilwEEW7F4HAhEExS7g/Y3SdJO6MH7/f02boSTHjuXKUGMPZ2iSJMNEM2M36JTsGPgyHivvvyE3xnSaFjuWESO0jvjoGfEBbaJ2lCJUiVYFurZ06TMzSy0eVJSj1WWLzZpla4s8LrEVqCeF9kJSEyxMydZ7gcd4jR6szcnR9A3m5NjTk5PLa4LJJjvNumZ3mGJ6OV2nJWIzdVVVNb1mTyhbFLW8NMq9uYCaNF34TSBCqLDJnJIbAcM95+rdof/omSNbCN/IBzUHmsDI9kPdovoja+/Ol08rcFpV2/niifuP3o7vbXh9yY3gWiYP93xy+Wf5rzvu4Z6KQE2p3ZYW7s/wIgu1QMUAt6WBTtl6VFqaUsEnJxc5nfmSo2VSRWZmkkPPt2qdVOwqrgmm+2qCRenpgsvowKZCEEhNmryaoMRpHKXJAlUQBHu0rDi1r0SpEPVJuyGzX9RhIxoYS1Wcm4MJRy6dbZ4E/MFMDyotIc18lpXNdzZFptDPrXttGDn+NvnLkCWGUiPkw3hm8y65PTfOL62446bYtadu7LAvYxgmb+PyQjO79xzKcghRwO0VCuEklaDRAb+huFgrJTW322zZCDWXSGlZUraZN1PziB1bCJwtU0u1Rt03aNBpTHxJTZCP0Pyo7SnRjNw0Bo/akFnokbeU5jj0JNqMabQ/9tGsbbk0lUG5l9IKfu97F+Tg7dOWrPLMx2s6dLz7ced+3dh+xz1tBpZOGTdeHv+Lt8uMNYs7NP+yTSWu2nNs4SLu+ZW//GJeepete6+dhRW5qWavZ638r2Mt2+Z7cnpP79e/W2h8dQfmRw5nrAHwhdaxGB+wCHl5XHZzMSPDpbNmW4taZhYwQTPT4UhWAvkcKYRgjcao5HDQ4FzF9tZYeD4mrCfUn48zeUWMcaWJluc4Y68Y509Rbi5iVrqYPTpq+t2+8fDh+oGjJ2+JWO1axpmnFStweSatUk8L1rtBc4S1hq8BzXwB9rklaoNuD5QZgOFKWe70tLSS5s1b53BOtyS1bZfiqQmmmMxsg/OBcuQ4W3N8fnp+OmLbbY8k+nSg4kZzmbL5LH9+JJfSDUXDooEwyuKUraf+TGyROTSUIVIPhobFcJG0S7lR1mfEDjLk3nEzNkxfRXHgsccqurat6vXOy7hlybGkE0tmZvYfNbJ8zup+h6aPnVLhKxpW3r65bdy49Qu5S4AGK0NTBnYp3fQ2jZSRzxkuvvn65vG13XOWTBm8vOuarl1ati5r3b4L5Ym0Rt044RWgG2MDpfnFxenpWRk4KSklWW+xqNXJGcTnz2teE8zDaazgarHXlJxh15r6BbUpgoMG00Y8FSMVxvxNi9TFX6fAOYh5nZg8yuY3Oiuac73RANC4aCxuk8RlThy6cLrc0KZDi8DU0h49Bt2H379v/vz5izv5mqe2r+Rb7amtrb/c8Ij8vumoZQfxHJjH0mmt8jd0J2dWLty5XLde1W3IaEWGoTmnngDcb0HrJJMWLVCa2QXaVW6uGZGils3z88WaYL5DnYZsNqCCW1zY5bKZos5Z/qLIEXfdopIafXPw/z0viZK9Mdfepb4ahTfv2H+rTCTyX3+/M9xfuHK9X9/BtX1vmX+k3baHu7aZEcvbugPWpgLpuE0gTQSNC2klAQk6vaBmUQ5GjDUiEuPFgJuZ0vwxLm/GT9YTLvQMN6nhA66Kuo2tb/j7XeTRho9IJhtzE8J8OxhTB1rrbYESq8UiCpKNM2qcLrdbq9M5jTZBSEoGMV3ieZfFaLfAX7PKaTDYzHZOhbX0kshP/0byMlGXRphEkb+xlEp8DT6l1LcWe4k/GdN/JOHLwtWbd6y+sHjN7kV7Vy+8GP+FqDlv6J/cC6FLXAX9+as08Tus5WGAXzqsRQI9p1Mgk9fpBD1Wq5FKrzKZDdp+gO0G+Cuq9XaR9AuKOHbbWRkt8t0kSYbXzErTRn/49EdC3z1KZiuv5AvqF4q/+qtEeUfKeRzE5/K9QDOrDKTYjFJSWlqqlJqekWw06/oFzaY0nkrYiI84T5teitc8olUKo/5pTH2WchX34JgfG4zccvvMQ/e4SlvmtWhZNRGbg1NmrKs/vaVm4Mkr2LR2ZuvkHc3kIfIXh+c8uotb9ldKhE4IAZhXHqoKeOi88vK8MLFm+dkZ/YLZKdHpJUyuqml8/f+enZXRRhYxU3qLeeLO/YsqXb3bn9hxiwlff7xuju2g8+m/ge6LO+JvyWYRmSRSwI1BjAbgAPxug6gBGHcJGNNSTCazSpKcZpKeYXO31+BuKIhs2A/HyIxbgNitw90fDyJyFhfHHNYT6Bvsc4SoeeM87fyN/tn4TLMZA+bOWdSl3+AJi54rbplZNEjkx/TutGibzOPPZ/VbMlFuR/q8qb3DMK7TzDSl3vJx9BR3lNVbNoGmayQ8r0YGg9liNEpY0p7F3euDEpClp2G2Q2FJhfG2oCVFjRetrIhsguecn2u2qGZAZWp+iWeRUHvHHQ3Nxo8WR/KV7Ugz6OgKwCaP/xVZUHFAqxUsFth6q43anro9HhTUzwAQCG4JUGyBYkHAsUJHjaUiY84Ub/C3CyStRxdHSkp2dR/8LddjVmDvmK7S7dKdS+TZyn5MxB9yF/kvaP7mM1oBWSxWm+VpGARWrIz6FC5CPBsxFp4Z8SCnHqXKBVo0Cwb3LB0xpRcbsU81/0XoCRhxVHc2It5ExxuJzpMuMJ4LIKuVEDLrXC53ktEGazwd1BmNatd5NjrPUEGNS+LTecVDtvFqsS1OmMOZnJzcFH/Ow+7qbo6UtKzeffgvGh6rLNLMUr35r5rOsanAPpcAvE/AXGgOvMEBG7UsSMB7tDQBnqSV7A7eCpsNYhfmaaUTntdyOjo7LaBod5idloIl5nNxQwhf1Iva6icxVwsriJoFQNkfWfevHT8Pn7B9ifzSwrN373iaPIZL5YuW+cMmzOGuh8YvXy3/pfDMafg7fhTM0YG6B5watUrSm4w8RqBZOSy8Xi04XbyR7pcdYNWy3oKxXnWWTovOglL2eP24kTQS6iBHgHRbHc5yeotWhWGWGzfdoXVrjKs3vr5gsUNluHvl8nS9Zfl8/B2+lru0ZffQ19xfob/6VbbhBoZ+X9OuNycimjbqPHkW5mdGFQGzUdIatJyKt1jhkxbpVRRatAAEhRaK7mXEOzZ2a5atnI5ygBSdDOwm3lDsrawYXiB/uHJvx6JDK+Qv2i87rxrJD76d+4885NW78Jch4UQdta/hP0hv7l3hikWkGYzgu530Jk+w7wKrtc7xhHuV1ZhODmjVgHAarSTR/6u6Uhk9qvScKvH9fjvHZRcsGBnkybbR2zuuX/LCLfpQqWj3iX3YlYB2byn3KutDuHKrPjikVmu0HHeTPrwsLLgt5l4MjlxQmCVceWHJ+i7bR2yjfeTw87mPhV8BX5MCIErQayWDUdKjotfjnckUGbaUXXl5uZz88vL8AePHD+BfqyguLh84obb2NnoOf4C+7md9pQY0GiIBsTMYkXgWd0VVCd0xK6Lfrhi0uPsHjhs3kHbJz584qHbCwPLi4gpGR8rgLG1lsQmdAwatzoHEWJYzeobUNCk1TXSmPseQwQhUU6FjkUo/lU2uPnCjISou1Zidk9LyJwVrJ663L7XtnHng6IZV+Fs8Rr997abVqzUT5zz7xLGL2v/cMB8TcEUtCGQ8zMeKlflYrTAfSdIr85H+53xKG/2NYua9cjPXZdWGowdm7bAtta+fWBuclJ+Gv/2P9uKx08/NmahZvXrT2u16+QC1A09Be/hq/rhJROn/Zjmp4ftY9t2jo+d8Lvqer+XPIhHlBMyEFwUOiD9Hq1RxIpz3Iv9rvsSb9WyvGnuxn6+9Xz4tn70f73nge2Jo+IW8qtCNxP6gM55eJHPQn0Bu0R+7N+bOPiBPuB93wz3v/568Cv0ZFD6RzJ+k9fxorfaAiaax0tIa65x6w1CB2055c2O0jx24guQtLfeTk5P+wX09UT7Kv0irBfyY2E9mwKwiBI4jj/kNQ7G4KYi3o6q4iBpKqKKVCbhzkVoE/MlI/UQ4Dy34Ou4g49OOJ6BrXsAcw9/XGtsDxz04axZfh3vBA335t8l8oT99PqChEEFkcxDtQBExid4MlHrI/NAHXC7/9jJl3U/xp4kWxhDoOQHGAEdWlISEcSL4YfXbJfzUiqu/8qdtmKQq9BuP4k9zJ6PtkSBQjwmJCjRN28NKrXau/69XV/Cn/0qVQzakrFGezB0MPwFztkbWSFDRDQuUJzM3ZXhggHyNLAhPaVwjQZuDZGeTNS4I/YPLlq9F1nhenkyM4eUwx6T4OcbGiZ/gSZigPDk6wSZto/C5oa0CnPMAHHlyFDgcvg4vb/Gt4GkJ5QUsAsZAh+CQEpUai7yd3nhUKZ6B8VFJkjfXXO53cm+N14+Hf3yr9967/tJ778FcrpOxkf7cdO2IEAAX8xxR+mCXP9CcNaXtKE1Fw7iP8Xv/naZm34KmnowjqZSmQl/3R/uK0lQRNenrFgR1WCI9PYUeJklYBshkBPSSKAJo1SoRWAac3SuRW5XoyfWA3u63+0mSvHvRrEUPT/3iC3RjHwjaMsgKggTbc8WX0Af22r3AuTwkCXrAt+FtX3wxNdLHEZLEUa02P2DVIE6QYCZEp4duNKKophtdGdUXK83OiDCq9BaZFfRIO81YsmTq4sW0zxbYSg7gewE85tMURTlKj+LR80BoCzcTWzfCs82BXhwEeqEHDLHxQC6I1mDU8AhIBpLg9MaTjEaWletXwv/9BsyNX3y/fZl5UL+BA83LXMf4k5vuqOrSpWreBuV8EUHH+DJBJYFMAtgHAEa40oRq0Ci0BfEt4e1e9Bj6BAl1VBUrGj5r9ojhRbEDSIMmySVBRyMjKU7fzi8mg0UtwMuJhgTaAW23iKLLrTZuChrV6WrORNRUllQTYt8ULCJ9yAzyMeGNpIhUsS/LyEFygahIwOHuBsAtGD5L0S2ite4SMiAoDElKKBW4csbMFbQO3YJo4TmhU+2sWbXB6TMGN9b+w/hJeSBxwicz5Q8qULSRThAsVhUHE+V2MkGtKDZeNBELu/j1R8p6lBNnVa9Jk/t3Wx3oX9y8rK08M3nCwE4rm2Ut6ZDf0sX8ZWHvrggPIjcqCrjVGodT40xKdhgMAuybAfbPujmophvoK7hxC1tw3kwDHFZqm0vjIntJuPwBNb297jSbdoa2qF9V4YCaHp7sPM1M01j+ZHbzbGtWYNSYMvhQ1O3O6cq9XyrMwQr4IygRpSo1o1FapCaiqNOrOIHbMFQrbEdxTrLOOJsZKwLoYa94/dWn5bflMvrKn7T9mPol/YF1hr/E47kkogMcTQvoMNLpVAajDj8raACtk674ompBcUsSl8KDSElfpBr8vpKa1ksHvpVfzX3jXdepTd72Eqyzwv7YSHNyVniTnTuHBok8L6g4LRL1OpVW4Hi1RBQmHpezlxK3XCm3PLfcWe6UyNnBf/01+Pp19kpWRz/BK8PTDPQU6D5Pw/4noa6BVA47jDYayK/mBUFNjFhIThFBFyJuTucGgelUUMdzMGDRTQP5o9BipiDcGAhfHovk55Kvr3ju5RVySNOjb/fu/Xqs9PmTXT6uPbdQ5rAcWmtd3r9bMNit//I32gRHlaZ7GY4i/A3gTxhkhXJGz2FqIHlLTzOJTYV9p4BX8Mo3wlSxhEhncyRRI4twpvGjjlAJbvMXvp1rP3gwmaDEyuNy/BHZBTp3LuoVsAGdzbAlJyXpQCHMa6bLIE5n6llqgUh2Pk2Vb6ShXwC0oBPHVw+qvNH6FJe/Mna5kCA9puM0juzau7lun3uqaUztKU/b+bcN9W9Zv3Czdbp9d/8+Ze1rFtSWcBem3jFoiqNt5dys5ukZKWW9KydNGzzWMMlfluezODxlA+gakkDWPQU6mBZVBdwi8G8NyFS00rUWU1ItaeBNJTzNdDEGKBq/lpDsObaDWpAp2S4STApeenkVFv5ce/aJ9X9hNcjZreSX8Ho8W34f58mbZVYTJSpnW0RuBYPn7TDEYCbvuALAHTAWJSZvFvljSo6HeSaTwbvkx/HnQpc1Ce0orzIgIhAMKyA8jyXa2FJZFD2b0fZmv9JD9S7y+Ro8pmkfeoEOfrMu/P6b9MHtW8Md///sA9euIT829vGqAgMOxBAqMdLj2qjoNcNKSzkFGq4ROjMYzIF2Q8hMpR3fCLuEdtQ8TIbI7ul4AZnZ8Gd8OwlkagPICEiRoESAYuKklSOhFBSGPtZOh07wBvl2MlNeCP3ky7XkSHgG6Az5AQsHHB7Ol0ilM5XA1QFvLPIlveZLcOegdyzUjOAsJ0c+ffb9xzZv2Cp/jV3nzzMa04J/jxwQU5h8R6GJYU0IZkbqRCGBNCrziiR5Zcyf/gj3zZWfngv9JINI6Ga6sxUVBKwgI6qtZo1aY7NbVCqjYKVatO+KL7LOOJYV08g9sU/4c6ab4/8kqugxTZ3yreXyQS47rOhOJkIlFJ4TQSRW8ZhC1B8FgqUyGr/HQODHi/s9OHvUqNnyQew+fvxmfVG1jgPhBdG+OPHmfeVKXqufy6Y9PdhPPnj8OHYrfV2SB+FPw39BX7DPnMADokgq6BJ6BBkz6g0cgadgl5z27FL86fHj8lei0lnTPoCR0FQpKlgiT2dzYx9CaXku9CF/dfz4o8rioMFGuZZLDb/NZBzgeFEZx06MaljRFV8ctgm3kFO41Pk1NfPn9e03d1Tr5s3btGnevPW3fafPqKmZPr2meXl58+aVlcqaN2Ijp+c6JOomFBfj9Qs1proJflT+6OpJbMSOVPlTG+KALxu551hbLUiP5khrrVatUulUhArmPgA/TjSOKX152Cs3lvYod43vN9I7vd/8Cvp/PtI/7C6luFRQBxWoafe0+gDrnVBNCPvZq/vkVfmjEH3BRhtOT5W/VV7pusPfyFO5J8LzAcJwcmx2O3TusqiRXQDVxA9YE5t3VFgSG2UlKirha/kDqruml5eph2pb9gVJqbpz2jjzMPM4eSrIR+0qJ0xqC+/zdsynegHexl1iMrBEve+pSxdCVFLaOpTjA7ywdSgPkiitvHwlgbnSZMdU/hVeeOEFPnT1asPOq1cpPdoLMnBxlAdQeUuU2MGJnXfGmIF6kmL52gq8S+j7Dq5p2g7OHdA/Rd2Nb0eZOd6Ld62QrwlX5Mfeoe2AbhWH74/QTeYfxt/YjuaILZYnr8A2uRbX3NAOA7UEzfWGedLkKDCeDbRe+a135McAJ7+Hdh9DO4liP9AERtV4LMbTBn/jqKV+8nHIsA5/up4OfPkyw+tv5cHkX9GxOSDgosR0u7g5O/3U7erbzdykkCp4aa0ir/SEdivQPqCFLQI2FWUREuEYSdFosUoFSmfRlRghjKQhYE53gsfppdgnecgKedCTM999d+aT+PjpX3GyASf/SvsONYi6cG/Jq8yJnhZM10SPWiOuMSuA/OOvV1eIOsUKgOWd0O5L1s5+hqF/fCtfVP2Xd4L6L+oabSPyaf4k7in8DdbSLGBRq4BPAtMRsajh1XUisyolsQPkj2M3UeuS1Y97MuvSt1f4F20PPmjD1FCFGzoKDWGTpKKx8wFD5NzYBH0dnB1UdNGf9E/fxf9xcuQutzg5QkOTk0PX8D3/NrYwm5KxnnC8ospif4ShYQs1tCjGJBx6SPRyA8Rj7FkO81Sb9EWeBQ4Veoh/UPSuWKHA5kN+M84CvUSPKgJejVZrAB5o0PB1khEVIY6+VKE+aBk6iC6gH5GKKaY+ylFx7ELcnKAHz99vnKQb26sHCI+WPfzmjfNad+/aduGdlNbcx7+DhgjLmT5OVWAc2z1KsPz2IfX8OydOMH1K/oZ/ATuERYxWpAZ0iEggg6soI9kBTLhxu5jfCcV9+5wjob8d4184C39gXU7hcviSVIAslGIajEYRaTSiaKWmCb2RcQ/TS5E1KPYeopiAgYEwA7C3tB3+2J/frUv6kMnf9x06s3NLcXl6pmts2s7WA7W++SQN6HIFyMKXxDFR/mQRgUMBgzKq7UThT40wst6CP126gT0JR2/Cnzh5GeDwCuFzxgOaBayMB3BASQhjAnUi028VNAbh1RdvEIuwAXnZB1flJ0L0BdTKJnwg8YxgeihBdCAqKuLXifjmZ8QKB10xm0658m3EaooN9JAw3Apf5utQK+V+8zQCPATyU0X320ebmv2tIgZTxuOC8Oz9Ed6QHNAKPMhwIHMobXwU1X0Knnhp7QWzv2zWrH8q7eX6SB8RGD3AYFQQsDE+LGrVWo4wRtwUSI1KVDYsw+5hrzhLfuLqB8CK4ZU/+ffUz2z0R+n/Q/4UzhLHwVkxo+YBm9FkIhotT7TEoiFEMhkk1j/se6VyNhuRK/GIEMCuhGOSWs+fih4UfBKOAD2XT8C5fArGSg/oI/YoCdVpebYVV+Lw3wzKnlfJ3+lth+fttUwyjunRa6xukvGA8NT6Re26dG89byPbj73kOzSOybfOgFotIU3cDRVmcYAkdj81Pidv0YjB5LsHJm9qv27pP5q0T2Z3qmq1Ju5+CkdRPSYDj2N9CFdu2QfH+oi7n2rsI3o/NWLwiEV5OcKVfyxdF9g68QHWx2/kG/SicFnpQ1SDmAUrIeqmfdhYsVxvqf/FgTWFE8URzwlZ21dmd80/8Cb0MVSehE6E6xp5EEhsijk5RrWtjAdVU0P0pIghGof7yJPRvcwOTXkQMKFYK6XyExO8pJNxFmgcrpJHosPh04DZKQEtoYY/FVP1FJsmG9DHzoRiyzw847ffZsgj58yaDW1HQNvnWFugMETEtDFI4lRNjDVmh1Fifmd2L2vdc/YsJVeSvJZ/ES8Q18F8Yc9BludBW8M76JlSxlUcWICDLNgc2s/9Ak9XUlqN2vEES/9zrxs1HyzdcBcZvk+uRSPDbwEOW5/QiMBXEJX9FQDTFO7xBuqRUfu0XBtnoMbhXtDHqfADyvqhD0TJAgf8O2Japmk2KxWXcsUOfIoZp+VaZp3G4d7Qvp61B/mWo+0FQYUpeYvYt3HskDojtul6Zpq+SC3TONwT2j8efgYoCshBGlaWi3ahU+zS5FnQRJKilmkcn5HJGmebflwxTctvR0zTsC+X5XdxZXgs49GUNpJEfl5JFVP5XeXcmukc0F4aN3RGRFot0DLElh+BZHmcp93j8lf+gb7O8/fKnyu+coq8Qn178KH4PoiqSR+NaY4en9/ZN9Avf7VX/mWH5agJ59EsG+Fww+/yhdC58DIQe/4d+glF+DT06wgbGd0G7I7waVAZOUVIvTmblmsZm6Y8FNZ26QYdz06eZTpeVNBgPTj/r3noDSoeDu+WK9GY8AHA57SAIUIzeKQ2qTkYZ/gVfwylnVGM9o8pzLtjxOAXrtTeUTRuyP3QRw+5E3qC1lVFrQMZJrPZaDDwasSrid2s2xY0B/SmbmazZOSkjTHTthItip1+cyNi2KKbRf3NpXK/lIafkH+o9BRnb2/bLSW1/ZTcESNk+Sl+jDgoL597Yhzpz87BQFqXAzhPJtMAkaCj6VATzOjYGYX1DTb049SEXtsp3oTeZVVO1IQO/Z+DfegIdCYOH+NYdcc1a2CfR1B6Au8LojqJYitVCbiOHqeIhBC76SlluhdesF5OX8f9ItdevoxrGO7vl7fgseElyI1aBuzIYNDrRZCgJVFMMms0xGXT085AfvJFzlTkWNFrNbPiV+ZXfMlib7BeV+9OI4aNbtGivP2w9uUtWoweNmK2/F1O6fKpvTr26Ny5R6eeU5fTsZ+E+XcODwU8ALkQ5BwQc1S01q2I6wAfEtZgqVSEnOjd8Pgrn0z8CIQcufZH+1132SO6BfTXnvUHmn9EtwDlQtSIXB2vbtphgmpR7sftQbX4aOInV+SptMcfKd+XZ+Os8FzFxg/yOBXHge9r+Kan4b9I3fLsRqkbNe2TLhbEfC2I+MzSFt+n/daixJ0xSQLLe2DNtwHtitd9LCpUZ1OMBkkJVgPrzXSf/bcyGtTeoPpQ3Ud+BlvCrW9FK5nuIz8T0X3kSdwA+buo7kM94f2Juo88SdF9OKDBtUCD9zHaBZChdkMmdNaxERKELCFiNVQIM/35OzMasvntQT/j23DoRl2QklifLxEe5f8v8Pi5CTiwfAhb8Eig5BFYNNUDR4Y6cOexZTODxcM4hRuEd9/iWW7Q9Vr+QZyyhK0BhT/nEPlMeZbj6a3Pa8qzapwLUnjD2LFkP1nRMGY0OUCf/zL8T5wufBV9nsI59rwX43R58Fb8oPDVn3+IGkZfjsjVaFj4MuAgtbloNIB8BnrOX2+EDEm4/R4evfyWjzTefsfTH+A2AqJaAo/rmEkkoqD44i0ieEGCRYQLdwI690z4KtvzpAAcKwl6kBSbypXG9jS8kZR67c/I6/D8kU9B8/nyV089pez3YXknHhFeAfsN9IuVGEJOp1bnMsMHHadW26iCCUt6LULB6FuEflmVJK1M1/QyJ0olfKzB3KO8zbA25T3MY/RDqmdWZlSXVY/Uy3/vQWlXj+ohQ/15Q6opHLP52ejvYjaTR5wCp9Ly9M5Op6FqYNMLO9xYPhZGjruz+3vtqpWDVq6qXbVq0Cr+5YFrVvdfvXrg6lX9Vyl62938VDRJXI9clKbZ9HrerKIVHd02ldkk8AxQldHeY8K2AUulNIEIu4Aqt1PGk8ZNKqrpX1ic6k0dOad5S3gTNMVVWZreYk6+s7i0TWanan0vVVahy1faGs5j6ISo4wZKLaPnkRb9JUjFi3W4kVLFLkw99mx6oE/wD1I0FnUTJpyfMEHZn1P88fCPwvMg84LsShNawBahOgKaU1KceE9AySCle9bPvyg8L/+mw2qajwtZ+OO4mrV1BzQCu1RJbEolZjvxllpx9cX564XnjfK/dVjHxj0K+udw4RyNkw6YLVRHd5hAcha0WmudmnZxxQcH0B+R2hlvjRIDSyMt2JDftX377CK/enzqI4XdO7XPGmqcYJzEP52enV5SiTl4m7ZuIdunfTxB4/8f9LHxTUV0ROSH+Ku4v/AZrFcNZ9MXcEB7EJNFjV4t6kWDVpI0FABUyvVHhNxGE4DSPQNGRLo7ee6OlfKDu/DiXcJnRvm6DqvkaydOMKMODsMxQntAd9JRGqATtVo9UdXpoOtGMdQZ523rb2d3GTyFOZtWNXic4kztPduYPvMW6DOZEZso6FICKFNSHTVpxlsobpQ/+Lci8gcn6+E4/xReGsMzjsccVgl8HeMWiXQfOqE/sp581pBKPrs2efK5yZOBjnSFtZxn8hKjI3AseOgiZpuN0pGoucK/Zs3PigwlH6ZyVLgU2r+aYEsWCOA5BbMyOmh0zAb9KjNBB6kFmvEa/g58m/AnSkLDAy2QLklncOnd7qQkgKWFt1itII8la+HkGojO7RZMDoegoyTJUidEEdBXxFDQT4tomyuj5yFS9zFSNQwmrlAompoPCIZDQU1WLr4mL3WslfGpdn3ajm6b72acamDrvm1HCy7rQmBWLaeWTbUt3DG/eFo5w7F7+DF4ksSxGokZqEMgLT0lJc3tVtsdDjgjHkGvt1tArbXD39T0JHeEwBRF55kgBN5cpmAykBC5JzhQ0LdX5/Ryn3qitmW/qsJ+PTullflUk83j5RP19fVCeUYuYGpweJkn11PuWz7lnRMn8G+AoZx8kH8OzxRPwzyLUdeAx5OZqW5RpEzSl5aTU5RZ4HZnZsJ0HWqYr3oHTTHnMykwhWmyT7FrHp/5v0yV3PS3x2418YG3+g/+uSaLwaomv6A48yPgnTn8pCKjUg8PNRBUQUMkicdqUQF31GIVmbYgAfPLLbf7S7F51x+7dv3xx6m6ulOPzp2r2EBq0UnQ2USqU4vUfZTnJIHeB4MQEKUREatqqbcc9OrWc0+eXCzX/rB58w/IFXJAk2/Z/Yua5UOktcWbo1LUFnVGPVFfFESj0SQ0Cy1Ay9F6tBXtRvvRIXQ/bhO4f0+3++47Mnvu5BUrpq/pcrjftm2DdpXdeWerTdLBFgsX+pY6xoxJmiAeMAwZYhmR1q5dZoecfNK7d36HEQcmLD24adfhNXP1vfZ2P6LFfZCmD+l1pNcD2r33La6rOTpuw4aJW4bt2DHqnsCqVZ3W5d1+e+H8jKlTs2aaBgywDcbdXRUVKW1altQd3XLPuvkzB3dvU1LSpvvgmfPX3bPlaJ22x73V9913sPcR3T6JdO2q4ntQ/k+R4CVf5IMSER/905h80P/fX8x+00WFGjmjdYVvDLn7H5+j8SvMtkHlWOrMmW3zZpaW+H25kXdr5N0ZeceRd6nJd+pxBzSV2Vrw/3i26ffsJmNFx86G+VCBVKAym5/7dtonuHfoHHV14DpOmyZvLamoKNlZUllZ8md5WUVpFv0qg4hRXvZIRWlpBTeovKysvGHVJ9Nwb36tfOqTaQ3qMvjD3Ulfd5VWVJSGHiytKCv30u/4FdpQDtI2f9Lmu+hv5S3TppEsOmLoGfnUtE/4lR9OmzatYQ6u3g7PFcKP/Cb08wV8wLvgwxD4EJpNB7/+Ie7+V8m0D7n3yvytQu1KS8v3lJRUchmRp0Ph8vLSL+FB+a2Kksp8+G/os2HOtGm4+4eKrHU7vwRtFD3Re3IOlFAk0XtykYvek8fdIij35BvpNbkwP3JPDrI1Px8NYz729jPUHRQZFGfQmASQYGkbdnPXembffgdniWuYfbss4DYbDFRVtIDGaOG1WiMyGLcMlZDhEMgXvmh6kEYhs/JGYzS1+SRokWn14pqoIin3Ue56QKaVO6C/h39nnnNOLfWVQ7woNsq0BKulG2TaiKvbrcRa+e54sRbgLA9CG5k/ArUDKj4NiS4NMZ7vVDwaNsY7NCh7FeuDaovMpSHRo0GhoLSHxn2KujMAfL+WB+GHWXs96hbw6HVqtUTvU5GWU0mSEWZjgP4kNU/LOemUbiupY43PH48HloRs4JGxIu4cmA7JvajMOjK0fIy5duDwUcCT4QxPFB0MsMSguCDfQgcbdrOgDox+5+/Hp4TxsF8O6suMdGqydSgVcAsil3lWZqNTvPN+r8jNrajMya0QROWd+R2H2wMsz4dfQAbUPuAxUC6i44lOr1aJGk7DGbGWqJFOVOuIVisJBmqprCyKpW5g/MVZGTPcwt47o3iQ689Y7d40vGPP6g4jNrjXqPu/4u+ZvbDZsqXNFmT3Kt1E5ZELzAZ0DllZVcQ2gWTBmJOTlKTJQMim0RR6U1P1zZxOWj/cGPWC8MVGjjNHVUb8TnJjdkknXbcQV2pPiLNT4s6TqoN+f7DPxEnVQ3y+IX0mhi61LSxs3bqwsC3+Nvrpj+rx3buPr64e363b+Gp/Gfy6bZk/8g5wq+BvQ5fEkojkytNrVBUvSZRaXIm7doI9IN5yj9UvXRo5KxBG8CIsl788hZNOKbjcX64V1oRfgT1MDxi0IA6AEsmpNgfZgfBdKWhECYHzZBA/jXjOKhfWfBN6I3T1m9UjcI9r13DPEWXyRjxnxdy5K1if/AVhjeiDPrMCJi3rEg5JgHVLox+YZ4evUY36bx2LvsaeWd9CKtkvUFuNPaCmAQqY2xwEeTmKcsyfe//1J/geQuoytr53yf7wwMbnWXzCzZ6X32XP8y8Iq4UwSCM5AZMdDqXWYSVEKxkMqE5LVZTKJqobCwbMzopQOqrDw0LKhdXN69fslr+Rv9404va01c2fXxR8bSs2Ht9TKYTvvXvQwAHDdhzJaz7oMWVNMOYasQzgRS3nWq0oSTqiZma5eKsczoFReNARPRlWARSI09euyU+MWP0t15Ir+pZ/gcIIz5E3xvaVXAVZj9EokRpoeYleNokJ90U+JuHRDDbk6q6GJPIliHdT51IadRZ/iFfxvyIvKkKjAmaD0WgjzTJUKputOSEtxXwa1KQJekSDaEBms1bxijXj4lOuLJTFfFhTEQsM9DVJPVgZQylzo3TIjk0VjuYBKvOwxLyxXK406jOX5Y6QmCF70swZe44e6923by+pLgNLd25MybM6/IVdWgt80YJAh0lt1ywZ0x5/uGDy/KWE5I+sblWle33VEvlsZaXQR9ur96AeIwPT2rTjSJ++VR1hrc/AWnvAWq2gTQUDBgC/zZoE3/T65CREF2oIJlEnejFJTNKYTM72GrZaEy5GGkTYZw310E2sjpawTrrISF3iaKYsf4bZnquwyBcmjasZZZ6Svm/W0ePH78WdlmpHDw/eJpDeqzZ18GcMDV66dO4VeYp59ILpC6aDznkRf4vaiojpnC3O0CJ6PK8S2qtxSxY5SwMKlEhhXyQHexxdp7oRTKnNggULhLULFjSM5a6HBIDBKYBBJ4CBGjDfF1ADzzUJgkPSR9YqwVo5ZGWfuca1NuKmiaY8ofnx4m9kcCe5fs9DuMeJvXVDJ08dNWLC9JFkonz7C5fxXS++dGDztr277tkOesn7MHYu/wWMXBnQ61X0VsNudxh0KjtbkzkS0GmGcXVKzFwkqhM3Gp5IY/GWaJRwTqn5kQ7AqRbyt/Nc/vQBi6bzX8gp0wcunIOfCj1wZEWvTss24QYY/zUYP4f/DTlRl4DFarFQQ55O5xKsglVtNNojIDACCNSw+O4sTrjpdse59cFkTIk7HXXDPvVUh0HaxYa7591z7NDe2dttSx3rxwwiU+V3uvdSTVt9+eL51+ZP1dy5jp6/SzCnVrDHtE5zz4DBkWo0AuaJohdkIVt7I4DBCNurQhkR53TqLZ4UcU0vasxaUmWpjAMTZQeRQhWsPGxprlKnJyehLOwz3hkDNqzAhgEzvBgv5O8Q5fV9h08cMeK2Yf258T2qnn8Jbw50dlbhNg1rx1fk98Xk0Ppd++/euIHZJT7F3+LmbN6VAY1Kcpgkk9nstJzFvlMOojKfj0bZs4kWxwJ0qxL28sYQe5im9EBcZP2iG4LqeYf8Ewuox7IL5vA14DLN5mxxZIOKnppiUKUAXuV4eAvPqJMLplRcbzcY1NqzuOXjqUgdCWOuoiQpEp0Rm1PkxobEJTCJK65Tljjb1hXV1cMWkjkClzO+14DRNq7jvpnjF1T0qR4K8/p8yuCFc+Qu3OAjo7zVHbv03LpsE13DlMHz5spdqE4NZ/shFpNfFFALFguwZKvaAOdACU8vBnm1MSa/Mv4Ikhsj8h/+XwH5OFyLP0ZPC5uRDeQfndZoVAEtsQMJFFkQhlYt0ZBqDlkST/5LcfCJ3TTekPbm6dbttw8cktVv3brMgqTm+CfzCRwafvz4cDm9vBB4sfwgwGMwnHs1rNVIfY04muSPcJxGxdHoAYHGbrHogQTtgl3G4Ugq5s5b5d9XHG5psJ1ZAeu7LhvvL+nIeRT77xPQf59InEISdM1LWMMLlMHCUEQnaXgQB24WqKCY6n3MYq4sLy5O4eX/GaZA7cd/8g9xZcy2Qf1blDhFoY56McXbnq3US4T8Of3qx/xDNqxPlRtYPm+QSx8Pz1dsgswOK5I6RG2CMfcSQbG2Pg4t19nkX1MxHw6jn6DdG+HlJomIuAwpObXvitbV5eyROuDX+Aq+GjhdGpoQaKdHacmSaLXZxGTEp2ekJPcLpqS4CLKarKOsM6111metoppYrS6XqSbochBNTTBdWiZtloDrEJoOqGh4LLUczYplbhLIrKRNRU3KgVLayHkzEU1QugJzv526lv6sqW7uge3b97NS5vMuLvg9jPDBei4tUv576KSL//jotcnTdKP2B3HGy1Rj5OJqrCejiYEqs0USk11wYFyihU9Jdbv6Bd1u4gDSbDSnm5eZN5t5NTGb44qvm6SZUp30hgSCs1IoInExs262mltUZKeG71tWZQ89Xn+zwuyh1bCOcBiPkneCZt3KBLIa87n9B3+S+1H4A/bfkxgDrHt8qLAdJUYcMQzC/+jz4kP8SQ/OypY/Ychczp8ku8T2Edsa4L/ipKTWazRqRIwGlVaj3RJUa4T4fmnkn69pxrfGUcojxn1OXfbitp2bQ4e20iFnZMs7LYobB+AbTb9wRehiyUFZCJklUiHnhGuQ7RRnItxZObveYOalbFxQiqpK2Vp/wke5f3D0Hi474IzEQ+4dasRVeAY+iK/iHzEIr0XDG6O9qfL103f4KC6Q3wmHw1ehyQtCF1MOyhvNxgv9BuPl1GMDwcaz4WdP2VO60ffH1ZZuZ8Of1BuNCMH4BcoMlNxwk4TOQCPMaEjAbtbpQNTlqUu6CiEtr7VYDWYAUMAVNBgEiRsZrJHwvdJjEidJaoHwQKerWJb44bMUtClIqNIVV9YsEgZDp8+ASR6VB1+4gB946vrdsHfcjNBWoXPoFa7sr6d5FN1HgCeV3OvY+gqXNcIzbn0Wa2R9RljflcT1UfjAGTkhDIH2vi6N8IH9cMF+hB6ud7hF1LgfCjweBXioQCMPBhwGtVqr0wnUsKtSiRhznNGkNVCAOINaXiQBFrdKqpjQCWootiCWibVo+HCl1l4kENoXg0Uk24LXzJI4RWDR+xn5wOX//HH5el8Ki26hs1w3LhS6nwvKT8dwmgu/zvL4DQHMykdjAkm5eXnZ+dmeNLeodWtJst2jNhIPKSjMzafzswdzic7lUicnJY8MapMsyDIyiPi48gewWf74hEWN9pToSfchmouUljzwsCvNiGDrpIfA58zhSkssZcoCuI2fYeuxe0a2uCQXL55/YMeOe+cvlosvtRh5z7Gln4fegUUJQ+Sz8s+vyhcmaPd9MlQ+997PP35wLjTsk33a8bj9lZPYskO+L7ZU2PedsG/DxfaWHDIZzpFIKn9FyH2acBj+nQ1/Wp/k0ot030pLEf2JO3udLSI9e/D9MMMd+j2b8STomh8KeyuwekYYsxiAkUGOUCyOr5HEynDigxfIolAnofM+ihc6aPssa2tA3QO51KGW14A6LRKTMVXERhHr4TNHtDz8UkvD2gHcFhYj6fTTHKogWgFJHZ6YTMlfCihgxwYOe3BOrg7/8zf8WegoqSqSPyAl8kv+rK18/fXq7fx5zZMLQklEv3JOdF1j2Lry2Dq7w/eV7Hvb2Lrz2feCm+TbHhyoNFEPbcB8PinZ7RoZLHKPdB90P+rmje7N8HbB/bH7R3fYLTmJ201zcY8MqnliHRkk1qZprGcVxEfD3jQJNwFsiSXh5kPxSbg3yyfjknD3BT6QkIQbD9qzh63nFeojz9ZTGFvfq+w7i62mmWj452FvNKC5JWnUPEbUmQkRnXYIj3uCkKNRE1WEUvmbboGHVo5gdaP8/POX5edbZpWmy89exn++RNZsWfvcoIaFQmcYczmM0ZON2bIJjIsZjNfC9y4wB6qTalFtoFSrApqBeYnX67SAC+naIi1nhJcq7UjtMu2j2o+1UjrRagXMAwryFoxGBjG5KXyj4X/UeYFWUoAfCtS95O6GgeTC1tBY/sF9+67X7ttHCAAM5hbZb5ibj8HniDJXmJk3YAZlmSAWr0gHjBDwgrggGn8kh9sRsvZC6N9CZyDID16vja55JFuzn/U7Fb4fgn51qH8gH1gGVnGcQYMFLdbqDQSkCkAcFQjNqdT3AGhj/KFQKkjAEv3+hFh0SywDjL9UTZfqwTQ531QuKfRv8lXDT/gV2UGmHeay8T8P7ZNHL5YN+9h+9Iqd9XL2HSgA/wD73obtjyr8O/+i0IfGd6FmaFCgRapNNGeLRPLoXUgvIVKQn5xjzhkVtJnTslXZo4KCaosZm1VmlWghIiB+Fct8NzxSvTcxF3IsD4PNgAsw9XdlRRhQayoVwWmQqIcjCNRl2TS7uxnIKP/i/Pc2NDvd7K7352Pxk7TTqZ9g6flj9wi67UcaXj6yXafaeYx7/s6vVn7wwYpv1n+IhRMn5IZPjz4e6vbcocPPcmcfi63xQbbG1mw/ABP5fbAfyTQjojE5WYesDpWABAdJTTHqsG5UMAljm15U6J3fX1nkv5mwQ8sPc0qC0taYWcmUQn0crIFzt3r1s0NbVvn3+ldvPvT5K63wRuz8CZ+Uez7xImnZ8MalU/i03Ocn+Rs5UqOW1lbZDrTHS2uBA4+i3MqoJkTr9vBZ2f+dQTVNitiUJ5VZojzJ0siTTIi77Xec/siROwovyalrVpw4+sDxlavl1EuFdxx5BKcDH3pG/v6cfGYq8KExWHXik6+vffiw/OcY4ETTcPdnsA13jNEccQ3IcYVUjkOTAY+1yBnQc1gn5HCYMwEHYQwIFUT5D8M51qZNpI0l2kZN25j1Wl7VpM1yOKtbhD+Az41hfK4CmlpBYwJc5Fw5zQQjE07gHzz7KJX32bMTlGdr2LM4z5yD2+YVaPi4Z0+xGuz02YkJz7rh2T7uFJ0z7lnGa9mzCq+tSFOeNcGzGpNVYbSRZ1mNIsaX5yp8+ed4vvx5fXqqIk/F+DLwTrZG0FPcwIcHB1omCVqUkWFx2O0galoEC63eajCqvLTQj0nLmXitysSl1gQXue9yc26OKiZML6H8UzHnxVXMbcynxMVlYKbBG5zksNA7OCVLNS2gAKhC5s757bXnPnhz6anmnNP3jG+ASmhddMblFUIXZ6+afywp9Z556xZ8L4cBDVw0wfKaBfNunyy/NuZe+cptbTd7cPFHl7+6+Le3L7N1nQAY36bU3ES9A81SQXl3mL0AFmuuRsgvsObm5ObUBHNzDcTgrgkakDqZ0Fz3jlhlyEhNw8RSELF0Brlexaqi3CFJaThadzeapZvGZvG3ff/hmbWiWP/5v1588+Mdx+XfFkzfvjxwrO/Ge15/8e59eOdLn42YPVh+TzgBz90Xqk29wrUeM3Pv/Q1vFBTvWbv5wCbtNnZOS+XBsEetkBEFAlkGXtLqJBUyGnUqYjbN5dfwXGt1T/VQkAZ4g0GbLCnFp6i/fwI/ZUxKjdOwsx0GyUYk3rJyjMLYqO/Bi2U450W5Z+esC+6A3IxvFZqRccVi38Rdu379CfmDZ3/liyhMZwKuDGQ5VjNAa8uU3IbUDGS1Un1W8GSmZqQDBPkUI3GkIwco4w5HLNN+0yy1SkmN3IjndxngQRpnt1ERBeTWcsZF76noO+bspfu3bD8k/7QHt6mb0Ub+7Ysv5V9++UF+jruG3xu0Y+GE9j/tPvLCWd6mkl9eevDExI/kH7H683M4qR/utmKzQuMejejhuWh4wJetoVl2Cc87PXqzRsxrpvdkejJrgh6PTaJpdpELawlNtEuo4bomKDki/LAoLq/2zbEiO96oWl6aWJCRWRbsGfSNmzb1QmBSze973/1w77wpa76+uONvHeuKtk6qm3fh+zC6tGr2gN7jRo85evfUXVpOv27M6n2Dxg7u2mlgj8GD144dP3R4pPbnTr4a9iETdQh4XOnpBpUqKxXZ7d6s9JTUlJrgBJ5iBeHNZk0q0pzFasYhi/zD42ofWhqz57D0G4DEuUyPYNk5EC4VvbQ0FA+kdd6cOYt37+zaf6kzY82pR54chqvx9G4DZR/JlH+TP1mHF1WPdaV6u40NjN9Ykd4vxd/D6x25Zfg5/CFuI4qb7vxVPiH/yOZ9KlKD24VaBlxmlUqNXGqXO8lss/E1QZtJZ1TbgT9W3azANTbftK51pOJ2fEVrGGPUDcWsr6+hcsbdgAtlwqsgi5phDu0C6XajUXQYaMiPO8lu7Bu024lKZekbVBFtjBYUNW46rkywtShEzeOzYJ/F6knC1kyOeDSYL/vp80++w2/++LGcv3mVEPqnsHzLphUi5xWWcP+UV8ob8BJ8O/eDvLnBic04Xb4mf85/IP8uf4GTgSNRODGaz857q0AGvQDXak1mgx7IlBEJJiFDIDoiCCoVobWKUKNNKNH4EpfBlnqFc+tqBkwfP2LZqZP3yc/hX/GQGeMnz99w8lmuzybKO64BfxxPa7Ogv9gcZsP3fqzGQ5dAjtNlQDaT0WiTXDxNUIoNvM2AAkZLN4Q0LqNdA/sHgn5c/k8/s7clVL+j3mRK+kIgQdhL4PxT0Z7zDypt5Uvze5PHZPUcN6A1fuj8VU2RKq1CDj9NXrw2Lle3SmWqWLnv+l1c++S7s4YsDT1H57cP9nkJwCgNlQeSUzkOOzUakG3TM4xiklgTdNqSHBpsZOhEczo3QShm+oukeU+sdJyT62Wv5n2np8yr21bvLXCntm85dKRAJj/XcVq6XCt8Fup3512PHObmNLzRs4tquW3EuOeb5cgpMKdhALMymJOB1gTkiSQKABRBIkaTTjBKvFIsvUnGXhCYQLvBVFzK9Tv4srefPy5POId77lxffLKEVJ+Su3zKt2oY9STuc2Tt9Eju8AvyHt4Le9MSZPukFGRX5WdlWVyUNSNVsY93uV3uvsHmGWex5omgq7mruSkHaMCZSDE71CjiV7KbwKbFjqwl7XCEgJWXSgJ1UeUV04LI228kFhcWfHHo5ItbD6SE0QjuIzn00Ys/X5cvz5y+cMfcjpRkzNtz/MxgPOb2C8scnHbz7ZPrklRY2rQufcGo0dPMK9Oe29JnQnJaVrsRXUYx6lHeJS1zxEZF/orVgkf92Lod8P0wwJfVdjY49LRInseAHKmOmmCq0WJXAxqqHXG1nRPSaJkTDoTdBPzP0pZWfABO7QeG825+SbrX1rvDnAnyhk7P5DarWeFwTSkh75AToRG9OsNGz1rDXe4WOib/ey++9GeNS79LZ2a5c9F+wMUBfB+Q3NNQccDtBky0UqeFDFqaz2jSJBMgyiKJZqOuKkgkbUq9johAQWUkC72nzHBjJkvwA359fsrBTjxf/8s7mz5f+txDW+Q/W983aNkGjv9Bfrd9dZsquZb88Du2b5V/Pfbm9/I8+YVuPd9m8HpM3sfnAb3NQh0DHpKcadUl67JzOMkiZQJS8pLTmW70etPTgdOlm4wKn1CICTUuR45wYx1VWlo+kjleVPY/ksvJErlF5B7b9VDbu/ZULhjXPqsItr5k8pJzJwfe+dn2WU+2mzWHPCd//X6/KX1bmHPaDOlUOK0P3e5Mf2FGyxkP1j2GK/dW95i9hMFzGK0vA/tsguPbMuB20vAMvVUEOUNrU9tgj43E3SirJahJFJwRS0czGsNkT8NSSS7lHECoy/gy+foXP4URLsQOrmjvjgGdzi0OPvUGzr/7AP7uZ/kX7KZ1m3D2JpFf+rc7fnvjvZflsc+hGE1OgTnReAqXUaXSaonD4XJbgSpbHRrEpAXjjWm3WJrFGI55lADGyAUw3tpvB0Ux7g35zsUVNc7ZFXXzyAkFr0ID1mpWioZ5ddxlZfxI/VFkQ0UBl1qkPMvuMJJ0wpkEs2SMY1hVcRsXY1SsqAUFQWkJB3TGwnf667vPPjiNjfds6N7smdJWXGv5X/LV9z/m7g6Nlf/+3jcrsL96rnxN0RFoLZzdfD/gBRmocyDLpE7neYvgBtqmV/OeTH2KI6VvUOcwpVtEYJ5EtPOM7EbL+9ykMhHMSQJsp6WJLFRsssMiqLzEMD/TjbP43dd/vPeb39551r5wLS45sPPeMw8O7bsTt+dK5R/l9/TyJHy3FnQA3Re4wLMu5fOH5VEmrtMLH8r//OPCx/LHoSf1FGatQG7exNeADjAm0BZznMZssdhtNqsJEY3ocJqNvGmAaZyJjEQzEFcA6jDnRliPQAZEVmLiQSuXaoI6kx0nR8ucOyupnRD+uKoS1V8QAOktXDSTPBwHK00h6+XmyDufwe+ebz3Cn56aWd59yOKBh3HO0/JsXH/+x9AkUolrp8w0rnRP3yd/wCWHuja8B/MeDPCeJbQBXAMZBWk0dq3FSETQzYnL7XDwJiOy6+xwDHQOTTyg/UVNrQXZtMo2MDeRAruF8hnW7efqDy05+Mb3915749Cie++dze04wa0JLf71HU6egndy7/zKrQotfGibwL+i4F4p4N5uoG/NUL9AgRWl5XrUIJXkepJEvT4tN4nPL8jLc2pIljOrJkjv5TiryelI1ZgYv4tKnU0qG1lYRpbKiJxCNabccoclUrtIqR5WGsEN9kBb7OfODOvetedto9P3nT28adwqF+9aPXbjkTP700ff1rNrz6EH8XN7nnjz/PPfJ63JkM999R/54+3zF2zDGX9+iTt61iR9/fK5t87sbmjUqRdFdWo0+XPQk5/gqE5NFeU3622WiAG70RbAzh9rMzehjV1p8249kCnUpA3jX1R3p/wrzn7ggjatXcmRy4043Z3p+YruXmFT9HzoHwt2V8KzbD/YswuVZ5srz+bDswX5zZP00WdB5qVz6AmyQjJoQC3RqEAFas7lceY8Z6ZG4zSTYp+UXRMsSgLFDUkmKUN6THpWEtREKpKK9DZbAcjlWJ/eN6hvWlQQzkFlQUHijtLdZDVkcMyzkmr9nsgXEufHwdRlGrKBe+bypWcm//OnX/9+4rNpMsaHzp7Z+WDdjlVrt21at34bfn10/5OD5u49zufX3VNVUTP0w9de/+xu3A578CI8Y93C2atDL23bvX/Lll27ufvK22zpQ+lVS1jzPFhzAfLDiu1uk1ScZdcWZmTkY6zNkviSUoueltJJDuKMQtBZ8wst8FfIzS3qG8zFtEzZjTUU/fG1XRN91m2cSCsolsPSoqe/sTS1pTQnS/GzsVj9jLrB7/l5o1d/s0t+0+VqVTzKNbnP8Ikud78utx0Y8bL86Z1Xjl+8KowOr5r7+vfcnx/JW5/FuuLhw71tijeWjR3sGz7c16H7ftz6JBl9Yu7uevkD+WN8Wb68aCW95QKKXCUMAR5REUgGcd2sJzqdXm93GLRms95I9BYkNdrxqizxNZMjFZNxTGWVlHswNcCaH91+bKuhyaU5BaUO+YFn5JTX8FycUrxAGJJfvMLpLfSGPonciu3Hb9UMorgvL2JzuQI4ugLRqhfFoRXReyChitrh6O/NkroXpvkt6UlKEdhJerk+yWUkjSeJniOgh91ZXsVKxo/ywt/xx4AX0lqf/QOFqRZtdnamSxQzLSSvmSPdmA5U24i8Ji+nJl4vUhsdycSO7I1Ve/2KmgI4bKlMYE+WSJoGuzdSR41ESVG5F/vMplyPaDbFVIY8fskSf9vDO1/28e65k3ccmbmYZN87PvT0uEPd+hzsy7e6a/A3S/+Uf8Pauruw5voPbza8jO/A2ifPyP+R1zy8H4+WD+57hNLXMljfVr4dao5mBtLMBs7AA7NSq/nmtvx8Z25ystNqszl5Z4uiXDeriJXrSPNS/NUE01IsiLMatSL7vdbI2SMeaHAYE4pgmeMLMcQ+UnuQx2KOQ1tOcmKPCIIeTehuilaSaIupOmApJxNCH8j//mFeakVmh56LF5ZlCVwG1s9YMC/f91OgY0FpecXY0aWZJL3hU1yDJ31l2G295/Qd8g/dOZK8S95w4Su9/LX8vu6QvlPfcYad923Ajg5sPyfA+ukdmAEkDJDsrQbQo4waXuNOkswjgxKPHaOCwJatqOo1f/yiogVmqRzBbrbMVKywxq63ONWr7ym1Zd+79G6sumwt3peOR+OyaGVZ+U15X6Y8lu/XeLtFfVEozoHsbEBJyB9IskfnlJwiWUDUM2EXEEXsQCmNJf1umFQpmwWrmGyNz/enOn8p9PVvP7zywhvrd+/etmXLwU0wqb0pOP1nUIzd8rfyl3/IXyTL48nL77391gdv/eNdwJFZ7H50CMgEFYFUE3E4NWq1k4BAYEUjg1aNVSM6LaJ+ZFDko0VCKptWUMb0Vripu0u52cuVfPw5zvzt2HedHsjdN/HeRw4/2qrFBZxix/rf/8QtjpxoP3fpS+dfPq+R29PatACXMoBLIeoZMDrUQGVQRkaOmjRvwUeqtPEm3uTVefOVb94UVrXS1NQDNdEaKDBVgpQmeuOkcYqyQUWCUqYMkcEthk7dc/y2Msz//Pj3Gc+alt1xcEf5uM217RaMbPXltxNOlSzc033Vqnn55VlWd828E7OxGac9uMcwZPKlj6Yt6eq16DPaje+353Ca44GCVFYn+3mAa1vmYwGylkZFsKTklNLp6SUcj1nyWACxmqgsTYtTV1bGnSRs9hBvKbues+Pl3FF8WrZcIIv4B2WLvPXN0GfsrhpjNcikSaxubCBg4FQqgefVWrWWFo2lADMGBU7g1BoNrglqjOrkmwwZKx2LmeOGMiSfFDrCFRyQ59QTMzkBsvzjTzaMFP6l+Fv/Ef6e/054DeWjHoGsZg5HjtuMkIG4SUGhOb+ZPR/+ZmozU0cGM7EWFq213sD8zP4bs/pSKtGoUQN1ECXqHm0pjdVT8jEiKmG+NruqqnV666zAgBVr0+2rf/p8S2pGwNY8N6MV/GrIFF+ahfuKr94ht90xbprxXtvhk3dg6/gR+3ZO0C7B3z48sE9z+GX3O+vmya/U4q8VmXQhs08tR2qUFTCrBIIEWomE7xdUqag7WdXFyqL4i1MQxa2eUuwnHr6ffO35r0OO/0PZdwBGUW1/z526bdrOzvZNdrPpgSRkUyCULL1DQnVpCb0jHSlKFwUEBERAka5UBV8UERWwICKoD58NG8/efXYfZIfv3ju7m02Cvu9vJNlAsnPOvfe0e875HWB7/ivyG7IuSpNrW5AvRvU+HyJbi9CzoZylEKPDxbJgMdIGh8MpShQN3x5V3UhOJtVvNlmMkiwYTYLoMIkOh2iiKI/HVh3x0LFSJdxLh13cWL9io7GeMm54BxLBwEja2hYwWSAzC2QB3fbiazLaSs+GWuto2Ssfj9eq24LL1lytsC34Z4+HJoza12fWhKsbT4KUB8Ab2oNa1ZitXc8C+UTgxiJgv2Oa9h38snDM+DlTN87/VhuB+LJpg2g38y/oG1SGs628YDByJotIywxDEEZBplW70cCZBItoMoi81cAbeMqqI+a2ujkfsSY/qOoybBSHrq+YrIxM9InMKKMJ2p3/fFkz7cEu4I7mXbUVXcH0y9q+I+BB8NykDzStFHi+eW3j0fWn5s04ueEJYDg88MWonrceCOVjOpTHHEhnlslIKoo1YDVmud0eowfGGSTjthqpQFpNJMA4BEaA7gyjxMc/Si/i8BcXyySl5uNmnUnLikXejS7+XCCEh7kHSgJ4OjRLpd7Vzj+n99bVeysqu3fY07bbfXv6P7EtepasWL+ICtse6TX0rfepg3XjH1i9bBX1RN3QjauAh9p73fXClYmbdjwduhvPh76FHg3lvBnRN5yVHvQQRDOhWdBmMBiDxub5qje1mSEo0tmp2ZURZ6pdECsjgicpv/o3bIAk4tkEzfos+mBjBsmTLdqH+x78+LPoZ2Tq9pUgOLbzLYMVMvvWgXPHHWjRvkNvujzab/vCM/vI6uvvffbOmjV7lkf61IyZNOTIP8l/on85cICchfZlGq5TGAKtYUU4QNtMCBHHbaM8XgdZHXHQooxNNSqwEKwwfq6IG6DGUxiRGQqm6eTpk6/rAZMc5LhWnZ69+/beBzqdPv3wgVc/O32k6/h8em2x9taWvQV55Pprp0jnoF/fu/JTViaiaV2MJi/U3X4r5yIIr5fnKF8KjSZCQjXrpk2ESewXMdGJockJbz6ZpEAMsgfdkDj0GdY2PZEH/52a0/Ifq848AVzdwuVt5xRMrrnnSC2ZM7Ty2CVQBrKlR9TN2rWZtxY/ej/449opfIb3wL0fC8+wj2gd9sk87xM4h+BISZVtNlN1xGYTRMoHTYpPgBblXGyiV4MLav0eNlTUjtKH/uDyvPgAanRQ99RtWz+5Z85992zYePr0iHVdPv2x14YfXtPe0r5P673q9U0ffjUkWsl01rhQBvRu3n5J+/LJaujTpMC4qITeQmTDuGho2Aq9ymYZPqORI1NbZLDFJQ4ZWaDUSEFaZYTkWqTSBQ74QdhUiwdacDuRg4JEKUZywseQHclxYKw4zVEKzQJnV9HVE7r3V4O48wzXpcaEsLgdcMR9kHxA5h1YUhxc1C1j0Z8/dJvQp42vw9Y5wwdWjxgEAqXV705btWXqswsXb+zW/h97g1PpvpV9ug+bXbTxC+0n7eOUYErPsQuKisDudYOqx86YH1nbaVVVl+Kyp9PwGRkCeZ4Gz0gzFCmkZZlUQfQRhKhm0fnNTT5rLpEhZZA8lZGRm+uvjuQqgmC1WmoiVjqR+UuuH26c9VOK25FlaJcC/sRkJgFwAjaNiNcyOx6zmT4kVL17d+fFo1trn2u/Nj9R8P17//5x4JOPHV3W4+Ae0C/9SJH2+W//1X4DU6sWj+iRKfmLerV5663Aka2njo7cMCozs92IbjNuB0r3/i0njXrp2/OQrzGQrwGQr2yiWzg1jVFsottN2Bg6JzdNJB2K4nDIlVAus7NJMgMPhyftjThqxA7U41AS00v+jiMosnSXb377Q/v1L9k5vHP+ewtLe5w79ZeMzFqYGdTvFU24PnYLESDSobbPczjThBTRlB5EeCjmdMHJZGSyihsVtznSTWKKg+EJN59WHeGtemZObzS/yRTo2CHksnANNIXqUfS7OcgJDnRSQVk7AAIUdWT33En+8nBOC9si0LrucVC6SCnKcec3y5w0d9+w2c26ds2cC43V2z8wW86NKRyQma+9HU29917y3yA3P9NdUD763NBZZ85MGHfdTHbTeYKKnn6cbg9fBYkBYafLDf1CK0+QAseibjQ3k55hsvvsSNKsEc7lgrzQEuUTJejwSWo8hfZ3fFEhBfnIiDeOUiBrCmZNBPp2QdZKyQlTP3i514aWEwId2vTKmH8wev2RBWrLYJv2aRNabug1an56y1Y9wGYtSh2rGXZraNQIqCSmrlkDNoJQSeao0K3DauZOPXz4Uz02w/VqnaHfkIo0v+TxMCpBmBjKH7A6ayKS1UoZjRbkH1O+msZViI3ULCpCRKFZKboKR3uBbkUoPTLC1/PjtJ9+1sDkLy6BPtq5+Ysr5fmvfn3t/Mb9+7aAlru2kbwW1T4hBwATGPjwfeWLp94Fv9eef/rUWW3cS0jW0V1XfxibpEF7oMqsA7prKSwdTPe7KyN+P6ST12MSo0TZkvMHifxufQ6BxrldIqM0pDLxs491sQhK0AGi+2s3Pv8hCi1A+wdu166cfbjHjl2btyzZ0a11wayxH1wEC069CdKBHZIqmpgtnKHy0Yde+dc9i+dNMxvudDwZs6fVuB6sQ9gvKIoJ+mEuo9FuMnl9pGywqHBNXbKqmhyUyarn71vFytvqR13Wp5DgscbDFIMyumBycKiLCsM6+ulqZZOwfcJzE7YJmxTQqua5UaAl1aND+9SWvmV1Halnl/laprbvAKRvv8W2a9WNn+guzLuETLQKe0hCkhA0kFURLSbAmThoAYykZBKRMsHzZnW/61xR/ThKPTDJQFDhHCpVZBAYA91FW6h9P1Z7u4cTrIW+PVhJPVrXcYyXarsZ+MFDYzzav9E9CNy/++l2UBv0CCtGQJICDW2U1xtw0I6MzBR0+XEikmInYhceT0TMokzirGr9NNRWDcZeh/7+hiMRuvzlxUbsL/7uUgP/ReIuYxnOBfYh/NDidAuLQlYW4bDbAwbC0DzfY0XnT4l4PGaH15wLXT6zyqRXRhgp7vnFfYEGfCAzY9WtP07lZCEwlhTgCCLLmk+BpKuFZaWzn7nrz+9+/2X6vnbs8EePbV0V5nay6X3Xr3xqfkcYS6/asXPd6q1714KRPwHDnn7az9pX2g/aN737rNrdPX3gELvd2G7yjnNgw5WXL7zzxpuvxu6wW+IcbBd8fzdHG0x1wjMlexMN6lnprfj8LIPnugz6vQpRFS7gJUlE6JPQh+Clyshj/Mf8jzwl8q/DF5SZ4nkYbZtQ4gxYocOm/mWFbexyMgdgocTag0V48FIOoMs03+ffEzc+A5e1zDX3k4ujS0EQvAdEhCkOstY++sAK7TCkawuqEcb5s/7hQjNDSBxNS4Sk2lkGEsZ+zP7IUiL7OnwBCWNZmwUGShHo+pjxXeJfl/5CKwpDoDKUWYOuONwK5JDjjQpsAe+tuy+6lFy8eZ2WCT747vu6qxok6JEVex5Zq/2mXdNuaO8SDWt3d+HvT8Iz1AGv8Rn8/Qy4xnNxzXCmLqPw5zvj2t5wONXAMCxFoqZYi8XIUrwAaJozInQsjiJYq943hhvD5VDjaejI86WCFHIvPTAGorZ9dee1Q9e///dv9IboB2T6dRiIRb8kXdithc9F93Tj8Rq2CadYjEYTQ4tWgrDZYPir2uGqWc2iyStCA6HisouK0F88swLAPcL5bjR0tbRMgc9+jWK0T7dpV9jt186XiPb88z+S/5o5q64rdeLBrteXM59GFx+8e+cmcun1c1jOesZy7m4iC2qLrDQYkCgiNL4WkcrOcaRA30fiZSv0gUzQQoleKiM5A2+NVdcmhyaJegw9Ge9D45J0dNykpHyiwo8ecPnUtF1hmkYjs2sXLPjkn2vfn3P2gbV3zCk7cMucaST9p3a1U882Fbev2r9/Ffn8NSBt0H478PZXJ9/QXujc56yeHxoM93UY2lfQrcE+Z6J9ljmog9uRCuEKy8AZluRuzjDPw09GYzcnIeMumqT3yETvgX7nxr/+5+/gHgX2AHxONv6djjdOEr8Sai2QmUzw1I0dtYIMzEn5Jv3nhyd+fhI8AZ/gO3uLfmf/Z60kEKak7BeA/HxHr4ZnNI24JVxAmVwOWbZZTX6rP5juRVG795iXtFBeL6E6baqtOqJSVpydoGmoOiqKChI1HDhzGJ/4ltgpdOPGxIdKwfg3HiahmrUADpXgDtpYamyfZYGxvvbNm7WprJn10nPaFapMO7p0Vcsnj223VbabGQqNm/bygqlF0VxUp689l+44/szVw89BnnE/CnvQmkl1xjzPJW4jfsNZNhYuUpg1AiqRZUP8xvaOcBIbwzVO1myHzockigxrZl1ugpd4P1R8hlQDyTN2oiZSYK+2k6J9vf0x+2n7x/Yf7TfsnIOy2w08D/1dSeJpA4yrUa1XIVPDTGfglyXMG8xVBmHZKrgdcAY2GQXJWomIdbE0nLwMT7U1gMoTyYCfgCGuX4lleAIqaK2CzmP3tdp5n/a49l/tc9IJ+i8+kLFj/K79JnCYHKll3n1ve20tmAT6k8e14+1nLP/063vxWe0L+Z2AdVLpTftA9Brt4Uk12gCemfoabXCTGu1jN76jruD3aK73e934D30cniE39KV7hXNY1eH30x6CVnmCzkh3pNZEHA5aVdkaeHrMUk3ErND+mghtrW8xb+LbJUp4ka9EmQAbS3G0A1YlIOugzXo7AH384u5/P+GzV8y6rcSr+MtbZflLwbe5h1/bM3dIi1ZDpoG7j35An9QGaI9qJ5aZVnDtdwKVfC965tLxKXdqNtQnT3SFa4Dot0Ivr3c4EzidMvRBFUZCWTnG63OYJXNNBEAfizBCX5o3WgWCwp0w9f5zg7K1+qJNOZZhre/dA3HCyQ+GHX7t4m7te+3E7t2gO/ho7pDRk4dMg6r8zKXHjn5Azo+uQq/JcF2HGKWEnjvE8mpH2lTkoV02EHaD3eG00tWRJVZAWIEFiahZMKGWGXO8aSdZRGc0lFGk6W8il6pMXWwsjGSgkRBGke9xANK0A8vghZgMDo7JoA3KoNvmICz1Mhjv+2EfhD9/HucWuxGX4D9AvaZgvba/VlKAIUmv2eAZfhK//5vo5w2o3EV/fxX+guhItUgNZBzVHBbiXEFx2GWGO8waGZI0WniOotCEgOoIaSU88SKqioaNMzhDEOuyDMikRdtwmrSf1jZog8FBpvP1ofT+a6e0wU175eA5QnxtxvZeJbqGM1jCaLXSUAYIu8MoV6PW+xQY3CDNUB1hKNpaXS8DCeWQ1+AY6VXsAdRKJweKaGTa0ItSevONL6K/UFuiOaDDz8SNM/v2aW+B0L4Hwd0nLjOdH9TGXTwzf5aWPZ1o2sMX15noe6QzId2MNgH3awqQ7u7hdJWQeBsUAIJCY6tIjrQ7eAlG85SNMGDSrRz5FDDotTY4SZvUYZV0TRHCLVBovoa1TAlwAYoluQBNPLarbsuuecMnpnYkhz2svdciEOlOerZEL4Ot2gQyfzbo/ivQtmh3/qK9Mqdxn17s/MM1h1HusnBXl9edSrEEI6emQtrtdo/bhNaXYNxUwO9ivRRLAVkgBEnwC5TIoEbwmkiqACqEHwVSEFTRSHkYLB9FuJVHb8BFV0iJRs6k9FfiE76QQVUUAbkAUKj3Dcb60NHHl3/QSaJQvSwlApm0u3r/cRKUt8175ejmnOpOuzpV52w++kp2e9D65B/SILKatUVXka+3HQne1e4YP0oih0b3S6PGg2Va9rD20UJyPqNGd+tnuiOUgelMBK7CHeGeabw11ely8alUBk0ZM6iMnNw0gRd4aK+EaoFcLzwmnBY+Fm4IjCAQXtEJHJTT6fWq1REvTbBQT9Bv0FdpKm7Dm7bfYxVBtGq8rbo1T88qs+IKNajIShKVIjBuS49NPEfpJAGQU1/Vfh+4fx7gth07c6Fr19pHty6541jRY12A4fyb0Q13bX709u9se57urf1n9ZwFMzcvmDh25tylbY8eeH7n3J0B+8FF808hfLBYjyDBE53CmTxJAoS3DwyCuNYCFljARAuwsIAyLmfAHAaMY4C+ncOHD9f7FIc3KiYOYRQQgI5mcRnYc8RKSh8dkqJ/Mp3rdi3bQM+8doqa0u/I9S1JeupgXE8ZvrvxA9Q7UE8JWE/V1UpOgktoHqDrQUirQlSGc82CxcpyHG8hrVbFoqg21JjjN1MmxiyQMgn1AUkq8EdilqRVbEppck1g4rShS2a5CPnf8ASjNksBBOXggdPDH+p+/YL2bk63MhD9SBuYPi54GpqMf4ydChZq/dr0z4kGyFWiI7qTADc0aKOH4/uhFmEnkGWDTVHsBlWxyqA6IlOsuTrCKvUGWQYxXDI9gdnQAkNphkZ5r3ZnXtGojSvKvUpG217lpe625DtP0/uhnZ2jPbbKtJXrtRd4XwdXYVTyt72fecTN+i33JPdbUjTB0ZwBanGsOJv2WwZi/ZbU5Ojvp6m76P3Xh6Kmy8b9lo1jtMY9jyj/hmwNXqfu4WzBLFMST1lEyQIjUL9QKJAU0iakQAtmMyFaKCRNhFJfUY+UR3X9Dupw2YyO9VDUjizD8+pRr7LUblV+1YhumeWlrXpGv3gH7AbDL0W/6zPldlumf0NrW8ktG6h7oj7y0+v/3bqkHNIZ672EOnvwTfsWl0CbdwLbvKKwy2DW0dzMCAWPocy4jZS2goY2L0lV48XTbR59orbu9tOk6fSu6Im4xbs+FD+jGr5lC/gMNLHIbuAIQRA50aqYKehnmDnJKsBItiKUfDMSc+Pqs12okAEKHzXrkfvavXbxuW/m/fbcc+CjDPXU42Rx9OqXLci3Y7mZCHzWLMxPKOzkaMgKYTATZsQPoOBzqJqkLthQYxMeShjwkBzZA9zof8hKV/ok+hOPkwfBNUO2RCTahVOMLMszpEgQJp7kJdkMfQX4LJKpSXYWkp8VurnHgP6ablfn3AMA+n9dzG+IPfp61+irCYyE5TFfoW04lbBaTQYYTNB2B4FcBchszH2DXoLB2uQGNCn/hDLQMRezJFDvXQoroGNw4wsNhgOkAJ7Yt2/qnH0PUuLFp09chu5bXYf5t2rZswnc1zsR0jIa935boV8ZDvuhz0TbOVGkFTskyMkJNRGOo21Q9MSaiIKcllCihaRhfUXsVjZP73mFXnogiKhB31IdtRuf/Xa43e/X92hPde69/wHgOKz7K9Ez55/8WbPdrv2OhJZo4EuZoHTBE81JEm3GF1ScWI2IgbRI9f5T0yOHFyR0E6fp9M08puiFeocJxGN1uOsPhscZjMAoqDbS4xFsgteHYGAKZIqwSBa/heIZAINEEYAKUA1uBdDmnwY/AspCgXB6TjcAZIvshLupFqphlSLUSnWXeky9qv5HZS2UqsqKwWCxQHfUQjfsX5sR32n0emaDcDGRZMa49fVVCH5ZIgKJQLsMfAkOmXbuH78j40Cnrx4mndrn2n/3/Nx3Z8v9Y/ccMZMj7/3km+Uz2h/dE+2rHdW21J5pv2H1Vz+jdR+E7nYh71bCSwwOF7h4FrqxFoPBqBBGwpdi4SC7ltMW0kJZLEaTZK+JSLSJMlopT31WoeIv/Fk5PrQEt2RRQRwRhdzoxpSKdWnBs3z/+ecef9G8bffubeZzjz9z/sikW6dOeuc98qB2SNsGOoBQdCfcr6OgGBRrB7RHgB0YtT+0b6L/0s9NMTw3edhfUInh4WILACaeIATaajIZaaPdASyypTrSF+H5VMi3yqflH2XGQskywXE2eLAoU8K41N8hNojt6nUM0JsHkeUJAsVmh68C/mKwYcep374Cn5z+Qdvo3boBOLX/aG+QA90X76s9e+0UWRE9S126bTF4G+rwJXCt78J3tp0w7WtRXoT5COq8DKJfWPWKapBlVUIU1cysoMVCVUZcKXpCyuKyuKwej7dfxGM1VkasyS1wMeDAhn1UOJRIuoCmYpfUqO63tKy0TGU5geLaAWrLivt23rfmvt1rf/no8rUffv96yhevrP7xtRUPbB6QQ+dfAL9fOH32/PMvnCLf0a5r1+DCR+GW9AEs6Phkliew2+3ydrr1+IYld2O9chLuRTnuj3MSAVTPwkopaCKkW5IEm0kwpQVZt9PtrIq43YIouiojoihIlRFBbazukjzR2CnC/OjeporcTSTtiu6UBgMuEHtFrjp/fvbkpUvfP6t5aoFt9fR567U/oa2cOm4+Xb52+YhFNk5ePmnTfrq8rufA4WP7g+e1M92G9OuF6r8g7aj+C+OcIE8ZoSdVRhiRUhvgnAAV7T8q66qly9fVDYC/gvfSDmOqufj3FaJnOJ3mgcRLisnMWK0Gg2JWbCrOJIpW2mK0VEaMKkqV3DymSsLpRb6YCXAIdjsWWaHbEKpCezF9aBhcB2V7677YO6/PtDxy+kbqiPabNn9t9AoOrDKXgIugpm4A8h1WwnPWBZ+7bljfIXygVyGtAWJ2ONvt8wRojrAGAtAWsh67w+H1mE0mhvVAD9DN+WiOFv1ABHoVnLVABKLoMEmih0W3yfFACt+I1MdQySVp8elVcn0UlQ+yYBiVD6iQIx5GVYBYGAUdXpl0pZTx0ZOgr9rmt8c3tx+Sv70wEt78+Ltds0HlyailLBVcpR2m6HWyxlEFZv44oUYG57WW1pHjftROTcqL7iIZo5PW/IjX1ZD3DLoP9P5mhtv7LZIXho0WL5UO46h0Kj0r289beLgfPO8iwlBf1yC1PV19Aypt6IKoqstlhVIoESjDBuP6+A1oE7ivv4qddAXt13GRcSE6m5y+188yOeSlKy12urcuB4Y3T5544Y+lSyx7nO+cPfdl9yXdlhz+3jZvVbMBlSerJ949pN+urt1td8/ftqL9pI4GUtg4cfshyCOSOxXuJ08Uh93QlvMUyzI8I4irTcBE8SK7kgSkBSXkhuPGj8YdszKlB0jo+l8G403gl5eOcJTGnqHLo8e0b6mx18+Rm9uPKay7Hz4E5UHQ85haGCd9hfocDN/9ovc5CHImICSnhU6Kka7Anx0Gf81KdAkHeZOZlGUUJlnMVigT0PWSSKgBCiB9pNWsxlrk0YHSVVvDO9MGkRE+LXpgdKV2xuYetc9/0qcbWHpReyFtWgmUTS1zxK2A107dWhx9FERFm6bnaFh4HpyYnoKwk0RXfFajVbFJJBJOzoJ7y+PF2smlwzjmSAqLsCRSo7Xl+el9500qaubKK+/eoSN5Dkrh09oN7bdp/FLjZtAbfIXzIoAYB9dBz9F0C2cwtCjaTChTg9M0pniSJixWimQFlDCGMKHtQhFtPFnTqlWDWnH9Fq/sJvkaQ5N0TckxlK7puTXaDG5ocroG0vUEpMuJ615Lwh6AJmrCs2NiLDwwVEUKAPzPxECZSN6XRocnIMcvfsBEcL22VmPQ6peCC9fPge81BSnIm/SMxp+L4z2GhXE+MBg5GiUdWaASSVnjOPYX1rtO/e2vw3WO6d4YbkcHuhK+d//EsxK50Vjuswd+VlbYCqAcM4zBSKsUh8SaSHQHJjVpKwGs5gPLqPPa3FptLlb11BH43h3gs+7G/djDsM3rAr9fyVyEMZKD8BF9wtlekbbYaIph4MFyopGBqTzhwX1hItQ+NhZVOLD2Jp14zorkkMZR34WM2/FQLhz+k90KJEYWAFOcmSWn0yt/+OSBT37+z2cPfPt53R3Acc9q8qU77wEKmVKnfapq48FWBQSuR4HXBpZqixXtW2jCl+VRfWz/PPPCP611/8hBazUCrs1UzM/QWG/qBPphfB5KwyrJMEZgMrIm1gI9XxOoiphUAzRbj8cORMVN2rdBLCZCGwbGwAOxaW/dUWhwu1Mn6rpHPwdb0a4BYjtcvCh8KRN5YZWA4RdnkA1WhaeRLjaqCbCMRm6+3ixcX58ogz5jR845U1v75Z6Nm+Gxm9ZnQDFJwJN3eehDq8EDRAPZu1lsKaLYsiqCZP7/I7YctwtIu4C8K84PdSIuR8Pguj2LfZ8OYUl/Bi8I6DGSLMAlC+OHmRs+DT+uoml8GUrGAoSsDtv1X/ixfn39Y/WlJEh0K03fAZ+L4srO4XQLXDxOhgGz3WFRq+CRA2bouHPQGUZ16xxfFeHUv76CjhVo2RPhpSuGmpIHyI8vXX73nDZeewrUXVh22+yVr5LTN+3cvo86sk4r1cRho0cMxvIwCd3fQnpQHIewkdNFiuJsDpMZ7rDD6TIpkCgTJMpk4lSDyJmrIjZEUSK+bHIl3oCkUD1BGNTxICbqzL4Hbp81444HyWP7dKKQ/tHEESNHDNZ4pCygf3YR0pUTo6s8nILoEeEy2dRkinSC4ivUlJqbU0KuxlS0r/0PWpefkkmILQs8H4ugTmoD/RAfcXu4r8PplAgDJwsCwuJPlcSqSKpUIJ2WfpRuSEyq9DF8QUkS5REd0IA7HB4P1BoeCTUT+w3TDUsM8ABLhhrDGQNtMMRQSGfc/FK3SRCJAOeg/xWLGwPJMWURQbfRbvw6/5VF/HPi5pn3bjZqy8Adhs2b5q6WzqT+VvsrtNIp2g/a1chD1ZZxM46dWv74oYlDhS1HtY+wD9wF8rgV8mglUomh4RYKD4AEBVmUXKiFMSCLkkoIcLWJ14mPCQpKCGGiTXZ4MO20D/pXUpOD2QC4qN7wKaH6qhsyC4eV8W5VzMw3B+XXHjn+2oUnH3+dfWTfPjDg1gkTppWMaDtlBjn9kzrtDU3T/qu9A5QfkHWKfvLq1Q9eX/Ps2A8xD53hIb4ek6ee4QyCohiTajabIOsytIsOOwVNODy0NmAwQF4MojlhrfTghQg1SfTGGh1ApqyHj65Yl09rQPbUXnoV3PLfd18Hx2q/WXbb5EVRcAHazneKAX3fFqjGLoCfhg0fMVy3c9iPR34X8uNlluh4HGXRSD80EE/deLzW5+dtDfJu+s8vTPz8JAOBMr0U6ZEzKdKQ6uOVBrUBJRj/6iKMRmvCKYoQYEi/PyPgFAJCZhYTTA9WRch0s7cyYjCbn7pxJmw1Wrqlm9PNRECVoXmTPWh6XHKTU6w3s2EBtR6bKiFUJ6TauFBpyO/SoZtKHKiwO4EnEywJnXwCIbYaqYnfgBG33da7qF2XUgwrs2IFc3HH8hWtV1/Slte9vG21cQ3bbQJFY3iZw/SR5Tdu6PEc9lE/jeUoNxG6l8pCL3U8a6SJBjnEe+FaVWH5XB7u7xAIKpWXoNvPsnYH4YA2XILnlk/l9VIpJqlUykN5FCiW9un2JfBs2CV7jf2MnTZSdrsnBn0MGsAeN7jwSU7Oxs8LHriY3HDFwZXSpVVHQL4XkL+e+M17Rlo9d8NmM7hDW2bevH7GZuk5ftH5Bb/dIHQA5OMbhaET9z21/Mzh6eMt1Q9FgB+fiUcgn+l0T2jvcT8osR7hy+Capl5J36Mz84t+ZnIIvTrAhBqqbYKFAg16QBvUnUH5ccH3fwTKj4vwE4PD+QaHy+1mHazoI0UykObyw2V0QWXrcjlYB/QwHSIPAyzezrqrIqzapEAgSf9ak5SwX44VCqD1iGUpyhRsrVC1JeUFa1575vX92bZ2Y0YUZKgZhcVBawk4H/ri82JyuvbalgPUWa3zO59Vm5dynY+cIn1QVTOvnNYxLiD/x3B84IH0N2MUheR52QgkSXYYZaPX54HueVWEEQHkAgCe4KH9kPmEi1xPeKjpnUzcu9RdJGxK8oDuOseNye+g5/ZSZE/+qT2xnVxcumTB7JVluj+tlSLDAv7QjNAPaD1m7IiRSGYhvUhmvcSAsI8SGBLG705RcAq+FMbtgatKesxKQmQtUGQ9Zo9ZcKpYWEN/J6g3kdPgX4rnE00EM9qb3JaQSHy2cCyIZfIbfLbmTtIlUoESWaLYieTapkYxJtHxil4xIKNM3Hu1ksIzDXQd9suxbhymx6Q/1ffpE45Uk5wUkz4Bf1aPeYrDLqPJRNDQLSM46A96oI8GlWRDh7DiLx3CoPxELfRwtV17dc/s+jl0+4/1STcoByuZIUQ+URXOzfE5ASDSg7xgUBQhSPiYgkJzpj8TXfy7JT/NNHM3q4447W5UQRSPCuqbTxxJ10J6BgAXu+kGENfP6i/RLKE4nB+aHaG/LiNTttgrCnv279cjLzi0y+337N2zadPgAVu2PbB3fcUt2ZFA8x79+vUY0JLcoU0r7wOlGw3IcRQNmqmtgaHsSW3z4cPQj+8LuoFZpa0HF2nf4JvAq4v1HkaET/Uw7vnuG84yGiyiwHMsI0mcYKFNCknaHWaTyS5ZeM7CGVXBJLJGHW8pIdAgccfXCLYSFwUHEYp+CChUSMFYTPTsog1rd9266pC25wQwb7z7xNX+wwrp8vnrHtGGfw3u0m6DOzENPAo+q5u2HfS8/8EFUKbVWG4ByTSMvkXC6bQYFNpAe32EozpiNZlNNRERuuqE2cBTBmd9BkbvpElgDCTX0IBAPA0TRAPtkJiAeOYBjMRJB5R+uOee0+BVrYScFU9A6CkZ6otNFy9uiu6IJSF0Gh9mXoU0uomu4XQDrShAslski8drgFJsMEiEBDWNpHJWAmpMmkT65lwoaVBOo0SRPog4FCslibv0IDY6XgXNa0Gu9jaQL11+7yWtXHsT/PuPa7NX/kmXg3u1W9donx/YueMY9VjdG6+NGIfOcwU8zxcxjvbEcJnH7TakQXkUhHTZYIOqEQVvGZmOVNRyRog2sTqShpD7PDaOkq3wf5wyjGcL9HmGclKlZ5KKTC6vxkBLULNj/L5E/gDhVkDLSOqWkexgXHB7qHe4xbYuz959/mP+0N69h1xg05qzLXcHW/ctWTjLCLqQI+s+Khp5R8tzjwLoOEb3opw5OWrvY+0mDct/+/d7sbyOhvztxD0KE8MtGQAUu51NS1NJL2+BW0B6g+mpTmjM7UapMmKU7AQDnUCFKWCAh+F5xkORlN7krzM3PMFd0jVSMoNF8VuNELrUbWjrrYlBMGQW4PbtO2S58OQ9J51HzUMHTBnHgj7a4/yl3mMth5VnNz15yQw+0VKgfcj7hrjxyH3CkEmHTi7X7h0/1fJALXQT6vt5nse5VRv0aTNlEiojs4lmJA4leoyMhaDtKgV9dFThaLSYKAYYrXiuSWMlhMnHA83wRW4Q7wn8DEIiYEUQyMrMop9/5Zllj93+DEKDHmXIyugLOvfJC5C26HfoD9P5YMr6iR9+uOh23demV2E9bEV0WeJ0WTkR0yUStE2hOCtXGbFajaJJhHSp/0e6EKCoSNKrXtmwcN/stRfA8bfy+/pzhbJeYLq2Af2BEcBzF27ZVHzyPF6rCkjTJVzT4SXGh0tQSaCTQ+2hNCOb0FWhi7RBMgkbY+QZXwpHmSUzVN2SxNuslEDBIJ/HSxfSIe1DcbizxITcIjlxTZ6oZkjQq8TOuJK0npf2bKveM3Tbnt1P79379Su7+nI+fxhwFS41vqb6ukYnkVsOpqyc9eGHt4yAfIxGew7XliTsxORwKcEBlmXsIiSRtPA0QDd9vKDKstUqmBja6VBEi0FSoZdLqiolmFirCihRV9T1fCTQleqtEWQizokONAPNeQg0ZihArVt4W8ldYNJDMwZsq5q29/YrMCxjwJ9gozaN7ADjnNhmgBnaerghT8dyKpCHp3AvTgpRHS7weVKgR8PYXITXiys1FRvLMDZ/qllwCTURL+Fy2dzulOqIm+JZm36A4wWbTQGzYygriRvGFNIHghg6DVIs6N9A3QMCQAlQhZsO9axteefC5xavLq/t++h92ivUD5p4VptJMcK8f3186fLzm7vQ0XXkTKb7tpOXL1155zaRDEdPgsOYjyDk4xDcCzeMLoaGCwTRa7MrPh/HGTwqPEqqwSYyKal2RfGxRp+xKuLziTYbjLNsogGIajIfsUajUAP42PoC/gT9aQLADJQi+lNIFQQU+tCh1nctP7hodbtDT76nXaDe1c5vPtpb26r1fbvLhns70VoVeKzzfeu7dNE+sJFs9Jow+dxj1ETtjphM7MU14xnE7HB5elpGIC3Aqn4iGBR4mwrPkeBlUz0eLwyXvFmZosWd6q6OBInUVG8gkFEdCVA+ShU4b1wwGmxKqIn+T7jKSZtDNd2c0rL42YJbFKRWTJ5Tanw4UNlzX5/+wYfd7jv37AHz3yQvaLtm/0Ix/PDNL825dPmdlWF9mzquvXj50nMHWkbvg5JzlqxI7FU+5LUW58bSiZnhVmlskGEZi4ej09Ntituj2Dw2grdQgQBhITIzVKsfwROncxRFMEwQ5QuB6LHxemqs6G9Y/QtOQzpDVIPTWL+bMFAIKvm1YMVl8sKFGQtKDvl79z7Ys1fgUMs275Abf1kEZeca2jx+2GNvd+lyal4xhba19I4nunTZvi9Pq6IegxuK7V0v6AMPY78lBhD3hKtEqbSnagsq9vZhYybRrFlm2JtjZ2w9JdPAQW07VkeK+tZEchiaoWsiQQVaRkt1BOpigWpbxIh2u8gUtWW6ubu1rI607+ZOrYnY3EQBavmHnzA2mxMPLsaxnA4DD9ekIUZVks1vXGUIZRD6fmV4RBUeiCYCnDTTqw4p3AGLSq1QOBUsDqYJZKyLuawdTT2AChGfOHrvqjuOhB4vO3v/Uw/uHerrVtq/eQfZK6j8LTtqN9y19VBhvznrHrh/aut95ZNHD28+YurWHr5BU+7oeNeeAQ/u3jRlcEUQbFo5d/O8hZMXzlnW9u5H3KC/durdji17t0sRfee9z65d/LDf8diKocuHtU63yv5QzhRPwLtsTG9vmnfDgsHT2omCPaNdBPU6wVj5GnMQRsr3hFNaETbV5cxyuIVcQ4tOHTu28Oc2d5tgXGbq0zfcBWVb1UhzM3RNKyOdwmabzRzuRPd09GyNEYV6ehHSkCssRFKyHA6nO+yWKyNuKTYn80O4ki/Go+jY8uuLfvM1d+DVIkuKAyVJ1Z1/seyqXu1583Xf0m3l6hWTW2lP7N46enhkhmVP+r+eabjkQ6ffde/4+dv6HfnH9L65W8uH9evTfOgkuOCdB0/ptPChnX1Gt7EpzXu1PX/3gFt6DOrRxXahGYjUr/Yb7vXjxt5lJPn1U6tXVrqV1Pz02anpqbdP6O0L+rageORGDM/fR3QKp/lkiRAkShQ5u8ORkmrguBQvrgmWBcGObv4bYvrXRyKJDExATssncbkvFWoC679idp8uuWN2j/E3b9GlCoP7f/5KObgne/SLTyF0/3V3dk+px/f/Wfs2ju+vQtkbge9I2oVTTC6X2elkrDJ0MGDE7qRlkXBYHBhG0OxNhhFsYL5ugiOo00kiHMENe9bu+vf3O6cs65cx75El9tx2ZTvnkQ8dJ2dGN/zxuY4mWPXoK+SKaL/bphYA6gWi0cwT1L3VLZwZEATW5vMRLJGd47FDlQ4F3xP0BCmjMRUPOJEbDTiJ1aI0RmSun3EC0jg3vspiEQBBBgxOA34KIdKQiXknGBgq2rd7W/qh+9ZtlvIy24yvGQ7G5mYZtMvaj2ltO1aMHVadNANFh4s64NRuaP996xKfV5InmIGmTXE0K26m84Ww9LtB394EVxz15Wem8TzrVRTIV06uW4X62wylJ92dThkMqZURg0RJjdqQ/4KveqTpNC6lAVu6M68z1u3aD9//DD7/85vobZ3bMvesu3+NsXtp8eA+PUBmRVvznevvXiu3qyjq27MvmaJ9pn0DLbZMFmo/al8FX3vh2El/ICeQGnjy0W27UgLZgfjsFqYF0xf6qIVhJyBYluR5lSJJm2qSqiMmGIuwADcYxgFPk3LGKJi2OzygfsAkR166oHGvgHB2s6pXWu/sNjpvZF6zlOY2pnPdgtt2gmbk8QsleTPy23TAz+4P5es1uJY2Ij9sN5skiYIBkkrZLaJkVgm2X4SIN80m1xTHEez0vn/kltsdZUo7QP2ZeFzdx9q8Mz/wLcP3+2fTffQn1r0JDVo4+6VvSdPUav2eB/PO7rBm0nhWGPkG6SR+wz1vqXrP28Jar4vkG9xRYpqZA/B3MmK/UxTDtvPrKJF7an1uSxK2HTwzqVBGX2EGEzL0PdEdTvMsp9mUahWNFl4QLKTV5GQLCj3BmoiHVvNqIqrCm0TRAsMmpiaCwMd0xJtYC3ReQ5xVHbVXLyOoAHimFSWAeEkcbmqkinVYBNWmx8Dkc8WZ3rRWfTN47addx+7Z+VPxspdXPrB1xcrtkxeW7bQXFxWXOOzFhSUlTm2weRU7b0keXVL3A2W9fu6b03QvbaX2IugA5oClILRc+1L76odPxkz65ur73906/sc4r3BPjVA+8oj+4eZWOiPdROQEM7OyszO9RDrNNmuelS7mZAZVNxQQt5cTqiKcRNqrdPiK+KVtjOebcFs/2qgRY03XgRyqXdU+W7N502rMV6ndHmpRUuoAZJMVIFOir5FFwAUc2m/a+08e6d3/yYcfeWJg36fqPm28BjHMhJ1Qv+0lHJDLseGyNIs/3Z3rJIjcdAvdrLnP5/aL/uqIKorWVCtppKxWkcpNz8pKN6ZXRwhWYkmWpfTAuGB4DKsjpN/ny/HpYE0G/5GcjgCEETfL9OGfcHslHW0li5UlHZbTUUqPe/yofVBJ6UDHY489ecQxIBTq73j0iVcecvQrbNHP+eAuZ9/CwkrnTqj5vtcebtm8ZVmzUjAMqNA17F2UW1ycW6Q9rn0GFk7NKijImqKt0BbPymxWkHkr5LvNjfX0BvootHa5xNRwG4XItqd5U41Gr52g85rBzy5golwuu2SvjOBydyMFz7hkz8hIy6ayKyMcJTKpDMkwsTRGglu0EjG3Ts86hprgsFjLEMAMjcD2UI4nk1Rs9hjHOlK5vg4CaPP6xWZjRjUH2y+fbz5qZPNz7zw7aYa1Z2lJd2X2+AkzlR4l8NWcCWTKn8DjHDO6uQaua1+5RtcowAPA85cdhW3K8z2XTj9/yZlf3qq5+59IhlGv66vce0QBUQ59rtvDnXxSx04tCwvLg+Yclu1NmMvtnSRDn77lrWoivVu37tTMrbiRQSvvVKoopZ3K6a581/brIl35TD8PD0bQbDby+IZWTuBa1TtY8SFHjdA1EiehPmXZ4JoWSYP+TWlZ/aUuVJLYyQqWlgRLUBUZhm6LzQqHP0Z+4+/QYsfxl49vuWXwluMv/2NHi47+Mr7U1rX3wgnlE1JSJ5RPXNCzq1LKTzDbMyb170N27Lm+3+DZZU+mL3U/uaLNwpphS9szg31p2nLtUe2INn/qVHAnGAgGgIVpvs1qmvYuFKg67ezALl0GgvaAhB8t/A4yPCq3TXH5qK73LClp2abFh/tr89uUF8J1zkI5H3YzjHPzifbEvHAzp1zWsll6en6KheC49pQlX20pGzp0bF2yLtLa1r6goKUtv3llJN8GmVSRpytHcmmbFPAInspIisViEuxJq1wROhdDs0AAbueKCkJ43ZuuMK6xa7TEamJ6KLbP4G9Xlfp60cZ/f/vII+vGjF/z8IFv/71x0cDhbeekpM5uO3yg9sZfrySZ9uHJLdrH2k/aJ9p3/fsDBaQCEQS2PPXR16fb5OW1OUOvuOnKIduE8wTs19A2Sbg3kiDHgQmE+UlAlBf4cHoW2z39np1ZCn9Ojv1c91g+048yHAG7iWzY96wNxLiUdqJ1OMVmoGiB52kD5XAKAmMyQb/NRNMehqiOMErD0ToNG0UQDiWG8QwkH1byvvbNT3/2I+l8+MvOqCv58P7Dq8ToafCgB0wAJeTxPUfbz1iuaVBR/YhHjEB69kEbk0P3groX0iPTDsKM8i6U02U2A44TMHSnDYNNeOur75rQo6N3NsXKJDu9dhkQXz38vvekMHPitnXbNrfN1waDndAxqwM8cB25Xxgy6YXL/3zPGn1Jp2fajat0NXMF927lcAb4LNpqEEysTWWNRsoCPSpFsjBmCYiMGYgiMDO0wWpAwHv4grcgBpSdVOVaj1LDZVAM/BNUMsoY/CdE0dU52s4+YEyO9sCS3Wu1h3PAsN7a7hww8o6dd1P3bh2hfVu9tUYrAb8M3zoCqCO2VYMXNBXNI95DLwQ1DJpznhYWGLPZDo+JnVIMggCJCRVIF4sSc45jXRA6MCeuVNfh20BN9xJtf8f8og7dS8BQ9JWZUdTG1rJNuFj/gp7zDP0q6MWchesRCIuEohhtErUuIhEmo5EgCpDQXURzo3Wtrnu3rB6ol2H8ll/IkpJAh8zZE8ZNLL4ld2SX0ePpV3uEMx3d1vtt+bfPx7minXR3YhRzEfoZnrCZJghUbUgyKBF5sVVBjA347mrQhmZQtQWjIn3mBVOYi0+PmBya2Wtj0/fg8HsYDDd5DxgTYTEf5c2Y1yfCXNzYY2r55BHoYhFE32Rak/lQXyloHgjK/9l4dn2EN4UJZX2EgC4mXFgcSF9KsAxi2oJNVsL5406OnXl3l7mrnEv9H+9rv3zxrYeGMe1KWlbkT52+74nccCs05pAw1GVoh6j3mROQZgXGpVlEC6I10ZnoS+wOD2zRt3lPV/v2PftSrcUypazS19mY1TlLYYJBRalKCXaherbr6O/WLaO3SSyiyizFxXIrgsmmmttcZG4uV9CzY++yVs1dBQWu5q3KenfsafC0b2P3IPpDsXOqm6ZQ/cS9pK/4FWh4G4CuohxF9ToVYcRJoSJVSbwCf/uKusnfZSRekXUzZ45/7z0Zf667B38hm+Mv11biLx/rf3cv/hJ14S/Ui/fdh7CrWfyF/AF/ufYF/kJnJv9b3VX85Vf8Ga/9ZG0ptZP5ssnaHw+PtHlat2nTqVVHxiDKskkBgOvSolnP3n3ogsysrIIWnMnQsdTT3uRMS6tyVhqM4Y6F4eYFBdle1RUJZmSklJcVterb2yQbO3bO9nhTWvXuIcs9erdK8XqyO3c0mhmRqdcWiY2II4ZJcZvmvpSUBMUaxNGw+i8BMOZInGkZXQWGWDWkYt8J+s8loQx0KFXooAcpVFPPZWZxWSALFXrBSMtBcRhhrSyrDAGsIQxAB9fZ7R3ToSf+FJ20oNPwnFuqHqCPxF60HVRYYOoqtiqZVtcZvjR2gS9vtQxq0b9F1ynlJdOoNwcVDmjRdVqrkqmt8W9UPkh/FHsR9eL3LMaftT8Gwx/sMrUl/B0O/85U9J7t9LdH73TXoBb56EmlU/U+MG0cfYE9COMuHzElXC6TJLTZHq/JbGZ53mgweG2ATkn1iLZUW4GNMlI2a9jqXBexgrCZ5w0Ig05iAcXEJ5di0Ndzbuk1XZ6hj1pU3+LdwH1IdAqHcNaiuAwofiqkR/UhUu8c3vXMkdVTpOif72nbjfuYYZMmDmf2GeOtxNcnRE+C7dSUPseub2H2A7p3t2690Wx2kjipvUK/wPwH8uRB6LUiNOCqzeXmDAbKZGIZxm2T0aw20QYQP1YHZEcWKFkkJdVgMjH9Iia9MkY6h/MxOpDt37CiF/TH+CgtA0E5A7KCDGWI1Mv7H33+yD3zcYk/OKY9aN5nOX3ass8cL/evG69lgzJyc/rGVFTyPxeEX35ZO6PnZOikXDrU76LZ6TTwtAL/3usTHdURAdqFmoiZE+EHbaRoZ3LTXpNkuhXlw0KJ/j09kx5Sg2rTPr6HHjr98stNe/mozzddurTp7fp2PkhjJar1hDYiRiNHKQohOsyi2evjPFURVrbKVRHKysEPEYio/lMFoDEOadOMv6LTVp9ND5YkynYu1M6bByy4DrRiAcj/GVWC/sIoJ08uj17F5aAbll+foleD6r2OizD+gpsYFs532UVFgXYQmjIRGh+PlyENZgWeZbtLcdKK06nQFDz/VtQeaoqDXeOo43YMFtmgVULX4PFknA3KeRYmVe+MxN2ZUAvAaLN6yLzJ8+c9on15Glz8AVBntKd+1+b2mTpltJs6vm3mkpplXaIa0/mt57Xo983njpzSKja7sTvdG3pozWEcWZbD5NJ0MzKPonxEXm66necFIZegCvIZknO7/ZURu1vKaZaVlyeLNM0JXi6rMmLk6rGeFhU4K1ohIONY1VSrhvcGDRiRdEYS8x3RrDlVLwPFQIWxcSQ6a51HjBozYvD8a4MYupZ9FNAMXfjQ0vPnnl2wcvL8iru23dJy7tjqIJmmfbt20pCxpc8Y9mgRhn2klG4xThkzXPtV+/CT54ec3vbWhdzFQyeMwvg4gJ4LdRJHZIStDAtIlkS9CtURaDIoBt8hFzTsVtCLg6jna6N5p5nOYIxGXL+F6YT8zl/h3rPwbHJEZtgK35cBqBeBILnKCCkmOk+SW91jrdrgQC15697oHrocbIxexT5sWWw2N4/wbFmTCRjMlJkSRCNP8DURFh41szU2rLsiGV4rjldeVKTj2eo1IrjjIVh2EA3wRi1kpw+SX5PDHtTCm6KHyEHoeetjPXI80TacQnGchTGgme8ii7MUlNls4HmyMsKLhgSqr/NmT0Q9dEiQcBEZ7qV79dXaBQvo8nXalRVRjSRXgFr0vEdRjgpjf/QJ5xBut4e3KCzrs3hof4CyV0cIivJ4vanVES+qwzQapeqI0QO348XYo28Kd9koGI910MJv8N2krI8xn1p+X4//fPHf7x9+t/yJvFnjtmy8d2vF0u54tjk1MyNHe0F7XHtAW3Xn1pTqbsAHmgHmu7Tm0RwdSx73o1TAdfIjXAiPqtoNnEAQTs5OB9I8Pp+1MuLz2R0Od2XEIRoMtF2lzWhAZ2KTGhUTNxhnadPvS8pi80xxBKsTLWNgd7pi9ptrjr+R/3jK/HEb7xv44KjZ42rJkVr/2bM2frpo2M5vF65dzw/o+eyT0/cN8muj6fI12uzgnI9iWEPaBFz7kEVsDFf50tJSvcEsp8vlT7VlZcmskbBYoMkiUqmc7CDLGr0UDDxtMiFLsl+mREYGNRERN9hSqMHW4g+EA77qSMDqtFoowqAj3oX0DNWlWG09oV8axXrm4tZML5OI994mIB/yqaybg68oIVxsgDsH7aZUv4u+KQjLb11r2T+4XgpZDQwGjvwbJJY3oufBVnI+pdDR3ahfEq0L3M8MYkU40+P3+9yBDJRQ8lkzMkSaI1C3JEv4qKxMNxeg6fRYt6QnYuX8KHSkRNGU4vdD0+NX7RJU8qxK1Fvyc/GJJ4kBzv97Jf6yfzJpJVyOtsLNeyi5nnudUaGNE1wlnea/6qLUgqjDhGRMLhJ1UmJMGniuESZNCXFruA3LuD25ZDPCFjBnZQXSCVJs4WGMpWXpkiiJNRFJIlPc7pQU6BKk0AXFNZECMpckoVFjWRLjpCUhw9fPtms6wTU+hwK7sv8bhgaBW9viPXrkePXFa1UNEWkWH2uRhEjz8enUJbNn9Y8MWrqvsj2z9x8YnGb+LAxOc9viJHCa/e85FvWrnpa2Koh6SuE6oJ7SMnSbSlN2R3ZZbonkM2Zk+AIlZZYCB2Vs2ap5UVWkuTcQby91E3a7262gLG020aCdNFYF12AJGmKzJ1ahSTtp5k37SZPXAP5QFjnk5Q+a6/2l79aeeGHOskUr+D3Ot58/92WPpV2WHH5oc2DebeMHDO4Tbm23LViBek1rJtw9pF/3wV162O5asH15+0mdWdRsevsu96z+k2cEVqS1rejZSz8TB6Bs7MD4ZMPDBSTUdSYZCoPZLEkIiV62Uw6n3SqbbAxpQwg4hCCheinJyjAYCKcgIQIx56uiCd+xiD4kF8XxcPAhj2PinFwTh8RZd2ttrjbQNTULg+JcjmPinMXCvMriRrg4xBVI70Aoy3ZibLhYp5fluIb0qpBelrRVRkQSIMxrTDSqvYRSLjYgOj57+O/pjrerJtGd1LLarM/etKZNq1oLJH7xxtV6rCEXMSJcSDqdLpFTFNoG/UJZkmwuyu2xiqroMJFQ4GiOZGwkA5eckl1WUwxxKD75Iu4vNsa6Sl5o+DIJfQg326G1Li2ZVVCWhEB056zyFnixreCoti23sh6GqK32NFggwRVP7gF2EqPCIdLhcAqc1UorkHZJFBUn5XLLgk2wm0h7Jaa9gAQKIl+hJKdqihXWx+oq/0/06z3CMfKv1LYKTuzQrb5PeGKzQrzkBtBD+7TZlPpmYW0v6GCI9QvTsXV3E5Fwvol1wZW2qrxgUxRBddMer2p18iYY5BgBCe0fS5rgB21zW3maikG8Jgc9RCOk+lhgkYh76s94/Hzv23f6xIn6M45gn9AJp/676eTJTdqNy0nIT/iEx/LD0G96VY8ubIJoVUVV0WlX3F4PJFkwOSsjJpNgc6uIcBgTkSQtiDQRm0idXILesA87boaKGpLduCP7jTdqr15t2pX95PKNG5dHDzXpzNZx3l7FOEx9wlkWhjXxLI+axW1Ws9Wu8iaJISWsQCxWK0MRNuT9xS6ub0ZmPZXQe24ApMVhIfzH/qWJJf2X1tM1xHv6V3SQxReSF9RBRXfSej1/G4SZg+vce4ezSatVVcwCZ+AtFoOg0HaHYJY5EkaVkEBeUTkxMdWsCYENNh/XaBe1IxssnhxoA95PKSzu8MIz7w4PgpHntW+U9u5a7T10WKXQMNBaO3WXL3oM/GSwaEHqsdhsiwkY01JEuWqOomg0FAdqNDNNSZA0uFycxB2DoTCaoG5EaITQJYWamLDGrxaS2y+TNVkcbSuUaOzFqFsIMmoVDEmi9yI4HbL0+lCkZ/XebkjLvbgXtnc4B8CwkIQekoHjGAHSAixVkVjzjAk6RgK+4qhKuuL4azrqW4uT+s3n712d6DjXu2JjXeeAWBGr5eWJirA/tiYmnuYFES0Ix9ExhHx4nuhEvURyIf1NViAATzvl0bJPnwbvgsd/qef/weuD47NPLuEYqWs4HZjNFhJ6+JyFE0ReBKYE65TBolIsDJrEeiyxWMdj42cDOR6cYZ47gOPginalVusbY3pNXVW8zx4+fwD0TR6APCP8ldwAQfl8KarBIKQQdFqQgXoKNaYD4IexK1x8Qr9VSMG3Zf8zakLsl940btKlKiAPIEcPHLp9+8NHZu7I3GXv3Hp4Va++qSV5Wfu0z5nOWvM+2kvaMW2dtnn9+pTKwUACrQD7rexOj+bQB6/H+mQx/XRrGPMNCaupBOWBKhbS7yVgzCeiHg2M1S5EzF4GqjCdmxQMOg9ELy67rKf/pkmkJE70OSj1wVQcExXx0Xv0A9v2H43xMaxfz8pb+kAu6NbRf5Z/8Yv2q/Y75qH2zcd2tNMWUzvrRhIk0f/Gd/SPzBAihygmhoYLbcbmXlHIcBUWpaUVCl4jU1KamlsdSU3lLBYZgUBlOThorV0ZhYXQ2HGxzHIcvL8pRm4oeSBIZhYb1Esq9FYfFbf6YKQAuCuocwZdhwCcIXOUysWZ9I+VY9oOK5y0N/pD3bcL+/ct7X7X/UfPZPQdPHb3umUPjhicWVjRUXu2becu7Wa2z27j9pWRZ0APMKZ0RZr2ye/aVe03uT9IOf4OMGnfXzmsfTZQakbdUrtx3Z+dDwLnlqd1jH3I/3a6F5FJFBHVYRXy7xGFoLMwKxAoFDxGJlScgqfPuSMpKSxcAzR/Lt3BOqoizmBhIU2TrP3/tAboQoioXwOcDCzTQZrQ3nKOojIqjoHkaAfo7V0mD+k3aN7X2vXPXu0XDufmTV25b3uXTl03zp2/fnVhp8LnyvILiksL8kuCZRkZIAANowAKPIttP7908QrV58M5j3/y0ePaH5upLHDb3LtWz554trj4aT3XOhhjTGeijkfCY3Sa1YAfepV+1emQPFxWNhtgA0afL7064qMFpSYiGJ1GI1UTMSqxJjPpxYaD3ZpoPr1AwEEySa49mkyfSSSnZkH54WMINXqp9kc8rlHBH9r1pEQteRDlZBF69Om8Fb1wRLO4sj0PJoNOibwtEZsn2BLGONnEwnAeTzgyXekcq9hsbHpmCsHm5HoDVRGvN9NBKJJSo6DpwmcU1kgpqMvQ70nphibdSFURR6wHdjG3nqO4MPyHeDNsXhIKaR6+BqhoqvGVJrle3BnTOMDJJJcB8td/fJd6Rloy96FNm3ZMWSc/Zz2zPhHXOD79We+KPbxVGDrxxfc/ujRpqmXpCfuizrFwprKrEaToddETED4kYSbKwh4zAAaWpljKwhMGowHZCpplAQxiE1az6XwoELdQJQGVfGnt8W1aZ7oYKrg/kH1ESMo6Jgl8Tg/c+9Iy7CFp2mzkWCNr4Tmjka6KGFUKqrpkcBL8tEaDqJBViD0LA5XM3rtShyp5B5lB6kgcN/IAxo1sg5/bGe7rqhhWkJOBMmfheQNAMz1EijAYSAstkl59iEhiCi0e8xA3hKhXFdgdaE5PiHymVmt7AVjk4qBFAd5XUPcjXR7tlffU9Mwy8gJ6Xuz5hEB0CgcQrhQvCOgmiaYZRpQozsBBTQgfzPCm2FUq8j8Tl4ax8sH6hGTMEpYEMLImlQ7aaGOe0caBcm0Rmn47+xJ5dSsaeruVHBvdQY5uwLOCZrpAGqzQeWcImjYyjE0VDFaTiOiAq21QmeSKW2urpHnx8aatHFBPQf06gHba87Xa8/BL8nqs1v4NUlc3WBG8JnDvX8K+Wr9wnigIZrj8lIngabgqRiPHsRZWkgmKN9FGIFAWKzoT8Owle2qOhghpDkxekQ40gBYGnQojgP+HyHGg9yWtN5h+V22Jtlpbcwl8oPW+RHUiQXRR9GMcG7eNvkCeJVdg2kZA2qZh3w36D/B8cAaDkWApGrpwosjzFtIiyVDO4erxooj8GZWj9c63+G3WTUmLQSDoxMXoI0drzz4PdmqzXgbNQO4r2izQfszeLPCM1olsRgraULA/+qs2EOOcoLtJHe9UJNqHA0azmaUtMDoHInJvTSzHVkd4jhLNNHRpSRrPb7vJlPt42TQ28jr0eRwC9YamkS9oGrhLx0FFcnr9D4yECggDXJPzMWyXNCirIs8Y4DEy8PDZBpqH8mrmVVaEvpyYLLI6DY0frsSfqkPkBAzkk9oN8CKCyflMu0GXr617Kw7vQj2qn5dqhC2DY6N2Yb+BsdhsolWWRYZS7SaqGsZxrNWGei7ReHSKqAgl36k0vPeG8YUfT1XUQXT020KEzaqNw9isUFshdFYwNY7OGvPqAbEd0rAe35tAGoysSBDQybBZWcrhRECFFgshcaIK/zbWOq1nK29CQyAG3BOqnzWIY4ruCMGnduzIrkc61G7cG8PvQXg+AYUkYnA3SZi0DpTZMxtkihJoaGrsdtpAOV0kIzDVEVmAsawo0JTRYbUZdYzapJ7TppNPAMuhkSL60rQG+PZAh61dNX6hjNaGWjh6DUKu9Yu/fh1bHfCzZrf4dADbejwjF9ErnAWcnCzTViOUF4vVSbk9iqTSMCLkaCtUe7QVirZL5LHQJBN2M8rQKiXokTGdceCjMSOnT43U1o4ZNT1YGAc/AoXau7JHR0DKcb5/jtFRkHR85dkYy7cg7EBIvgZO5KwKZcZpFKiJDaI1BubbqhHkTWw6QBBPa8JgKzVJaL7UeITmG71I+r9sEc1lOsd6910YE6In8gtvfA39wn9A/8gHrcGIcGHA4WAFo1FifUSa3Q6VS0amg5WgBAcks1nywQ9KUVKqIwpNuW/SXyCH/mIfsWjrrcKo/glVSNgcbgSVGsfPAKjBNh/Qi6surv/tF37uYnmHfYRw7VPwdd0vpg1ba1YUae+vW20mu5rXvnvHNFAMWixfXN66ddEoCygCraNdK7/8ZMAg6p6rv37xA/J3AeRrH8YMwXzZRNECzZ3DwnIpPh9ngXwRvIOvjKQ7ZBm6uazD6HYH0A2wEUqM0f5/4QvEfB8ygBqh02LctQYYCVaNlSaBD9asGLnS+dBw7ak3v+L8N+RH7AtY21fnwOlTwpL5c9bQ4I9nzg/u2/wGASyA+LZtu9ZF0//9XfSsc/XhHY9tI/S90l7Fe+UnslD/a7rbbZQtFsVIM34iw+UiGCOdneM2KsbqSLoiCIoffrB2e6A6YqdZH4LrRrDioUv/k7WGm6bDnP3Pfevy8Iw733vP8rcbN2WqoF0BQQluX+rfbB/aP+0C3r9U6LlPDbe0y7KQSRAuwWRmOT8M08wCnZVNiC6o1TNdiuJi4YfF6w1WRryS2RI2WixUFRrAifU9ymr9f3Mc306WgXyn/88N7a/9ulK7R/rrHf3Krn0AMnPAx0039SYzYPBMBfZzayZ1DteSAmCNzdfwM5mASMtm3A2wNTBeKPMf+PNfJH5erz1NQ7Wn6bmsp0Ht6QFoqw/iO4h+4VwixW1HIBC+FKirU0wOOi1IqG63Wh1xu31Oymx2cJxQHeEcyYnb0M1TQRgF1k7A6JZNjtvTA3onKL48Zbn/R9qbgEdRZQvAde+tqt6X6u7qLel0Op0VyNokIUFII6vIEsLaQACRfd9X2RUEBEQUBJFdRUQQiBhFwWXEBRccHXVGfajz1NFxXOfpKHTlP/dWdacTwP+9/5dP6E66655z7tnvuefgu/6Dcm7/afcTP3Q41WbjzIdPKP9SPup3Tjsp6NcXf+pUvvzlWeWbe7fdnVHf/9vP33+H9RhWjwxmlzIcXmVzrKq5MDc8WhjKcOl1gQxdhsx5XeAygoXLzgnRygwIXb1ywE2PceWrjnEjV/UGbXHF9VqnuW3VngCJlKCb4wfN+fNm7Tx36/YZL922sqFByw0Oyv0C4ZH7v1nCjnSfeWrFqXolMyVHeFu2W/mZ1kwqtKaK2czO0SCyu2TZ43HaHQ6f3muHYMZOHCaDCALtkWlccz6S7EhLL/A4tBPIqwYDVDjSUEitMiITlReTswH6xnrmdsIPPPrs0Q13pI4HuB0Vozz0qVomxWhsUl7jXwEae7ie0VzeaXLKHhBL7JZlr88JXpXTZrDSe3DgVBncWK6LYa1D0Pm2yb4KCaHSups5wacysv7zLWAksU3LlfUdo72nD6GtOiu7Vobb4beOvKi8hirJU0of5e3dvS2rDDPgm3rUndY/UfjuAh5ow+jWK5ot2e1EBD9d5/EYidHrY2GgqOeJJBGLxUXnpVzNwaldOzUKJjOpLbJoyZTq//yo1Rzs3JSSW/1BuV/ZoFYbeFAehe0cwGZltOsfzec8FoPHYLSKomSUvD6OcxldYGJc6RbaxNOCLBajzWQzylp4Vd8yM1bV0uUQtAnLzZCqs9fQEue0qcsXKb6GBvRVw6WXT72ZtXJI75NPoodp8pGlX4VLyq937NDy0SrP2bju0TAEWtRjNEKUaREtdomFMwZs0hHRgS3ggeDExOUWPeZbaExnODULTcjYDas0ku2j8d+uFGoBh3EqjV7jX2N+e/9oG50ei3pgX4vFagQv8TqJ6LrrJKKT++hJzUSzCjsWEs8Fkpx58eimzUAejRisiC6Zi6Y+fCnz4aPgP+udLhe22ex6u+xmDeHNelrIyI2OORw2vebDa3USLcrQtEE7rfx4Gkx9vaHZjb+3YR/qnOrG/35GmaTqZvDjmZ/qprMCOTdE/3aI8NwGj5enbWV4k95tM1kHxCwmoMObV3f9b9GIU/NK6a40d+OkDvyyg9OaG3JSB/7yeWUSTkP9RyT80VUafwS4QdE2DiCF0SAHwPhinJ6WJttJRlA2ChaLZDRin0TsDpx2FZs4Wk3saeE3w8Y4K3X0siEpRk6tQ24la5HLmKergExFuYfWP1ydy+/719Pp+f6w4enPVjBWIuOQLRC+d6rSG51+bKHy3pXdQnfFM2D78Pke9A3jLjpz8TWW5/dyfaN5VpPJrBMlLwgexhCLSGbi8wt6vctiM8sSp5OxO0V5tRzAeA3ArzGGEWAevSnjqlGME5gGax7ImNrhV9ViYL+RiZ0HUn+8f4r93+PIpdkZiOb7q9YcW4VczEk+XpfSh4v1rGd9tbrRz+Kd/2I9B0tYz8G3GyIdbaSFr6A+u157Np0vx6nz5QiWhVyCOaekPj9lvpy6xtLEGtyUH+jtTIIraZvCxqY/N5RHbKTVd6hP8hjzae7kEjPDGlnP38Nc82zEPdpsRMDRxfqHmdkkn/802DzNkxSv1VsR7zSqNEkDRI0Zuc2dFeGzE+Gz44XhdhEN4FL6q9tF7GfvJ9F71OJaey4agKi/1AfRwdqMBl5KA2Bxs9AKn2SvRvoMSgOkfSOLEgFlZrha3mlV6bw26cMl18Aoj16E5XLCqhfXimYX6BrMj0uugVEBvQbL5eWoflxyDTaDiq3xirZGQWKNErqGs6gdyWm1Buu3ztb4Sl3jP9o3iugaYrs2JLtFz8m+8Pm1wirOT31FnoDEOJ0Gj8diJ3xautXlsoyJuVwS57RLdgjsOTp/J2UUJb0Jps25S3G2UwpmWsyuQjTlg7RpVQvfUP4zJFEbVIMar7zP65XKt75f8a1r/5m+yg/7192x7R60efdDymzTxyfXXJyv4rcE7G4X2i8ZD0yZGTUqMTMKb+AwyBv1jW3UlwYzo2/BZ2pfu7pEXztDreZJ21jvdKm5q13y2WuTc/NS9lhme+zUnp5Cf/X5S5N985J7LEvqNyxCiz2eoPKqg57ZtOLVAJPXNJ/ItVqD9fJm8lrXkleDjFcDaS2+kdpXgHbJ7httK9tsottq5UTO65Nto2M2ub+8Qt4i83RKCjEYHKy5gHl067nlrY1x6+YCmU4IGJ00WGzVTkDhUNgVv8e0Z8s9D5jwDHfr9gFX7kTv/eNbvvKzf6DX1J4BWr9y1pvKR6f7ue120WOzAcz+NDftBuoG18HtBmidtCMYMV81ufya0CbveDsQbb+rgQux7U2X//WPX+P/+Pd3ivveLYb4k7ot927YasE9zetxhvK9cgllg3PqQT7lm3jVMy898xIZ9tjjjz/GtdhDOus5dQ95EhRyecK12pEWe8jvTN1DnoQk+AYKBlK/kZhny3jxE20NWbtDH1bv3Tc1hIIua4vvsJ7HjBfj6hq/a7yYQ3mRhEO6lmuocx9HJeY+psiSG2QJebypcx+TPR/rEj0fk7Lkltinm3s+Jp+9NvFsgD+SkKV0ioDk156eQiP1+UsTz2+WpXQKP/JrK7SCf3dyjX6oMrFGJl1jsjt4nTUSfSt1eA/KSX6HrjI03Ze6CvsOy4EyXD7QcLElvuOj6xg9sq71Oiw/yfbiVxWX7xLfoKvoPbJkaKGXPwV/ldaWG2iPCQ4TIugEndFEw0SR0GN3Ohey+RBMq+9mFTc52pmUHEJ7N57YSYum99EsMquO5uisFXg2rSNnzyYCRFGcnjOaDBgEySbq9WRATC9f+9koeeRFy8bnHbwjedylzRlgs60YbT5qLQsZTBbS/YK7FW1Yz3JGm8stZSEoqdKj97SgTSXs2QitFq9MtNkkjudlo+TBEvGnEafLOSbG2VzITMByud2+0TE3kSDikRx6iHX06dfqcpuaK0oJetQTPntIjWY7IbVinlEWHVJGxpSvOt5U1n3p9EdZ1T7+9zalWvlv5UP7Pse9C/Et2/AAVo++FOD1s9z0SIjFHA4X0em8FhfHuwBe0e1xg+ryeFw+H2yAz+bSsRZDLtlkhxcnY6arAb4OtFpZ/9UAqyX+A5WvIjeVdl4+OlHqr+zUgN26JFnznw2wvsnq7XpH8xw2p8nk9nhlzuUCD0Byejg+PU32Omy85HbS1pJ6sBHpyTIrT0rCSG0JqF4fEVJPi3PzUg6i3Pyb+1Z2vKm6U3nXXDpfSjseQ33UQ7OGPgfn3WPfJ99QkznkZmxTz8niTezsbNksCu8ygHcc6+3WNxr+Y3htkkz0jKT/V5CLEEkFedzWRQByh6rq7BnnlY9eRKuUra+AcTC/pmxF3Ybcv+xegLhLWc6IR1FRi7O00qXa+aM6SxCs8eBoW7NosBkgBkSYcDpJstOqTKzjnQ6DaLECvxKOHlDaid7UPLO+9WlFM+CsnpGOPKQ8Sk8gETsoVQ8hV6BRyiF0+E31GPKwcgCNVlaqR5Gv3B+/i51DzrsfVzG6Aoy1bD7EiGjQziOkAx0hmcxGi0Ey6EEf6c0SAGlHgijQmhJzzGIURWLS2zgi/zGgyTacpSWhJIQJmMk65RNK01rlDVSinNfo+jKqUF5Fg+jZJPryHvQiJajS+R7Fz/LIM7QZZGCr6AQeMyfYbKDSXDIvUW/VIBqs9PiWns1d3apVbZPRGUXYLZ+s7EpXCBRcljhj4Sdbke+c0v47Jf486vWLct9j6N5lf5qB8e9n/vKigp33aP72l9pZS08Giwls0ONMN2VzXaNhv2zH2JepN5kyZZKTKwQcgTExbxb8b/Aa7FaHk1ZR0hZYVc1DxLRKm2SvYbW1Puszpdbc5Ja3z+6ItJb7FFY880DnLl2qD6zd9WR00J8fexbpv56rdJ4wbumyJTuPC92vFN0xf95a9I5S+vYzW7b85aUXv1L6L7tr3UpUuIfBfAvAPE14gwtybWgf0EyBs9vNuW6fL1cgbduB1+PBen1+bcyktzvDmKbfOexO6ZScyLm1hj0npdFGJE9qhUlunoaBnWJQXnnojnl3LL1pQhbGBzpGGTIT1+UqF7v0HDjgQM+udx8CGSxA6ch/Y91stP/yI+vmJlDqNwRt/vDtz/6M9r6nyhcP+BwTYoDN4GhhGy5bTDM7XS4QtCAntm1nyAxmBsfE6MGJl3htsBXONm0IyQNRax4L2Nx16qo0OLCLVvCvXnlogVPr2xF8zZk7jrx028Tl67QNum/99oO51StXjp/Sb05bfuLyeS/uXbYr6Dm2oXmLnn/ljkX3Tlk8bm6v/io+BsDnKKsFAnyMJt6e68kIBj12F2cSC9o46UCx2hjEVRlhS9hfGwu7jUaLRVcbs9j/d/iglLsMjlByyptHS0QmtqsIIX2ir1wRuvnwW1snrl9lMFd36lgFiK3fYDHsRz8n+sYhvHc57RRnmzb29tGz16uYPXhoykgA1g7+x9OwP1ncoGg7m93gDmZmZgUCbh9vF8LZPrXRoSA4M7OyAqNjWQ4bxKRmeh7ZjE7qpYXWUSf6gxsqAe2GzowPX7j6PsqDD+1s2IFuWbml1f0Tz7H176nFtYibCLB3Z32Kh0QLnS6Ln7pmHOfPMLgA9gyjgU16MQoeVoBVG/PYqbM2ICbIqRVLV9+2ibQY4x3+wxsm5K2FB9e8/mLrmyR3bVlDHbFflq6+6vKIbe8Gmn0APjrBzoVujGYafWl6n17i6MyxLI6z+XzGMTEfyXDZXEB8Gz1EbFEDmOwmlrhkmeB4oGaLacXOkCbnvO3AXTu3b3sy4K6Zu6g83ZlZXZWXWYH+WXNjlxrSTSl9p/H586SnMkg5pjy12ni7rsteJOO/XilatXj+HYzvbQDvVtYLtCaaieyOkM/vD9n1fFbY5xPtdjQgZrfJJtFUG8tglYst4W3Rt6T1qIJWqqgcDzue74pOvqV5WsHfq1SB3XonHVbw3ufjEsMK4lVr5yVE9Zk3KJyTAc5FTOf3j7Y16nw+8IzoUQVxQKhqGRNzO+lhRa2I9olPiFiURInoeUK0aivQ/InhMS3n7rQ8rmgNcLXy54MHUVFC8W/b2JyAT9X3z2o1T3TO6ELmg94Uzb0KxtqY2y0CPYtFpIGnzl3UwPu/Q9dWudTQgEINmibfvl1NxNPEfLyqWXWfeyUxI7o/mxHdJhkb59NcIg4z2N20vxHQV+ZuiAZoAaBstsk2t8dicWCHYUzM4RQQRto921Y8kFoYqFYctQIV3aesIs8qq8ZPnjLxydfOnnuDlh5d+WnHujt3oiNK9zff+4DV0aVpczUYDBjiDafR4rS4PeCtcXbQtXY3EEwekFoxeC0YnEkIOqGI1ilGCqWRfOX8/OXLFz35z3Nnv1HO89Vr4vG9e/bsPf/18198eQ7najOuAIb1wnDVDmQSj0Gy5+Tm2tNFAwE7IPoDfnAu/H6OHYdJkoXPgVg2rA3MToy7bTXlM9UOCFnZtLMFreClCodvrvvsiGStADTT6RF5PP475Yuj27esn/+3jbCDPU5GHlq67oHHn+zZ8/XnT+1GZP5DMeWy68tnVh50Zd23aPKhEYeOdbp91uyJ82dvmrV84QZk7/vsPtjn44BPF7rPZAKnnpMOZTPT07kO0QCy2z36dIcjQx+Q/aNjcrp6VNp6cHrbVL10zRPS5nrdFiPU1WPSD3bc0zHa7sbbrnFQ+nv15l3WffZ7Oe2sdCgfgP2nsPnMafSKT5qTD2SkmQfE0mwShHCSG+tYdIFbBmzJvkRCIiyjh3utD0n5gPJVp2i7bpXVV5+TrlI+tO62dx3Al7U+KVXj5wnKMn42k5/2qk/K4s3e8H5Q85kAy9WrMTqdddDIZs4NZ/mAw8oKEm66wLm4UNQpCVar8RICpyKKatEYxCM7V/xGfX0ZdeepJlVtktYQuTzCDFJ4Ym5JJG/cjT0n9uqqrCiuKCqqKC4dXG8aNcpUP5jm89AhoR/JE58FH93Dhbn8qFs2GGw2go6T70kTISRqsPQiaaFGVAeK/I229bO1q+pqLTkTlMqU17qU1+hQUWZWUVFWZtEXiRdzCuFFSWZmoTgzs7BQ/aH673H6Gn5H8X5X6Id/F6/QuRMnOJEt/QZtH+WBP+HKPPiDf98N/z2xkP69W7wyJPkf9ZuxC75/WsMpK+o0tEbHJqeg0xKXVPixByArKQ5nFhIAuaQ4lFUkTs8qLAQ8KLj0Z0WMhieBhj5tvTRKQx/x/vGif7L/qeW6cioMwJZ4MVCmpIRSJjNUTEn3yszmxVVgiorQDOUeoNdLwCfGpmOcjrOe5ng7j3mOsgYNlt0Rmar90jkTHzxSN2LKlP2b4fNvC8OwIh6GEMd0giAG1puUvkBX5f4dO0Tu8OHDdB86CrVkq7gG7Hxm1CKlc6Z0+GPzII+2J/XqHT61DxQtTtLlqncMNA+1fV6lhhL1US+k51anTa+7sWxQUX5lJn0zbUDnstqKolKxKjcn6u6Vu6hLXcduVcXsTf6CLnXtb64poHC8BPQ1iisAP+m0jQ9S/DQAEt3t3DLePXvSA0eFfiMnTd+3Fb7zMtBEbPqKEzj9CcQDOaiI5FVGdETccvLklpPKioaGBg6jJ+Bzgaaf4NlOzvGUThcliEgmrjgC2BWr6Qbq7wkp+0MCR/ZMnNfEJXambtOBKZNHmrVNaQ0vCRKwfyqR69VNp8330EuP7Z44R+h39/7pk0Y2NSW+Yxf5dykPoyC8P8aeYePcUYNJfY5efVDZm/VlzY8Kaf/iCUd3T5ir9FYfvOXA9PGj2dOpmuFGCh352boCeFoa15arBI1i9xFSXFyACpzl5YbaMApzxfXUGP6p/ioRzwPWyK3URslRLSNoDVSytA3XpYzUxi8sj8VWLh/RsWhY3bD0RZX5+dU35OZUK++mw/vi6pHLlo+ILV9cnZ17Q3V+bgexLrZ82fDhy7zDBg0r6ZjfoSovr6pDfscSeOtdNjy2fHksv0N1LvwMaDJb6EhGajjIUaOvGPbKWWtABgr5n+rL/hhmdAzgWn7biOqSIYOGpS3skE8fnFtNAaC/oAC0q8nvQH/eQc3HvgB7YBZ3cRLnBRHmeYONFj1rrEf1Ls3tsbVodk9WvQdiHjo0yzNunDFUkivuKhs2wTgB9dlgLqwsa6HTaT85J7YKwiUeAuMoX8uP4XneYWScV6/qdKCyHC6nHd8icsI3IeGNE/t1HJcXKcmdOOGIPHKkZVy/0tLykpJyVp8FuuAQ6IJPgO+tTxKgGWaqAEgjSKHySDkxKk9/FFZemfK2JiP6a8qIfktDw5YGVUZS9Yv9KZ4jdsrQXDHjwYR8ECPlurot+6ZMGaHyL3znGPuOjfNF6b0Gk/pNG22b96bGY4mvh7R/8QT6GHT6sQcTD4O/pg4HGF6D5+Gm/8DzzA1RhJCgajgklFfm5cg6gpW/bz6CMrYoJyO17k8jfXwtZOoig6kV/zhpBZCvVod0zfzzB3xNgmnDBg0p6zDituWxoSsXAlNWdyjIBwauaUeZlfIQZdaqPJV/YH1tr2H9v7K9eRng0Yungd6mEzxK2rVUkgv9KMmTOmQdfFZ6krIdwZr5qGdVNomtFNfRvaS4qnsEa73J1tZ0N7x/m+G+RVhKOgHu1EbZT8tUdGwGxmytLGALkdmiisyI20BcCjpU5zWLC0VVFRWMPcoKfLrpO/ZsT9Rs42QUlffJWDYQtgI1ssJ1jB32FKsuQTGYNqpBC8eyt8zKJUwsJ6AqwG+btgZoKq4jlxeVI2lpVVwIRUP7QjhUKBtseQYCS7I+fm8kXBXhf+Gq5FzPhalKeC5fwgtmfecWqfAWod6JH+GSzFARRWMMgK19vijVqfle+xnzGqiNIGgI4DMf8CGMGwNR2GPk5Hwo6tvnwz6LTiMcUzICxEeV16EfGoJ6VbJFUnyFA9OnR5upqJqllDWprQuC/pFYoOnhAiga2BfAAc3usVXV/FMYVg5ff+2XZ6JeUw+0Xl35ds706XNOtgYAAZ8cAj65EfZQf4KxRkvOa2YF5Sfty6z2Gh0CnVbQ1I3tvbWBOqj0y5E/8kPRoYTL9lUSrH9rPltWkiTU/wWaFCT5CvYhLclQKQtdzcN/4PRmqet8lWCUecUMlMxilbPVxemHjlM2YRwO8t7kA/ldA/xgbiA6UHBUJ8GSNPf+EuqpPL1sSop+XwN7KD6BueLmTcKlM1DPKcqh+VOmzKe0Frz4tNBI8YpaSX/DCsNew9sGnlOtZf01SK/CKEwKlqpiR5/xMPjRPZgfTgyNaCDon+t+75fE9whaCDQd1PSDRtO0qEW22dLSVKJqKqHMoXJ2yrM813mNFibk7MEE9fYlXozRBOsmVVeU9Gp2yyn8eDY+TawAh/U04QwlBmxQqXo1CpTr8NlwYSF4+4X0u8XAq3vYfuhPcFjlVQiqcPFM5dClS6p/0ItfTNYIfeAz0pOYCGAa4XMsr6AeUaJeuGP8ZaHPu0yf9yRG4QR8xP4UB9pXDwo4sRHJPRZOTKFr+5Qx+KTuA/is8zRHCC8gsJnFalWveo8S+3YqYwwLf1mv4il0gb3+DPAE3inW/KHrbtTWxEZp3/3/sscY/QCC+RFfBTDqQJOYIeLQEWLQI14AF7UfV3O+LJIyN56moght5/nDP//5Tzock1jp33R90QPrn2Y6gRiuqRPU3REn0MWz6O4wuJUpoEv0/wtd0piiSxCAxpHD/AXQuu2jRtFqtlltkp3XdTGiQVyM41Ff+I2ZvbZRNFIzbKzKvn1nxJIuViSz8+Z+3e7Zf+TEzX0z0YH4w/iH0xeGH7lh4574d0dgrU0gB52a9nAGkFUdlVUh7AGHrhIElnRqcE63n0RPvLnP5do3Vc1l2MFRfwZg83G9oxlWn4UzYWQxCyLinC4XJ5r5NL8JW6l5cJ0B4AT4Tl/WA6aqqtXwKzXvwg5MnRFU4QQHw4pZIw2sI2FnZ1zZ5+/ope3p7nMe4w23TkSTvo7/0LY8x1f70qCsziP78hfi2+5C+NJHU49un6CE8ZtyzYSVynS05aFtsaAKK9CRX8boWBU16TmDSRQNkh1xZxjtEOp7SjQajOo7A6Nki6mGjirWODKU6faBcxsqD9EBqsvQYuT67o7L7+AftzXyoSPfKj/EPzpyBOedVuvigefIJ7BmGheNuvQunUv0W6w6UbQG0vUuV5rOehYWSuP8bNE0SptEnW7KVWRH1brn6dSNDOxx0uyzDYUrO+MalFeEaSlcwy2Tu1W1P3Z69qC+Ze7Qs1nhHgvG32gpKOtUtY6/EOx+12dxEf1HvmHBsobTpzcNDTgix+/scETrOdgDYNNx7Z6CDeOoLIAgnNIRnpxJ8pZGhUQdt9rFkKpvcrQx3pW37QKsj7Czv6XwvDp4HvUPyqNWI4cEnkeSHWOTgCieJk5lWVMqns1oskdH1MG0IUpnCfV6+mlibLzvKaUQ/QXoTAJX/o7fabyfklmVKSMs/BJb0/ckwRgU2jPwcEJ3ryapfSJSGBuffpq/cJnWfKBhgOoe/hPOylVEXRad3oyQ3m7DZguHLFZ4bX0G9eH07BEUvgRnNoOJ5DwrZrfoKipzysme6R2LXI0DblGO8L5zOcGKm6viw/GeKbdnzj3LeGAN0KUPwGjhCqNGQbSYzaLNahEpRXRAYkoRXZIiqb0nWddUoDbluDDZtq1R+bkRvQJ0eBq/c3rX5Uv8BcpupXQNWnM6nL/EBbiOUbPVLxK/k5BghlvqomoGN6BEd5PTtoBD/Zt7xTenFbNyWSm6Os9D7aJRznoRynYs4j4/v9fYft7k5Zujw6ZOGN1v/foHb57ypet/kAe/G4+s39ltzKufX3yhyxOdFsRfV+LK3zbR/cE9tP1JixrZBtmoFWmk+L5Zf/UOxbW6hjGghz6C75m43NPAmkA04KAB1IVoSS+NXDQkaWYb8hFlmfVMNJUVfB0wzDfKd+y5R2EvgvBciepSC6EDgp0Oq0XTpVbKO9qWkNa6VC36K0DlIRrVaotJfDD+pvI86nb29FPPKc+iKI7gQfGjR979S95f3j0SP6rOI3+XzxNXga6silpAcfMWo86ic0icvYsB1XJGwIYuaITF9ai31jY0ktoEtrQkpyLbUd4+zAoLMiU7RBfmc8hx9zeK9WnUB21V6pRtB3p+yDWt/QiPUXorDygfK87VIJMJ3hNZlwCjHgwt4qw2nLAeGBZFsKyqAa+BcQGSmCRKTN3xfa5UMg688j0eBgqPMiCqu7I+qe+sbL1LnJ8bGpUF2Ut4j9ttl3Q8L9HqGa/g7mKDJSVq1DSjxQFrCtq+CkkQ2HRZtTNY8szDQeepozKHDzHty04UTAhsA50r5+mM8BMfvRB/GO1tN3rYkt3R2edXSO2d31yY3/sQf0m5pDwdX38EnX78woj/KG/Hf8G+fg3FaNWFRRNVPQLx4LX0yIBr6pHfWLybA8yzgtmTMuBt+ImBSHajQaOskVEWX01ZT5VKVxUFdrxM894rAPIDoX69nziyb1u3I9ixb0PHI7ELT2lz2MfCOnaIgLpHHbxdIsTlsqcZjXQUDy/w2ooCrGjhPOy1JSHfVw3LVItUKqhFh32V7VwoE0tIlFjGoDNinD2luqABl6L0K02c8ovy+z+Qrts9Dy7e2Hn3M3jNop/aH/lZ+XWY8oTyMipEPdELi5TPy795f8Tzrw57kt0H6dF0iR/F9F0ZQEsErDcYMIiVzYoFwlnOAM/rgbR9WWmP1KKTVmlJZWYlAvPvkCJ2zAs9kGuPsukC6rVp8fOvKl2V6Qci5JcrwyagI+h+pTj+78suWG8uyHgPtg+domYLb7KC2bFKdpO1EQ1qiJlMNoGqDpum+WwJ1dHiLgxzlJieZWpEAgMv4W5U1YLW/ee/lTrG6pef4OtO71IePoKPwbrzgdeHwLpurk/UIumsgt5tteq9HkEPC5+OCYJkMCT2xkCZnnOw11IKN7QsIGIuBkoCEMrkYINUjVNOdj98kkGC3kEWREDrjESHz53GR557hgGk/Kz8ow40z3vv0T2YDjSpBNhkauNMlFtFkEJREj1u2WRCdpGyN2Ls3dLZSLAII0QxioDPQV0NOs1Jh8c2Dl097q+bh7bTjZxUbpKf9ztfuwSK+sC8d1/bdemRuwZ4atct+4/y9fsftaMw9Ab6dGO6tmfUbTSZiF2UBOYSgM61iyIyCmAHTkkY4TMpYpJs2NFq1q4mNMAdrEUq8w75blf64wtXvv0CLevX3eI+J9sqJo5E0SN8KP57aM2aSx9t3Tw6W6lVe4mvAJr0YTLuBE6x2/ROBK6JnsguCFjMJlDG/TmecyY9H8zIk+KneKqSfWHCEqHVLaCIy+ksc9gxNKUxgsVfLyonlM/f+Wz+lvhPJHB5LL8HHTvxhvKlUrDo3VGo/8W1EzT7BrrjKvvW7w/sW+g69o25Q9S6IdATv/BHmC9eG5UhsPL5vGYPL0gOh+DxgiPOmRrRkNOgcD0S7z0LK3hAAw+G1TwJhoxc3eVBa9qt9uelrqezTH1tRHyIRFC/6YPM3nNBa83yNe5I4+vTfTUvRLMfUo4rJ78+i8d6l2xFPZTGPftGBEXlX2P+9mdsif+u/Fn56Db+L4wOeZp98nFdolarz6dDTr1O50zzO1wgRCdjeif1SC0IozNJe1XTXCuWwrSsiWEoIcJtkeSyqsoVHJkfzmEPcv3w9H2NeyD2Mdq712aD1/pP5ft4KaVf/BkaA5VOmpu8Y0XAFtjzBL4J9sauE3jW1LDV7+jP4Hf6JpT4He6h/U6vfU+vfg8Y+xgvkiD4AIQLRMExRrTUh0e4kdr7N1OiTrBmEVy5fv0/eBEvBZ59G76nsO/pwHt08IIo6OC7HNIhg15AovqEyJtlqa3mkk9ywv9o2Pr1X324YcNX9InxO/BSVRaA7n35aniqESKTLF7QiQYAFlS1kQg6kxkTI6mN0WuUBp1oQ4LW5Til7binuRIhFCYhNgnQhPi+RxYo8+cdR/ce7rF7BypXLvDV8TXoTSWi9iS4DOs+z+5xOrn50c4mnVVntxNedDqR0WqVEBLAJZN5QXDZYX2jpTZmMyLQHEa7EYlOg2iojYk2QUZWNl8o4cGye0O0JI3e02ibnIPiaC6GSoy1Vh0aADbRJz1ErTr/fPxp5YNtLyIF9OhaNFB5HG27cvFrL+qjNNC+2i9sUB5CN6O/qvdJtPtpXD5Xzt3AHYyOr84TdVnmqlJZ5qrSAwUOR6BKlyd06uyryK6ojZXKA2L51bWx/Pzi0prS/qXnSvlg6ejSLaV7S/nSqNvfq7TUkJWZ/Xb6pXTMpc9Kx0aSnp7tbkdoawmb2UALaURDYlxbolCSolovqQJbPztS3Lbt1f0mmgusyrFakafOamMt1QRdcxOuxJSt8hy1AX+AzpDVLrXgHKHh5ph9Q7dfFq/Pan/fLatWKacfifbq3VV32PnApid6Dt7/8KPkclVVdEzFkv4DiuJj6+qJssMwDHeV0NxRvQoRN2PJkhmH9igHBb7jupkDRkg7Nm3ciNJQtveNunGxHcNiPC4ZFz91bNdjD6r0HQw8Mh54xAXRTC43I9rJpNe7w6LosAbdbuTwWx3WvHzZ5OJctbGg3gZe0XGO2Li3uUscMYEf5sAOd23MIeMM1oi/VXn+7NYDnFMmxWot9GlGRheRw6wDMw3B2OwKquWRpB00DJ6Pjj/z/s2PbAwVnn9dKZuPCpB18YQZs5Wfvl88YcJiPBZ9uOfucT02ZNRH7rkffag8UVcXG4j+qpwYXFc3RKtL6sDuOPZg8vgQ4NyRyaOdy4eolNeDKZIcgpnOoeZBDHj5WtEIx9xzwvQdQMZ3VL4AP+AeNAPnP/34nxrPPPUULlT+pXwJQvg/rz955ZMLdK0MbS0T56U39ZwGQZJlZDALBsHnd7FmZZKNQ5SUBmyQa2MGGduvRcpI645pTMCcWogCoIVzVMjoWWNZRcY6CpcK4ToyDuD78UcK4Sz0evxnCiX68qbXn1ReBGG7QG3Dm8AMXzA4b4rmgiqlYxF4+LnZQtWATQQIwYkAZ53ChozNGuE6l7YS0p+QfPLFlX/gpviTODv+MR6XkHPVPp9q+pZ8CjKeTfsA8kR229IMWVlpGSY3EXNyM8wms4l2SvJyMgQ1jtqY187zYMZrY5w7pVD2+r3QtQ7g6rlV6NpFs/AP7vPIy4V7y18bM7t5DrNWL7t45weuZavaHRo14tXWhbKWLdPvP6r6PJOUGXxndj/HQrs9mcxmA616MxisNrNl4AhzukGk+0uL3rQdTrSoa9mTobnmDf6nGUH038rt5H1lOKpRLK++So5u3nzl881/fv55oN1JoB3tEW3n2kXdBBus2Co5GL1slEJgvdzanc8W3CxkEq15hgSGXHKJKK583X63bXS0/6jv0YFGFwrkjRs+aQ6+dWNc2Nug1it9q+oKkKPf1V4fwDOvsp54FdE0vdksIGS16QUT5g2gTw0IbJm5mVFYSaLW5UyzZcAgunJ6F75S1gGLvBpfuHBhw5kz6C9o7/i949EVZdbevXuVlXStWbB2PdNT0WhQjwWa9TS5rJJkt5tEYBkXxladTTIhdUhAhM5TTc15Jq+Ls1m+7JJ4SL0kTrM+NQg/t1+5Ih5D3n0VVlfJPmR5nAhky+6e8UEgzhdfWLrtUVxy+Tw+OkebRd0I8LgY7iVRtwlznMUIAiJYBKvNSCw2EZsZGDWtdF8kOWYoMWIITaCDhY6yoUKJQUKwUGKIUPLOIdNfdWwfNibq77DM+K6cK+V3kP+Ad+Gm01GsehehEwtFaWBM5EwDwQml+99y1EomL7t4UB3ts4XEATZIBR6P0pEb4vfv4xeRhIKfXnj74w/ev0j+kxjF/NwdD+7ZtPG+AxspDcq5qbDuf4E/WRz1EqPHbneJRt6fZuEGxiwgVuLAmJMeVGrNKlNH/am9RXW0ZDE7RGFhxdIUgqkfXpw0zbz7GRRETgoCG0F4lmTduX7MKttp+dOjf//+h0+1gYVbVjIbltP0Pv8IP4pzcH4ui4tFyzLkgJv3Znp1JNNuNlslvUDEcLac4Q7waU69YJV4oJVzYMxu54xpA2M6nTa6zlus1llSJvVUpTYaYNmQnMzs8vaVeeWeikim5NJ55Dwxr6wSUVScWTrECDiZjqIeO+/9Df+NS0ZMfu2OH1aNjL817OInqwfj0gFvl/3+3UsLxj3SOFBJe23uiEceH/CcB/292/oDG3Ffr5LR9a49myg+6bC/DaAP/VwO145bEe3Txgc6ypSWxhWE7PYCnY8vLMrI9eTWxvxtwCr7kc3f37/Cv8XPm4g/mp3Xy089Hb/fIDs97jBzbSym67g2zKehfURnX3WNJSUzqvkznoqUWayZUrnQfBEk4cDohw7o0s+6oebL0wMGPvXg4SMHzvQffEx5Ad/Xf8SIwUdG1SkNvYYQ5Vl9Le763CvMY3nqKcpvytfKVydO4Bpv3kcXL36EHn8nvvjxB5iTgrn3Qcf9yu6K5XA9ojmZFtnl59J0Oo6XXBYxN49I3oA3UBfzeo1+l80YHhAzuptz3tfoIM7mZmlaX63lqCwHVoxQdCSnvbmk49NNi2/fefH5Fy7uX7R4Y+OEkc+HPp82Z96M6bP56jWNXt79wqaXLv753KaXXHzgqVUr7kS6eFdkXr9m9V13slw0zuB7wz6aQSolUceZdWaLldMZWBszddy3/U9lrZLQsHaYjkaXyCYqa89RqcMZVBDZcPPP6HOBP3rjDNA98FzOIuosOqtNtBhpFKFh3uq56j5F1FvUKEoF+Dkq0jjj/Q8ufpKYnk5pfYHOAANaGxN3sjhkB8ZxyWYjtcE0iGcegHy9O1mh5kFfPpTw5FY0oLdO/teHjeB2WCcvmD+Frz517+4GbFWWjB8z6la6bhUw/vewrpmTuZujOeAOCUZYTBJkk8koGN0eCAW4ATGXC+v11gExvc2EWZjUcuRPakse1cWkF9VyJTrUUwr7klXRuEZ5+QIa9tuHb6MnGr5ZvWjqbXH0ulKBPogg4b7tl8+j19GPI+tH1at2PRW2G6NZJqNR0hngjUyIWUfcHjMAZDCbeWS08a4BSe9RC+Cual3PxlwB19lp8s2TAIl0bFBq3/7wN+XwBdTxSvy2qYtWf0O9tcvnt9+HhAj6QKlYBhDRezhgjnkv81/zog7M8zpB0BsEmeg4XWohe4qhdWrtXxvIOOVwg3IY2PfKTeQpsCUHgZe6UZtOFjC7VsMN4zeRsyBrhVGPgRPcbouD49PS/aDT/Q6D0TAwBsryao3uDGmHGOC4lFXKVpwQr1ANPjZ1QfuTe+KbyMDn2gjtqvrPqj/xRrwYWdqMjK3e3iAegQAdk84HF598SI1JvADDkwyGDNDntdG2oUAgK8PgZ8D4M4RwdjCrLpaRVhcLZgQzjP7rwKZdnGrbupMoui6oiDnPchgVoy8ZzMpgvDEF5l+Vrxvhv2tBjjofxIWaP1vTFOM38f/mCmhPSz4nR07nDIbMTK9kThfatvEWcAV1YJPhJ6G6WKakN+gHxgwt4L5qhFWCxBXXADsJfXni90DxBxc9sa+Z4HOHj506fczJC/Fi+pvj++Ob8G1DZs1de0rDoHr7tKVb0kmHvbMP3XdyyKwFa1R/rzvw2Trm78Wurj+H99vgfTv2vp7h/Szo6a/ZXZXaRE8Sg8fjtNiJ4E+jPUmo/HIS7UnCoh4xZZpPMnt+7fldKQ58y44kIh6see2L1+8qQRXxr/DXyiOHn1T99XHDp45djwo2rlNeJI/tUP10xP3Y9E/yEd+Hy+NWR2/m7YEMzunNNhiN2c4Mu5BfwOWBFLmiLieIsjfU3zXTtcJFAPqQLbAigI0kEAiF0mpjITtnmGWA9waDemsvGYyANW1+RUOSeqmqKjEY96oW5clpzCw3oBqjZFv9vOSVRfx8x0UTxw7aV34keGHHIy/uWtXqLTpaOyA65DHX5m3b183bJN6WeLdjLbxT8c5k9xH7cm258miaz5QfkvNtRGhXCC9NnMMe0NH5StlsQ1QN4kgdF9M8R6msgh6HJ/rFu8DNVwu6NQyKkc6KUPbQ+R2GhYYXZvX01W/tXf3S041/qu69td7XM6tweGhY1dxhQ5dUV1ZWLXZV1szNa58VXnNyxJ1d79m/d1vXDcNPrglntc+bW1PZc8TgwcN70ZzeCFAMtwFvCVwgaiXANqJOwANovK5ZosTRJFN05DZlWwNTcmy8Qyov476MFrS3I2E6NByVBBEjEdHZhANiOhsWE5YlZTKh2q+MJw1KMTz48nnaazjxbM1mOkShMjlH5kUmB51pnYbPBMGqw6kTRac/zYtMEPxZTSaHWVTnFkYiLcYLNqfSaFlMFpBZvaZFuxuq15/osBNs2fGvFY+fPHTioZOP3/btblQx7exCdKvyxgNP4BXxVY/tQ+2VBxefnaKwO1D0bnOA9fEujHo5J5YMkpPILgnoJ9l0EKLp3MkJiqk6PXSNnoBk0tX3XK7uBHj5PLWb29A3fBWb2WjhukUlwouCntPp9Dyx2uhpdSPq9VQMrCmvF4UzqB2tQ0dFf5T7RGrq04B08CKXPDpdGTbzHnTnbrRaKY4sREOW2hE4Msol8vmVDDL+PuV51CWPw02/ARzPAxw0D7ox6hFog2E7pwOe53mr1SUDO7mcFJqTYMbhn2gwZnMGncXOJidvMwQNxYYmA7jWToMTDKJDL+i7mFEvdgbYjkEMwR97z1Hor5ElTaZJHWpc0dwMrkVyVAYuI3ixcv/ae9C7+K/KLWiBsgE9E396+McJtOYpr89Rjs1Dd6MvlDRWnwgYk98ANwvsYICbFJVNeqffz1v1bo4DQmcETU6f00eRsmtIEcDEyQuCo4uxGQvOz17zCQxaZHVapVPY8R3L1YUy1du5iZyYs72aGiO/nXlUWYpGoCGDB8+c+/KkW95667XKf3z545yphL99O/n85/5LvdIaNKH/jcpbypdHlQPDmN0/BvsUYfNnaRw3Keo16jxpgmA3Z3o8yO40283hbLdRQhJFxxDL1CFkx3aPhocdYMdckL3GgFOLxhvXTUMmcmhqEjIxoFZIIKIhdmwURabHsxv6UMRG4cavAJkpFQwxvhDt/XnKjYu6Tb99O7rwCMUGyxQz5jvC1vFeNnfdQWsCbIIRVJjTJVo1qEWAVOBs2k4UXSPvSOU9pI6hTWQevfM+3KDsQjf8igybz50++tq+RvLFrq+WkM/j35w+F8fvgsw3AV/8D6xr4kZELYLBoCOgloxmCz0v7RV1xGxCUCgWmgTgazYLhtfgQUwODS35+aocHz0k1Dg4yb1cE/5b/BTOiX+EJ8PiCV4FWD6At28yWOqjVj3PmUSIIjgTAMNfCxiDQa8BY2DAoP8XYJIHZ85y1p2e/f8BngyA5ABAf0PfzEN1c1DFvCsZqh3cjT7mS4SPQF5qozYLpxOdXi/ofD4j6JYBoNMxtzuNpNnPsnXTUDGwJsBzKqbTkUZUyIZwcNeYsaIe9juuGrxRTuGhapTbffmLg6+1v71g05T9R0/vH7a3XPkc7ev12R1fKE3k05+QYe7SgkH93zjz9IeVkeMLlUf6jUROCu8nQL8fGP26Ra2JGVU80E9HlVbUEivW1ej66widzNRKkbKupa2baaU0BCW3KIZNm9CvW0DDQABEPldGoQManXAQfYMfh3VpnQZlEQE/Aw9H9NHNdRrwJPz45s10x+lWOdDHZCh8x85V0hqkRD5SpaWZwSZSWhJal1R8rdQkymqVmsQdfinZYKnr3LXfU6jb/ehjZPAOGj52DO45L97r7sNAn+9BxnyMPjdG/ZQ+RrDlnMlkQDxvtkAYqUM6Xn8VZa4uilQDRtarXaJmhkxT1i4A8rx0SJmI3gYS/a1eWQM08qMvldr4WxTfroD4SVhb4HJP06BV1KGzbB3SkmubHRRKeRl13YQ+pzS7cs88xpNbAYcb4Dl+rmvU67DabHaDXvbyHOf3y3aSls5bvBbQe+0aOINM7I30sZ7rpziR1L4GqV08wR3zsObzbk8NAlVHnjVgMeD4ddxlq10iK57kmgzphozLT8Be7xhS7/cvKoqPxIdCHTrsiU8GhVLnnRK6BR8DlmjmQzP4j5KIgNB0hitwosVqQgIAd1JHb94BaGVl10p8GjRI2BQD0luxCCv2of+Iq+CxFQfi04AYLw8aiTe2WMtC17IIGCOzCIoB6a02MxLpWnrhj9ZyJsbSs5H0n6wU0X/2rxQUK6V5fL71AOl4JQPfO7zXldfVGH8d6ITuoBNoTTroaYdoZl32DLakKioEOZDZa0IZ92o9TZMrbIwUl3otiO/e9NmlJuXzS1zT3ace2Hvy5IP7j5NPv1O+QY6fvkdm5efvnnmTivxF9S6DE71OnhH2g++YA9GjJ2D3uAkfBh9J53Tbxdw8pw5YxN+IbqK1BZm8JRNenoLYg+eKW94RvyrjRRNAiWmvWpyh5rw8qQngiQPHrhrYc8gtDx9//KExQ3vVrRwVu3Xu+Nmzb53Dn1g5a9qBtLRHFz/X8OSzSw8HPA/OWbDk1nsXbbvjzrsX3QuwEyDuj7BnRk4Cz9dsEwTRBFR0OG08U6s2m6jTWZ9jNNSBkIhMk1wzi6TNtaepJB21xaEy8mPDLuVfm9D9Dz+x6a+XEXqX37vpEWUF+Xz/pmeVVWwPPwQZCmi+0KCobEbI4AAm5SwWq4E3uD1m7MAMEAcdJyGdTbo/Sa1wdTYp5XSb+Z9SIr2lA69HPaskt/2qfLoJvfLwE0unIdvpvyjvosjoWaAtdikTyOf3r52+Q1YG45ceV3aNVu0PwEn+zfziwqgZnBgeY9BXvMA/l4QIa6ThUqvkUWI60tG7lEaSLgy7cg+ZMU/VHx+A3v0FninRuleLVeCtvNNh4c+2MOfF16h7TZkpojZXwLecfm/TqttW3rnpQ/Txa8fxovi2OzZuvROPi9/X8A677/9PoPPnsJabuykaMBoskl1AnMslWIhJdru9ZpPJ47IIdpmYqJxakJHJaSRSQy9eNRcMNHfxVTt90MCRqiwUcVJN5XR7nBHy0aFHzFYbPOyRQ8pv977uDTy89hFH9qsQWuAF7eoGBW6ti28AxXFi9nww+Du67SN9VTlyAT0+5X9md8GmRaVCCDky9fn5smwjpKRUbANiE3XGRJGTbNagtdhKbMRqlSTTGXQTqxorPeXN5rKZcGUGEoomdeawFtq3GrGmErQ9BMjJJjaUXRh9K2V21TlsRXms9g+iZJA79POsmbsOPdR3wIA+upWZSLdhU3q+0x1p16OjwBcvjt44udPaZWO7oI8XT1m0nJA2o/tV15jfun2Z0lhVJfQ39ek7pPfo6PQbOmPSf0BNV1WXfQu4N2q4j41KBZl6vctqKyTE5gLcC3QUd2OsoICTWqBclEC5AVCmOJdS81x2jUHLqRlNqlnUJECixEGkyU0pWc/s9kQ6I49W6MCOeP6qYdyvj3FlpvJbKsZtlnXpNrkjxZj/OYlxeTeKMeqlYTyw7+guM6qTGGNUCPju5X8CfsziekfNHtA6gYAkSuFs13OwcVZUwum5THTTyZhJfwawIhDtwBuOMA+EzTtkf9W06jui5mPYnLhI+8qITnJ5wrnlKOUCJAmFZw66azWyDpoVRrr5PD9fVNYPqJ80atTEkQPx+N41L55Hm7t0j/S4U2kzvkObAYjsX7/9wR133cXinRKwObthn/K59lxHbnc0vTxfpy+AWIfrmBEsdDqDlnBHfb7uhk5pHXI6NFKQCzzsn/xyuoWeWH5+sKC4oKaAFBSYQjlcBrKSjIwcwOpUCW/i6WesMbvFNFMbI6czsT29qrRFYm7itcpaUlpNqZM1WD7Kk0hKtdhz7UioUqtlB+ZWO+JX4ko8cVTtGGlqzv0z/9qzcvOtc+bsfuxgn7q6/sZVmcpPj3UdsEs5g1ffsXJit5oeU6riV0y31A+5VSCrzatvvzGSOXrwk7fWJXmhoqv5rbFj0X2SjEldv07du0y7YcPiGYtnJPlA5Dgvl831jFqCgt1u80HUn5PrTmd0c7jPAQFsqAw8URosZtEfCriZDWpSC91U5raHqMy6rFgOMwWpizDsW9z83av8NGhmmE4jW8AvIYTxxMoEG5Cpyuya7o68LC/pMJ4sVt6fBmzx+oObtu3dsfkuLhXuJP8GOPD/RLvGvxTe/9/8W876uF2ffwF8tORa7Lsl2h0cxxuurEvh300q3EGA+3HgXyebmGz3c/QsyuV06iyEHhhQ/jPH/FGDuZffb7TbPaqisaPSBlE0Gon61sisUkq3M2/LlH3q2JdEgjR11Mu+yeMobwV3zz505Mg+1G05cE9sokD63r4ZmGdE7NVXn3tdmSrdwpikGWbanXhm1O50iDrO5zObdQ46CtxJYbbHbI6go9gBJsHhsBlsbhVQGyqOWm1iUCwW4TcieKMaBgYqVKmZ39T4tAUaCZOgXUMDcdESp6SdikX0W4qE8mwCidUMiQaKA7C8igNCdYDDUsAhi5sbdfuJbLTbgpmZNo9opMfcosfr8aq091DaezzgADmYJbPbLaABokYuiGwkGOS4gIoB17wHFINmR/KaXeeaD0xpAjgxQjQiZyXT2Hj8qnsmDO41ZtOsv2fMkFbVdH3v077R9dnTMu5AHy+ZcvNEA9aN6TF85mnr+BvaLxmzKdp1XnDEMLV2M4FbmJsRdfPEJVv9hlDIn0HH/mbnBGgtEMXNFqNzhHqZzZzH5fJ4wJe7idXWlrL4EpzjMTwEf4kQM2VkJrNg10ErccIQLi8rb7lViQqhSXPvyJiWvT7a99P3utZEb9bNyPj77LvG9hg8YRv6eNiI4Lyu0U1jlrS/obzEenrm8J6jddgwqfeUJUzGubNgo37kglxbbkLUnmvjSaas1wcCwEvtCn1nwEY5uDAVa9lBZdzMFdA3BvMZlmAEnKIGQGoWjxla7ZNoNYt/a08kR8OoEwo3dywAS1ZRGbEhcPScqU05Jizf4Fzq39CIez5815ING/rNzcQ6PAeRHRlTh40aUjcmNu3spMGOGf+19N6Xzr1xrnf37JFEXh9/ev9+/Ohde+/au3ctqyfEuA33Nj7If6HV0BoEhETq3eoogpgGxSdHYJG5U+cTYXFCXcnhcjpwAh9cvHgx6rV4MXkwLuDLwBMdwF++D/SjiesS9UB8T8N7A4d4lgMx6hCQRP8cPF9AZc2ufE1yoKKjSqWImrEiKeG98NvwJUtQ17uVv6CO4K+P7Kv8yLvjc9EcpVHpq/rqy8HX7Qf8mAMWRbbq9YYcLpCezhlIbp5s9VohkniOsZ4D9syESk4GOEPC261Rc46tj7KQpNIdwMiLeGTVnHgiFYlhceovcdsO/fqNXELmCjh3fJ9Bt7hw192zxi/u0L/fCID0v6cOWzJX6YGHHRwT7te1x81bV2xWePrThQuUHkyOaoDfNgPcGeCj2z2S5DAAZRwkmOlJS7N0sTKY0wBmF2U8Zgx1Wua0vZbDrmnlDFA1nOjIdS0UZLL5XEGbtMLaG4cOnbiUAt5u+sClM9CWd4zzTJNw+bShSZBru6zYDCtlgKwfBxgNEK9BzG1nuVG3R0dviN3EYsRSgMvJXuNrxtz2kGbgWpjj40rDrsdQ76MPrBwxZdqYURNmjCaTlHkvvYY2vnyedrLffv82RqNqWH8brO/hukYtgig6HZzZYfb6bG6mLZ1OG+iPBkG4lqZXlWQLc9vywC45pIg4h469071c3j5z54GDu+bvtC41DbvxaTL1wTs3GmcseOPcCxfWzND3uYnO4yaTGD3MXNuopUW9SOryf1A0AntQTFFeSZEnkyiuFGeKK6M1mQTPLo7aRMEMlIZnc2YBY8OZFhSGp6dcFE0QOaJ6DSptVzbTFGj5QLN++4n5XuB2Bh0CyIoPtraV82UGfjMAj2nOF/8Hzpe2dl6YyUUxirgysHxt7+vRG3iyhKAFBFywrGlD1t+xctDwqSMS3tftYk/lMbJxnYx92W0cN9Wcu3Bg7Y4HdmzaAnRpQJeIV9jCZoRaTFarXuAEt2wVdSLjAZNBd5ZpLkdLLjwfaZkjoLMww1k0YxmpjMi0jIDZQuLt2GXb4OHZdXfemdXWX4h+kI6ieP2RI/VKsLKdgckp7Mtm0JcyVx01c7IFqCYb3B693IhKTlkkSVMvEixsTuYEWtxYbJ4qRN1TT5gGmOpQoaepJC7h5/G4zYxBS2fwXyjpMwYvmYueiR8+uLpPtxWb0RWm477FHvIZPwFgiEQteo6HmNDC8W6PDIam15MxAMpATw1OtKhSSK38SJQlVMrJYoRv0UW6ljIcdzu4um9X0E9evLUlPJp+/QT065dcLtcn6swIyByXS7WsITdA8vJz9QFKBj7Ll8XCUtlh9T2TpESkuYgtRU1pmZpUihQjlSRJyiTzHXi/pmV5hNuO7U3VbOakobPHMT3Lf6mkUz3L6DUmPLBzj5u79qNEoz9euADRGebIBrbpLOyfAaydjWDECQC8gInRpMfU5glqvjxS0/ook6Y5IJByRvBjW5X/WX2gxOp6ajX6Bl9WbI+074pDQJuP0SfkR9AHecCbksNtMPMkQPILAgZ3tpsD3VR6yifS/ncgR5maq5Nybo+KtfPGZt+mBuXlpp7aN3vVRSjPitGmyMC2N7TvXJnZfVJs5epVK3Paj41mtQ928nRsWxfJ69i+201lleiTcFldl4KhK2eMm7hw4YTCW7ovHVqUHagrC8vt6se0dYKMhEAXPAb22gWR7ZioDG6OIcuexnF2R4ZBKGjjoFU7LIMZDBKLJaeLgbG4Baw31QyE87KwLCW6qfmD5peINdiijRMkDTNdBtJmsdHeb1o4KsrksYfuWVrP80sf2HXnXTvGz43/mDv7hlvHLZg5tG/dzWOHE/3mPTdu/jPPHd61av6JGnnzlbTcGfUTZo5zjh3SrXbqIthHP+B1CvZaz3WIymAveL2eA43DcQYjzeKx8xHaoLA9Zc7E6UKSLcvUEcookoYiSMK5yr9Xv35htfKvs6gQ/x7fgBfEBeU9FlcxXQ30Az8d4kG36IV4ikvnHI6MdC+fGSJpciAQ1GxkAKgmcyoF5RQbmZIABm5IGIo8qxqxk6w8DyjTZCI4rzwEpqNn/3nrpo165Xik4oORXbJPbH/g+O69H6KfSEW/AwPbHJ696HYyWfxi3JRF3Q+caTy47nzV94PqWb7pE6DLD/wvYEczuQFRyZbB8w5B8FoMIBWhLDntOQ06qv1LT2U4RAfjWSJSWRZUcmmjn5PnixFVr5appZqg/1m4UekRQXQ9kj1hA2SpMyI/PP7IvP1HdqyzHh0/4b1Zt6/qWDF2xniy6IV3DHSOuPja2X3vu8fkK79t3ySinShw4fj6e88q44WdVH713DnyMv9voGHvqNeIsOSg85mddthY0e2xEyfHYwloXQKWU8fwABzg0xiVaxOja1qUCqtJAxJGLD5VA4ggSDlBYTz17ytRu3nFRekOyZNVXNWrakzDit+RaxW+RynEPX4aV6Ebab1x8UV0m+KKn29qwm2aFuGDZLNdR3LxhPhmdu/tjaZFJB+vsuvwPI7TftataQrZhufadcJCTtB+ZoPPnWU/W6J+DiDOUm4hj5HNTC67Rb1XyWVGBghkjuUZ1A0YKnrSS0WwRnVlWUGGo7Xs5fxfZW/JrgfWbbp/wpz4j9kLqsaOnz9zaJ9BN40dvp2K3nPkn1T0jkfluy/782bWj2ei17MviB7Vs8oY8hyeo/aRQJzVQCes82aOt9kNVivPQ5zUBUIODt1IO560PNrT+l473UzfIlEXrqhEttWPZFlI0aFVyq+l7tWWYjxHyZ7QxbYTfRRvs/HEuDM0hwxrNuJVrEtRr6jDmJHBSXa7FzyE7ByLy6WTGlGXqDFktOmCumIdgRinhkuD73WlnFEfYUOhW50jAM2Yn8ayShnM8w8XMf2LUlwa5KIOnNJQOynHse6he8fqZwqVK3btuRFL1LsbPX7G6F/QxvMvK3PLS28f1WGwbBv/HQpSb28HeLYgj7DPP+CVnI/LgojJbs/keSd4sX4Qx3B2wPMMAGhGXRsynU4qgjUgglFOna1Xk3QsHNeRP6ZAPFJz97ukBO577P611oHDxk2YPBVksLoSZBARKoO/IZ34yvP733OPcWxfu30zyOD6+y48ocrgLsqreqUveRmvBl5dmeBVdg+f3vujFfCTo9VGHWcv8Pud9sxQG58vZNfxhUVybm3MKcOPa2MFBUTS2wIWYqmNhcmlzO8z8cpMlJnJETbvoJje3kvedS5WI+bW1/eSY7CTJVfMf9Cxmnc5JDvUQdKgMbXRU7hX5oJZc1dUPlrdo65mP6J38+LfJ+7vzd3w77p6giYbYo9Or+2+Yz9+J1734KI5B/GxhRuVL5SPvZKyaVSvwiZuJFml3sbDTS8Czn2FN7hCrorOVQ5mZrbPFnw+r8PptHiLwLWu7ugM0zHKQbfbVhtzp6e723rbltbG8travcgo48ramMAmPDS706wI9jbmtl11gYw52c0+fl7YRUWjXFLjCXC0PeVq18rKCAh6Hi2Rod63g6Qeb/ZV5iw9GMF6fEz0+/PSVuOpgyob0l1Bv7h6+JhKni97aMmbLzy3aN39G+/ceedinBV/PXZrcIWx4lFyRV9SPOk2YfLjuuKSOXPEeV2GTRqufKt8/vc/Xfz8LxdeU88yaP/zvwFN2nEduPpoSaEYaWf1+XL8or+qukB2ZQeya2OZrGN/wBPw6H1IX8EGXpCS2pi6+8n8CLuAlCBEc5MdSaOBOgJdUtOleeXXIQLNoQKDtEiiljMc0ealh8owvgYRxKNEF//bonU7N2zYcefiY5OGg3x7ccXwsYsvtiTBlR6PVtjntUGz/v6n9y598Opr4ANugLD9ZsC/hBsWtRQhqzXDb7PllJZlFdDpLcFYFuLSA+nADCY6RdnnqI3pfTz8sRUFbLbmVvDA/s2YJ+fEJooFIs340RFRzajT40YtbyRTNUUPcUIy7oaSuKEGv09FuEL5HYkvfNbrkTYZTxVPmlKK/kmOKotUxJSx6FMVVdRts+/Noxb9VsFcNKneCMJOmiBA5X8DWS8Cvu/K3R7t3gnUlUX0c8VFRVGurKAgixPzxfxu3SuqPdW1MR3pTAbEciyds0rblg6I5RkLUXGUb9sZ/ogZfqfHbrcVaLfAWJCQuHimnt9pRx/NwpBIDzUXXrLSx9ww1XogEJ1RZXn71EwN+yeAgGBMMeqy8nzIHanUTB2duV5Z5qHnXM71fds+6tettvfvJt4n4qzJfYcNdeL8mYMXTLDwtwcXHO5aO+O2Xp1Ku9zYV/myUz++YuTMUvRuAVZE1OhN6zcuGH+uzYqSCfVjxk0ZfvSdhQ5pW5XSH63D6cpo3C6XP7Rr6eHDqPb4Thys3bUU9MdnQMdvgY55XIQbF43ke3U6u74dx2Xm6fPalxuAhqAd7fmZ7VC72liuBeXDn3R9OigQb7rdaeP0rO61WW0Ua7RK/NPy1jujUhHJAxKAUQjTlDCQKQM3E4jVG0jI7XF7ytUGMmRil9UrllY3tCtcveSW1PL5fqtn3hIfNPrI8RpWWo/6GvOLCq2KF/1k6phbv87+1+Yq/F+zly180KucwLNcnWosH01d0P4U4P4nZSh/M98XeKgjvcVcka93uTLlYtr3v1O7stpYfjt72Bb01saswXRJMoLlcOszeQkMuoRtJCgFJSyn46raGJ9UoIxvRo+qB9ZRqaCOnmqR9klJUgRQUopow98UBSIxusgpylNzwyv4m5U5vw8R+ExNnLzhBo8mThHxGOIFvmTPqlfPP7fkjqmLa+7cuXYp1Z/P6g8c1VOx0i94SkeFiievPFLBl05wjqtX/q188vmLw8/t/MvrL7P4uoLOtQSeaMeNirbPESGGcDq5wqKAuzZmDoAq0dfGJJeYwdtsgWAA20nAFrA5c9q0wXWxNvYsm5OqEJZzSFazNpMjRYMCFdTu8ik0aKFJ6PywCBUeHCnz8PKscfvP+4Iq0unhBq9LRbo4zfdYvl4oG3P76EkTyHbnT2fKDQxT5RxaIzJcT/V569YNs2ZNLpfUWn7W24P6CYOjxRZqGfxibl52ADY4O8TMpDfNksO7bdnBbEAvG0Jn3i/zhroYb0+5l3odvNSGfgCx/MfYoc9Gnl3ZMSf7httmNGP1RBIrfGzlMxOMDxk3Hj7eGh2KA517O56/mavkbomWlVTkc/k6UcwK+VxpFgvHhdJIh6oKn6e9RSrM50l7T3tPBsnIqY1l2Imx1fBMJrQeVp+ZEv2x1Lc2Hw2lZCap/SpGVDBl8IgTBwSJ2sUMHEzgq3PzOV9dfP2j0F7P3SvXrxg0ceXgtW1vXs2vDb77+ql30w/Y1sxYMq9t32ldbt5QnOYRV98SQm13PnzHpuDQAYMGde4TyPHnTz5ZUN773geWb3T16tv75oLK/KBDzs+IPNLuBjXPflvTD+Q3YRD4PtOibQ2Cx9MOZ2UFiorznU5zbawtWHl7O0PYzbe1tQ22hY10tnW2DaKgn1pBCzhEejZMSSDIxmnJuRSSqLtb1jZVi2llYuURJxsMKKkHcRGVPHJzvUYnlJeU47NHqhehJ5RaIYLVTRaq8eBb1h589OEDB3LVvS4gRzcjv/LlZmUbZkKqwzv798laX7T+3u8EuuMEtaH4HtLu2YW4W6OVMtG5eK/OmxX2ym4Z/Dumobg00FZY73PynI3qJzsBdcWJbpuOiKQ2Ri1cMt3TEseW2podbuXROvNylGTZMo96hybB0WRw5JDyAz5zZSmKdEjPy1iNZw4uX474+DbSQXm/dxuGLzqepzy5cT1aaKGYZKJOG9cr9zlLAEvmqx0CHdwJ+DgIu1gbLch0GwwZPMmz20kGKSpOS7e0oV1GLP8Pa98BJlWRBNz94uScZ3d2Zmc2L5uG3WVJO+ScwzJkkHwkQUBABMQIR1Awi4piAAVUBsVwYj4V9PTOuzOcd3qeekHRU8+7U/ftX90vzJvZBe7/v18l+La6urq6qrqqurvajdwwnT53AbluwnHIoZ4CTWrPJOp3s7KnTKhoRp3epHYNNeuzOtweLe4E88qsePTXkROujfOkb5nF3/7y6dfeWH2ohjFwDwnHh26bsP3ytbsnXTmUG7FjS2jEOOnlo29L/wGn/GPpq8VzIrstTYfZXvjVn3peeWr+qx/98QWIBck5zw/Y7dyDyIz6dD6DG0zZ00UiLhJbRUYUjQJ5X6GhNtlCHgg63+Fbl/TgunV4yqX4AzxA+gXzhvQuLm9PUl6uAV62gXxEwXKPS1UlkMts58RKCH7sogXx3Wq42Ni0S7RyXKG1sAy83wK7xQqaYs1/xwaEoyprC5RdsGZi1WhE10rFgCf6zpGHqmgoqjsQuObyP26LVlS1PNr+EFsi/atbnxk/m9Fny+e7dn+yEX9527333XL74UM9rn1/fbR3aUXv6ut2XPNhorCgacCkS26bv+uDS9d9gD999L4HMo/fd/AxWc8rO37Jm/h/oHp0TWpIqKjUWVlZFC4oiBcWIWN9rc1WZa+rr+c5zl7ENiTr66txhTFWHBuXrnQWhriAucrB2mtLE6jYEXCDaYcQiLNTT69WPtn2SpKcK1NMOT3fkpOaUcq0aNEPvcoQwfK+WxXEqeRvrKr7ZWK8uVSf0ydnd0WcZM9eNPXB+n74KuOD/wgPSAxMzxhWV3PgMsumKxuXv/kmNmYYPOMAN9L08Mvkwt1tG1/qPbZ9J/5JOlRquyoQHvh4t17Mr7d988229iN4G/OpdPlM3EH3oyAIZOtoDY6alI8zGLDRCPJFa4SARDFGL6kZ0aq7GqMtUnQ0XuK7x/H+ZZlVqzLLmMX4ban2KqkA/4XE2Apul8DfRs8e9QP5+jn4SxEaYc9I1VbEjeEwLiiurHQ7ChzdamBO3BEUgdjaQYoEeYvGpv1enxVibqPVwdlpzk6vs0mF4/leIi3z0qjzgMAJ8MYZbV8nnvuec7+lmt/z9MuW0aP80nbiIGWWMv02XSa2/8mwY8+ua8xMoXEjs/g71ev5x3+vkgzgFklpdqe088grzz/Gjjv60BP3gB5NJG98KfVthqUSIZZ1M0FBMIOiRopCcl0bA3DXztjB8Np9AuFxsut7I7qrmElFhWEocha1DyYD6QNW1uObuPAEPnti/vw/n3nt44WMa+s6ybVOng46JRufeOXlkxulvdt3TJmy81qgsRJovAdojMNMgAdQacYxzuC2W8rKfKGQ3RDjutVUBOMoTqI8hCJCBMxnxOe2G3iBh3VRsCtvqCWTXVx40T1Sp84GRDRE6W2YMJykfoH9ZFL8Xg95FFw/lMoZvmmLpf/gV0avCzOjwutG419K/1443TdrJJa++cvH0tfDmV67H2zf+wCzeNzuBTt2lN6/Yf0DpTt2zN89/iqX622pHaN3EtLNz95lsdz1LLFrx0DuhkI8m4CIdnyqrMoVDocsLKnuKIY4CGvLYWjFjhBmrFa/114DNs7u4030fSZeeZ9JljunEqnkrRIOUfeKrqBfIch58C7yF0Nnyo8Bb2odquYxMp2zFtLZ3ZKkPBDsURIY3JdSusucxZUwxpUwRmK7p6bcMQEiDnsZstnsIF8sON8O+lJwodcTJO6LO+0psGFDpZy3SHTKW+Tdy8tmEnMSFvSr7gHh/CTFRfokRUZ5AXnT5HNlJvDzP/xKexI5NyeB26Q2di3/Ovgu41NFRRi7RJuFDbA2tjjuC49L+xByOB3jwIux2zAdqc2bN4WK5VCTEcrAtNvxee8gy+eMFBc86WXunSh93jSotnXTrFtuueLqEd27xQf1/Q37xE9/IQTb73buW8c+sW3Dviss1xkGT5+zjc5JDczJGfBN6lBftC5V1iNss/JVVYb6Yre7wmCwhtnWVIm9QiSpxEAk0jg2HYs4ahgyPZ50TU3AFOg1Nu0JeE1O8MlspgL1EpBq/vL/rq8dkr3ELL/REpezv8QFjzob48osurTDObAIKa+fsd2z94j6YvYDiy/kWyr1UlwbbGWSj63T+zbYPL1/MvpG1sO5WagMfLRA6kH9HNzr6KLF2IDDuAg7wdHZJzYdbn9SWjN+uYEdpfN10D+AV3NAfv0gvQEbz1vNomiwWCFGZJxOq9fABYJuRFjjTLsLbGZe4DiL3YgNXs5OZ1ktgEDP4GgTnHTmnqUns6u7a6POOttrU5l0w5WZDP7gN9IwPPViKqnSv/atw2eXSZv5Mz/NYaxSrdSgSCfI470gjxX0fmdjysKZzUajXRAcTiuZvsfT1gIRC0ZKmODV1WHO3sPkFVFTNQjfW9W4eV6mTfq8W6rDsm8df0bWBTPw5iLgzSsQbybR9JTHbjAYk6giGq2KRBLIyHVvrIpQga/yFpfJql1cUMu5ubHpkM/udljsyKjkWNS9a71u60Qllj1h0zn35M1TEfXIkLu+X2rMofxU01xF1eeQPBNxR5472H6AVAbIppbaX8++fn6UZJXadxJf7RFix2CspWhMyumzWm1MNMrBSG1sWXmxIgDFBbBGGWF8DtB2LxfJE4BcHdddRqF0y9Itj1FLHGVHxw7ftKBzpYWpmkB0XVhCHYtsi4/CGIaAn1OCGiAmKe1W5PP5rWwpWW/8XLJ7vAKirbgjZPcXOOpgsbExjk7LTVJ/OiV/tfFqjwPS5UZxas6d8BlymfQPMh19Uk3N1LE5R5pHenHHB3QYA8attFLXhhe6TvKAuw7yfxjmqQgNTtmYYNDk9xdynCMaC9NJsqXDBTb3+LTJ5hDtnD93hpL6M1XaXpk8PWVJnzwG2fZmJwZfv2mmcNjAVa1ckChJ9F65Vn6inswJ23fV9pMlO0i24/mMtFA3Fxg9CHNRAja4O5qbqnPY7VWRkoTP1L17gotwjU1VtSEfZ4nFwANAJdjFlpTEHBZw8h0OkyX/icakYn3VC8p5O7A5rzYqboA+48HkpzqwP8J6uRJFU5beo6U6pszdevu24bosR93Mm3dfPqx8q6wuNyWVJEdqbKi4fNTysVqGo6Z3ZUmiz/A5fWHcW2F+3gH7VIImpxwBs8cVjZYIhR7BU1rmC8sJDBe41z6XzxU3xhlqQeIFRhsdshHn5XeqchKQ8sVXuj40EldAnaqYzkLE5EfItjbGmnqFcO+26vr+o0bgZ6UvK2q6la+VPt53W/dkB7JVjVvG7cZzXfeGF2/56XXpQ+ldw37TzTtOZ46Z5flbJk3mZoGf6gM589ltVohJGa/PxwguG+8PeG12jpjZlDnNWV1WK4JgVE1ROF5S7x3lVDQp0duxGN2hJTd/mI6zKm0PSuueO2vtES/7/tQO6VuZInDn21PlL69Zy7wg07UG6JoCdPnRlFSQ1DxmRIPBbzJ5LRaHUUAsIwaCNjchzZu2+QUjizg/5zeRgEbk7AzdJWmVxYhQmrd2K7dC40a6SmUXKmp7menk0fut0vXKg/fX45KLFdp7klfvmWrGRh69b/9OmqHRT/M/QHMFrcnQmvIJyCWKmOctDOI8XrdA9jVNZC1NGdOmMMuMTbP2zm+TqkW85UROzoQfZG4kiZv2JczTCjXtoevY0h3X/fS+jgpiH9ukyXwT2I4K1IQ2pvzdWZu9VKyp8cZDoUiE3pZq7hErIKRUpWNhoW6ccmdqhe1Ptq9sHTbeLN+bGpt2OvyVCJxYiM6957ospaPepSvVJNcWybk25ZKvTZFI3COH4+Ar5VyeYsjlqTvvPfjh99+uvHT9cvMzNfjKM2/OCMXWlkO8JH15t1EY9MTUi25Lv7x52+BZnodvejAjcL2uXDV+qhMnnn5Uqjkgnr3ZtN+Ay9eb37hs4TVT90+g1VHHTZlN9h1hfv5D3wuvAS+oosITtMbjUXKIlot6orV1hQ4fhMJBn8NZDXLu9Jlj4L57STIIdFYM691c3fnsltyBkwfutMHFyzRfMKZzBZM50Uo3ZXDjGK7pzs1vPgf+/N1N4PsdEQf+Z/vN1126/upbt18qj+qKdb1+Ng37sI9papsf2cv3+qJ9Cb7rN2fO/OmTl96X91bBHv+ef5+OcXzKGRcjbnegAtntATFQWxelpsmfjhY4fePTTmSEgVqMDg6GjbicACX3WG42Ponn7qiq1kmZVjLonAilhdOHKDjcb3DPXus3pCpb+0h/7TpIeQCX2x/07vvh43322+y4nLlLjVFI/fE2XoT5K4RIc0mqMYGQ3yWIEWtBgehnS0BGx6YTCU8oFCOui8szS1ghMEjATlYQPB4WfH2fXXYD7AXZ2v4BpRBw/t1/3e0/5aZKdoiNguLe6+6s9L5t35qdwTuVsS068PWPP/4Nf/iUfc81224V8L+fen3m0G7SrfKgHh2IIziELTjS/nxg+0P7j91Kbd5bMHcfw/hqYXTeQtZncthrKorjcXtINLFCXX1VKZm9WLqqQAiGgiEQ1SCyWulyanXUoOJihKL6AqowqNz7wzo7o6/CpLv6EXVnyxx4tSJG+pEz80799qbLfrbz7fvwiJp7LCunzrjopnsfeGDF/Nca71IGf5HnoZuW7rUyxqsu2npAkjyDh08e3jbpugVzJi44WC3dLvPgUG91zGw7HfPiVBLWJGNhxB93VFbGS3l3xCjW1Zd63B4YogcUtFs3KyikuZuvsDAaheFHHapu5swnHTTZ3OrqcGGOggaxWn8qfs4KsrDI4i3KwO5qfG3+igce0BWSPfjrXUs23vzOc1dftFEeFv5Z9cH5k+YsyJaUvfuKi64yMtYblt30UG/ZPk8BOR5KfbtS8JoS0YgggvMa9NisVjECfngwWgTzaC0qKjCRkyEFPp+TTLwl7Sugl6zGpk2O7P0qXUUU3el+/T0/ZVzUc3UnndnR27DuvhLz49aNUy/z3Vl9eu+vPjQ+Ig/5U88fnpUmPWVdu3LpZp4Z8PRrbWO6bdsk/Vf6oX2goqC9Pv6SaSVSfPQ2xOB2mM+vlbo8A1I+xmh020TRwcEa6HSMn+bEvJ0TqTcE7qqZzh7SJRB0UZzithIrSkcik00eZGMvkf46KzONUCiNzEhtuHwr1/OnOdLfCUXCaw8/DHJ1BHQpCjyOkzgHBYPFFqvgdkesxVyiRLaCPrCCAZ8PuImQzwduhcNINAnlSpE+maGwM7snoTJVLp/pzTIWX2TfOnv7NVt3LV5le7LwvQc++vqrT3YsUKQIj1666O3f//kXS6babn6YbFBIX0ofDzmqyM+L8p0pM/DxeeBjDPVJkeUYeb3h4nhQDkWDYNPoX5xes0B5aM5751zb6yyh5QGyG1+KV5nNvniZxy/bzNT2IrTt2Ny7BdT95r0/o+7km0cOmfv3BLK27z0cKBu9kL32yAnXA+BJkveSQIZJ/akEGpcqQAmIJE0FRqPLlDCVlBoT9oJolAcF9QXMlM6A1yOnETw5dOpPvevLpzmVfR/dvNPVtIbJHoTvKUeR6Q39Eq09pL+OygaT4EqOp0Eks1oVCpAQNZZk3pbflAL5GA70l4CtrQT5SDhNFgdIiCNqsiaE0rKg308lw292Ok3j0n6n31lsKy6UfeHiAofVBrbIlrsxQz15ut3cRb07Ohmq6Gjl7jha+qs4uzlJhKfRffOOq+6/9+R4vLZ9Erta2oIPrv/99l+tHdhXFqAz29bsWrhr6xY8aedNUqZQ2rXwsflLG4aNkAWon3L/9AP2bu5bcNti5P5pgddms/sEu1Acd5FrVXZcgwyoSL1/SsrhBNX7p/Vd3z+Vo2Ol+D09WkbPiJKAMuec48PFKyb+fJv0z4krihlmI7dGxGvHkuunC6ZO4paQ66fSytSgSTFmxpWh+uHST/t33XzHzbt2ZO/ufAc+/+iUFVncLhcvWIRAkDyjrt7dqU9ZEO/gmUKW3OFh1Es0ne86ZoWKxPS5V01JmEjfun3qqf6TzZfZbl53y30Hbl+113O577q5k9ml0m+HjTQsu+q1l55949Klpu3XAj974MPsPqCtEJWhrakC8sCCwW4rDoVspRAsGcTyCkYo9XEBLpCQ72jbA0UBxsoGAshsdpJP5rTdXmSHT3Y7ubOdIfXOI53uambj32ypLn9Lp3KXxWUCeetaPxivh5TyJft9ZbQWZrxY9DFbl46KBycOH3DgNjI69445bf6t1zzeun5aj1EVE1deVIs/7NHcvd+aBff+4k0y0m0HZg3acU+fmS0zI3WFI7bJb06Ap/Ihe1zwoTCMfUmquJh1eR1Bh8lqsBsKCoJBt9nO8uUVLqvXxJlhkoQiGO4TaYNgFszI/iy9wFeiG6d6PkOpIe3SD4+ea3cpVXWUyfKXlomNzfSoSbNX9LkKcd49xzn7Dz9478zU8Mln9rUu2N299a09KzceKp+xbPmsuXNXzMMfnnj4oROVt4ydMbZ/Y69A3Ywx/RZLnz3MPXEKz7lq09atV2/aRB7yAX3ZyH0D9uC6lE8UQmFvzIJQLO4IC2AN4k6H00EmsTg9xjnLucLJFjlrna1O1klurDqdbMQewjaWxFcB+dpqhN7pNtIrnilxLNlDVi4/6G+uqjEU3VPu+hpETo3MTjUkSaG2jddfcdke83rLDSNGjRrdr0/rqAGD1ng3WLevuPTam8ZPYTLz1qzbYLpzUGufgfP6NTcN2mNesn7VnE11trn0XRX8d7aIl2gNdrPLQq92en0mm3qRu+E4KWIiX/biyVUIuYqJ/tShdiDBqc/slymJ/T0bFy6cMr2lsKm2cjd3Xfsc5q7pkxZNN8wR6vsNnK687YLeZou4TykNVlYULcjp9PoE8PuoILEejwmbbJQGEz4JNLS+lOfxtOh3GuhNLeK3Nfppar6R6aOjgenAn0mh6dI3ChHt0+nZeuUur0vgl1KaUsCXn9P7+80pi0FEDodTdPoDrAXIOAFmkhXd5BavA4kg363JVrUusO4CV/7FJLluEeutWDFx3aqNQ8ZNWbBxo8BeO2rgpj3k/tElYzYtwi/8+HfsWBmR9e5d/HfmX/SOrB0NTlntopmzkEclHE6r5Wk8FE0j92uOmxjyTviwTFpkWV6+rEJmSNlRVufIr81Ro7qxzJK3basmTFg/btz69fjveMkU3CL9cop0E7t//XpSK6wS+pfv/QZPQLccj7Poc16mrVxPLjm18/9vbeRxQhszSqYsotkMhtFiPf+wcivoaENShqMfDGLxBHSKXQ98dIAFKyLVU4JsgddrFYusrIk1RWOFBTI3C4GbVp/gk621SUgZbUMFARnIbUGEnIoJa8y+fpZ79tafXeep5eqFtc3kMiqI1GC5Cdd7L7vsop9t3TBjxvoNvfpu6l7dfP+GU3PS6anMk+1D5oaWXDNv1HBHRUVZDTePzASRx4/QKeZLGIMFlT9BrhGZrDbzs7SIhFyUzKDSpV5PUuJW6veB7DHTykoSxdXFpzbiW1tqTatMb3EXE7wfA95/AEL69pt+n0Wph2kFvETEBaXgkKCrh6nfb8HZ/RYvuVKMP44WTx64ofep8jhuMiyayPl+anv1LZGOZQ/oVh+Yb1JfjcMYCSJDWIwRR1mMO9dXo882sn2kCZeC40TEZjnx4TajZ+k97m5oSsrtAw0tFEVDt0Si3ODkampLq56mFJfi7ieihb5QyKJcSguBaXbT+jFO5Vq5bqM9v5Jvdsvm3Be8tSvU7G/J1cP19DdutUBueU+Y42YH3LFy3qnKhpLqcewbS+l1bvzJ0ikbV+Ve9m4/9LZltXUxyS3DuEYCf+LgubkKgi5cDEphMhUH2URJ3BCi1yeLfEVUO1x2i49cuTLLV666vD6Zf5807jzX1cl7W0YB6ZeWzh8BdDPRxW0r560nn8g102WTybXJH9/DD4zsM2hE/9GX74JgD77Ktyblt3qfZT+E+SB7Flbe5wsV2axF1mgsUNhPFp4AEGkDnhvJ1dvH0rzxKXIbnBj07J3A3OvXuqvo2TnQ+I2v5y6hV9I3rNjYf3LbwlPljcW1Y7n+uz3yfXSJw5+snLhxVfs/3rassiwmNH4LNL6v3KG30zv0PHKhc16hF4E8ubRZ/hV6vXvp0fSsyzv0/cdWFVZWnuo/acrCDUQsqpeN37gc37rYconpbaYvIVB/hx7jfmTt4f5C31m2m0mpMwPPCzZQS7P9FBDGUiYa4BdPeafcRG3Rb2MZsc9Pzg/EcWkZqdCHn8B9nD72klXSL11RfjX3F6kwXDMFv9Mu4C/CqdVSNfMDLXAo39//DqbIQf1wm8dm471WKyhrIOix0SueHg94M86cC/2mThf68+u/5d7tzz0glL3dLx1fMFOUVouz5l00W8Q7xWnsYmn1i6/jHa9Ilo1bN21mpm/ctHUdoRNs+jFqt3yoAE1Pufycx2i3BwXksFgQxxZGxJNgzt0hIUQdB6NA7tZ6gjhI/9eGidJQY676MtkrJNmjC7I1J/ekHCXwjTzjyzvB9yxz9sUlDj/oEVO19efYunLPldIX+4aOHDFMWrFz2MBTOOZ4/gk8L4Ed0te2F5+QbopIf2IO/XyPtf2ofc926acEM9qzi9rCZvQcexP4nfVoccqFysqCVo+bt7rrYnWxhmRNhWzCoP+UKVhg5DlHaSLB0mgIoQSJ2xzIR/7P43EodaDkPTSaAPO3BLKXL1t09TJIGEpO75dld80Ud7oIK1dItWwGCDW+1zG37Xisz6ULpzfsuW7Dbvdy760TxjT1G7u+rfvtu1ePmRBNVBX/gsn0aVmb6FYULWga02PRsikX2RYnm8obXL5Y08S+S9dUrpxvWGV4C9vk9WwNzF8bzB+tzGj3kURRIGhV6xdbadDAKyXuGlHee0pkhaUWIC+V4fTgt+or66KJCvf8BcMi8aqmhlPWi52RniPZ5vVbLGvdI9I/naHvHOET0H+A3wN2YFLKYULIGwy6OJutKBqQPf3jaa/b2c8K+mVGBVS4zcDtbEWNxmwe45U8LzS3rgZd+LsoIvBwdV1JIl5p3DspTUsJVEfK8dW/tFxsLW8ZcwS3T3/ooelSUY9qE/T5H4i/fgvrQQBi+WkpD3iHnkChhWUNEG4WxyMGLylxC44yj30+MxsgV9QdcjhvcchrQ412tI/4qfkH4LJLhHr8Tas4QNznpFM7Ooafxm0bhg2jVnf5uI0rhg7F7ikLpUP9YYF4Eg+Rnpx5/J4rxrVevqttJh7SPnXzanvf5ZMovz0whpMwhno0JOWpjDkNXK3PwpYW1LK1Dckyi9VC1TJhlX2tYG64mH/4Wb0A39i9L6MGRhAM0e0jGiJRue6Fvcqhd1LmZ8EtTyUqE4WFPSb2HlFYXLhqzuzV8MeI3hN7FBbCD57EHx6/qW/bgMZCX+Hcwa21g/sNqrn4qitX1QzqN7i2dfBc+Nw4oK3vjRkaG3wI9vlTsD3kPXLObOEsYJo5mXRDHuld1GUkxVZoVcYFN+zb+NBDG/fhD3fdhT+QCl98EX8ildy1S9eHh/RhFGzggHl9Tlq4gkUW2gfbZR/y/W9lTXeSGxoQIv78wN69V20c2fZIRcmWWBW76Zfv7b0H/0aqWLgI95rxwsihr6JOdQ8MRox48pKzkTWZWSMJdngAqiNXcTtdw8VxtsyG2ThTfD02K3UPuE/befzPB7oPaP8T4O4OuG+luFMpm4ERRBYL2GwSWE4phMKBV4NFJKoZkZpsai3/4LuSO4P/uuMXpDRTL/XFH+C/z2Za5s5u/+Vc6ot8B+v8e5R/bSmn2241Cx6PzWV1eX0uu8OuVi2rO251W9zKSmahOTHVne6u21LIp0EmQ3OvQTdUkth0YWmsoD5xr+TWkXZrS53hYuPb0wiFc9pfJbGdFS9jTwF9PvCWVqcCpmAQDKPg87kchYLg9Dq80ZjX5VYu1fvl0l92tohlrCzL2iEwrssEHT6lqo2FbCwTV/Yl5cAuaLn8kmf+DS/tGQKs1rSpwiSTFFcGUFIsKkVjLYM39x8/deaihyOhmSW/ws9LU5k6GMzG/uPWdK8rZUauXzFl6MTJPQdUjZ/D9CB837o1WlpQROvSAO+PwdiCaGbKY7WwvgDjEgTGF7TwobCfZX3Ui2BZIzLa5VK3VuNJ3P04E0RBdfrrtFdqz/F8ihwXkHqE3k5pEhzDfZm09OM1Nz11x7UH7esjD85ftXFlD2yWirlPL5fcR3fe/sJ1W42P7VizfPN87CB+TxX+M3uPwNM6twG0LGWze72CzecDvQuGvITMVCy9wrvZe8x7ysvZvUXeMd5Z3hXe3d67vKKZ9XpZg8GlCJIBJ0FJzblKqntAs7NbxCh7qq48v+ieg7fvvQ/3OXiT9NycNCftZKfMnTOFw6u5Sey/pG+lHzCH7YxD+m97v+dff/519mdPvfYa9cVZ6RHuBTxWqACdJS8X9ktFiTLzjMFqMtkEg8FmMO6ZZjCwKRJKmvdMM+1TE5ChNxpq9S/AqhVh2Mak29sMwSsPv6p//eyspnvbZ98HvfQvkZ6KHTt58ujJk9DvlfBlk75fhuWBGXn9Mime/9/6ZRvdSS9bovT781nP/hqH720XoeMYHlwiPat0TGvYXiWNRgs6DqNq8spVBVNkERMJZGE4nzMU8nWrEIucXDVyB1Bt8kwDiBFOqhVrlSEWy+sJWTzIn0qpB3ldIYsIXV/8U4/HKmLwHywa9VW1xt69F0dLooWwsiQKyxqk0SmHx2YSjAaTw2X3uhxGp6cu1jdQ6LYaBIPF43S4LUZRdDBAr3SI+wTP4H8rv+FhMhrdHjfanXa7TSSpaBIE6660cECp31Qlc0d9XsZGLsrIBZz6Mr0wnlHcY/bshallV2/u39J96ozFA+L81JJuJVctaxlSXlcOfb3CvYOr+XdgXmpTAcxxDPgVglyjnzWyPMOwu9MMfVPQ8RLJSuKk+toW5kkVIFwt/VM6hHt+wS/at2UL5bf0DuDsSXGWpbwqTsztpoaqFuwURrVvzKjS44qVNPtjuKd0SPpn6gvck3tn39ItFFeWPgUXzzMChwEXV8TVciy5fpOLy10GdPFffCG9gtuwnXtny5Z956KJB7YqY+VhkC/l0SSWlRCaXvkiBUtgGz9xy9J9lKa5gOsAzI9I5IkRBVZkEcchA0Q/KjaBDhJm5aUZDfTQq5K9pojFMhGG24wP9Pnoe+mdPl/8g++3bMOGfctU/mXx16UCPMIc4kTowyBgddBALaptaHhjRkNDLm53GRDtb/av/ccXfXD19x/1IeNftm/DhmWgByukNrS043WwZAUps4l3OpHbCvrIotp3ziQJkQ10AWPpMVQSpKrnsHexEznG31yfcBX2aZTacKCvb3hdjJ3KDWm+A/Bewm1CO4UYmMTilA0miEOiQKq4I5ZUKn+zga4tgF2m0Cv6vSWNOw8flj4XYqtmz151aDxipL9Kk/GRjh8AhxWiy4RBNJuNFohwQfxtHM0+26zgeXBmzmCEf8FmCTJuct+b1NtRy00nnTmHj6FHP5iI5rJG8EWS/uYklj4/fJgpGH+IdH1M/kO6DwcPH6bv+yBydpwf5CpFCYScIvMZQx6Wtz7BMshj48QSXNXYSOC2SHXctdxogBuowA3seA85HmWZkx3PZZrq7KwMSmDvQYjbIiwA2BIKS27l3Ia8GbaYL2VPdvwuEy3mEQFHVRT38Y4vuP78GYAfhJBDYG4bKb89dI90ittCaaN4DP9mPfAD25OI7fhCw0HaA5zWnsAx38hwTMfHmXiJSYW7R3pGj4/5htmi4vsqE9Pje0aPD+CaVXzPZBJZfBdLA7m1wu0AVwp0lxmH4dMEHm3AxPcqSMEizZcy4VihBfi41h+yUHbKw6Zvn0L7HnwG2g8m7dFadEBpP05pH3aWMrGSGPKU4BXhCPlD357weT7lc5nM5453KZ8ZL3R7Emh1e3P4vL3jM/KWBMAPAXjg8zMIiY8xMPGtjSq/51P+lCl8/Js67l9puAgegMviIXBnAc78OMMnSgUX7VCZv2f0+ICPU1R872Q8enzP6PEB3EQZH1OSh68lB9/nzGQV31sZX1iHryUH3+e0X8DHlVXn4mvLwXeWma3iezcTdOvwteXgO8tMV8ZbmcjBB/MxV6wCuHICZ2SYDSSGe5zBbpgQfLLjvzBqbJYVRdGrq0D2Bwu/hDZDqQwM6HgRu2FutoPF86esLFPsLGUZXByzunPa5ffFMlci2oLBZPYxLNH6nlBXfa1Fff63vmD8cymfypXx30THj+1uq9yJgh/gBlMbMVSBu0Tmk7G4wOrJ5bse3z+ZfTI+lzd2Pnz/ZJbK+MREXS6+gdxc4ZCMD8a1Aa+h8OQ02b+IPkSpPvwlE69CJp0+XAXtBlP9G6q0k/XiVlhk3SkzWwvs4Bp6ytxQ2rwAfO9Dda5CsW31oHMAja18KQ6YraJRhaZnnGiNE2EB+NIFaEKquCAYZKxWHzXwhRGypTg27YMl3hQMXT8taEqZnPSciIll5EfLQgHHm13s8Tmzq7b8bkLnQibkgBAzMNOpcIk06VW25KcP2JLcWiXM1ueeI+O7GGRkjDATxldJx7cdlWIzHV8YxldZUMibsuMD+N3SFC7Cjwf44YR3xrGfI8Lxeifh+L8zsAYW5MATua2k/KvSrQ0Evx3wY6udN+fw70mADwL/PMDB/qk443Z7Al6zyeT1sBCP+K6f5oX1lxPNHq9oJ7fLRIfy2BvN8HQ6tAROtEdMNiWjwezdkjhh1ZMnjOziv+OZJxavvuyuDB72Kj+oo9f2N6Rt7bXME9deeeL29p38/cAi1U5WUvmtUuxfuyy/SCOfwj2p2ckROjiwL7ijPeMLeEzqukR5crWKzzgSx1VdpoYDORW0qi5DICHz5WrKlwI0NFVKOFMQlHkT9HCFEV8oGNqT9gZ5hTccsIbV8l+tyS5P5pyTP7FOPGJi97b/5r4u2PQmeUeUjP860C+NTw4BbXDJfLkRvmt8Id8jqh6v0vOV+Yr6IoSvdn8uX1fp+arAKXwNRDW+vg72A1N81Yr9UPBhb8wsZPHtpusAwTdSgdsg2xnkj3NMFo68q4ipzaX4DD9SfGFaGzPIE9OJ/V4ZsTxVKn66Tp+Edt/CeEvRkvfJKr8WDQdPN5mKQTsTNbx7bHiLDa+04dk2PNaGUzaMbBaB2JMZ9B8NqyIzp6nvUUNlZhh+D1GrhZ2gR32tjjw9ou/bCy8iM3jDU1I1JozN5Ka/zW53WkjFabPZwrEut42EXDYLrz4sZefB1ZevdSk+d+sbVXn3UbL33mLZO29MYzOEquwNuutub7bf/96vpNfxt3OlFfygn/5Krrq138y/4flz4XuaXp2m81Wj+HvV6rz+KaOqFsB9Qf0UMl+jFbiACveeHo74Hzp84FfcqML9MWPT43tGjw/gNqlw7+jhvoR+R1J8tUq/FSrc9xnRiHkZDpsBbjrFN0aBC8ty5zZb9fJE8VFbW0vWHxmfZnMNxxkTXypPIIuull7jpgszaTbBicakKq0mE4/JwQLeZoeJsztIaGcQx6YNrNk0fpqZTZFHQMemWeWeCl1JUJeX8urrSkgBDfq4HDkM4YY/mY/wZT9V4vulP+HfPp65p/09pmzXrl1cxa7/Xvnww6Jvs0z/M3p+AN9uV/khZQx6fjyj5wfAXS3zw2PJ40dbDr6zzEEZjrGKMjIKR86E5uA7y+yQ4bxOsx7fVrr2Eh2pU3TkjKIjEdCRK0KF9kDO2nQRwM+j/sBYJGvoLQp8N2cpvq2i2hLJgZfxL1Dx69ayArKWhQq6xH9GwS9QeAJdBdjZiqosdoIbZGME5UVd3hqjoZVxAtw86iONzYVjNIR56259Hq3EXmC7U7Dm0ErqllXzZ8BajXPTmKwQ5a199Xl0aSjk9gBXzY1W2hMdcGoxga49yIJq4x157Z/Rtwe4DZrvqG9/lvmZ0t5rz23fltP+LLOZfl8A/s0CasMbqExwtH/q/UaICUeRSgHl+c1XQJthwn3QZjyx38x+LEvTr5AJNLEX27ClsHBoQyoUht/8fvjN6RnasMXhgL9ZrfA3iwX+ZjLD34zGoQ1MgBh7VFyb7cdZpf7TmKVxgkYjr64zHMuU8qXwOyptUFrr1xmZzj15dBJvwoQaUwmObSL0NBF6mgg9TYSeJkIPpydIo0jFm88zJsuzQplnRefg2c9UWoxUOo1D0V86foV6parYohTwrCgVCA8t2gI8K0r5fPCbxwO/AXlFhChYVAOCGr86O/EnSw+bpaeI0lMUOQc9S/LoGYbX/X+gh+jWLGpnkgrWa2XNZsArYOLegAHl6NZxkM3+1M5MIHYArZ0lQ1dAH8NLyi36mF3GvUDFreVSGD+NaT7PeP2GnFwKxX1Gxc3cViDjLgPchpKyTrhvpbgbc3EHKe7XM/4gb9XBf0PqrVHck2TcxbL9CoL94v1Bs1ePG/T/Vqqnjbm+L9PxmoaX4AQ4L7VfkxS4QnUNYTMqThUfXSsb5bWS4NOtlWxYWStVnDQmmaTAFsqxCbjVsKqGnQRSsUU6GhVbRGl8NRPI0ngJwOloZL7B12RpDGRpHAMytojys0nhp1OxsXVgYwtq6vhcOXgA4BOUn5NlfrplflYCPz3llYJ+rsbAmBbxU1XcMCZJtntmDa2ME+AS3AgFJ7G7RhnOoiGkcDKtT6n4jAIzTY05mkjMMaW2kc/XIZneV1Xc0GZch01uU0fUY2BFbSe9k/v5XutHZNap/TSQfsLde3bdj8Bq/YjMwg6r3Kaa9INrunfuh/BH5T31pRidTMOs12flg/JI5bsmSzL/AbJKlY+RWh6zOW/NNJM102jmxZz5fJbUeaPwbQr8DAUeFAov8gexPQd+pJbfbM5bSzXUMl7pFKkfp+IFuEdU+Xs2o2Kl+J7R49OtraY8fM/o8QHcHhmue0AlUaGvLQdfdq21G3PxteXgO0vnGOB8hX49vl3Si1wfiq8HhfsU6FuKrE9AhOv3ik4t1/wkwBVxPQFuig7O8ShJof2QKSoMWrK55l2kLpsOZzbGC5fJKNWYsS0H5z+zMeOPmXitjLILfNkxB93nwyfDUXw/ZGLhLD6Q5T50reqR628wOETkH4dK1ZFrsvwktCmi68mUHH/jcfjx+FQj00L8jRbib7QQf6OF+BstxN9oIet7C1nfW8j63kLW9xYcctLk44+ZRH3A0pXLgbqg06CLbcNybKsyIMfnkGmdo9Iqr6toCeLRZ6iUtC5OFRUNLSZEsDIV4ZBChUyGMo8m0LUXhLsATwvtfxQOKN6xB3QHeWJMbt5pEMBfw5OcX5rqLvCIQnvBdiJvMaPP85lAz16gc9qSp2cWmwIo4wS4a+icps8LRx5iOkPzjT3paAd0vEzzjDgApJ7seDkTLDD6df17Af4kXe+n0vV+wLUkR0ZYAtDXZsIRMZgztnz8a9FCwE9GRzpYGAhnsaOu8K+dKfOCdDAjVJjFruGeqeFegjD6RJbHAM01FYRk7Dp5lPFv1PAvwaoEE8lCkQK5By1fLPexQO1DZzdJDhEHu6b/jIpfi4sKyVyG8+iHOZL3q3rmzZGGVsYJcCfpXE7Ng9MQUrgE9H2I0torb80m+Uin1W7gcmgF1nLLKK3Tcmi1O2n2kjXraJVxX63i7iqvJ2PX8VrGv1HFn+W1m658TqUHjdekjwcp/b3z6LcA/S6ThTPk0N8f7NZ1lP7pOfQHCP2+gMmpo38Y4N4mPAiwfSj9w+mdOgLtANylTjNjzMG9l8aMRA5nUNzXqNCAW3CasVGPG+ZnG53HPoqfYlD8GbNVQSvjpHFkTwUngbMosb7ZinVww2Dt0+GDNW2Vgs+Sh+8ZPb7sGilYcvA9qe1JjVDgVipwfiVxq1/zZ6trH+iTBX2K4ik/gwtT5eVDC4n5KySz7QsriyuwoCpXtwSzJvu3qxJSSHUrGsrTLTp/FH56LjwNUFDYa3LmwG8B+3wt/62ybyswm39N8/N9aH7+7UyfnvLGrZonxHuU/QoH8qC6lAthj9PgxKzX53RdP83J8xa6P8Gz2Ivyi7fV18WUtzLUfQivW96E0G1ANL7KnsnuO+C/kZQ6Oad2E9C5iZ8M8jwiVR4KFztc9N6ZQwjzJaXO4mL77HRxcbioyDsrXcSFXZxxVppzZ29gnOtglHyrNHskqtmtUOaM07oFbhzB3KYlz2+6Zn146tqtl910ewU+W3LVwNnrepx69zscvV+SDjyO92w5NT96Z9muzVeuvxUXNPWf+dgDP7WzLO6DfVKH9EvnW4rd1mxTIsfmMMju5HT+0haA0+2lA9wXatzxdqY+Kc+Iakfpmizvzb/OblXiSiJQJk+Ay/U/5bn+Xtujf52dLZ0ms91KZ/tMpkk32xr+kIrf2IN5Q42jaTp7YdihngDQ5JX2IZSqfRhTzCm1TS+yxPfq06AeBdDa5PfTgtvpvqjSzcmOWzIur74naJOi/US1fvrhLzt+oG36OGmbxZnuLfqeuuinJ3NApS1BOupV6j/HeBZp/fRnHuj4Vm4zhHQUH9ZywfH0yuYfymj+wVd8jn4+1foZwIzp+J6Op1kez5lM/2T+eIg8UfubyIl5iV39DnlTFpbyT5MudV6pfFE7PJD6j9d8J0vZ76FdaYZpdJJTGG+njL36QIdMtAm8kLfIEQ6SOp2hO1+QP87e2XF6aMf+onOM82ttnAOZ0cpc18njfD2TvNC89WGW5PTD/Q/9DGKG5/bzyoX76Zsdj42Oxxnsuh+qg3I/g+nev66fdy/cT2t+P8W15xjPV1o/Q5h0bj+/7aIfKh+HVPmQ97s1uwPy0cWwupKPW7+U5eNjpRXtUUz2ChVprbTcr27fHtbiUnlNtFrtufv2p/T79gDHy3bQUBDJ2bfPPcMA9mqv4jEQPxG5fNicY9/o+QVq34Yq8OvBvhF7WAkGjo2VKMhz8At3avj3wzpD/XQf9dM/zfjiWO+vyfgPKfi1mIJJkKW1pCGLXcG9i85xuWI7P1ZXYpKZw7OCti7PX1xFbedQxXa+q8pFKWH5qvJCuQ9dmyWUR9l+WhivcqbEL58p2ZdxuPPOlEyi5zyy/fQj77hRWSqXZWl/piih70mbi2w/PZnj6niKSUf1CW+X4xkjrNH66c88pY6ngXQ0qXui03jy++nFrFXGUyKP518ZT7TLMzJfaf0MYJYh/YkVQ7dI536IrFLbSc+EyDZT24vznyDHNUh3f8m4LPKhEJ2cEfnVzoWA/RRlKXYo+lFA9SMWzh6T6XJ/GORzba48K5vOVTn7wuDLGf6rwksfEfkM0sjwi4zDo2xnyTL3OtCl28/OOXeQu599Sr+fDZQHFf2DlUK3P7YA4BbQnGJDnr/iD+pzhVcA3DCqz+Pz4IJhPVxeXj47fobMLSqICrn5Tzknb1bxKuNXs9UoUpwHT/Avo7LToOjcc6ocxIihmxoPdJn330B1Ybyic5qPEyfTuLAk1KnNMDqObD8t+DtFf2Kyv7I7EyrUt4I2U+hYsv30Y3ilTYmsc3dnCmJ5bRbk9dOTOarSVk06GlrT9b7KcKpz4xWdO6G2IceVmLH1sU5t8vvR+Su159/z+krrZ0B2TS4i/fCV4c79EHmiOteQq3PaeuSn3RX4sk01+aL6Ju9bXaOTMtIqSDfMIrrJzY7rM9IfOW9J8yRzwS+iFhvkrTgaF5z58sazpB98kZwnma/bG4mXCvrYNx/3gI7DxOfKkB0mmM0lmVgiBz4f94CnaJxVTD3vpzOJsi5k+TOiKzJ+kH1yfg9a1FD8b2ZKKjrjJ7pC8RP4DdRWKCetHsiUV3dB/34N/37ZZ8ww5RT/c5mKpi7oP6TST+EBuopivzdT3ZLHSzLXn/FbVfxgY4Ts/k60WIaW55Znie2Q6dbvAx3MxEs0uF2AT5d31dk2tzc373pKn3fVn6n6IRMuPFfeVWeLY8QWBwrE3PHIeUyzls99nV0h2+IKaou/zUQTMm6FX4CfT1D5uFiRvcmUv2S1BPhPMpGYS9TBE/zfUflYxVPZm0T2GshWD1LpzcE3oOMuGV8hxVedKSruCp9DxTdgP8VXkoOPytfFynjSdEZxNcW3MhMv64xPMCv4CPxCGD9g7O7U9k1kGu/UcO7veF/2p8oozoWZsu5d0HhIpZHZ305prNVoBNlIUBm6WJnLP6pzuTwTicq4lDn/jusp4yFnCZi/o2zu65Ca+wKePSXTY6T0PJUxWbPZLy33lVFzJ2jAy5QjXjrDr2R8QVOuTCSg3wepTPZWZBzLMslpabVsTo3KJOAl9HEVWfqoDPZW5uBieQ7kPPGPGbu7M31abofAr5ZlMEEpbM+Ei3Lyc/L479Twy/4tkXE3kXF3tMvc3yEtd6TmzItI7q+oOgf3Vpi7PUKdq5Sl+i1ej9rRvKxFeCNTVcbbzwN/Gn0rw1c75bPodVXnhb8b/RfgyXpZL6+Xv8jUKz1o62V+myPoC6VNg9zmkUzThdocwPW5/fyQqS+/QJujuDS3n68yTV22EYdrbe7BWGkzUG7zZqa29wXaHEPfK20GyW1e7NyGxpbUtyMxnyBef50uJ6H7fnov/S515HwHPku/7fL7kXN8P3CO70fl7x0emuv/TPt+T0dJl9+Pyd/RMRhzP8rbBbJc4XIYs3rGytCtwpSbb8+HP42tVK5wDdWJzzMN3bItuoC/W5k7BiflbbAfMkmlD42n+W2OYKfSprvc5tNMjwu1OYAHQBsaL9GOCpKVpvzcfn6bo3i82oZ2VNWjU5uOISReonwvp3y8XppIcRkQ4iv5M44y+P4q/cnpjgJE27Q/l9fm7vabuvx+5BzfD5zj+1H5Oz1jEqTjWKTMYbEyhxFyciESsgQ6nXfRw5/GFQo8sTyeeOQC8HfjkMonGoqjhNKDjrf5bY5k25TQNhUXbnMAe/P6CV+wzdFsG6Wfc7Sher5IsQ1OtU0zbVNce8E2x3CZ2qYHaePr3IbKSiWdryq9rHSk8r6flr/T+dV/V+XkN3nfj7Qf6hJeLyf674qctN9Lzxx+pn2/pz3T5fdj8nd0I+jHDMrbJcqa8wdZ1+UV+pmM12kTdLqeD38avSvD+yj8o5mQ97zwd6PPFD0Py3r+ZCas9KDpeX6bI+jPSpsCuc2JTPRCbQ6gT3L7eToTdl2gzVH0p9x+nshEu2xDZURucw96T2lTI7d5PBMsvUCbY1qb2nO1oXKF6fxWd5Ir/Xe9XOm/6+2P/vuRc3w/cI7vernCVH6qO8mV/rsqV3IsW6fGsmCvbLL9YegmW2Gwy7xEFv401XECHyHwxYUXgNfslZJjQPHgOeLrbJsj2TYJ2qb8wm00e6X1E7pgm6PZNko/ndp0PETyBZTvDcp8n6TfD+Z9Py1/lxJ53+9u/6HL70eU79fmfT8gzezy+1H5O7oXvg+kurFWsQuSrOfyCYpPMiGfqD8rlw9/Gp2V4cMU/kymKHRe+Lupr0t0IirrxO8yUaUHTY/y2xxR/FcGx+Q2v86UXKjNAVyt2nTakTHqF/PnL7/N0Wwb2pGx5BxtqI6v1a03Oh/o20ykqivadG2O5ftAndtIfyDxB52v3rI8tH+t6a3+u6rn0/O+H21voN9voXHMZ9r3Y/J6gxqBplvp2Dfk6i2xVRjVVoVyz6znw2t6S44nYtS99gLwst6SMTfKY+7INCp9aHzKb3NEa9Oktul5oTYHqP9D55B25G6s1rfokraj2Ta0I3fPc7Shc7gh388YSv2MZOqCbY5l2ww7R5uOh2C+9pJ5ZKfm2oe875p9yPuu2odi+H4DuWPATu2Q5eQ/sh3Ig9fsQ953xT5IafKdyI/y/R5pSZffj8nflfhO1OKuU+hhfbZrfaa8i1iV7DtReIHtEdNBS5mySt7eRcwian7+KfQ7Oe7vRu3P8UxlFzELxb9Axj83e+tkTEV1Dqzsf4qaX3gKfSjjjii2LazzplV4inuRjLsNaZ765FBhDqzsg4iab3AK3YV0GZKNGVcX/hTFvUTGHciewSMFvYXc/CKsQ6K2Dp1Cv5Z5Xki5+IKWUdfD072+8RrP1RU7GiwQOttvUbNdp8gt3ez6cDDj78LeU7rXyrhD2fNyZl8wB1bWQ1HTj1PoKRl3LcX9YKZaZ1VUeIp7g4y7F9IsVktVTQ7sVpgbLc/gKIN17Qc0zymyAjNQL4+dcy157U6j73LbnSvnQttVaO3uRt+iGVq7C+Re8vo8ktPnBXIweW0PYHde2/PkYvLaHu3U9jw5GdJWza9A23vQv/Panic3k9f2GPo6r+15cjS0poaaKykVr98P1gdaLkIIdfXz07k/lzpyfl4m52xUiC5+fuQCPz9wgZ8fzf15h4f8XMvdlMk5nfP8/Fjuz3NjZCLXJGdDeEfP9BqOE+Oj5pTzYU+T9ed/hL0bszpYU4aG7WQSuoA9gjr+Z9gDOPo/wx7FsfPDigM12HsAZmYObFMe7HAN9lgOzwhsswrbMYTegVPj7TI5HqP8ny/HZXk/P5378/bn8n5O47Pz/PzIBX5+4AI/P5r3c1LXIRv/A18u8PNjuT9HjfBzzTei8mVTdHM50u0wdAlLfcL/EZb6gxosmYNGbb7yYY90gm06J+wBnPyf8R7tBJuHV/XdqHw582CHnhP2WCfYYZp8PQSwWT+rTPbvKP/Xyn5e3s9P5/5cSuT9nPp75/n5kbyfX5v3c+r/nefnR/N+niY/1/y+MtkfPM/Pj+X+XPH3Mqq/R89VwapaSlfVP2Yq6vP8PRl+vApP7kAQ+DIFvrwiH56uaaK2tpwip2K0tcVwnPSkyiSFJfunsq+qwND9088y9dW8eveHwqk+KnjUPYpzMGp3mmRaD2ljI3tAQGudQmtdn65oVeHVuyhZvHUq3uydhYSu9grx2Gzk7Id6BC3vjsNMDX47YuQ6I4ydwDucXcKL2n7CqY7Fun2P79XvbA9pbVd1rRQ5Nz/ONAQ92llcUgebuwo/y59BJlSYshhoFUCLgTyajlrfaKnVFZEnL2HF++LGeCN+tqjb5m41bfyZUW3LG5Mj4/eRuq5SG/6uYyuyoHDKYhHMZqvNwI5LG8yo9g21YC95cStbKzOJb/EGbLHq0l1X/hTzCyvNt9zw/4+ejr9xjzKP879AfhRP2T1er8FoDHh56xaXEe0lLxiG3qCl1LR3VGoY8oxTvC+TbIjAr+akDeMvKieOHlLU3GScZq4b11o9cfSgyDzndOc87tGSbiV9WxYs7gN/rtt3KalP4OReZG4XnoO/iagIDUxFRQ6xHOsMFxQ4nM5o0GkwFFg9XArzHL9nGuL2Ke+6hwKOMw0NpBivSk22bpxS7NCtEYc14hh86t72z+77d+nIwf0KknWGCdYZo8tHDk6Fp9knWCqHci+dPInhP1NxeXGP7ltXwR9LZ81syo+fqO49IMuH6m8E8/wNqnuLZPtAYPJjKkcZ24Pc6zgfDqo/i2R9M8nxQBziAWO8rotY7ZCGl+JT2uh0TfqenmsUtX2ZU1IVtcsNdL/me/U726O9jdq772m+XdTy7Xr4SgpfpYfX3bGvUnRnhbzvnfS7tDosiEGV3FXMcpBVHjlQSwriPcHBcxyDHdjpstl4bCKvDVuOT3PwSJlt8hZd7jtXRJLjbGMylpVnZvmqX3wmvSULNfewBUdsmmBr/V6a2y/LcUjpF7MmrPSLz9tv0svGG1mdHt3w2S9WTVR1ySb92YKjuo6Zjq+4jcwzwmcogOJocModCwbjcaPX5wPdSsRi8Ug8At2mjNNAx5CPt8ZP4iGoVZFu5Y5CVsidXSteE9E8UUfUN1klrB3fWj1p7JBIU4NhuuOifQqlZwsThd1b5lzUUlRS1Nhj+/LqLM1ajJ5RY3Tm1idp9Oqg0ev9GXfYlnsmUYYfr8Ibx75K4Z0U/vGMy90VvPBvGZ7UtvmlHCXfAvGS5QTLkJ7odUEN9rMs7OtEunogz7lgqS7IdO9/SxfR/yITKuuSjue03MWNCGIaFEkZAa1fuXv4WCZWbdOX51HPbNIza9XauvWddn8K2f15ZzZl+JkavLZu0fpf2GbPhZe+o/CitidxSqJnQzrW0b2N79XvoHt3dKVTBr1OGQw8UGX5v9CpuMfnj9fgPljWqTNtNSAzRbJO3RcfmWxaPnlUlzpl0OuUwYBZC7b8X+iU1i/VqSlyt6pO6TrO1alhqYKwXqfC4XgR6FGK6FM8XvQ0tqBpKE6USi6Vm0zSVczV8j+rVZauc6rVLQqxndRKR7aWQ8qoOSTFR1QyZd9mAlExd49Ihh+vwis+orJT+W3GH+gKnurVWllXsKxX76u64s3qigz7WS4s6NWgLmD3g22fSOOLVUpO3S2f00lQD/DbTCKaUyMiH/40TAKFL6Hwn2YqEpbOubVDGl9k/5Ju9BPsRdVdjvM5LXd3IylDrehtgaK332ZK60WUq7e5Z58E4xjldB85+oUsnpxzVTLsTO2cVFZnTQTanHdHUnqawovafsQpeV9DOkv3L75Xv4POurV90Fk03k1m90ER2/F37i3mef4T8v4ZsqLGVFDgeaPBYAaWmMxmm4XBzJ5pZqOAiTP0plyQTSfISo3jxqRItRkUK8k8f+TI39c899gvjhzh3nrqiBWLFunLp7rsi+N5sVNfYECgrzeT5+6rhGqwqPQl3fjYc2t6087SFum/VutTxGc+zb2A/ySIYCtiKRPiSXV8QeQZsA+PTeNpIWvdq1S0Xjbe99qvBkGraIn0h5gu1ha1ePQUOq3z07WTkVlYboyag9V8eVzfWBfS1fyhcGrulcRAQ1HnSF/L0R5Sc7TaObjudJeoX24+l+I8pOLU4h8FZ3cFZ0cd2bukMtOg2Hk5F7OO7ml+r36X7TyBp3sTorY3ocHTPY7v1e8qPOpFY96p8nenEqsSHrTUVoZN+njmIWYg/wLMDcQPDEtu3ggiu4U4/aE3dPPiJvXExW+v+BU08GC28Ado+wXEHk/Q2KMiZWXk2INhkIAEOrUkBlHdGF0ckrWpx1U7r5lK3PE76StUyYskQjiBGYYjhZxlcw00OOPOyom8+N+/CgFStzwKsB/xVyMbeFfFZmSyWMxI4BDPsdhuZc28jWEMLA+rIMtio4gBESlbXgv41AqG4KE26B5ed8edYllzWbO/2S/6xbLKiZubDx1S/tssfcWntzQ/+ECPw4d7PPBgs1yLuuP30lf4ONBgQnUpr5HhkYFlEeIFMydi+FcwCYgUYG6hnUI80qA+10jrXDfHSTnOsmZ8/E/NV/5nPB5+ZTN36IPmTT8s4/+8qQepdT0SxlhO8Ven3AZOMLKsICBsJtXHjZgOSn4UMouc4IaRxGEEMI5Y+fj/XNn8J8CPh8MQ9m5q/uDDHptoXbTR+C32cmalQ4A1nMjMYfwiV8yMdAnib6hsKP8Pc+EDvWU5HqMn0/gZRWFJL40x72H2UvziddcRXnwP8L9T4UGSuCw8VorSx7wm7qPO8F6w3yo8qu0SHNb+H0Gm3+64ksaMTSmryDBGDmMDxz+d5k52PJeyGR1DAcfTaUyqEhJEVSgAv2nV8evrREDJk1/c736s5H73h9mz35g9m7y9sJOdybaCLLOwlthY8oofw/EI36FKsc5AxTDbekj6N27mz7TfQBUb2u+G9v3U9tBYfsOPvWMazm/vjgH0IWyUXmNnMsvbb5Dbz5BuZO2YhfbRlENrj+6YxuHbp6GqThhmUAzSjTIGjHdB/ym1f8SS+hukCvod05i8/o045mZell7DxkPZ/hn0KDuTC9H2IkqmAiLH8YLAyIwwGGEkwAqRVX053RN2OrbE4BdzEWUN06DjkMwlBj0GfYSVPmpTPl6g4xQQxxmMIkuYxeNOPaieIgw6Br+YxXTg7W/qOCiPAvBL+7gwZhT5CCv4RSSwpAdwThHpwUAZCl1o3fgv1I20L9sN6MlRGAdLzlKK73dEqTV+H9Hnp6GHxzuqOB9/GplhhH4T2B5RtFjNHM89nzbxIv/CNBEIrW3N6V/lYJzlG3k2yZZ4mSO21TbpFrwo9GIIL2Y//HE095jzoBsvl25wH8zpx4vGpiqR08naRQtnsbM2m8/vMlvMz6edFpvlhWk2hERBfD6NBU54YRqHatWeA62deKAS4i1xx91Ailujp4R1cz7pZqCGEFVcrJEm3VxcjCsPuqUb8HL3QSeei+dqdDqlO6U7iWyOxdezG9lngCfeJ5AgWKzkCZPaZK32rqX89g4tBcBufGDVinvvWbn6fubwmoMH16y+6y5az3IN6MMU9AGdWzOqSfnMBpIxYjkDa7GCfCKYVZL2qm1oUF9pyr5QEVMK0pJf7OGj7U8+3H7y2Af0H82Gc2/DGuh9ggOZERDLINmk0iwcWXdi3soJ+A/cFcQyjwG7PArscoXSBoN8CUS8yJiw+thODFpJo/AfJnBXjPkhwu+V1wsXtDvLb4NRRFIWxDA8a8DgEYFqEUOumXHZgpN+z7408SX8B/btHyPcn/FjOTjMZE0w8QaQfZ6BiIu8DcIaBZYudASXblHQYfTGVKzSGrxDxTxG+kcu7pqUBwuCgTWbIbYiz4vCDBjpiwW1GnJdKMfScqC0h/hZvANQ/wH64Iqwd4w0mnRBxi8q+ddtMI92FEIlqB71QUPRNakxoKm4Oh4vLSzELGsd2KtX30ZQLJ/VCh4hN3xYQ7/H0z0anpjWYwj8GQxXPJ6Ohp+YRl6p4KLRWvi/oCn4eJozPTGNc8OffwCjV6U9H0MfGKf/V5VfjNaVU9fUHcdJTJ/3kQVS91yyu8HZxdemc0DvvZ4ZsldyrFmx7uJLLln1h25NLXUNTfMOfLru4tVrV31Y171HfV2PZAO+iQCsol8IwHy8g9mM19+498Zbbtu7b5/07typbfPnt0mPS+/eeMstN5Iv89smL5g1I413EKBb98mfCBDo2ffsKOZ31L76STxEFjBEzL9O0+Jsknl4Z8VHALmZ1u/wsqPYxxWbHIOVj2FEmHQjcQNp02Rtg95GQXvyi/35rvKPJK+CqH0rQ+u73s+O4iqoXfyb9Ajdqf4bJtbxb3gCXeOmop3sDPZhZEANKT8yGIjaYGw0MSBnsLSwX01DZxWXsU9tMmcJqK8rwY046TViL3NYegSPfVR6FI/biZe14tVF0s+l6wsB/3LAf7GCP8AaBB7xBpZ0YBBZct1M6KoDv1rSNt5oxI1JwB99DI+XHnkE0BfiFfiSImlnKxVb9CXQ+BE/ULFBdtQ7VciQosjE8bRzdofTiDFj5Tl+f9rCmUCggfNa6kP/oJRfYSUpnqv9efu+wEuvvMAE6R/gjzzxwzOvvab+SX39H/mHubcFi0tE/WEw19J14Ax5tIgfBDQVgD3BDCyjsO4LKIB0T9CTSisg2P3XMqdWAyyMhdw2ZV5V5p2MZWiq1E4qPFuIEXU4Lda7phkNd02zGC1GiNi4u8jSjO+ahly6V5lktVIf8KNPP8q2ltX9YvgX5X8++ID75wcfSNPgV1q2u6qtsZP8v2AyGSzgAtktrNWKTDyLrA6z3Q7GjbMSJtPXYqjlUU0PMXL6dYtNOuPg2sXpi8bECr0EJu6ll1QrBAZOs0OM1jerWDpRNIIfYjSZgAHAAZ74r+exdKxTNnX7yfs344ipI31I+/FjmrHDHQ7o42vog64rYN5gDcZqNJNsoAaZjbGVE1/BH70CrnkpWTaz7baDZwRrhIBhSRIRedmH6bRGEBrCGDB8/bVix5+UhtDxOQHHVxA3CBA5VKZcnMFkwiLPQ/gAdJgNlBBtXGSJkDecgCQSNDSXif7KiS9/9dXLEy+//HKgjT/x4YcnTlx88Ur9vFkh5vEZBBNrxSaIt8w2o9UKasaZs6uEwjy/+ryqPEf6GQpoEyTdoc0PxvNBs7Zx+8G/6Z2KWg0GI/IavT6/1enk/pJ2Ou1mbE6ZXUPNRgcoAaqd0VBbNSNZq3u4TfHncl6WVV/EZZmmwUMnbeHWCUz8ouHL5zAi3jV18LyZ0j7csWNFv55L10tjID7CHQvZN5jLHSI/t+PL9h00ZirqWMIeYbbCt0UIte+i3yIdi9ljzBb4djF820m/hTouZY8zqyEir2PmKXBFAHeEwi2W4YD0JuDXbv4dFEFLUi18AMZn8KCI2eWyRzwBvijq8Bq8s9NWg9EyO203YDtLnvfxMB7n7LTHhVCYCc9OE0sjZzizekmescv6d7oXjSlXlHXKLzsDyq9SxtndRaoxMf/pdnz/dT+/lZklTcJXSpfhl9qv/eYr6W93vJXgHr790WdeOonxiR3Sb7dLT+7Av2LAMPD/xfz124ifdnHHbm4t2JUoIpnq61KDy8L+gMtdFAVPjbjCVi7qDoSFbjVBX6IiZuQZn6fCYmQMyGKwwMg9AZcjVWpymGalHe7KOIrPSrNFEbC9rQ1vNGTdVlKcvIGG0aBOZAOwxZV9liCnVrkmCD5/c1L0QUyMm9x+G46XifHmUvjNXep0uFpx0l1aBjCsx+8WGOatCYPqdg0dVfegV/rp7aV3jf3mQFl4V/Hwwc270pf+47P4roH9x0tf1E94z/z6yvn8ZGPxge/HbejX/afrWOzv9/xxPPMSX8MzuPYEbsIpPMW7VnoiKf40fnScMS8cwTxWJXXIsQJ5O2MtPxVVoJmpBhQxeL0sk4jH/YGAnYlwlVUW56y0wWLh/XwiwfvZcDRaNisd5Rhv2DsrHXZnH3p0IT+Z81onXW/yq+2Th/L85M0qn/yysvpqlcyHKCIP6AFjSKErBvd8SThs4KpWLkiUJHqvXHtqARm89F/pUyZw/+eDHizZv/Ch+5hD0tyL8H2rtp8s2bHAdJ/p+czTHsyTgS/BE5hH7znS7+JtkiSPkZzZHQlrjhNNSHXjsdFoMzkYE+tyGyxWEGneirlZaTs+hRmw+9iKjXY7gg+s0YVazyfNipdNBJf8S6xJYxL+D+9hDrZPx9dI608dO8Zu5A5JA+88vVVqx+xW9vk7ZJrGAk0LgO/V6O7UyNKieNxSwXEOo6UaoYDf4u9WU2oym1an4+Zim922Ol1kbzWvMG827zZzdju2sGa72V7h8YRXpwMBj8hXcBWr047qaDVTfbLjueO+0qHkz8cd7qHV1VyAPi1cNSPnTUZlRDOc8oCSnZ6bzD5HjWGGYo19MX1PtpH8Ut4dJrMlkHdb5H89YqyhmVvgfGRP++CFQ5+Cf958ae+rxUc9K4auWolvkRaRX4fwJ0cLcfNNB25r2viz4K5bdo588bX1y1paR67eNHHnLbvE3095hPLnoo4e3Dw+hSrR3FTSbbE4rIXlBRBKhyorORQuiBcXFyDWyldVh9xuf7nBbxibxlwFay30O+IMspLnH84kW4lrLY/PmWOCqKa6WlSXMtbIxnFj9rl43TPx7qSoPWBehVkn4z6yHw+v75cac0i4UWCKF49qa3M/fut8fu2CB+v74V3vSrNZz9zbNj53sP0AO+EXlZvrFsyYNRcf/+bht9trmaO3bZQOte+D1TgI838MZDKMilAclcE4b0tNwrHiSq4clVdUsPaigjIuYbNFWfBIWC5RWooiTl/Iybo4V1U1EypjBVGYlfYXRFkxXuQDYQGJdVew5gQnlputolk0c04rizgXeQgjqVopJ3VXaHSalP/iV6bdr066nIlQ31akz/XGWEW4yew7k271qWGyhGL4yCfLyFvlcexPsgOfkV46fB3888cn8aCHr4J/pBduaJdOf7dkOzPQKI6UDLZB+FZpIb719s9vx7uli8kv+Ku0kOn++eeft59MXc28naG+breO77kM8MgIWtKIhqE7UuNh3n0mp8NRXtAN9Wpt7TG0gecFYSgqMPEjhvdtam66JF3uK7IWlV6SjseLino1t7Q0N3Cr080NzQ1WsZ/b6r4kPRgWOGtQrF+dhjBDLQkI8YmiA7JLSZcyYEStqi9drWJZC0cTCFXkYaNkFOe+aVpWg/UKQ5Y8HybCBD5Pkzv7tLT2ZDcz+PD1fQ78Gg9hls+eOnyueamjT6i4W92ofjPbBk8xLOPj7ubG5Lafvh41rkdqxIjg1F5DbrxxYLdwsvuD7L/ve6l9FT/ox0UT5k0Y65xSUp7oG+s+v8eYyZOHWqrjw0pa4mnmffAx5q+S7piza9ccactocY75AL6B5jcCsBacAX5bkQ/1QjtTIy0QuLiJ32u12oyRwsLGqvq6uN9fV2Xk+N59GuPdQt2Ss9OofmU9Y2br67s5QrHZ6Ugk5LYwbmZW2u3meN41K82rYqgrehjQnjundpVwOJ+7uc+0sMRbk5+9Fd2syj+V1/pX0eWlpFRmdYTBb/2mx5FfP/3ivJln31+w3lewbCnr2r/7iv/D25vAR1Fkj+NV1df03PeRSTKZTA5CgIRMQrgkrVxBBMLNcCUccomAgIDcp4ggGDkEVETBC0RQIMT7vkHwWtz1xGNdb3Zl3ZVkOr9X1T2TScDd7/fz+//+k3RPd0/3q1ev3lld9Wp71lZXVcUd4V7jR48qwt6FW+w73Nctq7h+2thOpCL+otD75SfWHY/Eb+NOzZmttr0x/qdddy/bEho14GBJr9I2OYNuGIpz1y9z33Hn1de0aztkEdBPZAHaqaRM09WoOqC7lNH+SFYBn+/zeZwOK2/xWsz52aFCxPESbwga5EBmRi6fk5YWDOYU5nuFomLJlFcAgZytOsanZ7Xj7VwoUsi73K7qmB+57fBnSfNyOfn5soXSlK5uo0t3VBfnZrFm5AQJpi+cfck1uHxddLGGWDYiwcbpf2UgxmVRDuTbFcXRchDr8giGr/KIF0vRfP42ZVTO0m0VZ2Y9MueMsnVxzogePZ4tJT+WPKuOvDXjr2rFLcpfyQpflYo6D/DgjA5jQlwdE+xW4t74C5Xz2/7+97+/Q9o8v1Lr++0ItNvDvw1xWAiNUuwuuyD6gxZrULRb+XBWoB4POCE6RIfdZnddacbD2ArQA+Fu7diGByArnFe0DAwrWqfWLMmkWTQpozBZxfQyW4g+6qBZN/HuQy/E6jvOnX2oHnevPzL7huInx7x4kH97xndvqf9u3HVv34bP+bcbysif4+/23bed3B8f8vb307T3eLeqf+J3sPep77N3wrCPu+hKhe19dKVCZtPGgHxNApvfBt2sVOYgZMjGeVZfHud0FmSkp0sGg7NtAYaWnxfLt+d6vJ55sWxvhR3bvGDw7V671xQIhObFMjICoNvnxYolCBhNAWrcx2mS9D8x7LqiTyyfSuWmU7mPrRdPGz+/tBz2zoQEiRIYdskX5qarZY677ux/64RrJj8349OmjDULeX7hqq745Rl1Y4bcevv+bW58Ss2FyP8v+PSjdxdesb5nl/Pnb+9fmLMZ/6msYtPk2oO3Dbya0oAu//M2yIgbVSkFTuS22lzYbjFD2CuAH2ZzC16PiyOSQQLn22wwCFYjh4SEDSuKJkzXJf41W8kpIuk+GPzhKHVMMPeDmpO27fn77nt+DD53TrWQK9SO+D0ye7daSGbvJZ3ib9Ftb7wWMGO58wE3HxqhtPdRR9HttBqN/gBye9zVMZPBzNsEK293YpGY7eCii3Yzb/RwRuonam/1tEjAB6FAl5Su9US/BHbkegQPbICmUJZbBhvtsPSQV3Ff9Um6Pad9wdabLwXH8c+P3nvgAdjUcVh5ZPfBB2HDG+9mPqSAkPoU/5pQgJyoHPUEjzIGfDWgMxpYKhs75laGvYOHp6cPDucaS5E0ZnSv3MLcCbGOhfZuE2KhoRNi3srBYT4UUmRXpb0wFLIXcoEOV48KjJoQ466cEBM5zmUMQL1eoyawUDOHrIpLgc3AqbpMYNcsZ7maVpZEKdKp3MUcKQznjMuYLfSVp+FyK5bKOoGbVe4TJa/T4yZibmqnpghsQA+cYEOxps2jJfxr08ZGytJz/O4bI56rfeMHDZ0cb6NM7uwd3KlL9ytLox09eSO6D7q3zZJXiyvzsqIl2w5MfZhYOxZ2BM7pUBo/OLhnceaIsQOWXL1AHdymY8/cjH7/nr8+lPnOqo5j5uDpS65bqO7r2r2kV0+la+/sTbgNHlIjtE0v7X/lgLD3irGC+sP3j6sf7v5m+NDRA4eOGscdfkidq54fU7MdB+5588fGidmV+bmgy7qrI3n6Hi+M2qPRSseABzzXNAhC7IKQZkz3+MQORS5PgPMVkjQu1+/35eaGamK5nM9psNTEDG4Iql5JzREMZKfauxXLU4+Dc2kdv/llmq+RbyJSBAcx0RwOKUFOXw/MV/ztqG/3psqqob17KM7F5x5Z8TDO23do/z0rl+94sEe0WCkrKL+Gr3tGHRvfMVBZvsF1V3b38uhV+EV1DHZdJJnqn3Av/OPtK3fumFvWp2fngeryVX+jPhr1Y58HmUmHKCufRTNXOyyZ4dwCPqNNfpbR6LKZ0niSkYHy5epYnmCxQhWziDUUdDgdNbE2EGrnZ+UX5x/JfyH/TD4o+yxrsfWIlbdZQec56QtVt2yuzLc6ndZ8zuR2t6uOuTlTIi7TIs5Cqu7GOXTdkPguxH7WWwd/mvhR7mVUoyaPhjTNLm0Z1XdwFSJz0BmdhJLysMcRBheDr+Yn39b5q3vUb5+nLi0++dRfi1dNwC9w8VdJZ1F9Yf9Q1YTVIXW/cY9nZa67YUlcJT+vm7juh+XXr3N68iem/zZ8OH5xiNYn0Y4fBDzhZZSappT75EyPlecDJiGMnA4HEmQ+kuNOM6VVxzwZsHlEE1TaZIIA1cRnBsQA9aNE4I3oqeY+COqjglosbO2c6htIIhtBVpZHHHa6DnsmBrWe7wgLdsFhxdgBwufgB1z/0pil5/6J/7T0tte6HOx9N7618Sds2bAWb+g0u3BdZR/Dyy978BxcRjZGblxg2XN355czVdmvppfzhZ64ulidJual4yqoY8L/8YEHlI1uVfpLgbQMPksUfRyPkYd3C+4sk9Xm5F1Gl8EfTOezZNluzhKMgjEnYuAhGAcfB1uCyO6wV8fSPQ4L/BmzXJxoTI1iWjW0ZtycXaKab6O7OszNiSYcHdq4rggHTqQLmrscdK4LvByPEM4Pl0fzirAkco8Ne3vrLW+ujP9l5Zvra98cpn6Fhz/22iE8svFp/GyV+lXZsQ45BkM78sW57eoOPINu289tx2fU4u3nzm1fvSKYztYdRzaw8c+BjS9Dp5Q1bXJD6XwQIlaz2e3Jy8gIWowC4ZHNFizu2DHoQXyn8jYcz1XHcvmQyWyCOpsreMybeXPUj4rtxUoxR7+y4KCquKb4fLEkc8XF0Wj76ljUFXKDuQy5i9yz3SvcW9zPu0+7P3fLNs5NBx643X4/yJefT/TKUSG5QT+mh1q/VWsvoTnoS/rhJRoJXcwx6EEqMBAPVE0YfIN8rSuTyRORmK+gK+9yHwln51TzwzZnj1+4e078Bu5ag/rNstv9z7T74oNz/+Q2vhYaPWfF7W3IN43TjQ/cu/2x9CevVst/V3/Fc7Mzt7evKCrI2J6W+eG1c8JHtj19qGx7m67twjnW7Rl5c5cuWJmr7j7FfMYbmtysn8+HMtH1ypV+pwSBStBj5YiRWJ18KEtM96SDKHlrYhwH/CcFbcHqmNVmttnlLLkYaCmvlG+Xz8hfyIIs21zMlbrBEbXrEhaNtpKs5IsgzLsgmMt30IoKunw5ISrDbqfPAY7B+9g9/+HMhf0fGXPvLeo3S79v/O38UnXqpto7bxZGZKtnrxy93NXwUd7PV6qPhz/52IWnYgX3wyNt8xs//bf6Dx9f5FYvgDxtbrILZjEMdqSAjsQSImURKIv6N1RnQdhItywHBETg1rr5QqyHlVku9h0u6UTerB23vX7v3hdvG1prxOdvX/rQCfXnC1fgjnfe+fk53G7wE0casfHwA+fhcwsfvfUT+KhPLt4fcD6x/tgb3F+vG6PWqKvmLlKzb6JjCbfyQTxb/N4OZI7fhUMsRkdNF0Dmq5ARNFsHwHKtck3HkqLikmIUcYiiCaHStunpBRkZvkgk2lEs8qN0e/r5dM7EpadnZaXVxfKy6sfkta+L2dqCwm/bNk+SrXUxTq4fw7nhO5B4haqFiYVJ/q2oSLw3SAnEm2dhJF/mZ3GpLgWbyeJrdkP0kJy+ceVPbV65csO6W7BxW+ceV3XuUnFFt8ZY7y5DPbdZVk9cf9um9eMXe7YYC9svO0JfYOFtb549++b776ljHqi9Y//undvI07c/8Ih8067PX33ro/VLTZXDG8L0JRfBmU0/cvcI20Hr56GNiiPDC6GeTebA3/Vy+W3MlnrsPx4zm402IxwplpjNFrIRmbPZAjkQ9PjrYjk5LuTKoj86YjZXhWuQa7ZrhUuQOZeI6nHgWIznRS/SoulkLK3H2Ik+S3qa5GHdRaPDiwkQ4gosghtWri2CAE6YBLTSXyI7OjnJa9GBjt5tPp63Ljp4UNmaJdOXH9lSeXdleUl0yvKB065X33xw2+FgqF8onfTfunPfhifVF4ZcuHYh7560dupNqtAbuyiPeGH3JJDDivwoB6Kfa5UyZDZbckNui1u0GQRBDLSxibaCts7supjTmevNzQN/yOlNB7bwYq/NjCVORiILd+n/uGSQp1WseTi3M3lIwwEf67eL4jwa3zGecNhT3SLKEuB94wPqPzhu0wvYa7iNVC5a88/fVy7cXtCpc7v8sq7t1VfwUT5tVJfrG78Wejd8tncuZ7/4NHnizAm8Ht/89Nt3rli2a8eqm+I/3nKL9n42hPL4Q6CTbNDi+agY1SilvvaZmaE2OfZQjgEZUMeSjPZvxDLaKe2y3oihdrTTFqShnc3seiNmxqFQGp/2RkwfI0NfpkBVaSvSVbVPFSZsXRed60sorxM+kp0DLp8zB/xjp2RHUDvisaNoCcqlYy200QGuRJcJf2iz+vsTR9Tfb9+M5SNHsLx5rNr47Z0fL0BN332HSfzWFTi6+c7bl2+pHnygrmoY+f1r9alHDuBe33yJ+xw8oD79NW6P+9aq37yhfqjW4cqP1SNcxfLZCzZh1LtSfX84HQ3BXc2/IbyN7NDeU5ROPGc2G4wSxLd2l9/p9Lis4Aq77IE0B8S4b8SwKFplL7KZQ2ZiNtj4EA8m0vUubexx8F/BtG6rl2paW2sjDfVOeImLkHza3C5fuQuam3l3YQ9fLb4R21U0/e56yxUbdzaOmH0Qv8ldTZBTdeK1S1VEVqlFkT14RHwFyY1/THLHjtVi9W5sTOtoFEF9lQi4X6aAKQxyG/SEuXBOrtnvl4NpYExMaU7krI7Rl0NMTemeSTNTpkwNK0EOEK9O3bAnXMaiGsaFTh8dElTiyyNldkSm/hOHHtt3Y7s31IybVz+6/+EDa9apGW+0u3HfYzgkjFafUX96Vj0x03T3FxOx4dEv/vbjJ4fU3yd+cbfpetzvGezGPZldrG76jF/DV4JdDKFhissSCvFuj8cPbkVW2O22OEIWpllCITrBDQ6PxQx25ICDJ2IgqxUtpQtdZsqEkJ1H+Y1qDKcn7Eh2IrgcVJ1KDjJ3z/l1N/9rx85fb258tWTf8LVPDqyc+Mn26P0jj96YXYulex5ETbdvVtUH1Ls79Zm5vO1di8mt2FN25Y3q91SGxKYm/lU2nsAEOqMMHVImWkTgH0yMslUw87zJ6/F0iHCooE3QZmuDIiYzMRg6lQc7OPOcgbqY1+t08oa8wroYKri9YG/BkQLexhUU5AmiRayLQQRiwRUWbMizWPIMHDHLHMcRGlJU6ENzmztPmjVosnulRcCb1Dopw15lHJFxfkSKgIuJuejleihZCCxp7Q8ueSbhxzbGr+dI/Ey393vM/LrmnPrzoL3cmBU3Tlvmnmjt2WdDoHTUqMo2C+a8lTHJObd7RbBT5dhr2gm9Lz4t9I57//xn8n3cS2LqZ/FeU+eMm+rtpszOaZcVzIj2LZ0847j12tIOobYhb3rZIODrNyEYeYPvimQ6OlHiiCwIBPwlE1uF2cAhffllG6porWFZRWmnoSOx7LL7WByT/vFPSA7fteG1jbjiVq0vzNH0C12j0p5vOK/+yMbgnD9Pc8z+Az8aP9bU1PRX9vtg+P3vl/sdYfApXtaf/0T7/Qeay/Y3/Gz8GMpR3DxH2vlhV9wOF7XD7XCNHdsd48oc2nLjFWX6+mwyg0PL+UdTSIPT2BpOHwanHy7qh/shBQh0GTi5SXwuNIU1OIZmOG0UH4DozOB0w0XdcDcKp5iBuhRWF4C1j8H6Z9MVGqzjGqx7AFaxkg5gCigsVrFqMzajGgTRFdZwYxDpfxImXD4EMUcWPxBi8WlKttslUjdYcnFpQbuvKjbHjWm3cY17jnul+wW3KLtpVJ0ZzIQYwe61ibPFFSJn5EQFroii0chVxYz21KiBcj4EDIUtRjNipr20CMDpsJMki3fiJq/aPH2u9cmMPz/0xflfvjp4zlNnW1Vz63qS/eWzM0Zb73xUPaf+ov6knnvqbvPMae9S/A1oMv8K6YUsqL3iNttMEAsTIghWDikmdFifj8wMoD6KmulUiEm8vkhePjgvURp7fNulR+WKLVtWVPbown2KC3qu3t4vp9/21T1HsLEcC5pe5kbwK6CMPMUhm83EYoFAAJnk2QQTARW9Mq6kS2KuslZD5hZFvT4PBMwR0q0ZHre3uaTGSAv8CxSnCRFZFG1mq2xWLObDMWJBRe8w7N/RsS9hA+/z8ils1kMWLuO+SQWJV6Qi3wp3gpBsMjHcSY2MZfEyuOd2KqeQgTZenyNKapvB3Z9KpFTa+1CFkmF2Wj0epzOQaAG/1WDyEK0VoBG0NiiB/9R20A5atUZK7VLahajNxyktlDxIqauPjWxzu32yzWY2+3z+gNlnrfFgDxA40WYnWb3ZPjG5I8mfqa2XQo2UdkwepLZnnDQfs7GJC5oqGT4cCqKhSoGIAoGgBTuddnswmJ5hDzpRANu4gFdB3OEYQl4bb5ktYlFOYBfVqHYSBKkFmolOawGCZtcfIIsX4C/UrFcvxXhaFT/qj3FG05u+4ScJr0JU3A5NVMoDKM8Qsrtc0NbtO4Tsdosle3DMZglZiiyDLNWW2RbRzlksQnogkJ7urYqlI6GgKiYkHQGkdzLpltDR7IfpDY/dRqzFW3TmotcX7aT5NlI5mDknx0YJEM3ddvKTxj7yQ+3xV4ZtevnGybtzeeGO2u63luYvXfze13/23Dz82v0zZk+ufuBG7sBRdbX6zw1v1i1oODp50rCKTq+8m5+ztYf6Y/xfsbnr1N9Xzbt5O6bD2M3gMLwgrEICRKD9lFyOiCJvwDKPeZM5Q8Q2EVt4kSM8D1cx+N/gqzkT2s0RLQLvkr0sSVTJqbmT0TIcxR7M4TA2408v4K/i+yeqb3Gl6mu1/PkG51b+ovpD4wmun+YrTle70DWGkISyFTvHI4mXDLJAaIcdGw1eUZgyChKzUXthB3cgvvx57ne1izjj9x2S+d8XNFhBgPU4wDKhq5UcieOwgRAjJ2PRiI1mCwegq2MGOumEwzKSoTZ6pFBB34608JKjzqS2dtFhpcBoMg57gmRJfDt/VeMTpDL+MHe/2uV6LptzzdgZz4hLOzUcbiQ1/Cjyj9Q5N4di+GjLOTc3cl+RmjvuoDZNH/9pF6XzTNeex/vJx+Q0PJ+reNkkEjoynr7Zq4BritVRSbEeV5gcEUzDs/M/4P24UP0Qyh/Y9A9+mTgM+LVY8WEkigaBSAZikI0CORwTBCkgMrJ2SfFN9IYTIhi8fheOkg0z1G/qsPUf+LFVVs5/Y3ygsJ72w2agt/mD3FnkRlmoEI1WyvL9diHMmzLpSPb2nhxrzqGYPyyE7ZzBaQ22NbQ9FOMqDNWGJgNnUILtKg2K01tpoNN6xkX1Gb2styyF9LQTUu+D4Jr7Glx0WFtuNu2r0cYFCEwwtLcaB/cufnJh5z1Dlu+5b8mJeasfW7FLfeeKqcXtp1xVOX68WtNuas++Y8f2u5EMfPBTnLZ8xweHD36kfoM9Hw5Zvnrlyi3zrtt6ceXKO+bM26i1XymQfCf/OshEUDGDGufoTEcgHJ3GlqAYNCIdqhQuHc+LDXfzrzfcOZ49e3eTyhfzBuRCYcXmQiYjMro9gg2eNlGaF6Wyss9RytJbYG14DOsyuHv+u6vXvL9w6it773+BELTjl3Vr/7ENwizy3NdfvqSPx/pB7cKdE76CWCNPcbp5XrZafX4n8JhTMh+KSYh1ZbSYbUQhJ190lLG+ClCW3Kyhscf2DSrv3uXAYw+ObNdRGLVwbkP7R0+4tvq/4999tM65Lcj04UxcxddwF8CmtEdLlWvyDEGPwdOhqCByKJZWoPjSKwtol2lBppKXmek/FKvOxJmK01OJMu2ZIHuZbpNJOBQz0RtN9EYT+HfOQzFDhT7qU4/NmzuntKFW2sWSFrIPXhLTjGU0dAphygrlHivm2D6S+qsvE3Nje9f2WzesYm7fudsHbO1jiw3MWD23+7zesLtxKPup5/wrZ++csm7rSPJbYVr73Ojtw9oFhEzb+O1t89Svxm5tn9suraig6LZhHaJuSvf5qJwfKdihbTcoIy12B+Kx2SiJHG/CBEIos9XAu6y81e2xG2TDoZjFVCxXyTXyHJmvgt1K+Yh8RhZs4HNwskPggSYEhfgV/L38Yf55XuCpZNCOixuiryVJMe6G11pqJd1lYC+0WNc865IPu1iXPBem4bUH/7qz9s6fcPlzqolcsXvLTuxR73+eZOBR6uc4vA3P3IZz1E+2qdu2gTzPRxf4kXyVPoZ8kFJk4JFJgjjGbKF1kGUBU0x5qsJm43vxYXwa/4KFKoxtOIQJhgYcN07nt1b9SVFN0WF9m8991Zihbdwz27bFO2/bhicDDkDXpk+BrjeBh4DgAe3tAhf1hNnLc1qlCK1e+Xz89dj4C2TV2tvXvKv+NBbPVqvGEnP86JLaJWoD7jOWjNp2ZhsuUM/C15lt6nfYt+0M4995dN4Rf5qNox6kdJB4ZCQiEk1mCWooYTYu+4yIi8QKkYjcHLKSHCGcjQwi1YROIho3Lko3J5tvcGkNMZ3QIGgavfFBbnRjEDT7wlN44271YfXhXT/W1lIc5gMOI3UcBijtW+EgCoRwc/iV/BGes/GD+Gqe4/EZhItA49PZs+PGlVAULotBOTVOWCfxaMCAkfjHXXgUHrVbvfFUfAPFgOIA4SV/Fd8N8RC9guYQ6ERb3mgiBvCykXCY2ULkb6Giog4ZO3LDsL8Vf4I/abyLc6oL1YVkCX5BVeLrhhOE56qboQ3noWP8SLB5AspXvHTipQhMdChm4yq4XziOq8CYskrRuGb9iR3QrB4sbsXUEqrDSI87ECaZ8V08ER8BGUtTjAaaZMljNzHNe+pUMqUSjmijnNnLW5b1wUMO1+7f3ufakkh+YUbQGy2M75Iyv8Nyv875HXMKc+58iM1hj+8ih5Owict1WdhRh5skjA5LI1FGMmsf3JoCW3zk31/+pDakwm76jRTyZ8kzdBTYcQIyg1E9Rk/EcGPrmbPnSKHWHqyuDB/qJ8iEo5M+VHRRn/ShpdaAyCmztlZ85LfzOm1oGQL4SUZeEEQs8SriWEGoUfM3oazE2BQ6opZkkifjH9WSZ2obZrH5DL/RMhMwOJ6nMyvVVGRTYXBsMpiRPFkLSF/8lL9Dx5vWFfAWUOgEmEeRk4gAAI7FSCNDv7AZCWYjoQqkTbyv+Eijq1anFas3wwE4n+JwkYF4goK4FIco4NCG4sD91LA6STuGgwQxoxmcVkkycLKotkKkGVAzNoykgM9HtQyhVLowePmKRQCAMjIIKnexFWkS4JKIRRhqGm6/nefv0GGxdpJQW8UqgPtFZAzA6OzCFKagTifjjGQ92RBo4BDaYMAkDbMYwXXeYrhReIQYRIDHXRTwf4HnoPVllGvD8GPkT+AH8EyoTHEJskyMRrNowWYZ6mvQkDwaEyhUfZZpM9xoKuiwXntGzEQJDGvS9BteyJ/l5jC70kExJuZ5CzxrHyGeQL0hESY1z+/mdIMBlGgIgbx8Xlur7tR1GJ4R38VNYjIjoSzFSjiwv6JBlgiQF5q8pCKa6i9A+7BtRm0tnqbJkWxvliXAT0ZdFBtvMMiy0STSWTUqLzEU+XhCshIoIp2+jiQ/JQeua2LG6MDNqT1b25hN/fgZOh/IqL1ikQw8Z+CMyEREWQTAx2Nyo4FTtWGdLDFHc0+3R5+D6eDPqpsAHBNf/o6GWUJEpwHDXYAW7KZYecFkFCC4gQDNIsoA+kRMjJuaNYOOfzRB5OZyGO76fgZ3fTwHqEQEKBIqcfEpfrZWD002GK3KFatEDAajCeIyo6QmWrMh0Zrxy5FKa9KysK5MgEigUPBCqNfFAu4zDT43idGpg2LX6GRCRiCOeKnEtCAUl5is6jBy11M6aVpKExyiwW2mkygRLGHwa3jebJQZ5sY4q8JxqIKEtbZoZsZmOtGAswxHWKftpNp4DhFq1U1E4OZcLBD6sFrUMp1EeR54k9LJQlUI8JSB40yiVpgYT2inhqR2KmzFUdHEZAhdR+l683WonDanaoauC2TQBSaDIBMBXGw4AMB1MWJoFHUpKGzBUJq0wjF5rxbPb9xae5bpPn55o4vyk463TiciADyD2WLkOIvBxDA2NDDUj8dIXC/gsnRixej7GbXkk8atIHV4frxBfKShulYogXpoOSMWMl3L+EkWCTEZGT9d/F/zU1TnpzYaP3FdLr6j6UumIxg/gXWiL0Kw0cBfhKJws5W5lJ+wBhP+uEmA+3yNpaha437SdBqDq9PJYKIvWICfMNb46UTM2CDyFxNlxP9Y7mgx4ajGT41bySe1qlQbb8DzoRb8fY2dalvaOBPqAfUALW0ygZRDqxjV/8RSrfRUC7ZKGr+EAXxd11ZJvcLsjAl1VGxGk0REk2jmLCbdsEL7Nxqa2z9JuxbWlTktlM1Aj1C9rVtZpne5ZBk0Z5EN9VUcVkFwIGyTZbMBG+wOs43Vx9zA1LAigx42kosyUhlXJ96tpb5O0+Y001kVTG1q3NdQW3uWaTLGfvFdsh0YsDFbtjMWTLH3JtRdcciUuGYLMCHYwP/Mhql82IIRI0lWTPDib+e5z1BSDyXp6gTvwmQUjRZkNgmq4RIXI5rKkyl+BqWrEXiSWbKkv8EvB7IiLllGkq6i0SibOGIidodFkuxWC6uTNW7Q6WpoMDXbzMuIc6oBpREZ037QrrRNKavWMhWoWVTgWE0JEs23AJ1L66ooNvB+LGbOZLIYKG0NWtFyQ6ozFE+IYooT4GjpE+neAHBs/CP+HJAXmpL7jNIBpfpbJlSquGSjKBgFYFpkNgJ5L3G6dJl3tLAiSYMLpWgWV/e/dB+MS9ZLYDOt+ylOhE1GbHTYLQaDw8pxdpuVqWBbg8zxHDsU+bhJ59vEiMOU+nVJci7QNapJjgesTAOjq8a8RGgIQbt+RusrnK2tTfhVOi9R+hJiMZskqSV946nOYcN/pC+TF0Zf5sjpDhfXBeREd7qa/U9GX+BemchmE9BX4i7Klzihl6WvXiqUwpQqnp9Uq5pPyiXrlaSvwSQA8zrsNp53mGXZbjEzolrigsyULVg70LZJa/eH9E3apLIwrSbTTPEGnYnVTfw5pgS5t4CHQQnXpvrHLjRCSbPIDodInE6P22Y0epAguB2gIsw8UxInYrLQYE+4zBbKyzouLTxnR7PKaGW+mqc+JrRHUjnrWkTX0EyVtMCtn+J1Go02k0tiatrNeyxumQ4QpkxgijmJtRH0tj0h4YnRnsmmiaZKebME6CYwocHPAjvSNtO1uCYRrO3YeJ0kPrTdHMiHJippblH0SYLDQeySPeDnrNaAR5b9gsfrYRQj3gab1oSKMWY2xh2i6kwimUK8Vo3ZGl0uVXCiunKiTXs2RYD0ZmZNfPEpTZCYumL9qIjM408xnemsQxCzk4sIFVXo0ToOO8L8qYYofwru6qTdD3WFs+b7qXQXXXI/3PWX5vsZfNcJHb6KKiou84Bs1+8nUxP348vdT6bSW/T7yZQkfEcdRkLz7SUJ6M13I5oRMd7AT9VjJyplLjbSWJs/WYiKUBSVo26oAvVEfVF/NAgNRSPRGFSNJqGp6Do0G81DC9EStAKtQevRRrQFv6XMsOb1GbFYmDXLlt935BJhtpjZaeCtwpQpUqh80EZhqrNtj9HLhblzXYUVY1YI84zZXa/eLEycaIp0679FmDRp3tTZ/HULSVrJkJuFGTO4YHToeuG66273FfWsXiMs9Ha4avxqYeGCBbVTJ1037bp6zINqm1wzrXrMyGEjtbOxo4YN6j+0aqh2dk1lVc+Kvr36amdK917dyqPFUe2sc2lxUWF+Tr521q5NTiQU9Ae1s6x0v89lo44HPXPbzaz/UzsD+7FmxZJFS+hZKLZy6aJpw6p6Fef4zWjRImT25xT3qho2zbh2/pyZs2dqTyycN3vLxvVr18PZsdimW9ZeRAnR8yem3zi1cff655Lx2P+335RdfHq+Bh+bpsoGJOuHl/vqWEyno+bqm/C/PJb+4LrvD+5JvY7/4HjqVLxb2+K7pkzBu7Wtoem/Xz+lXWo8OWUKmTp1qjpF2041333qslfpA5eDJ7SZSD8Tapo/ky49nkA/E8fTz0R2rF2WfmIP4wg7Q6iSyeA7/9/JINqK7kR3oXvRPvQQOogOo6PoBHoaPY9eRq+jt9Fp9D46iz5Gn6Ov0LfoB/QL+hX9CzWgJsxBKGzCNuzCPhzEIc50lJRMfLAeG+uEP/2Ji056qB6bFI9wNnPg5sd+Ez77LDRoy+F/CZ+LnabcX4+tdcJ770nlU/fVYxvc9H72kOVPXBS+/DIydMXRBuErY9cZe+qxs0545x1Tt+vurccuuOl03ojVdarw17/mj1xzokn41tpj1u567K0T3nrLVjH7rnrsOy683Xb0zU/VY1InfP994Zj1T9dj7rjwg/OquTvqcVqd8Nprrp7z7qzHwePC6x3G3/pcPRbrhJ9/Lqre+Hw9lpSQ8Msvr//w9renv3r/87PGj19Ou3rxgX8If/lLsP+Sg78KH39cj7OO+vou3FqPQ8eFl719FtxRjzOPCi+/9FI9Divyy6+/ffp94ewHZ6kcO2IvvPLGyTPCB4ePnnj6eeHgwwe1q48eOVb/jPDw1jvvunef8ND+h7Srt2/befdeYf+KNes3bhF0beGILV259pZNwqKp182et1CYVDNJuzp52sw584WaQUNHjqkW+lf2165eUzVs1FihsrxbRc++gq61HLHSzt2VXkJxKJJfWCTo+soRS8/KadNO8Esmm8sn6JrKFOMNZrtbQP9qaHqSNu5R4dfzv8IvR2MX/t34JEZwj084/8HD+xfVVBb70fnzyF9cWbNo/8MfGOuxQZE/+eLrv/0ofPTxR/DMidjnX337wy/Cx1e6mjkEDJgJG2DjUQybsR27sR+nw1UWEOpzZv1F+kErFedrNbX2//b7f6/i/udf9M2uJ1J+mU34/+F6bqtrCaWaf5lN+gM4vv/l/fh/eZ0qzpb/DaCMT7X8b7z2/+IupqaT94Bm5nZfct+US4BN+R/c09D0P8FBV/oTL1H9NX9gBv7w+oTmj2YexqcYiQkppqKFwZiYaja0D+rM/ElqO3qjfmgAGoyGoxgahyaga9F0dD26Ad2IbkLL0Cq0Dm1At6FatB3tQveg+9AD6BF0CD2OjqMn0bPoRfQqehOdQu+iD9Gf0afoHPoGfYd+Qn9H/0S/ozjGWMAytmAH9uAAzsBhzqFclzZ50QNfC6++qiud/tfVHjwvvP125bRbHv6n8EZmzZL7vhBefDF47U33fyO8NGj2xsM/CqdPXzNz86N/F05mj11xzyfCs8+GJizdc054bui8rUf/Jrz/ftWcTUd+Es7kjVqz6yPhyScj41bu/lR46l9Nz4JlsuEs0Cw+7FPkYfO3HftO+KBt47Og1ixM43iwR7Hnx9bu+LNQV0x1pNCr17+fAx1nALUUhhv82K+Y6j546sxzJ196gzNiMEaKve/U9Q9dEF5/XZAtDg+ErfU4WzF1KOnUtcdVIkKF8ecwj404Ax53wl9EMet61tvzrXfeA0t1VHiNvMa8uiefffHVeuw5LpD6Z154pR67jwrCQwL7STl4+CgYxePCQxUHHnsCLOVR4UHxQfbTrnvue6AeW44LIhiL/TSxviCvl9lP3TfWglWSjgvru916O1gl8ahws/Fm9tOiJSvWMDNoXLh4+WqwjUcFy1SLZgg6g2VpEqaWz5g1VxWmWKdoV0eNrZncKFjBvExqEBx9Hbop6T9o6L+EvtGrBw75Tejj7MOAfwRavx6nHxecZz/+/CswrEcFzwUP+6n4bz+eB4OppAsXyEPieuNUa1/nhQvOvtapxvXiQ8To7QXWEoz2UeF1/Do8URfDahEYDTCuYHq8vzIzkpaZnddW8KKEVWDD4f5fGwe//TVfiZaw7P+ZhYDoKloWucymTyprtUU8UcdlNtzqRh9cy0/ZpFa/C3CtPPUctjBsUlnEkwvfLm1+W3Jr/fx//b1V+bj1uY4jfS4DQ7k6zBbf8DsHG/9OQ8mU5s/U5r/UT8POxOVUlaxfizclnms8ORVHQS+DP54ElXyw9XkzIIJTVDo5xX6bSv/p3Wyj+/gunD2B/kdqcHgi+09Ruy9OVD+vUT/V/sfDXpyR+OmF1vbhhcTBy83Pq59fov6bLyXvEk8lVH62fgClQgETGNCXNTATtUe12+FG1sewEN3Ij+CHabnWBdQy13rYEV7Ifd4Y5oc1hhHNs4r4t/k3WexBsxISIgscZ9BHWRZFU97B0kddjrCD8G82lF/Dd6Rf/LKG03xHhPE0vIKbzC0BOGk0XyWmOUrtDH7RqXHJsQs0w+JklceNeAVuZO8Xmp+TUBeFvvORMDbISAK1pphjDIjMIUJEuPB4jLDhKPZXtEl5zYPZ9NSNGvBr1LspfLUKT1T3sPHYffhXSfYf0sPAP9vQk2SrOXSuMSrhn+UfA7w9J+iQFcTh5N2OLh2Ly2VsI6PIiBJ+acNaOi6w6Rug36NwP8DmaYLhFNgyLuXvbJjOPxrfE78L6XOZvwH4E3T4gEsr+DLhn40fiD/MT2hYyy/VniHwzC69jJZP0PeQmN9Fi2joQq7VxzXFhL1IQDKqUtrwnIiwyBkM0KwSfS9okgUiSZyBE4/EbByW6WjYIyw5e8pUxyuKotHU4WVafhOabVTGUZknm4eo5fjNIfht1aruwRNxDTlN3o13JGXxt+MvkR50XNE+dD/fli9guWeKFaPfYLAjlBU2u6EZ6eRMnk9nDZqclZfanK7EGEiaQCa7Ay5301F9PTCd6xPJtuJ9i969afF7N9307pLFZxaNmPjQpImPTJ54cOKERyaSyfT6+/DTokVnFk98ZELNgYnwy8RHKCNNQyP4a/khwGk2No8rH2Lrcoir+0JMPRLi6akQSy9EK8DD6Fw1bdqwmZ0XLeq+tM2cOe3mZ9XU5Ew2VFaar0GKwveyFxe7S0t7XTN5/tKZkn/U2HT/WP/KVQMXzF1QjwN1savn9lm+eDk7vGpxp1kzZrHDkhmZ40ePZ4dpo70jhoxgh84hYo+uPdgh6Wrt0LYDHCremLHt3MUzRg/p2rZt1yGjZyyeK03MmziFTU2dmJeXDQdPxPLs7N2Q/ZXmrA1a11HK7PP/vE82cMu8gn+wo8NvI9llpdGSfP3bpX/79O/E71Krc/xffm99ntsKfqI87rPSzp1Lt9Hdv8rLysty6JFa3gk+h8rLysrJELqPp9ELZE3y3vhjpZ07dWI34zfob+pYuv8XvXkbPeJ2wK4dnKnvl5eXfQUneCscjKbAFsIOP9kp2iXeC452lZZ2Jun6TSoHB1/Txz7sXNq5LRyArD6GNvAh7iKyIFcdbzRabRII66mkAmRMjSLZqAxYnEyZ9ee5qnqiTlVnn+Uuzv/LjBOqirm6mR8uZGPzcuk6MzzNZeuiupk3g0LyYLcdwmuAWXQq+W6OjskLO3ArKcnl1zTyC95euODUggUnYX8jv6ZhGblywckFcAwXF9IswallRFhGWbc53Z0OJeXiHEMWtvuhrE/fgf9WL6xZia3kNP8yGAyeeGDCBBBCth9wKTrJ32CfihrYhll4HTeeuxFoGaC2wYqQW5LSgpxPtw2cnQPbwBmNDqZKjH9gG9iAQC1fnK/FRGVu/J0Tes3ptfXaqX2vvmZKnz5TJl49oJosu+62K+f2nlp7dd+pfaZM6dP32uk0L1AQEf5xfifTZ4WgNXqjpYo7L6tdSUVJVm8egX7rCwquT4/O9U1fnJAtlZ07d+t2JfOaywoiBfTFhj1WFOmmmO2V3SLdItCYVBM+EWNqEL7MqOhkYXP2ZU1Cdc3YbIT1JBJUQ2ozkz36TOXWGrJcn3pO55DkphxjfV4pI0l+8B5s37MH2/bco57fs0c9f0/Fpl9v2/Trpk3/gP1tPxZkZLRtm5FRgI8mjtRpXZcNrFrapeuc033njexABuzB9nsSD1Ng8NhtFzbS5y9YtEcSjxao/xjYtduAjo+36dUb8Sn0DIIeLkMTFVd6ttfexp7dgTcgQznqFHIFXNq7y9xAUVlZSUk7GrV4YrYAtgHVB5XMLllRIgRKAiWUeK+w1Bv6zPyEgsMpiTcupRlLXaDPqxFSjjFbW1LLrHQpiXDhZcjSof3Iuf1Oz+kK1Bm0rMslZMGdUuhAv9X1vXoVPN6REgTkPK3pZv4JPhPoEEXViqtNTjjMdbDY7T5RTOO40jJfIfAIRE4+nz2cE2b8InbUZICbI2JRtIRycA4qGheNwlaYeLFQmJpoPTE3yuXrVA6OvZcuhcPy84h0RRyRJbTJl/LLWcayTuX5rhSCfLF/5NTKKSMfiD7QR/7uO2NvOBg5pXLqyP3R/b2Nf/ub3Gf/3Q8sWvTAQwsWPMRtfKC38bvv5D4p9/SR//Y3Y2840KCoixc8RG99iPl/3VEf7nZ+G/KibOABr88r2Fwu7M5wmEyCm4vkuJ1e5KXdvzEb3E7SaLVNMSs8aeaIwZDFJN/QLPklOgekLhaRUn2IUBKpI2nSQ5olkoY9qbXFo76fu+3wkiWHt839/vvK79utHV+9Zu34MevxoresB+YsOXx4yewDtrcqv/+edB2/9uax49atprp6P5rL89x7yIPCaKbi9yKLaDCYTSargNLtyJ4dEaycyxWg6AdixS7s4kSLSVJshpChyMDJ4KFxXIhVhkPNiSbSTp3s0sX+SnMyRzYXhqUqSE7YZHoNF+Gwz1GEsS7n5SkV2n94yZTBGH9JcH9fuVttUmjlKpPVunvJYQVjd7lPPU6+VJsGT6FVTNaM+p9TaF5d/iDUrFhJM3tEu8cRFLIjst/s8YT8Rf4KP+f326lT2qVoXJeUvLBU+Xp91D6w+dqAkydcBmglZvCUg8IiKzdfv3r6LZO6r809XBvPqj2ct7bb5PWTbrl+M39wxIcjptw5aObqLoXr7uzc+c51hV1Wzxxwx/XDzw5neE0AvK4DvNpSvBxpJk+aN0sobGfNcKSlhTKKMioyuIwMz+XxYlZLlMoTivFS5KI+yinUSg9f2qtntHz9w7dMuuIWHcmc9RWT1z+8vjzas9dS/uAV1ys91+VwG26YubpbgYZqQbfVM+fewuWs66lcfwWlYVMT0HAaSqNrIrktZoEPpsvMj6codSwWSvPySVmpliA3mjCrnJV4yDUL1/7Qc64Sq80UM+8Ypczt+cPMWCfc6909OOO+PnOVNZMmr1bm9b5P/WrdzQs7UrqshbIqIYYx0XhBNFsgqioqSk4zc7qiTpeHcBGy9vevzF/9TndkOIfTacp79WtO/Vp9DXel4wrTkJ/s5KfQVaSwKx17mpdz8TnIWvctI3qP2TC0a1t+SmMME1wxuVfnKyf7uF5If5Z7BJ5NRzmKzSlJFi5gCWRkii4jgCuKnipqlc+dmq68fEdqEVGddSTOHSmYNTpRXJ75ppEDyouxPW/eldMeyIwf6DVJL3j+ktgDUypviVIazGl6j+8Ofk0QLVf6p3tNJkeGwRBwBLLCG4zYmH5LOp6ajoel4/QNMpYz8jOwJwPzGTjDf1NoQ4iEfAt9631khA/7/EgU3RsycabfWuHGbtCygPs4Zxdwv6I0qQH9Z9/6V0q1mMbJTdZHaFG7XDjjxmtVip9PVI5suqUdqw05Mbjx00TNek5urOo1ifmEzfUKIfSfYOPcMuGy8NWuxB4/r5WCjw6On2tZCvn34EWDtbkhO5s686XCSVbWIkURTTZOSndxXjBKRCJZ4ZDT53N5Axk2Z6Y5PQ3zppBgMDszvLzdYgjxaXxQtluCshy02Hm3xDlRxSuvJRI6alOVWuY4dERLinCR5mJqCZNZtxrNP0mTO0pl5WyLQvWijnKP5CgX4Ae+9I0a9VjNG/CpwdfQb/Uj9Rh+Nqbeja/Yq96Fe8TujeF/0l1f9Yu9eKz6NhyrpthK/M+9qonySrWey9wD1rejzeRyGXiLw4HcCJSXk3CkBiJlqyiJNTGTZJPA8HASJyEZXGZ95iuiU0W7sByhlwZYdIxPCc1lwZzmZMLn5DCfsOenzfB5Hq9Tl+K16hKyF3+9bts6/LJ6BXyp9XczedqDENcB2sKFeikRwJE3uDjwhz0UvyodvyrAj6ImY0RTMGuJ3Vqik4zkUxBJZJ0m5lnwOUZ3xAxFk+z4Z/AVv0BpJOo0CqKBShuny2UJBJAgikaE0jO8tpqY6HXJMlDKK3tlZOJQoBVpEmhcssBY1JEP/jhd0xsk3sESnUXZtERKmEh+cDW5blje8+lpoTRx9eiacDrZS57ki4umLeWIGH9CKCqeO1dQ295N+dXD1t/szXzKa5R8v1sUTV7JDvF+eoZfqI75ZKNcE3Mb/fAnmc3QemZOapGPPuF2Jwyt3mzY3Zzb0BEu4aXScIS1Hk39U73w01r12+dvuw2f/BlzL6j1v+Fx6j51+0Hu8WWvzIqr3MR1ePyHL6mvrntTX5PtfraWZG/WBzFYaevyeu3pCJk8brffbhdNXFbY5Uv3VcfS080epzlI0TRw1TFDevOQU5qgsEXS/Oaszs1ry+eV6YmKJByBv9IClr8MTygq7V7Sp8eqjfjL7y48fQ++/RP1jp+Jop5Rz2P/HTuuH3yNfY9j2y3Cey8e234yLX6QVODNn6ttV7JcTLPUUXwt8GEBKkadUDd0QLk2v21x1y4e0V1Q0JGzWLtFOnTwOw1iaRSLyOWiSfOsHOK7X2HoYoy2zW9bFSst6lY0OCY5PbZuoW4kwHXrZo/gfG9WcHAsy+PCdmMVm0lPiixbLE0WzgKeMDRoBUskp+XwpCNio9r0efCFEpGSMzWRjDMlM5eebi+Imc8RdWlpNpzhEp8rynk9jmaC5UesuBBzrh7kCiwJbp/LinFpvlQ+67kTn/5mWFk84KZZpmc64LWTB9dtfndu225p4V59J48Rxd4n1piOnZ+wc/g2db3y0JKZxGIdMEYdhQ9c9f3Dx0Qc8g4Z7cA5AXyn2m58vdqharA0xz59ztKp6kwSxNW7Bse4v00twgtts7DSr81jtNf0NqDzVKBzOvDIHKWNkJER9FrMMm/w+cTMAOeX/CRIsxsHnVlhfzDDEvDyYJ1s9dioOGJur4RDZroiQkwWOGxjKWf1gZiJJJ8VLVI/pSR5ZBMYo3QmM5txGcEJ6uRzERewVBBHnjvQdRG2PLH5Cc8wtT5/yc37Hnlw2TWvbvk17dg773CPbsZp6l/xHeqszfGAkr2hQ756JcnrPpTcq7bH71Ndcr86jT/O5HSI0t4kSQYzz9sIxjaDze4wiaA5THbTERPn4kwm3gK+sZOnmbudJKgPZ6+IJnInpBpbPQmbNmJRG/UNG3/88V3x355/nhif3xt/A+8ks+O1Qm+aorhhDODyJOCymdG5QslK93i8RroomlfKyPSBL22WBsfMHmOQc1TR7gY6kjPBgBWXrHmtL0ITZQiUajPRGRpUAKd13bfsyEM37lvftmb4il3HjkmYWzVj0uF34k/EvwGkHps7u/TI9vhq4aS6/IrVRs3v3gy4vcXoNEhpY5FlI5KsNpuIMQ8WyMjZHQaLhCxItJo4o1PE1THRyaeSqEvLZVNSiCRjhiWzrTRMJnPxqY2PX6UG9gGhup/j5PidjFbLH1ELgVjV5D6Kz4+Az2SWh61KKTCKomThTWYzZ7XSBNQS4CMYeQtdMchmwJKHswJbe3ASoYr/hBBOxQaw4yfvK1LvWHvsGP74fbUfnjmBrnSBf52ozhZONk4gFrVITWM06gc4rWG5HborISNPIGyUZZGnU5XZYg4Sxxs5Y3WMc2qYJNO8pqpOfcg1nYPhwWF+zeONC7mSuI97qfEdjpW8hU+7e2PDl1DefiivgO8K5V2hhCRsMhiIKHIYyjMGRY7nqmK8DUtIAn7xoJTi/BUtC4wmSoM67yfb41u5zvEZ5Ol9G7i8jRsa/xL/FO/U83H+yPcVRiMrCqCuSoZNMhO3GyxaWtDCGcFGmI0876yOEd6FqSWLahnTUIp46+uElYEEI4cdgdYrj2K7E4TaAYqQ8H2fm7JPVX/BDiw9Pn1dqPHXg0d2jR50+OAD/avxHDwAD8Y1YwfEx6u/qL/cxPVYyRaAwaiG5qXlB4KT1F6xyAZJNLvNBs7jdRJQQSdiTrvBZpboiiFM4SRqri9RRO1R1OX1VWCWyNrH3xwMty3xqd9+qC584WdLZ3vXzW0XTxvak7vf3rVX40m+a1xp82pZHT6zYVkBHROLkOCGNg+DL5IPJdusHEZOJwdmMhiMyAZDNvCk5PdnVsf8YDmdZiyxPIfRZP6tZI9acwp/7f2GiaatjXAUuU4uug9iLQGLlrmde+PM6EEZwTkfvP/s9Q579q2HJwWKI4NN5SMHpfWwFvqd2fkmvAlP27xWzRR6Nz674d37yGh1+tQ4Hk2Gj5hWbJa2iF16M/p5aKci0K8NQuEIV4RtmBWbyXmAKFGXr7Tc2Ynmekkt++QCRxtP3pK3Tzwxjq7e6IvMenF6eVpZUWnJeEHQEWhjxId7Hxq7Wx0OVLvPPyg2PKPmVrxSXfFd70fx6L93ilIcrriS8dYqaMP+fG/kR9lotJIXdAQ8AUHkDIRANGT1I2T1GPhIDucIOgbHxGCQ+G2mLGje4zGT3UM8ialxKVlSmnPcavnbnHryNo72LDV3u/i8IQzVBAOrd1Hw/dWZH742o+P1eatnjr1h0qzhrhyrvetv8bPZ07MzMopoKjQSyVmWP7dyyupFk2IrS7/quL6srI689FnpwG4DsgvzGU3fYgvg0ZwxHZWggOmKn3TFw+pYlYD3CkcEQvOyaWnpAGct/VbqfD427WEDaMCbEkZiL/O9A+B7HwOZl1Ch4sV0cRRikDE/OFaE4SNKNrbiCQXZKimNNlHlFP5WDcDzaqc1qgvAMNrngFw/wg8BPshE3ZSQWUi3eRGyyQIfypIDrkBVzGU32NNtxFYVI96U6Rqo5RKo2B7OQo5SJ00VyFb+okR2sl7uAFgk/pF4vfqJ+u3nr3qWrtxy1+49Dz3/7Miq2+/bQcriJyDkD3yL22bdEvxL/TsnZXLlix+on/zzxffVX+PPSB9p87+GoI3cEm69vvZumoDp5BmDTLC2DjYnCsjGhTjC0e7HokQ2aUeLGbc0JT9s3JL4WVJAN/LN+fvPxy/Ajs2FupqrQ8ea16rk6bxthOhEfx7CjopTXVq8hqaLD9JQoW738CX8vK1bnyXe+PcMzlHuX3i9DifEVi6XaIoijmNgolH9jQlLsCTjfMAr6sHr1a0j8fXqmt3CZHXrCHz9qq1bAZb6M1+NnTqsDMUMgGi9iYZR9CQdTMLyZGoz92gecOykWfvU+3bz1TdNACA4CUOg63ZiuvIyEuhSy/rT2rPAdOrP+KFl8U/4jy6oWykfN4ExfUdagGSUrVjZWrKc0URXkzUkV5Nt8eqb2a4o5t5Rv9yqfonHOPAk0RiPE86Hh6sHNF+iBUxZkniI3UwGnodA/lKYILFYm4oCMO9xqA/gzK04UxinHsDDfYSLxzXe+Df3IPlAOsVoVKA46WqOdFFpjAVO4PeMETgtN07zQvHJtUbZApJ3Te/8l0/O8u+RhoY/79x5KTy6VikdCwDqSJLEPWPYouiXgwf60hMpIx/8pfP00rMAowG30+DhB8gHehu2VRyXwKvH7fRXqF3+A0AAogGkdFT38tNxZ4Apo1zFTuia8KIkGaFxaDpd2rTJZSX1bAf60BpHGHf+ZdnhZWSnMOivf/0rnkRhAcDOcCTTPjKDAPjxmM5J5cGhQEWnWoOC8E0flYM7x6cBrF/wJACltW+6OpJsb5oPcXpbxUkAH0Rf/XPIINH1N6CNo2mnSlpndgqCFY7kS+k/PPrlge13qCNxhvrVc8/RtiUCepPQnJa6LLGVOkHuBZ4jEE5EX2mxemzqkqDcdadPx8efPg30N6IL3EvcjMTYEh7RORQGGRGBriN5siRVRySSwhhJfbyS1JM/bdumZm5j+d+JkcTIy0yO3CcEnpdEwlO1kHypCpazLEpeLhscfZL/IT6L3HFOmytr5KpSnxOl//Scei2+iz3HoWHQELnwnAd8rgw0UilymUHNE28gkJZBMjJDPuS1e494v/DyDs5rBAVtpPm4wB4EXYItDTPDGE3MP9OGVbRI95pY405bK0FPvMSWfYt6XJSWtN33Htu5c/XN/UvbR3r3eF89duwYd6KxH3dizeJtq80bDH3GTliDpz/66MUvqG0Ee5KKs6JkJTAmgbSgD6XiCCh6dRSTGLZwFv8YtcugdQlSjf2EkxdLWc5SYsR55GX+bWceXcraIfG/IqQeR8ZjuMaKrTQpKGj4DOFB7oj4FYQxtqMiMnL1eChdjqEkmXA8qr3J4I4c27Hj6H2jBw4YI35V++iR2waMG39NUxM24e4clGHP538Gto3Y8wVDE6ZrtwsG5ijSXGqjmz7n58I9ouBw03M7kOIpwEvkm9jv5XDeh56DnNDzJXA+hJ1z7PxROA+xcyM7r216n88XV8G5iZ2voX1j7HczOwffmPuYnfvYeX7y9wCT1RWEwPk0kIp2ikXk6HgeLBtEgsF3Hv5EDPP1uD9dr6RFF2JyJnqYv6Yxitc/jTcS8hR+VB3Gygg0/cYfEc4Brf2M1v/GF6Esp2LCad407EvLcjhzceE4Rxnca4B7D6TeG/873Os+xm6tb/r8WFqWP6DdnYT9QuJ+oPSvqL7pcfocoYFqkRIied48nJ/XjpbxegZWMqBdl2TgbRl4dcb9GYR2jJehcePKdJCoNQ6pMBkuRccYSMBF8ea1o8ikgMMZUAACSHhcS5j2pgBr1zzarg6R//kn8Kgex2n1TeOPpaVZXLmFcCe9T93f4r5f4D7XMZzBZ2B6a0YGvXWcfq/OK9q9wMNNm1VQzooL94jgNpFRESJF+kYWRjhPBB6+XzFGIvA0jtgjGoqF4yiSGn4DAdYyJg9IhzW96TDKqcNuF852weN/VywuFzLnYtd2Fz7jAgg6CK0d6KTuT9nzWH/eha5BfZVS3CdUFyIPhLA7hIeGcHYIo1BxqAbcslAokJaLQ0WhQSHydggHwO8O4W2h/SGCKGJJDJM4JmQhj8oCK6NN01TUrg57TXi4CXD8t+IymQiXi007TLjChItM2GbCqBlYWQsZyqMyxOA0UThHSYBW9ILidbk4MZe4drjwAy5c4cJFLmxz4RSsGBy8HOpcALKbJ/BTNDhTgWYjlTbYOMyI3zPiVcbHjS+CpjdiZMwyFhtvN/J9jZjrZcQu4z4jIfVNhxSXERg1F0tbJLxCwtUSHiQ1Y1w9bhz836AxKSsT2px7lv8UyhRCrEz1d8D9SiWAPX09eIcHD/fg+R7s8uDVHojksjxQyDbF7vHIci72V/hxkR/b/KyEZvrq/LQO/P7R/OdAF4nx3q9Qm9I6LIWxNwyE+V0JhMOiFRjodAQ/FcGbInhpBFdH8KCITpsElQHPWtKH685oY7hJo81i0FXzlP5YKpJWQG25UxI+K4FPIRrxAiP+0IhLjRjIFjHiNcajRpJtxC8aMSMdJRynE26fERMfHLrgG8h3jFEP6ET/ErS6ge5vYGKdlL8adQXTe3mCrLf5dUC3QiUTe2y4zoa323C2DdtsNiLm0q8iW4XtjI2/RE4S+jaP6ltKozcOowFKN+z29PLM96z18C978DmN8sWeKk+NZ6/niOeMx5AHLWDJxZ7THvyUB2/y4KUeXO3BgzwtSZcsJ6HH86gep+WA9w3xB3b0dWCPA2c7MHJAm1w85vDxUq72aKKuVqbTaTtatGc7HkY9FScO9g2eCJJAEK8K4qxgTRAI+CclEAyL0n9vU51HcC7w3wpWf1uKnhighLHkKnf1dXEPuupcZJhrresV1wcuHlSHzwWt5aKt9Yzicrl44EMXCFobJlwfuFKZvVqXdqbXf+QnsnLsWh3IYYicw3S9K28Ek0jElZ5L/isjavSYp67Q9YZTgzXnMPiNbhw4HcBPBfCmAF4awIMC2Blofpw+dyPQcQR7zqU9N/8wiig+nHU6Cz+VhTdl4aVZuDoLD8rCzqzEo/qzV8OzvdizHp1OYfUDmmcHjwrivkHsDmIUhAbcrHiCQaqyghVBXBTENcE5QWILpiqtZD1WQD2uYTC9Gj6/fgQcbCLufm7sd2PJDfA+USzuNGTLJRnbM/AcsEU3JKBoeCXsfx61/0k5AMpeVg522HCFDRfRC60x0m3vAQbLr/tQTzU9jtIVxx9bxBY+Rx71OdhzRYBDTyUN+yP4ociJCOkTWRAhH0bw2gjOjuAaar7+pbgjEZlqH1ukKFIRuT2yF5pfRKlqrEz37cDbelnsA/DBp7aL/N9Rio0THtdtnMj/dhdC1icRblp5TDNthWXNMs7u02T8t5P6feuPeTwGS/I+xh/sPo0/fntJvy8EJh1cXnYf+FR0zbRj4irkQFcpXoddNiIBgilBtBntostpE0Xe8TweiGQ8AG7mYU/w1bS/lPbbOKKt1rR0Rdhqh51c5VHJSiQcqbvnqRH45R3p3ud9xu6TpuJp3/FFZIh6dXzrJkw+//i6R3dMUSMUj8bv+OcRL5ZATJemmGVeEEwy2hKThW0QG2q5KBj8bF6KdMoJR3kIPE6MX7cIL8cWv3Biwernjms5HeL885yfwUlXLBC80N5/w5YYSgHEOkOiWbwvkpdTiDk/NuMVi9aNV0/8AAgcf271AopPI/8KQsIZ8K8BH8lgQFYTtyVmMgCYU4WJbgiHNmhQirDe2Jojfcbc0MN5R9YnTy08yzf4CnwdSrYs09fbRPwrnADwrBDRWUTJapNMCoO4jYbSej55mmxAX8EiamV57Cc83nvtave2wPVPLB54aJRwl79tac8pN5Rle2j/2sdqjPzStAfitDzFCDE1DdRZ+kBz3RhE7ITQhJsthnSWuSBKwh8PevWgGgvjnFz1CwpH4I9wXwnHkAm1UdwckY3EaLbIEHNuGoPEzTG0la58lDrwGSBlcVEdUULmq7vl/cLYGdPHCftl/gjmB1RWDlAbWR/gx/x68guLJcPNOArgsJufGCNs1dM4X4oevz6BHoPxNPlFRBoMAABg9Ho+MYZsawXDw0XKXOQXgCGisPpJLs7S8kirI7leEJfbaR1tohkCfofTZq2K2WycXBXjgqhFPiTa1SVoA5y09QxZfqleX5wetL/9jiUrb1Wnk/7pT7+X5tiUvXYh9+pmhmcuGUBeZ2sL9VUCFrOZiOBCEGKzS+LXMSRhmZMkzliPHXVmjDBcqsfOZO6saFGL8beJ8D7qsOJIGaWzI+rB/da7Z7QvmRa8aT4ZcB3B+Z0XVpTF510H9btIBnC8MBiloUFKeiDgckkSSjdbLMjvRzYztnJms90ufx2z12NXHfYjf8vikyPncBFdfbookfCqiL7U7IHpgLPSSPMya24JuD7suRi8bvSQPrOv6Gb4P609CXiU1bX3/uv8s/+zz2QmM5PJBoFMMpMhhCTkZ0kIBJAQFoddWYQgEJAgIJiwBkFBBQEVBQpoXUAsiCmtBcVK7QuVfrYqWn19KVTs02Lra7++An/evff/ZzJZsJUnMSaE3HvOPdu995xzz1lv2LZk5aoDjTUiXEONuWvwsuHls2KrBpez85Y33LNhZXxEzkJFD/5ElVJfITxzwcPSMFMWNDNpXm+GXbRzwMAb+nJZZlE0X47vEOEd4kxxiUibRL8YRt80iTtEThBF2o92ICOdlub3ozX48YN4La29HB+HW9Cia7At2YQ2uSZcMX7G9KXLiA8MusKWkkTdlkg4CtAvJC7NatuIWFEeInwiDTC5Zo63p0Pqq633L9xi2iIMKRgw9Ik+WcOlAX36D+VaDJsXLHpgWOX4Gtozd3XDHENZedmQlYtKhsYiFSX6OcsWTxs60UNZ5hAf9s+pGjqG5EQLTKBGyhQEDYRGjqJEAwMYA3M5rmGVkvj7DWcMrMEAddxpKCIBI5Eq7C9XvCS4q2SyEk4Yy34ohj2aSFJojg6K1E+a5IfggkdW/yPjKhSoLw8enA3/LuvnwktR+QwcQmSWoaqo6wgXD5guZTrsZrNFFNH93IpTt72i40pcFF0uw+W4y2WhLfYrcQsWXxoJEscliN2lRw/oVlM36RohuSlq5xlMVVywNsjjyAZ1fcOKT0KbdCWRxuW5Efu6IHxRfstaNL7hAXrY6g1nTAPCu7akp8NTSz8sfZDI0A0k6zSJXeZLItoqBA0y93oDELTClbgWk4qBFpB0+iv6TNTJSNlDRRZcFZmm10zP27R0j7ya4pnfv9z6xrLD0PfOUuzHgiIl0RySUR2wg35gkRTpmx4EOVwwmOMQvXqH19E/v296umAUjJfjM4UlAmUS/EJYoNGHkOnOpC/HM5FYnnRbL8fdhEYpFJqptC8BJWLPOtSkF0dKnr21iHyLrayapVYcS0aDiDAuzI8OzI3mhwvtKwaVoP82P7hm9bpVcx+oX7xq3tASprmssDQycFCR/Hnz4KEbS6V7l9+3aGc2XdgUv7d+WnM+bZ1C9kxWPtNxoQP3lTCdpAFD3p4plW+wd/L6L+QzZ89iH24FW93xNfcwsGC/K46oA62W46z43ZsJhNsi5neSvTjIHouXwucgdInuhJAdeT3at7rKP6X+q9qpDZUFbLs/wzU7/YnSiTrbFDqd8HYH2innkp5A/SQH3jZZVm0IZAKM2hAoabNSuowgYVI6AVFfwDU3+sLn5DfhN9u3b6fTsW2m5Q/YH8E8Pk+tFVIkOTQCA2iaZxi9oAMSiwzyo1MZZBKrQEVELZneFkk09rMoKaA40zVqz0JQthy6+dIh+BTu0sX+qBX9+WcTUOH8kMDB78gMoERyIx2jGUbLCYJBqzXqeI5HcBh0tSSgom1qQlISUOIpV9TOhmJOFeTgdvn6+msYJp+nf0n7AYaowHsPwYsieBqgR3vbCCnA0BoNh4AKer2B5zizwSAatYIWAUU/hwZBBRspScn178wrUx3cCDofyolFnYk173364rlfP72nRUFBe/Ql/V3yZwoWvaxZazBwFD5XMALHqWumKPYWa+48PtpDWTES48Ag56+Xr7d/dQiaDnEPal/Sy2vVRVPyn9mfQqvKy/7oxIJOBgzLaHhmR5zH/Y4enarwUel2opzWEkXaonas/ZMPnSes+2lr69dNZM632HOwgsyZhk77AQD1TpfLq9PrvS6zWbM9bjbbaMa2PU6jUymtZ1rhCLyQvBS71/nYhOgxtjEZSg39EA6FOx3qsQ5aMehd0QkTM/v310zV5Y2uKK6ryyjI46bp+9ZwLzfJe7OzQrnjq3OzsrOzakeRGK1czPwMvsuuQ7KbJumATo+4CbQcPv1EoxciJOBBkj5DuNsX+YTvTskN/zZMPqew687NRX/OEX2/whynzrFfEx2zo7MtTVFaXnnUiEipHvgS7wISXFLOfDinKUrBCfI+3WH9mTP6wzp03pPOn5fPEr58RPiC5aAPjqZAEnXg0RlIo2Gb+QOgwtMWFUvCyvk5IemE65hezZjjcCAmj8Lyo00qvzvnzZFEGscUNRpByzAcB5uFbtPi3MOE/uCK99lYd3bijnpEd3K68tsJfKBUcqNDiMvt1lhttnREkHQbg45LXrdZAwijIxFkCnDH9xQeJ7Dvlcc01p9Y0y14vLf98/Xsua5MhvP1G7RIlxS86pT4EdZnFmkSB80IwYDJbA549TYbOr0hVeZ3IHNp1iiS+LvpESIFlm5YJqsg4/6DoRjsXSLzDsl/OQRfuAW6fB3WPLmhm1RSHXH2CLyTO03qZBZJHgGHingdwIdeuCOODr68nw/zyMa2wkp0bZqO1R6m5rCiozpSd8yqQEtLwaX35FNczkPy32wQ+v6BePQamr+G+zuaH1sVD0DiJECB1+t5I5BoSTBU07SOb9ayZH4cqIuE8zwXVH1PcggBsRJjFi2O2oe3tOS0/Wn+VeqTBdyih+RXrtm3bbP32B+ikl0jAIbn9UgjcEl0KPHgrFY1np7fRTyqzqVqfILGuDoioShVjkWZzyPka2nqsr+JoErKZAGjMTDo1GCx0jq9blwcoLWZzaZxcbMJ2TPNuDifutuRDJzuGcm4sIyo7H4kyxbvgB98oOyBX3yBd0FqwSb5xe3b4aRNcNh27BtY1/El8yhfZMmm78Zd34Rx3wCR5w9AAc4H7lNUjpjN0FRrx2cnc/uwJuwpiMVAnurn6X3sQRi87bFHwY3bHnsMGr7z2BzqPDUckBUDGY3OlkwMXYKbqZRQ2clp+hSmTCOir98yz0HQkZinCM9TdJvzHAV//F7mOfYd53kCzTOdzFOv0PYdhTq/I7SFophNU7C149RJi9XIdaNt72MPgpu3PfYo+Pi2xx4DX3znsZhu2ao8XFLoRlMhTLcQNKvTPHfSmpYyTa9065znILj8vcxzFLR9L/McA+3faZ5DaJ7hZJ4VCm2/UKij6Cl0qIO/Oel08aAbbXsfexB6b3vsUfDP2x57DNq/81hMt/GKPEBNgm65mG650J6cxhVImaZXunXOcxBmfS/zHE3Ymf/nPMcg853mIXsWn27JBqPxeLAC3A/rgVXSUVYqm5ptsjAU8Sfnqb7OZ+XJTIyNgyAolwIui8WKtji/n7bSGSFXWpphZjyNsdNWC8AZ6+rbjB4ZeokWVcWK9w1fJY2ktxc6g9qj5Aosmilqw8zDpU1T6pvrZ68c+/ikM0wrzzRef/3oB/LkUaPuW/zB/1Lb3n3p3uOzb7zJaGD5U2OuX++4OU1+S1ZqyuL3JH3ZSvJK3mcziqLFqbej/Z61MJ40l9FK2y0WWjMzTnuT1cS7ohhVnYTERzgYluNnpMku30zftavHDynK7V9ov3nB/OJnlNny8ubdjxj36rxD6mYw9cfH3tjFVl7/+NH1tE2lG+IXplsGOhuEvA6HE93fnAZ0RA1lev1+cWbczzidtJvGedk8T1sTzhd06Kvo1pQ6keSY0gy1HCpE9MFUIjKxv7Wf+qTfCde6Jet3dSUiNV7+UD63bW/65InffPYPQsejcIVKRnyGbgP1MIJsjQ44QOB1C3aqOk3CT2ApQCcqWA7U8uvRSLKcgOq9SCkmACPP7tn99BMH9j3x+Oi6SWPGjv8B/NMb594889bP3jyzrXnd1o0til//TrAWPE/PBhwISALgOIqnKMicRrAALMNuscTxv7CAPHeLiv7zF5vWUvGVD6+66VFy0D4Fa2EmwtcL7pB8BqMRpvE2m8+DTpu8CAyS0VKNLsui9kpcbIWlp6AHeK5gJ2lZVydpHr5LJo+xyr0yK+Ej7eYwJF5S+dPM1XOmVVaVD6rTbNbtW7XhsQm1qyfa4Z61w6rWVEl1/QYMHBDz3bmwYU7ligG1lZmLMa4XEW0LEK4hsEqKutw2vz9ocjMASUSmHoDMoNlkNl2Om8x+c9hMa2mzmfa6JJOlGl1avY4rcS9awUlauBLnWzvOvoZWRnyj5URiOn2jeclemtgh1aNYQsIp6lB9osXkK/bpJLzAdgcseOrxDYeMOy3bq8efrjBGJ495eJP+YbTKjTuPnYc196xeNMPTIJXWLwwXzr3bNHVxw4yWIEXqXaM7GOLHEMRT/LS1THKZWFY0c+iuCLEHz8RciWtMJgr7PkvJg3fF9xnt4TogV8ik49MEOT56cbk8Dz6ybumXmScMrhvQu3//BPiN3HcpfCX2n3YcO5HfQ/QtpKei29/dUsBps+Fu8FaHFXAsm44InG4xmZCtom0255W4rRUOIsTkVGIS32cqMZWjeVTscfXqJGQg6VzO7nR/EjrCwiPb5I7CnbY7Bo+ePHJcRW2g0QdvysvE0ISK9bvh6rU733WVxupGDBufmw73NL7qDbUo9PsQLIB9kIzgGgA1UkD0+fQ6HQe4kBOAkEc8YDtuo2w22ijs10O9nihmIKmY4emi6kpO5vRjh3g3VVU7gxM8U0uAwD77Nux+5vldbxe3eGeMneqcVb3isceqaodVj6yqHAuX3L/jpyfO/8eT7tEPrM0obH6gZtio4ZVjxyo6uAaG6GmI5wWSBd3kNUCj4wEyIRpBcyUunIaDAEN4nepSUb23XNJ7C0P71+5qPiJXUlXUjZfkj47uhqHWJdgX9aGqN25Ek/5gkhRKN3isVodgYEAfjssPAZDvEILZwezL8WAQqY2XhESQruRdjitM7d5y/paKgR/Fda2KkA5ppB6EQk6VWJhWBc/s2PHsrHE1d+x5sOmp2tG1dx3e+lBl5UOW2pqR454ZOwoOXbCk4Z7qeXrKNGPwpHvr4+UzjJTubmhbsGBASfugUql4nUT4/RHid1+0NhfIBHVSrtXv5wx6ZHS5LDcAWY47vDO9S7yveM94Wa+XNgvNhkcNlMGA+F6OiEEj7nfheypxE420OwueJKSVvOpPrYogf7Rvw679ew/N3eJtMY3NS/B+dI3Ce2rO/Tt+cvIXv6wb4+6TsxJzf+14aXRV5ahRiszWoTv9Ud4DWBL7yDIZcbMSntfp9Wbi14FmrcnoN1JGDcNAfMWHeo1yvX87ryRsvtDpkOrFYxlz2onvK2aN/uZS+6zlCz6hPpv/+zbeoz+ufcX2wgs2aMQ4TEQ4vKziMEIKYRwwAggNM/FZoXMFg0EzKioJDBBwjAR2jUe6w6ft2MUAk/AXzGq/RD2oIsDN1x7Xy/sTGGAc1iAcNiIczCRil+VxI0tjtVgcTmca2plYFghCmt1tbTYZjRSPkeEd1gQdIsgKehKdr5OtdTtxgUWdfnecRh3hk2hBd2k01zZo2N5hA8prxAR6J0JmyTar30Dn2N+k4vgWwrEC4ehEZqNWyvZ5XS5PwO+32mxBt8fDazRBl9esQdupF9gYPUZS7wkoSLblRSLKk4ZkMnYPjvXqizLBENq8ER9v5Tx7Y8/Tvz538Wnuzq7uqIZh+kd2aBW8zyO8Swh/raBYcioeeMEsijatINgYURDgWQOnOo3aEDHf7sWvp8gTUoREnBtpQvun6+PrjlgWivUTJswXFzoOIcl6XPtfm5YPLx44bOW6XmCzDINEKgmbQrDZfw2byJK1C+xp6z9tD3SBzW3WPq6XtyWBd8I2oF2tQvIanU6vFT+B0KUzNJ3uTUvjdTTNm+1neUAQiHgUtyaRoC5GDslzF+h0ikTlwVgEdsFktipTo0aGatgjCYSgkUhVQVFxqizpkO2qlBBCGoEWbIFgMAuJU5bPphdoPfoIiq6zXCd2kcSzmF58moQ+xB9thMWkc6UiSqTPJHFrzttknOh7qMU30b7OHRo+pDytVpyKJEjKrJJKPVicdH1Hs0fqp9fVzZn9Cdr8y4aUBNAXv08q9RNbxbwKj3LZxE6US94etsoMJYbRGpv1mp2K+7EkTLyPPa3Dt1knLjvVOnWHWyH5eE6nE5BRQAKk2idGopBV4pqNWhWweEvIil1y4ocZBPZCZJd+2/b7+Z9RnyxglyOzVCf/FcPGcO9FcJ/gGoEI0hCPAmkeu91ls1pxICRhk7wUjyySw9PssiXXHG37tyyREgGkO02RcXR5zFMVPzt05NS+MYdKDfZ/+lnHuRoKKoXsGZRFwS1Bl1aE30juGhDQzXKklAEBy2qQZPvS0zOQMRItlgwOeCxadLbQphsdGmYnCXT9KztEJ2nTu3d8tkot2HoLi8S+r6I5v0fchpJPIJzHcF+Tji7FkttoMol6PRJ+wYIwtwi0iD5MHI64RNpUYe9hD+gUSaeRdbSzcOMpS6P3jdO+RvuJv1x6T/4l8+qL2558cvvzcKSt3XepJ1zENL0opsDFyvav4KZqGJ2FpMgOW35kb/SdfsPbaDm1Tf7le5eYV3/4yJNPPvwCHHnJ125LwOXzEFxsg3xonxBFvd2OIRMrlObxCDRttJ5VYCMdL+l+cE7eqrqsu4ckpdJg/PSUsHKSFh8Xu2anbyudqMtdTKcnaXIN4RbCuPkDAYRVJrI/CLFMb8IEBcwulS7dzU+X0EUqbr1HVVLwE24hOklU1/QQHQBBPfscZeH24d6wkg4JO01RHE83K+bRcyE160nhzgHMEvY5wgo0vhrZ3K+5p5XxidwrMr6q23grkapqLEnsESJBJGeNPULt5n6I9C1PEgUNTZOgLsdpGaGZo5JBly6xaxIHIdpUHKV2I6W+Ol8+zP7YtnWr7VqPOQF+nIdUF9FfyzPNHLzlnMn4DfzBYZlEb9gj1/CkOJ+mP/sragq3mcRuciSzEtbXCCwFKCWmP0KN6Xd7e4WjzPD1QzffP8L+Sgkuw46r7PPUa9x+dMbOkox2hwNJiNvBGpotgror4dBPalBU6ZncdeuB8L/7Thg3JpSVrVuiC4+v6Ddh3KhgVq62wTybfT6rf1a4etbdA8jXrYsR/gH2CNLFfaTvU6FkQyB1HAcUhuEmhc3JHfFCpGchGIV3UfL/wM8RB2/+XGHjH3wf40+l16UbwTjBPYvOBiHJwKBDAa0zmrRMc+pRoGtz+M7dn5q76TVLo7ho6tSFYqP9JHtk65JYWXnRshY07wTmfXoVO570XdZCwLCQ2hGHB9WkvEQgfBUOhDHvNyn+1nDH+8yz3DpzNqu7H79h+Vp2KTnDnA1MloyUbwQpK5XhgwC/LPm71M8XwonkTqsTmp2Ss8FJA2fAWYC+Heechf7a7HzUecB53HnWedFpaO1456TTqdFk5U3H+cWd+eFd4Yq8AhcMlHJub+Zec/evdUyktSAo2SFjhgEzfMZsxtnK5plmWGBOfZjSy9jPOxaSsTYKJzwHEqnOFDQVmEiasjJUyW+Wm3DeriVb80dCu6vXAYhIafidISxrLYM5ZdBRNq9sRRnNlsGiso1lSF/HnCwrA2JWnpoKjv+A3ub66ipAFsOOZsp0Z8ItmZDNrMykLmZmqoPxUGXc4S7jvkQabpIENOxD5XdF5fe6v/v63t4GAQ68jXDnO/6MNMeJrHqY9PvJkqxlJWkgCKXggSAVtAtCeY6JBrg4M5LutulLI5FIYYEz5babWvaTv0UJUHvq7yA1eTs/IyO/IBAo+Dw/QL7JXx5GfwsHA2GqID8jUFCAfpwfCIbR9/nnl9yt/HI4iH6IB74SQP8YKMj/a0b//ugX8l9R/y0fLpZJvSMG/EFupq+itdGkMpMfpEnIsviBG0ruA27Knc7j16BoNSVhtJqgPfht2P4BjpB/TM3tiVesfnDvGHTC59FdBndVIvADAD9UO+CjfEFdCnwYI9Fv+7fhAGsXwxH1cEtPJOQvG+vrG0/0iggFlnd8yZRyMYQFYjosyqdyjLTdho3tYEqADqdS7w4nTOfjUoBUMYxlqg8w6QcLK0d7Rm6eVxYauWRMbUOlX14GwxNt0ZzcQumBk/ctO7l26MimF2bJ7dD9+T3TaycdhB9OfOy+SWme2mWPTx29YVbxgJkb6HfkN6Y6SoYP23/X4lMbqoc3vX5fw/GWu4Jw0P3rPRt9APwfXHnEdnjanVVNbxw1GH43mzbZtE0vCImqVAYJKZWykw81EuqtTdMPadNUTT8uXLwznh0ns+OR7d1VcuVXICR+AEJI3Dhx4c6ZXwAXuCEuXHj8jjfZpCEIMprsM/b75dePHxPRnVZFLWr+3tC3EbfoZuuTiOdoobUTcZtutT6PeB42P0R8hZZbv0V8lZbnPoh4gY7bdyJepPfaP0bcoeX2nxEvtdzV3yO+RrcXv4z4OiWd9yO+QVud7yJepltLH6KS1nwHX99wVQG3sJYrEc+hnq2I23SvtRvxPGy+ivgK3W79FPFV4L8iXqA/5lYiXqSV9hcRd+h2++eIl+Z+mZ/mukafLsqIr9Nni99HfIMOOjsRL9O9zq/0iDQN8Hq8x6QoI4FX4lsCpWSopiOybFVgVNAKRu/id5PWaQOvoCewMpgv4S9oG9jCK/yXHNdQRQkt8czl0TaBXsYqnrL3KtAz+KeIQI/0QHt9rDKRSS9FauojqweFFyvpXbG5vrEunhgzKJXYNrY2VnptqmRp+7zZpniJEE+lXxXPqhRxeyioj7SzBQva5V+Dad1XTTCxayoMhBIHNMKCJXzopRqMSgnwgBwKVfDKOJqgLt5/if7AparKlBVd8U6i/1rYG7Z1J5ab6No6noS2MKmsC6abyfp6snVx8AtCX1aJRi7BTPE8E5Y95KYcYsxQful+CtgpZp/DjOKvjKOG2K9hsc9WL9gztNVztoqtXl2QcQ8Zc/inzMSpZcqxA6ObyAa4iBt0gG20XEHGftO1ucC3mf5qJ6TwVmZqKO2hMPlZDgmrBtp5ZTGoK/E62U/EC+lV5YWsMvHqxHEvz3WqeDBV1ksYG19g9w9GVrtMpyGbSy7i0sUH65Q/M6QndC50bMx92GXz8O0al32vxkrsSu+VC8YPYeBi85uNDblGTKQK42HTJmhZaFDBWPLGZxwyHOYqevdxvMWlyUX0lZFAFfNtHFc0jtkCFXL+7zhvhRwCWPLWCK42bFt+rgrBWyuZKA05h5j1bJtivMRzFIVtiF42WftRuiYshMXJ+oNX0/vn+J189DHT8WxvGprn8eCFrCGu5TWddrTLuxnWo7jKgCQLbR8eJedt6iqYzJKpqCI1PVfvZijdEFjwCkL0Ha42yKuKnX0LWe5dGLHp3uxRCjtTcr1uJnbF1WY8Zk46HazKmKlZccnyf3iySzkztOlmxtG6/9DvnHvjY1bDFWV4mn1vGGbgO+JdbI5/w3//Tuck99dEv5q12cdahs1xfigdjicO87YZOV2pVTEpdFqIiXQiU04PKkz3j8TZ4yEwKyEAVWXGOFxjuFmVW+UKXQ2Ek5UTTlmdxxDCF9IHuRgqb3Uqy/IIF9WwhmsfN9NE+yLktxon9rmafJ1Mq4Gm5FBooYe1NWMutOtSq1SFfDKTfV1qj1iFtDKF0kBudOpYSSAgopZVd2dkTa1Q7NsnvVNDlNeokDPlWDm2rpTKXFCxDEst4YTEpTGHYUm5sSgz80V3pu7cVB6uRsgsw9rRMJOOhkHfoDl+WpxMrcFcXUqPKMOgYwWf/pru0xqeCT8Ja8CsuqVR25LIlDU4el/fX1ubTCaJjBKXQuESFLX2/8MGstRM61npskyQEHMI4lya2h/VKpLFuqTww7K5HJu0UxUdzej29Dzt4+Lr8SVVRxV4HPkvzkUICnj+Kt9AgRvhSkI9gcYj1vywl/vPemKvBk0eY49ENFgV0+t+I9k4365GizS+PS/c8UlKuFkDzO+hst5JG0BCXXuXOF0mxg7W9h736G8BvYf9AAAAeNptnAV421bbhg+fozSldczM62rp2I7HtqPTdevarbCuo85N3MRrEqex3a4dMzMzMzMz8/aNmZmZt9+2nkDzZ9fVvEeyrPtIdnQ/r+WMMFL/75/nyTQyxH/e7tUflDDCiSCSKKKJIR5pIMNIIxlORpCRZBQZTZYgY8iSZCmyNFmGLEuWI8uTFciKZCWyMlmFrEpWI6uTNciaZC2yNlmHrEvWI+uTDciGZCMylmxMxpEY8UlALImTBEmSJpIim5BNyWZkc7IF2ZJsRdIkQ7KkmYTEkfFkazKBbEO2JRPJdmQSmUy2JzuQKWRqdf7TyY5kBtmJzCQ7k13IrmQ3sjuZRfYgOcrIxeQQcii5l5xGPieHkePI0eRcciW5hHJyFBXkYHIy+ZH8RI6lkhxBFXmX/EDOI1eRX8jP5FdyEbmWPEkeJ9eR2aSFnEBaydMkT54gT5HnyTPkWfIc+YLMIS+RF8iL5HrSRr4nJ5JXycvkFdJOviLfkCPJnqRA5pJO0kG6yAWkSOaRbtJDSqRCymQ+WUC+JHuRRWQh2ZvsS/Yhd5ALyf5kP3IAOZB8Tb4ld1FNDfVoAx1GG8k/5F86nI6gI+ko8h8ldDRdgo6hlC5Jl6JL02XosnQ5ujxdga5IV6Ir01XI7+QPuipdja5O16Br0rXo2nQdui5dj65PN6Ab0o3oWLox+ZO8RsfRGPVpQC2N0wRN0iaaopvQTelmdHO6BfmQfES3pFvRNM3QLG2mIXV0PN2aTqDb0G3pRLoduYHcSCfRyXR7ugOdQqfSaXQ63ZHOIH+Rv8nH5BO6E51Jd6a70F3pbnR3OovuQXN0Nm2hrTRP59A22k4LdE86l3bQTnI37aJF2k3nkU/JZ7SHlmiZVuh8uoDuRRfSRXRvug/dl+5H96cH0APpQfRgegi5jB5KD6OH0yPokfQoejQ9hh5Lj6PH0xPoifQkejI9hZ5KT6On0zPomfQsejY9h55Lz6Pn0wvohfQiejG9hF5KL6OX0yvolfQqejW9hl5Lr6PX0xvojfQmejO9hd5Kb6O30zvonfQueje9h95L76P30wfog/Qh+jB9hD5KH6OP0yfok/Qp+jR9hj5Ln6PP0xfoi/R/9CX6Mn2Fvkpfo6/TN+ib9C36Nn2Hvkvfo+/TD+iH9CP6Mf2Efko/o5/TL+iX9Cv6Nf2Gfku/o9/TH+iP9Cf6M/2F/kp/o7/TP+if9C/6N/2H/kv/Y4RRxhhngkmmmGaGeayBDWONbDgbwUayUWw0W4KNYUuypdjSbBm2LFuOLc9WYCuyldjKbBW2KluNrc7WYGuytdjabB22LluPrc82YBuyjdhYtjEbx2LMZwGzLM4SLMmaWIptwjZlm7HN2RZsS7YVS7MMy7JmFjLHxrOt2QS2DduWTWTbsUlsMtue7cCmsKlsGpvOdmQz2E5sJtuZ7cJ2Zbux3dkstgfLsdmshbWyPJvD2lg7K7A92VzWwTpZFyuybjaP9bASK7MKm88WsL3YQraI7c32Yfuy/dj+7AB2IDuIHcwOYYeyw9jh7Ah2JDuKHc2OYcey49jx7AR2IjuJncxOYaey09jp7Ax2JjuLnc3OYeey89j57AJ2IbuIXcwuYZeyy9jl7Ap2JbuKXc2uYdey69j17AZ2I7uJ3cxuYbey28jr5AN2O3mT3cHuZHexu9k97F52H7ufPcAeZA+xh9kj7FHyFnmbvEPeJ2+Q99hj7HH2BHuSPcWeZs+wZ9lz7Hn2AnuR/Y+9xF5mr7BX2WvsdfYGe5O9xd5m77B32XvsffYB+5B9xD5mn7BP2Wfsc/YF+5J9xb5m37Bv2Xfse/YD+5H9xH5mv7Bf2W/sd/YH+5P9xf5m/7B/2X+ccMoZ51xwyRXX3HCPN/BhvJEP5yP4SD6Kj+ZL8DF8Sb4UX5ovw5fly/Hl+Qp8Rb4SX5mvwlflq/HV+Rp8Tb4WX5uvw9fl6/H1+QZ8Q74RH8s35uN4jPs84JbHeYIneRNP8U34pnwzvjnfgm/Jt+JpnuFZ3sxD7vh4vjWfwLfh2/KJfDs+iU/m2/Md+BQ+lU/j0/mOfAbfic/kO/Nd+K58N747n8X34Dk+m7fwVp7nc3gbb+cFviefyzvIFbyTd/Ei7+bzeA8v8TKv8Pl8Ad+LL+SL+N58H74v34/vT87nB/AD+UH8YH4IP5Qfxg/nR/Aj+VH8aH4MP5Yfx4/nJ/ATyen8JH4yP4WczU/lp/HT+Rn8TH4WP5ufw8/l5/Hz+QX8Qn4Rv5hfwi/ll/HL+RX8Sn4Vv5pfw6/l1/Hr+Q38Rn4Tv5nfwm/lt/Hb+R38Tn4Xv5vfw+/l9/H7+QP8Qf4Qf5g/wh/lj/HH+RP8Sf4Uf5o/w5/lz/Hn+Qv8Rf4//hJ/mb/CX+Wv8df5G/xN/hZ/m7/D3+Xv8ff5B/xD/hH/mH/CP+Wf8c/5F/xL/hX/mn/Dv+Xf8e/5D/xH/hP/mf/Cf+W/8d/5H/xP/hf/m//D/+X/CSKoYIILIaRQQgsjPNEgholGMVyMECPFKDFaLCHGiCXFUmJpsYxYViwnlhcriBXFSmJlsYpYVawmVhdriDXFWmJtsY5YV6wn1hcbiA3FRmKs2FiMEzHhi0BYERcJkRRNIiU2EZuKzcTmYguxpdhKpEVGZEWzCIUT48XWYoLYRmwrJortxCQxWWwvdhBTxFQxTUwXO4oZYicxU+wsdhG7it3E7mKW2EPkxGzRIlpFXswRbaJdFMSeYq7oEJ2iSxRFt5gnekRJlEVFzBcLxF5ioVgk9hb7iH3FfmJ/cYA4UBwkDhaHiEPFYeJwcYQ4UhwljhbHiGPFceJ4cYI4UZwkThaniFPFaeJ0cYY4U5wlzhbniHPFeeJ8cYG4UFwkLhaXiEvFZeJycYW4UlwlrhbXiGvFdeJ6cYO4Udwkbha3iFvFbeJ2cYe4U9wl7hb3iHvFfeJ+8YB4UDwkHhaPiEfFY+Jx8YR4UjwlnhbPiGfFc+J58YJ4UfxPvCReFq+IV8Vr4nXxhnhTvCXeFu+Id8V74n3xgfhQfCQ+Fp+IT8Vn4nPxhfhSfCW+Ft+Ib8V34nvxg/hR/CR+Fr+IX8Vv4nfxh/hT/CX+Fv+If8V/kkgqmeRSSCmV1NJITzbIYbJRDpcj5Eg5So6WS8gxckm5lFxaLiOXlcvJ5eUKckW5klxZriJXlavJ1eUack25llxbriPXlevJ9eUGckO5kRwrN5bjZEz6MpBWxmVCJmWTTMlN5KZyM7m53EJuKbeSaZmRWdksQ+nkeLm1nCC3kdvKiXI7OUlOltvLHeQUOVVOk9PljnKG3EnOlDvLXeSucje5u5wl95A5OVu2yFaZl3Nkm2yXBbmnnCs7ZKfskkXZLefJHlmSZVmR8+UCuZdcKBfJveU+cl+5n9xfHiAPlAfJg+Uh8lB5mDxcHiGPlEfJo+Ux8lh5nDxeniBPlCfJk+Up8lR5mjxdniHPlGfJs+U58lx5njxfXiAvlBfJi+Ul8lJ5mbxcXiGvlFfJq+U18lp5nbxe3iBvlDfJm+Ut8lZ5m7xd3iHvlHfJu+U98l55n7xfPiAflA/Jh+Uj8lH5mHxcPiGflE/Jp+Uz8ln5nHxeviBflP+TL8mX5SvyVfmafF2+Id+Ub8m35TvyXfmefF9+ID+UH8mP5SfyU/mZ/Fx+Ib+UX8mv5TfyW/md/F7+IH+UP8mf5S/yV/mb/F3+If+Uf8m/5T/yX/mfIooqprgSSiqltDLKUw1qmGpUw9UINVKNUqPVEmqMWlItpZZWy6hl1XJqebWCWlGtpFZWq6hV1WpqdbWGWlOtpdZW66h11XpqfbWB2lBtpMaqjdU4FVO+CpRVcZVQSdWkUmoTtanaTG2utlBbqq1UWmVUVjWrUDk1Xm2tJqht1LZqotpOTVKT1fZqBzVFTVXT1HS1o5qhdlIz1c5qF7Wr2k3trmapPVROzVYtqlXl1RzVptpVQe2p5qoO1am6VFF1q3mqR5VUWVXUfLVA7aUWqkVqb7WP2lftp/ZXB6gD1UHqYHWIOlQdpg5XR6gj1VHqaHWMOlYdp45XJ6gT1UnqZHWKOlWdpk5XZ6gz1VnqbHWOOledp85XF6gL1UXqYnWJulRdpi5XV6gr1VXqanWNulZdp65XN6gb1U3qZnWLulXdpm5Xd6g71V3qbnWPulfdp+5XD6gH1UPqYfWIelQ9ph5XT6gn1VPqafWMelY9p55XL6gX1f/US+pl9Yp6Vb2mXldvqDfVW+pt9Y56V72n3lcfqA/VR+pj9Yn6VH2mPldfqC/VV+pr9Y36Vn2nvlc/qB/VT+pn9Yv6Vf2mfld/qD/VX+pv9Y/6V/2niaaaaa6FllpprY32dIMephv1cD1Cj9Sj9Gi9hB6jl9RL6aX1MnpZvZxeXq+gV9Qr6ZX1KnpVvZpeXa+h19Rr6bX1OnpdvZ5eX2+gN9Qb6bF6Yz1Ox7SvA211XCd0UjfplN5Eb6o305vrLfSWeiud1hmd1c061E6P11vrCXobva2eqLfTk/Rkvb3eQU/RU/U0PV3vqGfonfRMvbPeRe+qd9O761l6D53Ts3WLbtV5PUe36XZd0HvqubpDd+ouXdTdep7u0SVd1hU9Xy/Qe+mFepHeW++j99X76f31AfpAfZA+WB+iD9WH6cP1EfpIfZQ+Wh+jj9XH6eP1CfpEfZI+WZ+iT9Wn6dP1GfpMfZY+W5+jz9Xn6fP1BfpCfZG+WF+iL9WX6cv1FfpKfZW+Wl+jr9XX6ev1DfpGfZO+Wd+ib9W36dv1HfpOfZe+W9+j79X36fv1A/pB/ZB+WD+iH9WP6cf1E/pJ/ZR+Wj+jn9XP6ef1C/pF/T/9kn5Zv6Jf1a/p1/Ub+k39ln5bv6Pf1e/p9/UH+kP9kf5Yf6I/1Z/pz/UX+kv9lf5af6O/1d/p7/UP+kf9k/5Z/0JuIjfrX/Vv5DZyO3lE/05uIbeSR/Uf5CDyEDmcXK3/1H/pv/U/+l/ymP7PEEPJfeR+wwwn9xhhpFFGG2M802CGmUYz3IwwI80oM9osYcaQ38ySZimztFnGLGuWM8ubFcyKZiWzslnFrGpWM6ubNcyaZi2ztlnHrGvWM+ubDcgxZkOzkRlrNjbjTMz4JjDWxE3CJE2TSZlNzKZmM7M5OcNsQc4iZ5LvzJbkYXIpOclsZdLkHHI5Od5kTJacQk41zSY0zow3W5sJZhuzrZlotjOTzGSzvdnBTDFTzTQz3exoZpidzEyzs9nF7Gp2M7ubWWYPkzOzTYtpNXkzx7SZdlMwe5q5psN0mi5TNN1mnukxJVM2FTPfLDB7mYVmkdnb7GP2NfuZ/c0B5E5zoDnIHGwOMYeaw8zh5ghzpDnKHG2OMcea48zx5gRzojnJnGxOMaea08zp5gxzpjnLnG3OMeea88z55gJzobnIXGwuMZeay8zl5gpzpbnKXG2uMdea68z15gZzo7nJ3GxuMbea28zt5g5zp7mLPEAeNHebe8y95j5zv3nAPGgeMg+bR8yj5jHzuHnCPGmeMk+bZ8yz5jnzvHnBvGj+Z14yL5tXzKvmNfO6ecO8ad4yb5t3zLvmPfO++cB8aD4yH5tPzKfmM/O5+cJ8ab4yX5tvzLfmO/O9+cH8aH4yP5tfzK/mN/O7+cP8af4yf5t/zL/mP4941GMe94QnPeVpz3ie1+AN8xq94d4Ib6Q3yhvtLeGN8Zb0lvKW9pbxlvWW85b3VvBW9FbyVvZW8Vb1VvNW99bw1vTW8tb21vHW9dbz1vc28Db0NvLGeht747yY53uBZ724l/CSXpOX8jbxNvU28zb3tvC29Lby0l7Gy3rNXug5b7y3tTfB28bb1pvobedN8iZ723s7eFO8qd40b7q3ozfD28mb6e3s7eLt6u3m7e7N0pWuwrhx6XGozV5xfr6n1FLsyfPOSqyhs9DaWiyPHTcuptOduZaeYpfORVWlZ/fk5+dVrl50uthW7MrP1bmoDsu2FHpaKp1zOvJ7DWvpHzdkq7vLtbTku8oNLX1D1dySq+2yNSrN1f3nyjoEMA9gGAHz9dIQ9u8o3zfUIaaRj6oKoz3m62XY+AGTahswqfH9+2rrGzaObyl2duaw0DZgYdjWA/bT3j8WW8/O9Yj26g81oVzoaM2rQr3oCTiSAo5kQnQkhejUTcCcC1FlE7ZhhT2HbTOAsWf/uHHbgbOau9hCW08+39WR62ottKiJuZZKOa866qVx4sDtOgYsqInRCeqoFzGxevSio/pDTYqe3xU9f9LA53cNfP6k6Pld0QnuynUXS+WeYnd7noddbTzf1aYn4+CLOPjJ0cEX62X45PZKV1uup9LZkauUhxcHLqkp0Rx6ojlMGTiHnoFzmBLNoScqU6Nnlepl2NQBp7E04DROG7i38sC9TYt2U47OyLTaS1quvaTTo5e0Er2k03FUFRzV9OioKvUip/cUutpkpfZz+PTFjrAycElPx0tfwW/NjAGzXTBgPHPAeGH/WO0cHeuiemnYuf9tvKhvKDuKXW2l+q93rGkcagzVRw1QLWocNYGaRG1CTaGmUTOoWdRm1BDVRTUFfgr8FLgpcFPgpsBNgZsCNwVuCtwUuClwU+CmwE05Obm92FNthGo/o3VpHHMa7DTYabDTYKfBToOdBjsNdhrsNNhpsNOhnF5nVvqZGRxvBuwM2BmwM2BnwM6AnQE7A3YG7AzYGbAzYGdw3Bmc7yzOdxb8LPhZ8LPgZ8HPgp8FPwt+Fvws+Fnws+Bnwc+CnwW/Gfxm8JvBbwa/Gfxm8JvBbwa/Gfxm8JvBbwa/Gfxm8JvBbwY/BD8EPwQ/BD8EPwQ/BD8EPwQ/BD8EPwQ/BD8EPwQ/BN+B78B34DvwHfgOfAe+A9+B71IN6dq1JPo1z/UNdTqMai4fXe0mlzpypfZoXOwf1/fijxuHGkP1UQNUixpHTaAmUZtQU6hp1AxqFrUZNUSNzoYfAz8Gfgz8GPgx8GPgx8CPJRunDrxalwYsYAvMJIaZxDCTGGYSw0ximImPmfiYiY+Z+JiJj5n4mImPmfg4Ez7OhI8z4YPvg++D74Pvg++DH4AfgB+AH4AfgB+AH4AfgBuAG4AbgBuAG4AbgBuAa8G14FpwLbgWXAuuBdfiuC34FnwLvgXfgm/Bt+Bb8OPgx8GPgx8HPw5+HPw4+HHw4+DHwY+DHwc/Dn4c/Dj4cfAT4CfAT4CfAD8BfgL8BPgJ8BPgJ8BPgJ8APwF+AvwE+Anwk+AnwU+CnwQ/CX4S/CT4SfCT4CfBT4KfBD8JfhL8JPhJ8OF/H/734X8f/vfhfx/+9+F/H/734X8f/vfhfx/+9+F/H/734X8f/vfhfx/+91PgIwf4yAE+coCPHOAjB/jIAT5ygI8c4CMH+MgBPnKAjxzgp8BHm+OnwUcW8JEFfGQBH1nARxbwkQV8ZAEfWcBHFvCRBXxkAR9ZwE+DnwY/Az7ygI884CMP+MgDPvKAjzzgIw/4yAM+8oCPPOAjD/jIAz7ygI884CMP+MgDPvKAjzzgIw/4yAM+8oAP//vwvg/v+/C+D+/78L4P7/vwvg/v+/C+D+/78L4P7/vwvg/v+/C4D4/78LgPj/vwuA+P+/C4D4/78LgPj/vwuA+P+/C4D4/78LgPj/vwuA+P+/C4D4/78LgPj/vwuA+P+/C4D4/78LjvwHfgO/Ad+A58B75zXltPbn6+KrzZXt3ktVH9sWCc79U7kQFrLGocNYGaRG0a3l4szs3NLs4f+Kw0agY1i9qMGqJG5yKAxQNYPIDFA1g8gMUDWDyAxYMYZhFrQk2hgg93B3B3AHcHcHcAdwdwdwB3B77fWO11Zuc7igv6DwoCDyDwAAIPIPAAAg8g8AACDyDwAAIPIPAAAg8g8AACDyDwAAIPIPAAAg8g8AACDwLwIfIAIg8g8gAiDyDyACIPIPIAIg8g8gAiDyDyACIPIPIAIg8g8gAiDyDyACIPIPIAIg8g8gAiDyDyACIPIPIAIg8g8gAiDyDyACIPIPIAIg8g8gAiDyDyACIPIPIAIg8g8gAiDyDyACIPIPIAIg8g8gAiDyDyACIPIPIAIg8g8gAiDyDyACIPIPIAIg8g6gCiDiDiACIOIOIAIg6SoSwXu4ql4a2FfE++VCjVlxrSHd3tufrQy3UVy/mOfCHXGHaXCtWevb7ahGU8PqGIUePkzkLtE4doYfqAjRsmd+bboo1GF6qbL8aSdZbI5Ms5OT5Xzc8aHLFzdRWvcuS09upI1EBy21x3d05NzHXObs2x7SpsUoXtVNAgs+0LfEp7UU4ttHXm+LRcRWMWfPv2As9W/21fKjROGDCDkdigd7kh13fgjfmBh5vvPdxC7+EuWVn8qdHB1J8vZtcOpq12MLI131HOaexLLKodUu3Bcv2QajuTc+uH1BEdUleF7VXQxeh4eE97UZVqBxOT9cLL1WMCl3dXj6el+q+6KIu1E9w48NyOHDS9xuLAV6cy8NUp9r060XsCkgwgyQCSDCDJAJIMIMkAkgwgyQDNcYDmOEBzHKA5DtAcB2iOA0g1gFQDSDWAVANINYBUA0g1gFQDSDWAVANINYBUA0g1gFQDSDWAVANINYBUA0g1gFQDSDWAVANINYBUA0g1gFQDSDWAVANINYBUA0g1gFQDSDVwEd+iHbZohy3aYYt22EKnFjq10KmFTi3aYYt22EKkFiK1EKmFSC1EaiFSC5FaiNRCpBYitRCphUgtRGohUguRWojUQqQWIrUQqYVILURqIVILkVqI1KIJtmiCLRxq4VALh1o41MKhFg61cKiFQy0cauFQC4daONTCoRYOtXCohUMtHGrhUAuHWjjUwqEWDrVwqIVDLRxq4VALh1o41MKhFg61cKiFQy0cauFQC4daONTCoRYOtXCohUMtHGrhUAuHWjjUwqEWDrVwqIVDLRxq4VALh1o41MKhFg61cKiFQy0cauFQC4daONTCoRYOtXCohUMtHGrhUAuHWjjUwqEWDrVwqIVDLRxq4VALh1o41KIZtmiGLZphi2bYwrEWjrVohi2aYYtm2KIZtnCwhYMtHGzhYItm2KIZtmiGLZphi2bYohm2aIYtmmGLZtiiGbZohi2aYYtm2KIZtmiGLZphi2bYohm2aIYtmmGLZtiiGbZohi2aYYtm2KIZtmiGLZphi2bYohm2aIYtmmGLZtiiGbZohi2aYYtm2KIZtmiGLZphi2bYohm2aIYtmmGLZtiiGbZohi2aYYtm2KIZtmiGLZphi2bYohm2aIYtmmGLZtiiGbZohi2aYYtm2KIZtmiGLZphi2bYohm2aIYtmmGLZtiiGbZohi2aYYsPxy0+HLdoji0+HLdoki2aZIsm2aJJtmiSLZpkC/9b+N/C/xb+t/C/hf8t/G/hf9vc5OXmFAqxcU29VyYkAIsEYJEALBKARQKwSAAWCcAiAVgkAIsEYJEALBKARQKwSAAWCcAiAVgkAIsEYJEALBKARQKwSAAWCcAiAVgkAIsEYJEALBKARQKwSAAWCcAiAVgkAIsEYJEALBKARQKwSABxJIA4EkAcCSCOBBBHAogjAcSRAOJIAHEkgDgSQBwJII4EEEcCiCMBxJEA4kgAcSSAOBJAHAkgjgQQh9HjMHocRo/D6HFcOeK4csRx5YjjyhHHlSOOK0ccV444rhxxXDniuHLEceWI48oRT/VyMG9cOeK4csRx5YjjyhHHlSOOK0ccV444rhxxXDniuHLEceWI48oRx5UjjitHHFeOOK4c8bSTpfb8/FxDtXfIzSnl24od0bC7+qN9WH04L9eZK5dke6GnME+WS9VULusbyvo2qvfhYrURiHaaSat5ldmVckm15trypXbZmS/n22Rnbl5ujujJzclXn1nKz9Ol9kJX7cZ4qV5MqVillirzvEp3d75nVm1VR3FBvqc6iPabTQyLYPOq4C6R68jP4dWGRbYVOvMdsrW6XGbteT4/N18uyi0sdPFqq8LL1X8Li61mTqEr1zE3N4dX/8nqVPNY1Znv5NV/0UJXpYtX/6lS9fG57aK2E11/oDvPuvMN9WG5VG1VZP0nn1esHlD1CEXtUKo9znxVhc+PShWqqv9qpa3WybR71VJqr+6zfppizdHvSrXGUH3UANWixlETqEnUJtQUaho1g5pFbUYNUV1UY+DHwI+BHwM/Bn4M/Bj4MfBj4MfAj4EfAz8Gfgz8GPgx8H3wffB98H3wffB98H3wffB98H3wffB98H3wffB98H3wA/AD8APwA/AD8APwA/AD8APwA/AD8APwA/AD8APwA/At+BZ8C74F34JvwbfgW/At+BZ8C74F34JvwbfgW/Dj4MfBj4MfBz8Ofhz8OPhx8OPgx8GPgx8HPw5+HPw4+HHwE+AnwE+AnwA/AX4C/AT4CfAT4CfAT4CfAD8BfgL8BPgJ8JPgJ8FPgp8EPwl+Evwk+Enwk+AnwU+CnwQ/CX4S/CT4SfCbwG8Cvwn8JvCbwG8Cvwn8JvCbwG8Cvwn8JvCbwG8Cvwn8JvBT4KfAT4GfAj8Ffgr8FPgp8FPgp8BPgZ8CPwV+CvwU+Cnw0+CnwU+DnwY/DX4a/DT4afDT4KfBT4OfBj8Nfhr8NPhp8DPgZ8DPgJ8BPwN+BvwM+BnwM+BnwM+AnwE/A34G/Az4GfCz4GfBz4KfBT8Lfhb8LPhZ8LPgZ8HPgu/AiTJZLIRnQngmhGdCeCaEZ0J4JoRnQngmhGdCeCaEZ0J4JoRnQngmhGdCeCaEZ0J4JoRnQngmhGdCeCaEZ0J4JoRnQngmhGdCeCaEZ0J4JoRnQngmhGdCeCaEZ0J4JoRnQngmhGdCeCaEZ0J4JoRnQngmhGdCeCaEZ0J4JoRnQngmhGdCeCaEZ0J4JoRnQngmhGdCeCaEZ0J4JoRnQngmhGdCeCaEZ0J4JoRnQngmhGdCeCaEZ0J4JoRnQngmhGdCeCaEZ0J4JoRnQngmhGdCeCaEZ0J4JoRnQngmhGdCeCaEZ0J4JoRnQngmhGdCeCaEZ0J4JoRnQngmhGdCeCaEZ0J4JoRnQngmhGdCeCaEZ0J4JoRnQngmhGdCeCaEZ0J4JoRnQngmhGdCeCaEZ0J4JoRnQngmhGdCeCaEZ0J4JoRnwqRTM+r3OtWCqMyIvtq4oF68Gb0fsHsLekfR8+CZEJ4J4ZkQngnhmRCeCeGZEJ4J4ZkQngnhmRCeCeGZEJ4J4ZkQngnhmRCeCeGZEJ4J4ZkQnglToZfuvV/p5XpHDem+O7MNub7hqHT/Vz3rp2FUbvCKAVvUT9vALeorlhywRd+Ol8wNsXLgvup3lgfuq75izIAtemc+Jvf/1w2LvhoefQ0tN2Acra/PC+vr45HR+r6ZjMwtvozn1eeA59XHI6L1vdgRucUWvbBv1LeuIew/z/37V2H01d5or6PCwSc5P3hFOPis5wef9XCos54f6qyHg896fvBZD4c46/n/v65hQv+xFfqG3oS+s1DoG03uGxX7nj25/9nF/tlNHnzoxcErJg8+F8XB52LyUOeiONS5mDz4XBQHn4vJQ5yL4hDnov613+jrksX+YX1tfVLR2vpwRH1t3yRGFBdbjJ5Th0fPqQ+H19f20oYXBy550/tGlb75TO/fYaV/OL1/apX+4fT+WVb6Zzl98VlWFp/l9P5ZVvpnOX2xWVYGLqmZ0WV2Yb14M/vmvLBvzjP7d7+w/3dlZvS7sjD6GnztmuaQ2Rwym0Nmc8hsDpnNIbM5ZDaHzOaQ2Rwym0Nmc8hsDpnNIbM5ZDaHzOaQ2Rwym0Nmc8hsDpnNIbM5ZDSHjOaQ0RwymkNGc8hoDpnMIZM5ZDKHTOaQyRwymUMmc8hkDpnMIZM5ZDKHTOaQyZzfy8PxIZM5ZDKHTOaQyRwymUMmc8hkDpnMIZM5ZDKHTOaQyRwymUMmc8hkDpnMIZM5ZDKHTOaQyRwymUMmc8hkDhnMIYM5ZDCHDOaQwRwymEPmcshcDpnLIXM5ZC6HzOWQuRwyl0PWcshYLt67X8wfmcohUzlkKodM5ZCpHDKVQ6ZyyFQOmcohUzlkKodM5ZCpHDKVQ6ZyyFQOmcohUzlkKodM5ZCpHDKVQ6ZyyFQOmcohUzlkKodM5ZCpHDKVQ6/u0Ks79OoOvbpDr+7QqztkKIcM5ZChHDKUQ4ZyyFAOGco19fJwvMhQDhnKIUM5ZCiHDOWQoRwylEOGcshQDhnKIUM5ZCiHDOXQqzv06g69ukOv7tCrO/TqDr26Q6/u0Ks79OoOvbpDr+7Qqzv06g69ukOv7tCrO/TqDr26Q6/u0Ks79OoOvbpDr+7Qqzv06A49ukOP7tCjO/ToDj26Q4/u0KM79OgOPbpDj+7Qozv06A49ukOP7tCbO/TmDr25Q2/u0Ju7LLhZcLPgZsHNgtsMbjO4zeA2g9sMXjN4zeA1g9cMXjN4zeA0g9MMTghOCE4ITghOiOML8bqG4IbghuCG4IbghuCGOM4Q/BD8EHwHngPPgefAceA4cBw4DhwHjgPHgRN9BuKPi3xYrVnUZtTex11UI99Vq48aH17pasWfbbbO7hg+r1Is52tZuKeUb8U2eG7knmrNoILlg+WHqrPQVf8DunxLsQvPDqyX36ulI9dZ3bvXk2sttOSqaSt6LI7ZJbDnBPacwJ4T2HOidzvndZUq3fmeQrEnWpPC8UTXi2rFcUXXi2q1UU1juzS2S/uio9CTw0IcNaG686V8uXd1E2pKldrz8/IdorXY1SbCSk8RD2B6aUwvjROVASwDWAaTymBSGUwqA24Gz4tuavqxKOz4sSiEVGsCNcknt3d6+VK50Jkr4+WJRSqs1tAUu/Ll9kJPq1deUKwPSl51Vb7Q1l5ubyy39+QxLg2bU5jfO24sVV/tLixEu2qyXq6np7igIz+nrOujSndDvfbUNosebC0u6IpGs6swD5u1djX2jWaX6inPx58D+X4s3lDsKbfX/mIx19FY6CrX3mUt5UKxa1h+XqUwv/rO6GrBcxK+bC9WSvnh1TdjR7Gt9rbpKpYbak+q5s6OcnffcHb9tpmPe7I+7sX6uIfq415ptVrUJlQ87mM93s/xAMsBluN4fpQxqhX7jzJGtWL7KGNUawI1iQpelDWqNY2aQe3lNKOGqNHbIp4APwF+AvwE+AnwE+AnwE+AnwA/AT5+2+L4bYvXftu6Z3cUW+bq6mtWqzJa6pgT1Z4ylsul9lxrXtZ/6ta59erNKXR0VC8dxeh3Gnd2fdyZrdZMQ7RFT/WV1uWeQq6t0h3VHiy3dkW1Y46q9WMd0TsgnsV5yTqv0DV/dqW6k3JtFG3TUOzOd2FlqbNQfavmWvLV99T8vgVeqnSpOfnO6rtK1H7IUnd1vqKlozJbtudzVXprIdfZe6FKJFLDOislvM/yWJdBzaJGL0kWL0kWL0kWL0kWL0kWL0kWL0kWL0kWL0kWL0kWL0kWL0kWvCx4WVwAs0lwkuAkwUmCkwQnCU4U/3x8tJxO9tUm1BRqGjWDmkVtRg1RXVSjdqZaY1Ftwv6asL8m7K8J+4viXjXNNKOGjdGt4ln1e+ojq7/H+WrvWq5ejWr3oE3tVveCQvVNVb/JXRup9nyt6Lm56IH6He3aqLH3rnZtwdTuO9e3K+fm1x+t7nlWd0elVCq0dQ2r3bXGTfiG+rg+HF1fVb9zjwdHDVhTX+HVJlSfakNtFN2Vr6/szHUX5nmz8+Vo82H1e/MY1ycfjU17Php483Pz8XD9nj3Wlns39KonJRqN6L2Djwf6RsPqx4611QPHqKuCnTVGd/OjheG4nY9p9A6G1e/n45nzithzQ+30Ydh/Crxy75RNdfLR9x6qB1z7YkPt5ajVqi9rpX5G6rOrv8y4E+FwJ8LhTkS1BqPqaWPAX2EOb1nYU708FFrqH8CNqv/l/ICHRw8Y99S+2J031ZelI18q7TmsqrbqJCJ9VIXXOx5eF13vUuOcYqWnf6H6Ruvbru69vqW6APuWej/JGFt9H8VG9H2EUVu0wzGDQv3BkfgDmdof0YxtyXUPWI4NWs4OWh43YDk56PlB33LvCZpVLHfmeuZ69RM1troWW9pBe7KDyMEQy00DlmM1+oDl7KBl27t94+xcT2EsDn5M/cFMLNogVtvpuCHWxQats0NsZwdtlxhif4kh9pcYYn+JQftLDTG/1BDzSw0xv9QQ80sNMb/UEPNLDTG/1P+fXzb+/+e32LrB29khthu8v8QQ+0sMsb/EEPsb6vw19b7Jhlg3eLvEENslBnEH7W+xdYO3SwyxXX1/tb/cqkbgQv1zTxN2tdV/GXsHfu8gMIvyPcXaSFcvF/VavVTUqle/TNRGpnaJiAaF6Fdclwp71bepXyLqo/rlob5RVyHa0chBH2ePHPTh9YjFP6YeOejz6Ib+mxsN/fczvL7bFw39NyuWGEQa29GyxCBYddXoxXmLb1TfT3XV8H5q31LvDhr72H0P9T7NRNtUWkz01ErL8P5911bXr9vVwbDeW2y1ldGzKy0jB/6PS2oPRJew6gPR/wFlVk9+Tr6n2n+OqjukbhrYqH9FnxYjCQ/vXax/rW9Mn4D6v983om/doMX6V/tGDYge9bV1wUOS0bf7qn1Yphljf8A4qI3F1FmZ8P8AjHyfawAAAAMACAACABEAAf//AAN42iXNuw2DUBBE0dn3JtiVnLg3LH8EbTikL+MCTCNAA+YTGMxIBFc62YUBOKknaiScAX5gbPlF5shRnjjJM2d54U9eucobN/nvL5g33iD72zu59x7JhyhgcYkrUtziLj+iRI4qKhioY1J2tAPvjxreeNpNkj1IXEEQx//73o637xn1OE9RESNWFhbBQiyukBQWkkJNCJikEDUkSgQR66tTW4aU1vYigoUYP8iX5sNovv0KBlRikLvq8n+bY5DHzvxmdnZn5s3CAIjRihzM44cj03Cw9KBUQkBlEIyOTk6heuzJ+CPU0xMkPr8DRsbIoAltJMOvtaxvoCLR5s9/O+igzHA5LuuOEEhl4rclxjxHI7pxE7dwF8OYwAzyeIpnmMM8lrGLAwbGJmtaTLvpNDnTa/rNbHJPdA+B/evpvtIDpSHShc/3UumV0mulN54CVnzN/SSfu7e6t6W0fSXqXcJugfI3QvZUjWx0h9ZxdJvyzL3XUx88JTFp1EcDCO2FPY8GfZaPGrWj9ElpV2lP6bPSF6WvSt88pZipgXNo5wy6kHPrzFlktes+d9GtURdor3m74L77Xl5QFt0qZcHf9aPcbcr+siccc0kEoaQ4tViqpAo1UiNppCUjtchInTQiyy6Tt5HlWzDo8K8jpBSehcRSK820Qntqz+wl40L6mwGXd3m0uCW3guvc74Ow/jae70JP+W9v+n+6QXnqa9snXXo6UDpUWizHXcn7Dy3Idx0AAHja7VsBaBbZEZ55721u4+WiiTHVNMSYSBCxkgaRIBLsESSENFgRCTaIFZsGa0MIIiIicgSRIBJEQhArVkRERMQeQbyc53mpl6bRU2s9L5d6aZrTv+p5wQtBrDWd93bjzv/vv8n+MbFeW8J8O//svJl58+bt7nu7AQSAaZADZYC1v9zYADYoksDICOgz+JtfNPyaZADT9S8QIOm8BUnwFkmTqeXbkALvQCpkwmJYCiWwEiphLWyCBtgN+6EFjsAJaIdeuAePYRheYBKmYibZQPobpONbgLLZ+S3bnKPa4xynrSQfCGpGw4yOtMy0WudX2un0+eknZi5wfs08MHMgY2nGXudXRvesyllXMsuc9pnnnOOczc4xO9No2TmX5xbObZo7kFuS25r7ZF6Fkb4zb++88/MiebPzyvK2553Mu5Nv5xfn1+a35nea8yL/zvwkx878hc6x4LZzXNjiHH900/QKf3zAPR6ifOljG6BoEXWEhylbFXAIjlJWTsM5OA8XoQO64Drcphz1Q4SyNATPqFESpmA6zsYcnI8LsRCX4nJ8F8uwEtfgOtyANbgFG3A77sJGbMJmbMHDeAxP4hl8Hy/gJbyC3XgT7+BdHMAHOIjD+FwIYYtUkSGyRK4oEItEkSgWJaJUlItVYq2o1iNutRBmGOw0CB6KXxm+N1aOzbGSkf5Y3tFBxTRzYlsF4UgHk2z34Sbrdy/5IAv9Y1ke2RDLx7ETkBPsjs2JK/F5d/OgJtJrv01XZ0PcmAUkqRErG8DeZe+CHPsD+wOYa39od0CufcX+GhYk/yx5jZ7xNNcGzTxPotGtsTYTn00zGSGP6hR1VcuIsYpkR2s/ZdpafoXmN0I3aadDASyCIiima0AplMMqugpUw0aohTrYCjvoarAH9ul2omoUcYVoJ/738idk42ORTVikJVAkd4yiq18Ay0n/Mmt7XuwmPCOuE74w8mPiIOEZ/HQUId1KslKsVCvNyrCyrB9a2ZSPD+2L9kf2Jftj+xO7g7LxqenXd16/dARqWF0DQRmk2YpFWIwlWIrluArXYjVuxFqsw624A3fjHtyHB7AVj+BxPIVnsQ3b8TJ24jW8hT3Yh/fwET7BpxShEtPEDJEpskWeWCAWiyVimVghVooKsVpUifVik9gs6sU2sVO8J/aK/eKgOCSOihPitDgnzouLokN0ievitugV/SIiHosh8UyCTJIpMl3OljlyvlwoC+VSuVy+K8tkpVwj18kNskZukQ1yu9wlG2WTbJYt8rA8Jk/KM/J9eUFekldkt7wp78i7ckA+kINyWD5XQtkqVWWoLJWrCtQiVaSKVYkqVeVqlVqrqtVGVavq1Fa1Q+1We9Q+dUC1qiPquDqlzqo21W5qY6XGpOM0NkOaxyHDdxu+W/Mi2+hkG77S8JWGZ22jeK4ToI99xn5frF9RZXSqfG3bDd/u81Vg+AKffr3h6w1favhSH899cXmh4QtNbJdNbJfH7GNQHsbmbZ88IM9h8hMVJ4+tyfBPQ/NOPAfH4qPqxOFrffHzOM3YYarnC4/77F/3dFybzYa/7fFRNo0dmWJ42+isYDZ3szGtCuBt31j3sdh4Tgp47RlNN04PnQp050shw8fML+Pd8WqO4cPfDdLUH1WX+pPqVtfUZ+rP6i/qtrqjvlL96u/qHl0T/2lfgDS6Tq4kqiBaTVRFtJ5oE9FmonqibUQ7id4j2ku0n+gg0SHycZSOJ7wanTSsY3WfavhDL6/ji/9/HZ/QdbxSP/O7WMiwxkP5Uw+5PAqrxzzrQzzOcIghkwe1pScQT1LKsIrhQQ/xvIdimYfykpG/iLUjnb5sMXyj0bnss1+TIPJWNkOW/6A8h8mPE6EbJ/d7PTHEWpa32thMusjqhPuVJewsz38qw0UeipMe4myGTh/XGOxmyPvO29ayaLmc5S1q7BhGjfUSps8zw/te4/UlKg8sTm4/qs79uCaGD38dz1Kd6qq6qb5QPepL1av+qu6qv6n7KqL+oR6oh+qR+kY9Vt+qJ2pIPVcvktcl/zy5GrJCXcHBvYIDrV+BVrAAeu5cJOog6iLSeblN1EvUT9FE6PiYSOfumZ6ivjmQEYBBOhBaP0hSFGhHmjUQ6t9ay+x80OpfDdO9T4CMGgGd+7l0NnWs+yZZFGRxubEJMRbHaxvf4zgxmsoAUxNoamLeVMcYx6OOsdyNcYOxOINwTgKVOVqXQVmfFs/Wa/A7fZx2kxpB3LH8z0cQlHsBS6KqKG3c6hl7bumeLHF7Uh7SYtC4OX5eMcaASp9AjHHz6sVYDltYjOkTHL/xayUo7zqCjZMSQfxaGcvva+t53NF8DT2PN/buDvHRN3yHeFCvsYJQbHN2DOLLo/SB8ft8bTsZDiaGuD4WuTywLYQ+C4nF4+xCOPsJXBLH/j5fBsL3ui/g7Cm9GnbRk4d/lpTquupTX9O8ANBPtnpWZOldErNXstrgb02vnPo98mbXr8oyETeaiJs8XkbYbkKPJ+FymcuwPr6Osx/D5VHYFutRVmt0o3LOLvFhxMs1j9+V86iYTcealeG14rwfA3PSxOSO5IjPL9cPysCYvY7y28iywdHzGL5+hbqlPid9/ZbTPAehs3O48/tTszJiVqBlBnPNquWp4Y8ZPt3bqXAkXK4qvNW305bruNZ6YuXqrLe/IQYMv4Oti7mdVoMpPowwv5HYmF0L3E6N5zEqQo4RHwblZJuXAS4JygbPAO+7m4Gq+NlzbLoxlDD9dg8djwYTqdkbaiCqZv8ACwg/od/OSq2EPZ/MfNli/GcehEwLLWEpy7Js621ruvUD+6J5F3bN/sy+Yd+0b9mf21/YX9n9FM1q8iYhB+bDQt0yjj9UDw3enwLLQ1Ns+eGUWX40ZZYfT5nlbydgWVdiXkAlOnYTt+hEOmpRr6mSzFO08wQ9FDV+YfV73FFJzP6jBO1/E1r/RoL6V92xD6t/3x3RsPoPE9S/mqD+jQT1exLU/zJB/SGmn0dXVkEzI9ttMYtZ7H35hQRaaSG1v3O1vz/Pwy2jX3nQk5XGViZpZGgkqjhW4kfXZuP4mvIWQ+ZRVTBJvQ+ZPMpXZHy0ej37nHfscAzMSZsncTXbQuQhoO/cF48kjh2H3+XLQyShL35Gd7JePls4X/K46NRs95tdswm/X+PvwhbFvmdMtNXUYfh43Hevqz1M2GN72Gy8et+j3mp57/jC1+xEdt/mkAftXb+9ayDaTrSLSD+hNxE1E7UQHSbST/P6reAZoveJLhDp979XiPRbu5tEd4juEunV0AOiQaJh6skyfY8JhbNDayaINCc1PvPQncdtb/o8dr6P8mGYLz6YprNLMglfkZROjp1x4mkP4F8BsXnys+HYHP0GzFi+5SHTDD+Px34noncX9bcXKxL+wmh0Ny4ITzO+i+0nBbeq+1+4F45z1R4KodPMvrzpfB33yMBIgr5xmWKcpF7/V9wLZb2+98h681QyyvsRzH96xNeJGOxiWB8KIdiv/u8NXMF21cya8F8Do38v6uOsETOc/+DQX8HTuq5zpNhZ5/0b9HXxHAAAAAABAAAAANWkJwgAAAAAyEN6pwAAAADYonM1` diff --git a/vendor/github.com/alecthomas/chroma/v2/formatters/svg/svg.go b/vendor/github.com/alecthomas/chroma/v2/formatters/svg/svg.go new file mode 100644 index 000000000..6d457f90a --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/formatters/svg/svg.go @@ -0,0 +1,222 @@ +// Package svg contains an SVG formatter. +package svg + +import ( + "encoding/base64" + "errors" + "fmt" + "io" + "os" + "path" + "strings" + + "github.com/alecthomas/chroma/v2" +) + +// Option sets an option of the SVG formatter. +type Option func(f *Formatter) + +// FontFamily sets the font-family. +func FontFamily(fontFamily string) Option { return func(f *Formatter) { f.fontFamily = fontFamily } } + +// EmbedFontFile embeds given font file +func EmbedFontFile(fontFamily string, fileName string) (option Option, err error) { + var format FontFormat + switch path.Ext(fileName) { + case ".woff": + format = WOFF + case ".woff2": + format = WOFF2 + case ".ttf": + format = TRUETYPE + default: + return nil, errors.New("unexpected font file suffix") + } + + var content []byte + if content, err = os.ReadFile(fileName); err == nil { + option = EmbedFont(fontFamily, base64.StdEncoding.EncodeToString(content), format) + } + return +} + +// EmbedFont embeds given base64 encoded font +func EmbedFont(fontFamily string, font string, format FontFormat) Option { + return func(f *Formatter) { f.fontFamily = fontFamily; f.embeddedFont = font; f.fontFormat = format } +} + +// New SVG formatter. +func New(options ...Option) *Formatter { + f := &Formatter{fontFamily: "Consolas, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace"} + for _, option := range options { + option(f) + } + return f +} + +// Formatter that generates SVG. +type Formatter struct { + fontFamily string + embeddedFont string + fontFormat FontFormat +} + +func (f *Formatter) Format(w io.Writer, style *chroma.Style, iterator chroma.Iterator) (err error) { + f.writeSVG(w, style, iterator.Tokens()) + return err +} + +var svgEscaper = strings.NewReplacer( + `&`, "&", + `<`, "<", + `>`, ">", + `"`, """, + ` `, " ", + ` `, "    ", +) + +// EscapeString escapes special characters. +func escapeString(s string) string { + return svgEscaper.Replace(s) +} + +func (f *Formatter) writeSVG(w io.Writer, style *chroma.Style, tokens []chroma.Token) { // nolint: gocyclo + svgStyles := f.styleToSVG(style) + lines := chroma.SplitTokensIntoLines(tokens) + + fmt.Fprint(w, "\n") + fmt.Fprint(w, "\n") + fmt.Fprintf(w, "\n", 8*maxLineWidth(lines), 10+int(16.8*float64(len(lines)+1))) + + if f.embeddedFont != "" { + f.writeFontStyle(w) + } + + fmt.Fprintf(w, "\n", style.Get(chroma.Background).Background.String()) + fmt.Fprintf(w, "\n", f.fontFamily, style.Get(chroma.Text).Colour.String()) + + f.writeTokenBackgrounds(w, lines, style) + + for index, tokens := range lines { + fmt.Fprintf(w, "", 1.2*float64(index+1)) + + for _, token := range tokens { + text := escapeString(token.String()) + attr := f.styleAttr(svgStyles, token.Type) + if attr != "" { + text = fmt.Sprintf("%s", attr, text) + } + fmt.Fprint(w, text) + } + fmt.Fprint(w, "") + } + + fmt.Fprint(w, "\n\n") + fmt.Fprint(w, "\n") +} + +func maxLineWidth(lines [][]chroma.Token) int { + maxWidth := 0 + for _, tokens := range lines { + length := 0 + for _, token := range tokens { + length += len(strings.ReplaceAll(token.String(), ` `, " ")) + } + if length > maxWidth { + maxWidth = length + } + } + return maxWidth +} + +// There is no background attribute for text in SVG so simply calculate the position and text +// of tokens with a background color that differs from the default and add a rectangle for each before +// adding the token. +func (f *Formatter) writeTokenBackgrounds(w io.Writer, lines [][]chroma.Token, style *chroma.Style) { + for index, tokens := range lines { + lineLength := 0 + for _, token := range tokens { + length := len(strings.ReplaceAll(token.String(), ` `, " ")) + tokenBackground := style.Get(token.Type).Background + if tokenBackground.IsSet() && tokenBackground != style.Get(chroma.Background).Background { + fmt.Fprintf(w, "\n", escapeString(token.String()), lineLength, 1.2*float64(index)+0.25, length, style.Get(token.Type).Background.String()) + } + lineLength += length + } + } +} + +type FontFormat int + +// https://transfonter.org/formats +const ( + WOFF FontFormat = iota + WOFF2 + TRUETYPE +) + +var fontFormats = [...]string{ + "woff", + "woff2", + "truetype", +} + +func (f *Formatter) writeFontStyle(w io.Writer) { + fmt.Fprintf(w, ``, f.fontFamily, fontFormats[f.fontFormat], f.embeddedFont, fontFormats[f.fontFormat]) +} + +func (f *Formatter) styleAttr(styles map[chroma.TokenType]string, tt chroma.TokenType) string { + if _, ok := styles[tt]; !ok { + tt = tt.SubCategory() + if _, ok := styles[tt]; !ok { + tt = tt.Category() + if _, ok := styles[tt]; !ok { + return "" + } + } + } + return styles[tt] +} + +func (f *Formatter) styleToSVG(style *chroma.Style) map[chroma.TokenType]string { + converted := map[chroma.TokenType]string{} + bg := style.Get(chroma.Background) + // Convert the style. + for t := range chroma.StandardTypes { + entry := style.Get(t) + if t != chroma.Background { + entry = entry.Sub(bg) + } + if entry.IsZero() { + continue + } + converted[t] = StyleEntryToSVG(entry) + } + return converted +} + +// StyleEntryToSVG converts a chroma.StyleEntry to SVG attributes. +func StyleEntryToSVG(e chroma.StyleEntry) string { + var styles []string + + if e.Colour.IsSet() { + styles = append(styles, "fill=\""+e.Colour.String()+"\"") + } + if e.Bold == chroma.Yes { + styles = append(styles, "font-weight=\"bold\"") + } + if e.Italic == chroma.Yes { + styles = append(styles, "font-style=\"italic\"") + } + if e.Underline == chroma.Yes { + styles = append(styles, "text-decoration=\"underline\"") + } + return strings.Join(styles, " ") +} diff --git a/vendor/github.com/alecthomas/chroma/v2/formatters/tokens.go b/vendor/github.com/alecthomas/chroma/v2/formatters/tokens.go new file mode 100644 index 000000000..3bdd57ccf --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/formatters/tokens.go @@ -0,0 +1,18 @@ +package formatters + +import ( + "fmt" + "io" + + "github.com/alecthomas/chroma/v2" +) + +// Tokens formatter outputs the raw token structures. +var Tokens = Register("tokens", chroma.FormatterFunc(func(w io.Writer, s *chroma.Style, it chroma.Iterator) error { + for t := it(); t != chroma.EOF; t = it() { + if _, err := fmt.Fprintln(w, t.GoString()); err != nil { + return err + } + } + return nil +})) diff --git a/vendor/github.com/alecthomas/chroma/v2/formatters/tty_indexed.go b/vendor/github.com/alecthomas/chroma/v2/formatters/tty_indexed.go new file mode 100644 index 000000000..d48fb993c --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/formatters/tty_indexed.go @@ -0,0 +1,284 @@ +package formatters + +import ( + "io" + "math" + + "github.com/alecthomas/chroma/v2" +) + +type ttyTable struct { + foreground map[chroma.Colour]string + background map[chroma.Colour]string +} + +var c = chroma.MustParseColour + +var ttyTables = map[int]*ttyTable{ + 8: { + foreground: map[chroma.Colour]string{ + c("#000000"): "\033[30m", c("#7f0000"): "\033[31m", c("#007f00"): "\033[32m", c("#7f7fe0"): "\033[33m", + c("#00007f"): "\033[34m", c("#7f007f"): "\033[35m", c("#007f7f"): "\033[36m", c("#e5e5e5"): "\033[37m", + c("#555555"): "\033[1m\033[30m", c("#ff0000"): "\033[1m\033[31m", c("#00ff00"): "\033[1m\033[32m", c("#ffff00"): "\033[1m\033[33m", + c("#0000ff"): "\033[1m\033[34m", c("#ff00ff"): "\033[1m\033[35m", c("#00ffff"): "\033[1m\033[36m", c("#ffffff"): "\033[1m\033[37m", + }, + background: map[chroma.Colour]string{ + c("#000000"): "\033[40m", c("#7f0000"): "\033[41m", c("#007f00"): "\033[42m", c("#7f7fe0"): "\033[43m", + c("#00007f"): "\033[44m", c("#7f007f"): "\033[45m", c("#007f7f"): "\033[46m", c("#e5e5e5"): "\033[47m", + c("#555555"): "\033[1m\033[40m", c("#ff0000"): "\033[1m\033[41m", c("#00ff00"): "\033[1m\033[42m", c("#ffff00"): "\033[1m\033[43m", + c("#0000ff"): "\033[1m\033[44m", c("#ff00ff"): "\033[1m\033[45m", c("#00ffff"): "\033[1m\033[46m", c("#ffffff"): "\033[1m\033[47m", + }, + }, + 16: { + foreground: map[chroma.Colour]string{ + c("#000000"): "\033[30m", c("#7f0000"): "\033[31m", c("#007f00"): "\033[32m", c("#7f7fe0"): "\033[33m", + c("#00007f"): "\033[34m", c("#7f007f"): "\033[35m", c("#007f7f"): "\033[36m", c("#e5e5e5"): "\033[37m", + c("#555555"): "\033[90m", c("#ff0000"): "\033[91m", c("#00ff00"): "\033[92m", c("#ffff00"): "\033[93m", + c("#0000ff"): "\033[94m", c("#ff00ff"): "\033[95m", c("#00ffff"): "\033[96m", c("#ffffff"): "\033[97m", + }, + background: map[chroma.Colour]string{ + c("#000000"): "\033[40m", c("#7f0000"): "\033[41m", c("#007f00"): "\033[42m", c("#7f7fe0"): "\033[43m", + c("#00007f"): "\033[44m", c("#7f007f"): "\033[45m", c("#007f7f"): "\033[46m", c("#e5e5e5"): "\033[47m", + c("#555555"): "\033[100m", c("#ff0000"): "\033[101m", c("#00ff00"): "\033[102m", c("#ffff00"): "\033[103m", + c("#0000ff"): "\033[104m", c("#ff00ff"): "\033[105m", c("#00ffff"): "\033[106m", c("#ffffff"): "\033[107m", + }, + }, + 256: { + foreground: map[chroma.Colour]string{ + c("#000000"): "\033[38;5;0m", c("#800000"): "\033[38;5;1m", c("#008000"): "\033[38;5;2m", c("#808000"): "\033[38;5;3m", + c("#000080"): "\033[38;5;4m", c("#800080"): "\033[38;5;5m", c("#008080"): "\033[38;5;6m", c("#c0c0c0"): "\033[38;5;7m", + c("#808080"): "\033[38;5;8m", c("#ff0000"): "\033[38;5;9m", c("#00ff00"): "\033[38;5;10m", c("#ffff00"): "\033[38;5;11m", + c("#0000ff"): "\033[38;5;12m", c("#ff00ff"): "\033[38;5;13m", c("#00ffff"): "\033[38;5;14m", c("#ffffff"): "\033[38;5;15m", + c("#000000"): "\033[38;5;16m", c("#00005f"): "\033[38;5;17m", c("#000087"): "\033[38;5;18m", c("#0000af"): "\033[38;5;19m", + c("#0000d7"): "\033[38;5;20m", c("#0000ff"): "\033[38;5;21m", c("#005f00"): "\033[38;5;22m", c("#005f5f"): "\033[38;5;23m", + c("#005f87"): "\033[38;5;24m", c("#005faf"): "\033[38;5;25m", c("#005fd7"): "\033[38;5;26m", c("#005fff"): "\033[38;5;27m", + c("#008700"): "\033[38;5;28m", c("#00875f"): "\033[38;5;29m", c("#008787"): "\033[38;5;30m", c("#0087af"): "\033[38;5;31m", + c("#0087d7"): "\033[38;5;32m", c("#0087ff"): "\033[38;5;33m", c("#00af00"): "\033[38;5;34m", c("#00af5f"): "\033[38;5;35m", + c("#00af87"): "\033[38;5;36m", c("#00afaf"): "\033[38;5;37m", c("#00afd7"): "\033[38;5;38m", c("#00afff"): "\033[38;5;39m", + c("#00d700"): "\033[38;5;40m", c("#00d75f"): "\033[38;5;41m", c("#00d787"): "\033[38;5;42m", c("#00d7af"): "\033[38;5;43m", + c("#00d7d7"): "\033[38;5;44m", c("#00d7ff"): "\033[38;5;45m", c("#00ff00"): "\033[38;5;46m", c("#00ff5f"): "\033[38;5;47m", + c("#00ff87"): "\033[38;5;48m", c("#00ffaf"): "\033[38;5;49m", c("#00ffd7"): "\033[38;5;50m", c("#00ffff"): "\033[38;5;51m", + c("#5f0000"): "\033[38;5;52m", c("#5f005f"): "\033[38;5;53m", c("#5f0087"): "\033[38;5;54m", c("#5f00af"): "\033[38;5;55m", + c("#5f00d7"): "\033[38;5;56m", c("#5f00ff"): "\033[38;5;57m", c("#5f5f00"): "\033[38;5;58m", c("#5f5f5f"): "\033[38;5;59m", + c("#5f5f87"): "\033[38;5;60m", c("#5f5faf"): "\033[38;5;61m", c("#5f5fd7"): "\033[38;5;62m", c("#5f5fff"): "\033[38;5;63m", + c("#5f8700"): "\033[38;5;64m", c("#5f875f"): "\033[38;5;65m", c("#5f8787"): "\033[38;5;66m", c("#5f87af"): "\033[38;5;67m", + c("#5f87d7"): "\033[38;5;68m", c("#5f87ff"): "\033[38;5;69m", c("#5faf00"): "\033[38;5;70m", c("#5faf5f"): "\033[38;5;71m", + c("#5faf87"): "\033[38;5;72m", c("#5fafaf"): "\033[38;5;73m", c("#5fafd7"): "\033[38;5;74m", c("#5fafff"): "\033[38;5;75m", + c("#5fd700"): "\033[38;5;76m", c("#5fd75f"): "\033[38;5;77m", c("#5fd787"): "\033[38;5;78m", c("#5fd7af"): "\033[38;5;79m", + c("#5fd7d7"): "\033[38;5;80m", c("#5fd7ff"): "\033[38;5;81m", c("#5fff00"): "\033[38;5;82m", c("#5fff5f"): "\033[38;5;83m", + c("#5fff87"): "\033[38;5;84m", c("#5fffaf"): "\033[38;5;85m", c("#5fffd7"): "\033[38;5;86m", c("#5fffff"): "\033[38;5;87m", + c("#870000"): "\033[38;5;88m", c("#87005f"): "\033[38;5;89m", c("#870087"): "\033[38;5;90m", c("#8700af"): "\033[38;5;91m", + c("#8700d7"): "\033[38;5;92m", c("#8700ff"): "\033[38;5;93m", c("#875f00"): "\033[38;5;94m", c("#875f5f"): "\033[38;5;95m", + c("#875f87"): "\033[38;5;96m", c("#875faf"): "\033[38;5;97m", c("#875fd7"): "\033[38;5;98m", c("#875fff"): "\033[38;5;99m", + c("#878700"): "\033[38;5;100m", c("#87875f"): "\033[38;5;101m", c("#878787"): "\033[38;5;102m", c("#8787af"): "\033[38;5;103m", + c("#8787d7"): "\033[38;5;104m", c("#8787ff"): "\033[38;5;105m", c("#87af00"): "\033[38;5;106m", c("#87af5f"): "\033[38;5;107m", + c("#87af87"): "\033[38;5;108m", c("#87afaf"): "\033[38;5;109m", c("#87afd7"): "\033[38;5;110m", c("#87afff"): "\033[38;5;111m", + c("#87d700"): "\033[38;5;112m", c("#87d75f"): "\033[38;5;113m", c("#87d787"): "\033[38;5;114m", c("#87d7af"): "\033[38;5;115m", + c("#87d7d7"): "\033[38;5;116m", c("#87d7ff"): "\033[38;5;117m", c("#87ff00"): "\033[38;5;118m", c("#87ff5f"): "\033[38;5;119m", + c("#87ff87"): "\033[38;5;120m", c("#87ffaf"): "\033[38;5;121m", c("#87ffd7"): "\033[38;5;122m", c("#87ffff"): "\033[38;5;123m", + c("#af0000"): "\033[38;5;124m", c("#af005f"): "\033[38;5;125m", c("#af0087"): "\033[38;5;126m", c("#af00af"): "\033[38;5;127m", + c("#af00d7"): "\033[38;5;128m", c("#af00ff"): "\033[38;5;129m", c("#af5f00"): "\033[38;5;130m", c("#af5f5f"): "\033[38;5;131m", + c("#af5f87"): "\033[38;5;132m", c("#af5faf"): "\033[38;5;133m", c("#af5fd7"): "\033[38;5;134m", c("#af5fff"): "\033[38;5;135m", + c("#af8700"): "\033[38;5;136m", c("#af875f"): "\033[38;5;137m", c("#af8787"): "\033[38;5;138m", c("#af87af"): "\033[38;5;139m", + c("#af87d7"): "\033[38;5;140m", c("#af87ff"): "\033[38;5;141m", c("#afaf00"): "\033[38;5;142m", c("#afaf5f"): "\033[38;5;143m", + c("#afaf87"): "\033[38;5;144m", c("#afafaf"): "\033[38;5;145m", c("#afafd7"): "\033[38;5;146m", c("#afafff"): "\033[38;5;147m", + c("#afd700"): "\033[38;5;148m", c("#afd75f"): "\033[38;5;149m", c("#afd787"): "\033[38;5;150m", c("#afd7af"): "\033[38;5;151m", + c("#afd7d7"): "\033[38;5;152m", c("#afd7ff"): "\033[38;5;153m", c("#afff00"): "\033[38;5;154m", c("#afff5f"): "\033[38;5;155m", + c("#afff87"): "\033[38;5;156m", c("#afffaf"): "\033[38;5;157m", c("#afffd7"): "\033[38;5;158m", c("#afffff"): "\033[38;5;159m", + c("#d70000"): "\033[38;5;160m", c("#d7005f"): "\033[38;5;161m", c("#d70087"): "\033[38;5;162m", c("#d700af"): "\033[38;5;163m", + c("#d700d7"): "\033[38;5;164m", c("#d700ff"): "\033[38;5;165m", c("#d75f00"): "\033[38;5;166m", c("#d75f5f"): "\033[38;5;167m", + c("#d75f87"): "\033[38;5;168m", c("#d75faf"): "\033[38;5;169m", c("#d75fd7"): "\033[38;5;170m", c("#d75fff"): "\033[38;5;171m", + c("#d78700"): "\033[38;5;172m", c("#d7875f"): "\033[38;5;173m", c("#d78787"): "\033[38;5;174m", c("#d787af"): "\033[38;5;175m", + c("#d787d7"): "\033[38;5;176m", c("#d787ff"): "\033[38;5;177m", c("#d7af00"): "\033[38;5;178m", c("#d7af5f"): "\033[38;5;179m", + c("#d7af87"): "\033[38;5;180m", c("#d7afaf"): "\033[38;5;181m", c("#d7afd7"): "\033[38;5;182m", c("#d7afff"): "\033[38;5;183m", + c("#d7d700"): "\033[38;5;184m", c("#d7d75f"): "\033[38;5;185m", c("#d7d787"): "\033[38;5;186m", c("#d7d7af"): "\033[38;5;187m", + c("#d7d7d7"): "\033[38;5;188m", c("#d7d7ff"): "\033[38;5;189m", c("#d7ff00"): "\033[38;5;190m", c("#d7ff5f"): "\033[38;5;191m", + c("#d7ff87"): "\033[38;5;192m", c("#d7ffaf"): "\033[38;5;193m", c("#d7ffd7"): "\033[38;5;194m", c("#d7ffff"): "\033[38;5;195m", + c("#ff0000"): "\033[38;5;196m", c("#ff005f"): "\033[38;5;197m", c("#ff0087"): "\033[38;5;198m", c("#ff00af"): "\033[38;5;199m", + c("#ff00d7"): "\033[38;5;200m", c("#ff00ff"): "\033[38;5;201m", c("#ff5f00"): "\033[38;5;202m", c("#ff5f5f"): "\033[38;5;203m", + c("#ff5f87"): "\033[38;5;204m", c("#ff5faf"): "\033[38;5;205m", c("#ff5fd7"): "\033[38;5;206m", c("#ff5fff"): "\033[38;5;207m", + c("#ff8700"): "\033[38;5;208m", c("#ff875f"): "\033[38;5;209m", c("#ff8787"): "\033[38;5;210m", c("#ff87af"): "\033[38;5;211m", + c("#ff87d7"): "\033[38;5;212m", c("#ff87ff"): "\033[38;5;213m", c("#ffaf00"): "\033[38;5;214m", c("#ffaf5f"): "\033[38;5;215m", + c("#ffaf87"): "\033[38;5;216m", c("#ffafaf"): "\033[38;5;217m", c("#ffafd7"): "\033[38;5;218m", c("#ffafff"): "\033[38;5;219m", + c("#ffd700"): "\033[38;5;220m", c("#ffd75f"): "\033[38;5;221m", c("#ffd787"): "\033[38;5;222m", c("#ffd7af"): "\033[38;5;223m", + c("#ffd7d7"): "\033[38;5;224m", c("#ffd7ff"): "\033[38;5;225m", c("#ffff00"): "\033[38;5;226m", c("#ffff5f"): "\033[38;5;227m", + c("#ffff87"): "\033[38;5;228m", c("#ffffaf"): "\033[38;5;229m", c("#ffffd7"): "\033[38;5;230m", c("#ffffff"): "\033[38;5;231m", + c("#080808"): "\033[38;5;232m", c("#121212"): "\033[38;5;233m", c("#1c1c1c"): "\033[38;5;234m", c("#262626"): "\033[38;5;235m", + c("#303030"): "\033[38;5;236m", c("#3a3a3a"): "\033[38;5;237m", c("#444444"): "\033[38;5;238m", c("#4e4e4e"): "\033[38;5;239m", + c("#585858"): "\033[38;5;240m", c("#626262"): "\033[38;5;241m", c("#6c6c6c"): "\033[38;5;242m", c("#767676"): "\033[38;5;243m", + c("#808080"): "\033[38;5;244m", c("#8a8a8a"): "\033[38;5;245m", c("#949494"): "\033[38;5;246m", c("#9e9e9e"): "\033[38;5;247m", + c("#a8a8a8"): "\033[38;5;248m", c("#b2b2b2"): "\033[38;5;249m", c("#bcbcbc"): "\033[38;5;250m", c("#c6c6c6"): "\033[38;5;251m", + c("#d0d0d0"): "\033[38;5;252m", c("#dadada"): "\033[38;5;253m", c("#e4e4e4"): "\033[38;5;254m", c("#eeeeee"): "\033[38;5;255m", + }, + background: map[chroma.Colour]string{ + c("#000000"): "\033[48;5;0m", c("#800000"): "\033[48;5;1m", c("#008000"): "\033[48;5;2m", c("#808000"): "\033[48;5;3m", + c("#000080"): "\033[48;5;4m", c("#800080"): "\033[48;5;5m", c("#008080"): "\033[48;5;6m", c("#c0c0c0"): "\033[48;5;7m", + c("#808080"): "\033[48;5;8m", c("#ff0000"): "\033[48;5;9m", c("#00ff00"): "\033[48;5;10m", c("#ffff00"): "\033[48;5;11m", + c("#0000ff"): "\033[48;5;12m", c("#ff00ff"): "\033[48;5;13m", c("#00ffff"): "\033[48;5;14m", c("#ffffff"): "\033[48;5;15m", + c("#000000"): "\033[48;5;16m", c("#00005f"): "\033[48;5;17m", c("#000087"): "\033[48;5;18m", c("#0000af"): "\033[48;5;19m", + c("#0000d7"): "\033[48;5;20m", c("#0000ff"): "\033[48;5;21m", c("#005f00"): "\033[48;5;22m", c("#005f5f"): "\033[48;5;23m", + c("#005f87"): "\033[48;5;24m", c("#005faf"): "\033[48;5;25m", c("#005fd7"): "\033[48;5;26m", c("#005fff"): "\033[48;5;27m", + c("#008700"): "\033[48;5;28m", c("#00875f"): "\033[48;5;29m", c("#008787"): "\033[48;5;30m", c("#0087af"): "\033[48;5;31m", + c("#0087d7"): "\033[48;5;32m", c("#0087ff"): "\033[48;5;33m", c("#00af00"): "\033[48;5;34m", c("#00af5f"): "\033[48;5;35m", + c("#00af87"): "\033[48;5;36m", c("#00afaf"): "\033[48;5;37m", c("#00afd7"): "\033[48;5;38m", c("#00afff"): "\033[48;5;39m", + c("#00d700"): "\033[48;5;40m", c("#00d75f"): "\033[48;5;41m", c("#00d787"): "\033[48;5;42m", c("#00d7af"): "\033[48;5;43m", + c("#00d7d7"): "\033[48;5;44m", c("#00d7ff"): "\033[48;5;45m", c("#00ff00"): "\033[48;5;46m", c("#00ff5f"): "\033[48;5;47m", + c("#00ff87"): "\033[48;5;48m", c("#00ffaf"): "\033[48;5;49m", c("#00ffd7"): "\033[48;5;50m", c("#00ffff"): "\033[48;5;51m", + c("#5f0000"): "\033[48;5;52m", c("#5f005f"): "\033[48;5;53m", c("#5f0087"): "\033[48;5;54m", c("#5f00af"): "\033[48;5;55m", + c("#5f00d7"): "\033[48;5;56m", c("#5f00ff"): "\033[48;5;57m", c("#5f5f00"): "\033[48;5;58m", c("#5f5f5f"): "\033[48;5;59m", + c("#5f5f87"): "\033[48;5;60m", c("#5f5faf"): "\033[48;5;61m", c("#5f5fd7"): "\033[48;5;62m", c("#5f5fff"): "\033[48;5;63m", + c("#5f8700"): "\033[48;5;64m", c("#5f875f"): "\033[48;5;65m", c("#5f8787"): "\033[48;5;66m", c("#5f87af"): "\033[48;5;67m", + c("#5f87d7"): "\033[48;5;68m", c("#5f87ff"): "\033[48;5;69m", c("#5faf00"): "\033[48;5;70m", c("#5faf5f"): "\033[48;5;71m", + c("#5faf87"): "\033[48;5;72m", c("#5fafaf"): "\033[48;5;73m", c("#5fafd7"): "\033[48;5;74m", c("#5fafff"): "\033[48;5;75m", + c("#5fd700"): "\033[48;5;76m", c("#5fd75f"): "\033[48;5;77m", c("#5fd787"): "\033[48;5;78m", c("#5fd7af"): "\033[48;5;79m", + c("#5fd7d7"): "\033[48;5;80m", c("#5fd7ff"): "\033[48;5;81m", c("#5fff00"): "\033[48;5;82m", c("#5fff5f"): "\033[48;5;83m", + c("#5fff87"): "\033[48;5;84m", c("#5fffaf"): "\033[48;5;85m", c("#5fffd7"): "\033[48;5;86m", c("#5fffff"): "\033[48;5;87m", + c("#870000"): "\033[48;5;88m", c("#87005f"): "\033[48;5;89m", c("#870087"): "\033[48;5;90m", c("#8700af"): "\033[48;5;91m", + c("#8700d7"): "\033[48;5;92m", c("#8700ff"): "\033[48;5;93m", c("#875f00"): "\033[48;5;94m", c("#875f5f"): "\033[48;5;95m", + c("#875f87"): "\033[48;5;96m", c("#875faf"): "\033[48;5;97m", c("#875fd7"): "\033[48;5;98m", c("#875fff"): "\033[48;5;99m", + c("#878700"): "\033[48;5;100m", c("#87875f"): "\033[48;5;101m", c("#878787"): "\033[48;5;102m", c("#8787af"): "\033[48;5;103m", + c("#8787d7"): "\033[48;5;104m", c("#8787ff"): "\033[48;5;105m", c("#87af00"): "\033[48;5;106m", c("#87af5f"): "\033[48;5;107m", + c("#87af87"): "\033[48;5;108m", c("#87afaf"): "\033[48;5;109m", c("#87afd7"): "\033[48;5;110m", c("#87afff"): "\033[48;5;111m", + c("#87d700"): "\033[48;5;112m", c("#87d75f"): "\033[48;5;113m", c("#87d787"): "\033[48;5;114m", c("#87d7af"): "\033[48;5;115m", + c("#87d7d7"): "\033[48;5;116m", c("#87d7ff"): "\033[48;5;117m", c("#87ff00"): "\033[48;5;118m", c("#87ff5f"): "\033[48;5;119m", + c("#87ff87"): "\033[48;5;120m", c("#87ffaf"): "\033[48;5;121m", c("#87ffd7"): "\033[48;5;122m", c("#87ffff"): "\033[48;5;123m", + c("#af0000"): "\033[48;5;124m", c("#af005f"): "\033[48;5;125m", c("#af0087"): "\033[48;5;126m", c("#af00af"): "\033[48;5;127m", + c("#af00d7"): "\033[48;5;128m", c("#af00ff"): "\033[48;5;129m", c("#af5f00"): "\033[48;5;130m", c("#af5f5f"): "\033[48;5;131m", + c("#af5f87"): "\033[48;5;132m", c("#af5faf"): "\033[48;5;133m", c("#af5fd7"): "\033[48;5;134m", c("#af5fff"): "\033[48;5;135m", + c("#af8700"): "\033[48;5;136m", c("#af875f"): "\033[48;5;137m", c("#af8787"): "\033[48;5;138m", c("#af87af"): "\033[48;5;139m", + c("#af87d7"): "\033[48;5;140m", c("#af87ff"): "\033[48;5;141m", c("#afaf00"): "\033[48;5;142m", c("#afaf5f"): "\033[48;5;143m", + c("#afaf87"): "\033[48;5;144m", c("#afafaf"): "\033[48;5;145m", c("#afafd7"): "\033[48;5;146m", c("#afafff"): "\033[48;5;147m", + c("#afd700"): "\033[48;5;148m", c("#afd75f"): "\033[48;5;149m", c("#afd787"): "\033[48;5;150m", c("#afd7af"): "\033[48;5;151m", + c("#afd7d7"): "\033[48;5;152m", c("#afd7ff"): "\033[48;5;153m", c("#afff00"): "\033[48;5;154m", c("#afff5f"): "\033[48;5;155m", + c("#afff87"): "\033[48;5;156m", c("#afffaf"): "\033[48;5;157m", c("#afffd7"): "\033[48;5;158m", c("#afffff"): "\033[48;5;159m", + c("#d70000"): "\033[48;5;160m", c("#d7005f"): "\033[48;5;161m", c("#d70087"): "\033[48;5;162m", c("#d700af"): "\033[48;5;163m", + c("#d700d7"): "\033[48;5;164m", c("#d700ff"): "\033[48;5;165m", c("#d75f00"): "\033[48;5;166m", c("#d75f5f"): "\033[48;5;167m", + c("#d75f87"): "\033[48;5;168m", c("#d75faf"): "\033[48;5;169m", c("#d75fd7"): "\033[48;5;170m", c("#d75fff"): "\033[48;5;171m", + c("#d78700"): "\033[48;5;172m", c("#d7875f"): "\033[48;5;173m", c("#d78787"): "\033[48;5;174m", c("#d787af"): "\033[48;5;175m", + c("#d787d7"): "\033[48;5;176m", c("#d787ff"): "\033[48;5;177m", c("#d7af00"): "\033[48;5;178m", c("#d7af5f"): "\033[48;5;179m", + c("#d7af87"): "\033[48;5;180m", c("#d7afaf"): "\033[48;5;181m", c("#d7afd7"): "\033[48;5;182m", c("#d7afff"): "\033[48;5;183m", + c("#d7d700"): "\033[48;5;184m", c("#d7d75f"): "\033[48;5;185m", c("#d7d787"): "\033[48;5;186m", c("#d7d7af"): "\033[48;5;187m", + c("#d7d7d7"): "\033[48;5;188m", c("#d7d7ff"): "\033[48;5;189m", c("#d7ff00"): "\033[48;5;190m", c("#d7ff5f"): "\033[48;5;191m", + c("#d7ff87"): "\033[48;5;192m", c("#d7ffaf"): "\033[48;5;193m", c("#d7ffd7"): "\033[48;5;194m", c("#d7ffff"): "\033[48;5;195m", + c("#ff0000"): "\033[48;5;196m", c("#ff005f"): "\033[48;5;197m", c("#ff0087"): "\033[48;5;198m", c("#ff00af"): "\033[48;5;199m", + c("#ff00d7"): "\033[48;5;200m", c("#ff00ff"): "\033[48;5;201m", c("#ff5f00"): "\033[48;5;202m", c("#ff5f5f"): "\033[48;5;203m", + c("#ff5f87"): "\033[48;5;204m", c("#ff5faf"): "\033[48;5;205m", c("#ff5fd7"): "\033[48;5;206m", c("#ff5fff"): "\033[48;5;207m", + c("#ff8700"): "\033[48;5;208m", c("#ff875f"): "\033[48;5;209m", c("#ff8787"): "\033[48;5;210m", c("#ff87af"): "\033[48;5;211m", + c("#ff87d7"): "\033[48;5;212m", c("#ff87ff"): "\033[48;5;213m", c("#ffaf00"): "\033[48;5;214m", c("#ffaf5f"): "\033[48;5;215m", + c("#ffaf87"): "\033[48;5;216m", c("#ffafaf"): "\033[48;5;217m", c("#ffafd7"): "\033[48;5;218m", c("#ffafff"): "\033[48;5;219m", + c("#ffd700"): "\033[48;5;220m", c("#ffd75f"): "\033[48;5;221m", c("#ffd787"): "\033[48;5;222m", c("#ffd7af"): "\033[48;5;223m", + c("#ffd7d7"): "\033[48;5;224m", c("#ffd7ff"): "\033[48;5;225m", c("#ffff00"): "\033[48;5;226m", c("#ffff5f"): "\033[48;5;227m", + c("#ffff87"): "\033[48;5;228m", c("#ffffaf"): "\033[48;5;229m", c("#ffffd7"): "\033[48;5;230m", c("#ffffff"): "\033[48;5;231m", + c("#080808"): "\033[48;5;232m", c("#121212"): "\033[48;5;233m", c("#1c1c1c"): "\033[48;5;234m", c("#262626"): "\033[48;5;235m", + c("#303030"): "\033[48;5;236m", c("#3a3a3a"): "\033[48;5;237m", c("#444444"): "\033[48;5;238m", c("#4e4e4e"): "\033[48;5;239m", + c("#585858"): "\033[48;5;240m", c("#626262"): "\033[48;5;241m", c("#6c6c6c"): "\033[48;5;242m", c("#767676"): "\033[48;5;243m", + c("#808080"): "\033[48;5;244m", c("#8a8a8a"): "\033[48;5;245m", c("#949494"): "\033[48;5;246m", c("#9e9e9e"): "\033[48;5;247m", + c("#a8a8a8"): "\033[48;5;248m", c("#b2b2b2"): "\033[48;5;249m", c("#bcbcbc"): "\033[48;5;250m", c("#c6c6c6"): "\033[48;5;251m", + c("#d0d0d0"): "\033[48;5;252m", c("#dadada"): "\033[48;5;253m", c("#e4e4e4"): "\033[48;5;254m", c("#eeeeee"): "\033[48;5;255m", + }, + }, +} + +func entryToEscapeSequence(table *ttyTable, entry chroma.StyleEntry) string { + out := "" + if entry.Bold == chroma.Yes { + out += "\033[1m" + } + if entry.Underline == chroma.Yes { + out += "\033[4m" + } + if entry.Italic == chroma.Yes { + out += "\033[3m" + } + if entry.Colour.IsSet() { + out += table.foreground[findClosest(table, entry.Colour)] + } + if entry.Background.IsSet() { + out += table.background[findClosest(table, entry.Background)] + } + return out +} + +func findClosest(table *ttyTable, seeking chroma.Colour) chroma.Colour { + closestColour := chroma.Colour(0) + closest := float64(math.MaxFloat64) + for colour := range table.foreground { + distance := colour.Distance(seeking) + if distance < closest { + closest = distance + closestColour = colour + } + } + return closestColour +} + +func styleToEscapeSequence(table *ttyTable, style *chroma.Style) map[chroma.TokenType]string { + style = clearBackground(style) + out := map[chroma.TokenType]string{} + for _, ttype := range style.Types() { + entry := style.Get(ttype) + out[ttype] = entryToEscapeSequence(table, entry) + } + return out +} + +// Clear the background colour. +func clearBackground(style *chroma.Style) *chroma.Style { + builder := style.Builder() + bg := builder.Get(chroma.Background) + bg.Background = 0 + bg.NoInherit = true + builder.AddEntry(chroma.Background, bg) + style, _ = builder.Build() + return style +} + +type indexedTTYFormatter struct { + table *ttyTable +} + +func (c *indexedTTYFormatter) Format(w io.Writer, style *chroma.Style, it chroma.Iterator) (err error) { + theme := styleToEscapeSequence(c.table, style) + for token := it(); token != chroma.EOF; token = it() { + clr, ok := theme[token.Type] + + // This search mimics how styles.Get() is used in tty_truecolour.go. + if !ok { + clr, ok = theme[token.Type.SubCategory()] + if !ok { + clr, ok = theme[token.Type.Category()] + if !ok { + clr, ok = theme[chroma.Text] + if !ok { + clr = theme[chroma.Background] + } + } + } + } + + writeToken(w, clr, token.Value) + } + return nil +} + +// TTY is an 8-colour terminal formatter. +// +// The Lab colour space is used to map RGB values to the most appropriate index colour. +var TTY = Register("terminal", &indexedTTYFormatter{ttyTables[8]}) + +// TTY8 is an 8-colour terminal formatter. +// +// The Lab colour space is used to map RGB values to the most appropriate index colour. +var TTY8 = Register("terminal8", &indexedTTYFormatter{ttyTables[8]}) + +// TTY16 is a 16-colour terminal formatter. +// +// It uses \033[3xm for normal colours and \033[90Xm for bright colours. +// +// The Lab colour space is used to map RGB values to the most appropriate index colour. +var TTY16 = Register("terminal16", &indexedTTYFormatter{ttyTables[16]}) + +// TTY256 is a 256-colour terminal formatter. +// +// The Lab colour space is used to map RGB values to the most appropriate index colour. +var TTY256 = Register("terminal256", &indexedTTYFormatter{ttyTables[256]}) diff --git a/vendor/github.com/alecthomas/chroma/v2/formatters/tty_truecolour.go b/vendor/github.com/alecthomas/chroma/v2/formatters/tty_truecolour.go new file mode 100644 index 000000000..43b096476 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/formatters/tty_truecolour.go @@ -0,0 +1,76 @@ +package formatters + +import ( + "fmt" + "io" + "regexp" + + "github.com/alecthomas/chroma/v2" +) + +// TTY16m is a true-colour terminal formatter. +var TTY16m = Register("terminal16m", chroma.FormatterFunc(trueColourFormatter)) + +var crOrCrLf = regexp.MustCompile(`\r?\n`) + +// Print the text with the given formatting, resetting the formatting at the end +// of each line and resuming it on the next line. +// +// This way, a pager (like https://github.com/walles/moar for example) can show +// any line in the output by itself, and it will get the right formatting. +func writeToken(w io.Writer, formatting string, text string) { + if formatting == "" { + fmt.Fprint(w, text) + return + } + + newlineIndices := crOrCrLf.FindAllStringIndex(text, -1) + + afterLastNewline := 0 + for _, indices := range newlineIndices { + newlineStart, afterNewline := indices[0], indices[1] + fmt.Fprint(w, formatting) + fmt.Fprint(w, text[afterLastNewline:newlineStart]) + fmt.Fprint(w, "\033[0m") + fmt.Fprint(w, text[newlineStart:afterNewline]) + afterLastNewline = afterNewline + } + + if afterLastNewline < len(text) { + // Print whatever is left after the last newline + fmt.Fprint(w, formatting) + fmt.Fprint(w, text[afterLastNewline:]) + fmt.Fprint(w, "\033[0m") + } +} + +func trueColourFormatter(w io.Writer, style *chroma.Style, it chroma.Iterator) error { + style = clearBackground(style) + for token := it(); token != chroma.EOF; token = it() { + entry := style.Get(token.Type) + if entry.IsZero() { + fmt.Fprint(w, token.Value) + continue + } + + formatting := "" + if entry.Bold == chroma.Yes { + formatting += "\033[1m" + } + if entry.Underline == chroma.Yes { + formatting += "\033[4m" + } + if entry.Italic == chroma.Yes { + formatting += "\033[3m" + } + if entry.Colour.IsSet() { + formatting += fmt.Sprintf("\033[38;2;%d;%d;%dm", entry.Colour.Red(), entry.Colour.Green(), entry.Colour.Blue()) + } + if entry.Background.IsSet() { + formatting += fmt.Sprintf("\033[48;2;%d;%d;%dm", entry.Background.Red(), entry.Background.Green(), entry.Background.Blue()) + } + + writeToken(w, formatting, token.Value) + } + return nil +} diff --git a/vendor/github.com/alecthomas/chroma/v2/iterator.go b/vendor/github.com/alecthomas/chroma/v2/iterator.go new file mode 100644 index 000000000..cf39bb577 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/iterator.go @@ -0,0 +1,93 @@ +package chroma + +import "strings" + +// An Iterator across tokens. +// +// EOF will be returned at the end of the Token stream. +// +// If an error occurs within an Iterator, it may propagate this in a panic. Formatters should recover. +type Iterator func() Token + +// Tokens consumes all tokens from the iterator and returns them as a slice. +func (i Iterator) Tokens() []Token { + var out []Token + for t := i(); t != EOF; t = i() { + out = append(out, t) + } + return out +} + +// Stdlib converts a Chroma iterator to a Go 1.23-compatible iterator. +func (i Iterator) Stdlib() func(yield func(Token) bool) { + return func(yield func(Token) bool) { + for t := i(); t != EOF; t = i() { + if !yield(t) { + return + } + } + } +} + +// Concaterator concatenates tokens from a series of iterators. +func Concaterator(iterators ...Iterator) Iterator { + return func() Token { + for len(iterators) > 0 { + t := iterators[0]() + if t != EOF { + return t + } + iterators = iterators[1:] + } + return EOF + } +} + +// Literator converts a sequence of literal Tokens into an Iterator. +func Literator(tokens ...Token) Iterator { + return func() Token { + if len(tokens) == 0 { + return EOF + } + token := tokens[0] + tokens = tokens[1:] + return token + } +} + +// SplitTokensIntoLines splits tokens containing newlines in two. +func SplitTokensIntoLines(tokens []Token) (out [][]Token) { + var line []Token // nolint: prealloc +tokenLoop: + for _, token := range tokens { + for strings.Contains(token.Value, "\n") { + parts := strings.SplitAfterN(token.Value, "\n", 2) + // Token becomes the tail. + token.Value = parts[1] + + // Append the head to the line and flush the line. + clone := token.Clone() + clone.Value = parts[0] + line = append(line, clone) + out = append(out, line) + line = nil + + // If the tail token is empty, don't emit it. + if len(token.Value) == 0 { + continue tokenLoop + } + } + line = append(line, token) + } + if len(line) > 0 { + out = append(out, line) + } + // Strip empty trailing token line. + if len(out) > 0 { + last := out[len(out)-1] + if len(last) == 1 && last[0].Value == "" { + out = out[:len(out)-1] + } + } + return out +} diff --git a/vendor/github.com/alecthomas/chroma/v2/lexer.go b/vendor/github.com/alecthomas/chroma/v2/lexer.go new file mode 100644 index 000000000..602db1c4f --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexer.go @@ -0,0 +1,179 @@ +package chroma + +import ( + "fmt" + "strings" +) + +var ( + defaultOptions = &TokeniseOptions{ + State: "root", + EnsureLF: true, + } +) + +// Config for a lexer. +type Config struct { + // Name of the lexer. + Name string `xml:"name,omitempty"` + + // Shortcuts for the lexer + Aliases []string `xml:"alias,omitempty"` + + // File name globs + Filenames []string `xml:"filename,omitempty"` + + // Secondary file name globs + AliasFilenames []string `xml:"alias_filename,omitempty"` + + // MIME types + MimeTypes []string `xml:"mime_type,omitempty"` + + // Regex matching is case-insensitive. + CaseInsensitive bool `xml:"case_insensitive,omitempty"` + + // Regex matches all characters. + DotAll bool `xml:"dot_all,omitempty"` + + // Regex does not match across lines ($ matches EOL). + // + // Defaults to multiline. + NotMultiline bool `xml:"not_multiline,omitempty"` + + // Don't strip leading and trailing newlines from the input. + // DontStripNL bool + + // Strip all leading and trailing whitespace from the input + // StripAll bool + + // Make sure that the input ends with a newline. This + // is required for some lexers that consume input linewise. + EnsureNL bool `xml:"ensure_nl,omitempty"` + + // If given and greater than 0, expand tabs in the input. + // TabSize int + + // Priority of lexer. + // + // If this is 0 it will be treated as a default of 1. + Priority float32 `xml:"priority,omitempty"` + + // Analyse is a list of regexes to match against the input. + // + // If a match is found, the score is returned if single attribute is set to true, + // otherwise the sum of all the score of matching patterns will be + // used as the final score. + Analyse *AnalyseConfig `xml:"analyse,omitempty"` +} + +// AnalyseConfig defines the list of regexes analysers. +type AnalyseConfig struct { + Regexes []RegexConfig `xml:"regex,omitempty"` + // If true, the first matching score is returned. + First bool `xml:"first,attr"` +} + +// RegexConfig defines a single regex pattern and its score in case of match. +type RegexConfig struct { + Pattern string `xml:"pattern,attr"` + Score float32 `xml:"score,attr"` +} + +// Token output to formatter. +type Token struct { + Type TokenType `json:"type"` + Value string `json:"value"` +} + +func (t *Token) String() string { return t.Value } +func (t *Token) GoString() string { return fmt.Sprintf("&Token{%s, %q}", t.Type, t.Value) } + +// Clone returns a clone of the Token. +func (t *Token) Clone() Token { + return *t +} + +// EOF is returned by lexers at the end of input. +var EOF Token + +// TokeniseOptions contains options for tokenisers. +type TokeniseOptions struct { + // State to start tokenisation in. Defaults to "root". + State string + // Nested tokenisation. + Nested bool + + // If true, all EOLs are converted into LF + // by replacing CRLF and CR + EnsureLF bool +} + +// A Lexer for tokenising source code. +type Lexer interface { + // Config describing the features of the Lexer. + Config() *Config + // Tokenise returns an Iterator over tokens in text. + Tokenise(options *TokeniseOptions, text string) (Iterator, error) + // SetRegistry sets the registry this Lexer is associated with. + // + // The registry should be used by the Lexer if it needs to look up other + // lexers. + SetRegistry(registry *LexerRegistry) Lexer + // SetAnalyser sets a function the Lexer should use for scoring how + // likely a fragment of text is to match this lexer, between 0.0 and 1.0. + // A value of 1 indicates high confidence. + // + // Lexers may ignore this if they implement their own analysers. + SetAnalyser(analyser func(text string) float32) Lexer + // AnalyseText scores how likely a fragment of text is to match + // this lexer, between 0.0 and 1.0. A value of 1 indicates high confidence. + AnalyseText(text string) float32 +} + +// Trace is the trace of a tokenisation process. +type Trace struct { + Lexer string `json:"lexer"` + State string `json:"state"` + Rule int `json:"rule"` + Pattern string `json:"pattern"` + Pos int `json:"pos"` + Length int `json:"length"` + Elapsed float64 `json:"elapsedMs"` // Elapsed time spent matching for this rule. +} + +// TracingLexer is a Lexer that can trace its tokenisation process. +type TracingLexer interface { + Lexer + SetTracing(enable bool) +} + +// Lexers is a slice of lexers sortable by name. +type Lexers []Lexer + +func (l Lexers) Len() int { return len(l) } +func (l Lexers) Swap(i, j int) { l[i], l[j] = l[j], l[i] } +func (l Lexers) Less(i, j int) bool { + return strings.ToLower(l[i].Config().Name) < strings.ToLower(l[j].Config().Name) +} + +// PrioritisedLexers is a slice of lexers sortable by priority. +type PrioritisedLexers []Lexer + +func (l PrioritisedLexers) Len() int { return len(l) } +func (l PrioritisedLexers) Swap(i, j int) { l[i], l[j] = l[j], l[i] } +func (l PrioritisedLexers) Less(i, j int) bool { + ip := l[i].Config().Priority + if ip == 0 { + ip = 1 + } + jp := l[j].Config().Priority + if jp == 0 { + jp = 1 + } + return ip > jp +} + +// Analyser determines how appropriate this lexer is for the given text. +type Analyser interface { + AnalyseText(text string) float32 +} diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/README.md b/vendor/github.com/alecthomas/chroma/v2/lexers/README.md new file mode 100644 index 000000000..60a0055ad --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/README.md @@ -0,0 +1,46 @@ +# Chroma lexers + +All lexers in Chroma should now be defined in XML unless they require custom code. + +## Lexer tests + +The tests in this directory feed a known input `testdata/.actual` into the parser for `` and check +that its output matches `.expected`. + +It is also possible to perform several tests on a same parser ``, by placing know inputs `*.actual` into a +directory `testdata//`. + +### Running the tests + +Run the tests as normal: +```go +go test ./lexers +``` + +### Update existing tests + +When you add a new test data file (`*.actual`), you need to regenerate all tests. That's how Chroma creates the `*.expected` test file based on the corresponding lexer. + +To regenerate all tests, type in your terminal: + +```go +RECORD=true go test ./lexers +``` + +This first sets the `RECORD` environment variable to `true`. Then it runs `go test` on the `./lexers` directory of the Chroma project. + +(That environment variable tells Chroma it needs to output test data. After running `go test ./lexers` you can remove or reset that variable.) + +#### Windows users + +Windows users will find that the `RECORD=true go test ./lexers` command fails in both the standard command prompt terminal and in PowerShell. + +Instead we have to perform both steps separately: + +- Set the `RECORD` environment variable to `true`. + + In the regular command prompt window, the `set` command sets an environment variable for the current session: `set RECORD=true`. See [this page](https://superuser.com/questions/212150/how-to-set-env-variable-in-windows-cmd-line) for more. + + In PowerShell, you can use the `$env:RECORD = 'true'` command for that. See [this article](https://mcpmag.com/articles/2019/03/28/environment-variables-in-powershell.aspx) for more. + + You can also make a persistent environment variable by hand in the Windows computer settings. See [this article](https://www.computerhope.com/issues/ch000549.htm) for how. +- When the environment variable is set, run `go test ./lexers`. + +Chroma will now regenerate the test files and print its results to the console window. diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/caddyfile.go b/vendor/github.com/alecthomas/chroma/v2/lexers/caddyfile.go new file mode 100644 index 000000000..82a7efa48 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/caddyfile.go @@ -0,0 +1,275 @@ +package lexers + +import ( + . "github.com/alecthomas/chroma/v2" // nolint +) + +// Matcher token stub for docs, or +// Named matcher: @name, or +// Path matcher: /foo, or +// Wildcard path matcher: * +// nolint: gosec +var caddyfileMatcherTokenRegexp = `(\[\\]|@[^\s]+|/[^\s]+|\*)` + +// Comment at start of line, or +// Comment preceded by whitespace +var caddyfileCommentRegexp = `(^|\s+)#.*\n` + +// caddyfileCommon are the rules common to both of the lexer variants +func caddyfileCommonRules() Rules { + return Rules{ + "site_block_common": { + Include("site_body"), + // Any other directive + {`[^\s#]+`, Keyword, Push("directive")}, + Include("base"), + }, + "site_body": { + // Import keyword + {`\b(import|invoke)\b( [^\s#]+)`, ByGroups(Keyword, Text), Push("subdirective")}, + // Matcher definition + {`@[^\s]+(?=\s)`, NameDecorator, Push("matcher")}, + // Matcher token stub for docs + {`\[\\]`, NameDecorator, Push("matcher")}, + // These cannot have matchers but may have things that look like + // matchers in their arguments, so we just parse as a subdirective. + {`\b(try_files|tls|log|bind)\b`, Keyword, Push("subdirective")}, + // These are special, they can nest more directives + {`\b(handle_errors|handle_path|handle_response|replace_status|handle|route)\b`, Keyword, Push("nested_directive")}, + // uri directive has special syntax + {`\b(uri)\b`, Keyword, Push("uri_directive")}, + }, + "matcher": { + {`\{`, Punctuation, Push("block")}, + // Not can be one-liner + {`not`, Keyword, Push("deep_not_matcher")}, + // Heredoc for CEL expression + Include("heredoc"), + // Backtick for CEL expression + {"`", StringBacktick, Push("backticks")}, + // Any other same-line matcher + {`[^\s#]+`, Keyword, Push("arguments")}, + // Terminators + {`\s*\n`, Text, Pop(1)}, + {`\}`, Punctuation, Pop(1)}, + Include("base"), + }, + "block": { + {`\}`, Punctuation, Pop(2)}, + // Using double quotes doesn't stop at spaces + {`"`, StringDouble, Push("double_quotes")}, + // Using backticks doesn't stop at spaces + {"`", StringBacktick, Push("backticks")}, + // Not can be one-liner + {`not`, Keyword, Push("not_matcher")}, + // Directives & matcher definitions + Include("site_body"), + // Any directive + {`[^\s#]+`, Keyword, Push("subdirective")}, + Include("base"), + }, + "nested_block": { + {`\}`, Punctuation, Pop(2)}, + // Using double quotes doesn't stop at spaces + {`"`, StringDouble, Push("double_quotes")}, + // Using backticks doesn't stop at spaces + {"`", StringBacktick, Push("backticks")}, + // Not can be one-liner + {`not`, Keyword, Push("not_matcher")}, + // Directives & matcher definitions + Include("site_body"), + // Any other subdirective + {`[^\s#]+`, Keyword, Push("directive")}, + Include("base"), + }, + "not_matcher": { + {`\}`, Punctuation, Pop(2)}, + {`\{(?=\s)`, Punctuation, Push("block")}, + {`[^\s#]+`, Keyword, Push("arguments")}, + {`\s+`, Text, nil}, + }, + "deep_not_matcher": { + {`\}`, Punctuation, Pop(2)}, + {`\{(?=\s)`, Punctuation, Push("block")}, + {`[^\s#]+`, Keyword, Push("deep_subdirective")}, + {`\s+`, Text, nil}, + }, + "directive": { + {`\{(?=\s)`, Punctuation, Push("block")}, + {caddyfileMatcherTokenRegexp, NameDecorator, Push("arguments")}, + {caddyfileCommentRegexp, CommentSingle, Pop(1)}, + {`\s*\n`, Text, Pop(1)}, + Include("base"), + }, + "nested_directive": { + {`\{(?=\s)`, Punctuation, Push("nested_block")}, + {caddyfileMatcherTokenRegexp, NameDecorator, Push("nested_arguments")}, + {caddyfileCommentRegexp, CommentSingle, Pop(1)}, + {`\s*\n`, Text, Pop(1)}, + Include("base"), + }, + "subdirective": { + {`\{(?=\s)`, Punctuation, Push("block")}, + {caddyfileCommentRegexp, CommentSingle, Pop(1)}, + {`\s*\n`, Text, Pop(1)}, + Include("base"), + }, + "arguments": { + {`\{(?=\s)`, Punctuation, Push("block")}, + {caddyfileCommentRegexp, CommentSingle, Pop(2)}, + {`\\\n`, Text, nil}, // Skip escaped newlines + {`\s*\n`, Text, Pop(2)}, + Include("base"), + }, + "nested_arguments": { + {`\{(?=\s)`, Punctuation, Push("nested_block")}, + {caddyfileCommentRegexp, CommentSingle, Pop(2)}, + {`\\\n`, Text, nil}, // Skip escaped newlines + {`\s*\n`, Text, Pop(2)}, + Include("base"), + }, + "deep_subdirective": { + {`\{(?=\s)`, Punctuation, Push("block")}, + {caddyfileCommentRegexp, CommentSingle, Pop(3)}, + {`\s*\n`, Text, Pop(3)}, + Include("base"), + }, + "uri_directive": { + {`\{(?=\s)`, Punctuation, Push("block")}, + {caddyfileMatcherTokenRegexp, NameDecorator, nil}, + {`(strip_prefix|strip_suffix|replace|path_regexp)`, NameConstant, Push("arguments")}, + {caddyfileCommentRegexp, CommentSingle, Pop(1)}, + {`\s*\n`, Text, Pop(1)}, + Include("base"), + }, + "double_quotes": { + Include("placeholder"), + {`\\"`, StringDouble, nil}, + {`[^"]`, StringDouble, nil}, + {`"`, StringDouble, Pop(1)}, + }, + "backticks": { + Include("placeholder"), + {"\\\\`", StringBacktick, nil}, + {"[^`]", StringBacktick, nil}, + {"`", StringBacktick, Pop(1)}, + }, + "optional": { + // Docs syntax for showing optional parts with [ ] + {`\[`, Punctuation, Push("optional")}, + Include("name_constants"), + {`\|`, Punctuation, nil}, + {`[^\[\]\|]+`, String, nil}, + {`\]`, Punctuation, Pop(1)}, + }, + "heredoc": { + {`(<<([a-zA-Z0-9_-]+))(\n(.*|\n)*)(\s*)(\2)`, ByGroups(StringHeredoc, nil, String, String, String, StringHeredoc), nil}, + }, + "name_constants": { + {`\b(most_recently_modified|largest_size|smallest_size|first_exist|internal|disable_redirects|ignore_loaded_certs|disable_certs|private_ranges|first|last|before|after|on|off)\b(\||(?=\]|\s|$))`, ByGroups(NameConstant, Punctuation), nil}, + }, + "placeholder": { + // Placeholder with dots, colon for default value, brackets for args[0:] + {`\{[\w+.\[\]\:\$-]+\}`, StringEscape, nil}, + // Handle opening brackets with no matching closing one + {`\{[^\}\s]*\b`, String, nil}, + }, + "base": { + {caddyfileCommentRegexp, CommentSingle, nil}, + {`\[\\]`, NameDecorator, nil}, + Include("name_constants"), + Include("heredoc"), + {`(https?://)?([a-z0-9.-]+)(:)([0-9]+)([^\s]*)`, ByGroups(Name, Name, Punctuation, NumberInteger, Name), nil}, + {`\[`, Punctuation, Push("optional")}, + {"`", StringBacktick, Push("backticks")}, + {`"`, StringDouble, Push("double_quotes")}, + Include("placeholder"), + {`[a-z-]+/[a-z-+]+`, String, nil}, + {`[0-9]+([smhdk]|ns|us|µs|ms)?\b`, NumberInteger, nil}, + {`[^\s\n#\{]+`, String, nil}, + {`/[^\s#]*`, Name, nil}, + {`\s+`, Text, nil}, + }, + } +} + +// Caddyfile lexer. +var Caddyfile = Register(MustNewLexer( + &Config{ + Name: "Caddyfile", + Aliases: []string{"caddyfile", "caddy"}, + Filenames: []string{"Caddyfile*"}, + MimeTypes: []string{}, + }, + caddyfileRules, +)) + +func caddyfileRules() Rules { + return Rules{ + "root": { + {caddyfileCommentRegexp, CommentSingle, nil}, + // Global options block + {`^\s*(\{)\s*$`, ByGroups(Punctuation), Push("globals")}, + // Top level import + {`(import)(\s+)([^\s]+)`, ByGroups(Keyword, Text, NameVariableMagic), nil}, + // Snippets + {`(&?\([^\s#]+\))(\s*)(\{)`, ByGroups(NameVariableAnonymous, Text, Punctuation), Push("snippet")}, + // Site label + {`[^#{(\s,]+`, GenericHeading, Push("label")}, + // Site label with placeholder + {`\{[\w+.\[\]\:\$-]+\}`, StringEscape, Push("label")}, + {`\s+`, Text, nil}, + }, + "globals": { + {`\}`, Punctuation, Pop(1)}, + // Global options are parsed as subdirectives (no matcher) + {`[^\s#]+`, Keyword, Push("subdirective")}, + Include("base"), + }, + "snippet": { + {`\}`, Punctuation, Pop(1)}, + Include("site_body"), + // Any other directive + {`[^\s#]+`, Keyword, Push("directive")}, + Include("base"), + }, + "label": { + // Allow multiple labels, comma separated, newlines after + // a comma means another label is coming + {`,\s*\n?`, Text, nil}, + {` `, Text, nil}, + // Site label with placeholder + Include("placeholder"), + // Site label + {`[^#{(\s,]+`, GenericHeading, nil}, + // Comment after non-block label (hack because comments end in \n) + {`#.*\n`, CommentSingle, Push("site_block")}, + // Note: if \n, we'll never pop out of the site_block, it's valid + {`\{(?=\s)|\n`, Punctuation, Push("site_block")}, + }, + "site_block": { + {`\}`, Punctuation, Pop(2)}, + Include("site_block_common"), + }, + }.Merge(caddyfileCommonRules()) +} + +// Caddyfile directive-only lexer. +var CaddyfileDirectives = Register(MustNewLexer( + &Config{ + Name: "Caddyfile Directives", + Aliases: []string{"caddyfile-directives", "caddyfile-d", "caddy-d"}, + Filenames: []string{}, + MimeTypes: []string{}, + }, + caddyfileDirectivesRules, +)) + +func caddyfileDirectivesRules() Rules { + return Rules{ + // Same as "site_block" in Caddyfile + "root": { + Include("site_block_common"), + }, + }.Merge(caddyfileCommonRules()) +} diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/cl.go b/vendor/github.com/alecthomas/chroma/v2/lexers/cl.go new file mode 100644 index 000000000..3eb0c2307 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/cl.go @@ -0,0 +1,243 @@ +package lexers + +import ( + . "github.com/alecthomas/chroma/v2" // nolint +) + +var ( + clBuiltinFunctions = []string{ + "<", "<=", "=", ">", ">=", "-", "/", "/=", "*", "+", "1-", "1+", + "abort", "abs", "acons", "acos", "acosh", "add-method", "adjoin", + "adjustable-array-p", "adjust-array", "allocate-instance", + "alpha-char-p", "alphanumericp", "append", "apply", "apropos", + "apropos-list", "aref", "arithmetic-error-operands", + "arithmetic-error-operation", "array-dimension", "array-dimensions", + "array-displacement", "array-element-type", "array-has-fill-pointer-p", + "array-in-bounds-p", "arrayp", "array-rank", "array-row-major-index", + "array-total-size", "ash", "asin", "asinh", "assoc", "assoc-if", + "assoc-if-not", "atan", "atanh", "atom", "bit", "bit-and", "bit-andc1", + "bit-andc2", "bit-eqv", "bit-ior", "bit-nand", "bit-nor", "bit-not", + "bit-orc1", "bit-orc2", "bit-vector-p", "bit-xor", "boole", + "both-case-p", "boundp", "break", "broadcast-stream-streams", + "butlast", "byte", "byte-position", "byte-size", "caaaar", "caaadr", + "caaar", "caadar", "caaddr", "caadr", "caar", "cadaar", "cadadr", + "cadar", "caddar", "cadddr", "caddr", "cadr", "call-next-method", "car", + "cdaaar", "cdaadr", "cdaar", "cdadar", "cdaddr", "cdadr", "cdar", + "cddaar", "cddadr", "cddar", "cdddar", "cddddr", "cdddr", "cddr", "cdr", + "ceiling", "cell-error-name", "cerror", "change-class", "char", "char<", + "char<=", "char=", "char>", "char>=", "char/=", "character", + "characterp", "char-code", "char-downcase", "char-equal", + "char-greaterp", "char-int", "char-lessp", "char-name", + "char-not-equal", "char-not-greaterp", "char-not-lessp", "char-upcase", + "cis", "class-name", "class-of", "clear-input", "clear-output", + "close", "clrhash", "code-char", "coerce", "compile", + "compiled-function-p", "compile-file", "compile-file-pathname", + "compiler-macro-function", "complement", "complex", "complexp", + "compute-applicable-methods", "compute-restarts", "concatenate", + "concatenated-stream-streams", "conjugate", "cons", "consp", + "constantly", "constantp", "continue", "copy-alist", "copy-list", + "copy-pprint-dispatch", "copy-readtable", "copy-seq", "copy-structure", + "copy-symbol", "copy-tree", "cos", "cosh", "count", "count-if", + "count-if-not", "decode-float", "decode-universal-time", "delete", + "delete-duplicates", "delete-file", "delete-if", "delete-if-not", + "delete-package", "denominator", "deposit-field", "describe", + "describe-object", "digit-char", "digit-char-p", "directory", + "directory-namestring", "disassemble", "documentation", "dpb", + "dribble", "echo-stream-input-stream", "echo-stream-output-stream", + "ed", "eighth", "elt", "encode-universal-time", "endp", + "enough-namestring", "ensure-directories-exist", + "ensure-generic-function", "eq", "eql", "equal", "equalp", "error", + "eval", "evenp", "every", "exp", "export", "expt", "fboundp", + "fceiling", "fdefinition", "ffloor", "fifth", "file-author", + "file-error-pathname", "file-length", "file-namestring", + "file-position", "file-string-length", "file-write-date", + "fill", "fill-pointer", "find", "find-all-symbols", "find-class", + "find-if", "find-if-not", "find-method", "find-package", "find-restart", + "find-symbol", "finish-output", "first", "float", "float-digits", + "floatp", "float-precision", "float-radix", "float-sign", "floor", + "fmakunbound", "force-output", "format", "fourth", "fresh-line", + "fround", "ftruncate", "funcall", "function-keywords", + "function-lambda-expression", "functionp", "gcd", "gensym", "gentemp", + "get", "get-decoded-time", "get-dispatch-macro-character", "getf", + "gethash", "get-internal-real-time", "get-internal-run-time", + "get-macro-character", "get-output-stream-string", "get-properties", + "get-setf-expansion", "get-universal-time", "graphic-char-p", + "hash-table-count", "hash-table-p", "hash-table-rehash-size", + "hash-table-rehash-threshold", "hash-table-size", "hash-table-test", + "host-namestring", "identity", "imagpart", "import", + "initialize-instance", "input-stream-p", "inspect", + "integer-decode-float", "integer-length", "integerp", + "interactive-stream-p", "intern", "intersection", + "invalid-method-error", "invoke-debugger", "invoke-restart", + "invoke-restart-interactively", "isqrt", "keywordp", "last", "lcm", + "ldb", "ldb-test", "ldiff", "length", "lisp-implementation-type", + "lisp-implementation-version", "list", "list*", "list-all-packages", + "listen", "list-length", "listp", "load", + "load-logical-pathname-translations", "log", "logand", "logandc1", + "logandc2", "logbitp", "logcount", "logeqv", "logical-pathname", + "logical-pathname-translations", "logior", "lognand", "lognor", + "lognot", "logorc1", "logorc2", "logtest", "logxor", "long-site-name", + "lower-case-p", "machine-instance", "machine-type", "machine-version", + "macroexpand", "macroexpand-1", "macro-function", "make-array", + "make-broadcast-stream", "make-concatenated-stream", "make-condition", + "make-dispatch-macro-character", "make-echo-stream", "make-hash-table", + "make-instance", "make-instances-obsolete", "make-list", + "make-load-form", "make-load-form-saving-slots", "make-package", + "make-pathname", "make-random-state", "make-sequence", "make-string", + "make-string-input-stream", "make-string-output-stream", "make-symbol", + "make-synonym-stream", "make-two-way-stream", "makunbound", "map", + "mapc", "mapcan", "mapcar", "mapcon", "maphash", "map-into", "mapl", + "maplist", "mask-field", "max", "member", "member-if", "member-if-not", + "merge", "merge-pathnames", "method-combination-error", + "method-qualifiers", "min", "minusp", "mismatch", "mod", + "muffle-warning", "name-char", "namestring", "nbutlast", "nconc", + "next-method-p", "nintersection", "ninth", "no-applicable-method", + "no-next-method", "not", "notany", "notevery", "nreconc", "nreverse", + "nset-difference", "nset-exclusive-or", "nstring-capitalize", + "nstring-downcase", "nstring-upcase", "nsublis", "nsubst", "nsubst-if", + "nsubst-if-not", "nsubstitute", "nsubstitute-if", "nsubstitute-if-not", + "nth", "nthcdr", "null", "numberp", "numerator", "nunion", "oddp", + "open", "open-stream-p", "output-stream-p", "package-error-package", + "package-name", "package-nicknames", "packagep", + "package-shadowing-symbols", "package-used-by-list", "package-use-list", + "pairlis", "parse-integer", "parse-namestring", "pathname", + "pathname-device", "pathname-directory", "pathname-host", + "pathname-match-p", "pathname-name", "pathnamep", "pathname-type", + "pathname-version", "peek-char", "phase", "plusp", "position", + "position-if", "position-if-not", "pprint", "pprint-dispatch", + "pprint-fill", "pprint-indent", "pprint-linear", "pprint-newline", + "pprint-tab", "pprint-tabular", "prin1", "prin1-to-string", "princ", + "princ-to-string", "print", "print-object", "probe-file", "proclaim", + "provide", "random", "random-state-p", "rassoc", "rassoc-if", + "rassoc-if-not", "rational", "rationalize", "rationalp", "read", + "read-byte", "read-char", "read-char-no-hang", "read-delimited-list", + "read-from-string", "read-line", "read-preserving-whitespace", + "read-sequence", "readtable-case", "readtablep", "realp", "realpart", + "reduce", "reinitialize-instance", "rem", "remhash", "remove", + "remove-duplicates", "remove-if", "remove-if-not", "remove-method", + "remprop", "rename-file", "rename-package", "replace", "require", + "rest", "restart-name", "revappend", "reverse", "room", "round", + "row-major-aref", "rplaca", "rplacd", "sbit", "scale-float", "schar", + "search", "second", "set", "set-difference", + "set-dispatch-macro-character", "set-exclusive-or", + "set-macro-character", "set-pprint-dispatch", "set-syntax-from-char", + "seventh", "shadow", "shadowing-import", "shared-initialize", + "short-site-name", "signal", "signum", "simple-bit-vector-p", + "simple-condition-format-arguments", "simple-condition-format-control", + "simple-string-p", "simple-vector-p", "sin", "sinh", "sixth", "sleep", + "slot-boundp", "slot-exists-p", "slot-makunbound", "slot-missing", + "slot-unbound", "slot-value", "software-type", "software-version", + "some", "sort", "special-operator-p", "sqrt", "stable-sort", + "standard-char-p", "store-value", "stream-element-type", + "stream-error-stream", "stream-external-format", "streamp", "string", + "string<", "string<=", "string=", "string>", "string>=", "string/=", + "string-capitalize", "string-downcase", "string-equal", + "string-greaterp", "string-left-trim", "string-lessp", + "string-not-equal", "string-not-greaterp", "string-not-lessp", + "stringp", "string-right-trim", "string-trim", "string-upcase", + "sublis", "subseq", "subsetp", "subst", "subst-if", "subst-if-not", + "substitute", "substitute-if", "substitute-if-not", "subtypep", "svref", + "sxhash", "symbol-function", "symbol-name", "symbolp", "symbol-package", + "symbol-plist", "symbol-value", "synonym-stream-symbol", "syntax:", + "tailp", "tan", "tanh", "tenth", "terpri", "third", + "translate-logical-pathname", "translate-pathname", "tree-equal", + "truename", "truncate", "two-way-stream-input-stream", + "two-way-stream-output-stream", "type-error-datum", + "type-error-expected-type", "type-of", "typep", "unbound-slot-instance", + "unexport", "unintern", "union", "unread-char", "unuse-package", + "update-instance-for-different-class", + "update-instance-for-redefined-class", "upgraded-array-element-type", + "upgraded-complex-part-type", "upper-case-p", "use-package", + "user-homedir-pathname", "use-value", "values", "values-list", "vector", + "vectorp", "vector-pop", "vector-push", "vector-push-extend", "warn", + "wild-pathname-p", "write", "write-byte", "write-char", "write-line", + "write-sequence", "write-string", "write-to-string", "yes-or-no-p", + "y-or-n-p", "zerop", + } + + clSpecialForms = []string{ + "block", "catch", "declare", "eval-when", "flet", "function", "go", "if", + "labels", "lambda", "let", "let*", "load-time-value", "locally", "macrolet", + "multiple-value-call", "multiple-value-prog1", "progn", "progv", "quote", + "return-from", "setq", "symbol-macrolet", "tagbody", "the", "throw", + "unwind-protect", + } + + clMacros = []string{ + "and", "assert", "call-method", "case", "ccase", "check-type", "cond", + "ctypecase", "decf", "declaim", "defclass", "defconstant", "defgeneric", + "define-compiler-macro", "define-condition", "define-method-combination", + "define-modify-macro", "define-setf-expander", "define-symbol-macro", + "defmacro", "defmethod", "defpackage", "defparameter", "defsetf", + "defstruct", "deftype", "defun", "defvar", "destructuring-bind", "do", + "do*", "do-all-symbols", "do-external-symbols", "dolist", "do-symbols", + "dotimes", "ecase", "etypecase", "formatter", "handler-bind", + "handler-case", "ignore-errors", "incf", "in-package", "lambda", "loop", + "loop-finish", "make-method", "multiple-value-bind", "multiple-value-list", + "multiple-value-setq", "nth-value", "or", "pop", + "pprint-exit-if-list-exhausted", "pprint-logical-block", "pprint-pop", + "print-unreadable-object", "prog", "prog*", "prog1", "prog2", "psetf", + "psetq", "push", "pushnew", "remf", "restart-bind", "restart-case", + "return", "rotatef", "setf", "shiftf", "step", "time", "trace", "typecase", + "unless", "untrace", "when", "with-accessors", "with-compilation-unit", + "with-condition-restarts", "with-hash-table-iterator", + "with-input-from-string", "with-open-file", "with-open-stream", + "with-output-to-string", "with-package-iterator", "with-simple-restart", + "with-slots", "with-standard-io-syntax", + } + + clLambdaListKeywords = []string{ + "&allow-other-keys", "&aux", "&body", "&environment", "&key", "&optional", + "&rest", "&whole", + } + + clDeclarations = []string{ + "dynamic-extent", "ignore", "optimize", "ftype", "inline", "special", + "ignorable", "notinline", "type", + } + + clBuiltinTypes = []string{ + "atom", "boolean", "base-char", "base-string", "bignum", "bit", + "compiled-function", "extended-char", "fixnum", "keyword", "nil", + "signed-byte", "short-float", "single-float", "double-float", "long-float", + "simple-array", "simple-base-string", "simple-bit-vector", "simple-string", + "simple-vector", "standard-char", "unsigned-byte", + + // Condition Types + "arithmetic-error", "cell-error", "condition", "control-error", + "division-by-zero", "end-of-file", "error", "file-error", + "floating-point-inexact", "floating-point-overflow", + "floating-point-underflow", "floating-point-invalid-operation", + "parse-error", "package-error", "print-not-readable", "program-error", + "reader-error", "serious-condition", "simple-condition", "simple-error", + "simple-type-error", "simple-warning", "stream-error", "storage-condition", + "style-warning", "type-error", "unbound-variable", "unbound-slot", + "undefined-function", "warning", + } + + clBuiltinClasses = []string{ + "array", "broadcast-stream", "bit-vector", "built-in-class", "character", + "class", "complex", "concatenated-stream", "cons", "echo-stream", + "file-stream", "float", "function", "generic-function", "hash-table", + "integer", "list", "logical-pathname", "method-combination", "method", + "null", "number", "package", "pathname", "ratio", "rational", "readtable", + "real", "random-state", "restart", "sequence", "standard-class", + "standard-generic-function", "standard-method", "standard-object", + "string-stream", "stream", "string", "structure-class", "structure-object", + "symbol", "synonym-stream", "t", "two-way-stream", "vector", + } +) + +// Common Lisp lexer. +var CommonLisp = Register(TypeRemappingLexer(MustNewXMLLexer( + embedded, + "embedded/common_lisp.xml", +), TypeMapping{ + {NameVariable, NameFunction, clBuiltinFunctions}, + {NameVariable, Keyword, clSpecialForms}, + {NameVariable, NameBuiltin, clMacros}, + {NameVariable, Keyword, clLambdaListKeywords}, + {NameVariable, Keyword, clDeclarations}, + {NameVariable, KeywordType, clBuiltinTypes}, + {NameVariable, NameClass, clBuiltinClasses}, +})) diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/dns.go b/vendor/github.com/alecthomas/chroma/v2/lexers/dns.go new file mode 100644 index 000000000..7e699622a --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/dns.go @@ -0,0 +1,17 @@ +package lexers + +import ( + "regexp" +) + +// TODO(moorereason): can this be factored away? +var zoneAnalyserRe = regexp.MustCompile(`(?m)^@\s+IN\s+SOA\s+`) + +func init() { // nolint: gochecknoinits + Get("dns").SetAnalyser(func(text string) float32 { + if zoneAnalyserRe.FindString(text) != "" { + return 1.0 + } + return 0.0 + }) +} diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/emacs.go b/vendor/github.com/alecthomas/chroma/v2/lexers/emacs.go new file mode 100644 index 000000000..869b0f3f4 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/emacs.go @@ -0,0 +1,533 @@ +package lexers + +import ( + . "github.com/alecthomas/chroma/v2" // nolint +) + +var ( + emacsMacros = []string{ + "atomic-change-group", "case", "block", "cl-block", "cl-callf", "cl-callf2", + "cl-case", "cl-decf", "cl-declaim", "cl-declare", + "cl-define-compiler-macro", "cl-defmacro", "cl-defstruct", + "cl-defsubst", "cl-deftype", "cl-defun", "cl-destructuring-bind", + "cl-do", "cl-do*", "cl-do-all-symbols", "cl-do-symbols", "cl-dolist", + "cl-dotimes", "cl-ecase", "cl-etypecase", "eval-when", "cl-eval-when", "cl-flet", + "cl-flet*", "cl-function", "cl-incf", "cl-labels", "cl-letf", + "cl-letf*", "cl-load-time-value", "cl-locally", "cl-loop", + "cl-macrolet", "cl-multiple-value-bind", "cl-multiple-value-setq", + "cl-progv", "cl-psetf", "cl-psetq", "cl-pushnew", "cl-remf", + "cl-return", "cl-return-from", "cl-rotatef", "cl-shiftf", + "cl-symbol-macrolet", "cl-tagbody", "cl-the", "cl-typecase", + "combine-after-change-calls", "condition-case-unless-debug", "decf", + "declaim", "declare", "declare-function", "def-edebug-spec", + "defadvice", "defclass", "defcustom", "defface", "defgeneric", + "defgroup", "define-advice", "define-alternatives", + "define-compiler-macro", "define-derived-mode", "define-generic-mode", + "define-global-minor-mode", "define-globalized-minor-mode", + "define-minor-mode", "define-modify-macro", + "define-obsolete-face-alias", "define-obsolete-function-alias", + "define-obsolete-variable-alias", "define-setf-expander", + "define-skeleton", "defmacro", "defmethod", "defsetf", "defstruct", + "defsubst", "deftheme", "deftype", "defun", "defvar-local", + "delay-mode-hooks", "destructuring-bind", "do", "do*", + "do-all-symbols", "do-symbols", "dolist", "dont-compile", "dotimes", + "dotimes-with-progress-reporter", "ecase", "ert-deftest", "etypecase", + "eval-and-compile", "eval-when-compile", "flet", "ignore-errors", + "incf", "labels", "lambda", "letrec", "lexical-let", "lexical-let*", + "loop", "multiple-value-bind", "multiple-value-setq", "noreturn", + "oref", "oref-default", "oset", "oset-default", "pcase", + "pcase-defmacro", "pcase-dolist", "pcase-exhaustive", "pcase-let", + "pcase-let*", "pop", "psetf", "psetq", "push", "pushnew", "remf", + "return", "rotatef", "rx", "save-match-data", "save-selected-window", + "save-window-excursion", "setf", "setq-local", "shiftf", + "track-mouse", "typecase", "unless", "use-package", "when", + "while-no-input", "with-case-table", "with-category-table", + "with-coding-priority", "with-current-buffer", "with-demoted-errors", + "with-eval-after-load", "with-file-modes", "with-local-quit", + "with-output-to-string", "with-output-to-temp-buffer", + "with-parsed-tramp-file-name", "with-selected-frame", + "with-selected-window", "with-silent-modifications", "with-slots", + "with-syntax-table", "with-temp-buffer", "with-temp-file", + "with-temp-message", "with-timeout", "with-tramp-connection-property", + "with-tramp-file-property", "with-tramp-progress-reporter", + "with-wrapper-hook", "load-time-value", "locally", "macrolet", "progv", + "return-from", + } + + emacsSpecialForms = []string{ + "and", "catch", "cond", "condition-case", "defconst", "defvar", + "function", "if", "interactive", "let", "let*", "or", "prog1", + "prog2", "progn", "quote", "save-current-buffer", "save-excursion", + "save-restriction", "setq", "setq-default", "subr-arity", + "unwind-protect", "while", + } + + emacsBuiltinFunction = []string{ + "%", "*", "+", "-", "/", "/=", "1+", "1-", "<", "<=", "=", ">", ">=", + "Snarf-documentation", "abort-recursive-edit", "abs", + "accept-process-output", "access-file", "accessible-keymaps", "acos", + "active-minibuffer-window", "add-face-text-property", + "add-name-to-file", "add-text-properties", "all-completions", + "append", "apply", "apropos-internal", "aref", "arrayp", "aset", + "ash", "asin", "assoc", "assoc-string", "assq", "atan", "atom", + "autoload", "autoload-do-load", "backtrace", "backtrace--locals", + "backtrace-debug", "backtrace-eval", "backtrace-frame", + "backward-char", "backward-prefix-chars", "barf-if-buffer-read-only", + "base64-decode-region", "base64-decode-string", + "base64-encode-region", "base64-encode-string", "beginning-of-line", + "bidi-find-overridden-directionality", "bidi-resolved-levels", + "bitmap-spec-p", "bobp", "bolp", "bool-vector", + "bool-vector-count-consecutive", "bool-vector-count-population", + "bool-vector-exclusive-or", "bool-vector-intersection", + "bool-vector-not", "bool-vector-p", "bool-vector-set-difference", + "bool-vector-subsetp", "bool-vector-union", "boundp", + "buffer-base-buffer", "buffer-chars-modified-tick", + "buffer-enable-undo", "buffer-file-name", "buffer-has-markers-at", + "buffer-list", "buffer-live-p", "buffer-local-value", + "buffer-local-variables", "buffer-modified-p", "buffer-modified-tick", + "buffer-name", "buffer-size", "buffer-string", "buffer-substring", + "buffer-substring-no-properties", "buffer-swap-text", "bufferp", + "bury-buffer-internal", "byte-code", "byte-code-function-p", + "byte-to-position", "byte-to-string", "byteorder", + "call-interactively", "call-last-kbd-macro", "call-process", + "call-process-region", "cancel-kbd-macro-events", "capitalize", + "capitalize-region", "capitalize-word", "car", "car-less-than-car", + "car-safe", "case-table-p", "category-docstring", + "category-set-mnemonics", "category-table", "category-table-p", + "ccl-execute", "ccl-execute-on-string", "ccl-program-p", "cdr", + "cdr-safe", "ceiling", "char-after", "char-before", + "char-category-set", "char-charset", "char-equal", "char-or-string-p", + "char-resolve-modifiers", "char-syntax", "char-table-extra-slot", + "char-table-p", "char-table-parent", "char-table-range", + "char-table-subtype", "char-to-string", "char-width", "characterp", + "charset-after", "charset-id-internal", "charset-plist", + "charset-priority-list", "charsetp", "check-coding-system", + "check-coding-systems-region", "clear-buffer-auto-save-failure", + "clear-charset-maps", "clear-face-cache", "clear-font-cache", + "clear-image-cache", "clear-string", "clear-this-command-keys", + "close-font", "clrhash", "coding-system-aliases", + "coding-system-base", "coding-system-eol-type", "coding-system-p", + "coding-system-plist", "coding-system-priority-list", + "coding-system-put", "color-distance", "color-gray-p", + "color-supported-p", "combine-after-change-execute", + "command-error-default-function", "command-remapping", "commandp", + "compare-buffer-substrings", "compare-strings", + "compare-window-configurations", "completing-read", + "compose-region-internal", "compose-string-internal", + "composition-get-gstring", "compute-motion", "concat", "cons", + "consp", "constrain-to-field", "continue-process", + "controlling-tty-p", "coordinates-in-window-p", "copy-alist", + "copy-category-table", "copy-file", "copy-hash-table", "copy-keymap", + "copy-marker", "copy-sequence", "copy-syntax-table", "copysign", + "cos", "current-active-maps", "current-bidi-paragraph-direction", + "current-buffer", "current-case-table", "current-column", + "current-global-map", "current-idle-time", "current-indentation", + "current-input-mode", "current-local-map", "current-message", + "current-minor-mode-maps", "current-time", "current-time-string", + "current-time-zone", "current-window-configuration", + "cygwin-convert-file-name-from-windows", + "cygwin-convert-file-name-to-windows", "daemon-initialized", + "daemonp", "dbus--init-bus", "dbus-get-unique-name", + "dbus-message-internal", "debug-timer-check", "declare-equiv-charset", + "decode-big5-char", "decode-char", "decode-coding-region", + "decode-coding-string", "decode-sjis-char", "decode-time", + "default-boundp", "default-file-modes", "default-printer-name", + "default-toplevel-value", "default-value", "define-category", + "define-charset-alias", "define-charset-internal", + "define-coding-system-alias", "define-coding-system-internal", + "define-fringe-bitmap", "define-hash-table-test", "define-key", + "define-prefix-command", "delete", + "delete-all-overlays", "delete-and-extract-region", "delete-char", + "delete-directory-internal", "delete-field", "delete-file", + "delete-frame", "delete-other-windows-internal", "delete-overlay", + "delete-process", "delete-region", "delete-terminal", + "delete-window-internal", "delq", "describe-buffer-bindings", + "describe-vector", "destroy-fringe-bitmap", "detect-coding-region", + "detect-coding-string", "ding", "directory-file-name", + "directory-files", "directory-files-and-attributes", "discard-input", + "display-supports-face-attributes-p", "do-auto-save", "documentation", + "documentation-property", "downcase", "downcase-region", + "downcase-word", "draw-string", "dump-colors", "dump-emacs", + "dump-face", "dump-frame-glyph-matrix", "dump-glyph-matrix", + "dump-glyph-row", "dump-redisplay-history", "dump-tool-bar-row", + "elt", "emacs-pid", "encode-big5-char", "encode-char", + "encode-coding-region", "encode-coding-string", "encode-sjis-char", + "encode-time", "end-kbd-macro", "end-of-line", "eobp", "eolp", "eq", + "eql", "equal", "equal-including-properties", "erase-buffer", + "error-message-string", "eval", "eval-buffer", "eval-region", + "event-convert-list", "execute-kbd-macro", "exit-recursive-edit", + "exp", "expand-file-name", "expt", "external-debugging-output", + "face-attribute-relative-p", "face-attributes-as-vector", "face-font", + "fboundp", "fceiling", "fetch-bytecode", "ffloor", + "field-beginning", "field-end", "field-string", + "field-string-no-properties", "file-accessible-directory-p", + "file-acl", "file-attributes", "file-attributes-lessp", + "file-directory-p", "file-executable-p", "file-exists-p", + "file-locked-p", "file-modes", "file-name-absolute-p", + "file-name-all-completions", "file-name-as-directory", + "file-name-completion", "file-name-directory", + "file-name-nondirectory", "file-newer-than-file-p", "file-readable-p", + "file-regular-p", "file-selinux-context", "file-symlink-p", + "file-system-info", "file-system-info", "file-writable-p", + "fillarray", "find-charset-region", "find-charset-string", + "find-coding-systems-region-internal", "find-composition-internal", + "find-file-name-handler", "find-font", "find-operation-coding-system", + "float", "float-time", "floatp", "floor", "fmakunbound", + "following-char", "font-at", "font-drive-otf", "font-face-attributes", + "font-family-list", "font-get", "font-get-glyphs", + "font-get-system-font", "font-get-system-normal-font", "font-info", + "font-match-p", "font-otf-alternates", "font-put", + "font-shape-gstring", "font-spec", "font-variation-glyphs", + "font-xlfd-name", "fontp", "fontset-font", "fontset-info", + "fontset-list", "fontset-list-all", "force-mode-line-update", + "force-window-update", "format", "format-mode-line", + "format-network-address", "format-time-string", "forward-char", + "forward-comment", "forward-line", "forward-word", + "frame-border-width", "frame-bottom-divider-width", + "frame-can-run-window-configuration-change-hook", "frame-char-height", + "frame-char-width", "frame-face-alist", "frame-first-window", + "frame-focus", "frame-font-cache", "frame-fringe-width", "frame-list", + "frame-live-p", "frame-or-buffer-changed-p", "frame-parameter", + "frame-parameters", "frame-pixel-height", "frame-pixel-width", + "frame-pointer-visible-p", "frame-right-divider-width", + "frame-root-window", "frame-scroll-bar-height", + "frame-scroll-bar-width", "frame-selected-window", "frame-terminal", + "frame-text-cols", "frame-text-height", "frame-text-lines", + "frame-text-width", "frame-total-cols", "frame-total-lines", + "frame-visible-p", "framep", "frexp", "fringe-bitmaps-at-pos", + "fround", "fset", "ftruncate", "funcall", "funcall-interactively", + "function-equal", "functionp", "gap-position", "gap-size", + "garbage-collect", "gc-status", "generate-new-buffer-name", "get", + "get-buffer", "get-buffer-create", "get-buffer-process", + "get-buffer-window", "get-byte", "get-char-property", + "get-char-property-and-overlay", "get-file-buffer", "get-file-char", + "get-internal-run-time", "get-load-suffixes", "get-pos-property", + "get-process", "get-screen-color", "get-text-property", + "get-unicode-property-internal", "get-unused-category", + "get-unused-iso-final-char", "getenv-internal", "gethash", + "gfile-add-watch", "gfile-rm-watch", "global-key-binding", + "gnutls-available-p", "gnutls-boot", "gnutls-bye", "gnutls-deinit", + "gnutls-error-fatalp", "gnutls-error-string", "gnutls-errorp", + "gnutls-get-initstage", "gnutls-peer-status", + "gnutls-peer-status-warning-describe", "goto-char", "gpm-mouse-start", + "gpm-mouse-stop", "group-gid", "group-real-gid", + "handle-save-session", "handle-switch-frame", "hash-table-count", + "hash-table-p", "hash-table-rehash-size", + "hash-table-rehash-threshold", "hash-table-size", "hash-table-test", + "hash-table-weakness", "iconify-frame", "identity", "image-flush", + "image-mask-p", "image-metadata", "image-size", "imagemagick-types", + "imagep", "indent-to", "indirect-function", "indirect-variable", + "init-image-library", "inotify-add-watch", "inotify-rm-watch", + "input-pending-p", "insert", "insert-and-inherit", + "insert-before-markers", "insert-before-markers-and-inherit", + "insert-buffer-substring", "insert-byte", "insert-char", + "insert-file-contents", "insert-startup-screen", "int86", + "integer-or-marker-p", "integerp", "interactive-form", "intern", + "intern-soft", "internal--track-mouse", "internal-char-font", + "internal-complete-buffer", "internal-copy-lisp-face", + "internal-default-process-filter", + "internal-default-process-sentinel", "internal-describe-syntax-value", + "internal-event-symbol-parse-modifiers", + "internal-face-x-get-resource", "internal-get-lisp-face-attribute", + "internal-lisp-face-attribute-values", "internal-lisp-face-empty-p", + "internal-lisp-face-equal-p", "internal-lisp-face-p", + "internal-make-lisp-face", "internal-make-var-non-special", + "internal-merge-in-global-face", + "internal-set-alternative-font-family-alist", + "internal-set-alternative-font-registry-alist", + "internal-set-font-selection-order", + "internal-set-lisp-face-attribute", + "internal-set-lisp-face-attribute-from-resource", + "internal-show-cursor", "internal-show-cursor-p", "interrupt-process", + "invisible-p", "invocation-directory", "invocation-name", "isnan", + "iso-charset", "key-binding", "key-description", + "keyboard-coding-system", "keymap-parent", "keymap-prompt", "keymapp", + "keywordp", "kill-all-local-variables", "kill-buffer", "kill-emacs", + "kill-local-variable", "kill-process", "last-nonminibuffer-frame", + "lax-plist-get", "lax-plist-put", "ldexp", "length", + "libxml-parse-html-region", "libxml-parse-xml-region", + "line-beginning-position", "line-end-position", "line-pixel-height", + "list", "list-fonts", "list-system-processes", "listp", "load", + "load-average", "local-key-binding", "local-variable-if-set-p", + "local-variable-p", "locale-info", "locate-file-internal", + "lock-buffer", "log", "logand", "logb", "logior", "lognot", "logxor", + "looking-at", "lookup-image", "lookup-image-map", "lookup-key", + "lower-frame", "lsh", "macroexpand", "make-bool-vector", + "make-byte-code", "make-category-set", "make-category-table", + "make-char", "make-char-table", "make-directory-internal", + "make-frame-invisible", "make-frame-visible", "make-hash-table", + "make-indirect-buffer", "make-keymap", "make-list", + "make-local-variable", "make-marker", "make-network-process", + "make-overlay", "make-serial-process", "make-sparse-keymap", + "make-string", "make-symbol", "make-symbolic-link", "make-temp-name", + "make-terminal-frame", "make-variable-buffer-local", + "make-variable-frame-local", "make-vector", "makunbound", + "map-char-table", "map-charset-chars", "map-keymap", + "map-keymap-internal", "mapatoms", "mapc", "mapcar", "mapconcat", + "maphash", "mark-marker", "marker-buffer", "marker-insertion-type", + "marker-position", "markerp", "match-beginning", "match-data", + "match-end", "matching-paren", "max", "max-char", "md5", "member", + "memory-info", "memory-limit", "memory-use-counts", "memq", "memql", + "menu-bar-menu-at-x-y", "menu-or-popup-active-p", + "menu-or-popup-active-p", "merge-face-attribute", "message", + "message-box", "message-or-box", "min", + "minibuffer-completion-contents", "minibuffer-contents", + "minibuffer-contents-no-properties", "minibuffer-depth", + "minibuffer-prompt", "minibuffer-prompt-end", + "minibuffer-selected-window", "minibuffer-window", "minibufferp", + "minor-mode-key-binding", "mod", "modify-category-entry", + "modify-frame-parameters", "modify-syntax-entry", + "mouse-pixel-position", "mouse-position", "move-overlay", + "move-point-visually", "move-to-column", "move-to-window-line", + "msdos-downcase-filename", "msdos-long-file-names", "msdos-memget", + "msdos-memput", "msdos-mouse-disable", "msdos-mouse-enable", + "msdos-mouse-init", "msdos-mouse-p", "msdos-remember-default-colors", + "msdos-set-keyboard", "msdos-set-mouse-buttons", + "multibyte-char-to-unibyte", "multibyte-string-p", "narrow-to-region", + "natnump", "nconc", "network-interface-info", + "network-interface-list", "new-fontset", "newline-cache-check", + "next-char-property-change", "next-frame", "next-overlay-change", + "next-property-change", "next-read-file-uses-dialog-p", + "next-single-char-property-change", "next-single-property-change", + "next-window", "nlistp", "nreverse", "nth", "nthcdr", "null", + "number-or-marker-p", "number-to-string", "numberp", + "open-dribble-file", "open-font", "open-termscript", + "optimize-char-table", "other-buffer", "other-window-for-scrolling", + "overlay-buffer", "overlay-end", "overlay-get", "overlay-lists", + "overlay-properties", "overlay-put", "overlay-recenter", + "overlay-start", "overlayp", "overlays-at", "overlays-in", + "parse-partial-sexp", "play-sound-internal", "plist-get", + "plist-member", "plist-put", "point", "point-marker", "point-max", + "point-max-marker", "point-min", "point-min-marker", + "pos-visible-in-window-p", "position-bytes", "posix-looking-at", + "posix-search-backward", "posix-search-forward", "posix-string-match", + "posn-at-point", "posn-at-x-y", "preceding-char", + "prefix-numeric-value", "previous-char-property-change", + "previous-frame", "previous-overlay-change", + "previous-property-change", "previous-single-char-property-change", + "previous-single-property-change", "previous-window", "prin1", + "prin1-to-string", "princ", "print", "process-attributes", + "process-buffer", "process-coding-system", "process-command", + "process-connection", "process-contact", "process-datagram-address", + "process-exit-status", "process-filter", "process-filter-multibyte-p", + "process-id", "process-inherit-coding-system-flag", "process-list", + "process-mark", "process-name", "process-plist", + "process-query-on-exit-flag", "process-running-child-p", + "process-send-eof", "process-send-region", "process-send-string", + "process-sentinel", "process-status", "process-tty-name", + "process-type", "processp", "profiler-cpu-log", + "profiler-cpu-running-p", "profiler-cpu-start", "profiler-cpu-stop", + "profiler-memory-log", "profiler-memory-running-p", + "profiler-memory-start", "profiler-memory-stop", "propertize", + "purecopy", "put", "put-text-property", + "put-unicode-property-internal", "puthash", "query-font", + "query-fontset", "quit-process", "raise-frame", "random", "rassoc", + "rassq", "re-search-backward", "re-search-forward", "read", + "read-buffer", "read-char", "read-char-exclusive", + "read-coding-system", "read-command", "read-event", + "read-from-minibuffer", "read-from-string", "read-function", + "read-key-sequence", "read-key-sequence-vector", + "read-no-blanks-input", "read-non-nil-coding-system", "read-string", + "read-variable", "recent-auto-save-p", "recent-doskeys", + "recent-keys", "recenter", "recursion-depth", "recursive-edit", + "redirect-debugging-output", "redirect-frame-focus", "redisplay", + "redraw-display", "redraw-frame", "regexp-quote", "region-beginning", + "region-end", "register-ccl-program", "register-code-conversion-map", + "remhash", "remove-list-of-text-properties", "remove-text-properties", + "rename-buffer", "rename-file", "replace-match", + "reset-this-command-lengths", "resize-mini-window-internal", + "restore-buffer-modified-p", "resume-tty", "reverse", "round", + "run-hook-with-args", "run-hook-with-args-until-failure", + "run-hook-with-args-until-success", "run-hook-wrapped", "run-hooks", + "run-window-configuration-change-hook", "run-window-scroll-functions", + "safe-length", "scan-lists", "scan-sexps", "scroll-down", + "scroll-left", "scroll-other-window", "scroll-right", "scroll-up", + "search-backward", "search-forward", "secure-hash", "select-frame", + "select-window", "selected-frame", "selected-window", + "self-insert-command", "send-string-to-terminal", "sequencep", + "serial-process-configure", "set", "set-buffer", + "set-buffer-auto-saved", "set-buffer-major-mode", + "set-buffer-modified-p", "set-buffer-multibyte", "set-case-table", + "set-category-table", "set-char-table-extra-slot", + "set-char-table-parent", "set-char-table-range", "set-charset-plist", + "set-charset-priority", "set-coding-system-priority", + "set-cursor-size", "set-default", "set-default-file-modes", + "set-default-toplevel-value", "set-file-acl", "set-file-modes", + "set-file-selinux-context", "set-file-times", "set-fontset-font", + "set-frame-height", "set-frame-position", "set-frame-selected-window", + "set-frame-size", "set-frame-width", "set-fringe-bitmap-face", + "set-input-interrupt-mode", "set-input-meta-mode", "set-input-mode", + "set-keyboard-coding-system-internal", "set-keymap-parent", + "set-marker", "set-marker-insertion-type", "set-match-data", + "set-message-beep", "set-minibuffer-window", + "set-mouse-pixel-position", "set-mouse-position", + "set-network-process-option", "set-output-flow-control", + "set-process-buffer", "set-process-coding-system", + "set-process-datagram-address", "set-process-filter", + "set-process-filter-multibyte", + "set-process-inherit-coding-system-flag", "set-process-plist", + "set-process-query-on-exit-flag", "set-process-sentinel", + "set-process-window-size", "set-quit-char", + "set-safe-terminal-coding-system-internal", "set-screen-color", + "set-standard-case-table", "set-syntax-table", + "set-terminal-coding-system-internal", "set-terminal-local-value", + "set-terminal-parameter", "set-text-properties", "set-time-zone-rule", + "set-visited-file-modtime", "set-window-buffer", + "set-window-combination-limit", "set-window-configuration", + "set-window-dedicated-p", "set-window-display-table", + "set-window-fringes", "set-window-hscroll", "set-window-margins", + "set-window-new-normal", "set-window-new-pixel", + "set-window-new-total", "set-window-next-buffers", + "set-window-parameter", "set-window-point", "set-window-prev-buffers", + "set-window-redisplay-end-trigger", "set-window-scroll-bars", + "set-window-start", "set-window-vscroll", "setcar", "setcdr", + "setplist", "show-face-resources", "signal", "signal-process", "sin", + "single-key-description", "skip-chars-backward", "skip-chars-forward", + "skip-syntax-backward", "skip-syntax-forward", "sleep-for", "sort", + "sort-charsets", "special-variable-p", "split-char", + "split-window-internal", "sqrt", "standard-case-table", + "standard-category-table", "standard-syntax-table", "start-kbd-macro", + "start-process", "stop-process", "store-kbd-macro-event", "string", + "string-as-multibyte", "string-as-unibyte", "string-bytes", + "string-collate-equalp", "string-collate-lessp", "string-equal", + "string-lessp", "string-make-multibyte", "string-make-unibyte", + "string-match", "string-to-char", "string-to-multibyte", + "string-to-number", "string-to-syntax", "string-to-unibyte", + "string-width", "stringp", "subr-name", "subrp", + "subst-char-in-region", "substitute-command-keys", + "substitute-in-file-name", "substring", "substring-no-properties", + "suspend-emacs", "suspend-tty", "suspicious-object", "sxhash", + "symbol-function", "symbol-name", "symbol-plist", "symbol-value", + "symbolp", "syntax-table", "syntax-table-p", "system-groups", + "system-move-file-to-trash", "system-name", "system-users", "tan", + "terminal-coding-system", "terminal-list", "terminal-live-p", + "terminal-local-value", "terminal-name", "terminal-parameter", + "terminal-parameters", "terpri", "test-completion", + "text-char-description", "text-properties-at", "text-property-any", + "text-property-not-all", "this-command-keys", + "this-command-keys-vector", "this-single-command-keys", + "this-single-command-raw-keys", "time-add", "time-less-p", + "time-subtract", "tool-bar-get-system-style", "tool-bar-height", + "tool-bar-pixel-width", "top-level", "trace-redisplay", + "trace-to-stderr", "translate-region-internal", "transpose-regions", + "truncate", "try-completion", "tty-display-color-cells", + "tty-display-color-p", "tty-no-underline", + "tty-suppress-bold-inverse-default-colors", "tty-top-frame", + "tty-type", "type-of", "undo-boundary", "unencodable-char-position", + "unhandled-file-name-directory", "unibyte-char-to-multibyte", + "unibyte-string", "unicode-property-table-internal", "unify-charset", + "unintern", "unix-sync", "unlock-buffer", "upcase", "upcase-initials", + "upcase-initials-region", "upcase-region", "upcase-word", + "use-global-map", "use-local-map", "user-full-name", + "user-login-name", "user-real-login-name", "user-real-uid", + "user-uid", "variable-binding-locus", "vconcat", "vector", + "vector-or-char-table-p", "vectorp", "verify-visited-file-modtime", + "vertical-motion", "visible-frame-list", "visited-file-modtime", + "w16-get-clipboard-data", "w16-selection-exists-p", + "w16-set-clipboard-data", "w32-battery-status", + "w32-default-color-map", "w32-define-rgb-color", + "w32-display-monitor-attributes-list", "w32-frame-menu-bar-size", + "w32-frame-rect", "w32-get-clipboard-data", + "w32-get-codepage-charset", "w32-get-console-codepage", + "w32-get-console-output-codepage", "w32-get-current-locale-id", + "w32-get-default-locale-id", "w32-get-keyboard-layout", + "w32-get-locale-info", "w32-get-valid-codepages", + "w32-get-valid-keyboard-layouts", "w32-get-valid-locale-ids", + "w32-has-winsock", "w32-long-file-name", "w32-reconstruct-hot-key", + "w32-register-hot-key", "w32-registered-hot-keys", + "w32-selection-exists-p", "w32-send-sys-command", + "w32-set-clipboard-data", "w32-set-console-codepage", + "w32-set-console-output-codepage", "w32-set-current-locale", + "w32-set-keyboard-layout", "w32-set-process-priority", + "w32-shell-execute", "w32-short-file-name", "w32-toggle-lock-key", + "w32-unload-winsock", "w32-unregister-hot-key", "w32-window-exists-p", + "w32notify-add-watch", "w32notify-rm-watch", + "waiting-for-user-input-p", "where-is-internal", "widen", + "widget-apply", "widget-get", "widget-put", + "window-absolute-pixel-edges", "window-at", "window-body-height", + "window-body-width", "window-bottom-divider-width", "window-buffer", + "window-combination-limit", "window-configuration-frame", + "window-configuration-p", "window-dedicated-p", + "window-display-table", "window-edges", "window-end", "window-frame", + "window-fringes", "window-header-line-height", "window-hscroll", + "window-inside-absolute-pixel-edges", "window-inside-edges", + "window-inside-pixel-edges", "window-left-child", + "window-left-column", "window-line-height", "window-list", + "window-list-1", "window-live-p", "window-margins", + "window-minibuffer-p", "window-mode-line-height", "window-new-normal", + "window-new-pixel", "window-new-total", "window-next-buffers", + "window-next-sibling", "window-normal-size", "window-old-point", + "window-parameter", "window-parameters", "window-parent", + "window-pixel-edges", "window-pixel-height", "window-pixel-left", + "window-pixel-top", "window-pixel-width", "window-point", + "window-prev-buffers", "window-prev-sibling", + "window-redisplay-end-trigger", "window-resize-apply", + "window-resize-apply-total", "window-right-divider-width", + "window-scroll-bar-height", "window-scroll-bar-width", + "window-scroll-bars", "window-start", "window-system", + "window-text-height", "window-text-pixel-size", "window-text-width", + "window-top-child", "window-top-line", "window-total-height", + "window-total-width", "window-use-time", "window-valid-p", + "window-vscroll", "windowp", "write-char", "write-region", + "x-backspace-delete-keys-p", "x-change-window-property", + "x-change-window-property", "x-close-connection", + "x-close-connection", "x-create-frame", "x-create-frame", + "x-delete-window-property", "x-delete-window-property", + "x-disown-selection-internal", "x-display-backing-store", + "x-display-backing-store", "x-display-color-cells", + "x-display-color-cells", "x-display-grayscale-p", + "x-display-grayscale-p", "x-display-list", "x-display-list", + "x-display-mm-height", "x-display-mm-height", "x-display-mm-width", + "x-display-mm-width", "x-display-monitor-attributes-list", + "x-display-pixel-height", "x-display-pixel-height", + "x-display-pixel-width", "x-display-pixel-width", "x-display-planes", + "x-display-planes", "x-display-save-under", "x-display-save-under", + "x-display-screens", "x-display-screens", "x-display-visual-class", + "x-display-visual-class", "x-family-fonts", "x-file-dialog", + "x-file-dialog", "x-file-dialog", "x-focus-frame", "x-frame-geometry", + "x-frame-geometry", "x-get-atom-name", "x-get-resource", + "x-get-selection-internal", "x-hide-tip", "x-hide-tip", + "x-list-fonts", "x-load-color-file", "x-menu-bar-open-internal", + "x-menu-bar-open-internal", "x-open-connection", "x-open-connection", + "x-own-selection-internal", "x-parse-geometry", "x-popup-dialog", + "x-popup-menu", "x-register-dnd-atom", "x-select-font", + "x-select-font", "x-selection-exists-p", "x-selection-owner-p", + "x-send-client-message", "x-server-max-request-size", + "x-server-max-request-size", "x-server-vendor", "x-server-vendor", + "x-server-version", "x-server-version", "x-show-tip", "x-show-tip", + "x-synchronize", "x-synchronize", "x-uses-old-gtk-dialog", + "x-window-property", "x-window-property", "x-wm-set-size-hint", + "xw-color-defined-p", "xw-color-defined-p", "xw-color-values", + "xw-color-values", "xw-display-color-p", "xw-display-color-p", + "yes-or-no-p", "zlib-available-p", "zlib-decompress-region", + "forward-point", + } + + emacsBuiltinFunctionHighlighted = []string{ + "defvaralias", "provide", "require", + "with-no-warnings", "define-widget", "with-electric-help", + "throw", "defalias", "featurep", + } + + emacsLambdaListKeywords = []string{ + "&allow-other-keys", "&aux", "&body", "&environment", "&key", "&optional", + "&rest", "&whole", + } + + emacsErrorKeywords = []string{ + "cl-assert", "cl-check-type", "error", "signal", + "user-error", "warn", + } +) + +// EmacsLisp lexer. +var EmacsLisp = Register(TypeRemappingLexer(MustNewXMLLexer( + embedded, + "embedded/emacslisp.xml", +), TypeMapping{ + {NameVariable, NameFunction, emacsBuiltinFunction}, + {NameVariable, NameBuiltin, emacsSpecialForms}, + {NameVariable, NameException, emacsErrorKeywords}, + {NameVariable, NameBuiltin, append(emacsBuiltinFunctionHighlighted, emacsMacros...)}, + {NameVariable, KeywordPseudo, emacsLambdaListKeywords}, +})) diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/abap.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/abap.xml new file mode 100644 index 000000000..e8140b738 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/abap.xml @@ -0,0 +1,154 @@ + + + ABAP + abap + *.abap + *.ABAP + text/x-abap + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/abnf.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/abnf.xml new file mode 100644 index 000000000..3ffd51c6c --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/abnf.xml @@ -0,0 +1,66 @@ + + + ABNF + abnf + *.abnf + text/x-abnf + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/actionscript.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/actionscript.xml new file mode 100644 index 000000000..d6727a103 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/actionscript.xml @@ -0,0 +1,68 @@ + + + ActionScript + as + actionscript + *.as + application/x-actionscript + text/x-actionscript + text/actionscript + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/actionscript_3.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/actionscript_3.xml new file mode 100644 index 000000000..e5f653848 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/actionscript_3.xml @@ -0,0 +1,163 @@ + + + ActionScript 3 + as3 + actionscript3 + *.as + application/x-actionscript3 + text/x-actionscript3 + text/actionscript3 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ada.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ada.xml new file mode 100644 index 000000000..5854a20e9 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ada.xml @@ -0,0 +1,321 @@ + + + Ada + ada + ada95 + ada2005 + *.adb + *.ads + *.ada + text/x-ada + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/agda.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/agda.xml new file mode 100644 index 000000000..6f2b2d508 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/agda.xml @@ -0,0 +1,66 @@ + + + Agda + agda + *.agda + text/x-agda + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/al.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/al.xml new file mode 100644 index 000000000..30bad5ae9 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/al.xml @@ -0,0 +1,75 @@ + + + AL + al + *.al + *.dal + text/x-al + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/alloy.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/alloy.xml new file mode 100644 index 000000000..1de9ea6cc --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/alloy.xml @@ -0,0 +1,58 @@ + + + + Alloy + alloy + *.als + text/x-alloy + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/angular2.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/angular2.xml new file mode 100644 index 000000000..230ef868c --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/angular2.xml @@ -0,0 +1,109 @@ + + + Angular2 + ng2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/antlr.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/antlr.xml new file mode 100644 index 000000000..e57edd404 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/antlr.xml @@ -0,0 +1,317 @@ + + + ANTLR + antlr + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/apacheconf.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/apacheconf.xml new file mode 100644 index 000000000..7643541c1 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/apacheconf.xml @@ -0,0 +1,74 @@ + + + ApacheConf + apacheconf + aconf + apache + .htaccess + apache.conf + apache2.conf + text/x-apacheconf + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/apl.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/apl.xml new file mode 100644 index 000000000..959448ca4 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/apl.xml @@ -0,0 +1,59 @@ + + + APL + apl + *.apl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/applescript.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/applescript.xml new file mode 100644 index 000000000..5a6224ac0 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/applescript.xml @@ -0,0 +1,151 @@ + + + AppleScript + applescript + *.applescript + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/arangodb_aql.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/arangodb_aql.xml new file mode 100644 index 000000000..434b395a1 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/arangodb_aql.xml @@ -0,0 +1,174 @@ + + + ArangoDB AQL + aql + *.aql + text/x-aql + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/arduino.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/arduino.xml new file mode 100644 index 000000000..6a75df5b9 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/arduino.xml @@ -0,0 +1,322 @@ + + + Arduino + arduino + *.ino + text/x-arduino + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/armasm.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/armasm.xml new file mode 100644 index 000000000..340278d37 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/armasm.xml @@ -0,0 +1,126 @@ + + + ArmAsm + armasm + *.s + *.S + text/x-armasm + text/x-asm + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/atl.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/atl.xml new file mode 100644 index 000000000..623dc205e --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/atl.xml @@ -0,0 +1,165 @@ + + + ATL + atl + *.atl + text/x-atl + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/autohotkey.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/autohotkey.xml new file mode 100644 index 000000000..6ec94edeb --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/autohotkey.xml @@ -0,0 +1,78 @@ + + + + AutoHotkey + autohotkey + ahk + *.ahk + *.ahkl + text/x-autohotkey + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/autoit.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/autoit.xml new file mode 100644 index 000000000..1f7e15df3 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/autoit.xml @@ -0,0 +1,70 @@ + + + + AutoIt + autoit + *.au3 + text/x-autoit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/awk.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/awk.xml new file mode 100644 index 000000000..07476ff74 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/awk.xml @@ -0,0 +1,95 @@ + + + Awk + awk + gawk + mawk + nawk + *.awk + application/x-awk + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ballerina.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ballerina.xml new file mode 100644 index 000000000..d13c12319 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ballerina.xml @@ -0,0 +1,97 @@ + + + Ballerina + ballerina + *.bal + text/x-ballerina + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bash.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bash.xml new file mode 100644 index 000000000..6163cc613 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bash.xml @@ -0,0 +1,222 @@ + + + Bash + bash + sh + ksh + zsh + shell + *.sh + *.ksh + *.bash + *.ebuild + *.eclass + .env + .env.* + *.env + *.exheres-0 + *.exlib + *.zsh + *.zshrc + .bashrc + bashrc + .bash_* + bash_* + zshrc + .zshrc + APKBUILD + PKGBUILD + application/x-sh + application/x-shellscript + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bash_session.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bash_session.xml new file mode 100644 index 000000000..82c5fd6d0 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bash_session.xml @@ -0,0 +1,25 @@ + + + Bash Session + bash-session + console + shell-session + *.sh-session + text/x-sh + true + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/batchfile.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/batchfile.xml new file mode 100644 index 000000000..d3e062728 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/batchfile.xml @@ -0,0 +1,660 @@ + + + Batchfile + bat + batch + dosbatch + winbatch + *.bat + *.cmd + application/x-dos-batch + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/beef.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/beef.xml new file mode 100644 index 000000000..031a220f2 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/beef.xml @@ -0,0 +1,120 @@ + + + Beef + beef + *.bf + text/x-beef + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bibtex.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bibtex.xml new file mode 100644 index 000000000..8fde161b3 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bibtex.xml @@ -0,0 +1,152 @@ + + + BibTeX + bib + bibtex + *.bib + text/x-bibtex + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bicep.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bicep.xml new file mode 100644 index 000000000..db90f31b3 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bicep.xml @@ -0,0 +1,84 @@ + + + Bicep + bicep + *.bicep + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/blitzbasic.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/blitzbasic.xml new file mode 100644 index 000000000..591b1ad0f --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/blitzbasic.xml @@ -0,0 +1,141 @@ + + + BlitzBasic + blitzbasic + b3d + bplus + *.bb + *.decls + text/x-bb + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bnf.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bnf.xml new file mode 100644 index 000000000..5c9842477 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bnf.xml @@ -0,0 +1,28 @@ + + + BNF + bnf + *.bnf + text/x-bnf + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bqn.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bqn.xml new file mode 100644 index 000000000..c1090ea5a --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bqn.xml @@ -0,0 +1,83 @@ + + + BQN + bqn + *.bqn + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/brainfuck.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/brainfuck.xml new file mode 100644 index 000000000..4c84c3308 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/brainfuck.xml @@ -0,0 +1,51 @@ + + + Brainfuck + brainfuck + bf + *.bf + *.b + application/x-brainfuck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/c#.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/c#.xml new file mode 100644 index 000000000..f1e21db03 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/c#.xml @@ -0,0 +1,121 @@ + + + C# + csharp + c# + *.cs + text/x-csharp + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/c++.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/c++.xml new file mode 100644 index 000000000..680a19afb --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/c++.xml @@ -0,0 +1,331 @@ + + + C++ + cpp + c++ + *.cpp + *.hpp + *.c++ + *.h++ + *.cc + *.hh + *.cxx + *.hxx + *.C + *.H + *.cp + *.CPP + *.tpp + text/x-c++hdr + text/x-c++src + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/c.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/c.xml new file mode 100644 index 000000000..35ee32dce --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/c.xml @@ -0,0 +1,260 @@ + + + C + c + *.c + *.h + *.idc + *.x[bp]m + text/x-chdr + text/x-csrc + image/x-xbitmap + image/x-xpixmap + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/c3.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/c3.xml new file mode 100644 index 000000000..8094ce4b8 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/c3.xml @@ -0,0 +1,374 @@ + + + C3 + c3 + *.c3 + *.c3i + *.c3t + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cap_n_proto.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cap_n_proto.xml new file mode 100644 index 000000000..3e7d1470b --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cap_n_proto.xml @@ -0,0 +1,122 @@ + + + Cap'n Proto + capnp + *.capnp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cassandra_cql.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cassandra_cql.xml new file mode 100644 index 000000000..1a78f99a1 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cassandra_cql.xml @@ -0,0 +1,137 @@ + + + Cassandra CQL + cassandra + cql + *.cql + text/x-cql + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + 6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ceylon.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ceylon.xml new file mode 100644 index 000000000..4c4121835 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ceylon.xml @@ -0,0 +1,151 @@ + + + Ceylon + ceylon + *.ceylon + text/x-ceylon + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cfengine3.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cfengine3.xml new file mode 100644 index 000000000..495030505 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cfengine3.xml @@ -0,0 +1,197 @@ + + + CFEngine3 + cfengine3 + cf3 + *.cf + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cfstatement.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cfstatement.xml new file mode 100644 index 000000000..46a84cf6a --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cfstatement.xml @@ -0,0 +1,92 @@ + + + cfstatement + cfs + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/chaiscript.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/chaiscript.xml new file mode 100644 index 000000000..860439aa8 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/chaiscript.xml @@ -0,0 +1,134 @@ + + + ChaiScript + chai + chaiscript + *.chai + text/x-chaiscript + application/x-chaiscript + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/chapel.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/chapel.xml new file mode 100644 index 000000000..c89cafc6a --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/chapel.xml @@ -0,0 +1,143 @@ + + + Chapel + chapel + chpl + *.chpl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cheetah.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cheetah.xml new file mode 100644 index 000000000..284457c6c --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cheetah.xml @@ -0,0 +1,55 @@ + + + Cheetah + cheetah + spitfire + *.tmpl + *.spt + application/x-cheetah + application/x-spitfire + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/clojure.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/clojure.xml new file mode 100644 index 000000000..967ba399c --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/clojure.xml @@ -0,0 +1,71 @@ + + + Clojure + clojure + clj + edn + *.clj + *.edn + text/x-clojure + application/x-clojure + application/edn + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cmake.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cmake.xml new file mode 100644 index 000000000..b041cfd01 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cmake.xml @@ -0,0 +1,90 @@ + + + CMake + cmake + *.cmake + CMakeLists.txt + text/x-cmake + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cobol.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cobol.xml new file mode 100644 index 000000000..a8a80291d --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cobol.xml @@ -0,0 +1,90 @@ + + + COBOL + cobol + *.cob + *.COB + *.cpy + *.CPY + text/x-cobol + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/coffeescript.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/coffeescript.xml new file mode 100644 index 000000000..e29722fb8 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/coffeescript.xml @@ -0,0 +1,210 @@ + + + CoffeeScript + coffee-script + coffeescript + coffee + *.coffee + text/coffeescript + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/common_lisp.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/common_lisp.xml new file mode 100644 index 000000000..0fb9a7a4b --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/common_lisp.xml @@ -0,0 +1,184 @@ + + + Common Lisp + common-lisp + cl + lisp + *.cl + *.lisp + text/x-common-lisp + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/coq.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/coq.xml new file mode 100644 index 000000000..62f64ff99 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/coq.xml @@ -0,0 +1,136 @@ + + + Coq + coq + *.v + text/x-coq + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/core.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/core.xml new file mode 100644 index 000000000..f0a9d2905 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/core.xml @@ -0,0 +1,79 @@ + + + Core + core + *.core + text/x-core + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/crystal.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/crystal.xml new file mode 100644 index 000000000..94853db33 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/crystal.xml @@ -0,0 +1,762 @@ + + + Crystal + cr + crystal + *.cr + text/x-crystal + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/css.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/css.xml new file mode 100644 index 000000000..adc13c75a --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/css.xml @@ -0,0 +1,323 @@ + + + CSS + css + *.css + text/css + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/csv.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/csv.xml new file mode 100644 index 000000000..b70c2f8b1 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/csv.xml @@ -0,0 +1,53 @@ + + + + + CSV + csv + *.csv + text/csv + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cue.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cue.xml new file mode 100644 index 000000000..2a12f3953 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cue.xml @@ -0,0 +1,85 @@ + + + CUE + cue + *.cue + text/x-cue + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cython.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cython.xml new file mode 100644 index 000000000..15dfe4d4f --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cython.xml @@ -0,0 +1,372 @@ + + + Cython + cython + pyx + pyrex + *.pyx + *.pxd + *.pxi + text/x-cython + application/x-cython + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/d.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/d.xml new file mode 100644 index 000000000..19c85e2c8 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/d.xml @@ -0,0 +1,133 @@ + + + D + d + *.d + *.di + text/x-d + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dart.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dart.xml new file mode 100644 index 000000000..f1b454faf --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dart.xml @@ -0,0 +1,213 @@ + + + Dart + dart + *.dart + text/x-dart + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dax.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dax.xml new file mode 100644 index 000000000..2bb3a1aa7 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dax.xml @@ -0,0 +1,39 @@ + + + Dax + dax + *.dax + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/desktop_entry.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/desktop_entry.xml new file mode 100644 index 000000000..ad71ad471 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/desktop_entry.xml @@ -0,0 +1,17 @@ + + + Desktop file + desktop + desktop_entry + *.desktop + application/x-desktop + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/devicetree.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/devicetree.xml new file mode 100644 index 000000000..2db54ddc5 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/devicetree.xml @@ -0,0 +1,251 @@ + + + Devicetree + devicetree + dts + *.dts + *.dtsi + text/x-devicetree + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/diff.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/diff.xml new file mode 100644 index 000000000..dc0beb7fd --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/diff.xml @@ -0,0 +1,52 @@ + + + Diff + diff + udiff + *.diff + *.patch + text/x-diff + text/x-patch + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/django_jinja.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/django_jinja.xml new file mode 100644 index 000000000..3c97c222e --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/django_jinja.xml @@ -0,0 +1,153 @@ + + + Django/Jinja + django + jinja + application/x-django-templating + application/x-jinja + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dns.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dns.xml new file mode 100644 index 000000000..ef8f663f9 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dns.xml @@ -0,0 +1,44 @@ + + + + dns + zone + bind + *.zone + text/dns + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/docker.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/docker.xml new file mode 100644 index 000000000..261834f42 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/docker.xml @@ -0,0 +1,68 @@ + + + Docker + docker + dockerfile + containerfile + Dockerfile + Dockerfile.* + *.Dockerfile + *.docker + Containerfile + Containerfile.* + *.Containerfile + text/x-dockerfile-config + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dtd.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dtd.xml new file mode 100644 index 000000000..0edbbdeac --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dtd.xml @@ -0,0 +1,168 @@ + + + DTD + dtd + *.dtd + application/xml-dtd + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dylan.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dylan.xml new file mode 100644 index 000000000..3660d1440 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dylan.xml @@ -0,0 +1,176 @@ + + + Dylan + dylan + *.dylan + *.dyl + *.intr + text/x-dylan + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ebnf.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ebnf.xml new file mode 100644 index 000000000..df5d62ffa --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ebnf.xml @@ -0,0 +1,90 @@ + + + EBNF + ebnf + *.ebnf + text/x-ebnf + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/elixir.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/elixir.xml new file mode 100644 index 000000000..286f53a24 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/elixir.xml @@ -0,0 +1,744 @@ + + + Elixir + elixir + ex + exs + *.ex + *.eex + *.exs + text/x-elixir + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/elm.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/elm.xml new file mode 100644 index 000000000..ed65efc63 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/elm.xml @@ -0,0 +1,119 @@ + + + Elm + elm + *.elm + text/x-elm + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/emacslisp.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/emacslisp.xml new file mode 100644 index 000000000..668bc621e --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/emacslisp.xml @@ -0,0 +1,132 @@ + + + EmacsLisp + emacs + elisp + emacs-lisp + *.el + text/x-elisp + application/x-elisp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/erlang.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/erlang.xml new file mode 100644 index 000000000..b18658868 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/erlang.xml @@ -0,0 +1,166 @@ + + + Erlang + erlang + *.erl + *.hrl + *.es + *.escript + text/x-erlang + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/factor.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/factor.xml new file mode 100644 index 000000000..4743b9a2e --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/factor.xml @@ -0,0 +1,412 @@ + + + Factor + factor + *.factor + text/x-factor + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/fennel.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/fennel.xml new file mode 100644 index 000000000..b9b6d5950 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/fennel.xml @@ -0,0 +1,68 @@ + + + Fennel + fennel + fnl + *.fennel + text/x-fennel + application/x-fennel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/fish.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/fish.xml new file mode 100644 index 000000000..deb78145e --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/fish.xml @@ -0,0 +1,159 @@ + + + Fish + fish + fishshell + *.fish + *.load + application/x-fish + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/forth.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/forth.xml new file mode 100644 index 000000000..31096a225 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/forth.xml @@ -0,0 +1,78 @@ + + + Forth + forth + *.frt + *.fth + *.fs + application/x-forth + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/fortran.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/fortran.xml new file mode 100644 index 000000000..6140e7041 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/fortran.xml @@ -0,0 +1,102 @@ + + + Fortran + fortran + f90 + *.f03 + *.f90 + *.f95 + *.F03 + *.F90 + *.F95 + text/x-fortran + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/fortranfixed.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/fortranfixed.xml new file mode 100644 index 000000000..11343c0e7 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/fortranfixed.xml @@ -0,0 +1,71 @@ + + + FortranFixed + fortranfixed + *.f + *.F + text/x-fortran + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/fsharp.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/fsharp.xml new file mode 100644 index 000000000..e1c19ffb4 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/fsharp.xml @@ -0,0 +1,245 @@ + + + FSharp + fsharp + *.fs + *.fsi + text/x-fsharp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gas.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gas.xml new file mode 100644 index 000000000..7557bce0f --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gas.xml @@ -0,0 +1,150 @@ + + + GAS + gas + asm + *.s + *.S + text/x-gas + 0.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gdscript.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gdscript.xml new file mode 100644 index 000000000..811f38d02 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gdscript.xml @@ -0,0 +1,259 @@ + + + GDScript + gdscript + gd + *.gd + text/x-gdscript + application/x-gdscript + 0.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gdscript3.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gdscript3.xml new file mode 100644 index 000000000..b50c9dd7b --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gdscript3.xml @@ -0,0 +1,270 @@ + + + GDScript3 + gdscript3 + gd3 + *.gd + text/x-gdscript + application/x-gdscript + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gherkin.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gherkin.xml new file mode 100644 index 000000000..c53a2cbb5 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gherkin.xml @@ -0,0 +1,263 @@ + + + Gherkin + cucumber + Cucumber + gherkin + Gherkin + *.feature + *.FEATURE + text/x-gherkin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gleam.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gleam.xml new file mode 100644 index 000000000..396632203 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gleam.xml @@ -0,0 +1,100 @@ + + + Gleam + gleam + *.gleam + text/x-gleam + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/glsl.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/glsl.xml new file mode 100644 index 000000000..ca0b696de --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/glsl.xml @@ -0,0 +1,65 @@ + + + GLSL + glsl + *.vert + *.frag + *.geo + text/x-glslsrc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gnuplot.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gnuplot.xml new file mode 100644 index 000000000..ee6a245f3 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gnuplot.xml @@ -0,0 +1,289 @@ + + + Gnuplot + gnuplot + *.plot + *.plt + text/x-gnuplot + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/go_template.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/go_template.xml new file mode 100644 index 000000000..36f737b93 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/go_template.xml @@ -0,0 +1,114 @@ + + + Go Template + go-template + *.gotmpl + *.go.tmpl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/graphql.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/graphql.xml new file mode 100644 index 000000000..b06227357 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/graphql.xml @@ -0,0 +1,88 @@ + + + GraphQL + graphql + graphqls + gql + *.graphql + *.graphqls + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/groff.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/groff.xml new file mode 100644 index 000000000..3af0a43e7 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/groff.xml @@ -0,0 +1,90 @@ + + + Groff + groff + nroff + man + *.[1-9] + *.1p + *.3pm + *.man + application/x-troff + text/troff + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/groovy.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/groovy.xml new file mode 100644 index 000000000..3cca2e9a5 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/groovy.xml @@ -0,0 +1,135 @@ + + + Groovy + groovy + *.groovy + *.gradle + text/x-groovy + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/handlebars.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/handlebars.xml new file mode 100644 index 000000000..7cf2a648a --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/handlebars.xml @@ -0,0 +1,147 @@ + + + Handlebars + handlebars + hbs + *.handlebars + *.hbs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hare.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hare.xml new file mode 100644 index 000000000..c1f7e9433 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hare.xml @@ -0,0 +1,98 @@ + + + Hare + hare + *.ha + text/x-hare + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/haskell.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/haskell.xml new file mode 100644 index 000000000..1fad08231 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/haskell.xml @@ -0,0 +1,275 @@ + + + Haskell + haskell + hs + *.hs + text/x-haskell + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hcl.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hcl.xml new file mode 100644 index 000000000..d3ed208af --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hcl.xml @@ -0,0 +1,143 @@ + + + HCL + hcl + *.hcl + application/x-hcl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hexdump.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hexdump.xml new file mode 100644 index 000000000..a6f28eab1 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hexdump.xml @@ -0,0 +1,189 @@ + + + Hexdump + hexdump + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hlb.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hlb.xml new file mode 100644 index 000000000..9723fd9c2 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hlb.xml @@ -0,0 +1,131 @@ + + + HLB + hlb + *.hlb + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hlsl.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hlsl.xml new file mode 100644 index 000000000..41ab32395 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hlsl.xml @@ -0,0 +1,110 @@ + + + HLSL + hlsl + *.hlsl + *.hlsli + *.cginc + *.fx + *.fxh + text/x-hlsl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/holyc.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/holyc.xml new file mode 100644 index 000000000..cd2d9d16b --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/holyc.xml @@ -0,0 +1,252 @@ + + + HolyC + holyc + *.HC + *.hc + *.HH + *.hh + *.hc.z + *.HC.Z + text/x-chdr + text/x-csrc + image/x-xbitmap + image/x-xpixmap + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/html.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/html.xml new file mode 100644 index 000000000..2f1a8a979 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/html.xml @@ -0,0 +1,159 @@ + + + HTML + html + *.html + *.htm + *.xhtml + *.xslt + text/html + application/xhtml+xml + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hy.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hy.xml new file mode 100644 index 000000000..a0dae46ae --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hy.xml @@ -0,0 +1,104 @@ + + + Hy + hylang + *.hy + text/x-hy + application/x-hy + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/idris.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/idris.xml new file mode 100644 index 000000000..9592d8822 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/idris.xml @@ -0,0 +1,216 @@ + + + Idris + idris + idr + *.idr + text/x-idris + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/igor.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/igor.xml new file mode 100644 index 000000000..1cc020570 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/igor.xml @@ -0,0 +1,47 @@ + + + Igor + igor + igorpro + *.ipf + text/ipf + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ini.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ini.xml new file mode 100644 index 000000000..3f1de09cb --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ini.xml @@ -0,0 +1,52 @@ + + + INI + ini + cfg + dosini + *.ini + *.cfg + *.inf + *.service + *.socket + *.container + *.network + *.build + *.pod + *.kube + *.volume + *.image + .gitconfig + .editorconfig + pylintrc + .pylintrc + text/x-ini + text/inf + 0.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/io.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/io.xml new file mode 100644 index 000000000..9ad94fa52 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/io.xml @@ -0,0 +1,71 @@ + + + Io + io + *.io + text/x-iosrc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/iscdhcpd.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/iscdhcpd.xml new file mode 100644 index 000000000..645cb05d5 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/iscdhcpd.xml @@ -0,0 +1,96 @@ + + + ISCdhcpd + iscdhcpd + dhcpd.conf + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/j.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/j.xml new file mode 100644 index 000000000..872d08122 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/j.xml @@ -0,0 +1,157 @@ + + + J + j + *.ijs + text/x-j + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/janet.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/janet.xml new file mode 100644 index 000000000..fe139e856 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/janet.xml @@ -0,0 +1,48 @@ + + + + Janet + janet + *.janet + *.jdn + text/x-janet + application/x-janet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/java.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/java.xml new file mode 100644 index 000000000..3ce33ff6d --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/java.xml @@ -0,0 +1,193 @@ + + + Java + java + *.java + text/x-java + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/javascript.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/javascript.xml new file mode 100644 index 000000000..efe80ed37 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/javascript.xml @@ -0,0 +1,160 @@ + + + JavaScript + js + javascript + *.js + *.jsm + *.mjs + *.cjs + application/javascript + application/x-javascript + text/x-javascript + text/javascript + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/json.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/json.xml new file mode 100644 index 000000000..a34abfa49 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/json.xml @@ -0,0 +1,112 @@ + + + JSON + json + *.json + *.jsonc + *.avsc + application/json + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/jsonata.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/jsonata.xml new file mode 100644 index 000000000..c0eafabe3 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/jsonata.xml @@ -0,0 +1,83 @@ + + + JSONata + jsonata + *.jsonata + true + + + + + + + + + + // Spread operator + + + // Sort operator + + + // Descendant | Wildcard | Multiplication + + + // Division + + + // Comparison operators + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/jsonnet.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/jsonnet.xml new file mode 100644 index 000000000..1633a5e40 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/jsonnet.xml @@ -0,0 +1,138 @@ + + + + Jsonnet + jsonnet + *.jsonnet + *.libsonnet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/julia.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/julia.xml new file mode 100644 index 000000000..776dcdbcb --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/julia.xml @@ -0,0 +1,400 @@ + + + Julia + julia + jl + *.jl + text/x-julia + application/x-julia + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/jungle.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/jungle.xml new file mode 100644 index 000000000..92c785d0c --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/jungle.xml @@ -0,0 +1,98 @@ + + + Jungle + jungle + *.jungle + text/x-jungle + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/kakoune.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/kakoune.xml new file mode 100644 index 000000000..afc048960 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/kakoune.xml @@ -0,0 +1,96 @@ + + + + Kakoune + kak + kakoune + kakrc + kakscript + *.kak + kakrc + application/x-sh + application/x-shellscript + text/x-shellscript + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/kdl.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/kdl.xml new file mode 100644 index 000000000..bc6ebfb80 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/kdl.xml @@ -0,0 +1,75 @@ + + + KDL + kdl + *.kdl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/kotlin.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/kotlin.xml new file mode 100644 index 000000000..28bf2d8ba --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/kotlin.xml @@ -0,0 +1,234 @@ + + + Kotlin + kotlin + *.kt + *.kts + text/x-kotlin + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lean.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lean.xml new file mode 100644 index 000000000..6ac5151bb --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lean.xml @@ -0,0 +1,56 @@ + + + Lean4 + lean4 + lean + *.lean + text/x-lean4 + text/x-lean + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lighttpd_configuration_file.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lighttpd_configuration_file.xml new file mode 100644 index 000000000..1319e5c83 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lighttpd_configuration_file.xml @@ -0,0 +1,42 @@ + + + Lighttpd configuration file + lighty + lighttpd + text/x-lighttpd-conf + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/llvm.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/llvm.xml new file mode 100644 index 000000000..f24f1522b --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/llvm.xml @@ -0,0 +1,73 @@ + + + LLVM + llvm + *.ll + text/x-llvm + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lox.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lox.xml new file mode 100644 index 000000000..8dec0a856 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lox.xml @@ -0,0 +1,78 @@ + + + lox + *.lox + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lua.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lua.xml new file mode 100644 index 000000000..e3d778f12 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lua.xml @@ -0,0 +1,160 @@ + + + Lua + lua + luau + *.lua + *.wlua + *.luau + text/x-lua + application/x-lua + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/makefile.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/makefile.xml new file mode 100644 index 000000000..a82a7f8d5 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/makefile.xml @@ -0,0 +1,131 @@ + + + Makefile + make + makefile + mf + bsdmake + *.mak + *.mk + Makefile + makefile + Makefile.* + GNUmakefile + BSDmakefile + Justfile + justfile + .justfile + text/x-makefile + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mako.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mako.xml new file mode 100644 index 000000000..782414087 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mako.xml @@ -0,0 +1,120 @@ + + + Mako + mako + *.mao + application/x-mako + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mason.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mason.xml new file mode 100644 index 000000000..5873f2afc --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mason.xml @@ -0,0 +1,89 @@ + + + Mason + mason + *.m + *.mhtml + *.mc + *.mi + autohandler + dhandler + application/x-mason + 0.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/materialize_sql_dialect.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/materialize_sql_dialect.xml new file mode 100644 index 000000000..7094ddc3e --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/materialize_sql_dialect.xml @@ -0,0 +1,155 @@ + + + Materialize SQL dialect + text/x-materializesql + true + true + materialize + mzsql + + + + + + + + + + + + + + + + + + + 6 + 12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 12 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mathematica.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mathematica.xml new file mode 100644 index 000000000..0b8dfb617 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mathematica.xml @@ -0,0 +1,60 @@ + + + Mathematica + mathematica + mma + nb + *.cdf + *.m + *.ma + *.mt + *.mx + *.nb + *.nbp + *.wl + application/mathematica + application/vnd.wolfram.mathematica + application/vnd.wolfram.mathematica.package + application/vnd.wolfram.cdf + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/matlab.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/matlab.xml new file mode 100644 index 000000000..ebb4e2c33 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/matlab.xml @@ -0,0 +1,114 @@ + + + Matlab + matlab + *.m + text/matlab + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mcfunction.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mcfunction.xml new file mode 100644 index 000000000..a6aa6dbe8 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mcfunction.xml @@ -0,0 +1,138 @@ + + + + MCFunction + mcfunction + mcf + *.mcfunction + text/mcfunction + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/meson.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/meson.xml new file mode 100644 index 000000000..130047df6 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/meson.xml @@ -0,0 +1,85 @@ + + + Meson + meson + meson.build + meson.build + meson_options.txt + text/x-meson + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/metal.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/metal.xml new file mode 100644 index 000000000..62d04ba84 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/metal.xml @@ -0,0 +1,270 @@ + + + Metal + metal + *.metal + text/x-metal + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/microcad.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/microcad.xml new file mode 100644 index 000000000..6de71ef0a --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/microcad.xml @@ -0,0 +1,139 @@ + + + microcad + µcad + *.µcad + *.ucad + *.mcad + text/microcad + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/minizinc.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/minizinc.xml new file mode 100644 index 000000000..1ad6860f4 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/minizinc.xml @@ -0,0 +1,82 @@ + + + MiniZinc + minizinc + MZN + mzn + *.mzn + *.dzn + *.fzn + text/minizinc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mlir.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mlir.xml new file mode 100644 index 000000000..025c3dc56 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mlir.xml @@ -0,0 +1,73 @@ + + + MLIR + mlir + *.mlir + text/x-mlir + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/modelica.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/modelica.xml new file mode 100644 index 000000000..e5fa60f99 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/modelica.xml @@ -0,0 +1,106 @@ + + + Modelica + modelica + *.mo + text/x-modelica + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/modula-2.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/modula-2.xml new file mode 100644 index 000000000..0bf37bcc3 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/modula-2.xml @@ -0,0 +1,245 @@ + + + Modula-2 + modula2 + m2 + *.def + *.mod + text/x-modula2 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mojo.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mojo.xml new file mode 100644 index 000000000..677811eb1 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mojo.xml @@ -0,0 +1,228 @@ + + + Mojo + mojo + 🔥 + *.mojo + *.🔥 + text/x-mojo + application/x-mojo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/monkeyc.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/monkeyc.xml new file mode 100644 index 000000000..7445a639d --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/monkeyc.xml @@ -0,0 +1,153 @@ + + + MonkeyC + monkeyc + *.mc + text/x-monkeyc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/moonbit.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/moonbit.xml new file mode 100644 index 000000000..846e724dc --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/moonbit.xml @@ -0,0 +1,75 @@ + + + MoonBit + moonbit + mbt + *.mbt + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/moonscript.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/moonscript.xml new file mode 100644 index 000000000..293f538cd --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/moonscript.xml @@ -0,0 +1,83 @@ + + + + MoonScript + moonscript + moon + *.moon + text/x-moonscript + application/x-moonscript + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/morrowindscript.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/morrowindscript.xml new file mode 100644 index 000000000..724a19fc6 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/morrowindscript.xml @@ -0,0 +1,90 @@ + + + MorrowindScript + morrowind + mwscript + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/myghty.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/myghty.xml new file mode 100644 index 000000000..6d03917e5 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/myghty.xml @@ -0,0 +1,77 @@ + + + Myghty + myghty + *.myt + autodelegate + application/x-myghty + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mysql.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mysql.xml new file mode 100644 index 000000000..b6c2046d5 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mysql.xml @@ -0,0 +1,121 @@ + + + MySQL + mysql + mariadb + *.sql + text/x-mysql + text/x-mariadb + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nasm.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nasm.xml new file mode 100644 index 000000000..defe65b3c --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nasm.xml @@ -0,0 +1,126 @@ + + + NASM + nasm + *.asm + *.ASM + *.nasm + text/x-nasm + true + 1.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/natural.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/natural.xml new file mode 100644 index 000000000..707252b4c --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/natural.xml @@ -0,0 +1,143 @@ + + + Natural + natural + *.NSN + *.NSP + *.NSS + *.NSH + *.NSG + *.NSL + *.NSA + *.NSM + *.NSC + *.NS7 + text/x-natural + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ndisasm.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ndisasm.xml new file mode 100644 index 000000000..74d443b64 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ndisasm.xml @@ -0,0 +1,123 @@ + + + NDISASM + ndisasm + text/x-disasm + true + 0.5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/newspeak.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/newspeak.xml new file mode 100644 index 000000000..b93265706 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/newspeak.xml @@ -0,0 +1,121 @@ + + + Newspeak + newspeak + *.ns2 + text/x-newspeak + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nginx_configuration_file.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nginx_configuration_file.xml new file mode 100644 index 000000000..a80d04993 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nginx_configuration_file.xml @@ -0,0 +1,101 @@ + + + Nginx configuration file + nginx + nginx.conf + text/x-nginx-conf + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nim.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nim.xml new file mode 100644 index 000000000..bfdd6156a --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nim.xml @@ -0,0 +1,211 @@ + + + Nim + nim + nimrod + *.nim + *.nimrod + text/x-nim + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nix.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nix.xml new file mode 100644 index 000000000..dd54d36fd --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nix.xml @@ -0,0 +1,258 @@ + + + Nix + nixos + nix + *.nix + text/x-nix + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nsis.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nsis.xml new file mode 100644 index 000000000..6c3a7be96 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nsis.xml @@ -0,0 +1,59 @@ + + + NSIS + nsis + nsi + nsh + *.nsi + *.nsh + text/x-nsis + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nu.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nu.xml new file mode 100644 index 000000000..326558086 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nu.xml @@ -0,0 +1,121 @@ + + + Nu + nu + *.nu + text/plain + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/objective-c.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/objective-c.xml new file mode 100644 index 000000000..0dc932857 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/objective-c.xml @@ -0,0 +1,510 @@ + + + Objective-C + objective-c + objectivec + obj-c + objc + *.m + *.h + text/x-objective-c + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/objectpascal.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/objectpascal.xml new file mode 100644 index 000000000..0b7213121 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/objectpascal.xml @@ -0,0 +1,142 @@ + + + ObjectPascal + objectpascal + *.pas + *.pp + *.inc + *.dpr + *.dpk + *.lpr + *.lpk + text/x-pascal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ocaml.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ocaml.xml new file mode 100644 index 000000000..1770d1d15 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ocaml.xml @@ -0,0 +1,153 @@ + + + OCaml + ocaml + *.ml + *.mli + *.mll + *.mly + text/x-ocaml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/octave.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/octave.xml new file mode 100644 index 000000000..0515d2898 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/octave.xml @@ -0,0 +1,101 @@ + + + Octave + octave + *.m + text/octave + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/odin.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/odin.xml new file mode 100644 index 000000000..8a529497d --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/odin.xml @@ -0,0 +1,127 @@ + + + Odin + odin + *.odin + text/odin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/onesenterprise.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/onesenterprise.xml new file mode 100644 index 000000000..530bad70e --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/onesenterprise.xml @@ -0,0 +1,92 @@ + + + OnesEnterprise + ones + onesenterprise + 1S + 1S:Enterprise + *.EPF + *.epf + *.ERF + *.erf + application/octet-stream + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/openedge_abl.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/openedge_abl.xml new file mode 100644 index 000000000..04a80f3ce --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/openedge_abl.xml @@ -0,0 +1,101 @@ + + + OpenEdge ABL + openedge + abl + progress + openedgeabl + *.p + *.cls + *.w + *.i + text/x-openedge + application/x-openedge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/openscad.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/openscad.xml new file mode 100644 index 000000000..84d0fe135 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/openscad.xml @@ -0,0 +1,96 @@ + + + OpenSCAD + openscad + *.scad + text/x-scad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/org_mode.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/org_mode.xml new file mode 100644 index 000000000..259e54ef5 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/org_mode.xml @@ -0,0 +1,329 @@ + + + Org Mode + org + orgmode + *.org + text/org + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2 + 4 + + + + + + + + + + + + 2 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/pacmanconf.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/pacmanconf.xml new file mode 100644 index 000000000..caf723675 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/pacmanconf.xml @@ -0,0 +1,37 @@ + + + PacmanConf + pacmanconf + pacman.conf + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/perl.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/perl.xml new file mode 100644 index 000000000..8ac02ab40 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/perl.xml @@ -0,0 +1,400 @@ + + + Perl + perl + pl + *.pl + *.pm + *.t + text/x-perl + application/x-perl + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/php.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/php.xml new file mode 100644 index 000000000..c9e22ea57 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/php.xml @@ -0,0 +1,212 @@ + + + PHP + php + php3 + php4 + php5 + *.php + *.php[345] + *.inc + text/x-php + true + true + true + 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/pig.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/pig.xml new file mode 100644 index 000000000..5acd77399 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/pig.xml @@ -0,0 +1,105 @@ + + + Pig + pig + *.pig + text/x-pig + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/pkgconfig.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/pkgconfig.xml new file mode 100644 index 000000000..875dcba6a --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/pkgconfig.xml @@ -0,0 +1,73 @@ + + + PkgConfig + pkgconfig + *.pc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/pl_pgsql.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/pl_pgsql.xml new file mode 100644 index 000000000..e3e813ad5 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/pl_pgsql.xml @@ -0,0 +1,119 @@ + + + PL/pgSQL + plpgsql + text/x-plpgsql + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/plaintext.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/plaintext.xml new file mode 100644 index 000000000..d5e3243ee --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/plaintext.xml @@ -0,0 +1,21 @@ + + + plaintext + text + plain + no-highlight + *.txt + text/plain + -1 + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/plutus_core.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/plutus_core.xml new file mode 100644 index 000000000..4ff5a9703 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/plutus_core.xml @@ -0,0 +1,105 @@ + + + Plutus Core + plutus-core + plc + *.plc + text/x-plutus-core + application/x-plutus-core + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/pony.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/pony.xml new file mode 100644 index 000000000..4efa9db50 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/pony.xml @@ -0,0 +1,135 @@ + + + Pony + pony + *.pony + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/postgresql_sql_dialect.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/postgresql_sql_dialect.xml new file mode 100644 index 000000000..e901c1855 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/postgresql_sql_dialect.xml @@ -0,0 +1,155 @@ + + + PostgreSQL SQL dialect + postgresql + postgres + text/x-postgresql + true + true + + + + + + + + + + + + + + + + + + + 6 + 12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 12 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/postscript.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/postscript.xml new file mode 100644 index 000000000..15a3422d0 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/postscript.xml @@ -0,0 +1,89 @@ + + + PostScript + postscript + postscr + *.ps + *.eps + application/postscript + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/povray.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/povray.xml new file mode 100644 index 000000000..f37dab908 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/povray.xml @@ -0,0 +1,58 @@ + + + POVRay + pov + *.pov + *.inc + text/x-povray + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/powerquery.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/powerquery.xml new file mode 100644 index 000000000..0ff1e3557 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/powerquery.xml @@ -0,0 +1,51 @@ + + + PowerQuery + powerquery + pq + *.pq + text/x-powerquery + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/powershell.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/powershell.xml new file mode 100644 index 000000000..b63a15081 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/powershell.xml @@ -0,0 +1,230 @@ + + + PowerShell + powershell + posh + ps1 + psm1 + psd1 + pwsh + *.ps1 + *.psm1 + *.psd1 + text/x-powershell + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/prolog.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/prolog.xml new file mode 100644 index 000000000..391bae36b --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/prolog.xml @@ -0,0 +1,115 @@ + + + Prolog + prolog + *.ecl + *.prolog + *.pro + *.pl + text/x-prolog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/promela.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/promela.xml new file mode 100644 index 000000000..84558c3b6 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/promela.xml @@ -0,0 +1,119 @@ + + + + Promela + promela + *.pml + *.prom + *.prm + *.promela + *.pr + *.pm + text/x-promela + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/promql.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/promql.xml new file mode 100644 index 000000000..e95e333d5 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/promql.xml @@ -0,0 +1,123 @@ + + + PromQL + promql + *.promql + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/properties.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/properties.xml new file mode 100644 index 000000000..d5ae0a283 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/properties.xml @@ -0,0 +1,45 @@ + + + properties + java-properties + *.properties + text/x-java-properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/protocol_buffer.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/protocol_buffer.xml new file mode 100644 index 000000000..157d321f8 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/protocol_buffer.xml @@ -0,0 +1,118 @@ + + + Protocol Buffer + protobuf + proto + *.proto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/prql.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/prql.xml new file mode 100644 index 000000000..21f21c65c --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/prql.xml @@ -0,0 +1,161 @@ + + + PRQL + prql + *.prql + application/prql + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/psl.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/psl.xml new file mode 100644 index 000000000..ab375dae4 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/psl.xml @@ -0,0 +1,213 @@ + + + PSL + psl + *.psl + *.BATCH + *.TRIG + *.PROC + text/x-psl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/puppet.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/puppet.xml new file mode 100644 index 000000000..fbb587cf5 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/puppet.xml @@ -0,0 +1,100 @@ + + + Puppet + puppet + *.pp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/python.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/python.xml new file mode 100644 index 000000000..eaa9c3076 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/python.xml @@ -0,0 +1,595 @@ + + + Python + python + py + sage + python3 + py3 + starlark + *.py + *.pyi + *.pyw + *.jy + *.sage + *.sc + SConstruct + SConscript + *.bzl + BUCK + BUILD + BUILD.bazel + WORKSPACE + WORKSPACE.bzlmod + WORKSPACE.bazel + MODULE.bazel + REPO.bazel + *.star + *.tac + text/x-python + application/x-python + text/x-python3 + application/x-python3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/python_2.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/python_2.xml new file mode 100644 index 000000000..3297a2260 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/python_2.xml @@ -0,0 +1,356 @@ + + + Python 2 + python2 + py2 + text/x-python2 + application/x-python2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/qbasic.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/qbasic.xml new file mode 100644 index 000000000..193fe1807 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/qbasic.xml @@ -0,0 +1,173 @@ + + + QBasic + qbasic + basic + *.BAS + *.bas + text/basic + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/qml.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/qml.xml new file mode 100644 index 000000000..43eb3eb3d --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/qml.xml @@ -0,0 +1,113 @@ + + + QML + qml + qbs + *.qml + *.qbs + application/x-qml + application/x-qt.qbs+qml + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/r.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/r.xml new file mode 100644 index 000000000..c1fba4e5e --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/r.xml @@ -0,0 +1,128 @@ + + + R + splus + s + r + *.S + *.R + *.r + .Rhistory + .Rprofile + .Renviron + text/S-plus + text/S + text/x-r-source + text/x-r + text/x-R + text/x-r-history + text/x-r-profile + 0.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/racket.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/racket.xml new file mode 100644 index 000000000..6cdd30312 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/racket.xml @@ -0,0 +1,260 @@ + + + Racket + racket + rkt + *.rkt + *.rktd + *.rktl + text/x-racket + application/x-racket + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ragel.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ragel.xml new file mode 100644 index 000000000..69638d2ec --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ragel.xml @@ -0,0 +1,149 @@ + + + Ragel + ragel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/react.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/react.xml new file mode 100644 index 000000000..a4109b094 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/react.xml @@ -0,0 +1,236 @@ + + + react + jsx + react + *.jsx + *.react + text/jsx + text/typescript-jsx + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/reasonml.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/reasonml.xml new file mode 100644 index 000000000..8b7bcc506 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/reasonml.xml @@ -0,0 +1,147 @@ + + + ReasonML + reason + reasonml + *.re + *.rei + text/x-reasonml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/reg.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/reg.xml new file mode 100644 index 000000000..501d38033 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/reg.xml @@ -0,0 +1,68 @@ + + + reg + registry + *.reg + text/x-windows-registry + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rego.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rego.xml new file mode 100644 index 000000000..517b7133b --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rego.xml @@ -0,0 +1,94 @@ + + + Rego + rego + *.rego + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rexx.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rexx.xml new file mode 100644 index 000000000..e682500cb --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rexx.xml @@ -0,0 +1,127 @@ + + + Rexx + rexx + arexx + *.rexx + *.rex + *.rx + *.arexx + text/x-rexx + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rgbasm.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rgbasm.xml new file mode 100644 index 000000000..6814ca1c7 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rgbasm.xml @@ -0,0 +1,239 @@ + + + RGBDS Assembly + rgbasm + *.asm + 0.5 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ring.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ring.xml new file mode 100644 index 000000000..44454ea8f --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ring.xml @@ -0,0 +1,74 @@ + + + Ring + ring + *.ring + *.rh + *.rform + text/x-ring + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rpgle.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rpgle.xml new file mode 100644 index 000000000..c74cd2c39 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rpgle.xml @@ -0,0 +1,176 @@ + + + RPGLE + SQLRPGLE + RPG IV + *.RPGLE + *.rpgle + *.SQLRPGLE + *.sqlrpgle + text/x-rpgle + text/x-sqlrpgle + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rpm_spec.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rpm_spec.xml new file mode 100644 index 000000000..8362772a6 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rpm_spec.xml @@ -0,0 +1,58 @@ + + + + RPMSpec + spec + *.spec + text/x-rpm-spec + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ruby.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ruby.xml new file mode 100644 index 000000000..baa7e4359 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ruby.xml @@ -0,0 +1,724 @@ + + + Ruby + rb + ruby + duby + *.rb + *.rbw + Rakefile + *.rake + *.gemspec + *.rbx + *.duby + Gemfile + Vagrantfile + text/x-ruby + application/x-ruby + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rust.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rust.xml new file mode 100644 index 000000000..083b96ffe --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rust.xml @@ -0,0 +1,375 @@ + + + Rust + rust + rs + *.rs + *.rs.in + text/rust + text/x-rust + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sas.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sas.xml new file mode 100644 index 000000000..af1107bf9 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sas.xml @@ -0,0 +1,191 @@ + + + SAS + sas + *.SAS + *.sas + text/x-sas + text/sas + application/x-sas + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sass.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sass.xml new file mode 100644 index 000000000..f80159491 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sass.xml @@ -0,0 +1,362 @@ + + + Sass + sass + *.sass + text/x-sass + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/scala.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/scala.xml new file mode 100644 index 000000000..2f8ddd49e --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/scala.xml @@ -0,0 +1,274 @@ + + + Scala + scala + *.scala + text/x-scala + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/scheme.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/scheme.xml new file mode 100644 index 000000000..0198bd722 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/scheme.xml @@ -0,0 +1,106 @@ + + + Scheme + scheme + scm + *.scm + *.ss + text/x-scheme + application/x-scheme + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/scilab.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/scilab.xml new file mode 100644 index 000000000..9e109495f --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/scilab.xml @@ -0,0 +1,98 @@ + + + Scilab + scilab + *.sci + *.sce + *.tst + text/scilab + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/scss.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/scss.xml new file mode 100644 index 000000000..ee060fc2b --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/scss.xml @@ -0,0 +1,373 @@ + + + SCSS + scss + *.scss + text/x-scss + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sed.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sed.xml new file mode 100644 index 000000000..fd77d083f --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sed.xml @@ -0,0 +1,92 @@ + + + + Sed + sed + gsed + ssed + *.sed + *.[gs]sed + text/x-sed + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sieve.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sieve.xml new file mode 100644 index 000000000..fc605638a --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sieve.xml @@ -0,0 +1,61 @@ + + + Sieve + sieve + *.siv + *.sieve + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/smali.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/smali.xml new file mode 100644 index 000000000..e468766d1 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/smali.xml @@ -0,0 +1,73 @@ + + + + Smali + smali + *.smali + text/smali + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/smalltalk.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/smalltalk.xml new file mode 100644 index 000000000..00271118f --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/smalltalk.xml @@ -0,0 +1,294 @@ + + + Smalltalk + smalltalk + squeak + st + *.st + text/x-smalltalk + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/smarty.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/smarty.xml new file mode 100644 index 000000000..dd7752c58 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/smarty.xml @@ -0,0 +1,79 @@ + + + Smarty + smarty + *.tpl + application/x-smarty + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/snbt.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/snbt.xml new file mode 100644 index 000000000..fdb12d0fe --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/snbt.xml @@ -0,0 +1,58 @@ + + + + SNBT + snbt + *.snbt + text/snbt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/snobol.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/snobol.xml new file mode 100644 index 000000000..f53dbcba1 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/snobol.xml @@ -0,0 +1,95 @@ + + + Snobol + snobol + *.snobol + text/x-snobol + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/solidity.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/solidity.xml new file mode 100644 index 000000000..24c4ccbae --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/solidity.xml @@ -0,0 +1,291 @@ + + + Solidity + sol + solidity + *.sol + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sourcepawn.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sourcepawn.xml new file mode 100644 index 000000000..caca401e3 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sourcepawn.xml @@ -0,0 +1,59 @@ + + + SourcePawn + sp + *.sp + *.inc + text/x-sourcepawn + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sparql.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sparql.xml new file mode 100644 index 000000000..7dc65af71 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sparql.xml @@ -0,0 +1,160 @@ + + + SPARQL + sparql + *.rq + *.sparql + application/sparql-query + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sql.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sql.xml new file mode 100644 index 000000000..b542b65fe --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sql.xml @@ -0,0 +1,90 @@ + + + SQL + sql + *.sql + text/x-sql + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/squidconf.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/squidconf.xml new file mode 100644 index 000000000..cbd8dbce3 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/squidconf.xml @@ -0,0 +1,63 @@ + + + SquidConf + squidconf + squid.conf + squid + squid.conf + text/x-squidconf + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/standard_ml.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/standard_ml.xml new file mode 100644 index 000000000..39cf4f2af --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/standard_ml.xml @@ -0,0 +1,548 @@ + + + Standard ML + sml + *.sml + *.sig + *.fun + text/x-standardml + application/x-standardml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/stas.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/stas.xml new file mode 100644 index 000000000..56b4f9238 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/stas.xml @@ -0,0 +1,85 @@ + + + stas + *.stas + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/stylus.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/stylus.xml new file mode 100644 index 000000000..c2d88073a --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/stylus.xml @@ -0,0 +1,132 @@ + + + Stylus + stylus + *.styl + text/x-styl + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/swift.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/swift.xml new file mode 100644 index 000000000..416bf90c5 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/swift.xml @@ -0,0 +1,207 @@ + + + Swift + swift + *.swift + text/x-swift + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/systemd.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/systemd.xml new file mode 100644 index 000000000..e31bfc29f --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/systemd.xml @@ -0,0 +1,63 @@ + + + SYSTEMD + systemd + *.automount + *.device + *.dnssd + *.link + *.mount + *.netdev + *.network + *.path + *.scope + *.service + *.slice + *.socket + *.swap + *.target + *.timer + text/plain + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/systemverilog.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/systemverilog.xml new file mode 100644 index 000000000..fac3da235 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/systemverilog.xml @@ -0,0 +1,181 @@ + + + systemverilog + systemverilog + sv + *.sv + *.svh + text/x-systemverilog + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tablegen.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tablegen.xml new file mode 100644 index 000000000..a020ce804 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tablegen.xml @@ -0,0 +1,69 @@ + + + TableGen + tablegen + *.td + text/x-tablegen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tal.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tal.xml new file mode 100644 index 000000000..a071d4c1a --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tal.xml @@ -0,0 +1,43 @@ + + + + Tal + tal + uxntal + *.tal + text/x-uxntal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tasm.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tasm.xml new file mode 100644 index 000000000..1347f5396 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tasm.xml @@ -0,0 +1,135 @@ + + + TASM + tasm + *.asm + *.ASM + *.tasm + text/x-tasm + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tcl.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tcl.xml new file mode 100644 index 000000000..7ed69bc26 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tcl.xml @@ -0,0 +1,272 @@ + + + Tcl + tcl + *.tcl + *.rvt + text/x-tcl + text/x-script.tcl + application/x-tcl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tcsh.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tcsh.xml new file mode 100644 index 000000000..9895643c4 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tcsh.xml @@ -0,0 +1,121 @@ + + + Tcsh + tcsh + csh + *.tcsh + *.csh + application/x-csh + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/termcap.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/termcap.xml new file mode 100644 index 000000000..e863bbd05 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/termcap.xml @@ -0,0 +1,75 @@ + + + Termcap + termcap + termcap + termcap.src + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/terminfo.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/terminfo.xml new file mode 100644 index 000000000..9e8f56ec4 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/terminfo.xml @@ -0,0 +1,84 @@ + + + Terminfo + terminfo + terminfo + terminfo.src + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/terraform.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/terraform.xml new file mode 100644 index 000000000..f8df6be2a --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/terraform.xml @@ -0,0 +1,149 @@ + + + Terraform + terraform + tf + hcl + *.tf + *.hcl + application/x-tf + application/x-terraform + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tex.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tex.xml new file mode 100644 index 000000000..809bb9a29 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tex.xml @@ -0,0 +1,113 @@ + + + TeX + tex + latex + *.tex + *.aux + *.toc + text/x-tex + text/x-latex + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/thrift.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/thrift.xml new file mode 100644 index 000000000..f14257d4f --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/thrift.xml @@ -0,0 +1,154 @@ + + + Thrift + thrift + *.thrift + application/x-thrift + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/toml.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/toml.xml new file mode 100644 index 000000000..87bd19df4 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/toml.xml @@ -0,0 +1,45 @@ + + + TOML + toml + *.toml + Pipfile + poetry.lock + uv.lock + text/x-toml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tradingview.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tradingview.xml new file mode 100644 index 000000000..3671f61ed --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tradingview.xml @@ -0,0 +1,81 @@ + + + TradingView + tradingview + tv + *.tv + text/x-tradingview + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/transact-sql.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/transact-sql.xml new file mode 100644 index 000000000..b0490aa7c --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/transact-sql.xml @@ -0,0 +1,137 @@ + + + Transact-SQL + tsql + t-sql + text/x-tsql + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/turing.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/turing.xml new file mode 100644 index 000000000..4eab69b73 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/turing.xml @@ -0,0 +1,82 @@ + + + Turing + turing + *.turing + *.tu + text/x-turing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/turtle.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/turtle.xml new file mode 100644 index 000000000..7c572f9ca --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/turtle.xml @@ -0,0 +1,170 @@ + + + Turtle + turtle + *.ttl + text/turtle + application/x-turtle + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/twig.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/twig.xml new file mode 100644 index 000000000..de95c5f91 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/twig.xml @@ -0,0 +1,155 @@ + + + Twig + twig + *.twig + application/x-twig + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/txtpb.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/txtpb.xml new file mode 100644 index 000000000..9cb48c031 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/txtpb.xml @@ -0,0 +1,162 @@ + + + Protocol Buffer Text Format + txtpb + *.txtpb + *.textproto + *.textpb + *.pbtxt + application/x-protobuf-text + false + false + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/typescript.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/typescript.xml new file mode 100644 index 000000000..a3e3be239 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/typescript.xml @@ -0,0 +1,302 @@ + + + TypeScript + ts + tsx + typescript + *.ts + *.tsx + *.mts + *.cts + text/x-typescript + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/typoscript.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/typoscript.xml new file mode 100644 index 000000000..bc416d472 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/typoscript.xml @@ -0,0 +1,178 @@ + + + TypoScript + typoscript + *.ts + text/x-typoscript + true + 0.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/typoscriptcssdata.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/typoscriptcssdata.xml new file mode 100644 index 000000000..62c42c153 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/typoscriptcssdata.xml @@ -0,0 +1,52 @@ + + + TypoScriptCssData + typoscriptcssdata + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/typoscripthtmldata.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/typoscripthtmldata.xml new file mode 100644 index 000000000..1b0af3a4e --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/typoscripthtmldata.xml @@ -0,0 +1,52 @@ + + + TypoScriptHtmlData + typoscripthtmldata + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/typst.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/typst.xml new file mode 100644 index 000000000..330dc40fa --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/typst.xml @@ -0,0 +1,108 @@ + + + + Typst + typst + *.typ + text/x-typst + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ucode.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ucode.xml new file mode 100644 index 000000000..054fa8913 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ucode.xml @@ -0,0 +1,147 @@ + + + ucode + *.uc + application/x.ucode + text/x.ucode + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/v.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/v.xml new file mode 100644 index 000000000..e1af3d1cd --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/v.xml @@ -0,0 +1,355 @@ + + + V + v + vlang + *.v + *.vv + v.mod + text/x-v + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/v_shell.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/v_shell.xml new file mode 100644 index 000000000..34ce61065 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/v_shell.xml @@ -0,0 +1,365 @@ + + + V shell + vsh + vshell + *.vsh + text/x-vsh + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/vala.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/vala.xml new file mode 100644 index 000000000..17c1acf48 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/vala.xml @@ -0,0 +1,72 @@ + + + + Vala + vala + vapi + *.vala + *.vapi + text/x-vala + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/vb_net.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/vb_net.xml new file mode 100644 index 000000000..9f85afd0e --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/vb_net.xml @@ -0,0 +1,162 @@ + + + VB.net + vb.net + vbnet + *.vb + *.bas + text/x-vbnet + text/x-vba + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/verilog.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/verilog.xml new file mode 100644 index 000000000..cd4b9ff09 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/verilog.xml @@ -0,0 +1,158 @@ + + + verilog + verilog + v + *.v + text/x-verilog + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/vhdl.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/vhdl.xml new file mode 100644 index 000000000..aa4204486 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/vhdl.xml @@ -0,0 +1,171 @@ + + + VHDL + vhdl + *.vhdl + *.vhd + text/x-vhdl + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/vhs.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/vhs.xml new file mode 100644 index 000000000..ee84d1292 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/vhs.xml @@ -0,0 +1,48 @@ + + + VHS + vhs + tape + cassette + *.tape + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/viml.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/viml.xml new file mode 100644 index 000000000..43e6bfa74 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/viml.xml @@ -0,0 +1,85 @@ + + + VimL + vim + *.vim + .vimrc + .exrc + .gvimrc + _vimrc + _exrc + _gvimrc + vimrc + gvimrc + text/x-vim + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/vue.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/vue.xml new file mode 100644 index 000000000..e2f75e1dc --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/vue.xml @@ -0,0 +1,295 @@ + + + vue + vue + vuejs + *.vue + text/x-vue + application/x-vue + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/wat.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/wat.xml new file mode 100644 index 000000000..4a7f7e465 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/wat.xml @@ -0,0 +1,149 @@ + + + WebAssembly Text Format + wast + wat + *.wat + *.wast + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/wdte.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/wdte.xml new file mode 100644 index 000000000..c663ee2fe --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/wdte.xml @@ -0,0 +1,43 @@ + + + WDTE + *.wdte + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/webgpu_shading_language.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/webgpu_shading_language.xml new file mode 100644 index 000000000..ea2b6e1ef --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/webgpu_shading_language.xml @@ -0,0 +1,142 @@ + + + WebGPU Shading Language + wgsl + *.wgsl + text/wgsl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/webvtt.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/webvtt.xml new file mode 100644 index 000000000..08a7efc3a --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/webvtt.xml @@ -0,0 +1,283 @@ + + + WebVTT + vtt + *.vtt + text/vtt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/whiley.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/whiley.xml new file mode 100644 index 000000000..1762c966e --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/whiley.xml @@ -0,0 +1,57 @@ + + + Whiley + whiley + *.whiley + text/x-whiley + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/xml.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/xml.xml new file mode 100644 index 000000000..2c6a4d990 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/xml.xml @@ -0,0 +1,95 @@ + + + XML + xml + *.xml + *.xsl + *.rss + *.xslt + *.xsd + *.wsdl + *.wsf + *.svg + *.csproj + *.vcxproj + *.fsproj + text/xml + application/xml + image/svg+xml + application/rss+xml + application/atom+xml + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/xorg.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/xorg.xml new file mode 100644 index 000000000..53bf43286 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/xorg.xml @@ -0,0 +1,35 @@ + + + Xorg + xorg.conf + xorg.conf + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/yaml.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/yaml.xml new file mode 100644 index 000000000..070755416 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/yaml.xml @@ -0,0 +1,122 @@ + + + YAML + yaml + *.yaml + *.yml + text/x-yaml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/yang.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/yang.xml new file mode 100644 index 000000000..f3da7ceb3 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/yang.xml @@ -0,0 +1,99 @@ + + + YANG + yang + *.yang + application/yang + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/z80_assembly.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/z80_assembly.xml new file mode 100644 index 000000000..5bb77a9ad --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/z80_assembly.xml @@ -0,0 +1,74 @@ + + + Z80 Assembly + z80 + *.z80 + *.asm + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/zed.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/zed.xml new file mode 100644 index 000000000..929f49532 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/zed.xml @@ -0,0 +1,51 @@ + + + Zed + zed + *.zed + text/zed + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/zig.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/zig.xml new file mode 100644 index 000000000..5617f9141 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/zig.xml @@ -0,0 +1,187 @@ + + + Zig + zig + *.zig + *.zon + text/zig + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/gemtext.go b/vendor/github.com/alecthomas/chroma/v2/lexers/gemtext.go new file mode 100644 index 000000000..2fed8d62f --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/gemtext.go @@ -0,0 +1,37 @@ +package lexers + +import ( + . "github.com/alecthomas/chroma/v2" // nolint +) + +// Gemtext lexer. +var Gemtext = Register(MustNewLexer( + &Config{ + Name: "Gemtext", + Aliases: []string{"gemtext", "gmi", "gmni", "gemini"}, + Filenames: []string{"*.gmi", "*.gmni", "*.gemini"}, + MimeTypes: []string{"text/gemini"}, + }, + gemtextRules, +)) + +func gemtextRules() Rules { + return Rules{ + "root": { + {`^(#[^#].+\r?\n)`, ByGroups(GenericHeading), nil}, + {`^(#{2,3}.+\r?\n)`, ByGroups(GenericSubheading), nil}, + {`^(\* )(.+\r?\n)`, ByGroups(Keyword, Text), nil}, + {`^(>)(.+\r?\n)`, ByGroups(Keyword, GenericEmph), nil}, + {"^(```\\r?\\n)([\\w\\W]*?)(^```)(.+\\r?\\n)?", ByGroups(String, Text, String, Comment), nil}, + { + "^(```)(\\w+)(\\r?\\n)([\\w\\W]*?)(^```)(.+\\r?\\n)?", + UsingByGroup(2, 4, String, String, String, Text, String, Comment), + nil, + }, + {"^(```)(.+\\r?\\n)([\\w\\W]*?)(^```)(.+\\r?\\n)?", ByGroups(String, String, Text, String, Comment), nil}, + {`^(=>)(\s*)([^\s]+)(\s*)$`, ByGroups(Keyword, Text, NameAttribute, Text), nil}, + {`^(=>)(\s*)([^\s]+)(\s+)(.+)$`, ByGroups(Keyword, Text, NameAttribute, Text, NameTag), nil}, + {`(.|(?:\r?\n))`, ByGroups(Text), nil}, + }, + } +} diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/genshi.go b/vendor/github.com/alecthomas/chroma/v2/lexers/genshi.go new file mode 100644 index 000000000..7f396f4b8 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/genshi.go @@ -0,0 +1,118 @@ +package lexers + +import ( + . "github.com/alecthomas/chroma/v2" // nolint +) + +// Genshi Text lexer. +var GenshiText = Register(MustNewLexer( + &Config{ + Name: "Genshi Text", + Aliases: []string{"genshitext"}, + Filenames: []string{}, + MimeTypes: []string{"application/x-genshi-text", "text/x-genshi"}, + }, + genshiTextRules, +)) + +func genshiTextRules() Rules { + return Rules{ + "root": { + {`[^#$\s]+`, Other, nil}, + {`^(\s*)(##.*)$`, ByGroups(Text, Comment), nil}, + {`^(\s*)(#)`, ByGroups(Text, CommentPreproc), Push("directive")}, + Include("variable"), + {`[#$\s]`, Other, nil}, + }, + "directive": { + {`\n`, Text, Pop(1)}, + {`(?:def|for|if)\s+.*`, Using("Python"), Pop(1)}, + {`(choose|when|with)([^\S\n]+)(.*)`, ByGroups(Keyword, Text, Using("Python")), Pop(1)}, + {`(choose|otherwise)\b`, Keyword, Pop(1)}, + {`(end\w*)([^\S\n]*)(.*)`, ByGroups(Keyword, Text, Comment), Pop(1)}, + }, + "variable": { + {`(?)`, ByGroups(CommentPreproc, Using("Python"), CommentPreproc), nil}, + {`<\s*(script|style)\s*.*?>.*?<\s*/\1\s*>`, Other, nil}, + {`<\s*py:[a-zA-Z0-9]+`, NameTag, Push("pytag")}, + {`<\s*[a-zA-Z0-9:.]+`, NameTag, Push("tag")}, + Include("variable"), + {`[<$]`, Other, nil}, + }, + "pytag": { + {`\s+`, Text, nil}, + {`[\w:-]+\s*=`, NameAttribute, Push("pyattr")}, + {`/?\s*>`, NameTag, Pop(1)}, + }, + "pyattr": { + {`(")(.*?)(")`, ByGroups(LiteralString, Using("Python"), LiteralString), Pop(1)}, + {`(')(.*?)(')`, ByGroups(LiteralString, Using("Python"), LiteralString), Pop(1)}, + {`[^\s>]+`, LiteralString, Pop(1)}, + }, + "tag": { + {`\s+`, Text, nil}, + {`py:[\w-]+\s*=`, NameAttribute, Push("pyattr")}, + {`[\w:-]+\s*=`, NameAttribute, Push("attr")}, + {`/?\s*>`, NameTag, Pop(1)}, + }, + "attr": { + {`"`, LiteralString, Push("attr-dstring")}, + {`'`, LiteralString, Push("attr-sstring")}, + {`[^\s>]*`, LiteralString, Pop(1)}, + }, + "attr-dstring": { + {`"`, LiteralString, Pop(1)}, + Include("strings"), + {`'`, LiteralString, nil}, + }, + "attr-sstring": { + {`'`, LiteralString, Pop(1)}, + Include("strings"), + {`'`, LiteralString, nil}, + }, + "strings": { + {`[^"'$]+`, LiteralString, nil}, + Include("variable"), + }, + "variable": { + {`(?>=|<<|>>|<=|>=|&\^=|&\^|\+=|-=|\*=|/=|%=|&=|\|=|&&|\|\||<-|\+\+|--|==|!=|:=|\.\.\.|[+\-*/%&])`, Operator, nil}, + {`([a-zA-Z_]\w*)(\s*)(\()`, ByGroups(NameFunction, UsingSelf("root"), Punctuation), nil}, + {`[|^<>=!()\[\]{}.,;:~]`, Punctuation, nil}, + {`[^\W\d]\w*`, NameOther, nil}, + }, + } +} + +var GoHTMLTemplate = Register(DelegatingLexer(HTML, MustNewXMLLexer( + embedded, + "embedded/go_template.xml", +).SetConfig( + &Config{ + Name: "Go HTML Template", + Aliases: []string{"go-html-template"}, + }, +))) + +var GoTextTemplate = Register(MustNewXMLLexer( + embedded, + "embedded/go_template.xml", +).SetConfig( + &Config{ + Name: "Go Text Template", + Aliases: []string{"go-text-template"}, + }, +)) diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/haxe.go b/vendor/github.com/alecthomas/chroma/v2/lexers/haxe.go new file mode 100644 index 000000000..9a72de865 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/haxe.go @@ -0,0 +1,647 @@ +package lexers + +import ( + . "github.com/alecthomas/chroma/v2" // nolint +) + +// Haxe lexer. +var Haxe = Register(MustNewLexer( + &Config{ + Name: "Haxe", + Aliases: []string{"hx", "haxe", "hxsl"}, + Filenames: []string{"*.hx", "*.hxsl"}, + MimeTypes: []string{"text/haxe", "text/x-haxe", "text/x-hx"}, + DotAll: true, + }, + haxeRules, +)) + +func haxeRules() Rules { + return Rules{ + "root": { + Include("spaces"), + Include("meta"), + {`(?:package)\b`, KeywordNamespace, Push("semicolon", "package")}, + {`(?:import)\b`, KeywordNamespace, Push("semicolon", "import")}, + {`(?:using)\b`, KeywordNamespace, Push("semicolon", "using")}, + {`(?:extern|private)\b`, KeywordDeclaration, nil}, + {`(?:abstract)\b`, KeywordDeclaration, Push("abstract")}, + {`(?:class|interface)\b`, KeywordDeclaration, Push("class")}, + {`(?:enum)\b`, KeywordDeclaration, Push("enum")}, + {`(?:typedef)\b`, KeywordDeclaration, Push("typedef")}, + {`(?=.)`, Text, Push("expr-statement")}, + }, + "spaces": { + {`\s+`, Text, nil}, + {`//[^\n\r]*`, CommentSingle, nil}, + {`/\*.*?\*/`, CommentMultiline, nil}, + {`(#)(if|elseif|else|end|error)\b`, CommentPreproc, MutatorFunc(haxePreProcMutator)}, + }, + "string-single-interpol": { + {`\$\{`, LiteralStringInterpol, Push("string-interpol-close", "expr")}, + {`\$\$`, LiteralStringEscape, nil}, + {`\$(?=(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+))`, LiteralStringInterpol, Push("ident")}, + Include("string-single"), + }, + "string-single": { + {`'`, LiteralStringSingle, Pop(1)}, + {`\\.`, LiteralStringEscape, nil}, + {`.`, LiteralStringSingle, nil}, + }, + "string-double": { + {`"`, LiteralStringDouble, Pop(1)}, + {`\\.`, LiteralStringEscape, nil}, + {`.`, LiteralStringDouble, nil}, + }, + "string-interpol-close": { + {`\$(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+)`, LiteralStringInterpol, nil}, + {`\}`, LiteralStringInterpol, Pop(1)}, + }, + "package": { + Include("spaces"), + {`(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+)`, NameNamespace, nil}, + {`\.`, Punctuation, Push("import-ident")}, + Default(Pop(1)), + }, + "import": { + Include("spaces"), + {`(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+)`, NameNamespace, nil}, + {`\*`, Keyword, nil}, + {`\.`, Punctuation, Push("import-ident")}, + {`in`, KeywordNamespace, Push("ident")}, + Default(Pop(1)), + }, + "import-ident": { + Include("spaces"), + {`\*`, Keyword, Pop(1)}, + {`(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+)`, NameNamespace, Pop(1)}, + }, + "using": { + Include("spaces"), + {`(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+)`, NameNamespace, nil}, + {`\.`, Punctuation, Push("import-ident")}, + Default(Pop(1)), + }, + "preproc-error": { + {`\s+`, CommentPreproc, nil}, + {`'`, LiteralStringSingle, Push("#pop", "string-single")}, + {`"`, LiteralStringDouble, Push("#pop", "string-double")}, + Default(Pop(1)), + }, + "preproc-expr": { + {`\s+`, CommentPreproc, nil}, + {`\!`, CommentPreproc, nil}, + {`\(`, CommentPreproc, Push("#pop", "preproc-parenthesis")}, + {`(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+)`, CommentPreproc, Pop(1)}, + {`\.[0-9]+`, LiteralNumberFloat, nil}, + {`[0-9]+[eE][+\-]?[0-9]+`, LiteralNumberFloat, nil}, + {`[0-9]+\.[0-9]*[eE][+\-]?[0-9]+`, LiteralNumberFloat, nil}, + {`[0-9]+\.[0-9]+`, LiteralNumberFloat, nil}, + {`[0-9]+\.(?!(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+)|\.\.)`, LiteralNumberFloat, nil}, + {`0x[0-9a-fA-F]+`, LiteralNumberHex, nil}, + {`[0-9]+`, LiteralNumberInteger, nil}, + {`'`, LiteralStringSingle, Push("#pop", "string-single")}, + {`"`, LiteralStringDouble, Push("#pop", "string-double")}, + }, + "preproc-parenthesis": { + {`\s+`, CommentPreproc, nil}, + {`\)`, CommentPreproc, Pop(1)}, + Default(Push("preproc-expr-in-parenthesis")), + }, + "preproc-expr-chain": { + {`\s+`, CommentPreproc, nil}, + {`(?:%=|&=|\|=|\^=|\+=|\-=|\*=|/=|<<=|>\s*>\s*=|>\s*>\s*>\s*=|==|!=|<=|>\s*=|&&|\|\||<<|>>>|>\s*>|\.\.\.|<|>|%|&|\||\^|\+|\*|/|\-|=>|=)`, CommentPreproc, Push("#pop", "preproc-expr-in-parenthesis")}, + Default(Pop(1)), + }, + "preproc-expr-in-parenthesis": { + {`\s+`, CommentPreproc, nil}, + {`\!`, CommentPreproc, nil}, + {`\(`, CommentPreproc, Push("#pop", "preproc-expr-chain", "preproc-parenthesis")}, + {`(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+)`, CommentPreproc, Push("#pop", "preproc-expr-chain")}, + {`\.[0-9]+`, LiteralNumberFloat, Push("#pop", "preproc-expr-chain")}, + {`[0-9]+[eE][+\-]?[0-9]+`, LiteralNumberFloat, Push("#pop", "preproc-expr-chain")}, + {`[0-9]+\.[0-9]*[eE][+\-]?[0-9]+`, LiteralNumberFloat, Push("#pop", "preproc-expr-chain")}, + {`[0-9]+\.[0-9]+`, LiteralNumberFloat, Push("#pop", "preproc-expr-chain")}, + {`[0-9]+\.(?!(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+)|\.\.)`, LiteralNumberFloat, Push("#pop", "preproc-expr-chain")}, + {`0x[0-9a-fA-F]+`, LiteralNumberHex, Push("#pop", "preproc-expr-chain")}, + {`[0-9]+`, LiteralNumberInteger, Push("#pop", "preproc-expr-chain")}, + {`'`, LiteralStringSingle, Push("#pop", "preproc-expr-chain", "string-single")}, + {`"`, LiteralStringDouble, Push("#pop", "preproc-expr-chain", "string-double")}, + }, + "abstract": { + Include("spaces"), + Default(Pop(1), Push("abstract-body"), Push("abstract-relation"), Push("abstract-opaque"), Push("type-param-constraint"), Push("type-name")), + }, + "abstract-body": { + Include("spaces"), + {`\{`, Punctuation, Push("#pop", "class-body")}, + }, + "abstract-opaque": { + Include("spaces"), + {`\(`, Punctuation, Push("#pop", "parenthesis-close", "type")}, + Default(Pop(1)), + }, + "abstract-relation": { + Include("spaces"), + {`(?:to|from)`, KeywordDeclaration, Push("type")}, + {`,`, Punctuation, nil}, + Default(Pop(1)), + }, + "meta": { + Include("spaces"), + {`@`, NameDecorator, Push("meta-body", "meta-ident", "meta-colon")}, + }, + "meta-colon": { + Include("spaces"), + {`:`, NameDecorator, Pop(1)}, + Default(Pop(1)), + }, + "meta-ident": { + Include("spaces"), + {`(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+)`, NameDecorator, Pop(1)}, + }, + "meta-body": { + Include("spaces"), + {`\(`, NameDecorator, Push("#pop", "meta-call")}, + Default(Pop(1)), + }, + "meta-call": { + Include("spaces"), + {`\)`, NameDecorator, Pop(1)}, + Default(Pop(1), Push("meta-call-sep"), Push("expr")), + }, + "meta-call-sep": { + Include("spaces"), + {`\)`, NameDecorator, Pop(1)}, + {`,`, Punctuation, Push("#pop", "meta-call")}, + }, + "typedef": { + Include("spaces"), + Default(Pop(1), Push("typedef-body"), Push("type-param-constraint"), Push("type-name")), + }, + "typedef-body": { + Include("spaces"), + {`=`, Operator, Push("#pop", "optional-semicolon", "type")}, + }, + "enum": { + Include("spaces"), + Default(Pop(1), Push("enum-body"), Push("bracket-open"), Push("type-param-constraint"), Push("type-name")), + }, + "enum-body": { + Include("spaces"), + Include("meta"), + {`\}`, Punctuation, Pop(1)}, + {`(?!(?:function|class|static|var|if|else|while|do|for|break|return|continue|extends|implements|import|switch|case|default|public|private|try|untyped|catch|new|this|throw|extern|enum|in|interface|cast|override|dynamic|typedef|package|inline|using|null|true|false|abstract)\b)(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+)`, Name, Push("enum-member", "type-param-constraint")}, + }, + "enum-member": { + Include("spaces"), + {`\(`, Punctuation, Push("#pop", "semicolon", "flag", "function-param")}, + Default(Pop(1), Push("semicolon"), Push("flag")), + }, + "class": { + Include("spaces"), + Default(Pop(1), Push("class-body"), Push("bracket-open"), Push("extends"), Push("type-param-constraint"), Push("type-name")), + }, + "extends": { + Include("spaces"), + {`(?:extends|implements)\b`, KeywordDeclaration, Push("type")}, + {`,`, Punctuation, nil}, + Default(Pop(1)), + }, + "bracket-open": { + Include("spaces"), + {`\{`, Punctuation, Pop(1)}, + }, + "bracket-close": { + Include("spaces"), + {`\}`, Punctuation, Pop(1)}, + }, + "class-body": { + Include("spaces"), + Include("meta"), + {`\}`, Punctuation, Pop(1)}, + {`(?:static|public|private|override|dynamic|inline|macro)\b`, KeywordDeclaration, nil}, + Default(Push("class-member")), + }, + "class-member": { + Include("spaces"), + {`(var)\b`, KeywordDeclaration, Push("#pop", "optional-semicolon", "var")}, + {`(function)\b`, KeywordDeclaration, Push("#pop", "optional-semicolon", "class-method")}, + }, + "function-local": { + Include("spaces"), + {`(?!(?:function|class|static|var|if|else|while|do|for|break|return|continue|extends|implements|import|switch|case|default|public|private|try|untyped|catch|new|this|throw|extern|enum|in|interface|cast|override|dynamic|typedef|package|inline|using|null|true|false|abstract)\b)(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+)`, NameFunction, Push("#pop", "optional-expr", "flag", "function-param", "parenthesis-open", "type-param-constraint")}, + Default(Pop(1), Push("optional-expr"), Push("flag"), Push("function-param"), Push("parenthesis-open"), Push("type-param-constraint")), + }, + "optional-expr": { + Include("spaces"), + Include("expr"), + Default(Pop(1)), + }, + "class-method": { + Include("spaces"), + {`(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+)`, NameFunction, Push("#pop", "optional-expr", "flag", "function-param", "parenthesis-open", "type-param-constraint")}, + }, + "function-param": { + Include("spaces"), + {`\)`, Punctuation, Pop(1)}, + {`\?`, Punctuation, nil}, + {`(?!(?:function|class|static|var|if|else|while|do|for|break|return|continue|extends|implements|import|switch|case|default|public|private|try|untyped|catch|new|this|throw|extern|enum|in|interface|cast|override|dynamic|typedef|package|inline|using|null|true|false|abstract)\b)(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+)`, Name, Push("#pop", "function-param-sep", "assign", "flag")}, + }, + "function-param-sep": { + Include("spaces"), + {`\)`, Punctuation, Pop(1)}, + {`,`, Punctuation, Push("#pop", "function-param")}, + }, + "prop-get-set": { + Include("spaces"), + {`\(`, Punctuation, Push("#pop", "parenthesis-close", "prop-get-set-opt", "comma", "prop-get-set-opt")}, + Default(Pop(1)), + }, + "prop-get-set-opt": { + Include("spaces"), + {`(?:default|null|never|dynamic|get|set)\b`, Keyword, Pop(1)}, + {`(?!(?:function|class|static|var|if|else|while|do|for|break|return|continue|extends|implements|import|switch|case|default|public|private|try|untyped|catch|new|this|throw|extern|enum|in|interface|cast|override|dynamic|typedef|package|inline|using|null|true|false|abstract)\b)(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+)`, Text, Pop(1)}, + }, + "expr-statement": { + Include("spaces"), + Default(Pop(1), Push("optional-semicolon"), Push("expr")), + }, + "expr": { + Include("spaces"), + {`@`, NameDecorator, Push("#pop", "optional-expr", "meta-body", "meta-ident", "meta-colon")}, + {`(?:\+\+|\-\-|~(?!/)|!|\-)`, Operator, nil}, + {`\(`, Punctuation, Push("#pop", "expr-chain", "parenthesis")}, + {`(?:static|public|private|override|dynamic|inline)\b`, KeywordDeclaration, nil}, + {`(?:function)\b`, KeywordDeclaration, Push("#pop", "expr-chain", "function-local")}, + {`\{`, Punctuation, Push("#pop", "expr-chain", "bracket")}, + {`(?:true|false|null)\b`, KeywordConstant, Push("#pop", "expr-chain")}, + {`(?:this)\b`, Keyword, Push("#pop", "expr-chain")}, + {`(?:cast)\b`, Keyword, Push("#pop", "expr-chain", "cast")}, + {`(?:try)\b`, Keyword, Push("#pop", "catch", "expr")}, + {`(?:var)\b`, KeywordDeclaration, Push("#pop", "var")}, + {`(?:new)\b`, Keyword, Push("#pop", "expr-chain", "new")}, + {`(?:switch)\b`, Keyword, Push("#pop", "switch")}, + {`(?:if)\b`, Keyword, Push("#pop", "if")}, + {`(?:do)\b`, Keyword, Push("#pop", "do")}, + {`(?:while)\b`, Keyword, Push("#pop", "while")}, + {`(?:for)\b`, Keyword, Push("#pop", "for")}, + {`(?:untyped|throw)\b`, Keyword, nil}, + {`(?:return)\b`, Keyword, Push("#pop", "optional-expr")}, + {`(?:macro)\b`, Keyword, Push("#pop", "macro")}, + {`(?:continue|break)\b`, Keyword, Pop(1)}, + {`(?:\$\s*[a-z]\b|\$(?!(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+)))`, Name, Push("#pop", "dollar")}, + {`(?!(?:function|class|static|var|if|else|while|do|for|break|return|continue|extends|implements|import|switch|case|default|public|private|try|untyped|catch|new|this|throw|extern|enum|in|interface|cast|override|dynamic|typedef|package|inline|using|null|true|false|abstract)\b)(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+)`, Name, Push("#pop", "expr-chain")}, + {`\.[0-9]+`, LiteralNumberFloat, Push("#pop", "expr-chain")}, + {`[0-9]+[eE][+\-]?[0-9]+`, LiteralNumberFloat, Push("#pop", "expr-chain")}, + {`[0-9]+\.[0-9]*[eE][+\-]?[0-9]+`, LiteralNumberFloat, Push("#pop", "expr-chain")}, + {`[0-9]+\.[0-9]+`, LiteralNumberFloat, Push("#pop", "expr-chain")}, + {`[0-9]+\.(?!(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+)|\.\.)`, LiteralNumberFloat, Push("#pop", "expr-chain")}, + {`0x[0-9a-fA-F]+`, LiteralNumberHex, Push("#pop", "expr-chain")}, + {`[0-9]+`, LiteralNumberInteger, Push("#pop", "expr-chain")}, + {`'`, LiteralStringSingle, Push("#pop", "expr-chain", "string-single-interpol")}, + {`"`, LiteralStringDouble, Push("#pop", "expr-chain", "string-double")}, + {`~/(\\\\|\\/|[^/\n])*/[gimsu]*`, LiteralStringRegex, Push("#pop", "expr-chain")}, + {`\[`, Punctuation, Push("#pop", "expr-chain", "array-decl")}, + }, + "expr-chain": { + Include("spaces"), + {`(?:\+\+|\-\-)`, Operator, nil}, + {`(?:%=|&=|\|=|\^=|\+=|\-=|\*=|/=|<<=|>\s*>\s*=|>\s*>\s*>\s*=|==|!=|<=|>\s*=|&&|\|\||<<|>>>|>\s*>|\.\.\.|<|>|%|&|\||\^|\+|\*|/|\-|=>|=)`, Operator, Push("#pop", "expr")}, + {`(?:in)\b`, Keyword, Push("#pop", "expr")}, + {`\?`, Operator, Push("#pop", "expr", "ternary", "expr")}, + {`(\.)((?!(?:function|class|static|var|if|else|while|do|for|break|return|continue|extends|implements|import|switch|case|default|public|private|try|untyped|catch|new|this|throw|extern|enum|in|interface|cast|override|dynamic|typedef|package|inline|using|null|true|false|abstract)\b)(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+))`, ByGroups(Punctuation, Name), nil}, + {`\[`, Punctuation, Push("array-access")}, + {`\(`, Punctuation, Push("call")}, + Default(Pop(1)), + }, + "macro": { + Include("spaces"), + Include("meta"), + {`:`, Punctuation, Push("#pop", "type")}, + {`(?:extern|private)\b`, KeywordDeclaration, nil}, + {`(?:abstract)\b`, KeywordDeclaration, Push("#pop", "optional-semicolon", "abstract")}, + {`(?:class|interface)\b`, KeywordDeclaration, Push("#pop", "optional-semicolon", "macro-class")}, + {`(?:enum)\b`, KeywordDeclaration, Push("#pop", "optional-semicolon", "enum")}, + {`(?:typedef)\b`, KeywordDeclaration, Push("#pop", "optional-semicolon", "typedef")}, + Default(Pop(1), Push("expr")), + }, + "macro-class": { + {`\{`, Punctuation, Push("#pop", "class-body")}, + Include("class"), + }, + "cast": { + Include("spaces"), + {`\(`, Punctuation, Push("#pop", "parenthesis-close", "cast-type", "expr")}, + Default(Pop(1), Push("expr")), + }, + "cast-type": { + Include("spaces"), + {`,`, Punctuation, Push("#pop", "type")}, + Default(Pop(1)), + }, + "catch": { + Include("spaces"), + {`(?:catch)\b`, Keyword, Push("expr", "function-param", "parenthesis-open")}, + Default(Pop(1)), + }, + "do": { + Include("spaces"), + Default(Pop(1), Push("do-while"), Push("expr")), + }, + "do-while": { + Include("spaces"), + {`(?:while)\b`, Keyword, Push("#pop", "parenthesis", "parenthesis-open")}, + }, + "while": { + Include("spaces"), + {`\(`, Punctuation, Push("#pop", "expr", "parenthesis")}, + }, + "for": { + Include("spaces"), + {`\(`, Punctuation, Push("#pop", "expr", "parenthesis")}, + }, + "if": { + Include("spaces"), + {`\(`, Punctuation, Push("#pop", "else", "optional-semicolon", "expr", "parenthesis")}, + }, + "else": { + Include("spaces"), + {`(?:else)\b`, Keyword, Push("#pop", "expr")}, + Default(Pop(1)), + }, + "switch": { + Include("spaces"), + Default(Pop(1), Push("switch-body"), Push("bracket-open"), Push("expr")), + }, + "switch-body": { + Include("spaces"), + {`(?:case|default)\b`, Keyword, Push("case-block", "case")}, + {`\}`, Punctuation, Pop(1)}, + }, + "case": { + Include("spaces"), + {`:`, Punctuation, Pop(1)}, + Default(Pop(1), Push("case-sep"), Push("case-guard"), Push("expr")), + }, + "case-sep": { + Include("spaces"), + {`:`, Punctuation, Pop(1)}, + {`,`, Punctuation, Push("#pop", "case")}, + }, + "case-guard": { + Include("spaces"), + {`(?:if)\b`, Keyword, Push("#pop", "parenthesis", "parenthesis-open")}, + Default(Pop(1)), + }, + "case-block": { + Include("spaces"), + {`(?!(?:case|default)\b|\})`, Keyword, Push("expr-statement")}, + Default(Pop(1)), + }, + "new": { + Include("spaces"), + Default(Pop(1), Push("call"), Push("parenthesis-open"), Push("type")), + }, + "array-decl": { + Include("spaces"), + {`\]`, Punctuation, Pop(1)}, + Default(Pop(1), Push("array-decl-sep"), Push("expr")), + }, + "array-decl-sep": { + Include("spaces"), + {`\]`, Punctuation, Pop(1)}, + {`,`, Punctuation, Push("#pop", "array-decl")}, + }, + "array-access": { + Include("spaces"), + Default(Pop(1), Push("array-access-close"), Push("expr")), + }, + "array-access-close": { + Include("spaces"), + {`\]`, Punctuation, Pop(1)}, + }, + "comma": { + Include("spaces"), + {`,`, Punctuation, Pop(1)}, + }, + "colon": { + Include("spaces"), + {`:`, Punctuation, Pop(1)}, + }, + "semicolon": { + Include("spaces"), + {`;`, Punctuation, Pop(1)}, + }, + "optional-semicolon": { + Include("spaces"), + {`;`, Punctuation, Pop(1)}, + Default(Pop(1)), + }, + "ident": { + Include("spaces"), + {`(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+)`, Name, Pop(1)}, + }, + "dollar": { + Include("spaces"), + {`\{`, Punctuation, Push("#pop", "expr-chain", "bracket-close", "expr")}, + Default(Pop(1), Push("expr-chain")), + }, + "type-name": { + Include("spaces"), + {`_*[A-Z]\w*`, Name, Pop(1)}, + }, + "type-full-name": { + Include("spaces"), + {`\.`, Punctuation, Push("ident")}, + Default(Pop(1)), + }, + "type": { + Include("spaces"), + {`\?`, Punctuation, nil}, + {`(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+)`, Name, Push("#pop", "type-check", "type-full-name")}, + {`\{`, Punctuation, Push("#pop", "type-check", "type-struct")}, + {`\(`, Punctuation, Push("#pop", "type-check", "type-parenthesis")}, + }, + "type-parenthesis": { + Include("spaces"), + Default(Pop(1), Push("parenthesis-close"), Push("type")), + }, + "type-check": { + Include("spaces"), + {`->`, Punctuation, Push("#pop", "type")}, + {`<(?!=)`, Punctuation, Push("type-param")}, + Default(Pop(1)), + }, + "type-struct": { + Include("spaces"), + {`\}`, Punctuation, Pop(1)}, + {`\?`, Punctuation, nil}, + {`>`, Punctuation, Push("comma", "type")}, + {`(?!(?:function|class|static|var|if|else|while|do|for|break|return|continue|extends|implements|import|switch|case|default|public|private|try|untyped|catch|new|this|throw|extern|enum|in|interface|cast|override|dynamic|typedef|package|inline|using|null|true|false|abstract)\b)(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+)`, Name, Push("#pop", "type-struct-sep", "type", "colon")}, + Include("class-body"), + }, + "type-struct-sep": { + Include("spaces"), + {`\}`, Punctuation, Pop(1)}, + {`,`, Punctuation, Push("#pop", "type-struct")}, + }, + "type-param-type": { + {`\.[0-9]+`, LiteralNumberFloat, Pop(1)}, + {`[0-9]+[eE][+\-]?[0-9]+`, LiteralNumberFloat, Pop(1)}, + {`[0-9]+\.[0-9]*[eE][+\-]?[0-9]+`, LiteralNumberFloat, Pop(1)}, + {`[0-9]+\.[0-9]+`, LiteralNumberFloat, Pop(1)}, + {`[0-9]+\.(?!(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+)|\.\.)`, LiteralNumberFloat, Pop(1)}, + {`0x[0-9a-fA-F]+`, LiteralNumberHex, Pop(1)}, + {`[0-9]+`, LiteralNumberInteger, Pop(1)}, + {`'`, LiteralStringSingle, Push("#pop", "string-single")}, + {`"`, LiteralStringDouble, Push("#pop", "string-double")}, + {`~/(\\\\|\\/|[^/\n])*/[gim]*`, LiteralStringRegex, Pop(1)}, + {`\[`, Operator, Push("#pop", "array-decl")}, + Include("type"), + }, + "type-param": { + Include("spaces"), + Default(Pop(1), Push("type-param-sep"), Push("type-param-type")), + }, + "type-param-sep": { + Include("spaces"), + {`>`, Punctuation, Pop(1)}, + {`,`, Punctuation, Push("#pop", "type-param")}, + }, + "type-param-constraint": { + Include("spaces"), + {`<(?!=)`, Punctuation, Push("#pop", "type-param-constraint-sep", "type-param-constraint-flag", "type-name")}, + Default(Pop(1)), + }, + "type-param-constraint-sep": { + Include("spaces"), + {`>`, Punctuation, Pop(1)}, + {`,`, Punctuation, Push("#pop", "type-param-constraint-sep", "type-param-constraint-flag", "type-name")}, + }, + "type-param-constraint-flag": { + Include("spaces"), + {`:`, Punctuation, Push("#pop", "type-param-constraint-flag-type")}, + Default(Pop(1)), + }, + "type-param-constraint-flag-type": { + Include("spaces"), + {`\(`, Punctuation, Push("#pop", "type-param-constraint-flag-type-sep", "type")}, + Default(Pop(1), Push("type")), + }, + "type-param-constraint-flag-type-sep": { + Include("spaces"), + {`\)`, Punctuation, Pop(1)}, + {`,`, Punctuation, Push("type")}, + }, + "parenthesis": { + Include("spaces"), + Default(Pop(1), Push("parenthesis-close"), Push("flag"), Push("expr")), + }, + "parenthesis-open": { + Include("spaces"), + {`\(`, Punctuation, Pop(1)}, + }, + "parenthesis-close": { + Include("spaces"), + {`\)`, Punctuation, Pop(1)}, + }, + "var": { + Include("spaces"), + {`(?!(?:function|class|static|var|if|else|while|do|for|break|return|continue|extends|implements|import|switch|case|default|public|private|try|untyped|catch|new|this|throw|extern|enum|in|interface|cast|override|dynamic|typedef|package|inline|using|null|true|false|abstract)\b)(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+)`, Text, Push("#pop", "var-sep", "assign", "flag", "prop-get-set")}, + }, + "var-sep": { + Include("spaces"), + {`,`, Punctuation, Push("#pop", "var")}, + Default(Pop(1)), + }, + "assign": { + Include("spaces"), + {`=`, Operator, Push("#pop", "expr")}, + Default(Pop(1)), + }, + "flag": { + Include("spaces"), + {`:`, Punctuation, Push("#pop", "type")}, + Default(Pop(1)), + }, + "ternary": { + Include("spaces"), + {`:`, Operator, Pop(1)}, + }, + "call": { + Include("spaces"), + {`\)`, Punctuation, Pop(1)}, + Default(Pop(1), Push("call-sep"), Push("expr")), + }, + "call-sep": { + Include("spaces"), + {`\)`, Punctuation, Pop(1)}, + {`,`, Punctuation, Push("#pop", "call")}, + }, + "bracket": { + Include("spaces"), + {`(?!(?:\$\s*[a-z]\b|\$(?!(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+))))(?!(?:function|class|static|var|if|else|while|do|for|break|return|continue|extends|implements|import|switch|case|default|public|private|try|untyped|catch|new|this|throw|extern|enum|in|interface|cast|override|dynamic|typedef|package|inline|using|null|true|false|abstract)\b)(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+)`, Name, Push("#pop", "bracket-check")}, + {`'`, LiteralStringSingle, Push("#pop", "bracket-check", "string-single")}, + {`"`, LiteralStringDouble, Push("#pop", "bracket-check", "string-double")}, + Default(Pop(1), Push("block")), + }, + "bracket-check": { + Include("spaces"), + {`:`, Punctuation, Push("#pop", "object-sep", "expr")}, + Default(Pop(1), Push("block"), Push("optional-semicolon"), Push("expr-chain")), + }, + "block": { + Include("spaces"), + {`\}`, Punctuation, Pop(1)}, + Default(Push("expr-statement")), + }, + "object": { + Include("spaces"), + {`\}`, Punctuation, Pop(1)}, + Default(Pop(1), Push("object-sep"), Push("expr"), Push("colon"), Push("ident-or-string")), + }, + "ident-or-string": { + Include("spaces"), + {`(?!(?:function|class|static|var|if|else|while|do|for|break|return|continue|extends|implements|import|switch|case|default|public|private|try|untyped|catch|new|this|throw|extern|enum|in|interface|cast|override|dynamic|typedef|package|inline|using|null|true|false|abstract)\b)(?:_*[a-z]\w*|_+[0-9]\w*|_*[A-Z]\w*|_+|\$\w+)`, Name, Pop(1)}, + {`'`, LiteralStringSingle, Push("#pop", "string-single")}, + {`"`, LiteralStringDouble, Push("#pop", "string-double")}, + }, + "object-sep": { + Include("spaces"), + {`\}`, Punctuation, Pop(1)}, + {`,`, Punctuation, Push("#pop", "object")}, + }, + } +} + +func haxePreProcMutator(state *LexerState) error { + stack, ok := state.Get("haxe-pre-proc").([][]string) + if !ok { + stack = [][]string{} + } + + proc := state.Groups[2] + switch proc { + case "if": + stack = append(stack, state.Stack) + case "else", "elseif": + if len(stack) > 0 { + state.Stack = stack[len(stack)-1] + } + case "end": + if len(stack) > 0 { + stack = stack[:len(stack)-1] + } + } + + if proc == "if" || proc == "elseif" { + state.Stack = append(state.Stack, "preproc-expr") + } + + if proc == "error" { + state.Stack = append(state.Stack, "preproc-error") + } + state.Set("haxe-pre-proc", stack) + return nil +} diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/html.go b/vendor/github.com/alecthomas/chroma/v2/lexers/html.go new file mode 100644 index 000000000..c858042bf --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/html.go @@ -0,0 +1,8 @@ +package lexers + +import ( + "github.com/alecthomas/chroma/v2" +) + +// HTML lexer. +var HTML = chroma.MustNewXMLLexer(embedded, "embedded/html.xml") diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/http.go b/vendor/github.com/alecthomas/chroma/v2/lexers/http.go new file mode 100644 index 000000000..b57cb1b84 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/http.go @@ -0,0 +1,131 @@ +package lexers + +import ( + "strings" + + . "github.com/alecthomas/chroma/v2" // nolint +) + +// HTTP lexer. +var HTTP = Register(httpBodyContentTypeLexer(MustNewLexer( + &Config{ + Name: "HTTP", + Aliases: []string{"http"}, + Filenames: []string{}, + MimeTypes: []string{}, + NotMultiline: true, + DotAll: true, + }, + httpRules, +))) + +func httpRules() Rules { + return Rules{ + "root": { + {`(GET|POST|PUT|DELETE|HEAD|OPTIONS|TRACE|PATCH|CONNECT)( +)([^ ]+)( +)(HTTP)(/)([123](?:\.[01])?)(\r?\n|\Z)`, ByGroups(NameFunction, Text, NameNamespace, Text, KeywordReserved, Operator, LiteralNumber, Text), Push("headers")}, + {`(HTTP)(/)([123](?:\.[01])?)( +)(\d{3})( *)([^\r\n]*)(\r?\n|\Z)`, ByGroups(KeywordReserved, Operator, LiteralNumber, Text, LiteralNumber, Text, NameException, Text), Push("headers")}, + }, + "headers": { + {`([^\s:]+)( *)(:)( *)([^\r\n]+)(\r?\n|\Z)`, EmitterFunc(httpHeaderBlock), nil}, + {`([\t ]+)([^\r\n]+)(\r?\n|\Z)`, EmitterFunc(httpContinuousHeaderBlock), nil}, + {`\r?\n`, Text, Push("content")}, + }, + "content": { + {`.+`, EmitterFunc(httpContentBlock), nil}, + }, + } +} + +func httpContentBlock(groups []string, state *LexerState) Iterator { + tokens := []Token{ + {Generic, groups[0]}, + } + return Literator(tokens...) +} + +func httpHeaderBlock(groups []string, state *LexerState) Iterator { + tokens := []Token{ + {Name, groups[1]}, + {Text, groups[2]}, + {Operator, groups[3]}, + {Text, groups[4]}, + {Literal, groups[5]}, + {Text, groups[6]}, + } + return Literator(tokens...) +} + +func httpContinuousHeaderBlock(groups []string, state *LexerState) Iterator { + tokens := []Token{ + {Text, groups[1]}, + {Literal, groups[2]}, + {Text, groups[3]}, + } + return Literator(tokens...) +} + +func httpBodyContentTypeLexer(lexer Lexer) Lexer { return &httpBodyContentTyper{lexer} } + +type httpBodyContentTyper struct{ Lexer } + +func (d *httpBodyContentTyper) Tokenise(options *TokeniseOptions, text string) (Iterator, error) { // nolint: gocognit + var contentType string + var isContentType bool + var subIterator Iterator + + it, err := d.Lexer.Tokenise(options, text) + if err != nil { + return nil, err + } + + return func() Token { + token := it() + + if token == EOF { + if subIterator != nil { + return subIterator() + } + return EOF + } + + switch { + case token.Type == Name && strings.ToLower(token.Value) == "content-type": + { + isContentType = true + } + case token.Type == Literal && isContentType: + { + isContentType = false + contentType = strings.TrimSpace(token.Value) + pos := strings.Index(contentType, ";") + if pos > 0 { + contentType = strings.TrimSpace(contentType[:pos]) + } + } + case token.Type == Generic && contentType != "": + { + lexer := MatchMimeType(contentType) + + // application/calendar+xml can be treated as application/xml + // if there's not a better match. + if lexer == nil && strings.Contains(contentType, "+") { + slashPos := strings.Index(contentType, "/") + plusPos := strings.LastIndex(contentType, "+") + contentType = contentType[:slashPos+1] + contentType[plusPos+1:] + lexer = MatchMimeType(contentType) + } + + if lexer == nil { + token.Type = Text + } else { + subIterator, err = lexer.Tokenise(nil, token.Value) + if err != nil { + panic(err) + } + return EOF + } + } + } + return token + }, nil +} diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/lexers.go b/vendor/github.com/alecthomas/chroma/v2/lexers/lexers.go new file mode 100644 index 000000000..bef42edec --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/lexers.go @@ -0,0 +1,85 @@ +package lexers + +import ( + "embed" + "io/fs" + + "github.com/alecthomas/chroma/v2" +) + +//go:embed embedded +var embedded embed.FS + +// GlobalLexerRegistry is the global LexerRegistry of Lexers. +var GlobalLexerRegistry = func() *chroma.LexerRegistry { + reg := chroma.NewLexerRegistry() + // index(reg) + paths, err := fs.Glob(embedded, "embedded/*.xml") + if err != nil { + panic(err) + } + for _, path := range paths { + reg.Register(chroma.MustNewXMLLexer(embedded, path)) + } + return reg +}() + +// Names of all lexers, optionally including aliases. +func Names(withAliases bool) []string { + return GlobalLexerRegistry.Names(withAliases) +} + +// Aliases of all the lexers, and skip those lexers who do not have any aliases, +// or show their name instead +func Aliases(skipWithoutAliases bool) []string { + return GlobalLexerRegistry.Aliases(skipWithoutAliases) +} + +// Get a Lexer by name, alias or file extension. +// +// Note that this if there isn't an exact match on name or alias, this will +// call Match(), so it is not efficient. +func Get(name string) chroma.Lexer { + return GlobalLexerRegistry.Get(name) +} + +// MatchMimeType attempts to find a lexer for the given MIME type. +func MatchMimeType(mimeType string) chroma.Lexer { + return GlobalLexerRegistry.MatchMimeType(mimeType) +} + +// Match returns the first lexer matching filename. +// +// Note that this iterates over all file patterns in all lexers, so it's not +// particularly efficient. +func Match(filename string) chroma.Lexer { + return GlobalLexerRegistry.Match(filename) +} + +// Register a Lexer with the global registry. +func Register(lexer chroma.Lexer) chroma.Lexer { + return GlobalLexerRegistry.Register(lexer) +} + +// Analyse text content and return the "best" lexer.. +func Analyse(text string) chroma.Lexer { + return GlobalLexerRegistry.Analyse(text) +} + +// PlaintextRules is used for the fallback lexer as well as the explicit +// plaintext lexer. +func PlaintextRules() chroma.Rules { + return chroma.Rules{ + "root": []chroma.Rule{ + {`.+`, chroma.Text, nil}, + {`\n`, chroma.Text, nil}, + }, + } +} + +// Fallback lexer if no other is found. +var Fallback chroma.Lexer = chroma.MustNewLexer(&chroma.Config{ + Name: "fallback", + Filenames: []string{"*"}, + Priority: -1, +}, PlaintextRules) diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/markdown.go b/vendor/github.com/alecthomas/chroma/v2/lexers/markdown.go new file mode 100644 index 000000000..bcd5b1784 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/markdown.go @@ -0,0 +1,46 @@ +package lexers + +import ( + . "github.com/alecthomas/chroma/v2" // nolint +) + +// Markdown lexer. +var Markdown = Register(MustNewLexer( + &Config{ + Name: "markdown", + Aliases: []string{"md", "mkd"}, + Filenames: []string{"*.md", "*.mkd", "*.markdown"}, + MimeTypes: []string{"text/x-markdown"}, + }, + markdownRules, +)) + +func markdownRules() Rules { + return Rules{ + "root": { + {`^(#[^#].+\n)`, ByGroups(GenericHeading), nil}, + {`^(#{2,6}.+\n)`, ByGroups(GenericSubheading), nil}, + {`^(\s*)([*-] )(\[[ xX]\])( .+\n)`, ByGroups(Text, Keyword, Keyword, UsingSelf("inline")), nil}, + {`^(\s*)([*-])(\s)(.+\n)`, ByGroups(Text, Keyword, Text, UsingSelf("inline")), nil}, + {`^(\s*)([0-9]+\.)( .+\n)`, ByGroups(Text, Keyword, UsingSelf("inline")), nil}, + {`^(\s*>\s)(.+\n)`, ByGroups(Keyword, GenericEmph), nil}, + {"^(```\\n)([\\w\\W]*?)(^```$)", ByGroups(String, Text, String), nil}, + { + "^(```)(\\w+)(\\n)([\\w\\W]*?)(^```$)", + UsingByGroup(2, 4, String, String, String, Text, String), + nil, + }, + Include("inline"), + }, + "inline": { + {`\\.`, Text, nil}, + {`(\s)(\*|_)((?:(?!\2).)*)(\2)((?=\W|\n))`, ByGroups(Text, GenericEmph, GenericEmph, GenericEmph, Text), nil}, + {`(\s)((\*\*|__).*?)\3((?=\W|\n))`, ByGroups(Text, GenericStrong, GenericStrong, Text), nil}, + {`(\s)(~~[^~]+~~)((?=\W|\n))`, ByGroups(Text, GenericDeleted, Text), nil}, + {"`[^`]+`", LiteralStringBacktick, nil}, + {`[@#][\w/:]+`, NameEntity, nil}, + {`(!?\[)([^]]+)(\])(\()([^)]+)(\))`, ByGroups(Text, NameTag, Text, Text, NameAttribute, Text), nil}, + {`.|\n`, Text, nil}, + }, + } +} diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/markless.go b/vendor/github.com/alecthomas/chroma/v2/lexers/markless.go new file mode 100644 index 000000000..508513d78 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/markless.go @@ -0,0 +1,168 @@ +package lexers + +import ( + . "github.com/alecthomas/chroma/v2" // nolint +) + +// Markless lexer. +var Markless = Register(MustNewLexer( + &Config{ + Name: "Markless", + Aliases: []string{"mess"}, + Filenames: []string{"*.mess", "*.markless"}, + MimeTypes: []string{"text/x-markless"}, + }, + marklessRules, +)) + +func marklessRules() Rules { + return Rules{ + "root": { + Include("block"), + }, + // Block directives + "block": { + Include("header"), + Include("ordered-list"), + Include("unordered-list"), + Include("code-block"), + Include("blockquote"), + Include("blockquote-header"), + Include("align"), + Include("comment"), + Include("instruction"), + Include("embed"), + Include("footnote"), + Include("horizontal-rule"), + Include("paragraph"), + }, + "header": { + {`(# )(.*)$`, ByGroups(Keyword, GenericHeading), Push("inline")}, + {`(##+)(.*)$`, ByGroups(Keyword, GenericSubheading), Push("inline")}, + }, + "ordered-list": { + {`([0-9]+\.)`, Keyword, nil}, + }, + "unordered-list": { + {`(- )`, Keyword, nil}, + }, + "code-block": { + {`(::+)( *)(\w*)([^\n]*)(\n)([\w\W]*?)(^\1$)`, UsingByGroup(3, 6, Keyword, TextWhitespace, NameFunction, String, TextWhitespace, Text, Keyword), nil}, + }, + "blockquote": { + {`(\| )(.*)$`, ByGroups(Keyword, GenericInserted), nil}, + }, + "blockquote-header": { + {`(~ )([^|\n]+)(\| )(.*?\n)`, ByGroups(Keyword, NameEntity, Keyword, GenericInserted), Push("inline-blockquote")}, + {`(~ )(.*)$`, ByGroups(Keyword, NameEntity), nil}, + }, + "inline-blockquote": { + {`^( +)(\| )(.*$)`, ByGroups(TextWhitespace, Keyword, GenericInserted), nil}, + Default(Pop(1)), + }, + "align": { + {`(\|\|)|(\|<)|(\|>)|(><)`, Keyword, nil}, + }, + "comment": { + {`(;[; ]).*?$`, CommentSingle, nil}, + }, + "instruction": { + {`(! )([^ ]+)(.+?)$`, ByGroups(Keyword, NameFunction, NameVariable), nil}, + }, + "embed": { + {`(\[ )([^ ]+)( )([^,]+)`, ByGroups(Keyword, NameFunction, TextWhitespace, String), Push("embed-options")}, + }, + "embed-options": { + {`\\.`, Text, nil}, + {`,`, Punctuation, nil}, + {`\]?$`, Keyword, Pop(1)}, + // Generic key or key/value pair + {`( *)([^, \]]+)([^,\]]+)?`, ByGroups(TextWhitespace, NameFunction, String), nil}, + {`.`, Text, nil}, + }, + "footnote": { + {`(\[)([0-9]+)(\])`, ByGroups(Keyword, NameVariable, Keyword), Push("inline")}, + }, + "horizontal-rule": { + {`(==+)$`, LiteralOther, nil}, + }, + "paragraph": { + {` *`, TextWhitespace, Push("inline")}, + }, + // Inline directives + "inline": { + Include("escapes"), + Include("dashes"), + Include("newline"), + Include("italic"), + Include("underline"), + Include("bold"), + Include("strikethrough"), + Include("code"), + Include("compound"), + Include("footnote-reference"), + Include("subtext"), + Include("subtext"), + Include("url"), + {`.`, Text, nil}, + {`\n`, TextWhitespace, Pop(1)}, + }, + "escapes": { + {`\\.`, Text, nil}, + }, + "dashes": { + {`-{2,3}`, TextPunctuation, nil}, + }, + "newline": { + {`-/-`, TextWhitespace, nil}, + }, + "italic": { + {`(//)(.*?)(\1)`, ByGroups(Keyword, GenericEmph, Keyword), nil}, + }, + "underline": { + {`(__)(.*?)(\1)`, ByGroups(Keyword, GenericUnderline, Keyword), nil}, + }, + "bold": { + {`(\*\*)(.*?)(\1)`, ByGroups(Keyword, GenericStrong, Keyword), nil}, + }, + "strikethrough": { + {`(<-)(.*?)(->)`, ByGroups(Keyword, GenericDeleted, Keyword), nil}, + }, + "code": { + {"(``+)(.*?)(\\1)", ByGroups(Keyword, LiteralStringBacktick, Keyword), nil}, + }, + "compound": { + {`(''+)(.*?)(''\()`, ByGroups(Keyword, UsingSelf("inline"), Keyword), Push("compound-options")}, + }, + "compound-options": { + {`\\.`, Text, nil}, + {`,`, Punctuation, nil}, + {`\)`, Keyword, Pop(1)}, + // Hex Color + {` *#[0-9A-Fa-f]{3,6} *`, LiteralNumberHex, nil}, + // Named Color + {` *(indian-red|light-coral|salmon|dark-salmon|light-salmon|crimson|red|firebrick|dark-red|pink|light-pink|hot-pink|deep-pink|medium-violet-red|pale-violet-red|coral|tomato|orange-red|dark-orange|orange|gold|yellow|light-yellow|lemon-chiffon|light-goldenrod-yellow|papayawhip|moccasin|peachpuff|pale-goldenrod|khaki|dark-khaki|lavender|thistle|plum|violet|orchid|fuchsia|magenta|medium-orchid|medium-purple|rebecca-purple|blue-violet|dark-violet|dark-orchid|dark-magenta|purple|indigo|slate-blue|dark-slate-blue|medium-slate-blue|green-yellow|chartreuse|lawn-green|lime|lime-green|pale-green|light-green|medium-spring-green|spring-green|medium-sea-green|sea-green|forest-green|green|dark-green|yellow-green|olive-drab|olive|dark-olive-green|medium-aquamarine|dark-sea-green|light-sea-green|dark-cyan|teal|aqua|cyan|light-cyan|pale-turquoise|aquamarine|turquoise|medium-turquoise|dark-turquoise|cadet-blue|steel-blue|light-steel-blue|powder-blue|light-blue|sky-blue|light-sky-blue|deep-sky-blue|dodger-blue|cornflower-blue|royal-blue|blue|medium-blue|dark-blue|navy|midnight-blue|cornsilk|blanched-almond|bisque|navajo-white|wheat|burlywood|tan|rosy-brown|sandy-brown|goldenrod|dark-goldenrod|peru|chocolate|saddle-brown|sienna|brown|maroon|white|snow|honeydew|mintcream|azure|alice-blue|ghost-white|white-smoke|seashell|beige|oldlace|floral-white|ivory|antique-white|linen|lavenderblush|mistyrose|gainsboro|light-gray|silver|dark-gray|gray|dim-gray|light-slate-gray|slate-gray|dark-slate-gray) *`, LiteralOther, nil}, + // Named size + {` *(microscopic|tiny|small|normal|big|large|huge|gigantic) *`, NameTag, nil}, + // Options + {` *(bold|italic|underline|strikethrough|subtext|supertext|spoiler) *`, NameBuiltin, nil}, + // URL. Note the missing ) and , in the match. + {` *\w[-\w+.]*://[\w$\-_.+!*'(&/:;=?@z%#\\]+ *`, String, nil}, + // Generic key or key/value pair + {`( *)([^, )]+)( [^,)]+)?`, ByGroups(TextWhitespace, NameFunction, String), nil}, + {`.`, Text, nil}, + }, + "footnote-reference": { + {`(\[)([0-9]+)(\])`, ByGroups(Keyword, NameVariable, Keyword), nil}, + }, + "subtext": { + {`(v\()(.*?)(\))`, ByGroups(Keyword, UsingSelf("inline"), Keyword), nil}, + }, + "supertext": { + {`(\^\()(.*?)(\))`, ByGroups(Keyword, UsingSelf("inline"), Keyword), nil}, + }, + "url": { + {`\w[-\w+.]*://[\w\$\-_.+!*'()&,/:;=?@z%#\\]+`, String, nil}, + }, + } +} diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/mysql.go b/vendor/github.com/alecthomas/chroma/v2/lexers/mysql.go new file mode 100644 index 000000000..32e94c2f2 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/mysql.go @@ -0,0 +1,33 @@ +package lexers + +import ( + "regexp" +) + +var ( + mysqlAnalyserNameBetweenBacktickRe = regexp.MustCompile("`[a-zA-Z_]\\w*`") + mysqlAnalyserNameBetweenBracketRe = regexp.MustCompile(`\[[a-zA-Z_]\w*\]`) +) + +func init() { // nolint: gochecknoinits + Get("mysql"). + SetAnalyser(func(text string) float32 { + nameBetweenBacktickCount := len(mysqlAnalyserNameBetweenBacktickRe.FindAllString(text, -1)) + nameBetweenBracketCount := len(mysqlAnalyserNameBetweenBracketRe.FindAllString(text, -1)) + + var result float32 + + // Same logic as above in the TSQL analysis. + dialectNameCount := nameBetweenBacktickCount + nameBetweenBracketCount + if dialectNameCount >= 1 && nameBetweenBacktickCount >= (2*nameBetweenBracketCount) { + // Found at least twice as many `name` as [name]. + result += 0.5 + } else if nameBetweenBacktickCount > nameBetweenBracketCount { + result += 0.2 + } else if nameBetweenBacktickCount > 0 { + result += 0.1 + } + + return result + }) +} diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/php.go b/vendor/github.com/alecthomas/chroma/v2/lexers/php.go new file mode 100644 index 000000000..ff82f6eaf --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/php.go @@ -0,0 +1,37 @@ +package lexers + +import ( + "strings" + + . "github.com/alecthomas/chroma/v2" // nolint +) + +// phtml lexer is PHP in HTML. +var _ = Register(DelegatingLexer(HTML, MustNewLexer( + &Config{ + Name: "PHTML", + Aliases: []string{"phtml"}, + Filenames: []string{"*.phtml", "*.php", "*.php[345]", "*.inc"}, + MimeTypes: []string{"application/x-php", "application/x-httpd-php", "application/x-httpd-php3", "application/x-httpd-php4", "application/x-httpd-php5", "text/x-php"}, + DotAll: true, + CaseInsensitive: true, + EnsureNL: true, + Priority: 2, + }, + func() Rules { + return Get("PHP").(*RegexLexer).MustRules(). + Rename("root", "php"). + Merge(Rules{ + "root": { + {`<\?(php)?`, CommentPreproc, Push("php")}, + {`[^<]+`, Other, nil}, + {`<`, Other, nil}, + }, + }) + }, +).SetAnalyser(func(text string) float32 { + if strings.Contains(text, ">|>|»|\)|\]|\})` + colonPairPattern = `(?:)(?\w[\w'-]*)(?` + colonPairOpeningBrackets + `)` + colonPairLookahead = `(?=(:['\w-]+` + + colonPairOpeningBrackets + `.+?` + colonPairClosingBrackets + `)?` + namePattern = `(?:(?!` + colonPairPattern + `)(?:::|[\w':-]))+` + variablePattern = `[$@%&]+[.^:?=!~]?` + namePattern + globalVariablePattern = `[$@%&]+\*` + namePattern + ) + + keywords := []string{ + `BEGIN`, `CATCH`, `CHECK`, `CLOSE`, `CONTROL`, `DOC`, `END`, `ENTER`, `FIRST`, `INIT`, + `KEEP`, `LAST`, `LEAVE`, `NEXT`, `POST`, `PRE`, `QUIT`, `UNDO`, `anon`, `augment`, `but`, + `class`, `constant`, `default`, `does`, `else`, `elsif`, `enum`, `for`, `gather`, `given`, + `grammar`, `has`, `if`, `import`, `is`, `of`, `let`, `loop`, `made`, `make`, `method`, + `module`, `multi`, `my`, `need`, `orwith`, `our`, `proceed`, `proto`, `repeat`, `require`, + `where`, `return`, `return-rw`, `returns`, `->`, `-->`, `role`, `state`, `sub`, `no`, + `submethod`, `subset`, `succeed`, `supersede`, `try`, `unit`, `unless`, `until`, + `use`, `when`, `while`, `with`, `without`, `export`, `native`, `repr`, `required`, `rw`, + `symbol`, `default`, `cached`, `DEPRECATED`, `dynamic`, `hidden-from-backtrace`, `nodal`, + `pure`, `raw`, `start`, `react`, `supply`, `whenever`, `also`, `rule`, `token`, `regex`, + `dynamic-scope`, `built`, `temp`, + } + + keywordsPattern := Words(`(?)`, `(>=)`, `minmax`, `notandthen`, `S`, + } + + wordOperatorsPattern := Words(`(?<=^|\b|\s)`, `(?=$|\b|\s)`, wordOperators...) + + operators := []string{ + `++`, `--`, `-`, `**`, `!`, `+`, `~`, `?`, `+^`, `~^`, `?^`, `^`, `*`, `/`, `%`, `%%`, `+&`, + `+<`, `+>`, `~&`, `~<`, `~>`, `?&`, `+|`, `+^`, `~|`, `~^`, `?`, `?|`, `?^`, `&`, `^`, + `<=>`, `^…^`, `^…`, `…^`, `…`, `...`, `...^`, `^...`, `^...^`, `..`, `..^`, `^..`, `^..^`, + `::=`, `:=`, `!=`, `==`, `<=`, `<`, `>=`, `>`, `~~`, `===`, `&&`, `||`, `|`, `^^`, `//`, + `??`, `!!`, `^fff^`, `^ff^`, `<==`, `==>`, `<<==`, `==>>`, `=>`, `=`, `<<`, `«`, `>>`, `»`, + `,`, `>>.`, `».`, `.&`, `.=`, `.^`, `.?`, `.+`, `.*`, `.`, `∘`, `∩`, `⊍`, `∪`, `⊎`, `∖`, + `⊖`, `≠`, `≤`, `≥`, `=:=`, `=~=`, `≅`, `∈`, `∉`, `≡`, `≢`, `∋`, `∌`, `⊂`, `⊄`, `⊆`, `⊈`, + `⊃`, `⊅`, `⊇`, `⊉`, `:`, `!!!`, `???`, `¯`, `×`, `÷`, `−`, `⁺`, `⁻`, + } + + operatorsPattern := Words(``, ``, operators...) + + builtinTypes := []string{ + `False`, `True`, `Order`, `More`, `Less`, `Same`, `Any`, `Array`, `Associative`, `AST`, + `atomicint`, `Attribute`, `Backtrace`, `Backtrace::Frame`, `Bag`, `Baggy`, `BagHash`, + `Blob`, `Block`, `Bool`, `Buf`, `Callable`, `CallFrame`, `Cancellation`, `Capture`, + `CArray`, `Channel`, `Code`, `compiler`, `Complex`, `ComplexStr`, `CompUnit`, + `CompUnit::PrecompilationRepository`, `CompUnit::Repository`, `Empty`, + `CompUnit::Repository::FileSystem`, `CompUnit::Repository::Installation`, `Cool`, + `CurrentThreadScheduler`, `CX::Warn`, `CX::Take`, `CX::Succeed`, `CX::Return`, `CX::Redo`, + `CX::Proceed`, `CX::Next`, `CX::Last`, `CX::Emit`, `CX::Done`, `Cursor`, `Date`, `Dateish`, + `DateTime`, `Distribution`, `Distribution::Hash`, `Distribution::Locally`, + `Distribution::Path`, `Distribution::Resource`, `Distro`, `Duration`, `Encoding`, + `Encoding::GlobalLexerRegistry`, `Endian`, `Enumeration`, `Exception`, `Failure`, `FatRat`, `Grammar`, + `Hash`, `HyperWhatever`, `Instant`, `Int`, `int`, `int16`, `int32`, `int64`, `int8`, `str`, + `IntStr`, `IO`, `IO::ArgFiles`, `IO::CatHandle`, `IO::Handle`, `IO::Notification`, + `IO::Notification::Change`, `IO::Path`, `IO::Path::Cygwin`, `IO::Path::Parts`, + `IO::Path::QNX`, `IO::Path::Unix`, `IO::Path::Win32`, `IO::Pipe`, `IO::Socket`, + `IO::Socket::Async`, `IO::Socket::Async::ListenSocket`, `IO::Socket::INET`, `IO::Spec`, + `IO::Spec::Cygwin`, `IO::Spec::QNX`, `IO::Spec::Unix`, `IO::Spec::Win32`, `IO::Special`, + `Iterable`, `Iterator`, `Junction`, `Kernel`, `Label`, `List`, `Lock`, `Lock::Async`, + `Lock::ConditionVariable`, `long`, `longlong`, `Macro`, `Map`, `Match`, + `Metamodel::AttributeContainer`, `Metamodel::C3MRO`, `Metamodel::ClassHOW`, + `Metamodel::ConcreteRoleHOW`, `Metamodel::CurriedRoleHOW`, `Metamodel::DefiniteHOW`, + `Metamodel::Documenting`, `Metamodel::EnumHOW`, `Metamodel::Finalization`, + `Metamodel::MethodContainer`, `Metamodel::Mixins`, `Metamodel::MROBasedMethodDispatch`, + `Metamodel::MultipleInheritance`, `Metamodel::Naming`, `Metamodel::Primitives`, + `Metamodel::PrivateMethodContainer`, `Metamodel::RoleContainer`, `Metamodel::RolePunning`, + `Metamodel::Stashing`, `Metamodel::Trusting`, `Metamodel::Versioning`, `Method`, `Mix`, + `MixHash`, `Mixy`, `Mu`, `NFC`, `NFD`, `NFKC`, `NFKD`, `Nil`, `Num`, `num32`, `num64`, + `Numeric`, `NumStr`, `ObjAt`, `Order`, `Pair`, `Parameter`, `Perl`, `Pod::Block`, + `Pod::Block::Code`, `Pod::Block::Comment`, `Pod::Block::Declarator`, `Pod::Block::Named`, + `Pod::Block::Para`, `Pod::Block::Table`, `Pod::Heading`, `Pod::Item`, `Pointer`, + `Positional`, `PositionalBindFailover`, `Proc`, `Proc::Async`, `Promise`, `Proxy`, + `PseudoStash`, `QuantHash`, `RaceSeq`, `Raku`, `Range`, `Rat`, `Rational`, `RatStr`, + `Real`, `Regex`, `Routine`, `Routine::WrapHandle`, `Scalar`, `Scheduler`, `Semaphore`, + `Seq`, `Sequence`, `Set`, `SetHash`, `Setty`, `Signature`, `size_t`, `Slip`, `Stash`, + `Str`, `StrDistance`, `Stringy`, `Sub`, `Submethod`, `Supplier`, `Supplier::Preserving`, + `Supply`, `Systemic`, `Tap`, `Telemetry`, `Telemetry::Instrument::Thread`, + `Telemetry::Instrument::ThreadPool`, `Telemetry::Instrument::Usage`, `Telemetry::Period`, + `Telemetry::Sampler`, `Thread`, `Test`, `ThreadPoolScheduler`, `UInt`, `uint16`, `uint32`, + `uint64`, `uint8`, `Uni`, `utf8`, `ValueObjAt`, `Variable`, `Version`, `VM`, `Whatever`, + `WhateverCode`, `WrapHandle`, `NativeCall`, + // Pragmas + `precompilation`, `experimental`, `worries`, `MONKEY-TYPING`, `MONKEY-SEE-NO-EVAL`, + `MONKEY-GUTS`, `fatal`, `lib`, `isms`, `newline`, `nqp`, `soft`, + `strict`, `trace`, `variables`, + } + + builtinTypesPattern := Words(`(? 0 { + if tokenClass == rakuPod { + match, err := podRegex.FindRunesMatchStartingAt(text, searchPos+nChars) + if err == nil { + closingChars = match.Runes() + nextClosePos = match.Index + } else { + nextClosePos = -1 + } + } else { + nextClosePos = indexAt(text, closingChars, searchPos+nChars) + } + + nextOpenPos := indexAt(text, openingChars, searchPos+nChars) + + switch { + case nextClosePos == -1: + nextClosePos = len(text) + nestingLevel = 0 + case nextOpenPos != -1 && nextOpenPos < nextClosePos: + nestingLevel++ + nChars = len(openingChars) + searchPos = nextOpenPos + default: // next_close_pos < next_open_pos + nestingLevel-- + nChars = len(closingChars) + searchPos = nextClosePos + } + } + + endPos = nextClosePos + } + + if endPos < 0 { + // if we didn't find a closer, just highlight the + // rest of the text in this class + endPos = len(text) + } + + adverbre := regexp.MustCompile(`:to\b|:heredoc\b`) + var heredocTerminator []rune + var endHeredocPos int + if adverbre.MatchString(string(adverbs)) { + if endPos != len(text) { + heredocTerminator = text[state.Pos:endPos] + nChars = len(heredocTerminator) + } else { + endPos = state.Pos + 1 + heredocTerminator = []rune{} + nChars = 0 + } + + if nChars > 0 { + endHeredocPos = indexAt(text[endPos:], heredocTerminator, 0) + if endHeredocPos > -1 { + endPos += endHeredocPos + } else { + endPos = len(text) + } + } + } + + textBetweenBrackets := string(text[state.Pos:endPos]) + switch tokenClass { + case rakuPod, rakuPodDeclaration, rakuNameAttribute: + state.NamedGroups[`value`] = textBetweenBrackets + state.NamedGroups[`closing_delimiters`] = string(closingChars) + case rakuQuote: + if len(heredocTerminator) > 0 { + // Length of heredoc terminator + closing chars + `;` + heredocFristPunctuationLen := nChars + len(openingChars) + 1 + + state.NamedGroups[`opening_delimiters`] = string(openingChars) + + string(text[state.Pos:state.Pos+heredocFristPunctuationLen]) + + state.NamedGroups[`value`] = + string(text[state.Pos+heredocFristPunctuationLen : endPos]) + + if endHeredocPos > -1 { + state.NamedGroups[`closing_delimiters`] = string(heredocTerminator) + } + } else { + state.NamedGroups[`value`] = textBetweenBrackets + if nChars > 0 { + state.NamedGroups[`closing_delimiters`] = string(closingChars) + } + } + default: + state.Groups = []string{state.Groups[0] + string(text[state.Pos:endPos+nChars])} + } + + state.Pos = endPos + nChars + + return nil + } + } + + // Raku rules + // Empty capture groups are placeholders and will be replaced by mutators + // DO NOT REMOVE THEM! + return Rules{ + "root": { + // Placeholder, will be overwritten by mutators, DO NOT REMOVE! + {`\A\z`, nil, nil}, + Include("common"), + {`{`, Punctuation, Push(`root`)}, + {`\(`, Punctuation, Push(`root`)}, + {`[)}]`, Punctuation, Pop(1)}, + {`;`, Punctuation, nil}, + {`\[|\]`, Operator, nil}, + {`.+?`, Text, nil}, + }, + "common": { + {`^#![^\n]*$`, CommentHashbang, nil}, + Include("pod"), + // Multi-line, Embedded comment + { + "#`(?(?" + bracketsPattern + `)\k*)`, + CommentMultiline, + findBrackets(rakuMultilineComment), + }, + {`#[^\n]*$`, CommentSingle, nil}, + // /regex/ + { + `(?<=(?:^|\(|=|:|~~|\[|{|,|=>)\s*)(/)(?!\]|\))((?:\\\\|\\/|.)*?)((?>)(\S+?)(<<)`, ByGroups(Operator, UsingSelf("root"), Operator), nil}, + {`(»)(\S+?)(«)`, ByGroups(Operator, UsingSelf("root"), Operator), nil}, + // Hyperoperator | «*« + {`(<<)(\S+?)(<<)`, ByGroups(Operator, UsingSelf("root"), Operator), nil}, + {`(«)(\S+?)(«)`, ByGroups(Operator, UsingSelf("root"), Operator), nil}, + // Hyperoperator | »*» + {`(>>)(\S+?)(>>)`, ByGroups(Operator, UsingSelf("root"), Operator), nil}, + {`(»)(\S+?)(»)`, ByGroups(Operator, UsingSelf("root"), Operator), nil}, + // <> + {`(?>)[^\n])+?[},;] *\n)(?!(?:(?!>>).)+?>>\S+?>>)`, Punctuation, Push("<<")}, + // «quoted words» + {`(? operators | something < onething > something + { + `(?<=[$@%&]?\w[\w':-]* +)(<=?)( *[^ ]+? *)(>=?)(?= *[$@%&]?\w[\w':-]*)`, + ByGroups(Operator, UsingSelf("root"), Operator), + nil, + }, + // + { + `(?])+?)(>)(?!\s*(?:\d+|\.(?:Int|Numeric)|[$@%]\*?\w[\w':-]*[^(]|\s+\[))`, + ByGroups(Punctuation, String, Punctuation), + nil, + }, + {`C?X::['\w:-]+`, NameException, nil}, + Include("metaoperator"), + // Pair | key => value + { + `(\w[\w'-]*)(\s*)(=>)`, + ByGroups(String, Text, Operator), + nil, + }, + Include("colon-pair"), + // Token + { + `(?<=(?:^|\s)(?:regex|token|rule)(\s+))` + namePattern + colonPairLookahead + `\s*[({])`, + NameFunction, + Push("token", "name-adverb"), + }, + // Substitution + {`(?<=^|\b|\s)(?(?:qq|q|Q))(?(?::?(?:heredoc|to|qq|ww|q|w|s|a|h|f|c|b|to|v|x))*)(?\s*)(?(?[^0-9a-zA-Z:\s])\k*)`, + EmitterFunc(quote), + findBrackets(rakuQuote), + }, + // Function + { + `\b` + namePattern + colonPairLookahead + `\()`, + NameFunction, + Push("name-adverb"), + }, + // Method + { + `(?(?[^\w:\s])\k*)`, + ByGroupNames( + map[string]Emitter{ + `opening_delimiters`: Punctuation, + `delimiter`: nil, + }, + ), + findBrackets(rakuMatchRegex), + }, + }, + "substitution": { + Include("colon-pair-attribute"), + // Substitution | s{regex} = value + { + `(?(?` + bracketsPattern + `)\k*)`, + ByGroupNames(map[string]Emitter{ + `opening_delimiters`: Punctuation, + `delimiter`: nil, + }), + findBrackets(rakuMatchRegex), + }, + // Substitution | s/regex/string/ + { + `(?[^\w:\s])`, + Punctuation, + findBrackets(rakuSubstitutionRegex), + }, + }, + "number": { + {`0_?[0-7]+(_[0-7]+)*`, LiteralNumberOct, nil}, + {`0x[0-9A-Fa-f]+(_[0-9A-Fa-f]+)*`, LiteralNumberHex, nil}, + {`0b[01]+(_[01]+)*`, LiteralNumberBin, nil}, + { + `(?i)(\d*(_\d*)*\.\d+(_\d*)*|\d+(_\d*)*\.\d+(_\d*)*)(e[+-]?\d+)?`, + LiteralNumberFloat, + nil, + }, + {`(?i)\d+(_\d*)*e[+-]?\d+(_\d*)*`, LiteralNumberFloat, nil}, + {`(?<=\d+)i`, NameConstant, nil}, + {`\d+(_\d+)*`, LiteralNumberInteger, nil}, + }, + "name-adverb": { + Include("colon-pair-attribute-keyvalue"), + Default(Pop(1)), + }, + "colon-pair": { + // :key(value) + {colonPairPattern, colonPair(String), findBrackets(rakuNameAttribute)}, + // :123abc + { + `(:)(\d+)(\w[\w'-]*)`, + ByGroups(Punctuation, UsingSelf("number"), String), + nil, + }, + // :key + {`(:)(!?)(\w[\w'-]*)`, ByGroups(Punctuation, Operator, String), nil}, + {`\s+`, Text, nil}, + }, + "colon-pair-attribute": { + // :key(value) + {colonPairPattern, colonPair(NameAttribute), findBrackets(rakuNameAttribute)}, + // :123abc + { + `(:)(\d+)(\w[\w'-]*)`, + ByGroups(Punctuation, UsingSelf("number"), NameAttribute), + nil, + }, + // :key + {`(:)(!?)(\w[\w'-]*)`, ByGroups(Punctuation, Operator, NameAttribute), nil}, + {`\s+`, Text, nil}, + }, + "colon-pair-attribute-keyvalue": { + // :key(value) + {colonPairPattern, colonPair(NameAttribute), findBrackets(rakuNameAttribute)}, + }, + "escape-qq": { + { + `(? + { + `(?`), + tokenType: Punctuation, + stateName: `root`, + pushState: true, + }), + }, + // {code} + Include(`closure`), + // Properties + {`(:)(\w+)`, ByGroups(Punctuation, NameAttribute), nil}, + // Operator + {`\|\||\||&&|&|\.\.|\*\*|%%|%|:|!|<<|«|>>|»|\+|\*\*|\*|\?|=|~|<~~>`, Operator, nil}, + // Anchors + {`\^\^|\^|\$\$|\$`, NameEntity, nil}, + {`\.`, NameEntity, nil}, + {`#[^\n]*\n`, CommentSingle, nil}, + // Lookaround + { + `(?`), + tokenType: Punctuation, + stateName: `regex`, + pushState: true, + }), + }, + { + `(?)`, + ByGroups(Punctuation, Operator, OperatorWord, Punctuation), + nil, + }, + // <$variable> + { + `(?)`, + ByGroups(Punctuation, Operator, NameVariable, Punctuation), + nil, + }, + // Capture markers + {`(?`, Operator, nil}, + { + `(? + {`(?`, Punctuation, Pop(1)}, + // + { + `\(`, + Punctuation, + replaceRule(ruleReplacingConfig{ + delimiter: []rune(`)>`), + tokenType: Punctuation, + stateName: `root`, + popState: true, + pushState: true, + }), + }, + // + { + `\s+`, + StringRegex, + replaceRule(ruleReplacingConfig{ + delimiter: []rune(`>`), + tokenType: Punctuation, + stateName: `regex`, + popState: true, + pushState: true, + }), + }, + // + { + `:`, + Punctuation, + replaceRule(ruleReplacingConfig{ + delimiter: []rune(`>`), + tokenType: Punctuation, + stateName: `root`, + popState: true, + pushState: true, + }), + }, + }, + "regex-variable": { + Include(`regex-starting-operators`), + // + {`(&)?(\w[\w':-]*)(>)`, ByGroups(Operator, NameFunction, Punctuation), Pop(1)}, + // `, Punctuation, Pop(1)}, + Include("regex-class-builtin"), + Include("variable"), + Include(`regex-starting-operators`), + Include("colon-pair-attribute"), + {`(?] + { + `\b([RZX]+)\b(\[)([^\s\]]+?)(\])`, + ByGroups(OperatorWord, Punctuation, UsingSelf("root"), Punctuation), + nil, + }, + // Z=> + {`\b([RZX]+)\b([^\s\]]+)`, ByGroups(OperatorWord, UsingSelf("operator")), nil}, + }, + "operator": { + // Word Operator + {wordOperatorsPattern, OperatorWord, nil}, + // Operator + {operatorsPattern, Operator, nil}, + }, + "pod": { + // Single-line pod declaration + {`(#[|=])\s`, Keyword, Push("pod-single")}, + // Multi-line pod declaration + { + "(?#[|=])(?(?" + bracketsPattern + `)\k*)(?)(?)`, + ByGroupNames( + map[string]Emitter{ + `keyword`: Keyword, + `opening_delimiters`: Punctuation, + `delimiter`: nil, + `value`: UsingSelf("pod-declaration"), + `closing_delimiters`: Punctuation, + }), + findBrackets(rakuPodDeclaration), + }, + Include("pod-blocks"), + }, + "pod-blocks": { + // =begin code + { + `(?<=^ *)(? *)(?=begin)(? +)(?code)(?[^\n]*)(?.*?)(?^\k)(?=end)(? +)\k`, + EmitterFunc(podCode), + nil, + }, + // =begin + { + `(?<=^ *)(? *)(?=begin)(? +)(?!code)(?\w[\w'-]*)(?[^\n]*)(?)(?)`, + ByGroupNames( + map[string]Emitter{ + `ws`: Comment, + `keyword`: Keyword, + `ws2`: StringDoc, + `name`: Keyword, + `config`: EmitterFunc(podConfig), + `value`: UsingSelf("pod-begin"), + `closing_delimiters`: Keyword, + }), + findBrackets(rakuPod), + }, + // =for ... + { + `(?<=^ *)(? *)(?=(?:for|defn))(? +)(?\w[\w'-]*)(?[^\n]*\n)`, + ByGroups(Comment, Keyword, StringDoc, Keyword, EmitterFunc(podConfig)), + Push("pod-paragraph"), + }, + // =config + { + `(?<=^ *)(? *)(?=config)(? +)(?\w[\w'-]*)(?[^\n]*\n)`, + ByGroups(Comment, Keyword, StringDoc, Keyword, EmitterFunc(podConfig)), + nil, + }, + // =alias + { + `(?<=^ *)(? *)(?=alias)(? +)(?\w[\w'-]*)(?[^\n]*\n)`, + ByGroups(Comment, Keyword, StringDoc, Keyword, StringDoc), + nil, + }, + // =encoding + { + `(?<=^ *)(? *)(?=encoding)(? +)(?[^\n]+)`, + ByGroups(Comment, Keyword, StringDoc, Name), + nil, + }, + // =para ... + { + `(?<=^ *)(? *)(?=(?:para|table|pod))(?(? *)(?=head\d+)(? *)(?#?)`, + ByGroups(Comment, Keyword, GenericHeading, Keyword), + Push("pod-heading"), + }, + // =item ... + { + `(?<=^ *)(? *)(?=(?:item\d*|comment|data|[A-Z]+))(? *)(?#?)`, + ByGroups(Comment, Keyword, StringDoc, Keyword), + Push("pod-paragraph"), + }, + { + `(?<=^ *)(? *)(?=finish)(?[^\n]*)`, + ByGroups(Comment, Keyword, EmitterFunc(podConfig)), + Push("pod-finish"), + }, + // ={custom} ... + { + `(?<=^ *)(? *)(?=\w[\w'-]*)(? *)(?#?)`, + ByGroups(Comment, Name, StringDoc, Keyword), + Push("pod-paragraph"), + }, + // = podconfig + { + `(?<=^ *)(? *=)(? *)(?(?::\w[\w'-]*(?:` + colonPairOpeningBrackets + `.+?` + + colonPairClosingBrackets + `) *)*\n)`, + ByGroups(Keyword, StringDoc, EmitterFunc(podConfig)), + nil, + }, + }, + "pod-begin": { + Include("pod-blocks"), + Include("pre-pod-formatter"), + {`.+?`, StringDoc, nil}, + }, + "pod-declaration": { + Include("pre-pod-formatter"), + {`.+?`, StringDoc, nil}, + }, + "pod-paragraph": { + {`\n *\n|\n(?=^ *=)`, StringDoc, Pop(1)}, + Include("pre-pod-formatter"), + {`.+?`, StringDoc, nil}, + }, + "pod-single": { + {`\n`, StringDoc, Pop(1)}, + Include("pre-pod-formatter"), + {`.+?`, StringDoc, nil}, + }, + "pod-heading": { + {`\n *\n|\n(?=^ *=)`, GenericHeading, Pop(1)}, + Include("pre-pod-formatter"), + {`.+?`, GenericHeading, nil}, + }, + "pod-finish": { + {`\z`, nil, Pop(1)}, + Include("pre-pod-formatter"), + {`.+?`, StringDoc, nil}, + }, + "pre-pod-formatter": { + // C, B, ... + { + `(?[CBIUDTKRPAELZVMSXN])(?<+|«)`, + ByGroups(Keyword, Punctuation), + findBrackets(rakuPodFormatter), + }, + }, + "pod-formatter": { + // Placeholder rule, will be replaced by mutators. DO NOT REMOVE! + {`>`, Punctuation, Pop(1)}, + Include("pre-pod-formatter"), + // Placeholder rule, will be replaced by mutators. DO NOT REMOVE! + {`.+?`, StringOther, nil}, + }, + "variable": { + {variablePattern, NameVariable, Push("name-adverb")}, + {globalVariablePattern, NameVariableGlobal, Push("name-adverb")}, + {`[$@]<[^>]+>`, NameVariable, nil}, + {`\$[/!¢]`, NameVariable, nil}, + {`[$@%]`, NameVariable, nil}, + }, + "single-quote": { + {`(?>(?!\s*(?:\d+|\.(?:Int|Numeric)|[$@%]\*?[\w':-]+|\s+\[))`, Punctuation, Pop(1)}, + Include("ww"), + }, + "«": { + {`»(?!\s*(?:\d+|\.(?:Int|Numeric)|[$@%]\*?[\w':-]+|\s+\[))`, Punctuation, Pop(1)}, + Include("ww"), + }, + "ww": { + Include("single-quote"), + Include("qq"), + }, + "qq": { + Include("qq-variable"), + Include("closure"), + Include(`escape-char`), + Include("escape-hexadecimal"), + Include("escape-c-name"), + Include("escape-qq"), + {`.+?`, StringDouble, nil}, + }, + "qq-variable": { + { + `(?\.)(?` + namePattern + `)` + colonPairLookahead + `\()`, + ByGroupNames(map[string]Emitter{ + `operator`: Operator, + `method_name`: NameFunction, + }), + Push(`name-adverb`), + }, + // Function/Signature + { + `\(`, Punctuation, replaceRule( + ruleReplacingConfig{ + delimiter: []rune(`)`), + tokenType: Punctuation, + stateName: `root`, + pushState: true, + }), + }, + Default(Pop(1)), + }, + "Q": { + Include("escape-qq"), + {`.+?`, String, nil}, + }, + "Q-closure": { + Include("escape-qq"), + Include("closure"), + {`.+?`, String, nil}, + }, + "Q-variable": { + Include("escape-qq"), + Include("qq-variable"), + {`.+?`, String, nil}, + }, + "closure": { + {`(? -1 { + idx = utf8.RuneCountInString(text[:idx]) + + // Search again if the substr is escaped with backslash + if (idx > 1 && strFromPos[idx-1] == '\\' && strFromPos[idx-2] != '\\') || + (idx == 1 && strFromPos[idx-1] == '\\') { + idx = indexAt(str[pos:], substr, idx+1) + + idx = utf8.RuneCountInString(text[:idx]) + + if idx < 0 { + return idx + } + } + idx += pos + } + + return idx +} + +type rulePosition int + +const ( + topRule rulePosition = 0 - iota + bottomRule +) + +type ruleMakingConfig struct { + delimiter []rune + pattern string + tokenType Emitter + mutator Mutator + numberOfDelimiterChars int +} + +type ruleReplacingConfig struct { + delimiter []rune + pattern string + tokenType Emitter + numberOfDelimiterChars int + mutator Mutator + appendMutator Mutator + rulePosition rulePosition + stateName string + pop bool + popState bool + pushState bool +} + +// Pops rule from state-stack and replaces the rule with the previous rule +func popRule(rule ruleReplacingConfig) MutatorFunc { + return func(state *LexerState) error { + stackName := genStackName(rule.stateName, rule.rulePosition) + + stack, ok := state.Get(stackName).([]ruleReplacingConfig) + + if ok && len(stack) > 0 { + // Pop from stack + stack = stack[:len(stack)-1] + lastRule := stack[len(stack)-1] + lastRule.pushState = false + lastRule.popState = false + lastRule.pop = true + state.Set(stackName, stack) + + // Call replaceRule to use the last rule + err := replaceRule(lastRule)(state) + if err != nil { + panic(err) + } + } + + return nil + } +} + +// Replaces a state's rule based on the rule config and position +func replaceRule(rule ruleReplacingConfig) MutatorFunc { + return func(state *LexerState) error { + stateName := rule.stateName + stackName := genStackName(rule.stateName, rule.rulePosition) + + stack, ok := state.Get(stackName).([]ruleReplacingConfig) + if !ok { + stack = []ruleReplacingConfig{} + } + + // If state-stack is empty fill it with the placeholder rule + if len(stack) == 0 { + stack = []ruleReplacingConfig{ + { + // Placeholder, will be overwritten by mutators, DO NOT REMOVE! + pattern: `\A\z`, + tokenType: nil, + mutator: nil, + stateName: stateName, + rulePosition: rule.rulePosition, + }, + } + state.Set(stackName, stack) + } + + var mutator Mutator + mutators := []Mutator{} + + switch { + case rule.rulePosition == topRule && rule.mutator == nil: + // Default mutator for top rule + mutators = []Mutator{Pop(1), popRule(rule)} + case rule.rulePosition == topRule && rule.mutator != nil: + // Default mutator for top rule, when rule.mutator is set + mutators = []Mutator{rule.mutator, popRule(rule)} + case rule.mutator != nil: + mutators = []Mutator{rule.mutator} + } + + if rule.appendMutator != nil { + mutators = append(mutators, rule.appendMutator) + } + + if len(mutators) > 0 { + mutator = Mutators(mutators...) + } else { + mutator = nil + } + + ruleConfig := ruleMakingConfig{ + pattern: rule.pattern, + delimiter: rule.delimiter, + numberOfDelimiterChars: rule.numberOfDelimiterChars, + tokenType: rule.tokenType, + mutator: mutator, + } + + cRule := makeRule(ruleConfig) + + switch rule.rulePosition { + case topRule: + state.Rules[stateName][0] = cRule + case bottomRule: + state.Rules[stateName][len(state.Rules[stateName])-1] = cRule + } + + // Pop state name from stack if asked. State should be popped first before Pushing + if rule.popState { + err := Pop(1).Mutate(state) + if err != nil { + panic(err) + } + } + + // Push state name to stack if asked + if rule.pushState { + err := Push(stateName).Mutate(state) + if err != nil { + panic(err) + } + } + + if !rule.pop { + state.Set(stackName, append(stack, rule)) + } + + return nil + } +} + +// Generates rule replacing stack using state name and rule position +func genStackName(stateName string, rulePosition rulePosition) (stackName string) { + switch rulePosition { + case topRule: + stackName = stateName + `-top-stack` + case bottomRule: + stackName = stateName + `-bottom-stack` + } + return +} + +// Makes a compiled rule and returns it +func makeRule(config ruleMakingConfig) *CompiledRule { + var rePattern string + + if len(config.delimiter) > 0 { + delimiter := string(config.delimiter) + + if config.numberOfDelimiterChars > 1 { + delimiter = strings.Repeat(delimiter, config.numberOfDelimiterChars) + } + + rePattern = `(? 1 { + lang = langMatch[1] + } + + // Tokenise code based on lang property + sublexer := Get(lang) + if sublexer != nil { + iterator, err := sublexer.Tokenise(nil, state.NamedGroups[`value`]) + + if err != nil { + panic(err) + } else { + iterators = append(iterators, iterator) + } + } else { + iterators = append(iterators, Literator(tokens[4])) + } + + // Append the rest of the tokens + iterators = append(iterators, Literator(tokens[5:]...)) + + return Concaterator(iterators...) +} diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/rst.go b/vendor/github.com/alecthomas/chroma/v2/lexers/rst.go new file mode 100644 index 000000000..66ec03cdf --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/rst.go @@ -0,0 +1,89 @@ +package lexers + +import ( + "strings" + + . "github.com/alecthomas/chroma/v2" // nolint +) + +// Restructuredtext lexer. +var Restructuredtext = Register(MustNewLexer( + &Config{ + Name: "reStructuredText", + Aliases: []string{"rst", "rest", "restructuredtext"}, + Filenames: []string{"*.rst", "*.rest"}, + MimeTypes: []string{"text/x-rst", "text/prs.fallenstein.rst"}, + }, + restructuredtextRules, +)) + +func restructuredtextRules() Rules { + return Rules{ + "root": { + {"^(=+|-+|`+|:+|\\.+|\\'+|\"+|~+|\\^+|_+|\\*+|\\++|#+)([ \\t]*\\n)(.+)(\\n)(\\1)(\\n)", ByGroups(GenericHeading, Text, GenericHeading, Text, GenericHeading, Text), nil}, + {"^(\\S.*)(\\n)(={3,}|-{3,}|`{3,}|:{3,}|\\.{3,}|\\'{3,}|\"{3,}|~{3,}|\\^{3,}|_{3,}|\\*{3,}|\\+{3,}|#{3,})(\\n)", ByGroups(GenericHeading, Text, GenericHeading, Text), nil}, + {`^(\s*)([-*+])( .+\n(?:\1 .+\n)*)`, ByGroups(Text, LiteralNumber, UsingSelf("inline")), nil}, + {`^(\s*)([0-9#ivxlcmIVXLCM]+\.)( .+\n(?:\1 .+\n)*)`, ByGroups(Text, LiteralNumber, UsingSelf("inline")), nil}, + {`^(\s*)(\(?[0-9#ivxlcmIVXLCM]+\))( .+\n(?:\1 .+\n)*)`, ByGroups(Text, LiteralNumber, UsingSelf("inline")), nil}, + {`^(\s*)([A-Z]+\.)( .+\n(?:\1 .+\n)+)`, ByGroups(Text, LiteralNumber, UsingSelf("inline")), nil}, + {`^(\s*)(\(?[A-Za-z]+\))( .+\n(?:\1 .+\n)+)`, ByGroups(Text, LiteralNumber, UsingSelf("inline")), nil}, + {`^(\s*)(\|)( .+\n(?:\| .+\n)*)`, ByGroups(Text, Operator, UsingSelf("inline")), nil}, + {`^( *\.\.)(\s*)((?:source)?code(?:-block)?)(::)([ \t]*)([^\n]+)(\n[ \t]*\n)([ \t]+)(.*)(\n)((?:(?:\8.*|)\n)+)`, EmitterFunc(rstCodeBlock), nil}, + {`^( *\.\.)(\s*)([\w:-]+?)(::)(?:([ \t]*)(.*))`, ByGroups(Punctuation, Text, OperatorWord, Punctuation, Text, UsingSelf("inline")), nil}, + {`^( *\.\.)(\s*)(_(?:[^:\\]|\\.)+:)(.*?)$`, ByGroups(Punctuation, Text, NameTag, UsingSelf("inline")), nil}, + {`^( *\.\.)(\s*)(\[.+\])(.*?)$`, ByGroups(Punctuation, Text, NameTag, UsingSelf("inline")), nil}, + {`^( *\.\.)(\s*)(\|.+\|)(\s*)([\w:-]+?)(::)(?:([ \t]*)(.*))`, ByGroups(Punctuation, Text, NameTag, Text, OperatorWord, Punctuation, Text, UsingSelf("inline")), nil}, + {`^ *\.\..*(\n( +.*\n|\n)+)?`, CommentPreproc, nil}, + {`^( *)(:[a-zA-Z-]+:)(\s*)$`, ByGroups(Text, NameClass, Text), nil}, + {`^( *)(:.*?:)([ \t]+)(.*?)$`, ByGroups(Text, NameClass, Text, NameFunction), nil}, + {`^(\S.*(?)(`__?)", ByGroups(LiteralString, LiteralStringInterpol, LiteralString), nil}, + {"`.+?`__?", LiteralString, nil}, + {"(`.+?`)(:[a-zA-Z0-9:-]+?:)?", ByGroups(NameVariable, NameAttribute), nil}, + {"(:[a-zA-Z0-9:-]+?:)(`.+?`)", ByGroups(NameAttribute, NameVariable), nil}, + {`\*\*.+?\*\*`, GenericStrong, nil}, + {`\*.+?\*`, GenericEmph, nil}, + {`\[.*?\]_`, LiteralString, nil}, + {`<.+?>`, NameTag, nil}, + {"[^\\\\\\n\\[*`:]+", Text, nil}, + {`.`, Text, nil}, + }, + "literal": { + {"[^`]+", LiteralString, nil}, + {"``((?=$)|(?=[-/:.,; \\n\\x00\\\u2010\\\u2011\\\u2012\\\u2013\\\u2014\\\u00a0\\'\\\"\\)\\]\\}\\>\\\u2019\\\u201d\\\u00bb\\!\\?]))", LiteralString, Pop(1)}, + {"`", LiteralString, nil}, + }, + } +} + +func rstCodeBlock(groups []string, state *LexerState) Iterator { + iterators := []Iterator{} + tokens := []Token{ + {Punctuation, groups[1]}, + {Text, groups[2]}, + {OperatorWord, groups[3]}, + {Punctuation, groups[4]}, + {Text, groups[5]}, + {Keyword, groups[6]}, + {Text, groups[7]}, + } + code := strings.Join(groups[8:], "") + lexer := Get(groups[6]) + if lexer == nil { + tokens = append(tokens, Token{String, code}) + iterators = append(iterators, Literator(tokens...)) + } else { + sub, err := lexer.Tokenise(nil, code) + if err != nil { + panic(err) + } + iterators = append(iterators, Literator(tokens...), sub) + } + return Concaterator(iterators...) +} diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/svelte.go b/vendor/github.com/alecthomas/chroma/v2/lexers/svelte.go new file mode 100644 index 000000000..39211c4fc --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/svelte.go @@ -0,0 +1,70 @@ +package lexers + +import ( + . "github.com/alecthomas/chroma/v2" // nolint +) + +// Svelte lexer. +var Svelte = Register(DelegatingLexer(HTML, MustNewLexer( + &Config{ + Name: "Svelte", + Aliases: []string{"svelte"}, + Filenames: []string{"*.svelte"}, + MimeTypes: []string{"application/x-svelte"}, + DotAll: true, + }, + svelteRules, +))) + +func svelteRules() Rules { + return Rules{ + "root": { + // Let HTML handle the comments, including comments containing script and style tags + {``, Other, Pop(1)}, + {`.+?`, Other, nil}, + }, + "templates": { + {`}`, Punctuation, Pop(1)}, + // Let TypeScript handle strings and the curly braces inside them + {`(?]*>`, Using("TypoScriptHTMLData"), nil}, + {`&[^;\n]*;`, LiteralString, nil}, + {`(_CSS_DEFAULT_STYLE)(\s*)(\()(?s)(.*(?=\n\)))`, ByGroups(NameClass, Text, LiteralStringSymbol, Using("TypoScriptCSSData")), nil}, + }, + "literal": { + {`0x[0-9A-Fa-f]+t?`, LiteralNumberHex, nil}, + {`[0-9]+`, LiteralNumberInteger, nil}, + {`(###\w+###)`, NameConstant, nil}, + }, + "label": { + {`(EXT|FILE|LLL):[^}\n"]*`, LiteralString, nil}, + {`(?![^\w\-])([\w\-]+(?:/[\w\-]+)+/?)(\S*\n)`, ByGroups(LiteralString, LiteralString), nil}, + }, + "punctuation": { + {`[,.]`, Punctuation, nil}, + }, + "operator": { + {`[<>,:=.*%+|]`, Operator, nil}, + }, + "structure": { + {`[{}()\[\]\\]`, LiteralStringSymbol, nil}, + }, + "constant": { + {`(\{)(\$)((?:[\w\-]+\.)*)([\w\-]+)(\})`, ByGroups(LiteralStringSymbol, Operator, NameConstant, NameConstant, LiteralStringSymbol), nil}, + {`(\{)([\w\-]+)(\s*:\s*)([\w\-]+)(\})`, ByGroups(LiteralStringSymbol, NameConstant, Operator, NameConstant, LiteralStringSymbol), nil}, + {`(#[a-fA-F0-9]{6}\b|#[a-fA-F0-9]{3}\b)`, LiteralStringChar, nil}, + }, + "comment": { + {`(? 0 { + // Exhaust the iterator stack, if any. + for len(l.iteratorStack) > 0 { + n := len(l.iteratorStack) - 1 + t := l.iteratorStack[n]() + if t.Type == Ignore { + continue + } + if t == EOF { + l.iteratorStack = l.iteratorStack[:n] + continue + } + return t + } + + l.State = l.Stack[len(l.Stack)-1] + selectedRule, ok := l.Rules[l.State] + if !ok { + panic("unknown state " + l.State) + } + var start time.Time + if l.Lexer.trace { + start = time.Now() + } + ruleIndex, rule, groups, namedGroups := matchRules(l.Text, l.Pos, selectedRule) + if l.Lexer.trace { + var length int + if groups != nil { + length = len(groups[0]) + } else { + length = -1 + } + _ = trace.Encode(Trace{ //nolint + Lexer: l.Lexer.config.Name, + State: l.State, + Rule: ruleIndex, + Pattern: rule.Pattern, + Pos: l.Pos, + Length: length, + Elapsed: float64(time.Since(start)) / float64(time.Millisecond), + }) + // fmt.Fprintf(os.Stderr, "%s: pos=%d, text=%q, elapsed=%s\n", l.State, l.Pos, string(l.Text[l.Pos:]), time.Since(start)) + } + // No match. + if groups == nil { + // From Pygments :\ + // + // If the RegexLexer encounters a newline that is flagged as an error token, the stack is + // emptied and the lexer continues scanning in the 'root' state. This can help producing + // error-tolerant highlighting for erroneous input, e.g. when a single-line string is not + // closed. + if l.Text[l.Pos] == '\n' && l.State != l.options.State { + l.Stack = []string{l.options.State} + continue + } + l.Pos++ + return Token{Error, string(l.Text[l.Pos-1 : l.Pos])} + } + l.Rule = ruleIndex + l.Groups = groups + l.NamedGroups = namedGroups + l.Pos += utf8.RuneCountInString(groups[0]) + if rule.Mutator != nil { + if err := rule.Mutator.Mutate(l); err != nil { + panic(err) + } + } + if rule.Type != nil { + l.iteratorStack = append(l.iteratorStack, rule.Type.Emit(l.Groups, l)) + } + } + // Exhaust the IteratorStack, if any. + // Duplicate code, but eh. + for len(l.iteratorStack) > 0 { + n := len(l.iteratorStack) - 1 + t := l.iteratorStack[n]() + if t.Type == Ignore { + continue + } + if t == EOF { + l.iteratorStack = l.iteratorStack[:n] + continue + } + return t + } + + // If we get to here and we still have text, return it as an error. + if l.Pos != len(l.Text) && len(l.Stack) == 0 { + value := string(l.Text[l.Pos:]) + l.Pos = len(l.Text) + return Token{Type: Error, Value: value} + } + return EOF +} + +// RegexLexer is the default lexer implementation used in Chroma. +type RegexLexer struct { + registry *LexerRegistry // The LexerRegistry this Lexer is associated with, if any. + config *Config + analyser func(text string) float32 + trace bool + + mu sync.Mutex + compiled bool + rawRules Rules + rules map[string][]*CompiledRule + fetchRulesFunc func() (Rules, error) + compileOnce sync.Once +} + +func (r *RegexLexer) String() string { + return r.config.Name +} + +// Rules in the Lexer. +func (r *RegexLexer) Rules() (Rules, error) { + if err := r.needRules(); err != nil { + return nil, err + } + return r.rawRules, nil +} + +// SetRegistry the lexer will use to lookup other lexers if necessary. +func (r *RegexLexer) SetRegistry(registry *LexerRegistry) Lexer { + r.registry = registry + return r +} + +// SetAnalyser sets the analyser function used to perform content inspection. +func (r *RegexLexer) SetAnalyser(analyser func(text string) float32) Lexer { + r.analyser = analyser + return r +} + +// AnalyseText scores how likely a fragment of text is to match this lexer, between 0.0 and 1.0. +func (r *RegexLexer) AnalyseText(text string) float32 { + if r.analyser != nil { + return r.analyser(text) + } + return 0 +} + +// SetConfig replaces the Config for this Lexer. +func (r *RegexLexer) SetConfig(config *Config) *RegexLexer { + r.config = config + return r +} + +// Config returns the Config for this Lexer. +func (r *RegexLexer) Config() *Config { + return r.config +} + +// Regex compilation is deferred until the lexer is used. This is to avoid significant init() time costs. +func (r *RegexLexer) maybeCompile() (err error) { + r.mu.Lock() + defer r.mu.Unlock() + if r.compiled { + return nil + } + for state, rules := range r.rules { + for i, rule := range rules { + if rule.Regexp == nil { + pattern := "(?:" + rule.Pattern + ")" + if rule.flags != "" { + pattern = "(?" + rule.flags + ")" + pattern + } + pattern = `\G` + pattern + rule.Regexp, err = regexp2.Compile(pattern, 0) + if err != nil { + return fmt.Errorf("failed to compile rule %s.%d: %s", state, i, err) + } + rule.Regexp.MatchTimeout = time.Millisecond * 250 + } + } + } +restart: + seen := map[LexerMutator]bool{} + for state := range r.rules { + for i := range len(r.rules[state]) { + rule := r.rules[state][i] + if compile, ok := rule.Mutator.(LexerMutator); ok { + if seen[compile] { + return fmt.Errorf("saw mutator %T twice; this should not happen", compile) + } + seen[compile] = true + if err := compile.MutateLexer(r.rules, state, i); err != nil { + return err + } + // Process the rules again in case the mutator added/removed rules. + // + // This sounds bad, but shouldn't be significant in practice. + goto restart + } + } + } + // Validate emitters + for state := range r.rules { + for i := range len(r.rules[state]) { + rule := r.rules[state][i] + if validate, ok := rule.Type.(ValidatingEmitter); ok { + if err := validate.ValidateEmitter(rule); err != nil { + return fmt.Errorf("%s: %s: %s: %w", r.config.Name, state, rule.Pattern, err) + } + } + } + } + r.compiled = true + return nil +} + +func (r *RegexLexer) fetchRules() error { + rules, err := r.fetchRulesFunc() + if err != nil { + return fmt.Errorf("%s: failed to compile rules: %w", r.config.Name, err) + } + if _, ok := rules["root"]; !ok { + return fmt.Errorf("no \"root\" state") + } + compiledRules := map[string][]*CompiledRule{} + for state, rules := range rules { + compiledRules[state] = nil + for _, rule := range rules { + flags := "" + if !r.config.NotMultiline { + flags += "m" + } + if r.config.CaseInsensitive { + flags += "i" + } + if r.config.DotAll { + flags += "s" + } + compiledRules[state] = append(compiledRules[state], &CompiledRule{Rule: rule, flags: flags}) + } + } + + r.rawRules = rules + r.rules = compiledRules + return nil +} + +func (r *RegexLexer) needRules() error { + var err error + if r.fetchRulesFunc != nil { + r.compileOnce.Do(func() { + err = r.fetchRules() + }) + } + if err := r.maybeCompile(); err != nil { + return err + } + return err +} + +// Tokenise text using lexer, returning an iterator. +func (r *RegexLexer) Tokenise(options *TokeniseOptions, text string) (Iterator, error) { + err := r.needRules() + if err != nil { + return nil, err + } + if options == nil { + options = defaultOptions + } + if options.EnsureLF { + text = ensureLF(text) + } + newlineAdded := false + if !options.Nested && r.config.EnsureNL && !strings.HasSuffix(text, "\n") { + text += "\n" + newlineAdded = true + } + state := &LexerState{ + Registry: r.registry, + newlineAdded: newlineAdded, + options: options, + Lexer: r, + Text: []rune(text), + Stack: []string{options.State}, + Rules: r.rules, + MutatorContext: map[interface{}]interface{}{}, + } + return state.Iterator, nil +} + +// MustRules is like Rules() but will panic on error. +func (r *RegexLexer) MustRules() Rules { + rules, err := r.Rules() + if err != nil { + panic(err) + } + return rules +} + +func matchRules(text []rune, pos int, rules []*CompiledRule) (int, *CompiledRule, []string, map[string]string) { + for i, rule := range rules { + match, err := rule.Regexp.FindRunesMatchStartingAt(text, pos) + if match != nil && err == nil && match.Index == pos { + groups := []string{} + namedGroups := make(map[string]string) + for _, g := range match.Groups() { + namedGroups[g.Name] = g.String() + groups = append(groups, g.String()) + } + return i, rule, groups, namedGroups + } + } + return 0, &CompiledRule{}, nil, nil +} + +// replace \r and \r\n with \n +// same as strings.ReplaceAll but more efficient +func ensureLF(text string) string { + buf := make([]byte, len(text)) + var j int + for i := range len(text) { + c := text[i] + if c == '\r' { + if i < len(text)-1 && text[i+1] == '\n' { + continue + } + c = '\n' + } + buf[j] = c + j++ + } + return string(buf[:j]) +} diff --git a/vendor/github.com/alecthomas/chroma/v2/registry.go b/vendor/github.com/alecthomas/chroma/v2/registry.go new file mode 100644 index 000000000..a309af9db --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/registry.go @@ -0,0 +1,228 @@ +package chroma + +import ( + "path/filepath" + "sort" + "strings" +) + +var ( + ignoredSuffixes = [...]string{ + // Editor backups + "~", ".bak", ".old", ".orig", + // Debian and derivatives apt/dpkg/ucf backups + ".dpkg-dist", ".dpkg-old", ".ucf-dist", ".ucf-new", ".ucf-old", + // Red Hat and derivatives rpm backups + ".rpmnew", ".rpmorig", ".rpmsave", + // Build system input/template files + ".in", + } +) + +// LexerRegistry is a registry of Lexers. +type LexerRegistry struct { + Lexers Lexers + byName map[string]Lexer + byAlias map[string]Lexer +} + +// NewLexerRegistry creates a new LexerRegistry of Lexers. +func NewLexerRegistry() *LexerRegistry { + return &LexerRegistry{ + byName: map[string]Lexer{}, + byAlias: map[string]Lexer{}, + } +} + +// Names of all lexers, optionally including aliases. +func (l *LexerRegistry) Names(withAliases bool) []string { + out := []string{} + for _, lexer := range l.Lexers { + config := lexer.Config() + out = append(out, config.Name) + if withAliases { + out = append(out, config.Aliases...) + } + } + sort.Strings(out) + return out +} + +// Aliases of all the lexers, and skip those lexers who do not have any aliases, +// or show their name instead +func (l *LexerRegistry) Aliases(skipWithoutAliases bool) []string { + out := []string{} + for _, lexer := range l.Lexers { + config := lexer.Config() + if len(config.Aliases) == 0 { + if skipWithoutAliases { + continue + } + out = append(out, config.Name) + } + out = append(out, config.Aliases...) + } + sort.Strings(out) + return out +} + +// Get a Lexer by name, alias or file extension. +func (l *LexerRegistry) Get(name string) Lexer { + if lexer := l.byName[name]; lexer != nil { + return lexer + } + if lexer := l.byAlias[name]; lexer != nil { + return lexer + } + if lexer := l.byName[strings.ToLower(name)]; lexer != nil { + return lexer + } + if lexer := l.byAlias[strings.ToLower(name)]; lexer != nil { + return lexer + } + + candidates := PrioritisedLexers{} + // Try file extension. + if lexer := l.Match("filename." + name); lexer != nil { + candidates = append(candidates, lexer) + } + // Try exact filename. + if lexer := l.Match(name); lexer != nil { + candidates = append(candidates, lexer) + } + if len(candidates) == 0 { + return nil + } + sort.Sort(candidates) + return candidates[0] +} + +// MatchMimeType attempts to find a lexer for the given MIME type. +func (l *LexerRegistry) MatchMimeType(mimeType string) Lexer { + matched := PrioritisedLexers{} + for _, l := range l.Lexers { + for _, lmt := range l.Config().MimeTypes { + if mimeType == lmt { + matched = append(matched, l) + } + } + } + if len(matched) != 0 { + sort.Sort(matched) + return matched[0] + } + return nil +} + +// Match returns the first lexer matching filename. +// +// Note that this iterates over all file patterns in all lexers, so is not fast. +func (l *LexerRegistry) Match(filename string) Lexer { + filename = filepath.Base(filename) + matched := PrioritisedLexers{} + // First, try primary filename matches. + for _, lexer := range l.Lexers { + config := lexer.Config() + for _, glob := range config.Filenames { + ok, err := filepath.Match(glob, filename) + if err != nil { // nolint + panic(err) + } else if ok { + matched = append(matched, lexer) + } else { + for _, suf := range &ignoredSuffixes { + ok, err := filepath.Match(glob+suf, filename) + if err != nil { + panic(err) + } else if ok { + matched = append(matched, lexer) + break + } + } + } + } + } + if len(matched) > 0 { + sort.Sort(matched) + return matched[0] + } + matched = nil + // Next, try filename aliases. + for _, lexer := range l.Lexers { + config := lexer.Config() + for _, glob := range config.AliasFilenames { + ok, err := filepath.Match(glob, filename) + if err != nil { // nolint + panic(err) + } else if ok { + matched = append(matched, lexer) + } else { + for _, suf := range &ignoredSuffixes { + ok, err := filepath.Match(glob+suf, filename) + if err != nil { + panic(err) + } else if ok { + matched = append(matched, lexer) + break + } + } + } + } + } + if len(matched) > 0 { + sort.Sort(matched) + return matched[0] + } + return nil +} + +// Analyse text content and return the "best" lexer.. +func (l *LexerRegistry) Analyse(text string) Lexer { + var picked Lexer + highest := float32(0.0) + for _, lexer := range l.Lexers { + if analyser, ok := lexer.(Analyser); ok { + weight := analyser.AnalyseText(text) + if weight > highest { + picked = lexer + highest = weight + } + } + } + return picked +} + +// Register a Lexer with the LexerRegistry. If the lexer is already registered +// it will be replaced. +func (l *LexerRegistry) Register(lexer Lexer) Lexer { + lexer.SetRegistry(l) + config := lexer.Config() + + l.byName[config.Name] = lexer + l.byName[strings.ToLower(config.Name)] = lexer + + for _, alias := range config.Aliases { + l.byAlias[alias] = lexer + l.byAlias[strings.ToLower(alias)] = lexer + } + + l.Lexers = add(l.Lexers, lexer) + + return lexer +} + +// add adds a lexer to a slice of lexers if it doesn't already exist, or if found will replace it. +func add(lexers Lexers, lexer Lexer) Lexers { + for i, val := range lexers { + if val == nil { + continue + } + + if val.Config().Name == lexer.Config().Name { + lexers[i] = lexer + return lexers + } + } + + return append(lexers, lexer) +} diff --git a/vendor/github.com/alecthomas/chroma/v2/remap.go b/vendor/github.com/alecthomas/chroma/v2/remap.go new file mode 100644 index 000000000..bcf5e66d1 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/remap.go @@ -0,0 +1,94 @@ +package chroma + +type remappingLexer struct { + lexer Lexer + mapper func(Token) []Token +} + +// RemappingLexer remaps a token to a set of, potentially empty, tokens. +func RemappingLexer(lexer Lexer, mapper func(Token) []Token) Lexer { + return &remappingLexer{lexer, mapper} +} + +func (r *remappingLexer) AnalyseText(text string) float32 { + return r.lexer.AnalyseText(text) +} + +func (r *remappingLexer) SetAnalyser(analyser func(text string) float32) Lexer { + r.lexer.SetAnalyser(analyser) + return r +} + +func (r *remappingLexer) SetRegistry(registry *LexerRegistry) Lexer { + r.lexer.SetRegistry(registry) + return r +} + +func (r *remappingLexer) Config() *Config { + return r.lexer.Config() +} + +func (r *remappingLexer) Tokenise(options *TokeniseOptions, text string) (Iterator, error) { + it, err := r.lexer.Tokenise(options, text) + if err != nil { + return nil, err + } + var buffer []Token + return func() Token { + for { + if len(buffer) > 0 { + t := buffer[0] + buffer = buffer[1:] + return t + } + t := it() + if t == EOF { + return t + } + buffer = r.mapper(t) + } + }, nil +} + +// TypeMapping defines type maps for the TypeRemappingLexer. +type TypeMapping []struct { + From, To TokenType + Words []string +} + +// TypeRemappingLexer remaps types of tokens coming from a parent Lexer. +// +// eg. Map "defvaralias" tokens of type NameVariable to NameFunction: +// +// mapping := TypeMapping{ +// {NameVariable, NameFunction, []string{"defvaralias"}, +// } +// lexer = TypeRemappingLexer(lexer, mapping) +func TypeRemappingLexer(lexer Lexer, mapping TypeMapping) Lexer { + // Lookup table for fast remapping. + lut := map[TokenType]map[string]TokenType{} + for _, rt := range mapping { + km, ok := lut[rt.From] + if !ok { + km = map[string]TokenType{} + lut[rt.From] = km + } + if len(rt.Words) == 0 { + km[""] = rt.To + } else { + for _, k := range rt.Words { + km[k] = rt.To + } + } + } + return RemappingLexer(lexer, func(t Token) []Token { + if k, ok := lut[t.Type]; ok { + if tt, ok := k[t.Value]; ok { + t.Type = tt + } else if tt, ok := k[""]; ok { + t.Type = tt + } + } + return []Token{t} + }) +} diff --git a/vendor/github.com/alecthomas/chroma/v2/renovate.json5 b/vendor/github.com/alecthomas/chroma/v2/renovate.json5 new file mode 100644 index 000000000..9ade48124 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/renovate.json5 @@ -0,0 +1,24 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:recommended", + ":semanticCommits", + ":semanticCommitTypeAll(chore)", + ":semanticCommitScope(deps)", + "group:allNonMajor", + "schedule:earlyMondays", // Run once a week. + 'helpers:pinGitHubActionDigests', + ], + "packageRules": [ + { + "matchPackageNames": ["golangci-lint"], + "matchManagers": ["hermit"], + "enabled": false + }, + { + "matchPackageNames": ["github.com/gorilla/csrf"], + "matchManagers": ["gomod"], + "enabled": false + } + ] +} diff --git a/vendor/github.com/alecthomas/chroma/v2/serialise.go b/vendor/github.com/alecthomas/chroma/v2/serialise.go new file mode 100644 index 000000000..3d7f6c5d5 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/serialise.go @@ -0,0 +1,483 @@ +package chroma + +import ( + "compress/gzip" + "encoding/xml" + "errors" + "fmt" + "io" + "io/fs" + "math" + "path/filepath" + "reflect" + "regexp" + "strings" + + "github.com/dlclark/regexp2" +) + +// Serialisation of Chroma rules to XML. The format is: +// +// +// +// +// [<$EMITTER ...>] +// [<$MUTATOR ...>] +// +// +// +// +// eg. Include("String") would become: +// +// +// +// +// +// [null, null, {"kind": "include", "state": "String"}] +// +// eg. Rule{`\d+`, Text, nil} would become: +// +// +// +// +// +// eg. Rule{`"`, String, Push("String")} +// +// +// +// +// +// +// eg. Rule{`(\w+)(\n)`, ByGroups(Keyword, Whitespace), nil}, +// +// +// +// +// +var ( + // ErrNotSerialisable is returned if a lexer contains Rules that cannot be serialised. + ErrNotSerialisable = fmt.Errorf("not serialisable") + emitterTemplates = func() map[string]SerialisableEmitter { + out := map[string]SerialisableEmitter{} + for _, emitter := range []SerialisableEmitter{ + &byGroupsEmitter{}, + &usingSelfEmitter{}, + TokenType(0), + &usingEmitter{}, + &usingByGroup{}, + } { + out[emitter.EmitterKind()] = emitter + } + return out + }() + mutatorTemplates = func() map[string]SerialisableMutator { + out := map[string]SerialisableMutator{} + for _, mutator := range []SerialisableMutator{ + &includeMutator{}, + &combinedMutator{}, + &multiMutator{}, + &pushMutator{}, + &popMutator{}, + } { + out[mutator.MutatorKind()] = mutator + } + return out + }() +) + +// fastUnmarshalConfig unmarshals only the Config from a serialised lexer. +func fastUnmarshalConfig(from fs.FS, path string) (*Config, error) { + r, err := from.Open(path) + if err != nil { + return nil, err + } + defer r.Close() + dec := xml.NewDecoder(r) + for { + token, err := dec.Token() + if err != nil { + if errors.Is(err, io.EOF) { + return nil, fmt.Errorf("could not find element") + } + return nil, err + } + switch se := token.(type) { + case xml.StartElement: + if se.Name.Local != "config" { + break + } + + var config Config + err = dec.DecodeElement(&config, &se) + if err != nil { + return nil, fmt.Errorf("%s: %w", path, err) + } + return &config, nil + } + } +} + +// MustNewXMLLexer constructs a new RegexLexer from an XML file or panics. +func MustNewXMLLexer(from fs.FS, path string) *RegexLexer { + lex, err := NewXMLLexer(from, path) + if err != nil { + panic(err) + } + return lex +} + +// NewXMLLexer creates a new RegexLexer from a serialised RegexLexer. +func NewXMLLexer(from fs.FS, path string) (*RegexLexer, error) { + config, err := fastUnmarshalConfig(from, path) + if err != nil { + return nil, err + } + + for _, glob := range append(config.Filenames, config.AliasFilenames...) { + _, err := filepath.Match(glob, "") + if err != nil { + return nil, fmt.Errorf("%s: %q is not a valid glob: %w", config.Name, glob, err) + } + } + + var analyserFn func(string) float32 + + if config.Analyse != nil { + type regexAnalyse struct { + re *regexp2.Regexp + score float32 + } + + regexAnalysers := make([]regexAnalyse, 0, len(config.Analyse.Regexes)) + + regexFlags := regexp2.None + if config.CaseInsensitive { + regexFlags = regexp2.IgnoreCase + } + for _, ra := range config.Analyse.Regexes { + re, err := regexp2.Compile(ra.Pattern, regexFlags) + if err != nil { + return nil, fmt.Errorf("%s: %q is not a valid analyser regex: %w", config.Name, ra.Pattern, err) + } + + regexAnalysers = append(regexAnalysers, regexAnalyse{re, ra.Score}) + } + + analyserFn = func(text string) float32 { + var score float32 + + for _, ra := range regexAnalysers { + ok, err := ra.re.MatchString(text) + if err != nil { + return 0 + } + + if ok && config.Analyse.First { + return float32(math.Min(float64(ra.score), 1.0)) + } + + if ok { + score += ra.score + } + } + + return float32(math.Min(float64(score), 1.0)) + } + } + + return &RegexLexer{ + config: config, + analyser: analyserFn, + fetchRulesFunc: func() (Rules, error) { + var lexer struct { + Config + Rules Rules `xml:"rules"` + } + // Try to open .xml fallback to .xml.gz + fr, err := from.Open(path) + if err != nil { + if errors.Is(err, fs.ErrNotExist) { + path += ".gz" + fr, err = from.Open(path) + if err != nil { + return nil, err + } + } else { + return nil, err + } + } + defer fr.Close() + var r io.Reader = fr + if strings.HasSuffix(path, ".gz") { + r, err = gzip.NewReader(r) + if err != nil { + return nil, fmt.Errorf("%s: %w", path, err) + } + } + err = xml.NewDecoder(r).Decode(&lexer) + if err != nil { + return nil, fmt.Errorf("%s: %w", path, err) + } + return lexer.Rules, nil + }, + }, nil +} + +// Marshal a RegexLexer to XML. +func Marshal(l *RegexLexer) ([]byte, error) { + type lexer struct { + Config Config `xml:"config"` + Rules Rules `xml:"rules"` + } + + rules, err := l.Rules() + if err != nil { + return nil, err + } + root := &lexer{ + Config: *l.Config(), + Rules: rules, + } + data, err := xml.MarshalIndent(root, "", " ") + if err != nil { + return nil, err + } + re := regexp.MustCompile(`>`) + data = re.ReplaceAll(data, []byte(`/>`)) + return data, nil +} + +// Unmarshal a RegexLexer from XML. +func Unmarshal(data []byte) (*RegexLexer, error) { + type lexer struct { + Config Config `xml:"config"` + Rules Rules `xml:"rules"` + } + root := &lexer{} + err := xml.Unmarshal(data, root) + if err != nil { + return nil, fmt.Errorf("invalid Lexer XML: %w", err) + } + lex, err := NewLexer(&root.Config, func() Rules { return root.Rules }) + if err != nil { + return nil, err + } + return lex, nil +} + +func marshalMutator(e *xml.Encoder, mutator Mutator) error { + if mutator == nil { + return nil + } + smutator, ok := mutator.(SerialisableMutator) + if !ok { + return fmt.Errorf("unsupported mutator: %w", ErrNotSerialisable) + } + return e.EncodeElement(mutator, xml.StartElement{Name: xml.Name{Local: smutator.MutatorKind()}}) +} + +func unmarshalMutator(d *xml.Decoder, start xml.StartElement) (Mutator, error) { + kind := start.Name.Local + mutator, ok := mutatorTemplates[kind] + if !ok { + return nil, fmt.Errorf("unknown mutator %q: %w", kind, ErrNotSerialisable) + } + value, target := newFromTemplate(mutator) + if err := d.DecodeElement(target, &start); err != nil { + return nil, err + } + return value().(SerialisableMutator), nil +} + +func marshalEmitter(e *xml.Encoder, emitter Emitter) error { + if emitter == nil { + return nil + } + semitter, ok := emitter.(SerialisableEmitter) + if !ok { + return fmt.Errorf("unsupported emitter %T: %w", emitter, ErrNotSerialisable) + } + return e.EncodeElement(emitter, xml.StartElement{ + Name: xml.Name{Local: semitter.EmitterKind()}, + }) +} + +func unmarshalEmitter(d *xml.Decoder, start xml.StartElement) (Emitter, error) { + kind := start.Name.Local + mutator, ok := emitterTemplates[kind] + if !ok { + return nil, fmt.Errorf("unknown emitter %q: %w", kind, ErrNotSerialisable) + } + value, target := newFromTemplate(mutator) + if err := d.DecodeElement(target, &start); err != nil { + return nil, err + } + return value().(SerialisableEmitter), nil +} + +func (r Rule) MarshalXML(e *xml.Encoder, _ xml.StartElement) error { + start := xml.StartElement{ + Name: xml.Name{Local: "rule"}, + } + if r.Pattern != "" { + start.Attr = append(start.Attr, xml.Attr{ + Name: xml.Name{Local: "pattern"}, + Value: r.Pattern, + }) + } + if err := e.EncodeToken(start); err != nil { + return err + } + if err := marshalEmitter(e, r.Type); err != nil { + return err + } + if err := marshalMutator(e, r.Mutator); err != nil { + return err + } + return e.EncodeToken(xml.EndElement{Name: start.Name}) +} + +func (r *Rule) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + for _, attr := range start.Attr { + if attr.Name.Local == "pattern" { + r.Pattern = attr.Value + break + } + } + for { + token, err := d.Token() + if err != nil { + return err + } + switch token := token.(type) { + case xml.StartElement: + mutator, err := unmarshalMutator(d, token) + if err != nil && !errors.Is(err, ErrNotSerialisable) { + return err + } else if err == nil { + if r.Mutator != nil { + return fmt.Errorf("duplicate mutator") + } + r.Mutator = mutator + continue + } + emitter, err := unmarshalEmitter(d, token) + if err != nil && !errors.Is(err, ErrNotSerialisable) { // nolint: gocritic + return err + } else if err == nil { + if r.Type != nil { + return fmt.Errorf("duplicate emitter") + } + r.Type = emitter + continue + } else { + return err + } + + case xml.EndElement: + return nil + } + } +} + +type xmlRuleState struct { + Name string `xml:"name,attr"` + Rules []Rule `xml:"rule"` +} + +type xmlRules struct { + States []xmlRuleState `xml:"state"` +} + +func (r Rules) MarshalXML(e *xml.Encoder, _ xml.StartElement) error { + xr := xmlRules{} + for state, rules := range r { + xr.States = append(xr.States, xmlRuleState{ + Name: state, + Rules: rules, + }) + } + return e.EncodeElement(xr, xml.StartElement{Name: xml.Name{Local: "rules"}}) +} + +func (r *Rules) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + xr := xmlRules{} + if err := d.DecodeElement(&xr, &start); err != nil { + return err + } + if *r == nil { + *r = Rules{} + } + for _, state := range xr.States { + (*r)[state.Name] = state.Rules + } + return nil +} + +type xmlTokenType struct { + Type string `xml:"type,attr"` +} + +func (t *TokenType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + el := xmlTokenType{} + if err := d.DecodeElement(&el, &start); err != nil { + return err + } + tt, err := TokenTypeString(el.Type) + if err != nil { + return err + } + *t = tt + return nil +} + +func (t TokenType) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + start.Attr = append(start.Attr, xml.Attr{Name: xml.Name{Local: "type"}, Value: t.String()}) + if err := e.EncodeToken(start); err != nil { + return err + } + return e.EncodeToken(xml.EndElement{Name: start.Name}) +} + +// This hijinks is a bit unfortunate but without it we can't deserialise into TokenType. +func newFromTemplate(template interface{}) (value func() interface{}, target interface{}) { + t := reflect.TypeOf(template) + if t.Kind() == reflect.Ptr { + v := reflect.New(t.Elem()) + return v.Interface, v.Interface() + } + v := reflect.New(t) + return func() interface{} { return v.Elem().Interface() }, v.Interface() +} + +func (b *Emitters) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + for { + token, err := d.Token() + if err != nil { + return err + } + switch token := token.(type) { + case xml.StartElement: + emitter, err := unmarshalEmitter(d, token) + if err != nil { + return err + } + *b = append(*b, emitter) + + case xml.EndElement: + return nil + } + } +} + +func (b Emitters) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + if err := e.EncodeToken(start); err != nil { + return err + } + for _, m := range b { + if err := marshalEmitter(e, m); err != nil { + return err + } + } + return e.EncodeToken(xml.EndElement{Name: start.Name}) +} diff --git a/vendor/github.com/alecthomas/chroma/v2/style.go b/vendor/github.com/alecthomas/chroma/v2/style.go new file mode 100644 index 000000000..cc8d9a602 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/style.go @@ -0,0 +1,481 @@ +package chroma + +import ( + "encoding/xml" + "fmt" + "io" + "sort" + "strings" +) + +// Trilean value for StyleEntry value inheritance. +type Trilean uint8 + +// Trilean states. +const ( + Pass Trilean = iota + Yes + No +) + +func (t Trilean) String() string { + switch t { + case Yes: + return "Yes" + case No: + return "No" + default: + return "Pass" + } +} + +// Prefix returns s with "no" as a prefix if Trilean is no. +func (t Trilean) Prefix(s string) string { + if t == Yes { + return s + } else if t == No { + return "no" + s + } + return "" +} + +// A StyleEntry in the Style map. +type StyleEntry struct { + // Hex colours. + Colour Colour + Background Colour + Border Colour + + Bold Trilean + Italic Trilean + Underline Trilean + NoInherit bool +} + +func (s StyleEntry) MarshalText() ([]byte, error) { + return []byte(s.String()), nil +} + +func (s StyleEntry) String() string { + out := []string{} + if s.Bold != Pass { + out = append(out, s.Bold.Prefix("bold")) + } + if s.Italic != Pass { + out = append(out, s.Italic.Prefix("italic")) + } + if s.Underline != Pass { + out = append(out, s.Underline.Prefix("underline")) + } + if s.NoInherit { + out = append(out, "noinherit") + } + if s.Colour.IsSet() { + out = append(out, s.Colour.String()) + } + if s.Background.IsSet() { + out = append(out, "bg:"+s.Background.String()) + } + if s.Border.IsSet() { + out = append(out, "border:"+s.Border.String()) + } + return strings.Join(out, " ") +} + +// Sub subtracts e from s where elements match. +func (s StyleEntry) Sub(e StyleEntry) StyleEntry { + out := StyleEntry{} + if e.Colour != s.Colour { + out.Colour = s.Colour + } + if e.Background != s.Background { + out.Background = s.Background + } + if e.Bold != s.Bold { + out.Bold = s.Bold + } + if e.Italic != s.Italic { + out.Italic = s.Italic + } + if e.Underline != s.Underline { + out.Underline = s.Underline + } + if e.Border != s.Border { + out.Border = s.Border + } + return out +} + +// Inherit styles from ancestors. +// +// Ancestors should be provided from oldest to newest. +func (s StyleEntry) Inherit(ancestors ...StyleEntry) StyleEntry { + out := s + for i := len(ancestors) - 1; i >= 0; i-- { + if out.NoInherit { + return out + } + ancestor := ancestors[i] + if !out.Colour.IsSet() { + out.Colour = ancestor.Colour + } + if !out.Background.IsSet() { + out.Background = ancestor.Background + } + if !out.Border.IsSet() { + out.Border = ancestor.Border + } + if out.Bold == Pass { + out.Bold = ancestor.Bold + } + if out.Italic == Pass { + out.Italic = ancestor.Italic + } + if out.Underline == Pass { + out.Underline = ancestor.Underline + } + } + return out +} + +func (s StyleEntry) IsZero() bool { + return s.Colour == 0 && s.Background == 0 && s.Border == 0 && s.Bold == Pass && s.Italic == Pass && + s.Underline == Pass && !s.NoInherit +} + +// A StyleBuilder is a mutable structure for building styles. +// +// Once built, a Style is immutable. +type StyleBuilder struct { + entries map[TokenType]string + name string + parent *Style +} + +func NewStyleBuilder(name string) *StyleBuilder { + return &StyleBuilder{name: name, entries: map[TokenType]string{}} +} + +func (s *StyleBuilder) AddAll(entries StyleEntries) *StyleBuilder { + for ttype, entry := range entries { + s.entries[ttype] = entry + } + return s +} + +func (s *StyleBuilder) Get(ttype TokenType) StyleEntry { + // This is less than ideal, but it's the price for not having to check errors on each Add(). + entry, _ := ParseStyleEntry(s.entries[ttype]) + if s.parent != nil { + entry = entry.Inherit(s.parent.Get(ttype)) + } + return entry +} + +// Add an entry to the Style map. +// +// See http://pygments.org/docs/styles/#style-rules for details. +func (s *StyleBuilder) Add(ttype TokenType, entry string) *StyleBuilder { // nolint: gocyclo + s.entries[ttype] = entry + return s +} + +func (s *StyleBuilder) AddEntry(ttype TokenType, entry StyleEntry) *StyleBuilder { + s.entries[ttype] = entry.String() + return s +} + +// Transform passes each style entry currently defined in the builder to the supplied +// function and saves the returned value. This can be used to adjust a style's colours; +// see Colour's ClampBrightness function, for example. +func (s *StyleBuilder) Transform(transform func(StyleEntry) StyleEntry) *StyleBuilder { + types := make(map[TokenType]struct{}) + for tt := range s.entries { + types[tt] = struct{}{} + } + if s.parent != nil { + for _, tt := range s.parent.Types() { + types[tt] = struct{}{} + } + } + for tt := range types { + s.AddEntry(tt, transform(s.Get(tt))) + } + return s +} + +func (s *StyleBuilder) Build() (*Style, error) { + style := &Style{ + Name: s.name, + entries: map[TokenType]StyleEntry{}, + parent: s.parent, + } + for ttype, descriptor := range s.entries { + entry, err := ParseStyleEntry(descriptor) + if err != nil { + return nil, fmt.Errorf("invalid entry for %s: %s", ttype, err) + } + style.entries[ttype] = entry + } + return style, nil +} + +// StyleEntries mapping TokenType to colour definition. +type StyleEntries map[TokenType]string + +// NewXMLStyle parses an XML style definition. +func NewXMLStyle(r io.Reader) (*Style, error) { + dec := xml.NewDecoder(r) + style := &Style{} + return style, dec.Decode(style) +} + +// MustNewXMLStyle is like NewXMLStyle but panics on error. +func MustNewXMLStyle(r io.Reader) *Style { + style, err := NewXMLStyle(r) + if err != nil { + panic(err) + } + return style +} + +// NewStyle creates a new style definition. +func NewStyle(name string, entries StyleEntries) (*Style, error) { + return NewStyleBuilder(name).AddAll(entries).Build() +} + +// MustNewStyle creates a new style or panics. +func MustNewStyle(name string, entries StyleEntries) *Style { + style, err := NewStyle(name, entries) + if err != nil { + panic(err) + } + return style +} + +// A Style definition. +// +// See http://pygments.org/docs/styles/ for details. Semantics are intended to be identical. +type Style struct { + Name string + entries map[TokenType]StyleEntry + parent *Style +} + +func (s *Style) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + if s.parent != nil { + return fmt.Errorf("cannot marshal style with parent") + } + start.Name = xml.Name{Local: "style"} + start.Attr = []xml.Attr{{Name: xml.Name{Local: "name"}, Value: s.Name}} + if err := e.EncodeToken(start); err != nil { + return err + } + sorted := make([]TokenType, 0, len(s.entries)) + for ttype := range s.entries { + sorted = append(sorted, ttype) + } + sort.Slice(sorted, func(i, j int) bool { return sorted[i] < sorted[j] }) + for _, ttype := range sorted { + entry := s.entries[ttype] + el := xml.StartElement{Name: xml.Name{Local: "entry"}} + el.Attr = []xml.Attr{ + {Name: xml.Name{Local: "type"}, Value: ttype.String()}, + {Name: xml.Name{Local: "style"}, Value: entry.String()}, + } + if err := e.EncodeToken(el); err != nil { + return err + } + if err := e.EncodeToken(xml.EndElement{Name: el.Name}); err != nil { + return err + } + } + return e.EncodeToken(xml.EndElement{Name: start.Name}) +} + +func (s *Style) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + for _, attr := range start.Attr { + if attr.Name.Local == "name" { + s.Name = attr.Value + } else { + return fmt.Errorf("unexpected attribute %s", attr.Name.Local) + } + } + if s.Name == "" { + return fmt.Errorf("missing style name attribute") + } + s.entries = map[TokenType]StyleEntry{} + for { + tok, err := d.Token() + if err != nil { + return err + } + switch el := tok.(type) { + case xml.StartElement: + if el.Name.Local != "entry" { + return fmt.Errorf("unexpected element %s", el.Name.Local) + } + var ttype TokenType + var entry StyleEntry + for _, attr := range el.Attr { + switch attr.Name.Local { + case "type": + ttype, err = TokenTypeString(attr.Value) + if err != nil { + return err + } + + case "style": + entry, err = ParseStyleEntry(attr.Value) + if err != nil { + return err + } + + default: + return fmt.Errorf("unexpected attribute %s", attr.Name.Local) + } + } + s.entries[ttype] = entry + + case xml.EndElement: + if el.Name.Local == start.Name.Local { + return nil + } + } + } +} + +// Types that are styled. +func (s *Style) Types() []TokenType { + dedupe := map[TokenType]bool{} + for tt := range s.entries { + dedupe[tt] = true + } + if s.parent != nil { + for _, tt := range s.parent.Types() { + dedupe[tt] = true + } + } + out := make([]TokenType, 0, len(dedupe)) + for tt := range dedupe { + out = append(out, tt) + } + return out +} + +// Builder creates a mutable builder from this Style. +// +// The builder can then be safely modified. This is a cheap operation. +func (s *Style) Builder() *StyleBuilder { + return &StyleBuilder{ + name: s.Name, + entries: map[TokenType]string{}, + parent: s, + } +} + +// Has checks if an exact style entry match exists for a token type. +// +// This is distinct from Get() which will merge parent tokens. +func (s *Style) Has(ttype TokenType) bool { + return !s.get(ttype).IsZero() || s.synthesisable(ttype) +} + +// Get a style entry. Will try sub-category or category if an exact match is not found, and +// finally return the Background. +func (s *Style) Get(ttype TokenType) StyleEntry { + return s.get(ttype).Inherit( + s.get(Background), + s.get(Text), + s.get(ttype.Category()), + s.get(ttype.SubCategory())) +} + +func (s *Style) get(ttype TokenType) StyleEntry { + out := s.entries[ttype] + if out.IsZero() && s.parent != nil { + return s.parent.get(ttype) + } + if out.IsZero() && s.synthesisable(ttype) { + out = s.synthesise(ttype) + } + return out +} + +func (s *Style) synthesise(ttype TokenType) StyleEntry { + bg := s.get(Background) + text := StyleEntry{Colour: bg.Colour} + text.Colour = text.Colour.BrightenOrDarken(0.5) + + switch ttype { + // If we don't have a line highlight colour, make one that is 10% brighter/darker than the background. + case LineHighlight: + return StyleEntry{Background: bg.Background.BrightenOrDarken(0.1)} + + // If we don't have line numbers, use the text colour but 20% brighter/darker + case LineNumbers, LineNumbersTable: + return text + + default: + return StyleEntry{} + } +} + +func (s *Style) synthesisable(ttype TokenType) bool { + return ttype == LineHighlight || ttype == LineNumbers || ttype == LineNumbersTable +} + +// MustParseStyleEntry parses a Pygments style entry or panics. +func MustParseStyleEntry(entry string) StyleEntry { + out, err := ParseStyleEntry(entry) + if err != nil { + panic(err) + } + return out +} + +// ParseStyleEntry parses a Pygments style entry. +func ParseStyleEntry(entry string) (StyleEntry, error) { // nolint: gocyclo + out := StyleEntry{} + parts := strings.Fields(entry) + for _, part := range parts { + switch { + case part == "italic": + out.Italic = Yes + case part == "noitalic": + out.Italic = No + case part == "bold": + out.Bold = Yes + case part == "nobold": + out.Bold = No + case part == "underline": + out.Underline = Yes + case part == "nounderline": + out.Underline = No + case part == "inherit": + out.NoInherit = false + case part == "noinherit": + out.NoInherit = true + case part == "bg:": + out.Background = 0 + case strings.HasPrefix(part, "bg:#"): + out.Background = ParseColour(part[3:]) + if !out.Background.IsSet() { + return StyleEntry{}, fmt.Errorf("invalid background colour %q", part) + } + case strings.HasPrefix(part, "border:#"): + out.Border = ParseColour(part[7:]) + if !out.Border.IsSet() { + return StyleEntry{}, fmt.Errorf("invalid border colour %q", part) + } + case strings.HasPrefix(part, "#"): + out.Colour = ParseColour(part) + if !out.Colour.IsSet() { + return StyleEntry{}, fmt.Errorf("invalid colour %q", part) + } + default: + return StyleEntry{}, fmt.Errorf("unknown style element %q", part) + } + } + return out, nil +} diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/abap.xml b/vendor/github.com/alecthomas/chroma/v2/styles/abap.xml new file mode 100644 index 000000000..36ea2f1d0 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/abap.xml @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/algol.xml b/vendor/github.com/alecthomas/chroma/v2/styles/algol.xml new file mode 100644 index 000000000..e8a6dc1b8 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/algol.xml @@ -0,0 +1,18 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/algol_nu.xml b/vendor/github.com/alecthomas/chroma/v2/styles/algol_nu.xml new file mode 100644 index 000000000..7fa340f32 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/algol_nu.xml @@ -0,0 +1,18 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/api.go b/vendor/github.com/alecthomas/chroma/v2/styles/api.go new file mode 100644 index 000000000..e26d6f0a5 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/api.go @@ -0,0 +1,65 @@ +package styles + +import ( + "embed" + "io/fs" + "sort" + + "github.com/alecthomas/chroma/v2" +) + +//go:embed *.xml +var embedded embed.FS + +// Registry of Styles. +var Registry = func() map[string]*chroma.Style { + registry := map[string]*chroma.Style{} + // Register all embedded styles. + files, err := fs.ReadDir(embedded, ".") + if err != nil { + panic(err) + } + for _, file := range files { + if file.IsDir() { + continue + } + r, err := embedded.Open(file.Name()) + if err != nil { + panic(err) + } + style, err := chroma.NewXMLStyle(r) + if err != nil { + panic(err) + } + registry[style.Name] = style + _ = r.Close() + } + return registry +}() + +// Fallback style. Reassign to change the default fallback style. +var Fallback = Registry["swapoff"] + +// Register a chroma.Style. +func Register(style *chroma.Style) *chroma.Style { + Registry[style.Name] = style + return style +} + +// Names of all available styles. +func Names() []string { + out := []string{} + for name := range Registry { + out = append(out, name) + } + sort.Strings(out) + return out +} + +// Get named style, or Fallback. +func Get(name string) *chroma.Style { + if style, ok := Registry[name]; ok { + return style + } + return Fallback +} diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/arduino.xml b/vendor/github.com/alecthomas/chroma/v2/styles/arduino.xml new file mode 100644 index 000000000..d9891dc53 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/arduino.xml @@ -0,0 +1,18 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/ashen.xml b/vendor/github.com/alecthomas/chroma/v2/styles/ashen.xml new file mode 100644 index 000000000..c22b3fa55 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/ashen.xml @@ -0,0 +1,69 @@ + + diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/aura-theme-dark-soft.xml b/vendor/github.com/alecthomas/chroma/v2/styles/aura-theme-dark-soft.xml new file mode 100644 index 000000000..ee7f1257f --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/aura-theme-dark-soft.xml @@ -0,0 +1,107 @@ + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/aura-theme-dark.xml b/vendor/github.com/alecthomas/chroma/v2/styles/aura-theme-dark.xml new file mode 100644 index 000000000..85e8ec936 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/aura-theme-dark.xml @@ -0,0 +1,107 @@ + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/autumn.xml b/vendor/github.com/alecthomas/chroma/v2/styles/autumn.xml new file mode 100644 index 000000000..74d2eae98 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/autumn.xml @@ -0,0 +1,36 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/average.xml b/vendor/github.com/alecthomas/chroma/v2/styles/average.xml new file mode 100644 index 000000000..79bdb95f3 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/average.xml @@ -0,0 +1,74 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/base16-snazzy.xml b/vendor/github.com/alecthomas/chroma/v2/styles/base16-snazzy.xml new file mode 100644 index 000000000..a05ba24e5 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/base16-snazzy.xml @@ -0,0 +1,74 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/borland.xml b/vendor/github.com/alecthomas/chroma/v2/styles/borland.xml new file mode 100644 index 000000000..0d8f574c6 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/borland.xml @@ -0,0 +1,26 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/bw.xml b/vendor/github.com/alecthomas/chroma/v2/styles/bw.xml new file mode 100644 index 000000000..fb0e868d1 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/bw.xml @@ -0,0 +1,23 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/catppuccin-frappe.xml b/vendor/github.com/alecthomas/chroma/v2/styles/catppuccin-frappe.xml new file mode 100644 index 000000000..66a361fb7 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/catppuccin-frappe.xml @@ -0,0 +1,83 @@ + diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/catppuccin-latte.xml b/vendor/github.com/alecthomas/chroma/v2/styles/catppuccin-latte.xml new file mode 100644 index 000000000..c87c8765d --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/catppuccin-latte.xml @@ -0,0 +1,83 @@ + diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/catppuccin-macchiato.xml b/vendor/github.com/alecthomas/chroma/v2/styles/catppuccin-macchiato.xml new file mode 100644 index 000000000..5dba9c647 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/catppuccin-macchiato.xml @@ -0,0 +1,83 @@ + diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/catppuccin-mocha.xml b/vendor/github.com/alecthomas/chroma/v2/styles/catppuccin-mocha.xml new file mode 100644 index 000000000..9f9b9152a --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/catppuccin-mocha.xml @@ -0,0 +1,83 @@ + diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/colorful.xml b/vendor/github.com/alecthomas/chroma/v2/styles/colorful.xml new file mode 100644 index 000000000..32442d716 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/colorful.xml @@ -0,0 +1,52 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/compat.go b/vendor/github.com/alecthomas/chroma/v2/styles/compat.go new file mode 100644 index 000000000..4a6aaa665 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/compat.go @@ -0,0 +1,66 @@ +package styles + +// Present for backwards compatibility. +// +// Deprecated: use styles.Get(name) instead. +var ( + Abap = Registry["abap"] + Algol = Registry["algol"] + AlgolNu = Registry["algol_nu"] + Arduino = Registry["arduino"] + Autumn = Registry["autumn"] + Average = Registry["average"] + Base16Snazzy = Registry["base16-snazzy"] + Borland = Registry["borland"] + BlackWhite = Registry["bw"] + CatppuccinFrappe = Registry["catppuccin-frappe"] + CatppuccinLatte = Registry["catppuccin-latte"] + CatppuccinMacchiato = Registry["catppuccin-macchiato"] + CatppuccinMocha = Registry["catppuccin-mocha"] + Colorful = Registry["colorful"] + DoomOne = Registry["doom-one"] + DoomOne2 = Registry["doom-one2"] + Dracula = Registry["dracula"] + Emacs = Registry["emacs"] + Friendly = Registry["friendly"] + Fruity = Registry["fruity"] + GitHubDark = Registry["github-dark"] + GitHub = Registry["github"] + GruvboxLight = Registry["gruvbox-light"] + Gruvbox = Registry["gruvbox"] + HrDark = Registry["hrdark"] + HrHighContrast = Registry["hr_high_contrast"] + Igor = Registry["igor"] + Lovelace = Registry["lovelace"] + Manni = Registry["manni"] + ModusOperandi = Registry["modus-operandi"] + ModusVivendi = Registry["modus-vivendi"] + Monokai = Registry["monokai"] + MonokaiLight = Registry["monokailight"] + Murphy = Registry["murphy"] + Native = Registry["native"] + Nord = Registry["nord"] + OnesEnterprise = Registry["onesenterprise"] + ParaisoDark = Registry["paraiso-dark"] + ParaisoLight = Registry["paraiso-light"] + Pastie = Registry["pastie"] + Perldoc = Registry["perldoc"] + Pygments = Registry["pygments"] + RainbowDash = Registry["rainbow_dash"] + RosePineDawn = Registry["rose-pine-dawn"] + RosePineMoon = Registry["rose-pine-moon"] + RosePine = Registry["rose-pine"] + Rrt = Registry["rrt"] + SolarizedDark = Registry["solarized-dark"] + SolarizedDark256 = Registry["solarized-dark256"] + SolarizedLight = Registry["solarized-light"] + SwapOff = Registry["swapoff"] + Tango = Registry["tango"] + Trac = Registry["trac"] + Vim = Registry["vim"] + VisualStudio = Registry["vs"] + Vulcan = Registry["vulcan"] + WitchHazel = Registry["witchhazel"] + XcodeDark = Registry["xcode-dark"] + Xcode = Registry["xcode"] +) diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/doom-one.xml b/vendor/github.com/alecthomas/chroma/v2/styles/doom-one.xml new file mode 100644 index 000000000..1f5127ef9 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/doom-one.xml @@ -0,0 +1,51 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/doom-one2.xml b/vendor/github.com/alecthomas/chroma/v2/styles/doom-one2.xml new file mode 100644 index 000000000..f47debaf0 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/doom-one2.xml @@ -0,0 +1,64 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/dracula.xml b/vendor/github.com/alecthomas/chroma/v2/styles/dracula.xml new file mode 100644 index 000000000..9df7da11c --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/dracula.xml @@ -0,0 +1,74 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/emacs.xml b/vendor/github.com/alecthomas/chroma/v2/styles/emacs.xml new file mode 100644 index 000000000..981ce8e40 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/emacs.xml @@ -0,0 +1,44 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/evergarden.xml b/vendor/github.com/alecthomas/chroma/v2/styles/evergarden.xml new file mode 100644 index 000000000..da1d9b843 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/evergarden.xml @@ -0,0 +1,33 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/friendly.xml b/vendor/github.com/alecthomas/chroma/v2/styles/friendly.xml new file mode 100644 index 000000000..f49801040 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/friendly.xml @@ -0,0 +1,44 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/fruity.xml b/vendor/github.com/alecthomas/chroma/v2/styles/fruity.xml new file mode 100644 index 000000000..bcc06aa7b --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/fruity.xml @@ -0,0 +1,19 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/github-dark.xml b/vendor/github.com/alecthomas/chroma/v2/styles/github-dark.xml new file mode 100644 index 000000000..711aeafc4 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/github-dark.xml @@ -0,0 +1,45 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/github.xml b/vendor/github.com/alecthomas/chroma/v2/styles/github.xml new file mode 100644 index 000000000..dd6a56db4 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/github.xml @@ -0,0 +1,39 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/gruvbox-light.xml b/vendor/github.com/alecthomas/chroma/v2/styles/gruvbox-light.xml new file mode 100644 index 000000000..8c4f0642c --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/gruvbox-light.xml @@ -0,0 +1,33 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/gruvbox.xml b/vendor/github.com/alecthomas/chroma/v2/styles/gruvbox.xml new file mode 100644 index 000000000..2f6a0a2a0 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/gruvbox.xml @@ -0,0 +1,33 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/hr_high_contrast.xml b/vendor/github.com/alecthomas/chroma/v2/styles/hr_high_contrast.xml new file mode 100644 index 000000000..61cde204a --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/hr_high_contrast.xml @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/hrdark.xml b/vendor/github.com/alecthomas/chroma/v2/styles/hrdark.xml new file mode 100644 index 000000000..bc7a6f315 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/hrdark.xml @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/igor.xml b/vendor/github.com/alecthomas/chroma/v2/styles/igor.xml new file mode 100644 index 000000000..773c83b60 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/igor.xml @@ -0,0 +1,9 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/lovelace.xml b/vendor/github.com/alecthomas/chroma/v2/styles/lovelace.xml new file mode 100644 index 000000000..e336c930a --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/lovelace.xml @@ -0,0 +1,53 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/manni.xml b/vendor/github.com/alecthomas/chroma/v2/styles/manni.xml new file mode 100644 index 000000000..99324bd3b --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/manni.xml @@ -0,0 +1,44 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/modus-operandi.xml b/vendor/github.com/alecthomas/chroma/v2/styles/modus-operandi.xml new file mode 100644 index 000000000..023137aae --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/modus-operandi.xml @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/modus-vivendi.xml b/vendor/github.com/alecthomas/chroma/v2/styles/modus-vivendi.xml new file mode 100644 index 000000000..8da663dcc --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/modus-vivendi.xml @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/monokai.xml b/vendor/github.com/alecthomas/chroma/v2/styles/monokai.xml new file mode 100644 index 000000000..1a789ddec --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/monokai.xml @@ -0,0 +1,29 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/monokailight.xml b/vendor/github.com/alecthomas/chroma/v2/styles/monokailight.xml new file mode 100644 index 000000000..85cd23e00 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/monokailight.xml @@ -0,0 +1,26 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/murphy.xml b/vendor/github.com/alecthomas/chroma/v2/styles/murphy.xml new file mode 100644 index 000000000..112d6205c --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/murphy.xml @@ -0,0 +1,52 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/native.xml b/vendor/github.com/alecthomas/chroma/v2/styles/native.xml new file mode 100644 index 000000000..43eea7fd5 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/native.xml @@ -0,0 +1,35 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/nord.xml b/vendor/github.com/alecthomas/chroma/v2/styles/nord.xml new file mode 100644 index 000000000..1c1d1ffb2 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/nord.xml @@ -0,0 +1,46 @@ + diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/nordic.xml b/vendor/github.com/alecthomas/chroma/v2/styles/nordic.xml new file mode 100644 index 000000000..4c36b8e4a --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/nordic.xml @@ -0,0 +1,46 @@ + diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/onedark.xml b/vendor/github.com/alecthomas/chroma/v2/styles/onedark.xml new file mode 100644 index 000000000..6921eb5ee --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/onedark.xml @@ -0,0 +1,25 @@ + diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/onesenterprise.xml b/vendor/github.com/alecthomas/chroma/v2/styles/onesenterprise.xml new file mode 100644 index 000000000..ce86db3fb --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/onesenterprise.xml @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/paraiso-dark.xml b/vendor/github.com/alecthomas/chroma/v2/styles/paraiso-dark.xml new file mode 100644 index 000000000..788db3f7c --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/paraiso-dark.xml @@ -0,0 +1,37 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/paraiso-light.xml b/vendor/github.com/alecthomas/chroma/v2/styles/paraiso-light.xml new file mode 100644 index 000000000..06a63bae1 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/paraiso-light.xml @@ -0,0 +1,37 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/pastie.xml b/vendor/github.com/alecthomas/chroma/v2/styles/pastie.xml new file mode 100644 index 000000000..a3b0abde5 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/pastie.xml @@ -0,0 +1,45 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/perldoc.xml b/vendor/github.com/alecthomas/chroma/v2/styles/perldoc.xml new file mode 100644 index 000000000..9e5564c3f --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/perldoc.xml @@ -0,0 +1,37 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/pygments.xml b/vendor/github.com/alecthomas/chroma/v2/styles/pygments.xml new file mode 100644 index 000000000..a3d0d8bab --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/pygments.xml @@ -0,0 +1,42 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/rainbow_dash.xml b/vendor/github.com/alecthomas/chroma/v2/styles/rainbow_dash.xml new file mode 100644 index 000000000..5b0fe49d6 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/rainbow_dash.xml @@ -0,0 +1,40 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/rose-pine-dawn.xml b/vendor/github.com/alecthomas/chroma/v2/styles/rose-pine-dawn.xml new file mode 100644 index 000000000..788bd6f65 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/rose-pine-dawn.xml @@ -0,0 +1,29 @@ + diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/rose-pine-moon.xml b/vendor/github.com/alecthomas/chroma/v2/styles/rose-pine-moon.xml new file mode 100644 index 000000000..f67b80432 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/rose-pine-moon.xml @@ -0,0 +1,29 @@ + diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/rose-pine.xml b/vendor/github.com/alecthomas/chroma/v2/styles/rose-pine.xml new file mode 100644 index 000000000..3fb70a5ac --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/rose-pine.xml @@ -0,0 +1,29 @@ + diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/rpgle.xml b/vendor/github.com/alecthomas/chroma/v2/styles/rpgle.xml new file mode 100644 index 000000000..678fd70fa --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/rpgle.xml @@ -0,0 +1,30 @@ + diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/rrt.xml b/vendor/github.com/alecthomas/chroma/v2/styles/rrt.xml new file mode 100644 index 000000000..f2c5feb93 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/rrt.xml @@ -0,0 +1,19 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/solarized-dark.xml b/vendor/github.com/alecthomas/chroma/v2/styles/solarized-dark.xml new file mode 100644 index 000000000..a3cf46fdd --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/solarized-dark.xml @@ -0,0 +1,39 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/solarized-dark256.xml b/vendor/github.com/alecthomas/chroma/v2/styles/solarized-dark256.xml new file mode 100644 index 000000000..977cfbe3f --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/solarized-dark256.xml @@ -0,0 +1,41 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/solarized-light.xml b/vendor/github.com/alecthomas/chroma/v2/styles/solarized-light.xml new file mode 100644 index 000000000..4fbc1d4a6 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/solarized-light.xml @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/swapoff.xml b/vendor/github.com/alecthomas/chroma/v2/styles/swapoff.xml new file mode 100644 index 000000000..8a398df8d --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/swapoff.xml @@ -0,0 +1,18 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/tango.xml b/vendor/github.com/alecthomas/chroma/v2/styles/tango.xml new file mode 100644 index 000000000..27f9b4b81 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/tango.xml @@ -0,0 +1,72 @@ + diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/tokyonight-day.xml b/vendor/github.com/alecthomas/chroma/v2/styles/tokyonight-day.xml new file mode 100644 index 000000000..c20d9a41e --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/tokyonight-day.xml @@ -0,0 +1,83 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/tokyonight-moon.xml b/vendor/github.com/alecthomas/chroma/v2/styles/tokyonight-moon.xml new file mode 100644 index 000000000..3312f029d --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/tokyonight-moon.xml @@ -0,0 +1,83 @@ + diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/tokyonight-night.xml b/vendor/github.com/alecthomas/chroma/v2/styles/tokyonight-night.xml new file mode 100644 index 000000000..c798bad4d --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/tokyonight-night.xml @@ -0,0 +1,83 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/tokyonight-storm.xml b/vendor/github.com/alecthomas/chroma/v2/styles/tokyonight-storm.xml new file mode 100644 index 000000000..c08115247 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/tokyonight-storm.xml @@ -0,0 +1,83 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/trac.xml b/vendor/github.com/alecthomas/chroma/v2/styles/trac.xml new file mode 100644 index 000000000..9f1d26678 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/trac.xml @@ -0,0 +1,35 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/vim.xml b/vendor/github.com/alecthomas/chroma/v2/styles/vim.xml new file mode 100644 index 000000000..fec693434 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/vim.xml @@ -0,0 +1,29 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/vs.xml b/vendor/github.com/alecthomas/chroma/v2/styles/vs.xml new file mode 100644 index 000000000..564350154 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/vs.xml @@ -0,0 +1,16 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/vulcan.xml b/vendor/github.com/alecthomas/chroma/v2/styles/vulcan.xml new file mode 100644 index 000000000..4e690945e --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/vulcan.xml @@ -0,0 +1,74 @@ + diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/witchhazel.xml b/vendor/github.com/alecthomas/chroma/v2/styles/witchhazel.xml new file mode 100644 index 000000000..52f229913 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/witchhazel.xml @@ -0,0 +1,31 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/xcode-dark.xml b/vendor/github.com/alecthomas/chroma/v2/styles/xcode-dark.xml new file mode 100644 index 000000000..93439791f --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/xcode-dark.xml @@ -0,0 +1,31 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/xcode.xml b/vendor/github.com/alecthomas/chroma/v2/styles/xcode.xml new file mode 100644 index 000000000..523d746cf --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/styles/xcode.xml @@ -0,0 +1,22 @@ + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/table.py b/vendor/github.com/alecthomas/chroma/v2/table.py new file mode 100644 index 000000000..ea4b7556a --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/table.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +import re +from collections import defaultdict +from subprocess import check_output + +README_FILE = "README.md" + +lines = check_output(["chroma", "--list"]).decode("utf-8").splitlines() +lines = [line.strip() for line in lines if line.startswith(" ") and not line.startswith(" ")] +lines = sorted(lines, key=lambda l: l.lower()) + +table = defaultdict(list) + +for line in lines: + table[line[0].upper()].append(line) + +rows = [] +for key, value in table.items(): + rows.append("{} | {}".format(key, ", ".join(value))) +tbody = "\n".join(rows) + +with open(README_FILE, "r") as f: + content = f.read() + +with open(README_FILE, "w") as f: + marker = re.compile(r"(?P:----: \\| --------\n).*?(?P\n\n)", re.DOTALL) + replacement = r"\g%s\g" % tbody + updated_content = marker.sub(replacement, content) + f.write(updated_content) + +print(tbody) diff --git a/vendor/github.com/alecthomas/chroma/v2/tokentype_enumer.go b/vendor/github.com/alecthomas/chroma/v2/tokentype_enumer.go new file mode 100644 index 000000000..c3b15f03c --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/tokentype_enumer.go @@ -0,0 +1,583 @@ +// Code generated by "enumer -text -type TokenType"; DO NOT EDIT. + +package chroma + +import ( + "fmt" + "strings" +) + +const _TokenTypeName = "IgnoreNoneOtherErrorCodeLineLineLinkLineTableTDLineTableLineHighlightLineNumbersTableLineNumbersLinePreWrapperBackgroundEOFTypeKeywordKeywordConstantKeywordDeclarationKeywordNamespaceKeywordPseudoKeywordReservedKeywordTypeNameNameAttributeNameClassNameConstantNameDecoratorNameEntityNameExceptionNameKeywordNameLabelNameNamespaceNameOperatorNameOtherNamePseudoNamePropertyNameTagNameBuiltinNameBuiltinPseudoNameVariableNameVariableAnonymousNameVariableClassNameVariableGlobalNameVariableInstanceNameVariableMagicNameFunctionNameFunctionMagicLiteralLiteralDateLiteralOtherLiteralStringLiteralStringAffixLiteralStringAtomLiteralStringBacktickLiteralStringBooleanLiteralStringCharLiteralStringDelimiterLiteralStringDocLiteralStringDoubleLiteralStringEscapeLiteralStringHeredocLiteralStringInterpolLiteralStringNameLiteralStringOtherLiteralStringRegexLiteralStringSingleLiteralStringSymbolLiteralNumberLiteralNumberBinLiteralNumberFloatLiteralNumberHexLiteralNumberIntegerLiteralNumberIntegerLongLiteralNumberOctLiteralNumberByteOperatorOperatorWordPunctuationCommentCommentHashbangCommentMultilineCommentSingleCommentSpecialCommentPreprocCommentPreprocFileGenericGenericDeletedGenericEmphGenericErrorGenericHeadingGenericInsertedGenericOutputGenericPromptGenericStrongGenericSubheadingGenericTracebackGenericUnderlineTextTextWhitespaceTextSymbolTextPunctuation" +const _TokenTypeLowerName = "ignorenoneothererrorcodelinelinelinklinetabletdlinetablelinehighlightlinenumberstablelinenumberslineprewrapperbackgroundeoftypekeywordkeywordconstantkeyworddeclarationkeywordnamespacekeywordpseudokeywordreservedkeywordtypenamenameattributenameclassnameconstantnamedecoratornameentitynameexceptionnamekeywordnamelabelnamenamespacenameoperatornameothernamepseudonamepropertynametagnamebuiltinnamebuiltinpseudonamevariablenamevariableanonymousnamevariableclassnamevariableglobalnamevariableinstancenamevariablemagicnamefunctionnamefunctionmagicliteralliteraldateliteralotherliteralstringliteralstringaffixliteralstringatomliteralstringbacktickliteralstringbooleanliteralstringcharliteralstringdelimiterliteralstringdocliteralstringdoubleliteralstringescapeliteralstringheredocliteralstringinterpolliteralstringnameliteralstringotherliteralstringregexliteralstringsingleliteralstringsymbolliteralnumberliteralnumberbinliteralnumberfloatliteralnumberhexliteralnumberintegerliteralnumberintegerlongliteralnumberoctliteralnumberbyteoperatoroperatorwordpunctuationcommentcommenthashbangcommentmultilinecommentsinglecommentspecialcommentpreproccommentpreprocfilegenericgenericdeletedgenericemphgenericerrorgenericheadinggenericinsertedgenericoutputgenericpromptgenericstronggenericsubheadinggenerictracebackgenericunderlinetexttextwhitespacetextsymboltextpunctuation" + +var _TokenTypeMap = map[TokenType]string{ + -14: _TokenTypeName[0:6], + -13: _TokenTypeName[6:10], + -12: _TokenTypeName[10:15], + -11: _TokenTypeName[15:20], + -10: _TokenTypeName[20:28], + -9: _TokenTypeName[28:36], + -8: _TokenTypeName[36:47], + -7: _TokenTypeName[47:56], + -6: _TokenTypeName[56:69], + -5: _TokenTypeName[69:85], + -4: _TokenTypeName[85:96], + -3: _TokenTypeName[96:100], + -2: _TokenTypeName[100:110], + -1: _TokenTypeName[110:120], + 0: _TokenTypeName[120:127], + 1000: _TokenTypeName[127:134], + 1001: _TokenTypeName[134:149], + 1002: _TokenTypeName[149:167], + 1003: _TokenTypeName[167:183], + 1004: _TokenTypeName[183:196], + 1005: _TokenTypeName[196:211], + 1006: _TokenTypeName[211:222], + 2000: _TokenTypeName[222:226], + 2001: _TokenTypeName[226:239], + 2002: _TokenTypeName[239:248], + 2003: _TokenTypeName[248:260], + 2004: _TokenTypeName[260:273], + 2005: _TokenTypeName[273:283], + 2006: _TokenTypeName[283:296], + 2007: _TokenTypeName[296:307], + 2008: _TokenTypeName[307:316], + 2009: _TokenTypeName[316:329], + 2010: _TokenTypeName[329:341], + 2011: _TokenTypeName[341:350], + 2012: _TokenTypeName[350:360], + 2013: _TokenTypeName[360:372], + 2014: _TokenTypeName[372:379], + 2100: _TokenTypeName[379:390], + 2101: _TokenTypeName[390:407], + 2200: _TokenTypeName[407:419], + 2201: _TokenTypeName[419:440], + 2202: _TokenTypeName[440:457], + 2203: _TokenTypeName[457:475], + 2204: _TokenTypeName[475:495], + 2205: _TokenTypeName[495:512], + 2300: _TokenTypeName[512:524], + 2301: _TokenTypeName[524:541], + 3000: _TokenTypeName[541:548], + 3001: _TokenTypeName[548:559], + 3002: _TokenTypeName[559:571], + 3100: _TokenTypeName[571:584], + 3101: _TokenTypeName[584:602], + 3102: _TokenTypeName[602:619], + 3103: _TokenTypeName[619:640], + 3104: _TokenTypeName[640:660], + 3105: _TokenTypeName[660:677], + 3106: _TokenTypeName[677:699], + 3107: _TokenTypeName[699:715], + 3108: _TokenTypeName[715:734], + 3109: _TokenTypeName[734:753], + 3110: _TokenTypeName[753:773], + 3111: _TokenTypeName[773:794], + 3112: _TokenTypeName[794:811], + 3113: _TokenTypeName[811:829], + 3114: _TokenTypeName[829:847], + 3115: _TokenTypeName[847:866], + 3116: _TokenTypeName[866:885], + 3200: _TokenTypeName[885:898], + 3201: _TokenTypeName[898:914], + 3202: _TokenTypeName[914:932], + 3203: _TokenTypeName[932:948], + 3204: _TokenTypeName[948:968], + 3205: _TokenTypeName[968:992], + 3206: _TokenTypeName[992:1008], + 3207: _TokenTypeName[1008:1025], + 4000: _TokenTypeName[1025:1033], + 4001: _TokenTypeName[1033:1045], + 5000: _TokenTypeName[1045:1056], + 6000: _TokenTypeName[1056:1063], + 6001: _TokenTypeName[1063:1078], + 6002: _TokenTypeName[1078:1094], + 6003: _TokenTypeName[1094:1107], + 6004: _TokenTypeName[1107:1121], + 6100: _TokenTypeName[1121:1135], + 6101: _TokenTypeName[1135:1153], + 7000: _TokenTypeName[1153:1160], + 7001: _TokenTypeName[1160:1174], + 7002: _TokenTypeName[1174:1185], + 7003: _TokenTypeName[1185:1197], + 7004: _TokenTypeName[1197:1211], + 7005: _TokenTypeName[1211:1226], + 7006: _TokenTypeName[1226:1239], + 7007: _TokenTypeName[1239:1252], + 7008: _TokenTypeName[1252:1265], + 7009: _TokenTypeName[1265:1282], + 7010: _TokenTypeName[1282:1298], + 7011: _TokenTypeName[1298:1314], + 8000: _TokenTypeName[1314:1318], + 8001: _TokenTypeName[1318:1332], + 8002: _TokenTypeName[1332:1342], + 8003: _TokenTypeName[1342:1357], +} + +func (i TokenType) String() string { + if str, ok := _TokenTypeMap[i]; ok { + return str + } + return fmt.Sprintf("TokenType(%d)", i) +} + +// An "invalid array index" compiler error signifies that the constant values have changed. +// Re-run the stringer command to generate them again. +func _TokenTypeNoOp() { + var x [1]struct{} + _ = x[Ignore-(-14)] + _ = x[None-(-13)] + _ = x[Other-(-12)] + _ = x[Error-(-11)] + _ = x[CodeLine-(-10)] + _ = x[LineLink-(-9)] + _ = x[LineTableTD-(-8)] + _ = x[LineTable-(-7)] + _ = x[LineHighlight-(-6)] + _ = x[LineNumbersTable-(-5)] + _ = x[LineNumbers-(-4)] + _ = x[Line-(-3)] + _ = x[PreWrapper-(-2)] + _ = x[Background-(-1)] + _ = x[EOFType-(0)] + _ = x[Keyword-(1000)] + _ = x[KeywordConstant-(1001)] + _ = x[KeywordDeclaration-(1002)] + _ = x[KeywordNamespace-(1003)] + _ = x[KeywordPseudo-(1004)] + _ = x[KeywordReserved-(1005)] + _ = x[KeywordType-(1006)] + _ = x[Name-(2000)] + _ = x[NameAttribute-(2001)] + _ = x[NameClass-(2002)] + _ = x[NameConstant-(2003)] + _ = x[NameDecorator-(2004)] + _ = x[NameEntity-(2005)] + _ = x[NameException-(2006)] + _ = x[NameKeyword-(2007)] + _ = x[NameLabel-(2008)] + _ = x[NameNamespace-(2009)] + _ = x[NameOperator-(2010)] + _ = x[NameOther-(2011)] + _ = x[NamePseudo-(2012)] + _ = x[NameProperty-(2013)] + _ = x[NameTag-(2014)] + _ = x[NameBuiltin-(2100)] + _ = x[NameBuiltinPseudo-(2101)] + _ = x[NameVariable-(2200)] + _ = x[NameVariableAnonymous-(2201)] + _ = x[NameVariableClass-(2202)] + _ = x[NameVariableGlobal-(2203)] + _ = x[NameVariableInstance-(2204)] + _ = x[NameVariableMagic-(2205)] + _ = x[NameFunction-(2300)] + _ = x[NameFunctionMagic-(2301)] + _ = x[Literal-(3000)] + _ = x[LiteralDate-(3001)] + _ = x[LiteralOther-(3002)] + _ = x[LiteralString-(3100)] + _ = x[LiteralStringAffix-(3101)] + _ = x[LiteralStringAtom-(3102)] + _ = x[LiteralStringBacktick-(3103)] + _ = x[LiteralStringBoolean-(3104)] + _ = x[LiteralStringChar-(3105)] + _ = x[LiteralStringDelimiter-(3106)] + _ = x[LiteralStringDoc-(3107)] + _ = x[LiteralStringDouble-(3108)] + _ = x[LiteralStringEscape-(3109)] + _ = x[LiteralStringHeredoc-(3110)] + _ = x[LiteralStringInterpol-(3111)] + _ = x[LiteralStringName-(3112)] + _ = x[LiteralStringOther-(3113)] + _ = x[LiteralStringRegex-(3114)] + _ = x[LiteralStringSingle-(3115)] + _ = x[LiteralStringSymbol-(3116)] + _ = x[LiteralNumber-(3200)] + _ = x[LiteralNumberBin-(3201)] + _ = x[LiteralNumberFloat-(3202)] + _ = x[LiteralNumberHex-(3203)] + _ = x[LiteralNumberInteger-(3204)] + _ = x[LiteralNumberIntegerLong-(3205)] + _ = x[LiteralNumberOct-(3206)] + _ = x[LiteralNumberByte-(3207)] + _ = x[Operator-(4000)] + _ = x[OperatorWord-(4001)] + _ = x[Punctuation-(5000)] + _ = x[Comment-(6000)] + _ = x[CommentHashbang-(6001)] + _ = x[CommentMultiline-(6002)] + _ = x[CommentSingle-(6003)] + _ = x[CommentSpecial-(6004)] + _ = x[CommentPreproc-(6100)] + _ = x[CommentPreprocFile-(6101)] + _ = x[Generic-(7000)] + _ = x[GenericDeleted-(7001)] + _ = x[GenericEmph-(7002)] + _ = x[GenericError-(7003)] + _ = x[GenericHeading-(7004)] + _ = x[GenericInserted-(7005)] + _ = x[GenericOutput-(7006)] + _ = x[GenericPrompt-(7007)] + _ = x[GenericStrong-(7008)] + _ = x[GenericSubheading-(7009)] + _ = x[GenericTraceback-(7010)] + _ = x[GenericUnderline-(7011)] + _ = x[Text-(8000)] + _ = x[TextWhitespace-(8001)] + _ = x[TextSymbol-(8002)] + _ = x[TextPunctuation-(8003)] +} + +var _TokenTypeValues = []TokenType{Ignore, None, Other, Error, CodeLine, LineLink, LineTableTD, LineTable, LineHighlight, LineNumbersTable, LineNumbers, Line, PreWrapper, Background, EOFType, Keyword, KeywordConstant, KeywordDeclaration, KeywordNamespace, KeywordPseudo, KeywordReserved, KeywordType, Name, NameAttribute, NameClass, NameConstant, NameDecorator, NameEntity, NameException, NameKeyword, NameLabel, NameNamespace, NameOperator, NameOther, NamePseudo, NameProperty, NameTag, NameBuiltin, NameBuiltinPseudo, NameVariable, NameVariableAnonymous, NameVariableClass, NameVariableGlobal, NameVariableInstance, NameVariableMagic, NameFunction, NameFunctionMagic, Literal, LiteralDate, LiteralOther, LiteralString, LiteralStringAffix, LiteralStringAtom, LiteralStringBacktick, LiteralStringBoolean, LiteralStringChar, LiteralStringDelimiter, LiteralStringDoc, LiteralStringDouble, LiteralStringEscape, LiteralStringHeredoc, LiteralStringInterpol, LiteralStringName, LiteralStringOther, LiteralStringRegex, LiteralStringSingle, LiteralStringSymbol, LiteralNumber, LiteralNumberBin, LiteralNumberFloat, LiteralNumberHex, LiteralNumberInteger, LiteralNumberIntegerLong, LiteralNumberOct, LiteralNumberByte, Operator, OperatorWord, Punctuation, Comment, CommentHashbang, CommentMultiline, CommentSingle, CommentSpecial, CommentPreproc, CommentPreprocFile, Generic, GenericDeleted, GenericEmph, GenericError, GenericHeading, GenericInserted, GenericOutput, GenericPrompt, GenericStrong, GenericSubheading, GenericTraceback, GenericUnderline, Text, TextWhitespace, TextSymbol, TextPunctuation} + +var _TokenTypeNameToValueMap = map[string]TokenType{ + _TokenTypeName[0:6]: Ignore, + _TokenTypeLowerName[0:6]: Ignore, + _TokenTypeName[6:10]: None, + _TokenTypeLowerName[6:10]: None, + _TokenTypeName[10:15]: Other, + _TokenTypeLowerName[10:15]: Other, + _TokenTypeName[15:20]: Error, + _TokenTypeLowerName[15:20]: Error, + _TokenTypeName[20:28]: CodeLine, + _TokenTypeLowerName[20:28]: CodeLine, + _TokenTypeName[28:36]: LineLink, + _TokenTypeLowerName[28:36]: LineLink, + _TokenTypeName[36:47]: LineTableTD, + _TokenTypeLowerName[36:47]: LineTableTD, + _TokenTypeName[47:56]: LineTable, + _TokenTypeLowerName[47:56]: LineTable, + _TokenTypeName[56:69]: LineHighlight, + _TokenTypeLowerName[56:69]: LineHighlight, + _TokenTypeName[69:85]: LineNumbersTable, + _TokenTypeLowerName[69:85]: LineNumbersTable, + _TokenTypeName[85:96]: LineNumbers, + _TokenTypeLowerName[85:96]: LineNumbers, + _TokenTypeName[96:100]: Line, + _TokenTypeLowerName[96:100]: Line, + _TokenTypeName[100:110]: PreWrapper, + _TokenTypeLowerName[100:110]: PreWrapper, + _TokenTypeName[110:120]: Background, + _TokenTypeLowerName[110:120]: Background, + _TokenTypeName[120:127]: EOFType, + _TokenTypeLowerName[120:127]: EOFType, + _TokenTypeName[127:134]: Keyword, + _TokenTypeLowerName[127:134]: Keyword, + _TokenTypeName[134:149]: KeywordConstant, + _TokenTypeLowerName[134:149]: KeywordConstant, + _TokenTypeName[149:167]: KeywordDeclaration, + _TokenTypeLowerName[149:167]: KeywordDeclaration, + _TokenTypeName[167:183]: KeywordNamespace, + _TokenTypeLowerName[167:183]: KeywordNamespace, + _TokenTypeName[183:196]: KeywordPseudo, + _TokenTypeLowerName[183:196]: KeywordPseudo, + _TokenTypeName[196:211]: KeywordReserved, + _TokenTypeLowerName[196:211]: KeywordReserved, + _TokenTypeName[211:222]: KeywordType, + _TokenTypeLowerName[211:222]: KeywordType, + _TokenTypeName[222:226]: Name, + _TokenTypeLowerName[222:226]: Name, + _TokenTypeName[226:239]: NameAttribute, + _TokenTypeLowerName[226:239]: NameAttribute, + _TokenTypeName[239:248]: NameClass, + _TokenTypeLowerName[239:248]: NameClass, + _TokenTypeName[248:260]: NameConstant, + _TokenTypeLowerName[248:260]: NameConstant, + _TokenTypeName[260:273]: NameDecorator, + _TokenTypeLowerName[260:273]: NameDecorator, + _TokenTypeName[273:283]: NameEntity, + _TokenTypeLowerName[273:283]: NameEntity, + _TokenTypeName[283:296]: NameException, + _TokenTypeLowerName[283:296]: NameException, + _TokenTypeName[296:307]: NameKeyword, + _TokenTypeLowerName[296:307]: NameKeyword, + _TokenTypeName[307:316]: NameLabel, + _TokenTypeLowerName[307:316]: NameLabel, + _TokenTypeName[316:329]: NameNamespace, + _TokenTypeLowerName[316:329]: NameNamespace, + _TokenTypeName[329:341]: NameOperator, + _TokenTypeLowerName[329:341]: NameOperator, + _TokenTypeName[341:350]: NameOther, + _TokenTypeLowerName[341:350]: NameOther, + _TokenTypeName[350:360]: NamePseudo, + _TokenTypeLowerName[350:360]: NamePseudo, + _TokenTypeName[360:372]: NameProperty, + _TokenTypeLowerName[360:372]: NameProperty, + _TokenTypeName[372:379]: NameTag, + _TokenTypeLowerName[372:379]: NameTag, + _TokenTypeName[379:390]: NameBuiltin, + _TokenTypeLowerName[379:390]: NameBuiltin, + _TokenTypeName[390:407]: NameBuiltinPseudo, + _TokenTypeLowerName[390:407]: NameBuiltinPseudo, + _TokenTypeName[407:419]: NameVariable, + _TokenTypeLowerName[407:419]: NameVariable, + _TokenTypeName[419:440]: NameVariableAnonymous, + _TokenTypeLowerName[419:440]: NameVariableAnonymous, + _TokenTypeName[440:457]: NameVariableClass, + _TokenTypeLowerName[440:457]: NameVariableClass, + _TokenTypeName[457:475]: NameVariableGlobal, + _TokenTypeLowerName[457:475]: NameVariableGlobal, + _TokenTypeName[475:495]: NameVariableInstance, + _TokenTypeLowerName[475:495]: NameVariableInstance, + _TokenTypeName[495:512]: NameVariableMagic, + _TokenTypeLowerName[495:512]: NameVariableMagic, + _TokenTypeName[512:524]: NameFunction, + _TokenTypeLowerName[512:524]: NameFunction, + _TokenTypeName[524:541]: NameFunctionMagic, + _TokenTypeLowerName[524:541]: NameFunctionMagic, + _TokenTypeName[541:548]: Literal, + _TokenTypeLowerName[541:548]: Literal, + _TokenTypeName[548:559]: LiteralDate, + _TokenTypeLowerName[548:559]: LiteralDate, + _TokenTypeName[559:571]: LiteralOther, + _TokenTypeLowerName[559:571]: LiteralOther, + _TokenTypeName[571:584]: LiteralString, + _TokenTypeLowerName[571:584]: LiteralString, + _TokenTypeName[584:602]: LiteralStringAffix, + _TokenTypeLowerName[584:602]: LiteralStringAffix, + _TokenTypeName[602:619]: LiteralStringAtom, + _TokenTypeLowerName[602:619]: LiteralStringAtom, + _TokenTypeName[619:640]: LiteralStringBacktick, + _TokenTypeLowerName[619:640]: LiteralStringBacktick, + _TokenTypeName[640:660]: LiteralStringBoolean, + _TokenTypeLowerName[640:660]: LiteralStringBoolean, + _TokenTypeName[660:677]: LiteralStringChar, + _TokenTypeLowerName[660:677]: LiteralStringChar, + _TokenTypeName[677:699]: LiteralStringDelimiter, + _TokenTypeLowerName[677:699]: LiteralStringDelimiter, + _TokenTypeName[699:715]: LiteralStringDoc, + _TokenTypeLowerName[699:715]: LiteralStringDoc, + _TokenTypeName[715:734]: LiteralStringDouble, + _TokenTypeLowerName[715:734]: LiteralStringDouble, + _TokenTypeName[734:753]: LiteralStringEscape, + _TokenTypeLowerName[734:753]: LiteralStringEscape, + _TokenTypeName[753:773]: LiteralStringHeredoc, + _TokenTypeLowerName[753:773]: LiteralStringHeredoc, + _TokenTypeName[773:794]: LiteralStringInterpol, + _TokenTypeLowerName[773:794]: LiteralStringInterpol, + _TokenTypeName[794:811]: LiteralStringName, + _TokenTypeLowerName[794:811]: LiteralStringName, + _TokenTypeName[811:829]: LiteralStringOther, + _TokenTypeLowerName[811:829]: LiteralStringOther, + _TokenTypeName[829:847]: LiteralStringRegex, + _TokenTypeLowerName[829:847]: LiteralStringRegex, + _TokenTypeName[847:866]: LiteralStringSingle, + _TokenTypeLowerName[847:866]: LiteralStringSingle, + _TokenTypeName[866:885]: LiteralStringSymbol, + _TokenTypeLowerName[866:885]: LiteralStringSymbol, + _TokenTypeName[885:898]: LiteralNumber, + _TokenTypeLowerName[885:898]: LiteralNumber, + _TokenTypeName[898:914]: LiteralNumberBin, + _TokenTypeLowerName[898:914]: LiteralNumberBin, + _TokenTypeName[914:932]: LiteralNumberFloat, + _TokenTypeLowerName[914:932]: LiteralNumberFloat, + _TokenTypeName[932:948]: LiteralNumberHex, + _TokenTypeLowerName[932:948]: LiteralNumberHex, + _TokenTypeName[948:968]: LiteralNumberInteger, + _TokenTypeLowerName[948:968]: LiteralNumberInteger, + _TokenTypeName[968:992]: LiteralNumberIntegerLong, + _TokenTypeLowerName[968:992]: LiteralNumberIntegerLong, + _TokenTypeName[992:1008]: LiteralNumberOct, + _TokenTypeLowerName[992:1008]: LiteralNumberOct, + _TokenTypeName[1008:1025]: LiteralNumberByte, + _TokenTypeLowerName[1008:1025]: LiteralNumberByte, + _TokenTypeName[1025:1033]: Operator, + _TokenTypeLowerName[1025:1033]: Operator, + _TokenTypeName[1033:1045]: OperatorWord, + _TokenTypeLowerName[1033:1045]: OperatorWord, + _TokenTypeName[1045:1056]: Punctuation, + _TokenTypeLowerName[1045:1056]: Punctuation, + _TokenTypeName[1056:1063]: Comment, + _TokenTypeLowerName[1056:1063]: Comment, + _TokenTypeName[1063:1078]: CommentHashbang, + _TokenTypeLowerName[1063:1078]: CommentHashbang, + _TokenTypeName[1078:1094]: CommentMultiline, + _TokenTypeLowerName[1078:1094]: CommentMultiline, + _TokenTypeName[1094:1107]: CommentSingle, + _TokenTypeLowerName[1094:1107]: CommentSingle, + _TokenTypeName[1107:1121]: CommentSpecial, + _TokenTypeLowerName[1107:1121]: CommentSpecial, + _TokenTypeName[1121:1135]: CommentPreproc, + _TokenTypeLowerName[1121:1135]: CommentPreproc, + _TokenTypeName[1135:1153]: CommentPreprocFile, + _TokenTypeLowerName[1135:1153]: CommentPreprocFile, + _TokenTypeName[1153:1160]: Generic, + _TokenTypeLowerName[1153:1160]: Generic, + _TokenTypeName[1160:1174]: GenericDeleted, + _TokenTypeLowerName[1160:1174]: GenericDeleted, + _TokenTypeName[1174:1185]: GenericEmph, + _TokenTypeLowerName[1174:1185]: GenericEmph, + _TokenTypeName[1185:1197]: GenericError, + _TokenTypeLowerName[1185:1197]: GenericError, + _TokenTypeName[1197:1211]: GenericHeading, + _TokenTypeLowerName[1197:1211]: GenericHeading, + _TokenTypeName[1211:1226]: GenericInserted, + _TokenTypeLowerName[1211:1226]: GenericInserted, + _TokenTypeName[1226:1239]: GenericOutput, + _TokenTypeLowerName[1226:1239]: GenericOutput, + _TokenTypeName[1239:1252]: GenericPrompt, + _TokenTypeLowerName[1239:1252]: GenericPrompt, + _TokenTypeName[1252:1265]: GenericStrong, + _TokenTypeLowerName[1252:1265]: GenericStrong, + _TokenTypeName[1265:1282]: GenericSubheading, + _TokenTypeLowerName[1265:1282]: GenericSubheading, + _TokenTypeName[1282:1298]: GenericTraceback, + _TokenTypeLowerName[1282:1298]: GenericTraceback, + _TokenTypeName[1298:1314]: GenericUnderline, + _TokenTypeLowerName[1298:1314]: GenericUnderline, + _TokenTypeName[1314:1318]: Text, + _TokenTypeLowerName[1314:1318]: Text, + _TokenTypeName[1318:1332]: TextWhitespace, + _TokenTypeLowerName[1318:1332]: TextWhitespace, + _TokenTypeName[1332:1342]: TextSymbol, + _TokenTypeLowerName[1332:1342]: TextSymbol, + _TokenTypeName[1342:1357]: TextPunctuation, + _TokenTypeLowerName[1342:1357]: TextPunctuation, +} + +var _TokenTypeNames = []string{ + _TokenTypeName[0:6], + _TokenTypeName[6:10], + _TokenTypeName[10:15], + _TokenTypeName[15:20], + _TokenTypeName[20:28], + _TokenTypeName[28:36], + _TokenTypeName[36:47], + _TokenTypeName[47:56], + _TokenTypeName[56:69], + _TokenTypeName[69:85], + _TokenTypeName[85:96], + _TokenTypeName[96:100], + _TokenTypeName[100:110], + _TokenTypeName[110:120], + _TokenTypeName[120:127], + _TokenTypeName[127:134], + _TokenTypeName[134:149], + _TokenTypeName[149:167], + _TokenTypeName[167:183], + _TokenTypeName[183:196], + _TokenTypeName[196:211], + _TokenTypeName[211:222], + _TokenTypeName[222:226], + _TokenTypeName[226:239], + _TokenTypeName[239:248], + _TokenTypeName[248:260], + _TokenTypeName[260:273], + _TokenTypeName[273:283], + _TokenTypeName[283:296], + _TokenTypeName[296:307], + _TokenTypeName[307:316], + _TokenTypeName[316:329], + _TokenTypeName[329:341], + _TokenTypeName[341:350], + _TokenTypeName[350:360], + _TokenTypeName[360:372], + _TokenTypeName[372:379], + _TokenTypeName[379:390], + _TokenTypeName[390:407], + _TokenTypeName[407:419], + _TokenTypeName[419:440], + _TokenTypeName[440:457], + _TokenTypeName[457:475], + _TokenTypeName[475:495], + _TokenTypeName[495:512], + _TokenTypeName[512:524], + _TokenTypeName[524:541], + _TokenTypeName[541:548], + _TokenTypeName[548:559], + _TokenTypeName[559:571], + _TokenTypeName[571:584], + _TokenTypeName[584:602], + _TokenTypeName[602:619], + _TokenTypeName[619:640], + _TokenTypeName[640:660], + _TokenTypeName[660:677], + _TokenTypeName[677:699], + _TokenTypeName[699:715], + _TokenTypeName[715:734], + _TokenTypeName[734:753], + _TokenTypeName[753:773], + _TokenTypeName[773:794], + _TokenTypeName[794:811], + _TokenTypeName[811:829], + _TokenTypeName[829:847], + _TokenTypeName[847:866], + _TokenTypeName[866:885], + _TokenTypeName[885:898], + _TokenTypeName[898:914], + _TokenTypeName[914:932], + _TokenTypeName[932:948], + _TokenTypeName[948:968], + _TokenTypeName[968:992], + _TokenTypeName[992:1008], + _TokenTypeName[1008:1025], + _TokenTypeName[1025:1033], + _TokenTypeName[1033:1045], + _TokenTypeName[1045:1056], + _TokenTypeName[1056:1063], + _TokenTypeName[1063:1078], + _TokenTypeName[1078:1094], + _TokenTypeName[1094:1107], + _TokenTypeName[1107:1121], + _TokenTypeName[1121:1135], + _TokenTypeName[1135:1153], + _TokenTypeName[1153:1160], + _TokenTypeName[1160:1174], + _TokenTypeName[1174:1185], + _TokenTypeName[1185:1197], + _TokenTypeName[1197:1211], + _TokenTypeName[1211:1226], + _TokenTypeName[1226:1239], + _TokenTypeName[1239:1252], + _TokenTypeName[1252:1265], + _TokenTypeName[1265:1282], + _TokenTypeName[1282:1298], + _TokenTypeName[1298:1314], + _TokenTypeName[1314:1318], + _TokenTypeName[1318:1332], + _TokenTypeName[1332:1342], + _TokenTypeName[1342:1357], +} + +// TokenTypeString retrieves an enum value from the enum constants string name. +// Throws an error if the param is not part of the enum. +func TokenTypeString(s string) (TokenType, error) { + if val, ok := _TokenTypeNameToValueMap[s]; ok { + return val, nil + } + + if val, ok := _TokenTypeNameToValueMap[strings.ToLower(s)]; ok { + return val, nil + } + return 0, fmt.Errorf("%s does not belong to TokenType values", s) +} + +// TokenTypeValues returns all values of the enum +func TokenTypeValues() []TokenType { + return _TokenTypeValues +} + +// TokenTypeStrings returns a slice of all String values of the enum +func TokenTypeStrings() []string { + strs := make([]string, len(_TokenTypeNames)) + copy(strs, _TokenTypeNames) + return strs +} + +// IsATokenType returns "true" if the value is listed in the enum definition. "false" otherwise +func (i TokenType) IsATokenType() bool { + _, ok := _TokenTypeMap[i] + return ok +} + +// MarshalText implements the encoding.TextMarshaler interface for TokenType +func (i TokenType) MarshalText() ([]byte, error) { + return []byte(i.String()), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface for TokenType +func (i *TokenType) UnmarshalText(text []byte) error { + var err error + *i, err = TokenTypeString(string(text)) + return err +} diff --git a/vendor/github.com/alecthomas/chroma/v2/types.go b/vendor/github.com/alecthomas/chroma/v2/types.go new file mode 100644 index 000000000..3009f9809 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/types.go @@ -0,0 +1,355 @@ +package chroma + +//go:generate enumer -text -type TokenType + +// TokenType is the type of token to highlight. +// +// It is also an Emitter, emitting a single token of itself +type TokenType int + +// Set of TokenTypes. +// +// Categories of types are grouped in ranges of 1000, while sub-categories are in ranges of 100. For +// example, the literal category is in the range 3000-3999. The sub-category for literal strings is +// in the range 3100-3199. + +// Meta token types. +const ( + // Default background style. + Background TokenType = -1 - iota + // PreWrapper style. + PreWrapper + // Line style. + Line + // Line numbers in output. + LineNumbers + // Line numbers in output when in table. + LineNumbersTable + // Line higlight style. + LineHighlight + // Line numbers table wrapper style. + LineTable + // Line numbers table TD wrapper style. + LineTableTD + // Line number links. + LineLink + // Code line wrapper style. + CodeLine + // Input that could not be tokenised. + Error + // Other is used by the Delegate lexer to indicate which tokens should be handled by the delegate. + Other + // No highlighting. + None + // Don't emit this token to the output. + Ignore + // Used as an EOF marker / nil token + EOFType TokenType = 0 +) + +// Keywords. +const ( + Keyword TokenType = 1000 + iota + KeywordConstant + KeywordDeclaration + KeywordNamespace + KeywordPseudo + KeywordReserved + KeywordType +) + +// Names. +const ( + Name TokenType = 2000 + iota + NameAttribute + NameClass + NameConstant + NameDecorator + NameEntity + NameException + NameKeyword + NameLabel + NameNamespace + NameOperator + NameOther + NamePseudo + NameProperty + NameTag +) + +// Builtin names. +const ( + NameBuiltin TokenType = 2100 + iota + NameBuiltinPseudo +) + +// Variable names. +const ( + NameVariable TokenType = 2200 + iota + NameVariableAnonymous + NameVariableClass + NameVariableGlobal + NameVariableInstance + NameVariableMagic +) + +// Function names. +const ( + NameFunction TokenType = 2300 + iota + NameFunctionMagic +) + +// Literals. +const ( + Literal TokenType = 3000 + iota + LiteralDate + LiteralOther +) + +// Strings. +const ( + LiteralString TokenType = 3100 + iota + LiteralStringAffix + LiteralStringAtom + LiteralStringBacktick + LiteralStringBoolean + LiteralStringChar + LiteralStringDelimiter + LiteralStringDoc + LiteralStringDouble + LiteralStringEscape + LiteralStringHeredoc + LiteralStringInterpol + LiteralStringName + LiteralStringOther + LiteralStringRegex + LiteralStringSingle + LiteralStringSymbol +) + +// Literals. +const ( + LiteralNumber TokenType = 3200 + iota + LiteralNumberBin + LiteralNumberFloat + LiteralNumberHex + LiteralNumberInteger + LiteralNumberIntegerLong + LiteralNumberOct + LiteralNumberByte +) + +// Operators. +const ( + Operator TokenType = 4000 + iota + OperatorWord +) + +// Punctuation. +const ( + Punctuation TokenType = 5000 + iota +) + +// Comments. +const ( + Comment TokenType = 6000 + iota + CommentHashbang + CommentMultiline + CommentSingle + CommentSpecial +) + +// Preprocessor "comments". +const ( + CommentPreproc TokenType = 6100 + iota + CommentPreprocFile +) + +// Generic tokens. +const ( + Generic TokenType = 7000 + iota + GenericDeleted + GenericEmph + GenericError + GenericHeading + GenericInserted + GenericOutput + GenericPrompt + GenericStrong + GenericSubheading + GenericTraceback + GenericUnderline +) + +// Text. +const ( + Text TokenType = 8000 + iota + TextWhitespace + TextSymbol + TextPunctuation +) + +// Aliases. +const ( + Whitespace = TextWhitespace + + Date = LiteralDate + + String = LiteralString + StringAffix = LiteralStringAffix + StringBacktick = LiteralStringBacktick + StringChar = LiteralStringChar + StringDelimiter = LiteralStringDelimiter + StringDoc = LiteralStringDoc + StringDouble = LiteralStringDouble + StringEscape = LiteralStringEscape + StringHeredoc = LiteralStringHeredoc + StringInterpol = LiteralStringInterpol + StringOther = LiteralStringOther + StringRegex = LiteralStringRegex + StringSingle = LiteralStringSingle + StringSymbol = LiteralStringSymbol + + Number = LiteralNumber + NumberBin = LiteralNumberBin + NumberFloat = LiteralNumberFloat + NumberHex = LiteralNumberHex + NumberInteger = LiteralNumberInteger + NumberIntegerLong = LiteralNumberIntegerLong + NumberOct = LiteralNumberOct +) + +var ( + StandardTypes = map[TokenType]string{ + Background: "bg", + PreWrapper: "chroma", + Line: "line", + LineNumbers: "ln", + LineNumbersTable: "lnt", + LineHighlight: "hl", + LineTable: "lntable", + LineTableTD: "lntd", + LineLink: "lnlinks", + CodeLine: "cl", + Text: "", + Whitespace: "w", + Error: "err", + Other: "x", + // I have no idea what this is used for... + // Escape: "esc", + + Keyword: "k", + KeywordConstant: "kc", + KeywordDeclaration: "kd", + KeywordNamespace: "kn", + KeywordPseudo: "kp", + KeywordReserved: "kr", + KeywordType: "kt", + + Name: "n", + NameAttribute: "na", + NameBuiltin: "nb", + NameBuiltinPseudo: "bp", + NameClass: "nc", + NameConstant: "no", + NameDecorator: "nd", + NameEntity: "ni", + NameException: "ne", + NameFunction: "nf", + NameFunctionMagic: "fm", + NameProperty: "py", + NameLabel: "nl", + NameNamespace: "nn", + NameOther: "nx", + NameTag: "nt", + NameVariable: "nv", + NameVariableClass: "vc", + NameVariableGlobal: "vg", + NameVariableInstance: "vi", + NameVariableMagic: "vm", + + Literal: "l", + LiteralDate: "ld", + + String: "s", + StringAffix: "sa", + StringBacktick: "sb", + StringChar: "sc", + StringDelimiter: "dl", + StringDoc: "sd", + StringDouble: "s2", + StringEscape: "se", + StringHeredoc: "sh", + StringInterpol: "si", + StringOther: "sx", + StringRegex: "sr", + StringSingle: "s1", + StringSymbol: "ss", + + Number: "m", + NumberBin: "mb", + NumberFloat: "mf", + NumberHex: "mh", + NumberInteger: "mi", + NumberIntegerLong: "il", + NumberOct: "mo", + + Operator: "o", + OperatorWord: "ow", + + Punctuation: "p", + + Comment: "c", + CommentHashbang: "ch", + CommentMultiline: "cm", + CommentPreproc: "cp", + CommentPreprocFile: "cpf", + CommentSingle: "c1", + CommentSpecial: "cs", + + Generic: "g", + GenericDeleted: "gd", + GenericEmph: "ge", + GenericError: "gr", + GenericHeading: "gh", + GenericInserted: "gi", + GenericOutput: "go", + GenericPrompt: "gp", + GenericStrong: "gs", + GenericSubheading: "gu", + GenericTraceback: "gt", + GenericUnderline: "gl", + } +) + +func (t TokenType) Parent() TokenType { + if t%100 != 0 { + return t / 100 * 100 + } + if t%1000 != 0 { + return t / 1000 * 1000 + } + return 0 +} + +func (t TokenType) Category() TokenType { + return t / 1000 * 1000 +} + +func (t TokenType) SubCategory() TokenType { + return t / 100 * 100 +} + +func (t TokenType) InCategory(other TokenType) bool { + return t/1000 == other/1000 +} + +func (t TokenType) InSubCategory(other TokenType) bool { + return t/100 == other/100 +} + +func (t TokenType) Emit(groups []string, _ *LexerState) Iterator { + return Literator(Token{Type: t, Value: groups[0]}) +} + +func (t TokenType) EmitterKind() string { return "token" } diff --git a/vendor/github.com/alecthomas/go-check-sumtype/.golangci.yml b/vendor/github.com/alecthomas/go-check-sumtype/.golangci.yml new file mode 100644 index 000000000..758ae1a9e --- /dev/null +++ b/vendor/github.com/alecthomas/go-check-sumtype/.golangci.yml @@ -0,0 +1,92 @@ +run: + tests: true + +output: + print-issued-lines: false + +linters: + enable-all: true + disable: + - cyclop + - depguard + - dupl + - dupword + - err113 + - errorlint + - exhaustive + - exhaustruct + - exportloopref + - forcetypeassert + - funlen + - gci + - gochecknoglobals + - gocognit + - goconst + - gocyclo + - godot + - godox + - gofumpt + - govet + - ireturn + - lll + - maintidx + - mnd + - mnd + - musttag + - nestif + - nilnil + - nlreturn + - nolintlint + - nonamedreturns + - paralleltest + - perfsprint + - predeclared + - revive + - stylecheck + - testableexamples + - testpackage + - thelper + - varnamelen + - wrapcheck + - wsl + +linters-settings: + govet: + enable: + - shadow + gocyclo: + min-complexity: 10 + dupl: + threshold: 100 + goconst: + min-len: 8 + min-occurrences: 3 + forbidigo: + exclude-godoc-examples: false + #forbid: + # - (Must)?NewLexer$ + +issues: + max-issues-per-linter: 0 + max-same-issues: 0 + exclude-use-default: false + exclude-dirs: + - _examples + exclude: + # Captured by errcheck. + - "^(G104|G204):" + # Very commonly not checked. + - 'Error return value of .(.*\.Help|.*\.MarkFlagRequired|(os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*printf?|os\.(Un)?Setenv). is not checked' + - 'exported method (.*\.MarshalJSON|.*\.UnmarshalJSON|.*\.EntityURN|.*\.GoString|.*\.Pos) should have comment or be unexported' + - "composite literal uses unkeyed fields" + - 'declaration of "err" shadows declaration' + - "should not use dot imports" + - "Potential file inclusion via variable" + - "should have comment or be unexported" + - "comment on exported var .* should be of the form" + - "at least one file in a package should have a package comment" + - "string literal contains the Unicode" + - "methods on the same type should have the same receiver name" + - "_TokenType_name should be _TokenTypeName" + - "`_TokenType_map` should be `_TokenTypeMap`" + - "rewrite if-else to switch statement" diff --git a/vendor/github.com/alecthomas/go-check-sumtype/README.md b/vendor/github.com/alecthomas/go-check-sumtype/README.md index 2ccec4e84..287aa68b7 100644 --- a/vendor/github.com/alecthomas/go-check-sumtype/README.md +++ b/vendor/github.com/alecthomas/go-check-sumtype/README.md @@ -92,6 +92,12 @@ passing checks, set the `-default-signifies-exhasutive=false` flag. As a special case, if the type switch statement contains a `default` clause that always panics, then exhaustiveness checks are still performed. +By default, `go-check-sumtype` will not include shared interfaces in the exhaustiviness check. +This can be changed by setting the `-include-shared-interfaces=true` flag. +When this flag is set, `go-check-sumtype` will not require that all concrete structs +are listed in the switch statement, as long as the switch statement is exhaustive +with respect to interfaces the structs implement. + ## Details and motivation Sum types are otherwise known as discriminated unions. That is, a sum type is diff --git a/vendor/github.com/alecthomas/go-check-sumtype/check.go b/vendor/github.com/alecthomas/go-check-sumtype/check.go index 1a0a32517..ff7fec728 100644 --- a/vendor/github.com/alecthomas/go-check-sumtype/check.go +++ b/vendor/github.com/alecthomas/go-check-sumtype/check.go @@ -29,7 +29,7 @@ func (e inexhaustiveError) Error() string { // Names returns a sorted list of names corresponding to the missing variant // cases. func (e inexhaustiveError) Names() []string { - var list []string + list := make([]string, 0, len(e.Missing)) for _, o := range e.Missing { list = append(list, o.Name()) } @@ -92,6 +92,10 @@ func missingVariantsInSwitch( ) (*sumTypeDef, []types.Object) { asserted := findTypeAssertExpr(swtch) ty := pkg.TypesInfo.TypeOf(asserted) + if ty == nil { + panic(fmt.Sprintf("no type found for asserted expression: %v", asserted)) + } + def := findDef(defs, ty) if def == nil { // We couldn't find a corresponding sum type, so there's @@ -103,11 +107,11 @@ func missingVariantsInSwitch( // A catch-all case defeats all exhaustiveness checks. return def, nil } - var variantTypes []types.Type + variantTypes := make([]types.Type, 0, len(variantExprs)) for _, expr := range variantExprs { variantTypes = append(variantTypes, pkg.TypesInfo.TypeOf(expr)) } - return def, def.missing(variantTypes) + return def, def.missing(variantTypes, config.IncludeSharedInterfaces) } // switchVariants returns all case expressions found in a type switch. This diff --git a/vendor/github.com/alecthomas/go-check-sumtype/config.go b/vendor/github.com/alecthomas/go-check-sumtype/config.go index 759176eb7..5c722b75c 100644 --- a/vendor/github.com/alecthomas/go-check-sumtype/config.go +++ b/vendor/github.com/alecthomas/go-check-sumtype/config.go @@ -2,4 +2,7 @@ package gochecksumtype type Config struct { DefaultSignifiesExhaustive bool + // IncludeSharedInterfaces in the exhaustiviness check. If true, we do not need to list all concrete structs, as long + // as the switch statement is exhaustive with respect to interfaces the structs implement. + IncludeSharedInterfaces bool } diff --git a/vendor/github.com/alecthomas/go-check-sumtype/def.go b/vendor/github.com/alecthomas/go-check-sumtype/def.go index 24729ac01..71bdf2f72 100644 --- a/vendor/github.com/alecthomas/go-check-sumtype/def.go +++ b/vendor/github.com/alecthomas/go-check-sumtype/def.go @@ -71,7 +71,7 @@ type sumTypeDef struct { // sum type declarations. If no such sum type definition could be found for // any of the given declarations, then an error is returned. func findSumTypeDefs(decls []sumTypeDecl) ([]sumTypeDef, []error) { - var defs []sumTypeDef + defs := make([]sumTypeDef, 0, len(decls)) var errs []error for _, decl := range decls { def, err := newSumTypeDef(decl.Package.Types, decl) @@ -104,7 +104,7 @@ func newSumTypeDef(pkg *types.Package, decl sumTypeDecl) (*sumTypeDef, error) { return nil, notInterfaceError{decl} } hasUnexported := false - for i := 0; i < iface.NumMethods(); i++ { + for i := range iface.NumMethods() { if !iface.Method(i).Exported() { hasUnexported = true break @@ -145,7 +145,7 @@ func (def *sumTypeDef) String() string { // missing returns a list of variants in this sum type that are not in the // given list of types. -func (def *sumTypeDef) missing(tys []types.Type) []types.Object { +func (def *sumTypeDef) missing(tys []types.Type, includeSharedInterfaces bool) []types.Object { // TODO(ag): This is O(n^2). Fix that. /shrug var missing []types.Object for _, v := range def.Variants { @@ -155,15 +155,29 @@ func (def *sumTypeDef) missing(tys []types.Type) []types.Object { ty = indirect(ty) if types.Identical(varty, ty) { found = true + break + } + if includeSharedInterfaces && implements(varty, ty) { + found = true + break } } - if !found { + if !found && !isInterface(varty) { + // we do not include interfaces extending the sumtype, as the + // all implementations of those interfaces are already covered + // by the sumtype. missing = append(missing, v) } } return missing } +func isInterface(ty types.Type) bool { + underlying := indirect(ty).Underlying() + _, ok := underlying.(*types.Interface) + return ok +} + // indirect dereferences through an arbitrary number of pointer types. func indirect(ty types.Type) types.Type { if ty, ok := ty.(*types.Pointer); ok { @@ -171,3 +185,11 @@ func indirect(ty types.Type) types.Type { } return ty } + +func implements(varty, interfaceType types.Type) bool { + underlying := interfaceType.Underlying() + if interf, ok := underlying.(*types.Interface); ok { + return types.Implements(varty, interf) || types.Implements(types.NewPointer(varty), interf) + } + return false +} diff --git a/vendor/github.com/alexkohler/nakedret/v2/README.md b/vendor/github.com/alexkohler/nakedret/v2/README.md index e30a0cde7..54f6ce6c2 100644 --- a/vendor/github.com/alexkohler/nakedret/v2/README.md +++ b/vendor/github.com/alexkohler/nakedret/v2/README.md @@ -6,7 +6,7 @@ nakedret is a Go static analysis tool to find naked returns in functions greater Install Nakedret via go install: ```cmd -go install github.com/alexkohler/nakedret/cmd/nakedret@latest +go install github.com/alexkohler/nakedret/v2/cmd/nakedret@latest ``` If you have not already added your `GOPATH/bin` directory to your `PATH` environment variable then you will need to do so. diff --git a/vendor/github.com/alexkohler/nakedret/v2/nakedret.go b/vendor/github.com/alexkohler/nakedret/v2/nakedret.go index a55735928..9f53d2a74 100644 --- a/vendor/github.com/alexkohler/nakedret/v2/nakedret.go +++ b/vendor/github.com/alexkohler/nakedret/v2/nakedret.go @@ -3,7 +3,6 @@ package nakedret import ( "bytes" "errors" - "flag" "fmt" "go/ast" "go/build" @@ -22,19 +21,15 @@ import ( const pwd = "./" -func NakedReturnAnalyzer(defaultLines uint, skipTestFiles bool) *analysis.Analyzer { - nakedRet := &NakedReturnRunner{} - flags := flag.NewFlagSet("nakedret", flag.ExitOnError) - flags.UintVar(&nakedRet.MaxLength, "l", defaultLines, "maximum number of lines for a naked return function") - flags.BoolVar(&nakedRet.SkipTestFiles, "skip-test-files", skipTestFiles, "set to true to skip test files") - var analyzer = &analysis.Analyzer{ +func NakedReturnAnalyzer(nakedRet *NakedReturnRunner) *analysis.Analyzer { + a := &analysis.Analyzer{ Name: "nakedret", Doc: "Checks that functions with naked returns are not longer than a maximum size (can be zero).", Run: nakedRet.run, - Flags: *flags, Requires: []*analysis.Analyzer{inspect.Analyzer}, } - return analyzer + + return a } type NakedReturnRunner struct { @@ -91,7 +86,7 @@ func checkNakedReturns(args []string, maxLength *uint, skipTestFiles bool, setEx return errors.New("max length nil") } - analyzer := NakedReturnAnalyzer(*maxLength, skipTestFiles) + analyzer := NakedReturnAnalyzer(&NakedReturnRunner{MaxLength: *maxLength, SkipTestFiles: skipTestFiles}) pass := &analysis.Pass{ Analyzer: analyzer, Fset: fset, diff --git a/vendor/github.com/alexkohler/prealloc/pkg/cmp.go b/vendor/github.com/alexkohler/prealloc/pkg/cmp.go new file mode 100644 index 000000000..81ad30617 --- /dev/null +++ b/vendor/github.com/alexkohler/prealloc/pkg/cmp.go @@ -0,0 +1,297 @@ +package pkg + +import ( + "go/ast" + "go/token" + "slices" +) + +func exprEqual(x, y ast.Expr) bool { + if x == nil || y == nil { + return x == y + } + + switch x := x.(type) { + case *ast.Ident: + y, ok := y.(*ast.Ident) + return ok && identEqual(x, y) + + case *ast.BasicLit: + y, ok := y.(*ast.BasicLit) + return ok && basicLitEqual(x, y) + + case *ast.FuncLit: + y, ok := y.(*ast.FuncLit) + return ok && funcLitEqual(x, y) + + case *ast.CompositeLit: + y, ok := y.(*ast.CompositeLit) + return ok && compositeLitEqual(x, y) + + case *ast.ParenExpr: + y, ok := y.(*ast.ParenExpr) + return ok && parenExprEqual(x, y) + + case *ast.SelectorExpr: + y, ok := y.(*ast.SelectorExpr) + return ok && selectorExprEqual(x, y) + + case *ast.IndexExpr: + y, ok := y.(*ast.IndexExpr) + return ok && indexExprEqual(x, y) + + case *ast.IndexListExpr: + y, ok := y.(*ast.IndexListExpr) + return ok && indexListExprEqual(x, y) + + case *ast.SliceExpr: + y, ok := y.(*ast.SliceExpr) + return ok && sliceExprEqual(x, y) + + case *ast.TypeAssertExpr: + y, ok := y.(*ast.TypeAssertExpr) + return ok && typeAssertExprEqual(x, y) + + case *ast.CallExpr: + y, ok := y.(*ast.CallExpr) + return ok && callExprEqual(x, y) + + case *ast.StarExpr: + y, ok := y.(*ast.StarExpr) + return ok && starExprEqual(x, y) + + case *ast.UnaryExpr: + y, ok := y.(*ast.UnaryExpr) + return ok && unaryExprEqual(x, y) + + case *ast.BinaryExpr: + y, ok := y.(*ast.BinaryExpr) + return ok && binaryExprEqual(x, y) + + case *ast.KeyValueExpr: + y, ok := y.(*ast.KeyValueExpr) + return ok && keyValueExprEqual(x, y) + + case *ast.ArrayType: + y, ok := y.(*ast.ArrayType) + return ok && arrayTypeEqual(x, y) + + case *ast.StructType: + y, ok := y.(*ast.StructType) + return ok && structTypeEqual(x, y) + + case *ast.FuncType: + y, ok := y.(*ast.FuncType) + return ok && funcTypeEqual(x, y) + + case *ast.InterfaceType: + y, ok := y.(*ast.InterfaceType) + return ok && interfaceTypeEqual(x, y) + + case *ast.MapType: + y, ok := y.(*ast.MapType) + return ok && mapTypeEqual(x, y) + + case *ast.ChanType: + y, ok := y.(*ast.ChanType) + return ok && chanTypeEqual(x, y) + + case *ast.Ellipsis: + y, ok := y.(*ast.Ellipsis) + return ok && ellipsisEqual(x, y) + + default: + return false + } +} + +func identEqual(x, y *ast.Ident) bool { + if x == nil || y == nil { + return x == y + } + return x.Name == y.Name +} + +func keyValueExprEqual(x, y *ast.KeyValueExpr) bool { + if x == nil || y == nil { + return x == y + } + return exprEqual(x.Key, y.Key) && exprEqual(x.Value, y.Value) +} + +func arrayTypeEqual(x, y *ast.ArrayType) bool { + if x == nil || y == nil { + return x == y + } + return exprEqual(x.Len, y.Len) && exprEqual(x.Elt, y.Elt) +} + +func structTypeEqual(x, y *ast.StructType) bool { + if x == nil || y == nil { + return x == y + } + return fieldListEqual(x.Fields, y.Fields) +} + +func funcTypeEqual(x, y *ast.FuncType) bool { + if x == nil || y == nil { + return x == y + } + return fieldListEqual(x.Params, y.Params) && fieldListEqual(x.Results, y.Results) && fieldListEqual(x.TypeParams, y.TypeParams) +} + +func basicLitEqual(x, y *ast.BasicLit) bool { + if x == nil || y == nil { + return x == y + } + return x.Kind == y.Kind && x.Value == y.Value +} + +func funcLitEqual(x, y *ast.FuncLit) bool { + if x == nil || y == nil { + return x == y + } + return funcTypeEqual(x.Type, y.Type) +} + +func compositeLitEqual(x, y *ast.CompositeLit) bool { + if x == nil || y == nil { + return x == y + } + return exprEqual(x.Type, y.Type) && exprSliceEqual(x.Elts, y.Elts) +} + +func selectorExprEqual(x, y *ast.SelectorExpr) bool { + if x == nil || y == nil { + return x == y + } + return exprEqual(x.X, y.X) && identEqual(x.Sel, y.Sel) +} + +func indexExprEqual(x, y *ast.IndexExpr) bool { + if x == nil || y == nil { + return x == y + } + return exprEqual(x.X, y.X) && exprEqual(x.Index, y.Index) +} + +func indexListExprEqual(x, y *ast.IndexListExpr) bool { + if x == nil || y == nil { + return x == y + } + return exprEqual(x.X, y.X) && exprSliceEqual(x.Indices, y.Indices) +} + +func sliceExprEqual(x, y *ast.SliceExpr) bool { + if x == nil || y == nil { + return x == y + } + return exprEqual(x.X, y.X) && exprEqual(x.Low, y.Low) && exprEqual(x.High, y.High) && exprEqual(x.Max, y.Max) +} + +func typeAssertExprEqual(x, y *ast.TypeAssertExpr) bool { + if x == nil || y == nil { + return x == y + } + return exprEqual(x.X, y.X) && exprEqual(x.Type, y.Type) +} + +func interfaceTypeEqual(x, y *ast.InterfaceType) bool { + if x == nil || y == nil { + return x == y + } + return fieldListEqual(x.Methods, y.Methods) +} + +func mapTypeEqual(x, y *ast.MapType) bool { + if x == nil || y == nil { + return x == y + } + return exprEqual(x.Key, y.Key) && exprEqual(x.Value, y.Value) +} + +func chanTypeEqual(x, y *ast.ChanType) bool { + if x == nil || y == nil { + return x == y + } + return x.Dir == y.Dir && exprEqual(x.Value, y.Value) +} + +func callExprEqual(x, y *ast.CallExpr) bool { + if x == nil || y == nil { + return x == y + } + return exprEqual(x.Fun, y.Fun) && exprSliceEqual(x.Args, y.Args) && x.Ellipsis.IsValid() == y.Ellipsis.IsValid() +} + +func ellipsisEqual(x, y *ast.Ellipsis) bool { + if x == nil || y == nil { + return x == y + } + return exprEqual(x.Elt, y.Elt) +} + +func unaryExprEqual(x, y *ast.UnaryExpr) bool { + if x == nil || y == nil { + return x == y + } + return x.Op == y.Op && exprEqual(x.X, y.X) +} + +func binaryExprEqual(x, y *ast.BinaryExpr) bool { + if x == nil || y == nil { + return x == y + } + if x.Op == y.Op { + if exprEqual(x.X, y.X) && exprEqual(x.Y, y.Y) { + return true + } + // commutative operators + switch x.Op { + case token.ADD, token.MUL, token.AND, token.OR, token.XOR, token.LAND, token.LOR, token.EQL, token.NEQ: + return exprEqual(x.X, y.Y) && exprEqual(x.Y, y.X) + default: + } + } + return false +} + +func parenExprEqual(x, y *ast.ParenExpr) bool { + if x == nil || y == nil { + return x == y + } + return exprEqual(x.X, y.X) +} + +func starExprEqual(x, y *ast.StarExpr) bool { + if x == nil || y == nil { + return x == y + } + return exprEqual(x.X, y.X) +} + +func exprSliceEqual(xs, ys []ast.Expr) bool { + return slices.EqualFunc(xs, ys, exprEqual) +} + +func fieldEqual(x, y *ast.Field) bool { + if x == nil || y == nil { + return x == y + } + return identSliceEqual(x.Names, y.Names) && exprEqual(x.Type, y.Type) +} + +func fieldListEqual(x, y *ast.FieldList) bool { + if x == nil || y == nil { + return x == y + } + return fieldSliceEqual(x.List, y.List) +} + +func identSliceEqual(xs, ys []*ast.Ident) bool { + return slices.EqualFunc(xs, ys, identEqual) +} + +func fieldSliceEqual(xs, ys []*ast.Field) bool { + return slices.EqualFunc(xs, ys, fieldEqual) +} diff --git a/vendor/github.com/alexkohler/prealloc/pkg/math.go b/vendor/github.com/alexkohler/prealloc/pkg/math.go new file mode 100644 index 000000000..4a4923682 --- /dev/null +++ b/vendor/github.com/alexkohler/prealloc/pkg/math.go @@ -0,0 +1,163 @@ +package pkg + +import ( + "go/ast" + "go/token" + "strconv" +) + +func addIntExpr(x, y ast.Expr) ast.Expr { + if x == nil || y == nil { + return nil + } + + xInt, xOK := intValue(x) + yInt, yOK := intValue(y) + + if xOK && yOK { + return intExpr(xInt + yInt) + } + if xOK { + if xInt == 0 { + return y + } + if xInt < 0 { + return &ast.BinaryExpr{X: y, Op: token.SUB, Y: intExpr(-xInt)} + } + } + if yOK { + if yInt == 0 { + return x + } + if yInt < 0 { + return &ast.BinaryExpr{X: x, Op: token.SUB, Y: intExpr(-yInt)} + } + } + if unary, ok := y.(*ast.UnaryExpr); ok && unary.Op == token.SUB { + return &ast.BinaryExpr{X: x, Op: token.SUB, Y: unary.X} + } + return &ast.BinaryExpr{X: x, Op: token.ADD, Y: y} +} + +func incIntExpr(x ast.Expr) ast.Expr { + if x == nil { + return nil + } + + xInt, xOK := intValue(x) + if xOK { + return intExpr(xInt + 1) + } + if binary, ok := x.(*ast.BinaryExpr); ok && binary.Op == token.SUB { + if yInt, yOK := intValue(binary.Y); yOK && yInt == 1 { + return binary.X + } + } + return &ast.BinaryExpr{X: x, Op: token.ADD, Y: intExpr(1)} +} + +func subIntExpr(x, y ast.Expr) ast.Expr { + if binary, ok := x.(*ast.BinaryExpr); ok && binary.Op == token.ADD { + if exprEqual(binary.X, y) { + return binary.Y + } + if exprEqual(binary.Y, y) { + return binary.X + } + } + + if unary, ok := y.(*ast.UnaryExpr); ok && unary.Op == token.SUB { + y = unary.X + } else { + y = &ast.UnaryExpr{Op: token.SUB, X: y} + } + return addIntExpr(x, y) +} + +func mulIntExpr(x, y ast.Expr) ast.Expr { + if x == nil || y == nil { + return nil + } + + xInt, xOK := intValue(x) + yInt, yOK := intValue(y) + + if xOK && yOK { + return intExpr(xInt * yInt) + } + if xOK { + if xInt == 0 { + return intExpr(0) + } + if xInt == 1 { + return y + } + } + if yOK { + if yInt == 0 { + return intExpr(0) + } + if yInt == 1 { + return x + } + } + return &ast.BinaryExpr{X: x, Op: token.MUL, Y: y} +} + +func divIntExpr(x, y ast.Expr) (ast.Expr, bool) { + if x == nil || y == nil { + return nil, false + } + + xInt, xOK := intValue(x) + yInt, yOK := intValue(y) + + if xOK && yOK { + return intExpr(xInt / yInt), xInt%yInt != 0 + } + if yOK && yInt == 0 { + return nil, false + } + if (xOK && xInt == 0) || (yOK && yInt == 1) { + return x, false + } + return &ast.BinaryExpr{X: x, Op: token.QUO, Y: y}, true +} + +func intExpr(n int) *ast.BasicLit { + return &ast.BasicLit{Kind: token.INT, Value: strconv.Itoa(n)} +} + +func intValue(expr ast.Expr) (int, bool) { + var negate bool + for { + switch e := expr.(type) { + case *ast.UnaryExpr: + if e.Op == token.SUB { + negate = !negate + expr = e.X + continue + } + case *ast.CallExpr: + if ident, ok := e.Fun.(*ast.Ident); ok && len(e.Args) == 1 { + switch ident.Name { + case "byte", "rune", "int", "int8", "int16", "int32", "int64", + "uint", "uint8", "uint16", "uint32", "uint64", "uintptr": + expr = e.Args[0] + continue + } + } + } + break + } + + if lit, ok := expr.(*ast.BasicLit); ok && lit.Kind == token.INT { + if i, err := strconv.Atoi(lit.Value); err == nil { + if negate { + return -i, true + } + return i, true + } + } + return 0, false +} diff --git a/vendor/github.com/alexkohler/prealloc/pkg/prealloc.go b/vendor/github.com/alexkohler/prealloc/pkg/prealloc.go index 72d8b95f7..959a8671c 100644 --- a/vendor/github.com/alexkohler/prealloc/pkg/prealloc.go +++ b/vendor/github.com/alexkohler/prealloc/pkg/prealloc.go @@ -1,15 +1,30 @@ package pkg import ( - "fmt" + "bytes" "go/ast" + "go/format" "go/token" + "go/types" + "strconv" + + "golang.org/x/tools/go/analysis" ) type sliceDeclaration struct { - name string - // sType string - genD *ast.GenDecl + name string + pos token.Pos + level int // Nesting level of this slice. Will be disqualified if appended at a deeper level. + lenExpr ast.Expr // Initial length of this slice. + exclude bool // Whether this slice has been disqualified due to an unsupported pattern. + hasReturn bool // Whether a return statement has been found after the first append. Any subsequent appends will disqualify this slice in simple mode. + assigning bool // Whether this slice is currently being assigned the result of an append. + detached bool // Whether this slice has been appended without reassignment. Will be disqualified if this happens more than once. +} + +type sliceAppend struct { + index int // Index of the target slice. + countExpr ast.Expr // Number of items appended. } type returnsVisitor struct { @@ -17,251 +32,848 @@ type returnsVisitor struct { simple bool includeRangeLoops bool includeForLoops bool + pass *analysis.Pass // visitor fields - sliceDeclarations []*sliceDeclaration - preallocHints []Hint - returnsInsideOfLoop bool - arrayTypes []string + sliceDeclarations []*sliceDeclaration + sliceAppends []*sliceAppend + loopVars []ast.Expr + level int // Current nesting level. Loops do not increment the level. + hasReturn bool // Whether a return statement has been found. Slices appended before and after a return are disqualified in simple mode. + hasGoto bool // Whether a goto statement has been found. Goto disqualifies pending and subsequent slices in simple mode. + hasBranch bool // Whether a branch statement has been found. Loops with branch statements are unsupported in simple mode. } -func Check(files []*ast.File, simple, includeRangeLoops, includeForLoops bool) []Hint { - hints := []Hint{} - for _, f := range files { - retVis := &returnsVisitor{ - simple: simple, - includeRangeLoops: includeRangeLoops, - includeForLoops: includeForLoops, - } +func Check(pass *analysis.Pass, simple, includeRangeLoops, includeForLoops bool) { + retVis := &returnsVisitor{ + simple: simple, + includeRangeLoops: includeRangeLoops, + includeForLoops: includeForLoops, + pass: pass, + } + for _, f := range pass.Files { ast.Walk(retVis, f) - // if simple is true, then we actually have to check if we had returns - // inside of our loop. Otherwise, we can just report all messages. - if !retVis.simple || !retVis.returnsInsideOfLoop { - hints = append(hints, retVis.preallocHints...) - } } - - return hints } -func contains(slice []string, item string) bool { - for _, s := range slice { - if s == item { - return true +func (v *returnsVisitor) Visit(node ast.Node) ast.Visitor { + switch s := node.(type) { + case *ast.FuncDecl: + if s.Body == nil { + return nil } - } + v.level = 0 + v.hasReturn = false + v.hasGoto = false + ast.Walk(v, s.Body) + return nil + + case *ast.FuncLit: + if s.Body == nil { + return nil + } + wasReturn := v.hasReturn + wasGoto := v.hasGoto + v.hasReturn = false + ast.Walk(v, s.Body) + v.hasReturn = wasReturn + v.hasGoto = wasGoto + return nil + + case *ast.BlockStmt: + declIdx := len(v.sliceDeclarations) + appendIdx := len(v.sliceAppends) + v.level++ + for _, stmt := range s.List { + ast.Walk(v, stmt) + } + v.level-- - return false -} + buf := bytes.NewBuffer(nil) + for i := declIdx; i < len(v.sliceDeclarations); i++ { + sliceDecl := v.sliceDeclarations[i] + if sliceDecl.exclude || v.hasGoto { + continue + } -func (v *returnsVisitor) Visit(node ast.Node) ast.Visitor { + capExpr := sliceDecl.lenExpr + for j := appendIdx; j < len(v.sliceAppends); j++ { + if v.sliceAppends[j] != nil && v.sliceAppends[j].index == i { + capExpr = addIntExpr(capExpr, v.sliceAppends[j].countExpr) + } + } + if capExpr == sliceDecl.lenExpr { + // nothing appended + continue + } + if capVal, ok := intValue(capExpr); ok && capVal <= 0 { + continue + } - v.sliceDeclarations = nil - v.returnsInsideOfLoop = false + buf.Reset() + buf.WriteString("Consider preallocating ") + buf.WriteString(sliceDecl.name) + if capExpr != nil { + undo := buf.Len() + buf.WriteString(" with capacity ") + if format.Node(buf, token.NewFileSet(), capExpr) != nil { + buf.Truncate(undo) + } + } + v.pass.Report(analysis.Diagnostic{ + Pos: sliceDecl.pos, + Message: buf.String(), + }) + } - switch n := node.(type) { - case *ast.TypeSpec: - if _, ok := n.Type.(*ast.ArrayType); ok { - if n.Name != nil { - v.arrayTypes = append(v.arrayTypes, n.Name.Name) + // discard slices and associated appends that are falling out of scope + v.sliceDeclarations = v.sliceDeclarations[:declIdx] + for i := appendIdx; i < len(v.sliceAppends); i++ { + if v.sliceAppends[i] != nil { + if v.sliceAppends[i].index >= declIdx { + v.sliceAppends[i] = nil + } else { + appendIdx = i + 1 + } } } - case *ast.FuncDecl: - if n.Body != nil { - for _, stmt := range n.Body.List { - switch s := stmt.(type) { - // Find non pre-allocated slices - case *ast.DeclStmt: - genD, ok := s.Decl.(*ast.GenDecl) - if !ok { + v.sliceAppends = v.sliceAppends[:appendIdx] + return nil + + case *ast.ValueSpec: + var isArrayOrSlice bool + if t := v.pass.TypesInfo.TypeOf(s.Type); t != nil { + switch t.Underlying().(type) { + case *types.Array, *types.Slice: + isArrayOrSlice = true + } + } + for i, name := range s.Names { + var lenExpr ast.Expr + if i >= len(s.Values) { + if !isArrayOrSlice { + continue + } + lenExpr = intExpr(0) + } else if lenExpr = v.isCreateArray(s.Values[i]); lenExpr == nil { + if id, ok := s.Values[i].(*ast.Ident); !ok || id.Name != "nil" { + continue + } + lenExpr = intExpr(0) + } + v.sliceDeclarations = append(v.sliceDeclarations, &sliceDeclaration{name: name.Name, pos: s.Pos(), level: v.level, lenExpr: lenExpr}) + } + + case *ast.AssignStmt: + if len(v.loopVars) > 0 { + if len(s.Lhs) == len(s.Rhs) { + for i, lhs := range s.Lhs { + if hasAny(s.Rhs[i], v.loopVars) { + v.loopVars = append(v.loopVars, lhs) + } + } + } else if len(s.Rhs) == 1 && hasAny(s.Rhs[0], v.loopVars) { + v.loopVars = append(v.loopVars, s.Lhs...) + } + } + if len(s.Lhs) != len(s.Rhs) { + return nil + } + for i, lhs := range s.Lhs { + ident, ok := lhs.(*ast.Ident) + if !ok { + continue + } + if lenExpr := v.isCreateArray(s.Rhs[i]); lenExpr != nil { + v.sliceDeclarations = append(v.sliceDeclarations, &sliceDeclaration{name: ident.Name, pos: s.Pos(), level: v.level, lenExpr: lenExpr}) + } else { + declIdx := -1 + for i := len(v.sliceDeclarations) - 1; i >= 0; i-- { + if v.sliceDeclarations[i].name == ident.Name { + declIdx = i + break + } + } + if declIdx < 0 { + continue + } + sliceDecl := v.sliceDeclarations[declIdx] + switch expr := s.Rhs[i].(type) { + case *ast.Ident: + // create a new slice declaration when reinitializing an existing slice to nil + if s.Tok == token.ASSIGN && expr.Name == "nil" { + v.sliceDeclarations = append(v.sliceDeclarations, &sliceDeclaration{name: ident.Name, pos: s.Pos(), level: v.level, lenExpr: intExpr(0)}) continue } - if genD.Tok == token.TYPE { - for _, spec := range genD.Specs { - tSpec, ok := spec.(*ast.TypeSpec) - if !ok { - continue - } - - if _, ok := tSpec.Type.(*ast.ArrayType); ok { - if tSpec.Name != nil { - v.arrayTypes = append(v.arrayTypes, tSpec.Name.Name) - } - } - } - } else if genD.Tok == token.VAR { - for _, spec := range genD.Specs { - vSpec, ok := spec.(*ast.ValueSpec) - if !ok { + case *ast.CallExpr: + if len(expr.Args) >= 2 && !sliceDecl.hasReturn && sliceDecl.level == v.level { + if funIdent, ok := expr.Fun.(*ast.Ident); ok && funIdent.Name == "append" { + if rhsIdent, ok := expr.Args[0].(*ast.Ident); ok && ident.Name == rhsIdent.Name { + sliceDecl.assigning = true continue } - var isArrType bool - switch val := vSpec.Type.(type) { - case *ast.ArrayType: - isArrType = true - case *ast.Ident: - isArrType = contains(v.arrayTypes, val.Name) - } - if isArrType { - if vSpec.Names != nil { - /*atID, ok := arrayType.Elt.(*ast.Ident) - if !ok { - continue - }*/ - - // We should handle multiple slices declared on same line e.g. var mySlice1, mySlice2 []uint32 - for _, vName := range vSpec.Names { - v.sliceDeclarations = append(v.sliceDeclarations, &sliceDeclaration{name: vName.Name /*sType: atID.Name,*/, genD: genD}) - } - } - } } } + } + sliceDecl.exclude = true + } + } - case *ast.RangeStmt: - if v.includeRangeLoops { - if len(v.sliceDeclarations) == 0 { - continue - } - // Check the value being ranged over and ensure it's not a channel (we cannot offer any recommendations on channel ranges). - rangeIdent, ok := s.X.(*ast.Ident) - if ok && rangeIdent.Obj != nil { - valueSpec, ok := rangeIdent.Obj.Decl.(*ast.ValueSpec) - if ok { - if _, rangeTargetIsChannel := valueSpec.Type.(*ast.ChanType); rangeTargetIsChannel { - continue - } - } - } - if s.Body != nil { - v.handleLoops(s.Body) - } + case *ast.CallExpr: + if funIdent, ok := s.Fun.(*ast.Ident); ok && funIdent.Name == "append" && len(s.Args) >= 2 { + if rhsIdent, ok := s.Args[0].(*ast.Ident); ok { + declIdx := -1 + for i := len(v.sliceDeclarations) - 1; i >= 0; i-- { + if v.sliceDeclarations[i].name == rhsIdent.Name { + declIdx = i + break } + } + if declIdx < 0 { + return v + } + sliceDecl := v.sliceDeclarations[declIdx] + if sliceDecl.exclude { + return v + } - case *ast.ForStmt: - if v.includeForLoops { - if len(v.sliceDeclarations) == 0 { - continue - } - if s.Body != nil { - v.handleLoops(s.Body) - } - } + if sliceDecl.hasReturn || sliceDecl.level != v.level || sliceDecl.detached { + sliceDecl.exclude = true + return v + } - default: + countExpr := v.appendCount(s) + if countExpr != nil && (hasAny(countExpr, v.loopVars) || hasVarReference(countExpr, sliceDecl.name)) { + // exclude slice if append count references it + sliceDecl.exclude = true + return v } + + if sliceDecl.assigning { + sliceDecl.assigning = false + } else { + sliceDecl.detached = true + } + v.sliceAppends = append(v.sliceAppends, &sliceAppend{index: declIdx, countExpr: countExpr}) + } + } + + case *ast.RangeStmt: + return v.walkRange(s) + + case *ast.ForStmt: + return v.walkFor(s) + + case *ast.SwitchStmt: + return v.walkSwitchSelect(s.Body) + + case *ast.TypeSwitchStmt: + return v.walkSwitchSelect(s.Body) + + case *ast.SelectStmt: + return v.walkSwitchSelect(s.Body) + + case *ast.ReturnStmt: + if !v.simple { + return nil + } + v.hasReturn = true + // flag all slices that have been appended at least once + for _, sliceApp := range v.sliceAppends { + if sliceApp != nil { + v.sliceDeclarations[sliceApp.index].hasReturn = true } } + + case *ast.BranchStmt: + if !v.simple { + return nil + } + if s.Label != nil { + v.hasGoto = true + } else { + v.hasBranch = true + } } + return v } -// handleLoops is a helper function to share the logic required for both *ast.RangeLoops and *ast.ForLoops -func (v *returnsVisitor) handleLoops(blockStmt *ast.BlockStmt) { +func (v *returnsVisitor) walkRange(stmt *ast.RangeStmt) ast.Visitor { + if len(v.sliceDeclarations) == 0 { + return v + } + if stmt.Body == nil { + return nil + } - for _, stmt := range blockStmt.List { - switch bodyStmt := stmt.(type) { - case *ast.AssignStmt: - asgnStmt := bodyStmt - for index, expr := range asgnStmt.Rhs { - if index >= len(asgnStmt.Lhs) { - continue + appendIdx := len(v.sliceAppends) + hadBranch := v.hasBranch + v.hasBranch = false + v.level-- + varsIdx := len(v.loopVars) + if stmt.Key != nil { + v.loopVars = append(v.loopVars, stmt.Key) + } + if stmt.Value != nil { + v.loopVars = append(v.loopVars, stmt.Value) + } + ast.Walk(v, stmt.Body) + v.level++ + v.loopVars = v.loopVars[:varsIdx] + + exclude := !v.includeRangeLoops || v.hasReturn || v.hasGoto || v.hasBranch + var loopCountExpr ast.Expr + if !exclude { + var ok bool + loopCountExpr, ok = v.rangeLoopCount(stmt) + exclude = !ok + } + if exclude { + // exclude all slices that were appended within this loop + for i := appendIdx; i < len(v.sliceAppends); i++ { + if v.sliceAppends[i] != nil { + v.sliceDeclarations[v.sliceAppends[i].index].exclude = true + } + } + } else { + for i, sliceDecl := range v.sliceDeclarations { + if sliceDecl.exclude { + continue + } + prev := -1 + for j := len(v.sliceAppends) - 1; j >= appendIdx; j-- { + if v.sliceAppends[j] != nil && v.sliceAppends[j].index == i { + if prev < 0 { + if loopCountExpr == nil { + // make appends indeterminate if the loop count is indeterminate + v.sliceAppends[j].countExpr = nil + } else if hasVarReference(loopCountExpr, sliceDecl.name) { + // exclude slice if loop count references it + sliceDecl.exclude = true + break + } + } else { + // consolidate appends to the same slice + v.sliceAppends[j].countExpr = addIntExpr(v.sliceAppends[j].countExpr, v.sliceAppends[prev].countExpr) + v.sliceAppends[prev] = nil + } + prev = j } + } + if prev >= 0 { + v.sliceAppends[prev].countExpr = mulIntExpr(v.sliceAppends[prev].countExpr, loopCountExpr) + } + } + } + v.hasBranch = hadBranch + return nil +} - lhsIdent, ok := asgnStmt.Lhs[index].(*ast.Ident) - if !ok { - continue - } +func (v *returnsVisitor) walkFor(stmt *ast.ForStmt) ast.Visitor { + if len(v.sliceDeclarations) == 0 { + return v + } + if stmt.Body == nil { + return nil + } - callExpr, ok := expr.(*ast.CallExpr) - if !ok { - continue + appendIdx := len(v.sliceAppends) + hadBranch := v.hasBranch + v.hasBranch = false + v.level-- + varsIdx := len(v.loopVars) + if assign, ok := stmt.Init.(*ast.AssignStmt); ok { + v.loopVars = append(v.loopVars, assign.Lhs...) + } + ast.Walk(v, stmt.Body) + v.level++ + v.loopVars = v.loopVars[:varsIdx] + + exclude := !v.includeForLoops || v.hasReturn || v.hasGoto || v.hasBranch + var loopCountExpr ast.Expr + if !exclude { + var ok bool + loopCountExpr, ok = v.forLoopCount(stmt) + exclude = !ok + } + if exclude { + // exclude all slices that were appended within this loop + for i := appendIdx; i < len(v.sliceAppends); i++ { + if v.sliceAppends[i] != nil { + v.sliceDeclarations[v.sliceAppends[i].index].exclude = true + } + } + } else { + for i, sliceDecl := range v.sliceDeclarations { + if sliceDecl.exclude { + continue + } + prev := -1 + for j := len(v.sliceAppends) - 1; j >= appendIdx; j-- { + if v.sliceAppends[j] != nil && v.sliceAppends[j].index == i { + if prev < 0 { + if loopCountExpr == nil { + // make appends indeterminate if the loop count is indeterminate + v.sliceAppends[j].countExpr = nil + } else if hasVarReference(loopCountExpr, sliceDecl.name) { + // exclude slice if loop count references it + sliceDecl.exclude = true + break + } + } else { + // consolidate appends to the same slice + v.sliceAppends[j].countExpr = addIntExpr(v.sliceAppends[j].countExpr, v.sliceAppends[prev].countExpr) + v.sliceAppends[prev] = nil + } + prev = j } + } + if prev >= 0 { + v.sliceAppends[prev].countExpr = mulIntExpr(v.sliceAppends[prev].countExpr, loopCountExpr) + } + } + } + v.hasBranch = hadBranch + return nil +} - rhsFuncIdent, ok := callExpr.Fun.(*ast.Ident) - if !ok { - continue - } +func (v *returnsVisitor) walkSwitchSelect(body *ast.BlockStmt) ast.Visitor { + hadBranch := v.hasBranch + v.hasBranch = false + ast.Walk(v, body) + v.hasBranch = hadBranch + return nil +} - if rhsFuncIdent.Name != "append" { - continue +func (v *returnsVisitor) isCreateArray(expr ast.Expr) ast.Expr { + switch e := expr.(type) { + case *ast.CompositeLit: + // []any{...} + if t := v.pass.TypesInfo.TypeOf(e); t != nil { + switch t.Underlying().(type) { + case *types.Array, *types.Slice: + return intExpr(len(e.Elts)) + } + } + case *ast.CallExpr: + switch len(e.Args) { + case 1: + // []any(nil) + arg, ok := e.Args[0].(*ast.Ident) + if !ok || arg.Name != "nil" { + return nil + } + if t := v.pass.TypesInfo.TypeOf(e.Fun); t != nil { + if _, ok := t.Underlying().(*types.Slice); ok { + return intExpr(0) } + } + case 2: + // make([]any, n) + ident, ok := e.Fun.(*ast.Ident) + if ok && ident.Name == "make" { + return e.Args[1] + } + } + } + return nil +} - // e.g., `x = append(x)` - // Pointless, but pre-allocation will not help. - if len(callExpr.Args) < 2 { - continue - } +func (v *returnsVisitor) rangeLoopCount(stmt *ast.RangeStmt) (ast.Expr, bool) { + x := stmt.X + if hasAny(x, v.loopVars) { + return nil, false + } - rhsIdent, ok := callExpr.Args[0].(*ast.Ident) - if !ok { - continue + if call, ok := x.(*ast.CallExpr); ok { + if len(call.Args) == 1 { + if _, ok := call.Fun.(*ast.ArrayType); ok { + x = call.Args[0] + } + } else if len(call.Args) >= 2 { + if funIdent, ok := call.Fun.(*ast.Ident); ok && funIdent.Name == "append" { + return addIntExpr(v.sliceLength(call.Args[0]), v.appendCount(call)), true + } + } + } + + xType := v.pass.TypesInfo.TypeOf(x) + if xType != nil { + xType = xType.Underlying() + } + + switch xType := xType.(type) { + case *types.Chan, *types.Signature: + return nil, false + case *types.Array: + if _, ok := stmt.X.(*ast.CompositeLit); ok && xType.Len() >= 0 { + return intExpr(int(xType.Len())), true + } + case *types.Slice: + if lit, ok := stmt.X.(*ast.CompositeLit); ok { + return intExpr(len(lit.Elts)), true + } + case *types.Map: + if lit, ok := x.(*ast.CompositeLit); ok { + return intExpr(len(lit.Elts)), true + } + case *types.Pointer: + if xType, ok := xType.Elem().(*types.Array); !ok { + return nil, true + } else if unary, ok := x.(*ast.UnaryExpr); ok && unary.Op == token.AND { + if _, ok := unary.X.(*ast.CompositeLit); ok && xType.Len() >= 0 { + return intExpr(int(xType.Len())), true + } + } + case *types.Basic: + if xType.Info()&types.IsString != 0 { + if lit, ok := x.(*ast.BasicLit); ok && lit.Kind == token.STRING { + if str, err := strconv.Unquote(lit.Value); err == nil { + return intExpr(len(str)), true } + } + } + default: + return nil, true + } - // e.g., `x = append(y, a)` - // This is weird (and maybe a logic error), - // but we cannot recommend pre-allocation. - if lhsIdent.Name != rhsIdent.Name { - continue + if hasCall(x) { + return nil, true + } + + if xType, ok := xType.(*types.Basic); ok { + switch { + case xType.Info()&types.IsInteger != 0: + return x, true + case xType.Info()&types.IsString != 0: + default: + return nil, true + } + } + + if slice, ok := x.(*ast.SliceExpr); ok { + high := slice.High + if high == nil { + high = &ast.CallExpr{Fun: ast.NewIdent("len"), Args: []ast.Expr{slice.X}} + } + if slice.Low != nil { + return subIntExpr(high, slice.Low), true + } + return high, true + } + + return &ast.CallExpr{Fun: ast.NewIdent("len"), Args: []ast.Expr{x}}, true +} + +func (v *returnsVisitor) appendCount(expr *ast.CallExpr) ast.Expr { + if expr.Ellipsis.IsValid() { + return v.sliceLength(expr.Args[1]) + } + return intExpr(len(expr.Args) - 1) +} + +func (v *returnsVisitor) sliceLength(expr ast.Expr) ast.Expr { + if call, ok := expr.(*ast.CallExpr); ok { + if len(call.Args) == 1 { + if _, ok := call.Fun.(*ast.ArrayType); ok { + expr = call.Args[0] + } + } else if len(call.Args) >= 2 { + if funIdent, ok := call.Fun.(*ast.Ident); ok && funIdent.Name == "append" { + return addIntExpr(v.sliceLength(call.Args[0]), v.appendCount(call)) + } + } + } + + xType := v.pass.TypesInfo.TypeOf(expr) + if xType == nil { + return nil + } + switch xType := xType.Underlying().(type) { + case *types.Array, *types.Slice: + if lit, ok := expr.(*ast.CompositeLit); ok { + return intExpr(len(lit.Elts)) + } + case *types.Basic: + if xType.Info()&types.IsString != 0 { + if lit, ok := expr.(*ast.BasicLit); ok && lit.Kind == token.STRING { + if str, err := strconv.Unquote(lit.Value); err == nil { + return intExpr(len(str)) } + } + } + default: + return nil + } + + if hasCall(expr) { + return nil + } + + if slice, ok := expr.(*ast.SliceExpr); ok { + high := slice.High + if high == nil { + high = &ast.CallExpr{Fun: ast.NewIdent("len"), Args: []ast.Expr{slice.X}} + } + if slice.Low != nil { + return subIntExpr(high, slice.Low) + } + return high + } + + return &ast.CallExpr{Fun: ast.NewIdent("len"), Args: []ast.Expr{expr}} +} + +func (v *returnsVisitor) forLoopCount(stmt *ast.ForStmt) (ast.Expr, bool) { + if stmt.Init == nil || stmt.Cond == nil || stmt.Post == nil { + return nil, false + } - // e.g., `x = append(x, y...)` - // we should ignore this. Pre-allocating in this case - // is confusing, and is not possible in general. - if callExpr.Ellipsis.IsValid() { + if hasAny(stmt.Init, v.loopVars) { + return nil, false + } + if hasAny(stmt.Cond, v.loopVars) { + return nil, false + } + + initAssign, ok := stmt.Init.(*ast.AssignStmt) + if !ok || len(initAssign.Lhs) != len(initAssign.Rhs) { + return nil, true + } + + for i, lhs := range initAssign.Lhs { + initIdent, ok := lhs.(*ast.Ident) + if !ok { + continue + } + + var reverse bool + var step ast.Expr + switch s := stmt.Post.(type) { + case *ast.IncDecStmt: + if isIdentName(s.X, initIdent.Name) { + reverse = s.Tok == token.DEC + step = intExpr(1) + } + + case *ast.AssignStmt: + if len(s.Lhs) != len(s.Rhs) { + return nil, true + } + + for i, lhs := range s.Lhs { + if !isIdentName(lhs, initIdent.Name) { continue } - - for _, sliceDecl := range v.sliceDeclarations { - if sliceDecl.name == lhsIdent.Name { - // This is a potential mark, we just need to make sure there are no returns/continues in the - // range loop. - // now we just need to grab whatever we're ranging over - /*sxIdent, ok := s.X.(*ast.Ident) - if !ok { - continue - }*/ - - v.preallocHints = append(v.preallocHints, Hint{ - Pos: sliceDecl.genD.Pos(), - DeclaredSliceName: sliceDecl.name, - }) + switch s.Tok { + case token.ADD_ASSIGN, token.SUB_ASSIGN: + step = s.Rhs[i] + reverse = s.Tok == token.SUB_ASSIGN + case token.ASSIGN: + if rhsBinary, ok := s.Rhs[i].(*ast.BinaryExpr); ok { + reverse = s.Tok == token.SUB + if rhsBinary.Op == token.ADD || reverse { + if isIdentName(rhsBinary.X, initIdent.Name) { + step = rhsBinary.Y + } else if isIdentName(rhsBinary.Y, initIdent.Name) { + step = rhsBinary.X + } + } + } else { + return nil, false } + default: + return nil, false + } + if step != nil { + break } } - case *ast.IfStmt: - ifStmt := bodyStmt - if ifStmt.Body != nil { - for _, ifBodyStmt := range ifStmt.Body.List { - // TODO should probably handle embedded ifs here - switch /*ift :=*/ ifBodyStmt.(type) { - case *ast.BranchStmt, *ast.ReturnStmt: - v.returnsInsideOfLoop = true - default: + } + + if step == nil { + continue + } + + lower := initAssign.Rhs[i] + if hasCall(lower) { + continue // NATO: this should trigger another attempt + } + + upper, op := forLoopUpperBound(stmt.Cond, initIdent.Name) + + if !reverse { + if op == token.GTR || op == token.GEQ { + return nil, false + } + } else { + if op == token.LSS || op == token.LEQ { + return nil, false + } + lower, upper = upper, lower + } + + if op == token.LEQ || op == token.GEQ { + upper = incIntExpr(upper) + } + + countExpr, rounded := divIntExpr(subIntExpr(upper, lower), step) + if rounded { + // extra capacity in case non-unary step increment is rounded down + countExpr = incIntExpr(countExpr) + } + return countExpr, true + } + + return nil, true +} + +func forLoopUpperBound(expr ast.Expr, name string) (ast.Expr, token.Token) { + binExpr, ok := expr.(*ast.BinaryExpr) + if !ok { + return nil, 0 + } + + switch binExpr.Op { + case token.LAND, token.LOR: + if xExpr, xOp := forLoopUpperBound(binExpr.X, name); xExpr != nil { + if yExpr, yOp := forLoopUpperBound(binExpr.Y, name); yExpr != nil { + if xOp == yOp { + var funName string + if binExpr.Op == token.LAND { + funName = "min" + } else { + funName = "max" } + if call, ok := xExpr.(*ast.CallExpr); ok { + if ident, ok := call.Fun.(*ast.Ident); ok && ident.Name == funName { + call.Args = append(call.Args, yExpr) + return xExpr, xOp + } + } + if call, ok := yExpr.(*ast.CallExpr); ok { + if ident, ok := call.Fun.(*ast.Ident); ok && ident.Name == funName { + call.Args = append(call.Args, xExpr) + return yExpr, yOp + } + } + return &ast.CallExpr{Fun: ast.NewIdent(funName), Args: []ast.Expr{xExpr, yExpr}}, xOp } } + } - default: - + case token.LSS, token.GTR, token.LEQ, token.GEQ, token.NEQ: + if ident, ok := binExpr.X.(*ast.Ident); ok && ident.Name == name { + if hasCall(binExpr.Y) { + return nil, 0 + } + return binExpr.Y, binExpr.Op + } else if ident, ok := binExpr.Y.(*ast.Ident); ok && ident.Name == name { + if hasCall(binExpr.X) { + return nil, 0 + } + // reverse the inequality + op := binExpr.Op + switch op { + case token.LSS: + op = token.GTR + case token.GTR: + op = token.LSS + case token.LEQ: + op = token.GEQ + case token.GEQ: + op = token.LEQ + default: + } + return binExpr.X, op } + + default: } + return nil, 0 } -// Hint stores the information about an occurrence of a slice that could be -// preallocated. -type Hint struct { - Pos token.Pos - DeclaredSliceName string +func isIdentName(expr ast.Expr, name string) bool { + ident, ok := expr.(*ast.Ident) + return ok && ident.Name == name } -func (h Hint) String() string { - return fmt.Sprintf("%v: Consider preallocating %v", h.Pos, h.DeclaredSliceName) +func hasAny(node ast.Node, exprs []ast.Expr) bool { + var found bool + ast.Inspect(node, func(node ast.Node) bool { + if expr, ok := node.(ast.Expr); ok { + for _, e := range exprs { + if exprEqual(expr, e) { + found = true + break + } + } + } + return !found + }) + return found } -func (h Hint) StringFromFS(f *token.FileSet) string { - file := f.File(h.Pos) - lineNumber := file.Position(h.Pos).Line +func hasCall(expr ast.Expr) bool { + var found bool + ast.Inspect(expr, func(n ast.Node) bool { + if call, ok := n.(*ast.CallExpr); ok { + switch fun := call.Fun.(type) { + case *ast.ArrayType, *ast.MapType: + // allow array/map type convertion + return true + case *ast.Ident: + switch fun.Name { + case "bool", "error", "string", "any", + "byte", "rune", "int", "int8", "int16", "int32", "int64", + "uint", "uint8", "uint16", "uint32", "uint64", "uintptr", + "float32", "float64", "complex64", "complex128": + // allow built-in type conversions + if len(call.Args) == 1 { + return true + } + case "len", "cap", "real", "imag", "min", "max", "complex": + // allow cheap pure built-in functions + return true + } + case *ast.SelectorExpr: + // allow argument-less methods + if len(call.Args) == 0 { + return true + } + } + found = true + } + return !found + }) + return found +} - return fmt.Sprintf("%v:%v Consider preallocating %v", file.Name(), lineNumber, h.DeclaredSliceName) +func hasVarReference(expr ast.Expr, name string) bool { + found := false + ast.Inspect(expr, func(node ast.Node) bool { + switch n := node.(type) { + case *ast.SelectorExpr: + // process target expression, ignore field selector + found = hasVarReference(n.X, name) + return false + case *ast.CallExpr: + // process args, ignore function name + for _, arg := range n.Args { + if found = hasVarReference(arg, name); found { + break + } + } + return false + case *ast.KeyValueExpr: + // process value, ignore key + found = hasVarReference(n.Value, name) + return false + case *ast.Ident: + found = n.Name == name + } + return !found + }) + return found } diff --git a/vendor/github.com/alfatraining/structtag/LICENSE b/vendor/github.com/alfatraining/structtag/LICENSE new file mode 100644 index 000000000..4fd15f9f8 --- /dev/null +++ b/vendor/github.com/alfatraining/structtag/LICENSE @@ -0,0 +1,60 @@ +Copyright (c) 2017, Fatih Arslan +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of structtag nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +This software includes some portions from Go. Go is used under the terms of the +BSD like license. + +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The Go gopher was designed by Renee French. http://reneefrench.blogspot.com/ The design is licensed under the Creative Commons 3.0 Attributions license. Read this article for more details: https://blog.golang.org/gopher diff --git a/vendor/github.com/alfatraining/structtag/README.md b/vendor/github.com/alfatraining/structtag/README.md new file mode 100644 index 000000000..4d0094bec --- /dev/null +++ b/vendor/github.com/alfatraining/structtag/README.md @@ -0,0 +1,92 @@ +# structtag [![](https://github.com/alfatraining/structtag/workflows/build/badge.svg)](https://github.com/alfatraining/structtag/actions) [![PkgGoDev](https://pkg.go.dev/badge/github.com/alfatraining/structtag)](https://pkg.go.dev/github.com/alfatraining/structtag) + +`structtag` is a library for parsing struct tags in Go during static analysis. +It is designed to provide a simple API for parsing struct field tags in Go code. +This fork focuses exclusively on **reading struct tags** and is not intended for modifying or rewriting them. +It also drops support for accessing the options of a struct tag individually. + +This project is a fork of [`fatih/structtag`](https://github.com/fatih/structtag), originally created by Fatih Arslan. +The primary changes in this fork are: + +- struct tag values are treated as blobs, options are not treated individually, +- the API surface is minimized, just so that the functionality used by [`4meepo/tagalign`](https://github.com/4meepo/tagalign) is provided. + +--- + +## Install + +To install the package: + +```bash +go get github.com/alfatraining/structtag +``` + +--- + +## Example Usage + +The following example demonstrates how to parse and output struct tags using `structtag`: + +```go +package main + +import ( + "fmt" + "reflect" + + "github.com/alfatraining/structtag" +) + +func main() { + type Example struct { + Field string `json:"foo,omitempty" xml:"bar"` + } + + // Get the struct tag from the field + tag := reflect.TypeOf(Example{}).Field(0).Tag + + // Parse the tag using structtag + tags, err := structtag.Parse(string(tag)) + if err != nil { + panic(err) + } + + // Iterate over all tags + for _, t := range tags.Tags() { + fmt.Printf("Key: %s, Value: %v\n", t.Key, t.Value) + } + // Output: + // Key: json, Value: foo,omitempty + // Key: xml, Value: bar +} +``` + +--- + +## API Overview + +### Parsing Struct Tags +Use `Parse` to parse a struct field's tag into a `Tags` object: +```go +tags, err := structtag.Parse(`json:"foo,omitempty" xml:"bar"`) +if err != nil { + panic(err) +} +``` + +### Accessing Tags +- **Retrieve all tags**: + ```go + allTags := tags.Tags() + ``` + +### Inspecting Tags +- **Key**: The key of the tag (e.g., `json` or `xml`). +- **Value**: The value of the tag (e.g., `"foo,omitempty"` for `json:"foo,omitempty"`). + +--- + +## Acknowledgments + +This project is based on [`fatih/structtag`](https://github.com/fatih/structtag), created by Fatih Arslan. +Inspiration for the style of this README was taken from [tylergannon/structtag](https://github.com/tylergannon/structtag), created by Tyler Gannon. diff --git a/vendor/github.com/alfatraining/structtag/tags.go b/vendor/github.com/alfatraining/structtag/tags.go new file mode 100644 index 000000000..227df3c2f --- /dev/null +++ b/vendor/github.com/alfatraining/structtag/tags.go @@ -0,0 +1,138 @@ +package structtag + +import ( + "bytes" + "errors" + "fmt" + "strconv" +) + +var ( + errTagSyntax = errors.New("bad syntax for struct tag pair") + errTagKeySyntax = errors.New("bad syntax for struct tag key") + errTagValueSyntax = errors.New("bad syntax for struct tag value") +) + +// Tags represent a set of tags from a single struct field +type Tags struct { + tags []*Tag +} + +// Tag defines a single struct's string literal tag +type Tag struct { + // Key is the tag key, such as json, xml, etc. + // i.e: `json:"foo,omitempty". Here key is: "json" + Key string + + // Value is the value stored for this tag key. + // i.e.: `json:"foo,omitempty". Here the value is: "foo,omitempty". + Value string +} + +// Parse parses a single struct field tag and returns the set of tags. +func Parse(tag string) (*Tags, error) { + var tags []*Tag + + hasTag := tag != "" + + // NOTE(arslan) following code is from reflect and vet package with some + // modifications to collect all necessary information and extend it with + // usable methods + for tag != "" { + // Skip leading space. + i := 0 + for i < len(tag) && tag[i] == ' ' { + i++ + } + tag = tag[i:] + if tag == "" { + break + } + + // Scan to colon. A space, a quote or a control character is a syntax error. + // Strictly speaking, control chars include the range [0x7f, 0x9f], not just + // [0x00, 0x1f], but in practice, we ignore the multi-byte control characters + // as it is simpler to inspect the tag's bytes than the tag's runes. + i = 0 + for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f { + i++ + } + + if i == 0 { + return nil, errTagKeySyntax + } + if i+1 >= len(tag) || tag[i] != ':' { + return nil, errTagSyntax + } + if tag[i+1] != '"' { + return nil, errTagValueSyntax + } + + key := tag[:i] + tag = tag[i+1:] + + // Scan quoted string to find value. + i = 1 + for i < len(tag) && tag[i] != '"' { + if tag[i] == '\\' { + i++ + } + i++ + } + if i >= len(tag) { + return nil, errTagValueSyntax + } + + qvalue := tag[:i+1] + tag = tag[i+1:] + + value, err := strconv.Unquote(qvalue) + if err != nil { + return nil, errTagValueSyntax + } + + tags = append(tags, &Tag{ + Key: key, + Value: value, + }) + } + + if hasTag && len(tags) == 0 { + return nil, nil + } + + return &Tags{ + tags: tags, + }, nil +} + +// Tags returns a slice of tags. The order is the original tag order. +func (t *Tags) Tags() []*Tag { + return t.tags +} + +// String reassembles the tags into a valid literal tag field representation +func (t *Tags) String() string { + tags := t.Tags() + if len(tags) == 0 { + return "" + } + + var buf bytes.Buffer + for i, tag := range t.Tags() { + buf.WriteString(tag.String()) + if i != len(tags)-1 { + buf.WriteString(" ") + } + } + return buf.String() +} + +// String reassembles the tag into a valid tag field representation +func (t *Tag) String() string { + return fmt.Sprintf(`%s:%q`, t.Key, t.Value) +} + +func (t *Tags) Len() int { + return len(t.tags) +} diff --git a/vendor/github.com/tdakkota/asciicheck/.gitignore b/vendor/github.com/alingse/nilnesserr/.gitignore similarity index 51% rename from vendor/github.com/tdakkota/asciicheck/.gitignore rename to vendor/github.com/alingse/nilnesserr/.gitignore index dfa562d3e..6f72f8926 100644 --- a/vendor/github.com/tdakkota/asciicheck/.gitignore +++ b/vendor/github.com/alingse/nilnesserr/.gitignore @@ -1,10 +1,6 @@ -# IntelliJ project files -.idea -*.iml -out -gen - -# Go template +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# # Binaries for programs and plugins *.exe *.exe~ @@ -20,13 +16,10 @@ gen # Dependency directories (remove the comment below to include it) # vendor/ -.idea/$CACHE_FILE$ -.idea/$PRODUCT_WORKSPACE_FILE$ -.idea/.gitignore -.idea/codeStyles -.idea/deployment.xml -.idea/inspectionProfiles/ -.idea/kotlinc.xml -.idea/misc.xml -.idea/modules.xml -asciicheck.iml + +# Go workspace file +go.work +go.work.sum + +# env file +.env diff --git a/vendor/github.com/alingse/nilnesserr/.golangci.yaml b/vendor/github.com/alingse/nilnesserr/.golangci.yaml new file mode 100644 index 000000000..6882e0f35 --- /dev/null +++ b/vendor/github.com/alingse/nilnesserr/.golangci.yaml @@ -0,0 +1,75 @@ +linters: + enable-all: true + disable: + - wsl + - varnamelen + - nilnil + - ireturn + - gochecknoglobals + - nolintlint + +linters-settings: + depguard: + rules: + main: + list-mode: lax + files: + - $all + allow: + - $gostd + - github.com/alingse/nilnesserr + cyclop: + max-complexity: 12 + lll: + line-length: 200 + +issues: + exclude-rules: + - path: internal/typeparams + linters: + - nonamedreturns + - nlreturn + - intrange + - mnd + - forcetypeassert + - exhaustruct + - exhaustive + - err113 + - gofumpt + - prealloc + - funclen + - gocritic + - funlen + - cyclop + - gocognit + + - path: nilness.go + linters: + - nonamedreturns + - nlreturn + - nilnil + - mnd + - forcetypeassert + - gochecknoglobals + - nestif + - funlen + - godox + - gocognit + - gofumpt + - exhaustive + - cyclop + - unparam + - gocyclo + + - text: "analysis." + linters: + - exhaustruct + + - text: "newAnalyzer" + linters: + - unparam + + - text: "indent-error-flow" + path: nilness.go + linters: + - revive diff --git a/vendor/github.com/olekukonko/tablewriter/LICENSE.md b/vendor/github.com/alingse/nilnesserr/LICENSE similarity index 88% rename from vendor/github.com/olekukonko/tablewriter/LICENSE.md rename to vendor/github.com/alingse/nilnesserr/LICENSE index a0769b5c1..6caf1ea1c 100644 --- a/vendor/github.com/olekukonko/tablewriter/LICENSE.md +++ b/vendor/github.com/alingse/nilnesserr/LICENSE @@ -1,4 +1,6 @@ -Copyright (C) 2014 by Oleku Konko +MIT License + +Copyright (c) 2024 alingse Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -7,13 +9,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/alingse/nilnesserr/README.md b/vendor/github.com/alingse/nilnesserr/README.md new file mode 100644 index 000000000..2299488ed --- /dev/null +++ b/vendor/github.com/alingse/nilnesserr/README.md @@ -0,0 +1,89 @@ +# nilnesserr + +nilnesserr = nilness + nilerr + +`nilnesserr` is a linter for report return nil error in Go. It combines the features of [nilness](https://cs.opensource.google/go/x/tools/+/refs/tags/v0.28.0:go/analysis/passes/nilness/nilness.go) and [nilerr](https://github.com/gostaticanalysis/nilerr), providing a concise way to detect return an unrelated/nil-values error. + +## Case + +case 1 +```go +err := do() +if err != nil { + return err +} +err2 := do2() +if err2 != nil { + return err // want `return a nil value error after check error` +} +``` + +case 2 + +```go +err := do() +if err != nil { + return err +} +_, err2 := do2() +if err2 != nil { + return errors.Wrap(err) // want `call function with a nil value error after check error` +} +``` + +case 3 + +```go +err := do() +if err != nil { + return err +} +_, err2 := do2() +if err2 != nil { + return fmt.Errorf("call do2 failed: %w",err) // want `call variadic function with a nil value error after check error` +} +``` + + +## Some Real Bugs + +- https://github.com/alingse/sundrylint/issues/4 +- https://github.com/alingse/nilnesserr/issues/1 +- https://github.com/alingse/nilnesserr/issues/11 +- https://github.com/alingse/nilnesserr/issues/15 + +We use https://github.com/alingse/go-linter-runner to run linter on GitHub Actions for public Go repos + +## Install + +```bash +go install github.com/alingse/nilnesserr/cmd/nilnesserr@latest +``` + + +## TODO + +case 3 + +```go +err := do() +if err != nil { + return err +} +_, ok := do2() +if !ok { + return err +} + +``` + +maybe this is also a bug, should return a non-nil value error after the if + +## License + +This project is licensed under the MIT License. See the LICENSE file for details. + +This project incorporates source code from two different libraries: + +1. [nilness](https://cs.opensource.google/go/x/tools/+/refs/tags/v0.28.0:go/analysis/passes/nilness/nilness.go) licensed under the BSD license. +2. [nilerr](https://github.com/gostaticanalysis/nilerr) licensed under the MIT license. diff --git a/vendor/github.com/alingse/nilnesserr/internal/typeparams/coretype.go b/vendor/github.com/alingse/nilnesserr/internal/typeparams/coretype.go new file mode 100644 index 000000000..7a744d123 --- /dev/null +++ b/vendor/github.com/alingse/nilnesserr/internal/typeparams/coretype.go @@ -0,0 +1,122 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package typeparams + +import ( + "go/types" +) + +// CoreType returns the core type of T or nil if T does not have a core type. +// +// See https://go.dev/ref/spec#Core_types for the definition of a core type. +func CoreType(T types.Type) types.Type { + U := T.Underlying() + if _, ok := U.(*types.Interface); !ok { + return U // for non-interface types, + } + + terms, err := NormalTerms(U) + if len(terms) == 0 || err != nil { + // len(terms) -> empty type set of interface. + // err != nil => U is invalid, exceeds complexity bounds, or has an empty type set. + return nil // no core type. + } + + U = terms[0].Type().Underlying() + var identical int // i in [0,identical) => Identical(U, terms[i].Type().Underlying()) + for identical = 1; identical < len(terms); identical++ { + if !types.Identical(U, terms[identical].Type().Underlying()) { + break + } + } + + if identical == len(terms) { + // https://go.dev/ref/spec#Core_types + // "There is a single type U which is the underlying type of all types in the type set of T" + return U + } + ch, ok := U.(*types.Chan) + if !ok { + return nil // no core type as identical < len(terms) and U is not a channel. + } + // https://go.dev/ref/spec#Core_types + // "the type chan E if T contains only bidirectional channels, or the type chan<- E or + // <-chan E depending on the direction of the directional channels present." + for chans := identical; chans < len(terms); chans++ { + curr, ok := terms[chans].Type().Underlying().(*types.Chan) + if !ok { + return nil + } + if !types.Identical(ch.Elem(), curr.Elem()) { + return nil // channel elements are not identical. + } + if ch.Dir() == types.SendRecv { + // ch is bidirectional. We can safely always use curr's direction. + ch = curr + } else if curr.Dir() != types.SendRecv && ch.Dir() != curr.Dir() { + // ch and curr are not bidirectional and not the same direction. + return nil + } + } + return ch +} + +// NormalTerms returns a slice of terms representing the normalized structural +// type restrictions of a type, if any. +// +// For all types other than *types.TypeParam, *types.Interface, and +// *types.Union, this is just a single term with Tilde() == false and +// Type() == typ. For *types.TypeParam, *types.Interface, and *types.Union, see +// below. +// +// Structural type restrictions of a type parameter are created via +// non-interface types embedded in its constraint interface (directly, or via a +// chain of interface embeddings). For example, in the declaration type +// T[P interface{~int; m()}] int the structural restriction of the type +// parameter P is ~int. +// +// With interface embedding and unions, the specification of structural type +// restrictions may be arbitrarily complex. For example, consider the +// following: +// +// type A interface{ ~string|~[]byte } +// +// type B interface{ int|string } +// +// type C interface { ~string|~int } +// +// type T[P interface{ A|B; C }] int +// +// In this example, the structural type restriction of P is ~string|int: A|B +// expands to ~string|~[]byte|int|string, which reduces to ~string|~[]byte|int, +// which when intersected with C (~string|~int) yields ~string|int. +// +// NormalTerms computes these expansions and reductions, producing a +// "normalized" form of the embeddings. A structural restriction is normalized +// if it is a single union containing no interface terms, and is minimal in the +// sense that removing any term changes the set of types satisfying the +// constraint. It is left as a proof for the reader that, modulo sorting, there +// is exactly one such normalized form. +// +// Because the minimal representation always takes this form, NormalTerms +// returns a slice of tilde terms corresponding to the terms of the union in +// the normalized structural restriction. An error is returned if the type is +// invalid, exceeds complexity bounds, or has an empty type set. In the latter +// case, NormalTerms returns ErrEmptyTypeSet. +// +// NormalTerms makes no guarantees about the order of terms, except that it +// is deterministic. +func NormalTerms(typ types.Type) ([]*types.Term, error) { + switch typ := typ.Underlying().(type) { + case *types.TypeParam: + return StructuralTerms(typ) + case *types.Union: + return UnionTermSet(typ) + case *types.Interface: + return InterfaceTermSet(typ) + default: + return []*types.Term{types.NewTerm(false, typ)}, nil + } +} diff --git a/vendor/github.com/alingse/nilnesserr/internal/typeparams/normalize.go b/vendor/github.com/alingse/nilnesserr/internal/typeparams/normalize.go new file mode 100644 index 000000000..0302872f4 --- /dev/null +++ b/vendor/github.com/alingse/nilnesserr/internal/typeparams/normalize.go @@ -0,0 +1,200 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package typeparams + +import ( + "errors" + "fmt" + "go/types" +) + +var ErrEmptyTypeSet = errors.New("empty type set") + +// StructuralTerms returns a slice of terms representing the normalized +// structural type restrictions of a type parameter, if any. +// +// Structural type restrictions of a type parameter are created via +// non-interface types embedded in its constraint interface (directly, or via a +// chain of interface embeddings). For example, in the declaration +// +// type T[P interface{~int; m()}] int +// +// the structural restriction of the type parameter P is ~int. +// +// With interface embedding and unions, the specification of structural type +// restrictions may be arbitrarily complex. For example, consider the +// following: +// +// type A interface{ ~string|~[]byte } +// +// type B interface{ int|string } +// +// type C interface { ~string|~int } +// +// type T[P interface{ A|B; C }] int +// +// In this example, the structural type restriction of P is ~string|int: A|B +// expands to ~string|~[]byte|int|string, which reduces to ~string|~[]byte|int, +// which when intersected with C (~string|~int) yields ~string|int. +// +// StructuralTerms computes these expansions and reductions, producing a +// "normalized" form of the embeddings. A structural restriction is normalized +// if it is a single union containing no interface terms, and is minimal in the +// sense that removing any term changes the set of types satisfying the +// constraint. It is left as a proof for the reader that, modulo sorting, there +// is exactly one such normalized form. +// +// Because the minimal representation always takes this form, StructuralTerms +// returns a slice of tilde terms corresponding to the terms of the union in +// the normalized structural restriction. An error is returned if the +// constraint interface is invalid, exceeds complexity bounds, or has an empty +// type set. In the latter case, StructuralTerms returns ErrEmptyTypeSet. +// +// StructuralTerms makes no guarantees about the order of terms, except that it +// is deterministic. +func StructuralTerms(tparam *types.TypeParam) ([]*types.Term, error) { + constraint := tparam.Constraint() + if constraint == nil { + return nil, fmt.Errorf("%s has nil constraint", tparam) + } + iface, _ := constraint.Underlying().(*types.Interface) + if iface == nil { + return nil, fmt.Errorf("constraint is %T, not *types.Interface", constraint.Underlying()) + } + return InterfaceTermSet(iface) +} + +// InterfaceTermSet computes the normalized terms for a constraint interface, +// returning an error if the term set cannot be computed or is empty. In the +// latter case, the error will be ErrEmptyTypeSet. +// +// See the documentation of StructuralTerms for more information on +// normalization. +func InterfaceTermSet(iface *types.Interface) ([]*types.Term, error) { + return computeTermSet(iface) +} + +// UnionTermSet computes the normalized terms for a union, returning an error +// if the term set cannot be computed or is empty. In the latter case, the +// error will be ErrEmptyTypeSet. +// +// See the documentation of StructuralTerms for more information on +// normalization. +func UnionTermSet(union *types.Union) ([]*types.Term, error) { + return computeTermSet(union) +} + +func computeTermSet(typ types.Type) ([]*types.Term, error) { + tset, err := computeTermSetInternal(typ, make(map[types.Type]*termSet), 0) + if err != nil { + return nil, err + } + if tset.terms.isEmpty() { + return nil, ErrEmptyTypeSet + } + if tset.terms.isAll() { + return nil, nil + } + var terms []*types.Term + for _, term := range tset.terms { + terms = append(terms, types.NewTerm(term.tilde, term.typ)) + } + return terms, nil +} + +// A termSet holds the normalized set of terms for a given type. +// +// The name termSet is intentionally distinct from 'type set': a type set is +// all types that implement a type (and includes method restrictions), whereas +// a term set just represents the structural restrictions on a type. +type termSet struct { + complete bool + terms termlist +} + +var ErrNilType = errors.New("nil type") +var ErrUnreachable = errors.New("unreachable") + +func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth int) (res *termSet, err error) { + if t == nil { + return nil, ErrNilType + } + + const maxTermCount = 100 + if tset, ok := seen[t]; ok { + if !tset.complete { + return nil, fmt.Errorf("cycle detected in the declaration of %s", t) + } + return tset, nil + } + + // Mark the current type as seen to avoid infinite recursion. + tset := new(termSet) + defer func() { + tset.complete = true + }() + seen[t] = tset + + switch u := t.Underlying().(type) { + case *types.Interface: + // The term set of an interface is the intersection of the term sets of its + // embedded types. + tset.terms = allTermlist + for i := 0; i < u.NumEmbeddeds(); i++ { + embedded := u.EmbeddedType(i) + if _, ok := embedded.Underlying().(*types.TypeParam); ok { + return nil, fmt.Errorf("invalid embedded type %T", embedded) + } + tset2, err := computeTermSetInternal(embedded, seen, depth+1) + if err != nil { + return nil, err + } + tset.terms = tset.terms.intersect(tset2.terms) + } + case *types.Union: + // The term set of a union is the union of term sets of its terms. + tset.terms = nil + for i := 0; i < u.Len(); i++ { + t := u.Term(i) + var terms termlist + switch t.Type().Underlying().(type) { + case *types.Interface: + tset2, err := computeTermSetInternal(t.Type(), seen, depth+1) + if err != nil { + return nil, err + } + terms = tset2.terms + case *types.TypeParam, *types.Union: + // A stand-alone type parameter or union is not permitted as union + // term. + return nil, fmt.Errorf("invalid union term %T", t) + default: + if t.Type() == types.Typ[types.Invalid] { + continue + } + terms = termlist{{t.Tilde(), t.Type()}} + } + tset.terms = tset.terms.union(terms) + if len(tset.terms) > maxTermCount { + return nil, fmt.Errorf("exceeded max term count %d", maxTermCount) + } + } + case *types.TypeParam: + return nil, ErrUnreachable + default: + // For all other types, the term set is just a single non-tilde term + // holding the type itself. + if u != types.Typ[types.Invalid] { + tset.terms = termlist{{false, t}} + } + } + return tset, nil +} + +// under is a facade for the go/types internal function of the same name. It is +// used by typeterm.go. +func under(t types.Type) types.Type { + return t.Underlying() +} diff --git a/vendor/github.com/alingse/nilnesserr/internal/typeparams/termlist.go b/vendor/github.com/alingse/nilnesserr/internal/typeparams/termlist.go new file mode 100644 index 000000000..cbd12f801 --- /dev/null +++ b/vendor/github.com/alingse/nilnesserr/internal/typeparams/termlist.go @@ -0,0 +1,163 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Code generated by copytermlist.go DO NOT EDIT. + +package typeparams + +import ( + "bytes" + "go/types" +) + +// A termlist represents the type set represented by the union +// t1 ∪ y2 ∪ ... tn of the type sets of the terms t1 to tn. +// A termlist is in normal form if all terms are disjoint. +// termlist operations don't require the operands to be in +// normal form. +type termlist []*term + +// allTermlist represents the set of all types. +// It is in normal form. +var allTermlist = termlist{new(term)} + +// String prints the termlist exactly (without normalization). +func (xl termlist) String() string { + if len(xl) == 0 { + return "∅" + } + var buf bytes.Buffer + for i, x := range xl { + if i > 0 { + buf.WriteString(" | ") + } + buf.WriteString(x.String()) + } + return buf.String() +} + +// isEmpty reports whether the termlist xl represents the empty set of types. +func (xl termlist) isEmpty() bool { + // If there's a non-nil term, the entire list is not empty. + // If the termlist is in normal form, this requires at most + // one iteration. + for _, x := range xl { + if x != nil { + return false + } + } + return true +} + +// isAll reports whether the termlist xl represents the set of all types. +func (xl termlist) isAll() bool { + // If there's a 𝓤 term, the entire list is 𝓤. + // If the termlist is in normal form, this requires at most + // one iteration. + for _, x := range xl { + if x != nil && x.typ == nil { + return true + } + } + return false +} + +// norm returns the normal form of xl. +func (xl termlist) norm() termlist { + // Quadratic algorithm, but good enough for now. + // TODO(gri) fix asymptotic performance + used := make([]bool, len(xl)) + var rl termlist + for i, xi := range xl { + if xi == nil || used[i] { + continue + } + for j := i + 1; j < len(xl); j++ { + xj := xl[j] + if xj == nil || used[j] { + continue + } + if u1, u2 := xi.union(xj); u2 == nil { + // If we encounter a 𝓤 term, the entire list is 𝓤. + // Exit early. + // (Note that this is not just an optimization; + // if we continue, we may end up with a 𝓤 term + // and other terms and the result would not be + // in normal form.) + if u1.typ == nil { + return allTermlist + } + xi = u1 + used[j] = true // xj is now unioned into xi - ignore it in future iterations + } + } + rl = append(rl, xi) + } + return rl +} + +// union returns the union xl ∪ yl. +func (xl termlist) union(yl termlist) termlist { + return append(xl, yl...).norm() +} + +// intersect returns the intersection xl ∩ yl. +func (xl termlist) intersect(yl termlist) termlist { + if xl.isEmpty() || yl.isEmpty() { + return nil + } + + // Quadratic algorithm, but good enough for now. + // TODO(gri) fix asymptotic performance + var rl termlist + for _, x := range xl { + for _, y := range yl { + if r := x.intersect(y); r != nil { + rl = append(rl, r) + } + } + } + return rl.norm() +} + +// equal reports whether xl and yl represent the same type set. +func (xl termlist) equal(yl termlist) bool { + // TODO(gri) this should be more efficient + return xl.subsetOf(yl) && yl.subsetOf(xl) +} + +// includes reports whether t ∈ xl. +func (xl termlist) includes(t types.Type) bool { + for _, x := range xl { + if x.includes(t) { + return true + } + } + return false +} + +// supersetOf reports whether y ⊆ xl. +func (xl termlist) supersetOf(y *term) bool { + for _, x := range xl { + if y.subsetOf(x) { + return true + } + } + return false +} + +// subsetOf reports whether xl ⊆ yl. +func (xl termlist) subsetOf(yl termlist) bool { + if yl.isEmpty() { + return xl.isEmpty() + } + + // each term x of xl must be a subset of yl + for _, x := range xl { + if !yl.supersetOf(x) { + return false // x is not a subset yl + } + } + return true +} diff --git a/vendor/github.com/alingse/nilnesserr/internal/typeparams/typeterm.go b/vendor/github.com/alingse/nilnesserr/internal/typeparams/typeterm.go new file mode 100644 index 000000000..35c66003d --- /dev/null +++ b/vendor/github.com/alingse/nilnesserr/internal/typeparams/typeterm.go @@ -0,0 +1,166 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Code generated by copytermlist.go DO NOT EDIT. + +package typeparams + +import "go/types" + +// A term describes elementary type sets: +// +// ∅: (*term)(nil) == ∅ // set of no types (empty set) +// 𝓤: &term{} == 𝓤 // set of all types (𝓤niverse) +// T: &term{false, T} == {T} // set of type T +// ~t: &term{true, t} == {t' | under(t') == t} // set of types with underlying type t +type term struct { + tilde bool // valid if typ != nil + typ types.Type +} + +func (x *term) String() string { + switch { + case x == nil: + return "∅" + case x.typ == nil: + return "𝓤" + case x.tilde: + return "~" + x.typ.String() + default: + return x.typ.String() + } +} + +// equal reports whether x and y represent the same type set. +func (x *term) equal(y *term) bool { + // easy cases + switch { + case x == nil || y == nil: + return x == y + case x.typ == nil || y.typ == nil: + return x.typ == y.typ + } + // ∅ ⊂ x, y ⊂ 𝓤 + + return x.tilde == y.tilde && types.Identical(x.typ, y.typ) +} + +// union returns the union x ∪ y: zero, one, or two non-nil terms. +func (x *term) union(y *term) (_, _ *term) { + // easy cases + switch { + case x == nil && y == nil: + return nil, nil // ∅ ∪ ∅ == ∅ + case x == nil: + return y, nil // ∅ ∪ y == y + case y == nil: + return x, nil // x ∪ ∅ == x + case x.typ == nil: + return x, nil // 𝓤 ∪ y == 𝓤 + case y.typ == nil: + return y, nil // x ∪ 𝓤 == 𝓤 + } + // ∅ ⊂ x, y ⊂ 𝓤 + + if x.disjoint(y) { + return x, y // x ∪ y == (x, y) if x ∩ y == ∅ + } + // x.typ == y.typ + + // ~t ∪ ~t == ~t + // ~t ∪ T == ~t + // T ∪ ~t == ~t + // T ∪ T == T + if x.tilde || !y.tilde { + return x, nil + } + return y, nil +} + +// intersect returns the intersection x ∩ y. +func (x *term) intersect(y *term) *term { + // easy cases + switch { + case x == nil || y == nil: + return nil // ∅ ∩ y == ∅ and ∩ ∅ == ∅ + case x.typ == nil: + return y // 𝓤 ∩ y == y + case y.typ == nil: + return x // x ∩ 𝓤 == x + } + // ∅ ⊂ x, y ⊂ 𝓤 + + if x.disjoint(y) { + return nil // x ∩ y == ∅ if x ∩ y == ∅ + } + // x.typ == y.typ + + // ~t ∩ ~t == ~t + // ~t ∩ T == T + // T ∩ ~t == T + // T ∩ T == T + if !x.tilde || y.tilde { + return x + } + return y +} + +// includes reports whether t ∈ x. +func (x *term) includes(t types.Type) bool { + // easy cases + switch { + case x == nil: + return false // t ∈ ∅ == false + case x.typ == nil: + return true // t ∈ 𝓤 == true + } + // ∅ ⊂ x ⊂ 𝓤 + + u := t + if x.tilde { + u = under(u) + } + return types.Identical(x.typ, u) +} + +// subsetOf reports whether x ⊆ y. +func (x *term) subsetOf(y *term) bool { + // easy cases + switch { + case x == nil: + return true // ∅ ⊆ y == true + case y == nil: + return false // x ⊆ ∅ == false since x != ∅ + case y.typ == nil: + return true // x ⊆ 𝓤 == true + case x.typ == nil: + return false // 𝓤 ⊆ y == false since y != 𝓤 + } + // ∅ ⊂ x, y ⊂ 𝓤 + + if x.disjoint(y) { + return false // x ⊆ y == false if x ∩ y == ∅ + } + // x.typ == y.typ + + // ~t ⊆ ~t == true + // ~t ⊆ T == false + // T ⊆ ~t == true + // T ⊆ T == true + return !x.tilde || y.tilde +} + +// disjoint reports whether x ∩ y == ∅. +// x.typ and y.typ must not be nil. +func (x *term) disjoint(y *term) bool { + ux := x.typ + if y.tilde { + ux = under(ux) + } + uy := y.typ + if x.tilde { + uy = under(uy) + } + return !types.Identical(ux, uy) +} diff --git a/vendor/github.com/alingse/nilnesserr/linter.go b/vendor/github.com/alingse/nilnesserr/linter.go new file mode 100644 index 000000000..2f5724628 --- /dev/null +++ b/vendor/github.com/alingse/nilnesserr/linter.go @@ -0,0 +1,50 @@ +package nilnesserr + +import ( + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/buildssa" +) + +const ( + linterName = "nilnesserr" + linterDoc = `Reports constructs that checks for err != nil, but returns a different nil value error. +Powered by nilness and nilerr.` + + linterReturnMessage = "return a nil value error after check error" + linterCallMessage = "call function with a nil value error after check error" + linterVariadicCallMessage = "call variadic function with a nil value error after check error" +) + +type LinterSetting struct{} + +func NewAnalyzer(setting LinterSetting) (*analysis.Analyzer, error) { + a, err := newAnalyzer(setting) + if err != nil { + return nil, err + } + + return &analysis.Analyzer{ + Name: linterName, + Doc: linterDoc, + Run: a.run, + Requires: []*analysis.Analyzer{ + buildssa.Analyzer, + }, + }, nil +} + +type analyzer struct { + setting LinterSetting +} + +func newAnalyzer(setting LinterSetting) (*analyzer, error) { + a := &analyzer{setting: setting} + + return a, nil +} + +func (a *analyzer) run(pass *analysis.Pass) (interface{}, error) { + _, _ = a.checkNilnesserr(pass) + + return nil, nil +} diff --git a/vendor/github.com/alingse/nilnesserr/nilerr.go b/vendor/github.com/alingse/nilnesserr/nilerr.go new file mode 100644 index 000000000..093fc1eb8 --- /dev/null +++ b/vendor/github.com/alingse/nilnesserr/nilerr.go @@ -0,0 +1,192 @@ +// some code was copy from https://github.com/gostaticanalysis/nilerr/blob/master/nilerr.go + +package nilnesserr + +import ( + "go/types" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/ssa" +) + +var errType = types.Universe.Lookup("error").Type().Underlying().(*types.Interface) // nolint: forcetypeassert + +func isErrType(res ssa.Value) bool { + return types.Implements(res.Type(), errType) +} + +func isConstNil(res ssa.Value) bool { + v, ok := res.(*ssa.Const) + if ok && v.IsNil() { + return true + } + + return false +} + +func extractCheckedErrorValue(binOp *ssa.BinOp) ssa.Value { + if isErrType(binOp.X) && isConstNil(binOp.Y) { + return binOp.X + } + if isErrType(binOp.Y) && isConstNil(binOp.X) { + return binOp.Y + } + + return nil +} + +type errFact fact + +func findLastNonnilValue(errors []errFact, res ssa.Value) ssa.Value { + if len(errors) == 0 { + return nil + } + + for j := len(errors) - 1; j >= 0; j-- { + last := errors[j] + if last.value == res { + return nil + } else if last.nilness == isnonnil { + return last.value + } + } + + return nil +} + +func checkNilnesserr(pass *analysis.Pass, b *ssa.BasicBlock, errors []errFact, isNilnees func(value ssa.Value) bool) { + for _, instr := range b.Instrs { + pos := instr.Pos() + if !pos.IsValid() { + continue + } + + switch instr := instr.(type) { + case *ssa.Return: + for _, value := range instr.Results { + if checkSSAValue(value, errors, isNilnees) { + pass.Report(analysis.Diagnostic{ + Pos: pos, + Message: linterReturnMessage, + }) + } + } + case *ssa.Call: + for _, value := range instr.Call.Args { + if checkSSAValue(value, errors, isNilnees) { + pass.Report(analysis.Diagnostic{ + Pos: pos, + Message: linterCallMessage, + }) + } + } + + // extra check for variadic arguments + variadicArgs := checkVariadicCall(instr) + for _, value := range variadicArgs { + if checkSSAValue(value, errors, isNilnees) { + pass.Report(analysis.Diagnostic{ + Pos: pos, + Message: linterVariadicCallMessage, + }) + } + } + } + } +} + +func checkSSAValue(res ssa.Value, errors []errFact, isNilnees func(value ssa.Value) bool) bool { + if !isErrType(res) || isConstNil(res) || !isNilnees(res) { + return false + } + // check the lastValue error that is isnonnil + lastValue := findLastNonnilValue(errors, res) + + return lastValue != nil +} + +func checkVariadicCall(call *ssa.Call) []ssa.Value { + alloc := validateVariadicCall(call) + if alloc == nil { + return nil + } + + return extractVariadicErrors(alloc) +} + +/* +example: fmt.Errorf("call Do2 got err %w", err) + +type *ssa.Alloc instr new [1]any (varargs) +type *ssa.IndexAddr instr &t4[0:int] +type *ssa.ChangeInterface instr change interface any <- error (t0) +type *ssa.Store instr *t5 = t6 +... +type *ssa.Slice instr slice t4[:] +type *ssa.Call instr fmt.Errorf("call Do2 got err ...":string, t7...) +*/ +func validateVariadicCall(call *ssa.Call) *ssa.Alloc { + fn, ok := call.Call.Value.(*ssa.Function) + if !ok { + return nil + } + if !fn.Signature.Variadic() { + return nil + } + + if len(call.Call.Args) == 0 { + return nil + } + lastArg := call.Call.Args[len(call.Call.Args)-1] + slice, ok := lastArg.(*ssa.Slice) + if !ok { + return nil + } + // check is t[:] + if !(slice.Low == nil && slice.High == nil && slice.Max == nil) { + return nil + } + alloc, ok := slice.X.(*ssa.Alloc) + if !ok { + return nil + } + valueType, ok := alloc.Type().(*types.Pointer) + if !ok { + return nil + } + + // check is array + _, ok = valueType.Elem().(*types.Array) + if !ok { + return nil + } + + return alloc +} + +// the Referrer chain is like this. +// Alloc --> IndexAddr --> ChangeInterface --> Store ---> Slice. +// Alloc --> IndexAddr --> Store --> Slice. +func extractVariadicErrors(alloc *ssa.Alloc) []ssa.Value { + values := make([]ssa.Value, 0) + + for _, instr := range *alloc.Referrers() { + indexAddr, ok := instr.(*ssa.IndexAddr) + if !ok { + continue + } + for _, instr2 := range *indexAddr.Referrers() { + store, ok := instr2.(*ssa.Store) + if !ok { + continue + } + value := store.Val + if change, ok := value.(*ssa.ChangeInterface); ok { + value = change.X + } + values = append(values, value) + } + } + + return values +} diff --git a/vendor/github.com/alingse/nilnesserr/nilness.go b/vendor/github.com/alingse/nilnesserr/nilness.go new file mode 100644 index 000000000..cd5a69107 --- /dev/null +++ b/vendor/github.com/alingse/nilnesserr/nilness.go @@ -0,0 +1,374 @@ +// This file was copy from https://cs.opensource.google/go/x/tools/+/master:go/analysis/passes/nilness/nilness.go +// I modified some to check the error return + +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package nilnesserr + +import ( + "go/token" + "go/types" + + "github.com/alingse/nilnesserr/internal/typeparams" + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/buildssa" + "golang.org/x/tools/go/ssa" +) + +func (a *analyzer) checkNilnesserr(pass *analysis.Pass) (interface{}, error) { + ssainput := pass.ResultOf[buildssa.Analyzer].(*buildssa.SSA) + for _, fn := range ssainput.SrcFuncs { + runFunc(pass, fn) + } + return nil, nil +} + +func runFunc(pass *analysis.Pass, fn *ssa.Function) { + // visit visits reachable blocks of the CFG in dominance order, + // maintaining a stack of dominating nilness facts. + // + // By traversing the dom tree, we can pop facts off the stack as + // soon as we've visited a subtree. Had we traversed the CFG, + // we would need to retain the set of facts for each block. + seen := make([]bool, len(fn.Blocks)) // seen[i] means visit should ignore block i + + var visit func(b *ssa.BasicBlock, stack []fact, errors []errFact) + + visit = func(b *ssa.BasicBlock, stack []fact, errors []errFact) { + if seen[b.Index] { + return + } + seen[b.Index] = true + + // check this block return a nil value error + checkNilnesserr( + pass, b, + errors, + func(v ssa.Value) bool { + return nilnessOf(stack, v) == isnil + }) + + // For nil comparison blocks, report an error if the condition + // is degenerate, and push a nilness fact on the stack when + // visiting its true and false successor blocks. + if binop, tsucc, fsucc := eq(b); binop != nil { + // extract the err != nil or err == nil + errValue := extractCheckedErrorValue(binop) + + xnil := nilnessOf(stack, binop.X) + ynil := nilnessOf(stack, binop.Y) + + if ynil != unknown && xnil != unknown && (xnil == isnil || ynil == isnil) { + // Degenerate condition: + // the nilness of both operands is known, + // and at least one of them is nil. + + // If tsucc's or fsucc's sole incoming edge is impossible, + // it is unreachable. Prune traversal of it and + // all the blocks it dominates. + // (We could be more precise with full dataflow + // analysis of control-flow joins.) + var skip *ssa.BasicBlock + if xnil == ynil { + skip = fsucc + } else { + skip = tsucc + } + for _, d := range b.Dominees() { + if d == skip && len(d.Preds) == 1 { + continue + } + + visit(d, stack, errors) + } + + return + } + + // "if x == nil" or "if nil == y" condition; x, y are unknown. + if xnil == isnil || ynil == isnil { + var newFacts facts + if xnil == isnil { + // x is nil, y is unknown: + // t successor learns y is nil. + newFacts = expandFacts(fact{binop.Y, isnil}) + } else { + // y is nil, x is unknown: + // t successor learns x is nil. + newFacts = expandFacts(fact{binop.X, isnil}) + } + + for _, d := range b.Dominees() { + // Successor blocks learn a fact + // only at non-critical edges. + // (We could do be more precise with full dataflow + // analysis of control-flow joins.) + s := stack + errs := errors + if len(d.Preds) == 1 { + if d == tsucc { + s = append(s, newFacts...) + // add nil error + if errValue != nil { + errs = append(errs, errFact{value: errValue, nilness: isnil}) + } + } else if d == fsucc { + s = append(s, newFacts.negate()...) + // add non-nil error + if errValue != nil { + errs = append(errs, errFact{value: errValue, nilness: isnonnil}) + } + } + } + + visit(d, s, errs) + } + return + } + } + + // In code of the form: + // + // if ptr, ok := x.(*T); ok { ... } else { fsucc } + // + // the fsucc block learns that ptr == nil, + // since that's its zero value. + if If, ok := b.Instrs[len(b.Instrs)-1].(*ssa.If); ok { + // Handle "if ok" and "if !ok" variants. + cond, fsucc := If.Cond, b.Succs[1] + if unop, ok := cond.(*ssa.UnOp); ok && unop.Op == token.NOT { + cond, fsucc = unop.X, b.Succs[0] + } + + // Match pattern: + // t0 = typeassert (pointerlike) + // t1 = extract t0 #0 // ptr + // t2 = extract t0 #1 // ok + // if t2 goto tsucc, fsucc + if extract1, ok := cond.(*ssa.Extract); ok && extract1.Index == 1 { + if assert, ok := extract1.Tuple.(*ssa.TypeAssert); ok && + isNillable(assert.AssertedType) { + for _, pinstr := range *assert.Referrers() { + if extract0, ok := pinstr.(*ssa.Extract); ok && + extract0.Index == 0 && + extract0.Tuple == extract1.Tuple { + for _, d := range b.Dominees() { + if len(d.Preds) == 1 && d == fsucc { + visit(d, append(stack, fact{extract0, isnil}), errors) + } + } + } + } + } + } + } + + for _, d := range b.Dominees() { + visit(d, stack, errors) + } + } + + // Visit the entry block. No need to visit fn.Recover. + if fn.Blocks != nil { + visit(fn.Blocks[0], make([]fact, 0, 20), nil) // 20 is plenty + } +} + +// A fact records that a block is dominated +// by the condition v == nil or v != nil. +type fact struct { + value ssa.Value + nilness nilness +} + +func (f fact) negate() fact { return fact{f.value, -f.nilness} } + +type nilness int + +const ( + isnonnil = -1 + unknown nilness = 0 + isnil = 1 +) + +var nilnessStrings = []string{"non-nil", "unknown", "nil"} + +func (n nilness) String() string { return nilnessStrings[n+1] } + +// nilnessOf reports whether v is definitely nil, definitely not nil, +// or unknown given the dominating stack of facts. +func nilnessOf(stack []fact, v ssa.Value) nilness { + switch v := v.(type) { + // unwrap ChangeInterface and Slice values recursively, to detect if underlying + // values have any facts recorded or are otherwise known with regard to nilness. + // + // This work must be in addition to expanding facts about + // ChangeInterfaces during inference/fact gathering because this covers + // cases where the nilness of a value is intrinsic, rather than based + // on inferred facts, such as a zero value interface variable. That + // said, this work alone would only inform us when facts are about + // underlying values, rather than outer values, when the analysis is + // transitive in both directions. + case *ssa.ChangeInterface: + if underlying := nilnessOf(stack, v.X); underlying != unknown { + return underlying + } + case *ssa.MakeInterface: + // A MakeInterface is non-nil unless its operand is a type parameter. + tparam, ok := types.Unalias(v.X.Type()).(*types.TypeParam) + if !ok { + return isnonnil + } + + // A MakeInterface of a type parameter is non-nil if + // the type parameter cannot be instantiated as an + // interface type (#66835). + if terms, err := typeparams.NormalTerms(tparam.Constraint()); err == nil && len(terms) > 0 { + return isnonnil + } + + // If the type parameter can be instantiated as an + // interface (and thus also as a concrete type), + // we can't determine the nilness. + + case *ssa.Slice: + if underlying := nilnessOf(stack, v.X); underlying != unknown { + return underlying + } + case *ssa.SliceToArrayPointer: + nn := nilnessOf(stack, v.X) + if slice2ArrayPtrLen(v) > 0 { + if nn == isnil { + // We know that *(*[1]byte)(nil) is going to panic because of the + // conversion. So return unknown to the caller, prevent useless + // nil deference reporting due to * operator. + return unknown + } + // Otherwise, the conversion will yield a non-nil pointer to array. + // Note that the instruction can still panic if array length greater + // than slice length. If the value is used by another instruction, + // that instruction can assume the panic did not happen when that + // instruction is reached. + return isnonnil + } + // In case array length is zero, the conversion result depends on nilness of the slice. + if nn != unknown { + return nn + } + } + + // Is value intrinsically nil or non-nil? + switch v := v.(type) { + case *ssa.Alloc, + *ssa.FieldAddr, + *ssa.FreeVar, + *ssa.Function, + *ssa.Global, + *ssa.IndexAddr, + *ssa.MakeChan, + *ssa.MakeClosure, + *ssa.MakeMap, + *ssa.MakeSlice: + return isnonnil + + case *ssa.Const: + if v.IsNil() { + return isnil // nil or zero value of a pointer-like type + } else { + return unknown // non-pointer + } + } + + // Search dominating control-flow facts. + for _, f := range stack { + if f.value == v { + return f.nilness + } + } + return unknown +} + +func slice2ArrayPtrLen(v *ssa.SliceToArrayPointer) int64 { + return v.Type().(*types.Pointer).Elem().Underlying().(*types.Array).Len() +} + +// If b ends with an equality comparison, eq returns the operation and +// its true (equal) and false (not equal) successors. +func eq(b *ssa.BasicBlock) (op *ssa.BinOp, tsucc, fsucc *ssa.BasicBlock) { + if If, ok := b.Instrs[len(b.Instrs)-1].(*ssa.If); ok { + if binop, ok := If.Cond.(*ssa.BinOp); ok { + switch binop.Op { + case token.EQL: + return binop, b.Succs[0], b.Succs[1] + case token.NEQ: + return binop, b.Succs[1], b.Succs[0] + } + } + } + return nil, nil, nil +} + +// expandFacts takes a single fact and returns the set of facts that can be +// known about it or any of its related values. Some operations, like +// ChangeInterface, have transitive nilness, such that if you know the +// underlying value is nil, you also know the value itself is nil, and vice +// versa. This operation allows callers to match on any of the related values +// in analyses, rather than just the one form of the value that happened to +// appear in a comparison. +// +// This work must be in addition to unwrapping values within nilnessOf because +// while this work helps give facts about transitively known values based on +// inferred facts, the recursive check within nilnessOf covers cases where +// nilness facts are intrinsic to the underlying value, such as a zero value +// interface variables. +// +// ChangeInterface is the only expansion currently supported, but others, like +// Slice, could be added. At this time, this tool does not check slice +// operations in a way this expansion could help. See +// https://play.golang.org/p/mGqXEp7w4fR for an example. +func expandFacts(f fact) []fact { + ff := []fact{f} + +Loop: + for { + switch v := f.value.(type) { + case *ssa.ChangeInterface: + f = fact{v.X, f.nilness} + ff = append(ff, f) + default: + break Loop + } + } + + return ff +} + +type facts []fact + +func (ff facts) negate() facts { + nn := make([]fact, len(ff)) + for i, f := range ff { + nn[i] = f.negate() + } + return nn +} + +func isNillable(t types.Type) bool { + // TODO(adonovan): CoreType (+ case *Interface) looks wrong. + // This should probably use Underlying, and handle TypeParam + // by computing the union across its normal terms. + switch t := typeparams.CoreType(t).(type) { + case *types.Pointer, + *types.Map, + *types.Signature, + *types.Chan, + *types.Interface, + *types.Slice: + return true + case *types.Basic: + return t == types.Typ[types.UnsafePointer] + } + return false +} diff --git a/vendor/github.com/ashanbrown/forbidigo/LICENSE b/vendor/github.com/ashanbrown/forbidigo/v2/LICENSE similarity index 100% rename from vendor/github.com/ashanbrown/forbidigo/LICENSE rename to vendor/github.com/ashanbrown/forbidigo/v2/LICENSE diff --git a/vendor/github.com/ashanbrown/forbidigo/forbidigo/config_options.go b/vendor/github.com/ashanbrown/forbidigo/v2/forbidigo/config_options.go similarity index 100% rename from vendor/github.com/ashanbrown/forbidigo/forbidigo/config_options.go rename to vendor/github.com/ashanbrown/forbidigo/v2/forbidigo/config_options.go diff --git a/vendor/github.com/ashanbrown/forbidigo/forbidigo/forbidigo.go b/vendor/github.com/ashanbrown/forbidigo/v2/forbidigo/forbidigo.go similarity index 94% rename from vendor/github.com/ashanbrown/forbidigo/forbidigo/forbidigo.go rename to vendor/github.com/ashanbrown/forbidigo/v2/forbidigo/forbidigo.go index a7a3ab591..913b45e95 100644 --- a/vendor/github.com/ashanbrown/forbidigo/forbidigo/forbidigo.go +++ b/vendor/github.com/ashanbrown/forbidigo/v2/forbidigo/forbidigo.go @@ -317,13 +317,15 @@ func (v *visitor) expandMatchText(node ast.Node, srcText string) (matchTexts []s // type. We don't care about the value. selectorText := v.textFor(node) if typeAndValue, ok := v.runConfig.TypesInfo.Types[selector]; ok { - m, p, ok := typeNameWithPackage(typeAndValue.Type) - if !ok { - v.runConfig.DebugLog("%s: selector %q with supported type %T", location, selectorText, typeAndValue.Type) + if typeName, pkgPath, ok := typeNameWithPackage(typeAndValue.Type); ok { + v.runConfig.DebugLog("%s: selector %q with supported type %q: %q -> %q, package %q", location, selectorText, typeAndValue.Type.String(), srcText, matchTexts, pkgPath) + matchTexts = []string{typeName + "." + field} + pkgText = pkgPath + } else { + // handle cases such as anonymous structs + v.runConfig.DebugLog("%s: selector %q with unknown type %T", location, selectorText, typeAndValue.Type) + matchTexts = []string{} } - matchTexts = []string{m + "." + field} - pkgText = p - v.runConfig.DebugLog("%s: selector %q with supported type %q: %q -> %q, package %q", location, selectorText, typeAndValue.Type.String(), srcText, matchTexts, pkgText) } // Some expressions need special treatment. switch selector := selector.(type) { @@ -340,7 +342,9 @@ func (v *visitor) expandMatchText(node ast.Node, srcText string) (matchTexts []s pkgText = packageName v.runConfig.DebugLog("%s: selector %q is variable of type %q: %q -> %q, package %q", location, selectorText, object.Type().String(), srcText, matchTexts, pkgText) } else { + // handle cases such as anonymous structs v.runConfig.DebugLog("%s: selector %q is variable with unsupported type %T", location, selectorText, object.Type()) + matchTexts = []string{} } default: // Something else? @@ -370,11 +374,14 @@ func typeNameWithPackage(t types.Type) (typeName, packagePath string, ok bool) { } switch t := t.(type) { + case *types.Alias: + return typeNameWithPackage(t.Rhs()) case *types.Named: obj := t.Obj() pkg := obj.Pkg() + // we either lack a package or the package is the "universe" (i.e. builtin) if pkg == nil { - return "", "", false + return obj.Name(), "", true } return pkg.Name() + "." + obj.Name(), pkg.Path(), true default: diff --git a/vendor/github.com/ashanbrown/forbidigo/forbidigo/patterns.go b/vendor/github.com/ashanbrown/forbidigo/v2/forbidigo/patterns.go similarity index 79% rename from vendor/github.com/ashanbrown/forbidigo/forbidigo/patterns.go rename to vendor/github.com/ashanbrown/forbidigo/v2/forbidigo/patterns.go index 2692dcd24..5f05cec94 100644 --- a/vendor/github.com/ashanbrown/forbidigo/forbidigo/patterns.go +++ b/vendor/github.com/ashanbrown/forbidigo/v2/forbidigo/patterns.go @@ -1,12 +1,14 @@ package forbidigo import ( + "bytes" "fmt" + "io" "regexp" "regexp/syntax" "strings" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" ) // pattern matches code that is not supposed to be used. @@ -33,15 +35,15 @@ type pattern struct { // patterns). type yamlPattern pattern -func (p *yamlPattern) UnmarshalYAML(unmarshal func(interface{}) error) error { +func (p *yamlPattern) UnmarshalYAML(value *yaml.Node) error { // Try struct first. It's unlikely that a regular expression string // is valid YAML for a struct. var ptrn pattern - if err := unmarshal(&ptrn); err != nil { + if err := unmarshalStrict(&ptrn, value); err != nil && err != io.EOF { errStr := err.Error() // Didn't work, try plain string. var ptrn string - if err := unmarshal(&ptrn); err != nil { + if err := unmarshalStrict(&ptrn, value); err != nil && err != io.EOF { return fmt.Errorf("pattern is neither a regular expression string (%s) nor a Pattern struct (%s)", err.Error(), errStr) } p.Pattern = ptrn @@ -51,6 +53,20 @@ func (p *yamlPattern) UnmarshalYAML(unmarshal func(interface{}) error) error { return ((*pattern)(p)).validate() } +// unmarshalStrict implements missing yaml.UnmarshalStrict in gopkg.in/yaml.v3. +// See https://github.com/go-yaml/yaml/issues/639. +// Inspired by https://github.com/ffenix113/zigbee_home/pull/68 +func unmarshalStrict(to any, node *yaml.Node) error { + buf := &bytes.Buffer{} + if err := yaml.NewEncoder(buf).Encode(node); err != nil { + return err + } + + decoder := yaml.NewDecoder(buf) + decoder.KnownFields(true) + return decoder.Decode(to) +} + var _ yaml.Unmarshaler = &yamlPattern{} // parse accepts a regular expression or, if the string starts with { or contains a line break, a @@ -61,7 +77,9 @@ func parse(ptrn string) (*pattern, error) { if strings.HasPrefix(strings.TrimSpace(ptrn), "{") || strings.Contains(ptrn, "\n") { // Embedded JSON or YAML. We can decode both with the YAML decoder. - if err := yaml.UnmarshalStrict([]byte(ptrn), pattern); err != nil { + decoder := yaml.NewDecoder(strings.NewReader(ptrn)) + decoder.KnownFields(true) + if err := decoder.Decode(pattern); err != nil && err != io.EOF { return nil, fmt.Errorf("parsing as JSON or YAML failed: %v", err) } } else { diff --git a/vendor/github.com/ashanbrown/makezero/LICENSE b/vendor/github.com/ashanbrown/makezero/v2/LICENSE similarity index 100% rename from vendor/github.com/ashanbrown/makezero/LICENSE rename to vendor/github.com/ashanbrown/makezero/v2/LICENSE diff --git a/vendor/github.com/ashanbrown/makezero/makezero/makezero.go b/vendor/github.com/ashanbrown/makezero/v2/makezero/makezero.go similarity index 100% rename from vendor/github.com/ashanbrown/makezero/makezero/makezero.go rename to vendor/github.com/ashanbrown/makezero/v2/makezero/makezero.go diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/go_module_metadata.go index b72921f87..1820ff0fb 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/go_module_metadata.go @@ -3,4 +3,4 @@ package aws // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.38.3" +const goModuleVersion = "1.39.2" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/user_agent.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/user_agent.go index 6ee3391be..3314230fd 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/user_agent.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/user_agent.go @@ -135,6 +135,8 @@ const ( UserAgentFeatureCredentialsAwsSdkStore = "y" // n/a (this is used by .NET based sdk) UserAgentFeatureCredentialsHTTP = "z" UserAgentFeatureCredentialsIMDS = "0" + + UserAgentFeatureBearerServiceEnvVars = "3" ) var credentialSourceToFeature = map[aws.CredentialSource]UserAgentFeature{ diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/partitions.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/partitions.go index d4e6611f7..6ad5df646 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/partitions.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/partitions.go @@ -3,7 +3,8 @@ package awsrulesfn // GetPartition returns an AWS [Partition] for the region provided. If the -// partition cannot be determined nil will be returned. +// partition cannot be determined then the default partition (AWS commercial) +// will be returned. func GetPartition(region string) *PartitionConfig { return getPartition(partitions, region) } @@ -332,7 +333,7 @@ var partitions = []Partition{ DnsSuffix: "c2s.ic.gov", DualStackDnsSuffix: "api.aws.ic.gov", SupportsFIPS: true, - SupportsDualStack: false, + SupportsDualStack: true, ImplicitGlobalRegion: "us-iso-east-1", }, Regions: map[string]RegionOverrides{ @@ -367,7 +368,7 @@ var partitions = []Partition{ DnsSuffix: "sc2s.sgov.gov", DualStackDnsSuffix: "api.aws.scloud", SupportsFIPS: true, - SupportsDualStack: false, + SupportsDualStack: true, ImplicitGlobalRegion: "us-isob-east-1", }, Regions: map[string]RegionOverrides{ @@ -395,7 +396,7 @@ var partitions = []Partition{ DnsSuffix: "cloud.adc-e.uk", DualStackDnsSuffix: "api.cloud-aws.adc-e.uk", SupportsFIPS: true, - SupportsDualStack: false, + SupportsDualStack: true, ImplicitGlobalRegion: "eu-isoe-west-1", }, Regions: map[string]RegionOverrides{ @@ -423,7 +424,7 @@ var partitions = []Partition{ DnsSuffix: "csp.hci.ic.gov", DualStackDnsSuffix: "api.aws.hci.ic.gov", SupportsFIPS: true, - SupportsDualStack: false, + SupportsDualStack: true, ImplicitGlobalRegion: "us-isof-south-1", }, Regions: map[string]RegionOverrides{ diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/partitions.json b/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/partitions.json index c6582c9c6..b346b0be9 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/partitions.json +++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/partitions.json @@ -162,7 +162,7 @@ "dualStackDnsSuffix" : "api.aws.ic.gov", "implicitGlobalRegion" : "us-iso-east-1", "name" : "aws-iso", - "supportsDualStack" : false, + "supportsDualStack" : true, "supportsFIPS" : true }, "regionRegex" : "^us\\-iso\\-\\w+\\-\\d+$", @@ -184,7 +184,7 @@ "dualStackDnsSuffix" : "api.aws.scloud", "implicitGlobalRegion" : "us-isob-east-1", "name" : "aws-iso-b", - "supportsDualStack" : false, + "supportsDualStack" : true, "supportsFIPS" : true }, "regionRegex" : "^us\\-isob\\-\\w+\\-\\d+$", @@ -203,7 +203,7 @@ "dualStackDnsSuffix" : "api.cloud-aws.adc-e.uk", "implicitGlobalRegion" : "eu-isoe-west-1", "name" : "aws-iso-e", - "supportsDualStack" : false, + "supportsDualStack" : true, "supportsFIPS" : true }, "regionRegex" : "^eu\\-isoe\\-\\w+\\-\\d+$", @@ -222,7 +222,7 @@ "dualStackDnsSuffix" : "api.aws.hci.ic.gov", "implicitGlobalRegion" : "us-isof-south-1", "name" : "aws-iso-f", - "supportsDualStack" : false, + "supportsDualStack" : true, "supportsFIPS" : true }, "regionRegex" : "^us\\-isof\\-\\w+\\-\\d+$", diff --git a/vendor/github.com/aymanbagabas/go-osc52/v2/LICENSE b/vendor/github.com/aymanbagabas/go-osc52/v2/LICENSE new file mode 100644 index 000000000..25cec1ed4 --- /dev/null +++ b/vendor/github.com/aymanbagabas/go-osc52/v2/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Ayman Bagabas + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/aymanbagabas/go-osc52/v2/README.md b/vendor/github.com/aymanbagabas/go-osc52/v2/README.md new file mode 100644 index 000000000..4de3a22d1 --- /dev/null +++ b/vendor/github.com/aymanbagabas/go-osc52/v2/README.md @@ -0,0 +1,83 @@ + +# go-osc52 + +

+ Latest Release + GoDoc +

+ +A Go library to work with the [ANSI OSC52](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands) terminal sequence. + +## Usage + +You can use this small library to construct an ANSI OSC52 sequence suitable for +your terminal. + + +### Example + +```go +import ( + "os" + "fmt" + + "github.com/aymanbagabas/go-osc52/v2" +) + +func main() { + s := "Hello World!" + + // Copy `s` to system clipboard + osc52.New(s).WriteTo(os.Stderr) + + // Copy `s` to primary clipboard (X11) + osc52.New(s).Primary().WriteTo(os.Stderr) + + // Query the clipboard + osc52.Query().WriteTo(os.Stderr) + + // Clear system clipboard + osc52.Clear().WriteTo(os.Stderr) + + // Use the fmt.Stringer interface to copy `s` to system clipboard + fmt.Fprint(os.Stderr, osc52.New(s)) + + // Or to primary clipboard + fmt.Fprint(os.Stderr, osc52.New(s).Primary()) +} +``` + +## SSH Example + +You can use this over SSH using [gliderlabs/ssh](https://github.com/gliderlabs/ssh) for instance: + +```go +var sshSession ssh.Session +seq := osc52.New("Hello awesome!") +// Check if term is screen or tmux +pty, _, _ := s.Pty() +if pty.Term == "screen" { + seq = seq.Screen() +} else if isTmux { + seq = seq.Tmux() +} +seq.WriteTo(sshSession.Stderr()) +``` + +## Tmux + +Make sure you have `set-clipboard on` in your config, otherwise, tmux won't +allow your application to access the clipboard [^1]. + +Using the tmux option, `osc52.TmuxMode` or `osc52.New(...).Tmux()`, wraps the +OSC52 sequence in a special tmux DCS sequence and pass it to the outer +terminal. This requires `allow-passthrough on` in your config. +`allow-passthrough` is no longer enabled by default +[since tmux 3.3a](https://github.com/tmux/tmux/issues/3218#issuecomment-1153089282) [^2]. + +[^1]: See [tmux clipboard](https://github.com/tmux/tmux/wiki/Clipboard) +[^2]: [What is allow-passthrough](https://github.com/tmux/tmux/wiki/FAQ#what-is-the-passthrough-escape-sequence-and-how-do-i-use-it) + +## Credits + +* [vim-oscyank](https://github.com/ojroques/vim-oscyank) this is heavily inspired by vim-oscyank. diff --git a/vendor/github.com/aymanbagabas/go-osc52/v2/osc52.go b/vendor/github.com/aymanbagabas/go-osc52/v2/osc52.go new file mode 100644 index 000000000..dc758d286 --- /dev/null +++ b/vendor/github.com/aymanbagabas/go-osc52/v2/osc52.go @@ -0,0 +1,305 @@ +// OSC52 is a terminal escape sequence that allows copying text to the clipboard. +// +// The sequence consists of the following: +// +// OSC 52 ; Pc ; Pd BEL +// +// Pc is the clipboard choice: +// +// c: clipboard +// p: primary +// q: secondary (not supported) +// s: select (not supported) +// 0-7: cut-buffers (not supported) +// +// Pd is the data to copy to the clipboard. This string should be encoded in +// base64 (RFC-4648). +// +// If Pd is "?", the terminal replies to the host with the current contents of +// the clipboard. +// +// If Pd is neither a base64 string nor "?", the terminal clears the clipboard. +// +// See https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands +// where Ps = 52 => Manipulate Selection Data. +// +// Examples: +// +// // copy "hello world" to the system clipboard +// fmt.Fprint(os.Stderr, osc52.New("hello world")) +// +// // copy "hello world" to the primary Clipboard +// fmt.Fprint(os.Stderr, osc52.New("hello world").Primary()) +// +// // limit the size of the string to copy 10 bytes +// fmt.Fprint(os.Stderr, osc52.New("0123456789").Limit(10)) +// +// // escape the OSC52 sequence for screen using DCS sequences +// fmt.Fprint(os.Stderr, osc52.New("hello world").Screen()) +// +// // escape the OSC52 sequence for Tmux +// fmt.Fprint(os.Stderr, osc52.New("hello world").Tmux()) +// +// // query the system Clipboard +// fmt.Fprint(os.Stderr, osc52.Query()) +// +// // query the primary clipboard +// fmt.Fprint(os.Stderr, osc52.Query().Primary()) +// +// // clear the system Clipboard +// fmt.Fprint(os.Stderr, osc52.Clear()) +// +// // clear the primary Clipboard +// fmt.Fprint(os.Stderr, osc52.Clear().Primary()) +package osc52 + +import ( + "encoding/base64" + "fmt" + "io" + "strings" +) + +// Clipboard is the clipboard buffer to use. +type Clipboard rune + +const ( + // SystemClipboard is the system clipboard buffer. + SystemClipboard Clipboard = 'c' + // PrimaryClipboard is the primary clipboard buffer (X11). + PrimaryClipboard = 'p' +) + +// Mode is the mode to use for the OSC52 sequence. +type Mode uint + +const ( + // DefaultMode is the default OSC52 sequence mode. + DefaultMode Mode = iota + // ScreenMode escapes the OSC52 sequence for screen using DCS sequences. + ScreenMode + // TmuxMode escapes the OSC52 sequence for tmux. Not needed if tmux + // clipboard is set to `set-clipboard on` + TmuxMode +) + +// Operation is the OSC52 operation. +type Operation uint + +const ( + // SetOperation is the copy operation. + SetOperation Operation = iota + // QueryOperation is the query operation. + QueryOperation + // ClearOperation is the clear operation. + ClearOperation +) + +// Sequence is the OSC52 sequence. +type Sequence struct { + str string + limit int + op Operation + mode Mode + clipboard Clipboard +} + +var _ fmt.Stringer = Sequence{} + +var _ io.WriterTo = Sequence{} + +// String returns the OSC52 sequence. +func (s Sequence) String() string { + var seq strings.Builder + // mode escape sequences start + seq.WriteString(s.seqStart()) + // actual OSC52 sequence start + seq.WriteString(fmt.Sprintf("\x1b]52;%c;", s.clipboard)) + switch s.op { + case SetOperation: + str := s.str + if s.limit > 0 && len(str) > s.limit { + return "" + } + b64 := base64.StdEncoding.EncodeToString([]byte(str)) + switch s.mode { + case ScreenMode: + // Screen doesn't support OSC52 but will pass the contents of a DCS + // sequence to the outer terminal unchanged. + // + // Here, we split the encoded string into 76 bytes chunks and then + // join the chunks with sequences. Finally, + // wrap the whole thing in + // . + // s := strings.SplitN(b64, "", 76) + s := make([]string, 0, len(b64)/76+1) + for i := 0; i < len(b64); i += 76 { + end := i + 76 + if end > len(b64) { + end = len(b64) + } + s = append(s, b64[i:end]) + } + seq.WriteString(strings.Join(s, "\x1b\\\x1bP")) + default: + seq.WriteString(b64) + } + case QueryOperation: + // OSC52 queries the clipboard using "?" + seq.WriteString("?") + case ClearOperation: + // OSC52 clears the clipboard if the data is neither a base64 string nor "?" + // we're using "!" as a default + seq.WriteString("!") + } + // actual OSC52 sequence end + seq.WriteString("\x07") + // mode escape end + seq.WriteString(s.seqEnd()) + return seq.String() +} + +// WriteTo writes the OSC52 sequence to the writer. +func (s Sequence) WriteTo(out io.Writer) (int64, error) { + n, err := out.Write([]byte(s.String())) + return int64(n), err +} + +// Mode sets the mode for the OSC52 sequence. +func (s Sequence) Mode(m Mode) Sequence { + s.mode = m + return s +} + +// Tmux sets the mode to TmuxMode. +// Used to escape the OSC52 sequence for `tmux`. +// +// Note: this is not needed if tmux clipboard is set to `set-clipboard on`. If +// TmuxMode is used, tmux must have `allow-passthrough on` set. +// +// This is a syntactic sugar for s.Mode(TmuxMode). +func (s Sequence) Tmux() Sequence { + return s.Mode(TmuxMode) +} + +// Screen sets the mode to ScreenMode. +// Used to escape the OSC52 sequence for `screen`. +// +// This is a syntactic sugar for s.Mode(ScreenMode). +func (s Sequence) Screen() Sequence { + return s.Mode(ScreenMode) +} + +// Clipboard sets the clipboard buffer for the OSC52 sequence. +func (s Sequence) Clipboard(c Clipboard) Sequence { + s.clipboard = c + return s +} + +// Primary sets the clipboard buffer to PrimaryClipboard. +// This is the X11 primary clipboard. +// +// This is a syntactic sugar for s.Clipboard(PrimaryClipboard). +func (s Sequence) Primary() Sequence { + return s.Clipboard(PrimaryClipboard) +} + +// Limit sets the limit for the OSC52 sequence. +// The default limit is 0 (no limit). +// +// Strings longer than the limit get ignored. Settting the limit to 0 or a +// negative value disables the limit. Each terminal defines its own escapse +// sequence limit. +func (s Sequence) Limit(l int) Sequence { + if l < 0 { + s.limit = 0 + } else { + s.limit = l + } + return s +} + +// Operation sets the operation for the OSC52 sequence. +// The default operation is SetOperation. +func (s Sequence) Operation(o Operation) Sequence { + s.op = o + return s +} + +// Clear sets the operation to ClearOperation. +// This clears the clipboard. +// +// This is a syntactic sugar for s.Operation(ClearOperation). +func (s Sequence) Clear() Sequence { + return s.Operation(ClearOperation) +} + +// Query sets the operation to QueryOperation. +// This queries the clipboard contents. +// +// This is a syntactic sugar for s.Operation(QueryOperation). +func (s Sequence) Query() Sequence { + return s.Operation(QueryOperation) +} + +// SetString sets the string for the OSC52 sequence. Strings are joined with a +// space character. +func (s Sequence) SetString(strs ...string) Sequence { + s.str = strings.Join(strs, " ") + return s +} + +// New creates a new OSC52 sequence with the given string(s). Strings are +// joined with a space character. +func New(strs ...string) Sequence { + s := Sequence{ + str: strings.Join(strs, " "), + limit: 0, + mode: DefaultMode, + clipboard: SystemClipboard, + op: SetOperation, + } + return s +} + +// Query creates a new OSC52 sequence with the QueryOperation. +// This returns a new OSC52 sequence to query the clipboard contents. +// +// This is a syntactic sugar for New().Query(). +func Query() Sequence { + return New().Query() +} + +// Clear creates a new OSC52 sequence with the ClearOperation. +// This returns a new OSC52 sequence to clear the clipboard. +// +// This is a syntactic sugar for New().Clear(). +func Clear() Sequence { + return New().Clear() +} + +func (s Sequence) seqStart() string { + switch s.mode { + case TmuxMode: + // Write the start of a tmux escape sequence. + return "\x1bPtmux;\x1b" + case ScreenMode: + // Write the start of a DCS sequence. + return "\x1bP" + default: + return "" + } +} + +func (s Sequence) seqEnd() string { + switch s.mode { + case TmuxMode: + // Terminate the tmux escape sequence. + return "\x1b\\" + case ScreenMode: + // Write the end of a DCS sequence. + return "\x1b\x5c" + default: + return "" + } +} diff --git a/vendor/github.com/bombsimon/wsl/v4/.golangci.yml b/vendor/github.com/bombsimon/wsl/v4/.golangci.yml index bde0ae54e..f4948e053 100644 --- a/vendor/github.com/bombsimon/wsl/v4/.golangci.yml +++ b/vendor/github.com/bombsimon/wsl/v4/.golangci.yml @@ -1,80 +1,79 @@ --- -run: - timeout: 1m - issues-exit-code: 1 - tests: true +version: "2" output: - print-issued-lines: false - sort-results: true formats: - - format: colored-line-number - -linters-settings: - gocognit: - min-complexity: 10 - - depguard: - rules: - main: - deny: - - pkg: "github.com/davecgh/go-spew/spew" - desc: not allowed - - misspell: - locale: US - - gocritic: - # Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` - # to see all tags and checks. Empty list by default. See - # https://github.com/go-critic/go-critic#usage -> section "Tags". - enabled-tags: - - diagnostic - - experimental - - opinionated - - performance - - style + text: + path: stdout + print-issued-lines: false linters: - enable-all: true + default: all disable: - cyclop - - deadcode - depguard - dupl - dupword - - exhaustivestruct - exhaustruct - forbidigo - funlen - - gci - gocognit - gocyclo - godox - - golint - - gomnd - - ifshort - - interfacer - lll - maintidx - - maligned + - mnd - nakedret - nestif - nlreturn - - nosnakecase - paralleltest - prealloc - rowserrcheck - - scopelint - - structcheck - testpackage - - varcheck + - tparallel - varnamelen - wastedassign + settings: + depguard: + rules: + main: + deny: + - pkg: github.com/davecgh/go-spew/spew + desc: not allowed + gocognit: + min-complexity: 10 + gocritic: + # Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` + # to see all tags and checks. Empty list by default. See + # https://github.com/go-critic/go-critic#usage -> section "Tags". + enabled-tags: + - diagnostic + - experimental + - opinionated + - performance + - style + misspell: + locale: US + + exclusions: + presets: + - comments + - common-false-positives + - std-error-handling + issues: - exclude-use-default: true max-issues-per-linter: 0 max-same-issues: 0 +formatters: + enable: + - gofmt + - gofumpt + - goimports + settings: + gofmt: + rewrite-rules: + - pattern: 'interface{}' + replacement: 'any' # vim: set sw=2 ts=2 et: diff --git a/vendor/github.com/bombsimon/wsl/v4/README.md b/vendor/github.com/bombsimon/wsl/v4/README.md index c9c42341e..e98fe1b4a 100644 --- a/vendor/github.com/bombsimon/wsl/v4/README.md +++ b/vendor/github.com/bombsimon/wsl/v4/README.md @@ -28,11 +28,6 @@ go install github.com/bombsimon/wsl/v4/cmd/wsl@master ## Usage -> **Note**: This linter provides a fixer that can fix most issues with the -> `--fix` flag. However, currently `golangci-lint` [does not support suggested -> fixes](https://github.com/golangci/golangci-lint/issues/1779) so the `--fix` -> flag in `golangci-lint` will **not** work. - `wsl` uses the [analysis](https://pkg.go.dev/golang.org/x/tools/go/analysis) package meaning it will operate on package level with the default analysis flags and way of working. @@ -47,9 +42,12 @@ wsl --allow-cuddle-declarations --fix ./... `wsl` is also integrated in [`golangci-lint`](https://golangci-lint.run) ```sh -golangci-lint run --no-config --disable-all --enable wsl +golangci-lint run --no-config --disable-all --enable wsl --fix ``` +> **Note**: If you're not sure what the diagnostic is trying to tell you, use +> any of the fix approaches to fix the code for you. + ## Issues and configuration The linter suppers a few ways to configure it to satisfy more than one kind of @@ -62,10 +60,6 @@ documentation](doc/configuration.md). Below are the available checklist for any hit from `wsl`. If you do not see any, feel free to raise an [issue](https://github.com/bombsimon/wsl/issues/new). -> **Note**: this linter doesn't take in consideration the issues that will be -> fixed with `go fmt -s` so ensure that the code is properly formatted before -> use. - * [Anonymous switch statements should never be cuddled](doc/rules.md#anonymous-switch-statements-should-never-be-cuddled) * [Append only allowed to cuddle with appended value](doc/rules.md#append-only-allowed-to-cuddle-with-appended-value) * [Assignments should only be cuddled with other assignments](doc/rules.md#assignments-should-only-be-cuddled-with-other-assignments) diff --git a/vendor/github.com/bombsimon/wsl/v4/analyzer.go b/vendor/github.com/bombsimon/wsl/v4/analyzer.go index 46d5019a7..12adbfa7a 100644 --- a/vendor/github.com/bombsimon/wsl/v4/analyzer.go +++ b/vendor/github.com/bombsimon/wsl/v4/analyzer.go @@ -3,6 +3,7 @@ package wsl import ( "flag" "go/ast" + "go/token" "strings" "golang.org/x/tools/go/analysis" @@ -36,6 +37,7 @@ func defaultConfig() *Configuration { AllowCuddleWithRHS: []string{"Unlock", "RUnlock"}, ErrorVariableNames: []string{"err"}, ForceCaseTrailingWhitespaceLimit: 0, + AllowCuddleUsedInBlock: false, } } @@ -67,6 +69,7 @@ func (wa *wslAnalyzer) flags() flag.FlagSet { flags.BoolVar(&wa.config.ForceExclusiveShortDeclarations, "force-short-decl-cuddling", false, "Force short declarations to cuddle by themselves") flags.BoolVar(&wa.config.StrictAppend, "strict-append", true, "Strict rules for append") flags.BoolVar(&wa.config.IncludeGenerated, "include-generated", false, "Include generated files") + flags.BoolVar(&wa.config.AllowCuddleUsedInBlock, "allow-cuddle-used-in-block", false, "Allow cuddling of variables used in block statements") flags.IntVar(&wa.config.ForceCaseTrailingWhitespaceLimit, "force-case-trailing-whitespace", 0, "Force newlines for case blocks > this number.") flags.Var(&multiStringValue{slicePtr: &wa.config.AllowCuddleWithCalls}, "allow-cuddle-with-calls", "Comma separated list of idents that can have cuddles after") @@ -76,14 +79,23 @@ func (wa *wslAnalyzer) flags() flag.FlagSet { return *flags } -func (wa *wslAnalyzer) run(pass *analysis.Pass) (interface{}, error) { +func (wa *wslAnalyzer) run(pass *analysis.Pass) (any, error) { for _, file := range pass.Files { - if !wa.config.IncludeGenerated && ast.IsGenerated(file) { + filename := getFilename(pass.Fset, file) + if !strings.HasSuffix(filename, ".go") { continue } - filename := pass.Fset.PositionFor(file.Pos(), false).Filename - if !strings.HasSuffix(filename, ".go") { + fn := pass.Fset.PositionFor(file.Pos(), false).Filename + + // if the file is related to cgo the filename of the unadjusted position is a not a '.go' file. + if !strings.HasSuffix(fn, ".go") { + continue + } + + // The file is skipped if the "unadjusted" file is a Go file, and it's a generated file (ex: "_test.go" file). + // The other non-Go files are skipped by the first 'if' with the adjusted position. + if !wa.config.IncludeGenerated && ast.IsGenerated(file) && strings.HasSuffix(fn, ".go") { continue } @@ -127,7 +139,7 @@ type multiStringValue struct { // Set implements the flag.Value interface and will overwrite the pointer to the // slice with a new pointer after splitting the flag by comma. func (m *multiStringValue) Set(value string) error { - s := []string{} + var s []string for _, v := range strings.Split(value, ",") { s = append(s, strings.TrimSpace(v)) @@ -146,3 +158,12 @@ func (m *multiStringValue) String() string { return strings.Join(*m.slicePtr, ", ") } + +func getFilename(fset *token.FileSet, file *ast.File) string { + filename := fset.PositionFor(file.Pos(), true).Filename + if !strings.HasSuffix(filename, ".go") { + return fset.PositionFor(file.Pos(), false).Filename + } + + return filename +} diff --git a/vendor/github.com/bombsimon/wsl/v4/wsl.go b/vendor/github.com/bombsimon/wsl/v4/wsl.go index 76f4abf61..88693f546 100644 --- a/vendor/github.com/bombsimon/wsl/v4/wsl.go +++ b/vendor/github.com/bombsimon/wsl/v4/wsl.go @@ -179,6 +179,18 @@ type Configuration struct { // errors even for generated files. Can be useful when developing // generators. IncludeGenerated bool + + // AllowCuddleUsedInBlock will allowing cuddling of variables with block statements + // if they are used anywhere in the block. This defaults to false but setting + // it to true will allow the following example: + // + // var numbers []int + // for i := 0; i < 10; i++ { + // if 1 == 1 { + // numbers = append(numbers, i) + // } + // } + AllowCuddleUsedInBlock bool } // fix is a range to fixup. @@ -304,12 +316,18 @@ func (p *processor) parseBlockStatements(statements []ast.Stmt) { } } - // We could potentially have a block which require us to check the first - // argument before ruling out an allowed cuddle. - var calledOrAssignedFirstInBlock []string + // Contains the union of all variable names used anywhere + // within the block body (if applicable) and is used to check + // if a preceding statement's variables are actually used within + // the block. This helps enforce rules about allowed cuddling. + var identifiersUsedInBlock []string if firstBodyStatement != nil { - calledOrAssignedFirstInBlock = append(p.findLHS(firstBodyStatement), p.findRHS(firstBodyStatement)...) + if p.config.AllowCuddleUsedInBlock { + identifiersUsedInBlock = p.findUsedVariablesInStatement(stmt) + } else { + identifiersUsedInBlock = append(p.findLHS(firstBodyStatement), p.findRHS(firstBodyStatement)...) + } } var ( @@ -353,7 +371,7 @@ func (p *processor) parseBlockStatements(statements []ast.Stmt) { return false } - for j := 0; j < n; j++ { + for j := range n { s1 := statements[i+j] s2 := statements[i+j+1] @@ -426,7 +444,7 @@ func (p *processor) parseBlockStatements(statements []ast.Stmt) { reportNewlineTwoLinesAbove := func(n1, n2 ast.Node, reason string) { if atLeastOneInListsMatch(rightAndLeftHandSide, assignedOnLineAbove) || - atLeastOneInListsMatch(assignedOnLineAbove, calledOrAssignedFirstInBlock) { + atLeastOneInListsMatch(assignedOnLineAbove, identifiersUsedInBlock) { // If both the assignment on the line above _and_ the assignment // two lines above is part of line or first in block, add the // newline as if non were. @@ -435,7 +453,7 @@ func (p *processor) parseBlockStatements(statements []ast.Stmt) { if isAssignmentTwoLinesAbove && (atLeastOneInListsMatch(rightAndLeftHandSide, assignedTwoLinesAbove) || - atLeastOneInListsMatch(assignedTwoLinesAbove, calledOrAssignedFirstInBlock)) { + atLeastOneInListsMatch(assignedTwoLinesAbove, identifiersUsedInBlock)) { p.addWhitespaceBeforeError(n1, reason) } else { // If the variable on the line above is allowed to be @@ -507,7 +525,7 @@ func (p *processor) parseBlockStatements(statements []ast.Stmt) { continue } - if atLeastOneInListsMatch(assignedOnLineAbove, calledOrAssignedFirstInBlock) { + if atLeastOneInListsMatch(assignedOnLineAbove, identifiersUsedInBlock) { continue } @@ -611,7 +629,7 @@ func (p *processor) parseBlockStatements(statements []ast.Stmt) { } if !atLeastOneInListsMatch(rightAndLeftHandSide, assignedOnLineAbove) { - if !atLeastOneInListsMatch(assignedOnLineAbove, calledOrAssignedFirstInBlock) { + if !atLeastOneInListsMatch(assignedOnLineAbove, identifiersUsedInBlock) { p.addWhitespaceBeforeError(t, reasonRangeCuddledWithoutUse) } } @@ -679,7 +697,7 @@ func (p *processor) parseBlockStatements(statements []ast.Stmt) { } } - if atLeastOneInListsMatch(assignedOnLineAbove, calledOrAssignedFirstInBlock) { + if atLeastOneInListsMatch(assignedOnLineAbove, identifiersUsedInBlock) { continue } @@ -687,7 +705,7 @@ func (p *processor) parseBlockStatements(statements []ast.Stmt) { p.addWhitespaceBeforeError(t, reasonDeferCuddledWithOtherVar) } case *ast.ForStmt: - if len(rightAndLeftHandSide) == 0 { + if len(rightAndLeftHandSide) == 0 && !p.config.AllowCuddleUsedInBlock { p.addWhitespaceBeforeError(t, reasonForWithoutCondition) continue } @@ -701,7 +719,7 @@ func (p *processor) parseBlockStatements(statements []ast.Stmt) { // comments regarding variable usages on the line before or as the // first line in the block for details. if !atLeastOneInListsMatch(rightAndLeftHandSide, assignedOnLineAbove) { - if !atLeastOneInListsMatch(assignedOnLineAbove, calledOrAssignedFirstInBlock) { + if !atLeastOneInListsMatch(assignedOnLineAbove, identifiersUsedInBlock) { p.addWhitespaceBeforeError(t, reasonForCuddledAssignWithoutUse) } } @@ -742,6 +760,10 @@ func (p *processor) parseBlockStatements(statements []ast.Stmt) { if !atLeastOneInListsMatch(rightAndLeftHandSide, assignedOnLineAbove) { if len(rightAndLeftHandSide) == 0 { + if p.config.AllowCuddleUsedInBlock { + continue + } + p.addWhitespaceBeforeError(t, reasonAnonSwitchCuddled) } else { p.addWhitespaceBeforeError(t, reasonSwitchCuddledWithoutUse) @@ -757,7 +779,7 @@ func (p *processor) parseBlockStatements(statements []ast.Stmt) { if !atLeastOneInListsMatch(rightHandSide, assignedOnLineAbove) { // Allow type assertion on variables used in the first case // immediately. - if !atLeastOneInListsMatch(assignedOnLineAbove, calledOrAssignedFirstInBlock) { + if !atLeastOneInListsMatch(assignedOnLineAbove, identifiersUsedInBlock) { p.addWhitespaceBeforeError(t, reasonTypeSwitchCuddledWithoutUse) } } @@ -839,6 +861,32 @@ func (p *processor) firstBodyStatement(i int, allStmt []ast.Stmt) ast.Node { return firstBodyStatement } +// findUsedVariablesInStatement processes a statement, +// returning a union of all variables used within it. +func (p *processor) findUsedVariablesInStatement(stmt ast.Stmt) []string { + var ( + used []string + seen = map[string]struct{}{} + ) + + // ast.Inspect walks the AST of the statement. + ast.Inspect(stmt, func(n ast.Node) bool { + // We're only interested in identifiers. + if ident, ok := n.(*ast.Ident); ok { + if _, exists := seen[ident.Name]; !exists { + seen[ident.Name] = struct{}{} + + used = append(used, ident.Name) + } + } + + // Continue walking the AST. + return true + }) + + return used +} + func (p *processor) findLHS(node ast.Node) []string { var lhs []string @@ -1030,7 +1078,7 @@ func (p *processor) findBlockStmt(node ast.Node) []*ast.BlockStmt { // Known fields with X that are handled: // IndexExpr, ExprStmt, SelectorExpr, StarExpr, ParentExpr, TypeAssertExpr, // RangeStmt, UnaryExpr, ParenExpr, SliceExpr, IncDecStmt. -func maybeX(node interface{}) (ast.Node, bool) { +func maybeX(node any) (ast.Node, bool) { maybeHasX := reflect.Indirect(reflect.ValueOf(node)).FieldByName("X") if !maybeHasX.IsValid() { return nil, false @@ -1113,8 +1161,8 @@ func (p *processor) findLeadingAndTrailingWhitespaces(ident *ast.Ident, stmt, ne return } - blockStartLine = p.fileSet.PositionFor(blockStartPos, false).Line - blockEndLine = p.fileSet.PositionFor(blockEndPos, false).Line + blockStartLine = p.fileSet.Position(blockStartPos).Line + blockEndLine = p.fileSet.Position(blockEndPos).Line // No whitespace possible if LBrace and RBrace is on the same line. if blockStartLine == blockEndLine { @@ -1362,14 +1410,14 @@ func isExampleFunc(ident *ast.Ident) bool { } func (p *processor) nodeStart(node ast.Node) int { - return p.fileSet.PositionFor(node.Pos(), false).Line + return p.fileSet.Position(node.Pos()).Line } func (p *processor) nodeEnd(node ast.Node) int { - line := p.fileSet.PositionFor(node.End(), false).Line + line := p.fileSet.Position(node.End()).Line if isEmptyLabeledStmt(node) { - return p.fileSet.PositionFor(node.Pos(), false).Line + return p.fileSet.Position(node.Pos()).Line } return line @@ -1407,8 +1455,8 @@ func (p *processor) addErrorRange(reportAt, start, end token.Pos, reason string) p.result[reportAt] = report } -func (p *processor) addWarning(w string, pos token.Pos, t interface{}) { - position := p.fileSet.PositionFor(pos, false) +func (p *processor) addWarning(w string, pos token.Pos, t any) { + position := p.fileSet.Position(pos) p.warnings = append(p.warnings, fmt.Sprintf("%s:%d: %s (%T)", position.Filename, position.Line, w, t), diff --git a/vendor/github.com/bombsimon/wsl/v5/.gitignore b/vendor/github.com/bombsimon/wsl/v5/.gitignore new file mode 100644 index 000000000..1c8eba613 --- /dev/null +++ b/vendor/github.com/bombsimon/wsl/v5/.gitignore @@ -0,0 +1,70 @@ + +# Created by https://www.gitignore.io/api/go,vim,macos + +### Go ### +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +### Go Patch ### +/vendor/ +/Godeps/ + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Vim ### +# Swap +[._]*.s[a-v][a-z] +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + + +# End of https://www.gitignore.io/api/go,vim,macos diff --git a/vendor/github.com/bombsimon/wsl/v5/.golangci.yml b/vendor/github.com/bombsimon/wsl/v5/.golangci.yml new file mode 100644 index 000000000..51b886463 --- /dev/null +++ b/vendor/github.com/bombsimon/wsl/v5/.golangci.yml @@ -0,0 +1,87 @@ +--- +version: "2" + +output: + formats: + text: + path: stdout + print-issued-lines: false + +linters: + default: all + disable: + - cyclop + - depguard + - dupl + - dupword + - err113 + - exhaustruct + - forbidigo + - funlen + - gocognit + - gocyclo + - godot + - godox + - lll + - maintidx + - mnd + - nakedret + - nestif + - nlreturn + - noinlineerr + - paralleltest + - prealloc + - rowserrcheck + - tagliatelle + - testpackage + - tparallel + - varnamelen + - wastedassign + - wsl + + settings: + depguard: + rules: + main: + deny: + - pkg: github.com/davecgh/go-spew/spew + desc: not allowed + gocognit: + min-complexity: 10 + gocritic: + # Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` + # to see all tags and checks. Empty list by default. See + # https://github.com/go-critic/go-critic#usage -> section "Tags". + enabled-tags: + - diagnostic + - experimental + - opinionated + - performance + - style + misspell: + locale: US + + exclusions: + presets: + - comments + - common-false-positives + - std-error-handling + rules: + - path: cmd/golangci-lint-migrate + linters: + - godoclint + +issues: + max-issues-per-linter: 0 + max-same-issues: 0 +formatters: + enable: + - gofmt + - gofumpt + - goimports + settings: + gofmt: + rewrite-rules: + - pattern: "interface{}" + replacement: "any" +# vim: set sw=2 ts=2 et: diff --git a/vendor/github.com/bombsimon/wsl/v5/CHECKS.md b/vendor/github.com/bombsimon/wsl/v5/CHECKS.md new file mode 100644 index 000000000..e9471b55e --- /dev/null +++ b/vendor/github.com/bombsimon/wsl/v5/CHECKS.md @@ -0,0 +1,1546 @@ +# Checks and configuration + +## Table of content + +- [Checks](#checks) + - [`after-block`](#after-block) + - [`append`](#append) + - [`assign`](#assign) + - [`assign-exclusive`](#assign-exclusive) + - [`assign-expr`](#assign-expr) + - [`branch`](#branch) + - [`decl`](#decl) + - [`defer`](#defer) + - [`err`](#err) + - [`expr`](#expr) + - [`for`](#for) + - [`go`](#go) + - [`if`](#if) + - [`inc-dec`](#inc-dec) + - [`label`](#label) + - [`leading-whitespace`](#leading-whitespace) + - [`range`](#range) + - [`return`](#return) + - [`select`](#select) + - [`send`](#send) + - [`switch`](#switch) + - [`trailing-whitespace`](#trailing-whitespace) + - [`type-switch`](#type-switch) +- [Configuration](#configuration) + - [`allow-first-in-block`](#allow-first-in-block) + - [`allow-whole-block`](#allow-whole-block) + - [`case-max-lines`](#case-max-lines) + +## Checks + +This document describes all the checks done by `wsl` with examples of what's not +allowed and what's allowed. + +### `after-block` + +Block statements (`if`, `for`, `switch`, etc.) should be followed by a blank +line to visually separate them from subsequent code. + +> **NOTE** An exception is made for `defer` statements that follow an +> `if err != nil` block when the defer references a variable assigned on the +> line above the if statement. This is a common pattern for resource cleanup. + + + + + + + +
BadGood
+ +```go +if true { + fmt.Println("hello") +} // 1 +fmt.Println("world") + +for i := 0; i < 3; i++ { + fmt.Println(i) +} // 2 +x := 1 +``` + + + +```go +if true { + fmt.Println("hello") +} + +fmt.Println("world") + +for i := 0; i < 3; i++ { + fmt.Println(i) +} + +x := 1 + +// Exception: defer after error check +f, err := os.Open("file.txt") +if err != nil { + return err +} +defer f.Close() +``` + +
+ +1 Missing whitespace after block + +2 Missing whitespace after block + + + +
+ +### `assign` + +Assign (`foo := bar`) or re-assignments (`foo = bar`) should only be cuddled +with other assignments or increment/decrement. + + + + + + + +
BadGood
+ +```go +if true { + fmt.Println("hello") +} +a := 1 // 1 + +defer func() { + fmt.Println("hello") +}() +a := 1 // 2 +``` + + + +```go +if true { + fmt.Println("hello") +} + +a := 1 + +defer func() { + fmt.Println("hello") +}() + +a := 1 + +a := 1 +b := 2 +c := 3 +``` + +
+ +1 Not an assign statement above + +2 Not an assign statement above + + + +
+ +### `branch` + +> Configurable via `branch-max-lines` + +Branch statement (`break`, `continue`, `fallthrough`, `goto`) should only be +cuddled if the block is less than `n` lines where `n` is the value of +`branch-max-statements`. + + + + + + + +
BadGood
+ +```go +for { + a, err : = SomeFn() + if err != nil { + return err + } + + fmt.Println(a) + break // 1 +} +``` + + + +```go +for { + a, err : = SomeFn() + if err != nil { + return err + } + + fmt.Println(a) + + break +} + +for { + fmt.Println("hello") + break +} +``` + +
+ +1 Block is more than 2 lines so should be a blank line above + + + +
+ +### `decl` + +Declarations should never be cuddled. When grouping multiple declarations +together they should be declared in the same group with parenthesis into a +single statement. The benefit of this is that it also aligns the declaration or +assignment increasing readability. + +> **NOTE** The fixer can't do smart adjustments if there are comments on the +> same line as the declaration. + + + + + + + +
BadGood
+ +```go +var a string +var b int // 1 + +const a = 1 +const b = 2 // 2 + +a := 1 +var b string // 3 + +fmt.Println("hello") +var a string // 4 +``` + + + +```go +var ( + a string + b int +) + +const ( + a = 1 + b = 2 +) + +a := 1 + +var b string + +fmt.Println("hello") + +var a string +``` + +
+ +1 Multiple declarations should be grouped to one + +2 Multiple declarations should be grouped to one + +3 Declaration should always have a whitespace above + +4 Declaration should always have a whitespace above + + + +
+ +### `defer` + +Deferring execution should only be used directly in the context of what's being +deferred and there should only be one statement above. + + + + + + + +
BadGood
+ +```go +val, closeFn := SomeFn() +val2 := fmt.Sprintf("v-%s", val) +fmt.Println(val) +defer closeFn() // 1 + +defer fn1() +a := 1 +defer fn3() // 2 + +f, err := os.Open("/path/to/f.txt") +if err != nil { + return err +} + +lines := ReadFile(f) +trimLines(lines) +defer f.Close() // 3 +``` + + + +```go +val, closeFn := SomeFn() +defer closeFn() + +defer fn1() +defer fn2() +defer fn3() + +f, err := os.Open("/path/to/f.txt") +if err != nil { + return err +} +defer f.Close() + +m.Lock() +defer m.Unlock() +``` + +
+ +1 More than a single statement between `defer` and `closeFn` + +2 `a` is not used in expression + +3 More than a single statement between `defer` and `f.Close` + + + +
+ +### `expr` + +Expressions can be multiple things and a big part of them are not handled by +`wsl`. However all function calls are expressions which can be verified. + +> **NOTE** This is one of the few rules with non-configurable exceptions. Given +> the idiomatic way to acquire and release mutex locks and the fact that the +> `sync` mutex from the standard library is so widely used, any call to `Lock`, +> `RWLock`, or `TryLock` can be cuddled above any other statement(s) and +> similarly `Unlock` and `RWUnlock` can be cuddled below any other statement(s). + + + + + + + +
BadGood
+ +```go +a := 1 +b := 2 +fmt.Println("not b") // 1 + +mu.Lock() +for _, item := range items { + // Safely work with item +} +mu.Unlock() +``` + + + +```go +a := 1 +b := 2 + +fmt.Println("not b") + +a := 1 +fmt.Println(a) +``` + +
+ +1 `b` is not used in expression + + + +
+ +### `for` + +> Configurable via `allow-first-in-block` to allow cuddling if the variable is +> used _first_ in the block (enabled by default). +> +> Configurable via `allow-whole-block` to allow cuddling if the variable is used +> _anywhere_ in the following block (disabled by default). +> +> See [Configuration](#configuration) for details. + + + + + + + +
BadGood
+ +```go +i := 0 +for j := 0; j < 3; j++ { // 1 + fmt.Println(j) +} + +a := 0 +i := 3 +for j := 0; j < i; j++ { // 2 + fmt.Println(j) +} + +x := 1 +for { // 3 + fmt.Println("hello") + break +} +``` + + + +```go +i := 0 +for j := 0; j < i; j++ { + fmt.Println(j) +} + +a := 0 + +i := 3 +for j := 0; j < i; j++ { + fmt.Println(j) +} + +// Allowed with `allow-first-in-block` +x := 1 +for { + x++ + break +} + +// Allowed with `allow-whole-block` +x := 1 +for { + fmt.Println("hello") + + if shouldIncrement() { + x++ + } +} +``` + +
+ +1 `i` is not used in expression + +2 More than one variable above statement + +3 No variable in expression + + + +
+ +### `go` + + + + + + + +
BadGood
+ +```go +someFunc := func() {} +go anotherFunc() // 1 + +x := 1 +go func () // 2 + fmt.Println(y) +}() + +someArg := 1 +go Fn(notArg) // 3 +``` + + + +```go +someFunc := func() {} +go someFunc() + +x := 1 +go func (s string) { + fmt.Println(s) +}(x) + +someArg := 1 +go Fn(someArg) +``` + +
+ +1 `someFunc` is not used in expression + +2 `x` is not used in expression + +3 `someArg` is not used in expression + + + +
+ +### `if` + +> Configurable via `allow-first-in-block` to allow cuddling if the variable is +> used _first_ in the block (enabled by default). +> +> Configurable via `allow-whole-block` to allow cuddling if the variable is used +> _anywhere_ in the following block (disabled by default). +> +> See [Configuration](#configuration) for details. + +`if` statements are one of several block statements (a statement with a block) +that can have some form of expression or condition. To make block context more +readable, only one variable is allowed immediately above the `if` statement and +the variable must be used in the condition (unless configured otherwise). + + + + + + + +
BadGood
+ +```go +x := 1 +if y > 1 { // 1 + fmt.Println("y > 1") +} + +a := 1 +b := 2 +if b > 1 { // 2 + fmt.Println("a > 1") +} + +a := 1 +b := 2 +if a > 1 { // 3 + fmt.Println("a > 1") +} + +a := 1 +b := 2 +if notEvenAOrB() { // 4 + fmt.Println("not a or b") +} + +a := 1 +x, err := SomeFn() // 5 +if err != nil { + return err +} +``` + + + +```go +x := 1 + +if y > 1 { + fmt.Println("y > 1") +} + +a := 1 + +b := 2 +if b > 1 { + fmt.Println("a > 1") +} + +b := 2 + +a := 1 +if a > 1 { + fmt.Println("a > b") +} + +a := 1 +b := 2 + +if notEvenAOrB() { + fmt.Println("not a or b") +} + +a := 1 + +x, err := SomeFn() +if err != nil { + return err +} + +// Allowed with `allow-first-in-block` +x := 1 +if xUsedFirstInBlock() { + x = 2 +} + +// Allowed with `allow-whole-block` +x := 1 +if xUsedLaterInBlock() { + fmt.Println("will use x later") + + if orEvenNestedWouldWork() { + x = 3 + } +} +``` + +
+ +1 `x` is not used in expression + +2 More than one variable above statement + +3 `b` is not used in expression and too many statements + +4 No variable in expression + +5 More than one variable above statement + + + +
+ +### `inc-dec` + + + + + + + +
BadGood
+ +```go +i := 1 + +if true { + fmt.Println("hello") +} +i++ // 1 + +defer func() { + fmt.Println("hello") +}() +i++ // 2 +``` + + + +```go +i := 1 +i++ + +i-- +j := i +j++ +``` + +
+ +1 Not an assign or inc/dec statement above + +2 Not an assign or inc/dec statement above + + + +
+ +### `label` + +Labels should never be cuddled. Labels in itself is often a symptom of big scope +and split context and because of that should always have an empty line above. + + + + + + + +
BadGood
+ +```go +L1: + if true { + _ = 1 + } +L2: // 1 + if true { + _ = 1 + } +``` + + + +```go +L1: + if true { + _ = 1 + } + +L2: + if true { + _ = 1 + } +``` + +
+ +1 Labels should always have a whitespabe above + + + +
+ +### `range` + +> Configurable via `allow-first-in-block` to allow cuddling if the variable is +> used _first_ in the block (enabled by default). +> +> Configurable via `allow-whole-block` to allow cuddling if the variable is used +> _anywhere_ in the following block (disabled by default). +> +> See [Configuration](#configuration) for details. + + + + + + + +
BadGood
+ +```go +someRange := []int{1, 2, 3} +for _, i := range thisIsNotSomeRange { // 1 + fmt.Println(i) +} + +x := 1 +for i := range make([]int, 3) { // 2 + fmt.Println("hello") + break +} + +s1 := []int{1, 2, 3} +s2 := []int{3, 2, 1} +for _, v := range s2 { // 3 + fmt.Println(v) +} +``` + + + +```go +someRange := []int{1, 2, 3} + +for _, i := range thisIsNotSomeRange { + fmt.Println(i) +} + +someRange := []int{1, 2, 3} +for _, i := range someRange { + fmt.Println(i) +} + +notARange := 1 +for i := range returnsRange(notARange) { + fmt.Println(i) +} + +s1 := []int{1, 2, 3} + +s2 := []int{3, 2, 1} +for _, v := range s2 { + fmt.Println(v) +} +``` + +
+ +1 `someRange` is not used in expression + +2 `x` is not used in expression + +3 More than one variable above statement + + + +
+ +### `return` + +> Configurable via `branch-max-lines` + +Return statements is an important statement that is easiy to miss in larger code +blocks. To better visualize the `return` statement and that the method is +returning it should always be followed by a blank line unless the scope is as +small as `branch-max-lines`. + + + + + + + +
BadGood
+ +```go +func Fn() int { + x, err := someFn() + if err != nil { + panic(err) + } + + fmt.Println(x) + return // 1 +} +``` + + + +```go +func Fn() int { + x, err := someFn() + if err != nil { + panic(err) + } + + fmt.Println(x) + + return +} +``` + +
+ +1 Block is more than 2 lines so should be a blank line above + + + +
+ +### `select` + +Identifiers used in case arms of select statements are allowed to be cuddled. + +> Configurable via `allow-first-in-block` to allow cuddling if the variable is +> used _first_ in the block (enabled by default). +> +> Configurable via `allow-whole-block` to allow cuddling if the variable is used +> _anywhere_ in the following block (disabled by default). +> +> See [Configuration](#configuration) for details. + + + + + + + +
BadGood
+ +```go +x := 0 +select { // 1 +case <-time.After(time.Second): + // ... +case <-stop: + // ... +} +``` + + + +```go +stop := make(chan struct{}) +select { +case <-time.After(time.Second): + // ... +case <-stop: + // ... +} + +x := 0 + +select { +case <-time.After(time.Second): + // ... +case <-stop: + // ... +} + +// Allowed with `allow-whole-block` +x := 1 +select { +case <-time.After(time.Second): + // ... +case <-stop: + Fn(x) +} +``` + +
+ +1 `x` is not used in expression + + + +
+ +### `send` + +Send statements should only be cuddled with a single variable that is used on +the line above. + + + + + + + +
BadGood
+ +```go +a := 1 +ch <- 1 // 1 + +b := 2 +<-ch // 2 +``` + + + +```go +a := 1 +ch <- a + +b := 1 + +<-ch +``` + +
+ +1 `a` is not used in expression + +2 `b` is not used in expression + + + +
+ +### `switch` + +In addition to checking the switch condition, switch statements also checks +identifiers in all case arms. If a variable is used in one or more of the case +arms it's allowed to be cuddled. + +> Configurable via `allow-first-in-block` to allow cuddling if the variable is +> used _first_ in the block (enabled by default). +> +> Configurable via `allow-whole-block` to allow cuddling if the variable is used +> _anywhere_ in the following block (disabled by default). +> +> See [Configuration](#configuration) for details. + + + + + + + +
BadGood
+ +```go +x := 0 +switch y { // 1 +case 1: + // ... +case 2: + // ... +} + + +x := 0 +y := 1 +switch y { // 2 +case 1: + // ... +case 2: + // ... +} +``` + + + +```go +n := 1 +switch n { +case 1: + // ... +case 2: + // ... +} + +n := 1 +switch { +case n < 1: + // ... +case n > 1: + // ... +} + +x := 0 + +switch y { +case 1: + // ... +case 2: + // ... +} + + +x := 0 + +y := 1 +switch y { +case 1: + // ... +case 2: + // ... +} + +// Allowed with `allow-whole-block` +x := 1 +switch y { +case 1: + // ... +case 2: + fmt.Println(x) +} +``` + +
+ +1 `x` is not used in expression + +2 More than one variable above statement + + + +
+ +### `type-switch` + +> Configurable via `allow-first-in-block` to allow cuddling if the variable is +> used _first_ in the block (enabled by default). +> +> Configurable via `allow-whole-block` to allow cuddling if the variable is used +> _anywhere_ in the following block (disabled by default). +> +> See [Configuration](#configuration) for details. + + + + + + + +
BadGood
+ +```go +x := someType() +switch y.(type) { // 1 +case int32: + // ... +case int64: + // ... +} + + +x := 0 +y := someType() +switch y.(type) { +case int32: + // ... +case int64: + // ... +} +``` + + + +```go +x := someType() + +switch y.(type) { +case int32: + // ... +case int64: + // ... +} + + +x := 0 + +y := someType() +switch y.(type) { +case int32: + // ... +case int64: + // ... +} + +// Allowed with `allow-whole-block` +x := 1 +switch y.(type) { +case int32: + // ... +case int64: + fmt.Println(x) +} +``` + +
+ +1 `x` is not used in expression + + + +
+ +### `append` + +Append enables strict `append` checking where assignments that are +re-assignments with `append` (e.g. `x = append(x, y)`) is only allowed to be +cuddled with other assignments if the `append` uses the variable on the line +above. + + + + + + + +
BadGood
+ +```go +s := []string{} + +a := 1 +s = append(s, 2) // 1 +b := 3 +s = append(s, a) // 2 +``` + + + +```go +s := []string{} + +a := 1 +s = append(s, a) + +b := 3 + +s = append(s, 2) +``` + +
+ +1 `a` is not used in append + +2 `b` is not used in append + + + +
+ +### `assign-exclusive` + +Assign exclusive does not allow mixing new assignments (`:=`) with +re-assignments (`=`). + + + + + + + +
BadGood
+ +```go +a := 1 +b = 2 // 1 +c := 3 // 2 +d = 4 // 3 +``` + + + +```go +a := 1 +c := 3 + +b = 2 +d = 4 +``` + +
+ +1 `a` is not a re-assignment + +2 `b` is not a new assignment + +3 `c` is not a re-assignment + + + +
+ +### `assign-expr` + +Assignments are allowed to be cuddled with expressions, primarily to support +mixing assignments and function calls which can often make sense in shorter +flows. By enabling this check `wsl` will ensure assignments are not cuddled with +expressions. + + + + + + + +
BadGood
+ +```go +t1.Fn1() +x := t1.Fn2() // 1 +t1.Fn3() +``` + + + +```go +t1.Fn1() + +x := t1.Fn2() +t1.Fn3() +``` + +
+ +1 Line above is not an assignment + + + +
+ +### `err` + + + + + + + +
BadGood
+ +```go +_, err := SomeFn() + +if err != nil { // 1 + return fmt.Errorf("failed to fn: %w", err) +} +``` + + + +```go +_, err := SomeFn() +if err != nil { + return fmt.Errorf("failed to fn: %w", err) +} +``` + +
+ +1 Whitespace between error assignment and error checking + + + +
+ +### `leading-whitespace` + + + + + + +
BadGood
+ +```go +if true { + + fmt.Println("hello") +} +``` + + + +```go +if true { + fmt.Println("hello") +} +``` + +
+ +### `trailing-whitespace` + + + + + + +
BadGood
+ +```go +if true { + fmt.Println("hello") + +} +``` + + + +```go +if true { + fmt.Println("hello") +} +``` + +
+ +## Configuration + +One shared logic across different checks is the logic around statements +containing a block, i.e. a statement with a following `{}` (e.g. `if`, `for`, +`switch` etc). + +`wsl` only allows one statement immediately above and that statement must also +be referenced in the expression in the statement with the block. E.g. + +```go +someVariable := true +if someVariable { + // Here `someVariable` used in the `if` expression is the only variable + // immediately above the statement. +} +``` + +This can be configured to be more "laxed" by also allowing a single statement +immediately above if it's used either first in the following block or anywhere +inside the following block. + +### `allow-first-in-block` + +By setting this to true (default), the variable doesn't have to be used in the +expression itself but is also allowed if it's the first statement in the block +body. + +```go +someVariable := 1 +if anotherVariable { + someVariable++ +} +``` + +### `allow-whole-block` + +This is similar to `allow-first-in-block` but now allows the lack of whitespace +if it's used anywhere in the following block. + +```go +someVariable := 1 +if anotherVariable { + someFn(yetAnotherVariable) + + if stillNotSomeVariable { + someVariable++ + } +} +``` + +### `case-max-lines` + +When set to a value greater than 0, case clauses in `switch` and `select` +statements that exceed this number of lines will require a blank line before the +next case. Setting this to 1 will make it always enabled. + +Comments between case clauses are handled based on their indentation: + +- **Indented comments** (deeper than `case`) are treated as trailing comments + that belong to the current case body. +- **Left-aligned comments** (at the same level as `case`) are treated as leading + comments that belong to the next case. + +The blank line is placed at the transition point between trailing and leading +content. This means: + +- If all comments are indented, the blank line goes before the next `case`. +- If all comments are left-aligned, the blank line goes after the last + statement. +- If comments transition from indented to left-aligned, the blank line goes at + the transition point. + +Additionally, left-aligned comments must be flush against the next `case` - no +blank line is allowed between them. This ensures consistent formatting where +leading comments are visually attached to the case they describe. + + + + + + + +
BadGood
+ +```go +switch n { +case 1: + fmt.Println("hello") +case 2: // 1 + fmt.Println("world") +} + +switch n { +case 1: + fmt.Println("hello") + // Trailing comment +case 2: // 2 + fmt.Println("world") +} + +switch n { +case 1: + fmt.Println("hello") + // Trailing comment +// Leading comment +case 2: // 3 + fmt.Println("world") +} + +switch n { +case 1: + fmt.Println("hello") +// Leading comment + +case 2: // 4 + fmt.Println("world") +} +``` + + + +```go +switch n { +case 1: + fmt.Println("hello") + +case 2: + fmt.Println("world") +} + +switch n { +case 1: + fmt.Println("hello") + // Trailing comment + +case 2: + fmt.Println("world") +} + +switch n { +case 1: + fmt.Println("hello") + // Trailing comment + +// Leading comment +case 2: + fmt.Println("world") +} + +switch n { +case 1: + fmt.Println("hello") + +// Leading comment +case 2: + fmt.Println("world") +} +``` + +
+ +1 Missing blank line after case body + +2 Missing blank line after trailing comment + +3 Missing blank line at transition (after trailing comment) + +4 Unnecessary blank line before case (after leading comment) + + + +
diff --git a/vendor/github.com/bombsimon/wsl/v5/LICENSE b/vendor/github.com/bombsimon/wsl/v5/LICENSE new file mode 100644 index 000000000..f881b648e --- /dev/null +++ b/vendor/github.com/bombsimon/wsl/v5/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 - 2025 Simon Sawert + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/bombsimon/wsl/v5/README.md b/vendor/github.com/bombsimon/wsl/v5/README.md new file mode 100644 index 000000000..d038ef514 --- /dev/null +++ b/vendor/github.com/bombsimon/wsl/v5/README.md @@ -0,0 +1,187 @@ +# wsl - whitespace linter + +[![GitHub Actions](https://github.com/bombsimon/wsl/actions/workflows/go.yml/badge.svg)](https://github.com/bombsimon/wsl/actions/workflows/go.yml) +[![Coverage Status](https://coveralls.io/repos/github/bombsimon/wsl/badge.svg?branch=main)](https://coveralls.io/github/bombsimon/wsl?branch=main) + +`wsl` (**w**hite**s**pace **l**inter) is a linter that wants you to use empty +lines to separate grouping of different types to increase readability. There are +also a few places where it encourages you to _remove_ whitespaces which is at +the start and the end of blocks or between assigning and error checking. + +## Checks and configuration + +Each check can be disabled or enabled individually to the point where no checks +can be run. The idea with this is to attract more users. Some checks have +configuration that affect how they work but most of them can only be turned on +or off. + +### Checks + +This is an exhaustive list of all the checks that can be enabled or disabled and +their default value. The names are the same as the Go +[AST](https://pkg.go.dev/go/ast) type name for built-ins. + +The base rule is that statements that has a block (e.g. `for`, `range`, +`switch`, `if` etc) should always only be directly adjacent with a single +variable and only if it's used in the expression in the block itself. + +For more details and examples, see [CHECKS](CHECKS.md). + +✅ = enabled by default, ❌ = disabled by default + +#### Built-ins and keywords + +- ✅ **assign** - Assignments should only be cuddled with other assignments, + or increment/decrement +- ✅ **branch** - Branch statement (`break`, `continue`, `fallthrough`, `goto`) + should only be cuddled if the block is less than `n` lines where `n` is the + value of [`branch-max-lines`](#configuration) +- ✅ **decl** - Declarations should never be cuddled +- ✅ **defer** - Defer should only be cuddled with other `defer`, after error + checking or with a single variable used on the line above +- ✅ **expr** - Expressions are e.g. function calls or index expressions, they + should only be cuddled with variables used on the line above +- ✅ **for** - For loops should only be cuddled with a single variable used on + the line above +- ✅ **go** - Go should only be cuddled with other `go` or a single variable + used on the line above +- ✅ **if** - If should only be cuddled with a single variable used on the line + above +- ✅ **inc-dec** - Increment/decrement (`++/--`) has the same rules as `assign` +- ✅ **label** - Labels should never be cuddled +- ✅ **range** - Range should only be cuddled with a single variable used on the + line above +- ✅ **return** - Return should only be cuddled if the block is less than `n` + lines where `n` is the value of [`branch-max-lines`](#configuration) +- ✅ **select** - Select should only be cuddled with a single variable used on + the line above +- ✅ **send** - Send should only be cuddled with a single variable used on the + line above +- ✅ **switch** - Switch should only be cuddled with a single variable used on + the line above +- ✅ **type-switch** - Type switch should only be cuddled with a single variable + used on the line above + +#### Specific `wsl` cases + +- ❌ **after-block** - Require empty line after block statements +- ✅ **append** - Only allow re-assigning with `append` if the value being + appended exist on the line above +- ❌ **assign-exclusive** - Only allow cuddling either new variables or + re-assigning of existing ones +- ❌ **assign-expr** - Don't allow assignments to be cuddled with expressions, + e.g. function calls +- ✅ **err** - Error checking must follow immediately after the error variable + is assigned +- ✅ **leading-whitespace** - Disallow leading empty lines in blocks +- ✅ **trailing-whitespace** - Disallow trailing empty lines in blocks + +### Configuration + +Other than enabling or disabling specific checks some checks can be configured +in more details. + +- ✅ **allow-first-in-block** - Allow cuddling a variable if it's used first in + the immediate following block, even if the statement with the block doesn't + use the variable (see [Configuration](CHECKS.md#allow-first-in-block) for + details) +- ❌ **allow-whole-block** - Same as above, but allows cuddling if the variable + is used _anywhere_ in the following (or nested) block (see + [Configuration](CHECKS.md#allow-whole-block) for details) +- **branch-max-lines** - If a block contains more than this number of lines the + branch statement (e.g. `return`, `break`, `continue`) need to be separated by + a whitespace (default 2) +- **case-max-lines** - If set to a non negative number, `case` blocks needs to + end with a whitespace if exceeding this number (default 0, 0 = off, 1 = + always) +- ❌ **include-generated** - Include generated files when checking + +## Installation + +```sh +# Latest release +go install github.com/bombsimon/wsl/v5/cmd/wsl@latest + +# Main branch +go install github.com/bombsimon/wsl/v5/cmd/wsl@main +``` + +## Usage + +> **Note**: This linter provides a fixer that can fix most issues with the +> `--fix` flag. + +`wsl` uses the [analysis] package meaning it will operate on package level with +the default analysis flags and way of working. + +```sh +wsl --help +wsl [flags] + +wsl --default none --enable branch,return --fix ./... +``` + +`wsl` is also integrated in [`golangci-lint`][golangci-lint] but since v5 which +had a bunch of breaking changes it's renamed to `wsl_v5`. The previous version +of `wsl` is deprecated and will be removed from `golangci-lint` eventually. + +```sh +golangci-lint run --no-config --enable-only wsl_v5 --fix +``` + +This is an exhaustive, default, configuration for `wsl_v5` in `golangci-lint`. + +```yaml +linters: + default: none + enable: + - wsl_v5 + + settings: + wsl_v5: + allow-first-in-block: true + allow-whole-block: false + branch-max-lines: 2 + case-max-lines: 0 + default: ~ # Can be `all`, `none`, `default` or empty + enable: + - append + - assign + - branch + - decl + - defer + - err + - expr + - for + - go + - if + - inc-dec + - label + - range + - return + - select + - send + - switch + - type-switch + - leading-whitespace + - trailing-whitespace + disable: + - after-block + - assign-exclusive + - assign-expr +``` + +## See also + +- [`newline-after-block`][newline-after-block] - Require newline after blocks +- [`nlreturn`][nlreturn] - Use empty lines before `return` +- [`whitespace`][whitespace] - Don't use a blank newline at the start or end of + a block. +- [`gofumpt`][gofumpt] - Stricter formatter than `gofmt`. + + [analysis]: https://pkg.go.dev/golang.org/x/tools/go/analysis + [gofumpt]: https://github.com/mvdan/gofumpt + [golangci-lint]: https://golangci-lint.run + [newline-after-block]: https://github.com/breml/newline-after-block + [nlreturn]: https://github.com/ssgreg/nlreturn + [whitespace]: https://github.com/ultraware/whitespace diff --git a/vendor/github.com/bombsimon/wsl/v5/analyzer.go b/vendor/github.com/bombsimon/wsl/v5/analyzer.go new file mode 100644 index 000000000..4ceee1617 --- /dev/null +++ b/vendor/github.com/bombsimon/wsl/v5/analyzer.go @@ -0,0 +1,198 @@ +package wsl + +import ( + "flag" + "fmt" + "go/ast" + "go/token" + "os" + "strings" + "sync" + + "golang.org/x/tools/go/analysis" +) + +const version = "wsl version v5.6.0" + +func NewAnalyzer(config *Configuration) *analysis.Analyzer { + wa := &wslAnalyzer{config: config} + + return &analysis.Analyzer{ + Name: "wsl", + Doc: "add or remove empty lines", + Flags: wa.flags(), + Run: wa.run, + RunDespiteErrors: true, + } +} + +// wslAnalyzer is a wrapper around the configuration which is used to be able to +// set the configuration when creating the analyzer and later be able to update +// flags and running method. +type wslAnalyzer struct { + config *Configuration + + // When we use flags, we need to parse the ones used for checks into + // temporary variables so we can create the check set once the flag is being + // parsed by the analyzer and we run our analyzer. + defaultChecks string + enable []string + disable []string + + // To only validate and convert the parsed flags once we use a `sync.Once` + // to only create a check set once and store the set and potential error. We + // also store if we actually had a configuration to ensure we don't + // overwrite the checks if the analyzer was created with a proper wsl + // config. + cfgOnce sync.Once + didHaveConfig bool + checkSetErr error +} + +func (wa *wslAnalyzer) flags() flag.FlagSet { + flags := flag.NewFlagSet("wsl", flag.ExitOnError) + + if wa.config != nil { + wa.didHaveConfig = true + return *flags + } + + wa.config = NewConfig() + + flags.BoolVar(&wa.config.IncludeGenerated, "include-generated", false, "Include generated files") + flags.BoolVar(&wa.config.AllowFirstInBlock, "allow-first-in-block", true, "Allow cuddling if variable is used in the first statement in the block") + flags.BoolVar(&wa.config.AllowWholeBlock, "allow-whole-block", false, "Allow cuddling if variable is used anywhere in the block") + flags.IntVar(&wa.config.BranchMaxLines, "branch-max-lines", 2, "Max lines before requiring newline before branching, e.g. `return`, `break`, `continue` (0 = never)") + flags.IntVar(&wa.config.CaseMaxLines, "case-max-lines", 0, "Max lines before requiring a newline at the end of case (0 = never)") + + flags.StringVar(&wa.defaultChecks, "default", "", "Can be 'all' for all checks or 'none' for no checks or empty for default checks") + flags.Var(&multiStringValue{slicePtr: &wa.enable}, "enable", "Comma separated list of checks to enable") + flags.Var(&multiStringValue{slicePtr: &wa.disable}, "disable", "Comma separated list of checks to disable") + flags.Var(new(versionFlag), "V", "print version and exit") + + return *flags +} + +func (wa *wslAnalyzer) run(pass *analysis.Pass) (any, error) { + wa.cfgOnce.Do(func() { + // No need to update checks if config was passed when creating the + // analyzer. + if wa.didHaveConfig { + return + } + + // Parse the check params once if we set our config from flags. + wa.config.Checks, wa.checkSetErr = NewCheckSet(wa.defaultChecks, wa.enable, wa.disable) + }) + + if wa.checkSetErr != nil { + return nil, wa.checkSetErr + } + + for _, file := range pass.Files { + filename := getFilename(pass.Fset, file) + if !strings.HasSuffix(filename, ".go") { + continue + } + + // if the file is related to cgo the filename of the unadjusted position + // is a not a '.go' file. + unadjustedFilename := pass.Fset.PositionFor(file.Pos(), false).Filename + + // if the file is related to cgo the filename of the unadjusted position + // is a not a '.go' file. + if !strings.HasSuffix(unadjustedFilename, ".go") { + continue + } + + // The file is skipped if the "unadjusted" file is a Go file, and it's a + // generated file (ex: "_test.go" file). The other non-Go files are + // skipped by the first 'if' with the adjusted position. + if !wa.config.IncludeGenerated && ast.IsGenerated(file) { + continue + } + + wsl := New(file, pass, wa.config) + wsl.Run() + + for pos, fix := range wsl.issues { + textEdits := []analysis.TextEdit{} + + for _, f := range fix.fixRanges { + textEdits = append(textEdits, analysis.TextEdit{ + Pos: f.fixRangeStart, + End: f.fixRangeEnd, + NewText: f.fix, + }) + } + + pass.Report(analysis.Diagnostic{ + Pos: pos, + Category: "whitespace", + Message: fix.message, + SuggestedFixes: []analysis.SuggestedFix{ + { + TextEdits: textEdits, + }, + }, + }) + } + } + + //nolint:nilnil // A pass don't need to return anything. + return nil, nil +} + +// multiStringValue is a flag that supports multiple values. It's implemented to +// contain a pointer to a string slice that will be overwritten when the flag's +// `Set` method is called. +type multiStringValue struct { + slicePtr *[]string +} + +// Set implements the flag.Value interface and will overwrite the pointer to +// the +// slice with a new pointer after splitting the flag by comma. +func (m *multiStringValue) Set(value string) error { + var s []string + + for v := range strings.SplitSeq(value, ",") { + s = append(s, strings.TrimSpace(v)) + } + + *m.slicePtr = s + + return nil +} + +// String implements the flag.Value interface. +func (m *multiStringValue) String() string { + if m.slicePtr == nil { + return "" + } + + return strings.Join(*m.slicePtr, ", ") +} + +// https://cs.opensource.google/go/x/tools/+/refs/tags/v0.35.0:go/analysis/internal/analysisflags/flags.go;l=188-237;drc=99337ebe7b90918701a41932abf121600b972e34 +type versionFlag string + +func (*versionFlag) IsBoolFlag() bool { return true } +func (*versionFlag) Get() any { return nil } +func (*versionFlag) String() string { return "" } + +func (*versionFlag) Set(_ string) error { + fmt.Println(version) + os.Exit(0) + + return nil +} + +func getFilename(fset *token.FileSet, file *ast.File) string { + filename := fset.PositionFor(file.Pos(), true).Filename + if !strings.HasSuffix(filename, ".go") { + return fset.PositionFor(file.Pos(), false).Filename + } + + return filename +} diff --git a/vendor/github.com/bombsimon/wsl/v5/config.go b/vendor/github.com/bombsimon/wsl/v5/config.go new file mode 100644 index 000000000..ac4864ad4 --- /dev/null +++ b/vendor/github.com/bombsimon/wsl/v5/config.go @@ -0,0 +1,286 @@ +package wsl + +import ( + "fmt" + "strings" +) + +// CheckSet is a set of checks to run. +type CheckSet map[CheckType]struct{} + +// CheckType is a type that represents a checker to run. +type CheckType int + +// Each checker is represented by a CheckType that is used to enable or disable +// the check. +// A check can either be of a specific built-in keyword or custom checks. +const ( + CheckInvalid CheckType = iota + CheckAssign + CheckBranch + CheckDecl + CheckDefer + CheckExpr + CheckFor + CheckGo + CheckIf + CheckIncDec + CheckLabel + CheckRange + CheckReturn + CheckSelect + CheckSend + CheckSwitch + CheckTypeSwitch + + // CheckAfterBlock ensures there's a newline after each block. + CheckAfterBlock + // CheckAppend only allows assignments of `append` to be cuddled with other + // assignments if it's a variable used in the append statement, e.g. + // + // a := 1 + // x = append(x, a) + // . + CheckAppend + // CheckAssignExclusive only allows assignments of either new variables or + // re-assignment of existing ones, e.g. + // + // a := 1 + // b := 2 + // + // a = 1 + // b = 2 + // . + CheckAssignExclusive + // CheckAssignExpr will check so assignments are not cuddled with expression + // nodes, e.g. + // + // t1.Fn1() + // + // x := t1.Fn2() + // t1.Fn3() + // . + CheckAssignExpr + // CheckErr force error checking to follow immediately after an error + // variable is assigned, e.g. + // + // _, err := someFn() + // if err != nil { + // panic(err) + // } + // . + CheckErr + CheckLeadingWhitespace + CheckTrailingWhitespace + + //nolint:godoclint // No need to document + // CheckTypes only used for reporting. + CheckCaseTrailingNewline +) + +func (c CheckType) String() string { + return [...]string{ + "invalid", + "assign", + "branch", + "decl", + "defer", + "expr", + "for", + "go", + "if", + "inc-dec", + "label", + "range", + "return", + "select", + "send", + "switch", + "type-switch", + // + "after-block", + "append", + "assign-exclusive", + "assign-expr", + "err", + "leading-whitespace", + "trailing-whitespace", + // + "case-trailing-newline", + }[c] +} + +type Configuration struct { + IncludeGenerated bool + AllowFirstInBlock bool + AllowWholeBlock bool + BranchMaxLines int + CaseMaxLines int + Checks CheckSet +} + +func NewConfig() *Configuration { + return &Configuration{ + IncludeGenerated: false, + AllowFirstInBlock: true, + AllowWholeBlock: false, + CaseMaxLines: 0, + BranchMaxLines: 2, + Checks: DefaultChecks(), + } +} + +func NewWithChecks( + defaultChecks string, + enable []string, + disable []string, +) (*Configuration, error) { + checks, err := NewCheckSet(defaultChecks, enable, disable) + if err != nil { + return nil, fmt.Errorf("failed to create config: %w", err) + } + + cfg := NewConfig() + cfg.Checks = checks + + return cfg, nil +} + +func NewCheckSet( + defaultChecks string, + enable []string, + disable []string, +) (CheckSet, error) { + var cs CheckSet + + switch strings.ToLower(defaultChecks) { + case "", "default": + cs = DefaultChecks() + case "all": + cs = AllChecks() + case "none": + cs = NoChecks() + default: + return nil, fmt.Errorf("invalid preset '%s', must be `all`, `none` or `` (empty)", defaultChecks) + } + + for _, s := range enable { + check, err := CheckFromString(s) + if err != nil { + return nil, fmt.Errorf("invalid check '%s'", s) + } + + cs.Add(check) + } + + for _, s := range disable { + check, err := CheckFromString(s) + if err != nil { + return nil, fmt.Errorf("invalid check '%s'", s) + } + + cs.Remove(check) + } + + return cs, nil +} + +func DefaultChecks() CheckSet { + return CheckSet{ + CheckAppend: {}, + CheckAssign: {}, + CheckBranch: {}, + CheckDecl: {}, + CheckDefer: {}, + CheckErr: {}, + CheckExpr: {}, + CheckFor: {}, + CheckGo: {}, + CheckIf: {}, + CheckIncDec: {}, + CheckLabel: {}, + CheckLeadingWhitespace: {}, + CheckTrailingWhitespace: {}, + CheckRange: {}, + CheckReturn: {}, + CheckSelect: {}, + CheckSend: {}, + CheckSwitch: {}, + CheckTypeSwitch: {}, + } +} + +func AllChecks() CheckSet { + c := DefaultChecks() + c.Add(CheckAssignExclusive) + c.Add(CheckAssignExpr) + c.Add(CheckAfterBlock) + + return c +} + +func NoChecks() CheckSet { + return CheckSet{} +} + +func (c CheckSet) Add(check CheckType) { + c[check] = struct{}{} +} + +func (c CheckSet) Remove(check CheckType) { + delete(c, check) +} + +func CheckFromString(s string) (CheckType, error) { + switch strings.ToLower(s) { + case "assign": + return CheckAssign, nil + case "branch": + return CheckBranch, nil + case "decl": + return CheckDecl, nil + case "defer": + return CheckDefer, nil + case "expr": + return CheckExpr, nil + case "for": + return CheckFor, nil + case "go": + return CheckGo, nil + case "if": + return CheckIf, nil + case "inc-dec": + return CheckIncDec, nil + case "label": + return CheckLabel, nil + case "range": + return CheckRange, nil + case "return": + return CheckReturn, nil + case "select": + return CheckSelect, nil + case "send": + return CheckSend, nil + case "switch": + return CheckSwitch, nil + case "type-switch": + return CheckTypeSwitch, nil + + case "after-block": + return CheckAfterBlock, nil + case "append": + return CheckAppend, nil + case "assign-exclusive": + return CheckAssignExclusive, nil + case "assign-expr": + return CheckAssignExpr, nil + case "err": + return CheckErr, nil + case "leading-whitespace": + return CheckLeadingWhitespace, nil + case "trailing-whitespace": + return CheckTrailingWhitespace, nil + default: + return CheckInvalid, fmt.Errorf("invalid check '%s'", s) + } +} diff --git a/vendor/github.com/bombsimon/wsl/v5/cursor.go b/vendor/github.com/bombsimon/wsl/v5/cursor.go new file mode 100644 index 000000000..0d275829f --- /dev/null +++ b/vendor/github.com/bombsimon/wsl/v5/cursor.go @@ -0,0 +1,88 @@ +package wsl + +import ( + "go/ast" +) + +// Cursor holds a list of statements and a pointer to where in the list we are. +// Each block gets a new cursor and can be used to check previous or coming +// statements. +type Cursor struct { + currentIdx int + statements []ast.Stmt + checkType CheckType +} + +// NewCursor creates a new cursor with a given list of statements. +func NewCursor(statements []ast.Stmt) *Cursor { + return &Cursor{ + currentIdx: -1, + statements: statements, + } +} + +func (c *Cursor) SetChecker(ct CheckType) { + c.checkType = ct +} + +func (c *Cursor) NextNode() ast.Node { + defer c.Save()() + + var nextNode ast.Node + if c.Next() { + nextNode = c.Stmt() + } + + return nextNode +} + +func (c *Cursor) Next() bool { + if c.currentIdx >= len(c.statements)-1 { + return false + } + + c.currentIdx++ + + return true +} + +func (c *Cursor) Previous() bool { + if c.currentIdx <= 0 { + return false + } + + c.currentIdx-- + + return true +} + +func (c *Cursor) PreviousNode() ast.Node { + defer c.Save()() + + var previousNode ast.Node + if c.Previous() { + previousNode = c.Stmt() + } + + return previousNode +} + +func (c *Cursor) Stmt() ast.Stmt { + return c.statements[c.currentIdx] +} + +func (c *Cursor) Save() func() { + idx := c.currentIdx + + return func() { + c.currentIdx = idx + } +} + +func (c *Cursor) Len() int { + return len(c.statements) +} + +func (c *Cursor) Nth(n int) ast.Stmt { + return c.statements[n] +} diff --git a/vendor/github.com/bombsimon/wsl/v5/renovate.json b/vendor/github.com/bombsimon/wsl/v5/renovate.json new file mode 100644 index 000000000..cc31624f2 --- /dev/null +++ b/vendor/github.com/bombsimon/wsl/v5/renovate.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": ["config:recommended", ":disableDependencyDashboard"] +} diff --git a/vendor/github.com/bombsimon/wsl/v5/wsl.go b/vendor/github.com/bombsimon/wsl/v5/wsl.go new file mode 100644 index 000000000..14244d297 --- /dev/null +++ b/vendor/github.com/bombsimon/wsl/v5/wsl.go @@ -0,0 +1,1585 @@ +package wsl + +import ( + "bytes" + "fmt" + "go/ast" + "go/format" + "go/token" + "go/types" + "slices" + + "golang.org/x/tools/go/analysis" +) + +const ( + messageMissingWhitespaceAbove = "missing whitespace above this line" + messageMissingWhitespaceBelow = "missing whitespace below this line" + messageRemoveWhitespace = "unnecessary whitespace" +) + +type fixRange struct { + fixRangeStart token.Pos + fixRangeEnd token.Pos + fix []byte +} + +type issue struct { + message string + // We can report multiple fixes at the same position. This happens e.g. when + // we force error cuddling but the error assignment is already cuddled. + // See `checkError` for examples. + fixRanges []fixRange +} + +type WSL struct { + file *ast.File + fset *token.FileSet + typeInfo *types.Info + issues map[token.Pos]issue + config *Configuration + groupedDecls map[token.Pos]struct{} +} + +func New(file *ast.File, pass *analysis.Pass, cfg *Configuration) *WSL { + return &WSL{ + fset: pass.Fset, + file: file, + typeInfo: pass.TypesInfo, + issues: make(map[token.Pos]issue), + config: cfg, + groupedDecls: make(map[token.Pos]struct{}), + } +} + +// Run will run analysis on the file and pass passed to the constructor. It's +// typically only supposed to be used by [analysis.Analyzer]. +func (w *WSL) Run() { + ast.Inspect(w.file, func(n ast.Node) bool { + switch node := n.(type) { + case *ast.FuncDecl: + w.checkBlock(node.Body, NewCursor([]ast.Stmt{})) + case *ast.FuncLit: + w.checkBlock(node.Body, NewCursor([]ast.Stmt{})) + } + + return true + }) +} + +func (w *WSL) checkStmt(stmt ast.Stmt, cursor *Cursor) { + //nolint:gocritic // This is not commented out code, it's examples + switch s := stmt.(type) { + // if a {} else if b {} else {} + case *ast.IfStmt: + w.checkIf(s, cursor, false) + // for {} / for a; b; c {} + case *ast.ForStmt: + w.checkFor(s, cursor) + // for _, _ = range a {} + case *ast.RangeStmt: + w.checkRange(s, cursor) + // switch {} // switch a {} + case *ast.SwitchStmt: + w.checkSwitch(s, cursor) + // switch a.(type) {} + case *ast.TypeSwitchStmt: + w.checkTypeSwitch(s, cursor) + // return a + case *ast.ReturnStmt: + w.checkReturn(s, cursor) + // continue / break + case *ast.BranchStmt: + w.checkBranch(s, cursor) + // var a + case *ast.DeclStmt: + w.checkDeclStmt(s, cursor) + // a := a + case *ast.AssignStmt: + w.checkAssign(s, cursor) + // a++ / a-- + case *ast.IncDecStmt: + w.checkIncDec(s, cursor) + // defer func() {} + case *ast.DeferStmt: + w.checkDefer(s, cursor) + // go func() {} + case *ast.GoStmt: + w.checkGo(s, cursor) + // e.g. someFn() + case *ast.ExprStmt: + w.checkExprStmt(s, cursor) + // case: + case *ast.CaseClause: + w.checkCaseClause(s, cursor) + // case: + case *ast.CommClause: + w.checkCommClause(s, cursor) + // { } + case *ast.BlockStmt: + w.checkBlock(s, cursor) + // select { } + case *ast.SelectStmt: + w.checkSelect(s, cursor) + // ch <- ... + case *ast.SendStmt: + w.checkSend(s, cursor) + // LABEL: + case *ast.LabeledStmt: + w.checkLabel(s, cursor) + case *ast.EmptyStmt: + default: + } +} + +func (w *WSL) checkBody(body []ast.Stmt) { + cursor := NewCursor(body) + + for cursor.Next() { + w.checkStmt(cursor.Stmt(), cursor) + } +} + +func (w *WSL) checkCuddlingBlock( + stmt ast.Node, + blockList []ast.Stmt, + allowedIdents []*ast.Ident, + cursor *Cursor, + maxAllowedStatements int, +) { + var firstBlockStmt ast.Node + if len(blockList) > 0 { + firstBlockStmt = blockList[0] + } + + w.checkCuddlingMaxAllowed(stmt, firstBlockStmt, allowedIdents, cursor, maxAllowedStatements) +} + +func (w *WSL) checkCuddling(stmt ast.Node, cursor *Cursor, maxAllowedStatements int) { + w.checkCuddlingMaxAllowed(stmt, nil, []*ast.Ident{}, cursor, maxAllowedStatements) +} + +func (w *WSL) checkCuddlingMaxAllowed( + stmt ast.Node, + firstBlockStmt ast.Node, + allowedIdents []*ast.Ident, + cursor *Cursor, + maxAllowedStatements int, +) { + if _, ok := cursor.Stmt().(*ast.LabeledStmt); ok { + return + } + + previousNode := cursor.PreviousNode() + if previousNode != nil { + if _, ok := w.groupedDecls[previousNode.End()]; ok { + w.addErrorTooManyStatements(cursor.Stmt().Pos(), cursor.checkType) + return + } + } + + numStmtsAbove := w.numberOfStatementsAbove(cursor) + previousIdents := w.identsFromNode(previousNode, true) + + // If we don't have any statements above, we only care about potential error + // cuddling (for if statements) so check that. + if numStmtsAbove == 0 { + w.checkError(numStmtsAbove, stmt, previousNode, cursor) + return + } + + if w.isLockOrUnlock(stmt, previousNode) { + return + } + + nodeIsAssignDeclOrIncDec := func(n ast.Node) bool { + _, a := n.(*ast.AssignStmt) + _, d := n.(*ast.DeclStmt) + _, i := n.(*ast.IncDecStmt) + + return a || d || i + } + + _, currIsDefer := stmt.(*ast.DeferStmt) + + // We're cuddled but not with an assign, declare or defer statement which is + // never allowed. + if !nodeIsAssignDeclOrIncDec(previousNode) && !currIsDefer { + w.addErrorInvalidTypeCuddle(cursor.Stmt().Pos(), cursor.checkType) + return + } + + checkIntersection := func(other []*ast.Ident) bool { + anyIntersects := identIntersection(previousIdents, other) + if len(anyIntersects) > 0 { + // We have matches, but too many statements above. + if maxAllowedStatements != -1 && numStmtsAbove > maxAllowedStatements { + w.addErrorTooManyStatements(previousNode.Pos(), cursor.checkType) + } + + return true + } + + return false + } + + // FEATURE(AllowWholeBlock): Allow identifier used anywhere in block + // (including recursive blocks). + if w.config.AllowWholeBlock { + allIdentsInBlock := w.identsFromNode(stmt, false) + if checkIntersection(allIdentsInBlock) { + return + } + } + + // FEATURE(AllowFirstInBlock): Allow identifiers used first in block. + if !w.config.AllowWholeBlock && w.config.AllowFirstInBlock { + firstStmtIdents := w.identsFromNode(firstBlockStmt, true) + if checkIntersection(firstStmtIdents) { + return + } + } + + currentIdents := w.identsFromNode(stmt, true) + if checkIntersection(currentIdents) { + return + } + + if checkIntersection(allowedIdents) { + return + } + + intersects := identIntersection(currentIdents, previousIdents) + if len(intersects) > 0 { + return + } + + // We're cuddled but the line immediately above doesn't contain any + // variables used in this statement. + w.addErrorNoIntersection(stmt.Pos(), cursor.checkType) +} + +func (w *WSL) checkCuddlingWithoutIntersection(stmt ast.Node, cursor *Cursor) { + if w.numberOfStatementsAbove(cursor) == 0 { + return + } + + if _, ok := cursor.Stmt().(*ast.LabeledStmt); ok { + return + } + + previousNode := cursor.PreviousNode() + + currAssign, currIsAssign := stmt.(*ast.AssignStmt) + previousAssign, prevIsAssign := previousNode.(*ast.AssignStmt) + _, prevIsDecl := previousNode.(*ast.DeclStmt) + _, prevIsIncDec := previousNode.(*ast.IncDecStmt) + + // Cuddling without intersection is allowed for assignments and inc/dec + // statements. If however the check for declarations is disabled, we also + // allow cuddling with them as well. + // + // var x string + // x := "" + // y++ + if _, ok := w.config.Checks[CheckDecl]; ok { + prevIsDecl = false + } + + // If we enable exclusive assign checks we only allow new declarations or + // new assignments together but not mix and match. + // + // When this is enabled we also implicitly disable support to cuddle with + // anything else. + if _, ok := w.config.Checks[CheckAssignExclusive]; ok { + prevIsDecl = false + prevIsIncDec = false + + if prevIsAssign && currIsAssign { + prevIsAssign = previousAssign.Tok == currAssign.Tok + } + } + + prevIsValidType := previousNode == nil || prevIsAssign || prevIsDecl || prevIsIncDec + + if _, ok := w.config.Checks[CheckAssignExpr]; !ok { + if _, ok := previousNode.(*ast.ExprStmt); ok && w.hasIntersection(stmt, previousNode) { + prevIsValidType = prevIsValidType || ok + } + } + + if prevIsValidType { + return + } + + if w.isLockOrUnlock(stmt, previousNode) { + return + } + + w.addErrorInvalidTypeCuddle(stmt.Pos(), cursor.checkType) +} + +func (w *WSL) checkBlock(block *ast.BlockStmt, cursor *Cursor) { + // Block can be nil for function declarations without a body. + if block == nil { + return + } + + w.checkBlockLeadingNewline(block) + w.checkTrailingNewline(block) + w.checkNewlineAfterBlock(block, cursor) + + w.checkBody(block.List) +} + +func (w *WSL) checkNewlineAfterBlock(block *ast.BlockStmt, cursor *Cursor) { + if _, ok := w.config.Checks[CheckAfterBlock]; !ok { + return + } + + // For function blocks we don't have any statements in our cursor. + if cursor.Len() == 0 { + return + } + + defer cursor.Save()() + + // Capture current statement and previous node before moving cursor. + currentStmt := cursor.Stmt() + previousNode := cursor.PreviousNode() + + if !cursor.Next() { + // No more statements after this one so check for comments after. + // Skip comments that are inside the current statement (e.g., inside an else block). + if cPos := w.commentOnLineAfterNodePos(block); cPos != token.NoPos && cPos >= currentStmt.End() { + insertPos := w.lineStartOf(cPos) + w.addError( + block.Rbrace, + insertPos, + insertPos, + messageMissingWhitespaceBelow, + CheckAfterBlock, + ) + } + + return + } + + // Exception: if err != nil { } followed by defer that references + // a variable assigned above the if block. + if w.isErrNotNilCheck(currentStmt) != nil { + if deferStmt, ok := cursor.Stmt().(*ast.DeferStmt); ok && previousNode != nil { + if w.hasIntersection(previousNode, deferStmt) { + return + } + } + } + + rBraceLine := w.lineFor(block.Rbrace) + nextContentPos := cursor.Stmt().Pos() + nextContentLine := w.lineFor(nextContentPos) + + // Find the first comment between rbrace and the next statement. + for _, cg := range w.file.Comments { + if cg.End() <= block.Rbrace { + continue + } + + // Skip comments that are inside the current statement but after this block. + // This handles cases like comments inside an else block when checking the if-body. + if cg.Pos() < currentStmt.End() { + continue + } + + if w.lineFor(cg.End()) == rBraceLine { + continue + } + + commentLine := w.lineFor(cg.Pos()) + if commentLine > rBraceLine && commentLine < nextContentLine { + nextContentPos = cg.Pos() + nextContentLine = commentLine + } + + break + } + + if nextContentLine <= rBraceLine+1 { + insertPos := w.lineStartOf(nextContentPos) + w.addError( + block.Rbrace, + insertPos, + insertPos, + messageMissingWhitespaceBelow, + CheckAfterBlock, + ) + } +} + +func (w *WSL) checkCaseClause(stmt *ast.CaseClause, cursor *Cursor) { + w.checkCaseLeadingNewline(stmt) + + if w.config.CaseMaxLines != 0 { + w.checkCaseTrailingNewline(stmt.Body, cursor) + } + + w.checkBody(stmt.Body) +} + +func (w *WSL) checkCommClause(stmt *ast.CommClause, cursor *Cursor) { + w.checkCommLeadingNewline(stmt) + + if w.config.CaseMaxLines != 0 { + w.checkCaseTrailingNewline(stmt.Body, cursor) + } + + w.checkBody(stmt.Body) +} + +func (w *WSL) checkAssign(stmt *ast.AssignStmt, cursor *Cursor) { + defer w.checkAppend(stmt, cursor) + + if _, ok := w.config.Checks[CheckAssign]; !ok { + return + } + + cursor.SetChecker(CheckAssign) + + w.checkCuddlingWithoutIntersection(stmt, cursor) +} + +func (w *WSL) checkAppend(stmt *ast.AssignStmt, cursor *Cursor) { + if _, ok := w.config.Checks[CheckAppend]; !ok { + return + } + + if w.numberOfStatementsAbove(cursor) == 0 { + return + } + + previousNode := cursor.PreviousNode() + + var appendNode *ast.CallExpr + + for _, expr := range stmt.Rhs { + e, ok := expr.(*ast.CallExpr) + if !ok { + continue + } + + if f, ok := e.Fun.(*ast.Ident); ok && f.Name == "append" { + appendNode = e + break + } + } + + if appendNode == nil { + return + } + + if !w.hasIntersection(appendNode, previousNode) { + w.addErrorNoIntersection(stmt.Pos(), CheckAppend) + } +} + +func (w *WSL) checkBranch(stmt *ast.BranchStmt, cursor *Cursor) { + if _, ok := w.config.Checks[CheckBranch]; !ok { + return + } + + cursor.SetChecker(CheckBranch) + + if w.numberOfStatementsAbove(cursor) == 0 { + return + } + + lastStmtInBlock := cursor.statements[len(cursor.statements)-1] + firstStmts := cursor.Nth(0) + + if w.lineFor(lastStmtInBlock.End())-w.lineFor(firstStmts.Pos()) < w.config.BranchMaxLines { + return + } + + w.addErrorTooManyLines(stmt.Pos(), cursor.checkType) +} + +func (w *WSL) checkDeclStmt(stmt *ast.DeclStmt, cursor *Cursor) { + if _, ok := w.config.Checks[CheckDecl]; !ok { + return + } + + cursor.SetChecker(CheckDecl) + + if w.numberOfStatementsAbove(cursor) == 0 { + return + } + + // Try to do smart grouping and if we succeed return, otherwise do + // line-by-line fixing. + if w.maybeGroupDecl(stmt, cursor) { + return + } + + w.addErrorNeverAllow(stmt.Pos(), cursor.checkType) +} + +func (w *WSL) checkDefer(stmt *ast.DeferStmt, cursor *Cursor) { + w.maybeCheckExpr( + stmt, + cursor, + func(n ast.Node) (int, bool) { + _, previousIsDefer := n.(*ast.DeferStmt) + _, previousIsIf := n.(*ast.IfStmt) + + // We allow defer as a third node only if we have an if statement + // between, e.g. + // + // f, err := os.Open(file) + // if err != nil { + // return err + // } + // defer f.Close() + if previousIsIf && w.numberOfStatementsAbove(cursor) >= 2 { + defer cursor.Save()() + + cursor.Previous() + cursor.Previous() + + if w.hasIntersection(cursor.Stmt(), stmt) { + return 1, false + } + } + + // Only check cuddling if previous statement isn't also a defer. + return 1, !previousIsDefer + }, + CheckDefer, + ) +} + +func (w *WSL) checkError( + stmtsAbove int, + ifStmt ast.Node, + previousNode ast.Node, + cursor *Cursor, +) { + if _, ok := w.config.Checks[CheckErr]; !ok { + return + } + + if stmtsAbove > 0 { + return + } + + if _, ok := cursor.Stmt().(*ast.LabeledStmt); ok { + return + } + + defer cursor.Save()() + + errIdent := w.isErrNotNilCheck(ifStmt) + if errIdent == nil { + return + } + + previousIdents := []*ast.Ident{} + + if assign, ok := previousNode.(*ast.AssignStmt); ok { + for _, lhs := range assign.Lhs { + previousIdents = append(previousIdents, w.identsFromNode(lhs, true)...) + } + } + + if decl, ok := previousNode.(*ast.DeclStmt); ok { + if genDecl, ok := decl.Decl.(*ast.GenDecl); ok { + for _, spec := range genDecl.Specs { + if vs, ok := spec.(*ast.ValueSpec); ok { + previousIdents = append(previousIdents, vs.Names...) + } + } + } + } + + // Ensure that the error checked on this line was assigned or declared in + // the previous statement. + if len(identIntersection([]*ast.Ident{errIdent}, previousIdents)) == 0 { + return + } + + cursor.SetChecker(CheckErr) + + previousEndLine := w.lineFor(previousNode.End()) + + // Check for comments on the same line as the previous node (extends effective end line). + for _, cg := range w.file.Comments { + if cg.Pos() >= ifStmt.Pos() { + break + } + + if cg.Pos() < previousNode.End() || cg.End() > ifStmt.Pos() { + continue + } + + // There's a comment between the error variable and the if-statement. + // If it's on a different line, we can't do much about this. + if w.lineFor(cg.End()) != previousEndLine { + return + } + + // Comment is on the same line - no need to update since line stays the same. + } + + ifStmtLine := w.lineFor(ifStmt.Pos()) + file := w.fset.File(ifStmt.Pos()) + + // Remove blank lines between previous node and if statement. + removeStart := file.LineStart(previousEndLine + 1) + removeEnd := file.LineStart(ifStmtLine) + w.addErrorRemoveNewline(removeStart, removeEnd, cursor.checkType) + + // If we add the error at the same position but with a different fix + // range, only the fix range will be updated. + // + // a := 1 + // err := fn() + // + // if err != nil {} + // + // Should become + // + // a := 1 + // + // err := fn() + // if err != nil {} + cursor.Previous() + + // Add whitespace above the error assignment if there's a statement above. + if w.numberOfStatementsAbove(cursor) > 0 { + insertPos := w.lineStartOf(previousNode.Pos()) + w.addError(removeStart, insertPos, insertPos, messageMissingWhitespaceAbove, cursor.checkType) + } +} + +func (w *WSL) checkExprStmt(stmt *ast.ExprStmt, cursor *Cursor) { + w.maybeCheckExpr( + stmt, + cursor, + func(n ast.Node) (int, bool) { + _, ok := n.(*ast.ExprStmt) + return -1, !ok + }, + CheckExpr, + ) +} + +func (w *WSL) checkFor(stmt *ast.ForStmt, cursor *Cursor) { + w.maybeCheckBlock(stmt, stmt.Body, cursor, CheckFor) +} + +func (w *WSL) checkGo(stmt *ast.GoStmt, cursor *Cursor) { + w.maybeCheckExpr( + stmt, + cursor, + // We can cuddle any amount `go` statements so only check cuddling if + // the previous one isn't a `go` call. + func(n ast.Node) (int, bool) { + _, ok := n.(*ast.GoStmt) + return 1, !ok + }, + CheckGo, + ) +} + +func (w *WSL) checkIf(stmt *ast.IfStmt, cursor *Cursor, isElse bool) { + // if + w.checkBlock(stmt.Body, cursor) + + switch v := stmt.Else.(type) { + // else-if + case *ast.IfStmt: + w.checkIf(v, cursor, true) + + // else + case *ast.BlockStmt: + w.checkBlock(v, cursor) + } + + if _, ok := w.config.Checks[CheckIf]; !isElse && ok { + cursor.SetChecker(CheckIf) + w.checkCuddlingBlock(stmt, stmt.Body.List, []*ast.Ident{}, cursor, 1) + } else if _, ok := w.config.Checks[CheckErr]; !isElse && ok { + previousNode := cursor.PreviousNode() + + w.checkError( + w.numberOfStatementsAbove(cursor), + stmt, + previousNode, + cursor, + ) + } +} + +func (w *WSL) checkIncDec(stmt *ast.IncDecStmt, cursor *Cursor) { + if _, ok := w.config.Checks[CheckIncDec]; !ok { + return + } + + cursor.SetChecker(CheckIncDec) + + w.checkCuddlingWithoutIntersection(stmt, cursor) +} + +func (w *WSL) checkLabel(stmt *ast.LabeledStmt, cursor *Cursor) { + // We check the statement last because the statement is the same node as the + // label (it's a labeled statement). This means that we _first_ want to + // check any violations of cuddling the label (never cuddle label) before we + // actually check the inner statement. + // + // It's a subtle difference, but it makes the diagnostic make more sense. + // We do this by deferring the statmenet check so it happens last no matter + // if we have label checking enabled or not. + defer w.checkStmt(stmt.Stmt, cursor) + + if _, ok := w.config.Checks[CheckLabel]; !ok { + return + } + + cursor.SetChecker(CheckLabel) + + if w.numberOfStatementsAbove(cursor) == 0 { + return + } + + w.addErrorNeverAllow(stmt.Pos(), cursor.checkType) +} + +func (w *WSL) checkRange(stmt *ast.RangeStmt, cursor *Cursor) { + w.maybeCheckBlock(stmt, stmt.Body, cursor, CheckRange) +} + +func (w *WSL) checkReturn(stmt *ast.ReturnStmt, cursor *Cursor) { + if _, ok := w.config.Checks[CheckReturn]; !ok { + return + } + + cursor.SetChecker(CheckReturn) + + // There's only a return statement. + if cursor.Len() <= 1 { + return + } + + if w.numberOfStatementsAbove(cursor) == 0 { + return + } + + // If the distance between the first statement and the return statement is + // less than `n` LOC we're allowed to cuddle. + firstStmts := cursor.Nth(0) + if w.lineFor(stmt.End())-w.lineFor(firstStmts.Pos()) < w.config.BranchMaxLines { + return + } + + w.addErrorTooManyLines(stmt.Pos(), cursor.checkType) +} + +func (w *WSL) checkSelect(stmt *ast.SelectStmt, cursor *Cursor) { + w.maybeCheckBlock(stmt, stmt.Body, cursor, CheckSelect) +} + +func (w *WSL) checkSend(stmt *ast.SendStmt, cursor *Cursor) { + if _, ok := w.config.Checks[CheckSend]; !ok { + return + } + + cursor.SetChecker(CheckSend) + + var stmts []ast.Stmt + + ast.Inspect(stmt.Value, func(n ast.Node) bool { + if b, ok := n.(*ast.BlockStmt); ok { + stmts = b.List + return false + } + + return true + }) + + w.checkCuddlingBlock(stmt, stmts, []*ast.Ident{}, cursor, 1) +} + +func (w *WSL) checkSwitch(stmt *ast.SwitchStmt, cursor *Cursor) { + w.maybeCheckBlock(stmt, stmt.Body, cursor, CheckSwitch) +} + +func (w *WSL) checkTypeSwitch(stmt *ast.TypeSwitchStmt, cursor *Cursor) { + w.maybeCheckBlock(stmt, stmt.Body, cursor, CheckTypeSwitch) +} + +func (w *WSL) checkCaseTrailingNewline(body []ast.Stmt, cursor *Cursor) { + if len(body) == 0 { + return + } + + defer cursor.Save()() + + if !cursor.Next() { + return + } + + var nextCase ast.Node + + switch n := cursor.Stmt().(type) { + case *ast.CaseClause: + nextCase = n + case *ast.CommClause: + nextCase = n + default: + return + } + + var ( + firstStmt = body[0] + lastStmt = body[len(body)-1] + totalLines = w.lineFor(nextCase.Pos()) - w.lineFor(firstStmt.Pos()) + ) + + if totalLines < w.config.CaseMaxLines { + return + } + + var ( + lastStmtEndLine = w.lineFor(lastStmt.End()) + nextCaseLine = w.lineFor(nextCase.Pos()) + nextCaseCol = w.fset.PositionFor(nextCase.Pos(), false).Column + ) + + // Find transition point between trailing content (indented) and leading + // content (left-aligned). Trailing comments belong to current case, leading + // comments belong to next case. The blank line goes at the transition. + var ( + lastStmtOrCommentEnd = lastStmt.End() + nextCaseOrLeftAlignedComment = nextCase.Pos() + lastLeftAlignedCommentEnd = token.NoPos + ) + + for _, commentGroup := range w.file.Comments { + if commentGroup.Pos() >= nextCase.Pos() { + break + } + + if commentGroup.End() <= lastStmt.End() { + continue + } + + for _, comment := range commentGroup.List { + commentLine := w.lineFor(comment.Pos()) + if commentLine <= lastStmtEndLine || commentLine >= nextCaseLine { + continue + } + + col := w.fset.PositionFor(comment.Pos(), false).Column + if col <= nextCaseCol { + // Left-aligned: first one marks transition point + if lastLeftAlignedCommentEnd == token.NoPos { + nextCaseOrLeftAlignedComment = comment.Pos() + } + + lastLeftAlignedCommentEnd = comment.End() + } else { + // Indented: extend trailing content + lastStmtOrCommentEnd = comment.End() + } + } + } + + lastStmtOrCommentLine := w.lineFor(lastStmtOrCommentEnd) + nextCaseOrLeadingCommentLine := w.lineFor(nextCaseOrLeftAlignedComment) + + // Check for unnecessary blank line before case (leading comments should be flush). + if lastLeftAlignedCommentEnd != token.NoPos { + lastLeadingEndLine := w.lineFor(lastLeftAlignedCommentEnd) + + if lastLeadingEndLine < nextCaseLine-1 { + file := w.fset.File(nextCase.Pos()) + w.addErrorRemoveNewline(file.LineStart(lastLeadingEndLine+1), file.LineStart(nextCaseLine), CheckCaseTrailingNewline) + } + } + + // Already has a blank line at the boundary. + if nextCaseOrLeadingCommentLine > lastStmtOrCommentLine+1 { + return + } + + insertPos := w.lineStartOf(nextCaseOrLeftAlignedComment) + w.addError(lastStmtOrCommentEnd, insertPos, insertPos, messageMissingWhitespaceBelow, CheckCaseTrailingNewline) +} + +func (w *WSL) checkBlockLeadingNewline(body *ast.BlockStmt) { + w.checkLeadingNewline(body.Lbrace, body.List) +} + +func (w *WSL) checkCaseLeadingNewline(caseClause *ast.CaseClause) { + w.checkLeadingNewline(caseClause.Colon, caseClause.Body) +} + +func (w *WSL) checkCommLeadingNewline(commClause *ast.CommClause) { + w.checkLeadingNewline(commClause.Colon, commClause.Body) +} + +func (w *WSL) checkLeadingNewline(startPos token.Pos, body []ast.Stmt) { + if _, ok := w.config.Checks[CheckLeadingWhitespace]; !ok { + return + } + + if len(body) == 0 { + return + } + + var ( + openLine = w.lineFor(startPos) + firstStmtPos = body[0].Pos() + firstStmtLine = w.lineFor(firstStmtPos) + leadingComments []*ast.CommentGroup + ) + + for _, cg := range w.file.Comments { + if cg.Pos() >= firstStmtPos { + break + } + + if cg.Pos() > startPos { + leadingComments = append(leadingComments, cg) + } + } + + if len(leadingComments) == 0 { + if firstStmtLine := w.lineFor(firstStmtPos); firstStmtLine > openLine+1 { + file := w.fset.File(startPos) + w.addErrorRemoveNewline( + file.LineStart(openLine+1), + file.LineStart(firstStmtLine), + CheckLeadingWhitespace, + ) + } + + return + } + + var ( + firstContentLine = firstStmtLine + lastCommentEndLine = openLine + ) + + for _, comment := range leadingComments { + startLine := w.lineFor(comment.Pos()) + endLine := w.lineFor(comment.End()) + + if startLine > openLine && startLine < firstContentLine { + firstContentLine = startLine + } + + if endLine > lastCommentEndLine { + lastCommentEndLine = endLine + } + } + + file := w.fset.File(startPos) + + // Empty line after opening brace. + if firstContentLine > openLine+1 { + w.addErrorRemoveNewline( + file.LineStart(openLine+1), + file.LineStart(firstContentLine), + CheckLeadingWhitespace, + ) + } + + // Empty line between comments and first statement. + if lastCommentEndLine > openLine && firstStmtLine > lastCommentEndLine+1 { + w.addErrorRemoveNewline( + file.LineStart(lastCommentEndLine+1), + file.LineStart(firstStmtLine), + CheckLeadingWhitespace, + ) + } +} + +func (w *WSL) checkTrailingNewline(body *ast.BlockStmt) { + if _, ok := w.config.Checks[CheckTrailingWhitespace]; !ok { + return + } + + if len(body.List) == 0 { + return + } + + lastStmt := body.List[len(body.List)-1] + + // We don't want to force removal of the empty line for the last case since + // it can be used for consistency and readability. + if _, ok := lastStmt.(*ast.CaseClause); ok { + return + } + + lastContentPos := lastStmt.End() + + // Empty label statements need positional adjustment. #92 + if l, ok := lastStmt.(*ast.LabeledStmt); ok { + if _, ok := l.Stmt.(*ast.EmptyStmt); ok { + lastContentPos = lastStmt.Pos() + } + } + + // Find the last comment after last statement using position comparison. + for _, cg := range w.file.Comments { + if cg.End() <= lastContentPos { + continue + } + + if cg.Pos() >= body.Rbrace { + break + } + + if cg.End() < body.Rbrace { + lastContentPos = cg.End() + } + } + + closingLine := w.lineFor(body.Rbrace) + lastContentLine := w.lineFor(lastContentPos) + + if closingLine > lastContentLine+1 { + file := w.fset.File(body.Rbrace) + removeStart := file.LineStart(lastContentLine + 1) + removeEnd := file.LineStart(closingLine) + w.addErrorRemoveNewline(removeStart, removeEnd, CheckTrailingWhitespace) + } +} + +func (w *WSL) maybeGroupDecl(stmt *ast.DeclStmt, cursor *Cursor) bool { + firstNode := asGenDeclWithValueSpecs(cursor.PreviousNode()) + if firstNode == nil { + return false + } + + currentNode := asGenDeclWithValueSpecs(stmt) + if currentNode == nil { + return false + } + + // Both are not same type, e.g. `const` or `var` + if firstNode.Tok != currentNode.Tok { + return false + } + + group := &ast.GenDecl{ + Tok: firstNode.Tok, + Lparen: 1, + Specs: firstNode.Specs, + } + + group.Specs = append(group.Specs, currentNode.Specs...) + + reportNodes := []ast.Node{currentNode} + lastNode := currentNode + + for { + nextPeeked := cursor.NextNode() + if nextPeeked == nil { + break + } + + if w.lineFor(lastNode.End()) < w.lineFor(nextPeeked.Pos())-1 { + break + } + + nextNode := asGenDeclWithValueSpecs(nextPeeked) + if nextNode == nil { + break + } + + if nextNode.Tok != firstNode.Tok { + break + } + + cursor.Next() + + group.Specs = append(group.Specs, nextNode.Specs...) + reportNodes = append(reportNodes, nextNode) + lastNode = nextNode + } + + var buf bytes.Buffer + if err := format.Node(&buf, token.NewFileSet(), group); err != nil { + return false + } + + // We add a diagnostic to every subsequent statement to properly represent + // the violations. Duplicate fixes for the same range is fine. + for _, n := range reportNodes { + w.groupedDecls[n.End()] = struct{}{} + + w.addErrorWithMessageAndFix( + n.Pos(), + firstNode.Pos(), + lastNode.End(), + fmt.Sprintf("%s (never cuddle %s)", messageMissingWhitespaceAbove, CheckDecl), + buf.Bytes(), + ) + } + + return true +} + +func (w *WSL) maybeCheckBlock( + node ast.Node, + blockStmt *ast.BlockStmt, + cursor *Cursor, + check CheckType, +) { + w.checkBlock(blockStmt, cursor) + + if _, ok := w.config.Checks[check]; ok { + cursor.SetChecker(check) + + var ( + blockList []ast.Stmt + allowedIdents []*ast.Ident + ) + + if check != CheckSwitch && check != CheckTypeSwitch && check != CheckSelect { + blockList = blockStmt.List + } else { + allowedIdents = w.identsFromCaseArms(node) + } + + w.checkCuddlingBlock(node, blockList, allowedIdents, cursor, 1) + } +} + +func (w *WSL) maybeCheckExpr( + node ast.Node, + cursor *Cursor, + predicate func(ast.Node) (int, bool), + check CheckType, +) { + if _, ok := w.config.Checks[check]; ok { + cursor.SetChecker(check) + previousNode := cursor.PreviousNode() + + if n, ok := predicate(previousNode); ok { + w.checkCuddling(node, cursor, n) + } + } +} + +// numberOfStatementsAbove will find out how many lines above the cursor's +// current statement there is without any newlines between. +func (w *WSL) numberOfStatementsAbove(cursor *Cursor) int { + defer cursor.Save()() + + statementsWithoutNewlines := 0 + currentStmtStartLine := w.lineFor(cursor.Stmt().Pos()) + + for cursor.Previous() { + previousStmtEndLine := w.lineFor(cursor.Stmt().End()) + if previousStmtEndLine != currentStmtStartLine-1 { + break + } + + currentStmtStartLine = w.lineFor(cursor.Stmt().Pos()) + statementsWithoutNewlines++ + } + + return statementsWithoutNewlines +} + +func (w *WSL) lineFor(pos token.Pos) int { + return w.fset.PositionFor(pos, false).Line +} + +func (w *WSL) lineStartOf(pos token.Pos) token.Pos { + return w.fset.File(pos).LineStart(w.lineFor(pos)) +} + +func (w *WSL) implementsErr(node *ast.Ident) bool { + typeInfo := w.typeInfo.TypeOf(node) + if typeInfo == nil { + return false + } + + errorType, ok := types.Universe.Lookup("error").Type().Underlying().(*types.Interface) + if !ok { + return false + } + + return types.Implements(typeInfo, errorType) +} + +func (w *WSL) commentOnLineAfterNodePos(node ast.Node) token.Pos { + nodeEndLine := w.lineFor(node.End()) + + for _, cg := range w.file.Comments { + if cg.End() <= node.End() { + continue + } + + commentLine := w.lineFor(cg.Pos()) + if commentLine == nodeEndLine { + continue + } + + if commentLine == nodeEndLine+1 { + return cg.Pos() + } + + break + } + + return token.NoPos +} + +func (w *WSL) addErrorInvalidTypeCuddle(pos token.Pos, ct CheckType) { + reportMessage := fmt.Sprintf("%s (invalid statement above %s)", messageMissingWhitespaceAbove, ct) + insertPos := w.lineStartOf(pos) + w.addErrorWithMessage(pos, insertPos, insertPos, reportMessage) +} + +func (w *WSL) addErrorTooManyStatements(pos token.Pos, ct CheckType) { + reportMessage := fmt.Sprintf("%s (too many statements above %s)", messageMissingWhitespaceAbove, ct) + insertPos := w.lineStartOf(pos) + w.addErrorWithMessage(pos, insertPos, insertPos, reportMessage) +} + +func (w *WSL) addErrorNoIntersection(pos token.Pos, ct CheckType) { + reportMessage := fmt.Sprintf("%s (no shared variables above %s)", messageMissingWhitespaceAbove, ct) + insertPos := w.lineStartOf(pos) + w.addErrorWithMessage(pos, insertPos, insertPos, reportMessage) +} + +func (w *WSL) addErrorTooManyLines(pos token.Pos, ct CheckType) { + reportMessage := fmt.Sprintf("%s (too many lines above %s)", messageMissingWhitespaceAbove, ct) + insertPos := w.lineStartOf(pos) + w.addErrorWithMessage(pos, insertPos, insertPos, reportMessage) +} + +func (w *WSL) addErrorNeverAllow(pos token.Pos, ct CheckType) { + reportMessage := fmt.Sprintf("%s (never cuddle %s)", messageMissingWhitespaceAbove, ct) + insertPos := w.lineStartOf(pos) + w.addErrorWithMessage(pos, insertPos, insertPos, reportMessage) +} + +func (w *WSL) addError(report, start, end token.Pos, message string, ct CheckType) { + reportMessage := fmt.Sprintf("%s (%s)", message, ct) + w.addErrorWithMessage(report, start, end, reportMessage) +} + +func (w *WSL) addErrorRemoveNewline(start, end token.Pos, ct CheckType) { + reportMessage := fmt.Sprintf("%s (%s)", messageRemoveWhitespace, ct) + w.addErrorWithMessageAndFix(start, start, end, reportMessage, []byte{}) +} + +func (w *WSL) addErrorWithMessage(report, start, end token.Pos, message string) { + w.addErrorWithMessageAndFix(report, start, end, message, []byte("\n")) +} + +func (w *WSL) addErrorWithMessageAndFix(report, start, end token.Pos, message string, fix []byte) { + iss, ok := w.issues[report] + if !ok { + iss = issue{ + message: message, + fixRanges: []fixRange{}, + } + } + + iss.fixRanges = append(iss.fixRanges, fixRange{ + fixRangeStart: start, + fixRangeEnd: end, + fix: fix, + }) + + w.issues[report] = iss +} + +func asGenDeclWithValueSpecs(n ast.Node) *ast.GenDecl { + decl, ok := n.(*ast.DeclStmt) + if !ok { + return nil + } + + genDecl, ok := decl.Decl.(*ast.GenDecl) + if !ok { + return nil + } + + for _, spec := range genDecl.Specs { + // We only care about value specs and not type specs or import + // specs. We will never see any import specs but type specs we just + // separate with an empty line as usual. + valueSpec, ok := spec.(*ast.ValueSpec) + if !ok { + return nil + } + + // It's very hard to get comments right in the ast and with the current + // way the ast package works we simply don't support grouping at all if + // there are any comments related to the node. + if valueSpec.Doc != nil || valueSpec.Comment != nil { + return nil + } + } + + return genDecl +} + +func (w *WSL) hasIntersection(a, b ast.Node) bool { + return len(w.nodeIdentIntersection(a, b)) > 0 +} + +func (w *WSL) nodeIdentIntersection(a, b ast.Node) []*ast.Ident { + aI := w.identsFromNode(a, true) + bI := w.identsFromNode(b, true) + + return identIntersection(aI, bI) +} + +func identIntersection(a, b []*ast.Ident) []*ast.Ident { + intersects := []*ast.Ident{} + + for _, as := range a { + for _, bs := range b { + if as.Name == bs.Name { + intersects = append(intersects, as) + } + } + } + + return intersects +} + +func isTypeOrPredeclConst(obj types.Object) bool { + switch o := obj.(type) { + case *types.TypeName: + // Covers predeclared types ("string", "int", ...) and user types. + return true + case *types.Const: + // true/false/iota are universe consts. + return o.Parent() == types.Universe + case *types.Nil: + return true + case *types.PkgName: + // Skip package qualifiers like "fmt" in fmt.Println + return true + default: + return false + } +} + +// identsFromNode returns all *ast.Ident in a node except: +// - type names (types.TypeName) +// - builtin constants from the universe (true, false, iota) +// - nil (*types.Nil) +// - package names (types.PkgName) +// - the blank identifier "_" +func (w *WSL) identsFromNode(node ast.Node, skipBlock bool) []*ast.Ident { + var ( + idents []*ast.Ident + seen = map[string]struct{}{} + ) + + if node == nil { + return idents + } + + addIdent := func(ident *ast.Ident) { + if ident == nil { + return + } + + name := ident.Name + if name == "" || name == "_" { + return + } + + if _, ok := seen[name]; ok { + return + } + + idents = append(idents, ident) + seen[name] = struct{}{} + } + + ast.Inspect(node, func(n ast.Node) bool { + if skipBlock { + if _, ok := n.(*ast.BlockStmt); ok { + return false + } + } + + ident, ok := n.(*ast.Ident) + if !ok { + return true + } + + // Prefer Uses over Defs; fall back to Defs if not a use site. + var typesObject types.Object + if obj := w.typeInfo.Uses[ident]; obj != nil { + typesObject = obj + } else if obj := w.typeInfo.Defs[ident]; obj != nil { + typesObject = obj + } + + // Unresolved (could be a build-tag or syntax artifact). Keep it. + if typesObject == nil { + addIdent(ident) + return true + } + + if isTypeOrPredeclConst(typesObject) { + return true + } + + addIdent(ident) + + return true + }) + + return idents +} + +func (w *WSL) identsFromCaseArms(node ast.Node) []*ast.Ident { + var ( + idents []*ast.Ident + nodes []ast.Stmt + seen = map[string]struct{}{} + + addUnseen = func(node ast.Node) { + for _, ident := range w.identsFromNode(node, true) { + if _, ok := seen[ident.Name]; ok { + continue + } + + seen[ident.Name] = struct{}{} + idents = append(idents, ident) + } + } + ) + + switch v := node.(type) { + case *ast.SwitchStmt: + nodes = v.Body.List + case *ast.TypeSwitchStmt: + nodes = v.Body.List + case *ast.SelectStmt: + nodes = v.Body.List + default: + return idents + } + + for _, node := range nodes { + switch n := node.(type) { + case *ast.CommClause: + addUnseen(n.Comm) + case *ast.CaseClause: + for _, n := range n.List { + addUnseen(n) + } + default: + continue + } + } + + return idents +} + +// hasSelectorCall checks if node contains a selector call with one of the given names. +func hasSelectorCall(node ast.Node, selectorNames []string) bool { + var found bool + + ast.Inspect(node, func(n ast.Node) bool { + if found { + return false // Already found + } + + if _, ok := n.(*ast.BlockStmt); ok { + return false + } + + if sel, ok := n.(*ast.SelectorExpr); ok { + found = slices.Contains(selectorNames, sel.Sel.Name) + return false + } + + return true + }) + + return found +} + +func (w *WSL) isLockOrUnlock(current, previous ast.Node) bool { + // If we're an ExprStmt (e.g. X()), we check if we're calling `Unlock` or + // `RWUnlock`. No matter how deep this is or what previous statement was, we + // allow this. + // + // mu.Lock() + // [ANY BLOCK] + // mu.Unlock() + if _, ok := current.(*ast.ExprStmt); ok { + return hasSelectorCall(current, []string{"Unlock", "RWUnlock"}) + } + + if previous != nil { + return hasSelectorCall(previous, []string{"Lock", "RWLock", "TryLock"}) + } + + return false +} + +// isErrNotNilCheck returns the error identifier if stmt is an `if err != nil` +// or `if err == nil` check without an init statement, nil otherwise. +func (w *WSL) isErrNotNilCheck(stmt ast.Node) *ast.Ident { + ifStmt, ok := stmt.(*ast.IfStmt) + if !ok { + return nil + } + + // If the error checking has an init condition (e.g. if err := f();) we + // don't consider it an error check since the error is assigned on this row. + if ifStmt.Init != nil { + return nil + } + + // The condition must be a binary expression (X OP Y) + binaryExpr, ok := ifStmt.Cond.(*ast.BinaryExpr) + if !ok { + return nil + } + + // We must do not equal or equal comparison (!= or ==) + if binaryExpr.Op != token.NEQ && binaryExpr.Op != token.EQL { + return nil + } + + xIdent, ok := binaryExpr.X.(*ast.Ident) + if !ok { + return nil + } + + // X is not an error so it's not error checking + if !w.implementsErr(xIdent) { + return nil + } + + yIdent, ok := binaryExpr.Y.(*ast.Ident) + if !ok { + return nil + } + + // Y is not compared with `nil` + if yIdent.Name != "nil" { + return nil + } + + return xIdent +} diff --git a/vendor/github.com/butuzov/ireturn/analyzer/analyzer.go b/vendor/github.com/butuzov/ireturn/analyzer/analyzer.go index f68170fb3..86cc464c6 100644 --- a/vendor/github.com/butuzov/ireturn/analyzer/analyzer.go +++ b/vendor/github.com/butuzov/ireturn/analyzer/analyzer.go @@ -8,12 +8,12 @@ import ( "strings" "sync" - "github.com/butuzov/ireturn/analyzer/internal/config" - "github.com/butuzov/ireturn/analyzer/internal/types" - "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/ast/inspector" + + "github.com/butuzov/ireturn/analyzer/internal/config" + "github.com/butuzov/ireturn/analyzer/internal/types" ) const name string = "ireturn" // linter name @@ -23,11 +23,11 @@ type validator interface { } type analyzer struct { - once sync.Once - mu sync.RWMutex - handler validator - err error - diabledNolint bool + once sync.Once + mu sync.RWMutex + handler validator + err error + disabledNolint bool found []analysis.Diagnostic } @@ -63,7 +63,7 @@ func (a *analyzer) run(pass *analysis.Pass) (interface{}, error) { } // 003. Is it allowed to be checked? - if !a.diabledNolint && hasDisallowDirective(f.Doc) { + if !a.disabledNolint && hasDisallowDirective(f.Doc) { return } @@ -115,7 +115,7 @@ func (a *analyzer) readConfiguration(fs *flag.FlagSet) { // First: checking nonolint directive val := fs.Lookup("nonolint") if val != nil { - a.diabledNolint = fs.Lookup("nonolint").Value.String() == "true" + a.disabledNolint = fs.Lookup("nonolint").Value.String() == "true" } // Second: validators implementation next @@ -128,7 +128,7 @@ func (a *analyzer) readConfiguration(fs *flag.FlagSet) { } func NewAnalyzer() *analysis.Analyzer { - a := analyzer{} //nolint: exhaustivestruct + a := analyzer{} return &analysis.Analyzer{ Name: name, @@ -196,13 +196,14 @@ func filterInterfaces(p *analysis.Pass, ft *ast.FuncType, di map[string]struct{} typeParams := val.String() prefix, suffix := "interface{", "}" - if strings.HasPrefix(typeParams, prefix) { // nolint: gosimple + if strings.HasPrefix(typeParams, prefix) { //nolint:gosimple typeParams = typeParams[len(prefix):] } if strings.HasSuffix(typeParams, suffix) { typeParams = typeParams[:len(typeParams)-1] } + // todo: write test for this (1.18&1.19 only?) goVersion := runtime.Version() if strings.HasPrefix(goVersion, "go1.18") || strings.HasPrefix(goVersion, "go1.19") { typeParams = strings.ReplaceAll(typeParams, "|", " | ") diff --git a/vendor/github.com/butuzov/ireturn/analyzer/internal/config/allow.go b/vendor/github.com/butuzov/ireturn/analyzer/internal/config/allow.go index 6a294ca35..da101c786 100644 --- a/vendor/github.com/butuzov/ireturn/analyzer/internal/config/allow.go +++ b/vendor/github.com/butuzov/ireturn/analyzer/internal/config/allow.go @@ -2,7 +2,7 @@ package config import "github.com/butuzov/ireturn/analyzer/internal/types" -// allowConfig specifies a list of interfaces (keywords, patters and regular expressions) +// allowConfig specifies a list of interfaces (keywords, patterns and regular expressions) // that are allowed by ireturn as valid to return, any non listed interface are rejected. type allowConfig struct { *defaultConfig diff --git a/vendor/github.com/butuzov/ireturn/analyzer/internal/config/new.go b/vendor/github.com/butuzov/ireturn/analyzer/internal/config/new.go index 6aa04e52e..d6914af86 100644 --- a/vendor/github.com/butuzov/ireturn/analyzer/internal/config/new.go +++ b/vendor/github.com/butuzov/ireturn/analyzer/internal/config/new.go @@ -10,7 +10,6 @@ import ( var ErrCollisionOfInterests = errors.New("can't have both `-accept` and `-reject` specified at same time") -// nolint: exhaustivestruct func DefaultValidatorConfig() *allowConfig { return allowAll([]string{ types.NameEmpty, // "empty": empty interfaces (interface{}) diff --git a/vendor/github.com/butuzov/ireturn/analyzer/internal/config/reject.go b/vendor/github.com/butuzov/ireturn/analyzer/internal/config/reject.go index bef6913bb..b2cde910c 100644 --- a/vendor/github.com/butuzov/ireturn/analyzer/internal/config/reject.go +++ b/vendor/github.com/butuzov/ireturn/analyzer/internal/config/reject.go @@ -2,7 +2,7 @@ package config import "github.com/butuzov/ireturn/analyzer/internal/types" -// rejectConfig specifies a list of interfaces (keywords, patters and regular expressions) +// rejectConfig specifies a list of interfaces (keywords, patterns and regular expressions) // that are rejected by ireturn as valid to return, any non listed interface are allowed. type rejectConfig struct { *defaultConfig diff --git a/vendor/github.com/butuzov/ireturn/analyzer/internal/types/iface.go b/vendor/github.com/butuzov/ireturn/analyzer/internal/types/iface.go index 5e576374d..0f4286515 100644 --- a/vendor/github.com/butuzov/ireturn/analyzer/internal/types/iface.go +++ b/vendor/github.com/butuzov/ireturn/analyzer/internal/types/iface.go @@ -47,7 +47,7 @@ func (i IFace) HashString() string { } func (i IFace) ExportDiagnostic() analysis.Diagnostic { - return analysis.Diagnostic{ //nolint: exhaustivestruct + return analysis.Diagnostic{ Pos: i.Pos, Message: i.String(), } diff --git a/vendor/github.com/butuzov/ireturn/analyzer/std.go b/vendor/github.com/butuzov/ireturn/analyzer/std.go index cac464612..ce007be8b 100644 --- a/vendor/github.com/butuzov/ireturn/analyzer/std.go +++ b/vendor/github.com/butuzov/ireturn/analyzer/std.go @@ -200,4 +200,15 @@ var std = map[string]struct{}{ // added in Go v1.22 in compare to v1.21 (docker image) "go/version": {}, "math/rand/v2": {}, + // added in Go v1.23 in compare to v1.22 (docker image) + "iter": {}, + "structs": {}, + "unique": {}, + // added in Go v1.24 in compare to v1.23 (docker image) + "crypto/fips140": {}, + "crypto/hkdf": {}, + "crypto/mlkem": {}, + "crypto/pbkdf2": {}, + "crypto/sha3": {}, + "weak": {}, } diff --git a/vendor/github.com/butuzov/mirror/MIRROR_FUNCS.md b/vendor/github.com/butuzov/mirror/MIRROR_FUNCS.md index 3dcc01e96..da30c8e00 100644 --- a/vendor/github.com/butuzov/mirror/MIRROR_FUNCS.md +++ b/vendor/github.com/butuzov/mirror/MIRROR_FUNCS.md @@ -1,201 +1,55 @@ - -func (*bufio.Writer) Write([]byte) (int, error) -func (*bufio.Writer) WriteString(string) (int, error) - - -func (*bufio.Writer) WriteRune(rune) (int, error) -func (*bufio.Writer) WriteString(string) (int, error) - - -func (*bytes.Buffer) Write([]byte) (int, error) -func (*bytes.Buffer) WriteString(string) (int, error) - - -func (*bytes.Buffer) WriteRune(rune) (int, error) -func (*bytes.Buffer) WriteString(string) (int, error) - - -func bytes.Compare([]byte, []byte) int -func strings.Compare(string, string) int - - -func bytes.Contains([]byte, []byte) bool -func strings.Contains(string, string) bool - - -func bytes.ContainsAny([]byte, string) bool -func strings.ContainsAny(string, string) bool - - -func bytes.ContainsRune([]byte, byte) bool -func strings.ContainsRune(string, byte) bool - - -func bytes.Count([]byte, []byte) int -func strings.Count(string, string) int - - -func bytes.EqualFold([]byte, []byte) bool -func strings.EqualFold(string, string) bool - - -func bytes.HasPrefix([]byte, []byte) bool -func strings.HasPrefix(string, string) bool - - -func bytes.HasSuffix([]byte, []byte) bool -func strings.HasSuffix(string, string) bool - - -func bytes.Index([]byte, []byte) int -func strings.Index(string, string) int - - -func bytes.IndexAny([]byte, string) int -func strings.IndexAny(string, string) int - - -func bytes.IndexByte([]byte, byte) int -func strings.IndexByte(string, byte) int - - -func bytes.IndexFunc([]byte, func(rune) bool) int -func strings.IndexFunc(string, func(rune) bool) int - - -func bytes.IndexRune([]byte, rune) int -func strings.IndexRune(string, rune) int - - -func bytes.LastIndex([]byte, []byte) int -func strings.LastIndex(string, string) int - - -func bytes.LastIndexAny([]byte, string) int -func strings.LastIndexAny(string, string) int - - -func bytes.LastIndexByte([]byte, byte) int -func strings.LastIndexByte(string, byte) int - - -func bytes.LastIndexFunc([]byte, func(rune) bool) int -func strings.LastIndexFunc(string, func(rune) bool) int - - -func bytes.NewBuffer([]byte) *bytes.Buffer -func bytes.NewBufferString(string) *bytes.Buffer - - -func (*httptest.ResponseRecorder) Write([]byte) (int, error) -func (*httptest.ResponseRecorder) WriteString(string) (int, error) - - -func (*maphash.Hash) Write([]byte) (int, error) -func (*maphash.Hash) WriteString(string) (int, error) - - -func (*os.File) Write([]byte) (int, error) -func (*os.File) WriteString(string) (int, error) - - -func regexp.Match(string, []byte) (bool, error) -func regexp.MatchString(string, string) (bool, error) - - -func (*regexp.Regexp) FindAllIndex([]byte, int) [][]int -func (*regexp.Regexp) FindAllStringIndex(string, int) [][]int - - -func (*regexp.Regexp) FindAllSubmatchIndex([]byte, int) [][]int -func (*regexp.Regexp) FindAllStringSubmatchIndex(string, int) [][]int - - -func (*regexp.Regexp) FindIndex([]byte) []int -func (*regexp.Regexp) FindStringIndex(string) []int - - -func (*regexp.Regexp) FindSubmatchIndex([]byte) []int -func (*regexp.Regexp) FindStringSubmatchIndex(string) []int - - -func (*regexp.Regexp) Match([]byte) bool -func (*regexp.Regexp) MatchString(string) bool - - -func (*strings.Builder) Write([]byte) (int, error) -func (*strings.Builder) WriteString(string) (int, error) - - -func (*strings.Builder) WriteRune(rune) (int, error) -func (*strings.Builder) WriteString(string) (int, error) - - -func strings.Compare(string) int -func bytes.Compare([]byte) int - - -func strings.Contains(string) bool -func bytes.Contains([]byte) bool - - -func strings.ContainsAny(string) bool -func bytes.ContainsAny([]byte) bool - - -func strings.ContainsRune(string) bool -func bytes.ContainsRune([]byte) bool - - -func strings.EqualFold(string) bool -func bytes.EqualFold([]byte) bool - - -func strings.HasPrefix(string) bool -func bytes.HasPrefix([]byte) bool - - -func strings.HasSuffix(string) bool -func bytes.HasSuffix([]byte) bool - - -func strings.Index(string) int -func bytes.Index([]byte) int - - -func strings.IndexFunc(string, func(r rune) bool) int -func bytes.IndexFunc([]byte, func(r rune) bool) int - - -func strings.LastIndex(string) int -func bytes.LastIndex([]byte) int - - -func strings.LastIndexAny(string) int -func bytes.LastIndexAny([]byte) int - - -func strings.LastIndexFunc(string, func(r rune) bool) int -func bytes.LastIndexFunc([]byte, func(r rune) bool) int - - -func utf8.DecodeLastRune([]byte) (rune, int) -func utf8.DecodeLastRuneInString(string) (rune, int) - - -func utf8.DecodeRune([]byte) (rune, int) -func utf8.DecodeRuneInString(string) (rune, int) - - -func utf8.FullRune([]byte) bool -func utf8.FullRuneInString(string) bool - - -func utf8.RuneCount([]byte) int -func utf8.RuneCountInString(string) int - - -func utf8.Valid([]byte) bool -func utf8.ValidString(string) bool - + +| Function | Mirror | +|----------|--------| +| `func (*bufio.Writer) Write([]byte) (int, error)` | `func (*bufio.Writer) WriteString(string) (int, error)` | +| `func (*bufio.Writer) WriteRune(rune) (int, error)` | `func (*bufio.Writer) WriteString(string) (int, error)` | +| `func (*bytes.Buffer) Write([]byte) (int, error)` | `func (*bytes.Buffer) WriteString(string) (int, error)` | +| `func (*bytes.Buffer) WriteRune(rune) (int, error)` | `func (*bytes.Buffer) WriteString(string) (int, error)` | +| `func bytes.Compare([]byte, []byte) int` | `func strings.Compare(string, string) int` | +| `func bytes.Contains([]byte, []byte) bool` | `func strings.Contains(string, string) bool` | +| `func bytes.ContainsAny([]byte, string) bool` | `func strings.ContainsAny(string, string) bool` | +| `func bytes.ContainsRune([]byte, byte) bool` | `func strings.ContainsRune(string, byte) bool` | +| `func bytes.Count([]byte, []byte) int` | `func strings.Count(string, string) int` | +| `func bytes.EqualFold([]byte, []byte) bool` | `func strings.EqualFold(string, string) bool` | +| `func bytes.HasPrefix([]byte, []byte) bool` | `func strings.HasPrefix(string, string) bool` | +| `func bytes.HasSuffix([]byte, []byte) bool` | `func strings.HasSuffix(string, string) bool` | +| `func bytes.Index([]byte, []byte) int` | `func strings.Index(string, string) int` | +| `func bytes.IndexAny([]byte, string) int` | `func strings.IndexAny(string, string) int` | +| `func bytes.IndexByte([]byte, byte) int` | `func strings.IndexByte(string, byte) int` | +| `func bytes.IndexFunc([]byte, func(rune) bool) int` | `func strings.IndexFunc(string, func(rune) bool) int` | +| `func bytes.IndexRune([]byte, rune) int` | `func strings.IndexRune(string, rune) int` | +| `func bytes.LastIndex([]byte, []byte) int` | `func strings.LastIndex(string, string) int` | +| `func bytes.LastIndexAny([]byte, string) int` | `func strings.LastIndexAny(string, string) int` | +| `func bytes.LastIndexByte([]byte, byte) int` | `func strings.LastIndexByte(string, byte) int` | +| `func bytes.LastIndexFunc([]byte, func(rune) bool) int` | `func strings.LastIndexFunc(string, func(rune) bool) int` | +| `func bytes.NewBuffer([]byte) *bytes.Buffer` | `func bytes.NewBufferString(string) *bytes.Buffer` | +| `func (*httptest.ResponseRecorder) Write([]byte) (int, error)` | `func (*httptest.ResponseRecorder) WriteString(string) (int, error)` | +| `func maphash.Bytes([]byte) uint64` | `func maphash.String(string) uint64` | +| `func (*maphash.Hash) Write([]byte) (int, error)` | `func (*maphash.Hash) WriteString(string) (int, error)` | +| `func (*os.File) Write([]byte) (int, error)` | `func (*os.File) WriteString(string) (int, error)` | +| `func regexp.Match(string, []byte) (bool, error)` | `func regexp.MatchString(string, string) (bool, error)` | +| `func (*regexp.Regexp) FindAllIndex([]byte, int) [][]int` | `func (*regexp.Regexp) FindAllStringIndex(string, int) [][]int` | +| `func (*regexp.Regexp) FindAllSubmatchIndex([]byte, int) [][]int` | `func (*regexp.Regexp) FindAllStringSubmatchIndex(string, int) [][]int` | +| `func (*regexp.Regexp) FindIndex([]byte) []int` | `func (*regexp.Regexp) FindStringIndex(string) []int` | +| `func (*regexp.Regexp) FindSubmatchIndex([]byte) []int` | `func (*regexp.Regexp) FindStringSubmatchIndex(string) []int` | +| `func (*regexp.Regexp) Match([]byte) bool` | `func (*regexp.Regexp) MatchString(string) bool` | +| `func (*strings.Builder) Write([]byte) (int, error)` | `func (*strings.Builder) WriteString(string) (int, error)` | +| `func (*strings.Builder) WriteRune(rune) (int, error)` | `func (*strings.Builder) WriteString(string) (int, error)` | +| `func strings.Compare(string) int` | `func bytes.Compare([]byte) int` | +| `func strings.Contains(string) bool` | `func bytes.Contains([]byte) bool` | +| `func strings.ContainsAny(string) bool` | `func bytes.ContainsAny([]byte) bool` | +| `func strings.ContainsRune(string) bool` | `func bytes.ContainsRune([]byte) bool` | +| `func strings.EqualFold(string) bool` | `func bytes.EqualFold([]byte) bool` | +| `func strings.HasPrefix(string) bool` | `func bytes.HasPrefix([]byte) bool` | +| `func strings.HasSuffix(string) bool` | `func bytes.HasSuffix([]byte) bool` | +| `func strings.Index(string) int` | `func bytes.Index([]byte) int` | +| `func strings.IndexFunc(string, func(r rune) bool) int` | `func bytes.IndexFunc([]byte, func(r rune) bool) int` | +| `func strings.LastIndex(string) int` | `func bytes.LastIndex([]byte) int` | +| `func strings.LastIndexAny(string) int` | `func bytes.LastIndexAny([]byte) int` | +| `func strings.LastIndexFunc(string, func(r rune) bool) int` | `func bytes.LastIndexFunc([]byte, func(r rune) bool) int` | +| `func utf8.DecodeLastRune([]byte) (rune, int)` | `func utf8.DecodeLastRuneInString(string) (rune, int)` | +| `func utf8.DecodeRune([]byte) (rune, int)` | `func utf8.DecodeRuneInString(string) (rune, int)` | +| `func utf8.FullRune([]byte) bool` | `func utf8.FullRuneInString(string) bool` | +| `func utf8.RuneCount([]byte) int` | `func utf8.RuneCountInString(string) int` | +| `func utf8.Valid([]byte) bool` | `func utf8.ValidString(string) bool` | diff --git a/vendor/github.com/butuzov/mirror/Makefile b/vendor/github.com/butuzov/mirror/Makefile index ac267208f..dab6f160a 100644 --- a/vendor/github.com/butuzov/mirror/Makefile +++ b/vendor/github.com/butuzov/mirror/Makefile @@ -10,7 +10,8 @@ endef # Generate Artifacts ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ generate: ## Generate Assets - $(MAKE) + $(MAKE) generate-tests + $(MAKE) generate-mirror-table generate-tests: ## Generates Assets at testdata go run ./cmd/internal/tests/ "$(PWD)/testdata" @@ -52,7 +53,7 @@ tests-summary: bin/tparse lints: ## Run golangci-lint lints: bin/golangci-lint lints: - golangci-lint run --no-config ./... --skip-dirs "^(cmd|testdata)" + golangci-lint run --no-config ./... --exclude-dirs "^(cmd|testdata)" cover: ## Run Coverage @@ -71,8 +72,8 @@ bin/tparse: INSTALL_URL=github.com/mfridman/tparse@v0.13.2 bin/tparse: $(call install_go_bin, tparse, $(INSTALL_URL)) -bin/golangci-lint: ## Installs golangci-lint@v1.55.2 (if not exists) -bin/golangci-lint: INSTALL_URL=github.com/golangci/golangci-lint@v1.55.2 +bin/golangci-lint: ## Installs golangci-lint@v1.62.0 (if not exists) +bin/golangci-lint: INSTALL_URL=github.com/golangci/golangci-lint@v1.62.0 bin/golangci-lint: $(call install_go_bin, golangci-lint, $(INSTALL_URL)) @@ -99,7 +100,7 @@ help: dep-gawk @ echo "" -# Helper Mehtods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Helper Methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ dep-gawk: @ if [ -z "$(shell command -v gawk)" ]; then \ if [ -x /usr/local/bin/brew ]; then $(MAKE) _brew_gawk_install; exit 0; fi; \ @@ -111,21 +112,21 @@ dep-gawk: fi _brew_gawk_install: - @ echo "Instaling gawk using brew... " + @ echo "Installing gawk using brew... " @ brew install gawk --quiet @ echo "done" _ubuntu_gawk_install: - @ echo "Instaling gawk using apt-get... " + @ echo "Installing gawk using apt-get... " @ apt-get -q install gawk -y @ echo "done" _alpine_gawk_install: - @ echo "Instaling gawk using yum... " + @ echo "Installing gawk using yum... " @ apk add --update --no-cache gawk @ echo "done" _centos_gawk_install: - @ echo "Instaling gawk using yum... " + @ echo "Installing gawk using yum... " @ yum install -q -y gawk; @ echo "done" diff --git a/vendor/github.com/butuzov/mirror/analyzer.go b/vendor/github.com/butuzov/mirror/analyzer.go index 13ded46c6..b15019ce1 100644 --- a/vendor/github.com/butuzov/mirror/analyzer.go +++ b/vendor/github.com/butuzov/mirror/analyzer.go @@ -44,9 +44,9 @@ func Run(pass *analysis.Pass, withTests bool) []*checker.Violation { BytesFunctions, BytesBufferMethods, RegexpFunctions, RegexpRegexpMethods, StringFunctions, StringsBuilderMethods, + MaphashMethods, MaphashFunctions, BufioMethods, HTTPTestMethods, - OsFileMethods, MaphashMethods, - UTF8Functions, + OsFileMethods, UTF8Functions, ) check.Type = checker.WrapType(pass.TypesInfo) diff --git a/vendor/github.com/butuzov/mirror/checkers_maphash.go b/vendor/github.com/butuzov/mirror/checkers_maphash.go index 0aa43ff7b..345a64123 100644 --- a/vendor/github.com/butuzov/mirror/checkers_maphash.go +++ b/vendor/github.com/butuzov/mirror/checkers_maphash.go @@ -2,35 +2,66 @@ package mirror import "github.com/butuzov/mirror/internal/checker" -var MaphashMethods = []checker.Violation{ - { // (*hash/maphash).Write - Targets: checker.Bytes, - Type: checker.Method, - Package: "hash/maphash", - Struct: "Hash", - Caller: "Write", - Args: []int{0}, - AltCaller: "WriteString", +var ( + MaphashFunctions = []checker.Violation{ + { // maphash.Bytes + Targets: checker.Bytes, + Type: checker.Function, + Package: "hash/maphash", + Caller: "Bytes", + Args: []int{1}, + AltCaller: "String", - Generate: &checker.Generate{ - PreCondition: `h := maphash.Hash{}`, - Pattern: `Write($0)`, - Returns: []string{"int", "error"}, + Generate: &checker.Generate{ + Pattern: `Bytes(maphash.MakeSeed(), $0)`, + Returns: []string{"uint64"}, + }, }, - }, - { // (*hash/maphash).WriteString - Targets: checker.Strings, - Type: checker.Method, - Package: "hash/maphash", - Struct: "Hash", - Caller: "WriteString", - Args: []int{0}, - AltCaller: "Write", + { // maphash.String + Targets: checker.Strings, + Type: checker.Function, + Package: "hash/maphash", + Caller: "String", + Args: []int{1}, + AltCaller: "Bytes", - Generate: &checker.Generate{ - PreCondition: `h := maphash.Hash{}`, - Pattern: `WriteString($0)`, - Returns: []string{"int", "error"}, + Generate: &checker.Generate{ + Pattern: `String(maphash.MakeSeed(), $0)`, + Returns: []string{"uint64"}, + }, }, - }, -} + } + + MaphashMethods = []checker.Violation{ + { // (*hash/maphash).Write + Targets: checker.Bytes, + Type: checker.Method, + Package: "hash/maphash", + Struct: "Hash", + Caller: "Write", + Args: []int{0}, + AltCaller: "WriteString", + + Generate: &checker.Generate{ + PreCondition: `h := maphash.Hash{}`, + Pattern: `Write($0)`, + Returns: []string{"int", "error"}, + }, + }, + { // (*hash/maphash).WriteString + Targets: checker.Strings, + Type: checker.Method, + Package: "hash/maphash", + Struct: "Hash", + Caller: "WriteString", + Args: []int{0}, + AltCaller: "Write", + + Generate: &checker.Generate{ + PreCondition: `h := maphash.Hash{}`, + Pattern: `WriteString($0)`, + Returns: []string{"int", "error"}, + }, + }, + } +) diff --git a/vendor/github.com/butuzov/mirror/internal/checker/checker.go b/vendor/github.com/butuzov/mirror/internal/checker/checker.go index c1a941631..fb9ba4172 100644 --- a/vendor/github.com/butuzov/mirror/internal/checker/checker.go +++ b/vendor/github.com/butuzov/mirror/internal/checker/checker.go @@ -9,12 +9,12 @@ import ( "strings" ) -// Checker will perform standart check on package and its methods. +// Checker will perform standard check on package and its methods. type Checker struct { Violations []Violation // List of available violations Packages map[string][]int // Storing indexes of Violations per pkg/kg.Struct Type func(ast.Expr) string // Type Checker closure. - Print func(ast.Node) []byte // String representation of the expresion. + Print func(ast.Node) []byte // String representation of the expression. } func New(violations ...[]Violation) Checker { @@ -76,7 +76,7 @@ func (c *Checker) Handle(v *Violation, ce *ast.CallExpr) (map[int]ast.Expr, bool continue } - // is it convertsion call + // is it conversion call if !c.callConverts(call) { continue } diff --git a/vendor/github.com/butuzov/mirror/internal/checker/violation.go b/vendor/github.com/butuzov/mirror/internal/checker/violation.go index 3d8acf141..c2c149208 100644 --- a/vendor/github.com/butuzov/mirror/internal/checker/violation.go +++ b/vendor/github.com/butuzov/mirror/internal/checker/violation.go @@ -28,7 +28,7 @@ const ( UntypedRune string = "untyped rune" ) -// Violation describs what message we going to give to a particular code violation +// Violation describes what message we going to give to a particular code violation type Violation struct { Type ViolationType // Args []int // Indexes of the arguments needs to be checked @@ -143,7 +143,7 @@ func (v *Violation) Diagnostic(fSet *token.FileSet) analysis.Diagnostic { v.AltPackage = v.Package } - // Hooray! we dont need to change package and redo imports. + // Hooray! we don't need to change package and redo imports. if v.Type == Function && v.AltPackage == v.Package && noNl { diagnostic.SuggestedFixes = []analysis.SuggestedFix{{ Message: "Fix Issue With", @@ -166,7 +166,7 @@ type GolangIssue struct { Original string } -// Issue intended to be used only within `golangci-lint`, bu you can use use it +// Issue intended to be used only within `golangci-lint`, but you can use it // alongside Diagnostic if you wish. func (v *Violation) Issue(fSet *token.FileSet) GolangIssue { issue := GolangIssue{ diff --git a/vendor/github.com/butuzov/mirror/readme.md b/vendor/github.com/butuzov/mirror/readme.md index f830ea72e..f5cfa47a6 100644 --- a/vendor/github.com/butuzov/mirror/readme.md +++ b/vendor/github.com/butuzov/mirror/readme.md @@ -2,6 +2,13 @@ `mirror` suggests use of alternative functions/methods in order to gain performance boosts by avoiding unnecessary `[]byte/string` conversion calls. See [MIRROR_FUNCS.md](MIRROR_FUNCS.md) list of mirror functions you can use in go's stdlib. +--- + +[![United 24](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner-personal-page.svg)](https://u24.gov.ua/) +[![Help Oleg Butuzov](https://raw.githubusercontent.com/butuzov/butuzov/main/personal.svg)](https://github.com/butuzov) + +--- + ## Linter Use Cases ### `github.com/argoproj/argo-cd` @@ -86,13 +93,13 @@ util/cert/cert.go:82:10: avoid allocations with (*regexp.Regexp).MatchString (mi - flag `--tests` (e.g. `--tests=false`) - flag `--skip-files` (e.g. `--skip-files="_test.go"`) - - yaml confguration `run.skip-files`: + - yaml configuration `run.skip-files`: ```yaml run: skip-files: - '(.+)_test\.go' ``` - - yaml confguration `issues.exclude-rules`: + - yaml configuration `issues.exclude-rules`: ```yaml issues: exclude-rules: @@ -106,7 +113,7 @@ util/cert/cert.go:82:10: avoid allocations with (*regexp.Regexp).MatchString (mi ```shell # Update Assets (testdata/(strings|bytes|os|utf8|maphash|regexp|bufio).go) -(task|make) generated +(task|make) generate # Run Tests (task|make) tests # Lint Code diff --git a/vendor/github.com/catenacyber/perfsprint/analyzer/analyzer.go b/vendor/github.com/catenacyber/perfsprint/analyzer/analyzer.go index 543b4bdbc..c44104f5f 100644 --- a/vendor/github.com/catenacyber/perfsprint/analyzer/analyzer.go +++ b/vendor/github.com/catenacyber/perfsprint/analyzer/analyzer.go @@ -1,7 +1,9 @@ +// Package analyzer provides a static analysis tool that checks that fmt.Sprintf can be replaced with a faster alternative. package analyzer import ( "bytes" + "fmt" "go/ast" "go/format" "go/token" @@ -16,59 +18,468 @@ import ( "golang.org/x/tools/go/analysis" ) +type optionInt struct { + enabled bool + intConv bool +} + +type optionErr struct { + enabled bool + errError bool + errorf bool +} + +type optionStr struct { + enabled bool + sprintf1 bool + strconcat bool +} + +type optionConcatLoop struct { + enabled bool + otherOps bool +} + type perfSprint struct { - intConv bool - errError bool - errorf bool - sprintf1 bool + intFormat optionInt + errFormat optionErr + strFormat optionStr + concatLoop optionConcatLoop + + boolFormat bool + hexFormat bool + fiximports bool - strconcat bool } func newPerfSprint() *perfSprint { return &perfSprint{ - intConv: true, - errError: false, - errorf: true, - sprintf1: true, + intFormat: optionInt{enabled: true, intConv: true}, + errFormat: optionErr{enabled: true, errError: false, errorf: true}, + strFormat: optionStr{enabled: true, sprintf1: true, strconcat: true}, + concatLoop: optionConcatLoop{enabled: true, otherOps: false}, + boolFormat: true, + hexFormat: true, fiximports: true, - strconcat: true, } } +const ( + // checkerErrorFormat checks for error formatting. + checkerErrorFormat = "error-format" + // checkerIntegerFormat checks for integer formatting. + checkerIntegerFormat = "integer-format" + // checkerStringFormat checks for string formatting. + checkerStringFormat = "string-format" + // checkerBoolFormat checks for bool formatting. + checkerBoolFormat = "bool-format" + // checkerHexFormat checks for hexadecimal formatting. + checkerHexFormat = "hex-format" + // checkerConcatLoop checks for concatenation in loop. + checkerConcatLoop = "concat-loop" + // checkerFixImports fix needed imports from other fixes. + checkerFixImports = "fiximports" +) + func New() *analysis.Analyzer { n := newPerfSprint() r := &analysis.Analyzer{ Name: "perfsprint", + URL: "https://github.com/catenacyber/perfsprint", Doc: "Checks that fmt.Sprintf can be replaced with a faster alternative.", Run: n.run, Requires: []*analysis.Analyzer{inspect.Analyzer}, } - r.Flags.BoolVar(&n.intConv, "int-conversion", true, "optimizes even if it requires an int or uint type cast") - r.Flags.BoolVar(&n.errError, "err-error", false, "optimizes into err.Error() even if it is only equivalent for non-nil errors") - r.Flags.BoolVar(&n.errorf, "errorf", true, "optimizes fmt.Errorf") - r.Flags.BoolVar(&n.sprintf1, "sprintf1", true, "optimizes fmt.Sprintf with only one argument") - r.Flags.BoolVar(&n.fiximports, "fiximports", true, "fix needed imports from other fixes") - r.Flags.BoolVar(&n.strconcat, "strconcat", true, "optimizes into strings concatenation") + + r.Flags.BoolVar(&n.intFormat.enabled, checkerIntegerFormat, n.intFormat.enabled, "enable/disable optimization of integer formatting") + r.Flags.BoolVar(&n.intFormat.intConv, "int-conversion", n.intFormat.intConv, "optimizes even if it requires an int or uint type cast") + r.Flags.BoolVar(&n.errFormat.enabled, checkerErrorFormat, n.errFormat.enabled, "enable/disable optimization of error formatting") + r.Flags.BoolVar(&n.errFormat.errError, "err-error", n.errFormat.errError, "optimizes into err.Error() even if it is only equivalent for non-nil errors") + r.Flags.BoolVar(&n.errFormat.errorf, "errorf", n.errFormat.errorf, "optimizes fmt.Errorf") + + r.Flags.BoolVar(&n.boolFormat, checkerBoolFormat, n.boolFormat, "enable/disable optimization of bool formatting") + r.Flags.BoolVar(&n.hexFormat, checkerHexFormat, n.hexFormat, "enable/disable optimization of hex formatting") + r.Flags.BoolVar(&n.concatLoop.enabled, checkerConcatLoop, n.concatLoop.enabled, "enable/disable optimization of concat loop") + r.Flags.BoolVar(&n.concatLoop.otherOps, "loop-other-ops", n.concatLoop.otherOps, "optimization of concat loop even with other operations") + r.Flags.BoolVar(&n.strFormat.enabled, checkerStringFormat, n.strFormat.enabled, "enable/disable optimization of string formatting") + r.Flags.BoolVar(&n.strFormat.sprintf1, "sprintf1", n.strFormat.sprintf1, "optimizes fmt.Sprintf with only one argument") + r.Flags.BoolVar(&n.strFormat.strconcat, "strconcat", n.strFormat.strconcat, "optimizes into strings concatenation") + r.Flags.BoolVar(&n.fiximports, checkerFixImports, n.fiximports, "fix needed imports from other fixes") + return r } // true if verb is a format string that could be replaced with concatenation. func isConcatable(verb string) bool { - hasPrefix := - (strings.HasPrefix(verb, "%s") && !strings.Contains(verb, "%[1]s")) || - (strings.HasPrefix(verb, "%[1]s") && !strings.Contains(verb, "%s")) - hasSuffix := - (strings.HasSuffix(verb, "%s") && !strings.Contains(verb, "%[1]s")) || - (strings.HasSuffix(verb, "%[1]s") && !strings.Contains(verb, "%s")) + hasPrefix := (strings.HasPrefix(verb, "%s") && !strings.Contains(verb, "%[1]s")) || + (strings.HasPrefix(verb, "%[1]s") && !strings.Contains(verb, "%s")) + hasSuffix := (strings.HasSuffix(verb, "%s") && !strings.Contains(verb, "%[1]s")) || + (strings.HasSuffix(verb, "%[1]s") && !strings.Contains(verb, "%s")) if strings.Count(verb, "%[1]s") > 1 { return false } - return (hasPrefix || hasSuffix) && !(hasPrefix && hasSuffix) + // TODO handle case hasPrefix and hasSuffix + return (hasPrefix || hasSuffix) && !(hasPrefix && hasSuffix) //nolint:staticcheck +} + +func isStringAdd(st *ast.AssignStmt, idname string) ast.Expr { + // right is one + if len(st.Rhs) == 1 { + // right is addition + add, ok := st.Rhs[0].(*ast.BinaryExpr) + if ok && add.Op == token.ADD { + // right is addition to same ident name + x, ok := add.X.(*ast.Ident) + if ok && x.Name == idname { + return add.Y + } + } + } + return nil +} + +func (n *perfSprint) reportConcatLoop(pass *analysis.Pass, neededPackages map[string]map[string]struct{}, node ast.Node, adds map[string][]*ast.AssignStmt) *analysis.Diagnostic { + fname := pass.Fset.File(node.Pos()).Name() + if _, ok := neededPackages[fname]; !ok { + neededPackages[fname] = make(map[string]struct{}) + } + // note that we will need strings package + neededPackages[fname]["strings"] = struct{}{} + + // sort for reproducibility + keys := make([]string, 0, len(adds)) + for k := range adds { + keys = append(keys, k) + } + sort.Strings(keys) + + // use line number to define a unique variable name for the strings Builder + loopStartLine := pass.Fset.Position(node.Pos()).Line + + // If the loop does more with the string than concatenations + // add a TODO/FIXME comment that the fix is likely incomplete/incorrect + addTODO := "" + ast.Inspect(node, func(n ast.Node) bool { + if len(addTODO) > 0 { + // already found one, stop recursing + return false + } + switch x := n.(type) { + case *ast.AssignStmt: + // skip if this is one string concatenation that we are fixing + if (x.Tok == token.ASSIGN || x.Tok == token.ADD_ASSIGN) && len(x.Lhs) == 1 { + id, ok := x.Lhs[0].(*ast.Ident) + if ok { + _, ok = adds[id.Name] + if ok { + if x.Tok == token.ASSIGN && isStringAdd(x, id.Name) == nil { + addTODO = id.Name + } + return false + } + } + } + case *ast.Ident: + _, ok := adds[x.Name] + if ok { + // The variable name is used in some place else + addTODO = x.Name + return false + } + } + return true + }) + + prefix := "" + suffix := "" + if len(addTODO) > 0 { + if !n.concatLoop.otherOps { + return nil + } + prefix = fmt.Sprintf("// FIXME check usages of string identifier %s (and mayber others) in loop\n", addTODO) + } + // The fix contains 3 parts + // before the loop: declare the strings Builders + // during the loop: replace concatenation with Builder.WriteString + // after the loop: use the Builder.String to append to the pre-existing string + var prefixSb203 strings.Builder + var suffixSb203 strings.Builder + for _, k := range keys { + // lol + prefixSb203.WriteString(fmt.Sprintf("var %sSb%d strings.Builder\n", k, loopStartLine)) + suffixSb203.WriteString(fmt.Sprintf("\n%s += %sSb%d.String()", k, k, loopStartLine)) + } + prefix += prefixSb203.String() + suffix += suffixSb203.String() + te := []analysis.TextEdit{ + { + Pos: node.Pos(), + End: node.Pos(), + NewText: []byte(prefix), + }, + } + for _, k := range keys { + v := adds[k] + for _, st := range v { + // s += "x" -> use "x" + added := st.Rhs[0] + if st.Tok == token.ASSIGN { + // s = s + "x" -> use just "x", not `s + "x"` + added = isStringAdd(st, k) + } + te = append(te, analysis.TextEdit{ + Pos: st.Pos(), + End: added.Pos(), + NewText: []byte(fmt.Sprintf("%sSb%d.WriteString(", k, loopStartLine)), + }) + te = append(te, analysis.TextEdit{ + Pos: added.End(), + End: added.End(), + NewText: []byte(")"), + }) + } + } + te = append(te, analysis.TextEdit{ + Pos: node.End(), + End: node.End(), + NewText: []byte(suffix), + }) + + return newAnalysisDiagnostic( + checkerConcatLoop, + adds[keys[0]][0], + "string concatenation in a loop", + []analysis.SuggestedFix{ + { + Message: "Use a strings.Builder", + TextEdits: te, + }, + }, + ) +} + +func (n *perfSprint) runConcatLoop(pass *analysis.Pass, neededPackages map[string]map[string]struct{}) { + insp := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + // 2 different kinds of loops in go + nodeFilter := []ast.Node{ + (*ast.RangeStmt)(nil), + (*ast.ForStmt)(nil), + } + insp.Preorder(nodeFilter, func(node ast.Node) { + // set of variable names declared insied the loop + declInLoop := make(map[string]bool) + var bl []ast.Stmt + // just take the list of instruction of the loop + switch ra := node.(type) { + case *ast.RangeStmt: + bl = ra.Body.List + case *ast.ForStmt: + bl = ra.Body.List + } + // set of results : mapping a variable name to a list of statements like `s +=` + // one loop may be bad for multiple string variables, + // each being concatenated in multiple statements + adds := make(map[string][]*ast.AssignStmt) + for bs := 0; bs < len(bl); bs++ { + switch st := bl[bs].(type) { + case *ast.IfStmt: + // explore breadth first, but go inside the if/else blocks + if st.Body != nil { + bl = append(bl, st.Body.List...) + } + el, ok := st.Else.(*ast.BlockStmt) + if ok && el != nil { + bl = append(bl, el.List...) + } + case *ast.DeclStmt: + // identifiers defined within loop do not count + de, ok := st.Decl.(*ast.GenDecl) + if !ok { + break + } + if len(de.Specs) != 1 { + break + } + // is it possible to have len(de.Specs) > 1 for ValueSpec ? + vs, ok := de.Specs[0].(*ast.ValueSpec) + if !ok { + break + } + for n := range vs.Names { + declInLoop[vs.Names[n].Name] = true + } + case *ast.AssignStmt: + for n := range st.Lhs { + id, ok := st.Lhs[n].(*ast.Ident) + if !ok { + break + } + switch st.Tok { + case token.DEFINE: + declInLoop[id.Name] = true + case token.ASSIGN, token.ADD_ASSIGN: + if n > 0 { + // do not search bugs for multi-assign + break + } + _, local := declInLoop[id.Name] + if local { + break + } + ti, ok := pass.TypesInfo.Types[id] + if !ok || ti.Type.String() != "string" { + break + } + if st.Tok == token.ASSIGN { + if isStringAdd(st, id.Name) == nil { + break + } + } + // found a bad string concat in the loop + adds[id.Name] = append(adds[id.Name], st) + } + } + } + } + if len(adds) > 0 { + d := n.reportConcatLoop(pass, neededPackages, node, adds) + if d != nil { + pass.Report(*d) + } + } + }) +} + +func (n *perfSprint) fixImports(pass *analysis.Pass, neededPackages map[string]map[string]struct{}, removedFmtUsages map[string]int) { + if !n.fiximports { + return + } + for _, pkg := range pass.Pkg.Imports() { + if pkg.Path() == "fmt" { + insp := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + nodeFilter := []ast.Node{ + (*ast.SelectorExpr)(nil), + } + insp.Preorder(nodeFilter, func(node ast.Node) { + selec := node.(*ast.SelectorExpr) + selecok, ok := selec.X.(*ast.Ident) + if ok { + pkgname, ok := pass.TypesInfo.ObjectOf(selecok).(*types.PkgName) + if ok && pkgname.Name() == pkg.Name() { + fname := pass.Fset.File(pkgname.Pos()).Name() + removedFmtUsages[fname]-- + } + } + }) + } else if pkg.Path() == "errors" || pkg.Path() == "strconv" || pkg.Path() == "encoding/hex" || pkg.Path() == "strings" { + insp := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + nodeFilter := []ast.Node{ + (*ast.ImportSpec)(nil), + } + insp.Preorder(nodeFilter, func(node ast.Node) { + gd := node.(*ast.ImportSpec) + if gd.Path.Value == strconv.Quote(pkg.Path()) { + fname := pass.Fset.File(gd.Pos()).Name() + if _, ok := neededPackages[fname]; ok { + delete(neededPackages[fname], pkg.Path()) + } + } + }) + } + } + insp := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + nodeFilter := []ast.Node{ + (*ast.File)(nil), + } + insp.Preorder(nodeFilter, func(node ast.Node) { + gd := node.(*ast.File) + fname := pass.Fset.File(gd.Pos()).Name() + removed, hasFmt := removedFmtUsages[fname] + if (!hasFmt || removed < 0) && len(neededPackages[fname]) == 0 { + return + } + fix := "" + var ar analysis.Range + ar = gd.Decls[0] + start := gd.Decls[0].Pos() + end := gd.Decls[0].Pos() + if len(gd.Imports) == 0 { + fix += "import (\n" + } else { + id := gd.Decls[0].(*ast.GenDecl) + start = id.Specs[0].Pos() + end = id.Specs[0].Pos() + if removedFmtUsages[fname] >= 0 { + for sp := range id.Specs { + is := id.Specs[sp].(*ast.ImportSpec) + if is.Path.Value == strconv.Quote("fmt") { + ar = is + start = is.Pos() + end = is.End() + break + } + } + } + } + keys := make([]string, 0, len(neededPackages[fname])) + for k := range neededPackages[fname] { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + already := false + knames := strings.Split(k, "/") + kname := knames[len(knames)-1] + for i := range gd.Imports { // quadratic + if (gd.Imports[i].Name != nil && gd.Imports[i].Name.Name == kname) || (gd.Imports[i].Name == nil && strings.HasSuffix(gd.Imports[i].Path.Value, "/"+kname+`"`)) { + already = true + } + } + if already { + fix = fix + "\t\"" + k + "\" //TODO FIXME\n" + } else { + fix = fix + "\t\"" + k + "\"\n" + } + } + if len(gd.Imports) == 0 { + fix += ")\n" + } + pass.Report(*newAnalysisDiagnostic( + checkerFixImports, + ar, + "Fix imports", + []analysis.SuggestedFix{ + { + Message: "Fix imports", + TextEdits: []analysis.TextEdit{{ + Pos: start, + End: end, + NewText: []byte(fix), + }}, + }, + })) + }) } func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { + if !n.intFormat.enabled { + n.intFormat.intConv = false + } + if !n.errFormat.enabled { + n.errFormat.errError = false + n.errFormat.errorf = false + } + if !n.strFormat.enabled { + n.strFormat.sprintf1 = false + n.strFormat.strconcat = false + } + + neededPackages := make(map[string]map[string]struct{}) + if n.concatLoop.enabled { + n.runConcatLoop(pass, neededPackages) + } + removedFmtUsages := make(map[string]int) var fmtSprintObj, fmtSprintfObj, fmtErrorfObj types.Object for _, pkg := range pass.Pkg.Imports() { if pkg.Path() == "fmt" { @@ -78,10 +489,11 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { } } if fmtSprintfObj == nil && fmtSprintObj == nil && fmtErrorfObj == nil { + if len(neededPackages) > 0 { + n.fixImports(pass, neededPackages, removedFmtUsages) + } return nil, nil } - removedFmtUsages := make(map[string]int) - neededPackages := make(map[string]map[string]bool) insp := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) nodeFilter := []ast.Node{ @@ -102,28 +514,20 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { err error ) switch { - case calledObj == fmtErrorfObj && len(call.Args) == 1: - if n.errorf { - fn = "fmt.Errorf" - verb = "%s" - value = call.Args[0] - } else { - return - } + case calledObj == fmtErrorfObj && len(call.Args) == 1 && n.errFormat.errorf: + fn = "fmt.Errorf" + verb = "%s" + value = call.Args[0] case calledObj == fmtSprintObj && len(call.Args) == 1: fn = "fmt.Sprint" verb = "%v" value = call.Args[0] - case calledObj == fmtSprintfObj && len(call.Args) == 1: - if n.sprintf1 { - fn = "fmt.Sprintf" - verb = "%s" - value = call.Args[0] - } else { - return - } + case calledObj == fmtSprintfObj && len(call.Args) == 1 && n.strFormat.sprintf1: + fn = "fmt.Sprintf" + verb = "%s" + value = call.Args[0] case calledObj == fmtSprintfObj && len(call.Args) == 2: verbLit, ok := call.Args[0].(*ast.BasicLit) @@ -149,7 +553,7 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { switch verb { default: - if fn == "fmt.Sprintf" && isConcatable(verb) && n.strconcat { + if fn == "fmt.Sprintf" && isConcatable(verb) && n.strFormat.strconcat { break } return @@ -164,18 +568,17 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { switch { case isBasicType(valueType, types.String) && oneOf(verb, "%v", "%s"): fname := pass.Fset.File(call.Pos()).Name() - _, ok := neededPackages[fname] - if !ok { - neededPackages[fname] = make(map[string]bool) + if _, ok := neededPackages[fname]; !ok { + neededPackages[fname] = make(map[string]struct{}) } removedFmtUsages[fname]++ - if fn == "fmt.Errorf" { - neededPackages[fname]["errors"] = true - d = &analysis.Diagnostic{ - Pos: call.Pos(), - End: call.End(), - Message: fn + " can be replaced with errors.New", - SuggestedFixes: []analysis.SuggestedFix{ + if fn == "fmt.Errorf" && n.errFormat.enabled { + neededPackages[fname]["errors"] = struct{}{} + d = newAnalysisDiagnostic( + checkerErrorFormat, + call, + fn+" can be replaced with errors.New", + []analysis.SuggestedFix{ { Message: "Use errors.New", TextEdits: []analysis.TextEdit{{ @@ -185,13 +588,13 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { }}, }, }, - } - } else { - d = &analysis.Diagnostic{ - Pos: call.Pos(), - End: call.End(), - Message: fn + " can be replaced with just using the string", - SuggestedFixes: []analysis.SuggestedFix{ + ) + } else if fn != "fmt.Errorf" && n.strFormat.enabled { + d = newAnalysisDiagnostic( + checkerStringFormat, + call, + fn+" can be replaced with just using the string", + []analysis.SuggestedFix{ { Message: "Just use string value", TextEdits: []analysis.TextEdit{{ @@ -201,19 +604,19 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { }}, }, }, - } + ) } - case types.Implements(valueType, errIface) && oneOf(verb, "%v", "%s") && n.errError: + case types.Implements(valueType, errIface) && oneOf(verb, "%v", "%s") && n.errFormat.errError: // known false positive if this error is nil // fmt.Sprint(nil) does not panic like nil.Error() does errMethodCall := formatNode(pass.Fset, value) + ".Error()" fname := pass.Fset.File(call.Pos()).Name() removedFmtUsages[fname]++ - d = &analysis.Diagnostic{ - Pos: call.Pos(), - End: call.End(), - Message: fn + " can be replaced with " + errMethodCall, - SuggestedFixes: []analysis.SuggestedFix{ + d = newAnalysisDiagnostic( + checkerErrorFormat, + call, + fn+" can be replaced with "+errMethodCall, + []analysis.SuggestedFix{ { Message: "Use " + errMethodCall, TextEdits: []analysis.TextEdit{{ @@ -223,21 +626,20 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { }}, }, }, - } + ) - case isBasicType(valueType, types.Bool) && oneOf(verb, "%v", "%t"): + case isBasicType(valueType, types.Bool) && oneOf(verb, "%v", "%t") && n.boolFormat: fname := pass.Fset.File(call.Pos()).Name() removedFmtUsages[fname]++ - _, ok := neededPackages[fname] - if !ok { - neededPackages[fname] = make(map[string]bool) - } - neededPackages[fname]["strconv"] = true - d = &analysis.Diagnostic{ - Pos: call.Pos(), - End: call.End(), - Message: fn + " can be replaced with faster strconv.FormatBool", - SuggestedFixes: []analysis.SuggestedFix{ + if _, ok := neededPackages[fname]; !ok { + neededPackages[fname] = make(map[string]struct{}) + } + neededPackages[fname]["strconv"] = struct{}{} + d = newAnalysisDiagnostic( + checkerBoolFormat, + call, + fn+" can be replaced with faster strconv.FormatBool", + []analysis.SuggestedFix{ { Message: "Use strconv.FormatBool", TextEdits: []analysis.TextEdit{{ @@ -247,9 +649,9 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { }}, }, }, - } + ) - case isArray && isBasicType(a.Elem(), types.Uint8) && oneOf(verb, "%x"): + case isArray && isBasicType(a.Elem(), types.Uint8) && oneOf(verb, "%x") && n.hexFormat: if _, ok := value.(*ast.Ident); !ok { // Doesn't support array literals. return @@ -257,16 +659,15 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { fname := pass.Fset.File(call.Pos()).Name() removedFmtUsages[fname]++ - _, ok := neededPackages[fname] - if !ok { - neededPackages[fname] = make(map[string]bool) - } - neededPackages[fname]["encoding/hex"] = true - d = &analysis.Diagnostic{ - Pos: call.Pos(), - End: call.End(), - Message: fn + " can be replaced with faster hex.EncodeToString", - SuggestedFixes: []analysis.SuggestedFix{ + if _, ok := neededPackages[fname]; !ok { + neededPackages[fname] = make(map[string]struct{}) + } + neededPackages[fname]["encoding/hex"] = struct{}{} + d = newAnalysisDiagnostic( + checkerHexFormat, + call, + fn+" can be replaced with faster hex.EncodeToString", + []analysis.SuggestedFix{ { Message: "Use hex.EncodeToString", TextEdits: []analysis.TextEdit{ @@ -283,20 +684,19 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { }, }, }, - } - case isSlice && isBasicType(s.Elem(), types.Uint8) && oneOf(verb, "%x"): + ) + case isSlice && isBasicType(s.Elem(), types.Uint8) && oneOf(verb, "%x") && n.hexFormat: fname := pass.Fset.File(call.Pos()).Name() removedFmtUsages[fname]++ - _, ok := neededPackages[fname] - if !ok { - neededPackages[fname] = make(map[string]bool) - } - neededPackages[fname]["encoding/hex"] = true - d = &analysis.Diagnostic{ - Pos: call.Pos(), - End: call.End(), - Message: fn + " can be replaced with faster hex.EncodeToString", - SuggestedFixes: []analysis.SuggestedFix{ + if _, ok := neededPackages[fname]; !ok { + neededPackages[fname] = make(map[string]struct{}) + } + neededPackages[fname]["encoding/hex"] = struct{}{} + d = newAnalysisDiagnostic( + checkerHexFormat, + call, + fn+" can be replaced with faster hex.EncodeToString", + []analysis.SuggestedFix{ { Message: "Use hex.EncodeToString", TextEdits: []analysis.TextEdit{{ @@ -306,21 +706,20 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { }}, }, }, - } + ) - case isBasicType(valueType, types.Int8, types.Int16, types.Int32) && oneOf(verb, "%v", "%d") && n.intConv: + case isBasicType(valueType, types.Int8, types.Int16, types.Int32) && oneOf(verb, "%v", "%d") && n.intFormat.intConv: fname := pass.Fset.File(call.Pos()).Name() removedFmtUsages[fname]++ - _, ok := neededPackages[fname] - if !ok { - neededPackages[fname] = make(map[string]bool) - } - neededPackages[fname]["strconv"] = true - d = &analysis.Diagnostic{ - Pos: call.Pos(), - End: call.End(), - Message: fn + " can be replaced with faster strconv.Itoa", - SuggestedFixes: []analysis.SuggestedFix{ + if _, ok := neededPackages[fname]; !ok { + neededPackages[fname] = make(map[string]struct{}) + } + neededPackages[fname]["strconv"] = struct{}{} + d = newAnalysisDiagnostic( + checkerIntegerFormat, + call, + fn+" can be replaced with faster strconv.Itoa", + []analysis.SuggestedFix{ { Message: "Use strconv.Itoa", TextEdits: []analysis.TextEdit{ @@ -337,20 +736,19 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { }, }, }, - } - case isBasicType(valueType, types.Int) && oneOf(verb, "%v", "%d"): + ) + case isBasicType(valueType, types.Int) && oneOf(verb, "%v", "%d") && n.intFormat.enabled: fname := pass.Fset.File(call.Pos()).Name() removedFmtUsages[fname]++ - _, ok := neededPackages[fname] - if !ok { - neededPackages[fname] = make(map[string]bool) - } - neededPackages[fname]["strconv"] = true - d = &analysis.Diagnostic{ - Pos: call.Pos(), - End: call.End(), - Message: fn + " can be replaced with faster strconv.Itoa", - SuggestedFixes: []analysis.SuggestedFix{ + if _, ok := neededPackages[fname]; !ok { + neededPackages[fname] = make(map[string]struct{}) + } + neededPackages[fname]["strconv"] = struct{}{} + d = newAnalysisDiagnostic( + checkerIntegerFormat, + call, + fn+" can be replaced with faster strconv.Itoa", + []analysis.SuggestedFix{ { Message: "Use strconv.Itoa", TextEdits: []analysis.TextEdit{{ @@ -360,20 +758,19 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { }}, }, }, - } - case isBasicType(valueType, types.Int64) && oneOf(verb, "%v", "%d"): + ) + case isBasicType(valueType, types.Int64) && oneOf(verb, "%v", "%d") && n.intFormat.enabled: fname := pass.Fset.File(call.Pos()).Name() removedFmtUsages[fname]++ - _, ok := neededPackages[fname] - if !ok { - neededPackages[fname] = make(map[string]bool) - } - neededPackages[fname]["strconv"] = true - d = &analysis.Diagnostic{ - Pos: call.Pos(), - End: call.End(), - Message: fn + " can be replaced with faster strconv.FormatInt", - SuggestedFixes: []analysis.SuggestedFix{ + if _, ok := neededPackages[fname]; !ok { + neededPackages[fname] = make(map[string]struct{}) + } + neededPackages[fname]["strconv"] = struct{}{} + d = newAnalysisDiagnostic( + checkerIntegerFormat, + call, + fn+" can be replaced with faster strconv.FormatInt", + []analysis.SuggestedFix{ { Message: "Use strconv.FormatInt", TextEdits: []analysis.TextEdit{ @@ -390,25 +787,24 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { }, }, }, - } + ) - case isBasicType(valueType, types.Uint8, types.Uint16, types.Uint32, types.Uint) && oneOf(verb, "%v", "%d", "%x") && n.intConv: + case isBasicType(valueType, types.Uint8, types.Uint16, types.Uint32, types.Uint) && oneOf(verb, "%v", "%d", "%x") && n.intFormat.intConv: base := []byte("), 10") if verb == "%x" { base = []byte("), 16") } fname := pass.Fset.File(call.Pos()).Name() removedFmtUsages[fname]++ - _, ok := neededPackages[fname] - if !ok { - neededPackages[fname] = make(map[string]bool) - } - neededPackages[fname]["strconv"] = true - d = &analysis.Diagnostic{ - Pos: call.Pos(), - End: call.End(), - Message: fn + " can be replaced with faster strconv.FormatUint", - SuggestedFixes: []analysis.SuggestedFix{ + if _, ok := neededPackages[fname]; !ok { + neededPackages[fname] = make(map[string]struct{}) + } + neededPackages[fname]["strconv"] = struct{}{} + d = newAnalysisDiagnostic( + checkerIntegerFormat, + call, + fn+" can be replaced with faster strconv.FormatUint", + []analysis.SuggestedFix{ { Message: "Use strconv.FormatUint", TextEdits: []analysis.TextEdit{ @@ -425,24 +821,23 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { }, }, }, - } - case isBasicType(valueType, types.Uint64) && oneOf(verb, "%v", "%d", "%x"): + ) + case isBasicType(valueType, types.Uint64) && oneOf(verb, "%v", "%d", "%x") && n.intFormat.enabled: base := []byte(", 10") if verb == "%x" { base = []byte(", 16") } fname := pass.Fset.File(call.Pos()).Name() removedFmtUsages[fname]++ - _, ok := neededPackages[fname] - if !ok { - neededPackages[fname] = make(map[string]bool) - } - neededPackages[fname]["strconv"] = true - d = &analysis.Diagnostic{ - Pos: call.Pos(), - End: call.End(), - Message: fn + " can be replaced with faster strconv.FormatUint", - SuggestedFixes: []analysis.SuggestedFix{ + if _, ok := neededPackages[fname]; !ok { + neededPackages[fname] = make(map[string]struct{}) + } + neededPackages[fname]["strconv"] = struct{}{} + d = newAnalysisDiagnostic( + checkerIntegerFormat, + call, + fn+" can be replaced with faster strconv.FormatUint", + []analysis.SuggestedFix{ { Message: "Use strconv.FormatUint", TextEdits: []analysis.TextEdit{ @@ -459,25 +854,25 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { }, }, }, - } - case isBasicType(valueType, types.String) && fn == "fmt.Sprintf" && isConcatable(verb): + ) + case isBasicType(valueType, types.String) && fn == "fmt.Sprintf" && isConcatable(verb) && n.strFormat.enabled: var fix string if strings.HasSuffix(verb, "%s") { - fix = strconv.Quote(verb[:len(verb)-2]) + "+" + formatNode(pass.Fset, value) + fix = strings.ReplaceAll(strconv.Quote(verb[:len(verb)-2]), "%%", "%") + "+" + formatNode(pass.Fset, value) } else if strings.HasSuffix(verb, "%[1]s") { - fix = strconv.Quote(verb[:len(verb)-5]) + "+" + formatNode(pass.Fset, value) + fix = strings.ReplaceAll(strconv.Quote(verb[:len(verb)-5]), "%%", "%") + "+" + formatNode(pass.Fset, value) } else if strings.HasPrefix(verb, "%s") { - fix = formatNode(pass.Fset, value) + "+" + strconv.Quote(verb[2:]) + fix = formatNode(pass.Fset, value) + "+" + strings.ReplaceAll(strconv.Quote(verb[2:]), "%%", "%") } else { - fix = formatNode(pass.Fset, value) + "+" + strconv.Quote(verb[5:]) + fix = formatNode(pass.Fset, value) + "+" + strings.ReplaceAll(strconv.Quote(verb[5:]), "%%", "%") } fname := pass.Fset.File(call.Pos()).Name() removedFmtUsages[fname]++ - d = &analysis.Diagnostic{ - Pos: call.Pos(), - End: call.End(), - Message: fn + " can be replaced with string concatenation", - SuggestedFixes: []analysis.SuggestedFix{ + d = newAnalysisDiagnostic( + checkerStringFormat, + call, + fn+" can be replaced with string concatenation", + []analysis.SuggestedFix{ { Message: "Use string concatenation", TextEdits: []analysis.TextEdit{{ @@ -487,7 +882,7 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { }}, }, }, - } + ) } if d != nil { @@ -495,80 +890,8 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { } }) - if len(removedFmtUsages) > 0 && n.fiximports { - for _, pkg := range pass.Pkg.Imports() { - if pkg.Path() == "fmt" { - insp = pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) - nodeFilter = []ast.Node{ - (*ast.SelectorExpr)(nil), - } - insp.Preorder(nodeFilter, func(node ast.Node) { - selec := node.(*ast.SelectorExpr) - selecok, ok := selec.X.(*ast.Ident) - if ok { - pkgname, ok := pass.TypesInfo.ObjectOf(selecok).(*types.PkgName) - if ok && pkgname.Name() == pkg.Name() { - fname := pass.Fset.File(pkgname.Pos()).Name() - removedFmtUsages[fname]-- - } - } - }) - } else if pkg.Path() == "errors" || pkg.Path() == "strconv" || pkg.Path() == "encoding/hex" { - insp = pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) - nodeFilter = []ast.Node{ - (*ast.ImportSpec)(nil), - } - insp.Preorder(nodeFilter, func(node ast.Node) { - gd := node.(*ast.ImportSpec) - if gd.Path.Value == strconv.Quote(pkg.Path()) { - fname := pass.Fset.File(gd.Pos()).Name() - _, ok := neededPackages[fname] - if ok { - delete(neededPackages[fname], pkg.Path()) - } - } - }) - } - } - insp = pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) - nodeFilter = []ast.Node{ - (*ast.ImportSpec)(nil), - } - insp.Preorder(nodeFilter, func(node ast.Node) { - gd := node.(*ast.ImportSpec) - if gd.Path.Value == `"fmt"` { - fix := "" - fname := pass.Fset.File(gd.Pos()).Name() - if removedFmtUsages[fname] < 0 { - fix += `"fmt"` - if len(neededPackages[fname]) == 0 { - return - } - } - keys := make([]string, 0, len(neededPackages[fname])) - for k := range neededPackages[fname] { - keys = append(keys, k) - } - sort.Strings(keys) - for _, k := range keys { - fix = fix + "\n\t\"" + k + `"` - } - pass.Report(analysis.Diagnostic{ - Pos: gd.Pos(), - End: gd.End(), - Message: "Fix imports", - SuggestedFixes: []analysis.SuggestedFix{ - { - Message: "Fix imports", - TextEdits: []analysis.TextEdit{{ - Pos: gd.Pos(), - End: gd.End(), - NewText: []byte(fix), - }}, - }, - }}) - } - }) + if len(removedFmtUsages) > 0 || len(neededPackages) > 0 { + n.fixImports(pass, neededPackages, removedFmtUsages) } return nil, nil diff --git a/vendor/github.com/catenacyber/perfsprint/analyzer/diagnostic.go b/vendor/github.com/catenacyber/perfsprint/analyzer/diagnostic.go new file mode 100644 index 000000000..f1d8d090e --- /dev/null +++ b/vendor/github.com/catenacyber/perfsprint/analyzer/diagnostic.go @@ -0,0 +1,24 @@ +package analyzer + +import ( + "golang.org/x/tools/go/analysis" +) + +func newAnalysisDiagnostic( + checker string, + analysisRange analysis.Range, + message string, + suggestedFixes []analysis.SuggestedFix, +) *analysis.Diagnostic { + if checker != "" { + message = checker + ": " + message + } + + return &analysis.Diagnostic{ + Pos: analysisRange.Pos(), + End: analysisRange.End(), + SuggestedFixes: suggestedFixes, + Message: message, + Category: checker, // Possible hashtag available on the documentation + } +} diff --git a/vendor/github.com/ccojocar/zxcvbn-go/.golangci.yml b/vendor/github.com/ccojocar/zxcvbn-go/.golangci.yml index b54f70092..765d3b5ea 100644 --- a/vendor/github.com/ccojocar/zxcvbn-go/.golangci.yml +++ b/vendor/github.com/ccojocar/zxcvbn-go/.golangci.yml @@ -1,39 +1,46 @@ +version: "2" linters: enable: - asciicheck - bodyclose - dogsled - durationcheck - - errcheck - errorlint - - exportloopref - - gci - ginkgolinter - - gofmt - - gofumpt - - goimports - - gosimple - - govet - importas - - ineffassign - - megacheck - misspell - nakedret - nolintlint - revive - - staticcheck - - typecheck - unconvert - unparam - - unused - wastedassign - -linters-settings: - gci: - sections: - - standard - - default - - prefix(github.com/ccojocar) - -run: - timeout: 5m + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + paths: + - third_party$ + - builtin$ + - examples$ +formatters: + enable: + - gci + - gofmt + - gofumpt + - goimports + settings: + gci: + sections: + - standard + - default + - prefix(github.com/ccojocar) + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/vendor/github.com/ccojocar/zxcvbn-go/.goreleaser.yml b/vendor/github.com/ccojocar/zxcvbn-go/.goreleaser.yml index 2386aeee5..2b786c5d8 100644 --- a/vendor/github.com/ccojocar/zxcvbn-go/.goreleaser.yml +++ b/vendor/github.com/ccojocar/zxcvbn-go/.goreleaser.yml @@ -1,4 +1,4 @@ ---- +version: 2 project_name: zxcvbn-go release: diff --git a/vendor/github.com/ccojocar/zxcvbn-go/matching/dateMatchers.go b/vendor/github.com/ccojocar/zxcvbn-go/matching/dateMatchers.go index fd7f38332..c3829c925 100644 --- a/vendor/github.com/ccojocar/zxcvbn-go/matching/dateMatchers.go +++ b/vendor/github.com/ccojocar/zxcvbn-go/matching/dateMatchers.go @@ -39,7 +39,8 @@ func checkDate(day, month, year int64) (bool, int64, int64, int64) { return false, 0, 0, 0 } - if !((1900 <= year && year <= 2019) || (0 <= year && year <= 99)) { + //nolint:staticcheck // Ignore De Morgan's law optimization + if !((1900 <= year && year <= 2025) || (0 <= year && year <= 99)) { return false, 0, 0, 0 } diff --git a/vendor/github.com/ccojocar/zxcvbn-go/matching/leet.go b/vendor/github.com/ccojocar/zxcvbn-go/matching/leet.go index 1f303aa6e..f7fd30420 100644 --- a/vendor/github.com/ccojocar/zxcvbn-go/matching/leet.go +++ b/vendor/github.com/ccojocar/zxcvbn-go/matching/leet.go @@ -191,7 +191,7 @@ func createSubstitutionsMapsFromTable(table map[string][]string) []map[string]st func createWordForSubstitutionMap(word string, substitutionMap map[string]string) string { result := word for key, value := range substitutionMap { - result = strings.Replace(result, value, key, -1) + result = strings.ReplaceAll(result, value, key) } return result @@ -224,7 +224,7 @@ func copyMapRemovingSameValueFromOtherKeys(table map[string][]string, keyToFix s for key, values := range table { for _, value := range values { - if !(value == valueToFix && key != keyToFix) { + if value != valueToFix || key == keyToFix { result[key] = append(result[key], value) } } diff --git a/vendor/github.com/ccojocar/zxcvbn-go/scoring/scoring.go b/vendor/github.com/ccojocar/zxcvbn-go/scoring/scoring.go index f25606a8d..7154025a9 100644 --- a/vendor/github.com/ccojocar/zxcvbn-go/scoring/scoring.go +++ b/vendor/github.com/ccojocar/zxcvbn-go/scoring/scoring.go @@ -166,7 +166,7 @@ func displayTime(seconds float64) string { } func crackTimeToScore(seconds float64) int { - if seconds < math.Pow(10, 2) { + if seconds < 100 { return 0 } else if seconds < math.Pow(10, 4) { return 1 diff --git a/vendor/github.com/charithe/durationcheck/README.md b/vendor/github.com/charithe/durationcheck/README.md index 6f4279bd3..4aa9558f2 100644 --- a/vendor/github.com/charithe/durationcheck/README.md +++ b/vendor/github.com/charithe/durationcheck/README.md @@ -33,7 +33,7 @@ See the [test cases](testdata/src/a/a.go) for more examples of the types of erro Installation ------------- -Requires Go 1.11 or above. +Requires Go 1.14 or above. ``` go get -u github.com/charithe/durationcheck/cmd/durationcheck diff --git a/vendor/github.com/charithe/durationcheck/durationcheck.go b/vendor/github.com/charithe/durationcheck/durationcheck.go index c47b3a761..5fcb98a89 100644 --- a/vendor/github.com/charithe/durationcheck/durationcheck.go +++ b/vendor/github.com/charithe/durationcheck/durationcheck.go @@ -32,6 +32,7 @@ func run(pass *analysis.Pass) (interface{}, error) { nodeTypes := []ast.Node{ (*ast.BinaryExpr)(nil), + (*ast.AssignStmt)(nil), } inspect.Preorder(nodeTypes, check(pass)) @@ -52,25 +53,45 @@ func hasImport(pkg *types.Package, importPath string) bool { // check contains the logic for checking that time.Duration is used correctly in the code being analysed func check(pass *analysis.Pass) func(ast.Node) { return func(node ast.Node) { - expr := node.(*ast.BinaryExpr) - // we are only interested in multiplication - if expr.Op != token.MUL { - return + switch expr := node.(type) { + case *ast.BinaryExpr: + checkBinaryExpr(pass, expr) + case *ast.AssignStmt: + if expr.Tok != token.MUL_ASSIGN { + return + } + // '*=' assignment requires single-valued expressions + if len(expr.Lhs) != 1 || len(expr.Rhs) != 1 { + return + } + checkBinaryExpr(pass, &ast.BinaryExpr{ + X: expr.Lhs[0], + OpPos: expr.TokPos, + Op: expr.Tok, + Y: expr.Rhs[0], + }) } + } +} - // get the types of the two operands - x, xOK := pass.TypesInfo.Types[expr.X] - y, yOK := pass.TypesInfo.Types[expr.Y] +func checkBinaryExpr(pass *analysis.Pass, expr *ast.BinaryExpr) { + // we are only interested in multiplication + if expr.Op != token.MUL && expr.Op != token.MUL_ASSIGN { + return + } - if !xOK || !yOK { - return - } + // get the types of the two operands + x, xOK := pass.TypesInfo.Types[expr.X] + y, yOK := pass.TypesInfo.Types[expr.Y] - if isDuration(x.Type) && isDuration(y.Type) { - // check that both sides are acceptable expressions - if isUnacceptableExpr(pass, expr.X) && isUnacceptableExpr(pass, expr.Y) { - pass.Reportf(expr.Pos(), "Multiplication of durations: `%s`", formatNode(expr)) - } + if !xOK || !yOK { + return + } + + if isDuration(x.Type) && isDuration(y.Type) { + // check that both sides are acceptable expressions + if isUnacceptableExpr(pass, expr.X) && isUnacceptableExpr(pass, expr.Y) { + pass.Reportf(expr.Pos(), "Multiplication of durations: `%s`", formatNode(expr)) } } } diff --git a/vendor/github.com/charmbracelet/colorprofile/.golangci.yml b/vendor/github.com/charmbracelet/colorprofile/.golangci.yml new file mode 100644 index 000000000..be61d89ba --- /dev/null +++ b/vendor/github.com/charmbracelet/colorprofile/.golangci.yml @@ -0,0 +1,41 @@ +version: "2" +run: + tests: false +linters: + enable: + - bodyclose + - exhaustive + - goconst + - godot + - godox + - gomoddirectives + - goprintffuncname + - gosec + - misspell + - nakedret + - nestif + - nilerr + - noctx + - nolintlint + - prealloc + - revive + - rowserrcheck + - sqlclosecheck + - tparallel + - unconvert + - unparam + - whitespace + - wrapcheck + exclusions: + generated: lax + presets: + - common-false-positives +issues: + max-issues-per-linter: 0 + max-same-issues: 0 +formatters: + enable: + - gofumpt + - goimports + exclusions: + generated: lax diff --git a/vendor/github.com/charmbracelet/colorprofile/.goreleaser.yml b/vendor/github.com/charmbracelet/colorprofile/.goreleaser.yml new file mode 100644 index 000000000..40d9f298d --- /dev/null +++ b/vendor/github.com/charmbracelet/colorprofile/.goreleaser.yml @@ -0,0 +1,6 @@ +includes: + - from_url: + url: charmbracelet/meta/main/goreleaser-lib.yaml + +# yaml-language-server: $schema=https://goreleaser.com/static/schema-pro.json + diff --git a/vendor/github.com/charmbracelet/colorprofile/LICENSE b/vendor/github.com/charmbracelet/colorprofile/LICENSE new file mode 100644 index 000000000..b7974b076 --- /dev/null +++ b/vendor/github.com/charmbracelet/colorprofile/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020-2024 Charmbracelet, Inc + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/charmbracelet/colorprofile/README.md b/vendor/github.com/charmbracelet/colorprofile/README.md new file mode 100644 index 000000000..c72b2f4b5 --- /dev/null +++ b/vendor/github.com/charmbracelet/colorprofile/README.md @@ -0,0 +1,103 @@ +# Colorprofile + +

+ Latest Release + GoDoc + Build Status +

+ +A simple, powerful—and at times magical—package for detecting terminal color +profiles and performing color (and CSI) degradation. + +## Detecting the terminal’s color profile + +Detecting the terminal’s color profile is easy. + +```go +import "github.com/charmbracelet/colorprofile" + +// Detect the color profile. If you’re planning on writing to stderr you'd want +// to use os.Stderr instead. +p := colorprofile.Detect(os.Stdout, os.Environ()) + +// Comment on the profile. +fmt.Printf("You know, your colors are quite %s.", func() string { + switch p { + case colorprofile.TrueColor: + return "fancy" + case colorprofile.ANSI256: + return "1990s fancy" + case colorprofile.ANSI: + return "normcore" + case colorprofile.Ascii: + return "ancient" + case colorprofile.NoTTY: + return "naughty!" + } + return "...IDK" // this should never happen +}()) +``` + +## Downsampling colors + +When necessary, colors can be downsampled to a given profile, or manually +downsampled to a specific profile. + +```go +p := colorprofile.Detect(os.Stdout, os.Environ()) +c := color.RGBA{0x6b, 0x50, 0xff, 0xff} // #6b50ff + +// Downsample to the detected profile, when necessary. +convertedColor := p.Convert(c) + +// Or manually convert to a given profile. +ansi256Color := colorprofile.ANSI256.Convert(c) +ansiColor := colorprofile.ANSI.Convert(c) +noColor := colorprofile.Ascii.Convert(c) +noANSI := colorprofile.NoTTY.Convert(c) +``` + +## Automatic downsampling with a Writer + +You can also magically downsample colors in ANSI output, when necessary. If +output is not a TTY ANSI will be dropped entirely. + +```go +myFancyANSI := "\x1b[38;2;107;80;255mCute \x1b[1;3mpuppy!!\x1b[m" + +// Automatically downsample for the terminal at stdout. +w := colorprofile.NewWriter(os.Stdout, os.Environ()) +fmt.Fprintf(w, myFancyANSI) + +// Downsample to 4-bit ANSI. +w.Profile = colorprofile.ANSI +fmt.Fprintf(w, myFancyANSI) + +// Ascii-fy, no colors. +w.Profile = colorprofile.Ascii +fmt.Fprintf(w, myFancyANSI) + +// Strip ANSI altogether. +w.Profile = colorprofile.NoTTY +fmt.Fprintf(w, myFancyANSI) // not as fancy +``` + +## Feedback + +We’d love to hear your thoughts on this project. Feel free to drop us a note! + +- [Twitter](https://twitter.com/charmcli) +- [The Fediverse](https://mastodon.social/@charmcli) +- [Discord](https://charm.sh/chat) + +## License + +[MIT](https://github.com/charmbracelet/bubbletea/raw/master/LICENSE) + +--- + +Part of [Charm](https://charm.sh). + +The Charm logo + +Charm热爱开源 • Charm loves open source • نحنُ نحب المصادر المفتوحة diff --git a/vendor/github.com/charmbracelet/colorprofile/doc.go b/vendor/github.com/charmbracelet/colorprofile/doc.go new file mode 100644 index 000000000..bd522e903 --- /dev/null +++ b/vendor/github.com/charmbracelet/colorprofile/doc.go @@ -0,0 +1,4 @@ +// Package colorprofile provides a way to downsample ANSI escape sequence +// colors and styles automatically based on output, environment variables, and +// Terminfo databases. +package colorprofile diff --git a/vendor/github.com/charmbracelet/colorprofile/env.go b/vendor/github.com/charmbracelet/colorprofile/env.go new file mode 100644 index 000000000..749f989e2 --- /dev/null +++ b/vendor/github.com/charmbracelet/colorprofile/env.go @@ -0,0 +1,293 @@ +package colorprofile + +import ( + "bytes" + "io" + "os/exec" + "runtime" + "strconv" + "strings" + + "github.com/charmbracelet/x/term" + "github.com/xo/terminfo" +) + +const dumbTerm = "dumb" + +// Detect returns the color profile based on the terminal output, and +// environment variables. This respects NO_COLOR, CLICOLOR, and CLICOLOR_FORCE +// environment variables. +// +// The rules as follows: +// - TERM=dumb is always treated as NoTTY unless CLICOLOR_FORCE=1 is set. +// - If COLORTERM=truecolor, and the profile is not NoTTY, it gest upgraded to TrueColor. +// - Using any 256 color terminal (e.g. TERM=xterm-256color) will set the profile to ANSI256. +// - Using any color terminal (e.g. TERM=xterm-color) will set the profile to ANSI. +// - Using CLICOLOR=1 without TERM defined should be treated as ANSI if the +// output is a terminal. +// - NO_COLOR takes precedence over CLICOLOR/CLICOLOR_FORCE, and will disable +// colors but not text decoration, i.e. bold, italic, faint, etc. +// +// See https://no-color.org/ and https://bixense.com/clicolors/ for more information. +func Detect(output io.Writer, env []string) Profile { + out, ok := output.(term.File) + environ := newEnviron(env) + isatty := isTTYForced(environ) || (ok && term.IsTerminal(out.Fd())) + term, ok := environ.lookup("TERM") + isDumb := !ok || term == dumbTerm + envp := colorProfile(isatty, environ) + if envp == TrueColor || envNoColor(environ) { + // We already know we have TrueColor, or NO_COLOR is set. + return envp + } + + if isatty && !isDumb { + tip := Terminfo(term) + tmuxp := tmux(environ) + + // Color profile is the maximum of env, terminfo, and tmux. + return max(envp, max(tip, tmuxp)) + } + + return envp +} + +// Env returns the color profile based on the terminal environment variables. +// This respects NO_COLOR, CLICOLOR, and CLICOLOR_FORCE environment variables. +// +// The rules as follows: +// - TERM=dumb is always treated as NoTTY unless CLICOLOR_FORCE=1 is set. +// - If COLORTERM=truecolor, and the profile is not NoTTY, it gest upgraded to TrueColor. +// - Using any 256 color terminal (e.g. TERM=xterm-256color) will set the profile to ANSI256. +// - Using any color terminal (e.g. TERM=xterm-color) will set the profile to ANSI. +// - Using CLICOLOR=1 without TERM defined should be treated as ANSI if the +// output is a terminal. +// - NO_COLOR takes precedence over CLICOLOR/CLICOLOR_FORCE, and will disable +// colors but not text decoration, i.e. bold, italic, faint, etc. +// +// See https://no-color.org/ and https://bixense.com/clicolors/ for more information. +func Env(env []string) (p Profile) { + return colorProfile(true, newEnviron(env)) +} + +func colorProfile(isatty bool, env environ) (p Profile) { + term, ok := env.lookup("TERM") + isDumb := (!ok && runtime.GOOS != "windows") || term == dumbTerm + envp := envColorProfile(env) + if !isatty || isDumb { + // Check if the output is a terminal. + // Treat dumb terminals as NoTTY + p = NoTTY + } else { + p = envp + } + + if envNoColor(env) && isatty { + if p > Ascii { + p = Ascii + } + return //nolint:nakedret + } + + if cliColorForced(env) { + if p < ANSI { + p = ANSI + } + if envp > p { + p = envp + } + + return //nolint:nakedret + } + + if cliColor(env) { + if isatty && !isDumb && p < ANSI { + p = ANSI + } + } + + return p +} + +// envNoColor returns true if the environment variables explicitly disable color output +// by setting NO_COLOR (https://no-color.org/). +func envNoColor(env environ) bool { + noColor, _ := strconv.ParseBool(env.get("NO_COLOR")) + return noColor +} + +func cliColor(env environ) bool { + cliColor, _ := strconv.ParseBool(env.get("CLICOLOR")) + return cliColor +} + +func cliColorForced(env environ) bool { + cliColorForce, _ := strconv.ParseBool(env.get("CLICOLOR_FORCE")) + return cliColorForce +} + +func isTTYForced(env environ) bool { + skip, _ := strconv.ParseBool(env.get("TTY_FORCE")) + return skip +} + +func colorTerm(env environ) bool { + colorTerm := strings.ToLower(env.get("COLORTERM")) + return colorTerm == "truecolor" || colorTerm == "24bit" || + colorTerm == "yes" || colorTerm == "true" +} + +// envColorProfile returns infers the color profile from the environment. +func envColorProfile(env environ) (p Profile) { + term, ok := env.lookup("TERM") + if !ok || len(term) == 0 || term == dumbTerm { + p = NoTTY + if runtime.GOOS == "windows" { + // Use Windows API to detect color profile. Windows Terminal and + // cmd.exe don't define $TERM. + if wcp, ok := windowsColorProfile(env); ok { + p = wcp + } + } + } else { + p = ANSI + } + + parts := strings.Split(term, "-") + switch parts[0] { + case "alacritty", + "contour", + "foot", + "ghostty", + "kitty", + "rio", + "st", + "wezterm": + return TrueColor + case "xterm": + if len(parts) > 1 { + switch parts[1] { + case "ghostty", "kitty": + // These terminals can be defined as xterm-TERMNAME + return TrueColor + } + } + case "tmux", "screen": + if p < ANSI256 { + p = ANSI256 + } + } + + if isCloudShell, _ := strconv.ParseBool(env.get("GOOGLE_CLOUD_SHELL")); isCloudShell { + return TrueColor + } + + // GNU Screen doesn't support TrueColor + // Tmux doesn't support $COLORTERM + if colorTerm(env) && !strings.HasPrefix(term, "screen") && !strings.HasPrefix(term, "tmux") { + return TrueColor + } + + if strings.HasSuffix(term, "256color") && p < ANSI256 { + p = ANSI256 + } + + // Direct color terminals support true colors. + if strings.HasSuffix(term, "direct") { + return TrueColor + } + + return //nolint:nakedret +} + +// Terminfo returns the color profile based on the terminal's terminfo +// database. This relies on the Tc and RGB capabilities to determine if the +// terminal supports TrueColor. +// If term is empty or "dumb", it returns NoTTY. +func Terminfo(term string) (p Profile) { + if len(term) == 0 || term == "dumb" { + return NoTTY + } + + p = ANSI + ti, err := terminfo.Load(term) + if err != nil { + return + } + + extbools := ti.ExtBoolCapsShort() + if _, ok := extbools["Tc"]; ok { + return TrueColor + } + + if _, ok := extbools["RGB"]; ok { + return TrueColor + } + + return +} + +// Tmux returns the color profile based on `tmux info` output. Tmux supports +// overriding the terminal's color capabilities, so this function will return +// the color profile based on the tmux configuration. +func Tmux(env []string) Profile { + return tmux(newEnviron(env)) +} + +// tmux returns the color profile based on the tmux environment variables. +func tmux(env environ) (p Profile) { + if tmux, ok := env.lookup("TMUX"); !ok || len(tmux) == 0 { + // Not in tmux + return NoTTY + } + + // Check if tmux has either Tc or RGB capabilities. Otherwise, return + // ANSI256. + p = ANSI256 + cmd := exec.Command("tmux", "info") + out, err := cmd.Output() + if err != nil { + return + } + + for _, line := range bytes.Split(out, []byte("\n")) { + if (bytes.Contains(line, []byte("Tc")) || bytes.Contains(line, []byte("RGB"))) && + bytes.Contains(line, []byte("true")) { + return TrueColor + } + } + + return +} + +// environ is a map of environment variables. +type environ map[string]string + +// newEnviron returns a new environment map from a slice of environment +// variables. +func newEnviron(environ []string) environ { + m := make(map[string]string, len(environ)) + for _, e := range environ { + parts := strings.SplitN(e, "=", 2) + var value string + if len(parts) == 2 { + value = parts[1] + } + m[parts[0]] = value + } + return m +} + +// lookup returns the value of an environment variable and a boolean indicating +// if it exists. +func (e environ) lookup(key string) (string, bool) { + v, ok := e[key] + return v, ok +} + +// get returns the value of an environment variable and empty string if it +// doesn't exist. +func (e environ) get(key string) string { + v, _ := e.lookup(key) + return v +} diff --git a/vendor/github.com/charmbracelet/colorprofile/env_other.go b/vendor/github.com/charmbracelet/colorprofile/env_other.go new file mode 100644 index 000000000..080994bc1 --- /dev/null +++ b/vendor/github.com/charmbracelet/colorprofile/env_other.go @@ -0,0 +1,8 @@ +//go:build !windows +// +build !windows + +package colorprofile + +func windowsColorProfile(map[string]string) (Profile, bool) { + return 0, false +} diff --git a/vendor/github.com/charmbracelet/colorprofile/env_windows.go b/vendor/github.com/charmbracelet/colorprofile/env_windows.go new file mode 100644 index 000000000..3b9c28f96 --- /dev/null +++ b/vendor/github.com/charmbracelet/colorprofile/env_windows.go @@ -0,0 +1,45 @@ +//go:build windows +// +build windows + +package colorprofile + +import ( + "strconv" + + "golang.org/x/sys/windows" +) + +func windowsColorProfile(env map[string]string) (Profile, bool) { + if env["ConEmuANSI"] == "ON" { + return TrueColor, true + } + + if len(env["WT_SESSION"]) > 0 { + // Windows Terminal supports TrueColor + return TrueColor, true + } + + major, _, build := windows.RtlGetNtVersionNumbers() + if build < 10586 || major < 10 { + // No ANSI support before WindowsNT 10 build 10586 + if len(env["ANSICON"]) > 0 { + ansiconVer := env["ANSICON_VER"] + cv, err := strconv.Atoi(ansiconVer) + if err != nil || cv < 181 { + // No 8 bit color support before ANSICON 1.81 + return ANSI, true + } + + return ANSI256, true + } + + return NoTTY, true + } + + if build < 14931 { + // No true color support before build 14931 + return ANSI256, true + } + + return TrueColor, true +} diff --git a/vendor/github.com/charmbracelet/colorprofile/profile.go b/vendor/github.com/charmbracelet/colorprofile/profile.go new file mode 100644 index 000000000..2bcb37c6e --- /dev/null +++ b/vendor/github.com/charmbracelet/colorprofile/profile.go @@ -0,0 +1,399 @@ +package colorprofile + +import ( + "image/color" + "math" + + "github.com/charmbracelet/x/ansi" + "github.com/lucasb-eyer/go-colorful" +) + +// Profile is a color profile: NoTTY, Ascii, ANSI, ANSI256, or TrueColor. +type Profile byte + +const ( + // NoTTY is a profile with no terminal support. + NoTTY Profile = iota + // Ascii is a profile with no color support. + Ascii //nolint:revive + // ANSI is a profile with 16 colors (4-bit). + ANSI + // ANSI256 is a profile with 256 colors (8-bit). + ANSI256 + // TrueColor is a profile with 16 million colors (24-bit). + TrueColor +) + +// String returns the string representation of a Profile. +func (p Profile) String() string { + switch p { + case TrueColor: + return "TrueColor" + case ANSI256: + return "ANSI256" + case ANSI: + return "ANSI" + case Ascii: + return "Ascii" + case NoTTY: + return "NoTTY" + } + return "Unknown" +} + +// Convert transforms a given Color to a Color supported within the Profile. +func (p Profile) Convert(c color.Color) color.Color { + if p <= Ascii { + return nil + } + + switch c := c.(type) { + case ansi.BasicColor: + return c + + case ansi.ExtendedColor: + if p == ANSI { + return ansi256ToANSIColor(c) + } + return c + + case ansi.TrueColor, color.Color: + h, ok := colorful.MakeColor(c) + if !ok { + return nil + } + if p != TrueColor { + ac := hexToANSI256Color(h) + if p == ANSI { + return ansi256ToANSIColor(ac) + } + return ac + } + return c + } + + return c +} + +func hexToANSI256Color(c colorful.Color) ansi.ExtendedColor { + v2ci := func(v float64) int { + if v < 48 { + return 0 + } + if v < 115 { + return 1 + } + return int((v - 35) / 40) + } + + // Calculate the nearest 0-based color index at 16..231 + r := v2ci(c.R * 255.0) // 0..5 each + g := v2ci(c.G * 255.0) + b := v2ci(c.B * 255.0) + ci := 36*r + 6*g + b /* 0..215 */ + + // Calculate the represented colors back from the index + i2cv := [6]int{0, 0x5f, 0x87, 0xaf, 0xd7, 0xff} + cr := i2cv[r] // r/g/b, 0..255 each + cg := i2cv[g] + cb := i2cv[b] + + // Calculate the nearest 0-based gray index at 232..255 + var grayIdx int + average := (cr + cg + cb) / 3 + if average > 238 { + grayIdx = 23 + } else { + grayIdx = (average - 3) / 10 // 0..23 + } + gv := 8 + 10*grayIdx // same value for r/g/b, 0..255 + + // Return the one which is nearer to the original input rgb value + c2 := colorful.Color{R: float64(cr) / 255.0, G: float64(cg) / 255.0, B: float64(cb) / 255.0} + g2 := colorful.Color{R: float64(gv) / 255.0, G: float64(gv) / 255.0, B: float64(gv) / 255.0} + colorDist := c.DistanceHSLuv(c2) + grayDist := c.DistanceHSLuv(g2) + + if colorDist <= grayDist { + return ansi.ExtendedColor(16 + ci) //nolint:gosec + } + return ansi.ExtendedColor(232 + grayIdx) //nolint:gosec +} + +func ansi256ToANSIColor(c ansi.ExtendedColor) ansi.BasicColor { + var r int + md := math.MaxFloat64 + + h, _ := colorful.Hex(ansiHex[c]) + for i := 0; i <= 15; i++ { + hb, _ := colorful.Hex(ansiHex[i]) + d := h.DistanceHSLuv(hb) + + if d < md { + md = d + r = i + } + } + + return ansi.BasicColor(r) //nolint:gosec +} + +// RGB values of ANSI colors (0-255). +var ansiHex = []string{ + "#000000", + "#800000", + "#008000", + "#808000", + "#000080", + "#800080", + "#008080", + "#c0c0c0", + "#808080", + "#ff0000", + "#00ff00", + "#ffff00", + "#0000ff", + "#ff00ff", + "#00ffff", + "#ffffff", + "#000000", + "#00005f", + "#000087", + "#0000af", + "#0000d7", + "#0000ff", + "#005f00", + "#005f5f", + "#005f87", + "#005faf", + "#005fd7", + "#005fff", + "#008700", + "#00875f", + "#008787", + "#0087af", + "#0087d7", + "#0087ff", + "#00af00", + "#00af5f", + "#00af87", + "#00afaf", + "#00afd7", + "#00afff", + "#00d700", + "#00d75f", + "#00d787", + "#00d7af", + "#00d7d7", + "#00d7ff", + "#00ff00", + "#00ff5f", + "#00ff87", + "#00ffaf", + "#00ffd7", + "#00ffff", + "#5f0000", + "#5f005f", + "#5f0087", + "#5f00af", + "#5f00d7", + "#5f00ff", + "#5f5f00", + "#5f5f5f", + "#5f5f87", + "#5f5faf", + "#5f5fd7", + "#5f5fff", + "#5f8700", + "#5f875f", + "#5f8787", + "#5f87af", + "#5f87d7", + "#5f87ff", + "#5faf00", + "#5faf5f", + "#5faf87", + "#5fafaf", + "#5fafd7", + "#5fafff", + "#5fd700", + "#5fd75f", + "#5fd787", + "#5fd7af", + "#5fd7d7", + "#5fd7ff", + "#5fff00", + "#5fff5f", + "#5fff87", + "#5fffaf", + "#5fffd7", + "#5fffff", + "#870000", + "#87005f", + "#870087", + "#8700af", + "#8700d7", + "#8700ff", + "#875f00", + "#875f5f", + "#875f87", + "#875faf", + "#875fd7", + "#875fff", + "#878700", + "#87875f", + "#878787", + "#8787af", + "#8787d7", + "#8787ff", + "#87af00", + "#87af5f", + "#87af87", + "#87afaf", + "#87afd7", + "#87afff", + "#87d700", + "#87d75f", + "#87d787", + "#87d7af", + "#87d7d7", + "#87d7ff", + "#87ff00", + "#87ff5f", + "#87ff87", + "#87ffaf", + "#87ffd7", + "#87ffff", + "#af0000", + "#af005f", + "#af0087", + "#af00af", + "#af00d7", + "#af00ff", + "#af5f00", + "#af5f5f", + "#af5f87", + "#af5faf", + "#af5fd7", + "#af5fff", + "#af8700", + "#af875f", + "#af8787", + "#af87af", + "#af87d7", + "#af87ff", + "#afaf00", + "#afaf5f", + "#afaf87", + "#afafaf", + "#afafd7", + "#afafff", + "#afd700", + "#afd75f", + "#afd787", + "#afd7af", + "#afd7d7", + "#afd7ff", + "#afff00", + "#afff5f", + "#afff87", + "#afffaf", + "#afffd7", + "#afffff", + "#d70000", + "#d7005f", + "#d70087", + "#d700af", + "#d700d7", + "#d700ff", + "#d75f00", + "#d75f5f", + "#d75f87", + "#d75faf", + "#d75fd7", + "#d75fff", + "#d78700", + "#d7875f", + "#d78787", + "#d787af", + "#d787d7", + "#d787ff", + "#d7af00", + "#d7af5f", + "#d7af87", + "#d7afaf", + "#d7afd7", + "#d7afff", + "#d7d700", + "#d7d75f", + "#d7d787", + "#d7d7af", + "#d7d7d7", + "#d7d7ff", + "#d7ff00", + "#d7ff5f", + "#d7ff87", + "#d7ffaf", + "#d7ffd7", + "#d7ffff", + "#ff0000", + "#ff005f", + "#ff0087", + "#ff00af", + "#ff00d7", + "#ff00ff", + "#ff5f00", + "#ff5f5f", + "#ff5f87", + "#ff5faf", + "#ff5fd7", + "#ff5fff", + "#ff8700", + "#ff875f", + "#ff8787", + "#ff87af", + "#ff87d7", + "#ff87ff", + "#ffaf00", + "#ffaf5f", + "#ffaf87", + "#ffafaf", + "#ffafd7", + "#ffafff", + "#ffd700", + "#ffd75f", + "#ffd787", + "#ffd7af", + "#ffd7d7", + "#ffd7ff", + "#ffff00", + "#ffff5f", + "#ffff87", + "#ffffaf", + "#ffffd7", + "#ffffff", + "#080808", + "#121212", + "#1c1c1c", + "#262626", + "#303030", + "#3a3a3a", + "#444444", + "#4e4e4e", + "#585858", + "#626262", + "#6c6c6c", + "#767676", + "#808080", + "#8a8a8a", + "#949494", + "#9e9e9e", + "#a8a8a8", + "#b2b2b2", + "#bcbcbc", + "#c6c6c6", + "#d0d0d0", + "#dadada", + "#e4e4e4", + "#eeeeee", +} diff --git a/vendor/github.com/charmbracelet/colorprofile/writer.go b/vendor/github.com/charmbracelet/colorprofile/writer.go new file mode 100644 index 000000000..47f0c6eb9 --- /dev/null +++ b/vendor/github.com/charmbracelet/colorprofile/writer.go @@ -0,0 +1,169 @@ +package colorprofile + +import ( + "bytes" + "fmt" + "image/color" + "io" + "strconv" + + "github.com/charmbracelet/x/ansi" +) + +// NewWriter creates a new color profile writer that downgrades color sequences +// based on the detected color profile. +// +// If environ is nil, it will use os.Environ() to get the environment variables. +// +// It queries the given writer to determine if it supports ANSI escape codes. +// If it does, along with the given environment variables, it will determine +// the appropriate color profile to use for color formatting. +// +// This respects the NO_COLOR, CLICOLOR, and CLICOLOR_FORCE environment variables. +func NewWriter(w io.Writer, environ []string) *Writer { + return &Writer{ + Forward: w, + Profile: Detect(w, environ), + } +} + +// Writer represents a color profile writer that writes ANSI sequences to the +// underlying writer. +type Writer struct { + Forward io.Writer + Profile Profile +} + +// Write writes the given text to the underlying writer. +func (w *Writer) Write(p []byte) (int, error) { + switch w.Profile { + case TrueColor: + return w.Forward.Write(p) //nolint:wrapcheck + case NoTTY: + return io.WriteString(w.Forward, ansi.Strip(string(p))) //nolint:wrapcheck + case Ascii, ANSI, ANSI256: + return w.downsample(p) + default: + return 0, fmt.Errorf("invalid profile: %v", w.Profile) + } +} + +// downsample downgrades the given text to the appropriate color profile. +func (w *Writer) downsample(p []byte) (int, error) { + var buf bytes.Buffer + var state byte + + parser := ansi.GetParser() + defer ansi.PutParser(parser) + + for len(p) > 0 { + parser.Reset() + seq, _, read, newState := ansi.DecodeSequence(p, state, parser) + + switch { + case ansi.HasCsiPrefix(seq) && parser.Command() == 'm': + handleSgr(w, parser, &buf) + default: + // If we're not a style SGR sequence, just write the bytes. + if n, err := buf.Write(seq); err != nil { + return n, err //nolint:wrapcheck + } + } + + p = p[read:] + state = newState + } + + return w.Forward.Write(buf.Bytes()) //nolint:wrapcheck +} + +// WriteString writes the given text to the underlying writer. +func (w *Writer) WriteString(s string) (n int, err error) { + return w.Write([]byte(s)) +} + +func handleSgr(w *Writer, p *ansi.Parser, buf *bytes.Buffer) { + var style ansi.Style + params := p.Params() + for i := 0; i < len(params); i++ { + param := params[i] + + switch param := param.Param(0); param { + case 0: + // SGR default parameter is 0. We use an empty string to reduce the + // number of bytes written to the buffer. + style = append(style, "") + case 30, 31, 32, 33, 34, 35, 36, 37: // 8-bit foreground color + if w.Profile < ANSI { + continue + } + style = style.ForegroundColor( + w.Profile.Convert(ansi.BasicColor(param - 30))) //nolint:gosec + case 38: // 16 or 24-bit foreground color + var c color.Color + if n := ansi.ReadStyleColor(params[i:], &c); n > 0 { + i += n - 1 + } + if w.Profile < ANSI { + continue + } + style = style.ForegroundColor(w.Profile.Convert(c)) + case 39: // default foreground color + if w.Profile < ANSI { + continue + } + style = style.DefaultForegroundColor() + case 40, 41, 42, 43, 44, 45, 46, 47: // 8-bit background color + if w.Profile < ANSI { + continue + } + style = style.BackgroundColor( + w.Profile.Convert(ansi.BasicColor(param - 40))) //nolint:gosec + case 48: // 16 or 24-bit background color + var c color.Color + if n := ansi.ReadStyleColor(params[i:], &c); n > 0 { + i += n - 1 + } + if w.Profile < ANSI { + continue + } + style = style.BackgroundColor(w.Profile.Convert(c)) + case 49: // default background color + if w.Profile < ANSI { + continue + } + style = style.DefaultBackgroundColor() + case 58: // 16 or 24-bit underline color + var c color.Color + if n := ansi.ReadStyleColor(params[i:], &c); n > 0 { + i += n - 1 + } + if w.Profile < ANSI { + continue + } + style = style.UnderlineColor(w.Profile.Convert(c)) + case 59: // default underline color + if w.Profile < ANSI { + continue + } + style = style.DefaultUnderlineColor() + case 90, 91, 92, 93, 94, 95, 96, 97: // 8-bit bright foreground color + if w.Profile < ANSI { + continue + } + style = style.ForegroundColor( + w.Profile.Convert(ansi.BasicColor(param - 90 + 8))) //nolint:gosec + case 100, 101, 102, 103, 104, 105, 106, 107: // 8-bit bright background color + if w.Profile < ANSI { + continue + } + style = style.BackgroundColor( + w.Profile.Convert(ansi.BasicColor(param - 100 + 8))) //nolint:gosec + default: + // If this is not a color attribute, just append it to the style. + style = append(style, strconv.Itoa(param)) + } + } + + _, _ = buf.WriteString(style.String()) +} diff --git a/vendor/github.com/charmbracelet/lipgloss/.gitignore b/vendor/github.com/charmbracelet/lipgloss/.gitignore new file mode 100644 index 000000000..db482015d --- /dev/null +++ b/vendor/github.com/charmbracelet/lipgloss/.gitignore @@ -0,0 +1,2 @@ +ssh_example_ed25519* +dist/ diff --git a/vendor/github.com/charmbracelet/lipgloss/.golangci.yml b/vendor/github.com/charmbracelet/lipgloss/.golangci.yml new file mode 100644 index 000000000..90c5c08bd --- /dev/null +++ b/vendor/github.com/charmbracelet/lipgloss/.golangci.yml @@ -0,0 +1,41 @@ +run: + tests: false + +issues: + include: + - EXC0001 + - EXC0005 + - EXC0011 + - EXC0012 + - EXC0013 + + max-issues-per-linter: 0 + max-same-issues: 0 + +linters: + enable: + - bodyclose + - exhaustive + - goconst + - godot + - godox + - gofumpt + - goimports + - gomoddirectives + - goprintffuncname + - gosec + - misspell + - nakedret + - nestif + - nilerr + - noctx + - nolintlint + - prealloc + - revive + - rowserrcheck + - sqlclosecheck + - tparallel + - unconvert + - unparam + - whitespace + - wrapcheck diff --git a/vendor/github.com/charmbracelet/lipgloss/.goreleaser.yml b/vendor/github.com/charmbracelet/lipgloss/.goreleaser.yml new file mode 100644 index 000000000..3353d0202 --- /dev/null +++ b/vendor/github.com/charmbracelet/lipgloss/.goreleaser.yml @@ -0,0 +1,5 @@ +# yaml-language-server: $schema=https://goreleaser.com/static/schema-pro.json +version: 2 +includes: + - from_url: + url: charmbracelet/meta/main/goreleaser-lib.yaml diff --git a/vendor/github.com/charmbracelet/lipgloss/LICENSE b/vendor/github.com/charmbracelet/lipgloss/LICENSE new file mode 100644 index 000000000..6f5b1fa62 --- /dev/null +++ b/vendor/github.com/charmbracelet/lipgloss/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021-2023 Charmbracelet, Inc + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/charmbracelet/lipgloss/README.md b/vendor/github.com/charmbracelet/lipgloss/README.md new file mode 100644 index 000000000..cee2371ce --- /dev/null +++ b/vendor/github.com/charmbracelet/lipgloss/README.md @@ -0,0 +1,815 @@ +# Lip Gloss + +

+ Lip Gloss title treatment
+ Latest Release + GoDoc + Build Status + phorm.ai +

+ +Style definitions for nice terminal layouts. Built with TUIs in mind. + +![Lip Gloss example](https://github.com/user-attachments/assets/7950b1c1-e0e3-427e-8e7d-6f7f6ad17ca7) + +Lip Gloss takes an expressive, declarative approach to terminal rendering. +Users familiar with CSS will feel at home with Lip Gloss. + +```go + +import "github.com/charmbracelet/lipgloss" + +var style = lipgloss.NewStyle(). + Bold(true). + Foreground(lipgloss.Color("#FAFAFA")). + Background(lipgloss.Color("#7D56F4")). + PaddingTop(2). + PaddingLeft(4). + Width(22) + +fmt.Println(style.Render("Hello, kitty")) +``` + +## Colors + +Lip Gloss supports the following color profiles: + +### ANSI 16 colors (4-bit) + +```go +lipgloss.Color("5") // magenta +lipgloss.Color("9") // red +lipgloss.Color("12") // light blue +``` + +### ANSI 256 Colors (8-bit) + +```go +lipgloss.Color("86") // aqua +lipgloss.Color("201") // hot pink +lipgloss.Color("202") // orange +``` + +### True Color (16,777,216 colors; 24-bit) + +```go +lipgloss.Color("#0000FF") // good ol' 100% blue +lipgloss.Color("#04B575") // a green +lipgloss.Color("#3C3C3C") // a dark gray +``` + +...as well as a 1-bit ASCII profile, which is black and white only. + +The terminal's color profile will be automatically detected, and colors outside +the gamut of the current palette will be automatically coerced to their closest +available value. + +### Adaptive Colors + +You can also specify color options for light and dark backgrounds: + +```go +lipgloss.AdaptiveColor{Light: "236", Dark: "248"} +``` + +The terminal's background color will automatically be detected and the +appropriate color will be chosen at runtime. + +### Complete Colors + +CompleteColor specifies exact values for True Color, ANSI256, and ANSI color +profiles. + +```go +lipgloss.CompleteColor{TrueColor: "#0000FF", ANSI256: "86", ANSI: "5"} +``` + +Automatic color degradation will not be performed in this case and it will be +based on the color specified. + +### Complete Adaptive Colors + +You can use `CompleteColor` with `AdaptiveColor` to specify the exact values for +light and dark backgrounds without automatic color degradation. + +```go +lipgloss.CompleteAdaptiveColor{ + Light: CompleteColor{TrueColor: "#d7ffae", ANSI256: "193", ANSI: "11"}, + Dark: CompleteColor{TrueColor: "#d75fee", ANSI256: "163", ANSI: "5"}, +} +``` + +## Inline Formatting + +Lip Gloss supports the usual ANSI text formatting options: + +```go +var style = lipgloss.NewStyle(). + Bold(true). + Italic(true). + Faint(true). + Blink(true). + Strikethrough(true). + Underline(true). + Reverse(true) +``` + +## Block-Level Formatting + +Lip Gloss also supports rules for block-level formatting: + +```go +// Padding +var style = lipgloss.NewStyle(). + PaddingTop(2). + PaddingRight(4). + PaddingBottom(2). + PaddingLeft(4) + +// Margins +var style = lipgloss.NewStyle(). + MarginTop(2). + MarginRight(4). + MarginBottom(2). + MarginLeft(4) +``` + +There is also shorthand syntax for margins and padding, which follows the same +format as CSS: + +```go +// 2 cells on all sides +lipgloss.NewStyle().Padding(2) + +// 2 cells on the top and bottom, 4 cells on the left and right +lipgloss.NewStyle().Margin(2, 4) + +// 1 cell on the top, 4 cells on the sides, 2 cells on the bottom +lipgloss.NewStyle().Padding(1, 4, 2) + +// Clockwise, starting from the top: 2 cells on the top, 4 on the right, 3 on +// the bottom, and 1 on the left +lipgloss.NewStyle().Margin(2, 4, 3, 1) +``` + +## Aligning Text + +You can align paragraphs of text to the left, right, or center. + +```go +var style = lipgloss.NewStyle(). + Width(24). + Align(lipgloss.Left). // align it left + Align(lipgloss.Right). // no wait, align it right + Align(lipgloss.Center) // just kidding, align it in the center +``` + +## Width and Height + +Setting a minimum width and height is simple and straightforward. + +```go +var style = lipgloss.NewStyle(). + SetString("What’s for lunch?"). + Width(24). + Height(32). + Foreground(lipgloss.Color("63")) +``` + +## Borders + +Adding borders is easy: + +```go +// Add a purple, rectangular border +var style = lipgloss.NewStyle(). + BorderStyle(lipgloss.NormalBorder()). + BorderForeground(lipgloss.Color("63")) + +// Set a rounded, yellow-on-purple border to the top and left +var anotherStyle = lipgloss.NewStyle(). + BorderStyle(lipgloss.RoundedBorder()). + BorderForeground(lipgloss.Color("228")). + BorderBackground(lipgloss.Color("63")). + BorderTop(true). + BorderLeft(true) + +// Make your own border +var myCuteBorder = lipgloss.Border{ + Top: "._.:*:", + Bottom: "._.:*:", + Left: "|*", + Right: "|*", + TopLeft: "*", + TopRight: "*", + BottomLeft: "*", + BottomRight: "*", +} +``` + +There are also shorthand functions for defining borders, which follow a similar +pattern to the margin and padding shorthand functions. + +```go +// Add a thick border to the top and bottom +lipgloss.NewStyle(). + Border(lipgloss.ThickBorder(), true, false) + +// Add a double border to the top and left sides. Rules are set clockwise +// from top. +lipgloss.NewStyle(). + Border(lipgloss.DoubleBorder(), true, false, false, true) +``` + +For more on borders see [the docs][docs]. + +## Copying Styles + +Just use assignment: + +```go +style := lipgloss.NewStyle().Foreground(lipgloss.Color("219")) + +copiedStyle := style // this is a true copy + +wildStyle := style.Blink(true) // this is also true copy, with blink added + +``` + +Since `Style` data structures contains only primitive types, assigning a style +to another effectively creates a new copy of the style without mutating the +original. + +## Inheritance + +Styles can inherit rules from other styles. When inheriting, only unset rules +on the receiver are inherited. + +```go +var styleA = lipgloss.NewStyle(). + Foreground(lipgloss.Color("229")). + Background(lipgloss.Color("63")) + +// Only the background color will be inherited here, because the foreground +// color will have been already set: +var styleB = lipgloss.NewStyle(). + Foreground(lipgloss.Color("201")). + Inherit(styleA) +``` + +## Unsetting Rules + +All rules can be unset: + +```go +var style = lipgloss.NewStyle(). + Bold(true). // make it bold + UnsetBold(). // jk don't make it bold + Background(lipgloss.Color("227")). // yellow background + UnsetBackground() // never mind +``` + +When a rule is unset, it won't be inherited or copied. + +## Enforcing Rules + +Sometimes, such as when developing a component, you want to make sure style +definitions respect their intended purpose in the UI. This is where `Inline` +and `MaxWidth`, and `MaxHeight` come in: + +```go +// Force rendering onto a single line, ignoring margins, padding, and borders. +someStyle.Inline(true).Render("yadda yadda") + +// Also limit rendering to five cells +someStyle.Inline(true).MaxWidth(5).Render("yadda yadda") + +// Limit rendering to a 5x5 cell block +someStyle.MaxWidth(5).MaxHeight(5).Render("yadda yadda") +``` + +## Tabs + +The tab character (`\t`) is rendered differently in different terminals (often +as 8 spaces, sometimes 4). Because of this inconsistency, Lip Gloss converts +tabs to 4 spaces at render time. This behavior can be changed on a per-style +basis, however: + +```go +style := lipgloss.NewStyle() // tabs will render as 4 spaces, the default +style = style.TabWidth(2) // render tabs as 2 spaces +style = style.TabWidth(0) // remove tabs entirely +style = style.TabWidth(lipgloss.NoTabConversion) // leave tabs intact +``` + +## Rendering + +Generally, you just call the `Render(string...)` method on a `lipgloss.Style`: + +```go +style := lipgloss.NewStyle().Bold(true).SetString("Hello,") +fmt.Println(style.Render("kitty.")) // Hello, kitty. +fmt.Println(style.Render("puppy.")) // Hello, puppy. +``` + +But you could also use the Stringer interface: + +```go +var style = lipgloss.NewStyle().SetString("你好,猫咪。").Bold(true) +fmt.Println(style) // 你好,猫咪。 +``` + +### Custom Renderers + +Custom renderers allow you to render to a specific outputs. This is +particularly important when you want to render to different outputs and +correctly detect the color profile and dark background status for each, such as +in a server-client situation. + +```go +func myLittleHandler(sess ssh.Session) { + // Create a renderer for the client. + renderer := lipgloss.NewRenderer(sess) + + // Create a new style on the renderer. + style := renderer.NewStyle().Background(lipgloss.AdaptiveColor{Light: "63", Dark: "228"}) + + // Render. The color profile and dark background state will be correctly detected. + io.WriteString(sess, style.Render("Heyyyyyyy")) +} +``` + +For an example on using a custom renderer over SSH with [Wish][wish] see the +[SSH example][ssh-example]. + +## Utilities + +In addition to pure styling, Lip Gloss also ships with some utilities to help +assemble your layouts. + +### Joining Paragraphs + +Horizontally and vertically joining paragraphs is a cinch. + +```go +// Horizontally join three paragraphs along their bottom edges +lipgloss.JoinHorizontal(lipgloss.Bottom, paragraphA, paragraphB, paragraphC) + +// Vertically join two paragraphs along their center axes +lipgloss.JoinVertical(lipgloss.Center, paragraphA, paragraphB) + +// Horizontally join three paragraphs, with the shorter ones aligning 20% +// from the top of the tallest +lipgloss.JoinHorizontal(0.2, paragraphA, paragraphB, paragraphC) +``` + +### Measuring Width and Height + +Sometimes you’ll want to know the width and height of text blocks when building +your layouts. + +```go +// Render a block of text. +var style = lipgloss.NewStyle(). + Width(40). + Padding(2) +var block string = style.Render(someLongString) + +// Get the actual, physical dimensions of the text block. +width := lipgloss.Width(block) +height := lipgloss.Height(block) + +// Here's a shorthand function. +w, h := lipgloss.Size(block) +``` + +### Placing Text in Whitespace + +Sometimes you’ll simply want to place a block of text in whitespace. + +```go +// Center a paragraph horizontally in a space 80 cells wide. The height of +// the block returned will be as tall as the input paragraph. +block := lipgloss.PlaceHorizontal(80, lipgloss.Center, fancyStyledParagraph) + +// Place a paragraph at the bottom of a space 30 cells tall. The width of +// the text block returned will be as wide as the input paragraph. +block := lipgloss.PlaceVertical(30, lipgloss.Bottom, fancyStyledParagraph) + +// Place a paragraph in the bottom right corner of a 30x80 cell space. +block := lipgloss.Place(30, 80, lipgloss.Right, lipgloss.Bottom, fancyStyledParagraph) +``` + +You can also style the whitespace. For details, see [the docs][docs]. + +## Rendering Tables + +Lip Gloss ships with a table rendering sub-package. + +```go +import "github.com/charmbracelet/lipgloss/table" +``` + +Define some rows of data. + +```go +rows := [][]string{ + {"Chinese", "您好", "你好"}, + {"Japanese", "こんにちは", "やあ"}, + {"Arabic", "أهلين", "أهلا"}, + {"Russian", "Здравствуйте", "Привет"}, + {"Spanish", "Hola", "¿Qué tal?"}, +} +``` + +Use the table package to style and render the table. + +```go +var ( + purple = lipgloss.Color("99") + gray = lipgloss.Color("245") + lightGray = lipgloss.Color("241") + + headerStyle = lipgloss.NewStyle().Foreground(purple).Bold(true).Align(lipgloss.Center) + cellStyle = lipgloss.NewStyle().Padding(0, 1).Width(14) + oddRowStyle = cellStyle.Foreground(gray) + evenRowStyle = cellStyle.Foreground(lightGray) +) + +t := table.New(). + Border(lipgloss.NormalBorder()). + BorderStyle(lipgloss.NewStyle().Foreground(purple)). + StyleFunc(func(row, col int) lipgloss.Style { + switch { + case row == table.HeaderRow: + return headerStyle + case row%2 == 0: + return evenRowStyle + default: + return oddRowStyle + } + }). + Headers("LANGUAGE", "FORMAL", "INFORMAL"). + Rows(rows...) + +// You can also add tables row-by-row +t.Row("English", "You look absolutely fabulous.", "How's it going?") +``` + +Print the table. + +```go +fmt.Println(t) +``` + +![Table Example](https://github.com/charmbracelet/lipgloss/assets/42545625/6e4b70c4-f494-45da-a467-bdd27df30d5d) + +> [!WARNING] +> Table `Rows` need to be declared before `Offset` otherwise it does nothing. + +### Table Borders + +There are helpers to generate tables in markdown or ASCII style: + +#### Markdown Table + +```go +table.New().Border(lipgloss.MarkdownBorder()).BorderTop(false).BorderBottom(false) +``` + +``` +| LANGUAGE | FORMAL | INFORMAL | +|----------|--------------|-----------| +| Chinese | Nǐn hǎo | Nǐ hǎo | +| French | Bonjour | Salut | +| Russian | Zdravstvuyte | Privet | +| Spanish | Hola | ¿Qué tal? | +``` + +#### ASCII Table + +```go +table.New().Border(lipgloss.ASCIIBorder()) +``` + +``` ++----------+--------------+-----------+ +| LANGUAGE | FORMAL | INFORMAL | ++----------+--------------+-----------+ +| Chinese | Nǐn hǎo | Nǐ hǎo | +| French | Bonjour | Salut | +| Russian | Zdravstvuyte | Privet | +| Spanish | Hola | ¿Qué tal? | ++----------+--------------+-----------+ +``` + +For more on tables see [the docs](https://pkg.go.dev/github.com/charmbracelet/lipgloss?tab=doc) and [examples](https://github.com/charmbracelet/lipgloss/tree/master/examples/table). + +## Rendering Lists + +Lip Gloss ships with a list rendering sub-package. + +```go +import "github.com/charmbracelet/lipgloss/list" +``` + +Define a new list. + +```go +l := list.New("A", "B", "C") +``` + +Print the list. + +```go +fmt.Println(l) + +// • A +// • B +// • C +``` + +Lists have the ability to nest. + +```go +l := list.New( + "A", list.New("Artichoke"), + "B", list.New("Baking Flour", "Bananas", "Barley", "Bean Sprouts"), + "C", list.New("Cashew Apple", "Cashews", "Coconut Milk", "Curry Paste", "Currywurst"), + "D", list.New("Dill", "Dragonfruit", "Dried Shrimp"), + "E", list.New("Eggs"), + "F", list.New("Fish Cake", "Furikake"), + "J", list.New("Jicama"), + "K", list.New("Kohlrabi"), + "L", list.New("Leeks", "Lentils", "Licorice Root"), +) +``` + +Print the list. + +```go +fmt.Println(l) +``` + +

+image +

+ +Lists can be customized via their enumeration function as well as using +`lipgloss.Style`s. + +```go +enumeratorStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("99")).MarginRight(1) +itemStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("212")).MarginRight(1) + +l := list.New( + "Glossier", + "Claire’s Boutique", + "Nyx", + "Mac", + "Milk", + ). + Enumerator(list.Roman). + EnumeratorStyle(enumeratorStyle). + ItemStyle(itemStyle) +``` + +Print the list. + +

+List example +

+ +In addition to the predefined enumerators (`Arabic`, `Alphabet`, `Roman`, `Bullet`, `Tree`), +you may also define your own custom enumerator: + +```go +l := list.New("Duck", "Duck", "Duck", "Duck", "Goose", "Duck", "Duck") + +func DuckDuckGooseEnumerator(l list.Items, i int) string { + if l.At(i).Value() == "Goose" { + return "Honk →" + } + return "" +} + +l = l.Enumerator(DuckDuckGooseEnumerator) +``` + +Print the list: + +

+image +

+ +If you need, you can also build lists incrementally: + +```go +l := list.New() + +for i := 0; i < repeat; i++ { + l.Item("Lip Gloss") +} +``` + +## Rendering Trees + +Lip Gloss ships with a tree rendering sub-package. + +```go +import "github.com/charmbracelet/lipgloss/tree" +``` + +Define a new tree. + +```go +t := tree.Root("."). + Child("A", "B", "C") +``` + +Print the tree. + +```go +fmt.Println(t) + +// . +// ├── A +// ├── B +// └── C +``` + +Trees have the ability to nest. + +```go +t := tree.Root("."). + Child("macOS"). + Child( + tree.New(). + Root("Linux"). + Child("NixOS"). + Child("Arch Linux (btw)"). + Child("Void Linux"), + ). + Child( + tree.New(). + Root("BSD"). + Child("FreeBSD"). + Child("OpenBSD"), + ) +``` + +Print the tree. + +```go +fmt.Println(t) +``` + +

+Tree Example (simple) +

+ +Trees can be customized via their enumeration function as well as using +`lipgloss.Style`s. + +```go +enumeratorStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("63")).MarginRight(1) +rootStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("35")) +itemStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("212")) + +t := tree. + Root("⁜ Makeup"). + Child( + "Glossier", + "Fenty Beauty", + tree.New().Child( + "Gloss Bomb Universal Lip Luminizer", + "Hot Cheeks Velour Blushlighter", + ), + "Nyx", + "Mac", + "Milk", + ). + Enumerator(tree.RoundedEnumerator). + EnumeratorStyle(enumeratorStyle). + RootStyle(rootStyle). + ItemStyle(itemStyle) +``` + +Print the tree. + +

+Tree Example (makeup) +

+ +The predefined enumerators for trees are `DefaultEnumerator` and `RoundedEnumerator`. + +If you need, you can also build trees incrementally: + +```go +t := tree.New() + +for i := 0; i < repeat; i++ { + t.Child("Lip Gloss") +} +``` + +--- + +## FAQ + +
+ +Why are things misaligning? Why are borders at the wrong widths? + +

This is most likely due to your locale and encoding, particularly with +regard to Chinese, Japanese, and Korean (for example, zh_CN.UTF-8 +or ja_JP.UTF-8). The most direct way to fix this is to set +RUNEWIDTH_EASTASIAN=0 in your environment.

+ +

For details see https://github.com/charmbracelet/lipgloss/issues/40.

+
+ +
+ +Why isn't Lip Gloss displaying colors? + +

Lip Gloss automatically degrades colors to the best available option in the +given terminal, and if output's not a TTY it will remove color output entirely. +This is common when running tests, CI, or when piping output elsewhere.

+ +

If necessary, you can force a color profile in your tests with +SetColorProfile.

+ +```go +import ( + "github.com/charmbracelet/lipgloss" + "github.com/muesli/termenv" +) + +lipgloss.SetColorProfile(termenv.TrueColor) +``` + +_Note:_ this option limits the flexibility of your application and can cause +ANSI escape codes to be output in cases where that might not be desired. Take +careful note of your use case and environment before choosing to force a color +profile. + +
+ +## What about [Bubble Tea][tea]? + +Lip Gloss doesn’t replace Bubble Tea. Rather, it is an excellent Bubble Tea +companion. It was designed to make assembling terminal user interface views as +simple and fun as possible so that you can focus on building your application +instead of concerning yourself with low-level layout details. + +In simple terms, you can use Lip Gloss to help build your Bubble Tea views. + +[tea]: https://github.com/charmbracelet/tea + +## Under the Hood + +Lip Gloss is built on the excellent [Termenv][termenv] and [Reflow][reflow] +libraries which deal with color and ANSI-aware text operations, respectively. +For many use cases Termenv and Reflow will be sufficient for your needs. + +[termenv]: https://github.com/muesli/termenv +[reflow]: https://github.com/muesli/reflow + +## Rendering Markdown + +For a more document-centric rendering solution with support for things like +lists, tables, and syntax-highlighted code have a look at [Glamour][glamour], +the stylesheet-based Markdown renderer. + +[glamour]: https://github.com/charmbracelet/glamour + +## Contributing + +See [contributing][contribute]. + +[contribute]: https://github.com/charmbracelet/lipgloss/contribute + +## Feedback + +We’d love to hear your thoughts on this project. Feel free to drop us a note! + +- [Twitter](https://twitter.com/charmcli) +- [The Fediverse](https://mastodon.social/@charmcli) +- [Discord](https://charm.sh/chat) + +## License + +[MIT](https://github.com/charmbracelet/lipgloss/raw/master/LICENSE) + +--- + +Part of [Charm](https://charm.sh). + +The Charm logo + +Charm热爱开源 • Charm loves open source + +[docs]: https://pkg.go.dev/github.com/charmbracelet/lipgloss?tab=doc +[wish]: https://github.com/charmbracelet/wish +[ssh-example]: examples/ssh diff --git a/vendor/github.com/charmbracelet/lipgloss/Taskfile.yaml b/vendor/github.com/charmbracelet/lipgloss/Taskfile.yaml new file mode 100644 index 000000000..0b4a7711a --- /dev/null +++ b/vendor/github.com/charmbracelet/lipgloss/Taskfile.yaml @@ -0,0 +1,19 @@ +# https://taskfile.dev + +version: '3' + +tasks: + lint: + desc: Run base linters + cmds: + - golangci-lint run + + test: + desc: Run tests + cmds: + - go test ./... {{.CLI_ARGS}} + + test:table: + desc: Run table tests + cmds: + - go test ./table {{.CLI_ARGS}} diff --git a/vendor/github.com/charmbracelet/lipgloss/align.go b/vendor/github.com/charmbracelet/lipgloss/align.go new file mode 100644 index 000000000..ce654b232 --- /dev/null +++ b/vendor/github.com/charmbracelet/lipgloss/align.go @@ -0,0 +1,83 @@ +package lipgloss + +import ( + "strings" + + "github.com/charmbracelet/x/ansi" + "github.com/muesli/termenv" +) + +// Perform text alignment. If the string is multi-lined, we also make all lines +// the same width by padding them with spaces. If a termenv style is passed, +// use that to style the spaces added. +func alignTextHorizontal(str string, pos Position, width int, style *termenv.Style) string { + lines, widestLine := getLines(str) + var b strings.Builder + + for i, l := range lines { + lineWidth := ansi.StringWidth(l) + + shortAmount := widestLine - lineWidth // difference from the widest line + shortAmount += max(0, width-(shortAmount+lineWidth)) // difference from the total width, if set + + if shortAmount > 0 { + switch pos { //nolint:exhaustive + case Right: + s := strings.Repeat(" ", shortAmount) + if style != nil { + s = style.Styled(s) + } + l = s + l + case Center: + // Note: remainder goes on the right. + left := shortAmount / 2 //nolint:mnd + right := left + shortAmount%2 //nolint:mnd + + leftSpaces := strings.Repeat(" ", left) + rightSpaces := strings.Repeat(" ", right) + + if style != nil { + leftSpaces = style.Styled(leftSpaces) + rightSpaces = style.Styled(rightSpaces) + } + l = leftSpaces + l + rightSpaces + default: // Left + s := strings.Repeat(" ", shortAmount) + if style != nil { + s = style.Styled(s) + } + l += s + } + } + + b.WriteString(l) + if i < len(lines)-1 { + b.WriteRune('\n') + } + } + + return b.String() +} + +func alignTextVertical(str string, pos Position, height int, _ *termenv.Style) string { + strHeight := strings.Count(str, "\n") + 1 + if height < strHeight { + return str + } + + switch pos { + case Top: + return str + strings.Repeat("\n", height-strHeight) + case Center: + topPadding, bottomPadding := (height-strHeight)/2, (height-strHeight)/2 //nolint:mnd + if strHeight+topPadding+bottomPadding > height { + topPadding-- + } else if strHeight+topPadding+bottomPadding < height { + bottomPadding++ + } + return strings.Repeat("\n", topPadding) + str + strings.Repeat("\n", bottomPadding) + case Bottom: + return strings.Repeat("\n", height-strHeight) + str + } + return str +} diff --git a/vendor/github.com/charmbracelet/lipgloss/ansi_unix.go b/vendor/github.com/charmbracelet/lipgloss/ansi_unix.go new file mode 100644 index 000000000..d416b8c99 --- /dev/null +++ b/vendor/github.com/charmbracelet/lipgloss/ansi_unix.go @@ -0,0 +1,7 @@ +//go:build !windows +// +build !windows + +package lipgloss + +// enableLegacyWindowsANSI is only needed on Windows. +func enableLegacyWindowsANSI() {} diff --git a/vendor/github.com/charmbracelet/lipgloss/ansi_windows.go b/vendor/github.com/charmbracelet/lipgloss/ansi_windows.go new file mode 100644 index 000000000..0cf56e4c7 --- /dev/null +++ b/vendor/github.com/charmbracelet/lipgloss/ansi_windows.go @@ -0,0 +1,22 @@ +//go:build windows +// +build windows + +package lipgloss + +import ( + "sync" + + "github.com/muesli/termenv" +) + +var enableANSI sync.Once + +// enableANSIColors enables support for ANSI color sequences in the Windows +// default console (cmd.exe and the PowerShell application). Note that this +// only works with Windows 10. Also note that Windows Terminal supports colors +// by default. +func enableLegacyWindowsANSI() { + enableANSI.Do(func() { + _, _ = termenv.EnableWindowsANSIConsole() + }) +} diff --git a/vendor/github.com/charmbracelet/lipgloss/borders.go b/vendor/github.com/charmbracelet/lipgloss/borders.go new file mode 100644 index 000000000..b36f87438 --- /dev/null +++ b/vendor/github.com/charmbracelet/lipgloss/borders.go @@ -0,0 +1,490 @@ +package lipgloss + +import ( + "strings" + + "github.com/charmbracelet/x/ansi" + "github.com/muesli/termenv" + "github.com/rivo/uniseg" +) + +// Border contains a series of values which comprise the various parts of a +// border. +type Border struct { + Top string + Bottom string + Left string + Right string + TopLeft string + TopRight string + BottomLeft string + BottomRight string + MiddleLeft string + MiddleRight string + Middle string + MiddleTop string + MiddleBottom string +} + +// GetTopSize returns the width of the top border. If borders contain runes of +// varying widths, the widest rune is returned. If no border exists on the top +// edge, 0 is returned. +func (b Border) GetTopSize() int { + return getBorderEdgeWidth(b.TopLeft, b.Top, b.TopRight) +} + +// GetRightSize returns the width of the right border. If borders contain +// runes of varying widths, the widest rune is returned. If no border exists on +// the right edge, 0 is returned. +func (b Border) GetRightSize() int { + return getBorderEdgeWidth(b.TopRight, b.Right, b.BottomRight) +} + +// GetBottomSize returns the width of the bottom border. If borders contain +// runes of varying widths, the widest rune is returned. If no border exists on +// the bottom edge, 0 is returned. +func (b Border) GetBottomSize() int { + return getBorderEdgeWidth(b.BottomLeft, b.Bottom, b.BottomRight) +} + +// GetLeftSize returns the width of the left border. If borders contain runes +// of varying widths, the widest rune is returned. If no border exists on the +// left edge, 0 is returned. +func (b Border) GetLeftSize() int { + return getBorderEdgeWidth(b.TopLeft, b.Left, b.BottomLeft) +} + +func getBorderEdgeWidth(borderParts ...string) (maxWidth int) { + for _, piece := range borderParts { + w := maxRuneWidth(piece) + if w > maxWidth { + maxWidth = w + } + } + return maxWidth +} + +var ( + noBorder = Border{} + + normalBorder = Border{ + Top: "─", + Bottom: "─", + Left: "│", + Right: "│", + TopLeft: "┌", + TopRight: "┐", + BottomLeft: "└", + BottomRight: "┘", + MiddleLeft: "├", + MiddleRight: "┤", + Middle: "┼", + MiddleTop: "┬", + MiddleBottom: "┴", + } + + roundedBorder = Border{ + Top: "─", + Bottom: "─", + Left: "│", + Right: "│", + TopLeft: "╭", + TopRight: "╮", + BottomLeft: "╰", + BottomRight: "╯", + MiddleLeft: "├", + MiddleRight: "┤", + Middle: "┼", + MiddleTop: "┬", + MiddleBottom: "┴", + } + + blockBorder = Border{ + Top: "█", + Bottom: "█", + Left: "█", + Right: "█", + TopLeft: "█", + TopRight: "█", + BottomLeft: "█", + BottomRight: "█", + MiddleLeft: "█", + MiddleRight: "█", + Middle: "█", + MiddleTop: "█", + MiddleBottom: "█", + } + + outerHalfBlockBorder = Border{ + Top: "▀", + Bottom: "▄", + Left: "▌", + Right: "▐", + TopLeft: "▛", + TopRight: "▜", + BottomLeft: "▙", + BottomRight: "▟", + } + + innerHalfBlockBorder = Border{ + Top: "▄", + Bottom: "▀", + Left: "▐", + Right: "▌", + TopLeft: "▗", + TopRight: "▖", + BottomLeft: "▝", + BottomRight: "▘", + } + + thickBorder = Border{ + Top: "━", + Bottom: "━", + Left: "┃", + Right: "┃", + TopLeft: "┏", + TopRight: "┓", + BottomLeft: "┗", + BottomRight: "┛", + MiddleLeft: "┣", + MiddleRight: "┫", + Middle: "╋", + MiddleTop: "┳", + MiddleBottom: "┻", + } + + doubleBorder = Border{ + Top: "═", + Bottom: "═", + Left: "║", + Right: "║", + TopLeft: "╔", + TopRight: "╗", + BottomLeft: "╚", + BottomRight: "╝", + MiddleLeft: "╠", + MiddleRight: "╣", + Middle: "╬", + MiddleTop: "╦", + MiddleBottom: "╩", + } + + hiddenBorder = Border{ + Top: " ", + Bottom: " ", + Left: " ", + Right: " ", + TopLeft: " ", + TopRight: " ", + BottomLeft: " ", + BottomRight: " ", + MiddleLeft: " ", + MiddleRight: " ", + Middle: " ", + MiddleTop: " ", + MiddleBottom: " ", + } + + markdownBorder = Border{ + Top: "-", + Bottom: "-", + Left: "|", + Right: "|", + TopLeft: "|", + TopRight: "|", + BottomLeft: "|", + BottomRight: "|", + MiddleLeft: "|", + MiddleRight: "|", + Middle: "|", + MiddleTop: "|", + MiddleBottom: "|", + } + + asciiBorder = Border{ + Top: "-", + Bottom: "-", + Left: "|", + Right: "|", + TopLeft: "+", + TopRight: "+", + BottomLeft: "+", + BottomRight: "+", + MiddleLeft: "+", + MiddleRight: "+", + Middle: "+", + MiddleTop: "+", + MiddleBottom: "+", + } +) + +// NormalBorder returns a standard-type border with a normal weight and 90 +// degree corners. +func NormalBorder() Border { + return normalBorder +} + +// RoundedBorder returns a border with rounded corners. +func RoundedBorder() Border { + return roundedBorder +} + +// BlockBorder returns a border that takes the whole block. +func BlockBorder() Border { + return blockBorder +} + +// OuterHalfBlockBorder returns a half-block border that sits outside the frame. +func OuterHalfBlockBorder() Border { + return outerHalfBlockBorder +} + +// InnerHalfBlockBorder returns a half-block border that sits inside the frame. +func InnerHalfBlockBorder() Border { + return innerHalfBlockBorder +} + +// ThickBorder returns a border that's thicker than the one returned by +// NormalBorder. +func ThickBorder() Border { + return thickBorder +} + +// DoubleBorder returns a border comprised of two thin strokes. +func DoubleBorder() Border { + return doubleBorder +} + +// HiddenBorder returns a border that renders as a series of single-cell +// spaces. It's useful for cases when you want to remove a standard border but +// maintain layout positioning. This said, you can still apply a background +// color to a hidden border. +func HiddenBorder() Border { + return hiddenBorder +} + +// MarkdownBorder return a table border in markdown style. +// +// Make sure to disable top and bottom border for the best result. This will +// ensure that the output is valid markdown. +// +// table.New().Border(lipgloss.MarkdownBorder()).BorderTop(false).BorderBottom(false) +func MarkdownBorder() Border { + return markdownBorder +} + +// ASCIIBorder returns a table border with ASCII characters. +func ASCIIBorder() Border { + return asciiBorder +} + +func (s Style) applyBorder(str string) string { + var ( + border = s.getBorderStyle() + hasTop = s.getAsBool(borderTopKey, false) + hasRight = s.getAsBool(borderRightKey, false) + hasBottom = s.getAsBool(borderBottomKey, false) + hasLeft = s.getAsBool(borderLeftKey, false) + + topFG = s.getAsColor(borderTopForegroundKey) + rightFG = s.getAsColor(borderRightForegroundKey) + bottomFG = s.getAsColor(borderBottomForegroundKey) + leftFG = s.getAsColor(borderLeftForegroundKey) + + topBG = s.getAsColor(borderTopBackgroundKey) + rightBG = s.getAsColor(borderRightBackgroundKey) + bottomBG = s.getAsColor(borderBottomBackgroundKey) + leftBG = s.getAsColor(borderLeftBackgroundKey) + ) + + // If a border is set and no sides have been specifically turned on or off + // render borders on all sides. + if s.implicitBorders() { + hasTop = true + hasRight = true + hasBottom = true + hasLeft = true + } + + // If no border is set or all borders are been disabled, abort. + if border == noBorder || (!hasTop && !hasRight && !hasBottom && !hasLeft) { + return str + } + + lines, width := getLines(str) + + if hasLeft { + if border.Left == "" { + border.Left = " " + } + width += maxRuneWidth(border.Left) + } + + if hasRight && border.Right == "" { + border.Right = " " + } + + // If corners should be rendered but are set with the empty string, fill them + // with a single space. + if hasTop && hasLeft && border.TopLeft == "" { + border.TopLeft = " " + } + if hasTop && hasRight && border.TopRight == "" { + border.TopRight = " " + } + if hasBottom && hasLeft && border.BottomLeft == "" { + border.BottomLeft = " " + } + if hasBottom && hasRight && border.BottomRight == "" { + border.BottomRight = " " + } + + // Figure out which corners we should actually be using based on which + // sides are set to show. + if hasTop { + switch { + case !hasLeft && !hasRight: + border.TopLeft = "" + border.TopRight = "" + case !hasLeft: + border.TopLeft = "" + case !hasRight: + border.TopRight = "" + } + } + if hasBottom { + switch { + case !hasLeft && !hasRight: + border.BottomLeft = "" + border.BottomRight = "" + case !hasLeft: + border.BottomLeft = "" + case !hasRight: + border.BottomRight = "" + } + } + + // For now, limit corners to one rune. + border.TopLeft = getFirstRuneAsString(border.TopLeft) + border.TopRight = getFirstRuneAsString(border.TopRight) + border.BottomRight = getFirstRuneAsString(border.BottomRight) + border.BottomLeft = getFirstRuneAsString(border.BottomLeft) + + var out strings.Builder + + // Render top + if hasTop { + top := renderHorizontalEdge(border.TopLeft, border.Top, border.TopRight, width) + top = s.styleBorder(top, topFG, topBG) + out.WriteString(top) + out.WriteRune('\n') + } + + leftRunes := []rune(border.Left) + leftIndex := 0 + + rightRunes := []rune(border.Right) + rightIndex := 0 + + // Render sides + for i, l := range lines { + if hasLeft { + r := string(leftRunes[leftIndex]) + leftIndex++ + if leftIndex >= len(leftRunes) { + leftIndex = 0 + } + out.WriteString(s.styleBorder(r, leftFG, leftBG)) + } + out.WriteString(l) + if hasRight { + r := string(rightRunes[rightIndex]) + rightIndex++ + if rightIndex >= len(rightRunes) { + rightIndex = 0 + } + out.WriteString(s.styleBorder(r, rightFG, rightBG)) + } + if i < len(lines)-1 { + out.WriteRune('\n') + } + } + + // Render bottom + if hasBottom { + bottom := renderHorizontalEdge(border.BottomLeft, border.Bottom, border.BottomRight, width) + bottom = s.styleBorder(bottom, bottomFG, bottomBG) + out.WriteRune('\n') + out.WriteString(bottom) + } + + return out.String() +} + +// Render the horizontal (top or bottom) portion of a border. +func renderHorizontalEdge(left, middle, right string, width int) string { + if middle == "" { + middle = " " + } + + leftWidth := ansi.StringWidth(left) + rightWidth := ansi.StringWidth(right) + + runes := []rune(middle) + j := 0 + + out := strings.Builder{} + out.WriteString(left) + for i := leftWidth + rightWidth; i < width+rightWidth; { + out.WriteRune(runes[j]) + j++ + if j >= len(runes) { + j = 0 + } + i += ansi.StringWidth(string(runes[j])) + } + out.WriteString(right) + + return out.String() +} + +// Apply foreground and background styling to a border. +func (s Style) styleBorder(border string, fg, bg TerminalColor) string { + if fg == noColor && bg == noColor { + return border + } + + style := termenv.Style{} + + if fg != noColor { + style = style.Foreground(fg.color(s.r)) + } + if bg != noColor { + style = style.Background(bg.color(s.r)) + } + + return style.Styled(border) +} + +func maxRuneWidth(str string) int { + var width int + + state := -1 + for len(str) > 0 { + var w int + _, str, w, state = uniseg.FirstGraphemeClusterInString(str, state) + if w > width { + width = w + } + } + + return width +} + +func getFirstRuneAsString(str string) string { + if str == "" { + return str + } + r := []rune(str) + return string(r[0]) +} diff --git a/vendor/github.com/charmbracelet/lipgloss/color.go b/vendor/github.com/charmbracelet/lipgloss/color.go new file mode 100644 index 000000000..6caf3a3d5 --- /dev/null +++ b/vendor/github.com/charmbracelet/lipgloss/color.go @@ -0,0 +1,172 @@ +package lipgloss + +import ( + "strconv" + + "github.com/muesli/termenv" +) + +// TerminalColor is a color intended to be rendered in the terminal. +type TerminalColor interface { + color(*Renderer) termenv.Color + RGBA() (r, g, b, a uint32) +} + +var noColor = NoColor{} + +// NoColor is used to specify the absence of color styling. When this is active +// foreground colors will be rendered with the terminal's default text color, +// and background colors will not be drawn at all. +// +// Example usage: +// +// var style = someStyle.Background(lipgloss.NoColor{}) +type NoColor struct{} + +func (NoColor) color(*Renderer) termenv.Color { + return termenv.NoColor{} +} + +// RGBA returns the RGBA value of this color. Because we have to return +// something, despite this color being the absence of color, we're returning +// black with 100% opacity. +// +// Red: 0x0, Green: 0x0, Blue: 0x0, Alpha: 0xFFFF. +// +// Deprecated. +func (n NoColor) RGBA() (r, g, b, a uint32) { + return 0x0, 0x0, 0x0, 0xFFFF //nolint:mnd +} + +// Color specifies a color by hex or ANSI value. For example: +// +// ansiColor := lipgloss.Color("21") +// hexColor := lipgloss.Color("#0000ff") +type Color string + +func (c Color) color(r *Renderer) termenv.Color { + return r.ColorProfile().Color(string(c)) +} + +// RGBA returns the RGBA value of this color. This satisfies the Go Color +// interface. Note that on error we return black with 100% opacity, or: +// +// Red: 0x0, Green: 0x0, Blue: 0x0, Alpha: 0xFFFF. +// +// Deprecated. +func (c Color) RGBA() (r, g, b, a uint32) { + return termenv.ConvertToRGB(c.color(renderer)).RGBA() +} + +// ANSIColor is a color specified by an ANSI color value. It's merely syntactic +// sugar for the more general Color function. Invalid colors will render as +// black. +// +// Example usage: +// +// // These two statements are equivalent. +// colorA := lipgloss.ANSIColor(21) +// colorB := lipgloss.Color("21") +type ANSIColor uint + +func (ac ANSIColor) color(r *Renderer) termenv.Color { + return Color(strconv.FormatUint(uint64(ac), 10)).color(r) +} + +// RGBA returns the RGBA value of this color. This satisfies the Go Color +// interface. Note that on error we return black with 100% opacity, or: +// +// Red: 0x0, Green: 0x0, Blue: 0x0, Alpha: 0xFFFF. +// +// Deprecated. +func (ac ANSIColor) RGBA() (r, g, b, a uint32) { + cf := Color(strconv.FormatUint(uint64(ac), 10)) + return cf.RGBA() +} + +// AdaptiveColor provides color options for light and dark backgrounds. The +// appropriate color will be returned at runtime based on the darkness of the +// terminal background color. +// +// Example usage: +// +// color := lipgloss.AdaptiveColor{Light: "#0000ff", Dark: "#000099"} +type AdaptiveColor struct { + Light string + Dark string +} + +func (ac AdaptiveColor) color(r *Renderer) termenv.Color { + if r.HasDarkBackground() { + return Color(ac.Dark).color(r) + } + return Color(ac.Light).color(r) +} + +// RGBA returns the RGBA value of this color. This satisfies the Go Color +// interface. Note that on error we return black with 100% opacity, or: +// +// Red: 0x0, Green: 0x0, Blue: 0x0, Alpha: 0xFFFF. +// +// Deprecated. +func (ac AdaptiveColor) RGBA() (r, g, b, a uint32) { + return termenv.ConvertToRGB(ac.color(renderer)).RGBA() +} + +// CompleteColor specifies exact values for truecolor, ANSI256, and ANSI color +// profiles. Automatic color degradation will not be performed. +type CompleteColor struct { + TrueColor string + ANSI256 string + ANSI string +} + +func (c CompleteColor) color(r *Renderer) termenv.Color { + p := r.ColorProfile() + switch p { //nolint:exhaustive + case termenv.TrueColor: + return p.Color(c.TrueColor) + case termenv.ANSI256: + return p.Color(c.ANSI256) + case termenv.ANSI: + return p.Color(c.ANSI) + default: + return termenv.NoColor{} + } +} + +// RGBA returns the RGBA value of this color. This satisfies the Go Color +// interface. Note that on error we return black with 100% opacity, or: +// +// Red: 0x0, Green: 0x0, Blue: 0x0, Alpha: 0xFFFF. +// CompleteAdaptiveColor specifies exact values for truecolor, ANSI256, and ANSI color +// +// Deprecated. +func (c CompleteColor) RGBA() (r, g, b, a uint32) { + return termenv.ConvertToRGB(c.color(renderer)).RGBA() +} + +// CompleteAdaptiveColor specifies exact values for truecolor, ANSI256, and ANSI color +// profiles, with separate options for light and dark backgrounds. Automatic +// color degradation will not be performed. +type CompleteAdaptiveColor struct { + Light CompleteColor + Dark CompleteColor +} + +func (cac CompleteAdaptiveColor) color(r *Renderer) termenv.Color { + if r.HasDarkBackground() { + return cac.Dark.color(r) + } + return cac.Light.color(r) +} + +// RGBA returns the RGBA value of this color. This satisfies the Go Color +// interface. Note that on error we return black with 100% opacity, or: +// +// Red: 0x0, Green: 0x0, Blue: 0x0, Alpha: 0xFFFF. +// +// Deprecated. +func (cac CompleteAdaptiveColor) RGBA() (r, g, b, a uint32) { + return termenv.ConvertToRGB(cac.color(renderer)).RGBA() +} diff --git a/vendor/github.com/charmbracelet/lipgloss/get.go b/vendor/github.com/charmbracelet/lipgloss/get.go new file mode 100644 index 000000000..422b4ce95 --- /dev/null +++ b/vendor/github.com/charmbracelet/lipgloss/get.go @@ -0,0 +1,556 @@ +package lipgloss + +import ( + "strings" + + "github.com/charmbracelet/x/ansi" +) + +// GetBold returns the style's bold value. If no value is set false is returned. +func (s Style) GetBold() bool { + return s.getAsBool(boldKey, false) +} + +// GetItalic returns the style's italic value. If no value is set false is +// returned. +func (s Style) GetItalic() bool { + return s.getAsBool(italicKey, false) +} + +// GetUnderline returns the style's underline value. If no value is set false is +// returned. +func (s Style) GetUnderline() bool { + return s.getAsBool(underlineKey, false) +} + +// GetStrikethrough returns the style's strikethrough value. If no value is set false +// is returned. +func (s Style) GetStrikethrough() bool { + return s.getAsBool(strikethroughKey, false) +} + +// GetReverse returns the style's reverse value. If no value is set false is +// returned. +func (s Style) GetReverse() bool { + return s.getAsBool(reverseKey, false) +} + +// GetBlink returns the style's blink value. If no value is set false is +// returned. +func (s Style) GetBlink() bool { + return s.getAsBool(blinkKey, false) +} + +// GetFaint returns the style's faint value. If no value is set false is +// returned. +func (s Style) GetFaint() bool { + return s.getAsBool(faintKey, false) +} + +// GetForeground returns the style's foreground color. If no value is set +// NoColor{} is returned. +func (s Style) GetForeground() TerminalColor { + return s.getAsColor(foregroundKey) +} + +// GetBackground returns the style's background color. If no value is set +// NoColor{} is returned. +func (s Style) GetBackground() TerminalColor { + return s.getAsColor(backgroundKey) +} + +// GetWidth returns the style's width setting. If no width is set 0 is +// returned. +func (s Style) GetWidth() int { + return s.getAsInt(widthKey) +} + +// GetHeight returns the style's height setting. If no height is set 0 is +// returned. +func (s Style) GetHeight() int { + return s.getAsInt(heightKey) +} + +// GetAlign returns the style's implicit horizontal alignment setting. +// If no alignment is set Position.Left is returned. +func (s Style) GetAlign() Position { + v := s.getAsPosition(alignHorizontalKey) + if v == Position(0) { + return Left + } + return v +} + +// GetAlignHorizontal returns the style's implicit horizontal alignment setting. +// If no alignment is set Position.Left is returned. +func (s Style) GetAlignHorizontal() Position { + v := s.getAsPosition(alignHorizontalKey) + if v == Position(0) { + return Left + } + return v +} + +// GetAlignVertical returns the style's implicit vertical alignment setting. +// If no alignment is set Position.Top is returned. +func (s Style) GetAlignVertical() Position { + v := s.getAsPosition(alignVerticalKey) + if v == Position(0) { + return Top + } + return v +} + +// GetPadding returns the style's top, right, bottom, and left padding values, +// in that order. 0 is returned for unset values. +func (s Style) GetPadding() (top, right, bottom, left int) { + return s.getAsInt(paddingTopKey), + s.getAsInt(paddingRightKey), + s.getAsInt(paddingBottomKey), + s.getAsInt(paddingLeftKey) +} + +// GetPaddingTop returns the style's top padding. If no value is set 0 is +// returned. +func (s Style) GetPaddingTop() int { + return s.getAsInt(paddingTopKey) +} + +// GetPaddingRight returns the style's right padding. If no value is set 0 is +// returned. +func (s Style) GetPaddingRight() int { + return s.getAsInt(paddingRightKey) +} + +// GetPaddingBottom returns the style's bottom padding. If no value is set 0 is +// returned. +func (s Style) GetPaddingBottom() int { + return s.getAsInt(paddingBottomKey) +} + +// GetPaddingLeft returns the style's left padding. If no value is set 0 is +// returned. +func (s Style) GetPaddingLeft() int { + return s.getAsInt(paddingLeftKey) +} + +// GetHorizontalPadding returns the style's left and right padding. Unset +// values are measured as 0. +func (s Style) GetHorizontalPadding() int { + return s.getAsInt(paddingLeftKey) + s.getAsInt(paddingRightKey) +} + +// GetVerticalPadding returns the style's top and bottom padding. Unset values +// are measured as 0. +func (s Style) GetVerticalPadding() int { + return s.getAsInt(paddingTopKey) + s.getAsInt(paddingBottomKey) +} + +// GetColorWhitespace returns the style's whitespace coloring setting. If no +// value is set false is returned. +func (s Style) GetColorWhitespace() bool { + return s.getAsBool(colorWhitespaceKey, false) +} + +// GetMargin returns the style's top, right, bottom, and left margins, in that +// order. 0 is returned for unset values. +func (s Style) GetMargin() (top, right, bottom, left int) { + return s.getAsInt(marginTopKey), + s.getAsInt(marginRightKey), + s.getAsInt(marginBottomKey), + s.getAsInt(marginLeftKey) +} + +// GetMarginTop returns the style's top margin. If no value is set 0 is +// returned. +func (s Style) GetMarginTop() int { + return s.getAsInt(marginTopKey) +} + +// GetMarginRight returns the style's right margin. If no value is set 0 is +// returned. +func (s Style) GetMarginRight() int { + return s.getAsInt(marginRightKey) +} + +// GetMarginBottom returns the style's bottom margin. If no value is set 0 is +// returned. +func (s Style) GetMarginBottom() int { + return s.getAsInt(marginBottomKey) +} + +// GetMarginLeft returns the style's left margin. If no value is set 0 is +// returned. +func (s Style) GetMarginLeft() int { + return s.getAsInt(marginLeftKey) +} + +// GetHorizontalMargins returns the style's left and right margins. Unset +// values are measured as 0. +func (s Style) GetHorizontalMargins() int { + return s.getAsInt(marginLeftKey) + s.getAsInt(marginRightKey) +} + +// GetVerticalMargins returns the style's top and bottom margins. Unset values +// are measured as 0. +func (s Style) GetVerticalMargins() int { + return s.getAsInt(marginTopKey) + s.getAsInt(marginBottomKey) +} + +// GetBorder returns the style's border style (type Border) and value for the +// top, right, bottom, and left in that order. If no value is set for the +// border style, Border{} is returned. For all other unset values false is +// returned. +func (s Style) GetBorder() (b Border, top, right, bottom, left bool) { + return s.getBorderStyle(), + s.getAsBool(borderTopKey, false), + s.getAsBool(borderRightKey, false), + s.getAsBool(borderBottomKey, false), + s.getAsBool(borderLeftKey, false) +} + +// GetBorderStyle returns the style's border style (type Border). If no value +// is set Border{} is returned. +func (s Style) GetBorderStyle() Border { + return s.getBorderStyle() +} + +// GetBorderTop returns the style's top border setting. If no value is set +// false is returned. +func (s Style) GetBorderTop() bool { + return s.getAsBool(borderTopKey, false) +} + +// GetBorderRight returns the style's right border setting. If no value is set +// false is returned. +func (s Style) GetBorderRight() bool { + return s.getAsBool(borderRightKey, false) +} + +// GetBorderBottom returns the style's bottom border setting. If no value is +// set false is returned. +func (s Style) GetBorderBottom() bool { + return s.getAsBool(borderBottomKey, false) +} + +// GetBorderLeft returns the style's left border setting. If no value is +// set false is returned. +func (s Style) GetBorderLeft() bool { + return s.getAsBool(borderLeftKey, false) +} + +// GetBorderTopForeground returns the style's border top foreground color. If +// no value is set NoColor{} is returned. +func (s Style) GetBorderTopForeground() TerminalColor { + return s.getAsColor(borderTopForegroundKey) +} + +// GetBorderRightForeground returns the style's border right foreground color. +// If no value is set NoColor{} is returned. +func (s Style) GetBorderRightForeground() TerminalColor { + return s.getAsColor(borderRightForegroundKey) +} + +// GetBorderBottomForeground returns the style's border bottom foreground +// color. If no value is set NoColor{} is returned. +func (s Style) GetBorderBottomForeground() TerminalColor { + return s.getAsColor(borderBottomForegroundKey) +} + +// GetBorderLeftForeground returns the style's border left foreground +// color. If no value is set NoColor{} is returned. +func (s Style) GetBorderLeftForeground() TerminalColor { + return s.getAsColor(borderLeftForegroundKey) +} + +// GetBorderTopBackground returns the style's border top background color. If +// no value is set NoColor{} is returned. +func (s Style) GetBorderTopBackground() TerminalColor { + return s.getAsColor(borderTopBackgroundKey) +} + +// GetBorderRightBackground returns the style's border right background color. +// If no value is set NoColor{} is returned. +func (s Style) GetBorderRightBackground() TerminalColor { + return s.getAsColor(borderRightBackgroundKey) +} + +// GetBorderBottomBackground returns the style's border bottom background +// color. If no value is set NoColor{} is returned. +func (s Style) GetBorderBottomBackground() TerminalColor { + return s.getAsColor(borderBottomBackgroundKey) +} + +// GetBorderLeftBackground returns the style's border left background +// color. If no value is set NoColor{} is returned. +func (s Style) GetBorderLeftBackground() TerminalColor { + return s.getAsColor(borderLeftBackgroundKey) +} + +// GetBorderTopWidth returns the width of the top border. If borders contain +// runes of varying widths, the widest rune is returned. If no border exists on +// the top edge, 0 is returned. +// +// Deprecated: This function simply calls Style.GetBorderTopSize. +func (s Style) GetBorderTopWidth() int { + return s.GetBorderTopSize() +} + +// GetBorderTopSize returns the width of the top border. If borders contain +// runes of varying widths, the widest rune is returned. If no border exists on +// the top edge, 0 is returned. +func (s Style) GetBorderTopSize() int { + if !s.getAsBool(borderTopKey, false) && !s.implicitBorders() { + return 0 + } + return s.getBorderStyle().GetTopSize() +} + +// GetBorderLeftSize returns the width of the left border. If borders contain +// runes of varying widths, the widest rune is returned. If no border exists on +// the left edge, 0 is returned. +func (s Style) GetBorderLeftSize() int { + if !s.getAsBool(borderLeftKey, false) && !s.implicitBorders() { + return 0 + } + return s.getBorderStyle().GetLeftSize() +} + +// GetBorderBottomSize returns the width of the bottom border. If borders +// contain runes of varying widths, the widest rune is returned. If no border +// exists on the left edge, 0 is returned. +func (s Style) GetBorderBottomSize() int { + if !s.getAsBool(borderBottomKey, false) && !s.implicitBorders() { + return 0 + } + return s.getBorderStyle().GetBottomSize() +} + +// GetBorderRightSize returns the width of the right border. If borders +// contain runes of varying widths, the widest rune is returned. If no border +// exists on the right edge, 0 is returned. +func (s Style) GetBorderRightSize() int { + if !s.getAsBool(borderRightKey, false) && !s.implicitBorders() { + return 0 + } + return s.getBorderStyle().GetRightSize() +} + +// GetHorizontalBorderSize returns the width of the horizontal borders. If +// borders contain runes of varying widths, the widest rune is returned. If no +// border exists on the horizontal edges, 0 is returned. +func (s Style) GetHorizontalBorderSize() int { + return s.GetBorderLeftSize() + s.GetBorderRightSize() +} + +// GetVerticalBorderSize returns the width of the vertical borders. If +// borders contain runes of varying widths, the widest rune is returned. If no +// border exists on the vertical edges, 0 is returned. +func (s Style) GetVerticalBorderSize() int { + return s.GetBorderTopSize() + s.GetBorderBottomSize() +} + +// GetInline returns the style's inline setting. If no value is set false is +// returned. +func (s Style) GetInline() bool { + return s.getAsBool(inlineKey, false) +} + +// GetMaxWidth returns the style's max width setting. If no value is set 0 is +// returned. +func (s Style) GetMaxWidth() int { + return s.getAsInt(maxWidthKey) +} + +// GetMaxHeight returns the style's max height setting. If no value is set 0 is +// returned. +func (s Style) GetMaxHeight() int { + return s.getAsInt(maxHeightKey) +} + +// GetTabWidth returns the style's tab width setting. If no value is set 4 is +// returned which is the implicit default. +func (s Style) GetTabWidth() int { + return s.getAsInt(tabWidthKey) +} + +// GetUnderlineSpaces returns whether or not the style is set to underline +// spaces. If not value is set false is returned. +func (s Style) GetUnderlineSpaces() bool { + return s.getAsBool(underlineSpacesKey, false) +} + +// GetStrikethroughSpaces returns whether or not the style is set to strikethrough +// spaces. If not value is set false is returned. +func (s Style) GetStrikethroughSpaces() bool { + return s.getAsBool(strikethroughSpacesKey, false) +} + +// GetHorizontalFrameSize returns the sum of the style's horizontal margins, padding +// and border widths. +// +// Provisional: this method may be renamed. +func (s Style) GetHorizontalFrameSize() int { + return s.GetHorizontalMargins() + s.GetHorizontalPadding() + s.GetHorizontalBorderSize() +} + +// GetVerticalFrameSize returns the sum of the style's vertical margins, padding +// and border widths. +// +// Provisional: this method may be renamed. +func (s Style) GetVerticalFrameSize() int { + return s.GetVerticalMargins() + s.GetVerticalPadding() + s.GetVerticalBorderSize() +} + +// GetFrameSize returns the sum of the margins, padding and border width for +// both the horizontal and vertical margins. +func (s Style) GetFrameSize() (x, y int) { + return s.GetHorizontalFrameSize(), s.GetVerticalFrameSize() +} + +// GetTransform returns the transform set on the style. If no transform is set +// nil is returned. +func (s Style) GetTransform() func(string) string { + return s.getAsTransform(transformKey) +} + +// Returns whether or not the given property is set. +func (s Style) isSet(k propKey) bool { + return s.props.has(k) +} + +func (s Style) getAsBool(k propKey, defaultVal bool) bool { + if !s.isSet(k) { + return defaultVal + } + return s.attrs&int(k) != 0 +} + +func (s Style) getAsColor(k propKey) TerminalColor { + if !s.isSet(k) { + return noColor + } + + var c TerminalColor + switch k { //nolint:exhaustive + case foregroundKey: + c = s.fgColor + case backgroundKey: + c = s.bgColor + case marginBackgroundKey: + c = s.marginBgColor + case borderTopForegroundKey: + c = s.borderTopFgColor + case borderRightForegroundKey: + c = s.borderRightFgColor + case borderBottomForegroundKey: + c = s.borderBottomFgColor + case borderLeftForegroundKey: + c = s.borderLeftFgColor + case borderTopBackgroundKey: + c = s.borderTopBgColor + case borderRightBackgroundKey: + c = s.borderRightBgColor + case borderBottomBackgroundKey: + c = s.borderBottomBgColor + case borderLeftBackgroundKey: + c = s.borderLeftBgColor + } + + if c != nil { + return c + } + + return noColor +} + +func (s Style) getAsInt(k propKey) int { + if !s.isSet(k) { + return 0 + } + switch k { //nolint:exhaustive + case widthKey: + return s.width + case heightKey: + return s.height + case paddingTopKey: + return s.paddingTop + case paddingRightKey: + return s.paddingRight + case paddingBottomKey: + return s.paddingBottom + case paddingLeftKey: + return s.paddingLeft + case marginTopKey: + return s.marginTop + case marginRightKey: + return s.marginRight + case marginBottomKey: + return s.marginBottom + case marginLeftKey: + return s.marginLeft + case maxWidthKey: + return s.maxWidth + case maxHeightKey: + return s.maxHeight + case tabWidthKey: + return s.tabWidth + } + return 0 +} + +func (s Style) getAsPosition(k propKey) Position { + if !s.isSet(k) { + return Position(0) + } + switch k { //nolint:exhaustive + case alignHorizontalKey: + return s.alignHorizontal + case alignVerticalKey: + return s.alignVertical + } + return Position(0) +} + +func (s Style) getBorderStyle() Border { + if !s.isSet(borderStyleKey) { + return noBorder + } + return s.borderStyle +} + +// Returns whether or not the style has implicit borders. This happens when +// a border style has been set but no border sides have been explicitly turned +// on or off. +func (s Style) implicitBorders() bool { + var ( + borderStyle = s.getBorderStyle() + topSet = s.isSet(borderTopKey) + rightSet = s.isSet(borderRightKey) + bottomSet = s.isSet(borderBottomKey) + leftSet = s.isSet(borderLeftKey) + ) + return borderStyle != noBorder && !(topSet || rightSet || bottomSet || leftSet) +} + +func (s Style) getAsTransform(propKey) func(string) string { + if !s.isSet(transformKey) { + return nil + } + return s.transform +} + +// Split a string into lines, additionally returning the size of the widest +// line. +func getLines(s string) (lines []string, widest int) { + lines = strings.Split(s, "\n") + + for _, l := range lines { + w := ansi.StringWidth(l) + if widest < w { + widest = w + } + } + + return lines, widest +} diff --git a/vendor/github.com/charmbracelet/lipgloss/join.go b/vendor/github.com/charmbracelet/lipgloss/join.go new file mode 100644 index 000000000..b0a23a546 --- /dev/null +++ b/vendor/github.com/charmbracelet/lipgloss/join.go @@ -0,0 +1,175 @@ +package lipgloss + +import ( + "math" + "strings" + + "github.com/charmbracelet/x/ansi" +) + +// JoinHorizontal is a utility function for horizontally joining two +// potentially multi-lined strings along a vertical axis. The first argument is +// the position, with 0 being all the way at the top and 1 being all the way +// at the bottom. +// +// If you just want to align to the top, center or bottom you may as well just +// use the helper constants Top, Center, and Bottom. +// +// Example: +// +// blockB := "...\n...\n..." +// blockA := "...\n...\n...\n...\n..." +// +// // Join 20% from the top +// str := lipgloss.JoinHorizontal(0.2, blockA, blockB) +// +// // Join on the top edge +// str := lipgloss.JoinHorizontal(lipgloss.Top, blockA, blockB) +func JoinHorizontal(pos Position, strs ...string) string { + if len(strs) == 0 { + return "" + } + if len(strs) == 1 { + return strs[0] + } + + var ( + // Groups of strings broken into multiple lines + blocks = make([][]string, len(strs)) + + // Max line widths for the above text blocks + maxWidths = make([]int, len(strs)) + + // Height of the tallest block + maxHeight int + ) + + // Break text blocks into lines and get max widths for each text block + for i, str := range strs { + blocks[i], maxWidths[i] = getLines(str) + if len(blocks[i]) > maxHeight { + maxHeight = len(blocks[i]) + } + } + + // Add extra lines to make each side the same height + for i := range blocks { + if len(blocks[i]) >= maxHeight { + continue + } + + extraLines := make([]string, maxHeight-len(blocks[i])) + + switch pos { //nolint:exhaustive + case Top: + blocks[i] = append(blocks[i], extraLines...) + + case Bottom: + blocks[i] = append(extraLines, blocks[i]...) + + default: // Somewhere in the middle + n := len(extraLines) + split := int(math.Round(float64(n) * pos.value())) + top := n - split + bottom := n - top + + blocks[i] = append(extraLines[top:], blocks[i]...) + blocks[i] = append(blocks[i], extraLines[bottom:]...) + } + } + + // Merge lines + var b strings.Builder + for i := range blocks[0] { // remember, all blocks have the same number of members now + for j, block := range blocks { + b.WriteString(block[i]) + + // Also make lines the same length + b.WriteString(strings.Repeat(" ", maxWidths[j]-ansi.StringWidth(block[i]))) + } + if i < len(blocks[0])-1 { + b.WriteRune('\n') + } + } + + return b.String() +} + +// JoinVertical is a utility function for vertically joining two potentially +// multi-lined strings along a horizontal axis. The first argument is the +// position, with 0 being all the way to the left and 1 being all the way to +// the right. +// +// If you just want to align to the left, right or center you may as well just +// use the helper constants Left, Center, and Right. +// +// Example: +// +// blockB := "...\n...\n..." +// blockA := "...\n...\n...\n...\n..." +// +// // Join 20% from the top +// str := lipgloss.JoinVertical(0.2, blockA, blockB) +// +// // Join on the right edge +// str := lipgloss.JoinVertical(lipgloss.Right, blockA, blockB) +func JoinVertical(pos Position, strs ...string) string { + if len(strs) == 0 { + return "" + } + if len(strs) == 1 { + return strs[0] + } + + var ( + blocks = make([][]string, len(strs)) + maxWidth int + ) + + for i := range strs { + var w int + blocks[i], w = getLines(strs[i]) + if w > maxWidth { + maxWidth = w + } + } + + var b strings.Builder + for i, block := range blocks { + for j, line := range block { + w := maxWidth - ansi.StringWidth(line) + + switch pos { //nolint:exhaustive + case Left: + b.WriteString(line) + b.WriteString(strings.Repeat(" ", w)) + + case Right: + b.WriteString(strings.Repeat(" ", w)) + b.WriteString(line) + + default: // Somewhere in the middle + if w < 1 { + b.WriteString(line) + break + } + + split := int(math.Round(float64(w) * pos.value())) + right := w - split + left := w - right + + b.WriteString(strings.Repeat(" ", left)) + b.WriteString(line) + b.WriteString(strings.Repeat(" ", right)) + } + + // Write a newline as long as we're not on the last line of the + // last block. + if !(i == len(blocks)-1 && j == len(block)-1) { + b.WriteRune('\n') + } + } + } + + return b.String() +} diff --git a/vendor/github.com/charmbracelet/lipgloss/position.go b/vendor/github.com/charmbracelet/lipgloss/position.go new file mode 100644 index 000000000..185f5af3b --- /dev/null +++ b/vendor/github.com/charmbracelet/lipgloss/position.go @@ -0,0 +1,154 @@ +package lipgloss + +import ( + "math" + "strings" + + "github.com/charmbracelet/x/ansi" +) + +// Position represents a position along a horizontal or vertical axis. It's in +// situations where an axis is involved, like alignment, joining, placement and +// so on. +// +// A value of 0 represents the start (the left or top) and 1 represents the end +// (the right or bottom). 0.5 represents the center. +// +// There are constants Top, Bottom, Center, Left and Right in this package that +// can be used to aid readability. +type Position float64 + +func (p Position) value() float64 { + return math.Min(1, math.Max(0, float64(p))) +} + +// Position aliases. +const ( + Top Position = 0.0 + Bottom Position = 1.0 + Center Position = 0.5 + Left Position = 0.0 + Right Position = 1.0 +) + +// Place places a string or text block vertically in an unstyled box of a given +// width or height. +func Place(width, height int, hPos, vPos Position, str string, opts ...WhitespaceOption) string { + return renderer.Place(width, height, hPos, vPos, str, opts...) +} + +// Place places a string or text block vertically in an unstyled box of a given +// width or height. +func (r *Renderer) Place(width, height int, hPos, vPos Position, str string, opts ...WhitespaceOption) string { + return r.PlaceVertical(height, vPos, r.PlaceHorizontal(width, hPos, str, opts...), opts...) +} + +// PlaceHorizontal places a string or text block horizontally in an unstyled +// block of a given width. If the given width is shorter than the max width of +// the string (measured by its longest line) this will be a noop. +func PlaceHorizontal(width int, pos Position, str string, opts ...WhitespaceOption) string { + return renderer.PlaceHorizontal(width, pos, str, opts...) +} + +// PlaceHorizontal places a string or text block horizontally in an unstyled +// block of a given width. If the given width is shorter than the max width of +// the string (measured by its longest line) this will be a noöp. +func (r *Renderer) PlaceHorizontal(width int, pos Position, str string, opts ...WhitespaceOption) string { + lines, contentWidth := getLines(str) + gap := width - contentWidth + + if gap <= 0 { + return str + } + + ws := newWhitespace(r, opts...) + + var b strings.Builder + for i, l := range lines { + // Is this line shorter than the longest line? + short := max(0, contentWidth-ansi.StringWidth(l)) + + switch pos { //nolint:exhaustive + case Left: + b.WriteString(l) + b.WriteString(ws.render(gap + short)) + + case Right: + b.WriteString(ws.render(gap + short)) + b.WriteString(l) + + default: // somewhere in the middle + totalGap := gap + short + + split := int(math.Round(float64(totalGap) * pos.value())) + left := totalGap - split + right := totalGap - left + + b.WriteString(ws.render(left)) + b.WriteString(l) + b.WriteString(ws.render(right)) + } + + if i < len(lines)-1 { + b.WriteRune('\n') + } + } + + return b.String() +} + +// PlaceVertical places a string or text block vertically in an unstyled block +// of a given height. If the given height is shorter than the height of the +// string (measured by its newlines) then this will be a noop. +func PlaceVertical(height int, pos Position, str string, opts ...WhitespaceOption) string { + return renderer.PlaceVertical(height, pos, str, opts...) +} + +// PlaceVertical places a string or text block vertically in an unstyled block +// of a given height. If the given height is shorter than the height of the +// string (measured by its newlines) then this will be a noöp. +func (r *Renderer) PlaceVertical(height int, pos Position, str string, opts ...WhitespaceOption) string { + contentHeight := strings.Count(str, "\n") + 1 + gap := height - contentHeight + + if gap <= 0 { + return str + } + + ws := newWhitespace(r, opts...) + + _, width := getLines(str) + emptyLine := ws.render(width) + b := strings.Builder{} + + switch pos { //nolint:exhaustive + case Top: + b.WriteString(str) + b.WriteRune('\n') + for i := 0; i < gap; i++ { + b.WriteString(emptyLine) + if i < gap-1 { + b.WriteRune('\n') + } + } + + case Bottom: + b.WriteString(strings.Repeat(emptyLine+"\n", gap)) + b.WriteString(str) + + default: // Somewhere in the middle + split := int(math.Round(float64(gap) * pos.value())) + top := gap - split + bottom := gap - top + + b.WriteString(strings.Repeat(emptyLine+"\n", top)) + b.WriteString(str) + + for i := 0; i < bottom; i++ { + b.WriteRune('\n') + b.WriteString(emptyLine) + } + } + + return b.String() +} diff --git a/vendor/github.com/charmbracelet/lipgloss/ranges.go b/vendor/github.com/charmbracelet/lipgloss/ranges.go new file mode 100644 index 000000000..d17169987 --- /dev/null +++ b/vendor/github.com/charmbracelet/lipgloss/ranges.go @@ -0,0 +1,48 @@ +package lipgloss + +import ( + "strings" + + "github.com/charmbracelet/x/ansi" +) + +// StyleRanges allows to, given a string, style ranges of it differently. +// The function will take into account existing styles. +// Ranges should not overlap. +func StyleRanges(s string, ranges ...Range) string { + if len(ranges) == 0 { + return s + } + + var buf strings.Builder + lastIdx := 0 + stripped := ansi.Strip(s) + + // Use Truncate and TruncateLeft to style match.MatchedIndexes without + // losing the original option style: + for _, rng := range ranges { + // Add the text before this match + if rng.Start > lastIdx { + buf.WriteString(ansi.Cut(s, lastIdx, rng.Start)) + } + // Add the matched range with its highlight + buf.WriteString(rng.Style.Render(ansi.Cut(stripped, rng.Start, rng.End))) + lastIdx = rng.End + } + + // Add any remaining text after the last match + buf.WriteString(ansi.TruncateLeft(s, lastIdx, "")) + + return buf.String() +} + +// NewRange returns a range that can be used with [StyleRanges]. +func NewRange(start, end int, style Style) Range { + return Range{start, end, style} +} + +// Range to be used with [StyleRanges]. +type Range struct { + Start, End int + Style Style +} diff --git a/vendor/github.com/charmbracelet/lipgloss/renderer.go b/vendor/github.com/charmbracelet/lipgloss/renderer.go new file mode 100644 index 000000000..233aa7c00 --- /dev/null +++ b/vendor/github.com/charmbracelet/lipgloss/renderer.go @@ -0,0 +1,181 @@ +package lipgloss + +import ( + "io" + "sync" + + "github.com/muesli/termenv" +) + +// We're manually creating the struct here to avoid initializing the output and +// query the terminal multiple times. +var renderer = &Renderer{ + output: termenv.DefaultOutput(), +} + +// Renderer is a lipgloss terminal renderer. +type Renderer struct { + output *termenv.Output + colorProfile termenv.Profile + hasDarkBackground bool + + getColorProfile sync.Once + explicitColorProfile bool + + getBackgroundColor sync.Once + explicitBackgroundColor bool + + mtx sync.RWMutex +} + +// DefaultRenderer returns the default renderer. +func DefaultRenderer() *Renderer { + return renderer +} + +// SetDefaultRenderer sets the default global renderer. +func SetDefaultRenderer(r *Renderer) { + renderer = r +} + +// NewRenderer creates a new Renderer. +// +// w will be used to determine the terminal's color capabilities. +func NewRenderer(w io.Writer, opts ...termenv.OutputOption) *Renderer { + r := &Renderer{ + output: termenv.NewOutput(w, opts...), + } + return r +} + +// Output returns the termenv output. +func (r *Renderer) Output() *termenv.Output { + r.mtx.RLock() + defer r.mtx.RUnlock() + return r.output +} + +// SetOutput sets the termenv output. +func (r *Renderer) SetOutput(o *termenv.Output) { + r.mtx.Lock() + defer r.mtx.Unlock() + r.output = o +} + +// ColorProfile returns the detected termenv color profile. +func (r *Renderer) ColorProfile() termenv.Profile { + r.mtx.RLock() + defer r.mtx.RUnlock() + + if !r.explicitColorProfile { + r.getColorProfile.Do(func() { + // NOTE: we don't need to lock here because sync.Once provides its + // own locking mechanism. + r.colorProfile = r.output.EnvColorProfile() + }) + } + + return r.colorProfile +} + +// ColorProfile returns the detected termenv color profile. +func ColorProfile() termenv.Profile { + return renderer.ColorProfile() +} + +// SetColorProfile sets the color profile on the renderer. This function exists +// mostly for testing purposes so that you can assure you're testing against +// a specific profile. +// +// Outside of testing you likely won't want to use this function as the color +// profile will detect and cache the terminal's color capabilities and choose +// the best available profile. +// +// Available color profiles are: +// +// termenv.Ascii // no color, 1-bit +// termenv.ANSI //16 colors, 4-bit +// termenv.ANSI256 // 256 colors, 8-bit +// termenv.TrueColor // 16,777,216 colors, 24-bit +// +// This function is thread-safe. +func (r *Renderer) SetColorProfile(p termenv.Profile) { + r.mtx.Lock() + defer r.mtx.Unlock() + + r.colorProfile = p + r.explicitColorProfile = true +} + +// SetColorProfile sets the color profile on the default renderer. This +// function exists mostly for testing purposes so that you can assure you're +// testing against a specific profile. +// +// Outside of testing you likely won't want to use this function as the color +// profile will detect and cache the terminal's color capabilities and choose +// the best available profile. +// +// Available color profiles are: +// +// termenv.Ascii // no color, 1-bit +// termenv.ANSI //16 colors, 4-bit +// termenv.ANSI256 // 256 colors, 8-bit +// termenv.TrueColor // 16,777,216 colors, 24-bit +// +// This function is thread-safe. +func SetColorProfile(p termenv.Profile) { + renderer.SetColorProfile(p) +} + +// HasDarkBackground returns whether or not the terminal has a dark background. +func HasDarkBackground() bool { + return renderer.HasDarkBackground() +} + +// HasDarkBackground returns whether or not the renderer will render to a dark +// background. A dark background can either be auto-detected, or set explicitly +// on the renderer. +func (r *Renderer) HasDarkBackground() bool { + r.mtx.RLock() + defer r.mtx.RUnlock() + + if !r.explicitBackgroundColor { + r.getBackgroundColor.Do(func() { + // NOTE: we don't need to lock here because sync.Once provides its + // own locking mechanism. + r.hasDarkBackground = r.output.HasDarkBackground() + }) + } + + return r.hasDarkBackground +} + +// SetHasDarkBackground sets the background color detection value for the +// default renderer. This function exists mostly for testing purposes so that +// you can assure you're testing against a specific background color setting. +// +// Outside of testing you likely won't want to use this function as the +// backgrounds value will be automatically detected and cached against the +// terminal's current background color setting. +// +// This function is thread-safe. +func SetHasDarkBackground(b bool) { + renderer.SetHasDarkBackground(b) +} + +// SetHasDarkBackground sets the background color detection value on the +// renderer. This function exists mostly for testing purposes so that you can +// assure you're testing against a specific background color setting. +// +// Outside of testing you likely won't want to use this function as the +// backgrounds value will be automatically detected and cached against the +// terminal's current background color setting. +// +// This function is thread-safe. +func (r *Renderer) SetHasDarkBackground(b bool) { + r.mtx.Lock() + defer r.mtx.Unlock() + + r.hasDarkBackground = b + r.explicitBackgroundColor = true +} diff --git a/vendor/github.com/charmbracelet/lipgloss/runes.go b/vendor/github.com/charmbracelet/lipgloss/runes.go new file mode 100644 index 000000000..7a49e326c --- /dev/null +++ b/vendor/github.com/charmbracelet/lipgloss/runes.go @@ -0,0 +1,43 @@ +package lipgloss + +import ( + "strings" +) + +// StyleRunes apply a given style to runes at the given indices in the string. +// Note that you must provide styling options for both matched and unmatched +// runes. Indices out of bounds will be ignored. +func StyleRunes(str string, indices []int, matched, unmatched Style) string { + // Convert slice of indices to a map for easier lookups + m := make(map[int]struct{}) + for _, i := range indices { + m[i] = struct{}{} + } + + var ( + out strings.Builder + group strings.Builder + style Style + runes = []rune(str) + ) + + for i, r := range runes { + group.WriteRune(r) + + _, matches := m[i] + _, nextMatches := m[i+1] + + if matches != nextMatches || i == len(runes)-1 { + // Flush + if matches { + style = matched + } else { + style = unmatched + } + out.WriteString(style.Render(group.String())) + group.Reset() + } + } + + return out.String() +} diff --git a/vendor/github.com/charmbracelet/lipgloss/set.go b/vendor/github.com/charmbracelet/lipgloss/set.go new file mode 100644 index 000000000..fde38faec --- /dev/null +++ b/vendor/github.com/charmbracelet/lipgloss/set.go @@ -0,0 +1,799 @@ +package lipgloss + +// Set a value on the underlying rules map. +func (s *Style) set(key propKey, value interface{}) { + // We don't allow negative integers on any of our other values, so just keep + // them at zero or above. We could use uints instead, but the + // conversions are a little tedious, so we're sticking with ints for + // sake of usability. + switch key { //nolint:exhaustive + case foregroundKey: + s.fgColor = colorOrNil(value) + case backgroundKey: + s.bgColor = colorOrNil(value) + case widthKey: + s.width = max(0, value.(int)) + case heightKey: + s.height = max(0, value.(int)) + case alignHorizontalKey: + s.alignHorizontal = value.(Position) + case alignVerticalKey: + s.alignVertical = value.(Position) + case paddingTopKey: + s.paddingTop = max(0, value.(int)) + case paddingRightKey: + s.paddingRight = max(0, value.(int)) + case paddingBottomKey: + s.paddingBottom = max(0, value.(int)) + case paddingLeftKey: + s.paddingLeft = max(0, value.(int)) + case marginTopKey: + s.marginTop = max(0, value.(int)) + case marginRightKey: + s.marginRight = max(0, value.(int)) + case marginBottomKey: + s.marginBottom = max(0, value.(int)) + case marginLeftKey: + s.marginLeft = max(0, value.(int)) + case marginBackgroundKey: + s.marginBgColor = colorOrNil(value) + case borderStyleKey: + s.borderStyle = value.(Border) + case borderTopForegroundKey: + s.borderTopFgColor = colorOrNil(value) + case borderRightForegroundKey: + s.borderRightFgColor = colorOrNil(value) + case borderBottomForegroundKey: + s.borderBottomFgColor = colorOrNil(value) + case borderLeftForegroundKey: + s.borderLeftFgColor = colorOrNil(value) + case borderTopBackgroundKey: + s.borderTopBgColor = colorOrNil(value) + case borderRightBackgroundKey: + s.borderRightBgColor = colorOrNil(value) + case borderBottomBackgroundKey: + s.borderBottomBgColor = colorOrNil(value) + case borderLeftBackgroundKey: + s.borderLeftBgColor = colorOrNil(value) + case maxWidthKey: + s.maxWidth = max(0, value.(int)) + case maxHeightKey: + s.maxHeight = max(0, value.(int)) + case tabWidthKey: + // TabWidth is the only property that may have a negative value (and + // that negative value can be no less than -1). + s.tabWidth = value.(int) + case transformKey: + s.transform = value.(func(string) string) + default: + if v, ok := value.(bool); ok { //nolint:nestif + if v { + s.attrs |= int(key) + } else { + s.attrs &^= int(key) + } + } else if attrs, ok := value.(int); ok { + // bool attrs + if attrs&int(key) != 0 { + s.attrs |= int(key) + } else { + s.attrs &^= int(key) + } + } + } + + // Set the prop on + s.props = s.props.set(key) +} + +// setFrom sets the property from another style. +func (s *Style) setFrom(key propKey, i Style) { + switch key { //nolint:exhaustive + case foregroundKey: + s.set(foregroundKey, i.fgColor) + case backgroundKey: + s.set(backgroundKey, i.bgColor) + case widthKey: + s.set(widthKey, i.width) + case heightKey: + s.set(heightKey, i.height) + case alignHorizontalKey: + s.set(alignHorizontalKey, i.alignHorizontal) + case alignVerticalKey: + s.set(alignVerticalKey, i.alignVertical) + case paddingTopKey: + s.set(paddingTopKey, i.paddingTop) + case paddingRightKey: + s.set(paddingRightKey, i.paddingRight) + case paddingBottomKey: + s.set(paddingBottomKey, i.paddingBottom) + case paddingLeftKey: + s.set(paddingLeftKey, i.paddingLeft) + case marginTopKey: + s.set(marginTopKey, i.marginTop) + case marginRightKey: + s.set(marginRightKey, i.marginRight) + case marginBottomKey: + s.set(marginBottomKey, i.marginBottom) + case marginLeftKey: + s.set(marginLeftKey, i.marginLeft) + case marginBackgroundKey: + s.set(marginBackgroundKey, i.marginBgColor) + case borderStyleKey: + s.set(borderStyleKey, i.borderStyle) + case borderTopForegroundKey: + s.set(borderTopForegroundKey, i.borderTopFgColor) + case borderRightForegroundKey: + s.set(borderRightForegroundKey, i.borderRightFgColor) + case borderBottomForegroundKey: + s.set(borderBottomForegroundKey, i.borderBottomFgColor) + case borderLeftForegroundKey: + s.set(borderLeftForegroundKey, i.borderLeftFgColor) + case borderTopBackgroundKey: + s.set(borderTopBackgroundKey, i.borderTopBgColor) + case borderRightBackgroundKey: + s.set(borderRightBackgroundKey, i.borderRightBgColor) + case borderBottomBackgroundKey: + s.set(borderBottomBackgroundKey, i.borderBottomBgColor) + case borderLeftBackgroundKey: + s.set(borderLeftBackgroundKey, i.borderLeftBgColor) + case maxWidthKey: + s.set(maxWidthKey, i.maxWidth) + case maxHeightKey: + s.set(maxHeightKey, i.maxHeight) + case tabWidthKey: + s.set(tabWidthKey, i.tabWidth) + case transformKey: + s.set(transformKey, i.transform) + default: + // Set attributes for set bool properties + s.set(key, i.attrs) + } +} + +func colorOrNil(c interface{}) TerminalColor { + if c, ok := c.(TerminalColor); ok { + return c + } + return nil +} + +// Bold sets a bold formatting rule. +func (s Style) Bold(v bool) Style { + s.set(boldKey, v) + return s +} + +// Italic sets an italic formatting rule. In some terminal emulators this will +// render with "reverse" coloring if not italic font variant is available. +func (s Style) Italic(v bool) Style { + s.set(italicKey, v) + return s +} + +// Underline sets an underline rule. By default, underlines will not be drawn on +// whitespace like margins and padding. To change this behavior set +// UnderlineSpaces. +func (s Style) Underline(v bool) Style { + s.set(underlineKey, v) + return s +} + +// Strikethrough sets a strikethrough rule. By default, strikes will not be +// drawn on whitespace like margins and padding. To change this behavior set +// StrikethroughSpaces. +func (s Style) Strikethrough(v bool) Style { + s.set(strikethroughKey, v) + return s +} + +// Reverse sets a rule for inverting foreground and background colors. +func (s Style) Reverse(v bool) Style { + s.set(reverseKey, v) + return s +} + +// Blink sets a rule for blinking foreground text. +func (s Style) Blink(v bool) Style { + s.set(blinkKey, v) + return s +} + +// Faint sets a rule for rendering the foreground color in a dimmer shade. +func (s Style) Faint(v bool) Style { + s.set(faintKey, v) + return s +} + +// Foreground sets a foreground color. +// +// // Sets the foreground to blue +// s := lipgloss.NewStyle().Foreground(lipgloss.Color("#0000ff")) +// +// // Removes the foreground color +// s.Foreground(lipgloss.NoColor) +func (s Style) Foreground(c TerminalColor) Style { + s.set(foregroundKey, c) + return s +} + +// Background sets a background color. +func (s Style) Background(c TerminalColor) Style { + s.set(backgroundKey, c) + return s +} + +// Width sets the width of the block before applying margins. The width, if +// set, also determines where text will wrap. +func (s Style) Width(i int) Style { + s.set(widthKey, i) + return s +} + +// Height sets the height of the block before applying margins. If the height of +// the text block is less than this value after applying padding (or not), the +// block will be set to this height. +func (s Style) Height(i int) Style { + s.set(heightKey, i) + return s +} + +// Align is a shorthand method for setting horizontal and vertical alignment. +// +// With one argument, the position value is applied to the horizontal alignment. +// +// With two arguments, the value is applied to the horizontal and vertical +// alignments, in that order. +func (s Style) Align(p ...Position) Style { + if len(p) > 0 { + s.set(alignHorizontalKey, p[0]) + } + if len(p) > 1 { + s.set(alignVerticalKey, p[1]) + } + return s +} + +// AlignHorizontal sets a horizontal text alignment rule. +func (s Style) AlignHorizontal(p Position) Style { + s.set(alignHorizontalKey, p) + return s +} + +// AlignVertical sets a vertical text alignment rule. +func (s Style) AlignVertical(p Position) Style { + s.set(alignVerticalKey, p) + return s +} + +// Padding is a shorthand method for setting padding on all sides at once. +// +// With one argument, the value is applied to all sides. +// +// With two arguments, the value is applied to the vertical and horizontal +// sides, in that order. +// +// With three arguments, the value is applied to the top side, the horizontal +// sides, and the bottom side, in that order. +// +// With four arguments, the value is applied clockwise starting from the top +// side, followed by the right side, then the bottom, and finally the left. +// +// With more than four arguments no padding will be added. +func (s Style) Padding(i ...int) Style { + top, right, bottom, left, ok := whichSidesInt(i...) + if !ok { + return s + } + + s.set(paddingTopKey, top) + s.set(paddingRightKey, right) + s.set(paddingBottomKey, bottom) + s.set(paddingLeftKey, left) + return s +} + +// PaddingLeft adds padding on the left. +func (s Style) PaddingLeft(i int) Style { + s.set(paddingLeftKey, i) + return s +} + +// PaddingRight adds padding on the right. +func (s Style) PaddingRight(i int) Style { + s.set(paddingRightKey, i) + return s +} + +// PaddingTop adds padding to the top of the block. +func (s Style) PaddingTop(i int) Style { + s.set(paddingTopKey, i) + return s +} + +// PaddingBottom adds padding to the bottom of the block. +func (s Style) PaddingBottom(i int) Style { + s.set(paddingBottomKey, i) + return s +} + +// ColorWhitespace determines whether or not the background color should be +// applied to the padding. This is true by default as it's more than likely the +// desired and expected behavior, but it can be disabled for certain graphic +// effects. +// +// Deprecated: Just use margins and padding. +func (s Style) ColorWhitespace(v bool) Style { + s.set(colorWhitespaceKey, v) + return s +} + +// Margin is a shorthand method for setting margins on all sides at once. +// +// With one argument, the value is applied to all sides. +// +// With two arguments, the value is applied to the vertical and horizontal +// sides, in that order. +// +// With three arguments, the value is applied to the top side, the horizontal +// sides, and the bottom side, in that order. +// +// With four arguments, the value is applied clockwise starting from the top +// side, followed by the right side, then the bottom, and finally the left. +// +// With more than four arguments no margin will be added. +func (s Style) Margin(i ...int) Style { + top, right, bottom, left, ok := whichSidesInt(i...) + if !ok { + return s + } + + s.set(marginTopKey, top) + s.set(marginRightKey, right) + s.set(marginBottomKey, bottom) + s.set(marginLeftKey, left) + return s +} + +// MarginLeft sets the value of the left margin. +func (s Style) MarginLeft(i int) Style { + s.set(marginLeftKey, i) + return s +} + +// MarginRight sets the value of the right margin. +func (s Style) MarginRight(i int) Style { + s.set(marginRightKey, i) + return s +} + +// MarginTop sets the value of the top margin. +func (s Style) MarginTop(i int) Style { + s.set(marginTopKey, i) + return s +} + +// MarginBottom sets the value of the bottom margin. +func (s Style) MarginBottom(i int) Style { + s.set(marginBottomKey, i) + return s +} + +// MarginBackground sets the background color of the margin. Note that this is +// also set when inheriting from a style with a background color. In that case +// the background color on that style will set the margin color on this style. +func (s Style) MarginBackground(c TerminalColor) Style { + s.set(marginBackgroundKey, c) + return s +} + +// Border is shorthand for setting the border style and which sides should +// have a border at once. The variadic argument sides works as follows: +// +// With one value, the value is applied to all sides. +// +// With two values, the values are applied to the vertical and horizontal +// sides, in that order. +// +// With three values, the values are applied to the top side, the horizontal +// sides, and the bottom side, in that order. +// +// With four values, the values are applied clockwise starting from the top +// side, followed by the right side, then the bottom, and finally the left. +// +// With more than four arguments the border will be applied to all sides. +// +// Examples: +// +// // Applies borders to the top and bottom only +// lipgloss.NewStyle().Border(lipgloss.NormalBorder(), true, false) +// +// // Applies rounded borders to the right and bottom only +// lipgloss.NewStyle().Border(lipgloss.RoundedBorder(), false, true, true, false) +func (s Style) Border(b Border, sides ...bool) Style { + s.set(borderStyleKey, b) + + top, right, bottom, left, ok := whichSidesBool(sides...) + if !ok { + top = true + right = true + bottom = true + left = true + } + + s.set(borderTopKey, top) + s.set(borderRightKey, right) + s.set(borderBottomKey, bottom) + s.set(borderLeftKey, left) + + return s +} + +// BorderStyle defines the Border on a style. A Border contains a series of +// definitions for the sides and corners of a border. +// +// Note that if border visibility has not been set for any sides when setting +// the border style, the border will be enabled for all sides during rendering. +// +// You can define border characters as you'd like, though several default +// styles are included: NormalBorder(), RoundedBorder(), BlockBorder(), +// OuterHalfBlockBorder(), InnerHalfBlockBorder(), ThickBorder(), +// and DoubleBorder(). +// +// Example: +// +// lipgloss.NewStyle().BorderStyle(lipgloss.ThickBorder()) +func (s Style) BorderStyle(b Border) Style { + s.set(borderStyleKey, b) + return s +} + +// BorderTop determines whether or not to draw a top border. +func (s Style) BorderTop(v bool) Style { + s.set(borderTopKey, v) + return s +} + +// BorderRight determines whether or not to draw a right border. +func (s Style) BorderRight(v bool) Style { + s.set(borderRightKey, v) + return s +} + +// BorderBottom determines whether or not to draw a bottom border. +func (s Style) BorderBottom(v bool) Style { + s.set(borderBottomKey, v) + return s +} + +// BorderLeft determines whether or not to draw a left border. +func (s Style) BorderLeft(v bool) Style { + s.set(borderLeftKey, v) + return s +} + +// BorderForeground is a shorthand function for setting all of the +// foreground colors of the borders at once. The arguments work as follows: +// +// With one argument, the argument is applied to all sides. +// +// With two arguments, the arguments are applied to the vertical and horizontal +// sides, in that order. +// +// With three arguments, the arguments are applied to the top side, the +// horizontal sides, and the bottom side, in that order. +// +// With four arguments, the arguments are applied clockwise starting from the +// top side, followed by the right side, then the bottom, and finally the left. +// +// With more than four arguments nothing will be set. +func (s Style) BorderForeground(c ...TerminalColor) Style { + if len(c) == 0 { + return s + } + + top, right, bottom, left, ok := whichSidesColor(c...) + if !ok { + return s + } + + s.set(borderTopForegroundKey, top) + s.set(borderRightForegroundKey, right) + s.set(borderBottomForegroundKey, bottom) + s.set(borderLeftForegroundKey, left) + + return s +} + +// BorderTopForeground set the foreground color for the top of the border. +func (s Style) BorderTopForeground(c TerminalColor) Style { + s.set(borderTopForegroundKey, c) + return s +} + +// BorderRightForeground sets the foreground color for the right side of the +// border. +func (s Style) BorderRightForeground(c TerminalColor) Style { + s.set(borderRightForegroundKey, c) + return s +} + +// BorderBottomForeground sets the foreground color for the bottom of the +// border. +func (s Style) BorderBottomForeground(c TerminalColor) Style { + s.set(borderBottomForegroundKey, c) + return s +} + +// BorderLeftForeground sets the foreground color for the left side of the +// border. +func (s Style) BorderLeftForeground(c TerminalColor) Style { + s.set(borderLeftForegroundKey, c) + return s +} + +// BorderBackground is a shorthand function for setting all of the +// background colors of the borders at once. The arguments work as follows: +// +// With one argument, the argument is applied to all sides. +// +// With two arguments, the arguments are applied to the vertical and horizontal +// sides, in that order. +// +// With three arguments, the arguments are applied to the top side, the +// horizontal sides, and the bottom side, in that order. +// +// With four arguments, the arguments are applied clockwise starting from the +// top side, followed by the right side, then the bottom, and finally the left. +// +// With more than four arguments nothing will be set. +func (s Style) BorderBackground(c ...TerminalColor) Style { + if len(c) == 0 { + return s + } + + top, right, bottom, left, ok := whichSidesColor(c...) + if !ok { + return s + } + + s.set(borderTopBackgroundKey, top) + s.set(borderRightBackgroundKey, right) + s.set(borderBottomBackgroundKey, bottom) + s.set(borderLeftBackgroundKey, left) + + return s +} + +// BorderTopBackground sets the background color of the top of the border. +func (s Style) BorderTopBackground(c TerminalColor) Style { + s.set(borderTopBackgroundKey, c) + return s +} + +// BorderRightBackground sets the background color of right side the border. +func (s Style) BorderRightBackground(c TerminalColor) Style { + s.set(borderRightBackgroundKey, c) + return s +} + +// BorderBottomBackground sets the background color of the bottom of the +// border. +func (s Style) BorderBottomBackground(c TerminalColor) Style { + s.set(borderBottomBackgroundKey, c) + return s +} + +// BorderLeftBackground set the background color of the left side of the +// border. +func (s Style) BorderLeftBackground(c TerminalColor) Style { + s.set(borderLeftBackgroundKey, c) + return s +} + +// Inline makes rendering output one line and disables the rendering of +// margins, padding and borders. This is useful when you need a style to apply +// only to font rendering and don't want it to change any physical dimensions. +// It works well with Style.MaxWidth. +// +// Because this in intended to be used at the time of render, this method will +// not mutate the style and instead return a copy. +// +// Example: +// +// var userInput string = "..." +// var userStyle = text.Style{ /* ... */ } +// fmt.Println(userStyle.Inline(true).Render(userInput)) +func (s Style) Inline(v bool) Style { + o := s // copy + o.set(inlineKey, v) + return o +} + +// MaxWidth applies a max width to a given style. This is useful in enforcing +// a certain width at render time, particularly with arbitrary strings and +// styles. +// +// Because this in intended to be used at the time of render, this method will +// not mutate the style and instead return a copy. +// +// Example: +// +// var userInput string = "..." +// var userStyle = text.Style{ /* ... */ } +// fmt.Println(userStyle.MaxWidth(16).Render(userInput)) +func (s Style) MaxWidth(n int) Style { + o := s // copy + o.set(maxWidthKey, n) + return o +} + +// MaxHeight applies a max height to a given style. This is useful in enforcing +// a certain height at render time, particularly with arbitrary strings and +// styles. +// +// Because this in intended to be used at the time of render, this method will +// not mutate the style and instead returns a copy. +func (s Style) MaxHeight(n int) Style { + o := s // copy + o.set(maxHeightKey, n) + return o +} + +// NoTabConversion can be passed to [Style.TabWidth] to disable the replacement +// of tabs with spaces at render time. +const NoTabConversion = -1 + +// TabWidth sets the number of spaces that a tab (/t) should be rendered as. +// When set to 0, tabs will be removed. To disable the replacement of tabs with +// spaces entirely, set this to [NoTabConversion]. +// +// By default, tabs will be replaced with 4 spaces. +func (s Style) TabWidth(n int) Style { + if n <= -1 { + n = -1 + } + s.set(tabWidthKey, n) + return s +} + +// UnderlineSpaces determines whether to underline spaces between words. By +// default, this is true. Spaces can also be underlined without underlining the +// text itself. +func (s Style) UnderlineSpaces(v bool) Style { + s.set(underlineSpacesKey, v) + return s +} + +// StrikethroughSpaces determines whether to apply strikethroughs to spaces +// between words. By default, this is true. Spaces can also be struck without +// underlining the text itself. +func (s Style) StrikethroughSpaces(v bool) Style { + s.set(strikethroughSpacesKey, v) + return s +} + +// Transform applies a given function to a string at render time, allowing for +// the string being rendered to be manipuated. +// +// Example: +// +// s := NewStyle().Transform(strings.ToUpper) +// fmt.Println(s.Render("raow!") // "RAOW!" +func (s Style) Transform(fn func(string) string) Style { + s.set(transformKey, fn) + return s +} + +// Renderer sets the renderer for the style. This is useful for changing the +// renderer for a style that is being used in a different context. +func (s Style) Renderer(r *Renderer) Style { + s.r = r + return s +} + +// whichSidesInt is a helper method for setting values on sides of a block based +// on the number of arguments. It follows the CSS shorthand rules for blocks +// like margin, padding. and borders. Here are how the rules work: +// +// 0 args: do nothing +// 1 arg: all sides +// 2 args: top -> bottom +// 3 args: top -> horizontal -> bottom +// 4 args: top -> right -> bottom -> left +// 5+ args: do nothing. +func whichSidesInt(i ...int) (top, right, bottom, left int, ok bool) { + switch len(i) { + case 1: + top = i[0] + bottom = i[0] + left = i[0] + right = i[0] + ok = true + case 2: //nolint:mnd + top = i[0] + bottom = i[0] + left = i[1] + right = i[1] + ok = true + case 3: //nolint:mnd + top = i[0] + left = i[1] + right = i[1] + bottom = i[2] + ok = true + case 4: //nolint:mnd + top = i[0] + right = i[1] + bottom = i[2] + left = i[3] + ok = true + } + return top, right, bottom, left, ok +} + +// whichSidesBool is like whichSidesInt, except it operates on a series of +// boolean values. See the comment on whichSidesInt for details on how this +// works. +func whichSidesBool(i ...bool) (top, right, bottom, left bool, ok bool) { + switch len(i) { + case 1: + top = i[0] + bottom = i[0] + left = i[0] + right = i[0] + ok = true + case 2: //nolint:mnd + top = i[0] + bottom = i[0] + left = i[1] + right = i[1] + ok = true + case 3: //nolint:mnd + top = i[0] + left = i[1] + right = i[1] + bottom = i[2] + ok = true + case 4: //nolint:mnd + top = i[0] + right = i[1] + bottom = i[2] + left = i[3] + ok = true + } + return top, right, bottom, left, ok +} + +// whichSidesColor is like whichSides, except it operates on a series of +// boolean values. See the comment on whichSidesInt for details on how this +// works. +func whichSidesColor(i ...TerminalColor) (top, right, bottom, left TerminalColor, ok bool) { + switch len(i) { + case 1: + top = i[0] + bottom = i[0] + left = i[0] + right = i[0] + ok = true + case 2: //nolint:mnd + top = i[0] + bottom = i[0] + left = i[1] + right = i[1] + ok = true + case 3: //nolint:mnd + top = i[0] + left = i[1] + right = i[1] + bottom = i[2] + ok = true + case 4: //nolint:mnd + top = i[0] + right = i[1] + bottom = i[2] + left = i[3] + ok = true + } + return top, right, bottom, left, ok +} diff --git a/vendor/github.com/charmbracelet/lipgloss/size.go b/vendor/github.com/charmbracelet/lipgloss/size.go new file mode 100644 index 000000000..e169ff5e2 --- /dev/null +++ b/vendor/github.com/charmbracelet/lipgloss/size.go @@ -0,0 +1,41 @@ +package lipgloss + +import ( + "strings" + + "github.com/charmbracelet/x/ansi" +) + +// Width returns the cell width of characters in the string. ANSI sequences are +// ignored and characters wider than one cell (such as Chinese characters and +// emojis) are appropriately measured. +// +// You should use this instead of len(string) len([]rune(string) as neither +// will give you accurate results. +func Width(str string) (width int) { + for _, l := range strings.Split(str, "\n") { + w := ansi.StringWidth(l) + if w > width { + width = w + } + } + + return width +} + +// Height returns height of a string in cells. This is done simply by +// counting \n characters. If your strings use \r\n for newlines you should +// convert them to \n first, or simply write a separate function for measuring +// height. +func Height(str string) int { + return strings.Count(str, "\n") + 1 +} + +// Size returns the width and height of the string in cells. ANSI sequences are +// ignored and characters wider than one cell (such as Chinese characters and +// emojis) are appropriately measured. +func Size(str string) (width, height int) { + width = Width(str) + height = Height(str) + return width, height +} diff --git a/vendor/github.com/charmbracelet/lipgloss/style.go b/vendor/github.com/charmbracelet/lipgloss/style.go new file mode 100644 index 000000000..59fa3ab21 --- /dev/null +++ b/vendor/github.com/charmbracelet/lipgloss/style.go @@ -0,0 +1,588 @@ +package lipgloss + +import ( + "strings" + "unicode" + + "github.com/charmbracelet/x/ansi" + "github.com/charmbracelet/x/cellbuf" + "github.com/muesli/termenv" +) + +const tabWidthDefault = 4 + +// Property for a key. +type propKey int64 + +// Available properties. +const ( + // Boolean props come first. + boldKey propKey = 1 << iota + italicKey + underlineKey + strikethroughKey + reverseKey + blinkKey + faintKey + underlineSpacesKey + strikethroughSpacesKey + colorWhitespaceKey + + // Non-boolean props. + foregroundKey + backgroundKey + widthKey + heightKey + alignHorizontalKey + alignVerticalKey + + // Padding. + paddingTopKey + paddingRightKey + paddingBottomKey + paddingLeftKey + + // Margins. + marginTopKey + marginRightKey + marginBottomKey + marginLeftKey + marginBackgroundKey + + // Border runes. + borderStyleKey + + // Border edges. + borderTopKey + borderRightKey + borderBottomKey + borderLeftKey + + // Border foreground colors. + borderTopForegroundKey + borderRightForegroundKey + borderBottomForegroundKey + borderLeftForegroundKey + + // Border background colors. + borderTopBackgroundKey + borderRightBackgroundKey + borderBottomBackgroundKey + borderLeftBackgroundKey + + inlineKey + maxWidthKey + maxHeightKey + tabWidthKey + + transformKey +) + +// props is a set of properties. +type props int64 + +// set sets a property. +func (p props) set(k propKey) props { + return p | props(k) +} + +// unset unsets a property. +func (p props) unset(k propKey) props { + return p &^ props(k) +} + +// has checks if a property is set. +func (p props) has(k propKey) bool { + return p&props(k) != 0 +} + +// NewStyle returns a new, empty Style. While it's syntactic sugar for the +// Style{} primitive, it's recommended to use this function for creating styles +// in case the underlying implementation changes. It takes an optional string +// value to be set as the underlying string value for this style. +func NewStyle() Style { + return renderer.NewStyle() +} + +// NewStyle returns a new, empty Style. While it's syntactic sugar for the +// Style{} primitive, it's recommended to use this function for creating styles +// in case the underlying implementation changes. It takes an optional string +// value to be set as the underlying string value for this style. +func (r *Renderer) NewStyle() Style { + s := Style{r: r} + return s +} + +// Style contains a set of rules that comprise a style as a whole. +type Style struct { + r *Renderer + props props + value string + + // we store bool props values here + attrs int + + // props that have values + fgColor TerminalColor + bgColor TerminalColor + + width int + height int + + alignHorizontal Position + alignVertical Position + + paddingTop int + paddingRight int + paddingBottom int + paddingLeft int + + marginTop int + marginRight int + marginBottom int + marginLeft int + marginBgColor TerminalColor + + borderStyle Border + borderTopFgColor TerminalColor + borderRightFgColor TerminalColor + borderBottomFgColor TerminalColor + borderLeftFgColor TerminalColor + borderTopBgColor TerminalColor + borderRightBgColor TerminalColor + borderBottomBgColor TerminalColor + borderLeftBgColor TerminalColor + + maxWidth int + maxHeight int + tabWidth int + + transform func(string) string +} + +// joinString joins a list of strings into a single string separated with a +// space. +func joinString(strs ...string) string { + return strings.Join(strs, " ") +} + +// SetString sets the underlying string value for this style. To render once +// the underlying string is set, use the Style.String. This method is +// a convenience for cases when having a stringer implementation is handy, such +// as when using fmt.Sprintf. You can also simply define a style and render out +// strings directly with Style.Render. +func (s Style) SetString(strs ...string) Style { + s.value = joinString(strs...) + return s +} + +// Value returns the raw, unformatted, underlying string value for this style. +func (s Style) Value() string { + return s.value +} + +// String implements stringer for a Style, returning the rendered result based +// on the rules in this style. An underlying string value must be set with +// Style.SetString prior to using this method. +func (s Style) String() string { + return s.Render() +} + +// Copy returns a copy of this style, including any underlying string values. +// +// Deprecated: to copy just use assignment (i.e. a := b). All methods also +// return a new style. +func (s Style) Copy() Style { + return s +} + +// Inherit overlays the style in the argument onto this style by copying each explicitly +// set value from the argument style onto this style if it is not already explicitly set. +// Existing set values are kept intact and not overwritten. +// +// Margins, padding, and underlying string values are not inherited. +func (s Style) Inherit(i Style) Style { + for k := boldKey; k <= transformKey; k <<= 1 { + if !i.isSet(k) { + continue + } + + switch k { //nolint:exhaustive + case marginTopKey, marginRightKey, marginBottomKey, marginLeftKey: + // Margins are not inherited + continue + case paddingTopKey, paddingRightKey, paddingBottomKey, paddingLeftKey: + // Padding is not inherited + continue + case backgroundKey: + // The margins also inherit the background color + if !s.isSet(marginBackgroundKey) && !i.isSet(marginBackgroundKey) { + s.set(marginBackgroundKey, i.bgColor) + } + } + + if s.isSet(k) { + continue + } + + s.setFrom(k, i) + } + return s +} + +// Render applies the defined style formatting to a given string. +func (s Style) Render(strs ...string) string { + if s.r == nil { + s.r = renderer + } + if s.value != "" { + strs = append([]string{s.value}, strs...) + } + + var ( + str = joinString(strs...) + + p = s.r.ColorProfile() + te = p.String() + teSpace = p.String() + teWhitespace = p.String() + + bold = s.getAsBool(boldKey, false) + italic = s.getAsBool(italicKey, false) + underline = s.getAsBool(underlineKey, false) + strikethrough = s.getAsBool(strikethroughKey, false) + reverse = s.getAsBool(reverseKey, false) + blink = s.getAsBool(blinkKey, false) + faint = s.getAsBool(faintKey, false) + + fg = s.getAsColor(foregroundKey) + bg = s.getAsColor(backgroundKey) + + width = s.getAsInt(widthKey) + height = s.getAsInt(heightKey) + horizontalAlign = s.getAsPosition(alignHorizontalKey) + verticalAlign = s.getAsPosition(alignVerticalKey) + + topPadding = s.getAsInt(paddingTopKey) + rightPadding = s.getAsInt(paddingRightKey) + bottomPadding = s.getAsInt(paddingBottomKey) + leftPadding = s.getAsInt(paddingLeftKey) + + colorWhitespace = s.getAsBool(colorWhitespaceKey, true) + inline = s.getAsBool(inlineKey, false) + maxWidth = s.getAsInt(maxWidthKey) + maxHeight = s.getAsInt(maxHeightKey) + + underlineSpaces = s.getAsBool(underlineSpacesKey, false) || (underline && s.getAsBool(underlineSpacesKey, true)) + strikethroughSpaces = s.getAsBool(strikethroughSpacesKey, false) || (strikethrough && s.getAsBool(strikethroughSpacesKey, true)) + + // Do we need to style whitespace (padding and space outside + // paragraphs) separately? + styleWhitespace = reverse + + // Do we need to style spaces separately? + useSpaceStyler = (underline && !underlineSpaces) || (strikethrough && !strikethroughSpaces) || underlineSpaces || strikethroughSpaces + + transform = s.getAsTransform(transformKey) + ) + + if transform != nil { + str = transform(str) + } + + if s.props == 0 { + return s.maybeConvertTabs(str) + } + + // Enable support for ANSI on the legacy Windows cmd.exe console. This is a + // no-op on non-Windows systems and on Windows runs only once. + enableLegacyWindowsANSI() + + if bold { + te = te.Bold() + } + if italic { + te = te.Italic() + } + if underline { + te = te.Underline() + } + if reverse { + teWhitespace = teWhitespace.Reverse() + te = te.Reverse() + } + if blink { + te = te.Blink() + } + if faint { + te = te.Faint() + } + + if fg != noColor { + te = te.Foreground(fg.color(s.r)) + if styleWhitespace { + teWhitespace = teWhitespace.Foreground(fg.color(s.r)) + } + if useSpaceStyler { + teSpace = teSpace.Foreground(fg.color(s.r)) + } + } + + if bg != noColor { + te = te.Background(bg.color(s.r)) + if colorWhitespace { + teWhitespace = teWhitespace.Background(bg.color(s.r)) + } + if useSpaceStyler { + teSpace = teSpace.Background(bg.color(s.r)) + } + } + + if underline { + te = te.Underline() + } + if strikethrough { + te = te.CrossOut() + } + + if underlineSpaces { + teSpace = teSpace.Underline() + } + if strikethroughSpaces { + teSpace = teSpace.CrossOut() + } + + // Potentially convert tabs to spaces + str = s.maybeConvertTabs(str) + // carriage returns can cause strange behaviour when rendering. + str = strings.ReplaceAll(str, "\r\n", "\n") + + // Strip newlines in single line mode + if inline { + str = strings.ReplaceAll(str, "\n", "") + } + + // Word wrap + if !inline && width > 0 { + wrapAt := width - leftPadding - rightPadding + str = cellbuf.Wrap(str, wrapAt, "") + } + + // Render core text + { + var b strings.Builder + + l := strings.Split(str, "\n") + for i := range l { + if useSpaceStyler { + // Look for spaces and apply a different styler + for _, r := range l[i] { + if unicode.IsSpace(r) { + b.WriteString(teSpace.Styled(string(r))) + continue + } + b.WriteString(te.Styled(string(r))) + } + } else { + b.WriteString(te.Styled(l[i])) + } + if i != len(l)-1 { + b.WriteRune('\n') + } + } + + str = b.String() + } + + // Padding + if !inline { //nolint:nestif + if leftPadding > 0 { + var st *termenv.Style + if colorWhitespace || styleWhitespace { + st = &teWhitespace + } + str = padLeft(str, leftPadding, st) + } + + if rightPadding > 0 { + var st *termenv.Style + if colorWhitespace || styleWhitespace { + st = &teWhitespace + } + str = padRight(str, rightPadding, st) + } + + if topPadding > 0 { + str = strings.Repeat("\n", topPadding) + str + } + + if bottomPadding > 0 { + str += strings.Repeat("\n", bottomPadding) + } + } + + // Height + if height > 0 { + str = alignTextVertical(str, verticalAlign, height, nil) + } + + // Set alignment. This will also pad short lines with spaces so that all + // lines are the same length, so we run it under a few different conditions + // beyond alignment. + { + numLines := strings.Count(str, "\n") + + if numLines != 0 || width != 0 { + var st *termenv.Style + if colorWhitespace || styleWhitespace { + st = &teWhitespace + } + str = alignTextHorizontal(str, horizontalAlign, width, st) + } + } + + if !inline { + str = s.applyBorder(str) + str = s.applyMargins(str, inline) + } + + // Truncate according to MaxWidth + if maxWidth > 0 { + lines := strings.Split(str, "\n") + + for i := range lines { + lines[i] = ansi.Truncate(lines[i], maxWidth, "") + } + + str = strings.Join(lines, "\n") + } + + // Truncate according to MaxHeight + if maxHeight > 0 { + lines := strings.Split(str, "\n") + height := min(maxHeight, len(lines)) + if len(lines) > 0 { + str = strings.Join(lines[:height], "\n") + } + } + + return str +} + +func (s Style) maybeConvertTabs(str string) string { + tw := tabWidthDefault + if s.isSet(tabWidthKey) { + tw = s.getAsInt(tabWidthKey) + } + switch tw { + case -1: + return str + case 0: + return strings.ReplaceAll(str, "\t", "") + default: + return strings.ReplaceAll(str, "\t", strings.Repeat(" ", tw)) + } +} + +func (s Style) applyMargins(str string, inline bool) string { + var ( + topMargin = s.getAsInt(marginTopKey) + rightMargin = s.getAsInt(marginRightKey) + bottomMargin = s.getAsInt(marginBottomKey) + leftMargin = s.getAsInt(marginLeftKey) + + styler termenv.Style + ) + + bgc := s.getAsColor(marginBackgroundKey) + if bgc != noColor { + styler = styler.Background(bgc.color(s.r)) + } + + // Add left and right margin + str = padLeft(str, leftMargin, &styler) + str = padRight(str, rightMargin, &styler) + + // Top/bottom margin + if !inline { + _, width := getLines(str) + spaces := strings.Repeat(" ", width) + + if topMargin > 0 { + str = styler.Styled(strings.Repeat(spaces+"\n", topMargin)) + str + } + if bottomMargin > 0 { + str += styler.Styled(strings.Repeat("\n"+spaces, bottomMargin)) + } + } + + return str +} + +// Apply left padding. +func padLeft(str string, n int, style *termenv.Style) string { + return pad(str, -n, style) +} + +// Apply right padding. +func padRight(str string, n int, style *termenv.Style) string { + return pad(str, n, style) +} + +// pad adds padding to either the left or right side of a string. +// Positive values add to the right side while negative values +// add to the left side. +func pad(str string, n int, style *termenv.Style) string { + if n == 0 { + return str + } + + sp := strings.Repeat(" ", abs(n)) + if style != nil { + sp = style.Styled(sp) + } + + b := strings.Builder{} + l := strings.Split(str, "\n") + + for i := range l { + switch { + // pad right + case n > 0: + b.WriteString(l[i]) + b.WriteString(sp) + // pad left + default: + b.WriteString(sp) + b.WriteString(l[i]) + } + + if i != len(l)-1 { + b.WriteRune('\n') + } + } + + return b.String() +} + +func max(a, b int) int { //nolint:unparam,predeclared + if a > b { + return a + } + return b +} + +func min(a, b int) int { //nolint:predeclared + if a < b { + return a + } + return b +} + +func abs(a int) int { + if a < 0 { + return -a + } + + return a +} diff --git a/vendor/github.com/charmbracelet/lipgloss/unset.go b/vendor/github.com/charmbracelet/lipgloss/unset.go new file mode 100644 index 000000000..1086e7226 --- /dev/null +++ b/vendor/github.com/charmbracelet/lipgloss/unset.go @@ -0,0 +1,331 @@ +package lipgloss + +// unset unsets a property from a style. +func (s *Style) unset(key propKey) { + s.props = s.props.unset(key) +} + +// UnsetBold removes the bold style rule, if set. +func (s Style) UnsetBold() Style { + s.unset(boldKey) + return s +} + +// UnsetItalic removes the italic style rule, if set. +func (s Style) UnsetItalic() Style { + s.unset(italicKey) + return s +} + +// UnsetUnderline removes the underline style rule, if set. +func (s Style) UnsetUnderline() Style { + s.unset(underlineKey) + return s +} + +// UnsetStrikethrough removes the strikethrough style rule, if set. +func (s Style) UnsetStrikethrough() Style { + s.unset(strikethroughKey) + return s +} + +// UnsetReverse removes the reverse style rule, if set. +func (s Style) UnsetReverse() Style { + s.unset(reverseKey) + return s +} + +// UnsetBlink removes the blink style rule, if set. +func (s Style) UnsetBlink() Style { + s.unset(blinkKey) + return s +} + +// UnsetFaint removes the faint style rule, if set. +func (s Style) UnsetFaint() Style { + s.unset(faintKey) + return s +} + +// UnsetForeground removes the foreground style rule, if set. +func (s Style) UnsetForeground() Style { + s.unset(foregroundKey) + return s +} + +// UnsetBackground removes the background style rule, if set. +func (s Style) UnsetBackground() Style { + s.unset(backgroundKey) + return s +} + +// UnsetWidth removes the width style rule, if set. +func (s Style) UnsetWidth() Style { + s.unset(widthKey) + return s +} + +// UnsetHeight removes the height style rule, if set. +func (s Style) UnsetHeight() Style { + s.unset(heightKey) + return s +} + +// UnsetAlign removes the horizontal and vertical text alignment style rule, if set. +func (s Style) UnsetAlign() Style { + s.unset(alignHorizontalKey) + s.unset(alignVerticalKey) + return s +} + +// UnsetAlignHorizontal removes the horizontal text alignment style rule, if set. +func (s Style) UnsetAlignHorizontal() Style { + s.unset(alignHorizontalKey) + return s +} + +// UnsetAlignVertical removes the vertical text alignment style rule, if set. +func (s Style) UnsetAlignVertical() Style { + s.unset(alignVerticalKey) + return s +} + +// UnsetPadding removes all padding style rules. +func (s Style) UnsetPadding() Style { + s.unset(paddingLeftKey) + s.unset(paddingRightKey) + s.unset(paddingTopKey) + s.unset(paddingBottomKey) + return s +} + +// UnsetPaddingLeft removes the left padding style rule, if set. +func (s Style) UnsetPaddingLeft() Style { + s.unset(paddingLeftKey) + return s +} + +// UnsetPaddingRight removes the right padding style rule, if set. +func (s Style) UnsetPaddingRight() Style { + s.unset(paddingRightKey) + return s +} + +// UnsetPaddingTop removes the top padding style rule, if set. +func (s Style) UnsetPaddingTop() Style { + s.unset(paddingTopKey) + return s +} + +// UnsetPaddingBottom removes the bottom padding style rule, if set. +func (s Style) UnsetPaddingBottom() Style { + s.unset(paddingBottomKey) + return s +} + +// UnsetColorWhitespace removes the rule for coloring padding, if set. +func (s Style) UnsetColorWhitespace() Style { + s.unset(colorWhitespaceKey) + return s +} + +// UnsetMargins removes all margin style rules. +func (s Style) UnsetMargins() Style { + s.unset(marginLeftKey) + s.unset(marginRightKey) + s.unset(marginTopKey) + s.unset(marginBottomKey) + return s +} + +// UnsetMarginLeft removes the left margin style rule, if set. +func (s Style) UnsetMarginLeft() Style { + s.unset(marginLeftKey) + return s +} + +// UnsetMarginRight removes the right margin style rule, if set. +func (s Style) UnsetMarginRight() Style { + s.unset(marginRightKey) + return s +} + +// UnsetMarginTop removes the top margin style rule, if set. +func (s Style) UnsetMarginTop() Style { + s.unset(marginTopKey) + return s +} + +// UnsetMarginBottom removes the bottom margin style rule, if set. +func (s Style) UnsetMarginBottom() Style { + s.unset(marginBottomKey) + return s +} + +// UnsetMarginBackground removes the margin's background color. Note that the +// margin's background color can be set from the background color of another +// style during inheritance. +func (s Style) UnsetMarginBackground() Style { + s.unset(marginBackgroundKey) + return s +} + +// UnsetBorderStyle removes the border style rule, if set. +func (s Style) UnsetBorderStyle() Style { + s.unset(borderStyleKey) + return s +} + +// UnsetBorderTop removes the border top style rule, if set. +func (s Style) UnsetBorderTop() Style { + s.unset(borderTopKey) + return s +} + +// UnsetBorderRight removes the border right style rule, if set. +func (s Style) UnsetBorderRight() Style { + s.unset(borderRightKey) + return s +} + +// UnsetBorderBottom removes the border bottom style rule, if set. +func (s Style) UnsetBorderBottom() Style { + s.unset(borderBottomKey) + return s +} + +// UnsetBorderLeft removes the border left style rule, if set. +func (s Style) UnsetBorderLeft() Style { + s.unset(borderLeftKey) + return s +} + +// UnsetBorderForeground removes all border foreground color styles, if set. +func (s Style) UnsetBorderForeground() Style { + s.unset(borderTopForegroundKey) + s.unset(borderRightForegroundKey) + s.unset(borderBottomForegroundKey) + s.unset(borderLeftForegroundKey) + return s +} + +// UnsetBorderTopForeground removes the top border foreground color rule, +// if set. +func (s Style) UnsetBorderTopForeground() Style { + s.unset(borderTopForegroundKey) + return s +} + +// UnsetBorderRightForeground removes the right border foreground color rule, +// if set. +func (s Style) UnsetBorderRightForeground() Style { + s.unset(borderRightForegroundKey) + return s +} + +// UnsetBorderBottomForeground removes the bottom border foreground color +// rule, if set. +func (s Style) UnsetBorderBottomForeground() Style { + s.unset(borderBottomForegroundKey) + return s +} + +// UnsetBorderLeftForeground removes the left border foreground color rule, +// if set. +func (s Style) UnsetBorderLeftForeground() Style { + s.unset(borderLeftForegroundKey) + return s +} + +// UnsetBorderBackground removes all border background color styles, if +// set. +func (s Style) UnsetBorderBackground() Style { + s.unset(borderTopBackgroundKey) + s.unset(borderRightBackgroundKey) + s.unset(borderBottomBackgroundKey) + s.unset(borderLeftBackgroundKey) + return s +} + +// UnsetBorderTopBackgroundColor removes the top border background color rule, +// if set. +// +// Deprecated: This function simply calls Style.UnsetBorderTopBackground. +func (s Style) UnsetBorderTopBackgroundColor() Style { + return s.UnsetBorderTopBackground() +} + +// UnsetBorderTopBackground removes the top border background color rule, +// if set. +func (s Style) UnsetBorderTopBackground() Style { + s.unset(borderTopBackgroundKey) + return s +} + +// UnsetBorderRightBackground removes the right border background color +// rule, if set. +func (s Style) UnsetBorderRightBackground() Style { + s.unset(borderRightBackgroundKey) + return s +} + +// UnsetBorderBottomBackground removes the bottom border background color +// rule, if set. +func (s Style) UnsetBorderBottomBackground() Style { + s.unset(borderBottomBackgroundKey) + return s +} + +// UnsetBorderLeftBackground removes the left border color rule, if set. +func (s Style) UnsetBorderLeftBackground() Style { + s.unset(borderLeftBackgroundKey) + return s +} + +// UnsetInline removes the inline style rule, if set. +func (s Style) UnsetInline() Style { + s.unset(inlineKey) + return s +} + +// UnsetMaxWidth removes the max width style rule, if set. +func (s Style) UnsetMaxWidth() Style { + s.unset(maxWidthKey) + return s +} + +// UnsetMaxHeight removes the max height style rule, if set. +func (s Style) UnsetMaxHeight() Style { + s.unset(maxHeightKey) + return s +} + +// UnsetTabWidth removes the tab width style rule, if set. +func (s Style) UnsetTabWidth() Style { + s.unset(tabWidthKey) + return s +} + +// UnsetUnderlineSpaces removes the value set by UnderlineSpaces. +func (s Style) UnsetUnderlineSpaces() Style { + s.unset(underlineSpacesKey) + return s +} + +// UnsetStrikethroughSpaces removes the value set by StrikethroughSpaces. +func (s Style) UnsetStrikethroughSpaces() Style { + s.unset(strikethroughSpacesKey) + return s +} + +// UnsetTransform removes the value set by Transform. +func (s Style) UnsetTransform() Style { + s.unset(transformKey) + return s +} + +// UnsetString sets the underlying string value to the empty string. +func (s Style) UnsetString() Style { + s.value = "" + return s +} diff --git a/vendor/github.com/charmbracelet/lipgloss/whitespace.go b/vendor/github.com/charmbracelet/lipgloss/whitespace.go new file mode 100644 index 000000000..040dc98e6 --- /dev/null +++ b/vendor/github.com/charmbracelet/lipgloss/whitespace.go @@ -0,0 +1,83 @@ +package lipgloss + +import ( + "strings" + + "github.com/charmbracelet/x/ansi" + "github.com/muesli/termenv" +) + +// whitespace is a whitespace renderer. +type whitespace struct { + re *Renderer + style termenv.Style + chars string +} + +// newWhitespace creates a new whitespace renderer. The order of the options +// matters, if you're using WithWhitespaceRenderer, make sure it comes first as +// other options might depend on it. +func newWhitespace(r *Renderer, opts ...WhitespaceOption) *whitespace { + w := &whitespace{ + re: r, + style: r.ColorProfile().String(), + } + for _, opt := range opts { + opt(w) + } + return w +} + +// Render whitespaces. +func (w whitespace) render(width int) string { + if w.chars == "" { + w.chars = " " + } + + r := []rune(w.chars) + j := 0 + b := strings.Builder{} + + // Cycle through runes and print them into the whitespace. + for i := 0; i < width; { + b.WriteRune(r[j]) + j++ + if j >= len(r) { + j = 0 + } + i += ansi.StringWidth(string(r[j])) + } + + // Fill any extra gaps white spaces. This might be necessary if any runes + // are more than one cell wide, which could leave a one-rune gap. + short := width - ansi.StringWidth(b.String()) + if short > 0 { + b.WriteString(strings.Repeat(" ", short)) + } + + return w.style.Styled(b.String()) +} + +// WhitespaceOption sets a styling rule for rendering whitespace. +type WhitespaceOption func(*whitespace) + +// WithWhitespaceForeground sets the color of the characters in the whitespace. +func WithWhitespaceForeground(c TerminalColor) WhitespaceOption { + return func(w *whitespace) { + w.style = w.style.Foreground(c.color(w.re)) + } +} + +// WithWhitespaceBackground sets the background color of the whitespace. +func WithWhitespaceBackground(c TerminalColor) WhitespaceOption { + return func(w *whitespace) { + w.style = w.style.Background(c.color(w.re)) + } +} + +// WithWhitespaceChars sets the characters to be rendered in the whitespace. +func WithWhitespaceChars(s string) WhitespaceOption { + return func(w *whitespace) { + w.chars = s + } +} diff --git a/vendor/github.com/charmbracelet/x/ansi/LICENSE b/vendor/github.com/charmbracelet/x/ansi/LICENSE new file mode 100644 index 000000000..65a5654e2 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Charmbracelet, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/charmbracelet/x/ansi/ansi.go b/vendor/github.com/charmbracelet/x/ansi/ansi.go new file mode 100644 index 000000000..d5a2f2519 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/ansi.go @@ -0,0 +1,11 @@ +package ansi + +import "io" + +// Execute is a function that "execute" the given escape sequence by writing it +// to the provided output writter. +// +// This is a syntactic sugar over [io.WriteString]. +func Execute(w io.Writer, s string) (int, error) { + return io.WriteString(w, s) //nolint:wrapcheck +} diff --git a/vendor/github.com/charmbracelet/x/ansi/ascii.go b/vendor/github.com/charmbracelet/x/ansi/ascii.go new file mode 100644 index 000000000..188582f7e --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/ascii.go @@ -0,0 +1,8 @@ +package ansi + +const ( + // SP is the space character (Char: \x20). + SP = 0x20 + // DEL is the delete character (Caret: ^?, Char: \x7f). + DEL = 0x7F +) diff --git a/vendor/github.com/charmbracelet/x/ansi/background.go b/vendor/github.com/charmbracelet/x/ansi/background.go new file mode 100644 index 000000000..46f821425 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/background.go @@ -0,0 +1,178 @@ +package ansi + +import ( + "fmt" + "image/color" + + "github.com/lucasb-eyer/go-colorful" +) + +// HexColor is a [color.Color] that can be formatted as a hex string. +type HexColor string + +// RGBA returns the RGBA values of the color. +func (h HexColor) RGBA() (r, g, b, a uint32) { + hex := h.color() + if hex == nil { + return 0, 0, 0, 0 + } + return hex.RGBA() +} + +// Hex returns the hex representation of the color. If the color is invalid, it +// returns an empty string. +func (h HexColor) Hex() string { + hex := h.color() + if hex == nil { + return "" + } + return hex.Hex() +} + +// String returns the color as a hex string. If the color is nil, an empty +// string is returned. +func (h HexColor) String() string { + return h.Hex() +} + +// color returns the underlying color of the HexColor. +func (h HexColor) color() *colorful.Color { + hex, err := colorful.Hex(string(h)) + if err != nil { + return nil + } + return &hex +} + +// XRGBColor is a [color.Color] that can be formatted as an XParseColor +// rgb: string. +// +// See: https://linux.die.net/man/3/xparsecolor +type XRGBColor struct { + color.Color +} + +// RGBA returns the RGBA values of the color. +func (x XRGBColor) RGBA() (r, g, b, a uint32) { + if x.Color == nil { + return 0, 0, 0, 0 + } + return x.Color.RGBA() +} + +// String returns the color as an XParseColor rgb: string. If the color is nil, +// an empty string is returned. +func (x XRGBColor) String() string { + if x.Color == nil { + return "" + } + r, g, b, _ := x.Color.RGBA() + // Get the lower 8 bits + return fmt.Sprintf("rgb:%04x/%04x/%04x", r, g, b) +} + +// XRGBAColor is a [color.Color] that can be formatted as an XParseColor +// rgba: string. +// +// See: https://linux.die.net/man/3/xparsecolor +type XRGBAColor struct { + color.Color +} + +// RGBA returns the RGBA values of the color. +func (x XRGBAColor) RGBA() (r, g, b, a uint32) { + if x.Color == nil { + return 0, 0, 0, 0 + } + return x.Color.RGBA() +} + +// String returns the color as an XParseColor rgba: string. If the color is nil, +// an empty string is returned. +func (x XRGBAColor) String() string { + if x.Color == nil { + return "" + } + r, g, b, a := x.RGBA() + // Get the lower 8 bits + return fmt.Sprintf("rgba:%04x/%04x/%04x/%04x", r, g, b, a) +} + +// SetForegroundColor returns a sequence that sets the default terminal +// foreground color. +// +// OSC 10 ; color ST +// OSC 10 ; color BEL +// +// Where color is the encoded color number. Most terminals support hex, +// XParseColor rgb: and rgba: strings. You could use [HexColor], [XRGBColor], +// or [XRGBAColor] to format the color. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands +func SetForegroundColor(s string) string { + return "\x1b]10;" + s + "\x07" +} + +// RequestForegroundColor is a sequence that requests the current default +// terminal foreground color. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands +const RequestForegroundColor = "\x1b]10;?\x07" + +// ResetForegroundColor is a sequence that resets the default terminal +// foreground color. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands +const ResetForegroundColor = "\x1b]110\x07" + +// SetBackgroundColor returns a sequence that sets the default terminal +// background color. +// +// OSC 11 ; color ST +// OSC 11 ; color BEL +// +// Where color is the encoded color number. Most terminals support hex, +// XParseColor rgb: and rgba: strings. You could use [HexColor], [XRGBColor], +// or [XRGBAColor] to format the color. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands +func SetBackgroundColor(s string) string { + return "\x1b]11;" + s + "\x07" +} + +// RequestBackgroundColor is a sequence that requests the current default +// terminal background color. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands +const RequestBackgroundColor = "\x1b]11;?\x07" + +// ResetBackgroundColor is a sequence that resets the default terminal +// background color. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands +const ResetBackgroundColor = "\x1b]111\x07" + +// SetCursorColor returns a sequence that sets the terminal cursor color. +// +// OSC 12 ; color ST +// OSC 12 ; color BEL +// +// Where color is the encoded color number. Most terminals support hex, +// XParseColor rgb: and rgba: strings. You could use [HexColor], [XRGBColor], +// or [XRGBAColor] to format the color. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands +func SetCursorColor(s string) string { + return "\x1b]12;" + s + "\x07" +} + +// RequestCursorColor is a sequence that requests the current terminal cursor +// color. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands +const RequestCursorColor = "\x1b]12;?\x07" + +// ResetCursorColor is a sequence that resets the terminal cursor color. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands +const ResetCursorColor = "\x1b]112\x07" diff --git a/vendor/github.com/charmbracelet/x/ansi/c0.go b/vendor/github.com/charmbracelet/x/ansi/c0.go new file mode 100644 index 000000000..28ff7c2a3 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/c0.go @@ -0,0 +1,79 @@ +package ansi + +// C0 control characters. +// +// These range from (0x00-0x1F) as defined in ISO 646 (ASCII). +// See: https://en.wikipedia.org/wiki/C0_and_C1_control_codes +const ( + // NUL is the null character (Caret: ^@, Char: \0). + NUL = 0x00 + // SOH is the start of heading character (Caret: ^A). + SOH = 0x01 + // STX is the start of text character (Caret: ^B). + STX = 0x02 + // ETX is the end of text character (Caret: ^C). + ETX = 0x03 + // EOT is the end of transmission character (Caret: ^D). + EOT = 0x04 + // ENQ is the enquiry character (Caret: ^E). + ENQ = 0x05 + // ACK is the acknowledge character (Caret: ^F). + ACK = 0x06 + // BEL is the bell character (Caret: ^G, Char: \a). + BEL = 0x07 + // BS is the backspace character (Caret: ^H, Char: \b). + BS = 0x08 + // HT is the horizontal tab character (Caret: ^I, Char: \t). + HT = 0x09 + // LF is the line feed character (Caret: ^J, Char: \n). + LF = 0x0A + // VT is the vertical tab character (Caret: ^K, Char: \v). + VT = 0x0B + // FF is the form feed character (Caret: ^L, Char: \f). + FF = 0x0C + // CR is the carriage return character (Caret: ^M, Char: \r). + CR = 0x0D + // SO is the shift out character (Caret: ^N). + SO = 0x0E + // SI is the shift in character (Caret: ^O). + SI = 0x0F + // DLE is the data link escape character (Caret: ^P). + DLE = 0x10 + // DC1 is the device control 1 character (Caret: ^Q). + DC1 = 0x11 + // DC2 is the device control 2 character (Caret: ^R). + DC2 = 0x12 + // DC3 is the device control 3 character (Caret: ^S). + DC3 = 0x13 + // DC4 is the device control 4 character (Caret: ^T). + DC4 = 0x14 + // NAK is the negative acknowledge character (Caret: ^U). + NAK = 0x15 + // SYN is the synchronous idle character (Caret: ^V). + SYN = 0x16 + // ETB is the end of transmission block character (Caret: ^W). + ETB = 0x17 + // CAN is the cancel character (Caret: ^X). + CAN = 0x18 + // EM is the end of medium character (Caret: ^Y). + EM = 0x19 + // SUB is the substitute character (Caret: ^Z). + SUB = 0x1A + // ESC is the escape character (Caret: ^[, Char: \e). + ESC = 0x1B + // FS is the file separator character (Caret: ^\). + FS = 0x1C + // GS is the group separator character (Caret: ^]). + GS = 0x1D + // RS is the record separator character (Caret: ^^). + RS = 0x1E + // US is the unit separator character (Caret: ^_). + US = 0x1F + + // LS0 is the locking shift 0 character. + // This is an alias for [SI]. + LS0 = SI + // LS1 is the locking shift 1 character. + // This is an alias for [SO]. + LS1 = SO +) diff --git a/vendor/github.com/charmbracelet/x/ansi/c1.go b/vendor/github.com/charmbracelet/x/ansi/c1.go new file mode 100644 index 000000000..71058f539 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/c1.go @@ -0,0 +1,72 @@ +package ansi + +// C1 control characters. +// +// These range from (0x80-0x9F) as defined in ISO 6429 (ECMA-48). +// See: https://en.wikipedia.org/wiki/C0_and_C1_control_codes +const ( + // PAD is the padding character. + PAD = 0x80 + // HOP is the high octet preset character. + HOP = 0x81 + // BPH is the break permitted here character. + BPH = 0x82 + // NBH is the no break here character. + NBH = 0x83 + // IND is the index character. + IND = 0x84 + // NEL is the next line character. + NEL = 0x85 + // SSA is the start of selected area character. + SSA = 0x86 + // ESA is the end of selected area character. + ESA = 0x87 + // HTS is the horizontal tab set character. + HTS = 0x88 + // HTJ is the horizontal tab with justification character. + HTJ = 0x89 + // VTS is the vertical tab set character. + VTS = 0x8A + // PLD is the partial line forward character. + PLD = 0x8B + // PLU is the partial line backward character. + PLU = 0x8C + // RI is the reverse index character. + RI = 0x8D + // SS2 is the single shift 2 character. + SS2 = 0x8E + // SS3 is the single shift 3 character. + SS3 = 0x8F + // DCS is the device control string character. + DCS = 0x90 + // PU1 is the private use 1 character. + PU1 = 0x91 + // PU2 is the private use 2 character. + PU2 = 0x92 + // STS is the set transmit state character. + STS = 0x93 + // CCH is the cancel character. + CCH = 0x94 + // MW is the message waiting character. + MW = 0x95 + // SPA is the start of guarded area character. + SPA = 0x96 + // EPA is the end of guarded area character. + EPA = 0x97 + // SOS is the start of string character. + SOS = 0x98 + // SGCI is the single graphic character introducer character. + SGCI = 0x99 + // SCI is the single character introducer character. + SCI = 0x9A + // CSI is the control sequence introducer character. + CSI = 0x9B + // ST is the string terminator character. + ST = 0x9C + // OSC is the operating system command character. + OSC = 0x9D + // PM is the privacy message character. + PM = 0x9E + // APC is the application program command character. + APC = 0x9F +) diff --git a/vendor/github.com/charmbracelet/x/ansi/charset.go b/vendor/github.com/charmbracelet/x/ansi/charset.go new file mode 100644 index 000000000..02edfe7ad --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/charset.go @@ -0,0 +1,55 @@ +package ansi + +// SelectCharacterSet sets the G-set character designator to the specified +// character set. +// +// ESC Ps Pd +// +// Where Ps is the G-set character designator, and Pd is the identifier. +// For 94-character sets, the designator can be one of: +// - ( G0 +// - ) G1 +// - * G2 +// - + G3 +// +// For 96-character sets, the designator can be one of: +// - - G1 +// - . G2 +// - / G3 +// +// Some common 94-character sets are: +// - 0 DEC Special Drawing Set +// - A United Kingdom (UK) +// - B United States (USASCII) +// +// Examples: +// +// ESC ( B Select character set G0 = United States (USASCII) +// ESC ( 0 Select character set G0 = Special Character and Line Drawing Set +// ESC ) 0 Select character set G1 = Special Character and Line Drawing Set +// ESC * A Select character set G2 = United Kingdom (UK) +// +// See: https://vt100.net/docs/vt510-rm/SCS.html +func SelectCharacterSet(gset byte, charset byte) string { + return "\x1b" + string(gset) + string(charset) +} + +// SCS is an alias for SelectCharacterSet. +func SCS(gset byte, charset byte) string { + return SelectCharacterSet(gset, charset) +} + +// LS1R (Locking Shift 1 Right) shifts G1 into GR character set. +const LS1R = "\x1b~" + +// LS2 (Locking Shift 2) shifts G2 into GL character set. +const LS2 = "\x1bn" + +// LS2R (Locking Shift 2 Right) shifts G2 into GR character set. +const LS2R = "\x1b}" + +// LS3 (Locking Shift 3) shifts G3 into GL character set. +const LS3 = "\x1bo" + +// LS3R (Locking Shift 3 Right) shifts G3 into GR character set. +const LS3R = "\x1b|" diff --git a/vendor/github.com/charmbracelet/x/ansi/clipboard.go b/vendor/github.com/charmbracelet/x/ansi/clipboard.go new file mode 100644 index 000000000..94d26c366 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/clipboard.go @@ -0,0 +1,75 @@ +package ansi + +import "encoding/base64" + +// Clipboard names. +const ( + SystemClipboard = 'c' + PrimaryClipboard = 'p' +) + +// SetClipboard returns a sequence for manipulating the clipboard. +// +// OSC 52 ; Pc ; Pd ST +// OSC 52 ; Pc ; Pd BEL +// +// Where Pc is the clipboard name and Pd is the base64 encoded data. +// Empty data or invalid base64 data will reset the clipboard. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands +func SetClipboard(c byte, d string) string { + if d != "" { + d = base64.StdEncoding.EncodeToString([]byte(d)) + } + return "\x1b]52;" + string(c) + ";" + d + "\x07" +} + +// SetSystemClipboard returns a sequence for setting the system clipboard. +// +// This is equivalent to SetClipboard(SystemClipboard, d). +func SetSystemClipboard(d string) string { + return SetClipboard(SystemClipboard, d) +} + +// SetPrimaryClipboard returns a sequence for setting the primary clipboard. +// +// This is equivalent to SetClipboard(PrimaryClipboard, d). +func SetPrimaryClipboard(d string) string { + return SetClipboard(PrimaryClipboard, d) +} + +// ResetClipboard returns a sequence for resetting the clipboard. +// +// This is equivalent to SetClipboard(c, ""). +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands +func ResetClipboard(c byte) string { + return SetClipboard(c, "") +} + +// ResetSystemClipboard is a sequence for resetting the system clipboard. +// +// This is equivalent to ResetClipboard(SystemClipboard). +const ResetSystemClipboard = "\x1b]52;c;\x07" + +// ResetPrimaryClipboard is a sequence for resetting the primary clipboard. +// +// This is equivalent to ResetClipboard(PrimaryClipboard). +const ResetPrimaryClipboard = "\x1b]52;p;\x07" + +// RequestClipboard returns a sequence for requesting the clipboard. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands +func RequestClipboard(c byte) string { + return "\x1b]52;" + string(c) + ";?\x07" +} + +// RequestSystemClipboard is a sequence for requesting the system clipboard. +// +// This is equivalent to RequestClipboard(SystemClipboard). +const RequestSystemClipboard = "\x1b]52;c;?\x07" + +// RequestPrimaryClipboard is a sequence for requesting the primary clipboard. +// +// This is equivalent to RequestClipboard(PrimaryClipboard). +const RequestPrimaryClipboard = "\x1b]52;p;?\x07" diff --git a/vendor/github.com/charmbracelet/x/ansi/color.go b/vendor/github.com/charmbracelet/x/ansi/color.go new file mode 100644 index 000000000..09feb9759 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/color.go @@ -0,0 +1,784 @@ +package ansi + +import ( + "image/color" + + "github.com/lucasb-eyer/go-colorful" +) + +// Color is a color that can be used in a terminal. ANSI (including +// ANSI256) and 24-bit "true colors" fall under this category. +type Color interface { + color.Color +} + +// BasicColor is an ANSI 3-bit or 4-bit color with a value from 0 to 15. +type BasicColor uint8 + +var _ Color = BasicColor(0) + +const ( + // Black is the ANSI black color. + Black BasicColor = iota + + // Red is the ANSI red color. + Red + + // Green is the ANSI green color. + Green + + // Yellow is the ANSI yellow color. + Yellow + + // Blue is the ANSI blue color. + Blue + + // Magenta is the ANSI magenta color. + Magenta + + // Cyan is the ANSI cyan color. + Cyan + + // White is the ANSI white color. + White + + // BrightBlack is the ANSI bright black color. + BrightBlack + + // BrightRed is the ANSI bright red color. + BrightRed + + // BrightGreen is the ANSI bright green color. + BrightGreen + + // BrightYellow is the ANSI bright yellow color. + BrightYellow + + // BrightBlue is the ANSI bright blue color. + BrightBlue + + // BrightMagenta is the ANSI bright magenta color. + BrightMagenta + + // BrightCyan is the ANSI bright cyan color. + BrightCyan + + // BrightWhite is the ANSI bright white color. + BrightWhite +) + +// RGBA returns the red, green, blue and alpha components of the color. It +// satisfies the color.Color interface. +func (c BasicColor) RGBA() (uint32, uint32, uint32, uint32) { + ansi := uint32(c) + if ansi > 15 { + return 0, 0, 0, 0xffff + } + + return ansiToRGB(byte(ansi)).RGBA() +} + +// IndexedColor is an ANSI 256 (8-bit) color with a value from 0 to 255. +type IndexedColor uint8 + +var _ Color = IndexedColor(0) + +// RGBA returns the red, green, blue and alpha components of the color. It +// satisfies the color.Color interface. +func (c IndexedColor) RGBA() (uint32, uint32, uint32, uint32) { + return ansiToRGB(byte(c)).RGBA() +} + +// ExtendedColor is an ANSI 256 (8-bit) color with a value from 0 to 255. +// +// Deprecated: use [IndexedColor] instead. +type ExtendedColor = IndexedColor + +// TrueColor is a 24-bit color that can be used in the terminal. +// This can be used to represent RGB colors. +// +// For example, the color red can be represented as: +// +// TrueColor(0xff0000) +// +// Deprecated: use [RGBColor] instead. +type TrueColor uint32 + +var _ Color = TrueColor(0) + +// RGBA returns the red, green, blue and alpha components of the color. It +// satisfies the color.Color interface. +func (c TrueColor) RGBA() (uint32, uint32, uint32, uint32) { + r, g, b := hexToRGB(uint32(c)) + return toRGBA(r, g, b) +} + +// RGBColor is a 24-bit color that can be used in the terminal. +// This can be used to represent RGB colors. +type RGBColor struct { + R uint8 + G uint8 + B uint8 +} + +// RGBA returns the red, green, blue and alpha components of the color. It +// satisfies the color.Color interface. +func (c RGBColor) RGBA() (uint32, uint32, uint32, uint32) { + return toRGBA(uint32(c.R), uint32(c.G), uint32(c.B)) +} + +// ansiToRGB converts an ANSI color to a 24-bit RGB color. +// +// r, g, b := ansiToRGB(57) +func ansiToRGB(ansi byte) color.Color { + return ansiHex[ansi] +} + +// hexToRGB converts a number in hexadecimal format to red, green, and blue +// values. +// +// r, g, b := hexToRGB(0x0000FF) +func hexToRGB(hex uint32) (uint32, uint32, uint32) { + return hex >> 16 & 0xff, hex >> 8 & 0xff, hex & 0xff +} + +// toRGBA converts an RGB 8-bit color values to 32-bit color values suitable +// for color.Color. +// +// color.Color requires 16-bit color values, so we duplicate the 8-bit values +// to fill the 16-bit values. +// +// This always returns 0xffff (opaque) for the alpha channel. +func toRGBA(r, g, b uint32) (uint32, uint32, uint32, uint32) { + r |= r << 8 + g |= g << 8 + b |= b << 8 + return r, g, b, 0xffff +} + +//nolint:unused +func distSq(r1, g1, b1, r2, g2, b2 int) int { + return ((r1-r2)*(r1-r2) + (g1-g2)*(g1-g2) + (b1-b2)*(b1-b2)) +} + +func to6Cube[T int | float64](v T) int { + if v < 48 { + return 0 + } + if v < 115 { + return 1 + } + return int((v - 35) / 40) +} + +// Convert256 converts a [color.Color], usually a 24-bit color, to xterm(1) 256 +// color palette. +// +// xterm provides a 6x6x6 color cube (16 - 231) and 24 greys (232 - 255). We +// map our RGB color to the closest in the cube, also work out the closest +// grey, and use the nearest of the two based on the lightness of the color. +// +// Note that the xterm has much lower resolution for darker colors (they are +// not evenly spread out), so our 6 levels are not evenly spread: 0x0, 0x5f +// (95), 0x87 (135), 0xaf (175), 0xd7 (215) and 0xff (255). Greys are more +// evenly spread (8, 18, 28 ... 238). +func Convert256(c color.Color) IndexedColor { + // If the color is already an IndexedColor, return it. + if i, ok := c.(IndexedColor); ok { + return i + } + + // Note: this is mostly ported from tmux/colour.c. + col, ok := colorful.MakeColor(c) + if !ok { + return IndexedColor(0) + } + + r := col.R * 255 + g := col.G * 255 + b := col.B * 255 + + q2c := [6]int{0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff} + + // Map RGB to 6x6x6 cube. + qr := to6Cube(r) + cr := q2c[qr] + qg := to6Cube(g) + cg := q2c[qg] + qb := to6Cube(b) + cb := q2c[qb] + + // If we have hit the color exactly, return early. + ci := (36 * qr) + (6 * qg) + qb + if cr == int(r) && cg == int(g) && cb == int(b) { + return IndexedColor(16 + ci) //nolint:gosec + } + + // Work out the closest grey (average of RGB). + greyAvg := int(r+g+b) / 3 + var greyIdx int + if greyAvg > 238 { + greyIdx = 23 + } else { + greyIdx = (greyAvg - 3) / 10 + } + grey := 8 + (10 * greyIdx) + + // Return the one which is nearer to the original input rgb value + // XXX: This is where it differs from tmux's implementation, we prefer the + // closer color to the original in terms of light distances rather than the + // cube distance. + c2 := colorful.Color{R: float64(cr) / 255.0, G: float64(cg) / 255.0, B: float64(cb) / 255.0} + g2 := colorful.Color{R: float64(grey) / 255.0, G: float64(grey) / 255.0, B: float64(grey) / 255.0} + colorDist := col.DistanceHSLuv(c2) + grayDist := col.DistanceHSLuv(g2) + + if colorDist <= grayDist { + return IndexedColor(16 + ci) //nolint:gosec + } + return IndexedColor(232 + greyIdx) //nolint:gosec + + // // Is grey or 6x6x6 color closest? + // d := distSq(cr, cg, cb, int(r), int(g), int(b)) + // if distSq(grey, grey, grey, int(r), int(g), int(b)) < d { + // return IndexedColor(232 + greyIdx) //nolint:gosec + // } + // return IndexedColor(16 + ci) //nolint:gosec +} + +// Convert16 converts a [color.Color] to a 16-color ANSI color. It will first +// try to find a match in the 256 xterm(1) color palette, and then map that to +// the 16-color ANSI palette. +func Convert16(c color.Color) BasicColor { + switch c := c.(type) { + case BasicColor: + // If the color is already a BasicColor, return it. + return c + case IndexedColor: + // If the color is already an IndexedColor, return the corresponding + // BasicColor. + return ansi256To16[c] + default: + c256 := Convert256(c) + return ansi256To16[c256] + } +} + +// RGB values of ANSI colors (0-255). +var ansiHex = [...]color.RGBA{ + 0: {R: 0x00, G: 0x00, B: 0x00, A: 0xff}, // "#000000" + 1: {R: 0x80, G: 0x00, B: 0x00, A: 0xff}, // "#800000" + 2: {R: 0x00, G: 0x80, B: 0x00, A: 0xff}, // "#008000" + 3: {R: 0x80, G: 0x80, B: 0x00, A: 0xff}, // "#808000" + 4: {R: 0x00, G: 0x00, B: 0x80, A: 0xff}, // "#000080" + 5: {R: 0x80, G: 0x00, B: 0x80, A: 0xff}, // "#800080" + 6: {R: 0x00, G: 0x80, B: 0x80, A: 0xff}, // "#008080" + 7: {R: 0xc0, G: 0xc0, B: 0xc0, A: 0xff}, // "#c0c0c0" + 8: {R: 0x80, G: 0x80, B: 0x80, A: 0xff}, // "#808080" + 9: {R: 0xff, G: 0x00, B: 0x00, A: 0xff}, // "#ff0000" + 10: {R: 0x00, G: 0xff, B: 0x00, A: 0xff}, // "#00ff00" + 11: {R: 0xff, G: 0xff, B: 0x00, A: 0xff}, // "#ffff00" + 12: {R: 0x00, G: 0x00, B: 0xff, A: 0xff}, // "#0000ff" + 13: {R: 0xff, G: 0x00, B: 0xff, A: 0xff}, // "#ff00ff" + 14: {R: 0x00, G: 0xff, B: 0xff, A: 0xff}, // "#00ffff" + 15: {R: 0xff, G: 0xff, B: 0xff, A: 0xff}, // "#ffffff" + 16: {R: 0x00, G: 0x00, B: 0x00, A: 0xff}, // "#000000" + 17: {R: 0x00, G: 0x00, B: 0x5f, A: 0xff}, // "#00005f" + 18: {R: 0x00, G: 0x00, B: 0x87, A: 0xff}, // "#000087" + 19: {R: 0x00, G: 0x00, B: 0xaf, A: 0xff}, // "#0000af" + 20: {R: 0x00, G: 0x00, B: 0xd7, A: 0xff}, // "#0000d7" + 21: {R: 0x00, G: 0x00, B: 0xff, A: 0xff}, // "#0000ff" + 22: {R: 0x00, G: 0x5f, B: 0x00, A: 0xff}, // "#005f00" + 23: {R: 0x00, G: 0x5f, B: 0x5f, A: 0xff}, // "#005f5f" + 24: {R: 0x00, G: 0x5f, B: 0x87, A: 0xff}, // "#005f87" + 25: {R: 0x00, G: 0x5f, B: 0xaf, A: 0xff}, // "#005faf" + 26: {R: 0x00, G: 0x5f, B: 0xd7, A: 0xff}, // "#005fd7" + 27: {R: 0x00, G: 0x5f, B: 0xff, A: 0xff}, // "#005fff" + 28: {R: 0x00, G: 0x87, B: 0x00, A: 0xff}, // "#008700" + 29: {R: 0x00, G: 0x87, B: 0x5f, A: 0xff}, // "#00875f" + 30: {R: 0x00, G: 0x87, B: 0x87, A: 0xff}, // "#008787" + 31: {R: 0x00, G: 0x87, B: 0xaf, A: 0xff}, // "#0087af" + 32: {R: 0x00, G: 0x87, B: 0xd7, A: 0xff}, // "#0087d7" + 33: {R: 0x00, G: 0x87, B: 0xff, A: 0xff}, // "#0087ff" + 34: {R: 0x00, G: 0xaf, B: 0x00, A: 0xff}, // "#00af00" + 35: {R: 0x00, G: 0xaf, B: 0x5f, A: 0xff}, // "#00af5f" + 36: {R: 0x00, G: 0xaf, B: 0x87, A: 0xff}, // "#00af87" + 37: {R: 0x00, G: 0xaf, B: 0xaf, A: 0xff}, // "#00afaf" + 38: {R: 0x00, G: 0xaf, B: 0xd7, A: 0xff}, // "#00afd7" + 39: {R: 0x00, G: 0xaf, B: 0xff, A: 0xff}, // "#00afff" + 40: {R: 0x00, G: 0xd7, B: 0x00, A: 0xff}, // "#00d700" + 41: {R: 0x00, G: 0xd7, B: 0x5f, A: 0xff}, // "#00d75f" + 42: {R: 0x00, G: 0xd7, B: 0x87, A: 0xff}, // "#00d787" + 43: {R: 0x00, G: 0xd7, B: 0xaf, A: 0xff}, // "#00d7af" + 44: {R: 0x00, G: 0xd7, B: 0xd7, A: 0xff}, // "#00d7d7" + 45: {R: 0x00, G: 0xd7, B: 0xff, A: 0xff}, // "#00d7ff" + 46: {R: 0x00, G: 0xff, B: 0x00, A: 0xff}, // "#00ff00" + 47: {R: 0x00, G: 0xff, B: 0x5f, A: 0xff}, // "#00ff5f" + 48: {R: 0x00, G: 0xff, B: 0x87, A: 0xff}, // "#00ff87" + 49: {R: 0x00, G: 0xff, B: 0xaf, A: 0xff}, // "#00ffaf" + 50: {R: 0x00, G: 0xff, B: 0xd7, A: 0xff}, // "#00ffd7" + 51: {R: 0x00, G: 0xff, B: 0xff, A: 0xff}, // "#00ffff" + 52: {R: 0x5f, G: 0x00, B: 0x00, A: 0xff}, // "#5f0000" + 53: {R: 0x5f, G: 0x00, B: 0x5f, A: 0xff}, // "#5f005f" + 54: {R: 0x5f, G: 0x00, B: 0x87, A: 0xff}, // "#5f0087" + 55: {R: 0x5f, G: 0x00, B: 0xaf, A: 0xff}, // "#5f00af" + 56: {R: 0x5f, G: 0x00, B: 0xd7, A: 0xff}, // "#5f00d7" + 57: {R: 0x5f, G: 0x00, B: 0xff, A: 0xff}, // "#5f00ff" + 58: {R: 0x5f, G: 0x5f, B: 0x00, A: 0xff}, // "#5f5f00" + 59: {R: 0x5f, G: 0x5f, B: 0x5f, A: 0xff}, // "#5f5f5f" + 60: {R: 0x5f, G: 0x5f, B: 0x87, A: 0xff}, // "#5f5f87" + 61: {R: 0x5f, G: 0x5f, B: 0xaf, A: 0xff}, // "#5f5faf" + 62: {R: 0x5f, G: 0x5f, B: 0xd7, A: 0xff}, // "#5f5fd7" + 63: {R: 0x5f, G: 0x5f, B: 0xff, A: 0xff}, // "#5f5fff" + 64: {R: 0x5f, G: 0x87, B: 0x00, A: 0xff}, // "#5f8700" + 65: {R: 0x5f, G: 0x87, B: 0x5f, A: 0xff}, // "#5f875f" + 66: {R: 0x5f, G: 0x87, B: 0x87, A: 0xff}, // "#5f8787" + 67: {R: 0x5f, G: 0x87, B: 0xaf, A: 0xff}, // "#5f87af" + 68: {R: 0x5f, G: 0x87, B: 0xd7, A: 0xff}, // "#5f87d7" + 69: {R: 0x5f, G: 0x87, B: 0xff, A: 0xff}, // "#5f87ff" + 70: {R: 0x5f, G: 0xaf, B: 0x00, A: 0xff}, // "#5faf00" + 71: {R: 0x5f, G: 0xaf, B: 0x5f, A: 0xff}, // "#5faf5f" + 72: {R: 0x5f, G: 0xaf, B: 0x87, A: 0xff}, // "#5faf87" + 73: {R: 0x5f, G: 0xaf, B: 0xaf, A: 0xff}, // "#5fafaf" + 74: {R: 0x5f, G: 0xaf, B: 0xd7, A: 0xff}, // "#5fafd7" + 75: {R: 0x5f, G: 0xaf, B: 0xff, A: 0xff}, // "#5fafff" + 76: {R: 0x5f, G: 0xd7, B: 0x00, A: 0xff}, // "#5fd700" + 77: {R: 0x5f, G: 0xd7, B: 0x5f, A: 0xff}, // "#5fd75f" + 78: {R: 0x5f, G: 0xd7, B: 0x87, A: 0xff}, // "#5fd787" + 79: {R: 0x5f, G: 0xd7, B: 0xaf, A: 0xff}, // "#5fd7af" + 80: {R: 0x5f, G: 0xd7, B: 0xd7, A: 0xff}, // "#5fd7d7" + 81: {R: 0x5f, G: 0xd7, B: 0xff, A: 0xff}, // "#5fd7ff" + 82: {R: 0x5f, G: 0xff, B: 0x00, A: 0xff}, // "#5fff00" + 83: {R: 0x5f, G: 0xff, B: 0x5f, A: 0xff}, // "#5fff5f" + 84: {R: 0x5f, G: 0xff, B: 0x87, A: 0xff}, // "#5fff87" + 85: {R: 0x5f, G: 0xff, B: 0xaf, A: 0xff}, // "#5fffaf" + 86: {R: 0x5f, G: 0xff, B: 0xd7, A: 0xff}, // "#5fffd7" + 87: {R: 0x5f, G: 0xff, B: 0xff, A: 0xff}, // "#5fffff" + 88: {R: 0x87, G: 0x00, B: 0x00, A: 0xff}, // "#870000" + 89: {R: 0x87, G: 0x00, B: 0x5f, A: 0xff}, // "#87005f" + 90: {R: 0x87, G: 0x00, B: 0x87, A: 0xff}, // "#870087" + 91: {R: 0x87, G: 0x00, B: 0xaf, A: 0xff}, // "#8700af" + 92: {R: 0x87, G: 0x00, B: 0xd7, A: 0xff}, // "#8700d7" + 93: {R: 0x87, G: 0x00, B: 0xff, A: 0xff}, // "#8700ff" + 94: {R: 0x87, G: 0x5f, B: 0x00, A: 0xff}, // "#875f00" + 95: {R: 0x87, G: 0x5f, B: 0x5f, A: 0xff}, // "#875f5f" + 96: {R: 0x87, G: 0x5f, B: 0x87, A: 0xff}, // "#875f87" + 97: {R: 0x87, G: 0x5f, B: 0xaf, A: 0xff}, // "#875faf" + 98: {R: 0x87, G: 0x5f, B: 0xd7, A: 0xff}, // "#875fd7" + 99: {R: 0x87, G: 0x5f, B: 0xff, A: 0xff}, // "#875fff" + 100: {R: 0x87, G: 0x87, B: 0x00, A: 0xff}, // "#878700" + 101: {R: 0x87, G: 0x87, B: 0x5f, A: 0xff}, // "#87875f" + 102: {R: 0x87, G: 0x87, B: 0x87, A: 0xff}, // "#878787" + 103: {R: 0x87, G: 0x87, B: 0xaf, A: 0xff}, // "#8787af" + 104: {R: 0x87, G: 0x87, B: 0xd7, A: 0xff}, // "#8787d7" + 105: {R: 0x87, G: 0x87, B: 0xff, A: 0xff}, // "#8787ff" + 106: {R: 0x87, G: 0xaf, B: 0x00, A: 0xff}, // "#87af00" + 107: {R: 0x87, G: 0xaf, B: 0x5f, A: 0xff}, // "#87af5f" + 108: {R: 0x87, G: 0xaf, B: 0x87, A: 0xff}, // "#87af87" + 109: {R: 0x87, G: 0xaf, B: 0xaf, A: 0xff}, // "#87afaf" + 110: {R: 0x87, G: 0xaf, B: 0xd7, A: 0xff}, // "#87afd7" + 111: {R: 0x87, G: 0xaf, B: 0xff, A: 0xff}, // "#87afff" + 112: {R: 0x87, G: 0xd7, B: 0x00, A: 0xff}, // "#87d700" + 113: {R: 0x87, G: 0xd7, B: 0x5f, A: 0xff}, // "#87d75f" + 114: {R: 0x87, G: 0xd7, B: 0x87, A: 0xff}, // "#87d787" + 115: {R: 0x87, G: 0xd7, B: 0xaf, A: 0xff}, // "#87d7af" + 116: {R: 0x87, G: 0xd7, B: 0xd7, A: 0xff}, // "#87d7d7" + 117: {R: 0x87, G: 0xd7, B: 0xff, A: 0xff}, // "#87d7ff" + 118: {R: 0x87, G: 0xff, B: 0x00, A: 0xff}, // "#87ff00" + 119: {R: 0x87, G: 0xff, B: 0x5f, A: 0xff}, // "#87ff5f" + 120: {R: 0x87, G: 0xff, B: 0x87, A: 0xff}, // "#87ff87" + 121: {R: 0x87, G: 0xff, B: 0xaf, A: 0xff}, // "#87ffaf" + 122: {R: 0x87, G: 0xff, B: 0xd7, A: 0xff}, // "#87ffd7" + 123: {R: 0x87, G: 0xff, B: 0xff, A: 0xff}, // "#87ffff" + 124: {R: 0xaf, G: 0x00, B: 0x00, A: 0xff}, // "#af0000" + 125: {R: 0xaf, G: 0x00, B: 0x5f, A: 0xff}, // "#af005f" + 126: {R: 0xaf, G: 0x00, B: 0x87, A: 0xff}, // "#af0087" + 127: {R: 0xaf, G: 0x00, B: 0xaf, A: 0xff}, // "#af00af" + 128: {R: 0xaf, G: 0x00, B: 0xd7, A: 0xff}, // "#af00d7" + 129: {R: 0xaf, G: 0x00, B: 0xff, A: 0xff}, // "#af00ff" + 130: {R: 0xaf, G: 0x5f, B: 0x00, A: 0xff}, // "#af5f00" + 131: {R: 0xaf, G: 0x5f, B: 0x5f, A: 0xff}, // "#af5f5f" + 132: {R: 0xaf, G: 0x5f, B: 0x87, A: 0xff}, // "#af5f87" + 133: {R: 0xaf, G: 0x5f, B: 0xaf, A: 0xff}, // "#af5faf" + 134: {R: 0xaf, G: 0x5f, B: 0xd7, A: 0xff}, // "#af5fd7" + 135: {R: 0xaf, G: 0x5f, B: 0xff, A: 0xff}, // "#af5fff" + 136: {R: 0xaf, G: 0x87, B: 0x00, A: 0xff}, // "#af8700" + 137: {R: 0xaf, G: 0x87, B: 0x5f, A: 0xff}, // "#af875f" + 138: {R: 0xaf, G: 0x87, B: 0x87, A: 0xff}, // "#af8787" + 139: {R: 0xaf, G: 0x87, B: 0xaf, A: 0xff}, // "#af87af" + 140: {R: 0xaf, G: 0x87, B: 0xd7, A: 0xff}, // "#af87d7" + 141: {R: 0xaf, G: 0x87, B: 0xff, A: 0xff}, // "#af87ff" + 142: {R: 0xaf, G: 0xaf, B: 0x00, A: 0xff}, // "#afaf00" + 143: {R: 0xaf, G: 0xaf, B: 0x5f, A: 0xff}, // "#afaf5f" + 144: {R: 0xaf, G: 0xaf, B: 0x87, A: 0xff}, // "#afaf87" + 145: {R: 0xaf, G: 0xaf, B: 0xaf, A: 0xff}, // "#afafaf" + 146: {R: 0xaf, G: 0xaf, B: 0xd7, A: 0xff}, // "#afafd7" + 147: {R: 0xaf, G: 0xaf, B: 0xff, A: 0xff}, // "#afafff" + 148: {R: 0xaf, G: 0xd7, B: 0x00, A: 0xff}, // "#afd700" + 149: {R: 0xaf, G: 0xd7, B: 0x5f, A: 0xff}, // "#afd75f" + 150: {R: 0xaf, G: 0xd7, B: 0x87, A: 0xff}, // "#afd787" + 151: {R: 0xaf, G: 0xd7, B: 0xaf, A: 0xff}, // "#afd7af" + 152: {R: 0xaf, G: 0xd7, B: 0xd7, A: 0xff}, // "#afd7d7" + 153: {R: 0xaf, G: 0xd7, B: 0xff, A: 0xff}, // "#afd7ff" + 154: {R: 0xaf, G: 0xff, B: 0x00, A: 0xff}, // "#afff00" + 155: {R: 0xaf, G: 0xff, B: 0x5f, A: 0xff}, // "#afff5f" + 156: {R: 0xaf, G: 0xff, B: 0x87, A: 0xff}, // "#afff87" + 157: {R: 0xaf, G: 0xff, B: 0xaf, A: 0xff}, // "#afffaf" + 158: {R: 0xaf, G: 0xff, B: 0xd7, A: 0xff}, // "#afffd7" + 159: {R: 0xaf, G: 0xff, B: 0xff, A: 0xff}, // "#afffff" + 160: {R: 0xd7, G: 0x00, B: 0x00, A: 0xff}, // "#d70000" + 161: {R: 0xd7, G: 0x00, B: 0x5f, A: 0xff}, // "#d7005f" + 162: {R: 0xd7, G: 0x00, B: 0x87, A: 0xff}, // "#d70087" + 163: {R: 0xd7, G: 0x00, B: 0xaf, A: 0xff}, // "#d700af" + 164: {R: 0xd7, G: 0x00, B: 0xd7, A: 0xff}, // "#d700d7" + 165: {R: 0xd7, G: 0x00, B: 0xff, A: 0xff}, // "#d700ff" + 166: {R: 0xd7, G: 0x5f, B: 0x00, A: 0xff}, // "#d75f00" + 167: {R: 0xd7, G: 0x5f, B: 0x5f, A: 0xff}, // "#d75f5f" + 168: {R: 0xd7, G: 0x5f, B: 0x87, A: 0xff}, // "#d75f87" + 169: {R: 0xd7, G: 0x5f, B: 0xaf, A: 0xff}, // "#d75faf" + 170: {R: 0xd7, G: 0x5f, B: 0xd7, A: 0xff}, // "#d75fd7" + 171: {R: 0xd7, G: 0x5f, B: 0xff, A: 0xff}, // "#d75fff" + 172: {R: 0xd7, G: 0x87, B: 0x00, A: 0xff}, // "#d78700" + 173: {R: 0xd7, G: 0x87, B: 0x5f, A: 0xff}, // "#d7875f" + 174: {R: 0xd7, G: 0x87, B: 0x87, A: 0xff}, // "#d78787" + 175: {R: 0xd7, G: 0x87, B: 0xaf, A: 0xff}, // "#d787af" + 176: {R: 0xd7, G: 0x87, B: 0xd7, A: 0xff}, // "#d787d7" + 177: {R: 0xd7, G: 0x87, B: 0xff, A: 0xff}, // "#d787ff" + 178: {R: 0xd7, G: 0xaf, B: 0x00, A: 0xff}, // "#d7af00" + 179: {R: 0xd7, G: 0xaf, B: 0x5f, A: 0xff}, // "#d7af5f" + 180: {R: 0xd7, G: 0xaf, B: 0x87, A: 0xff}, // "#d7af87" + 181: {R: 0xd7, G: 0xaf, B: 0xaf, A: 0xff}, // "#d7afaf" + 182: {R: 0xd7, G: 0xaf, B: 0xd7, A: 0xff}, // "#d7afd7" + 183: {R: 0xd7, G: 0xaf, B: 0xff, A: 0xff}, // "#d7afff" + 184: {R: 0xd7, G: 0xd7, B: 0x00, A: 0xff}, // "#d7d700" + 185: {R: 0xd7, G: 0xd7, B: 0x5f, A: 0xff}, // "#d7d75f" + 186: {R: 0xd7, G: 0xd7, B: 0x87, A: 0xff}, // "#d7d787" + 187: {R: 0xd7, G: 0xd7, B: 0xaf, A: 0xff}, // "#d7d7af" + 188: {R: 0xd7, G: 0xd7, B: 0xd7, A: 0xff}, // "#d7d7d7" + 189: {R: 0xd7, G: 0xd7, B: 0xff, A: 0xff}, // "#d7d7ff" + 190: {R: 0xd7, G: 0xff, B: 0x00, A: 0xff}, // "#d7ff00" + 191: {R: 0xd7, G: 0xff, B: 0x5f, A: 0xff}, // "#d7ff5f" + 192: {R: 0xd7, G: 0xff, B: 0x87, A: 0xff}, // "#d7ff87" + 193: {R: 0xd7, G: 0xff, B: 0xaf, A: 0xff}, // "#d7ffaf" + 194: {R: 0xd7, G: 0xff, B: 0xd7, A: 0xff}, // "#d7ffd7" + 195: {R: 0xd7, G: 0xff, B: 0xff, A: 0xff}, // "#d7ffff" + 196: {R: 0xff, G: 0x00, B: 0x00, A: 0xff}, // "#ff0000" + 197: {R: 0xff, G: 0x00, B: 0x5f, A: 0xff}, // "#ff005f" + 198: {R: 0xff, G: 0x00, B: 0x87, A: 0xff}, // "#ff0087" + 199: {R: 0xff, G: 0x00, B: 0xaf, A: 0xff}, // "#ff00af" + 200: {R: 0xff, G: 0x00, B: 0xd7, A: 0xff}, // "#ff00d7" + 201: {R: 0xff, G: 0x00, B: 0xff, A: 0xff}, // "#ff00ff" + 202: {R: 0xff, G: 0x5f, B: 0x00, A: 0xff}, // "#ff5f00" + 203: {R: 0xff, G: 0x5f, B: 0x5f, A: 0xff}, // "#ff5f5f" + 204: {R: 0xff, G: 0x5f, B: 0x87, A: 0xff}, // "#ff5f87" + 205: {R: 0xff, G: 0x5f, B: 0xaf, A: 0xff}, // "#ff5faf" + 206: {R: 0xff, G: 0x5f, B: 0xd7, A: 0xff}, // "#ff5fd7" + 207: {R: 0xff, G: 0x5f, B: 0xff, A: 0xff}, // "#ff5fff" + 208: {R: 0xff, G: 0x87, B: 0x00, A: 0xff}, // "#ff8700" + 209: {R: 0xff, G: 0x87, B: 0x5f, A: 0xff}, // "#ff875f" + 210: {R: 0xff, G: 0x87, B: 0x87, A: 0xff}, // "#ff8787" + 211: {R: 0xff, G: 0x87, B: 0xaf, A: 0xff}, // "#ff87af" + 212: {R: 0xff, G: 0x87, B: 0xd7, A: 0xff}, // "#ff87d7" + 213: {R: 0xff, G: 0x87, B: 0xff, A: 0xff}, // "#ff87ff" + 214: {R: 0xff, G: 0xaf, B: 0x00, A: 0xff}, // "#ffaf00" + 215: {R: 0xff, G: 0xaf, B: 0x5f, A: 0xff}, // "#ffaf5f" + 216: {R: 0xff, G: 0xaf, B: 0x87, A: 0xff}, // "#ffaf87" + 217: {R: 0xff, G: 0xaf, B: 0xaf, A: 0xff}, // "#ffafaf" + 218: {R: 0xff, G: 0xaf, B: 0xd7, A: 0xff}, // "#ffafd7" + 219: {R: 0xff, G: 0xaf, B: 0xff, A: 0xff}, // "#ffafff" + 220: {R: 0xff, G: 0xd7, B: 0x00, A: 0xff}, // "#ffd700" + 221: {R: 0xff, G: 0xd7, B: 0x5f, A: 0xff}, // "#ffd75f" + 222: {R: 0xff, G: 0xd7, B: 0x87, A: 0xff}, // "#ffd787" + 223: {R: 0xff, G: 0xd7, B: 0xaf, A: 0xff}, // "#ffd7af" + 224: {R: 0xff, G: 0xd7, B: 0xd7, A: 0xff}, // "#ffd7d7" + 225: {R: 0xff, G: 0xd7, B: 0xff, A: 0xff}, // "#ffd7ff" + 226: {R: 0xff, G: 0xff, B: 0x00, A: 0xff}, // "#ffff00" + 227: {R: 0xff, G: 0xff, B: 0x5f, A: 0xff}, // "#ffff5f" + 228: {R: 0xff, G: 0xff, B: 0x87, A: 0xff}, // "#ffff87" + 229: {R: 0xff, G: 0xff, B: 0xaf, A: 0xff}, // "#ffffaf" + 230: {R: 0xff, G: 0xff, B: 0xd7, A: 0xff}, // "#ffffd7" + 231: {R: 0xff, G: 0xff, B: 0xff, A: 0xff}, // "#ffffff" + 232: {R: 0x08, G: 0x08, B: 0x08, A: 0xff}, // "#080808" + 233: {R: 0x12, G: 0x12, B: 0x12, A: 0xff}, // "#121212" + 234: {R: 0x1c, G: 0x1c, B: 0x1c, A: 0xff}, // "#1c1c1c" + 235: {R: 0x26, G: 0x26, B: 0x26, A: 0xff}, // "#262626" + 236: {R: 0x30, G: 0x30, B: 0x30, A: 0xff}, // "#303030" + 237: {R: 0x3a, G: 0x3a, B: 0x3a, A: 0xff}, // "#3a3a3a" + 238: {R: 0x44, G: 0x44, B: 0x44, A: 0xff}, // "#444444" + 239: {R: 0x4e, G: 0x4e, B: 0x4e, A: 0xff}, // "#4e4e4e" + 240: {R: 0x58, G: 0x58, B: 0x58, A: 0xff}, // "#585858" + 241: {R: 0x62, G: 0x62, B: 0x62, A: 0xff}, // "#626262" + 242: {R: 0x6c, G: 0x6c, B: 0x6c, A: 0xff}, // "#6c6c6c" + 243: {R: 0x76, G: 0x76, B: 0x76, A: 0xff}, // "#767676" + 244: {R: 0x80, G: 0x80, B: 0x80, A: 0xff}, // "#808080" + 245: {R: 0x8a, G: 0x8a, B: 0x8a, A: 0xff}, // "#8a8a8a" + 246: {R: 0x94, G: 0x94, B: 0x94, A: 0xff}, // "#949494" + 247: {R: 0x9e, G: 0x9e, B: 0x9e, A: 0xff}, // "#9e9e9e" + 248: {R: 0xa8, G: 0xa8, B: 0xa8, A: 0xff}, // "#a8a8a8" + 249: {R: 0xb2, G: 0xb2, B: 0xb2, A: 0xff}, // "#b2b2b2" + 250: {R: 0xbc, G: 0xbc, B: 0xbc, A: 0xff}, // "#bcbcbc" + 251: {R: 0xc6, G: 0xc6, B: 0xc6, A: 0xff}, // "#c6c6c6" + 252: {R: 0xd0, G: 0xd0, B: 0xd0, A: 0xff}, // "#d0d0d0" + 253: {R: 0xda, G: 0xda, B: 0xda, A: 0xff}, // "#dadada" + 254: {R: 0xe4, G: 0xe4, B: 0xe4, A: 0xff}, // "#e4e4e4" + 255: {R: 0xee, G: 0xee, B: 0xee, A: 0xff}, // "#eeeeee" +} + +var ansi256To16 = [...]BasicColor{ + 0: 0, + 1: 1, + 2: 2, + 3: 3, + 4: 4, + 5: 5, + 6: 6, + 7: 7, + 8: 8, + 9: 9, + 10: 10, + 11: 11, + 12: 12, + 13: 13, + 14: 14, + 15: 15, + 16: 0, + 17: 4, + 18: 4, + 19: 4, + 20: 12, + 21: 12, + 22: 2, + 23: 6, + 24: 4, + 25: 4, + 26: 12, + 27: 12, + 28: 2, + 29: 2, + 30: 6, + 31: 4, + 32: 12, + 33: 12, + 34: 2, + 35: 2, + 36: 2, + 37: 6, + 38: 12, + 39: 12, + 40: 10, + 41: 10, + 42: 10, + 43: 10, + 44: 14, + 45: 12, + 46: 10, + 47: 10, + 48: 10, + 49: 10, + 50: 10, + 51: 14, + 52: 1, + 53: 5, + 54: 4, + 55: 4, + 56: 12, + 57: 12, + 58: 3, + 59: 8, + 60: 4, + 61: 4, + 62: 12, + 63: 12, + 64: 2, + 65: 2, + 66: 6, + 67: 4, + 68: 12, + 69: 12, + 70: 2, + 71: 2, + 72: 2, + 73: 6, + 74: 12, + 75: 12, + 76: 10, + 77: 10, + 78: 10, + 79: 10, + 80: 14, + 81: 12, + 82: 10, + 83: 10, + 84: 10, + 85: 10, + 86: 10, + 87: 14, + 88: 1, + 89: 1, + 90: 5, + 91: 4, + 92: 12, + 93: 12, + 94: 1, + 95: 1, + 96: 5, + 97: 4, + 98: 12, + 99: 12, + 100: 3, + 101: 3, + 102: 8, + 103: 4, + 104: 12, + 105: 12, + 106: 2, + 107: 2, + 108: 2, + 109: 6, + 110: 12, + 111: 12, + 112: 10, + 113: 10, + 114: 10, + 115: 10, + 116: 14, + 117: 12, + 118: 10, + 119: 10, + 120: 10, + 121: 10, + 122: 10, + 123: 14, + 124: 1, + 125: 1, + 126: 1, + 127: 5, + 128: 12, + 129: 12, + 130: 1, + 131: 1, + 132: 1, + 133: 5, + 134: 12, + 135: 12, + 136: 1, + 137: 1, + 138: 1, + 139: 5, + 140: 12, + 141: 12, + 142: 3, + 143: 3, + 144: 3, + 145: 7, + 146: 12, + 147: 12, + 148: 10, + 149: 10, + 150: 10, + 151: 10, + 152: 14, + 153: 12, + 154: 10, + 155: 10, + 156: 10, + 157: 10, + 158: 10, + 159: 14, + 160: 9, + 161: 9, + 162: 9, + 163: 9, + 164: 13, + 165: 12, + 166: 9, + 167: 9, + 168: 9, + 169: 9, + 170: 13, + 171: 12, + 172: 9, + 173: 9, + 174: 9, + 175: 9, + 176: 13, + 177: 12, + 178: 9, + 179: 9, + 180: 9, + 181: 9, + 182: 13, + 183: 12, + 184: 11, + 185: 11, + 186: 11, + 187: 11, + 188: 7, + 189: 12, + 190: 10, + 191: 10, + 192: 10, + 193: 10, + 194: 10, + 195: 14, + 196: 9, + 197: 9, + 198: 9, + 199: 9, + 200: 9, + 201: 13, + 202: 9, + 203: 9, + 204: 9, + 205: 9, + 206: 9, + 207: 13, + 208: 9, + 209: 9, + 210: 9, + 211: 9, + 212: 9, + 213: 13, + 214: 9, + 215: 9, + 216: 9, + 217: 9, + 218: 9, + 219: 13, + 220: 9, + 221: 9, + 222: 9, + 223: 9, + 224: 9, + 225: 13, + 226: 11, + 227: 11, + 228: 11, + 229: 11, + 230: 11, + 231: 15, + 232: 0, + 233: 0, + 234: 0, + 235: 0, + 236: 0, + 237: 0, + 238: 8, + 239: 8, + 240: 8, + 241: 8, + 242: 8, + 243: 8, + 244: 7, + 245: 7, + 246: 7, + 247: 7, + 248: 7, + 249: 7, + 250: 15, + 251: 15, + 252: 15, + 253: 15, + 254: 15, + 255: 15, +} diff --git a/vendor/github.com/charmbracelet/x/ansi/ctrl.go b/vendor/github.com/charmbracelet/x/ansi/ctrl.go new file mode 100644 index 000000000..64bcf1136 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/ctrl.go @@ -0,0 +1,156 @@ +package ansi + +import ( + "strconv" + "strings" +) + +// RequestNameVersion (XTVERSION) is a control sequence that requests the +// terminal's name and version. It responds with a DSR sequence identifying the +// terminal. +// +// CSI > 0 q +// DCS > | text ST +// +// See https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-PC-Style-Function-Keys +const ( + RequestNameVersion = "\x1b[>q" + XTVERSION = RequestNameVersion +) + +// RequestXTVersion is a control sequence that requests the terminal's XTVERSION. It responds with a DSR sequence identifying the version. +// +// CSI > Ps q +// DCS > | text ST +// +// See https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-PC-Style-Function-Keys +// +// Deprecated: use [RequestNameVersion] instead. +const RequestXTVersion = RequestNameVersion + +// PrimaryDeviceAttributes (DA1) is a control sequence that reports the +// terminal's primary device attributes. +// +// CSI c +// CSI 0 c +// CSI ? Ps ; ... c +// +// If no attributes are given, or if the attribute is 0, this function returns +// the request sequence. Otherwise, it returns the response sequence. +// +// Common attributes include: +// - 1 132 columns +// - 2 Printer port +// - 4 Sixel +// - 6 Selective erase +// - 7 Soft character set (DRCS) +// - 8 User-defined keys (UDKs) +// - 9 National replacement character sets (NRCS) (International terminal only) +// - 12 Yugoslavian (SCS) +// - 15 Technical character set +// - 18 Windowing capability +// - 21 Horizontal scrolling +// - 23 Greek +// - 24 Turkish +// - 42 ISO Latin-2 character set +// - 44 PCTerm +// - 45 Soft key map +// - 46 ASCII emulation +// +// See https://vt100.net/docs/vt510-rm/DA1.html +func PrimaryDeviceAttributes(attrs ...int) string { + if len(attrs) == 0 { + return RequestPrimaryDeviceAttributes + } else if len(attrs) == 1 && attrs[0] == 0 { + return "\x1b[0c" + } + + as := make([]string, len(attrs)) + for i, a := range attrs { + as[i] = strconv.Itoa(a) + } + return "\x1b[?" + strings.Join(as, ";") + "c" +} + +// DA1 is an alias for [PrimaryDeviceAttributes]. +func DA1(attrs ...int) string { + return PrimaryDeviceAttributes(attrs...) +} + +// RequestPrimaryDeviceAttributes is a control sequence that requests the +// terminal's primary device attributes (DA1). +// +// CSI c +// +// See https://vt100.net/docs/vt510-rm/DA1.html +const RequestPrimaryDeviceAttributes = "\x1b[c" + +// SecondaryDeviceAttributes (DA2) is a control sequence that reports the +// terminal's secondary device attributes. +// +// CSI > c +// CSI > 0 c +// CSI > Ps ; ... c +// +// See https://vt100.net/docs/vt510-rm/DA2.html +func SecondaryDeviceAttributes(attrs ...int) string { + if len(attrs) == 0 { + return RequestSecondaryDeviceAttributes + } + + as := make([]string, len(attrs)) + for i, a := range attrs { + as[i] = strconv.Itoa(a) + } + return "\x1b[>" + strings.Join(as, ";") + "c" +} + +// DA2 is an alias for [SecondaryDeviceAttributes]. +func DA2(attrs ...int) string { + return SecondaryDeviceAttributes(attrs...) +} + +// RequestSecondaryDeviceAttributes is a control sequence that requests the +// terminal's secondary device attributes (DA2). +// +// CSI > c +// +// See https://vt100.net/docs/vt510-rm/DA2.html +const RequestSecondaryDeviceAttributes = "\x1b[>c" + +// TertiaryDeviceAttributes (DA3) is a control sequence that reports the +// terminal's tertiary device attributes. +// +// CSI = c +// CSI = 0 c +// DCS ! | Text ST +// +// Where Text is the unit ID for the terminal. +// +// If no unit ID is given, or if the unit ID is 0, this function returns the +// request sequence. Otherwise, it returns the response sequence. +// +// See https://vt100.net/docs/vt510-rm/DA3.html +func TertiaryDeviceAttributes(unitID string) string { + switch unitID { + case "": + return RequestTertiaryDeviceAttributes + case "0": + return "\x1b[=0c" + } + + return "\x1bP!|" + unitID + "\x1b\\" +} + +// DA3 is an alias for [TertiaryDeviceAttributes]. +func DA3(unitID string) string { + return TertiaryDeviceAttributes(unitID) +} + +// RequestTertiaryDeviceAttributes is a control sequence that requests the +// terminal's tertiary device attributes (DA3). +// +// CSI = c +// +// See https://vt100.net/docs/vt510-rm/DA3.html +const RequestTertiaryDeviceAttributes = "\x1b[=c" diff --git a/vendor/github.com/charmbracelet/x/ansi/cursor.go b/vendor/github.com/charmbracelet/x/ansi/cursor.go new file mode 100644 index 000000000..4adf68964 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/cursor.go @@ -0,0 +1,635 @@ +package ansi + +import ( + "strconv" +) + +// SaveCursor (DECSC) is an escape sequence that saves the current cursor +// position. +// +// ESC 7 +// +// See: https://vt100.net/docs/vt510-rm/DECSC.html +const ( + SaveCursor = "\x1b7" + DECSC = SaveCursor +) + +// RestoreCursor (DECRC) is an escape sequence that restores the cursor +// position. +// +// ESC 8 +// +// See: https://vt100.net/docs/vt510-rm/DECRC.html +const ( + RestoreCursor = "\x1b8" + DECRC = RestoreCursor +) + +// RequestCursorPosition is an escape sequence that requests the current cursor +// position. +// +// CSI 6 n +// +// The terminal will report the cursor position as a CSI sequence in the +// following format: +// +// CSI Pl ; Pc R +// +// Where Pl is the line number and Pc is the column number. +// See: https://vt100.net/docs/vt510-rm/CPR.html +// +// Deprecated: use [RequestCursorPositionReport] instead. +const RequestCursorPosition = "\x1b[6n" + +// RequestExtendedCursorPosition (DECXCPR) is a sequence for requesting the +// cursor position report including the current page number. +// +// CSI ? 6 n +// +// The terminal will report the cursor position as a CSI sequence in the +// following format: +// +// CSI ? Pl ; Pc ; Pp R +// +// Where Pl is the line number, Pc is the column number, and Pp is the page +// number. +// See: https://vt100.net/docs/vt510-rm/DECXCPR.html +// +// Deprecated: use [RequestExtendedCursorPositionReport] instead. +const RequestExtendedCursorPosition = "\x1b[?6n" + +// CursorUp (CUU) returns a sequence for moving the cursor up n cells. +// +// CSI n A +// +// See: https://vt100.net/docs/vt510-rm/CUU.html +func CursorUp(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "A" +} + +// CUU is an alias for [CursorUp]. +func CUU(n int) string { + return CursorUp(n) +} + +// CUU1 is a sequence for moving the cursor up one cell. +const CUU1 = "\x1b[A" + +// CursorUp1 is a sequence for moving the cursor up one cell. +// +// This is equivalent to CursorUp(1). +// +// Deprecated: use [CUU1] instead. +const CursorUp1 = "\x1b[A" + +// CursorDown (CUD) returns a sequence for moving the cursor down n cells. +// +// CSI n B +// +// See: https://vt100.net/docs/vt510-rm/CUD.html +func CursorDown(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "B" +} + +// CUD is an alias for [CursorDown]. +func CUD(n int) string { + return CursorDown(n) +} + +// CUD1 is a sequence for moving the cursor down one cell. +const CUD1 = "\x1b[B" + +// CursorDown1 is a sequence for moving the cursor down one cell. +// +// This is equivalent to CursorDown(1). +// +// Deprecated: use [CUD1] instead. +const CursorDown1 = "\x1b[B" + +// CursorForward (CUF) returns a sequence for moving the cursor right n cells. +// +// # CSI n C +// +// See: https://vt100.net/docs/vt510-rm/CUF.html +func CursorForward(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "C" +} + +// CUF is an alias for [CursorForward]. +func CUF(n int) string { + return CursorForward(n) +} + +// CUF1 is a sequence for moving the cursor right one cell. +const CUF1 = "\x1b[C" + +// CursorRight (CUF) returns a sequence for moving the cursor right n cells. +// +// CSI n C +// +// See: https://vt100.net/docs/vt510-rm/CUF.html +// +// Deprecated: use [CursorForward] instead. +func CursorRight(n int) string { + return CursorForward(n) +} + +// CursorRight1 is a sequence for moving the cursor right one cell. +// +// This is equivalent to CursorRight(1). +// +// Deprecated: use [CUF1] instead. +const CursorRight1 = CUF1 + +// CursorBackward (CUB) returns a sequence for moving the cursor left n cells. +// +// # CSI n D +// +// See: https://vt100.net/docs/vt510-rm/CUB.html +func CursorBackward(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "D" +} + +// CUB is an alias for [CursorBackward]. +func CUB(n int) string { + return CursorBackward(n) +} + +// CUB1 is a sequence for moving the cursor left one cell. +const CUB1 = "\x1b[D" + +// CursorLeft (CUB) returns a sequence for moving the cursor left n cells. +// +// CSI n D +// +// See: https://vt100.net/docs/vt510-rm/CUB.html +// +// Deprecated: use [CursorBackward] instead. +func CursorLeft(n int) string { + return CursorBackward(n) +} + +// CursorLeft1 is a sequence for moving the cursor left one cell. +// +// This is equivalent to CursorLeft(1). +// +// Deprecated: use [CUB1] instead. +const CursorLeft1 = CUB1 + +// CursorNextLine (CNL) returns a sequence for moving the cursor to the +// beginning of the next line n times. +// +// CSI n E +// +// See: https://vt100.net/docs/vt510-rm/CNL.html +func CursorNextLine(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "E" +} + +// CNL is an alias for [CursorNextLine]. +func CNL(n int) string { + return CursorNextLine(n) +} + +// CursorPreviousLine (CPL) returns a sequence for moving the cursor to the +// beginning of the previous line n times. +// +// CSI n F +// +// See: https://vt100.net/docs/vt510-rm/CPL.html +func CursorPreviousLine(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "F" +} + +// CPL is an alias for [CursorPreviousLine]. +func CPL(n int) string { + return CursorPreviousLine(n) +} + +// CursorHorizontalAbsolute (CHA) returns a sequence for moving the cursor to +// the given column. +// +// Default is 1. +// +// CSI n G +// +// See: https://vt100.net/docs/vt510-rm/CHA.html +func CursorHorizontalAbsolute(col int) string { + var s string + if col > 0 { + s = strconv.Itoa(col) + } + return "\x1b[" + s + "G" +} + +// CHA is an alias for [CursorHorizontalAbsolute]. +func CHA(col int) string { + return CursorHorizontalAbsolute(col) +} + +// CursorPosition (CUP) returns a sequence for setting the cursor to the +// given row and column. +// +// Default is 1,1. +// +// CSI n ; m H +// +// See: https://vt100.net/docs/vt510-rm/CUP.html +func CursorPosition(col, row int) string { + if row <= 0 && col <= 0 { + return CursorHomePosition + } + + var r, c string + if row > 0 { + r = strconv.Itoa(row) + } + if col > 0 { + c = strconv.Itoa(col) + } + return "\x1b[" + r + ";" + c + "H" +} + +// CUP is an alias for [CursorPosition]. +func CUP(col, row int) string { + return CursorPosition(col, row) +} + +// CursorHomePosition is a sequence for moving the cursor to the upper left +// corner of the scrolling region. This is equivalent to `CursorPosition(1, 1)`. +const CursorHomePosition = "\x1b[H" + +// SetCursorPosition (CUP) returns a sequence for setting the cursor to the +// given row and column. +// +// CSI n ; m H +// +// See: https://vt100.net/docs/vt510-rm/CUP.html +// +// Deprecated: use [CursorPosition] instead. +func SetCursorPosition(col, row int) string { + if row <= 0 && col <= 0 { + return HomeCursorPosition + } + + var r, c string + if row > 0 { + r = strconv.Itoa(row) + } + if col > 0 { + c = strconv.Itoa(col) + } + return "\x1b[" + r + ";" + c + "H" +} + +// HomeCursorPosition is a sequence for moving the cursor to the upper left +// corner of the scrolling region. This is equivalent to `SetCursorPosition(1, 1)`. +// +// Deprecated: use [CursorHomePosition] instead. +const HomeCursorPosition = CursorHomePosition + +// MoveCursor (CUP) returns a sequence for setting the cursor to the +// given row and column. +// +// CSI n ; m H +// +// See: https://vt100.net/docs/vt510-rm/CUP.html +// +// Deprecated: use [CursorPosition] instead. +func MoveCursor(col, row int) string { + return SetCursorPosition(col, row) +} + +// CursorOrigin is a sequence for moving the cursor to the upper left corner of +// the display. This is equivalent to `SetCursorPosition(1, 1)`. +// +// Deprecated: use [CursorHomePosition] instead. +const CursorOrigin = "\x1b[1;1H" + +// MoveCursorOrigin is a sequence for moving the cursor to the upper left +// corner of the display. This is equivalent to `SetCursorPosition(1, 1)`. +// +// Deprecated: use [CursorHomePosition] instead. +const MoveCursorOrigin = CursorOrigin + +// CursorHorizontalForwardTab (CHT) returns a sequence for moving the cursor to +// the next tab stop n times. +// +// Default is 1. +// +// CSI n I +// +// See: https://vt100.net/docs/vt510-rm/CHT.html +func CursorHorizontalForwardTab(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "I" +} + +// CHT is an alias for [CursorHorizontalForwardTab]. +func CHT(n int) string { + return CursorHorizontalForwardTab(n) +} + +// EraseCharacter (ECH) returns a sequence for erasing n characters from the +// screen. This doesn't affect other cell attributes. +// +// Default is 1. +// +// CSI n X +// +// See: https://vt100.net/docs/vt510-rm/ECH.html +func EraseCharacter(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "X" +} + +// ECH is an alias for [EraseCharacter]. +func ECH(n int) string { + return EraseCharacter(n) +} + +// CursorBackwardTab (CBT) returns a sequence for moving the cursor to the +// previous tab stop n times. +// +// Default is 1. +// +// CSI n Z +// +// See: https://vt100.net/docs/vt510-rm/CBT.html +func CursorBackwardTab(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "Z" +} + +// CBT is an alias for [CursorBackwardTab]. +func CBT(n int) string { + return CursorBackwardTab(n) +} + +// VerticalPositionAbsolute (VPA) returns a sequence for moving the cursor to +// the given row. +// +// Default is 1. +// +// CSI n d +// +// See: https://vt100.net/docs/vt510-rm/VPA.html +func VerticalPositionAbsolute(row int) string { + var s string + if row > 0 { + s = strconv.Itoa(row) + } + return "\x1b[" + s + "d" +} + +// VPA is an alias for [VerticalPositionAbsolute]. +func VPA(row int) string { + return VerticalPositionAbsolute(row) +} + +// VerticalPositionRelative (VPR) returns a sequence for moving the cursor down +// n rows relative to the current position. +// +// Default is 1. +// +// CSI n e +// +// See: https://vt100.net/docs/vt510-rm/VPR.html +func VerticalPositionRelative(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "e" +} + +// VPR is an alias for [VerticalPositionRelative]. +func VPR(n int) string { + return VerticalPositionRelative(n) +} + +// HorizontalVerticalPosition (HVP) returns a sequence for moving the cursor to +// the given row and column. +// +// Default is 1,1. +// +// CSI n ; m f +// +// This has the same effect as [CursorPosition]. +// +// See: https://vt100.net/docs/vt510-rm/HVP.html +func HorizontalVerticalPosition(col, row int) string { + var r, c string + if row > 0 { + r = strconv.Itoa(row) + } + if col > 0 { + c = strconv.Itoa(col) + } + return "\x1b[" + r + ";" + c + "f" +} + +// HVP is an alias for [HorizontalVerticalPosition]. +func HVP(col, row int) string { + return HorizontalVerticalPosition(col, row) +} + +// HorizontalVerticalHomePosition is a sequence for moving the cursor to the +// upper left corner of the scrolling region. This is equivalent to +// `HorizontalVerticalPosition(1, 1)`. +const HorizontalVerticalHomePosition = "\x1b[f" + +// SaveCurrentCursorPosition (SCOSC) is a sequence for saving the current cursor +// position for SCO console mode. +// +// CSI s +// +// This acts like [DECSC], except the page number where the cursor is located +// is not saved. +// +// See: https://vt100.net/docs/vt510-rm/SCOSC.html +const ( + SaveCurrentCursorPosition = "\x1b[s" + SCOSC = SaveCurrentCursorPosition +) + +// SaveCursorPosition (SCP or SCOSC) is a sequence for saving the cursor +// position. +// +// CSI s +// +// This acts like Save, except the page number where the cursor is located is +// not saved. +// +// See: https://vt100.net/docs/vt510-rm/SCOSC.html +// +// Deprecated: use [SaveCurrentCursorPosition] instead. +const SaveCursorPosition = "\x1b[s" + +// RestoreCurrentCursorPosition (SCORC) is a sequence for restoring the current +// cursor position for SCO console mode. +// +// CSI u +// +// This acts like [DECRC], except the page number where the cursor was saved is +// not restored. +// +// See: https://vt100.net/docs/vt510-rm/SCORC.html +const ( + RestoreCurrentCursorPosition = "\x1b[u" + SCORC = RestoreCurrentCursorPosition +) + +// RestoreCursorPosition (RCP or SCORC) is a sequence for restoring the cursor +// position. +// +// CSI u +// +// This acts like Restore, except the cursor stays on the same page where the +// cursor was saved. +// +// See: https://vt100.net/docs/vt510-rm/SCORC.html +// +// Deprecated: use [RestoreCurrentCursorPosition] instead. +const RestoreCursorPosition = "\x1b[u" + +// SetCursorStyle (DECSCUSR) returns a sequence for changing the cursor style. +// +// Default is 1. +// +// CSI Ps SP q +// +// Where Ps is the cursor style: +// +// 0: Blinking block +// 1: Blinking block (default) +// 2: Steady block +// 3: Blinking underline +// 4: Steady underline +// 5: Blinking bar (xterm) +// 6: Steady bar (xterm) +// +// See: https://vt100.net/docs/vt510-rm/DECSCUSR.html +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Functions-using-CSI-_-ordered-by-the-final-character-lparen-s-rparen:CSI-Ps-SP-q.1D81 +func SetCursorStyle(style int) string { + if style < 0 { + style = 0 + } + return "\x1b[" + strconv.Itoa(style) + " q" +} + +// DECSCUSR is an alias for [SetCursorStyle]. +func DECSCUSR(style int) string { + return SetCursorStyle(style) +} + +// SetPointerShape returns a sequence for changing the mouse pointer cursor +// shape. Use "default" for the default pointer shape. +// +// OSC 22 ; Pt ST +// OSC 22 ; Pt BEL +// +// Where Pt is the pointer shape name. The name can be anything that the +// operating system can understand. Some common names are: +// +// - copy +// - crosshair +// - default +// - ew-resize +// - n-resize +// - text +// - wait +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Operating-System-Commands +func SetPointerShape(shape string) string { + return "\x1b]22;" + shape + "\x07" +} + +// ReverseIndex (RI) is an escape sequence for moving the cursor up one line in +// the same column. If the cursor is at the top margin, the screen scrolls +// down. +// +// This has the same effect as [RI]. +const ReverseIndex = "\x1bM" + +// HorizontalPositionAbsolute (HPA) returns a sequence for moving the cursor to +// the given column. This has the same effect as [CUP]. +// +// Default is 1. +// +// CSI n \` +// +// See: https://vt100.net/docs/vt510-rm/HPA.html +func HorizontalPositionAbsolute(col int) string { + var s string + if col > 0 { + s = strconv.Itoa(col) + } + return "\x1b[" + s + "`" +} + +// HPA is an alias for [HorizontalPositionAbsolute]. +func HPA(col int) string { + return HorizontalPositionAbsolute(col) +} + +// HorizontalPositionRelative (HPR) returns a sequence for moving the cursor +// right n columns relative to the current position. This has the same effect +// as [CUP]. +// +// Default is 1. +// +// CSI n a +// +// See: https://vt100.net/docs/vt510-rm/HPR.html +func HorizontalPositionRelative(n int) string { + var s string + if n > 0 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "a" +} + +// HPR is an alias for [HorizontalPositionRelative]. +func HPR(n int) string { + return HorizontalPositionRelative(n) +} + +// Index (IND) is an escape sequence for moving the cursor down one line in the +// same column. If the cursor is at the bottom margin, the screen scrolls up. +// This has the same effect as [IND]. +const Index = "\x1bD" diff --git a/vendor/github.com/charmbracelet/x/ansi/cwd.go b/vendor/github.com/charmbracelet/x/ansi/cwd.go new file mode 100644 index 000000000..b03ac1bb9 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/cwd.go @@ -0,0 +1,26 @@ +package ansi + +import ( + "net/url" + "path" +) + +// NotifyWorkingDirectory returns a sequence that notifies the terminal +// of the current working directory. +// +// OSC 7 ; Pt BEL +// +// Where Pt is a URL in the format "file://[host]/[path]". +// Set host to "localhost" if this is a path on the local computer. +// +// See: https://wezfurlong.org/wezterm/shell-integration.html#osc-7-escape-sequence-to-set-the-working-directory +// See: https://iterm2.com/documentation-escape-codes.html#:~:text=RemoteHost%20and%20CurrentDir%3A-,OSC%207,-%3B%20%5BPs%5D%20ST +func NotifyWorkingDirectory(host string, paths ...string) string { + path := path.Join(paths...) + u := &url.URL{ + Scheme: "file", + Host: host, + Path: path, + } + return "\x1b]7;" + u.String() + "\x07" +} diff --git a/vendor/github.com/charmbracelet/x/ansi/doc.go b/vendor/github.com/charmbracelet/x/ansi/doc.go new file mode 100644 index 000000000..e955e9f1b --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/doc.go @@ -0,0 +1,7 @@ +// Package ansi defines common ANSI escape sequences based on the ECMA-48 +// specs. +// +// All sequences use 7-bit C1 control codes, which are supported by most +// terminal emulators. OSC sequences are terminated by a BEL for wider +// compatibility with terminals. +package ansi diff --git a/vendor/github.com/charmbracelet/x/ansi/finalterm.go b/vendor/github.com/charmbracelet/x/ansi/finalterm.go new file mode 100644 index 000000000..2c2834728 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/finalterm.go @@ -0,0 +1,67 @@ +package ansi + +import "strings" + +// FinalTerm returns an escape sequence that is used for shell integrations. +// Originally, FinalTerm designed the protocol hence the name. +// +// OSC 133 ; Ps ; Pm ST +// OSC 133 ; Ps ; Pm BEL +// +// See: https://iterm2.com/documentation-shell-integration.html +func FinalTerm(pm ...string) string { + return "\x1b]133;" + strings.Join(pm, ";") + "\x07" +} + +// FinalTermPrompt returns an escape sequence that is used for shell +// integrations prompt marks. This is sent just before the start of the shell +// prompt. +// +// This is an alias for FinalTerm("A"). +func FinalTermPrompt(pm ...string) string { + if len(pm) == 0 { + return FinalTerm("A") + } + return FinalTerm(append([]string{"A"}, pm...)...) +} + +// FinalTermCmdStart returns an escape sequence that is used for shell +// integrations command start marks. This is sent just after the end of the +// shell prompt, before the user enters a command. +// +// This is an alias for FinalTerm("B"). +func FinalTermCmdStart(pm ...string) string { + if len(pm) == 0 { + return FinalTerm("B") + } + return FinalTerm(append([]string{"B"}, pm...)...) +} + +// FinalTermCmdExecuted returns an escape sequence that is used for shell +// integrations command executed marks. This is sent just before the start of +// the command output. +// +// This is an alias for FinalTerm("C"). +func FinalTermCmdExecuted(pm ...string) string { + if len(pm) == 0 { + return FinalTerm("C") + } + return FinalTerm(append([]string{"C"}, pm...)...) +} + +// FinalTermCmdFinished returns an escape sequence that is used for shell +// integrations command finished marks. +// +// If the command was sent after +// [FinalTermCmdStart], it indicates that the command was aborted. If the +// command was sent after [FinalTermCmdExecuted], it indicates the end of the +// command output. If neither was sent, [FinalTermCmdFinished] should be +// ignored. +// +// This is an alias for FinalTerm("D"). +func FinalTermCmdFinished(pm ...string) string { + if len(pm) == 0 { + return FinalTerm("D") + } + return FinalTerm(append([]string{"D"}, pm...)...) +} diff --git a/vendor/github.com/charmbracelet/x/ansi/focus.go b/vendor/github.com/charmbracelet/x/ansi/focus.go new file mode 100644 index 000000000..4e0207ceb --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/focus.go @@ -0,0 +1,9 @@ +package ansi + +// Focus is an escape sequence to notify the terminal that it has focus. +// This is used with [FocusEventMode]. +const Focus = "\x1b[I" + +// Blur is an escape sequence to notify the terminal that it has lost focus. +// This is used with [FocusEventMode]. +const Blur = "\x1b[O" diff --git a/vendor/github.com/charmbracelet/x/ansi/graphics.go b/vendor/github.com/charmbracelet/x/ansi/graphics.go new file mode 100644 index 000000000..d4a693b72 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/graphics.go @@ -0,0 +1,62 @@ +package ansi + +import ( + "bytes" + "strconv" + "strings" +) + +// SixelGraphics returns a sequence that encodes the given sixel image payload to +// a DCS sixel sequence. +// +// DCS p1; p2; p3; q [sixel payload] ST +// +// p1 = pixel aspect ratio, deprecated and replaced by pixel metrics in the payload +// +// p2 = This is supposed to be 0 for transparency, but terminals don't seem to +// to use it properly. Value 0 leaves an unsightly black bar on all terminals +// I've tried and looks correct with value 1. +// +// p3 = Horizontal grid size parameter. Everyone ignores this and uses a fixed grid +// size, as far as I can tell. +// +// See https://shuford.invisible-island.net/all_about_sixels.txt +func SixelGraphics(p1, p2, p3 int, payload []byte) string { + var buf bytes.Buffer + + buf.WriteString("\x1bP") + if p1 >= 0 { + buf.WriteString(strconv.Itoa(p1)) + } + buf.WriteByte(';') + if p2 >= 0 { + buf.WriteString(strconv.Itoa(p2)) + } + if p3 > 0 { + buf.WriteByte(';') + buf.WriteString(strconv.Itoa(p3)) + } + buf.WriteByte('q') + buf.Write(payload) + buf.WriteString("\x1b\\") + + return buf.String() +} + +// KittyGraphics returns a sequence that encodes the given image in the Kitty +// graphics protocol. +// +// APC G [comma separated options] ; [base64 encoded payload] ST +// +// See https://sw.kovidgoyal.net/kitty/graphics-protocol/ +func KittyGraphics(payload []byte, opts ...string) string { + var buf bytes.Buffer + buf.WriteString("\x1b_G") + buf.WriteString(strings.Join(opts, ",")) + if len(payload) > 0 { + buf.WriteString(";") + buf.Write(payload) + } + buf.WriteString("\x1b\\") + return buf.String() +} diff --git a/vendor/github.com/charmbracelet/x/ansi/hyperlink.go b/vendor/github.com/charmbracelet/x/ansi/hyperlink.go new file mode 100644 index 000000000..323bfe932 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/hyperlink.go @@ -0,0 +1,28 @@ +package ansi + +import "strings" + +// SetHyperlink returns a sequence for starting a hyperlink. +// +// OSC 8 ; Params ; Uri ST +// OSC 8 ; Params ; Uri BEL +// +// To reset the hyperlink, omit the URI. +// +// See: https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda +func SetHyperlink(uri string, params ...string) string { + var p string + if len(params) > 0 { + p = strings.Join(params, ":") + } + return "\x1b]8;" + p + ";" + uri + "\x07" +} + +// ResetHyperlink returns a sequence for resetting the hyperlink. +// +// This is equivalent to SetHyperlink("", params...). +// +// See: https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda +func ResetHyperlink(params ...string) string { + return SetHyperlink("", params...) +} diff --git a/vendor/github.com/charmbracelet/x/ansi/iterm2.go b/vendor/github.com/charmbracelet/x/ansi/iterm2.go new file mode 100644 index 000000000..0ecb336da --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/iterm2.go @@ -0,0 +1,18 @@ +package ansi + +import "fmt" + +// ITerm2 returns a sequence that uses the iTerm2 proprietary protocol. Use the +// iterm2 package for a more convenient API. +// +// OSC 1337 ; key = value ST +// +// Example: +// +// ITerm2(iterm2.File{...}) +// +// See https://iterm2.com/documentation-escape-codes.html +// See https://iterm2.com/documentation-images.html +func ITerm2(data any) string { + return "\x1b]1337;" + fmt.Sprint(data) + "\x07" +} diff --git a/vendor/github.com/charmbracelet/x/ansi/keypad.go b/vendor/github.com/charmbracelet/x/ansi/keypad.go new file mode 100644 index 000000000..9183c6a7e --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/keypad.go @@ -0,0 +1,28 @@ +package ansi + +// Keypad Application Mode (DECKPAM) is a mode that determines whether the +// keypad sends application sequences or ANSI sequences. +// +// This works like enabling [DECNKM]. +// Use [NumericKeypadMode] to set the numeric keypad mode. +// +// ESC = +// +// See: https://vt100.net/docs/vt510-rm/DECKPAM.html +const ( + KeypadApplicationMode = "\x1b=" + DECKPAM = KeypadApplicationMode +) + +// Keypad Numeric Mode (DECKPNM) is a mode that determines whether the keypad +// sends application sequences or ANSI sequences. +// +// This works the same as disabling [DECNKM]. +// +// ESC > +// +// See: https://vt100.net/docs/vt510-rm/DECKPNM.html +const ( + KeypadNumericMode = "\x1b>" + DECKPNM = KeypadNumericMode +) diff --git a/vendor/github.com/charmbracelet/x/ansi/kitty.go b/vendor/github.com/charmbracelet/x/ansi/kitty.go new file mode 100644 index 000000000..124ab839e --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/kitty.go @@ -0,0 +1,90 @@ +package ansi + +import "strconv" + +// Kitty keyboard protocol progressive enhancement flags. +// See: https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement +const ( + KittyDisambiguateEscapeCodes = 1 << iota + KittyReportEventTypes + KittyReportAlternateKeys + KittyReportAllKeysAsEscapeCodes + KittyReportAssociatedKeys + + KittyAllFlags = KittyDisambiguateEscapeCodes | KittyReportEventTypes | + KittyReportAlternateKeys | KittyReportAllKeysAsEscapeCodes | KittyReportAssociatedKeys +) + +// RequestKittyKeyboard is a sequence to request the terminal Kitty keyboard +// protocol enabled flags. +// +// See: https://sw.kovidgoyal.net/kitty/keyboard-protocol/ +const RequestKittyKeyboard = "\x1b[?u" + +// KittyKeyboard returns a sequence to request keyboard enhancements from the terminal. +// The flags argument is a bitmask of the Kitty keyboard protocol flags. While +// mode specifies how the flags should be interpreted. +// +// Possible values for flags mask: +// +// 1: Disambiguate escape codes +// 2: Report event types +// 4: Report alternate keys +// 8: Report all keys as escape codes +// 16: Report associated text +// +// Possible values for mode: +// +// 1: Set given flags and unset all others +// 2: Set given flags and keep existing flags unchanged +// 3: Unset given flags and keep existing flags unchanged +// +// See https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement +func KittyKeyboard(flags, mode int) string { + return "\x1b[=" + strconv.Itoa(flags) + ";" + strconv.Itoa(mode) + "u" +} + +// PushKittyKeyboard returns a sequence to push the given flags to the terminal +// Kitty Keyboard stack. +// +// Possible values for flags mask: +// +// 0: Disable all features +// 1: Disambiguate escape codes +// 2: Report event types +// 4: Report alternate keys +// 8: Report all keys as escape codes +// 16: Report associated text +// +// CSI > flags u +// +// See https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement +func PushKittyKeyboard(flags int) string { + var f string + if flags > 0 { + f = strconv.Itoa(flags) + } + + return "\x1b[>" + f + "u" +} + +// DisableKittyKeyboard is a sequence to push zero into the terminal Kitty +// Keyboard stack to disable the protocol. +// +// This is equivalent to PushKittyKeyboard(0). +const DisableKittyKeyboard = "\x1b[>u" + +// PopKittyKeyboard returns a sequence to pop n number of flags from the +// terminal Kitty Keyboard stack. +// +// CSI < flags u +// +// See https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement +func PopKittyKeyboard(n int) string { + var num string + if n > 0 { + num = strconv.Itoa(n) + } + + return "\x1b[<" + num + "u" +} diff --git a/vendor/github.com/charmbracelet/x/ansi/method.go b/vendor/github.com/charmbracelet/x/ansi/method.go new file mode 100644 index 000000000..0218809c9 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/method.go @@ -0,0 +1,172 @@ +package ansi + +// Method is a type that represents the how the renderer should calculate the +// display width of cells. +type Method uint8 + +// Display width modes. +const ( + WcWidth Method = iota + GraphemeWidth +) + +// StringWidth returns the width of a string in cells. This is the number of +// cells that the string will occupy when printed in a terminal. ANSI escape +// codes are ignored and wide characters (such as East Asians and emojis) are +// accounted for. +func (m Method) StringWidth(s string) int { + return stringWidth(m, s) +} + +// Truncate truncates a string to a given length, adding a tail to the end if +// the string is longer than the given length. This function is aware of ANSI +// escape codes and will not break them, and accounts for wide-characters (such +// as East-Asian characters and emojis). +func (m Method) Truncate(s string, length int, tail string) string { + return truncate(m, s, length, tail) +} + +// TruncateLeft truncates a string to a given length, adding a prefix to the +// beginning if the string is longer than the given length. This function is +// aware of ANSI escape codes and will not break them, and accounts for +// wide-characters (such as East-Asian characters and emojis). +func (m Method) TruncateLeft(s string, length int, prefix string) string { + return truncateLeft(m, s, length, prefix) +} + +// Cut the string, without adding any prefix or tail strings. This function is +// aware of ANSI escape codes and will not break them, and accounts for +// wide-characters (such as East-Asian characters and emojis). Note that the +// [left] parameter is inclusive, while [right] isn't. +func (m Method) Cut(s string, left, right int) string { + return cut(m, s, left, right) +} + +// Hardwrap wraps a string or a block of text to a given line length, breaking +// word boundaries. This will preserve ANSI escape codes and will account for +// wide-characters in the string. +// When preserveSpace is true, spaces at the beginning of a line will be +// preserved. +// This treats the text as a sequence of graphemes. +func (m Method) Hardwrap(s string, length int, preserveSpace bool) string { + return hardwrap(m, s, length, preserveSpace) +} + +// Wordwrap wraps a string or a block of text to a given line length, not +// breaking word boundaries. This will preserve ANSI escape codes and will +// account for wide-characters in the string. +// The breakpoints string is a list of characters that are considered +// breakpoints for word wrapping. A hyphen (-) is always considered a +// breakpoint. +// +// Note: breakpoints must be a string of 1-cell wide rune characters. +func (m Method) Wordwrap(s string, length int, breakpoints string) string { + return wordwrap(m, s, length, breakpoints) +} + +// Wrap wraps a string or a block of text to a given line length, breaking word +// boundaries if necessary. This will preserve ANSI escape codes and will +// account for wide-characters in the string. The breakpoints string is a list +// of characters that are considered breakpoints for word wrapping. A hyphen +// (-) is always considered a breakpoint. +// +// Note: breakpoints must be a string of 1-cell wide rune characters. +func (m Method) Wrap(s string, length int, breakpoints string) string { + return wrap(m, s, length, breakpoints) +} + +// DecodeSequence decodes the first ANSI escape sequence or a printable +// grapheme from the given data. It returns the sequence slice, the number of +// bytes read, the cell width for each sequence, and the new state. +// +// The cell width will always be 0 for control and escape sequences, 1 for +// ASCII printable characters, and the number of cells other Unicode characters +// occupy. It uses the uniseg package to calculate the width of Unicode +// graphemes and characters. This means it will always do grapheme clustering +// (mode 2027). +// +// Passing a non-nil [*Parser] as the last argument will allow the decoder to +// collect sequence parameters, data, and commands. The parser cmd will have +// the packed command value that contains intermediate and prefix characters. +// In the case of a OSC sequence, the cmd will be the OSC command number. Use +// [Cmd] and [Param] types to unpack command intermediates and prefixes as well +// as parameters. +// +// Zero [Cmd] means the CSI, DCS, or ESC sequence is invalid. Moreover, checking the +// validity of other data sequences, OSC, DCS, etc, will require checking for +// the returned sequence terminator bytes such as ST (ESC \\) and BEL). +// +// We store the command byte in [Cmd] in the most significant byte, the +// prefix byte in the next byte, and the intermediate byte in the least +// significant byte. This is done to avoid using a struct to store the command +// and its intermediates and prefixes. The command byte is always the least +// significant byte i.e. [Cmd & 0xff]. Use the [Cmd] type to unpack the +// command, intermediate, and prefix bytes. Note that we only collect the last +// prefix character and intermediate byte. +// +// The [p.Params] slice will contain the parameters of the sequence. Any +// sub-parameter will have the [parser.HasMoreFlag] set. Use the [Param] type +// to unpack the parameters. +// +// Example: +// +// var state byte // the initial state is always zero [NormalState] +// p := NewParser(32, 1024) // create a new parser with a 32 params buffer and 1024 data buffer (optional) +// input := []byte("\x1b[31mHello, World!\x1b[0m") +// for len(input) > 0 { +// seq, width, n, newState := DecodeSequence(input, state, p) +// log.Printf("seq: %q, width: %d", seq, width) +// state = newState +// input = input[n:] +// } +func (m Method) DecodeSequence(data []byte, state byte, p *Parser) (seq []byte, width, n int, newState byte) { + return decodeSequence(m, data, state, p) +} + +// DecodeSequenceInString decodes the first ANSI escape sequence or a printable +// grapheme from the given data. It returns the sequence slice, the number of +// bytes read, the cell width for each sequence, and the new state. +// +// The cell width will always be 0 for control and escape sequences, 1 for +// ASCII printable characters, and the number of cells other Unicode characters +// occupy. It uses the uniseg package to calculate the width of Unicode +// graphemes and characters. This means it will always do grapheme clustering +// (mode 2027). +// +// Passing a non-nil [*Parser] as the last argument will allow the decoder to +// collect sequence parameters, data, and commands. The parser cmd will have +// the packed command value that contains intermediate and prefix characters. +// In the case of a OSC sequence, the cmd will be the OSC command number. Use +// [Cmd] and [Param] types to unpack command intermediates and prefixes as well +// as parameters. +// +// Zero [Cmd] means the CSI, DCS, or ESC sequence is invalid. Moreover, checking the +// validity of other data sequences, OSC, DCS, etc, will require checking for +// the returned sequence terminator bytes such as ST (ESC \\) and BEL). +// +// We store the command byte in [Cmd] in the most significant byte, the +// prefix byte in the next byte, and the intermediate byte in the least +// significant byte. This is done to avoid using a struct to store the command +// and its intermediates and prefixes. The command byte is always the least +// significant byte i.e. [Cmd & 0xff]. Use the [Cmd] type to unpack the +// command, intermediate, and prefix bytes. Note that we only collect the last +// prefix character and intermediate byte. +// +// The [p.Params] slice will contain the parameters of the sequence. Any +// sub-parameter will have the [parser.HasMoreFlag] set. Use the [Param] type +// to unpack the parameters. +// +// Example: +// +// var state byte // the initial state is always zero [NormalState] +// p := NewParser(32, 1024) // create a new parser with a 32 params buffer and 1024 data buffer (optional) +// input := []byte("\x1b[31mHello, World!\x1b[0m") +// for len(input) > 0 { +// seq, width, n, newState := DecodeSequenceInString(input, state, p) +// log.Printf("seq: %q, width: %d", seq, width) +// state = newState +// input = input[n:] +// } +func (m Method) DecodeSequenceInString(data string, state byte, p *Parser) (seq string, width, n int, newState byte) { + return decodeSequence(m, data, state, p) +} diff --git a/vendor/github.com/charmbracelet/x/ansi/mode.go b/vendor/github.com/charmbracelet/x/ansi/mode.go new file mode 100644 index 000000000..03c91108c --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/mode.go @@ -0,0 +1,847 @@ +package ansi + +import ( + "strconv" + "strings" +) + +// ModeSetting represents a mode setting. +type ModeSetting byte + +// ModeSetting constants. +const ( + ModeNotRecognized ModeSetting = iota + ModeSet + ModeReset + ModePermanentlySet + ModePermanentlyReset +) + +// IsNotRecognized returns true if the mode is not recognized. +func (m ModeSetting) IsNotRecognized() bool { + return m == ModeNotRecognized +} + +// IsSet returns true if the mode is set or permanently set. +func (m ModeSetting) IsSet() bool { + return m == ModeSet || m == ModePermanentlySet +} + +// IsReset returns true if the mode is reset or permanently reset. +func (m ModeSetting) IsReset() bool { + return m == ModeReset || m == ModePermanentlyReset +} + +// IsPermanentlySet returns true if the mode is permanently set. +func (m ModeSetting) IsPermanentlySet() bool { + return m == ModePermanentlySet +} + +// IsPermanentlyReset returns true if the mode is permanently reset. +func (m ModeSetting) IsPermanentlyReset() bool { + return m == ModePermanentlyReset +} + +// Mode represents an interface for terminal modes. +// Modes can be set, reset, and requested. +type Mode interface { + Mode() int +} + +// SetMode (SM) or (DECSET) returns a sequence to set a mode. +// The mode arguments are a list of modes to set. +// +// If one of the modes is a [DECMode], the function will returns two escape +// sequences. +// +// ANSI format: +// +// CSI Pd ; ... ; Pd h +// +// DEC format: +// +// CSI ? Pd ; ... ; Pd h +// +// See: https://vt100.net/docs/vt510-rm/SM.html +func SetMode(modes ...Mode) string { + return setMode(false, modes...) +} + +// SM is an alias for [SetMode]. +func SM(modes ...Mode) string { + return SetMode(modes...) +} + +// DECSET is an alias for [SetMode]. +func DECSET(modes ...Mode) string { + return SetMode(modes...) +} + +// ResetMode (RM) or (DECRST) returns a sequence to reset a mode. +// The mode arguments are a list of modes to reset. +// +// If one of the modes is a [DECMode], the function will returns two escape +// sequences. +// +// ANSI format: +// +// CSI Pd ; ... ; Pd l +// +// DEC format: +// +// CSI ? Pd ; ... ; Pd l +// +// See: https://vt100.net/docs/vt510-rm/RM.html +func ResetMode(modes ...Mode) string { + return setMode(true, modes...) +} + +// RM is an alias for [ResetMode]. +func RM(modes ...Mode) string { + return ResetMode(modes...) +} + +// DECRST is an alias for [ResetMode]. +func DECRST(modes ...Mode) string { + return ResetMode(modes...) +} + +func setMode(reset bool, modes ...Mode) (s string) { + if len(modes) == 0 { + return //nolint:nakedret + } + + cmd := "h" + if reset { + cmd = "l" + } + + seq := "\x1b[" + if len(modes) == 1 { + switch modes[0].(type) { + case DECMode: + seq += "?" + } + return seq + strconv.Itoa(modes[0].Mode()) + cmd + } + + dec := make([]string, 0, len(modes)/2) + ansi := make([]string, 0, len(modes)/2) + for _, m := range modes { + switch m.(type) { + case DECMode: + dec = append(dec, strconv.Itoa(m.Mode())) + case ANSIMode: + ansi = append(ansi, strconv.Itoa(m.Mode())) + } + } + + if len(ansi) > 0 { + s += seq + strings.Join(ansi, ";") + cmd + } + if len(dec) > 0 { + s += seq + "?" + strings.Join(dec, ";") + cmd + } + return //nolint:nakedret +} + +// RequestMode (DECRQM) returns a sequence to request a mode from the terminal. +// The terminal responds with a report mode function [DECRPM]. +// +// ANSI format: +// +// CSI Pa $ p +// +// DEC format: +// +// CSI ? Pa $ p +// +// See: https://vt100.net/docs/vt510-rm/DECRQM.html +func RequestMode(m Mode) string { + seq := "\x1b[" + switch m.(type) { + case DECMode: + seq += "?" + } + return seq + strconv.Itoa(m.Mode()) + "$p" +} + +// DECRQM is an alias for [RequestMode]. +func DECRQM(m Mode) string { + return RequestMode(m) +} + +// ReportMode (DECRPM) returns a sequence that the terminal sends to the host +// in response to a mode request [DECRQM]. +// +// ANSI format: +// +// CSI Pa ; Ps ; $ y +// +// DEC format: +// +// CSI ? Pa ; Ps $ y +// +// Where Pa is the mode number, and Ps is the mode value. +// +// 0: Not recognized +// 1: Set +// 2: Reset +// 3: Permanent set +// 4: Permanent reset +// +// See: https://vt100.net/docs/vt510-rm/DECRPM.html +func ReportMode(mode Mode, value ModeSetting) string { + if value > 4 { + value = 0 + } + switch mode.(type) { + case DECMode: + return "\x1b[?" + strconv.Itoa(mode.Mode()) + ";" + strconv.Itoa(int(value)) + "$y" + } + return "\x1b[" + strconv.Itoa(mode.Mode()) + ";" + strconv.Itoa(int(value)) + "$y" +} + +// DECRPM is an alias for [ReportMode]. +func DECRPM(mode Mode, value ModeSetting) string { + return ReportMode(mode, value) +} + +// ANSIMode represents an ANSI terminal mode. +type ANSIMode int //nolint:revive + +// Mode returns the ANSI mode as an integer. +func (m ANSIMode) Mode() int { + return int(m) +} + +// DECMode represents a private DEC terminal mode. +type DECMode int + +// Mode returns the DEC mode as an integer. +func (m DECMode) Mode() int { + return int(m) +} + +// Keyboard Action Mode (KAM) is a mode that controls locking of the keyboard. +// When the keyboard is locked, it cannot send data to the terminal. +// +// See: https://vt100.net/docs/vt510-rm/KAM.html +const ( + KeyboardActionMode = ANSIMode(2) + KAM = KeyboardActionMode + + SetKeyboardActionMode = "\x1b[2h" + ResetKeyboardActionMode = "\x1b[2l" + RequestKeyboardActionMode = "\x1b[2$p" +) + +// Insert/Replace Mode (IRM) is a mode that determines whether characters are +// inserted or replaced when typed. +// +// When enabled, characters are inserted at the cursor position pushing the +// characters to the right. When disabled, characters replace the character at +// the cursor position. +// +// See: https://vt100.net/docs/vt510-rm/IRM.html +const ( + InsertReplaceMode = ANSIMode(4) + IRM = InsertReplaceMode + + SetInsertReplaceMode = "\x1b[4h" + ResetInsertReplaceMode = "\x1b[4l" + RequestInsertReplaceMode = "\x1b[4$p" +) + +// BiDirectional Support Mode (BDSM) is a mode that determines whether the +// terminal supports bidirectional text. When enabled, the terminal supports +// bidirectional text and is set to implicit bidirectional mode. When disabled, +// the terminal does not support bidirectional text. +// +// See ECMA-48 7.2.1. +const ( + BiDirectionalSupportMode = ANSIMode(8) + BDSM = BiDirectionalSupportMode + + SetBiDirectionalSupportMode = "\x1b[8h" + ResetBiDirectionalSupportMode = "\x1b[8l" + RequestBiDirectionalSupportMode = "\x1b[8$p" +) + +// Send Receive Mode (SRM) or Local Echo Mode is a mode that determines whether +// the terminal echoes characters back to the host. When enabled, the terminal +// sends characters to the host as they are typed. +// +// See: https://vt100.net/docs/vt510-rm/SRM.html +const ( + SendReceiveMode = ANSIMode(12) + LocalEchoMode = SendReceiveMode + SRM = SendReceiveMode + + SetSendReceiveMode = "\x1b[12h" + ResetSendReceiveMode = "\x1b[12l" + RequestSendReceiveMode = "\x1b[12$p" + + SetLocalEchoMode = "\x1b[12h" + ResetLocalEchoMode = "\x1b[12l" + RequestLocalEchoMode = "\x1b[12$p" +) + +// Line Feed/New Line Mode (LNM) is a mode that determines whether the terminal +// interprets the line feed character as a new line. +// +// When enabled, the terminal interprets the line feed character as a new line. +// When disabled, the terminal interprets the line feed character as a line feed. +// +// A new line moves the cursor to the first position of the next line. +// A line feed moves the cursor down one line without changing the column +// scrolling the screen if necessary. +// +// See: https://vt100.net/docs/vt510-rm/LNM.html +const ( + LineFeedNewLineMode = ANSIMode(20) + LNM = LineFeedNewLineMode + + SetLineFeedNewLineMode = "\x1b[20h" + ResetLineFeedNewLineMode = "\x1b[20l" + RequestLineFeedNewLineMode = "\x1b[20$p" +) + +// Cursor Keys Mode (DECCKM) is a mode that determines whether the cursor keys +// send ANSI cursor sequences or application sequences. +// +// See: https://vt100.net/docs/vt510-rm/DECCKM.html +const ( + CursorKeysMode = DECMode(1) + DECCKM = CursorKeysMode + + SetCursorKeysMode = "\x1b[?1h" + ResetCursorKeysMode = "\x1b[?1l" + RequestCursorKeysMode = "\x1b[?1$p" +) + +// Deprecated: use [SetCursorKeysMode] and [ResetCursorKeysMode] instead. +const ( + EnableCursorKeys = "\x1b[?1h" //nolint:revive // grouped constants + DisableCursorKeys = "\x1b[?1l" +) + +// Origin Mode (DECOM) is a mode that determines whether the cursor moves to the +// home position or the margin position. +// +// See: https://vt100.net/docs/vt510-rm/DECOM.html +const ( + OriginMode = DECMode(6) + DECOM = OriginMode + + SetOriginMode = "\x1b[?6h" + ResetOriginMode = "\x1b[?6l" + RequestOriginMode = "\x1b[?6$p" +) + +// Auto Wrap Mode (DECAWM) is a mode that determines whether the cursor wraps +// to the next line when it reaches the right margin. +// +// See: https://vt100.net/docs/vt510-rm/DECAWM.html +const ( + AutoWrapMode = DECMode(7) + DECAWM = AutoWrapMode + + SetAutoWrapMode = "\x1b[?7h" + ResetAutoWrapMode = "\x1b[?7l" + RequestAutoWrapMode = "\x1b[?7$p" +) + +// X10 Mouse Mode is a mode that determines whether the mouse reports on button +// presses. +// +// The terminal responds with the following encoding: +// +// CSI M CbCxCy +// +// Where Cb is the button-1, where it can be 1, 2, or 3. +// Cx and Cy are the x and y coordinates of the mouse event. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking +const ( + X10MouseMode = DECMode(9) + + SetX10MouseMode = "\x1b[?9h" + ResetX10MouseMode = "\x1b[?9l" + RequestX10MouseMode = "\x1b[?9$p" +) + +// Text Cursor Enable Mode (DECTCEM) is a mode that shows/hides the cursor. +// +// See: https://vt100.net/docs/vt510-rm/DECTCEM.html +const ( + TextCursorEnableMode = DECMode(25) + DECTCEM = TextCursorEnableMode + + SetTextCursorEnableMode = "\x1b[?25h" + ResetTextCursorEnableMode = "\x1b[?25l" + RequestTextCursorEnableMode = "\x1b[?25$p" +) + +// These are aliases for [SetTextCursorEnableMode] and [ResetTextCursorEnableMode]. +const ( + ShowCursor = SetTextCursorEnableMode + HideCursor = ResetTextCursorEnableMode +) + +// Text Cursor Enable Mode (DECTCEM) is a mode that shows/hides the cursor. +// +// See: https://vt100.net/docs/vt510-rm/DECTCEM.html +// +// Deprecated: use [SetTextCursorEnableMode] and [ResetTextCursorEnableMode] instead. +const ( + CursorEnableMode = DECMode(25) + RequestCursorVisibility = "\x1b[?25$p" +) + +// Numeric Keypad Mode (DECNKM) is a mode that determines whether the keypad +// sends application sequences or numeric sequences. +// +// This works like [DECKPAM] and [DECKPNM], but uses different sequences. +// +// See: https://vt100.net/docs/vt510-rm/DECNKM.html +const ( + NumericKeypadMode = DECMode(66) + DECNKM = NumericKeypadMode + + SetNumericKeypadMode = "\x1b[?66h" + ResetNumericKeypadMode = "\x1b[?66l" + RequestNumericKeypadMode = "\x1b[?66$p" +) + +// Backarrow Key Mode (DECBKM) is a mode that determines whether the backspace +// key sends a backspace or delete character. Disabled by default. +// +// See: https://vt100.net/docs/vt510-rm/DECBKM.html +const ( + BackarrowKeyMode = DECMode(67) + DECBKM = BackarrowKeyMode + + SetBackarrowKeyMode = "\x1b[?67h" + ResetBackarrowKeyMode = "\x1b[?67l" + RequestBackarrowKeyMode = "\x1b[?67$p" +) + +// Left Right Margin Mode (DECLRMM) is a mode that determines whether the left +// and right margins can be set with [DECSLRM]. +// +// See: https://vt100.net/docs/vt510-rm/DECLRMM.html +const ( + LeftRightMarginMode = DECMode(69) + DECLRMM = LeftRightMarginMode + + SetLeftRightMarginMode = "\x1b[?69h" + ResetLeftRightMarginMode = "\x1b[?69l" + RequestLeftRightMarginMode = "\x1b[?69$p" +) + +// Normal Mouse Mode is a mode that determines whether the mouse reports on +// button presses and releases. It will also report modifier keys, wheel +// events, and extra buttons. +// +// It uses the same encoding as [X10MouseMode] with a few differences: +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking +const ( + NormalMouseMode = DECMode(1000) + + SetNormalMouseMode = "\x1b[?1000h" + ResetNormalMouseMode = "\x1b[?1000l" + RequestNormalMouseMode = "\x1b[?1000$p" +) + +// VT Mouse Tracking is a mode that determines whether the mouse reports on +// button press and release. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking +// +// Deprecated: use [NormalMouseMode] instead. +const ( + MouseMode = DECMode(1000) + + EnableMouse = "\x1b[?1000h" + DisableMouse = "\x1b[?1000l" + RequestMouse = "\x1b[?1000$p" +) + +// Highlight Mouse Tracking is a mode that determines whether the mouse reports +// on button presses, releases, and highlighted cells. +// +// It uses the same encoding as [NormalMouseMode] with a few differences: +// +// On highlight events, the terminal responds with the following encoding: +// +// CSI t CxCy +// CSI T CxCyCxCyCxCy +// +// Where the parameters are startx, starty, endx, endy, mousex, and mousey. +const ( + HighlightMouseMode = DECMode(1001) + + SetHighlightMouseMode = "\x1b[?1001h" + ResetHighlightMouseMode = "\x1b[?1001l" + RequestHighlightMouseMode = "\x1b[?1001$p" +) + +// VT Hilite Mouse Tracking is a mode that determines whether the mouse reports on +// button presses, releases, and highlighted cells. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking +// +// Deprecated: use [HighlightMouseMode] instead. +const ( + MouseHiliteMode = DECMode(1001) + + EnableMouseHilite = "\x1b[?1001h" + DisableMouseHilite = "\x1b[?1001l" + RequestMouseHilite = "\x1b[?1001$p" +) + +// Button Event Mouse Tracking is essentially the same as [NormalMouseMode], +// but it also reports button-motion events when a button is pressed. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking +const ( + ButtonEventMouseMode = DECMode(1002) + + SetButtonEventMouseMode = "\x1b[?1002h" + ResetButtonEventMouseMode = "\x1b[?1002l" + RequestButtonEventMouseMode = "\x1b[?1002$p" +) + +// Cell Motion Mouse Tracking is a mode that determines whether the mouse +// reports on button press, release, and motion events. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking +// +// Deprecated: use [ButtonEventMouseMode] instead. +const ( + MouseCellMotionMode = DECMode(1002) + + EnableMouseCellMotion = "\x1b[?1002h" + DisableMouseCellMotion = "\x1b[?1002l" + RequestMouseCellMotion = "\x1b[?1002$p" +) + +// Any Event Mouse Tracking is the same as [ButtonEventMouseMode], except that +// all motion events are reported even if no mouse buttons are pressed. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking +const ( + AnyEventMouseMode = DECMode(1003) + + SetAnyEventMouseMode = "\x1b[?1003h" + ResetAnyEventMouseMode = "\x1b[?1003l" + RequestAnyEventMouseMode = "\x1b[?1003$p" +) + +// All Mouse Tracking is a mode that determines whether the mouse reports on +// button press, release, motion, and highlight events. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking +// +// Deprecated: use [AnyEventMouseMode] instead. +const ( + MouseAllMotionMode = DECMode(1003) + + EnableMouseAllMotion = "\x1b[?1003h" + DisableMouseAllMotion = "\x1b[?1003l" + RequestMouseAllMotion = "\x1b[?1003$p" +) + +// Focus Event Mode is a mode that determines whether the terminal reports focus +// and blur events. +// +// The terminal sends the following encoding: +// +// CSI I // Focus In +// CSI O // Focus Out +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Focus-Tracking +const ( + FocusEventMode = DECMode(1004) + + SetFocusEventMode = "\x1b[?1004h" + ResetFocusEventMode = "\x1b[?1004l" + RequestFocusEventMode = "\x1b[?1004$p" +) + +// Deprecated: use [SetFocusEventMode], [ResetFocusEventMode], and +// [RequestFocusEventMode] instead. +// Focus reporting mode constants. +const ( + ReportFocusMode = DECMode(1004) //nolint:revive // grouped constants + + EnableReportFocus = "\x1b[?1004h" + DisableReportFocus = "\x1b[?1004l" + RequestReportFocus = "\x1b[?1004$p" +) + +// SGR Extended Mouse Mode is a mode that changes the mouse tracking encoding +// to use SGR parameters. +// +// The terminal responds with the following encoding: +// +// CSI < Cb ; Cx ; Cy M +// +// Where Cb is the same as [NormalMouseMode], and Cx and Cy are the x and y. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking +const ( + SgrExtMouseMode = DECMode(1006) + + SetSgrExtMouseMode = "\x1b[?1006h" + ResetSgrExtMouseMode = "\x1b[?1006l" + RequestSgrExtMouseMode = "\x1b[?1006$p" +) + +// Deprecated: use [SgrExtMouseMode] [SetSgrExtMouseMode], +// [ResetSgrExtMouseMode], and [RequestSgrExtMouseMode] instead. +const ( + MouseSgrExtMode = DECMode(1006) //nolint:revive // grouped constants + EnableMouseSgrExt = "\x1b[?1006h" + DisableMouseSgrExt = "\x1b[?1006l" + RequestMouseSgrExt = "\x1b[?1006$p" +) + +// UTF-8 Extended Mouse Mode is a mode that changes the mouse tracking encoding +// to use UTF-8 parameters. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking +const ( + Utf8ExtMouseMode = DECMode(1005) + + SetUtf8ExtMouseMode = "\x1b[?1005h" + ResetUtf8ExtMouseMode = "\x1b[?1005l" + RequestUtf8ExtMouseMode = "\x1b[?1005$p" +) + +// URXVT Extended Mouse Mode is a mode that changes the mouse tracking encoding +// to use an alternate encoding. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking +const ( + UrxvtExtMouseMode = DECMode(1015) + + SetUrxvtExtMouseMode = "\x1b[?1015h" + ResetUrxvtExtMouseMode = "\x1b[?1015l" + RequestUrxvtExtMouseMode = "\x1b[?1015$p" +) + +// SGR Pixel Extended Mouse Mode is a mode that changes the mouse tracking +// encoding to use SGR parameters with pixel coordinates. +// +// This is similar to [SgrExtMouseMode], but also reports pixel coordinates. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking +const ( + SgrPixelExtMouseMode = DECMode(1016) + + SetSgrPixelExtMouseMode = "\x1b[?1016h" + ResetSgrPixelExtMouseMode = "\x1b[?1016l" + RequestSgrPixelExtMouseMode = "\x1b[?1016$p" +) + +// Alternate Screen Mode is a mode that determines whether the alternate screen +// buffer is active. When this mode is enabled, the alternate screen buffer is +// cleared. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer +const ( + AltScreenMode = DECMode(1047) + + SetAltScreenMode = "\x1b[?1047h" + ResetAltScreenMode = "\x1b[?1047l" + RequestAltScreenMode = "\x1b[?1047$p" +) + +// Save Cursor Mode is a mode that saves the cursor position. +// This is equivalent to [SaveCursor] and [RestoreCursor]. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer +const ( + SaveCursorMode = DECMode(1048) + + SetSaveCursorMode = "\x1b[?1048h" + ResetSaveCursorMode = "\x1b[?1048l" + RequestSaveCursorMode = "\x1b[?1048$p" +) + +// Alternate Screen Save Cursor Mode is a mode that saves the cursor position as in +// [SaveCursorMode], switches to the alternate screen buffer as in [AltScreenMode], +// and clears the screen on switch. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer +const ( + AltScreenSaveCursorMode = DECMode(1049) + + SetAltScreenSaveCursorMode = "\x1b[?1049h" + ResetAltScreenSaveCursorMode = "\x1b[?1049l" + RequestAltScreenSaveCursorMode = "\x1b[?1049$p" +) + +// Alternate Screen Buffer is a mode that determines whether the alternate screen +// buffer is active. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer +// +// Deprecated: use [AltScreenSaveCursorMode] instead. +const ( + AltScreenBufferMode = DECMode(1049) + + SetAltScreenBufferMode = "\x1b[?1049h" + ResetAltScreenBufferMode = "\x1b[?1049l" + RequestAltScreenBufferMode = "\x1b[?1049$p" + + EnableAltScreenBuffer = "\x1b[?1049h" + DisableAltScreenBuffer = "\x1b[?1049l" + RequestAltScreenBuffer = "\x1b[?1049$p" +) + +// Bracketed Paste Mode is a mode that determines whether pasted text is +// bracketed with escape sequences. +// +// See: https://cirw.in/blog/bracketed-paste +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Bracketed-Paste-Mode +const ( + BracketedPasteMode = DECMode(2004) + + SetBracketedPasteMode = "\x1b[?2004h" + ResetBracketedPasteMode = "\x1b[?2004l" + RequestBracketedPasteMode = "\x1b[?2004$p" +) + +// Deprecated: use [SetBracketedPasteMode], [ResetBracketedPasteMode], and +// [RequestBracketedPasteMode] instead. +const ( + EnableBracketedPaste = "\x1b[?2004h" //nolint:revive // grouped constants + DisableBracketedPaste = "\x1b[?2004l" + RequestBracketedPaste = "\x1b[?2004$p" +) + +// Synchronized Output Mode is a mode that determines whether output is +// synchronized with the terminal. +// +// See: https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036 +const ( + SynchronizedOutputMode = DECMode(2026) + + SetSynchronizedOutputMode = "\x1b[?2026h" + ResetSynchronizedOutputMode = "\x1b[?2026l" + RequestSynchronizedOutputMode = "\x1b[?2026$p" +) + +// Synchronized Output Mode. See [SynchronizedOutputMode]. +// +// Deprecated: use [SynchronizedOutputMode], [SetSynchronizedOutputMode], and +// [ResetSynchronizedOutputMode], and [RequestSynchronizedOutputMode] instead. +const ( + SyncdOutputMode = DECMode(2026) + + EnableSyncdOutput = "\x1b[?2026h" + DisableSyncdOutput = "\x1b[?2026l" + RequestSyncdOutput = "\x1b[?2026$p" +) + +// Unicode Core Mode is a mode that determines whether the terminal should use +// Unicode grapheme clustering to calculate the width of glyphs for each +// terminal cell. +// +// See: https://github.com/contour-terminal/terminal-unicode-core +const ( + UnicodeCoreMode = DECMode(2027) + + SetUnicodeCoreMode = "\x1b[?2027h" + ResetUnicodeCoreMode = "\x1b[?2027l" + RequestUnicodeCoreMode = "\x1b[?2027$p" +) + +// Grapheme Clustering Mode is a mode that determines whether the terminal +// should look for grapheme clusters instead of single runes in the rendered +// text. This makes the terminal properly render combining characters such as +// emojis. +// +// See: https://github.com/contour-terminal/terminal-unicode-core +// +// Deprecated: use [GraphemeClusteringMode], [SetUnicodeCoreMode], +// [ResetUnicodeCoreMode], and [RequestUnicodeCoreMode] instead. +const ( + GraphemeClusteringMode = DECMode(2027) + + SetGraphemeClusteringMode = "\x1b[?2027h" + ResetGraphemeClusteringMode = "\x1b[?2027l" + RequestGraphemeClusteringMode = "\x1b[?2027$p" +) + +// Grapheme Clustering Mode. See [GraphemeClusteringMode]. +// +// Deprecated: use [SetUnicodeCoreMode], [ResetUnicodeCoreMode], and +// [RequestUnicodeCoreMode] instead. +const ( + EnableGraphemeClustering = "\x1b[?2027h" + DisableGraphemeClustering = "\x1b[?2027l" + RequestGraphemeClustering = "\x1b[?2027$p" +) + +// LightDarkMode is a mode that enables reporting the operating system's color +// scheme (light or dark) preference. It reports the color scheme as a [DSR] +// and [LightDarkReport] escape sequences encoded as follows: +// +// CSI ? 997 ; 1 n for dark mode +// CSI ? 997 ; 2 n for light mode +// +// The color preference can also be requested via the following [DSR] and +// [RequestLightDarkReport] escape sequences: +// +// CSI ? 996 n +// +// See: https://contour-terminal.org/vt-extensions/color-palette-update-notifications/ +const ( + LightDarkMode = DECMode(2031) + + SetLightDarkMode = "\x1b[?2031h" + ResetLightDarkMode = "\x1b[?2031l" + RequestLightDarkMode = "\x1b[?2031$p" +) + +// InBandResizeMode is a mode that reports terminal resize events as escape +// sequences. This is useful for systems that do not support [SIGWINCH] like +// Windows. +// +// The terminal then sends the following encoding: +// +// CSI 48 ; cellsHeight ; cellsWidth ; pixelHeight ; pixelWidth t +// +// See: https://gist.github.com/rockorager/e695fb2924d36b2bcf1fff4a3704bd83 +const ( + InBandResizeMode = DECMode(2048) + + SetInBandResizeMode = "\x1b[?2048h" + ResetInBandResizeMode = "\x1b[?2048l" + RequestInBandResizeMode = "\x1b[?2048$p" +) + +// Win32Input is a mode that determines whether input is processed by the +// Win32 console and Conpty. +// +// See: https://github.com/microsoft/terminal/blob/main/doc/specs/%234999%20-%20Improved%20keyboard%20handling%20in%20Conpty.md +const ( + Win32InputMode = DECMode(9001) + + SetWin32InputMode = "\x1b[?9001h" + ResetWin32InputMode = "\x1b[?9001l" + RequestWin32InputMode = "\x1b[?9001$p" +) + +// Deprecated: use [SetWin32InputMode], [ResetWin32InputMode], and +// [RequestWin32InputMode] instead. +const ( + EnableWin32Input = "\x1b[?9001h" //nolint:revive // grouped constants + DisableWin32Input = "\x1b[?9001l" + RequestWin32Input = "\x1b[?9001$p" +) diff --git a/vendor/github.com/charmbracelet/x/ansi/modes.go b/vendor/github.com/charmbracelet/x/ansi/modes.go new file mode 100644 index 000000000..6856d35e4 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/modes.go @@ -0,0 +1,65 @@ +package ansi + +// Modes represents the terminal modes that can be set or reset. By default, +// all modes are [ModeNotRecognized]. +type Modes map[Mode]ModeSetting + +// Get returns the setting of a terminal mode. If the mode is not set, it +// returns [ModeNotRecognized]. +func (m Modes) Get(mode Mode) ModeSetting { + return m[mode] +} + +// Delete deletes a terminal mode. This has the same effect as setting the mode +// to [ModeNotRecognized]. +func (m Modes) Delete(mode Mode) { + delete(m, mode) +} + +// Set sets a terminal mode to [ModeSet]. +func (m Modes) Set(modes ...Mode) { + for _, mode := range modes { + m[mode] = ModeSet + } +} + +// PermanentlySet sets a terminal mode to [ModePermanentlySet]. +func (m Modes) PermanentlySet(modes ...Mode) { + for _, mode := range modes { + m[mode] = ModePermanentlySet + } +} + +// Reset sets a terminal mode to [ModeReset]. +func (m Modes) Reset(modes ...Mode) { + for _, mode := range modes { + m[mode] = ModeReset + } +} + +// PermanentlyReset sets a terminal mode to [ModePermanentlyReset]. +func (m Modes) PermanentlyReset(modes ...Mode) { + for _, mode := range modes { + m[mode] = ModePermanentlyReset + } +} + +// IsSet returns true if the mode is set to [ModeSet] or [ModePermanentlySet]. +func (m Modes) IsSet(mode Mode) bool { + return m[mode].IsSet() +} + +// IsPermanentlySet returns true if the mode is set to [ModePermanentlySet]. +func (m Modes) IsPermanentlySet(mode Mode) bool { + return m[mode].IsPermanentlySet() +} + +// IsReset returns true if the mode is set to [ModeReset] or [ModePermanentlyReset]. +func (m Modes) IsReset(mode Mode) bool { + return m[mode].IsReset() +} + +// IsPermanentlyReset returns true if the mode is set to [ModePermanentlyReset]. +func (m Modes) IsPermanentlyReset(mode Mode) bool { + return m[mode].IsPermanentlyReset() +} diff --git a/vendor/github.com/charmbracelet/x/ansi/mouse.go b/vendor/github.com/charmbracelet/x/ansi/mouse.go new file mode 100644 index 000000000..0e4776bb2 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/mouse.go @@ -0,0 +1,172 @@ +package ansi + +import ( + "fmt" +) + +// MouseButton represents the button that was pressed during a mouse message. +type MouseButton byte + +// Mouse event buttons +// +// This is based on X11 mouse button codes. +// +// 1 = left button +// 2 = middle button (pressing the scroll wheel) +// 3 = right button +// 4 = turn scroll wheel up +// 5 = turn scroll wheel down +// 6 = push scroll wheel left +// 7 = push scroll wheel right +// 8 = 4th button (aka browser backward button) +// 9 = 5th button (aka browser forward button) +// 10 +// 11 +// +// Other buttons are not supported. +const ( + MouseNone MouseButton = iota + MouseButton1 + MouseButton2 + MouseButton3 + MouseButton4 + MouseButton5 + MouseButton6 + MouseButton7 + MouseButton8 + MouseButton9 + MouseButton10 + MouseButton11 + + MouseLeft = MouseButton1 + MouseMiddle = MouseButton2 + MouseRight = MouseButton3 + MouseWheelUp = MouseButton4 + MouseWheelDown = MouseButton5 + MouseWheelLeft = MouseButton6 + MouseWheelRight = MouseButton7 + MouseBackward = MouseButton8 + MouseForward = MouseButton9 + MouseRelease = MouseNone +) + +var mouseButtons = map[MouseButton]string{ + MouseNone: "none", + MouseLeft: "left", + MouseMiddle: "middle", + MouseRight: "right", + MouseWheelUp: "wheelup", + MouseWheelDown: "wheeldown", + MouseWheelLeft: "wheelleft", + MouseWheelRight: "wheelright", + MouseBackward: "backward", + MouseForward: "forward", + MouseButton10: "button10", + MouseButton11: "button11", +} + +// String returns a string representation of the mouse button. +func (b MouseButton) String() string { + return mouseButtons[b] +} + +// EncodeMouseButton returns a byte representing a mouse button. +// The button is a bitmask of the following leftmost values: +// +// - The first two bits are the button number: +// 0 = left button, wheel up, or button no. 8 aka (backwards) +// 1 = middle button, wheel down, or button no. 9 aka (forwards) +// 2 = right button, wheel left, or button no. 10 +// 3 = release event, wheel right, or button no. 11 +// +// - The third bit indicates whether the shift key was pressed. +// +// - The fourth bit indicates the alt key was pressed. +// +// - The fifth bit indicates the control key was pressed. +// +// - The sixth bit indicates motion events. Combined with button number 3, i.e. +// release event, it represents a drag event. +// +// - The seventh bit indicates a wheel event. +// +// - The eighth bit indicates additional buttons. +// +// If button is [MouseNone], and motion is false, this returns a release event. +// If button is undefined, this function returns 0xff. +func EncodeMouseButton(b MouseButton, motion, shift, alt, ctrl bool) (m byte) { + // mouse bit shifts + const ( + bitShift = 0b0000_0100 + bitAlt = 0b0000_1000 + bitCtrl = 0b0001_0000 + bitMotion = 0b0010_0000 + bitWheel = 0b0100_0000 + bitAdd = 0b1000_0000 // additional buttons 8-11 + + bitsMask = 0b0000_0011 + ) + + if b == MouseNone { + m = bitsMask + } else if b >= MouseLeft && b <= MouseRight { + m = byte(b - MouseLeft) + } else if b >= MouseWheelUp && b <= MouseWheelRight { + m = byte(b - MouseWheelUp) + m |= bitWheel + } else if b >= MouseBackward && b <= MouseButton11 { + m = byte(b - MouseBackward) + m |= bitAdd + } else { + m = 0xff // invalid button + } + + if shift { + m |= bitShift + } + if alt { + m |= bitAlt + } + if ctrl { + m |= bitCtrl + } + if motion { + m |= bitMotion + } + + return //nolint:nakedret +} + +// x10Offset is the offset for X10 mouse events. +// See https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking +const x10Offset = 32 + +// MouseX10 returns an escape sequence representing a mouse event in X10 mode. +// Note that this requires the terminal support X10 mouse modes. +// +// CSI M Cb Cx Cy +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking +func MouseX10(b byte, x, y int) string { + return "\x1b[M" + string(b+x10Offset) + string(byte(x)+x10Offset+1) + string(byte(y)+x10Offset+1) +} + +// MouseSgr returns an escape sequence representing a mouse event in SGR mode. +// +// CSI < Cb ; Cx ; Cy M +// CSI < Cb ; Cx ; Cy m (release) +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking +func MouseSgr(b byte, x, y int, release bool) string { + s := 'M' + if release { + s = 'm' + } + if x < 0 { + x = -x + } + if y < 0 { + y = -y + } + return fmt.Sprintf("\x1b[<%d;%d;%d%c", b, x+1, y+1, s) +} diff --git a/vendor/github.com/charmbracelet/x/ansi/notification.go b/vendor/github.com/charmbracelet/x/ansi/notification.go new file mode 100644 index 000000000..c712f3405 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/notification.go @@ -0,0 +1,13 @@ +package ansi + +// Notify sends a desktop notification using iTerm's OSC 9. +// +// OSC 9 ; Mc ST +// OSC 9 ; Mc BEL +// +// Where Mc is the notification body. +// +// See: https://iterm2.com/documentation-escape-codes.html +func Notify(s string) string { + return "\x1b]9;" + s + "\x07" +} diff --git a/vendor/github.com/charmbracelet/x/ansi/parser.go b/vendor/github.com/charmbracelet/x/ansi/parser.go new file mode 100644 index 000000000..e770c15f9 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/parser.go @@ -0,0 +1,417 @@ +package ansi + +import ( + "unicode/utf8" + "unsafe" + + "github.com/charmbracelet/x/ansi/parser" +) + +// Parser represents a DEC ANSI compatible sequence parser. +// +// It uses a state machine to parse ANSI escape sequences and control +// characters. The parser is designed to be used with a terminal emulator or +// similar application that needs to parse ANSI escape sequences and control +// characters. +// See package [parser] for more information. +// +//go:generate go run ./gen.go +type Parser struct { + handler Handler + + // params contains the raw parameters of the sequence. + // These parameters used when constructing CSI and DCS sequences. + params []int + + // data contains the raw data of the sequence. + // These data used when constructing OSC, DCS, SOS, PM, and APC sequences. + data []byte + + // dataLen keeps track of the length of the data buffer. + // If dataLen is -1, the data buffer is unlimited and will grow as needed. + // Otherwise, dataLen is limited by the size of the data buffer. + dataLen int + + // paramsLen keeps track of the number of parameters. + // This is limited by the size of the params buffer. + // + // This is also used when collecting UTF-8 runes to keep track of the + // number of rune bytes collected. + paramsLen int + + // cmd contains the raw command along with the private prefix and + // intermediate bytes of the sequence. + // The first lower byte contains the command byte, the next byte contains + // the private prefix, and the next byte contains the intermediate byte. + // + // This is also used when collecting UTF-8 runes treating it as a slice of + // 4 bytes. + cmd int + + // state is the current state of the parser. + state byte +} + +// NewParser returns a new parser with the default settings. +// The [Parser] uses a default size of 32 for the parameters and 64KB for the +// data buffer. Use [Parser.SetParamsSize] and [Parser.SetDataSize] to set the +// size of the parameters and data buffer respectively. +func NewParser() *Parser { + p := new(Parser) + p.SetParamsSize(parser.MaxParamsSize) + p.SetDataSize(1024 * 64) // 64KB data buffer + return p +} + +// SetParamsSize sets the size of the parameters buffer. +// This is used when constructing CSI and DCS sequences. +func (p *Parser) SetParamsSize(size int) { + p.params = make([]int, size) +} + +// SetDataSize sets the size of the data buffer. +// This is used when constructing OSC, DCS, SOS, PM, and APC sequences. +// If size is less than or equal to 0, the data buffer is unlimited and will +// grow as needed. +func (p *Parser) SetDataSize(size int) { + if size <= 0 { + size = 0 + p.dataLen = -1 + } + p.data = make([]byte, size) +} + +// Params returns the list of parsed packed parameters. +func (p *Parser) Params() Params { + return unsafe.Slice((*Param)(unsafe.Pointer(&p.params[0])), p.paramsLen) +} + +// Param returns the parameter at the given index and falls back to the default +// value if the parameter is missing. If the index is out of bounds, it returns +// the default value and false. +func (p *Parser) Param(i, def int) (int, bool) { + if i < 0 || i >= p.paramsLen { + return def, false + } + return Param(p.params[i]).Param(def), true +} + +// Command returns the packed command of the last dispatched sequence. Use +// [Cmd] to unpack the command. +func (p *Parser) Command() int { + return p.cmd +} + +// Rune returns the last dispatched sequence as a rune. +func (p *Parser) Rune() rune { + rw := utf8ByteLen(byte(p.cmd & 0xff)) + if rw == -1 { + return utf8.RuneError + } + r, _ := utf8.DecodeRune((*[utf8.UTFMax]byte)(unsafe.Pointer(&p.cmd))[:rw]) + return r +} + +// Control returns the last dispatched sequence as a control code. +func (p *Parser) Control() byte { + return byte(p.cmd & 0xff) +} + +// Data returns the raw data of the last dispatched sequence. +func (p *Parser) Data() []byte { + return p.data[:p.dataLen] +} + +// Reset resets the parser to its initial state. +func (p *Parser) Reset() { + p.clear() + p.state = parser.GroundState +} + +// clear clears the parser parameters and command. +func (p *Parser) clear() { + if len(p.params) > 0 { + p.params[0] = parser.MissingParam + } + p.paramsLen = 0 + p.cmd = 0 +} + +// State returns the current state of the parser. +func (p *Parser) State() parser.State { + return p.state +} + +// StateName returns the name of the current state. +func (p *Parser) StateName() string { + return parser.StateNames[p.state] +} + +// Parse parses the given dispatcher and byte buffer. +// Deprecated: Loop over the buffer and call [Parser.Advance] instead. +func (p *Parser) Parse(b []byte) { + for i := range b { + p.Advance(b[i]) + } +} + +// Advance advances the parser using the given byte. It returns the action +// performed by the parser. +func (p *Parser) Advance(b byte) parser.Action { + switch p.state { + case parser.Utf8State: + // We handle UTF-8 here. + return p.advanceUtf8(b) + default: + return p.advance(b) + } +} + +func (p *Parser) collectRune(b byte) { + if p.paramsLen >= utf8.UTFMax { + return + } + + shift := p.paramsLen * 8 + p.cmd &^= 0xff << shift + p.cmd |= int(b) << shift + p.paramsLen++ +} + +func (p *Parser) advanceUtf8(b byte) parser.Action { + // Collect UTF-8 rune bytes. + p.collectRune(b) + rw := utf8ByteLen(byte(p.cmd & 0xff)) + if rw == -1 { + // We panic here because the first byte comes from the state machine, + // if this panics, it means there is a bug in the state machine! + panic("invalid rune") // unreachable + } + + if p.paramsLen < rw { + return parser.CollectAction + } + + // We have enough bytes to decode the rune using unsafe + if p.handler.Print != nil { + p.handler.Print(p.Rune()) + } + + p.state = parser.GroundState + p.paramsLen = 0 + + return parser.PrintAction +} + +func (p *Parser) advance(b byte) parser.Action { + state, action := parser.Table.Transition(p.state, b) + + // We need to clear the parser state if the state changes from EscapeState. + // This is because when we enter the EscapeState, we don't get a chance to + // clear the parser state. For example, when a sequence terminates with a + // ST (\x1b\\ or \x9c), we dispatch the current sequence and transition to + // EscapeState. However, the parser state is not cleared in this case and + // we need to clear it here before dispatching the esc sequence. + if p.state != state { + if p.state == parser.EscapeState { + p.performAction(parser.ClearAction, state, b) + } + if action == parser.PutAction && + p.state == parser.DcsEntryState && state == parser.DcsStringState { + // XXX: This is a special case where we need to start collecting + // non-string parameterized data i.e. doesn't follow the ECMA-48 § + // 5.4.1 string parameters format. + p.performAction(parser.StartAction, state, 0) + } + } + + // Handle special cases + switch { + case b == ESC && p.state == parser.EscapeState: + // Two ESCs in a row + p.performAction(parser.ExecuteAction, state, b) + default: + p.performAction(action, state, b) + } + + p.state = state + + return action +} + +func (p *Parser) parseStringCmd() { + // Try to parse the command + datalen := len(p.data) + if p.dataLen >= 0 { + datalen = p.dataLen + } + for i := range datalen { + d := p.data[i] + if d < '0' || d > '9' { + break + } + if p.cmd == parser.MissingCommand { + p.cmd = 0 + } + p.cmd *= 10 + p.cmd += int(d - '0') + } +} + +func (p *Parser) performAction(action parser.Action, state parser.State, b byte) { + switch action { + case parser.IgnoreAction: + break + + case parser.ClearAction: + p.clear() + + case parser.PrintAction: + p.cmd = int(b) + if p.handler.Print != nil { + p.handler.Print(rune(b)) + } + + case parser.ExecuteAction: + p.cmd = int(b) + if p.handler.Execute != nil { + p.handler.Execute(b) + } + + case parser.PrefixAction: + // Collect private prefix + // we only store the last prefix + p.cmd &^= 0xff << parser.PrefixShift + p.cmd |= int(b) << parser.PrefixShift + + case parser.CollectAction: + if state == parser.Utf8State { + // Reset the UTF-8 counter + p.paramsLen = 0 + p.collectRune(b) + } else { + // Collect intermediate bytes + // we only store the last intermediate byte + p.cmd &^= 0xff << parser.IntermedShift + p.cmd |= int(b) << parser.IntermedShift + } + + case parser.ParamAction: + // Collect parameters + if p.paramsLen >= len(p.params) { + break + } + + if b >= '0' && b <= '9' { + if p.params[p.paramsLen] == parser.MissingParam { + p.params[p.paramsLen] = 0 + } + + p.params[p.paramsLen] *= 10 + p.params[p.paramsLen] += int(b - '0') + } + + if b == ':' { + p.params[p.paramsLen] |= parser.HasMoreFlag + } + + if b == ';' || b == ':' { + p.paramsLen++ + if p.paramsLen < len(p.params) { + p.params[p.paramsLen] = parser.MissingParam + } + } + + case parser.StartAction: + if p.dataLen < 0 && p.data != nil { + p.data = p.data[:0] + } else { + p.dataLen = 0 + } + if p.state >= parser.DcsEntryState && p.state <= parser.DcsStringState { + // Collect the command byte for DCS + p.cmd |= int(b) + } else { + p.cmd = parser.MissingCommand + } + + case parser.PutAction: + switch p.state { + case parser.OscStringState: + if b == ';' && p.cmd == parser.MissingCommand { + p.parseStringCmd() + } + } + + if p.dataLen < 0 { + p.data = append(p.data, b) + } else { + if p.dataLen < len(p.data) { + p.data[p.dataLen] = b + p.dataLen++ + } + } + + case parser.DispatchAction: + // Increment the last parameter + if p.paramsLen > 0 && p.paramsLen < len(p.params)-1 || + p.paramsLen == 0 && len(p.params) > 0 && p.params[0] != parser.MissingParam { + p.paramsLen++ + } + + if p.state == parser.OscStringState && p.cmd == parser.MissingCommand { + // Ensure we have a command for OSC + p.parseStringCmd() + } + + data := p.data + if p.dataLen >= 0 { + data = data[:p.dataLen] + } + switch p.state { + case parser.CsiEntryState, parser.CsiParamState, parser.CsiIntermediateState: + p.cmd |= int(b) + if p.handler.HandleCsi != nil { + p.handler.HandleCsi(Cmd(p.cmd), p.Params()) + } + case parser.EscapeState, parser.EscapeIntermediateState: + p.cmd |= int(b) + if p.handler.HandleEsc != nil { + p.handler.HandleEsc(Cmd(p.cmd)) + } + case parser.DcsEntryState, parser.DcsParamState, parser.DcsIntermediateState, parser.DcsStringState: + if p.handler.HandleDcs != nil { + p.handler.HandleDcs(Cmd(p.cmd), p.Params(), data) + } + case parser.OscStringState: + if p.handler.HandleOsc != nil { + p.handler.HandleOsc(p.cmd, data) + } + case parser.SosStringState: + if p.handler.HandleSos != nil { + p.handler.HandleSos(data) + } + case parser.PmStringState: + if p.handler.HandlePm != nil { + p.handler.HandlePm(data) + } + case parser.ApcStringState: + if p.handler.HandleApc != nil { + p.handler.HandleApc(data) + } + } + } +} + +func utf8ByteLen(b byte) int { + if b <= 0b0111_1111 { // 0x00-0x7F + return 1 + } else if b >= 0b1100_0000 && b <= 0b1101_1111 { // 0xC0-0xDF + return 2 + } else if b >= 0b1110_0000 && b <= 0b1110_1111 { // 0xE0-0xEF + return 3 + } else if b >= 0b1111_0000 && b <= 0b1111_0111 { // 0xF0-0xF7 + return 4 + } + return -1 +} diff --git a/vendor/github.com/charmbracelet/x/ansi/parser/const.go b/vendor/github.com/charmbracelet/x/ansi/parser/const.go new file mode 100644 index 000000000..85c90869c --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/parser/const.go @@ -0,0 +1,79 @@ +// Package parser provides ANSI escape sequence parsing functionality. +package parser + +// Action is a DEC ANSI parser action. +type Action = byte + +// These are the actions that the parser can take. +const ( + NoneAction Action = iota + ClearAction + CollectAction + PrefixAction + DispatchAction + ExecuteAction + StartAction // Start of a data string + PutAction // Put into the data string + ParamAction + PrintAction + + IgnoreAction = NoneAction +) + +// ActionNames provides string names for parser actions. +var ActionNames = []string{ + "NoneAction", + "ClearAction", + "CollectAction", + "PrefixAction", + "DispatchAction", + "ExecuteAction", + "StartAction", + "PutAction", + "ParamAction", + "PrintAction", +} + +// State is a DEC ANSI parser state. +type State = byte + +// These are the states that the parser can be in. +const ( + GroundState State = iota + CsiEntryState + CsiIntermediateState + CsiParamState + DcsEntryState + DcsIntermediateState + DcsParamState + DcsStringState + EscapeState + EscapeIntermediateState + OscStringState + SosStringState + PmStringState + ApcStringState + + // Utf8State is not part of the DEC ANSI standard. It is used to handle + // UTF-8 sequences. + Utf8State +) + +// StateNames provides string names for parser states. +var StateNames = []string{ + "GroundState", + "CsiEntryState", + "CsiIntermediateState", + "CsiParamState", + "DcsEntryState", + "DcsIntermediateState", + "DcsParamState", + "DcsStringState", + "EscapeState", + "EscapeIntermediateState", + "OscStringState", + "SosStringState", + "PmStringState", + "ApcStringState", + "Utf8State", +} diff --git a/vendor/github.com/charmbracelet/x/ansi/parser/seq.go b/vendor/github.com/charmbracelet/x/ansi/parser/seq.go new file mode 100644 index 000000000..de7e15e68 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/parser/seq.go @@ -0,0 +1,136 @@ +package parser + +import "math" + +// Shift and masks for sequence parameters and intermediates. +const ( + PrefixShift = 8 + IntermedShift = 16 + FinalMask = 0xff + HasMoreFlag = math.MinInt32 + ParamMask = ^HasMoreFlag + MissingParam = ParamMask + MissingCommand = MissingParam + MaxParam = math.MaxUint16 // the maximum value a parameter can have +) + +const ( + // MaxParamsSize is the maximum number of parameters a sequence can have. + MaxParamsSize = 32 + + // DefaultParamValue is the default value used for missing parameters. + DefaultParamValue = 0 +) + +// Prefix returns the prefix byte of the sequence. +// This is always gonna be one of the following '<' '=' '>' '?' and in the +// range of 0x3C-0x3F. +// Zero is returned if the sequence does not have a prefix. +func Prefix(cmd int) int { + return (cmd >> PrefixShift) & FinalMask +} + +// Intermediate returns the intermediate byte of the sequence. +// An intermediate byte is in the range of 0x20-0x2F. This includes these +// characters from ' ', '!', '"', '#', '$', '%', '&', ”', '(', ')', '*', '+', +// ',', '-', '.', '/'. +// Zero is returned if the sequence does not have an intermediate byte. +func Intermediate(cmd int) int { + return (cmd >> IntermedShift) & FinalMask +} + +// Command returns the command byte of the CSI sequence. +func Command(cmd int) int { + return cmd & FinalMask +} + +// Param returns the parameter at the given index. +// It returns -1 if the parameter does not exist. +func Param(params []int, i int) int { + if len(params) == 0 || i < 0 || i >= len(params) { + return -1 + } + + p := params[i] & ParamMask + if p == MissingParam { + return -1 + } + + return p +} + +// HasMore returns true if the parameter has more sub-parameters. +func HasMore(params []int, i int) bool { + if len(params) == 0 || i >= len(params) { + return false + } + + return params[i]&HasMoreFlag != 0 +} + +// Subparams returns the sub-parameters of the given parameter. +// It returns nil if the parameter does not exist. +func Subparams(params []int, i int) []int { + if len(params) == 0 || i < 0 || i >= len(params) { + return nil + } + + // Count the number of parameters before the given parameter index. + var count int + var j int + for j = range params { + if count == i { + break + } + if !HasMore(params, j) { + count++ + } + } + + if count > i || j >= len(params) { + return nil + } + + var subs []int + for ; j < len(params); j++ { + if !HasMore(params, j) { + break + } + p := Param(params, j) + if p == -1 { + p = DefaultParamValue + } + subs = append(subs, p) + } + + p := Param(params, j) + if p == -1 { + p = DefaultParamValue + } + + return append(subs, p) +} + +// Len returns the number of parameters in the sequence. +// This will return the number of parameters in the sequence, excluding any +// sub-parameters. +func Len(params []int) int { + var n int + for i := range params { + if !HasMore(params, i) { + n++ + } + } + return n +} + +// Range iterates over the parameters of the sequence and calls the given +// function for each parameter. +// The function should return false to stop the iteration. +func Range(params []int, fn func(i int, param int, hasMore bool) bool) { + for i := range params { + if !fn(i, Param(params, i), HasMore(params, i)) { + break + } + } +} diff --git a/vendor/github.com/charmbracelet/x/ansi/parser/transition_table.go b/vendor/github.com/charmbracelet/x/ansi/parser/transition_table.go new file mode 100644 index 000000000..ef46b7b6a --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/parser/transition_table.go @@ -0,0 +1,273 @@ +package parser + +// Table values are generated like this: +// +// index: currentState << IndexStateShift | charCode +// value: action << TransitionActionShift | nextState +const ( + TransitionActionShift = 4 + TransitionStateMask = 15 + IndexStateShift = 8 + + // DefaultTableSize is the default size of the transition table. + DefaultTableSize = 4096 +) + +// Table is a DEC ANSI transition table. +var Table = GenerateTransitionTable() + +// TransitionTable is a DEC ANSI transition table. +// https://vt100.net/emu/dec_ansi_parser +type TransitionTable []byte + +// NewTransitionTable returns a new DEC ANSI transition table. +func NewTransitionTable(size int) TransitionTable { + if size <= 0 { + size = DefaultTableSize + } + return TransitionTable(make([]byte, size)) +} + +// SetDefault sets default transition. +func (t TransitionTable) SetDefault(action Action, state State) { + for i := range t { + t[i] = action<> TransitionActionShift +} + +// byte range macro. +func r(start, end byte) []byte { + var a []byte + for i := int(start); i <= int(end); i++ { + a = append(a, byte(i)) + } + return a +} + +// GenerateTransitionTable generates a DEC ANSI transition table compatible +// with the VT500-series of terminals. This implementation includes a few +// modifications that include: +// - A new Utf8State is introduced to handle UTF8 sequences. +// - Osc and Dcs data accept UTF8 sequences by extending the printable range +// to 0xFF and 0xFE respectively. +// - We don't ignore 0x3A (':') when building Csi and Dcs parameters and +// instead use it to denote sub-parameters. +// - Support dispatching SosPmApc sequences. +// - The DEL (0x7F) character is executed in the Ground state. +// - The DEL (0x7F) character is collected in the DcsPassthrough string state. +// - The ST C1 control character (0x9C) is executed and not ignored. +func GenerateTransitionTable() TransitionTable { + table := NewTransitionTable(DefaultTableSize) + table.SetDefault(NoneAction, GroundState) + + // Anywhere + for _, state := range r(GroundState, Utf8State) { + // Anywhere -> Ground + table.AddMany([]byte{0x18, 0x1a, 0x99, 0x9a}, state, ExecuteAction, GroundState) + table.AddRange(0x80, 0x8F, state, ExecuteAction, GroundState) + table.AddRange(0x90, 0x97, state, ExecuteAction, GroundState) + table.AddOne(0x9C, state, ExecuteAction, GroundState) + // Anywhere -> Escape + table.AddOne(0x1B, state, ClearAction, EscapeState) + // Anywhere -> SosStringState + table.AddOne(0x98, state, StartAction, SosStringState) + // Anywhere -> PmStringState + table.AddOne(0x9E, state, StartAction, PmStringState) + // Anywhere -> ApcStringState + table.AddOne(0x9F, state, StartAction, ApcStringState) + // Anywhere -> CsiEntry + table.AddOne(0x9B, state, ClearAction, CsiEntryState) + // Anywhere -> DcsEntry + table.AddOne(0x90, state, ClearAction, DcsEntryState) + // Anywhere -> OscString + table.AddOne(0x9D, state, StartAction, OscStringState) + // Anywhere -> Utf8 + table.AddRange(0xC2, 0xDF, state, CollectAction, Utf8State) // UTF8 2 byte sequence + table.AddRange(0xE0, 0xEF, state, CollectAction, Utf8State) // UTF8 3 byte sequence + table.AddRange(0xF0, 0xF4, state, CollectAction, Utf8State) // UTF8 4 byte sequence + } + + // Ground + table.AddRange(0x00, 0x17, GroundState, ExecuteAction, GroundState) + table.AddOne(0x19, GroundState, ExecuteAction, GroundState) + table.AddRange(0x1C, 0x1F, GroundState, ExecuteAction, GroundState) + table.AddRange(0x20, 0x7E, GroundState, PrintAction, GroundState) + table.AddOne(0x7F, GroundState, ExecuteAction, GroundState) + + // EscapeIntermediate + table.AddRange(0x00, 0x17, EscapeIntermediateState, ExecuteAction, EscapeIntermediateState) + table.AddOne(0x19, EscapeIntermediateState, ExecuteAction, EscapeIntermediateState) + table.AddRange(0x1C, 0x1F, EscapeIntermediateState, ExecuteAction, EscapeIntermediateState) + table.AddRange(0x20, 0x2F, EscapeIntermediateState, CollectAction, EscapeIntermediateState) + table.AddOne(0x7F, EscapeIntermediateState, IgnoreAction, EscapeIntermediateState) + // EscapeIntermediate -> Ground + table.AddRange(0x30, 0x7E, EscapeIntermediateState, DispatchAction, GroundState) + + // Escape + table.AddRange(0x00, 0x17, EscapeState, ExecuteAction, EscapeState) + table.AddOne(0x19, EscapeState, ExecuteAction, EscapeState) + table.AddRange(0x1C, 0x1F, EscapeState, ExecuteAction, EscapeState) + table.AddOne(0x7F, EscapeState, IgnoreAction, EscapeState) + // Escape -> Ground + table.AddRange(0x30, 0x4F, EscapeState, DispatchAction, GroundState) + table.AddRange(0x51, 0x57, EscapeState, DispatchAction, GroundState) + table.AddOne(0x59, EscapeState, DispatchAction, GroundState) + table.AddOne(0x5A, EscapeState, DispatchAction, GroundState) + table.AddOne(0x5C, EscapeState, DispatchAction, GroundState) + table.AddRange(0x60, 0x7E, EscapeState, DispatchAction, GroundState) + // Escape -> Escape_intermediate + table.AddRange(0x20, 0x2F, EscapeState, CollectAction, EscapeIntermediateState) + // Escape -> Sos_pm_apc_string + table.AddOne('X', EscapeState, StartAction, SosStringState) // SOS + table.AddOne('^', EscapeState, StartAction, PmStringState) // PM + table.AddOne('_', EscapeState, StartAction, ApcStringState) // APC + // Escape -> Dcs_entry + table.AddOne('P', EscapeState, ClearAction, DcsEntryState) + // Escape -> Csi_entry + table.AddOne('[', EscapeState, ClearAction, CsiEntryState) + // Escape -> Osc_string + table.AddOne(']', EscapeState, StartAction, OscStringState) + + // Sos_pm_apc_string + for _, state := range r(SosStringState, ApcStringState) { + table.AddRange(0x00, 0x17, state, PutAction, state) + table.AddOne(0x19, state, PutAction, state) + table.AddRange(0x1C, 0x1F, state, PutAction, state) + table.AddRange(0x20, 0x7F, state, PutAction, state) + // ESC, ST, CAN, and SUB terminate the sequence + table.AddOne(0x1B, state, DispatchAction, EscapeState) + table.AddOne(0x9C, state, DispatchAction, GroundState) + table.AddMany([]byte{0x18, 0x1A}, state, IgnoreAction, GroundState) + } + + // Dcs_entry + table.AddRange(0x00, 0x07, DcsEntryState, IgnoreAction, DcsEntryState) + table.AddRange(0x0E, 0x17, DcsEntryState, IgnoreAction, DcsEntryState) + table.AddOne(0x19, DcsEntryState, IgnoreAction, DcsEntryState) + table.AddRange(0x1C, 0x1F, DcsEntryState, IgnoreAction, DcsEntryState) + table.AddOne(0x7F, DcsEntryState, IgnoreAction, DcsEntryState) + // Dcs_entry -> Dcs_intermediate + table.AddRange(0x20, 0x2F, DcsEntryState, CollectAction, DcsIntermediateState) + // Dcs_entry -> Dcs_param + table.AddRange(0x30, 0x3B, DcsEntryState, ParamAction, DcsParamState) + table.AddRange(0x3C, 0x3F, DcsEntryState, PrefixAction, DcsParamState) + // Dcs_entry -> Dcs_passthrough + table.AddRange(0x08, 0x0D, DcsEntryState, PutAction, DcsStringState) // Follows ECMA-48 § 8.3.27 + // XXX: allows passing ESC (not a ECMA-48 standard) this to allow for + // passthrough of ANSI sequences like in Screen or Tmux passthrough mode. + table.AddOne(0x1B, DcsEntryState, PutAction, DcsStringState) + table.AddRange(0x40, 0x7E, DcsEntryState, StartAction, DcsStringState) + + // Dcs_intermediate + table.AddRange(0x00, 0x17, DcsIntermediateState, IgnoreAction, DcsIntermediateState) + table.AddOne(0x19, DcsIntermediateState, IgnoreAction, DcsIntermediateState) + table.AddRange(0x1C, 0x1F, DcsIntermediateState, IgnoreAction, DcsIntermediateState) + table.AddRange(0x20, 0x2F, DcsIntermediateState, CollectAction, DcsIntermediateState) + table.AddOne(0x7F, DcsIntermediateState, IgnoreAction, DcsIntermediateState) + // Dcs_intermediate -> Dcs_passthrough + table.AddRange(0x30, 0x3F, DcsIntermediateState, StartAction, DcsStringState) + table.AddRange(0x40, 0x7E, DcsIntermediateState, StartAction, DcsStringState) + + // Dcs_param + table.AddRange(0x00, 0x17, DcsParamState, IgnoreAction, DcsParamState) + table.AddOne(0x19, DcsParamState, IgnoreAction, DcsParamState) + table.AddRange(0x1C, 0x1F, DcsParamState, IgnoreAction, DcsParamState) + table.AddRange(0x30, 0x3B, DcsParamState, ParamAction, DcsParamState) + table.AddOne(0x7F, DcsParamState, IgnoreAction, DcsParamState) + table.AddRange(0x3C, 0x3F, DcsParamState, IgnoreAction, DcsParamState) + // Dcs_param -> Dcs_intermediate + table.AddRange(0x20, 0x2F, DcsParamState, CollectAction, DcsIntermediateState) + // Dcs_param -> Dcs_passthrough + table.AddRange(0x40, 0x7E, DcsParamState, StartAction, DcsStringState) + + // Dcs_passthrough + table.AddRange(0x00, 0x17, DcsStringState, PutAction, DcsStringState) + table.AddOne(0x19, DcsStringState, PutAction, DcsStringState) + table.AddRange(0x1C, 0x1F, DcsStringState, PutAction, DcsStringState) + table.AddRange(0x20, 0x7E, DcsStringState, PutAction, DcsStringState) + table.AddOne(0x7F, DcsStringState, PutAction, DcsStringState) + table.AddRange(0x80, 0xFF, DcsStringState, PutAction, DcsStringState) // Allow Utf8 characters by extending the printable range from 0x7F to 0xFF + // ST, CAN, SUB, and ESC terminate the sequence + table.AddOne(0x1B, DcsStringState, DispatchAction, EscapeState) + table.AddOne(0x9C, DcsStringState, DispatchAction, GroundState) + table.AddMany([]byte{0x18, 0x1A}, DcsStringState, IgnoreAction, GroundState) + + // Csi_param + table.AddRange(0x00, 0x17, CsiParamState, ExecuteAction, CsiParamState) + table.AddOne(0x19, CsiParamState, ExecuteAction, CsiParamState) + table.AddRange(0x1C, 0x1F, CsiParamState, ExecuteAction, CsiParamState) + table.AddRange(0x30, 0x3B, CsiParamState, ParamAction, CsiParamState) + table.AddOne(0x7F, CsiParamState, IgnoreAction, CsiParamState) + table.AddRange(0x3C, 0x3F, CsiParamState, IgnoreAction, CsiParamState) + // Csi_param -> Ground + table.AddRange(0x40, 0x7E, CsiParamState, DispatchAction, GroundState) + // Csi_param -> Csi_intermediate + table.AddRange(0x20, 0x2F, CsiParamState, CollectAction, CsiIntermediateState) + + // Csi_intermediate + table.AddRange(0x00, 0x17, CsiIntermediateState, ExecuteAction, CsiIntermediateState) + table.AddOne(0x19, CsiIntermediateState, ExecuteAction, CsiIntermediateState) + table.AddRange(0x1C, 0x1F, CsiIntermediateState, ExecuteAction, CsiIntermediateState) + table.AddRange(0x20, 0x2F, CsiIntermediateState, CollectAction, CsiIntermediateState) + table.AddOne(0x7F, CsiIntermediateState, IgnoreAction, CsiIntermediateState) + // Csi_intermediate -> Ground + table.AddRange(0x40, 0x7E, CsiIntermediateState, DispatchAction, GroundState) + // Csi_intermediate -> Csi_ignore + table.AddRange(0x30, 0x3F, CsiIntermediateState, IgnoreAction, GroundState) + + // Csi_entry + table.AddRange(0x00, 0x17, CsiEntryState, ExecuteAction, CsiEntryState) + table.AddOne(0x19, CsiEntryState, ExecuteAction, CsiEntryState) + table.AddRange(0x1C, 0x1F, CsiEntryState, ExecuteAction, CsiEntryState) + table.AddOne(0x7F, CsiEntryState, IgnoreAction, CsiEntryState) + // Csi_entry -> Ground + table.AddRange(0x40, 0x7E, CsiEntryState, DispatchAction, GroundState) + // Csi_entry -> Csi_intermediate + table.AddRange(0x20, 0x2F, CsiEntryState, CollectAction, CsiIntermediateState) + // Csi_entry -> Csi_param + table.AddRange(0x30, 0x3B, CsiEntryState, ParamAction, CsiParamState) + table.AddRange(0x3C, 0x3F, CsiEntryState, PrefixAction, CsiParamState) + + // Osc_string + table.AddRange(0x00, 0x06, OscStringState, IgnoreAction, OscStringState) + table.AddRange(0x08, 0x17, OscStringState, IgnoreAction, OscStringState) + table.AddOne(0x19, OscStringState, IgnoreAction, OscStringState) + table.AddRange(0x1C, 0x1F, OscStringState, IgnoreAction, OscStringState) + table.AddRange(0x20, 0xFF, OscStringState, PutAction, OscStringState) // Allow Utf8 characters by extending the printable range from 0x7F to 0xFF + + // ST, CAN, SUB, ESC, and BEL terminate the sequence + table.AddOne(0x1B, OscStringState, DispatchAction, EscapeState) + table.AddOne(0x07, OscStringState, DispatchAction, GroundState) + table.AddOne(0x9C, OscStringState, DispatchAction, GroundState) + table.AddMany([]byte{0x18, 0x1A}, OscStringState, IgnoreAction, GroundState) + + return table +} diff --git a/vendor/github.com/charmbracelet/x/ansi/parser_decode.go b/vendor/github.com/charmbracelet/x/ansi/parser_decode.go new file mode 100644 index 000000000..dfd2dc761 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/parser_decode.go @@ -0,0 +1,524 @@ +package ansi + +import ( + "unicode/utf8" + + "github.com/charmbracelet/x/ansi/parser" + "github.com/mattn/go-runewidth" + "github.com/rivo/uniseg" +) + +// State represents the state of the ANSI escape sequence parser used by +// [DecodeSequence]. +type State = byte + +// ANSI escape sequence states used by [DecodeSequence]. +const ( + NormalState State = iota + PrefixState + ParamsState + IntermedState + EscapeState + StringState +) + +// DecodeSequence decodes the first ANSI escape sequence or a printable +// grapheme from the given data. It returns the sequence slice, the number of +// bytes read, the cell width for each sequence, and the new state. +// +// The cell width will always be 0 for control and escape sequences, 1 for +// ASCII printable characters, and the number of cells other Unicode characters +// occupy. It uses the uniseg package to calculate the width of Unicode +// graphemes and characters. This means it will always do grapheme clustering +// (mode 2027). +// +// Passing a non-nil [*Parser] as the last argument will allow the decoder to +// collect sequence parameters, data, and commands. The parser cmd will have +// the packed command value that contains intermediate and prefix characters. +// In the case of a OSC sequence, the cmd will be the OSC command number. Use +// [Cmd] and [Param] types to unpack command intermediates and prefixes as well +// as parameters. +// +// Zero [Cmd] means the CSI, DCS, or ESC sequence is invalid. Moreover, checking the +// validity of other data sequences, OSC, DCS, etc, will require checking for +// the returned sequence terminator bytes such as ST (ESC \\) and BEL). +// +// We store the command byte in [Cmd] in the most significant byte, the +// prefix byte in the next byte, and the intermediate byte in the least +// significant byte. This is done to avoid using a struct to store the command +// and its intermediates and prefixes. The command byte is always the least +// significant byte i.e. [Cmd & 0xff]. Use the [Cmd] type to unpack the +// command, intermediate, and prefix bytes. Note that we only collect the last +// prefix character and intermediate byte. +// +// The [p.Params] slice will contain the parameters of the sequence. Any +// sub-parameter will have the [parser.HasMoreFlag] set. Use the [Param] type +// to unpack the parameters. +// +// Example: +// +// var state byte // the initial state is always zero [NormalState] +// p := NewParser(32, 1024) // create a new parser with a 32 params buffer and 1024 data buffer (optional) +// input := []byte("\x1b[31mHello, World!\x1b[0m") +// for len(input) > 0 { +// seq, width, n, newState := DecodeSequence(input, state, p) +// log.Printf("seq: %q, width: %d", seq, width) +// state = newState +// input = input[n:] +// } +// +// This function treats the text as a sequence of grapheme clusters. +func DecodeSequence[T string | []byte](b T, state byte, p *Parser) (seq T, width int, n int, newState byte) { + return decodeSequence(GraphemeWidth, b, state, p) +} + +// DecodeSequenceWc decodes the first ANSI escape sequence or a printable +// grapheme from the given data. It returns the sequence slice, the number of +// bytes read, the cell width for each sequence, and the new state. +// +// The cell width will always be 0 for control and escape sequences, 1 for +// ASCII printable characters, and the number of cells other Unicode characters +// occupy. It uses the uniseg package to calculate the width of Unicode +// graphemes and characters. This means it will always do grapheme clustering +// (mode 2027). +// +// Passing a non-nil [*Parser] as the last argument will allow the decoder to +// collect sequence parameters, data, and commands. The parser cmd will have +// the packed command value that contains intermediate and prefix characters. +// In the case of a OSC sequence, the cmd will be the OSC command number. Use +// [Cmd] and [Param] types to unpack command intermediates and prefixes as well +// as parameters. +// +// Zero [Cmd] means the CSI, DCS, or ESC sequence is invalid. Moreover, checking the +// validity of other data sequences, OSC, DCS, etc, will require checking for +// the returned sequence terminator bytes such as ST (ESC \\) and BEL). +// +// We store the command byte in [Cmd] in the most significant byte, the +// prefix byte in the next byte, and the intermediate byte in the least +// significant byte. This is done to avoid using a struct to store the command +// and its intermediates and prefixes. The command byte is always the least +// significant byte i.e. [Cmd & 0xff]. Use the [Cmd] type to unpack the +// command, intermediate, and prefix bytes. Note that we only collect the last +// prefix character and intermediate byte. +// +// The [p.Params] slice will contain the parameters of the sequence. Any +// sub-parameter will have the [parser.HasMoreFlag] set. Use the [Param] type +// to unpack the parameters. +// +// Example: +// +// var state byte // the initial state is always zero [NormalState] +// p := NewParser(32, 1024) // create a new parser with a 32 params buffer and 1024 data buffer (optional) +// input := []byte("\x1b[31mHello, World!\x1b[0m") +// for len(input) > 0 { +// seq, width, n, newState := DecodeSequenceWc(input, state, p) +// log.Printf("seq: %q, width: %d", seq, width) +// state = newState +// input = input[n:] +// } +// +// This function treats the text as a sequence of wide characters and runes. +func DecodeSequenceWc[T string | []byte](b T, state byte, p *Parser) (seq T, width int, n int, newState byte) { + return decodeSequence(WcWidth, b, state, p) +} + +func decodeSequence[T string | []byte](m Method, b T, state State, p *Parser) (seq T, width int, n int, newState byte) { + for i := 0; i < len(b); i++ { + c := b[i] + + switch state { + case NormalState: + switch c { + case ESC: + if p != nil { + if len(p.params) > 0 { + p.params[0] = parser.MissingParam + } + p.cmd = 0 + p.paramsLen = 0 + p.dataLen = 0 + } + state = EscapeState + continue + case CSI, DCS: + if p != nil { + if len(p.params) > 0 { + p.params[0] = parser.MissingParam + } + p.cmd = 0 + p.paramsLen = 0 + p.dataLen = 0 + } + state = PrefixState + continue + case OSC, APC, SOS, PM: + if p != nil { + p.cmd = parser.MissingCommand + p.dataLen = 0 + } + state = StringState + continue + } + + if p != nil { + p.dataLen = 0 + p.paramsLen = 0 + p.cmd = 0 + } + if c > US && c < DEL { + // ASCII printable characters + return b[i : i+1], 1, 1, NormalState + } + + if c <= US || c == DEL || c < 0xC0 { + // C0 & C1 control characters & DEL + return b[i : i+1], 0, 1, NormalState + } + + if utf8.RuneStart(c) { + seq, _, width, _ = FirstGraphemeCluster(b, -1) + if m == WcWidth { + width = runewidth.StringWidth(string(seq)) + } + i += len(seq) + return b[:i], width, i, NormalState + } + + // Invalid UTF-8 sequence + return b[:i], 0, i, NormalState + case PrefixState: + if c >= '<' && c <= '?' { + if p != nil { + // We only collect the last prefix character. + p.cmd &^= 0xff << parser.PrefixShift + p.cmd |= int(c) << parser.PrefixShift + } + break + } + + state = ParamsState + fallthrough + case ParamsState: + if c >= '0' && c <= '9' { + if p != nil { + if p.params[p.paramsLen] == parser.MissingParam { + p.params[p.paramsLen] = 0 + } + + p.params[p.paramsLen] *= 10 + p.params[p.paramsLen] += int(c - '0') + } + break + } + + if c == ':' { + if p != nil { + p.params[p.paramsLen] |= parser.HasMoreFlag + } + } + + if c == ';' || c == ':' { + if p != nil { + p.paramsLen++ + if p.paramsLen < len(p.params) { + p.params[p.paramsLen] = parser.MissingParam + } + } + break + } + + state = IntermedState + fallthrough + case IntermedState: + if c >= ' ' && c <= '/' { + if p != nil { + p.cmd &^= 0xff << parser.IntermedShift + p.cmd |= int(c) << parser.IntermedShift + } + break + } + + if p != nil { + // Increment the last parameter + if p.paramsLen > 0 && p.paramsLen < len(p.params)-1 || + p.paramsLen == 0 && len(p.params) > 0 && p.params[0] != parser.MissingParam { + p.paramsLen++ + } + } + + if c >= '@' && c <= '~' { + if p != nil { + p.cmd &^= 0xff + p.cmd |= int(c) + } + + if HasDcsPrefix(b) { + // Continue to collect DCS data + if p != nil { + p.dataLen = 0 + } + state = StringState + continue + } + + return b[:i+1], 0, i + 1, NormalState + } + + // Invalid CSI/DCS sequence + return b[:i], 0, i, NormalState + case EscapeState: + switch c { + case '[', 'P': + if p != nil { + if len(p.params) > 0 { + p.params[0] = parser.MissingParam + } + p.paramsLen = 0 + p.cmd = 0 + } + state = PrefixState + continue + case ']', 'X', '^', '_': + if p != nil { + p.cmd = parser.MissingCommand + p.dataLen = 0 + } + state = StringState + continue + } + + if c >= ' ' && c <= '/' { + if p != nil { + p.cmd &^= 0xff << parser.IntermedShift + p.cmd |= int(c) << parser.IntermedShift + } + continue + } else if c >= '0' && c <= '~' { + if p != nil { + p.cmd &^= 0xff + p.cmd |= int(c) + } + return b[:i+1], 0, i + 1, NormalState + } + + // Invalid escape sequence + return b[:i], 0, i, NormalState + case StringState: + switch c { + case BEL: + if HasOscPrefix(b) { + parseOscCmd(p) + return b[:i+1], 0, i + 1, NormalState + } + case CAN, SUB: + if HasOscPrefix(b) { + // Ensure we parse the OSC command number + parseOscCmd(p) + } + + // Cancel the sequence + return b[:i], 0, i, NormalState + case ST: + if HasOscPrefix(b) { + // Ensure we parse the OSC command number + parseOscCmd(p) + } + + return b[:i+1], 0, i + 1, NormalState + case ESC: + if HasStPrefix(b[i:]) { + if HasOscPrefix(b) { + // Ensure we parse the OSC command number + parseOscCmd(p) + } + + // End of string 7-bit (ST) + return b[:i+2], 0, i + 2, NormalState + } + + // Otherwise, cancel the sequence + return b[:i], 0, i, NormalState + } + + if p != nil && p.dataLen < len(p.data) { + p.data[p.dataLen] = c + p.dataLen++ + + // Parse the OSC command number + if c == ';' && HasOscPrefix(b) { + parseOscCmd(p) + } + } + } + } + + return b, 0, len(b), state +} + +func parseOscCmd(p *Parser) { + if p == nil || p.cmd != parser.MissingCommand { + return + } + for j := range p.dataLen { + d := p.data[j] + if d < '0' || d > '9' { + break + } + if p.cmd == parser.MissingCommand { + p.cmd = 0 + } + p.cmd *= 10 + p.cmd += int(d - '0') + } +} + +// Equal returns true if the given byte slices are equal. +func Equal[T string | []byte](a, b T) bool { + return string(a) == string(b) +} + +// HasPrefix returns true if the given byte slice has prefix. +func HasPrefix[T string | []byte](b, prefix T) bool { + return len(b) >= len(prefix) && Equal(b[0:len(prefix)], prefix) +} + +// HasSuffix returns true if the given byte slice has suffix. +func HasSuffix[T string | []byte](b, suffix T) bool { + return len(b) >= len(suffix) && Equal(b[len(b)-len(suffix):], suffix) +} + +// HasCsiPrefix returns true if the given byte slice has a CSI prefix. +func HasCsiPrefix[T string | []byte](b T) bool { + return (len(b) > 0 && b[0] == CSI) || + (len(b) > 1 && b[0] == ESC && b[1] == '[') +} + +// HasOscPrefix returns true if the given byte slice has an OSC prefix. +func HasOscPrefix[T string | []byte](b T) bool { + return (len(b) > 0 && b[0] == OSC) || + (len(b) > 1 && b[0] == ESC && b[1] == ']') +} + +// HasApcPrefix returns true if the given byte slice has an APC prefix. +func HasApcPrefix[T string | []byte](b T) bool { + return (len(b) > 0 && b[0] == APC) || + (len(b) > 1 && b[0] == ESC && b[1] == '_') +} + +// HasDcsPrefix returns true if the given byte slice has a DCS prefix. +func HasDcsPrefix[T string | []byte](b T) bool { + return (len(b) > 0 && b[0] == DCS) || + (len(b) > 1 && b[0] == ESC && b[1] == 'P') +} + +// HasSosPrefix returns true if the given byte slice has a SOS prefix. +func HasSosPrefix[T string | []byte](b T) bool { + return (len(b) > 0 && b[0] == SOS) || + (len(b) > 1 && b[0] == ESC && b[1] == 'X') +} + +// HasPmPrefix returns true if the given byte slice has a PM prefix. +func HasPmPrefix[T string | []byte](b T) bool { + return (len(b) > 0 && b[0] == PM) || + (len(b) > 1 && b[0] == ESC && b[1] == '^') +} + +// HasStPrefix returns true if the given byte slice has a ST prefix. +func HasStPrefix[T string | []byte](b T) bool { + return (len(b) > 0 && b[0] == ST) || + (len(b) > 1 && b[0] == ESC && b[1] == '\\') +} + +// HasEscPrefix returns true if the given byte slice has an ESC prefix. +func HasEscPrefix[T string | []byte](b T) bool { + return len(b) > 0 && b[0] == ESC +} + +// FirstGraphemeCluster returns the first grapheme cluster in the given string or byte slice. +// This is a syntactic sugar function that wraps +// uniseg.FirstGraphemeClusterInString and uniseg.FirstGraphemeCluster. +func FirstGraphemeCluster[T string | []byte](b T, state int) (T, T, int, int) { + switch b := any(b).(type) { + case string: + cluster, rest, width, newState := uniseg.FirstGraphemeClusterInString(b, state) + return T(cluster), T(rest), width, newState + case []byte: + cluster, rest, width, newState := uniseg.FirstGraphemeCluster(b, state) + return T(cluster), T(rest), width, newState + } + panic("unreachable") +} + +// Cmd represents a sequence command. This is used to pack/unpack a sequence +// command with its intermediate and prefix characters. Those are commonly +// found in CSI and DCS sequences. +type Cmd int + +// Prefix returns the unpacked prefix byte of the CSI sequence. +// This is always gonna be one of the following '<' '=' '>' '?' and in the +// range of 0x3C-0x3F. +// Zero is returned if the sequence does not have a prefix. +func (c Cmd) Prefix() byte { + return byte(parser.Prefix(int(c))) +} + +// Intermediate returns the unpacked intermediate byte of the CSI sequence. +// An intermediate byte is in the range of 0x20-0x2F. This includes these +// characters from ' ', '!', '"', '#', '$', '%', '&', ”', '(', ')', '*', '+', +// ',', '-', '.', '/'. +// Zero is returned if the sequence does not have an intermediate byte. +func (c Cmd) Intermediate() byte { + return byte(parser.Intermediate(int(c))) +} + +// Final returns the unpacked command byte of the CSI sequence. +func (c Cmd) Final() byte { + return byte(parser.Command(int(c))) +} + +// Command packs a command with the given prefix, intermediate, and final. A +// zero byte means the sequence does not have a prefix or intermediate. +// +// Prefixes are in the range of 0x3C-0x3F that is one of `<=>?`. +// +// Intermediates are in the range of 0x20-0x2F that is anything in +// `!"#$%&'()*+,-./`. +// +// Final bytes are in the range of 0x40-0x7E that is anything in the range +// `@A–Z[\]^_`a–z{|}~`. +func Command(prefix, inter, final byte) (c int) { + c = int(final) + c |= int(prefix) << parser.PrefixShift + c |= int(inter) << parser.IntermedShift + return +} + +// Param represents a sequence parameter. Sequence parameters with +// sub-parameters are packed with the HasMoreFlag set. This is used to unpack +// the parameters from a CSI and DCS sequences. +type Param int + +// Param returns the unpacked parameter at the given index. +// It returns the default value if the parameter is missing. +func (s Param) Param(def int) int { + p := int(s) & parser.ParamMask + if p == parser.MissingParam { + return def + } + return p +} + +// HasMore unpacks the HasMoreFlag from the parameter. +func (s Param) HasMore() bool { + return s&parser.HasMoreFlag != 0 +} + +// Parameter packs an escape code parameter with the given parameter and +// whether this parameter has following sub-parameters. +func Parameter(p int, hasMore bool) (s int) { + s = p & parser.ParamMask + if hasMore { + s |= parser.HasMoreFlag + } + return +} diff --git a/vendor/github.com/charmbracelet/x/ansi/parser_handler.go b/vendor/github.com/charmbracelet/x/ansi/parser_handler.go new file mode 100644 index 000000000..03f9ed4cb --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/parser_handler.go @@ -0,0 +1,60 @@ +package ansi + +import "unsafe" + +// Params represents a list of packed parameters. +type Params []Param + +// Param returns the parameter at the given index and if it is part of a +// sub-parameters. It falls back to the default value if the parameter is +// missing. If the index is out of bounds, it returns the default value and +// false. +func (p Params) Param(i, def int) (int, bool, bool) { + if i < 0 || i >= len(p) { + return def, false, false + } + return p[i].Param(def), p[i].HasMore(), true +} + +// ForEach iterates over the parameters and calls the given function for each +// parameter. If a parameter is part of a sub-parameter, it will be called with +// hasMore set to true. +// Use def to set a default value for missing parameters. +func (p Params) ForEach(def int, f func(i, param int, hasMore bool)) { + for i := range p { + f(i, p[i].Param(def), p[i].HasMore()) + } +} + +// ToParams converts a list of integers to a list of parameters. +func ToParams(params []int) Params { + return unsafe.Slice((*Param)(unsafe.Pointer(¶ms[0])), len(params)) +} + +// Handler handles actions performed by the parser. +// It is used to handle ANSI escape sequences, control characters, and runes. +type Handler struct { + // Print is called when a printable rune is encountered. + Print func(r rune) + // Execute is called when a control character is encountered. + Execute func(b byte) + // HandleCsi is called when a CSI sequence is encountered. + HandleCsi func(cmd Cmd, params Params) + // HandleEsc is called when an ESC sequence is encountered. + HandleEsc func(cmd Cmd) + // HandleDcs is called when a DCS sequence is encountered. + HandleDcs func(cmd Cmd, params Params, data []byte) + // HandleOsc is called when an OSC sequence is encountered. + HandleOsc func(cmd int, data []byte) + // HandlePm is called when a PM sequence is encountered. + HandlePm func(data []byte) + // HandleApc is called when an APC sequence is encountered. + HandleApc func(data []byte) + // HandleSos is called when a SOS sequence is encountered. + HandleSos func(data []byte) +} + +// SetHandler sets the handler for the parser. +func (p *Parser) SetHandler(h Handler) { + p.handler = h +} diff --git a/vendor/github.com/charmbracelet/x/ansi/parser_sync.go b/vendor/github.com/charmbracelet/x/ansi/parser_sync.go new file mode 100644 index 000000000..65d25a9a6 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/parser_sync.go @@ -0,0 +1,29 @@ +package ansi + +import ( + "sync" + + "github.com/charmbracelet/x/ansi/parser" +) + +var parserPool = sync.Pool{ + New: func() any { + p := NewParser() + p.SetParamsSize(parser.MaxParamsSize) + p.SetDataSize(1024 * 1024 * 4) // 4MB of data buffer + return p + }, +} + +// GetParser returns a parser from a sync pool. +func GetParser() *Parser { + return parserPool.Get().(*Parser) +} + +// PutParser returns a parser to a sync pool. The parser is reset +// automatically. +func PutParser(p *Parser) { + p.Reset() + p.dataLen = 0 + parserPool.Put(p) +} diff --git a/vendor/github.com/charmbracelet/x/ansi/passthrough.go b/vendor/github.com/charmbracelet/x/ansi/passthrough.go new file mode 100644 index 000000000..7ac7cef15 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/passthrough.go @@ -0,0 +1,60 @@ +package ansi + +import ( + "bytes" +) + +// ScreenPassthrough wraps the given ANSI sequence in a DCS passthrough +// sequence to be sent to the outer terminal. This is used to send raw escape +// sequences to the outer terminal when running inside GNU Screen. +// +// DCS ST +// +// Note: Screen limits the length of string sequences to 768 bytes (since 2014). +// Use zero to indicate no limit, otherwise, this will chunk the returned +// string into limit sized chunks. +// +// See: https://www.gnu.org/software/screen/manual/screen.html#String-Escapes +// See: https://git.savannah.gnu.org/cgit/screen.git/tree/src/screen.h?id=c184c6ec27683ff1a860c45be5cf520d896fd2ef#n44 +func ScreenPassthrough(seq string, limit int) string { + var b bytes.Buffer + b.WriteString("\x1bP") + if limit > 0 { + for i := 0; i < len(seq); i += limit { + end := min(i+limit, len(seq)) + b.WriteString(seq[i:end]) + if end < len(seq) { + b.WriteString("\x1b\\\x1bP") + } + } + } else { + b.WriteString(seq) + } + b.WriteString("\x1b\\") + return b.String() +} + +// TmuxPassthrough wraps the given ANSI sequence in a special DCS passthrough +// sequence to be sent to the outer terminal. This is used to send raw escape +// sequences to the outer terminal when running inside Tmux. +// +// DCS tmux ; ST +// +// Where is the given sequence in which all occurrences of ESC +// (0x1b) are doubled i.e. replaced with ESC ESC (0x1b 0x1b). +// +// Note: this needs the `allow-passthrough` option to be set to `on`. +// +// See: https://github.com/tmux/tmux/wiki/FAQ#what-is-the-passthrough-escape-sequence-and-how-do-i-use-it +func TmuxPassthrough(seq string) string { + var b bytes.Buffer + b.WriteString("\x1bPtmux;") + for i := range len(seq) { + if seq[i] == ESC { + b.WriteByte(ESC) + } + b.WriteByte(seq[i]) + } + b.WriteString("\x1b\\") + return b.String() +} diff --git a/vendor/github.com/charmbracelet/x/ansi/paste.go b/vendor/github.com/charmbracelet/x/ansi/paste.go new file mode 100644 index 000000000..2f9ea6f79 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/paste.go @@ -0,0 +1,7 @@ +package ansi + +// BracketedPasteStart is the control sequence to enable bracketed paste mode. +const BracketedPasteStart = "\x1b[200~" + +// BracketedPasteEnd is the control sequence to disable bracketed paste mode. +const BracketedPasteEnd = "\x1b[201~" diff --git a/vendor/github.com/charmbracelet/x/ansi/reset.go b/vendor/github.com/charmbracelet/x/ansi/reset.go new file mode 100644 index 000000000..c1b89ea49 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/reset.go @@ -0,0 +1,11 @@ +package ansi + +// ResetInitialState (RIS) resets the terminal to its initial state. +// +// ESC c +// +// See: https://vt100.net/docs/vt510-rm/RIS.html +const ( + ResetInitialState = "\x1bc" + RIS = ResetInitialState +) diff --git a/vendor/github.com/charmbracelet/x/ansi/screen.go b/vendor/github.com/charmbracelet/x/ansi/screen.go new file mode 100644 index 000000000..e2027dff9 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/screen.go @@ -0,0 +1,410 @@ +package ansi + +import ( + "strconv" + "strings" +) + +// EraseDisplay (ED) clears the display or parts of the display. A screen is +// the shown part of the terminal display excluding the scrollback buffer. +// Possible values: +// +// Default is 0. +// +// 0: Clear from cursor to end of screen. +// 1: Clear from cursor to beginning of the screen. +// 2: Clear entire screen (and moves cursor to upper left on DOS). +// 3: Clear entire display which delete all lines saved in the scrollback buffer (xterm). +// +// CSI J +// +// See: https://vt100.net/docs/vt510-rm/ED.html +func EraseDisplay(n int) string { + var s string + if n > 0 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "J" +} + +// ED is an alias for [EraseDisplay]. +func ED(n int) string { + return EraseDisplay(n) +} + +// EraseDisplay constants. +// These are the possible values for the EraseDisplay function. +const ( + EraseScreenBelow = "\x1b[J" + EraseScreenAbove = "\x1b[1J" + EraseEntireScreen = "\x1b[2J" + EraseEntireDisplay = "\x1b[3J" +) + +// EraseLine (EL) clears the current line or parts of the line. Possible values: +// +// 0: Clear from cursor to end of line. +// 1: Clear from cursor to beginning of the line. +// 2: Clear entire line. +// +// The cursor position is not affected. +// +// CSI K +// +// See: https://vt100.net/docs/vt510-rm/EL.html +func EraseLine(n int) string { + var s string + if n > 0 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "K" +} + +// EL is an alias for [EraseLine]. +func EL(n int) string { + return EraseLine(n) +} + +// EraseLine constants. +// These are the possible values for the EraseLine function. +const ( + EraseLineRight = "\x1b[K" + EraseLineLeft = "\x1b[1K" + EraseEntireLine = "\x1b[2K" +) + +// ScrollUp (SU) scrolls the screen up n lines. New lines are added at the +// bottom of the screen. +// +// CSI Pn S +// +// See: https://vt100.net/docs/vt510-rm/SU.html +func ScrollUp(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "S" +} + +// PanDown is an alias for [ScrollUp]. +func PanDown(n int) string { + return ScrollUp(n) +} + +// SU is an alias for [ScrollUp]. +func SU(n int) string { + return ScrollUp(n) +} + +// ScrollDown (SD) scrolls the screen down n lines. New lines are added at the +// top of the screen. +// +// CSI Pn T +// +// See: https://vt100.net/docs/vt510-rm/SD.html +func ScrollDown(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "T" +} + +// PanUp is an alias for [ScrollDown]. +func PanUp(n int) string { + return ScrollDown(n) +} + +// SD is an alias for [ScrollDown]. +func SD(n int) string { + return ScrollDown(n) +} + +// InsertLine (IL) inserts n blank lines at the current cursor position. +// Existing lines are moved down. +// +// CSI Pn L +// +// See: https://vt100.net/docs/vt510-rm/IL.html +func InsertLine(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "L" +} + +// IL is an alias for [InsertLine]. +func IL(n int) string { + return InsertLine(n) +} + +// DeleteLine (DL) deletes n lines at the current cursor position. Existing +// lines are moved up. +// +// CSI Pn M +// +// See: https://vt100.net/docs/vt510-rm/DL.html +func DeleteLine(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "M" +} + +// DL is an alias for [DeleteLine]. +func DL(n int) string { + return DeleteLine(n) +} + +// SetTopBottomMargins (DECSTBM) sets the top and bottom margins for the scrolling +// region. The default is the entire screen. +// +// Default is 1 and the bottom of the screen. +// +// CSI Pt ; Pb r +// +// See: https://vt100.net/docs/vt510-rm/DECSTBM.html +func SetTopBottomMargins(top, bot int) string { + var t, b string + if top > 0 { + t = strconv.Itoa(top) + } + if bot > 0 { + b = strconv.Itoa(bot) + } + return "\x1b[" + t + ";" + b + "r" +} + +// DECSTBM is an alias for [SetTopBottomMargins]. +func DECSTBM(top, bot int) string { + return SetTopBottomMargins(top, bot) +} + +// SetLeftRightMargins (DECSLRM) sets the left and right margins for the scrolling +// region. +// +// Default is 1 and the right of the screen. +// +// CSI Pl ; Pr s +// +// See: https://vt100.net/docs/vt510-rm/DECSLRM.html +func SetLeftRightMargins(left, right int) string { + var l, r string + if left > 0 { + l = strconv.Itoa(left) + } + if right > 0 { + r = strconv.Itoa(right) + } + return "\x1b[" + l + ";" + r + "s" +} + +// DECSLRM is an alias for [SetLeftRightMargins]. +func DECSLRM(left, right int) string { + return SetLeftRightMargins(left, right) +} + +// SetScrollingRegion (DECSTBM) sets the top and bottom margins for the scrolling +// region. The default is the entire screen. +// +// CSI ; r +// +// See: https://vt100.net/docs/vt510-rm/DECSTBM.html +// +// Deprecated: use [SetTopBottomMargins] instead. +func SetScrollingRegion(t, b int) string { + if t < 0 { + t = 0 + } + if b < 0 { + b = 0 + } + return "\x1b[" + strconv.Itoa(t) + ";" + strconv.Itoa(b) + "r" +} + +// InsertCharacter (ICH) inserts n blank characters at the current cursor +// position. Existing characters move to the right. Characters moved past the +// right margin are lost. ICH has no effect outside the scrolling margins. +// +// Default is 1. +// +// CSI Pn @ +// +// See: https://vt100.net/docs/vt510-rm/ICH.html +func InsertCharacter(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "@" +} + +// ICH is an alias for [InsertCharacter]. +func ICH(n int) string { + return InsertCharacter(n) +} + +// DeleteCharacter (DCH) deletes n characters at the current cursor position. +// As the characters are deleted, the remaining characters move to the left and +// the cursor remains at the same position. +// +// Default is 1. +// +// CSI Pn P +// +// See: https://vt100.net/docs/vt510-rm/DCH.html +func DeleteCharacter(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "P" +} + +// DCH is an alias for [DeleteCharacter]. +func DCH(n int) string { + return DeleteCharacter(n) +} + +// SetTabEvery8Columns (DECST8C) sets the tab stops at every 8 columns. +// +// CSI ? 5 W +// +// See: https://vt100.net/docs/vt510-rm/DECST8C.html +const ( + SetTabEvery8Columns = "\x1b[?5W" + DECST8C = SetTabEvery8Columns +) + +// HorizontalTabSet (HTS) sets a horizontal tab stop at the current cursor +// column. +// +// This is equivalent to [HTS]. +// +// ESC H +// +// See: https://vt100.net/docs/vt510-rm/HTS.html +const HorizontalTabSet = "\x1bH" + +// TabClear (TBC) clears tab stops. +// +// Default is 0. +// +// Possible values: +// 0: Clear tab stop at the current column. (default) +// 3: Clear all tab stops. +// +// CSI Pn g +// +// See: https://vt100.net/docs/vt510-rm/TBC.html +func TabClear(n int) string { + var s string + if n > 0 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "g" +} + +// TBC is an alias for [TabClear]. +func TBC(n int) string { + return TabClear(n) +} + +// RequestPresentationStateReport (DECRQPSR) requests the terminal to send a +// report of the presentation state. This includes the cursor information [DECCIR], +// and tab stop [DECTABSR] reports. +// +// Default is 0. +// +// Possible values: +// 0: Error, request ignored. +// 1: Cursor information report [DECCIR]. +// 2: Tab stop report [DECTABSR]. +// +// CSI Ps $ w +// +// See: https://vt100.net/docs/vt510-rm/DECRQPSR.html +func RequestPresentationStateReport(n int) string { + var s string + if n > 0 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "$w" +} + +// DECRQPSR is an alias for [RequestPresentationStateReport]. +func DECRQPSR(n int) string { + return RequestPresentationStateReport(n) +} + +// TabStopReport (DECTABSR) is the response to a tab stop report request. +// It reports the tab stops set in the terminal. +// +// The response is a list of tab stops separated by a slash (/) character. +// +// DCS 2 $ u D ... D ST +// +// Where D is a decimal number representing a tab stop. +// +// See: https://vt100.net/docs/vt510-rm/DECTABSR.html +func TabStopReport(stops ...int) string { + var s []string //nolint:prealloc + for _, v := range stops { + s = append(s, strconv.Itoa(v)) + } + return "\x1bP2$u" + strings.Join(s, "/") + "\x1b\\" +} + +// DECTABSR is an alias for [TabStopReport]. +func DECTABSR(stops ...int) string { + return TabStopReport(stops...) +} + +// CursorInformationReport (DECCIR) is the response to a cursor information +// report request. It reports the cursor position, visual attributes, and +// character protection attributes. It also reports the status of origin mode +// [DECOM] and the current active character set. +// +// The response is a list of values separated by a semicolon (;) character. +// +// DCS 1 $ u D ... D ST +// +// Where D is a decimal number representing a value. +// +// See: https://vt100.net/docs/vt510-rm/DECCIR.html +func CursorInformationReport(values ...int) string { + var s []string //nolint:prealloc + for _, v := range values { + s = append(s, strconv.Itoa(v)) + } + return "\x1bP1$u" + strings.Join(s, ";") + "\x1b\\" +} + +// DECCIR is an alias for [CursorInformationReport]. +func DECCIR(values ...int) string { + return CursorInformationReport(values...) +} + +// RepeatPreviousCharacter (REP) repeats the previous character n times. +// This is identical to typing the same character n times. +// +// Default is 1. +// +// CSI Pn b +// +// See: ECMA-48 § 8.3.103. +func RepeatPreviousCharacter(n int) string { + var s string + if n > 1 { + s = strconv.Itoa(n) + } + return "\x1b[" + s + "b" +} + +// REP is an alias for [RepeatPreviousCharacter]. +func REP(n int) string { + return RepeatPreviousCharacter(n) +} diff --git a/vendor/github.com/charmbracelet/x/ansi/sgr.go b/vendor/github.com/charmbracelet/x/ansi/sgr.go new file mode 100644 index 000000000..5e6d05dfe --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/sgr.go @@ -0,0 +1,79 @@ +package ansi + +// SelectGraphicRendition (SGR) is a command that sets display attributes. +// +// Default is 0. +// +// CSI Ps ; Ps ... m +// +// See: https://vt100.net/docs/vt510-rm/SGR.html +func SelectGraphicRendition(ps ...Attr) string { + if len(ps) == 0 { + return ResetStyle + } + + return NewStyle(ps...).String() +} + +// SGR is an alias for [SelectGraphicRendition]. +func SGR(ps ...Attr) string { + return SelectGraphicRendition(ps...) +} + +var attrStrings = map[int]string{ + ResetAttr: resetAttr, + BoldAttr: boldAttr, + FaintAttr: faintAttr, + ItalicAttr: italicAttr, + UnderlineAttr: underlineAttr, + SlowBlinkAttr: slowBlinkAttr, + RapidBlinkAttr: rapidBlinkAttr, + ReverseAttr: reverseAttr, + ConcealAttr: concealAttr, + StrikethroughAttr: strikethroughAttr, + NormalIntensityAttr: normalIntensityAttr, + NoItalicAttr: noItalicAttr, + NoUnderlineAttr: noUnderlineAttr, + NoBlinkAttr: noBlinkAttr, + NoReverseAttr: noReverseAttr, + NoConcealAttr: noConcealAttr, + NoStrikethroughAttr: noStrikethroughAttr, + BlackForegroundColorAttr: blackForegroundColorAttr, + RedForegroundColorAttr: redForegroundColorAttr, + GreenForegroundColorAttr: greenForegroundColorAttr, + YellowForegroundColorAttr: yellowForegroundColorAttr, + BlueForegroundColorAttr: blueForegroundColorAttr, + MagentaForegroundColorAttr: magentaForegroundColorAttr, + CyanForegroundColorAttr: cyanForegroundColorAttr, + WhiteForegroundColorAttr: whiteForegroundColorAttr, + ExtendedForegroundColorAttr: extendedForegroundColorAttr, + DefaultForegroundColorAttr: defaultForegroundColorAttr, + BlackBackgroundColorAttr: blackBackgroundColorAttr, + RedBackgroundColorAttr: redBackgroundColorAttr, + GreenBackgroundColorAttr: greenBackgroundColorAttr, + YellowBackgroundColorAttr: yellowBackgroundColorAttr, + BlueBackgroundColorAttr: blueBackgroundColorAttr, + MagentaBackgroundColorAttr: magentaBackgroundColorAttr, + CyanBackgroundColorAttr: cyanBackgroundColorAttr, + WhiteBackgroundColorAttr: whiteBackgroundColorAttr, + ExtendedBackgroundColorAttr: extendedBackgroundColorAttr, + DefaultBackgroundColorAttr: defaultBackgroundColorAttr, + ExtendedUnderlineColorAttr: extendedUnderlineColorAttr, + DefaultUnderlineColorAttr: defaultUnderlineColorAttr, + BrightBlackForegroundColorAttr: brightBlackForegroundColorAttr, + BrightRedForegroundColorAttr: brightRedForegroundColorAttr, + BrightGreenForegroundColorAttr: brightGreenForegroundColorAttr, + BrightYellowForegroundColorAttr: brightYellowForegroundColorAttr, + BrightBlueForegroundColorAttr: brightBlueForegroundColorAttr, + BrightMagentaForegroundColorAttr: brightMagentaForegroundColorAttr, + BrightCyanForegroundColorAttr: brightCyanForegroundColorAttr, + BrightWhiteForegroundColorAttr: brightWhiteForegroundColorAttr, + BrightBlackBackgroundColorAttr: brightBlackBackgroundColorAttr, + BrightRedBackgroundColorAttr: brightRedBackgroundColorAttr, + BrightGreenBackgroundColorAttr: brightGreenBackgroundColorAttr, + BrightYellowBackgroundColorAttr: brightYellowBackgroundColorAttr, + BrightBlueBackgroundColorAttr: brightBlueBackgroundColorAttr, + BrightMagentaBackgroundColorAttr: brightMagentaBackgroundColorAttr, + BrightCyanBackgroundColorAttr: brightCyanBackgroundColorAttr, + BrightWhiteBackgroundColorAttr: brightWhiteBackgroundColorAttr, +} diff --git a/vendor/github.com/charmbracelet/x/ansi/status.go b/vendor/github.com/charmbracelet/x/ansi/status.go new file mode 100644 index 000000000..3adfb028e --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/status.go @@ -0,0 +1,168 @@ +package ansi + +import ( + "strconv" + "strings" +) + +// StatusReport represents a terminal status report. +type StatusReport interface { + // StatusReport returns the status report identifier. + StatusReport() int +} + +// ANSIStatusReport represents an ANSI terminal status report. +type ANSIStatusReport int //nolint:revive + +// StatusReport returns the status report identifier. +func (s ANSIStatusReport) StatusReport() int { + return int(s) +} + +// DECStatusReport represents a DEC terminal status report. +type DECStatusReport int + +// StatusReport returns the status report identifier. +func (s DECStatusReport) StatusReport() int { + return int(s) +} + +// DeviceStatusReport (DSR) is a control sequence that reports the terminal's +// status. +// The terminal responds with a DSR sequence. +// +// CSI Ps n +// CSI ? Ps n +// +// If one of the statuses is a [DECStatus], the sequence will use the DEC +// format. +// +// See also https://vt100.net/docs/vt510-rm/DSR.html +func DeviceStatusReport(statues ...StatusReport) string { + var dec bool + list := make([]string, len(statues)) + seq := "\x1b[" + for i, status := range statues { + list[i] = strconv.Itoa(status.StatusReport()) + switch status.(type) { + case DECStatusReport: + dec = true + } + } + if dec { + seq += "?" + } + return seq + strings.Join(list, ";") + "n" +} + +// DSR is an alias for [DeviceStatusReport]. +func DSR(status StatusReport) string { + return DeviceStatusReport(status) +} + +// RequestCursorPositionReport is an escape sequence that requests the current +// cursor position. +// +// CSI 6 n +// +// The terminal will report the cursor position as a CSI sequence in the +// following format: +// +// CSI Pl ; Pc R +// +// Where Pl is the line number and Pc is the column number. +// See: https://vt100.net/docs/vt510-rm/CPR.html +const RequestCursorPositionReport = "\x1b[6n" + +// RequestExtendedCursorPositionReport (DECXCPR) is a sequence for requesting +// the cursor position report including the current page number. +// +// CSI ? 6 n +// +// The terminal will report the cursor position as a CSI sequence in the +// following format: +// +// CSI ? Pl ; Pc ; Pp R +// +// Where Pl is the line number, Pc is the column number, and Pp is the page +// number. +// See: https://vt100.net/docs/vt510-rm/DECXCPR.html +const RequestExtendedCursorPositionReport = "\x1b[?6n" + +// RequestLightDarkReport is a control sequence that requests the terminal to +// report its operating system light/dark color preference. Supported terminals +// should respond with a [LightDarkReport] sequence as follows: +// +// CSI ? 997 ; 1 n for dark mode +// CSI ? 997 ; 2 n for light mode +// +// See: https://contour-terminal.org/vt-extensions/color-palette-update-notifications/ +const RequestLightDarkReport = "\x1b[?996n" + +// CursorPositionReport (CPR) is a control sequence that reports the cursor's +// position. +// +// CSI Pl ; Pc R +// +// Where Pl is the line number and Pc is the column number. +// +// See also https://vt100.net/docs/vt510-rm/CPR.html +func CursorPositionReport(line, column int) string { + if line < 1 { + line = 1 + } + if column < 1 { + column = 1 + } + return "\x1b[" + strconv.Itoa(line) + ";" + strconv.Itoa(column) + "R" +} + +// CPR is an alias for [CursorPositionReport]. +func CPR(line, column int) string { + return CursorPositionReport(line, column) +} + +// ExtendedCursorPositionReport (DECXCPR) is a control sequence that reports the +// cursor's position along with the page number (optional). +// +// CSI ? Pl ; Pc R +// CSI ? Pl ; Pc ; Pv R +// +// Where Pl is the line number, Pc is the column number, and Pv is the page +// number. +// +// If the page number is zero or negative, the returned sequence won't include +// the page number. +// +// See also https://vt100.net/docs/vt510-rm/DECXCPR.html +func ExtendedCursorPositionReport(line, column, page int) string { + if line < 1 { + line = 1 + } + if column < 1 { + column = 1 + } + if page < 1 { + return "\x1b[?" + strconv.Itoa(line) + ";" + strconv.Itoa(column) + "R" + } + return "\x1b[?" + strconv.Itoa(line) + ";" + strconv.Itoa(column) + ";" + strconv.Itoa(page) + "R" +} + +// DECXCPR is an alias for [ExtendedCursorPositionReport]. +func DECXCPR(line, column, page int) string { + return ExtendedCursorPositionReport(line, column, page) +} + +// LightDarkReport is a control sequence that reports the terminal's operating +// system light/dark color preference. +// +// CSI ? 997 ; 1 n for dark mode +// CSI ? 997 ; 2 n for light mode +// +// See: https://contour-terminal.org/vt-extensions/color-palette-update-notifications/ +func LightDarkReport(dark bool) string { + if dark { + return "\x1b[?997;1n" + } + return "\x1b[?997;2n" +} diff --git a/vendor/github.com/charmbracelet/x/ansi/style.go b/vendor/github.com/charmbracelet/x/ansi/style.go new file mode 100644 index 000000000..d8a7efaec --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/style.go @@ -0,0 +1,673 @@ +package ansi + +import ( + "image/color" + "strconv" + "strings" +) + +// ResetStyle is a SGR (Select Graphic Rendition) style sequence that resets +// all attributes. +// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters +const ResetStyle = "\x1b[m" + +// Attr is a SGR (Select Graphic Rendition) style attribute. +type Attr = int + +// Style represents an ANSI SGR (Select Graphic Rendition) style. +type Style []string + +// NewStyle returns a new style with the given attributes. +func NewStyle(attrs ...Attr) Style { + if len(attrs) == 0 { + return Style{} + } + s := make(Style, 0, len(attrs)) + for _, a := range attrs { + attr, ok := attrStrings[a] + if ok { + s = append(s, attr) + } else { + if a < 0 { + a = 0 + } + s = append(s, strconv.Itoa(a)) + } + } + return s +} + +// String returns the ANSI SGR (Select Graphic Rendition) style sequence for +// the given style. +func (s Style) String() string { + if len(s) == 0 { + return ResetStyle + } + return "\x1b[" + strings.Join(s, ";") + "m" +} + +// Styled returns a styled string with the given style applied. +func (s Style) Styled(str string) string { + if len(s) == 0 { + return str + } + return s.String() + str + ResetStyle +} + +// Reset appends the reset style attribute to the style. +func (s Style) Reset() Style { + return append(s, resetAttr) +} + +// Bold appends the bold style attribute to the style. +func (s Style) Bold() Style { + return append(s, boldAttr) +} + +// Faint appends the faint style attribute to the style. +func (s Style) Faint() Style { + return append(s, faintAttr) +} + +// Italic appends the italic style attribute to the style. +func (s Style) Italic() Style { + return append(s, italicAttr) +} + +// Underline appends the underline style attribute to the style. +func (s Style) Underline() Style { + return append(s, underlineAttr) +} + +// UnderlineStyle appends the underline style attribute to the style. +func (s Style) UnderlineStyle(u UnderlineStyle) Style { + switch u { + case NoUnderlineStyle: + return s.NoUnderline() + case SingleUnderlineStyle: + return s.Underline() + case DoubleUnderlineStyle: + return append(s, doubleUnderlineStyle) + case CurlyUnderlineStyle: + return append(s, curlyUnderlineStyle) + case DottedUnderlineStyle: + return append(s, dottedUnderlineStyle) + case DashedUnderlineStyle: + return append(s, dashedUnderlineStyle) + } + return s +} + +// DoubleUnderline appends the double underline style attribute to the style. +// This is a convenience method for UnderlineStyle(DoubleUnderlineStyle). +func (s Style) DoubleUnderline() Style { + return s.UnderlineStyle(DoubleUnderlineStyle) +} + +// CurlyUnderline appends the curly underline style attribute to the style. +// This is a convenience method for UnderlineStyle(CurlyUnderlineStyle). +func (s Style) CurlyUnderline() Style { + return s.UnderlineStyle(CurlyUnderlineStyle) +} + +// DottedUnderline appends the dotted underline style attribute to the style. +// This is a convenience method for UnderlineStyle(DottedUnderlineStyle). +func (s Style) DottedUnderline() Style { + return s.UnderlineStyle(DottedUnderlineStyle) +} + +// DashedUnderline appends the dashed underline style attribute to the style. +// This is a convenience method for UnderlineStyle(DashedUnderlineStyle). +func (s Style) DashedUnderline() Style { + return s.UnderlineStyle(DashedUnderlineStyle) +} + +// SlowBlink appends the slow blink style attribute to the style. +func (s Style) SlowBlink() Style { + return append(s, slowBlinkAttr) +} + +// RapidBlink appends the rapid blink style attribute to the style. +func (s Style) RapidBlink() Style { + return append(s, rapidBlinkAttr) +} + +// Reverse appends the reverse style attribute to the style. +func (s Style) Reverse() Style { + return append(s, reverseAttr) +} + +// Conceal appends the conceal style attribute to the style. +func (s Style) Conceal() Style { + return append(s, concealAttr) +} + +// Strikethrough appends the strikethrough style attribute to the style. +func (s Style) Strikethrough() Style { + return append(s, strikethroughAttr) +} + +// NormalIntensity appends the normal intensity style attribute to the style. +func (s Style) NormalIntensity() Style { + return append(s, normalIntensityAttr) +} + +// NoItalic appends the no italic style attribute to the style. +func (s Style) NoItalic() Style { + return append(s, noItalicAttr) +} + +// NoUnderline appends the no underline style attribute to the style. +func (s Style) NoUnderline() Style { + return append(s, noUnderlineAttr) +} + +// NoBlink appends the no blink style attribute to the style. +func (s Style) NoBlink() Style { + return append(s, noBlinkAttr) +} + +// NoReverse appends the no reverse style attribute to the style. +func (s Style) NoReverse() Style { + return append(s, noReverseAttr) +} + +// NoConceal appends the no conceal style attribute to the style. +func (s Style) NoConceal() Style { + return append(s, noConcealAttr) +} + +// NoStrikethrough appends the no strikethrough style attribute to the style. +func (s Style) NoStrikethrough() Style { + return append(s, noStrikethroughAttr) +} + +// DefaultForegroundColor appends the default foreground color style attribute to the style. +func (s Style) DefaultForegroundColor() Style { + return append(s, defaultForegroundColorAttr) +} + +// DefaultBackgroundColor appends the default background color style attribute to the style. +func (s Style) DefaultBackgroundColor() Style { + return append(s, defaultBackgroundColorAttr) +} + +// DefaultUnderlineColor appends the default underline color style attribute to the style. +func (s Style) DefaultUnderlineColor() Style { + return append(s, defaultUnderlineColorAttr) +} + +// ForegroundColor appends the foreground color style attribute to the style. +func (s Style) ForegroundColor(c Color) Style { + return append(s, foregroundColorString(c)) +} + +// BackgroundColor appends the background color style attribute to the style. +func (s Style) BackgroundColor(c Color) Style { + return append(s, backgroundColorString(c)) +} + +// UnderlineColor appends the underline color style attribute to the style. +func (s Style) UnderlineColor(c Color) Style { + return append(s, underlineColorString(c)) +} + +// UnderlineStyle represents an ANSI SGR (Select Graphic Rendition) underline +// style. +type UnderlineStyle = byte + +const ( + doubleUnderlineStyle = "4:2" + curlyUnderlineStyle = "4:3" + dottedUnderlineStyle = "4:4" + dashedUnderlineStyle = "4:5" +) + +const ( + // NoUnderlineStyle is the default underline style. + NoUnderlineStyle UnderlineStyle = iota + // SingleUnderlineStyle is a single underline style. + SingleUnderlineStyle + // DoubleUnderlineStyle is a double underline style. + DoubleUnderlineStyle + // CurlyUnderlineStyle is a curly underline style. + CurlyUnderlineStyle + // DottedUnderlineStyle is a dotted underline style. + DottedUnderlineStyle + // DashedUnderlineStyle is a dashed underline style. + DashedUnderlineStyle +) + +// SGR (Select Graphic Rendition) style attributes. +// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters +const ( + ResetAttr Attr = 0 + BoldAttr Attr = 1 + FaintAttr Attr = 2 + ItalicAttr Attr = 3 + UnderlineAttr Attr = 4 + SlowBlinkAttr Attr = 5 + RapidBlinkAttr Attr = 6 + ReverseAttr Attr = 7 + ConcealAttr Attr = 8 + StrikethroughAttr Attr = 9 + NormalIntensityAttr Attr = 22 + NoItalicAttr Attr = 23 + NoUnderlineAttr Attr = 24 + NoBlinkAttr Attr = 25 + NoReverseAttr Attr = 27 + NoConcealAttr Attr = 28 + NoStrikethroughAttr Attr = 29 + BlackForegroundColorAttr Attr = 30 + RedForegroundColorAttr Attr = 31 + GreenForegroundColorAttr Attr = 32 + YellowForegroundColorAttr Attr = 33 + BlueForegroundColorAttr Attr = 34 + MagentaForegroundColorAttr Attr = 35 + CyanForegroundColorAttr Attr = 36 + WhiteForegroundColorAttr Attr = 37 + ExtendedForegroundColorAttr Attr = 38 + DefaultForegroundColorAttr Attr = 39 + BlackBackgroundColorAttr Attr = 40 + RedBackgroundColorAttr Attr = 41 + GreenBackgroundColorAttr Attr = 42 + YellowBackgroundColorAttr Attr = 43 + BlueBackgroundColorAttr Attr = 44 + MagentaBackgroundColorAttr Attr = 45 + CyanBackgroundColorAttr Attr = 46 + WhiteBackgroundColorAttr Attr = 47 + ExtendedBackgroundColorAttr Attr = 48 + DefaultBackgroundColorAttr Attr = 49 + ExtendedUnderlineColorAttr Attr = 58 + DefaultUnderlineColorAttr Attr = 59 + BrightBlackForegroundColorAttr Attr = 90 + BrightRedForegroundColorAttr Attr = 91 + BrightGreenForegroundColorAttr Attr = 92 + BrightYellowForegroundColorAttr Attr = 93 + BrightBlueForegroundColorAttr Attr = 94 + BrightMagentaForegroundColorAttr Attr = 95 + BrightCyanForegroundColorAttr Attr = 96 + BrightWhiteForegroundColorAttr Attr = 97 + BrightBlackBackgroundColorAttr Attr = 100 + BrightRedBackgroundColorAttr Attr = 101 + BrightGreenBackgroundColorAttr Attr = 102 + BrightYellowBackgroundColorAttr Attr = 103 + BrightBlueBackgroundColorAttr Attr = 104 + BrightMagentaBackgroundColorAttr Attr = 105 + BrightCyanBackgroundColorAttr Attr = 106 + BrightWhiteBackgroundColorAttr Attr = 107 + + RGBColorIntroducerAttr Attr = 2 + ExtendedColorIntroducerAttr Attr = 5 +) + +const ( + resetAttr = "0" + boldAttr = "1" + faintAttr = "2" + italicAttr = "3" + underlineAttr = "4" + slowBlinkAttr = "5" + rapidBlinkAttr = "6" + reverseAttr = "7" + concealAttr = "8" + strikethroughAttr = "9" + normalIntensityAttr = "22" + noItalicAttr = "23" + noUnderlineAttr = "24" + noBlinkAttr = "25" + noReverseAttr = "27" + noConcealAttr = "28" + noStrikethroughAttr = "29" + blackForegroundColorAttr = "30" + redForegroundColorAttr = "31" + greenForegroundColorAttr = "32" + yellowForegroundColorAttr = "33" + blueForegroundColorAttr = "34" + magentaForegroundColorAttr = "35" + cyanForegroundColorAttr = "36" + whiteForegroundColorAttr = "37" + extendedForegroundColorAttr = "38" + defaultForegroundColorAttr = "39" + blackBackgroundColorAttr = "40" + redBackgroundColorAttr = "41" + greenBackgroundColorAttr = "42" + yellowBackgroundColorAttr = "43" + blueBackgroundColorAttr = "44" + magentaBackgroundColorAttr = "45" + cyanBackgroundColorAttr = "46" + whiteBackgroundColorAttr = "47" + extendedBackgroundColorAttr = "48" + defaultBackgroundColorAttr = "49" + extendedUnderlineColorAttr = "58" + defaultUnderlineColorAttr = "59" + brightBlackForegroundColorAttr = "90" + brightRedForegroundColorAttr = "91" + brightGreenForegroundColorAttr = "92" + brightYellowForegroundColorAttr = "93" + brightBlueForegroundColorAttr = "94" + brightMagentaForegroundColorAttr = "95" + brightCyanForegroundColorAttr = "96" + brightWhiteForegroundColorAttr = "97" + brightBlackBackgroundColorAttr = "100" + brightRedBackgroundColorAttr = "101" + brightGreenBackgroundColorAttr = "102" + brightYellowBackgroundColorAttr = "103" + brightBlueBackgroundColorAttr = "104" + brightMagentaBackgroundColorAttr = "105" + brightCyanBackgroundColorAttr = "106" + brightWhiteBackgroundColorAttr = "107" +) + +// foregroundColorString returns the style SGR attribute for the given +// foreground color. +// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters +func foregroundColorString(c Color) string { + switch c := c.(type) { + case BasicColor: + // 3-bit or 4-bit ANSI foreground + // "3" or "9" where n is the color number from 0 to 7 + switch c { + case Black: + return blackForegroundColorAttr + case Red: + return redForegroundColorAttr + case Green: + return greenForegroundColorAttr + case Yellow: + return yellowForegroundColorAttr + case Blue: + return blueForegroundColorAttr + case Magenta: + return magentaForegroundColorAttr + case Cyan: + return cyanForegroundColorAttr + case White: + return whiteForegroundColorAttr + case BrightBlack: + return brightBlackForegroundColorAttr + case BrightRed: + return brightRedForegroundColorAttr + case BrightGreen: + return brightGreenForegroundColorAttr + case BrightYellow: + return brightYellowForegroundColorAttr + case BrightBlue: + return brightBlueForegroundColorAttr + case BrightMagenta: + return brightMagentaForegroundColorAttr + case BrightCyan: + return brightCyanForegroundColorAttr + case BrightWhite: + return brightWhiteForegroundColorAttr + } + case ExtendedColor: + // 256-color ANSI foreground + // "38;5;" + return "38;5;" + strconv.FormatUint(uint64(c), 10) + case TrueColor, color.Color: + // 24-bit "true color" foreground + // "38;2;;;" + r, g, b, _ := c.RGBA() + return "38;2;" + + strconv.FormatUint(uint64(shift(r)), 10) + ";" + + strconv.FormatUint(uint64(shift(g)), 10) + ";" + + strconv.FormatUint(uint64(shift(b)), 10) + } + return defaultForegroundColorAttr +} + +// backgroundColorString returns the style SGR attribute for the given +// background color. +// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters +func backgroundColorString(c Color) string { + switch c := c.(type) { + case BasicColor: + // 3-bit or 4-bit ANSI foreground + // "4" or "10" where n is the color number from 0 to 7 + switch c { + case Black: + return blackBackgroundColorAttr + case Red: + return redBackgroundColorAttr + case Green: + return greenBackgroundColorAttr + case Yellow: + return yellowBackgroundColorAttr + case Blue: + return blueBackgroundColorAttr + case Magenta: + return magentaBackgroundColorAttr + case Cyan: + return cyanBackgroundColorAttr + case White: + return whiteBackgroundColorAttr + case BrightBlack: + return brightBlackBackgroundColorAttr + case BrightRed: + return brightRedBackgroundColorAttr + case BrightGreen: + return brightGreenBackgroundColorAttr + case BrightYellow: + return brightYellowBackgroundColorAttr + case BrightBlue: + return brightBlueBackgroundColorAttr + case BrightMagenta: + return brightMagentaBackgroundColorAttr + case BrightCyan: + return brightCyanBackgroundColorAttr + case BrightWhite: + return brightWhiteBackgroundColorAttr + } + case ExtendedColor: + // 256-color ANSI foreground + // "48;5;" + return "48;5;" + strconv.FormatUint(uint64(c), 10) + case TrueColor, color.Color: + // 24-bit "true color" foreground + // "38;2;;;" + r, g, b, _ := c.RGBA() + return "48;2;" + + strconv.FormatUint(uint64(shift(r)), 10) + ";" + + strconv.FormatUint(uint64(shift(g)), 10) + ";" + + strconv.FormatUint(uint64(shift(b)), 10) + } + return defaultBackgroundColorAttr +} + +// underlineColorString returns the style SGR attribute for the given underline +// color. +// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters +func underlineColorString(c Color) string { + switch c := c.(type) { + // NOTE: we can't use 3-bit and 4-bit ANSI color codes with underline + // color, use 256-color instead. + // + // 256-color ANSI underline color + // "58;5;" + case BasicColor: + return "58;5;" + strconv.FormatUint(uint64(c), 10) + case ExtendedColor: + return "58;5;" + strconv.FormatUint(uint64(c), 10) + case TrueColor, color.Color: + // 24-bit "true color" foreground + // "38;2;;;" + r, g, b, _ := c.RGBA() + return "58;2;" + + strconv.FormatUint(uint64(shift(r)), 10) + ";" + + strconv.FormatUint(uint64(shift(g)), 10) + ";" + + strconv.FormatUint(uint64(shift(b)), 10) + } + return defaultUnderlineColorAttr +} + +// ReadStyleColor decodes a color from a slice of parameters. It returns the +// number of parameters read and the color. This function is used to read SGR +// color parameters following the ITU T.416 standard. +// +// It supports reading the following color types: +// - 0: implementation defined +// - 1: transparent +// - 2: RGB direct color +// - 3: CMY direct color +// - 4: CMYK direct color +// - 5: indexed color +// - 6: RGBA direct color (WezTerm extension) +// +// The parameters can be separated by semicolons (;) or colons (:). Mixing +// separators is not allowed. +// +// The specs supports defining a color space id, a color tolerance value, and a +// tolerance color space id. However, these values have no effect on the +// returned color and will be ignored. +// +// This implementation includes a few modifications to the specs: +// 1. Support for legacy color values separated by semicolons (;) with respect to RGB, and indexed colors +// 2. Support ignoring and omitting the color space id (second parameter) with respect to RGB colors +// 3. Support ignoring and omitting the 6th parameter with respect to RGB and CMY colors +// 4. Support reading RGBA colors +func ReadStyleColor(params Params, co *color.Color) (n int) { + if len(params) < 2 { // Need at least SGR type and color type + return 0 + } + + // First parameter indicates one of 38, 48, or 58 (foreground, background, or underline) + s := params[0] + p := params[1] + colorType := p.Param(0) + n = 2 + + paramsfn := func() (p1, p2, p3, p4 int) { + // Where should we start reading the color? + switch { + case s.HasMore() && p.HasMore() && len(params) > 8 && params[2].HasMore() && params[3].HasMore() && params[4].HasMore() && params[5].HasMore() && params[6].HasMore() && params[7].HasMore(): + // We have color space id, a 6th parameter, a tolerance value, and a tolerance color space + n += 7 + return params[3].Param(0), params[4].Param(0), params[5].Param(0), params[6].Param(0) + case s.HasMore() && p.HasMore() && len(params) > 7 && params[2].HasMore() && params[3].HasMore() && params[4].HasMore() && params[5].HasMore() && params[6].HasMore(): + // We have color space id, a 6th parameter, and a tolerance value + n += 6 + return params[3].Param(0), params[4].Param(0), params[5].Param(0), params[6].Param(0) + case s.HasMore() && p.HasMore() && len(params) > 6 && params[2].HasMore() && params[3].HasMore() && params[4].HasMore() && params[5].HasMore(): + // We have color space id and a 6th parameter + // 48 : 4 : : 1 : 2 : 3 :4 + n += 5 + return params[3].Param(0), params[4].Param(0), params[5].Param(0), params[6].Param(0) + case s.HasMore() && p.HasMore() && len(params) > 5 && params[2].HasMore() && params[3].HasMore() && params[4].HasMore() && !params[5].HasMore(): + // We have color space + // 48 : 3 : : 1 : 2 : 3 + n += 4 + return params[3].Param(0), params[4].Param(0), params[5].Param(0), -1 + case s.HasMore() && p.HasMore() && p.Param(0) == 2 && params[2].HasMore() && params[3].HasMore() && !params[4].HasMore(): + // We have color values separated by colons (:) + // 48 : 2 : 1 : 2 : 3 + fallthrough + case !s.HasMore() && !p.HasMore() && p.Param(0) == 2 && !params[2].HasMore() && !params[3].HasMore() && !params[4].HasMore(): + // Support legacy color values separated by semicolons (;) + // 48 ; 2 ; 1 ; 2 ; 3 + n += 3 + return params[2].Param(0), params[3].Param(0), params[4].Param(0), -1 + } + // Ambiguous SGR color + return -1, -1, -1, -1 + } + + switch colorType { + case 0: // implementation defined + return 2 + case 1: // transparent + *co = color.Transparent + return 2 + case 2: // RGB direct color + if len(params) < 5 { + return 0 + } + + r, g, b, _ := paramsfn() + if r == -1 || g == -1 || b == -1 { + return 0 + } + + *co = color.RGBA{ + R: uint8(r), //nolint:gosec + G: uint8(g), //nolint:gosec + B: uint8(b), //nolint:gosec + A: 0xff, + } + return //nolint:nakedret + + case 3: // CMY direct color + if len(params) < 5 { + return 0 + } + + c, m, y, _ := paramsfn() + if c == -1 || m == -1 || y == -1 { + return 0 + } + + *co = color.CMYK{ + C: uint8(c), //nolint:gosec + M: uint8(m), //nolint:gosec + Y: uint8(y), //nolint:gosec + K: 0, + } + return //nolint:nakedret + + case 4: // CMYK direct color + if len(params) < 6 { + return 0 + } + + c, m, y, k := paramsfn() + if c == -1 || m == -1 || y == -1 || k == -1 { + return 0 + } + + *co = color.CMYK{ + C: uint8(c), //nolint:gosec + M: uint8(m), //nolint:gosec + Y: uint8(y), //nolint:gosec + K: uint8(k), //nolint:gosec + } + return //nolint:nakedret + + case 5: // indexed color + if len(params) < 3 { + return 0 + } + switch { + case s.HasMore() && p.HasMore() && !params[2].HasMore(): + // Colon separated indexed color + // 38 : 5 : 234 + case !s.HasMore() && !p.HasMore() && !params[2].HasMore(): + // Legacy semicolon indexed color + // 38 ; 5 ; 234 + default: + return 0 + } + *co = ExtendedColor(params[2].Param(0)) //nolint:gosec + return 3 + + case 6: // RGBA direct color + if len(params) < 6 { + return 0 + } + + r, g, b, a := paramsfn() + if r == -1 || g == -1 || b == -1 || a == -1 { + return 0 + } + + *co = color.RGBA{ + R: uint8(r), //nolint:gosec + G: uint8(g), //nolint:gosec + B: uint8(b), //nolint:gosec + A: uint8(a), //nolint:gosec + } + return //nolint:nakedret + + default: + return 0 + } +} diff --git a/vendor/github.com/charmbracelet/x/ansi/termcap.go b/vendor/github.com/charmbracelet/x/ansi/termcap.go new file mode 100644 index 000000000..b59aa4203 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/termcap.go @@ -0,0 +1,41 @@ +package ansi + +import ( + "encoding/hex" + "strings" +) + +// XTGETTCAP (RequestTermcap) requests Termcap/Terminfo strings. +// +// DCS + q ST +// +// Where is a list of Termcap/Terminfo capabilities, encoded in 2-digit +// hexadecimals, separated by semicolons. +// +// See: https://man7.org/linux/man-pages/man5/terminfo.5.html +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands +func XTGETTCAP(caps ...string) string { + if len(caps) == 0 { + return "" + } + + s := "\x1bP+q" + for i, c := range caps { + if i > 0 { + s += ";" + } + s += strings.ToUpper(hex.EncodeToString([]byte(c))) + } + + return s + "\x1b\\" +} + +// RequestTermcap is an alias for [XTGETTCAP]. +func RequestTermcap(caps ...string) string { + return XTGETTCAP(caps...) +} + +// RequestTerminfo is an alias for [XTGETTCAP]. +func RequestTerminfo(caps ...string) string { + return XTGETTCAP(caps...) +} diff --git a/vendor/github.com/charmbracelet/x/ansi/title.go b/vendor/github.com/charmbracelet/x/ansi/title.go new file mode 100644 index 000000000..54ef94235 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/title.go @@ -0,0 +1,48 @@ +package ansi + +// SetIconNameWindowTitle returns a sequence for setting the icon name and +// window title. +// +// OSC 0 ; title ST +// OSC 0 ; title BEL +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Operating-System-Commands +func SetIconNameWindowTitle(s string) string { + return "\x1b]0;" + s + "\x07" +} + +// SetIconName returns a sequence for setting the icon name. +// +// OSC 1 ; title ST +// OSC 1 ; title BEL +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Operating-System-Commands +func SetIconName(s string) string { + return "\x1b]1;" + s + "\x07" +} + +// SetWindowTitle returns a sequence for setting the window title. +// +// OSC 2 ; title ST +// OSC 2 ; title BEL +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Operating-System-Commands +func SetWindowTitle(s string) string { + return "\x1b]2;" + s + "\x07" +} + +// DECSWT is a sequence for setting the window title. +// +// This is an alias for [SetWindowTitle]("1;"). +// See: EK-VT520-RM 5–156 https://vt100.net/dec/ek-vt520-rm.pdf +func DECSWT(name string) string { + return SetWindowTitle("1;" + name) +} + +// DECSIN is a sequence for setting the icon name. +// +// This is an alias for [SetWindowTitle]("L;"). +// See: EK-VT520-RM 5–134 https://vt100.net/dec/ek-vt520-rm.pdf +func DECSIN(name string) string { + return SetWindowTitle("L;" + name) +} diff --git a/vendor/github.com/charmbracelet/x/ansi/truncate.go b/vendor/github.com/charmbracelet/x/ansi/truncate.go new file mode 100644 index 000000000..3f541fa56 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/truncate.go @@ -0,0 +1,299 @@ +package ansi + +import ( + "bytes" + + "github.com/charmbracelet/x/ansi/parser" + "github.com/mattn/go-runewidth" + "github.com/rivo/uniseg" +) + +// Cut the string, without adding any prefix or tail strings. This function is +// aware of ANSI escape codes and will not break them, and accounts for +// wide-characters (such as East-Asian characters and emojis). +// This treats the text as a sequence of graphemes. +func Cut(s string, left, right int) string { + return cut(GraphemeWidth, s, left, right) +} + +// CutWc the string, without adding any prefix or tail strings. This function is +// aware of ANSI escape codes and will not break them, and accounts for +// wide-characters (such as East-Asian characters and emojis). +// Note that the [left] parameter is inclusive, while [right] isn't, +// which is to say it'll return `[left, right)`. +// +// This treats the text as a sequence of wide characters and runes. +func CutWc(s string, left, right int) string { + return cut(WcWidth, s, left, right) +} + +func cut(m Method, s string, left, right int) string { + if right <= left { + return "" + } + + truncate := Truncate + truncateLeft := TruncateLeft + if m == WcWidth { + truncate = TruncateWc + truncateLeft = TruncateWc + } + + if left == 0 { + return truncate(s, right, "") + } + return truncateLeft(truncate(s, right, ""), left, "") +} + +// Truncate truncates a string to a given length, adding a tail to the end if +// the string is longer than the given length. This function is aware of ANSI +// escape codes and will not break them, and accounts for wide-characters (such +// as East-Asian characters and emojis). +// This treats the text as a sequence of graphemes. +func Truncate(s string, length int, tail string) string { + return truncate(GraphemeWidth, s, length, tail) +} + +// TruncateWc truncates a string to a given length, adding a tail to the end if +// the string is longer than the given length. This function is aware of ANSI +// escape codes and will not break them, and accounts for wide-characters (such +// as East-Asian characters and emojis). +// This treats the text as a sequence of wide characters and runes. +func TruncateWc(s string, length int, tail string) string { + return truncate(WcWidth, s, length, tail) +} + +func truncate(m Method, s string, length int, tail string) string { + if sw := StringWidth(s); sw <= length { + return s + } + + tw := StringWidth(tail) + length -= tw + if length < 0 { + return "" + } + + var cluster []byte + var buf bytes.Buffer + curWidth := 0 + ignoring := false + pstate := parser.GroundState // initial state + b := []byte(s) + i := 0 + + // Here we iterate over the bytes of the string and collect printable + // characters and runes. We also keep track of the width of the string + // in cells. + // + // Once we reach the given length, we start ignoring characters and only + // collect ANSI escape codes until we reach the end of string. + for i < len(b) { + state, action := parser.Table.Transition(pstate, b[i]) + if state == parser.Utf8State { + // This action happens when we transition to the Utf8State. + var width int + cluster, _, width, _ = uniseg.FirstGraphemeCluster(b[i:], -1) + if m == WcWidth { + width = runewidth.StringWidth(string(cluster)) + } + + // increment the index by the length of the cluster + i += len(cluster) + curWidth += width + + // Are we ignoring? Skip to the next byte + if ignoring { + continue + } + + // Is this gonna be too wide? + // If so write the tail and stop collecting. + if curWidth > length && !ignoring { + ignoring = true + buf.WriteString(tail) + } + + if curWidth > length { + continue + } + + buf.Write(cluster) + + // Done collecting, now we're back in the ground state. + pstate = parser.GroundState + continue + } + + switch action { + case parser.PrintAction: + // Is this gonna be too wide? + // If so write the tail and stop collecting. + if curWidth >= length && !ignoring { + ignoring = true + buf.WriteString(tail) + } + + // Skip to the next byte if we're ignoring + if ignoring { + i++ + continue + } + + // collects printable ASCII + curWidth++ + fallthrough + case parser.ExecuteAction: + // execute action will be things like \n, which, if outside the cut, + // should be ignored. + if ignoring { + i++ + continue + } + fallthrough + default: + buf.WriteByte(b[i]) + i++ + } + + // Transition to the next state. + pstate = state + + // Once we reach the given length, we start ignoring runes and write + // the tail to the buffer. + if curWidth > length && !ignoring { + ignoring = true + buf.WriteString(tail) + } + } + + return buf.String() +} + +// TruncateLeft truncates a string from the left side by removing n characters, +// adding a prefix to the beginning if the string is longer than n. +// This function is aware of ANSI escape codes and will not break them, and +// accounts for wide-characters (such as East-Asian characters and emojis). +// This treats the text as a sequence of graphemes. +func TruncateLeft(s string, n int, prefix string) string { + return truncateLeft(GraphemeWidth, s, n, prefix) +} + +// TruncateLeftWc truncates a string from the left side by removing n characters, +// adding a prefix to the beginning if the string is longer than n. +// This function is aware of ANSI escape codes and will not break them, and +// accounts for wide-characters (such as East-Asian characters and emojis). +// This treats the text as a sequence of wide characters and runes. +func TruncateLeftWc(s string, n int, prefix string) string { + return truncateLeft(WcWidth, s, n, prefix) +} + +func truncateLeft(m Method, s string, n int, prefix string) string { + if n <= 0 { + return s + } + + var cluster []byte + var buf bytes.Buffer + curWidth := 0 + ignoring := true + pstate := parser.GroundState + b := []byte(s) + i := 0 + + for i < len(b) { + if !ignoring { + buf.Write(b[i:]) + break + } + + state, action := parser.Table.Transition(pstate, b[i]) + if state == parser.Utf8State { + var width int + cluster, _, width, _ = uniseg.FirstGraphemeCluster(b[i:], -1) + if m == WcWidth { + width = runewidth.StringWidth(string(cluster)) + } + + i += len(cluster) + curWidth += width + + if curWidth > n && ignoring { + ignoring = false + buf.WriteString(prefix) + } + + if curWidth > n { + buf.Write(cluster) + } + + if ignoring { + continue + } + + pstate = parser.GroundState + continue + } + + switch action { + case parser.PrintAction: + curWidth++ + + if curWidth > n && ignoring { + ignoring = false + buf.WriteString(prefix) + } + + if ignoring { + i++ + continue + } + + fallthrough + case parser.ExecuteAction: + // execute action will be things like \n, which, if outside the cut, + // should be ignored. + if ignoring { + i++ + continue + } + fallthrough + default: + buf.WriteByte(b[i]) + i++ + } + + pstate = state + if curWidth > n && ignoring { + ignoring = false + buf.WriteString(prefix) + } + } + + return buf.String() +} + +// ByteToGraphemeRange takes start and stop byte positions and converts them to +// grapheme-aware char positions. +// You can use this with [Truncate], [TruncateLeft], and [Cut]. +func ByteToGraphemeRange(str string, byteStart, byteStop int) (charStart, charStop int) { + bytePos, charPos := 0, 0 + gr := uniseg.NewGraphemes(str) + for byteStart > bytePos { + if !gr.Next() { + break + } + bytePos += len(gr.Str()) + charPos += max(1, gr.Width()) + } + charStart = charPos + for byteStop > bytePos { + if !gr.Next() { + break + } + bytePos += len(gr.Str()) + charPos += max(1, gr.Width()) + } + charStop = charPos + return +} diff --git a/vendor/github.com/charmbracelet/x/ansi/util.go b/vendor/github.com/charmbracelet/x/ansi/util.go new file mode 100644 index 000000000..103f452bb --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/util.go @@ -0,0 +1,92 @@ +package ansi + +import ( + "fmt" + "image/color" + "strconv" + "strings" + + "github.com/lucasb-eyer/go-colorful" +) + +// colorToHexString returns a hex string representation of a color. +func colorToHexString(c color.Color) string { //nolint:unused + if c == nil { + return "" + } + shift := func(v uint32) uint32 { + if v > 0xff { + return v >> 8 + } + return v + } + r, g, b, _ := c.RGBA() + r, g, b = shift(r), shift(g), shift(b) + return fmt.Sprintf("#%02x%02x%02x", r, g, b) +} + +// rgbToHex converts red, green, and blue values to a hexadecimal value. +// +// hex := rgbToHex(0, 0, 255) // 0x0000FF +func rgbToHex(r, g, b uint32) uint32 { //nolint:unused + return r<<16 + g<<8 + b +} + +type shiftable interface { + ~uint | ~uint16 | ~uint32 | ~uint64 +} + +func shift[T shiftable](x T) T { + if x > 0xff { + x >>= 8 + } + return x +} + +// XParseColor is a helper function that parses a string into a color.Color. It +// provides a similar interface to the XParseColor function in Xlib. It +// supports the following formats: +// +// - #RGB +// - #RRGGBB +// - rgb:RRRR/GGGG/BBBB +// - rgba:RRRR/GGGG/BBBB/AAAA +// +// If the string is not a valid color, nil is returned. +// +// See: https://linux.die.net/man/3/xparsecolor +func XParseColor(s string) color.Color { + switch { + case strings.HasPrefix(s, "#"): + c, err := colorful.Hex(s) + if err != nil { + return nil + } + + return c + case strings.HasPrefix(s, "rgb:"): + parts := strings.Split(s[4:], "/") + if len(parts) != 3 { + return nil + } + + r, _ := strconv.ParseUint(parts[0], 16, 32) + g, _ := strconv.ParseUint(parts[1], 16, 32) + b, _ := strconv.ParseUint(parts[2], 16, 32) + + return color.RGBA{uint8(shift(r)), uint8(shift(g)), uint8(shift(b)), 255} //nolint:gosec + case strings.HasPrefix(s, "rgba:"): + parts := strings.Split(s[5:], "/") + if len(parts) != 4 { + return nil + } + + r, _ := strconv.ParseUint(parts[0], 16, 32) + g, _ := strconv.ParseUint(parts[1], 16, 32) + b, _ := strconv.ParseUint(parts[2], 16, 32) + a, _ := strconv.ParseUint(parts[3], 16, 32) + + return color.RGBA{uint8(shift(r)), uint8(shift(g)), uint8(shift(b)), uint8(shift(a))} //nolint:gosec + } + return nil +} diff --git a/vendor/github.com/charmbracelet/x/ansi/width.go b/vendor/github.com/charmbracelet/x/ansi/width.go new file mode 100644 index 000000000..cc0858161 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/width.go @@ -0,0 +1,113 @@ +package ansi + +import ( + "bytes" + + "github.com/charmbracelet/x/ansi/parser" + "github.com/mattn/go-runewidth" + "github.com/rivo/uniseg" +) + +// Strip removes ANSI escape codes from a string. +func Strip(s string) string { + var ( + buf bytes.Buffer // buffer for collecting printable characters + ri int // rune index + rw int // rune width + pstate = parser.GroundState // initial state + ) + + // This implements a subset of the Parser to only collect runes and + // printable characters. + for i := range len(s) { + if pstate == parser.Utf8State { + // During this state, collect rw bytes to form a valid rune in the + // buffer. After getting all the rune bytes into the buffer, + // transition to GroundState and reset the counters. + buf.WriteByte(s[i]) + ri++ + if ri < rw { + continue + } + pstate = parser.GroundState + ri = 0 + rw = 0 + continue + } + + state, action := parser.Table.Transition(pstate, s[i]) + switch action { + case parser.CollectAction: + if state == parser.Utf8State { + // This action happens when we transition to the Utf8State. + rw = utf8ByteLen(s[i]) + buf.WriteByte(s[i]) + ri++ + } + case parser.PrintAction, parser.ExecuteAction: + // collects printable ASCII and non-printable characters + buf.WriteByte(s[i]) + } + + // Transition to the next state. + // The Utf8State is managed separately above. + if pstate != parser.Utf8State { + pstate = state + } + } + + return buf.String() +} + +// StringWidth returns the width of a string in cells. This is the number of +// cells that the string will occupy when printed in a terminal. ANSI escape +// codes are ignored and wide characters (such as East Asians and emojis) are +// accounted for. +// This treats the text as a sequence of grapheme clusters. +func StringWidth(s string) int { + return stringWidth(GraphemeWidth, s) +} + +// StringWidthWc returns the width of a string in cells. This is the number of +// cells that the string will occupy when printed in a terminal. ANSI escape +// codes are ignored and wide characters (such as East Asians and emojis) are +// accounted for. +// This treats the text as a sequence of wide characters and runes. +func StringWidthWc(s string) int { + return stringWidth(WcWidth, s) +} + +func stringWidth(m Method, s string) int { + if s == "" { + return 0 + } + + var ( + pstate = parser.GroundState // initial state + cluster string + width int + ) + + for i := 0; i < len(s); i++ { + state, action := parser.Table.Transition(pstate, s[i]) + if state == parser.Utf8State { + var w int + cluster, _, w, _ = uniseg.FirstGraphemeClusterInString(s[i:], -1) + if m == WcWidth { + w = runewidth.StringWidth(cluster) + } + width += w + i += len(cluster) - 1 + pstate = parser.GroundState + continue + } + + if action == parser.PrintAction { + width++ + } + + pstate = state + } + + return width +} diff --git a/vendor/github.com/charmbracelet/x/ansi/winop.go b/vendor/github.com/charmbracelet/x/ansi/winop.go new file mode 100644 index 000000000..0238780d0 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/winop.go @@ -0,0 +1,53 @@ +package ansi + +import ( + "strconv" + "strings" +) + +const ( + // ResizeWindowWinOp is a window operation that resizes the terminal + // window. + ResizeWindowWinOp = 4 + + // RequestWindowSizeWinOp is a window operation that requests a report of + // the size of the terminal window in pixels. The response is in the form: + // CSI 4 ; height ; width t + RequestWindowSizeWinOp = 14 + + // RequestCellSizeWinOp is a window operation that requests a report of + // the size of the terminal cell size in pixels. The response is in the form: + // CSI 6 ; height ; width t + RequestCellSizeWinOp = 16 +) + +// WindowOp (XTWINOPS) is a sequence that manipulates the terminal window. +// +// CSI Ps ; Ps ; Ps t +// +// Ps is a semicolon-separated list of parameters. +// See https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Functions-using-CSI-_-ordered-by-the-final-character-lparen-s-rparen:CSI-Ps;Ps;Ps-t.1EB0 +func WindowOp(p int, ps ...int) string { + if p <= 0 { + return "" + } + + if len(ps) == 0 { + return "\x1b[" + strconv.Itoa(p) + "t" + } + + params := make([]string, 0, len(ps)+1) + params = append(params, strconv.Itoa(p)) + for _, p := range ps { + if p >= 0 { + params = append(params, strconv.Itoa(p)) + } + } + + return "\x1b[" + strings.Join(params, ";") + "t" +} + +// XTWINOPS is an alias for [WindowOp]. +func XTWINOPS(p int, ps ...int) string { + return WindowOp(p, ps...) +} diff --git a/vendor/github.com/charmbracelet/x/ansi/wrap.go b/vendor/github.com/charmbracelet/x/ansi/wrap.go new file mode 100644 index 000000000..253e12335 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/wrap.go @@ -0,0 +1,474 @@ +package ansi + +import ( + "bytes" + "unicode" + "unicode/utf8" + + "github.com/charmbracelet/x/ansi/parser" + "github.com/mattn/go-runewidth" + "github.com/rivo/uniseg" +) + +// nbsp is a non-breaking space. +const nbsp = 0xA0 + +// Hardwrap wraps a string or a block of text to a given line length, breaking +// word boundaries. This will preserve ANSI escape codes and will account for +// wide-characters in the string. +// When preserveSpace is true, spaces at the beginning of a line will be +// preserved. +// This treats the text as a sequence of graphemes. +func Hardwrap(s string, limit int, preserveSpace bool) string { + return hardwrap(GraphemeWidth, s, limit, preserveSpace) +} + +// HardwrapWc wraps a string or a block of text to a given line length, breaking +// word boundaries. This will preserve ANSI escape codes and will account for +// wide-characters in the string. +// When preserveSpace is true, spaces at the beginning of a line will be +// preserved. +// This treats the text as a sequence of wide characters and runes. +func HardwrapWc(s string, limit int, preserveSpace bool) string { + return hardwrap(WcWidth, s, limit, preserveSpace) +} + +func hardwrap(m Method, s string, limit int, preserveSpace bool) string { + if limit < 1 { + return s + } + + var ( + cluster []byte + buf bytes.Buffer + curWidth int + forceNewline bool + pstate = parser.GroundState // initial state + b = []byte(s) + ) + + addNewline := func() { + buf.WriteByte('\n') + curWidth = 0 + } + + i := 0 + for i < len(b) { + state, action := parser.Table.Transition(pstate, b[i]) + if state == parser.Utf8State { //nolint:nestif + var width int + cluster, _, width, _ = uniseg.FirstGraphemeCluster(b[i:], -1) + if m == WcWidth { + width = runewidth.StringWidth(string(cluster)) + } + i += len(cluster) + + if curWidth+width > limit { + addNewline() + } + if !preserveSpace && curWidth == 0 && len(cluster) <= 4 { + // Skip spaces at the beginning of a line + if r, _ := utf8.DecodeRune(cluster); r != utf8.RuneError && unicode.IsSpace(r) { + pstate = parser.GroundState + continue + } + } + + buf.Write(cluster) + curWidth += width + pstate = parser.GroundState + continue + } + + switch action { + case parser.PrintAction, parser.ExecuteAction: + if b[i] == '\n' { + addNewline() + forceNewline = false + break + } + + if curWidth+1 > limit { + addNewline() + forceNewline = true + } + + // Skip spaces at the beginning of a line + if curWidth == 0 { + if !preserveSpace && forceNewline && unicode.IsSpace(rune(b[i])) { + break + } + forceNewline = false + } + + buf.WriteByte(b[i]) + if action == parser.PrintAction { + curWidth++ + } + default: + buf.WriteByte(b[i]) + } + + // We manage the UTF8 state separately manually above. + if pstate != parser.Utf8State { + pstate = state + } + i++ + } + + return buf.String() +} + +// Wordwrap wraps a string or a block of text to a given line length, not +// breaking word boundaries. This will preserve ANSI escape codes and will +// account for wide-characters in the string. +// The breakpoints string is a list of characters that are considered +// breakpoints for word wrapping. A hyphen (-) is always considered a +// breakpoint. +// +// Note: breakpoints must be a string of 1-cell wide rune characters. +// +// This treats the text as a sequence of graphemes. +func Wordwrap(s string, limit int, breakpoints string) string { + return wordwrap(GraphemeWidth, s, limit, breakpoints) +} + +// WordwrapWc wraps a string or a block of text to a given line length, not +// breaking word boundaries. This will preserve ANSI escape codes and will +// account for wide-characters in the string. +// The breakpoints string is a list of characters that are considered +// breakpoints for word wrapping. A hyphen (-) is always considered a +// breakpoint. +// +// Note: breakpoints must be a string of 1-cell wide rune characters. +// +// This treats the text as a sequence of wide characters and runes. +func WordwrapWc(s string, limit int, breakpoints string) string { + return wordwrap(WcWidth, s, limit, breakpoints) +} + +func wordwrap(m Method, s string, limit int, breakpoints string) string { + if limit < 1 { + return s + } + + var ( + cluster []byte + buf bytes.Buffer + word bytes.Buffer + space bytes.Buffer + curWidth int + wordLen int + pstate = parser.GroundState // initial state + b = []byte(s) + ) + + addSpace := func() { + curWidth += space.Len() + buf.Write(space.Bytes()) + space.Reset() + } + + addWord := func() { + if word.Len() == 0 { + return + } + + addSpace() + curWidth += wordLen + buf.Write(word.Bytes()) + word.Reset() + wordLen = 0 + } + + addNewline := func() { + buf.WriteByte('\n') + curWidth = 0 + space.Reset() + } + + i := 0 + for i < len(b) { + state, action := parser.Table.Transition(pstate, b[i]) + if state == parser.Utf8State { //nolint:nestif + var width int + cluster, _, width, _ = uniseg.FirstGraphemeCluster(b[i:], -1) + if m == WcWidth { + width = runewidth.StringWidth(string(cluster)) + } + i += len(cluster) + + r, _ := utf8.DecodeRune(cluster) + if r != utf8.RuneError && unicode.IsSpace(r) && r != nbsp { + addWord() + space.WriteRune(r) + } else if bytes.ContainsAny(cluster, breakpoints) { + addSpace() + addWord() + buf.Write(cluster) + curWidth++ + } else { + word.Write(cluster) + wordLen += width + if curWidth+space.Len()+wordLen > limit && + wordLen < limit { + addNewline() + } + } + + pstate = parser.GroundState + continue + } + + switch action { + case parser.PrintAction, parser.ExecuteAction: + r := rune(b[i]) + switch { + case r == '\n': + if wordLen == 0 { + if curWidth+space.Len() > limit { + curWidth = 0 + } else { + buf.Write(space.Bytes()) + } + space.Reset() + } + + addWord() + addNewline() + case unicode.IsSpace(r): + addWord() + space.WriteByte(b[i]) + case r == '-': + fallthrough + case runeContainsAny(r, breakpoints): + addSpace() + addWord() + buf.WriteByte(b[i]) + curWidth++ + default: + word.WriteByte(b[i]) + wordLen++ + if curWidth+space.Len()+wordLen > limit && + wordLen < limit { + addNewline() + } + } + + default: + word.WriteByte(b[i]) + } + + // We manage the UTF8 state separately manually above. + if pstate != parser.Utf8State { + pstate = state + } + i++ + } + + addWord() + + return buf.String() +} + +// Wrap wraps a string or a block of text to a given line length, breaking word +// boundaries if necessary. This will preserve ANSI escape codes and will +// account for wide-characters in the string. The breakpoints string is a list +// of characters that are considered breakpoints for word wrapping. A hyphen +// (-) is always considered a breakpoint. +// +// Note: breakpoints must be a string of 1-cell wide rune characters. +// +// This treats the text as a sequence of graphemes. +func Wrap(s string, limit int, breakpoints string) string { + return wrap(GraphemeWidth, s, limit, breakpoints) +} + +// WrapWc wraps a string or a block of text to a given line length, breaking word +// boundaries if necessary. This will preserve ANSI escape codes and will +// account for wide-characters in the string. The breakpoints string is a list +// of characters that are considered breakpoints for word wrapping. A hyphen +// (-) is always considered a breakpoint. +// +// Note: breakpoints must be a string of 1-cell wide rune characters. +// +// This treats the text as a sequence of wide characters and runes. +func WrapWc(s string, limit int, breakpoints string) string { + return wrap(WcWidth, s, limit, breakpoints) +} + +func wrap(m Method, s string, limit int, breakpoints string) string { + if limit < 1 { + return s + } + + var ( + cluster []byte + buf bytes.Buffer + word bytes.Buffer + space bytes.Buffer + spaceWidth int // width of the space buffer + curWidth int // written width of the line + wordLen int // word buffer len without ANSI escape codes + pstate = parser.GroundState // initial state + b = []byte(s) + ) + + addSpace := func() { + curWidth += spaceWidth + buf.Write(space.Bytes()) + space.Reset() + spaceWidth = 0 + } + + addWord := func() { + if word.Len() == 0 { + return + } + + addSpace() + curWidth += wordLen + buf.Write(word.Bytes()) + word.Reset() + wordLen = 0 + } + + addNewline := func() { + buf.WriteByte('\n') + curWidth = 0 + space.Reset() + spaceWidth = 0 + } + + i := 0 + for i < len(b) { + state, action := parser.Table.Transition(pstate, b[i]) + if state == parser.Utf8State { //nolint:nestif + var width int + cluster, _, width, _ = uniseg.FirstGraphemeCluster(b[i:], -1) + if m == WcWidth { + width = runewidth.StringWidth(string(cluster)) + } + i += len(cluster) + + r, _ := utf8.DecodeRune(cluster) + switch { + case r != utf8.RuneError && unicode.IsSpace(r) && r != nbsp: // nbsp is a non-breaking space + addWord() + space.WriteRune(r) + spaceWidth += width + case bytes.ContainsAny(cluster, breakpoints): + addSpace() + if curWidth+wordLen+width > limit { + word.Write(cluster) + wordLen += width + } else { + addWord() + buf.Write(cluster) + curWidth += width + } + default: + if wordLen+width > limit { + // Hardwrap the word if it's too long + addWord() + } + + word.Write(cluster) + wordLen += width + + if curWidth+wordLen+spaceWidth > limit { + addNewline() + } + } + + pstate = parser.GroundState + continue + } + + switch action { + case parser.PrintAction, parser.ExecuteAction: + switch r := rune(b[i]); { + case r == '\n': + if wordLen == 0 { + if curWidth+spaceWidth > limit { + curWidth = 0 + } else { + // preserve whitespaces + buf.Write(space.Bytes()) + } + space.Reset() + spaceWidth = 0 + } + + addWord() + addNewline() + case unicode.IsSpace(r): + addWord() + space.WriteRune(r) + spaceWidth++ + case r == '-': + fallthrough + case runeContainsAny(r, breakpoints): + addSpace() + if curWidth+wordLen >= limit { + // We can't fit the breakpoint in the current line, treat + // it as part of the word. + word.WriteRune(r) + wordLen++ + } else { + addWord() + buf.WriteRune(r) + curWidth++ + } + default: + if curWidth == limit { + addNewline() + } + word.WriteRune(r) + wordLen++ + + if wordLen == limit { + // Hardwrap the word if it's too long + addWord() + } + + if curWidth+wordLen+spaceWidth > limit { + addNewline() + } + } + + default: + word.WriteByte(b[i]) + } + + // We manage the UTF8 state separately manually above. + if pstate != parser.Utf8State { + pstate = state + } + i++ + } + + if wordLen == 0 { + if curWidth+spaceWidth > limit { + curWidth = 0 + } else { + // preserve whitespaces + buf.Write(space.Bytes()) + } + space.Reset() + spaceWidth = 0 + } + + addWord() + + return buf.String() +} + +func runeContainsAny(r rune, s string) bool { + for _, c := range s { + if c == r { + return true + } + } + return false +} diff --git a/vendor/github.com/charmbracelet/x/ansi/xterm.go b/vendor/github.com/charmbracelet/x/ansi/xterm.go new file mode 100644 index 000000000..83fd4bdc4 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/ansi/xterm.go @@ -0,0 +1,138 @@ +package ansi + +import "strconv" + +// KeyModifierOptions (XTMODKEYS) sets/resets xterm key modifier options. +// +// Default is 0. +// +// CSI > Pp m +// CSI > Pp ; Pv m +// +// If Pv is omitted, the resource is reset to its initial value. +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_ +func KeyModifierOptions(p int, vs ...int) string { + var pp, pv string + if p > 0 { + pp = strconv.Itoa(p) + } + + if len(vs) == 0 { + return "\x1b[>" + strconv.Itoa(p) + "m" + } + + v := vs[0] + if v > 0 { + pv = strconv.Itoa(v) + return "\x1b[>" + pp + ";" + pv + "m" + } + + return "\x1b[>" + pp + "m" +} + +// XTMODKEYS is an alias for [KeyModifierOptions]. +func XTMODKEYS(p int, vs ...int) string { + return KeyModifierOptions(p, vs...) +} + +// SetKeyModifierOptions sets xterm key modifier options. +// This is an alias for [KeyModifierOptions]. +func SetKeyModifierOptions(pp int, pv int) string { + return KeyModifierOptions(pp, pv) +} + +// ResetKeyModifierOptions resets xterm key modifier options. +// This is an alias for [KeyModifierOptions]. +func ResetKeyModifierOptions(pp int) string { + return KeyModifierOptions(pp) +} + +// QueryKeyModifierOptions (XTQMODKEYS) requests xterm key modifier options. +// +// Default is 0. +// +// CSI ? Pp m +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_ +func QueryKeyModifierOptions(pp int) string { + var p string + if pp > 0 { + p = strconv.Itoa(pp) + } + return "\x1b[?" + p + "m" +} + +// XTQMODKEYS is an alias for [QueryKeyModifierOptions]. +func XTQMODKEYS(pp int) string { + return QueryKeyModifierOptions(pp) +} + +// Modify Other Keys (modifyOtherKeys) is an xterm feature that allows the +// terminal to modify the behavior of certain keys to send different escape +// sequences when pressed. +// +// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys +const ( + SetModifyOtherKeys1 = "\x1b[>4;1m" + SetModifyOtherKeys2 = "\x1b[>4;2m" + ResetModifyOtherKeys = "\x1b[>4m" + QueryModifyOtherKeys = "\x1b[?4m" +) + +// ModifyOtherKeys returns a sequence that sets XTerm modifyOtherKeys mode. +// The mode argument specifies the mode to set. +// +// 0: Disable modifyOtherKeys mode. +// 1: Enable modifyOtherKeys mode 1. +// 2: Enable modifyOtherKeys mode 2. +// +// CSI > 4 ; mode m +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_ +// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys +// +// Deprecated: use [SetModifyOtherKeys1] or [SetModifyOtherKeys2] instead. +func ModifyOtherKeys(mode int) string { + return "\x1b[>4;" + strconv.Itoa(mode) + "m" +} + +// DisableModifyOtherKeys disables the modifyOtherKeys mode. +// +// CSI > 4 ; 0 m +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_ +// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys +// +// Deprecated: use [ResetModifyOtherKeys] instead. +const DisableModifyOtherKeys = "\x1b[>4;0m" + +// EnableModifyOtherKeys1 enables the modifyOtherKeys mode 1. +// +// CSI > 4 ; 1 m +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_ +// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys +// +// Deprecated: use [SetModifyOtherKeys1] instead. +const EnableModifyOtherKeys1 = "\x1b[>4;1m" + +// EnableModifyOtherKeys2 enables the modifyOtherKeys mode 2. +// +// CSI > 4 ; 2 m +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_ +// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys +// +// Deprecated: use [SetModifyOtherKeys2] instead. +const EnableModifyOtherKeys2 = "\x1b[>4;2m" + +// RequestModifyOtherKeys requests the modifyOtherKeys mode. +// +// CSI ? 4 m +// +// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_ +// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys +// +// Deprecated: use [QueryModifyOtherKeys] instead. +const RequestModifyOtherKeys = "\x1b[?4m" diff --git a/vendor/github.com/charmbracelet/x/cellbuf/LICENSE b/vendor/github.com/charmbracelet/x/cellbuf/LICENSE new file mode 100644 index 000000000..65a5654e2 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/cellbuf/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Charmbracelet, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/charmbracelet/x/cellbuf/buffer.go b/vendor/github.com/charmbracelet/x/cellbuf/buffer.go new file mode 100644 index 000000000..790d1f7c4 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/cellbuf/buffer.go @@ -0,0 +1,473 @@ +package cellbuf + +import ( + "strings" + + "github.com/mattn/go-runewidth" + "github.com/rivo/uniseg" +) + +// NewCell returns a new cell. This is a convenience function that initializes a +// new cell with the given content. The cell's width is determined by the +// content using [runewidth.RuneWidth]. +// This will only account for the first combined rune in the content. If the +// content is empty, it will return an empty cell with a width of 0. +func NewCell(r rune, comb ...rune) (c *Cell) { + c = new(Cell) + c.Rune = r + c.Width = runewidth.RuneWidth(r) + for _, r := range comb { + if runewidth.RuneWidth(r) > 0 { + break + } + c.Comb = append(c.Comb, r) + } + c.Comb = comb + c.Width = runewidth.StringWidth(string(append([]rune{r}, comb...))) + return +} + +// NewCellString returns a new cell with the given string content. This is a +// convenience function that initializes a new cell with the given content. The +// cell's width is determined by the content using [runewidth.StringWidth]. +// This will only use the first combined rune in the string. If the string is +// empty, it will return an empty cell with a width of 0. +func NewCellString(s string) (c *Cell) { + c = new(Cell) + for i, r := range s { + if i == 0 { + c.Rune = r + // We only care about the first rune's width + c.Width = runewidth.RuneWidth(r) + } else { + if runewidth.RuneWidth(r) > 0 { + break + } + c.Comb = append(c.Comb, r) + } + } + return +} + +// NewGraphemeCell returns a new cell. This is a convenience function that +// initializes a new cell with the given content. The cell's width is determined +// by the content using [uniseg.FirstGraphemeClusterInString]. +// This is used when the content is a grapheme cluster i.e. a sequence of runes +// that form a single visual unit. +// This will only return the first grapheme cluster in the string. If the +// string is empty, it will return an empty cell with a width of 0. +func NewGraphemeCell(s string) (c *Cell) { + g, _, w, _ := uniseg.FirstGraphemeClusterInString(s, -1) + return newGraphemeCell(g, w) +} + +func newGraphemeCell(s string, w int) (c *Cell) { + c = new(Cell) + c.Width = w + for i, r := range s { + if i == 0 { + c.Rune = r + } else { + c.Comb = append(c.Comb, r) + } + } + return +} + +// Line represents a line in the terminal. +// A nil cell represents an blank cell, a cell with a space character and a +// width of 1. +// If a cell has no content and a width of 0, it is a placeholder for a wide +// cell. +type Line []*Cell + +// Width returns the width of the line. +func (l Line) Width() int { + return len(l) +} + +// Len returns the length of the line. +func (l Line) Len() int { + return len(l) +} + +// String returns the string representation of the line. Any trailing spaces +// are removed. +func (l Line) String() (s string) { + for _, c := range l { + if c == nil { + s += " " + } else if c.Empty() { + continue + } else { + s += c.String() + } + } + s = strings.TrimRight(s, " ") + return +} + +// At returns the cell at the given x position. +// If the cell does not exist, it returns nil. +func (l Line) At(x int) *Cell { + if x < 0 || x >= len(l) { + return nil + } + + c := l[x] + if c == nil { + newCell := BlankCell + return &newCell + } + + return c +} + +// Set sets the cell at the given x position. If a wide cell is given, it will +// set the cell and the following cells to [EmptyCell]. It returns true if the +// cell was set. +func (l Line) Set(x int, c *Cell) bool { + return l.set(x, c, true) +} + +func (l Line) set(x int, c *Cell, clone bool) bool { + width := l.Width() + if x < 0 || x >= width { + return false + } + + // When a wide cell is partially overwritten, we need + // to fill the rest of the cell with space cells to + // avoid rendering issues. + prev := l.At(x) + if prev != nil && prev.Width > 1 { + // Writing to the first wide cell + for j := 0; j < prev.Width && x+j < l.Width(); j++ { + l[x+j] = prev.Clone().Blank() + } + } else if prev != nil && prev.Width == 0 { + // Writing to wide cell placeholders + for j := 1; j < maxCellWidth && x-j >= 0; j++ { + wide := l.At(x - j) + if wide != nil && wide.Width > 1 && j < wide.Width { + for k := 0; k < wide.Width; k++ { + l[x-j+k] = wide.Clone().Blank() + } + break + } + } + } + + if clone && c != nil { + // Clone the cell if not nil. + c = c.Clone() + } + + if c != nil && x+c.Width > width { + // If the cell is too wide, we write blanks with the same style. + for i := 0; i < c.Width && x+i < width; i++ { + l[x+i] = c.Clone().Blank() + } + } else { + l[x] = c + + // Mark wide cells with an empty cell zero width + // We set the wide cell down below + if c != nil && c.Width > 1 { + for j := 1; j < c.Width && x+j < l.Width(); j++ { + var wide Cell + l[x+j] = &wide + } + } + } + + return true +} + +// Buffer is a 2D grid of cells representing a screen or terminal. +type Buffer struct { + // Lines holds the lines of the buffer. + Lines []Line +} + +// NewBuffer creates a new buffer with the given width and height. +// This is a convenience function that initializes a new buffer and resizes it. +func NewBuffer(width int, height int) *Buffer { + b := new(Buffer) + b.Resize(width, height) + return b +} + +// String returns the string representation of the buffer. +func (b *Buffer) String() (s string) { + for i, l := range b.Lines { + s += l.String() + if i < len(b.Lines)-1 { + s += "\r\n" + } + } + return +} + +// Line returns a pointer to the line at the given y position. +// If the line does not exist, it returns nil. +func (b *Buffer) Line(y int) Line { + if y < 0 || y >= len(b.Lines) { + return nil + } + return b.Lines[y] +} + +// Cell implements Screen. +func (b *Buffer) Cell(x int, y int) *Cell { + if y < 0 || y >= len(b.Lines) { + return nil + } + return b.Lines[y].At(x) +} + +// maxCellWidth is the maximum width a terminal cell can get. +const maxCellWidth = 4 + +// SetCell sets the cell at the given x, y position. +func (b *Buffer) SetCell(x, y int, c *Cell) bool { + return b.setCell(x, y, c, true) +} + +// setCell sets the cell at the given x, y position. This will always clone and +// allocates a new cell if c is not nil. +func (b *Buffer) setCell(x, y int, c *Cell, clone bool) bool { + if y < 0 || y >= len(b.Lines) { + return false + } + return b.Lines[y].set(x, c, clone) +} + +// Height implements Screen. +func (b *Buffer) Height() int { + return len(b.Lines) +} + +// Width implements Screen. +func (b *Buffer) Width() int { + if len(b.Lines) == 0 { + return 0 + } + return b.Lines[0].Width() +} + +// Bounds returns the bounds of the buffer. +func (b *Buffer) Bounds() Rectangle { + return Rect(0, 0, b.Width(), b.Height()) +} + +// Resize resizes the buffer to the given width and height. +func (b *Buffer) Resize(width int, height int) { + if width == 0 || height == 0 { + b.Lines = nil + return + } + + if width > b.Width() { + line := make(Line, width-b.Width()) + for i := range b.Lines { + b.Lines[i] = append(b.Lines[i], line...) + } + } else if width < b.Width() { + for i := range b.Lines { + b.Lines[i] = b.Lines[i][:width] + } + } + + if height > len(b.Lines) { + for i := len(b.Lines); i < height; i++ { + b.Lines = append(b.Lines, make(Line, width)) + } + } else if height < len(b.Lines) { + b.Lines = b.Lines[:height] + } +} + +// FillRect fills the buffer with the given cell and rectangle. +func (b *Buffer) FillRect(c *Cell, rect Rectangle) { + cellWidth := 1 + if c != nil && c.Width > 1 { + cellWidth = c.Width + } + for y := rect.Min.Y; y < rect.Max.Y; y++ { + for x := rect.Min.X; x < rect.Max.X; x += cellWidth { + b.setCell(x, y, c, false) //nolint:errcheck + } + } +} + +// Fill fills the buffer with the given cell and rectangle. +func (b *Buffer) Fill(c *Cell) { + b.FillRect(c, b.Bounds()) +} + +// Clear clears the buffer with space cells and rectangle. +func (b *Buffer) Clear() { + b.ClearRect(b.Bounds()) +} + +// ClearRect clears the buffer with space cells within the specified +// rectangles. Only cells within the rectangle's bounds are affected. +func (b *Buffer) ClearRect(rect Rectangle) { + b.FillRect(nil, rect) +} + +// InsertLine inserts n lines at the given line position, with the given +// optional cell, within the specified rectangles. If no rectangles are +// specified, it inserts lines in the entire buffer. Only cells within the +// rectangle's horizontal bounds are affected. Lines are pushed out of the +// rectangle bounds and lost. This follows terminal [ansi.IL] behavior. +// It returns the pushed out lines. +func (b *Buffer) InsertLine(y, n int, c *Cell) { + b.InsertLineRect(y, n, c, b.Bounds()) +} + +// InsertLineRect inserts new lines at the given line position, with the +// given optional cell, within the rectangle bounds. Only cells within the +// rectangle's horizontal bounds are affected. Lines are pushed out of the +// rectangle bounds and lost. This follows terminal [ansi.IL] behavior. +func (b *Buffer) InsertLineRect(y, n int, c *Cell, rect Rectangle) { + if n <= 0 || y < rect.Min.Y || y >= rect.Max.Y || y >= b.Height() { + return + } + + // Limit number of lines to insert to available space + if y+n > rect.Max.Y { + n = rect.Max.Y - y + } + + // Move existing lines down within the bounds + for i := rect.Max.Y - 1; i >= y+n; i-- { + for x := rect.Min.X; x < rect.Max.X; x++ { + // We don't need to clone c here because we're just moving lines down. + b.setCell(x, i, b.Lines[i-n][x], false) + } + } + + // Clear the newly inserted lines within bounds + for i := y; i < y+n; i++ { + for x := rect.Min.X; x < rect.Max.X; x++ { + b.setCell(x, i, c, true) + } + } +} + +// DeleteLineRect deletes lines at the given line position, with the given +// optional cell, within the rectangle bounds. Only cells within the +// rectangle's bounds are affected. Lines are shifted up within the bounds and +// new blank lines are created at the bottom. This follows terminal [ansi.DL] +// behavior. +func (b *Buffer) DeleteLineRect(y, n int, c *Cell, rect Rectangle) { + if n <= 0 || y < rect.Min.Y || y >= rect.Max.Y || y >= b.Height() { + return + } + + // Limit deletion count to available space in scroll region + if n > rect.Max.Y-y { + n = rect.Max.Y - y + } + + // Shift cells up within the bounds + for dst := y; dst < rect.Max.Y-n; dst++ { + src := dst + n + for x := rect.Min.X; x < rect.Max.X; x++ { + // We don't need to clone c here because we're just moving cells up. + // b.lines[dst][x] = b.lines[src][x] + b.setCell(x, dst, b.Lines[src][x], false) + } + } + + // Fill the bottom n lines with blank cells + for i := rect.Max.Y - n; i < rect.Max.Y; i++ { + for x := rect.Min.X; x < rect.Max.X; x++ { + b.setCell(x, i, c, true) + } + } +} + +// DeleteLine deletes n lines at the given line position, with the given +// optional cell, within the specified rectangles. If no rectangles are +// specified, it deletes lines in the entire buffer. +func (b *Buffer) DeleteLine(y, n int, c *Cell) { + b.DeleteLineRect(y, n, c, b.Bounds()) +} + +// InsertCell inserts new cells at the given position, with the given optional +// cell, within the specified rectangles. If no rectangles are specified, it +// inserts cells in the entire buffer. This follows terminal [ansi.ICH] +// behavior. +func (b *Buffer) InsertCell(x, y, n int, c *Cell) { + b.InsertCellRect(x, y, n, c, b.Bounds()) +} + +// InsertCellRect inserts new cells at the given position, with the given +// optional cell, within the rectangle bounds. Only cells within the +// rectangle's bounds are affected, following terminal [ansi.ICH] behavior. +func (b *Buffer) InsertCellRect(x, y, n int, c *Cell, rect Rectangle) { + if n <= 0 || y < rect.Min.Y || y >= rect.Max.Y || y >= b.Height() || + x < rect.Min.X || x >= rect.Max.X || x >= b.Width() { + return + } + + // Limit number of cells to insert to available space + if x+n > rect.Max.X { + n = rect.Max.X - x + } + + // Move existing cells within rectangle bounds to the right + for i := rect.Max.X - 1; i >= x+n && i-n >= rect.Min.X; i-- { + // We don't need to clone c here because we're just moving cells to the + // right. + // b.lines[y][i] = b.lines[y][i-n] + b.setCell(i, y, b.Lines[y][i-n], false) + } + + // Clear the newly inserted cells within rectangle bounds + for i := x; i < x+n && i < rect.Max.X; i++ { + b.setCell(i, y, c, true) + } +} + +// DeleteCell deletes cells at the given position, with the given optional +// cell, within the specified rectangles. If no rectangles are specified, it +// deletes cells in the entire buffer. This follows terminal [ansi.DCH] +// behavior. +func (b *Buffer) DeleteCell(x, y, n int, c *Cell) { + b.DeleteCellRect(x, y, n, c, b.Bounds()) +} + +// DeleteCellRect deletes cells at the given position, with the given +// optional cell, within the rectangle bounds. Only cells within the +// rectangle's bounds are affected, following terminal [ansi.DCH] behavior. +func (b *Buffer) DeleteCellRect(x, y, n int, c *Cell, rect Rectangle) { + if n <= 0 || y < rect.Min.Y || y >= rect.Max.Y || y >= b.Height() || + x < rect.Min.X || x >= rect.Max.X || x >= b.Width() { + return + } + + // Calculate how many positions we can actually delete + remainingCells := rect.Max.X - x + if n > remainingCells { + n = remainingCells + } + + // Shift the remaining cells to the left + for i := x; i < rect.Max.X-n; i++ { + if i+n < rect.Max.X { + // We don't need to clone c here because we're just moving cells to + // the left. + // b.lines[y][i] = b.lines[y][i+n] + b.setCell(i, y, b.Lines[y][i+n], false) + } + } + + // Fill the vacated positions with the given cell + for i := rect.Max.X - n; i < rect.Max.X; i++ { + b.setCell(i, y, c, true) + } +} diff --git a/vendor/github.com/charmbracelet/x/cellbuf/cell.go b/vendor/github.com/charmbracelet/x/cellbuf/cell.go new file mode 100644 index 000000000..4d49d45ee --- /dev/null +++ b/vendor/github.com/charmbracelet/x/cellbuf/cell.go @@ -0,0 +1,508 @@ +package cellbuf + +import ( + "github.com/charmbracelet/x/ansi" +) + +var ( + // BlankCell is a cell with a single space, width of 1, and no style or link. + BlankCell = Cell{Rune: ' ', Width: 1} + + // EmptyCell is just an empty cell used for comparisons and as a placeholder + // for wide cells. + EmptyCell = Cell{} +) + +// Cell represents a single cell in the terminal screen. +type Cell struct { + // The style of the cell. Nil style means no style. Zero value prints a + // reset sequence. + Style Style + + // Link is the hyperlink of the cell. + Link Link + + // Comb is the combining runes of the cell. This is nil if the cell is a + // single rune or if it's a zero width cell that is part of a wider cell. + Comb []rune + + // Width is the mono-space width of the grapheme cluster. + Width int + + // Rune is the main rune of the cell. This is zero if the cell is part of a + // wider cell. + Rune rune +} + +// Append appends runes to the cell without changing the width. This is useful +// when we want to use the cell to store escape sequences or other runes that +// don't affect the width of the cell. +func (c *Cell) Append(r ...rune) { + for i, r := range r { + if i == 0 && c.Rune == 0 { + c.Rune = r + continue + } + c.Comb = append(c.Comb, r) + } +} + +// String returns the string content of the cell excluding any styles, links, +// and escape sequences. +func (c Cell) String() string { + if c.Rune == 0 { + return "" + } + if len(c.Comb) == 0 { + return string(c.Rune) + } + return string(append([]rune{c.Rune}, c.Comb...)) +} + +// Equal returns whether the cell is equal to the other cell. +func (c *Cell) Equal(o *Cell) bool { + return o != nil && + c.Width == o.Width && + c.Rune == o.Rune && + runesEqual(c.Comb, o.Comb) && + c.Style.Equal(&o.Style) && + c.Link.Equal(&o.Link) +} + +// Empty returns whether the cell is an empty cell. An empty cell is a cell +// with a width of 0, a rune of 0, and no combining runes. +func (c Cell) Empty() bool { + return c.Width == 0 && + c.Rune == 0 && + len(c.Comb) == 0 +} + +// Reset resets the cell to the default state zero value. +func (c *Cell) Reset() { + c.Rune = 0 + c.Comb = nil + c.Width = 0 + c.Style.Reset() + c.Link.Reset() +} + +// Clear returns whether the cell consists of only attributes that don't +// affect appearance of a space character. +func (c *Cell) Clear() bool { + return c.Rune == ' ' && len(c.Comb) == 0 && c.Width == 1 && c.Style.Clear() && c.Link.Empty() +} + +// Clone returns a copy of the cell. +func (c *Cell) Clone() (n *Cell) { + n = new(Cell) + *n = *c + return +} + +// Blank makes the cell a blank cell by setting the rune to a space, comb to +// nil, and the width to 1. +func (c *Cell) Blank() *Cell { + c.Rune = ' ' + c.Comb = nil + c.Width = 1 + return c +} + +// Link represents a hyperlink in the terminal screen. +type Link struct { + URL string + Params string +} + +// String returns a string representation of the hyperlink. +func (h Link) String() string { + return h.URL +} + +// Reset resets the hyperlink to the default state zero value. +func (h *Link) Reset() { + h.URL = "" + h.Params = "" +} + +// Equal returns whether the hyperlink is equal to the other hyperlink. +func (h *Link) Equal(o *Link) bool { + return o != nil && h.URL == o.URL && h.Params == o.Params +} + +// Empty returns whether the hyperlink is empty. +func (h Link) Empty() bool { + return h.URL == "" && h.Params == "" +} + +// AttrMask is a bitmask for text attributes that can change the look of text. +// These attributes can be combined to create different styles. +type AttrMask uint8 + +// These are the available text attributes that can be combined to create +// different styles. +const ( + BoldAttr AttrMask = 1 << iota + FaintAttr + ItalicAttr + SlowBlinkAttr + RapidBlinkAttr + ReverseAttr + ConcealAttr + StrikethroughAttr + + ResetAttr AttrMask = 0 +) + +// Contains returns whether the attribute mask contains the attribute. +func (a AttrMask) Contains(attr AttrMask) bool { + return a&attr == attr +} + +// UnderlineStyle is the style of underline to use for text. +type UnderlineStyle = ansi.UnderlineStyle + +// These are the available underline styles. +const ( + NoUnderline = ansi.NoUnderlineStyle + SingleUnderline = ansi.SingleUnderlineStyle + DoubleUnderline = ansi.DoubleUnderlineStyle + CurlyUnderline = ansi.CurlyUnderlineStyle + DottedUnderline = ansi.DottedUnderlineStyle + DashedUnderline = ansi.DashedUnderlineStyle +) + +// Style represents the Style of a cell. +type Style struct { + Fg ansi.Color + Bg ansi.Color + Ul ansi.Color + Attrs AttrMask + UlStyle UnderlineStyle +} + +// Sequence returns the ANSI sequence that sets the style. +func (s Style) Sequence() string { + if s.Empty() { + return ansi.ResetStyle + } + + var b ansi.Style + + if s.Attrs != 0 { + if s.Attrs&BoldAttr != 0 { + b = b.Bold() + } + if s.Attrs&FaintAttr != 0 { + b = b.Faint() + } + if s.Attrs&ItalicAttr != 0 { + b = b.Italic() + } + if s.Attrs&SlowBlinkAttr != 0 { + b = b.SlowBlink() + } + if s.Attrs&RapidBlinkAttr != 0 { + b = b.RapidBlink() + } + if s.Attrs&ReverseAttr != 0 { + b = b.Reverse() + } + if s.Attrs&ConcealAttr != 0 { + b = b.Conceal() + } + if s.Attrs&StrikethroughAttr != 0 { + b = b.Strikethrough() + } + } + if s.UlStyle != NoUnderline { + switch s.UlStyle { + case SingleUnderline: + b = b.Underline() + case DoubleUnderline: + b = b.DoubleUnderline() + case CurlyUnderline: + b = b.CurlyUnderline() + case DottedUnderline: + b = b.DottedUnderline() + case DashedUnderline: + b = b.DashedUnderline() + } + } + if s.Fg != nil { + b = b.ForegroundColor(s.Fg) + } + if s.Bg != nil { + b = b.BackgroundColor(s.Bg) + } + if s.Ul != nil { + b = b.UnderlineColor(s.Ul) + } + + return b.String() +} + +// DiffSequence returns the ANSI sequence that sets the style as a diff from +// another style. +func (s Style) DiffSequence(o Style) string { + if o.Empty() { + return s.Sequence() + } + + var b ansi.Style + + if !colorEqual(s.Fg, o.Fg) { + b = b.ForegroundColor(s.Fg) + } + + if !colorEqual(s.Bg, o.Bg) { + b = b.BackgroundColor(s.Bg) + } + + if !colorEqual(s.Ul, o.Ul) { + b = b.UnderlineColor(s.Ul) + } + + var ( + noBlink bool + isNormal bool + ) + + if s.Attrs != o.Attrs { + if s.Attrs&BoldAttr != o.Attrs&BoldAttr { + if s.Attrs&BoldAttr != 0 { + b = b.Bold() + } else if !isNormal { + isNormal = true + b = b.NormalIntensity() + } + } + if s.Attrs&FaintAttr != o.Attrs&FaintAttr { + if s.Attrs&FaintAttr != 0 { + b = b.Faint() + } else if !isNormal { + b = b.NormalIntensity() + } + } + if s.Attrs&ItalicAttr != o.Attrs&ItalicAttr { + if s.Attrs&ItalicAttr != 0 { + b = b.Italic() + } else { + b = b.NoItalic() + } + } + if s.Attrs&SlowBlinkAttr != o.Attrs&SlowBlinkAttr { + if s.Attrs&SlowBlinkAttr != 0 { + b = b.SlowBlink() + } else if !noBlink { + noBlink = true + b = b.NoBlink() + } + } + if s.Attrs&RapidBlinkAttr != o.Attrs&RapidBlinkAttr { + if s.Attrs&RapidBlinkAttr != 0 { + b = b.RapidBlink() + } else if !noBlink { + b = b.NoBlink() + } + } + if s.Attrs&ReverseAttr != o.Attrs&ReverseAttr { + if s.Attrs&ReverseAttr != 0 { + b = b.Reverse() + } else { + b = b.NoReverse() + } + } + if s.Attrs&ConcealAttr != o.Attrs&ConcealAttr { + if s.Attrs&ConcealAttr != 0 { + b = b.Conceal() + } else { + b = b.NoConceal() + } + } + if s.Attrs&StrikethroughAttr != o.Attrs&StrikethroughAttr { + if s.Attrs&StrikethroughAttr != 0 { + b = b.Strikethrough() + } else { + b = b.NoStrikethrough() + } + } + } + + if s.UlStyle != o.UlStyle { + b = b.UnderlineStyle(s.UlStyle) + } + + return b.String() +} + +// Equal returns true if the style is equal to the other style. +func (s *Style) Equal(o *Style) bool { + return s.Attrs == o.Attrs && + s.UlStyle == o.UlStyle && + colorEqual(s.Fg, o.Fg) && + colorEqual(s.Bg, o.Bg) && + colorEqual(s.Ul, o.Ul) +} + +func colorEqual(c, o ansi.Color) bool { + if c == nil && o == nil { + return true + } + if c == nil || o == nil { + return false + } + cr, cg, cb, ca := c.RGBA() + or, og, ob, oa := o.RGBA() + return cr == or && cg == og && cb == ob && ca == oa +} + +// Bold sets the bold attribute. +func (s *Style) Bold(v bool) *Style { + if v { + s.Attrs |= BoldAttr + } else { + s.Attrs &^= BoldAttr + } + return s +} + +// Faint sets the faint attribute. +func (s *Style) Faint(v bool) *Style { + if v { + s.Attrs |= FaintAttr + } else { + s.Attrs &^= FaintAttr + } + return s +} + +// Italic sets the italic attribute. +func (s *Style) Italic(v bool) *Style { + if v { + s.Attrs |= ItalicAttr + } else { + s.Attrs &^= ItalicAttr + } + return s +} + +// SlowBlink sets the slow blink attribute. +func (s *Style) SlowBlink(v bool) *Style { + if v { + s.Attrs |= SlowBlinkAttr + } else { + s.Attrs &^= SlowBlinkAttr + } + return s +} + +// RapidBlink sets the rapid blink attribute. +func (s *Style) RapidBlink(v bool) *Style { + if v { + s.Attrs |= RapidBlinkAttr + } else { + s.Attrs &^= RapidBlinkAttr + } + return s +} + +// Reverse sets the reverse attribute. +func (s *Style) Reverse(v bool) *Style { + if v { + s.Attrs |= ReverseAttr + } else { + s.Attrs &^= ReverseAttr + } + return s +} + +// Conceal sets the conceal attribute. +func (s *Style) Conceal(v bool) *Style { + if v { + s.Attrs |= ConcealAttr + } else { + s.Attrs &^= ConcealAttr + } + return s +} + +// Strikethrough sets the strikethrough attribute. +func (s *Style) Strikethrough(v bool) *Style { + if v { + s.Attrs |= StrikethroughAttr + } else { + s.Attrs &^= StrikethroughAttr + } + return s +} + +// UnderlineStyle sets the underline style. +func (s *Style) UnderlineStyle(style UnderlineStyle) *Style { + s.UlStyle = style + return s +} + +// Underline sets the underline attribute. +// This is a syntactic sugar for [UnderlineStyle]. +func (s *Style) Underline(v bool) *Style { + if v { + return s.UnderlineStyle(SingleUnderline) + } + return s.UnderlineStyle(NoUnderline) +} + +// Foreground sets the foreground color. +func (s *Style) Foreground(c ansi.Color) *Style { + s.Fg = c + return s +} + +// Background sets the background color. +func (s *Style) Background(c ansi.Color) *Style { + s.Bg = c + return s +} + +// UnderlineColor sets the underline color. +func (s *Style) UnderlineColor(c ansi.Color) *Style { + s.Ul = c + return s +} + +// Reset resets the style to default. +func (s *Style) Reset() *Style { + s.Fg = nil + s.Bg = nil + s.Ul = nil + s.Attrs = ResetAttr + s.UlStyle = NoUnderline + return s +} + +// Empty returns true if the style is empty. +func (s *Style) Empty() bool { + return s.Fg == nil && s.Bg == nil && s.Ul == nil && s.Attrs == ResetAttr && s.UlStyle == NoUnderline +} + +// Clear returns whether the style consists of only attributes that don't +// affect appearance of a space character. +func (s *Style) Clear() bool { + return s.UlStyle == NoUnderline && + s.Attrs&^(BoldAttr|FaintAttr|ItalicAttr|SlowBlinkAttr|RapidBlinkAttr) == 0 && + s.Fg == nil && + s.Bg == nil && + s.Ul == nil +} + +func runesEqual(a, b []rune) bool { + if len(a) != len(b) { + return false + } + for i, r := range a { + if r != b[i] { + return false + } + } + return true +} diff --git a/vendor/github.com/charmbracelet/x/cellbuf/errors.go b/vendor/github.com/charmbracelet/x/cellbuf/errors.go new file mode 100644 index 000000000..64258fe33 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/cellbuf/errors.go @@ -0,0 +1,6 @@ +package cellbuf + +import "errors" + +// ErrOutOfBounds is returned when the given x, y position is out of bounds. +var ErrOutOfBounds = errors.New("out of bounds") diff --git a/vendor/github.com/charmbracelet/x/cellbuf/geom.go b/vendor/github.com/charmbracelet/x/cellbuf/geom.go new file mode 100644 index 000000000..c12e6fb1d --- /dev/null +++ b/vendor/github.com/charmbracelet/x/cellbuf/geom.go @@ -0,0 +1,21 @@ +package cellbuf + +import ( + "image" +) + +// Position represents an x, y position. +type Position = image.Point + +// Pos is a shorthand for Position{X: x, Y: y}. +func Pos(x, y int) Position { + return image.Pt(x, y) +} + +// Rectange represents a rectangle. +type Rectangle = image.Rectangle + +// Rect is a shorthand for Rectangle. +func Rect(x, y, w, h int) Rectangle { + return image.Rect(x, y, x+w, y+h) +} diff --git a/vendor/github.com/charmbracelet/x/cellbuf/hardscroll.go b/vendor/github.com/charmbracelet/x/cellbuf/hardscroll.go new file mode 100644 index 000000000..402ac06a6 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/cellbuf/hardscroll.go @@ -0,0 +1,272 @@ +package cellbuf + +import ( + "strings" + + "github.com/charmbracelet/x/ansi" +) + +// scrollOptimize optimizes the screen to transform the old buffer into the new +// buffer. +func (s *Screen) scrollOptimize() { + height := s.newbuf.Height() + if s.oldnum == nil || len(s.oldnum) < height { + s.oldnum = make([]int, height) + } + + // Calculate the indices + s.updateHashmap() + if len(s.hashtab) < height { + return + } + + // Pass 1 - from top to bottom scrolling up + for i := 0; i < height; { + for i < height && (s.oldnum[i] == newIndex || s.oldnum[i] <= i) { + i++ + } + if i >= height { + break + } + + shift := s.oldnum[i] - i // shift > 0 + start := i + + i++ + for i < height && s.oldnum[i] != newIndex && s.oldnum[i]-i == shift { + i++ + } + end := i - 1 + shift + + if !s.scrolln(shift, start, end, height-1) { + continue + } + } + + // Pass 2 - from bottom to top scrolling down + for i := height - 1; i >= 0; { + for i >= 0 && (s.oldnum[i] == newIndex || s.oldnum[i] >= i) { + i-- + } + if i < 0 { + break + } + + shift := s.oldnum[i] - i // shift < 0 + end := i + + i-- + for i >= 0 && s.oldnum[i] != newIndex && s.oldnum[i]-i == shift { + i-- + } + + start := i + 1 - (-shift) + if !s.scrolln(shift, start, end, height-1) { + continue + } + } +} + +// scrolln scrolls the screen up by n lines. +func (s *Screen) scrolln(n, top, bot, maxY int) (v bool) { //nolint:unparam + const ( + nonDestScrollRegion = false + memoryBelow = false + ) + + blank := s.clearBlank() + if n > 0 { + // Scroll up (forward) + v = s.scrollUp(n, top, bot, 0, maxY, blank) + if !v { + s.buf.WriteString(ansi.SetTopBottomMargins(top+1, bot+1)) + + // XXX: How should we handle this in inline mode when not using alternate screen? + s.cur.X, s.cur.Y = -1, -1 + v = s.scrollUp(n, top, bot, top, bot, blank) + s.buf.WriteString(ansi.SetTopBottomMargins(1, maxY+1)) + s.cur.X, s.cur.Y = -1, -1 + } + + if !v { + v = s.scrollIdl(n, top, bot-n+1, blank) + } + + // Clear newly shifted-in lines. + if v && + (nonDestScrollRegion || (memoryBelow && bot == maxY)) { + if bot == maxY { + s.move(0, bot-n+1) + s.clearToBottom(nil) + } else { + for i := 0; i < n; i++ { + s.move(0, bot-i) + s.clearToEnd(nil, false) + } + } + } + } else if n < 0 { + // Scroll down (backward) + v = s.scrollDown(-n, top, bot, 0, maxY, blank) + if !v { + s.buf.WriteString(ansi.SetTopBottomMargins(top+1, bot+1)) + + // XXX: How should we handle this in inline mode when not using alternate screen? + s.cur.X, s.cur.Y = -1, -1 + v = s.scrollDown(-n, top, bot, top, bot, blank) + s.buf.WriteString(ansi.SetTopBottomMargins(1, maxY+1)) + s.cur.X, s.cur.Y = -1, -1 + + if !v { + v = s.scrollIdl(-n, bot+n+1, top, blank) + } + + // Clear newly shifted-in lines. + if v && + (nonDestScrollRegion || (memoryBelow && top == 0)) { + for i := 0; i < -n; i++ { + s.move(0, top+i) + s.clearToEnd(nil, false) + } + } + } + } + + if !v { + return + } + + s.scrollBuffer(s.curbuf, n, top, bot, blank) + + // shift hash values too, they can be reused + s.scrollOldhash(n, top, bot) + + return true +} + +// scrollBuffer scrolls the buffer by n lines. +func (s *Screen) scrollBuffer(b *Buffer, n, top, bot int, blank *Cell) { + if top < 0 || bot < top || bot >= b.Height() { + // Nothing to scroll + return + } + + if n < 0 { + // shift n lines downwards + limit := top - n + for line := bot; line >= limit && line >= 0 && line >= top; line-- { + copy(b.Lines[line], b.Lines[line+n]) + } + for line := top; line < limit && line <= b.Height()-1 && line <= bot; line++ { + b.FillRect(blank, Rect(0, line, b.Width(), 1)) + } + } + + if n > 0 { + // shift n lines upwards + limit := bot - n + for line := top; line <= limit && line <= b.Height()-1 && line <= bot; line++ { + copy(b.Lines[line], b.Lines[line+n]) + } + for line := bot; line > limit && line >= 0 && line >= top; line-- { + b.FillRect(blank, Rect(0, line, b.Width(), 1)) + } + } + + s.touchLine(b.Width(), b.Height(), top, bot-top+1, true) +} + +// touchLine marks the line as touched. +func (s *Screen) touchLine(width, height, y, n int, changed bool) { + if n < 0 || y < 0 || y >= height { + return // Nothing to touch + } + + for i := y; i < y+n && i < height; i++ { + if changed { + s.touch[i] = lineData{firstCell: 0, lastCell: width - 1} + } else { + delete(s.touch, i) + } + } +} + +// scrollUp scrolls the screen up by n lines. +func (s *Screen) scrollUp(n, top, bot, minY, maxY int, blank *Cell) bool { + if n == 1 && top == minY && bot == maxY { + s.move(0, bot) + s.updatePen(blank) + s.buf.WriteByte('\n') + } else if n == 1 && bot == maxY { + s.move(0, top) + s.updatePen(blank) + s.buf.WriteString(ansi.DeleteLine(1)) + } else if top == minY && bot == maxY { + if s.xtermLike { + s.move(0, bot) + } else { + s.move(0, top) + } + s.updatePen(blank) + if s.xtermLike { + s.buf.WriteString(ansi.ScrollUp(n)) + } else { + s.buf.WriteString(strings.Repeat("\n", n)) + } + } else if bot == maxY { + s.move(0, top) + s.updatePen(blank) + s.buf.WriteString(ansi.DeleteLine(n)) + } else { + return false + } + return true +} + +// scrollDown scrolls the screen down by n lines. +func (s *Screen) scrollDown(n, top, bot, minY, maxY int, blank *Cell) bool { + if n == 1 && top == minY && bot == maxY { + s.move(0, top) + s.updatePen(blank) + s.buf.WriteString(ansi.ReverseIndex) + } else if n == 1 && bot == maxY { + s.move(0, top) + s.updatePen(blank) + s.buf.WriteString(ansi.InsertLine(1)) + } else if top == minY && bot == maxY { + s.move(0, top) + s.updatePen(blank) + if s.xtermLike { + s.buf.WriteString(ansi.ScrollDown(n)) + } else { + s.buf.WriteString(strings.Repeat(ansi.ReverseIndex, n)) + } + } else if bot == maxY { + s.move(0, top) + s.updatePen(blank) + s.buf.WriteString(ansi.InsertLine(n)) + } else { + return false + } + return true +} + +// scrollIdl scrolls the screen n lines by using [ansi.DL] at del and using +// [ansi.IL] at ins. +func (s *Screen) scrollIdl(n, del, ins int, blank *Cell) bool { + if n < 0 { + return false + } + + // Delete lines + s.move(0, del) + s.updatePen(blank) + s.buf.WriteString(ansi.DeleteLine(n)) + + // Insert lines + s.move(0, ins) + s.updatePen(blank) + s.buf.WriteString(ansi.InsertLine(n)) + + return true +} diff --git a/vendor/github.com/charmbracelet/x/cellbuf/hashmap.go b/vendor/github.com/charmbracelet/x/cellbuf/hashmap.go new file mode 100644 index 000000000..0d25b5492 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/cellbuf/hashmap.go @@ -0,0 +1,301 @@ +package cellbuf + +import ( + "github.com/charmbracelet/x/ansi" +) + +// hash returns the hash value of a [Line]. +func hash(l Line) (h uint64) { + for _, c := range l { + var r rune + if c == nil { + r = ansi.SP + } else { + r = c.Rune + } + h += (h << 5) + uint64(r) + } + return +} + +// hashmap represents a single [Line] hash. +type hashmap struct { + value uint64 + oldcount, newcount int + oldindex, newindex int +} + +// The value used to indicate lines created by insertions and scrolls. +const newIndex = -1 + +// updateHashmap updates the hashmap with the new hash value. +func (s *Screen) updateHashmap() { + height := s.newbuf.Height() + if len(s.oldhash) >= height && len(s.newhash) >= height { + // rehash changed lines + for i := 0; i < height; i++ { + _, ok := s.touch[i] + if ok { + s.oldhash[i] = hash(s.curbuf.Line(i)) + s.newhash[i] = hash(s.newbuf.Line(i)) + } + } + } else { + // rehash all + if len(s.oldhash) != height { + s.oldhash = make([]uint64, height) + } + if len(s.newhash) != height { + s.newhash = make([]uint64, height) + } + for i := 0; i < height; i++ { + s.oldhash[i] = hash(s.curbuf.Line(i)) + s.newhash[i] = hash(s.newbuf.Line(i)) + } + } + + s.hashtab = make([]hashmap, height*2) + for i := 0; i < height; i++ { + hashval := s.oldhash[i] + + // Find matching hash or empty slot + idx := 0 + for idx < len(s.hashtab) && s.hashtab[idx].value != 0 { + if s.hashtab[idx].value == hashval { + break + } + idx++ + } + + s.hashtab[idx].value = hashval // in case this is a new hash + s.hashtab[idx].oldcount++ + s.hashtab[idx].oldindex = i + } + for i := 0; i < height; i++ { + hashval := s.newhash[i] + + // Find matching hash or empty slot + idx := 0 + for idx < len(s.hashtab) && s.hashtab[idx].value != 0 { + if s.hashtab[idx].value == hashval { + break + } + idx++ + } + + s.hashtab[idx].value = hashval // in case this is a new hash + s.hashtab[idx].newcount++ + s.hashtab[idx].newindex = i + + s.oldnum[i] = newIndex // init old indices slice + } + + // Mark line pair corresponding to unique hash pairs. + for i := 0; i < len(s.hashtab) && s.hashtab[i].value != 0; i++ { + hsp := &s.hashtab[i] + if hsp.oldcount == 1 && hsp.newcount == 1 && hsp.oldindex != hsp.newindex { + s.oldnum[hsp.newindex] = hsp.oldindex + } + } + + s.growHunks() + + // Eliminate bad or impossible shifts. This includes removing those hunks + // which could not grow because of conflicts, as well those which are to be + // moved too far, they are likely to destroy more than carry. + for i := 0; i < height; { + var start, shift, size int + for i < height && s.oldnum[i] == newIndex { + i++ + } + if i >= height { + break + } + start = i + shift = s.oldnum[i] - i + i++ + for i < height && s.oldnum[i] != newIndex && s.oldnum[i]-i == shift { + i++ + } + size = i - start + if size < 3 || size+min(size/8, 2) < abs(shift) { + for start < i { + s.oldnum[start] = newIndex + start++ + } + } + } + + // After clearing invalid hunks, try grow the rest. + s.growHunks() +} + +// scrollOldhash +func (s *Screen) scrollOldhash(n, top, bot int) { + if len(s.oldhash) == 0 { + return + } + + size := bot - top + 1 - abs(n) + if n > 0 { + // Move existing hashes up + copy(s.oldhash[top:], s.oldhash[top+n:top+n+size]) + // Recalculate hashes for newly shifted-in lines + for i := bot; i > bot-n; i-- { + s.oldhash[i] = hash(s.curbuf.Line(i)) + } + } else { + // Move existing hashes down + copy(s.oldhash[top-n:], s.oldhash[top:top+size]) + // Recalculate hashes for newly shifted-in lines + for i := top; i < top-n; i++ { + s.oldhash[i] = hash(s.curbuf.Line(i)) + } + } +} + +func (s *Screen) growHunks() { + var ( + backLimit int // limits for cells to fill + backRefLimit int // limit for references + i int + nextHunk int + ) + + height := s.newbuf.Height() + for i < height && s.oldnum[i] == newIndex { + i++ + } + for ; i < height; i = nextHunk { + var ( + forwardLimit int + forwardRefLimit int + end int + start = i + shift = s.oldnum[i] - i + ) + + // get forward limit + i = start + 1 + for i < height && + s.oldnum[i] != newIndex && + s.oldnum[i]-i == shift { + i++ + } + + end = i + for i < height && s.oldnum[i] == newIndex { + i++ + } + + nextHunk = i + forwardLimit = i + if i >= height || s.oldnum[i] >= i { + forwardRefLimit = i + } else { + forwardRefLimit = s.oldnum[i] + } + + i = start - 1 + + // grow back + if shift < 0 { + backLimit = backRefLimit + (-shift) + } + for i >= backLimit { + if s.newhash[i] == s.oldhash[i+shift] || + s.costEffective(i+shift, i, shift < 0) { + s.oldnum[i] = i + shift + } else { + break + } + i-- + } + + i = end + // grow forward + if shift > 0 { + forwardLimit = forwardRefLimit - shift + } + for i < forwardLimit { + if s.newhash[i] == s.oldhash[i+shift] || + s.costEffective(i+shift, i, shift > 0) { + s.oldnum[i] = i + shift + } else { + break + } + i++ + } + + backLimit = i + backRefLimit = backLimit + if shift > 0 { + backRefLimit += shift + } + } +} + +// costEffective returns true if the cost of moving line 'from' to line 'to' seems to be +// cost effective. 'blank' indicates whether the line 'to' would become blank. +func (s *Screen) costEffective(from, to int, blank bool) bool { + if from == to { + return false + } + + newFrom := s.oldnum[from] + if newFrom == newIndex { + newFrom = from + } + + // On the left side of >= is the cost before moving. On the right side -- + // cost after moving. + + // Calculate costs before moving. + var costBeforeMove int + if blank { + // Cost of updating blank line at destination. + costBeforeMove = s.updateCostBlank(s.newbuf.Line(to)) + } else { + // Cost of updating exiting line at destination. + costBeforeMove = s.updateCost(s.curbuf.Line(to), s.newbuf.Line(to)) + } + + // Add cost of updating source line + costBeforeMove += s.updateCost(s.curbuf.Line(newFrom), s.newbuf.Line(from)) + + // Calculate costs after moving. + var costAfterMove int + if newFrom == from { + // Source becomes blank after move + costAfterMove = s.updateCostBlank(s.newbuf.Line(from)) + } else { + // Source gets updated from another line + costAfterMove = s.updateCost(s.curbuf.Line(newFrom), s.newbuf.Line(from)) + } + + // Add cost of moving source line to destination + costAfterMove += s.updateCost(s.curbuf.Line(from), s.newbuf.Line(to)) + + // Return true if moving is cost effective (costs less or equal) + return costBeforeMove >= costAfterMove +} + +func (s *Screen) updateCost(from, to Line) (cost int) { + var fidx, tidx int + for i := s.newbuf.Width() - 1; i > 0; i, fidx, tidx = i-1, fidx+1, tidx+1 { + if !cellEqual(from.At(fidx), to.At(tidx)) { + cost++ + } + } + return +} + +func (s *Screen) updateCostBlank(to Line) (cost int) { + var tidx int + for i := s.newbuf.Width() - 1; i > 0; i, tidx = i-1, tidx+1 { + if !cellEqual(nil, to.At(tidx)) { + cost++ + } + } + return +} diff --git a/vendor/github.com/charmbracelet/x/cellbuf/link.go b/vendor/github.com/charmbracelet/x/cellbuf/link.go new file mode 100644 index 000000000..112f8e8ab --- /dev/null +++ b/vendor/github.com/charmbracelet/x/cellbuf/link.go @@ -0,0 +1,14 @@ +package cellbuf + +import ( + "github.com/charmbracelet/colorprofile" +) + +// Convert converts a hyperlink to respect the given color profile. +func ConvertLink(h Link, p colorprofile.Profile) Link { + if p == colorprofile.NoTTY { + return Link{} + } + + return h +} diff --git a/vendor/github.com/charmbracelet/x/cellbuf/screen.go b/vendor/github.com/charmbracelet/x/cellbuf/screen.go new file mode 100644 index 000000000..963b9cac3 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/cellbuf/screen.go @@ -0,0 +1,1457 @@ +package cellbuf + +import ( + "bytes" + "errors" + "io" + "os" + "strings" + "sync" + + "github.com/charmbracelet/colorprofile" + "github.com/charmbracelet/x/ansi" + "github.com/charmbracelet/x/term" +) + +// ErrInvalidDimensions is returned when the dimensions of a window are invalid +// for the operation. +var ErrInvalidDimensions = errors.New("invalid dimensions") + +// notLocal returns whether the coordinates are not considered local movement +// using the defined thresholds. +// This takes the number of columns, and the coordinates of the current and +// target positions. +func notLocal(cols, fx, fy, tx, ty int) bool { + // The typical distance for a [ansi.CUP] sequence. Anything less than this + // is considered local movement. + const longDist = 8 - 1 + return (tx > longDist) && + (tx < cols-1-longDist) && + (abs(ty-fy)+abs(tx-fx) > longDist) +} + +// relativeCursorMove returns the relative cursor movement sequence using one or two +// of the following sequences [ansi.CUU], [ansi.CUD], [ansi.CUF], [ansi.CUB], +// [ansi.VPA], [ansi.HPA]. +// When overwrite is true, this will try to optimize the sequence by using the +// screen cells values to move the cursor instead of using escape sequences. +func relativeCursorMove(s *Screen, fx, fy, tx, ty int, overwrite, useTabs, useBackspace bool) string { + var seq strings.Builder + + width, height := s.newbuf.Width(), s.newbuf.Height() + if ty != fy { + var yseq string + if s.xtermLike && !s.opts.RelativeCursor { + yseq = ansi.VerticalPositionAbsolute(ty + 1) + } + + // OPTIM: Use [ansi.LF] and [ansi.ReverseIndex] as optimizations. + + if ty > fy { + n := ty - fy + if cud := ansi.CursorDown(n); yseq == "" || len(cud) < len(yseq) { + yseq = cud + } + shouldScroll := !s.opts.AltScreen && fy+n >= s.scrollHeight + if lf := strings.Repeat("\n", n); shouldScroll || (fy+n < height && len(lf) < len(yseq)) { + // TODO: Ensure we're not unintentionally scrolling the screen down. + yseq = lf + s.scrollHeight = max(s.scrollHeight, fy+n) + } + } else if ty < fy { + n := fy - ty + if cuu := ansi.CursorUp(n); yseq == "" || len(cuu) < len(yseq) { + yseq = cuu + } + if n == 1 && fy-1 > 0 { + // TODO: Ensure we're not unintentionally scrolling the screen up. + yseq = ansi.ReverseIndex + } + } + + seq.WriteString(yseq) + } + + if tx != fx { + var xseq string + if s.xtermLike && !s.opts.RelativeCursor { + xseq = ansi.HorizontalPositionAbsolute(tx + 1) + } + + if tx > fx { + n := tx - fx + if useTabs { + var tabs int + var col int + for col = fx; s.tabs.Next(col) <= tx; col = s.tabs.Next(col) { + tabs++ + if col == s.tabs.Next(col) || col >= width-1 { + break + } + } + + if tabs > 0 { + cht := ansi.CursorHorizontalForwardTab(tabs) + tab := strings.Repeat("\t", tabs) + if false && s.xtermLike && len(cht) < len(tab) { + // TODO: The linux console and some terminals such as + // Alacritty don't support [ansi.CHT]. Enable this when + // we have a way to detect this, or after 5 years when + // we're sure everyone has updated their terminals :P + seq.WriteString(cht) + } else { + seq.WriteString(tab) + } + + n = tx - col + fx = col + } + } + + if cuf := ansi.CursorForward(n); xseq == "" || len(cuf) < len(xseq) { + xseq = cuf + } + + // If we have no attribute and style changes, overwrite is cheaper. + var ovw string + if overwrite && ty >= 0 { + for i := 0; i < n; i++ { + cell := s.newbuf.Cell(fx+i, ty) + if cell != nil && cell.Width > 0 { + i += cell.Width - 1 + if !cell.Style.Equal(&s.cur.Style) || !cell.Link.Equal(&s.cur.Link) { + overwrite = false + break + } + } + } + } + + if overwrite && ty >= 0 { + for i := 0; i < n; i++ { + cell := s.newbuf.Cell(fx+i, ty) + if cell != nil && cell.Width > 0 { + ovw += cell.String() + i += cell.Width - 1 + } else { + ovw += " " + } + } + } + + if overwrite && len(ovw) < len(xseq) { + xseq = ovw + } + } else if tx < fx { + n := fx - tx + if useTabs && s.xtermLike { + // VT100 does not support backward tabs [ansi.CBT]. + + col := fx + + var cbt int // cursor backward tabs count + for s.tabs.Prev(col) >= tx { + col = s.tabs.Prev(col) + cbt++ + if col == s.tabs.Prev(col) || col <= 0 { + break + } + } + + if cbt > 0 { + seq.WriteString(ansi.CursorBackwardTab(cbt)) + n = col - tx + } + } + + if cub := ansi.CursorBackward(n); xseq == "" || len(cub) < len(xseq) { + xseq = cub + } + + if useBackspace && n < len(xseq) { + xseq = strings.Repeat("\b", n) + } + } + + seq.WriteString(xseq) + } + + return seq.String() +} + +// moveCursor moves and returns the cursor movement sequence to move the cursor +// to the specified position. +// When overwrite is true, this will try to optimize the sequence by using the +// screen cells values to move the cursor instead of using escape sequences. +func moveCursor(s *Screen, x, y int, overwrite bool) (seq string) { + fx, fy := s.cur.X, s.cur.Y + + if !s.opts.RelativeCursor { + // Method #0: Use [ansi.CUP] if the distance is long. + seq = ansi.CursorPosition(x+1, y+1) + if fx == -1 || fy == -1 || notLocal(s.newbuf.Width(), fx, fy, x, y) { + return + } + } + + // Optimize based on options. + trials := 0 + if s.opts.HardTabs { + trials |= 2 // 0b10 in binary + } + if s.opts.Backspace { + trials |= 1 // 0b01 in binary + } + + // Try all possible combinations of hard tabs and backspace optimizations. + for i := 0; i <= trials; i++ { + // Skip combinations that are not enabled. + if i & ^trials != 0 { + continue + } + + useHardTabs := i&2 != 0 + useBackspace := i&1 != 0 + + // Method #1: Use local movement sequences. + nseq := relativeCursorMove(s, fx, fy, x, y, overwrite, useHardTabs, useBackspace) + if (i == 0 && len(seq) == 0) || len(nseq) < len(seq) { + seq = nseq + } + + // Method #2: Use [ansi.CR] and local movement sequences. + nseq = "\r" + relativeCursorMove(s, 0, fy, x, y, overwrite, useHardTabs, useBackspace) + if len(nseq) < len(seq) { + seq = nseq + } + + if !s.opts.RelativeCursor { + // Method #3: Use [ansi.CursorHomePosition] and local movement sequences. + nseq = ansi.CursorHomePosition + relativeCursorMove(s, 0, 0, x, y, overwrite, useHardTabs, useBackspace) + if len(nseq) < len(seq) { + seq = nseq + } + } + } + + return +} + +// moveCursor moves the cursor to the specified position. +func (s *Screen) moveCursor(x, y int, overwrite bool) { + if !s.opts.AltScreen && s.cur.X == -1 && s.cur.Y == -1 { + // First cursor movement in inline mode, move the cursor to the first + // column before moving to the target position. + s.buf.WriteByte('\r') //nolint:errcheck + s.cur.X, s.cur.Y = 0, 0 + } + s.buf.WriteString(moveCursor(s, x, y, overwrite)) //nolint:errcheck + s.cur.X, s.cur.Y = x, y +} + +func (s *Screen) move(x, y int) { + // XXX: Make sure we use the max height and width of the buffer in case + // we're in the middle of a resize operation. + width := max(s.newbuf.Width(), s.curbuf.Width()) + height := max(s.newbuf.Height(), s.curbuf.Height()) + + if width > 0 && x >= width { + // Handle autowrap + y += (x / width) + x %= width + } + + // XXX: Disable styles if there's any + // Some move operations such as [ansi.LF] can apply styles to the new + // cursor position, thus, we need to reset the styles before moving the + // cursor. + blank := s.clearBlank() + resetPen := y != s.cur.Y && !blank.Equal(&BlankCell) + if resetPen { + s.updatePen(nil) + } + + // Reset wrap around (phantom cursor) state + if s.atPhantom { + s.cur.X = 0 + s.buf.WriteByte('\r') //nolint:errcheck + s.atPhantom = false // reset phantom cell state + } + + // TODO: Investigate if we need to handle this case and/or if we need the + // following code. + // + // if width > 0 && s.cur.X >= width { + // l := (s.cur.X + 1) / width + // + // s.cur.Y += l + // if height > 0 && s.cur.Y >= height { + // l -= s.cur.Y - height - 1 + // } + // + // if l > 0 { + // s.cur.X = 0 + // s.buf.WriteString("\r" + strings.Repeat("\n", l)) //nolint:errcheck + // } + // } + + if height > 0 { + if s.cur.Y > height-1 { + s.cur.Y = height - 1 + } + if y > height-1 { + y = height - 1 + } + } + + if x == s.cur.X && y == s.cur.Y { + // We give up later because we need to run checks for the phantom cell + // and others before we can determine if we can give up. + return + } + + // We set the new cursor in [Screen.moveCursor]. + s.moveCursor(x, y, true) // Overwrite cells if possible +} + +// Cursor represents a terminal Cursor. +type Cursor struct { + Style + Link + Position +} + +// ScreenOptions are options for the screen. +type ScreenOptions struct { + // Term is the terminal type to use when writing to the screen. When empty, + // `$TERM` is used from [os.Getenv]. + Term string + // Profile is the color profile to use when writing to the screen. + Profile colorprofile.Profile + // RelativeCursor is whether to use relative cursor movements. This is + // useful when alt-screen is not used or when using inline mode. + RelativeCursor bool + // AltScreen is whether to use the alternate screen buffer. + AltScreen bool + // ShowCursor is whether to show the cursor. + ShowCursor bool + // HardTabs is whether to use hard tabs to optimize cursor movements. + HardTabs bool + // Backspace is whether to use backspace characters to move the cursor. + Backspace bool +} + +// lineData represents the metadata for a line. +type lineData struct { + // first and last changed cell indices + firstCell, lastCell int + // old index used for scrolling + oldIndex int //nolint:unused +} + +// Screen represents the terminal screen. +type Screen struct { + w io.Writer + buf *bytes.Buffer // buffer for writing to the screen + curbuf *Buffer // the current buffer + newbuf *Buffer // the new buffer + tabs *TabStops + touch map[int]lineData + queueAbove []string // the queue of strings to write above the screen + oldhash, newhash []uint64 // the old and new hash values for each line + hashtab []hashmap // the hashmap table + oldnum []int // old indices from previous hash + cur, saved Cursor // the current and saved cursors + opts ScreenOptions + mu sync.Mutex + method ansi.Method + scrollHeight int // keeps track of how many lines we've scrolled down (inline mode) + altScreenMode bool // whether alternate screen mode is enabled + cursorHidden bool // whether text cursor mode is enabled + clear bool // whether to force clear the screen + xtermLike bool // whether to use xterm-like optimizations, otherwise, it uses vt100 only + queuedText bool // whether we have queued non-zero width text queued up + atPhantom bool // whether the cursor is out of bounds and at a phantom cell +} + +// SetMethod sets the method used to calculate the width of cells. +func (s *Screen) SetMethod(method ansi.Method) { + s.method = method +} + +// UseBackspaces sets whether to use backspace characters to move the cursor. +func (s *Screen) UseBackspaces(v bool) { + s.opts.Backspace = v +} + +// UseHardTabs sets whether to use hard tabs to optimize cursor movements. +func (s *Screen) UseHardTabs(v bool) { + s.opts.HardTabs = v +} + +// SetColorProfile sets the color profile to use when writing to the screen. +func (s *Screen) SetColorProfile(p colorprofile.Profile) { + s.opts.Profile = p +} + +// SetRelativeCursor sets whether to use relative cursor movements. +func (s *Screen) SetRelativeCursor(v bool) { + s.opts.RelativeCursor = v +} + +// EnterAltScreen enters the alternate screen buffer. +func (s *Screen) EnterAltScreen() { + s.opts.AltScreen = true + s.clear = true + s.saved = s.cur +} + +// ExitAltScreen exits the alternate screen buffer. +func (s *Screen) ExitAltScreen() { + s.opts.AltScreen = false + s.clear = true + s.cur = s.saved +} + +// ShowCursor shows the cursor. +func (s *Screen) ShowCursor() { + s.opts.ShowCursor = true +} + +// HideCursor hides the cursor. +func (s *Screen) HideCursor() { + s.opts.ShowCursor = false +} + +// Bounds implements Window. +func (s *Screen) Bounds() Rectangle { + // Always return the new buffer bounds. + return s.newbuf.Bounds() +} + +// Cell implements Window. +func (s *Screen) Cell(x int, y int) *Cell { + return s.newbuf.Cell(x, y) +} + +// Redraw forces a full redraw of the screen. +func (s *Screen) Redraw() { + s.mu.Lock() + s.clear = true + s.mu.Unlock() +} + +// Clear clears the screen with blank cells. This is a convenience method for +// [Screen.Fill] with a nil cell. +func (s *Screen) Clear() bool { + return s.ClearRect(s.newbuf.Bounds()) +} + +// ClearRect clears the given rectangle with blank cells. This is a convenience +// method for [Screen.FillRect] with a nil cell. +func (s *Screen) ClearRect(r Rectangle) bool { + return s.FillRect(nil, r) +} + +// SetCell implements Window. +func (s *Screen) SetCell(x int, y int, cell *Cell) (v bool) { + s.mu.Lock() + defer s.mu.Unlock() + cellWidth := 1 + if cell != nil { + cellWidth = cell.Width + } + if prev := s.curbuf.Cell(x, y); !cellEqual(prev, cell) { + chg, ok := s.touch[y] + if !ok { + chg = lineData{firstCell: x, lastCell: x + cellWidth} + } else { + chg.firstCell = min(chg.firstCell, x) + chg.lastCell = max(chg.lastCell, x+cellWidth) + } + s.touch[y] = chg + } + + return s.newbuf.SetCell(x, y, cell) +} + +// Fill implements Window. +func (s *Screen) Fill(cell *Cell) bool { + return s.FillRect(cell, s.newbuf.Bounds()) +} + +// FillRect implements Window. +func (s *Screen) FillRect(cell *Cell, r Rectangle) bool { + s.mu.Lock() + defer s.mu.Unlock() + s.newbuf.FillRect(cell, r) + for i := r.Min.Y; i < r.Max.Y; i++ { + s.touch[i] = lineData{firstCell: r.Min.X, lastCell: r.Max.X} + } + return true +} + +// isXtermLike returns whether the terminal is xterm-like. This means that the +// terminal supports ECMA-48 and ANSI X3.64 escape sequences. +// TODO: Should this be a lookup table into each $TERM terminfo database? Like +// we could keep a map of ANSI escape sequence to terminfo capability name and +// check if the database supports the escape sequence. Instead of keeping a +// list of terminal names here. +func isXtermLike(termtype string) (v bool) { + parts := strings.Split(termtype, "-") + if len(parts) == 0 { + return + } + + switch parts[0] { + case + "alacritty", + "contour", + "foot", + "ghostty", + "kitty", + "linux", + "rio", + "screen", + "st", + "tmux", + "wezterm", + "xterm": + v = true + } + + return +} + +// NewScreen creates a new Screen. +func NewScreen(w io.Writer, width, height int, opts *ScreenOptions) (s *Screen) { + s = new(Screen) + s.w = w + if opts != nil { + s.opts = *opts + } + + if s.opts.Term == "" { + s.opts.Term = os.Getenv("TERM") + } + + if width <= 0 || height <= 0 { + if f, ok := w.(term.File); ok { + width, height, _ = term.GetSize(f.Fd()) + } + } + if width < 0 { + width = 0 + } + if height < 0 { + height = 0 + } + + s.buf = new(bytes.Buffer) + s.xtermLike = isXtermLike(s.opts.Term) + s.curbuf = NewBuffer(width, height) + s.newbuf = NewBuffer(width, height) + s.cur = Cursor{Position: Pos(-1, -1)} // start at -1 to force a move + s.saved = s.cur + s.reset() + + return +} + +// Width returns the width of the screen. +func (s *Screen) Width() int { + return s.newbuf.Width() +} + +// Height returns the height of the screen. +func (s *Screen) Height() int { + return s.newbuf.Height() +} + +// cellEqual returns whether the two cells are equal. A nil cell is considered +// a [BlankCell]. +func cellEqual(a, b *Cell) bool { + if a == b { + return true + } + if a == nil { + a = &BlankCell + } + if b == nil { + b = &BlankCell + } + return a.Equal(b) +} + +// putCell draws a cell at the current cursor position. +func (s *Screen) putCell(cell *Cell) { + width, height := s.newbuf.Width(), s.newbuf.Height() + if s.opts.AltScreen && s.cur.X == width-1 && s.cur.Y == height-1 { + s.putCellLR(cell) + } else { + s.putAttrCell(cell) + } +} + +// wrapCursor wraps the cursor to the next line. +// +//nolint:unused +func (s *Screen) wrapCursor() { + const autoRightMargin = true + if autoRightMargin { + // Assume we have auto wrap mode enabled. + s.cur.X = 0 + s.cur.Y++ + } else { + s.cur.X-- + } +} + +func (s *Screen) putAttrCell(cell *Cell) { + if cell != nil && cell.Empty() { + // XXX: Zero width cells are special and should not be written to the + // screen no matter what other attributes they have. + // Zero width cells are used for wide characters that are split into + // multiple cells. + return + } + + if cell == nil { + cell = s.clearBlank() + } + + // We're at pending wrap state (phantom cell), incoming cell should + // wrap. + if s.atPhantom { + s.wrapCursor() + s.atPhantom = false + } + + s.updatePen(cell) + s.buf.WriteRune(cell.Rune) //nolint:errcheck + for _, c := range cell.Comb { + s.buf.WriteRune(c) //nolint:errcheck + } + + s.cur.X += cell.Width + + if cell.Width > 0 { + s.queuedText = true + } + + if s.cur.X >= s.newbuf.Width() { + s.atPhantom = true + } +} + +// putCellLR draws a cell at the lower right corner of the screen. +func (s *Screen) putCellLR(cell *Cell) { + // Optimize for the lower right corner cell. + curX := s.cur.X + if cell == nil || !cell.Empty() { + s.buf.WriteString(ansi.ResetAutoWrapMode) //nolint:errcheck + s.putAttrCell(cell) + // Writing to lower-right corner cell should not wrap. + s.atPhantom = false + s.cur.X = curX + s.buf.WriteString(ansi.SetAutoWrapMode) //nolint:errcheck + } +} + +// updatePen updates the cursor pen styles. +func (s *Screen) updatePen(cell *Cell) { + if cell == nil { + cell = &BlankCell + } + + if s.opts.Profile != 0 { + // Downsample colors to the given color profile. + cell.Style = ConvertStyle(cell.Style, s.opts.Profile) + cell.Link = ConvertLink(cell.Link, s.opts.Profile) + } + + if !cell.Style.Equal(&s.cur.Style) { + seq := cell.Style.DiffSequence(s.cur.Style) + if cell.Style.Empty() && len(seq) > len(ansi.ResetStyle) { + seq = ansi.ResetStyle + } + s.buf.WriteString(seq) //nolint:errcheck + s.cur.Style = cell.Style + } + if !cell.Link.Equal(&s.cur.Link) { + s.buf.WriteString(ansi.SetHyperlink(cell.Link.URL, cell.Link.Params)) //nolint:errcheck + s.cur.Link = cell.Link + } +} + +// emitRange emits a range of cells to the buffer. It it equivalent to calling +// [Screen.putCell] for each cell in the range. This is optimized to use +// [ansi.ECH] and [ansi.REP]. +// Returns whether the cursor is at the end of interval or somewhere in the +// middle. +func (s *Screen) emitRange(line Line, n int) (eoi bool) { + for n > 0 { + var count int + for n > 1 && !cellEqual(line.At(0), line.At(1)) { + s.putCell(line.At(0)) + line = line[1:] + n-- + } + + cell0 := line[0] + if n == 1 { + s.putCell(cell0) + return false + } + + count = 2 + for count < n && cellEqual(line.At(count), cell0) { + count++ + } + + ech := ansi.EraseCharacter(count) + cup := ansi.CursorPosition(s.cur.X+count, s.cur.Y) + rep := ansi.RepeatPreviousCharacter(count) + if s.xtermLike && count > len(ech)+len(cup) && cell0 != nil && cell0.Clear() { + s.updatePen(cell0) + s.buf.WriteString(ech) //nolint:errcheck + + // If this is the last cell, we don't need to move the cursor. + if count < n { + s.move(s.cur.X+count, s.cur.Y) + } else { + return true // cursor in the middle + } + } else if s.xtermLike && count > len(rep) && + (cell0 == nil || (len(cell0.Comb) == 0 && cell0.Rune < 256)) { + // We only support ASCII characters. Most terminals will handle + // non-ASCII characters correctly, but some might not, ahem xterm. + // + // NOTE: [ansi.REP] only repeats the last rune and won't work + // if the last cell contains multiple runes. + + wrapPossible := s.cur.X+count >= s.newbuf.Width() + repCount := count + if wrapPossible { + repCount-- + } + + s.updatePen(cell0) + s.putCell(cell0) + repCount-- // cell0 is a single width cell ASCII character + + s.buf.WriteString(ansi.RepeatPreviousCharacter(repCount)) //nolint:errcheck + s.cur.X += repCount + if wrapPossible { + s.putCell(cell0) + } + } else { + for i := 0; i < count; i++ { + s.putCell(line.At(i)) + } + } + + line = line[clamp(count, 0, len(line)):] + n -= count + } + + return +} + +// putRange puts a range of cells from the old line to the new line. +// Returns whether the cursor is at the end of interval or somewhere in the +// middle. +func (s *Screen) putRange(oldLine, newLine Line, y, start, end int) (eoi bool) { + inline := min(len(ansi.CursorPosition(start+1, y+1)), + min(len(ansi.HorizontalPositionAbsolute(start+1)), + len(ansi.CursorForward(start+1)))) + if (end - start + 1) > inline { + var j, same int + for j, same = start, 0; j <= end; j++ { + oldCell, newCell := oldLine.At(j), newLine.At(j) + if same == 0 && oldCell != nil && oldCell.Empty() { + continue + } + if cellEqual(oldCell, newCell) { + same++ + } else { + if same > end-start { + s.emitRange(newLine[start:], j-same-start) + s.move(j, y) + start = j + } + same = 0 + } + } + + i := s.emitRange(newLine[start:], j-same-start) + + // Always return 1 for the next [Screen.move] after a [Screen.putRange] if + // we found identical characters at end of interval. + if same == 0 { + return i + } + return true + } + + return s.emitRange(newLine[start:], end-start+1) +} + +// clearToEnd clears the screen from the current cursor position to the end of +// line. +func (s *Screen) clearToEnd(blank *Cell, force bool) { //nolint:unparam + if s.cur.Y >= 0 { + curline := s.curbuf.Line(s.cur.Y) + for j := s.cur.X; j < s.curbuf.Width(); j++ { + if j >= 0 { + c := curline.At(j) + if !cellEqual(c, blank) { + curline.Set(j, blank) + force = true + } + } + } + } + + if force { + s.updatePen(blank) + count := s.newbuf.Width() - s.cur.X + if s.el0Cost() <= count { + s.buf.WriteString(ansi.EraseLineRight) //nolint:errcheck + } else { + for i := 0; i < count; i++ { + s.putCell(blank) + } + } + } +} + +// clearBlank returns a blank cell based on the current cursor background color. +func (s *Screen) clearBlank() *Cell { + c := BlankCell + if !s.cur.Style.Empty() || !s.cur.Link.Empty() { + c.Style = s.cur.Style + c.Link = s.cur.Link + } + return &c +} + +// insertCells inserts the count cells pointed by the given line at the current +// cursor position. +func (s *Screen) insertCells(line Line, count int) { + if s.xtermLike { + // Use [ansi.ICH] as an optimization. + s.buf.WriteString(ansi.InsertCharacter(count)) //nolint:errcheck + } else { + // Otherwise, use [ansi.IRM] mode. + s.buf.WriteString(ansi.SetInsertReplaceMode) //nolint:errcheck + } + + for i := 0; count > 0; i++ { + s.putAttrCell(line[i]) + count-- + } + + if !s.xtermLike { + s.buf.WriteString(ansi.ResetInsertReplaceMode) //nolint:errcheck + } +} + +// el0Cost returns the cost of using [ansi.EL] 0 i.e. [ansi.EraseLineRight]. If +// this terminal supports background color erase, it can be cheaper to use +// [ansi.EL] 0 i.e. [ansi.EraseLineRight] to clear +// trailing spaces. +func (s *Screen) el0Cost() int { + if s.xtermLike { + return 0 + } + return len(ansi.EraseLineRight) +} + +// transformLine transforms the given line in the current window to the +// corresponding line in the new window. It uses [ansi.ICH] and [ansi.DCH] to +// insert or delete characters. +func (s *Screen) transformLine(y int) { + var firstCell, oLastCell, nLastCell int // first, old last, new last index + oldLine := s.curbuf.Line(y) + newLine := s.newbuf.Line(y) + + // Find the first changed cell in the line + var lineChanged bool + for i := 0; i < s.newbuf.Width(); i++ { + if !cellEqual(newLine.At(i), oldLine.At(i)) { + lineChanged = true + break + } + } + + const ceolStandoutGlitch = false + if ceolStandoutGlitch && lineChanged { + s.move(0, y) + s.clearToEnd(nil, false) + s.putRange(oldLine, newLine, y, 0, s.newbuf.Width()-1) + } else { + blank := newLine.At(0) + + // It might be cheaper to clear leading spaces with [ansi.EL] 1 i.e. + // [ansi.EraseLineLeft]. + if blank == nil || blank.Clear() { + var oFirstCell, nFirstCell int + for oFirstCell = 0; oFirstCell < s.curbuf.Width(); oFirstCell++ { + if !cellEqual(oldLine.At(oFirstCell), blank) { + break + } + } + for nFirstCell = 0; nFirstCell < s.newbuf.Width(); nFirstCell++ { + if !cellEqual(newLine.At(nFirstCell), blank) { + break + } + } + + if nFirstCell == oFirstCell { + firstCell = nFirstCell + + // Find the first differing cell + for firstCell < s.newbuf.Width() && + cellEqual(oldLine.At(firstCell), newLine.At(firstCell)) { + firstCell++ + } + } else if oFirstCell > nFirstCell { + firstCell = nFirstCell + } else if oFirstCell < nFirstCell { + firstCell = oFirstCell + el1Cost := len(ansi.EraseLineLeft) + if el1Cost < nFirstCell-oFirstCell { + if nFirstCell >= s.newbuf.Width() { + s.move(0, y) + s.updatePen(blank) + s.buf.WriteString(ansi.EraseLineRight) //nolint:errcheck + } else { + s.move(nFirstCell-1, y) + s.updatePen(blank) + s.buf.WriteString(ansi.EraseLineLeft) //nolint:errcheck + } + + for firstCell < nFirstCell { + oldLine.Set(firstCell, blank) + firstCell++ + } + } + } + } else { + // Find the first differing cell + for firstCell < s.newbuf.Width() && cellEqual(newLine.At(firstCell), oldLine.At(firstCell)) { + firstCell++ + } + } + + // If we didn't find one, we're done + if firstCell >= s.newbuf.Width() { + return + } + + blank = newLine.At(s.newbuf.Width() - 1) + if blank != nil && !blank.Clear() { + // Find the last differing cell + nLastCell = s.newbuf.Width() - 1 + for nLastCell > firstCell && cellEqual(newLine.At(nLastCell), oldLine.At(nLastCell)) { + nLastCell-- + } + + if nLastCell >= firstCell { + s.move(firstCell, y) + s.putRange(oldLine, newLine, y, firstCell, nLastCell) + if firstCell < len(oldLine) && firstCell < len(newLine) { + copy(oldLine[firstCell:], newLine[firstCell:]) + } else { + copy(oldLine, newLine) + } + } + + return + } + + // Find last non-blank cell in the old line. + oLastCell = s.curbuf.Width() - 1 + for oLastCell > firstCell && cellEqual(oldLine.At(oLastCell), blank) { + oLastCell-- + } + + // Find last non-blank cell in the new line. + nLastCell = s.newbuf.Width() - 1 + for nLastCell > firstCell && cellEqual(newLine.At(nLastCell), blank) { + nLastCell-- + } + + if nLastCell == firstCell && s.el0Cost() < oLastCell-nLastCell { + s.move(firstCell, y) + if !cellEqual(newLine.At(firstCell), blank) { + s.putCell(newLine.At(firstCell)) + } + s.clearToEnd(blank, false) + } else if nLastCell != oLastCell && + !cellEqual(newLine.At(nLastCell), oldLine.At(oLastCell)) { + s.move(firstCell, y) + if oLastCell-nLastCell > s.el0Cost() { + if s.putRange(oldLine, newLine, y, firstCell, nLastCell) { + s.move(nLastCell+1, y) + } + s.clearToEnd(blank, false) + } else { + n := max(nLastCell, oLastCell) + s.putRange(oldLine, newLine, y, firstCell, n) + } + } else { + nLastNonBlank := nLastCell + oLastNonBlank := oLastCell + + // Find the last cells that really differ. + // Can be -1 if no cells differ. + for cellEqual(newLine.At(nLastCell), oldLine.At(oLastCell)) { + if !cellEqual(newLine.At(nLastCell-1), oldLine.At(oLastCell-1)) { + break + } + nLastCell-- + oLastCell-- + if nLastCell == -1 || oLastCell == -1 { + break + } + } + + n := min(oLastCell, nLastCell) + if n >= firstCell { + s.move(firstCell, y) + s.putRange(oldLine, newLine, y, firstCell, n) + } + + if oLastCell < nLastCell { + m := max(nLastNonBlank, oLastNonBlank) + if n != 0 { + for n > 0 { + wide := newLine.At(n + 1) + if wide == nil || !wide.Empty() { + break + } + n-- + oLastCell-- + } + } else if n >= firstCell && newLine.At(n) != nil && newLine.At(n).Width > 1 { + next := newLine.At(n + 1) + for next != nil && next.Empty() { + n++ + oLastCell++ + } + } + + s.move(n+1, y) + ichCost := 3 + nLastCell - oLastCell + if s.xtermLike && (nLastCell < nLastNonBlank || ichCost > (m-n)) { + s.putRange(oldLine, newLine, y, n+1, m) + } else { + s.insertCells(newLine[n+1:], nLastCell-oLastCell) + } + } else if oLastCell > nLastCell { + s.move(n+1, y) + dchCost := 3 + oLastCell - nLastCell + if dchCost > len(ansi.EraseLineRight)+nLastNonBlank-(n+1) { + if s.putRange(oldLine, newLine, y, n+1, nLastNonBlank) { + s.move(nLastNonBlank+1, y) + } + s.clearToEnd(blank, false) + } else { + s.updatePen(blank) + s.deleteCells(oLastCell - nLastCell) + } + } + } + } + + // Update the old line with the new line + if firstCell < len(oldLine) && firstCell < len(newLine) { + copy(oldLine[firstCell:], newLine[firstCell:]) + } else { + copy(oldLine, newLine) + } +} + +// deleteCells deletes the count cells at the current cursor position and moves +// the rest of the line to the left. This is equivalent to [ansi.DCH]. +func (s *Screen) deleteCells(count int) { + // [ansi.DCH] will shift in cells from the right margin so we need to + // ensure that they are the right style. + s.buf.WriteString(ansi.DeleteCharacter(count)) //nolint:errcheck +} + +// clearToBottom clears the screen from the current cursor position to the end +// of the screen. +func (s *Screen) clearToBottom(blank *Cell) { + row, col := s.cur.Y, s.cur.X + if row < 0 { + row = 0 + } + + s.updatePen(blank) + s.buf.WriteString(ansi.EraseScreenBelow) //nolint:errcheck + // Clear the rest of the current line + s.curbuf.ClearRect(Rect(col, row, s.curbuf.Width()-col, 1)) + // Clear everything below the current line + s.curbuf.ClearRect(Rect(0, row+1, s.curbuf.Width(), s.curbuf.Height()-row-1)) +} + +// clearBottom tests if clearing the end of the screen would satisfy part of +// the screen update. Scan backwards through lines in the screen checking if +// each is blank and one or more are changed. +// It returns the top line. +func (s *Screen) clearBottom(total int) (top int) { + if total <= 0 { + return + } + + top = total + last := s.newbuf.Width() + blank := s.clearBlank() + canClearWithBlank := blank == nil || blank.Clear() + + if canClearWithBlank { + var row int + for row = total - 1; row >= 0; row-- { + oldLine := s.curbuf.Line(row) + newLine := s.newbuf.Line(row) + + var col int + ok := true + for col = 0; ok && col < last; col++ { + ok = cellEqual(newLine.At(col), blank) + } + if !ok { + break + } + + for col = 0; ok && col < last; col++ { + ok = len(oldLine) == last && cellEqual(oldLine.At(col), blank) + } + if !ok { + top = row + } + } + + if top < total { + s.move(0, top-1) // top is 1-based + s.clearToBottom(blank) + if s.oldhash != nil && s.newhash != nil && + row < len(s.oldhash) && row < len(s.newhash) { + for row := top; row < s.newbuf.Height(); row++ { + s.oldhash[row] = s.newhash[row] + } + } + } + } + + return +} + +// clearScreen clears the screen and put cursor at home. +func (s *Screen) clearScreen(blank *Cell) { + s.updatePen(blank) + s.buf.WriteString(ansi.CursorHomePosition) //nolint:errcheck + s.buf.WriteString(ansi.EraseEntireScreen) //nolint:errcheck + s.cur.X, s.cur.Y = 0, 0 + s.curbuf.Fill(blank) +} + +// clearBelow clears everything below and including the row. +func (s *Screen) clearBelow(blank *Cell, row int) { + s.move(0, row) + s.clearToBottom(blank) +} + +// clearUpdate forces a screen redraw. +func (s *Screen) clearUpdate() { + blank := s.clearBlank() + var nonEmpty int + if s.opts.AltScreen { + // XXX: We're using the maximum height of the two buffers to ensure + // we write newly added lines to the screen in [Screen.transformLine]. + nonEmpty = max(s.curbuf.Height(), s.newbuf.Height()) + s.clearScreen(blank) + } else { + nonEmpty = s.newbuf.Height() + s.clearBelow(blank, 0) + } + nonEmpty = s.clearBottom(nonEmpty) + for i := 0; i < nonEmpty; i++ { + s.transformLine(i) + } +} + +// Flush flushes the buffer to the screen. +func (s *Screen) Flush() (err error) { + s.mu.Lock() + defer s.mu.Unlock() + return s.flush() +} + +func (s *Screen) flush() (err error) { + // Write the buffer + if s.buf.Len() > 0 { + _, err = s.w.Write(s.buf.Bytes()) //nolint:errcheck + if err == nil { + s.buf.Reset() + } + } + + return +} + +// Render renders changes of the screen to the internal buffer. Call +// [Screen.Flush] to flush pending changes to the screen. +func (s *Screen) Render() { + s.mu.Lock() + s.render() + s.mu.Unlock() +} + +func (s *Screen) render() { + // Do we need to render anything? + if s.opts.AltScreen == s.altScreenMode && + !s.opts.ShowCursor == s.cursorHidden && + !s.clear && + len(s.touch) == 0 && + len(s.queueAbove) == 0 { + return + } + + // TODO: Investigate whether this is necessary. Theoretically, terminals + // can add/remove tab stops and we should be able to handle that. We could + // use [ansi.DECTABSR] to read the tab stops, but that's not implemented in + // most terminals :/ + // // Are we using hard tabs? If so, ensure tabs are using the + // // default interval using [ansi.DECST8C]. + // if s.opts.HardTabs && !s.initTabs { + // s.buf.WriteString(ansi.SetTabEvery8Columns) + // s.initTabs = true + // } + + // Do we need alt-screen mode? + if s.opts.AltScreen != s.altScreenMode { + if s.opts.AltScreen { + s.buf.WriteString(ansi.SetAltScreenSaveCursorMode) + } else { + s.buf.WriteString(ansi.ResetAltScreenSaveCursorMode) + } + s.altScreenMode = s.opts.AltScreen + } + + // Do we need text cursor mode? + if !s.opts.ShowCursor != s.cursorHidden { + s.cursorHidden = !s.opts.ShowCursor + if s.cursorHidden { + s.buf.WriteString(ansi.HideCursor) + } + } + + // Do we have queued strings to write above the screen? + if len(s.queueAbove) > 0 { + // TODO: Use scrolling region if available. + // TODO: Use [Screen.Write] [io.Writer] interface. + + // We need to scroll the screen up by the number of lines in the queue. + // We can't use [ansi.SU] because we want the cursor to move down until + // it reaches the bottom of the screen. + s.move(0, s.newbuf.Height()-1) + s.buf.WriteString(strings.Repeat("\n", len(s.queueAbove))) + s.cur.Y += len(s.queueAbove) + // XXX: Now go to the top of the screen, insert new lines, and write + // the queued strings. It is important to use [Screen.moveCursor] + // instead of [Screen.move] because we don't want to perform any checks + // on the cursor position. + s.moveCursor(0, 0, false) + s.buf.WriteString(ansi.InsertLine(len(s.queueAbove))) + for _, line := range s.queueAbove { + s.buf.WriteString(line + "\r\n") + } + + // Clear the queue + s.queueAbove = s.queueAbove[:0] + } + + var nonEmpty int + + // XXX: In inline mode, after a screen resize, we need to clear the extra + // lines at the bottom of the screen. This is because in inline mode, we + // don't use the full screen height and the current buffer size might be + // larger than the new buffer size. + partialClear := !s.opts.AltScreen && s.cur.X != -1 && s.cur.Y != -1 && + s.curbuf.Width() == s.newbuf.Width() && + s.curbuf.Height() > 0 && + s.curbuf.Height() > s.newbuf.Height() + + if !s.clear && partialClear { + s.clearBelow(nil, s.newbuf.Height()-1) + } + + if s.clear { + s.clearUpdate() + s.clear = false + } else if len(s.touch) > 0 { + if s.opts.AltScreen { + // Optimize scrolling for the alternate screen buffer. + // TODO: Should we optimize for inline mode as well? If so, we need + // to know the actual cursor position to use [ansi.DECSTBM]. + s.scrollOptimize() + } + + var changedLines int + var i int + + if s.opts.AltScreen { + nonEmpty = min(s.curbuf.Height(), s.newbuf.Height()) + } else { + nonEmpty = s.newbuf.Height() + } + + nonEmpty = s.clearBottom(nonEmpty) + for i = 0; i < nonEmpty; i++ { + _, ok := s.touch[i] + if ok { + s.transformLine(i) + changedLines++ + } + } + } + + // Sync windows and screen + s.touch = make(map[int]lineData, s.newbuf.Height()) + + if s.curbuf.Width() != s.newbuf.Width() || s.curbuf.Height() != s.newbuf.Height() { + // Resize the old buffer to match the new buffer. + _, oldh := s.curbuf.Width(), s.curbuf.Height() + s.curbuf.Resize(s.newbuf.Width(), s.newbuf.Height()) + // Sync new lines to old lines + for i := oldh - 1; i < s.newbuf.Height(); i++ { + copy(s.curbuf.Line(i), s.newbuf.Line(i)) + } + } + + s.updatePen(nil) // nil indicates a blank cell with no styles + + // Do we have enough changes to justify toggling the cursor? + if s.buf.Len() > 1 && s.opts.ShowCursor && !s.cursorHidden && s.queuedText { + nb := new(bytes.Buffer) + nb.Grow(s.buf.Len() + len(ansi.HideCursor) + len(ansi.ShowCursor)) + nb.WriteString(ansi.HideCursor) + nb.Write(s.buf.Bytes()) + nb.WriteString(ansi.ShowCursor) + *s.buf = *nb + } + + s.queuedText = false +} + +// Close writes the final screen update and resets the screen. +func (s *Screen) Close() (err error) { + s.mu.Lock() + defer s.mu.Unlock() + + s.render() + s.updatePen(nil) + // Go to the bottom of the screen + s.move(0, s.newbuf.Height()-1) + + if s.altScreenMode { + s.buf.WriteString(ansi.ResetAltScreenSaveCursorMode) + s.altScreenMode = false + } + + if s.cursorHidden { + s.buf.WriteString(ansi.ShowCursor) + s.cursorHidden = false + } + + // Write the buffer + err = s.flush() + if err != nil { + return + } + + s.reset() + return +} + +// reset resets the screen to its initial state. +func (s *Screen) reset() { + s.scrollHeight = 0 + s.cursorHidden = false + s.altScreenMode = false + s.touch = make(map[int]lineData, s.newbuf.Height()) + if s.curbuf != nil { + s.curbuf.Clear() + } + if s.newbuf != nil { + s.newbuf.Clear() + } + s.buf.Reset() + s.tabs = DefaultTabStops(s.newbuf.Width()) + s.oldhash, s.newhash = nil, nil + + // We always disable HardTabs when termtype is "linux". + if strings.HasPrefix(s.opts.Term, "linux") { + s.opts.HardTabs = false + } +} + +// Resize resizes the screen. +func (s *Screen) Resize(width, height int) bool { + oldw := s.newbuf.Width() + oldh := s.newbuf.Height() + + if s.opts.AltScreen || width != oldw { + // We only clear the whole screen if the width changes. Adding/removing + // rows is handled by the [Screen.render] and [Screen.transformLine] + // methods. + s.clear = true + } + + // Clear new columns and lines + if width > oldh { + s.ClearRect(Rect(max(oldw-1, 0), 0, width-oldw, height)) + } else if width < oldw { + s.ClearRect(Rect(max(width-1, 0), 0, oldw-width, height)) + } + + if height > oldh { + s.ClearRect(Rect(0, max(oldh-1, 0), width, height-oldh)) + } else if height < oldh { + s.ClearRect(Rect(0, max(height-1, 0), width, oldh-height)) + } + + s.mu.Lock() + s.newbuf.Resize(width, height) + s.tabs.Resize(width) + s.oldhash, s.newhash = nil, nil + s.scrollHeight = 0 // reset scroll lines + s.mu.Unlock() + + return true +} + +// MoveTo moves the cursor to the given position. +func (s *Screen) MoveTo(x, y int) { + s.mu.Lock() + s.move(x, y) + s.mu.Unlock() +} + +// InsertAbove inserts string above the screen. The inserted string is not +// managed by the screen. This does nothing when alternate screen mode is +// enabled. +func (s *Screen) InsertAbove(str string) { + if s.opts.AltScreen { + return + } + s.mu.Lock() + for _, line := range strings.Split(str, "\n") { + s.queueAbove = append(s.queueAbove, s.method.Truncate(line, s.Width(), "")) + } + s.mu.Unlock() +} diff --git a/vendor/github.com/charmbracelet/x/cellbuf/sequence.go b/vendor/github.com/charmbracelet/x/cellbuf/sequence.go new file mode 100644 index 000000000..613eefef8 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/cellbuf/sequence.go @@ -0,0 +1,131 @@ +package cellbuf + +import ( + "bytes" + "image/color" + + "github.com/charmbracelet/x/ansi" +) + +// ReadStyle reads a Select Graphic Rendition (SGR) escape sequences from a +// list of parameters. +func ReadStyle(params ansi.Params, pen *Style) { + if len(params) == 0 { + pen.Reset() + return + } + + for i := 0; i < len(params); i++ { + param, hasMore, _ := params.Param(i, 0) + switch param { + case 0: // Reset + pen.Reset() + case 1: // Bold + pen.Bold(true) + case 2: // Dim/Faint + pen.Faint(true) + case 3: // Italic + pen.Italic(true) + case 4: // Underline + nextParam, _, ok := params.Param(i+1, 0) + if hasMore && ok { // Only accept subparameters i.e. separated by ":" + switch nextParam { + case 0, 1, 2, 3, 4, 5: + i++ + switch nextParam { + case 0: // No Underline + pen.UnderlineStyle(NoUnderline) + case 1: // Single Underline + pen.UnderlineStyle(SingleUnderline) + case 2: // Double Underline + pen.UnderlineStyle(DoubleUnderline) + case 3: // Curly Underline + pen.UnderlineStyle(CurlyUnderline) + case 4: // Dotted Underline + pen.UnderlineStyle(DottedUnderline) + case 5: // Dashed Underline + pen.UnderlineStyle(DashedUnderline) + } + } + } else { + // Single Underline + pen.Underline(true) + } + case 5: // Slow Blink + pen.SlowBlink(true) + case 6: // Rapid Blink + pen.RapidBlink(true) + case 7: // Reverse + pen.Reverse(true) + case 8: // Conceal + pen.Conceal(true) + case 9: // Crossed-out/Strikethrough + pen.Strikethrough(true) + case 22: // Normal Intensity (not bold or faint) + pen.Bold(false).Faint(false) + case 23: // Not italic, not Fraktur + pen.Italic(false) + case 24: // Not underlined + pen.Underline(false) + case 25: // Blink off + pen.SlowBlink(false).RapidBlink(false) + case 27: // Positive (not reverse) + pen.Reverse(false) + case 28: // Reveal + pen.Conceal(false) + case 29: // Not crossed out + pen.Strikethrough(false) + case 30, 31, 32, 33, 34, 35, 36, 37: // Set foreground + pen.Foreground(ansi.Black + ansi.BasicColor(param-30)) //nolint:gosec + case 38: // Set foreground 256 or truecolor + var c color.Color + n := ReadStyleColor(params[i:], &c) + if n > 0 { + pen.Foreground(c) + i += n - 1 + } + case 39: // Default foreground + pen.Foreground(nil) + case 40, 41, 42, 43, 44, 45, 46, 47: // Set background + pen.Background(ansi.Black + ansi.BasicColor(param-40)) //nolint:gosec + case 48: // Set background 256 or truecolor + var c color.Color + n := ReadStyleColor(params[i:], &c) + if n > 0 { + pen.Background(c) + i += n - 1 + } + case 49: // Default Background + pen.Background(nil) + case 58: // Set underline color + var c color.Color + n := ReadStyleColor(params[i:], &c) + if n > 0 { + pen.UnderlineColor(c) + i += n - 1 + } + case 59: // Default underline color + pen.UnderlineColor(nil) + case 90, 91, 92, 93, 94, 95, 96, 97: // Set bright foreground + pen.Foreground(ansi.BrightBlack + ansi.BasicColor(param-90)) //nolint:gosec + case 100, 101, 102, 103, 104, 105, 106, 107: // Set bright background + pen.Background(ansi.BrightBlack + ansi.BasicColor(param-100)) //nolint:gosec + } + } +} + +// ReadLink reads a hyperlink escape sequence from a data buffer. +func ReadLink(p []byte, link *Link) { + params := bytes.Split(p, []byte{';'}) + if len(params) != 3 { + return + } + link.Params = string(params[1]) + link.URL = string(params[2]) +} + +// ReadStyleColor reads a color from a list of parameters. +// See [ansi.ReadStyleColor] for more information. +func ReadStyleColor(params ansi.Params, c *color.Color) int { + return ansi.ReadStyleColor(params, c) +} diff --git a/vendor/github.com/charmbracelet/x/cellbuf/style.go b/vendor/github.com/charmbracelet/x/cellbuf/style.go new file mode 100644 index 000000000..82c4afb73 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/cellbuf/style.go @@ -0,0 +1,31 @@ +package cellbuf + +import ( + "github.com/charmbracelet/colorprofile" +) + +// Convert converts a style to respect the given color profile. +func ConvertStyle(s Style, p colorprofile.Profile) Style { + switch p { + case colorprofile.TrueColor: + return s + case colorprofile.Ascii: + s.Fg = nil + s.Bg = nil + s.Ul = nil + case colorprofile.NoTTY: + return Style{} + } + + if s.Fg != nil { + s.Fg = p.Convert(s.Fg) + } + if s.Bg != nil { + s.Bg = p.Convert(s.Bg) + } + if s.Ul != nil { + s.Ul = p.Convert(s.Ul) + } + + return s +} diff --git a/vendor/github.com/charmbracelet/x/cellbuf/tabstop.go b/vendor/github.com/charmbracelet/x/cellbuf/tabstop.go new file mode 100644 index 000000000..24eec449a --- /dev/null +++ b/vendor/github.com/charmbracelet/x/cellbuf/tabstop.go @@ -0,0 +1,137 @@ +package cellbuf + +// DefaultTabInterval is the default tab interval. +const DefaultTabInterval = 8 + +// TabStops represents horizontal line tab stops. +type TabStops struct { + stops []int + interval int + width int +} + +// NewTabStops creates a new set of tab stops from a number of columns and an +// interval. +func NewTabStops(width, interval int) *TabStops { + ts := new(TabStops) + ts.interval = interval + ts.width = width + ts.stops = make([]int, (width+(interval-1))/interval) + ts.init(0, width) + return ts +} + +// DefaultTabStops creates a new set of tab stops with the default interval. +func DefaultTabStops(cols int) *TabStops { + return NewTabStops(cols, DefaultTabInterval) +} + +// Resize resizes the tab stops to the given width. +func (ts *TabStops) Resize(width int) { + if width == ts.width { + return + } + + if width < ts.width { + size := (width + (ts.interval - 1)) / ts.interval + ts.stops = ts.stops[:size] + } else { + size := (width - ts.width + (ts.interval - 1)) / ts.interval + ts.stops = append(ts.stops, make([]int, size)...) + } + + ts.init(ts.width, width) + ts.width = width +} + +// IsStop returns true if the given column is a tab stop. +func (ts TabStops) IsStop(col int) bool { + mask := ts.mask(col) + i := col >> 3 + if i < 0 || i >= len(ts.stops) { + return false + } + return ts.stops[i]&mask != 0 +} + +// Next returns the next tab stop after the given column. +func (ts TabStops) Next(col int) int { + return ts.Find(col, 1) +} + +// Prev returns the previous tab stop before the given column. +func (ts TabStops) Prev(col int) int { + return ts.Find(col, -1) +} + +// Find returns the prev/next tab stop before/after the given column and delta. +// If delta is positive, it returns the next tab stop after the given column. +// If delta is negative, it returns the previous tab stop before the given column. +// If delta is zero, it returns the given column. +func (ts TabStops) Find(col, delta int) int { + if delta == 0 { + return col + } + + var prev bool + count := delta + if count < 0 { + count = -count + prev = true + } + + for count > 0 { + if !prev { + if col >= ts.width-1 { + return col + } + + col++ + } else { + if col < 1 { + return col + } + + col-- + } + + if ts.IsStop(col) { + count-- + } + } + + return col +} + +// Set adds a tab stop at the given column. +func (ts *TabStops) Set(col int) { + mask := ts.mask(col) + ts.stops[col>>3] |= mask +} + +// Reset removes the tab stop at the given column. +func (ts *TabStops) Reset(col int) { + mask := ts.mask(col) + ts.stops[col>>3] &= ^mask +} + +// Clear removes all tab stops. +func (ts *TabStops) Clear() { + ts.stops = make([]int, len(ts.stops)) +} + +// mask returns the mask for the given column. +func (ts *TabStops) mask(col int) int { + return 1 << (col & (ts.interval - 1)) +} + +// init initializes the tab stops starting from col until width. +func (ts *TabStops) init(col, width int) { + for x := col; x < width; x++ { + if x%ts.interval == 0 { + ts.Set(x) + } else { + ts.Reset(x) + } + } +} diff --git a/vendor/github.com/charmbracelet/x/cellbuf/utils.go b/vendor/github.com/charmbracelet/x/cellbuf/utils.go new file mode 100644 index 000000000..b0452fa9a --- /dev/null +++ b/vendor/github.com/charmbracelet/x/cellbuf/utils.go @@ -0,0 +1,38 @@ +package cellbuf + +import ( + "strings" +) + +// Height returns the height of a string. +func Height(s string) int { + return strings.Count(s, "\n") + 1 +} + +func min(a, b int) int { //nolint:predeclared + if a > b { + return b + } + return a +} + +func max(a, b int) int { //nolint:predeclared + if a > b { + return a + } + return b +} + +func clamp(v, low, high int) int { + if high < low { + low, high = high, low + } + return min(high, max(low, v)) +} + +func abs(a int) int { + if a < 0 { + return -a + } + return a +} diff --git a/vendor/github.com/charmbracelet/x/cellbuf/wrap.go b/vendor/github.com/charmbracelet/x/cellbuf/wrap.go new file mode 100644 index 000000000..f89f52f60 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/cellbuf/wrap.go @@ -0,0 +1,185 @@ +package cellbuf + +import ( + "bytes" + "unicode" + "unicode/utf8" + + "github.com/charmbracelet/x/ansi" +) + +const nbsp = '\u00a0' + +// Wrap returns a string that is wrapped to the specified limit applying any +// ANSI escape sequences in the string. It tries to wrap the string at word +// boundaries, but will break words if necessary. +// +// The breakpoints string is a list of characters that are considered +// breakpoints for word wrapping. A hyphen (-) is always considered a +// breakpoint. +// +// Note: breakpoints must be a string of 1-cell wide rune characters. +func Wrap(s string, limit int, breakpoints string) string { + if len(s) == 0 { + return "" + } + + if limit < 1 { + return s + } + + p := ansi.GetParser() + defer ansi.PutParser(p) + + var ( + buf bytes.Buffer + word bytes.Buffer + space bytes.Buffer + style, curStyle Style + link, curLink Link + curWidth int + wordLen int + ) + + hasBlankStyle := func() bool { + // Only follow reverse attribute, bg color and underline style + return !style.Attrs.Contains(ReverseAttr) && style.Bg == nil && style.UlStyle == NoUnderline + } + + addSpace := func() { + curWidth += space.Len() + buf.Write(space.Bytes()) + space.Reset() + } + + addWord := func() { + if word.Len() == 0 { + return + } + + curLink = link + curStyle = style + + addSpace() + curWidth += wordLen + buf.Write(word.Bytes()) + word.Reset() + wordLen = 0 + } + + addNewline := func() { + if !curStyle.Empty() { + buf.WriteString(ansi.ResetStyle) + } + if !curLink.Empty() { + buf.WriteString(ansi.ResetHyperlink()) + } + buf.WriteByte('\n') + if !curLink.Empty() { + buf.WriteString(ansi.SetHyperlink(curLink.URL, curLink.Params)) + } + if !curStyle.Empty() { + buf.WriteString(curStyle.Sequence()) + } + curWidth = 0 + space.Reset() + } + + var state byte + for len(s) > 0 { + seq, width, n, newState := ansi.DecodeSequence(s, state, p) + switch width { + case 0: + if ansi.Equal(seq, "\t") { + addWord() + space.WriteString(seq) + break + } else if ansi.Equal(seq, "\n") { + if wordLen == 0 { + if curWidth+space.Len() > limit { + curWidth = 0 + } else { + // preserve whitespaces + buf.Write(space.Bytes()) + } + space.Reset() + } + + addWord() + addNewline() + break + } else if ansi.HasCsiPrefix(seq) && p.Command() == 'm' { + // SGR style sequence [ansi.SGR] + ReadStyle(p.Params(), &style) + } else if ansi.HasOscPrefix(seq) && p.Command() == 8 { + // Hyperlink sequence [ansi.SetHyperlink] + ReadLink(p.Data(), &link) + } + + word.WriteString(seq) + default: + if len(seq) == 1 { + // ASCII + r, _ := utf8.DecodeRuneInString(seq) + if r != nbsp && unicode.IsSpace(r) && hasBlankStyle() { + addWord() + space.WriteRune(r) + break + } else if r == '-' || runeContainsAny(r, breakpoints) { + addSpace() + if curWidth+wordLen+width <= limit { + addWord() + buf.WriteString(seq) + curWidth += width + break + } + } + } + + if wordLen+width > limit { + // Hardwrap the word if it's too long + addWord() + } + + word.WriteString(seq) + wordLen += width + + if curWidth+wordLen+space.Len() > limit { + addNewline() + } + } + + s = s[n:] + state = newState + } + + if wordLen == 0 { + if curWidth+space.Len() > limit { + curWidth = 0 + } else { + // preserve whitespaces + buf.Write(space.Bytes()) + } + space.Reset() + } + + addWord() + + if !curLink.Empty() { + buf.WriteString(ansi.ResetHyperlink()) + } + if !curStyle.Empty() { + buf.WriteString(ansi.ResetStyle) + } + + return buf.String() +} + +func runeContainsAny[T string | []rune](r rune, s T) bool { + for _, c := range []rune(s) { + if c == r { + return true + } + } + return false +} diff --git a/vendor/github.com/charmbracelet/x/cellbuf/writer.go b/vendor/github.com/charmbracelet/x/cellbuf/writer.go new file mode 100644 index 000000000..ae8b2a810 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/cellbuf/writer.go @@ -0,0 +1,339 @@ +package cellbuf + +import ( + "bytes" + "fmt" + "strings" + + "github.com/charmbracelet/x/ansi" +) + +// CellBuffer is a cell buffer that represents a set of cells in a screen or a +// grid. +type CellBuffer interface { + // Cell returns the cell at the given position. + Cell(x, y int) *Cell + // SetCell sets the cell at the given position to the given cell. It + // returns whether the cell was set successfully. + SetCell(x, y int, c *Cell) bool + // Bounds returns the bounds of the cell buffer. + Bounds() Rectangle +} + +// FillRect fills the rectangle within the cell buffer with the given cell. +// This will not fill cells outside the bounds of the cell buffer. +func FillRect(s CellBuffer, c *Cell, rect Rectangle) { + for y := rect.Min.Y; y < rect.Max.Y; y++ { + for x := rect.Min.X; x < rect.Max.X; x++ { + s.SetCell(x, y, c) //nolint:errcheck + } + } +} + +// Fill fills the cell buffer with the given cell. +func Fill(s CellBuffer, c *Cell) { + FillRect(s, c, s.Bounds()) +} + +// ClearRect clears the rectangle within the cell buffer with blank cells. +func ClearRect(s CellBuffer, rect Rectangle) { + FillRect(s, nil, rect) +} + +// Clear clears the cell buffer with blank cells. +func Clear(s CellBuffer) { + Fill(s, nil) +} + +// SetContentRect clears the rectangle within the cell buffer with blank cells, +// and sets the given string as its content. If the height or width of the +// string exceeds the height or width of the cell buffer, it will be truncated. +func SetContentRect(s CellBuffer, str string, rect Rectangle) { + // Replace all "\n" with "\r\n" to ensure the cursor is reset to the start + // of the line. Make sure we don't replace "\r\n" with "\r\r\n". + str = strings.ReplaceAll(str, "\r\n", "\n") + str = strings.ReplaceAll(str, "\n", "\r\n") + ClearRect(s, rect) + printString(s, ansi.GraphemeWidth, rect.Min.X, rect.Min.Y, rect, str, true, "") +} + +// SetContent clears the cell buffer with blank cells, and sets the given string +// as its content. If the height or width of the string exceeds the height or +// width of the cell buffer, it will be truncated. +func SetContent(s CellBuffer, str string) { + SetContentRect(s, str, s.Bounds()) +} + +// Render returns a string representation of the grid with ANSI escape sequences. +func Render(d CellBuffer) string { + var buf bytes.Buffer + height := d.Bounds().Dy() + for y := 0; y < height; y++ { + _, line := RenderLine(d, y) + buf.WriteString(line) + if y < height-1 { + buf.WriteString("\r\n") + } + } + return buf.String() +} + +// RenderLine returns a string representation of the yth line of the grid along +// with the width of the line. +func RenderLine(d CellBuffer, n int) (w int, line string) { + var pen Style + var link Link + var buf bytes.Buffer + var pendingLine string + var pendingWidth int // this ignores space cells until we hit a non-space cell + + writePending := func() { + // If there's no pending line, we don't need to do anything. + if len(pendingLine) == 0 { + return + } + buf.WriteString(pendingLine) + w += pendingWidth + pendingWidth = 0 + pendingLine = "" + } + + for x := 0; x < d.Bounds().Dx(); x++ { + if cell := d.Cell(x, n); cell != nil && cell.Width > 0 { + // Convert the cell's style and link to the given color profile. + cellStyle := cell.Style + cellLink := cell.Link + if cellStyle.Empty() && !pen.Empty() { + writePending() + buf.WriteString(ansi.ResetStyle) //nolint:errcheck + pen.Reset() + } + if !cellStyle.Equal(&pen) { + writePending() + seq := cellStyle.DiffSequence(pen) + buf.WriteString(seq) // nolint:errcheck + pen = cellStyle + } + + // Write the URL escape sequence + if cellLink != link && link.URL != "" { + writePending() + buf.WriteString(ansi.ResetHyperlink()) //nolint:errcheck + link.Reset() + } + if cellLink != link { + writePending() + buf.WriteString(ansi.SetHyperlink(cellLink.URL, cellLink.Params)) //nolint:errcheck + link = cellLink + } + + // We only write the cell content if it's not empty. If it is, we + // append it to the pending line and width to be evaluated later. + if cell.Equal(&BlankCell) { + pendingLine += cell.String() + pendingWidth += cell.Width + } else { + writePending() + buf.WriteString(cell.String()) + w += cell.Width + } + } + } + if link.URL != "" { + buf.WriteString(ansi.ResetHyperlink()) //nolint:errcheck + } + if !pen.Empty() { + buf.WriteString(ansi.ResetStyle) //nolint:errcheck + } + return w, strings.TrimRight(buf.String(), " ") // Trim trailing spaces +} + +// ScreenWriter represents a writer that writes to a [Screen] parsing ANSI +// escape sequences and Unicode characters and converting them into cells that +// can be written to a cell [Buffer]. +type ScreenWriter struct { + *Screen +} + +// NewScreenWriter creates a new ScreenWriter that writes to the given Screen. +// This is a convenience function for creating a ScreenWriter. +func NewScreenWriter(s *Screen) *ScreenWriter { + return &ScreenWriter{s} +} + +// Write writes the given bytes to the screen. +// This will recognize ANSI [ansi.SGR] style and [ansi.SetHyperlink] escape +// sequences. +func (s *ScreenWriter) Write(p []byte) (n int, err error) { + printString(s.Screen, s.method, + s.cur.X, s.cur.Y, s.Bounds(), + p, false, "") + return len(p), nil +} + +// SetContent clears the screen with blank cells, and sets the given string as +// its content. If the height or width of the string exceeds the height or +// width of the screen, it will be truncated. +// +// This will recognize ANSI [ansi.SGR] style and [ansi.SetHyperlink] escape sequences. +func (s *ScreenWriter) SetContent(str string) { + s.SetContentRect(str, s.Bounds()) +} + +// SetContentRect clears the rectangle within the screen with blank cells, and +// sets the given string as its content. If the height or width of the string +// exceeds the height or width of the screen, it will be truncated. +// +// This will recognize ANSI [ansi.SGR] style and [ansi.SetHyperlink] escape +// sequences. +func (s *ScreenWriter) SetContentRect(str string, rect Rectangle) { + // Replace all "\n" with "\r\n" to ensure the cursor is reset to the start + // of the line. Make sure we don't replace "\r\n" with "\r\r\n". + str = strings.ReplaceAll(str, "\r\n", "\n") + str = strings.ReplaceAll(str, "\n", "\r\n") + s.ClearRect(rect) + printString(s.Screen, s.method, + rect.Min.X, rect.Min.Y, rect, + str, true, "") +} + +// Print prints the string at the current cursor position. It will wrap the +// string to the width of the screen if it exceeds the width of the screen. +// This will recognize ANSI [ansi.SGR] style and [ansi.SetHyperlink] escape +// sequences. +func (s *ScreenWriter) Print(str string, v ...interface{}) { + if len(v) > 0 { + str = fmt.Sprintf(str, v...) + } + printString(s.Screen, s.method, + s.cur.X, s.cur.Y, s.Bounds(), + str, false, "") +} + +// PrintAt prints the string at the given position. It will wrap the string to +// the width of the screen if it exceeds the width of the screen. +// This will recognize ANSI [ansi.SGR] style and [ansi.SetHyperlink] escape +// sequences. +func (s *ScreenWriter) PrintAt(x, y int, str string, v ...interface{}) { + if len(v) > 0 { + str = fmt.Sprintf(str, v...) + } + printString(s.Screen, s.method, + x, y, s.Bounds(), + str, false, "") +} + +// PrintCrop prints the string at the current cursor position and truncates the +// text if it exceeds the width of the screen. Use tail to specify a string to +// append if the string is truncated. +// This will recognize ANSI [ansi.SGR] style and [ansi.SetHyperlink] escape +// sequences. +func (s *ScreenWriter) PrintCrop(str string, tail string) { + printString(s.Screen, s.method, + s.cur.X, s.cur.Y, s.Bounds(), + str, true, tail) +} + +// PrintCropAt prints the string at the given position and truncates the text +// if it exceeds the width of the screen. Use tail to specify a string to append +// if the string is truncated. +// This will recognize ANSI [ansi.SGR] style and [ansi.SetHyperlink] escape +// sequences. +func (s *ScreenWriter) PrintCropAt(x, y int, str string, tail string) { + printString(s.Screen, s.method, + x, y, s.Bounds(), + str, true, tail) +} + +// printString draws a string starting at the given position. +func printString[T []byte | string]( + s CellBuffer, + m ansi.Method, + x, y int, + bounds Rectangle, str T, + truncate bool, tail string, +) { + p := ansi.GetParser() + defer ansi.PutParser(p) + + var tailc Cell + if truncate && len(tail) > 0 { + if m == ansi.WcWidth { + tailc = *NewCellString(tail) + } else { + tailc = *NewGraphemeCell(tail) + } + } + + decoder := ansi.DecodeSequenceWc[T] + if m == ansi.GraphemeWidth { + decoder = ansi.DecodeSequence[T] + } + + var cell Cell + var style Style + var link Link + var state byte + for len(str) > 0 { + seq, width, n, newState := decoder(str, state, p) + + switch width { + case 1, 2, 3, 4: // wide cells can go up to 4 cells wide + cell.Width += width + cell.Append([]rune(string(seq))...) + + if !truncate && x+cell.Width > bounds.Max.X && y+1 < bounds.Max.Y { + // Wrap the string to the width of the window + x = bounds.Min.X + y++ + } + if Pos(x, y).In(bounds) { + if truncate && tailc.Width > 0 && x+cell.Width > bounds.Max.X-tailc.Width { + // Truncate the string and append the tail if any. + cell := tailc + cell.Style = style + cell.Link = link + s.SetCell(x, y, &cell) + x += tailc.Width + } else { + // Print the cell to the screen + cell.Style = style + cell.Link = link + s.SetCell(x, y, &cell) //nolint:errcheck + x += width + } + } + + // String is too long for the line, truncate it. + // Make sure we reset the cell for the next iteration. + cell.Reset() + default: + // Valid sequences always have a non-zero Cmd. + // TODO: Handle cursor movement and other sequences + switch { + case ansi.HasCsiPrefix(seq) && p.Command() == 'm': + // SGR - Select Graphic Rendition + ReadStyle(p.Params(), &style) + case ansi.HasOscPrefix(seq) && p.Command() == 8: + // Hyperlinks + ReadLink(p.Data(), &link) + case ansi.Equal(seq, T("\n")): + y++ + case ansi.Equal(seq, T("\r")): + x = bounds.Min.X + default: + cell.Append([]rune(string(seq))...) + } + } + + // Advance the state and data + state = newState + str = str[n:] + } + + // Make sure to set the last cell if it's not empty. + if !cell.Empty() { + s.SetCell(x, y, &cell) //nolint:errcheck + cell.Reset() + } +} diff --git a/vendor/github.com/charmbracelet/x/term/LICENSE b/vendor/github.com/charmbracelet/x/term/LICENSE new file mode 100644 index 000000000..65a5654e2 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/term/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Charmbracelet, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/charmbracelet/x/term/term.go b/vendor/github.com/charmbracelet/x/term/term.go new file mode 100644 index 000000000..58d6522ca --- /dev/null +++ b/vendor/github.com/charmbracelet/x/term/term.go @@ -0,0 +1,49 @@ +package term + +// State contains platform-specific state of a terminal. +type State struct { + state +} + +// IsTerminal returns whether the given file descriptor is a terminal. +func IsTerminal(fd uintptr) bool { + return isTerminal(fd) +} + +// MakeRaw puts the terminal connected to the given file descriptor into raw +// mode and returns the previous state of the terminal so that it can be +// restored. +func MakeRaw(fd uintptr) (*State, error) { + return makeRaw(fd) +} + +// GetState returns the current state of a terminal which may be useful to +// restore the terminal after a signal. +func GetState(fd uintptr) (*State, error) { + return getState(fd) +} + +// SetState sets the given state of the terminal. +func SetState(fd uintptr, state *State) error { + return setState(fd, state) +} + +// Restore restores the terminal connected to the given file descriptor to a +// previous state. +func Restore(fd uintptr, oldState *State) error { + return restore(fd, oldState) +} + +// GetSize returns the visible dimensions of the given terminal. +// +// These dimensions don't include any scrollback buffer height. +func GetSize(fd uintptr) (width, height int, err error) { + return getSize(fd) +} + +// ReadPassword reads a line of input from a terminal without local echo. This +// is commonly used for inputting passwords and other sensitive data. The slice +// returned does not include the \n. +func ReadPassword(fd uintptr) ([]byte, error) { + return readPassword(fd) +} diff --git a/vendor/github.com/charmbracelet/x/term/term_other.go b/vendor/github.com/charmbracelet/x/term/term_other.go new file mode 100644 index 000000000..092c7e9d9 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/term/term_other.go @@ -0,0 +1,39 @@ +//go:build !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !zos && !windows && !solaris && !plan9 +// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!zos,!windows,!solaris,!plan9 + +package term + +import ( + "fmt" + "runtime" +) + +type state struct{} + +func isTerminal(fd uintptr) bool { + return false +} + +func makeRaw(fd uintptr) (*State, error) { + return nil, fmt.Errorf("terminal: MakeRaw not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} + +func getState(fd uintptr) (*State, error) { + return nil, fmt.Errorf("terminal: GetState not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} + +func restore(fd uintptr, state *State) error { + return fmt.Errorf("terminal: Restore not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} + +func getSize(fd uintptr) (width, height int, err error) { + return 0, 0, fmt.Errorf("terminal: GetSize not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} + +func setState(fd uintptr, state *State) error { + return fmt.Errorf("terminal: SetState not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} + +func readPassword(fd uintptr) ([]byte, error) { + return nil, fmt.Errorf("terminal: ReadPassword not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} diff --git a/vendor/github.com/charmbracelet/x/term/term_unix.go b/vendor/github.com/charmbracelet/x/term/term_unix.go new file mode 100644 index 000000000..1459cb1be --- /dev/null +++ b/vendor/github.com/charmbracelet/x/term/term_unix.go @@ -0,0 +1,96 @@ +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos +// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos + +package term + +import ( + "golang.org/x/sys/unix" +) + +type state struct { + unix.Termios +} + +func isTerminal(fd uintptr) bool { + _, err := unix.IoctlGetTermios(int(fd), ioctlReadTermios) + return err == nil +} + +func makeRaw(fd uintptr) (*State, error) { + termios, err := unix.IoctlGetTermios(int(fd), ioctlReadTermios) + if err != nil { + return nil, err + } + + oldState := State{state{Termios: *termios}} + + // This attempts to replicate the behaviour documented for cfmakeraw in + // the termios(3) manpage. + termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON + termios.Oflag &^= unix.OPOST + termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN + termios.Cflag &^= unix.CSIZE | unix.PARENB + termios.Cflag |= unix.CS8 + termios.Cc[unix.VMIN] = 1 + termios.Cc[unix.VTIME] = 0 + if err := unix.IoctlSetTermios(int(fd), ioctlWriteTermios, termios); err != nil { + return nil, err + } + + return &oldState, nil +} + +func setState(fd uintptr, state *State) error { + var termios *unix.Termios + if state != nil { + termios = &state.Termios + } + return unix.IoctlSetTermios(int(fd), ioctlWriteTermios, termios) +} + +func getState(fd uintptr) (*State, error) { + termios, err := unix.IoctlGetTermios(int(fd), ioctlReadTermios) + if err != nil { + return nil, err + } + + return &State{state{Termios: *termios}}, nil +} + +func restore(fd uintptr, state *State) error { + return unix.IoctlSetTermios(int(fd), ioctlWriteTermios, &state.Termios) +} + +func getSize(fd uintptr) (width, height int, err error) { + ws, err := unix.IoctlGetWinsize(int(fd), unix.TIOCGWINSZ) + if err != nil { + return 0, 0, err + } + return int(ws.Col), int(ws.Row), nil +} + +// passwordReader is an io.Reader that reads from a specific file descriptor. +type passwordReader int + +func (r passwordReader) Read(buf []byte) (int, error) { + return unix.Read(int(r), buf) +} + +func readPassword(fd uintptr) ([]byte, error) { + termios, err := unix.IoctlGetTermios(int(fd), ioctlReadTermios) + if err != nil { + return nil, err + } + + newState := *termios + newState.Lflag &^= unix.ECHO + newState.Lflag |= unix.ICANON | unix.ISIG + newState.Iflag |= unix.ICRNL + if err := unix.IoctlSetTermios(int(fd), ioctlWriteTermios, &newState); err != nil { + return nil, err + } + + defer unix.IoctlSetTermios(int(fd), ioctlWriteTermios, termios) + + return readPasswordLine(passwordReader(fd)) +} diff --git a/vendor/github.com/charmbracelet/x/term/term_unix_bsd.go b/vendor/github.com/charmbracelet/x/term/term_unix_bsd.go new file mode 100644 index 000000000..b435031aa --- /dev/null +++ b/vendor/github.com/charmbracelet/x/term/term_unix_bsd.go @@ -0,0 +1,11 @@ +//go:build darwin || dragonfly || freebsd || netbsd || openbsd +// +build darwin dragonfly freebsd netbsd openbsd + +package term + +import "golang.org/x/sys/unix" + +const ( + ioctlReadTermios = unix.TIOCGETA + ioctlWriteTermios = unix.TIOCSETA +) diff --git a/vendor/github.com/charmbracelet/x/term/term_unix_other.go b/vendor/github.com/charmbracelet/x/term/term_unix_other.go new file mode 100644 index 000000000..ee2a29eb1 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/term/term_unix_other.go @@ -0,0 +1,11 @@ +//go:build aix || linux || solaris || zos +// +build aix linux solaris zos + +package term + +import "golang.org/x/sys/unix" + +const ( + ioctlReadTermios = unix.TCGETS + ioctlWriteTermios = unix.TCSETS +) diff --git a/vendor/github.com/charmbracelet/x/term/term_windows.go b/vendor/github.com/charmbracelet/x/term/term_windows.go new file mode 100644 index 000000000..fe7afdec9 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/term/term_windows.go @@ -0,0 +1,87 @@ +//go:build windows +// +build windows + +package term + +import ( + "os" + + "golang.org/x/sys/windows" +) + +type state struct { + Mode uint32 +} + +func isTerminal(fd uintptr) bool { + var st uint32 + err := windows.GetConsoleMode(windows.Handle(fd), &st) + return err == nil +} + +func makeRaw(fd uintptr) (*State, error) { + var st uint32 + if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil { + return nil, err + } + raw := st &^ (windows.ENABLE_ECHO_INPUT | windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT | windows.ENABLE_PROCESSED_OUTPUT) + raw |= windows.ENABLE_VIRTUAL_TERMINAL_INPUT + if err := windows.SetConsoleMode(windows.Handle(fd), raw); err != nil { + return nil, err + } + return &State{state{st}}, nil +} + +func setState(fd uintptr, state *State) error { + var mode uint32 + if state != nil { + mode = state.Mode + } + return windows.SetConsoleMode(windows.Handle(fd), mode) +} + +func getState(fd uintptr) (*State, error) { + var st uint32 + if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil { + return nil, err + } + return &State{state{st}}, nil +} + +func restore(fd uintptr, state *State) error { + return windows.SetConsoleMode(windows.Handle(fd), state.Mode) +} + +func getSize(fd uintptr) (width, height int, err error) { + var info windows.ConsoleScreenBufferInfo + if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil { + return 0, 0, err + } + return int(info.Window.Right - info.Window.Left + 1), int(info.Window.Bottom - info.Window.Top + 1), nil +} + +func readPassword(fd uintptr) ([]byte, error) { + var st uint32 + if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil { + return nil, err + } + old := st + + st &^= (windows.ENABLE_ECHO_INPUT | windows.ENABLE_LINE_INPUT) + st |= (windows.ENABLE_PROCESSED_OUTPUT | windows.ENABLE_PROCESSED_INPUT) + if err := windows.SetConsoleMode(windows.Handle(fd), st); err != nil { + return nil, err + } + + defer windows.SetConsoleMode(windows.Handle(fd), old) + + var h windows.Handle + p, _ := windows.GetCurrentProcess() + if err := windows.DuplicateHandle(p, windows.Handle(fd), p, &h, 0, false, windows.DUPLICATE_SAME_ACCESS); err != nil { + return nil, err + } + + f := os.NewFile(uintptr(h), "stdin") + defer f.Close() + return readPasswordLine(f) +} diff --git a/vendor/github.com/charmbracelet/x/term/terminal.go b/vendor/github.com/charmbracelet/x/term/terminal.go new file mode 100644 index 000000000..8963163f8 --- /dev/null +++ b/vendor/github.com/charmbracelet/x/term/terminal.go @@ -0,0 +1,12 @@ +package term + +import ( + "io" +) + +// File represents a file that has a file descriptor and can be read from, +// written to, and closed. +type File interface { + io.ReadWriteCloser + Fd() uintptr +} diff --git a/vendor/github.com/charmbracelet/x/term/util.go b/vendor/github.com/charmbracelet/x/term/util.go new file mode 100644 index 000000000..b7313418f --- /dev/null +++ b/vendor/github.com/charmbracelet/x/term/util.go @@ -0,0 +1,47 @@ +package term + +import ( + "io" + "runtime" +) + +// readPasswordLine reads from reader until it finds \n or io.EOF. +// The slice returned does not include the \n. +// readPasswordLine also ignores any \r it finds. +// Windows uses \r as end of line. So, on Windows, readPasswordLine +// reads until it finds \r and ignores any \n it finds during processing. +func readPasswordLine(reader io.Reader) ([]byte, error) { + var buf [1]byte + var ret []byte + + for { + n, err := reader.Read(buf[:]) + if n > 0 { + switch buf[0] { + case '\b': + if len(ret) > 0 { + ret = ret[:len(ret)-1] + } + case '\n': + if runtime.GOOS != "windows" { + return ret, nil + } + // otherwise ignore \n + case '\r': + if runtime.GOOS == "windows" { + return ret, nil + } + // otherwise ignore \r + default: + ret = append(ret, buf[0]) + } + continue + } + if err != nil { + if err == io.EOF && len(ret) > 0 { + return ret, nil + } + return ret, err + } + } +} diff --git a/vendor/github.com/ckaznocha/intrange/.golangci.yml b/vendor/github.com/ckaznocha/intrange/.golangci.yml index 2ad830d1b..74a80105c 100644 --- a/vendor/github.com/ckaznocha/intrange/.golangci.yml +++ b/vendor/github.com/ckaznocha/intrange/.golangci.yml @@ -1,6 +1,9 @@ linters-settings: gci: - local-prefixes: github.com/ckaznocha/intrange + sections: + - standard + - default + - localmodule gocritic: enabled-tags: - diagnostic @@ -10,11 +13,9 @@ linters-settings: - style goimports: local-prefixes: github.com/ckaznocha/intrange - golint: - min-confidence: 0 govet: - check-shadowing: true enable: + - appends - asmdecl - assign - atomic @@ -22,9 +23,11 @@ linters-settings: - bools - buildtag - cgocall - - composite - - copylock + - composites + - copylocks - deepequalerrors + - defers + - directive - errorsas - fieldalignment - findcall @@ -36,18 +39,25 @@ linters-settings: - nilfunc - nilness - printf + - reflectvaluecompare - shadow - shift + - sigchanyzer + - slog - sortslice - stdmethods + - stdversion - stringintconv - structtag - testinggoroutine - tests + - timeformat - unmarshal - unreachable - unsafeptr - unusedresult + - unusedwrite + - waitgroup misspell: locale: US linters: @@ -57,18 +67,16 @@ linters: - dupl - errcheck - errorlint - - exportloopref - gci - gochecknoinits - goconst - gocritic - godot - godox - - goerr113 + - err113 - gofmt - gofumpt - goimports - - gomnd - goprintffuncname - gosec - gosimple @@ -94,6 +102,6 @@ linters: - wastedassign - whitespace - wsl -run: - skip-dirs: +issues: + exclude-dirs: - testdata/ diff --git a/vendor/github.com/ckaznocha/intrange/go.work b/vendor/github.com/ckaznocha/intrange/go.work index 3814c99f9..b7e127dcb 100644 --- a/vendor/github.com/ckaznocha/intrange/go.work +++ b/vendor/github.com/ckaznocha/intrange/go.work @@ -1,4 +1,6 @@ -go 1.22 +go 1.23.0 + +toolchain go1.23.4 use ( . diff --git a/vendor/github.com/ckaznocha/intrange/intrange.go b/vendor/github.com/ckaznocha/intrange/intrange.go index 44a15091e..79aca7973 100644 --- a/vendor/github.com/ckaznocha/intrange/intrange.go +++ b/vendor/github.com/ckaznocha/intrange/intrange.go @@ -79,6 +79,8 @@ func checkForStmt(pass *analysis.Pass, forStmt *ast.ForStmt) { return } + initAssign := init.Tok == token.ASSIGN + if len(init.Lhs) != 1 || len(init.Rhs) != 1 { return } @@ -97,16 +99,13 @@ func checkForStmt(pass *analysis.Pass, forStmt *ast.ForStmt) { return } - var nExpr ast.Expr + var ( + operand ast.Expr + hasEquivalentOperator bool + ) switch cond.Op { - case token.LSS: // ;i < n; - if isBenchmark(cond.Y) { - return - } - - nExpr = findNExpr(cond.Y) - + case token.LSS, token.LEQ: // ;i < n; || ;i <= n; x, ok := cond.X.(*ast.Ident) if !ok { return @@ -115,13 +114,10 @@ func checkForStmt(pass *analysis.Pass, forStmt *ast.ForStmt) { if x.Name != initIdent.Name { return } - case token.GTR: // ;n > i; - if isBenchmark(cond.X) { - return - } - - nExpr = findNExpr(cond.X) + hasEquivalentOperator = cond.Op == token.LEQ + operand = cond.Y + case token.GTR, token.GEQ: // ;n > i; || ;n >= i; y, ok := cond.Y.(*ast.Ident) if !ok { return @@ -130,6 +126,9 @@ func checkForStmt(pass *analysis.Pass, forStmt *ast.ForStmt) { if y.Name != initIdent.Name { return } + + hasEquivalentOperator = cond.Op == token.GEQ + operand = cond.X default: return } @@ -228,7 +227,7 @@ func checkForStmt(pass *analysis.Pass, forStmt *ast.ForStmt) { bc := &bodyChecker{ initIdent: initIdent, - nExpr: nExpr, + nExpr: findNExpr(operand), } ast.Inspect(forStmt.Body, bc.check) @@ -237,9 +236,59 @@ func checkForStmt(pass *analysis.Pass, forStmt *ast.ForStmt) { return } + if initAssign { + pass.Report(analysis.Diagnostic{ + Pos: forStmt.Pos(), + Message: msg + "\nBecause the key is not part of the loop's scope, take care to consider side effects.", + }) + + return + } + + operandIsNumberLit := isNumberLit(operand) + + if hasEquivalentOperator && !operandIsNumberLit { + return + } + + rangeX := operandToString( + pass, + initIdent, + operand, + hasEquivalentOperator && operandIsNumberLit, + ) + + var replacement string + if bc.accessed { + replacement = fmt.Sprintf("%s := range %s", initIdent.Name, rangeX) + } else { + replacement = fmt.Sprintf("range %s", rangeX) + } + + if isFunctionOrMethodCall(operand) { + pass.Report(analysis.Diagnostic{ + Pos: forStmt.Pos(), + Message: msg + "\nBecause the key is returned by a function or method, take care to consider side effects.", + }) + + return + } + pass.Report(analysis.Diagnostic{ Pos: forStmt.Pos(), Message: msg, + SuggestedFixes: []analysis.SuggestedFix{ + { + Message: fmt.Sprintf("Replace loop with `%s`", replacement), + TextEdits: []analysis.TextEdit{ + { + Pos: forStmt.Init.Pos(), + End: forStmt.Post.End(), + NewText: []byte(replacement), + }, + }, + }, + }, }) } @@ -275,12 +324,11 @@ func checkRangeStmt(pass *analysis.Pass, rangeStmt *ast.RangeStmt) { return } - fn, ok := x.Fun.(*ast.Ident) - if !ok { + if _, ok = x.Fun.(*ast.Ident); !ok { return } - if fn.Name != "len" || len(x.Args) != 1 { + if !isLen(x) { return } @@ -345,7 +393,7 @@ func checkRangeStmt(pass *analysis.Pass, rangeStmt *ast.RangeStmt) { func findNExpr(expr ast.Expr) ast.Expr { switch e := expr.(type) { case *ast.CallExpr: - if fun, ok := e.Fun.(*ast.Ident); ok && fun.Name == "len" && len(e.Args) == 1 { + if isLen(e) { return findNExpr(e.Args[0]) } @@ -363,26 +411,47 @@ func findNExpr(expr ast.Expr) ast.Expr { } } -func isBenchmark(expr ast.Expr) bool { - selectorExpr, ok := expr.(*ast.SelectorExpr) - if !ok { - return false - } +func recursiveOperandToString( + expr ast.Expr, + incrementInt bool, +) string { + switch e := expr.(type) { + case *ast.CallExpr: + args := "" - if selectorExpr.Sel.Name != "N" { - return false - } + for i, v := range e.Args { + if i > 0 { + args += ", " + } - ident, ok := selectorExpr.X.(*ast.Ident) - if !ok { - return false - } + args += recursiveOperandToString(v, incrementInt && len(e.Args) == 1) + } - if ident.Name == "b" { - return true - } + return recursiveOperandToString(e.Fun, false) + "(" + args + ")" + case *ast.BasicLit: + if incrementInt && e.Kind == token.INT { + v, err := strconv.Atoi(e.Value) + if err == nil { + return strconv.Itoa(v + 1) + } + + return e.Value + } - return false + return e.Value + case *ast.Ident: + return e.Name + case *ast.SelectorExpr: + return recursiveOperandToString(e.X, false) + "." + recursiveOperandToString(e.Sel, false) + case *ast.IndexExpr: + return recursiveOperandToString(e.X, false) + "[" + recursiveOperandToString(e.Index, false) + "]" + case *ast.BinaryExpr: + return recursiveOperandToString(e.X, false) + " " + e.Op.String() + " " + recursiveOperandToString(e.Y, false) + case *ast.StarExpr: + return "*" + recursiveOperandToString(e.X, false) + default: + return "" + } } func identEqual(a, b ast.Expr) bool { @@ -428,6 +497,7 @@ type bodyChecker struct { initIdent *ast.Ident nExpr ast.Expr modified bool + accessed bool } func (b *bodyChecker) check(n ast.Node) bool { @@ -446,11 +516,43 @@ func (b *bodyChecker) check(n ast.Node) bool { return false } + case *ast.Ident: + if identEqual(stmt, b.initIdent) { + b.accessed = true + } } return true } +func isNumberLit(exp ast.Expr) bool { + switch lit := exp.(type) { + case *ast.BasicLit: + if lit.Kind == token.INT { + return true + } + + return false + case *ast.CallExpr: + switch fun := lit.Fun.(type) { + case *ast.Ident: + if !isIntCast(fun) { + return false + } + default: + return false + } + + if len(lit.Args) != 1 { + return false + } + + return isNumberLit(lit.Args[0]) + default: + return false + } +} + func compareNumberLit(exp ast.Expr, val int) bool { switch lit := exp.(type) { case *ast.BasicLit: @@ -469,19 +571,7 @@ func compareNumberLit(exp ast.Expr, val int) bool { case *ast.CallExpr: switch fun := lit.Fun.(type) { case *ast.Ident: - switch fun.Name { - case - "int", - "int8", - "int16", - "int32", - "int64", - "uint", - "uint8", - "uint16", - "uint32", - "uint64": - default: + if !isIntCast(fun) { return false } default: @@ -497,3 +587,80 @@ func compareNumberLit(exp ast.Expr, val int) bool { return false } } + +func operandToString( + pass *analysis.Pass, + i *ast.Ident, + operand ast.Expr, + increment bool, +) string { + s := recursiveOperandToString(operand, increment) + t := pass.TypesInfo.TypeOf(i) + + if t == types.Typ[types.Int] { + if len(s) > 5 && s[:4] == "int(" && s[len(s)-1] == ')' { + s = s[4 : len(s)-1] + } + + return s + } + + if len(s) > 2 && s[len(s)-1] == ')' { + return s + } + + if operandIdent, ok := operand.(*ast.Ident); ok { + if operandType := pass.TypesInfo.TypeOf(operandIdent); operandType != nil && + operandType == t { + return s + } + } + + return t.String() + "(" + s + ")" +} + +func isFunctionOrMethodCall(expr ast.Expr) bool { + e, ok := expr.(*ast.CallExpr) + if !ok { + return false + } + + fun, ok := e.Fun.(*ast.Ident) + if !ok { + return true + } + + if isLen(e) || isIntCast(fun) { + return false + } + + return true +} + +func isIntCast(ident *ast.Ident) bool { + switch ident.Name { + case + "int", + "int8", + "int16", + "int32", + "int64", + "uint", + "uint8", + "uint16", + "uint32", + "uint64": + return true + default: + return false + } +} + +func isLen(exp *ast.CallExpr) bool { + fun, ok := exp.Fun.(*ast.Ident) + if !ok { + return false + } + + return fun.Name == "len" && len(exp.Args) == 1 +} diff --git a/vendor/github.com/curioswitch/go-reassign/.golangci.yml b/vendor/github.com/curioswitch/go-reassign/.golangci.yml index e3bf79ae7..fdf0bb2f2 100644 --- a/vendor/github.com/curioswitch/go-reassign/.golangci.yml +++ b/vendor/github.com/curioswitch/go-reassign/.golangci.yml @@ -5,14 +5,12 @@ linters: - bodyclose - decorder - durationcheck + - err113 - errchkjson - errname - errorlint - - execinquery - exhaustive - - exportloopref - gocritic - - goerr113 - gofmt - goimports - goprintffuncname @@ -20,7 +18,6 @@ linters: - importas - misspell - nolintlint - - nosnakecase - prealloc - predeclared - promlinter diff --git a/vendor/github.com/curioswitch/go-reassign/README.md b/vendor/github.com/curioswitch/go-reassign/README.md index ac9c131df..190756f92 100644 --- a/vendor/github.com/curioswitch/go-reassign/README.md +++ b/vendor/github.com/curioswitch/go-reassign/README.md @@ -47,7 +47,8 @@ Package variable reassignment is generally confusing, though, and we recommend a The `pattern` flag can be set to a regular expression to define what variables cannot be reassigned, and `.*` is recommended if it works with your code. -## Limitations +## Development -If a variable shadows the name of an import, an assignment of a field in the variable will trigger the linter. Shadowing -can be confusing, so it's recommended to rename the variable. +[mage](https://magefile.org/) is used for development. Run `go run mage.go -l` to see available targets. + +For example, to run checks before sending a PR, run `go run mage.go check`. diff --git a/vendor/github.com/curioswitch/go-reassign/internal/analyzer/analyzer.go b/vendor/github.com/curioswitch/go-reassign/internal/analyzer/analyzer.go index e1b47d5b9..c2a29c529 100644 --- a/vendor/github.com/curioswitch/go-reassign/internal/analyzer/analyzer.go +++ b/vendor/github.com/curioswitch/go-reassign/internal/analyzer/analyzer.go @@ -48,23 +48,35 @@ func run(pass *analysis.Pass) (interface{}, error) { func reportImported(pass *analysis.Pass, expr ast.Expr, checkRE *regexp.Regexp, prefix string) { switch x := expr.(type) { case *ast.SelectorExpr: - if !checkRE.MatchString(x.Sel.Name) { - return - } - selectIdent, ok := x.X.(*ast.Ident) if !ok { return } + var pkgPath string if selectObj, ok := pass.TypesInfo.Uses[selectIdent]; ok { - if pkg, ok := selectObj.(*types.PkgName); !ok || pkg.Imported() == pass.Pkg { + pkg, ok := selectObj.(*types.PkgName) + if !ok || pkg.Imported() == pass.Pkg { return } + pkgPath = pkg.Imported().Path() } - pass.Reportf(expr.Pos(), "%s variable %s in other package %s", prefix, x.Sel.Name, selectIdent.Name) + matches := false + if checkRE.MatchString(x.Sel.Name) { + matches = true + } + if !matches { + // Expression may include a package name, so check that too. Support was added later so we check + // just name and qualified name separately for compatibility. + if checkRE.MatchString(pkgPath + "." + x.Sel.Name) { + matches = true + } + } + if matches { + pass.Reportf(expr.Pos(), "%s variable %s in other package %s", prefix, x.Sel.Name, selectIdent.Name) + } case *ast.Ident: use, ok := pass.TypesInfo.Uses[x].(*types.Var) if !ok { diff --git a/vendor/github.com/daixiang0/gci/pkg/config/config.go b/vendor/github.com/daixiang0/gci/pkg/config/config.go index 814201a00..643a313f0 100644 --- a/vendor/github.com/daixiang0/gci/pkg/config/config.go +++ b/vendor/github.com/daixiang0/gci/pkg/config/config.go @@ -2,7 +2,6 @@ package config import ( "sort" - "strings" "gopkg.in/yaml.v3" @@ -64,11 +63,11 @@ func (g YamlConfig) Parse() (*Config, error) { sort.Slice(sections, func(i, j int) bool { sectionI, sectionJ := sections[i].Type(), sections[j].Type() - if g.Cfg.NoLexOrder || strings.Compare(sectionI, sectionJ) != 0 { + if g.Cfg.NoLexOrder || sectionI != sectionJ { return defaultOrder[sectionI] < defaultOrder[sectionJ] } - return strings.Compare(sections[i].String(), sections[j].String()) < 0 + return sections[i].String() < sections[j].String() }) } diff --git a/vendor/github.com/daixiang0/gci/pkg/section/standard_list.go b/vendor/github.com/daixiang0/gci/pkg/section/standard_list.go index 5a2dcdc89..34cf38cec 100644 --- a/vendor/github.com/daixiang0/gci/pkg/section/standard_list.go +++ b/vendor/github.com/daixiang0/gci/pkg/section/standard_list.go @@ -1,175 +1,185 @@ package section -// Code generated based on go1.23.0 X:boringcrypto,arenas. DO NOT EDIT. +// Code generated based on go1.25rc1 X:boringcrypto,arenas,synctest,jsonv2. DO NOT EDIT. var standardPackages = map[string]struct{}{ - "archive/tar": {}, - "archive/zip": {}, - "arena": {}, - "bufio": {}, - "bytes": {}, - "cmp": {}, - "compress/bzip2": {}, - "compress/flate": {}, - "compress/gzip": {}, - "compress/lzw": {}, - "compress/zlib": {}, - "container/heap": {}, - "container/list": {}, - "container/ring": {}, - "context": {}, - "crypto": {}, - "crypto/aes": {}, - "crypto/boring": {}, - "crypto/cipher": {}, - "crypto/des": {}, - "crypto/dsa": {}, - "crypto/ecdh": {}, - "crypto/ecdsa": {}, - "crypto/ed25519": {}, - "crypto/elliptic": {}, - "crypto/hmac": {}, - "crypto/md5": {}, - "crypto/rand": {}, - "crypto/rc4": {}, - "crypto/rsa": {}, - "crypto/sha1": {}, - "crypto/sha256": {}, - "crypto/sha512": {}, - "crypto/subtle": {}, - "crypto/tls": {}, - "crypto/tls/fipsonly": {}, - "crypto/x509": {}, - "crypto/x509/pkix": {}, - "database/sql": {}, - "database/sql/driver": {}, - "debug/buildinfo": {}, - "debug/dwarf": {}, - "debug/elf": {}, - "debug/gosym": {}, - "debug/macho": {}, - "debug/pe": {}, - "debug/plan9obj": {}, - "embed": {}, - "encoding": {}, - "encoding/ascii85": {}, - "encoding/asn1": {}, - "encoding/base32": {}, - "encoding/base64": {}, - "encoding/binary": {}, - "encoding/csv": {}, - "encoding/gob": {}, - "encoding/hex": {}, - "encoding/json": {}, - "encoding/pem": {}, - "encoding/xml": {}, - "errors": {}, - "expvar": {}, - "flag": {}, - "fmt": {}, - "go/ast": {}, - "go/build": {}, - "go/build/constraint": {}, - "go/constant": {}, - "go/doc": {}, - "go/doc/comment": {}, - "go/format": {}, - "go/importer": {}, - "go/parser": {}, - "go/printer": {}, - "go/scanner": {}, - "go/token": {}, - "go/types": {}, - "go/version": {}, - "hash": {}, - "hash/adler32": {}, - "hash/crc32": {}, - "hash/crc64": {}, - "hash/fnv": {}, - "hash/maphash": {}, - "html": {}, - "html/template": {}, - "image": {}, - "image/color": {}, - "image/color/palette": {}, - "image/draw": {}, - "image/gif": {}, - "image/jpeg": {}, - "image/png": {}, - "index/suffixarray": {}, - "io": {}, - "io/fs": {}, - "io/ioutil": {}, - "iter": {}, - "log": {}, - "log/slog": {}, - "log/syslog": {}, - "maps": {}, - "math": {}, - "math/big": {}, - "math/bits": {}, - "math/cmplx": {}, - "math/rand": {}, - "math/rand/v2": {}, - "mime": {}, - "mime/multipart": {}, - "mime/quotedprintable": {}, - "net": {}, - "net/http": {}, - "net/http/cgi": {}, - "net/http/cookiejar": {}, - "net/http/fcgi": {}, - "net/http/httptest": {}, - "net/http/httptrace": {}, - "net/http/httputil": {}, - "net/http/pprof": {}, - "net/mail": {}, - "net/netip": {}, - "net/rpc": {}, - "net/rpc/jsonrpc": {}, - "net/smtp": {}, - "net/textproto": {}, - "net/url": {}, - "os": {}, - "os/exec": {}, - "os/signal": {}, - "os/user": {}, - "path": {}, - "path/filepath": {}, - "plugin": {}, - "reflect": {}, - "regexp": {}, - "regexp/syntax": {}, - "runtime": {}, - "runtime/cgo": {}, - "runtime/coverage": {}, - "runtime/debug": {}, - "runtime/metrics": {}, - "runtime/pprof": {}, - "runtime/race": {}, - "runtime/trace": {}, - "slices": {}, - "sort": {}, - "strconv": {}, - "strings": {}, - "structs": {}, - "sync": {}, - "sync/atomic": {}, - "syscall": {}, - "testing": {}, - "testing/fstest": {}, - "testing/iotest": {}, - "testing/quick": {}, - "testing/slogtest": {}, - "text/scanner": {}, - "text/tabwriter": {}, - "text/template": {}, - "text/template/parse": {}, - "time": {}, - "time/tzdata": {}, - "unicode": {}, - "unicode/utf16": {}, - "unicode/utf8": {}, - "unique": {}, - "unsafe": {}, + "archive/tar": {}, + "archive/zip": {}, + "arena": {}, + "bufio": {}, + "bytes": {}, + "cmp": {}, + "compress/bzip2": {}, + "compress/flate": {}, + "compress/gzip": {}, + "compress/lzw": {}, + "compress/zlib": {}, + "container/heap": {}, + "container/list": {}, + "container/ring": {}, + "context": {}, + "crypto": {}, + "crypto/aes": {}, + "crypto/boring": {}, + "crypto/cipher": {}, + "crypto/des": {}, + "crypto/dsa": {}, + "crypto/ecdh": {}, + "crypto/ecdsa": {}, + "crypto/ed25519": {}, + "crypto/elliptic": {}, + "crypto/fips140": {}, + "crypto/hkdf": {}, + "crypto/hmac": {}, + "crypto/md5": {}, + "crypto/mlkem": {}, + "crypto/pbkdf2": {}, + "crypto/rand": {}, + "crypto/rc4": {}, + "crypto/rsa": {}, + "crypto/sha1": {}, + "crypto/sha256": {}, + "crypto/sha3": {}, + "crypto/sha512": {}, + "crypto/subtle": {}, + "crypto/tls": {}, + "crypto/tls/fipsonly": {}, + "crypto/x509": {}, + "crypto/x509/pkix": {}, + "database/sql": {}, + "database/sql/driver": {}, + "debug/buildinfo": {}, + "debug/dwarf": {}, + "debug/elf": {}, + "debug/gosym": {}, + "debug/macho": {}, + "debug/pe": {}, + "debug/plan9obj": {}, + "embed": {}, + "encoding": {}, + "encoding/ascii85": {}, + "encoding/asn1": {}, + "encoding/base32": {}, + "encoding/base64": {}, + "encoding/binary": {}, + "encoding/csv": {}, + "encoding/gob": {}, + "encoding/hex": {}, + "encoding/json": {}, + "encoding/json/jsontext": {}, + "encoding/json/v2": {}, + "encoding/pem": {}, + "encoding/xml": {}, + "errors": {}, + "expvar": {}, + "flag": {}, + "fmt": {}, + "go/ast": {}, + "go/build": {}, + "go/build/constraint": {}, + "go/constant": {}, + "go/doc": {}, + "go/doc/comment": {}, + "go/format": {}, + "go/importer": {}, + "go/parser": {}, + "go/printer": {}, + "go/scanner": {}, + "go/token": {}, + "go/types": {}, + "go/version": {}, + "hash": {}, + "hash/adler32": {}, + "hash/crc32": {}, + "hash/crc64": {}, + "hash/fnv": {}, + "hash/maphash": {}, + "html": {}, + "html/template": {}, + "image": {}, + "image/color": {}, + "image/color/palette": {}, + "image/draw": {}, + "image/gif": {}, + "image/jpeg": {}, + "image/png": {}, + "index/suffixarray": {}, + "io": {}, + "io/fs": {}, + "io/ioutil": {}, + "iter": {}, + "log": {}, + "log/slog": {}, + "log/syslog": {}, + "maps": {}, + "math": {}, + "math/big": {}, + "math/bits": {}, + "math/cmplx": {}, + "math/rand": {}, + "math/rand/v2": {}, + "mime": {}, + "mime/multipart": {}, + "mime/quotedprintable": {}, + "net": {}, + "net/http": {}, + "net/http/cgi": {}, + "net/http/cookiejar": {}, + "net/http/fcgi": {}, + "net/http/httptest": {}, + "net/http/httptrace": {}, + "net/http/httputil": {}, + "net/http/pprof": {}, + "net/mail": {}, + "net/netip": {}, + "net/rpc": {}, + "net/rpc/jsonrpc": {}, + "net/smtp": {}, + "net/textproto": {}, + "net/url": {}, + "os": {}, + "os/exec": {}, + "os/signal": {}, + "os/user": {}, + "path": {}, + "path/filepath": {}, + "plugin": {}, + "reflect": {}, + "regexp": {}, + "regexp/syntax": {}, + "runtime": {}, + "runtime/cgo": {}, + "runtime/coverage": {}, + "runtime/debug": {}, + "runtime/metrics": {}, + "runtime/pprof": {}, + "runtime/race": {}, + "runtime/trace": {}, + "slices": {}, + "sort": {}, + "strconv": {}, + "strings": {}, + "structs": {}, + "sync": {}, + "sync/atomic": {}, + "syscall": {}, + "syscall/js": {}, + "testing": {}, + "testing/fstest": {}, + "testing/iotest": {}, + "testing/quick": {}, + "testing/slogtest": {}, + "testing/synctest": {}, + "text/scanner": {}, + "text/tabwriter": {}, + "text/template": {}, + "text/template/parse": {}, + "time": {}, + "time/tzdata": {}, + "unicode": {}, + "unicode/utf16": {}, + "unicode/utf8": {}, + "unique": {}, + "unsafe": {}, + "weak": {}, } diff --git a/vendor/github.com/dave/dst/.gitignore b/vendor/github.com/dave/dst/.gitignore new file mode 100644 index 000000000..5a391e10f --- /dev/null +++ b/vendor/github.com/dave/dst/.gitignore @@ -0,0 +1,4 @@ +*.iml +.DS_Store +.idea/ +coverage.out diff --git a/vendor/github.com/dave/dst/.travis.yml b/vendor/github.com/dave/dst/.travis.yml new file mode 100644 index 000000000..f2af05327 --- /dev/null +++ b/vendor/github.com/dave/dst/.travis.yml @@ -0,0 +1,15 @@ +language: go +go: + - 1.x +notificaitons: + email: + recipients: dave@brophy.uk + on_failure: always +install: +# - go get -u github.com/dave/courtney + - go get -t -v ./... +script: + - go test ./... +# - courtney -v -timeout 20m +#after_success: +# - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/github.com/dave/dst/LICENSE b/vendor/github.com/dave/dst/LICENSE new file mode 100644 index 000000000..95bfa5bed --- /dev/null +++ b/vendor/github.com/dave/dst/LICENSE @@ -0,0 +1,51 @@ +MIT License + +Copyright (c) 2018 David Brophy + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +This package was forked from https://github.com/golang/go/tree/master/src/go/ast - original license: + +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/vendor/github.com/dave/dst/README.md b/vendor/github.com/dave/dst/README.md new file mode 100644 index 000000000..337781b86 --- /dev/null +++ b/vendor/github.com/dave/dst/README.md @@ -0,0 +1,706 @@ +[![Build Status](https://travis-ci.org/dave/dst.svg?branch=master)](https://travis-ci.org/dave/dst) +[![Documentation](https://img.shields.io/badge/godoc-documentation-brightgreen.svg)](https://godoc.org/github.com/dave/dst/decorator) +[![codecov](https://img.shields.io/badge/codecov-92%25-brightgreen.svg)](https://codecov.io/gh/dave/dst) +![stability-stable](https://img.shields.io/badge/stability-stable-brightgreen.svg) +[![Sourcegraph](https://sourcegraph.com/github.com/dave/dst/-/badge.svg)](https://sourcegraph.com/github.com/dave/dst?badge) + +# Decorated Syntax Tree + +The `dst` package enables manipulation of a Go syntax tree with high fidelity. Decorations (e.g. +comments and line spacing) remain attached to the correct nodes as the tree is modified. + +## Where does `go/ast` break? + +The `go/ast` package wasn't created with source manipulation as an intended use-case. Comments are +stored by their byte offset instead of attached to nodes, so re-arranging nodes breaks the output. +See [this Go issue](https://github.com/golang/go/issues/20744) for more information. + +Consider this example where we want to reverse the order of the two statements. As you can see the +comments don't remain attached to the correct nodes: + +```go +code := `package a + +func main(){ + var a int // foo + var b string // bar +} +` +fset := token.NewFileSet() +f, err := parser.ParseFile(fset, "", code, parser.ParseComments) +if err != nil { + panic(err) +} + +list := f.Decls[0].(*ast.FuncDecl).Body.List +list[0], list[1] = list[1], list[0] + +if err := format.Node(os.Stdout, fset, f); err != nil { + panic(err) +} + +//Output: +//package a +// +//func main() { +// // foo +// var b string +// var a int +// // bar +//} +``` + +Here's the same example using `dst`: + +```go +code := `package a + +func main(){ + var a int // foo + var b string // bar +} +` +f, err := decorator.Parse(code) +if err != nil { + panic(err) +} + +list := f.Decls[0].(*dst.FuncDecl).Body.List +list[0], list[1] = list[1], list[0] + +if err := decorator.Print(f); err != nil { + panic(err) +} + +//Output: +//package a +// +//func main() { +// var b string // bar +// var a int // foo +//} +``` + +## Usage + +Parsing a source file to `dst` and printing the results after modification can be accomplished with +several `Parse` and `Print` convenience functions in the [decorator](https://godoc.org/github.com/dave/dst/decorator) +package. + +For more fine-grained control you can use [Decorator](https://godoc.org/github.com/dave/dst/decorator#Decorator) +to convert from `ast` to `dst`, and [Restorer](https://godoc.org/github.com/dave/dst/decorator#Restorer) +to convert back again. + +### Comments + +Comments are added at decoration attachment points. [See here](https://github.com/dave/dst/blob/master/decorations-types-generated.go) +for a full list of these points, along with demonstration code of where they are rendered in the +output. + +The decoration attachment points have convenience functions `Append`, `Prepend`, `Replace`, `Clear` +and `All` to accomplish common tasks. Use the full text of your comment including the `//` or `/**/` +markers. When adding a line comment, a newline is automatically rendered. + +```go +code := `package main + +func main() { + println("Hello World!") +}` +f, err := decorator.Parse(code) +if err != nil { + panic(err) +} + +call := f.Decls[0].(*dst.FuncDecl).Body.List[0].(*dst.ExprStmt).X.(*dst.CallExpr) + +call.Decs.Start.Append("// you can add comments at the start...") +call.Decs.Fun.Append("/* ...in the middle... */") +call.Decs.End.Append("// or at the end.") + +if err := decorator.Print(f); err != nil { + panic(err) +} + +//Output: +//package main +// +//func main() { +// // you can add comments at the start... +// println /* ...in the middle... */ ("Hello World!") // or at the end. +//} +``` + +### Spacing + +The `Before` property marks the node as having a line space (new line or empty line) before the node. +These spaces are rendered before any decorations attached to the `Start` decoration point. The `After` +property is similar but rendered after the node (and after any `End` decorations). + +```go +code := `package main + +func main() { + println(a, b, c) +}` +f, err := decorator.Parse(code) +if err != nil { + panic(err) +} + +call := f.Decls[0].(*dst.FuncDecl).Body.List[0].(*dst.ExprStmt).X.(*dst.CallExpr) + +call.Decs.Before = dst.EmptyLine +call.Decs.After = dst.EmptyLine + +for _, v := range call.Args { + v := v.(*dst.Ident) + v.Decs.Before = dst.NewLine + v.Decs.After = dst.NewLine +} + +if err := decorator.Print(f); err != nil { + panic(err) +} + +//Output: +//package main +// +//func main() { +// +// println( +// a, +// b, +// c, +// ) +// +//} +``` + +### Decorations + +The common decoration properties (`Start`, `End`, `Before` and `After`) occur on all nodes, and can be +accessed with the `Decorations()` method on the `Node` interface: + +```go +code := `package main + +func main() { + var i int + i++ + println(i) +}` +f, err := decorator.Parse(code) +if err != nil { + panic(err) +} + +list := f.Decls[0].(*dst.FuncDecl).Body.List + +list[0].Decorations().Before = dst.EmptyLine +list[0].Decorations().End.Append("// the Decorations method allows access to the common") +list[1].Decorations().End.Append("// decoration properties (Before, Start, End and After)") +list[2].Decorations().End.Append("// for all nodes.") +list[2].Decorations().After = dst.EmptyLine + +if err := decorator.Print(f); err != nil { + panic(err) +} + +//Output: +//package main +// +//func main() { +// +// var i int // the Decorations method allows access to the common +// i++ // decoration properties (Before, Start, End and After) +// println(i) // for all nodes. +// +//} +``` + +#### dstutil.Decorations + +While debugging, it is often useful to have a list of all decorations attached to a node. The +[dstutil](https://github.com/dave/dst/tree/master/dstutil) package provides a helper function `Decorations` which +returns a list of the attachment points and all decorations for any node: + +```go +code := `package main + +// main comment +// is multi line +func main() { + + if true { + + // foo + println( /* foo inline */ "foo") + } else if false { + println /* bar inline */ ("bar") + + // bar after + + } else { + // empty block + } +}` + +f, err := decorator.Parse(code) +if err != nil { + panic(err) +} + +dst.Inspect(f, func(node dst.Node) bool { + if node == nil { + return false + } + before, after, points := dstutil.Decorations(node) + var info string + if before != dst.None { + info += fmt.Sprintf("- Before: %s\n", before) + } + for _, point := range points { + if len(point.Decs) == 0 { + continue + } + info += fmt.Sprintf("- %s: [", point.Name) + for i, dec := range point.Decs { + if i > 0 { + info += ", " + } + info += fmt.Sprintf("%q", dec) + } + info += "]\n" + } + if after != dst.None { + info += fmt.Sprintf("- After: %s\n", after) + } + if info != "" { + fmt.Printf("%T\n%s\n", node, info) + } + return true +}) + +//Output: +//*dst.FuncDecl +//- Before: NewLine +//- Start: ["// main comment", "// is multi line"] +// +//*dst.IfStmt +//- Before: NewLine +//- After: NewLine +// +//*dst.ExprStmt +//- Before: NewLine +//- Start: ["// foo"] +//- After: NewLine +// +//*dst.CallExpr +//- Lparen: ["/* foo inline */"] +// +//*dst.ExprStmt +//- Before: NewLine +//- End: ["\n", "\n", "// bar after"] +//- After: NewLine +// +//*dst.CallExpr +//- Fun: ["/* bar inline */"] +// +//*dst.BlockStmt +//- Lbrace: ["\n", "// empty block"] +``` + +### Newlines + +The `Before` and `After` properties cover the majority of cases, but occasionally a newline needs to +be rendered inside a node. Simply add a `\n` decoration to accomplish this. + +### Clone + +Re-using an existing node elsewhere in the tree will panic when the tree is restored to `ast`. Instead, +use the `Clone` function to make a deep copy of the node before re-use: + +```go +code := `package main + +var i /* a */ int` + +f, err := decorator.Parse(code) +if err != nil { + panic(err) +} + +cloned := dst.Clone(f.Decls[0]).(*dst.GenDecl) + +cloned.Decs.Before = dst.NewLine +cloned.Specs[0].(*dst.ValueSpec).Names[0].Name = "j" +cloned.Specs[0].(*dst.ValueSpec).Names[0].Decs.End.Replace("/* b */") + +f.Decls = append(f.Decls, cloned) + +if err := decorator.Print(f); err != nil { + panic(err) +} + +//Output: +//package main +// +//var i /* a */ int +//var j /* b */ int +``` + +### Apply + +The [dstutil](https://github.com/dave/dst/tree/master/dstutil) package is a fork of `golang.org/x/tools/go/ast/astutil`, +and provides the `Apply` function with similar semantics. + +### Imports + +The decorator can automatically manage the `import` block, which is a non-trivial task. + +Use [NewDecoratorWithImports](https://godoc.org/github.com/dave/dst/decorator#NewDecoratorWithImports) +and [NewRestorerWithImports](https://godoc.org/github.com/dave/dst/decorator#NewRestorerWithImports) +to create an import aware decorator / restorer. + +During decoration, remote identifiers are normalised - `*ast.SelectorExpr` nodes that represent +qualified identifiers are replaced with `*dst.Ident` nodes with the `Path` field set to the path of +the imported package. + +When adding a qualified identifier node, there is no need to use `*dst.SelectorExpr` - just add a +`*dst.Ident` and set `Path` to the imported package path. The restorer will wrap it in a +`*ast.SelectorExpr` where appropriate when converting back to ast, and also update the import +block. + +To enable import management, the decorator must be able to resolve the imported package for +selector expressions and identifiers, and the restorer must be able to resolve the name of a +package given it's path. Several implementations for these resolvers are provided, and the best +method will depend on the environment. [See below](#resolvers) for more details. + +### Load + +The [Load](https://godoc.org/github.com/dave/dst/decorator#Load) convenience function uses +`go/packages` to load packages and decorate all loaded ast files, with import management enabled: + +```go +// Create a simple module in a temporary directory +dir, err := tempDir(map[string]string{ + "go.mod": "module root", + "main.go": "package main \n\n func main() {}", +}) +defer os.RemoveAll(dir) +if err != nil { + panic(err) +} + +// Use the Load convenience function that calls go/packages to load the package. All loaded +// ast files are decorated to dst. +pkgs, err := decorator.Load(&packages.Config{Dir: dir, Mode: packages.LoadSyntax}, "root") +if err != nil { + panic(err) +} +p := pkgs[0] +f := p.Syntax[0] + +// Add a call expression. Note we don't have to use a SelectorExpr - just adding an Ident with +// the imported package path will do. The restorer will add SelectorExpr where appropriate when +// converting back to ast. Note the new Path field on *dst.Ident. Set this to the package path +// of the imported package, and the restorer will automatically add the import to the import +// block. +b := f.Decls[0].(*dst.FuncDecl).Body +b.List = append(b.List, &dst.ExprStmt{ + X: &dst.CallExpr{ + Fun: &dst.Ident{Path: "fmt", Name: "Println"}, + Args: []dst.Expr{ + &dst.BasicLit{Kind: token.STRING, Value: strconv.Quote("Hello, World!")}, + }, + }, +}) + +// Create a restorer with the import manager enabled, and print the result. As you can see, the +// import block is automatically managed, and the Println ident is converted to a SelectorExpr: +r := decorator.NewRestorerWithImports("root", gopackages.New(dir)) +if err := r.Print(p.Syntax[0]); err != nil { + panic(err) +} + +//Output: +//package main +// +//import "fmt" +// +//func main() { fmt.Println("Hello, World!") } +``` + +### Mappings + +The decorator exposes `Dst.Nodes` and `Ast.Nodes` which map between `ast.Node` and `dst.Node`. This +enables systems that refer to `ast` nodes (such as `go/types`) to be used: + +```go +code := `package main + +func main() { + var i int + i++ + println(i) +}` + +// Parse the code to AST +fset := token.NewFileSet() +astFile, err := parser.ParseFile(fset, "", code, parser.ParseComments) +if err != nil { + panic(err) +} + +// Invoke the type checker using AST as input +typesInfo := types.Info{ + Defs: make(map[*ast.Ident]types.Object), + Uses: make(map[*ast.Ident]types.Object), +} +conf := &types.Config{} +if _, err := conf.Check("", fset, []*ast.File{astFile}, &typesInfo); err != nil { + panic(err) +} + +// Create a new decorator, which will track the mapping between ast and dst nodes +dec := decorator.NewDecorator(fset) + +// Decorate the *ast.File to give us a *dst.File +f, err := dec.DecorateFile(astFile) +if err != nil { + panic(err) +} + +// Find the *dst.Ident for the definition of "i" +dstDef := f.Decls[0].(*dst.FuncDecl).Body.List[0].(*dst.DeclStmt).Decl.(*dst.GenDecl).Specs[0].(*dst.ValueSpec).Names[0] + +// Find the *ast.Ident using the Ast.Nodes mapping +astDef := dec.Ast.Nodes[dstDef].(*ast.Ident) + +// Find the types.Object corresponding to "i" +obj := typesInfo.Defs[astDef] + +// Find all the uses of that object +var astUses []*ast.Ident +for id, ob := range typesInfo.Uses { + if ob != obj { + continue + } + astUses = append(astUses, id) +} + +// Find each *dst.Ident in the Dst.Nodes mapping +var dstUses []*dst.Ident +for _, id := range astUses { + dstUses = append(dstUses, dec.Dst.Nodes[id].(*dst.Ident)) +} + +// Change the name of the original definition and all uses +dstDef.Name = "foo" +for _, id := range dstUses { + id.Name = "foo" +} + +// Print the DST +if err := decorator.Print(f); err != nil { + panic(err) +} + +//Output: +//package main +// +//func main() { +// var foo int +// foo++ +// println(foo) +//} +``` + +## Resolvers + +There are two separate interfaces defined by the [resolver package](https://github.com/dave/dst/tree/master/decorator/resolver) +which allow the decorator and restorer to automatically manage the imports block. + +The decorator uses a `DecoratorResolver` which resolves the package path of any `*ast.Ident`. This is +complicated by dot-import syntax ([see below](#dot-imports)). + +The restorer uses a `RestorerResolver` which resolves the name of any package given the path. This +is complicated by vendoring and Go modules. + +When `Resolver` is set on `Decorator` or `Restorer`, the `Path` property must be set to the local +package path. + +Several implementations of both interfaces that are suitable for different environments are +provided: + +### DecoratorResolver + +#### gotypes + +The [gotypes](https://github.com/dave/dst/blob/master/decorator/resolver/gotypes/resolver.go) +package provides a `DecoratorResolver` with full dot-import compatibility. However it requires full +export data for all imported packages, so the `Uses` map from `go/types.Info` is required. There +are several methods of generating `go/types.Info`. Using `golang.org/x/tools/go/packages.Load` is +recommended for full Go modules compatibility. See the [decorator.Load](https://godoc.org/github.com/dave/dst/decorator#Load) +convenience function to automate this. + +#### goast + +The [goast](https://github.com/dave/dst/blob/master/decorator/resolver/goast/resolver.go) package +provides a simplified `DecoratorResolver` that only needs to scan a single ast file. This is unable +to resolve identifiers from dot-imported packages, so will panic if a dot-import is encountered in +the import block. It uses the provided `RestorerResolver` to resolve the names of all imported +packages. If no `RestorerResolver` is provided, the [guess](#guess-and-simple) implementation is used. + +### RestorerResolver + +#### gopackages + +The [gopackages](https://github.com/dave/dst/blob/master/decorator/resolver/gopackages/resolver.go) +package provides a `RestorerResolver` with full compatibility with Go modules. It uses +`golang.org/x/tools/go/packages` to load the package data. This may be very slow, and uses the `go` +command line tool to query package data, so may not be compatible with some environments. + +#### gobuild + +The [gobuild](https://github.com/dave/dst/blob/master/decorator/resolver/gobuild/resolver.go) +package provides an alternative `RestorerResolver` that uses the legacy `go/build` system to load +the imported package data. This may be needed in some circumstances and provides better performance +than `go/packages`. However, this is not Go modules aware. + +#### guess and simple + +The [guess](https://github.com/dave/dst/blob/master/decorator/resolver/guess/resolver.go) and +[simple](https://github.com/dave/dst/blob/master/decorator/resolver/simple/resolver.go) packages +provide simple `RestorerResolver` implementations that may be useful in certain circumstances, or +where performance is critical. `simple` resolves paths only if they occur in a provided map. +`guess` guesses the package name based on the last part of the path. + +### Example + +Here's an example of supplying resolvers for the decorator and restorer: + +```go +code := `package main + + import "fmt" + + func main() { + fmt.Println("a") + }` + +dec := decorator.NewDecoratorWithImports(token.NewFileSet(), "main", goast.New()) + +f, err := dec.Parse(code) +if err != nil { + panic(err) +} + +f.Decls[1].(*dst.FuncDecl).Body.List[0].(*dst.ExprStmt).X.(*dst.CallExpr).Args = []dst.Expr{ + &dst.CallExpr{ + Fun: &dst.Ident{Name: "A", Path: "foo.bar/baz"}, + }, +} + +res := decorator.NewRestorerWithImports("main", guess.New()) +if err := res.Print(f); err != nil { + panic(err) +} + +//Output: +//package main +// +//import ( +// "fmt" +// +// "foo.bar/baz" +//) +// +//func main() { +// fmt.Println(baz.A()) +//} +``` + +### Alias + +To control the alias of imports, use a `FileRestorer`: + +```go +code := `package main + + import "fmt" + + func main() { + fmt.Println("a") + }` + +dec := decorator.NewDecoratorWithImports(token.NewFileSet(), "main", goast.New()) + +f, err := dec.Parse(code) +if err != nil { + panic(err) +} + +res := decorator.NewRestorerWithImports("main", guess.New()) + +fr := res.FileRestorer() +fr.Alias["fmt"] = "fmt1" + +if err := fr.Print(f); err != nil { + panic(err) +} + +//Output: +//package main +// +//import fmt1 "fmt" +// +//func main() { +// fmt1.Println("a") +//} +``` + +### Details + +For more information on exactly how the imports block is managed, read through the [test +cases](https://github.com/dave/dst/blob/master/decorator/restorer_resolver_test.go). + +### Dot-imports + +Consider this file... + +```go +package main + +import ( + . "a" +) + +func main() { + B() + C() +} +``` + +`B` and `C` could be local identifiers from a different file in this package, +or from the imported package `a`. If only one is from `a` and it is removed, we should remove the +import when we restore to `ast`. Thus the resolver needs to be able to resolve the package using +the full info from `go/types`. + +## Status + +This package is well tested and used in many projects. The API should be considered stable going forward. + +## Chat? + +Feel free to create an [issue](https://github.com/dave/dst/issues) or chat in the +[#dst](https://gophers.slack.com/messages/CCVL24MTQ) Gophers Slack channel. + +## Contributing + +For further developing or contributing to `dst`, check out [these notes](https://github.com/dave/dst/blob/master/contributing.md). + +## Special thanks + +Thanks very much to [hawkinsw](https://github.com/hawkinsw) for taking on the task of adding generics compatibility to `dst`. \ No newline at end of file diff --git a/vendor/github.com/dave/dst/README.md.tpl b/vendor/github.com/dave/dst/README.md.tpl new file mode 100644 index 000000000..26691f9bb --- /dev/null +++ b/vendor/github.com/dave/dst/README.md.tpl @@ -0,0 +1,239 @@ +[![Build Status](https://travis-ci.org/dave/dst.svg?branch=master)](https://travis-ci.org/dave/dst) +[![Documentation](https://img.shields.io/badge/godoc-documentation-brightgreen.svg)](https://godoc.org/github.com/dave/dst/decorator) +[![codecov](https://img.shields.io/badge/codecov-92%25-brightgreen.svg)](https://codecov.io/gh/dave/dst) +![stability-stable](https://img.shields.io/badge/stability-stable-brightgreen.svg) +[![Sourcegraph](https://sourcegraph.com/github.com/dave/dst/-/badge.svg)](https://sourcegraph.com/github.com/dave/dst?badge) + +# Decorated Syntax Tree + +The `dst` package enables manipulation of a Go syntax tree with high fidelity. Decorations (e.g. +comments and line spacing) remain attached to the correct nodes as the tree is modified. + +## Where does `go/ast` break? + +The `go/ast` package wasn't created with source manipulation as an intended use-case. Comments are +stored by their byte offset instead of attached to nodes, so re-arranging nodes breaks the output. +See [this Go issue](https://github.com/golang/go/issues/20744) for more information. + +Consider this example where we want to reverse the order of the two statements. As you can see the +comments don't remain attached to the correct nodes: + +{{ "ExampleAstBroken" | example }} + +Here's the same example using `dst`: + +{{ "ExampleDstFixed" | example }} + +## Usage + +Parsing a source file to `dst` and printing the results after modification can be accomplished with +several `Parse` and `Print` convenience functions in the [decorator](https://godoc.org/github.com/dave/dst/decorator) +package. + +For more fine-grained control you can use [Decorator](https://godoc.org/github.com/dave/dst/decorator#Decorator) +to convert from `ast` to `dst`, and [Restorer](https://godoc.org/github.com/dave/dst/decorator#Restorer) +to convert back again. + +### Comments + +Comments are added at decoration attachment points. [See here](https://github.com/dave/dst/blob/master/decorations-types-generated.go) +for a full list of these points, along with demonstration code of where they are rendered in the +output. + +The decoration attachment points have convenience functions `Append`, `Prepend`, `Replace`, `Clear` +and `All` to accomplish common tasks. Use the full text of your comment including the `//` or `/**/` +markers. When adding a line comment, a newline is automatically rendered. + +{{ "ExampleComment" | example }} + +### Spacing + +The `Before` property marks the node as having a line space (new line or empty line) before the node. +These spaces are rendered before any decorations attached to the `Start` decoration point. The `After` +property is similar but rendered after the node (and after any `End` decorations). + +{{ "ExampleSpace" | example }} + +### Decorations + +The common decoration properties (`Start`, `End`, `Before` and `After`) occur on all nodes, and can be +accessed with the `Decorations()` method on the `Node` interface: + +{{ "ExampleDecorated" | example }} + +#### dstutil.Decorations + +While debugging, it is often useful to have a list of all decorations attached to a node. The +[dstutil](https://github.com/dave/dst/tree/master/dstutil) package provides a helper function `Decorations` which +returns a list of the attachment points and all decorations for any node: + +{{ "ExampleDecorationPoints" | example }} + +### Newlines + +The `Before` and `After` properties cover the majority of cases, but occasionally a newline needs to +be rendered inside a node. Simply add a `\n` decoration to accomplish this. + +### Clone + +Re-using an existing node elsewhere in the tree will panic when the tree is restored to `ast`. Instead, +use the `Clone` function to make a deep copy of the node before re-use: + +{{ "ExampleClone" | example }} + +### Apply + +The [dstutil](https://github.com/dave/dst/tree/master/dstutil) package is a fork of `golang.org/x/tools/go/ast/astutil`, +and provides the `Apply` function with similar semantics. + +### Imports + +The decorator can automatically manage the `import` block, which is a non-trivial task. + +Use [NewDecoratorWithImports](https://godoc.org/github.com/dave/dst/decorator#NewDecoratorWithImports) +and [NewRestorerWithImports](https://godoc.org/github.com/dave/dst/decorator#NewRestorerWithImports) +to create an import aware decorator / restorer. + +During decoration, remote identifiers are normalised - `*ast.SelectorExpr` nodes that represent +qualified identifiers are replaced with `*dst.Ident` nodes with the `Path` field set to the path of +the imported package. + +When adding a qualified identifier node, there is no need to use `*dst.SelectorExpr` - just add a +`*dst.Ident` and set `Path` to the imported package path. The restorer will wrap it in a +`*ast.SelectorExpr` where appropriate when converting back to ast, and also update the import +block. + +To enable import management, the decorator must be able to resolve the imported package for +selector expressions and identifiers, and the restorer must be able to resolve the name of a +package given it's path. Several implementations for these resolvers are provided, and the best +method will depend on the environment. [See below](#resolvers) for more details. + +### Load + +The [Load](https://godoc.org/github.com/dave/dst/decorator#Load) convenience function uses +`go/packages` to load packages and decorate all loaded ast files, with import management enabled: + +{{ "ExampleImports" | example }} + +### Mappings + +The decorator exposes `Dst.Nodes` and `Ast.Nodes` which map between `ast.Node` and `dst.Node`. This +enables systems that refer to `ast` nodes (such as `go/types`) to be used: + +{{ "ExampleTypes" | example }} + +## Resolvers + +There are two separate interfaces defined by the [resolver package](https://github.com/dave/dst/tree/master/decorator/resolver) +which allow the decorator and restorer to automatically manage the imports block. + +The decorator uses a `DecoratorResolver` which resolves the package path of any `*ast.Ident`. This is +complicated by dot-import syntax ([see below](#dot-imports)). + +The restorer uses a `RestorerResolver` which resolves the name of any package given the path. This +is complicated by vendoring and Go modules. + +When `Resolver` is set on `Decorator` or `Restorer`, the `Path` property must be set to the local +package path. + +Several implementations of both interfaces that are suitable for different environments are +provided: + +### DecoratorResolver + +#### gotypes + +The [gotypes](https://github.com/dave/dst/blob/master/decorator/resolver/gotypes/resolver.go) +package provides a `DecoratorResolver` with full dot-import compatibility. However it requires full +export data for all imported packages, so the `Uses` map from `go/types.Info` is required. There +are several methods of generating `go/types.Info`. Using `golang.org/x/tools/go/packages.Load` is +recommended for full Go modules compatibility. See the [decorator.Load](https://godoc.org/github.com/dave/dst/decorator#Load) +convenience function to automate this. + +#### goast + +The [goast](https://github.com/dave/dst/blob/master/decorator/resolver/goast/resolver.go) package +provides a simplified `DecoratorResolver` that only needs to scan a single ast file. This is unable +to resolve identifiers from dot-imported packages, so will panic if a dot-import is encountered in +the import block. It uses the provided `RestorerResolver` to resolve the names of all imported +packages. If no `RestorerResolver` is provided, the [guess](#guess-and-simple) implementation is used. + +### RestorerResolver + +#### gopackages + +The [gopackages](https://github.com/dave/dst/blob/master/decorator/resolver/gopackages/resolver.go) +package provides a `RestorerResolver` with full compatibility with Go modules. It uses +`golang.org/x/tools/go/packages` to load the package data. This may be very slow, and uses the `go` +command line tool to query package data, so may not be compatible with some environments. + +#### gobuild + +The [gobuild](https://github.com/dave/dst/blob/master/decorator/resolver/gobuild/resolver.go) +package provides an alternative `RestorerResolver` that uses the legacy `go/build` system to load +the imported package data. This may be needed in some circumstances and provides better performance +than `go/packages`. However, this is not Go modules aware. + +#### guess and simple + +The [guess](https://github.com/dave/dst/blob/master/decorator/resolver/guess/resolver.go) and +[simple](https://github.com/dave/dst/blob/master/decorator/resolver/simple/resolver.go) packages +provide simple `RestorerResolver` implementations that may be useful in certain circumstances, or +where performance is critical. `simple` resolves paths only if they occur in a provided map. +`guess` guesses the package name based on the last part of the path. + +### Example + +Here's an example of supplying resolvers for the decorator and restorer: + +{{ "ExampleManualImports" | example }} + +### Alias + +To control the alias of imports, use a `FileRestorer`: + +{{ "ExampleAlias" | example }} + +### Details + +For more information on exactly how the imports block is managed, read through the [test +cases](https://github.com/dave/dst/blob/master/decorator/restorer_resolver_test.go). + +### Dot-imports + +Consider this file... + +```go +package main + +import ( + . "a" +) + +func main() { + B() + C() +} +``` + +`B` and `C` could be local identifiers from a different file in this package, +or from the imported package `a`. If only one is from `a` and it is removed, we should remove the +import when we restore to `ast`. Thus the resolver needs to be able to resolve the package using +the full info from `go/types`. + +## Status + +This package is well tested and used in many projects. The API should be considered stable going forward. + +## Chat? + +Feel free to create an [issue](https://github.com/dave/dst/issues) or chat in the +[#dst](https://gophers.slack.com/messages/CCVL24MTQ) Gophers Slack channel. + +## Contributing + +For further developing or contributing to `dst`, check out [these notes](https://github.com/dave/dst/blob/master/contributing.md). + +## Special thanks + +Thanks very much to [hawkinsw](https://github.com/hawkinsw) for taking on the task of adding generics compatibility to `dst`. \ No newline at end of file diff --git a/vendor/github.com/dave/dst/clone-generated.go b/vendor/github.com/dave/dst/clone-generated.go new file mode 100644 index 000000000..ab2287491 --- /dev/null +++ b/vendor/github.com/dave/dst/clone-generated.go @@ -0,0 +1,1628 @@ +package dst + +import "fmt" + +// Clone returns a deep copy of the node, ready to be re-used elsewhere in the tree. +func Clone(n Node) Node { + switch n := n.(type) { + case *ArrayType: + out := &ArrayType{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Decoration: Lbrack + out.Decs.Lbrack = append(out.Decs.Lbrack, n.Decs.Lbrack...) + + // Node: Len + if n.Len != nil { + out.Len = Clone(n.Len).(Expr) + } + + // Decoration: Len + out.Decs.Len = append(out.Decs.Len, n.Decs.Len...) + + // Node: Elt + if n.Elt != nil { + out.Elt = Clone(n.Elt).(Expr) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *AssignStmt: + out := &AssignStmt{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // List: Lhs + for _, v := range n.Lhs { + out.Lhs = append(out.Lhs, Clone(v).(Expr)) + } + + // Token: Tok + out.Tok = n.Tok + + // Decoration: Tok + out.Decs.Tok = append(out.Decs.Tok, n.Decs.Tok...) + + // List: Rhs + for _, v := range n.Rhs { + out.Rhs = append(out.Rhs, Clone(v).(Expr)) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *BadDecl: + out := &BadDecl{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Bad + out.Length = n.Length + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *BadExpr: + out := &BadExpr{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Bad + out.Length = n.Length + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *BadStmt: + out := &BadStmt{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Bad + out.Length = n.Length + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *BasicLit: + out := &BasicLit{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // String: Value + out.Value = n.Value + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + // Value: Kind + out.Kind = n.Kind + + out.Decs.After = n.Decs.After + + return out + case *BinaryExpr: + out := &BinaryExpr{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Node: X + if n.X != nil { + out.X = Clone(n.X).(Expr) + } + + // Decoration: X + out.Decs.X = append(out.Decs.X, n.Decs.X...) + + // Token: Op + out.Op = n.Op + + // Decoration: Op + out.Decs.Op = append(out.Decs.Op, n.Decs.Op...) + + // Node: Y + if n.Y != nil { + out.Y = Clone(n.Y).(Expr) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *BlockStmt: + out := &BlockStmt{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Decoration: Lbrace + out.Decs.Lbrace = append(out.Decs.Lbrace, n.Decs.Lbrace...) + + // List: List + for _, v := range n.List { + out.List = append(out.List, Clone(v).(Stmt)) + } + + // Token: Rbrace + out.RbraceHasNoPos = n.RbraceHasNoPos + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *BranchStmt: + out := &BranchStmt{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Token: Tok + out.Tok = n.Tok + + // Decoration: Tok + out.Decs.Tok = append(out.Decs.Tok, n.Decs.Tok...) + + // Node: Label + if n.Label != nil { + out.Label = Clone(n.Label).(*Ident) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *CallExpr: + out := &CallExpr{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Node: Fun + if n.Fun != nil { + out.Fun = Clone(n.Fun).(Expr) + } + + // Decoration: Fun + out.Decs.Fun = append(out.Decs.Fun, n.Decs.Fun...) + + // Decoration: Lparen + out.Decs.Lparen = append(out.Decs.Lparen, n.Decs.Lparen...) + + // List: Args + for _, v := range n.Args { + out.Args = append(out.Args, Clone(v).(Expr)) + } + + // Token: Ellipsis + out.Ellipsis = n.Ellipsis + + // Decoration: Ellipsis + out.Decs.Ellipsis = append(out.Decs.Ellipsis, n.Decs.Ellipsis...) + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *CaseClause: + out := &CaseClause{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Decoration: Case + out.Decs.Case = append(out.Decs.Case, n.Decs.Case...) + + // List: List + for _, v := range n.List { + out.List = append(out.List, Clone(v).(Expr)) + } + + // Decoration: Colon + out.Decs.Colon = append(out.Decs.Colon, n.Decs.Colon...) + + // List: Body + for _, v := range n.Body { + out.Body = append(out.Body, Clone(v).(Stmt)) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *ChanType: + out := &ChanType{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Decoration: Begin + out.Decs.Begin = append(out.Decs.Begin, n.Decs.Begin...) + + // Decoration: Arrow + out.Decs.Arrow = append(out.Decs.Arrow, n.Decs.Arrow...) + + // Node: Value + if n.Value != nil { + out.Value = Clone(n.Value).(Expr) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + // Value: Dir + out.Dir = n.Dir + + out.Decs.After = n.Decs.After + + return out + case *CommClause: + out := &CommClause{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Decoration: Case + out.Decs.Case = append(out.Decs.Case, n.Decs.Case...) + + // Node: Comm + if n.Comm != nil { + out.Comm = Clone(n.Comm).(Stmt) + } + + // Decoration: Comm + out.Decs.Comm = append(out.Decs.Comm, n.Decs.Comm...) + + // Decoration: Colon + out.Decs.Colon = append(out.Decs.Colon, n.Decs.Colon...) + + // List: Body + for _, v := range n.Body { + out.Body = append(out.Body, Clone(v).(Stmt)) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *CompositeLit: + out := &CompositeLit{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Node: Type + if n.Type != nil { + out.Type = Clone(n.Type).(Expr) + } + + // Decoration: Type + out.Decs.Type = append(out.Decs.Type, n.Decs.Type...) + + // Decoration: Lbrace + out.Decs.Lbrace = append(out.Decs.Lbrace, n.Decs.Lbrace...) + + // List: Elts + for _, v := range n.Elts { + out.Elts = append(out.Elts, Clone(v).(Expr)) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + // Value: Incomplete + out.Incomplete = n.Incomplete + + out.Decs.After = n.Decs.After + + return out + case *DeclStmt: + out := &DeclStmt{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Node: Decl + if n.Decl != nil { + out.Decl = Clone(n.Decl).(Decl) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *DeferStmt: + out := &DeferStmt{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Decoration: Defer + out.Decs.Defer = append(out.Decs.Defer, n.Decs.Defer...) + + // Node: Call + if n.Call != nil { + out.Call = Clone(n.Call).(*CallExpr) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *Ellipsis: + out := &Ellipsis{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Decoration: Ellipsis + out.Decs.Ellipsis = append(out.Decs.Ellipsis, n.Decs.Ellipsis...) + + // Node: Elt + if n.Elt != nil { + out.Elt = Clone(n.Elt).(Expr) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *EmptyStmt: + out := &EmptyStmt{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + // Value: Implicit + out.Implicit = n.Implicit + + out.Decs.After = n.Decs.After + + return out + case *ExprStmt: + out := &ExprStmt{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Node: X + if n.X != nil { + out.X = Clone(n.X).(Expr) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *Field: + out := &Field{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // List: Names + for _, v := range n.Names { + out.Names = append(out.Names, Clone(v).(*Ident)) + } + + // Node: Type + if n.Type != nil { + out.Type = Clone(n.Type).(Expr) + } + + // Decoration: Type + out.Decs.Type = append(out.Decs.Type, n.Decs.Type...) + + // Node: Tag + if n.Tag != nil { + out.Tag = Clone(n.Tag).(*BasicLit) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *FieldList: + out := &FieldList{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Token: Opening + out.Opening = n.Opening + + // Decoration: Opening + out.Decs.Opening = append(out.Decs.Opening, n.Decs.Opening...) + + // List: List + for _, v := range n.List { + out.List = append(out.List, Clone(v).(*Field)) + } + + // Token: Closing + out.Closing = n.Closing + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *File: + out := &File{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Decoration: Package + out.Decs.Package = append(out.Decs.Package, n.Decs.Package...) + + // Node: Name + if n.Name != nil { + out.Name = Clone(n.Name).(*Ident) + } + + // Decoration: Name + out.Decs.Name = append(out.Decs.Name, n.Decs.Name...) + + // List: Decls + for _, v := range n.Decls { + out.Decls = append(out.Decls, Clone(v).(Decl)) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + // Scope: Scope + out.Scope = CloneScope(n.Scope) + + // List: Imports + for _, v := range n.Imports { + out.Imports = append(out.Imports, Clone(v).(*ImportSpec)) + } + + out.Decs.After = n.Decs.After + + return out + case *ForStmt: + out := &ForStmt{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Decoration: For + out.Decs.For = append(out.Decs.For, n.Decs.For...) + + // Node: Init + if n.Init != nil { + out.Init = Clone(n.Init).(Stmt) + } + + // Decoration: Init + out.Decs.Init = append(out.Decs.Init, n.Decs.Init...) + + // Node: Cond + if n.Cond != nil { + out.Cond = Clone(n.Cond).(Expr) + } + + // Decoration: Cond + out.Decs.Cond = append(out.Decs.Cond, n.Decs.Cond...) + + // Node: Post + if n.Post != nil { + out.Post = Clone(n.Post).(Stmt) + } + + // Decoration: Post + out.Decs.Post = append(out.Decs.Post, n.Decs.Post...) + + // Node: Body + if n.Body != nil { + out.Body = Clone(n.Body).(*BlockStmt) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *FuncDecl: + out := &FuncDecl{} + + out.Decs.Before = n.Decs.Before + + // Init: Type + out.Type = &FuncType{} + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Token: Func + out.Type.Func = n.Type.Func + + // Decoration: Func + out.Decs.Func = append(out.Decs.Func, n.Decs.Func...) + + // Node: Recv + if n.Recv != nil { + out.Recv = Clone(n.Recv).(*FieldList) + } + + // Decoration: Recv + out.Decs.Recv = append(out.Decs.Recv, n.Decs.Recv...) + + // Node: Name + if n.Name != nil { + out.Name = Clone(n.Name).(*Ident) + } + + // Decoration: Name + out.Decs.Name = append(out.Decs.Name, n.Decs.Name...) + + // Node: TypeParams + if n.Type.TypeParams != nil { + out.Type.TypeParams = Clone(n.Type.TypeParams).(*FieldList) + } + + // Decoration: TypeParams + out.Decs.TypeParams = append(out.Decs.TypeParams, n.Decs.TypeParams...) + + // Node: Params + if n.Type.Params != nil { + out.Type.Params = Clone(n.Type.Params).(*FieldList) + } + + // Decoration: Params + out.Decs.Params = append(out.Decs.Params, n.Decs.Params...) + + // Node: Results + if n.Type.Results != nil { + out.Type.Results = Clone(n.Type.Results).(*FieldList) + } + + // Decoration: Results + out.Decs.Results = append(out.Decs.Results, n.Decs.Results...) + + // Node: Body + if n.Body != nil { + out.Body = Clone(n.Body).(*BlockStmt) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *FuncLit: + out := &FuncLit{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Node: Type + if n.Type != nil { + out.Type = Clone(n.Type).(*FuncType) + } + + // Decoration: Type + out.Decs.Type = append(out.Decs.Type, n.Decs.Type...) + + // Node: Body + if n.Body != nil { + out.Body = Clone(n.Body).(*BlockStmt) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *FuncType: + out := &FuncType{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Token: Func + out.Func = n.Func + + // Decoration: Func + out.Decs.Func = append(out.Decs.Func, n.Decs.Func...) + + // Node: TypeParams + if n.TypeParams != nil { + out.TypeParams = Clone(n.TypeParams).(*FieldList) + } + + // Decoration: TypeParams + out.Decs.TypeParams = append(out.Decs.TypeParams, n.Decs.TypeParams...) + + // Node: Params + if n.Params != nil { + out.Params = Clone(n.Params).(*FieldList) + } + + // Decoration: Params + out.Decs.Params = append(out.Decs.Params, n.Decs.Params...) + + // Node: Results + if n.Results != nil { + out.Results = Clone(n.Results).(*FieldList) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *GenDecl: + out := &GenDecl{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Token: Tok + out.Tok = n.Tok + + // Decoration: Tok + out.Decs.Tok = append(out.Decs.Tok, n.Decs.Tok...) + + // Token: Lparen + out.Lparen = n.Lparen + + // Decoration: Lparen + out.Decs.Lparen = append(out.Decs.Lparen, n.Decs.Lparen...) + + // List: Specs + for _, v := range n.Specs { + out.Specs = append(out.Specs, Clone(v).(Spec)) + } + + // Token: Rparen + out.Rparen = n.Rparen + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *GoStmt: + out := &GoStmt{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Decoration: Go + out.Decs.Go = append(out.Decs.Go, n.Decs.Go...) + + // Node: Call + if n.Call != nil { + out.Call = Clone(n.Call).(*CallExpr) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *Ident: + out := &Ident{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Decoration: X + out.Decs.X = append(out.Decs.X, n.Decs.X...) + + // String: Name + out.Name = n.Name + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + // Object: Obj + out.Obj = CloneObject(n.Obj) + + // Path: Path + out.Path = n.Path + + out.Decs.After = n.Decs.After + + return out + case *IfStmt: + out := &IfStmt{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Decoration: If + out.Decs.If = append(out.Decs.If, n.Decs.If...) + + // Node: Init + if n.Init != nil { + out.Init = Clone(n.Init).(Stmt) + } + + // Decoration: Init + out.Decs.Init = append(out.Decs.Init, n.Decs.Init...) + + // Node: Cond + if n.Cond != nil { + out.Cond = Clone(n.Cond).(Expr) + } + + // Decoration: Cond + out.Decs.Cond = append(out.Decs.Cond, n.Decs.Cond...) + + // Node: Body + if n.Body != nil { + out.Body = Clone(n.Body).(*BlockStmt) + } + + // Decoration: Else + out.Decs.Else = append(out.Decs.Else, n.Decs.Else...) + + // Node: Else + if n.Else != nil { + out.Else = Clone(n.Else).(Stmt) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *ImportSpec: + out := &ImportSpec{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Node: Name + if n.Name != nil { + out.Name = Clone(n.Name).(*Ident) + } + + // Decoration: Name + out.Decs.Name = append(out.Decs.Name, n.Decs.Name...) + + // Node: Path + if n.Path != nil { + out.Path = Clone(n.Path).(*BasicLit) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *IncDecStmt: + out := &IncDecStmt{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Node: X + if n.X != nil { + out.X = Clone(n.X).(Expr) + } + + // Decoration: X + out.Decs.X = append(out.Decs.X, n.Decs.X...) + + // Token: Tok + out.Tok = n.Tok + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *IndexExpr: + out := &IndexExpr{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Node: X + if n.X != nil { + out.X = Clone(n.X).(Expr) + } + + // Decoration: X + out.Decs.X = append(out.Decs.X, n.Decs.X...) + + // Decoration: Lbrack + out.Decs.Lbrack = append(out.Decs.Lbrack, n.Decs.Lbrack...) + + // Node: Index + if n.Index != nil { + out.Index = Clone(n.Index).(Expr) + } + + // Decoration: Index + out.Decs.Index = append(out.Decs.Index, n.Decs.Index...) + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *IndexListExpr: + out := &IndexListExpr{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Node: X + if n.X != nil { + out.X = Clone(n.X).(Expr) + } + + // Decoration: X + out.Decs.X = append(out.Decs.X, n.Decs.X...) + + // Decoration: Lbrack + out.Decs.Lbrack = append(out.Decs.Lbrack, n.Decs.Lbrack...) + + // List: Indices + for _, v := range n.Indices { + out.Indices = append(out.Indices, Clone(v).(Expr)) + } + + // Decoration: Indices + out.Decs.Indices = append(out.Decs.Indices, n.Decs.Indices...) + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *InterfaceType: + out := &InterfaceType{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Decoration: Interface + out.Decs.Interface = append(out.Decs.Interface, n.Decs.Interface...) + + // Node: Methods + if n.Methods != nil { + out.Methods = Clone(n.Methods).(*FieldList) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + // Value: Incomplete + out.Incomplete = n.Incomplete + + out.Decs.After = n.Decs.After + + return out + case *KeyValueExpr: + out := &KeyValueExpr{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Node: Key + if n.Key != nil { + out.Key = Clone(n.Key).(Expr) + } + + // Decoration: Key + out.Decs.Key = append(out.Decs.Key, n.Decs.Key...) + + // Decoration: Colon + out.Decs.Colon = append(out.Decs.Colon, n.Decs.Colon...) + + // Node: Value + if n.Value != nil { + out.Value = Clone(n.Value).(Expr) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *LabeledStmt: + out := &LabeledStmt{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Node: Label + if n.Label != nil { + out.Label = Clone(n.Label).(*Ident) + } + + // Decoration: Label + out.Decs.Label = append(out.Decs.Label, n.Decs.Label...) + + // Decoration: Colon + out.Decs.Colon = append(out.Decs.Colon, n.Decs.Colon...) + + // Node: Stmt + if n.Stmt != nil { + out.Stmt = Clone(n.Stmt).(Stmt) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *MapType: + out := &MapType{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Decoration: Map + out.Decs.Map = append(out.Decs.Map, n.Decs.Map...) + + // Node: Key + if n.Key != nil { + out.Key = Clone(n.Key).(Expr) + } + + // Decoration: Key + out.Decs.Key = append(out.Decs.Key, n.Decs.Key...) + + // Node: Value + if n.Value != nil { + out.Value = Clone(n.Value).(Expr) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *Package: + out := &Package{} + + // Value: Name + out.Name = n.Name + + // Scope: Scope + out.Scope = CloneScope(n.Scope) + + // Map: Imports + out.Imports = map[string]*Object{} + for k, v := range n.Imports { + out.Imports[k] = CloneObject(v) + } + + // Map: Files + out.Files = map[string]*File{} + for k, v := range n.Files { + out.Files[k] = Clone(v).(*File) + } + + return out + case *ParenExpr: + out := &ParenExpr{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Decoration: Lparen + out.Decs.Lparen = append(out.Decs.Lparen, n.Decs.Lparen...) + + // Node: X + if n.X != nil { + out.X = Clone(n.X).(Expr) + } + + // Decoration: X + out.Decs.X = append(out.Decs.X, n.Decs.X...) + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *RangeStmt: + out := &RangeStmt{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Decoration: For + out.Decs.For = append(out.Decs.For, n.Decs.For...) + + // Node: Key + if n.Key != nil { + out.Key = Clone(n.Key).(Expr) + } + + // Decoration: Key + out.Decs.Key = append(out.Decs.Key, n.Decs.Key...) + + // Node: Value + if n.Value != nil { + out.Value = Clone(n.Value).(Expr) + } + + // Decoration: Value + out.Decs.Value = append(out.Decs.Value, n.Decs.Value...) + + // Token: Tok + out.Tok = n.Tok + + // Decoration: Range + out.Decs.Range = append(out.Decs.Range, n.Decs.Range...) + + // Node: X + if n.X != nil { + out.X = Clone(n.X).(Expr) + } + + // Decoration: X + out.Decs.X = append(out.Decs.X, n.Decs.X...) + + // Node: Body + if n.Body != nil { + out.Body = Clone(n.Body).(*BlockStmt) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *ReturnStmt: + out := &ReturnStmt{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Decoration: Return + out.Decs.Return = append(out.Decs.Return, n.Decs.Return...) + + // List: Results + for _, v := range n.Results { + out.Results = append(out.Results, Clone(v).(Expr)) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *SelectStmt: + out := &SelectStmt{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Decoration: Select + out.Decs.Select = append(out.Decs.Select, n.Decs.Select...) + + // Node: Body + if n.Body != nil { + out.Body = Clone(n.Body).(*BlockStmt) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *SelectorExpr: + out := &SelectorExpr{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Node: X + if n.X != nil { + out.X = Clone(n.X).(Expr) + } + + // Decoration: X + out.Decs.X = append(out.Decs.X, n.Decs.X...) + + // Node: Sel + if n.Sel != nil { + out.Sel = Clone(n.Sel).(*Ident) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *SendStmt: + out := &SendStmt{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Node: Chan + if n.Chan != nil { + out.Chan = Clone(n.Chan).(Expr) + } + + // Decoration: Chan + out.Decs.Chan = append(out.Decs.Chan, n.Decs.Chan...) + + // Decoration: Arrow + out.Decs.Arrow = append(out.Decs.Arrow, n.Decs.Arrow...) + + // Node: Value + if n.Value != nil { + out.Value = Clone(n.Value).(Expr) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *SliceExpr: + out := &SliceExpr{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Node: X + if n.X != nil { + out.X = Clone(n.X).(Expr) + } + + // Decoration: X + out.Decs.X = append(out.Decs.X, n.Decs.X...) + + // Decoration: Lbrack + out.Decs.Lbrack = append(out.Decs.Lbrack, n.Decs.Lbrack...) + + // Node: Low + if n.Low != nil { + out.Low = Clone(n.Low).(Expr) + } + + // Decoration: Low + out.Decs.Low = append(out.Decs.Low, n.Decs.Low...) + + // Node: High + if n.High != nil { + out.High = Clone(n.High).(Expr) + } + + // Decoration: High + out.Decs.High = append(out.Decs.High, n.Decs.High...) + + // Node: Max + if n.Max != nil { + out.Max = Clone(n.Max).(Expr) + } + + // Decoration: Max + out.Decs.Max = append(out.Decs.Max, n.Decs.Max...) + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + // Value: Slice3 + out.Slice3 = n.Slice3 + + out.Decs.After = n.Decs.After + + return out + case *StarExpr: + out := &StarExpr{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Decoration: Star + out.Decs.Star = append(out.Decs.Star, n.Decs.Star...) + + // Node: X + if n.X != nil { + out.X = Clone(n.X).(Expr) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *StructType: + out := &StructType{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Decoration: Struct + out.Decs.Struct = append(out.Decs.Struct, n.Decs.Struct...) + + // Node: Fields + if n.Fields != nil { + out.Fields = Clone(n.Fields).(*FieldList) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + // Value: Incomplete + out.Incomplete = n.Incomplete + + out.Decs.After = n.Decs.After + + return out + case *SwitchStmt: + out := &SwitchStmt{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Decoration: Switch + out.Decs.Switch = append(out.Decs.Switch, n.Decs.Switch...) + + // Node: Init + if n.Init != nil { + out.Init = Clone(n.Init).(Stmt) + } + + // Decoration: Init + out.Decs.Init = append(out.Decs.Init, n.Decs.Init...) + + // Node: Tag + if n.Tag != nil { + out.Tag = Clone(n.Tag).(Expr) + } + + // Decoration: Tag + out.Decs.Tag = append(out.Decs.Tag, n.Decs.Tag...) + + // Node: Body + if n.Body != nil { + out.Body = Clone(n.Body).(*BlockStmt) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *TypeAssertExpr: + out := &TypeAssertExpr{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Node: X + if n.X != nil { + out.X = Clone(n.X).(Expr) + } + + // Decoration: X + out.Decs.X = append(out.Decs.X, n.Decs.X...) + + // Decoration: Lparen + out.Decs.Lparen = append(out.Decs.Lparen, n.Decs.Lparen...) + + // Node: Type + if n.Type != nil { + out.Type = Clone(n.Type).(Expr) + } + + // Decoration: Type + out.Decs.Type = append(out.Decs.Type, n.Decs.Type...) + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *TypeSpec: + out := &TypeSpec{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Node: Name + if n.Name != nil { + out.Name = Clone(n.Name).(*Ident) + } + + // Token: Assign + out.Assign = n.Assign + + // Decoration: Name + out.Decs.Name = append(out.Decs.Name, n.Decs.Name...) + + // Node: TypeParams + if n.TypeParams != nil { + out.TypeParams = Clone(n.TypeParams).(*FieldList) + } + + // Decoration: TypeParams + out.Decs.TypeParams = append(out.Decs.TypeParams, n.Decs.TypeParams...) + + // Node: Type + if n.Type != nil { + out.Type = Clone(n.Type).(Expr) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *TypeSwitchStmt: + out := &TypeSwitchStmt{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Decoration: Switch + out.Decs.Switch = append(out.Decs.Switch, n.Decs.Switch...) + + // Node: Init + if n.Init != nil { + out.Init = Clone(n.Init).(Stmt) + } + + // Decoration: Init + out.Decs.Init = append(out.Decs.Init, n.Decs.Init...) + + // Node: Assign + if n.Assign != nil { + out.Assign = Clone(n.Assign).(Stmt) + } + + // Decoration: Assign + out.Decs.Assign = append(out.Decs.Assign, n.Decs.Assign...) + + // Node: Body + if n.Body != nil { + out.Body = Clone(n.Body).(*BlockStmt) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *UnaryExpr: + out := &UnaryExpr{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // Token: Op + out.Op = n.Op + + // Decoration: Op + out.Decs.Op = append(out.Decs.Op, n.Decs.Op...) + + // Node: X + if n.X != nil { + out.X = Clone(n.X).(Expr) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + case *ValueSpec: + out := &ValueSpec{} + + out.Decs.Before = n.Decs.Before + + // Decoration: Start + out.Decs.Start = append(out.Decs.Start, n.Decs.Start...) + + // List: Names + for _, v := range n.Names { + out.Names = append(out.Names, Clone(v).(*Ident)) + } + + // Node: Type + if n.Type != nil { + out.Type = Clone(n.Type).(Expr) + } + + // Decoration: Assign + out.Decs.Assign = append(out.Decs.Assign, n.Decs.Assign...) + + // List: Values + for _, v := range n.Values { + out.Values = append(out.Values, Clone(v).(Expr)) + } + + // Decoration: End + out.Decs.End = append(out.Decs.End, n.Decs.End...) + + out.Decs.After = n.Decs.After + + return out + default: + panic(fmt.Sprintf("%T", n)) + } +} diff --git a/vendor/github.com/dave/dst/clone.go b/vendor/github.com/dave/dst/clone.go new file mode 100644 index 000000000..3f1e5f829 --- /dev/null +++ b/vendor/github.com/dave/dst/clone.go @@ -0,0 +1,11 @@ +package dst + +// CloneObject returns nil: After cloning a node, it should not be attached to the same object / scope. +func CloneObject(o *Object) *Object { + return nil +} + +// CloneScope returns nil: After cloning a node, it should not be attached to the same object / scope. +func CloneScope(s *Scope) *Scope { + return nil +} diff --git a/vendor/github.com/dave/dst/contributing.md b/vendor/github.com/dave/dst/contributing.md new file mode 100644 index 000000000..dc0240605 --- /dev/null +++ b/vendor/github.com/dave/dst/contributing.md @@ -0,0 +1,78 @@ +# Building / Developing / Contributing + +The `dst` package relies heavily on code generation. So heavily, in fact, that `README.md` is +itself generated by a preprocessor! Here are a few tips/tricks to get started developing `dst`. + +## Adding Features, Fixing Bugs + +Generally speaking, code handling node annotation is generated from the files in the `gendst` directory. +In order to add/change decorations, edit the `gendst/data.go` file. Once you have made your edits, you can +regenerate the library's source code based on those changes by + +1. `go run github.com/dave/dst/gendst`: This command will build and run a program generated from the + source code in the `gendst` folder that regenerates all the dst source fiels to reflect the changes + that you just made in the `gendst/data.go` file. + +Whenever you make a change to the `gendst/data.go` file, you must perform the aforementioned step. + +If you add a Node to the `gendst/data.go` file, you will need to make corresponding additions to non-generated +files as well. Those files include, but are not limited to,: + +- `dst.go` +- `walk.go` +- `dstutil/rewrite.go` + +Depending on the changes that you have made to the description of the decorated Nodes, you may have to change some, none, +or all of those files listed above (or even others that are not listed!). + +## Adding/Running Tests + +Any changes to the decorations of Nodes (or the addition of new Nodes) should be accompanied +by an entry in `gendst/positions.go`. + +The format of the file is ... + +``` +// +// startLine { + for i := startLine; i < endLine; i++ { + // we avoid the lines that follow the lines in the comment + avoid[i+1] = true + } + } + } + } + } + + // avoid newlines inside multi-line (back-quoted) strings or bad nodes + for _, frag := range f.fragments { + switch frag := frag.(type) { + case *stringFragment: + if !strings.HasPrefix(frag.String, "`") { + continue + } + + startLine := f.Fset.Position(frag.Pos).Line + endLine := f.Fset.Position(frag.Pos + token.Pos(len(frag.String))).Line + + // multi line string + if endLine > startLine { + for i := startLine; i < endLine; i++ { + // we avoid the lines that follow the lines in the string + avoid[i+1] = true + } + } + + case *badFragment: + + // Newlines inside bad nodes are not printed by the formatter, so there is no + // need to reconstruct them in the restorer. + + startLine := f.Fset.Position(frag.Pos).Line + endLine := f.Fset.Position(frag.Pos + token.Pos(frag.Length)).Line + + if endLine > startLine { + for i := startLine; i < endLine; i++ { + // we avoid the lines that follow the lines in the node + avoid[i+1] = true + } + } + } + } + + // Finding the positions of each newline is not easy. We step through the file one byte + // at a time and get the line number from the FileSet. As the line number increments, + // we know where the newlines are. + line := 1 + tokenf := f.Fset.File(astf.Pos()) + max := tokenf.Base() + tokenf.Size() + for i := tokenf.Base(); i < max; i++ { + pos := f.Fset.Position(token.Pos(i)) + if pos.Line != line { + + // if the line number has changed, we're on a new line + + line = pos.Line + + if avoid[line] { + // ignore if it's in the avoid list - e.g. inside a comment or multi-line + // string + continue + } + + // peek ahead to the next position in the fset. If we're on another new line, + // we have an empty line: + nextLine := line + if i < max-1 { + // can't peek forward at the end of the file + nextLine = f.Fset.Position(token.Pos(i + 1)).Line + } + + if nextLine != line { + // add an empty line fragment + f.addNewlineFragment(token.Pos(i-1), true) + + // for empty lines, increment past the second "\n" manually: + line = nextLine + i++ + + } else { + // add a new line fragment + f.addNewlineFragment(token.Pos(i-1), false) + } + + } + } + } + + switch val := node.(type) { + case *ast.File: + processFile(val) + case *ast.Package: + for _, file := range val.Files { + processFile(file) + } + } + + } + + // the comments and newline fragments will be after the node fragments, so we sort the entire + // list by fset position, ensuring that fragments with equal position stay in the original + // order. This ensures that decorations get added to the correct attachment points (which may + // occur at the same fset position). + sort.SliceStable(f.fragments, func(i, j int) bool { + return f.fragments[i].Position() < f.fragments[j].Position() + }) + + // We calculate the indent of the start and end of each node and comment. This is used to + // during the decoration attachment algorithm to correctly attach hanging indent comments. See + // issues 9 and 18 for more info. + currentIndent := 0 + for i, frag := range f.fragments { + if i == 0 || f.fragments[i-1].Newline() { + currentIndent = f.Fset.Position(frag.Position()).Column + } + switch frag := frag.(type) { + case *decorationFragment: + switch frag.Name { + case "Start": + f.startIndents[frag.Node] = currentIndent + case "End": + f.endIndents[frag.Node] = currentIndent + } + case *commentFragment: + frag.Indent = currentIndent + } + } +} + +func (f *fileDecorator) link() { + + // Pass 1: associate comment groups with decorations. Sweep up any other comments / new-lines / + // empty-lines and associate with the same decoration. + for i, frag := range f.fragments { + switch frag := frag.(type) { + case *decorationFragment: + + // Special case for hanging indent (See https://github.com/dave/dst/issues/18) + // + // If we're on the End decoration of a Stmt or Decl, and indents: end == start+1 (OR + // it's a case / comm clause), then search forward over empty lines for all comments + // with the same indent as the End decoration. + // + // These should be attached to the end node. We also search for subsequent comments that + // have the same indent as the Start. If the next decoration node is the start of a Stmt + // or Decl with the same indent as the original node, these are attached there. + + if frag.Name != "End" { + continue + } + _, stmt := frag.Node.(ast.Stmt) + _, decl := frag.Node.(ast.Decl) + if !stmt && !decl { + continue + } + + if _, labeledStmt := frag.Node.(*ast.LabeledStmt); labeledStmt { + // Special case: labeled statements shouldn't be treated in the same way. + continue + } + + start := f.startIndents[frag.Node] + end := f.endIndents[frag.Node] + + _, caseClause := frag.Node.(*ast.CaseClause) + _, commClause := frag.Node.(*ast.CommClause) + if start == end && (caseClause || commClause) { + // special case for case / comm clause with no items... the clause node starts and + // ends on the same line, but comments can still be hanging. We spoof an indented + // end position: + end++ + } + + if end != start+1 { + continue + } + + frags, next := f.findIndentedComments(i+1, [2]int{end, start}) + endFrags := frags[0] + nextFrags := frags[1] + if len(endFrags) > 0 { + // if endFrags ends with a newline, don't attach it because it was in between the + // two groups, so should be left unattached so we can attach it as spacing in the + // second pass + _, nl := endFrags[len(endFrags)-1].(*newlineFragment) + if nl { + f.attachToDecoration(endFrags[0:len(endFrags)-1], f.decorations, frag) + } else { + f.attachToDecoration(endFrags, f.decorations, frag) + } + } + if len(nextFrags) > 0 && next != nil { + _, nextStmt := next.Node.(ast.Stmt) + _, nextDecl := next.Node.(ast.Decl) + nextStart := f.startIndents[next.Node] + if (nextStmt || nextDecl) && nextStart == start { + f.attachToDecoration(nextFrags, f.decorations, next) + } + } + + case *commentFragment: + + if frag.Attached != nil { + continue + } + + // Comments (or comment groups) attach to decoration points in this precedence: + // + // 1) Before the comment on the same line + // 2) After the comment on the same line + // 3) After the comment on subsequent lines (but stopping at empty lines) + // 4) Before the comment on previous lines (but stopping at empty lines) + // 5) After the comment on subsequent lines + // 6) Before the comment on previous lines + // + // We always stop at tokens, strings. If we get to the end without finding a decoration point we panic. + + var frags []fragment // comment / new-line / empty-line + var dec *decorationFragment + var found bool + var try int + for !found { + try++ + switch try { + case 1: + // Before the comment on the same line (search backwards and stop at any newline) + frags, dec, found = f.findDecoration(true, true, i, -1, false) + case 2: + // After the comment on the same line + // After the comment on line+1 (search forwards and stop at any empty line) + frags, dec, found = f.findDecoration(false, true, i, 1, false) + case 3: + // Before the comment on line-1 (search backwards and stop at any empty line) + frags, dec, found = f.findDecoration(false, true, i, -1, false) + case 4: + // After the comment on line+2 (search forwards) + frags, dec, found = f.findDecoration(false, false, i, 1, false) + case 5: + // After the comment on line-2 (search backwards) + frags, dec, found = f.findDecoration(false, false, i, -1, false) + default: + panic("no decoration found for " + frag.Text) + } + } + f.attachToDecoration(frags, f.decorations, dec) + } + } + + // Pass 2: associate any new-lines / empty-lines that have not been added to decorations to node + // spacing. If they can't be attached as node spacing, attach them as decorations. + for i, frag := range f.fragments { + switch frag := frag.(type) { + case *newlineFragment: + + if frag.Attached != nil { + continue + } + + // If the newline is directly before / after a node, we can set the Before / After spacing + // of the node decoration instead of adding the newline as a decoration. + nodeBefore, _, foundBefore := f.findNode(i, 1) + nodeAfter, _, foundAfter := f.findNode(i, -1) + if foundBefore || foundAfter { + spaceType := dst.NewLine + if frag.Empty { + spaceType = dst.EmptyLine + } + if foundBefore { + f.before[nodeBefore] = spaceType + } + if foundAfter { + f.after[nodeAfter] = spaceType + } + continue + } + + // If this newline can't be associated with a node, attach it to the next / previous + // decoration location: + var dec *decorationFragment + var found bool + var try int + for !found { + try++ + switch try { + case 1: + // search backwards but stop at any token + _, dec, found = f.findDecoration(false, false, i, -1, false) + case 2: + // search forwards but stop at any token + _, dec, found = f.findDecoration(false, false, i, 1, false) + default: + panic("no decoration found for newline") + } + } + appendNewLine(f.decorations, dec.Node, dec.Name, frag.Empty) + } + } + + return +} + +func appendDecoration(m map[ast.Node]map[string][]string, n ast.Node, pos, text string) { + if m[n] == nil { + m[n] = map[string][]string{} + } + m[n][pos] = append(m[n][pos], text) +} + +func appendNewLine(m map[ast.Node]map[string][]string, n ast.Node, pos string, empty bool) { + if m[n] == nil { + m[n] = map[string][]string{} + } + num := 1 + if empty { + num = 2 + } + decs := m[n][pos] + if len(decs) > 0 && strings.HasPrefix(decs[len(decs)-1], "//") { + num-- + } + for i := 0; i < num; i++ { + m[n][pos] = append(m[n][pos], "\n") + } +} + +func (f *fileDecorator) attachToDecoration(frags []fragment, decorations map[ast.Node]map[string][]string, dec *decorationFragment) { + for _, fr := range frags { + switch fr := fr.(type) { + case *commentFragment: + appendDecoration(decorations, dec.Node, dec.Name, fr.Text) + fr.Attached = dec + case *newlineFragment: + appendNewLine(decorations, dec.Node, dec.Name, fr.Empty) + fr.Attached = dec + } + } +} + +func (f *fileDecorator) findDecoration(stopAtNewline, stopAtEmptyLine bool, from int, direction int, onlyClause bool) (swept []fragment, dec *decorationFragment, found bool) { + var frags []fragment + for i := from; i < len(f.fragments) && i >= 0; i += direction { + switch current := f.fragments[i].(type) { + case *decorationFragment: + if onlyClause { + switch current.Node.(type) { + case *ast.CommClause, *ast.CaseClause: + if current.Name == "Start" { + return frags, current, true + } + return + default: + return + } + } + return frags, current, true + case *newlineFragment: + if stopAtNewline { + return + } + if stopAtEmptyLine && current.Empty { + return + } + if current.Attached != nil { + continue + } + if direction == 1 { + frags = append(frags, current) + } else { + frags = append([]fragment{current}, frags...) + } + case *commentFragment: + if current.Attached != nil { + continue + } + if direction == 1 { + frags = append(frags, current) + } else { + frags = append([]fragment{current}, frags...) + } + case *tokenFragment, *stringFragment: + return + } + } + return +} + +func (f *fileDecorator) findNode(from int, direction int) (node ast.Node, dec *decorationFragment, found bool) { + + var name string + switch direction { + case 1: + name = "Start" + case -1: + name = "End" + } + + for i := from; i < len(f.fragments) && i >= 0; i += direction { + switch frag := f.fragments[i].(type) { + case *decorationFragment: + if frag.Name == name { + return frag.Node, frag, true + } + return + case *commentFragment: + if frag.Attached != nil && frag.Attached.Name == name { + return frag.Attached.Node, frag.Attached, true + } + case *newlineFragment: + if frag.Attached != nil && frag.Attached.Name == name { + return frag.Attached.Node, frag.Attached, true + } + case *tokenFragment, *stringFragment: + return + } + } + return +} + +func (f *fileDecorator) findIndentedComments(from int, indents [2]int) (frags [2][]fragment, nextDecoration *decorationFragment) { + var stage int + var pastNewline bool // while this is false, we're on the same line that the stmt ended, so we accept all comments regardless of the indent (e.g. empty clauses) - see "hanging-indent-same-line" test case. + for i := from; i < len(f.fragments); i++ { + switch current := f.fragments[i].(type) { + case *decorationFragment: + return frags, current + case *newlineFragment: + pastNewline = true + frags[stage] = append(frags[stage], current) + case *commentFragment: + if !pastNewline { + frags[stage] = append(frags[stage], current) + continue + } + if stage == 0 { + // Check indent matches. If not, move to second stage or exit if that doesn't match. + if current.Indent != indents[0] { + if current.Indent == indents[1] { + stage = 1 + } else { + return + } + } + } else if stage == 1 { + if current.Indent != indents[1] { + return + } + } + frags[stage] = append(frags[stage], current) + case *tokenFragment, *stringFragment: + return + } + } + return +} + +type fragment interface { + Position() token.Pos + Newline() bool // True if the fragment ends in a newline ("\n" or "//...") +} + +type tokenFragment struct { + Node ast.Node + Token token.Token + Pos token.Pos +} + +type stringFragment struct { + Node ast.Node + String string + Pos token.Pos +} + +type badFragment struct { + Node ast.Node + Pos token.Pos + Length int +} + +type commentFragment struct { + Text string + Pos token.Pos + Attached *decorationFragment // where did we attach this comment in pass 1? + Indent int // indent if this comment follows a newline +} + +type newlineFragment struct { + Pos token.Pos + Empty bool // true if this newline is an empty line (e.g. follows a "//" comment or "\n") + Attached *decorationFragment // where did we attach this comment in pass 1? +} + +type decorationFragment struct { + Node ast.Node + Name string + Pos token.Pos +} + +func (v *tokenFragment) Position() token.Pos { return v.Pos } +func (v *stringFragment) Position() token.Pos { return v.Pos } +func (v *commentFragment) Position() token.Pos { return v.Pos } +func (v *newlineFragment) Position() token.Pos { return v.Pos } +func (v *decorationFragment) Position() token.Pos { return v.Pos } +func (v *badFragment) Position() token.Pos { return v.Pos } + +func (v *tokenFragment) Newline() bool { return false } +func (v *stringFragment) Newline() bool { return false } +func (v *commentFragment) Newline() bool { return strings.HasPrefix(v.Text, "//") } +func (v *newlineFragment) Newline() bool { return true } +func (v *decorationFragment) Newline() bool { return false } +func (v *badFragment) Newline() bool { return false } + +func (f fileDecorator) debug(w io.Writer) { + formatPos := func(s token.Position) string { + return s.String()[strings.Index(s.String(), ":")+1:] + } + nodeType := func(n ast.Node) string { + return strings.Replace(fmt.Sprintf("%T", n), "*ast.", "", -1) + } + for _, v := range f.fragments { + switch v := v.(type) { + case *newlineFragment: + if v.Empty { + fmt.Fprintf(w, "Empty line %s\n", formatPos(f.Fset.Position(v.Pos))) + } else { + fmt.Fprintf(w, "New line %s\n", formatPos(f.Fset.Position(v.Pos))) + } + case *tokenFragment: + fmt.Fprintf(w, "%s %q %s\n", nodeType(v.Node), v.Token, formatPos(f.Fset.Position(v.Pos))) + case *stringFragment: + fmt.Fprintf(w, "%s %q %s\n", nodeType(v.Node), v.String, formatPos(f.Fset.Position(v.Pos))) + case *decorationFragment: + fmt.Fprintf(w, "%s %s %s\n", nodeType(v.Node), v.Name, formatPos(f.Fset.Position(v.Pos))) + case *commentFragment: + fmt.Fprintf(w, "%q %s\n", v.Text, formatPos(f.Fset.Position(v.Pos))) + case *badFragment: + fmt.Fprintf(w, "%s %d %s\n", nodeType(v.Node), v.Length, formatPos(f.Fset.Position(v.Pos))) + default: + fmt.Fprintf(w, "%T %s\n", v, formatPos(f.Fset.Position(v.Position()))) + } + } +} diff --git a/vendor/github.com/dave/dst/decorator/decorator-node-generated.go b/vendor/github.com/dave/dst/decorator/decorator-node-generated.go new file mode 100644 index 000000000..72044ec77 --- /dev/null +++ b/vendor/github.com/dave/dst/decorator/decorator-node-generated.go @@ -0,0 +1,2379 @@ +package decorator + +import ( + "github.com/dave/dst" + "go/ast" + "go/token" +) + +func (f *fileDecorator) decorateNode(parent ast.Node, parentName, parentField, parentFieldType string, n ast.Node) (dst.Node, error) { + if dn, ok := f.Dst.Nodes[n]; ok { + return dn, nil + } + switch n := n.(type) { + case *ast.ArrayType: + out := &dst.ArrayType{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: Lbrack + + // Node: Len + if n.Len != nil { + child, err := f.decorateNode(n, "ArrayType", "Len", "Expr", n.Len) + if err != nil { + return nil, err + } + out.Len = child.(dst.Expr) + } + + // Token: Rbrack + + // Node: Elt + if n.Elt != nil { + child, err := f.decorateNode(n, "ArrayType", "Elt", "Expr", n.Elt) + if err != nil { + return nil, err + } + out.Elt = child.(dst.Expr) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Lbrack"]; ok { + out.Decs.Lbrack = decs + } + if decs, ok := nd["Len"]; ok { + out.Decs.Len = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.AssignStmt: + out := &dst.AssignStmt{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // List: Lhs + for _, v := range n.Lhs { + child, err := f.decorateNode(n, "AssignStmt", "Lhs", "Expr", v) + if err != nil { + return nil, err + } + out.Lhs = append(out.Lhs, child.(dst.Expr)) + } + + // Token: Tok + out.Tok = n.Tok + + // List: Rhs + for _, v := range n.Rhs { + child, err := f.decorateNode(n, "AssignStmt", "Rhs", "Expr", v) + if err != nil { + return nil, err + } + out.Rhs = append(out.Rhs, child.(dst.Expr)) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Tok"]; ok { + out.Decs.Tok = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.BadDecl: + out := &dst.BadDecl{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Bad + out.Length = int(n.To - n.From) + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.BadExpr: + out := &dst.BadExpr{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Bad + out.Length = int(n.To - n.From) + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.BadStmt: + out := &dst.BadStmt{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Bad + out.Length = int(n.To - n.From) + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.BasicLit: + out := &dst.BasicLit{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // String: Value + out.Value = n.Value + + // Value: Kind + out.Kind = n.Kind + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.BinaryExpr: + out := &dst.BinaryExpr{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Node: X + if n.X != nil { + child, err := f.decorateNode(n, "BinaryExpr", "X", "Expr", n.X) + if err != nil { + return nil, err + } + out.X = child.(dst.Expr) + } + + // Token: Op + out.Op = n.Op + + // Node: Y + if n.Y != nil { + child, err := f.decorateNode(n, "BinaryExpr", "Y", "Expr", n.Y) + if err != nil { + return nil, err + } + out.Y = child.(dst.Expr) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["X"]; ok { + out.Decs.X = decs + } + if decs, ok := nd["Op"]; ok { + out.Decs.Op = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.BlockStmt: + out := &dst.BlockStmt{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: Lbrace + + // List: List + for _, v := range n.List { + child, err := f.decorateNode(n, "BlockStmt", "List", "Stmt", v) + if err != nil { + return nil, err + } + out.List = append(out.List, child.(dst.Stmt)) + } + + // Token: Rbrace + if n.Rbrace == token.NoPos { + out.RbraceHasNoPos = true + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Lbrace"]; ok { + out.Decs.Lbrace = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.BranchStmt: + out := &dst.BranchStmt{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: Tok + out.Tok = n.Tok + + // Node: Label + if n.Label != nil { + child, err := f.decorateNode(n, "BranchStmt", "Label", "Ident", n.Label) + if err != nil { + return nil, err + } + out.Label = child.(*dst.Ident) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Tok"]; ok { + out.Decs.Tok = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.CallExpr: + out := &dst.CallExpr{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Node: Fun + if n.Fun != nil { + child, err := f.decorateNode(n, "CallExpr", "Fun", "Expr", n.Fun) + if err != nil { + return nil, err + } + out.Fun = child.(dst.Expr) + } + + // Token: Lparen + + // List: Args + for _, v := range n.Args { + child, err := f.decorateNode(n, "CallExpr", "Args", "Expr", v) + if err != nil { + return nil, err + } + out.Args = append(out.Args, child.(dst.Expr)) + } + + // Token: Ellipsis + out.Ellipsis = n.Ellipsis.IsValid() + + // Token: Rparen + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Fun"]; ok { + out.Decs.Fun = decs + } + if decs, ok := nd["Lparen"]; ok { + out.Decs.Lparen = decs + } + if decs, ok := nd["Ellipsis"]; ok { + out.Decs.Ellipsis = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.CaseClause: + out := &dst.CaseClause{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: Case + + // List: List + for _, v := range n.List { + child, err := f.decorateNode(n, "CaseClause", "List", "Expr", v) + if err != nil { + return nil, err + } + out.List = append(out.List, child.(dst.Expr)) + } + + // Token: Colon + + // List: Body + for _, v := range n.Body { + child, err := f.decorateNode(n, "CaseClause", "Body", "Stmt", v) + if err != nil { + return nil, err + } + out.Body = append(out.Body, child.(dst.Stmt)) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Case"]; ok { + out.Decs.Case = decs + } + if decs, ok := nd["Colon"]; ok { + out.Decs.Colon = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.ChanType: + out := &dst.ChanType{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: Begin + + // Token: Chan + + // Token: Arrow + + // Node: Value + if n.Value != nil { + child, err := f.decorateNode(n, "ChanType", "Value", "Expr", n.Value) + if err != nil { + return nil, err + } + out.Value = child.(dst.Expr) + } + + // Value: Dir + out.Dir = dst.ChanDir(n.Dir) + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Begin"]; ok { + out.Decs.Begin = decs + } + if decs, ok := nd["Arrow"]; ok { + out.Decs.Arrow = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.CommClause: + out := &dst.CommClause{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: Case + + // Node: Comm + if n.Comm != nil { + child, err := f.decorateNode(n, "CommClause", "Comm", "Stmt", n.Comm) + if err != nil { + return nil, err + } + out.Comm = child.(dst.Stmt) + } + + // Token: Colon + + // List: Body + for _, v := range n.Body { + child, err := f.decorateNode(n, "CommClause", "Body", "Stmt", v) + if err != nil { + return nil, err + } + out.Body = append(out.Body, child.(dst.Stmt)) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Case"]; ok { + out.Decs.Case = decs + } + if decs, ok := nd["Comm"]; ok { + out.Decs.Comm = decs + } + if decs, ok := nd["Colon"]; ok { + out.Decs.Colon = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.CompositeLit: + out := &dst.CompositeLit{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Node: Type + if n.Type != nil { + child, err := f.decorateNode(n, "CompositeLit", "Type", "Expr", n.Type) + if err != nil { + return nil, err + } + out.Type = child.(dst.Expr) + } + + // Token: Lbrace + + // List: Elts + for _, v := range n.Elts { + child, err := f.decorateNode(n, "CompositeLit", "Elts", "Expr", v) + if err != nil { + return nil, err + } + out.Elts = append(out.Elts, child.(dst.Expr)) + } + + // Token: Rbrace + + // Value: Incomplete + out.Incomplete = n.Incomplete + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Type"]; ok { + out.Decs.Type = decs + } + if decs, ok := nd["Lbrace"]; ok { + out.Decs.Lbrace = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.DeclStmt: + out := &dst.DeclStmt{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Node: Decl + if n.Decl != nil { + child, err := f.decorateNode(n, "DeclStmt", "Decl", "Decl", n.Decl) + if err != nil { + return nil, err + } + out.Decl = child.(dst.Decl) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.DeferStmt: + out := &dst.DeferStmt{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: Defer + + // Node: Call + if n.Call != nil { + child, err := f.decorateNode(n, "DeferStmt", "Call", "CallExpr", n.Call) + if err != nil { + return nil, err + } + out.Call = child.(*dst.CallExpr) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Defer"]; ok { + out.Decs.Defer = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.Ellipsis: + out := &dst.Ellipsis{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: Ellipsis + + // Node: Elt + if n.Elt != nil { + child, err := f.decorateNode(n, "Ellipsis", "Elt", "Expr", n.Elt) + if err != nil { + return nil, err + } + out.Elt = child.(dst.Expr) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Ellipsis"]; ok { + out.Decs.Ellipsis = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.EmptyStmt: + out := &dst.EmptyStmt{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: Semicolon + + // Value: Implicit + out.Implicit = n.Implicit + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.ExprStmt: + out := &dst.ExprStmt{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Node: X + if n.X != nil { + child, err := f.decorateNode(n, "ExprStmt", "X", "Expr", n.X) + if err != nil { + return nil, err + } + out.X = child.(dst.Expr) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.Field: + out := &dst.Field{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // List: Names + for _, v := range n.Names { + child, err := f.decorateNode(n, "Field", "Names", "Ident", v) + if err != nil { + return nil, err + } + out.Names = append(out.Names, child.(*dst.Ident)) + } + + // Node: Type + if n.Type != nil { + child, err := f.decorateNode(n, "Field", "Type", "Expr", n.Type) + if err != nil { + return nil, err + } + out.Type = child.(dst.Expr) + } + + // Node: Tag + if n.Tag != nil { + child, err := f.decorateNode(n, "Field", "Tag", "BasicLit", n.Tag) + if err != nil { + return nil, err + } + out.Tag = child.(*dst.BasicLit) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Type"]; ok { + out.Decs.Type = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.FieldList: + out := &dst.FieldList{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: Opening + out.Opening = n.Opening.IsValid() + + // List: List + for _, v := range n.List { + child, err := f.decorateNode(n, "FieldList", "List", "Field", v) + if err != nil { + return nil, err + } + out.List = append(out.List, child.(*dst.Field)) + } + + // Token: Closing + out.Closing = n.Closing.IsValid() + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Opening"]; ok { + out.Decs.Opening = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.File: + out := &dst.File{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: Package + + // Node: Name + if n.Name != nil { + child, err := f.decorateNode(n, "File", "Name", "Ident", n.Name) + if err != nil { + return nil, err + } + out.Name = child.(*dst.Ident) + } + + // List: Decls + for _, v := range n.Decls { + child, err := f.decorateNode(n, "File", "Decls", "Decl", v) + if err != nil { + return nil, err + } + out.Decls = append(out.Decls, child.(dst.Decl)) + } + + // Scope: Scope + scope, err := f.decorateScope(n.Scope) + if err != nil { + return nil, err + } + out.Scope = scope + + // List: Imports + for _, v := range n.Imports { + child, err := f.decorateNode(n, "File", "Imports", "ImportSpec", v) + if err != nil { + return nil, err + } + out.Imports = append(out.Imports, child.(*dst.ImportSpec)) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Package"]; ok { + out.Decs.Package = decs + } + if decs, ok := nd["Name"]; ok { + out.Decs.Name = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.ForStmt: + out := &dst.ForStmt{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: For + + // Node: Init + if n.Init != nil { + child, err := f.decorateNode(n, "ForStmt", "Init", "Stmt", n.Init) + if err != nil { + return nil, err + } + out.Init = child.(dst.Stmt) + } + + // Token: InitSemicolon + + // Node: Cond + if n.Cond != nil { + child, err := f.decorateNode(n, "ForStmt", "Cond", "Expr", n.Cond) + if err != nil { + return nil, err + } + out.Cond = child.(dst.Expr) + } + + // Token: CondSemicolon + + // Node: Post + if n.Post != nil { + child, err := f.decorateNode(n, "ForStmt", "Post", "Stmt", n.Post) + if err != nil { + return nil, err + } + out.Post = child.(dst.Stmt) + } + + // Node: Body + if n.Body != nil { + child, err := f.decorateNode(n, "ForStmt", "Body", "BlockStmt", n.Body) + if err != nil { + return nil, err + } + out.Body = child.(*dst.BlockStmt) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["For"]; ok { + out.Decs.For = decs + } + if decs, ok := nd["Init"]; ok { + out.Decs.Init = decs + } + if decs, ok := nd["Cond"]; ok { + out.Decs.Cond = decs + } + if decs, ok := nd["Post"]; ok { + out.Decs.Post = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.FuncDecl: + out := &dst.FuncDecl{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Init: Type + out.Type = &dst.FuncType{} + f.Dst.Nodes[n.Type] = out.Type + f.Ast.Nodes[out.Type] = n.Type + + // Token: Func + out.Type.Func = true + + // Node: Recv + if n.Recv != nil { + child, err := f.decorateNode(n, "FuncDecl", "Recv", "FieldList", n.Recv) + if err != nil { + return nil, err + } + out.Recv = child.(*dst.FieldList) + } + + // Node: Name + if n.Name != nil { + child, err := f.decorateNode(n, "FuncDecl", "Name", "Ident", n.Name) + if err != nil { + return nil, err + } + out.Name = child.(*dst.Ident) + } + + // Node: TypeParams + if n.Type.TypeParams != nil { + child, err := f.decorateNode(n, "FuncDecl", "TypeParams", "FieldList", n.Type.TypeParams) + if err != nil { + return nil, err + } + out.Type.TypeParams = child.(*dst.FieldList) + } + + // Node: Params + if n.Type.Params != nil { + child, err := f.decorateNode(n, "FuncDecl", "Params", "FieldList", n.Type.Params) + if err != nil { + return nil, err + } + out.Type.Params = child.(*dst.FieldList) + } + + // Node: Results + if n.Type.Results != nil { + child, err := f.decorateNode(n, "FuncDecl", "Results", "FieldList", n.Type.Results) + if err != nil { + return nil, err + } + out.Type.Results = child.(*dst.FieldList) + } + + // Node: Body + if n.Body != nil { + child, err := f.decorateNode(n, "FuncDecl", "Body", "BlockStmt", n.Body) + if err != nil { + return nil, err + } + out.Body = child.(*dst.BlockStmt) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Func"]; ok { + out.Decs.Func = decs + } + if decs, ok := nd["Recv"]; ok { + out.Decs.Recv = decs + } + if decs, ok := nd["Name"]; ok { + out.Decs.Name = decs + } + if decs, ok := nd["TypeParams"]; ok { + out.Decs.TypeParams = decs + } + if decs, ok := nd["Params"]; ok { + out.Decs.Params = decs + } + if decs, ok := nd["Results"]; ok { + out.Decs.Results = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.FuncLit: + out := &dst.FuncLit{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Node: Type + if n.Type != nil { + child, err := f.decorateNode(n, "FuncLit", "Type", "FuncType", n.Type) + if err != nil { + return nil, err + } + out.Type = child.(*dst.FuncType) + } + + // Node: Body + if n.Body != nil { + child, err := f.decorateNode(n, "FuncLit", "Body", "BlockStmt", n.Body) + if err != nil { + return nil, err + } + out.Body = child.(*dst.BlockStmt) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Type"]; ok { + out.Decs.Type = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.FuncType: + out := &dst.FuncType{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: Func + out.Func = n.Func.IsValid() + + // Node: TypeParams + if n.TypeParams != nil { + child, err := f.decorateNode(n, "FuncType", "TypeParams", "FieldList", n.TypeParams) + if err != nil { + return nil, err + } + out.TypeParams = child.(*dst.FieldList) + } + + // Node: Params + if n.Params != nil { + child, err := f.decorateNode(n, "FuncType", "Params", "FieldList", n.Params) + if err != nil { + return nil, err + } + out.Params = child.(*dst.FieldList) + } + + // Node: Results + if n.Results != nil { + child, err := f.decorateNode(n, "FuncType", "Results", "FieldList", n.Results) + if err != nil { + return nil, err + } + out.Results = child.(*dst.FieldList) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Func"]; ok { + out.Decs.Func = decs + } + if decs, ok := nd["TypeParams"]; ok { + out.Decs.TypeParams = decs + } + if decs, ok := nd["Params"]; ok { + out.Decs.Params = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.GenDecl: + out := &dst.GenDecl{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: Tok + out.Tok = n.Tok + + // Token: Lparen + out.Lparen = n.Lparen.IsValid() + + // List: Specs + for _, v := range n.Specs { + child, err := f.decorateNode(n, "GenDecl", "Specs", "Spec", v) + if err != nil { + return nil, err + } + out.Specs = append(out.Specs, child.(dst.Spec)) + } + + // Token: Rparen + out.Rparen = n.Rparen.IsValid() + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Tok"]; ok { + out.Decs.Tok = decs + } + if decs, ok := nd["Lparen"]; ok { + out.Decs.Lparen = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.GoStmt: + out := &dst.GoStmt{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: Go + + // Node: Call + if n.Call != nil { + child, err := f.decorateNode(n, "GoStmt", "Call", "CallExpr", n.Call) + if err != nil { + return nil, err + } + out.Call = child.(*dst.CallExpr) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Go"]; ok { + out.Decs.Go = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.Ident: + out := &dst.Ident{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // String: Name + out.Name = n.Name + + // Object: Obj + ob, err := f.decorateObject(n.Obj) + if err != nil { + return nil, err + } + out.Obj = ob + + // Path: Path + if f.Resolver != nil { + path, err := f.resolvePath(false, parent, parentName, parentField, parentFieldType, n) + if err != nil { + return nil, err + } + out.Path = path + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["X"]; ok { + out.Decs.X = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.IfStmt: + out := &dst.IfStmt{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: If + + // Node: Init + if n.Init != nil { + child, err := f.decorateNode(n, "IfStmt", "Init", "Stmt", n.Init) + if err != nil { + return nil, err + } + out.Init = child.(dst.Stmt) + } + + // Node: Cond + if n.Cond != nil { + child, err := f.decorateNode(n, "IfStmt", "Cond", "Expr", n.Cond) + if err != nil { + return nil, err + } + out.Cond = child.(dst.Expr) + } + + // Node: Body + if n.Body != nil { + child, err := f.decorateNode(n, "IfStmt", "Body", "BlockStmt", n.Body) + if err != nil { + return nil, err + } + out.Body = child.(*dst.BlockStmt) + } + + // Token: ElseTok + + // Node: Else + if n.Else != nil { + child, err := f.decorateNode(n, "IfStmt", "Else", "Stmt", n.Else) + if err != nil { + return nil, err + } + out.Else = child.(dst.Stmt) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["If"]; ok { + out.Decs.If = decs + } + if decs, ok := nd["Init"]; ok { + out.Decs.Init = decs + } + if decs, ok := nd["Cond"]; ok { + out.Decs.Cond = decs + } + if decs, ok := nd["Else"]; ok { + out.Decs.Else = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.ImportSpec: + out := &dst.ImportSpec{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Node: Name + if n.Name != nil { + child, err := f.decorateNode(n, "ImportSpec", "Name", "Ident", n.Name) + if err != nil { + return nil, err + } + out.Name = child.(*dst.Ident) + } + + // Node: Path + if n.Path != nil { + child, err := f.decorateNode(n, "ImportSpec", "Path", "BasicLit", n.Path) + if err != nil { + return nil, err + } + out.Path = child.(*dst.BasicLit) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Name"]; ok { + out.Decs.Name = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.IncDecStmt: + out := &dst.IncDecStmt{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Node: X + if n.X != nil { + child, err := f.decorateNode(n, "IncDecStmt", "X", "Expr", n.X) + if err != nil { + return nil, err + } + out.X = child.(dst.Expr) + } + + // Token: Tok + out.Tok = n.Tok + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["X"]; ok { + out.Decs.X = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.IndexExpr: + out := &dst.IndexExpr{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Node: X + if n.X != nil { + child, err := f.decorateNode(n, "IndexExpr", "X", "Expr", n.X) + if err != nil { + return nil, err + } + out.X = child.(dst.Expr) + } + + // Token: Lbrack + + // Node: Index + if n.Index != nil { + child, err := f.decorateNode(n, "IndexExpr", "Index", "Expr", n.Index) + if err != nil { + return nil, err + } + out.Index = child.(dst.Expr) + } + + // Token: Rbrack + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["X"]; ok { + out.Decs.X = decs + } + if decs, ok := nd["Lbrack"]; ok { + out.Decs.Lbrack = decs + } + if decs, ok := nd["Index"]; ok { + out.Decs.Index = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.IndexListExpr: + out := &dst.IndexListExpr{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Node: X + if n.X != nil { + child, err := f.decorateNode(n, "IndexListExpr", "X", "Expr", n.X) + if err != nil { + return nil, err + } + out.X = child.(dst.Expr) + } + + // Token: Lbrack + + // List: Indices + for _, v := range n.Indices { + child, err := f.decorateNode(n, "IndexListExpr", "Indices", "Expr", v) + if err != nil { + return nil, err + } + out.Indices = append(out.Indices, child.(dst.Expr)) + } + + // Token: Rbrack + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["X"]; ok { + out.Decs.X = decs + } + if decs, ok := nd["Lbrack"]; ok { + out.Decs.Lbrack = decs + } + if decs, ok := nd["Indices"]; ok { + out.Decs.Indices = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.InterfaceType: + out := &dst.InterfaceType{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: Interface + + // Node: Methods + if n.Methods != nil { + child, err := f.decorateNode(n, "InterfaceType", "Methods", "FieldList", n.Methods) + if err != nil { + return nil, err + } + out.Methods = child.(*dst.FieldList) + } + + // Value: Incomplete + out.Incomplete = n.Incomplete + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Interface"]; ok { + out.Decs.Interface = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.KeyValueExpr: + out := &dst.KeyValueExpr{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Node: Key + if n.Key != nil { + child, err := f.decorateNode(n, "KeyValueExpr", "Key", "Expr", n.Key) + if err != nil { + return nil, err + } + out.Key = child.(dst.Expr) + } + + // Token: Colon + + // Node: Value + if n.Value != nil { + child, err := f.decorateNode(n, "KeyValueExpr", "Value", "Expr", n.Value) + if err != nil { + return nil, err + } + out.Value = child.(dst.Expr) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Key"]; ok { + out.Decs.Key = decs + } + if decs, ok := nd["Colon"]; ok { + out.Decs.Colon = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.LabeledStmt: + out := &dst.LabeledStmt{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Node: Label + if n.Label != nil { + child, err := f.decorateNode(n, "LabeledStmt", "Label", "Ident", n.Label) + if err != nil { + return nil, err + } + out.Label = child.(*dst.Ident) + } + + // Token: Colon + + // Node: Stmt + if n.Stmt != nil { + child, err := f.decorateNode(n, "LabeledStmt", "Stmt", "Stmt", n.Stmt) + if err != nil { + return nil, err + } + out.Stmt = child.(dst.Stmt) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Label"]; ok { + out.Decs.Label = decs + } + if decs, ok := nd["Colon"]; ok { + out.Decs.Colon = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.MapType: + out := &dst.MapType{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: Map + + // Token: Lbrack + + // Node: Key + if n.Key != nil { + child, err := f.decorateNode(n, "MapType", "Key", "Expr", n.Key) + if err != nil { + return nil, err + } + out.Key = child.(dst.Expr) + } + + // Token: Rbrack + + // Node: Value + if n.Value != nil { + child, err := f.decorateNode(n, "MapType", "Value", "Expr", n.Value) + if err != nil { + return nil, err + } + out.Value = child.(dst.Expr) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Map"]; ok { + out.Decs.Map = decs + } + if decs, ok := nd["Key"]; ok { + out.Decs.Key = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.Package: + out := &dst.Package{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + // Value: Name + out.Name = n.Name + + // Scope: Scope + scope, err := f.decorateScope(n.Scope) + if err != nil { + return nil, err + } + out.Scope = scope + + // Map: Imports + out.Imports = map[string]*dst.Object{} + for k, v := range n.Imports { + ob, err := f.decorateObject(v) + if err != nil { + return nil, err + } + out.Imports[k] = ob + } + + // Map: Files + out.Files = map[string]*dst.File{} + for k, v := range n.Files { + child, err := f.decorateNode(n, "Package", "Files", "File", v) + if err != nil { + return nil, err + } + out.Files[k] = child.(*dst.File) + } + + return out, nil + case *ast.ParenExpr: + out := &dst.ParenExpr{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: Lparen + + // Node: X + if n.X != nil { + child, err := f.decorateNode(n, "ParenExpr", "X", "Expr", n.X) + if err != nil { + return nil, err + } + out.X = child.(dst.Expr) + } + + // Token: Rparen + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Lparen"]; ok { + out.Decs.Lparen = decs + } + if decs, ok := nd["X"]; ok { + out.Decs.X = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.RangeStmt: + out := &dst.RangeStmt{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: For + + // Node: Key + if n.Key != nil { + child, err := f.decorateNode(n, "RangeStmt", "Key", "Expr", n.Key) + if err != nil { + return nil, err + } + out.Key = child.(dst.Expr) + } + + // Token: Comma + + // Node: Value + if n.Value != nil { + child, err := f.decorateNode(n, "RangeStmt", "Value", "Expr", n.Value) + if err != nil { + return nil, err + } + out.Value = child.(dst.Expr) + } + + // Token: Tok + out.Tok = n.Tok + + // Token: Range + + // Node: X + if n.X != nil { + child, err := f.decorateNode(n, "RangeStmt", "X", "Expr", n.X) + if err != nil { + return nil, err + } + out.X = child.(dst.Expr) + } + + // Node: Body + if n.Body != nil { + child, err := f.decorateNode(n, "RangeStmt", "Body", "BlockStmt", n.Body) + if err != nil { + return nil, err + } + out.Body = child.(*dst.BlockStmt) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["For"]; ok { + out.Decs.For = decs + } + if decs, ok := nd["Key"]; ok { + out.Decs.Key = decs + } + if decs, ok := nd["Value"]; ok { + out.Decs.Value = decs + } + if decs, ok := nd["Range"]; ok { + out.Decs.Range = decs + } + if decs, ok := nd["X"]; ok { + out.Decs.X = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.ReturnStmt: + out := &dst.ReturnStmt{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: Return + + // List: Results + for _, v := range n.Results { + child, err := f.decorateNode(n, "ReturnStmt", "Results", "Expr", v) + if err != nil { + return nil, err + } + out.Results = append(out.Results, child.(dst.Expr)) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Return"]; ok { + out.Decs.Return = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.SelectStmt: + out := &dst.SelectStmt{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: Select + + // Node: Body + if n.Body != nil { + child, err := f.decorateNode(n, "SelectStmt", "Body", "BlockStmt", n.Body) + if err != nil { + return nil, err + } + out.Body = child.(*dst.BlockStmt) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Select"]; ok { + out.Decs.Select = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.SelectorExpr: + + // Special case for *ast.SelectorExpr - replace with Ident if needed + id, err := f.decorateSelectorExpr(parent, parentName, parentField, parentFieldType, n) + if err != nil { + return nil, err + } + if id != nil { + return id, nil + } + + out := &dst.SelectorExpr{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Node: X + if n.X != nil { + child, err := f.decorateNode(n, "SelectorExpr", "X", "Expr", n.X) + if err != nil { + return nil, err + } + out.X = child.(dst.Expr) + } + + // Token: Period + + // Node: Sel + if n.Sel != nil { + child, err := f.decorateNode(n, "SelectorExpr", "Sel", "Ident", n.Sel) + if err != nil { + return nil, err + } + out.Sel = child.(*dst.Ident) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["X"]; ok { + out.Decs.X = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.SendStmt: + out := &dst.SendStmt{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Node: Chan + if n.Chan != nil { + child, err := f.decorateNode(n, "SendStmt", "Chan", "Expr", n.Chan) + if err != nil { + return nil, err + } + out.Chan = child.(dst.Expr) + } + + // Token: Arrow + + // Node: Value + if n.Value != nil { + child, err := f.decorateNode(n, "SendStmt", "Value", "Expr", n.Value) + if err != nil { + return nil, err + } + out.Value = child.(dst.Expr) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Chan"]; ok { + out.Decs.Chan = decs + } + if decs, ok := nd["Arrow"]; ok { + out.Decs.Arrow = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.SliceExpr: + out := &dst.SliceExpr{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Node: X + if n.X != nil { + child, err := f.decorateNode(n, "SliceExpr", "X", "Expr", n.X) + if err != nil { + return nil, err + } + out.X = child.(dst.Expr) + } + + // Token: Lbrack + + // Node: Low + if n.Low != nil { + child, err := f.decorateNode(n, "SliceExpr", "Low", "Expr", n.Low) + if err != nil { + return nil, err + } + out.Low = child.(dst.Expr) + } + + // Token: Colon1 + + // Node: High + if n.High != nil { + child, err := f.decorateNode(n, "SliceExpr", "High", "Expr", n.High) + if err != nil { + return nil, err + } + out.High = child.(dst.Expr) + } + + // Token: Colon2 + + // Node: Max + if n.Max != nil { + child, err := f.decorateNode(n, "SliceExpr", "Max", "Expr", n.Max) + if err != nil { + return nil, err + } + out.Max = child.(dst.Expr) + } + + // Token: Rbrack + + // Value: Slice3 + out.Slice3 = n.Slice3 + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["X"]; ok { + out.Decs.X = decs + } + if decs, ok := nd["Lbrack"]; ok { + out.Decs.Lbrack = decs + } + if decs, ok := nd["Low"]; ok { + out.Decs.Low = decs + } + if decs, ok := nd["High"]; ok { + out.Decs.High = decs + } + if decs, ok := nd["Max"]; ok { + out.Decs.Max = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.StarExpr: + out := &dst.StarExpr{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: Star + + // Node: X + if n.X != nil { + child, err := f.decorateNode(n, "StarExpr", "X", "Expr", n.X) + if err != nil { + return nil, err + } + out.X = child.(dst.Expr) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Star"]; ok { + out.Decs.Star = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.StructType: + out := &dst.StructType{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: Struct + + // Node: Fields + if n.Fields != nil { + child, err := f.decorateNode(n, "StructType", "Fields", "FieldList", n.Fields) + if err != nil { + return nil, err + } + out.Fields = child.(*dst.FieldList) + } + + // Value: Incomplete + out.Incomplete = n.Incomplete + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Struct"]; ok { + out.Decs.Struct = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.SwitchStmt: + out := &dst.SwitchStmt{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: Switch + + // Node: Init + if n.Init != nil { + child, err := f.decorateNode(n, "SwitchStmt", "Init", "Stmt", n.Init) + if err != nil { + return nil, err + } + out.Init = child.(dst.Stmt) + } + + // Node: Tag + if n.Tag != nil { + child, err := f.decorateNode(n, "SwitchStmt", "Tag", "Expr", n.Tag) + if err != nil { + return nil, err + } + out.Tag = child.(dst.Expr) + } + + // Node: Body + if n.Body != nil { + child, err := f.decorateNode(n, "SwitchStmt", "Body", "BlockStmt", n.Body) + if err != nil { + return nil, err + } + out.Body = child.(*dst.BlockStmt) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Switch"]; ok { + out.Decs.Switch = decs + } + if decs, ok := nd["Init"]; ok { + out.Decs.Init = decs + } + if decs, ok := nd["Tag"]; ok { + out.Decs.Tag = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.TypeAssertExpr: + out := &dst.TypeAssertExpr{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Node: X + if n.X != nil { + child, err := f.decorateNode(n, "TypeAssertExpr", "X", "Expr", n.X) + if err != nil { + return nil, err + } + out.X = child.(dst.Expr) + } + + // Token: Period + + // Token: Lparen + + // Node: Type + if n.Type != nil { + child, err := f.decorateNode(n, "TypeAssertExpr", "Type", "Expr", n.Type) + if err != nil { + return nil, err + } + out.Type = child.(dst.Expr) + } + + // Token: TypeToken + + // Token: Rparen + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["X"]; ok { + out.Decs.X = decs + } + if decs, ok := nd["Lparen"]; ok { + out.Decs.Lparen = decs + } + if decs, ok := nd["Type"]; ok { + out.Decs.Type = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.TypeSpec: + out := &dst.TypeSpec{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Node: Name + if n.Name != nil { + child, err := f.decorateNode(n, "TypeSpec", "Name", "Ident", n.Name) + if err != nil { + return nil, err + } + out.Name = child.(*dst.Ident) + } + + // Token: Assign + out.Assign = n.Assign.IsValid() + + // Node: TypeParams + if n.TypeParams != nil { + child, err := f.decorateNode(n, "TypeSpec", "TypeParams", "FieldList", n.TypeParams) + if err != nil { + return nil, err + } + out.TypeParams = child.(*dst.FieldList) + } + + // Node: Type + if n.Type != nil { + child, err := f.decorateNode(n, "TypeSpec", "Type", "Expr", n.Type) + if err != nil { + return nil, err + } + out.Type = child.(dst.Expr) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Name"]; ok { + out.Decs.Name = decs + } + if decs, ok := nd["TypeParams"]; ok { + out.Decs.TypeParams = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.TypeSwitchStmt: + out := &dst.TypeSwitchStmt{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: Switch + + // Node: Init + if n.Init != nil { + child, err := f.decorateNode(n, "TypeSwitchStmt", "Init", "Stmt", n.Init) + if err != nil { + return nil, err + } + out.Init = child.(dst.Stmt) + } + + // Node: Assign + if n.Assign != nil { + child, err := f.decorateNode(n, "TypeSwitchStmt", "Assign", "Stmt", n.Assign) + if err != nil { + return nil, err + } + out.Assign = child.(dst.Stmt) + } + + // Node: Body + if n.Body != nil { + child, err := f.decorateNode(n, "TypeSwitchStmt", "Body", "BlockStmt", n.Body) + if err != nil { + return nil, err + } + out.Body = child.(*dst.BlockStmt) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Switch"]; ok { + out.Decs.Switch = decs + } + if decs, ok := nd["Init"]; ok { + out.Decs.Init = decs + } + if decs, ok := nd["Assign"]; ok { + out.Decs.Assign = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.UnaryExpr: + out := &dst.UnaryExpr{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // Token: Op + out.Op = n.Op + + // Node: X + if n.X != nil { + child, err := f.decorateNode(n, "UnaryExpr", "X", "Expr", n.X) + if err != nil { + return nil, err + } + out.X = child.(dst.Expr) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Op"]; ok { + out.Decs.Op = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + case *ast.ValueSpec: + out := &dst.ValueSpec{} + f.Dst.Nodes[n] = out + f.Ast.Nodes[out] = n + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + // List: Names + for _, v := range n.Names { + child, err := f.decorateNode(n, "ValueSpec", "Names", "Ident", v) + if err != nil { + return nil, err + } + out.Names = append(out.Names, child.(*dst.Ident)) + } + + // Node: Type + if n.Type != nil { + child, err := f.decorateNode(n, "ValueSpec", "Type", "Expr", n.Type) + if err != nil { + return nil, err + } + out.Type = child.(dst.Expr) + } + + // Token: Assign + + // List: Values + for _, v := range n.Values { + child, err := f.decorateNode(n, "ValueSpec", "Values", "Expr", v) + if err != nil { + return nil, err + } + out.Values = append(out.Values, child.(dst.Expr)) + } + + if nd, ok := f.decorations[n]; ok { + if decs, ok := nd["Start"]; ok { + out.Decs.Start = decs + } + if decs, ok := nd["Assign"]; ok { + out.Decs.Assign = decs + } + if decs, ok := nd["End"]; ok { + out.Decs.End = decs + } + } + + return out, nil + } + return nil, nil +} diff --git a/vendor/github.com/dave/dst/decorator/decorator.go b/vendor/github.com/dave/dst/decorator/decorator.go new file mode 100644 index 000000000..dc9eaef7b --- /dev/null +++ b/vendor/github.com/dave/dst/decorator/decorator.go @@ -0,0 +1,560 @@ +package decorator + +import ( + "fmt" + "go/ast" + "go/parser" + "go/token" + "io" + "os" + "strings" + + "github.com/dave/dst" + "github.com/dave/dst/decorator/resolver" + "github.com/dave/dst/decorator/resolver/gotypes" + "github.com/dave/dst/dstutil" + "golang.org/x/tools/go/packages" +) + +// NewDecorator returns a new decorator. If fset is nil, a new FileSet is created. +func NewDecorator(fset *token.FileSet) *Decorator { + if fset == nil { + fset = token.NewFileSet() + } + return &Decorator{ + Map: newMap(), + Filenames: map[*dst.File]string{}, + Fset: fset, + } +} + +// NewDecoratorWithImports returns a new decorator with import management enabled. +func NewDecoratorWithImports(fset *token.FileSet, path string, resolver resolver.DecoratorResolver) *Decorator { + dec := NewDecorator(fset) + dec.Path = path + dec.Resolver = resolver + return dec +} + +// NewDecoratorFromPackage returns a new decorator configured to decorate files in pkg. +func NewDecoratorFromPackage(pkg *packages.Package) *Decorator { + return NewDecoratorWithImports(pkg.Fset, pkg.PkgPath, gotypes.New(pkg.TypesInfo.Uses)) +} + +// Decorator converts ast nodes into dst nodes, and converts decoration info from the ast fileset +// to the dst nodes. Create a new Decorator for each package you need to decorate. +type Decorator struct { + Map // Mapping between ast and dst Nodes, Objects and Scopes + Filenames map[*dst.File]string // Source file names + Fset *token.FileSet // The ast FileSet containing ast decoration info for the files + + // If a Resolver is provided, it is used to resolve remote identifiers from *ast.Ident and + // *ast.SelectorExpr nodes. Usually a remote identifier is a SelectorExpr qualified identifier, + // but in the case of dot-imports they can be simply Ident nodes. During decoration, remote + // identifiers are replaced with *dst.Ident with Path set to the path of imported package. + Resolver resolver.DecoratorResolver + // Local package path - required if Resolver is set. + Path string + // By default local idents are left with an empty Path, so they stay local if the local package + // is renamed. Setting ResolveLocalPath to true prevents this, so all idents will have the + // package path added. + ResolveLocalPath bool +} + +// Parse uses parser.ParseFile to parse and decorate a Go source file. The src parameter should +// be string, []byte, or io.Reader. +func (d *Decorator) Parse(src interface{}) (*dst.File, error) { + return d.ParseFile("", src, parser.ParseComments) +} + +// ParseFile uses parser.ParseFile to parse and decorate a Go source file. The ParseComments flag +// is added to mode if it doesn't exist. +func (d *Decorator) ParseFile(filename string, src interface{}, mode parser.Mode) (*dst.File, error) { + + // If ParseFile returns an error and also a non-nil file, the errors were just parse errors so + // we should continue decorating the file and return the error. + f, perr := parser.ParseFile(d.Fset, filename, src, mode|parser.ParseComments) + if perr != nil && f == nil { + return nil, perr + } + + file, err := d.DecorateFile(f) + if err != nil { + return nil, err + } + + return file, perr +} + +// ParseDir uses parser.ParseDir to parse and decorate a directory containing Go source. The +// ParseComments flag is added to mode if it doesn't exist. +func (d *Decorator) ParseDir(dir string, filter func(os.FileInfo) bool, mode parser.Mode) (map[string]*dst.Package, error) { + pkgs, err := parser.ParseDir(d.Fset, dir, filter, mode|parser.ParseComments) + if err != nil { + return nil, err + } + out := map[string]*dst.Package{} + for k, v := range pkgs { + pkg, err := d.DecorateNode(v) + if err != nil { + return nil, err + } + out[k] = pkg.(*dst.Package) + } + return out, nil +} + +// DecorateFile decorates *ast.File and returns *dst.File +func (d *Decorator) DecorateFile(f *ast.File) (*dst.File, error) { + file, err := d.DecorateNode(f) + if err != nil { + return nil, err + } + return file.(*dst.File), nil +} + +// DecorateNode decorates ast.Node and returns dst.Node +func (d *Decorator) DecorateNode(n ast.Node) (dst.Node, error) { + + if d.Resolver == nil && d.Path != "" { + panic("Decorator Path should be empty when Resolver is nil") + } + + if d.Resolver != nil && d.Path == "" { + panic("Decorator Path should be set when Resolver is set") + } + + fd := d.newFileDecorator() + if f, ok := n.(*ast.File); ok { + fd.file = f + } + fd.fragment(n) + fd.link() + + out, err := fd.decorateNode(nil, "", "", "", n) + if err != nil { + return nil, err + } + + //fmt.Println("\nFragments:") + //fd.debug(os.Stdout) + + //fmt.Println("\nDecorator:") + //debug(os.Stdout, out) + + // Populate Info with filenames if we're decorating a File or Package. + switch n := n.(type) { + case *ast.Package: + for k, v := range n.Files { + d.Filenames[d.Dst.Nodes[v].(*dst.File)] = k + } + case *ast.File: + d.Filenames[out.(*dst.File)] = d.Fset.File(n.Pos()).Name() + } + + return out, nil +} + +func (pd *Decorator) newFileDecorator() *fileDecorator { + return &fileDecorator{ + Decorator: pd, + startIndents: map[ast.Node]int{}, + endIndents: map[ast.Node]int{}, + before: map[ast.Node]dst.SpaceType{}, + after: map[ast.Node]dst.SpaceType{}, + decorations: map[ast.Node]map[string][]string{}, + } +} + +type fileDecorator struct { + *Decorator + file *ast.File // file we're decorating in for import name resolution - can be nil if we're just decorating an isolated node + cursor int + fragments []fragment + startIndents map[ast.Node]int + endIndents map[ast.Node]int + before, after map[ast.Node]dst.SpaceType + decorations map[ast.Node]map[string][]string +} + +// We never need to resolve idents that are in these fields (decorateSelectorExpr will override +// this check with the force parameter for SelectorExpr.Sel when needed). +var avoid = map[string]bool{ + "Field.Names": true, + "LabeledStmt.Label": true, + "BranchStmt.Label": true, + "ImportSpec.Name": true, + "ValueSpec.Names": true, + "TypeSpec.Name": true, + "FuncDecl.Name": true, + "File.Name": true, + "SelectorExpr.Sel": true, +} + +// decorateSelectorExpr is a special case for decorating a SelectorExpr, which might return an +// Ident if the resolver determines that the SelectorExpr represents a qualified ident. +func (f *fileDecorator) decorateSelectorExpr(parent ast.Node, parentName, parentField, parentFieldType string, n *ast.SelectorExpr) (dst.Node, error) { + + if f.Resolver == nil { + // continue to default logic in decorateNode + return nil, nil + } + + // resolve the path with force == true, so we skip the tests that would normally prevent the + // Sel field of SelectorExpr from being resolved. + path, err := f.resolvePath(true, n, "SelectorExpr", "Sel", "Ident", n.Sel) + if err != nil { + return nil, err + } + + if path == "" { + // path == "" -> not a qualified ident -> continue to default logic in decorateNode + return nil, nil + } + + // replace *ast.SelectorExpr with *dst.Ident and merge decorations + out := &dst.Ident{} + f.Dst.Nodes[n] = out + f.Dst.Nodes[n.X] = out + f.Dst.Nodes[n.Sel] = out + f.Ast.Nodes[out] = n + + // String: Name + out.Name = n.Sel.Name + + // Object: Obj + ob, err := f.decorateObject(n.Sel.Obj) + if err != nil { + return nil, err + } + out.Obj = ob + + // Path: Path + out.Path = path + + /* + We must merge the SelectorExpr decorations into an Ident. The Ident has an X decoration + attachment point, but we don't have a simple place to store the decorations and line + spacing from the X / Sel child nodes. This is rather an edge case, but we can fix it by + merging the line-spacing with decorations (line spacing becomes "\n" decorations) and + adding these to the Ident decorations. This will mean that decorated / restored code with + no mutations should be byte-perfect, which is essential. + + Here's a list of the decorations / line spacings we're merging: + + {1}{2}{3}{4}[ X ].{5}{6}{7}{8}{9}[ Sel ]{10}{11}{12}{13} + + 1: SelectorExpr Before Space - f.before[n] + + 2: SelectorExpr Start Decoration - f.decorations[n]["Start"] + 3: X Before Space - f.before[n.X] + 4: X Start Decoration - f.decorations[n.X]["Start"] + + 5: X End Decoration - f.decorations[n.X]["End"] + 6: X After Space - f.after[n.X] + 7: SelectorExpr X Decoration - f.decorations[n]["X"] + 8: Sel Before Space - f.before[n.Sel] + 9: Sel Start Decoration - f.decorations[n.Sel]["Start"] + + 10: Sel End decoration - f.decorations[n.Sel]["End"] + 11: Sel After Space - f.after[n.Sel] + 12: SelectorExpr End Decoration - f.decorations[n]["End"] + + 13: SelectorExpr After Space - f.after[n] + + 1: set Ident.Before + 2-4: merge into Ident.Start + 5-9: merge into Ident.X + 10-12: merge into Ident.End + 13: set Ident.After + */ + + out.Decs.Before = f.before[n] + out.Decs.After = f.after[n] + + var nStart, xBefore, xStart, xEnd, xAfter, nX, sBefore, sStart, sEnd, sAfter, nEnd interface{} + + xBefore = f.before[n.X] + xAfter = f.after[n.X] + + sBefore = f.before[n.Sel] + sAfter = f.after[n.Sel] + + if decs, ok := f.decorations[n]; ok { + nStart = decs["Start"] + nX = decs["X"] + nEnd = decs["End"] + } + if decs, ok := f.decorations[n.X]; ok { + xStart = decs["Start"] + xEnd = decs["End"] + } + if decs, ok := f.decorations[n.Sel]; ok { + sStart = decs["Start"] + sEnd = decs["End"] + } + + if iStart := mergeDecorations(nStart, xBefore, xStart); len(iStart) > 0 { + out.Decs.Start.Append(iStart...) + } + + if iX := mergeDecorations(xEnd, xAfter, nX, sBefore, sStart); len(iX) > 0 { + out.Decs.X.Append(iX...) + } + + if iEnd := mergeDecorations(sEnd, sAfter, nEnd); len(iEnd) > 0 { + out.Decs.End.Append(iEnd...) + } + + return out, nil + +} + +func (f *fileDecorator) resolvePath(force bool, parent ast.Node, parentName, parentField, parentFieldType string, id *ast.Ident) (string, error) { + + if f.Resolver == nil { + panic("resolvePath needs a Resolver") + } + + if !force { + if avoid[parentName+"."+parentField] { + return "", nil + } + if parentFieldType != "Expr" { + panic(fmt.Sprintf("decorateIdent: unsupported parentName %s, parentField %s, parentFieldType %s", parentName, parentField, parentFieldType)) + } + } + + path, err := f.Resolver.ResolveIdent(f.file, parent, parentField, id) + if err != nil { + return "", err + } + + path = stripVendor(path) + + if !f.ResolveLocalPath && path == stripVendor(f.Path) { + return "", nil + } + + return path, nil +} + +func stripVendor(path string) string { + findVendor := func(path string) (index int, ok bool) { + // Two cases, depending on internal at start of string or not. + // The order matters: we must return the index of the final element, + // because the final one is where the effective import path starts. + switch { + case strings.Contains(path, "/vendor/"): + return strings.LastIndex(path, "/vendor/") + 1, true + case strings.HasPrefix(path, "vendor/"): + return 0, true + } + return 0, false + } + i, ok := findVendor(path) + if !ok { + return path + } + return path[i+len("vendor/"):] +} + +func (f *fileDecorator) decorateObject(o *ast.Object) (*dst.Object, error) { + + if o == nil { + return nil, nil + } + + if do, ok := f.Dst.Objects[o]; ok { + return do, nil + } + + /* + // An Object describes a named language entity such as a package, + // constant, type, variable, function (incl. methods), or label. + // + // The Data fields contains object-specific data: + // + // Kind Data type Data value + // Pkg *Scope package scope + // Con int iota for the respective declaration + // + type Object struct { + Kind ObjKind + Name string // declared name + Decl interface{} // corresponding Field, XxxSpec, FuncDecl, LabeledStmt, AssignStmt, Scope; or nil + Data interface{} // object-specific data; or nil + Type interface{} // placeholder for type information; may be nil + } + */ + + out := &dst.Object{} + f.Dst.Objects[o] = out + f.Ast.Objects[out] = o + out.Kind = dst.ObjKind(o.Kind) + out.Name = o.Name + + switch decl := o.Decl.(type) { + case *ast.Scope: + s, err := f.decorateScope(decl) + if err != nil { + return nil, err + } + out.Decl = s + case ast.Node: + n, err := f.decorateNode(nil, "", "", "", decl) + if err != nil { + return nil, err + } + out.Decl = n + case nil: + default: + panic(fmt.Sprintf("o.Decl is %T", o.Data)) + } + + switch data := o.Data.(type) { + case int: + out.Data = data + case *ast.Scope: + s, err := f.decorateScope(data) + if err != nil { + return nil, err + } + out.Data = s + case ast.Node: + n, err := f.decorateNode(nil, "", "", "", data) + if err != nil { + return nil, err + } + out.Data = n + case nil: + default: + panic(fmt.Sprintf("o.Data is %T", o.Data)) + } + + return out, nil +} + +func (f *fileDecorator) decorateScope(s *ast.Scope) (*dst.Scope, error) { + + if s == nil { + return nil, nil + } + + if ds, ok := f.Dst.Scopes[s]; ok { + return ds, nil + } + + /* + // A Scope maintains the set of named language entities declared + // in the scope and a link to the immediately surrounding (outer) + // scope. + // + type Scope struct { + Outer *Scope + Objects map[string]*Object + } + */ + + out := &dst.Scope{} + f.Dst.Scopes[s] = out + f.Ast.Scopes[out] = s + + outer, err := f.decorateScope(s.Outer) + if err != nil { + return nil, err + } + out.Outer = outer + out.Objects = map[string]*dst.Object{} + + for k, v := range s.Objects { + ob, err := f.decorateObject(v) + if err != nil { + return nil, err + } + out.Objects[k] = ob + } + + return out, nil +} + +func debug(w io.Writer, file dst.Node) { + var result string + nodeType := func(n dst.Node) string { + return strings.Replace(fmt.Sprintf("%T", n), "*dst.", "", -1) + } + dst.Inspect(file, func(n dst.Node) bool { + if n == nil { + return false + } + var out string + before, after, points := dstutil.Decorations(n) + switch before { + case dst.NewLine: + out += " [New line before]" + case dst.EmptyLine: + out += " [Empty line before]" + } + for _, point := range points { + if len(point.Decs) > 0 { + var values string + for i, dec := range point.Decs { + if i > 0 { + values += " " + } + values += fmt.Sprintf("%q", dec) + } + out += fmt.Sprintf(" [%s %s]", point.Name, values) + } + } + switch after { + case dst.NewLine: + out += " [New line after]" + case dst.EmptyLine: + out += " [Empty line after]" + } + if out != "" { + result += nodeType(n) + out + "\n" + } + return true + }) + fmt.Fprint(w, result) +} + +// mergeDecorations merges several decoration lists and line spaces into a single decoration list +func mergeDecorations(decorationsOrLineSpace ...interface{}) []string { + var endsWithNewLine bool + var out []string + for _, v := range decorationsOrLineSpace { + switch v := v.(type) { + case nil: + // nothing + case []string: + if len(v) == 0 { + continue + } + out = append(out, v...) + endsWithNewLine = v[len(v)-1] == "\n" || strings.HasPrefix(v[len(v)-1], "//") + case dst.SpaceType: + switch v { + case dst.NewLine: + if endsWithNewLine { + // nothing to do + } else { + out = append(out, "\n") + } + endsWithNewLine = true + case dst.EmptyLine: + if endsWithNewLine { + out = append(out, "\n") + } else { + out = append(out, "\n", "\n") + } + endsWithNewLine = true + } + default: + panic(fmt.Sprintf("%T", v)) + } + } + return out +} diff --git a/vendor/github.com/dave/dst/decorator/helpers.go b/vendor/github.com/dave/dst/decorator/helpers.go new file mode 100644 index 000000000..679b6e701 --- /dev/null +++ b/vendor/github.com/dave/dst/decorator/helpers.go @@ -0,0 +1,64 @@ +package decorator + +import ( + "go/ast" + "go/format" + "go/parser" + "go/token" + "io" + "os" + + "github.com/dave/dst" +) + +// Parse uses parser.ParseFile to parse and decorate a Go source file. The src parameter should +// be string, []byte, or io.Reader. +func Parse(src interface{}) (*dst.File, error) { + return NewDecorator(token.NewFileSet()).Parse(src) +} + +// ParseFile uses parser.ParseFile to parse and decorate a Go source file. The ParseComments flag is +// added to mode if it doesn't exist. +func ParseFile(fset *token.FileSet, filename string, src interface{}, mode parser.Mode) (*dst.File, error) { + return NewDecorator(fset).ParseFile(filename, src, mode) +} + +// ParseDir uses parser.ParseDir to parse and decorate a directory containing Go source. The +// ParseComments flag is added to mode if it doesn't exist. +func ParseDir(fset *token.FileSet, dir string, filter func(os.FileInfo) bool, mode parser.Mode) (map[string]*dst.Package, error) { + return NewDecorator(fset).ParseDir(dir, filter, mode) +} + +// Decorate decorates an ast.Node and returns a dst.Node. +func Decorate(fset *token.FileSet, n ast.Node) (dst.Node, error) { + return NewDecorator(fset).DecorateNode(n) +} + +// Decorate decorates a *ast.File and returns a *dst.File. +func DecorateFile(fset *token.FileSet, f *ast.File) (*dst.File, error) { + return NewDecorator(fset).DecorateFile(f) +} + +// Print uses format.Node to print a *dst.File to stdout +func Print(f *dst.File) error { + return Fprint(os.Stdout, f) +} + +// Fprint uses format.Node to print a *dst.File to a writer +func Fprint(w io.Writer, f *dst.File) error { + fset, af, err := RestoreFile(f) + if err != nil { + return err + } + return format.Node(w, fset, af) +} + +// RestoreFile restores a *dst.File to a *token.FileSet and a *ast.File +func RestoreFile(file *dst.File) (*token.FileSet, *ast.File, error) { + r := NewRestorer() + f, err := r.RestoreFile(file) + if err != nil { + return nil, nil, err + } + return r.Fset, f, nil +} diff --git a/vendor/github.com/dave/dst/decorator/load.go b/vendor/github.com/dave/dst/decorator/load.go new file mode 100644 index 000000000..3e109f118 --- /dev/null +++ b/vendor/github.com/dave/dst/decorator/load.go @@ -0,0 +1,119 @@ +package decorator + +import ( + "bytes" + "errors" + "io/ioutil" + "os" + "path/filepath" + + "github.com/dave/dst" + "github.com/dave/dst/decorator/resolver" + "github.com/dave/dst/decorator/resolver/gopackages" + "golang.org/x/tools/go/packages" +) + +func Load(cfg *packages.Config, patterns ...string) ([]*Package, error) { + + if cfg == nil { + cfg = &packages.Config{Mode: packages.LoadSyntax} + } + + if cfg.Mode&packages.NeedSyntax == 0 { + return nil, errors.New("config mode should include NeedSyntax") + } + + pkgs, err := packages.Load(cfg, patterns...) + if err != nil { + return nil, err + } + + dpkgs := map[*packages.Package]*Package{} + + var convert func(p *packages.Package) (*Package, error) + convert = func(pkg *packages.Package) (*Package, error) { + if dp, ok := dpkgs[pkg]; ok { + return dp, nil + } + p := &Package{ + Package: pkg, + Imports: map[string]*Package{}, + } + dpkgs[pkg] = p + if len(pkg.Syntax) > 0 { + + // Only decorate files in the GoFiles list. Syntax also has preprocessed cgo files which + // break things. + goFiles := make(map[string]bool, len(pkg.GoFiles)) + for _, fpath := range pkg.GoFiles { + goFiles[fpath] = true + } + + p.Decorator = NewDecoratorFromPackage(pkg) + for _, f := range pkg.Syntax { + fpath := pkg.Fset.File(f.Pos()).Name() + if !goFiles[fpath] { + continue + } + file, err := p.Decorator.DecorateFile(f) + if err != nil { + return nil, err + } + p.Syntax = append(p.Syntax, file) + } + + dir, _ := filepath.Split(pkg.Fset.File(pkg.Syntax[0].Pos()).Name()) + p.Dir = dir + + for path, imp := range pkg.Imports { + dimp, err := convert(imp) + if err != nil { + return nil, err + } + p.Imports[path] = dimp + } + } + return p, nil + } + + var out []*Package + for _, pkg := range pkgs { + p, err := convert(pkg) + if err != nil { + return nil, err + } + out = append(out, p) + } + + return out, nil +} + +type Package struct { + *packages.Package + Dir string + Decorator *Decorator + Imports map[string]*Package + Syntax []*dst.File +} + +func (p *Package) Save() error { + return p.save(gopackages.New(p.Dir), ioutil.WriteFile) +} + +func (p *Package) SaveWithResolver(resolver resolver.RestorerResolver) error { + return p.save(resolver, ioutil.WriteFile) +} + +func (p *Package) save(resolver resolver.RestorerResolver, writeFile func(filename string, data []byte, perm os.FileMode) error) error { + r := NewRestorerWithImports(p.PkgPath, resolver) + for _, file := range p.Syntax { + buf := &bytes.Buffer{} + if err := r.Fprint(buf, file); err != nil { + return err + } + if err := writeFile(p.Decorator.Filenames[file], buf.Bytes(), 0666); err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/dave/dst/decorator/map.go b/vendor/github.com/dave/dst/decorator/map.go new file mode 100644 index 000000000..48d4adfe5 --- /dev/null +++ b/vendor/github.com/dave/dst/decorator/map.go @@ -0,0 +1,42 @@ +package decorator + +import ( + "go/ast" + + "github.com/dave/dst" +) + +func newMap() Map { + return Map{ + Ast: AstMap{ + Nodes: map[dst.Node]ast.Node{}, + Scopes: map[*dst.Scope]*ast.Scope{}, + Objects: map[*dst.Object]*ast.Object{}, + }, + Dst: DstMap{ + Nodes: map[ast.Node]dst.Node{}, + Scopes: map[*ast.Scope]*dst.Scope{}, + Objects: map[*ast.Object]*dst.Object{}, + }, + } +} + +// Map holds a record of the mapping between ast and dst nodes, objects and scopes. +type Map struct { + Ast AstMap + Dst DstMap +} + +// AstMap holds a record of the mapping from dst to ast nodes, objects and scopes. +type AstMap struct { + Nodes map[dst.Node]ast.Node // Mapping from dst to ast Nodes + Objects map[*dst.Object]*ast.Object // Mapping from dst to ast Objects + Scopes map[*dst.Scope]*ast.Scope // Mapping from dst to ast Scopes +} + +// DstMap holds a record of the mapping from ast to dst nodes, objects and scopes. +type DstMap struct { + Nodes map[ast.Node]dst.Node // Mapping from ast to dst Nodes + Objects map[*ast.Object]*dst.Object // Mapping from ast to dst Objects + Scopes map[*ast.Scope]*dst.Scope // Mapping from ast to dst Scopes +} diff --git a/vendor/github.com/dave/dst/decorator/resolver/gopackages/resolver.go b/vendor/github.com/dave/dst/decorator/resolver/gopackages/resolver.go new file mode 100644 index 000000000..7295d7df6 --- /dev/null +++ b/vendor/github.com/dave/dst/decorator/resolver/gopackages/resolver.go @@ -0,0 +1,61 @@ +package gopackages + +import ( + "fmt" + + "github.com/dave/dst/decorator/resolver" + "golang.org/x/tools/go/packages" +) + +func New(dir string) *RestorerResolver { + return &RestorerResolver{Dir: dir} +} + +func WithConfig(dir string, config packages.Config) *RestorerResolver { + return &RestorerResolver{Config: config, Dir: dir} +} + +func WithHints(dir string, hints map[string]string) *RestorerResolver { + return &RestorerResolver{Dir: dir, Hints: hints} +} + +type RestorerResolver struct { + Dir string + Config packages.Config + + // Hints (package path -> name) is first checked before asking the packages package + Hints map[string]string +} + +func (r *RestorerResolver) ResolvePackage(path string) (string, error) { + + if name, ok := r.Hints[path]; ok { + return name, nil + } + + if r.Dir != "" { + r.Config.Dir = r.Dir + } + r.Config.Mode = packages.LoadTypes + r.Config.Tests = false + + pkgs, err := packages.Load(&r.Config, "pattern="+path) + if err != nil { + return "", err + } + + if len(pkgs) > 1 { + return "", fmt.Errorf("%d packages found for %s, %s", len(pkgs), path, r.Config.Dir) + } + if len(pkgs) == 0 { + return "", resolver.ErrPackageNotFound + } + + p := pkgs[0] + + if len(p.Errors) > 0 { + return "", p.Errors[0] + } + + return p.Name, nil +} diff --git a/vendor/github.com/dave/dst/decorator/resolver/gotypes/resolver.go b/vendor/github.com/dave/dst/decorator/resolver/gotypes/resolver.go new file mode 100644 index 000000000..b79e56219 --- /dev/null +++ b/vendor/github.com/dave/dst/decorator/resolver/gotypes/resolver.go @@ -0,0 +1,64 @@ +package gotypes + +import ( + "errors" + "go/ast" + "go/types" +) + +func New(uses map[*ast.Ident]types.Object) *DecoratorResolver { + return &DecoratorResolver{Uses: uses} +} + +type DecoratorResolver struct { + Uses map[*ast.Ident]types.Object // Types info - must include Uses +} + +func (r *DecoratorResolver) ResolveIdent(file *ast.File, parent ast.Node, parentField string, id *ast.Ident) (string, error) { + + if r.Uses == nil { + return "", errors.New("gotypes.DecoratorResolver needs Uses in types info") + } + + if se, ok := parent.(*ast.SelectorExpr); ok && parentField == "Sel" { + + // if the parent is a SelectorExpr and this Ident is in the Sel field, only resolve the path + // if X is a package identifier + + xid, ok := se.X.(*ast.Ident) + if !ok { + // x is not an ident -> not a qualified identifier + return "", nil + } + obj, ok := r.Uses[xid] + if !ok { + // not found in uses -> not a qualified identifier + return "", nil + } + pn, ok := obj.(*types.PkgName) + if !ok { + // not a pkgname -> not a remote identifier + return "", nil + } + return pn.Imported().Path(), nil + } + + obj, ok := r.Uses[id] + if !ok { + // not found in uses -> not a remote identifier + return "", nil + } + + if v, ok := obj.(*types.Var); ok && v.IsField() { + // field ident (e.g. name of a field in a composite literal) -> doesn't need qualified ident + return "", nil + } + + pkg := obj.Pkg() + if pkg == nil { + // pre-defined idents in the universe scope - e.g. "byte" + return "", nil + } + + return pkg.Path(), nil +} diff --git a/vendor/github.com/dave/dst/decorator/resolver/resolver.go b/vendor/github.com/dave/dst/decorator/resolver/resolver.go new file mode 100644 index 000000000..ccda19193 --- /dev/null +++ b/vendor/github.com/dave/dst/decorator/resolver/resolver.go @@ -0,0 +1,26 @@ +package resolver + +import ( + "errors" + "go/ast" +) + +// RestorerResolver resolves a package path to a package name. +type RestorerResolver interface { + ResolvePackage(path string) (string, error) +} + +// DecoratorResolver resolves an identifier to a local or remote reference. +// +// Returns path == "" if the node is not a local or remote reference (e.g. a field in a composite +// literal, the selector in a selector expression etc.). +// +// Returns path == "" is the node is a local reference. +// +// Returns path != "" is the node is a remote reference. +type DecoratorResolver interface { + ResolveIdent(file *ast.File, parent ast.Node, parentField string, id *ast.Ident) (path string, err error) +} + +// ErrPackageNotFound means the package is not found +var ErrPackageNotFound = errors.New("package not found") diff --git a/vendor/github.com/dave/dst/decorator/restorer-generated.go b/vendor/github.com/dave/dst/decorator/restorer-generated.go new file mode 100644 index 000000000..4b5728ff4 --- /dev/null +++ b/vendor/github.com/dave/dst/decorator/restorer-generated.go @@ -0,0 +1,1956 @@ +package decorator + +import ( + "fmt" + "go/ast" + "go/token" + + "github.com/dave/dst" +) + +func (r *FileRestorer) restoreNode(n dst.Node, parentName, parentField, parentFieldType string, allowDuplicate bool) ast.Node { + if an, ok := r.Ast.Nodes[n]; ok { + if allowDuplicate { + return an + } else { + panic(fmt.Sprintf("duplicate node: %#v", n)) + } + } + switch n := n.(type) { + case *dst.ArrayType: + out := &ast.ArrayType{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: Lbrack + out.Lbrack = r.cursor + r.cursor += token.Pos(len(token.LBRACK.String())) + + // Decoration: Lbrack + r.applyDecorations(out, "Lbrack", n.Decs.Lbrack, false) + + // Node: Len + if n.Len != nil { + out.Len = r.restoreNode(n.Len, "ArrayType", "Len", "Expr", allowDuplicate).(ast.Expr) + } + + // Token: Rbrack + r.cursor += token.Pos(len(token.RBRACK.String())) + + // Decoration: Len + r.applyDecorations(out, "Len", n.Decs.Len, false) + + // Node: Elt + if n.Elt != nil { + out.Elt = r.restoreNode(n.Elt, "ArrayType", "Elt", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.AssignStmt: + out := &ast.AssignStmt{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // List: Lhs + for _, v := range n.Lhs { + out.Lhs = append(out.Lhs, r.restoreNode(v, "AssignStmt", "Lhs", "Expr", allowDuplicate).(ast.Expr)) + } + + // Token: Tok + out.Tok = n.Tok + out.TokPos = r.cursor + r.cursor += token.Pos(len(n.Tok.String())) + + // Decoration: Tok + r.applyDecorations(out, "Tok", n.Decs.Tok, false) + + // List: Rhs + for _, v := range n.Rhs { + out.Rhs = append(out.Rhs, r.restoreNode(v, "AssignStmt", "Rhs", "Expr", allowDuplicate).(ast.Expr)) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.BadDecl: + out := &ast.BadDecl{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Bad + out.From = r.cursor + r.cursor += token.Pos(n.Length) + out.To = r.cursor + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.BadExpr: + out := &ast.BadExpr{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Bad + out.From = r.cursor + r.cursor += token.Pos(n.Length) + out.To = r.cursor + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.BadStmt: + out := &ast.BadStmt{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Bad + out.From = r.cursor + r.cursor += token.Pos(n.Length) + out.To = r.cursor + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.BasicLit: + out := &ast.BasicLit{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // String: Value + r.applyLiteral(n.Value) + out.ValuePos = r.cursor + out.Value = n.Value + r.cursor += token.Pos(len(n.Value)) + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + + // Value: Kind + out.Kind = n.Kind + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.BinaryExpr: + out := &ast.BinaryExpr{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Node: X + if n.X != nil { + out.X = r.restoreNode(n.X, "BinaryExpr", "X", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: X + r.applyDecorations(out, "X", n.Decs.X, false) + + // Token: Op + out.Op = n.Op + out.OpPos = r.cursor + r.cursor += token.Pos(len(n.Op.String())) + + // Decoration: Op + r.applyDecorations(out, "Op", n.Decs.Op, false) + + // Node: Y + if n.Y != nil { + out.Y = r.restoreNode(n.Y, "BinaryExpr", "Y", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.BlockStmt: + out := &ast.BlockStmt{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: Lbrace + out.Lbrace = r.cursor + r.cursor += token.Pos(len(token.LBRACE.String())) + + // Decoration: Lbrace + r.applyDecorations(out, "Lbrace", n.Decs.Lbrace, false) + + // List: List + for _, v := range n.List { + out.List = append(out.List, r.restoreNode(v, "BlockStmt", "List", "Stmt", allowDuplicate).(ast.Stmt)) + } + + // Token: Rbrace + if n.RbraceHasNoPos { + out.Rbrace = token.NoPos + } else { + out.Rbrace = r.cursor + } + r.cursor += token.Pos(len(token.RBRACE.String())) + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.BranchStmt: + out := &ast.BranchStmt{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: Tok + out.Tok = n.Tok + out.TokPos = r.cursor + r.cursor += token.Pos(len(n.Tok.String())) + + // Decoration: Tok + r.applyDecorations(out, "Tok", n.Decs.Tok, false) + + // Node: Label + if n.Label != nil { + out.Label = r.restoreNode(n.Label, "BranchStmt", "Label", "Ident", allowDuplicate).(*ast.Ident) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.CallExpr: + out := &ast.CallExpr{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Node: Fun + if n.Fun != nil { + out.Fun = r.restoreNode(n.Fun, "CallExpr", "Fun", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: Fun + r.applyDecorations(out, "Fun", n.Decs.Fun, false) + + // Token: Lparen + out.Lparen = r.cursor + r.cursor += token.Pos(len(token.LPAREN.String())) + + // Decoration: Lparen + r.applyDecorations(out, "Lparen", n.Decs.Lparen, false) + + // List: Args + for _, v := range n.Args { + out.Args = append(out.Args, r.restoreNode(v, "CallExpr", "Args", "Expr", allowDuplicate).(ast.Expr)) + } + + // Token: Ellipsis + if n.Ellipsis { + out.Ellipsis = r.cursor + r.cursor += token.Pos(len(token.ELLIPSIS.String())) + } + + // Decoration: Ellipsis + r.applyDecorations(out, "Ellipsis", n.Decs.Ellipsis, false) + + // Token: Rparen + out.Rparen = r.cursor + r.cursor += token.Pos(len(token.RPAREN.String())) + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.CaseClause: + out := &ast.CaseClause{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: Case + out.Case = r.cursor + r.cursor += token.Pos(len(func() token.Token { + if n.List == nil { + return token.DEFAULT + } + return token.CASE + }().String())) + + // Decoration: Case + r.applyDecorations(out, "Case", n.Decs.Case, false) + + // List: List + for _, v := range n.List { + out.List = append(out.List, r.restoreNode(v, "CaseClause", "List", "Expr", allowDuplicate).(ast.Expr)) + } + + // Token: Colon + out.Colon = r.cursor + r.cursor += token.Pos(len(token.COLON.String())) + + // Decoration: Colon + r.applyDecorations(out, "Colon", n.Decs.Colon, false) + + // List: Body + for _, v := range n.Body { + out.Body = append(out.Body, r.restoreNode(v, "CaseClause", "Body", "Stmt", allowDuplicate).(ast.Stmt)) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.ChanType: + out := &ast.ChanType{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: Begin + out.Begin = r.cursor + r.cursor += token.Pos(len(func() token.Token { + if n.Dir == dst.RECV { + return token.ARROW + } + return token.CHAN + }().String())) + + // Token: Chan + if n.Dir == dst.RECV { + r.cursor += token.Pos(len(token.CHAN.String())) + } + + // Decoration: Begin + r.applyDecorations(out, "Begin", n.Decs.Begin, false) + + // Token: Arrow + if n.Dir == dst.SEND { + out.Arrow = r.cursor + r.cursor += token.Pos(len(token.ARROW.String())) + } + + // Decoration: Arrow + r.applyDecorations(out, "Arrow", n.Decs.Arrow, false) + + // Node: Value + if n.Value != nil { + out.Value = r.restoreNode(n.Value, "ChanType", "Value", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + + // Value: Dir + out.Dir = ast.ChanDir(n.Dir) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.CommClause: + out := &ast.CommClause{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: Case + out.Case = r.cursor + r.cursor += token.Pos(len(func() token.Token { + if n.Comm == nil { + return token.DEFAULT + } + return token.CASE + }().String())) + + // Decoration: Case + r.applyDecorations(out, "Case", n.Decs.Case, false) + + // Node: Comm + if n.Comm != nil { + out.Comm = r.restoreNode(n.Comm, "CommClause", "Comm", "Stmt", allowDuplicate).(ast.Stmt) + } + + // Decoration: Comm + r.applyDecorations(out, "Comm", n.Decs.Comm, false) + + // Token: Colon + out.Colon = r.cursor + r.cursor += token.Pos(len(token.COLON.String())) + + // Decoration: Colon + r.applyDecorations(out, "Colon", n.Decs.Colon, false) + + // List: Body + for _, v := range n.Body { + out.Body = append(out.Body, r.restoreNode(v, "CommClause", "Body", "Stmt", allowDuplicate).(ast.Stmt)) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.CompositeLit: + out := &ast.CompositeLit{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Node: Type + if n.Type != nil { + out.Type = r.restoreNode(n.Type, "CompositeLit", "Type", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: Type + r.applyDecorations(out, "Type", n.Decs.Type, false) + + // Token: Lbrace + out.Lbrace = r.cursor + r.cursor += token.Pos(len(token.LBRACE.String())) + + // Decoration: Lbrace + r.applyDecorations(out, "Lbrace", n.Decs.Lbrace, false) + + // List: Elts + for _, v := range n.Elts { + out.Elts = append(out.Elts, r.restoreNode(v, "CompositeLit", "Elts", "Expr", allowDuplicate).(ast.Expr)) + } + + // Token: Rbrace + out.Rbrace = r.cursor + r.cursor += token.Pos(len(token.RBRACE.String())) + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + + // Value: Incomplete + out.Incomplete = n.Incomplete + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.DeclStmt: + out := &ast.DeclStmt{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Node: Decl + if n.Decl != nil { + out.Decl = r.restoreNode(n.Decl, "DeclStmt", "Decl", "Decl", allowDuplicate).(ast.Decl) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.DeferStmt: + out := &ast.DeferStmt{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: Defer + out.Defer = r.cursor + r.cursor += token.Pos(len(token.DEFER.String())) + + // Decoration: Defer + r.applyDecorations(out, "Defer", n.Decs.Defer, false) + + // Node: Call + if n.Call != nil { + out.Call = r.restoreNode(n.Call, "DeferStmt", "Call", "CallExpr", allowDuplicate).(*ast.CallExpr) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.Ellipsis: + out := &ast.Ellipsis{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: Ellipsis + out.Ellipsis = r.cursor + r.cursor += token.Pos(len(token.ELLIPSIS.String())) + + // Decoration: Ellipsis + r.applyDecorations(out, "Ellipsis", n.Decs.Ellipsis, false) + + // Node: Elt + if n.Elt != nil { + out.Elt = r.restoreNode(n.Elt, "Ellipsis", "Elt", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.EmptyStmt: + out := &ast.EmptyStmt{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: Semicolon + if !n.Implicit { + out.Semicolon = r.cursor + r.cursor += token.Pos(len(token.ARROW.String())) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + + // Value: Implicit + out.Implicit = n.Implicit + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.ExprStmt: + out := &ast.ExprStmt{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Node: X + if n.X != nil { + out.X = r.restoreNode(n.X, "ExprStmt", "X", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.Field: + out := &ast.Field{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // List: Names + for _, v := range n.Names { + out.Names = append(out.Names, r.restoreNode(v, "Field", "Names", "Ident", allowDuplicate).(*ast.Ident)) + } + + // Node: Type + if n.Type != nil { + out.Type = r.restoreNode(n.Type, "Field", "Type", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: Type + r.applyDecorations(out, "Type", n.Decs.Type, false) + + // Node: Tag + if n.Tag != nil { + out.Tag = r.restoreNode(n.Tag, "Field", "Tag", "BasicLit", allowDuplicate).(*ast.BasicLit) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.FieldList: + out := &ast.FieldList{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: Opening + if n.Opening { + out.Opening = r.cursor + r.cursor += token.Pos(len(token.LPAREN.String())) + } + + // Decoration: Opening + r.applyDecorations(out, "Opening", n.Decs.Opening, false) + + // List: List + for _, v := range n.List { + out.List = append(out.List, r.restoreNode(v, "FieldList", "List", "Field", allowDuplicate).(*ast.Field)) + } + + // Token: Closing + if n.Closing { + out.Closing = r.cursor + r.cursor += token.Pos(len(token.RPAREN.String())) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.File: + out := &ast.File{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: Package + out.Package = r.cursor + r.cursor += token.Pos(len(token.PACKAGE.String())) + + // Decoration: Package + r.applyDecorations(out, "Package", n.Decs.Package, false) + + // Node: Name + if n.Name != nil { + out.Name = r.restoreNode(n.Name, "File", "Name", "Ident", allowDuplicate).(*ast.Ident) + } + + // Decoration: Name + r.applyDecorations(out, "Name", n.Decs.Name, false) + + // List: Decls + for _, v := range n.Decls { + out.Decls = append(out.Decls, r.restoreNode(v, "File", "Decls", "Decl", allowDuplicate).(ast.Decl)) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + + // Scope: Scope + out.Scope = r.restoreScope(n.Scope) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.ForStmt: + out := &ast.ForStmt{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: For + out.For = r.cursor + r.cursor += token.Pos(len(token.FOR.String())) + + // Decoration: For + r.applyDecorations(out, "For", n.Decs.For, false) + + // Node: Init + if n.Init != nil { + out.Init = r.restoreNode(n.Init, "ForStmt", "Init", "Stmt", allowDuplicate).(ast.Stmt) + } + + // Token: InitSemicolon + if n.Init != nil { + r.cursor += token.Pos(len(token.SEMICOLON.String())) + } + + // Decoration: Init + r.applyDecorations(out, "Init", n.Decs.Init, false) + + // Node: Cond + if n.Cond != nil { + out.Cond = r.restoreNode(n.Cond, "ForStmt", "Cond", "Expr", allowDuplicate).(ast.Expr) + } + + // Token: CondSemicolon + if n.Post != nil { + r.cursor += token.Pos(len(token.SEMICOLON.String())) + } + + // Decoration: Cond + r.applyDecorations(out, "Cond", n.Decs.Cond, false) + + // Node: Post + if n.Post != nil { + out.Post = r.restoreNode(n.Post, "ForStmt", "Post", "Stmt", allowDuplicate).(ast.Stmt) + } + + // Decoration: Post + r.applyDecorations(out, "Post", n.Decs.Post, false) + + // Node: Body + if n.Body != nil { + out.Body = r.restoreNode(n.Body, "ForStmt", "Body", "BlockStmt", allowDuplicate).(*ast.BlockStmt) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.FuncDecl: + out := &ast.FuncDecl{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Init: Type + out.Type = &ast.FuncType{} + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Special decoration: Start + r.applyDecorations(out, "Start", n.Type.Decs.Start, false) + + // Token: Func + if true { + out.Type.Func = r.cursor + r.cursor += token.Pos(len(token.FUNC.String())) + } + + // Decoration: Func + r.applyDecorations(out, "Func", n.Decs.Func, false) + + // Special decoration: Func + r.applyDecorations(out, "Func", n.Type.Decs.Func, false) + + // Node: Recv + if n.Recv != nil { + out.Recv = r.restoreNode(n.Recv, "FuncDecl", "Recv", "FieldList", allowDuplicate).(*ast.FieldList) + } + + // Decoration: Recv + r.applyDecorations(out, "Recv", n.Decs.Recv, false) + + // Node: Name + if n.Name != nil { + out.Name = r.restoreNode(n.Name, "FuncDecl", "Name", "Ident", allowDuplicate).(*ast.Ident) + } + + // Decoration: Name + r.applyDecorations(out, "Name", n.Decs.Name, false) + + // Node: TypeParams + if n.Type.TypeParams != nil { + out.Type.TypeParams = r.restoreNode(n.Type.TypeParams, "FuncDecl", "TypeParams", "FieldList", allowDuplicate).(*ast.FieldList) + } + + // Decoration: TypeParams + r.applyDecorations(out, "TypeParams", n.Decs.TypeParams, false) + + // Special decoration: TypeParams + r.applyDecorations(out, "TypeParams", n.Type.Decs.TypeParams, false) + + // Node: Params + if n.Type.Params != nil { + out.Type.Params = r.restoreNode(n.Type.Params, "FuncDecl", "Params", "FieldList", allowDuplicate).(*ast.FieldList) + } + + // Decoration: Params + r.applyDecorations(out, "Params", n.Decs.Params, false) + + // Special decoration: Params + r.applyDecorations(out, "Params", n.Type.Decs.Params, false) + + // Node: Results + if n.Type.Results != nil { + out.Type.Results = r.restoreNode(n.Type.Results, "FuncDecl", "Results", "FieldList", allowDuplicate).(*ast.FieldList) + } + + // Decoration: Results + r.applyDecorations(out, "Results", n.Decs.Results, false) + + // Special decoration: End + r.applyDecorations(out, "End", n.Type.Decs.End, false) + + // Node: Body + if n.Body != nil { + out.Body = r.restoreNode(n.Body, "FuncDecl", "Body", "BlockStmt", allowDuplicate).(*ast.BlockStmt) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.FuncLit: + out := &ast.FuncLit{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Node: Type + if n.Type != nil { + out.Type = r.restoreNode(n.Type, "FuncLit", "Type", "FuncType", allowDuplicate).(*ast.FuncType) + } + + // Decoration: Type + r.applyDecorations(out, "Type", n.Decs.Type, false) + + // Node: Body + if n.Body != nil { + out.Body = r.restoreNode(n.Body, "FuncLit", "Body", "BlockStmt", allowDuplicate).(*ast.BlockStmt) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.FuncType: + out := &ast.FuncType{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: Func + if n.Func { + out.Func = r.cursor + r.cursor += token.Pos(len(token.FUNC.String())) + } + + // Decoration: Func + r.applyDecorations(out, "Func", n.Decs.Func, false) + + // Node: TypeParams + if n.TypeParams != nil { + out.TypeParams = r.restoreNode(n.TypeParams, "FuncType", "TypeParams", "FieldList", allowDuplicate).(*ast.FieldList) + } + + // Decoration: TypeParams + r.applyDecorations(out, "TypeParams", n.Decs.TypeParams, false) + + // Node: Params + if n.Params != nil { + out.Params = r.restoreNode(n.Params, "FuncType", "Params", "FieldList", allowDuplicate).(*ast.FieldList) + } + + // Decoration: Params + r.applyDecorations(out, "Params", n.Decs.Params, false) + + // Node: Results + if n.Results != nil { + out.Results = r.restoreNode(n.Results, "FuncType", "Results", "FieldList", allowDuplicate).(*ast.FieldList) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.GenDecl: + out := &ast.GenDecl{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: Tok + out.Tok = n.Tok + out.TokPos = r.cursor + r.cursor += token.Pos(len(n.Tok.String())) + + // Decoration: Tok + r.applyDecorations(out, "Tok", n.Decs.Tok, false) + + // Token: Lparen + if n.Lparen { + out.Lparen = r.cursor + r.cursor += token.Pos(len(token.LPAREN.String())) + } + + // Decoration: Lparen + r.applyDecorations(out, "Lparen", n.Decs.Lparen, false) + + // List: Specs + for _, v := range n.Specs { + out.Specs = append(out.Specs, r.restoreNode(v, "GenDecl", "Specs", "Spec", allowDuplicate).(ast.Spec)) + } + + // Token: Rparen + if n.Rparen { + out.Rparen = r.cursor + r.cursor += token.Pos(len(token.RPAREN.String())) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.GoStmt: + out := &ast.GoStmt{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: Go + out.Go = r.cursor + r.cursor += token.Pos(len(token.GO.String())) + + // Decoration: Go + r.applyDecorations(out, "Go", n.Decs.Go, false) + + // Node: Call + if n.Call != nil { + out.Call = r.restoreNode(n.Call, "GoStmt", "Call", "CallExpr", allowDuplicate).(*ast.CallExpr) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.Ident: + + // Special case for *dst.Ident - replace with SelectorExpr if needed + sel := r.restoreIdent(n, parentName, parentField, parentFieldType, allowDuplicate) + if sel != nil { + return sel + } + + out := &ast.Ident{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Decoration: X + r.applyDecorations(out, "X", n.Decs.X, false) + + // String: Name + out.NamePos = r.cursor + out.Name = n.Name + r.cursor += token.Pos(len(n.Name)) + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + + // Object: Obj + out.Obj = r.restoreObject(n.Obj) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.IfStmt: + out := &ast.IfStmt{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: If + out.If = r.cursor + r.cursor += token.Pos(len(token.IF.String())) + + // Decoration: If + r.applyDecorations(out, "If", n.Decs.If, false) + + // Node: Init + if n.Init != nil { + out.Init = r.restoreNode(n.Init, "IfStmt", "Init", "Stmt", allowDuplicate).(ast.Stmt) + } + + // Decoration: Init + r.applyDecorations(out, "Init", n.Decs.Init, false) + + // Node: Cond + if n.Cond != nil { + out.Cond = r.restoreNode(n.Cond, "IfStmt", "Cond", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: Cond + r.applyDecorations(out, "Cond", n.Decs.Cond, false) + + // Node: Body + if n.Body != nil { + out.Body = r.restoreNode(n.Body, "IfStmt", "Body", "BlockStmt", allowDuplicate).(*ast.BlockStmt) + } + + // Token: ElseTok + if n.Else != nil { + r.cursor += token.Pos(len(token.ELSE.String())) + } + + // Decoration: Else + r.applyDecorations(out, "Else", n.Decs.Else, false) + + // Node: Else + if n.Else != nil { + out.Else = r.restoreNode(n.Else, "IfStmt", "Else", "Stmt", allowDuplicate).(ast.Stmt) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.ImportSpec: + out := &ast.ImportSpec{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Node: Name + if n.Name != nil { + out.Name = r.restoreNode(n.Name, "ImportSpec", "Name", "Ident", allowDuplicate).(*ast.Ident) + } + + // Decoration: Name + r.applyDecorations(out, "Name", n.Decs.Name, false) + + // Node: Path + if n.Path != nil { + out.Path = r.restoreNode(n.Path, "ImportSpec", "Path", "BasicLit", allowDuplicate).(*ast.BasicLit) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.IncDecStmt: + out := &ast.IncDecStmt{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Node: X + if n.X != nil { + out.X = r.restoreNode(n.X, "IncDecStmt", "X", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: X + r.applyDecorations(out, "X", n.Decs.X, false) + + // Token: Tok + out.Tok = n.Tok + out.TokPos = r.cursor + r.cursor += token.Pos(len(n.Tok.String())) + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.IndexExpr: + out := &ast.IndexExpr{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Node: X + if n.X != nil { + out.X = r.restoreNode(n.X, "IndexExpr", "X", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: X + r.applyDecorations(out, "X", n.Decs.X, false) + + // Token: Lbrack + out.Lbrack = r.cursor + r.cursor += token.Pos(len(token.LBRACK.String())) + + // Decoration: Lbrack + r.applyDecorations(out, "Lbrack", n.Decs.Lbrack, false) + + // Node: Index + if n.Index != nil { + out.Index = r.restoreNode(n.Index, "IndexExpr", "Index", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: Index + r.applyDecorations(out, "Index", n.Decs.Index, false) + + // Token: Rbrack + out.Rbrack = r.cursor + r.cursor += token.Pos(len(token.RBRACK.String())) + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.IndexListExpr: + out := &ast.IndexListExpr{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Node: X + if n.X != nil { + out.X = r.restoreNode(n.X, "IndexListExpr", "X", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: X + r.applyDecorations(out, "X", n.Decs.X, false) + + // Token: Lbrack + out.Lbrack = r.cursor + r.cursor += token.Pos(len(token.LBRACK.String())) + + // Decoration: Lbrack + r.applyDecorations(out, "Lbrack", n.Decs.Lbrack, false) + + // List: Indices + for _, v := range n.Indices { + out.Indices = append(out.Indices, r.restoreNode(v, "IndexListExpr", "Indices", "Expr", allowDuplicate).(ast.Expr)) + } + + // Decoration: Indices + r.applyDecorations(out, "Indices", n.Decs.Indices, false) + + // Token: Rbrack + out.Rbrack = r.cursor + r.cursor += token.Pos(len(token.RBRACK.String())) + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.InterfaceType: + out := &ast.InterfaceType{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: Interface + out.Interface = r.cursor + r.cursor += token.Pos(len(token.INTERFACE.String())) + + // Decoration: Interface + r.applyDecorations(out, "Interface", n.Decs.Interface, false) + + // Node: Methods + if n.Methods != nil { + out.Methods = r.restoreNode(n.Methods, "InterfaceType", "Methods", "FieldList", allowDuplicate).(*ast.FieldList) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + + // Value: Incomplete + out.Incomplete = n.Incomplete + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.KeyValueExpr: + out := &ast.KeyValueExpr{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Node: Key + if n.Key != nil { + out.Key = r.restoreNode(n.Key, "KeyValueExpr", "Key", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: Key + r.applyDecorations(out, "Key", n.Decs.Key, false) + + // Token: Colon + out.Colon = r.cursor + r.cursor += token.Pos(len(token.COLON.String())) + + // Decoration: Colon + r.applyDecorations(out, "Colon", n.Decs.Colon, false) + + // Node: Value + if n.Value != nil { + out.Value = r.restoreNode(n.Value, "KeyValueExpr", "Value", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.LabeledStmt: + out := &ast.LabeledStmt{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Node: Label + if n.Label != nil { + out.Label = r.restoreNode(n.Label, "LabeledStmt", "Label", "Ident", allowDuplicate).(*ast.Ident) + } + + // Decoration: Label + r.applyDecorations(out, "Label", n.Decs.Label, false) + + // Token: Colon + out.Colon = r.cursor + r.cursor += token.Pos(len(token.COLON.String())) + + // Decoration: Colon + r.applyDecorations(out, "Colon", n.Decs.Colon, false) + + // Node: Stmt + if n.Stmt != nil { + out.Stmt = r.restoreNode(n.Stmt, "LabeledStmt", "Stmt", "Stmt", allowDuplicate).(ast.Stmt) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.MapType: + out := &ast.MapType{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: Map + out.Map = r.cursor + r.cursor += token.Pos(len(token.MAP.String())) + + // Token: Lbrack + r.cursor += token.Pos(len(token.LBRACK.String())) + + // Decoration: Map + r.applyDecorations(out, "Map", n.Decs.Map, false) + + // Node: Key + if n.Key != nil { + out.Key = r.restoreNode(n.Key, "MapType", "Key", "Expr", allowDuplicate).(ast.Expr) + } + + // Token: Rbrack + r.cursor += token.Pos(len(token.RBRACK.String())) + + // Decoration: Key + r.applyDecorations(out, "Key", n.Decs.Key, false) + + // Node: Value + if n.Value != nil { + out.Value = r.restoreNode(n.Value, "MapType", "Value", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.Package: + out := &ast.Package{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + + // Value: Name + out.Name = n.Name + + // Scope: Scope + out.Scope = r.restoreScope(n.Scope) + + // Map: Imports + out.Imports = map[string]*ast.Object{} + for k, v := range n.Imports { + out.Imports[k] = r.restoreObject(v) + } + + // Map: Files + out.Files = map[string]*ast.File{} + for k, v := range n.Files { + out.Files[k] = r.restoreNode(v, "Package", "Files", "File", allowDuplicate).(*ast.File) + } + + return out + case *dst.ParenExpr: + out := &ast.ParenExpr{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: Lparen + out.Lparen = r.cursor + r.cursor += token.Pos(len(token.LPAREN.String())) + + // Decoration: Lparen + r.applyDecorations(out, "Lparen", n.Decs.Lparen, false) + + // Node: X + if n.X != nil { + out.X = r.restoreNode(n.X, "ParenExpr", "X", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: X + r.applyDecorations(out, "X", n.Decs.X, false) + + // Token: Rparen + out.Rparen = r.cursor + r.cursor += token.Pos(len(token.RPAREN.String())) + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.RangeStmt: + out := &ast.RangeStmt{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: For + out.For = r.cursor + r.cursor += token.Pos(len(token.FOR.String())) + + // Decoration: For + r.applyDecorations(out, "For", n.Decs.For, false) + + // Node: Key + if n.Key != nil { + out.Key = r.restoreNode(n.Key, "RangeStmt", "Key", "Expr", allowDuplicate).(ast.Expr) + } + + // Token: Comma + if n.Value != nil { + r.cursor += token.Pos(len(token.COMMA.String())) + } + + // Decoration: Key + r.applyDecorations(out, "Key", n.Decs.Key, false) + + // Node: Value + if n.Value != nil { + out.Value = r.restoreNode(n.Value, "RangeStmt", "Value", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: Value + r.applyDecorations(out, "Value", n.Decs.Value, false) + + // Token: Tok + if n.Tok != token.ILLEGAL { + out.Tok = n.Tok + out.TokPos = r.cursor + r.cursor += token.Pos(len(n.Tok.String())) + } + + // Token: Range + r.cursor += token.Pos(len(token.RANGE.String())) + + // Decoration: Range + r.applyDecorations(out, "Range", n.Decs.Range, false) + + // Node: X + if n.X != nil { + out.X = r.restoreNode(n.X, "RangeStmt", "X", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: X + r.applyDecorations(out, "X", n.Decs.X, false) + + // Node: Body + if n.Body != nil { + out.Body = r.restoreNode(n.Body, "RangeStmt", "Body", "BlockStmt", allowDuplicate).(*ast.BlockStmt) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.ReturnStmt: + out := &ast.ReturnStmt{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: Return + out.Return = r.cursor + r.cursor += token.Pos(len(token.RETURN.String())) + + // Decoration: Return + r.applyDecorations(out, "Return", n.Decs.Return, false) + + // List: Results + for _, v := range n.Results { + out.Results = append(out.Results, r.restoreNode(v, "ReturnStmt", "Results", "Expr", allowDuplicate).(ast.Expr)) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.SelectStmt: + out := &ast.SelectStmt{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: Select + out.Select = r.cursor + r.cursor += token.Pos(len(token.SELECT.String())) + + // Decoration: Select + r.applyDecorations(out, "Select", n.Decs.Select, false) + + // Node: Body + if n.Body != nil { + out.Body = r.restoreNode(n.Body, "SelectStmt", "Body", "BlockStmt", allowDuplicate).(*ast.BlockStmt) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.SelectorExpr: + out := &ast.SelectorExpr{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Node: X + if n.X != nil { + out.X = r.restoreNode(n.X, "SelectorExpr", "X", "Expr", allowDuplicate).(ast.Expr) + } + + // Token: Period + r.cursor += token.Pos(len(token.PERIOD.String())) + + // Decoration: X + r.applyDecorations(out, "X", n.Decs.X, false) + + // Node: Sel + if n.Sel != nil { + out.Sel = r.restoreNode(n.Sel, "SelectorExpr", "Sel", "Ident", allowDuplicate).(*ast.Ident) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.SendStmt: + out := &ast.SendStmt{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Node: Chan + if n.Chan != nil { + out.Chan = r.restoreNode(n.Chan, "SendStmt", "Chan", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: Chan + r.applyDecorations(out, "Chan", n.Decs.Chan, false) + + // Token: Arrow + out.Arrow = r.cursor + r.cursor += token.Pos(len(token.ARROW.String())) + + // Decoration: Arrow + r.applyDecorations(out, "Arrow", n.Decs.Arrow, false) + + // Node: Value + if n.Value != nil { + out.Value = r.restoreNode(n.Value, "SendStmt", "Value", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.SliceExpr: + out := &ast.SliceExpr{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Node: X + if n.X != nil { + out.X = r.restoreNode(n.X, "SliceExpr", "X", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: X + r.applyDecorations(out, "X", n.Decs.X, false) + + // Token: Lbrack + out.Lbrack = r.cursor + r.cursor += token.Pos(len(token.LBRACK.String())) + + // Decoration: Lbrack + r.applyDecorations(out, "Lbrack", n.Decs.Lbrack, false) + + // Node: Low + if n.Low != nil { + out.Low = r.restoreNode(n.Low, "SliceExpr", "Low", "Expr", allowDuplicate).(ast.Expr) + } + + // Token: Colon1 + r.cursor += token.Pos(len(token.COLON.String())) + + // Decoration: Low + r.applyDecorations(out, "Low", n.Decs.Low, false) + + // Node: High + if n.High != nil { + out.High = r.restoreNode(n.High, "SliceExpr", "High", "Expr", allowDuplicate).(ast.Expr) + } + + // Token: Colon2 + if n.Slice3 { + r.cursor += token.Pos(len(token.COLON.String())) + } + + // Decoration: High + r.applyDecorations(out, "High", n.Decs.High, false) + + // Node: Max + if n.Max != nil { + out.Max = r.restoreNode(n.Max, "SliceExpr", "Max", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: Max + r.applyDecorations(out, "Max", n.Decs.Max, false) + + // Token: Rbrack + out.Rbrack = r.cursor + r.cursor += token.Pos(len(token.RBRACK.String())) + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + + // Value: Slice3 + out.Slice3 = n.Slice3 + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.StarExpr: + out := &ast.StarExpr{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: Star + out.Star = r.cursor + r.cursor += token.Pos(len(token.MUL.String())) + + // Decoration: Star + r.applyDecorations(out, "Star", n.Decs.Star, false) + + // Node: X + if n.X != nil { + out.X = r.restoreNode(n.X, "StarExpr", "X", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.StructType: + out := &ast.StructType{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: Struct + out.Struct = r.cursor + r.cursor += token.Pos(len(token.STRUCT.String())) + + // Decoration: Struct + r.applyDecorations(out, "Struct", n.Decs.Struct, false) + + // Node: Fields + if n.Fields != nil { + out.Fields = r.restoreNode(n.Fields, "StructType", "Fields", "FieldList", allowDuplicate).(*ast.FieldList) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + + // Value: Incomplete + out.Incomplete = n.Incomplete + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.SwitchStmt: + out := &ast.SwitchStmt{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: Switch + out.Switch = r.cursor + r.cursor += token.Pos(len(token.SWITCH.String())) + + // Decoration: Switch + r.applyDecorations(out, "Switch", n.Decs.Switch, false) + + // Node: Init + if n.Init != nil { + out.Init = r.restoreNode(n.Init, "SwitchStmt", "Init", "Stmt", allowDuplicate).(ast.Stmt) + } + + // Decoration: Init + r.applyDecorations(out, "Init", n.Decs.Init, false) + + // Node: Tag + if n.Tag != nil { + out.Tag = r.restoreNode(n.Tag, "SwitchStmt", "Tag", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: Tag + r.applyDecorations(out, "Tag", n.Decs.Tag, false) + + // Node: Body + if n.Body != nil { + out.Body = r.restoreNode(n.Body, "SwitchStmt", "Body", "BlockStmt", allowDuplicate).(*ast.BlockStmt) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.TypeAssertExpr: + out := &ast.TypeAssertExpr{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Node: X + if n.X != nil { + out.X = r.restoreNode(n.X, "TypeAssertExpr", "X", "Expr", allowDuplicate).(ast.Expr) + } + + // Token: Period + r.cursor += token.Pos(len(token.PERIOD.String())) + + // Decoration: X + r.applyDecorations(out, "X", n.Decs.X, false) + + // Token: Lparen + out.Lparen = r.cursor + r.cursor += token.Pos(len(token.LPAREN.String())) + + // Decoration: Lparen + r.applyDecorations(out, "Lparen", n.Decs.Lparen, false) + + // Node: Type + if n.Type != nil { + out.Type = r.restoreNode(n.Type, "TypeAssertExpr", "Type", "Expr", allowDuplicate).(ast.Expr) + } + + // Token: TypeToken + if n.Type == nil { + r.cursor += token.Pos(len(token.TYPE.String())) + } + + // Decoration: Type + r.applyDecorations(out, "Type", n.Decs.Type, false) + + // Token: Rparen + out.Rparen = r.cursor + r.cursor += token.Pos(len(token.RPAREN.String())) + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.TypeSpec: + out := &ast.TypeSpec{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Node: Name + if n.Name != nil { + out.Name = r.restoreNode(n.Name, "TypeSpec", "Name", "Ident", allowDuplicate).(*ast.Ident) + } + + // Token: Assign + if n.Assign { + out.Assign = r.cursor + r.cursor += token.Pos(len(token.ASSIGN.String())) + } + + // Decoration: Name + r.applyDecorations(out, "Name", n.Decs.Name, false) + + // Node: TypeParams + if n.TypeParams != nil { + out.TypeParams = r.restoreNode(n.TypeParams, "TypeSpec", "TypeParams", "FieldList", allowDuplicate).(*ast.FieldList) + } + + // Decoration: TypeParams + r.applyDecorations(out, "TypeParams", n.Decs.TypeParams, false) + + // Node: Type + if n.Type != nil { + out.Type = r.restoreNode(n.Type, "TypeSpec", "Type", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.TypeSwitchStmt: + out := &ast.TypeSwitchStmt{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: Switch + out.Switch = r.cursor + r.cursor += token.Pos(len(token.SWITCH.String())) + + // Decoration: Switch + r.applyDecorations(out, "Switch", n.Decs.Switch, false) + + // Node: Init + if n.Init != nil { + out.Init = r.restoreNode(n.Init, "TypeSwitchStmt", "Init", "Stmt", allowDuplicate).(ast.Stmt) + } + + // Decoration: Init + r.applyDecorations(out, "Init", n.Decs.Init, false) + + // Node: Assign + if n.Assign != nil { + out.Assign = r.restoreNode(n.Assign, "TypeSwitchStmt", "Assign", "Stmt", allowDuplicate).(ast.Stmt) + } + + // Decoration: Assign + r.applyDecorations(out, "Assign", n.Decs.Assign, false) + + // Node: Body + if n.Body != nil { + out.Body = r.restoreNode(n.Body, "TypeSwitchStmt", "Body", "BlockStmt", allowDuplicate).(*ast.BlockStmt) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.UnaryExpr: + out := &ast.UnaryExpr{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Token: Op + out.Op = n.Op + out.OpPos = r.cursor + r.cursor += token.Pos(len(n.Op.String())) + + // Decoration: Op + r.applyDecorations(out, "Op", n.Decs.Op, false) + + // Node: X + if n.X != nil { + out.X = r.restoreNode(n.X, "UnaryExpr", "X", "Expr", allowDuplicate).(ast.Expr) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + case *dst.ValueSpec: + out := &ast.ValueSpec{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // List: Names + for _, v := range n.Names { + out.Names = append(out.Names, r.restoreNode(v, "ValueSpec", "Names", "Ident", allowDuplicate).(*ast.Ident)) + } + + // Node: Type + if n.Type != nil { + out.Type = r.restoreNode(n.Type, "ValueSpec", "Type", "Expr", allowDuplicate).(ast.Expr) + } + + // Token: Assign + if n.Values != nil { + r.cursor += token.Pos(len(token.ASSIGN.String())) + } + + // Decoration: Assign + r.applyDecorations(out, "Assign", n.Decs.Assign, false) + + // List: Values + for _, v := range n.Values { + out.Values = append(out.Values, r.restoreNode(v, "ValueSpec", "Values", "Expr", allowDuplicate).(ast.Expr)) + } + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + default: + panic(fmt.Sprintf("%T", n)) + } +} diff --git a/vendor/github.com/dave/dst/decorator/restorer.go b/vendor/github.com/dave/dst/decorator/restorer.go new file mode 100644 index 000000000..57717834f --- /dev/null +++ b/vendor/github.com/dave/dst/decorator/restorer.go @@ -0,0 +1,823 @@ +package decorator + +import ( + "fmt" + "go/ast" + "go/format" + "go/token" + "io" + "os" + "sort" + "strconv" + "strings" + + "github.com/dave/dst" + "github.com/dave/dst/decorator/resolver" +) + +// NewRestorer returns a restorer. +func NewRestorer() *Restorer { + return &Restorer{ + Map: newMap(), + Fset: token.NewFileSet(), + } +} + +// NewRestorerWithImports returns a restorer with import management attributes set. +func NewRestorerWithImports(path string, resolver resolver.RestorerResolver) *Restorer { + res := NewRestorer() + res.Path = path + res.Resolver = resolver + return res +} + +// Restorer restores dst.Node to ast.Node +type Restorer struct { + Map + Fset *token.FileSet // Fset is the *token.FileSet in use. Set this to use a pre-existing FileSet. + Extras bool // Resore Objects, Scopes etc. Not needed for printing the resultant AST. If set to true, Objects and Scopes must be carefully managed to avoid duplicate nodes. + + // If a Resolver is provided, the names of all imported packages are resolved, and the imports + // block is updated. All remote identifiers are updated (sometimes this involves changing + // SelectorExpr.X.Name, or even swapping between Ident and SelectorExpr). To force specific + // import alias names, use the FileRestorer.Alias map. + Resolver resolver.RestorerResolver + // Local package path - required if Resolver is set. + Path string +} + +// Print uses format.Node to print a *dst.File to stdout +func (pr *Restorer) Print(f *dst.File) error { + return pr.Fprint(os.Stdout, f) +} + +// Fprint uses format.Node to print a *dst.File to a writer +func (pr *Restorer) Fprint(w io.Writer, f *dst.File) error { + af, err := pr.RestoreFile(f) + if err != nil { + return err + } + return format.Node(w, pr.Fset, af) +} + +// RestoreFile restores a *dst.File to an *ast.File +func (pr *Restorer) RestoreFile(file *dst.File) (*ast.File, error) { + return pr.FileRestorer().RestoreFile(file) +} + +// FileRestorer restores a specific file with extra options +func (pr *Restorer) FileRestorer() *FileRestorer { + return &FileRestorer{ + Restorer: pr, + Alias: map[string]string{}, + } +} + +// FileRestorer restores a specific file with extra options +type FileRestorer struct { + *Restorer + Alias map[string]string // Map of package path -> package alias for imports + Name string // The name of the restored file in the FileSet. Can usually be left empty. + file *dst.File + lines []int + comments []*ast.CommentGroup + base int + cursor token.Pos + nodeDecl map[*ast.Object]dst.Node // Objects that have a ast.Node Decl (look up after file has been rendered) + nodeData map[*ast.Object]dst.Node // Objects that have a ast.Node Data (look up after file has been rendered) + cursorAtNewLine token.Pos // The cursor position directly after adding a newline decoration (or a line comment which ends in a "\n"). If we're still at this cursor position when we add a line space, reduce the "\n" by one. + packageNames map[string]string // names in the code of all imported packages ("." for dot-imports) +} + +// Print uses format.Node to print a *dst.File to stdout +func (r *FileRestorer) Print(f *dst.File) error { + return r.Fprint(os.Stdout, f) +} + +// Fprint uses format.Node to print a *dst.File to a writer +func (r *FileRestorer) Fprint(w io.Writer, f *dst.File) error { + af, err := r.RestoreFile(f) + if err != nil { + return err + } + return format.Node(w, r.Fset, af) +} + +// RestoreFile restores a *dst.File to *ast.File +func (r *FileRestorer) RestoreFile(file *dst.File) (*ast.File, error) { + + if r.Resolver == nil && r.Path != "" { + panic("Restorer Path should be empty when Resolver is nil") + } + + if r.Resolver != nil && r.Path == "" { + panic("Restorer Path should be set when Resolver is set") + } + + if r.Fset == nil { + r.Fset = token.NewFileSet() + } + + // reset the FileRestorer, but leave Name and the Alias map unchanged + + r.file = file + r.lines = []int{0} // initialise with the first line at Pos 0 + r.nodeDecl = map[*ast.Object]dst.Node{} + r.nodeData = map[*ast.Object]dst.Node{} + r.packageNames = map[string]string{} + r.comments = []*ast.CommentGroup{} + r.cursorAtNewLine = 0 + r.packageNames = map[string]string{} + + r.base = r.Fset.Base() // base is the pos that the file will start at in the fset + r.cursor = token.Pos(r.base) + + if err := r.updateImports(); err != nil { + return nil, err + } + + // restore the file, populate comments and lines + f := r.restoreNode(r.file, "", "", "", false).(*ast.File) + + for _, cg := range r.comments { + f.Comments = append(f.Comments, cg) + } + + ff := r.Fset.AddFile(r.Name, r.base, r.fileSize()) + if !ff.SetLines(r.lines) { + panic("ff.SetLines failed") + } + + if r.Extras { + // Sometimes new nodes are created here (e.g. in RangeStmt the "Object" is an AssignStmt + // which never occurs in the actual code). These shouldn't have position information but + // perhaps it doesn't matter? + for o, dn := range r.nodeDecl { + o.Decl = r.restoreNode(dn, "", "", "", true) + } + for o, dn := range r.nodeData { + o.Data = r.restoreNode(dn, "", "", "", true) + } + } + + return f, nil +} + +func (r *FileRestorer) updateImports() error { + + if r.Resolver == nil { + return nil + } + + // list of the import block(s) + var blocks []*dst.GenDecl + + // hasCgoBlock is only true if the "C" import is on it's own in a block at the start of the + // file. If so, this is avoided. If there are no more imports in the file, and a new block is + // added, it should be added below this block. + var hasCgoBlock bool + + // map of package path -> alias for all packages currently in the imports block(s). Alias can + // be an alias, an empty string, "_" or "." + importsFound := map[string]string{} + + // a list of all packages that occur in the source (package path -> true) + packagesInUse := map[string]bool{} + + // a list of all the imports that will be in the imports block after the update + importsRequired := map[string]bool{} + + dst.Inspect(r.file, func(n dst.Node) bool { + switch n := n.(type) { + case *dst.Ident: + if n.Path == "" { + return true + } + if n.Path == r.Path { + return true + } + packagesInUse[n.Path] = true + importsRequired[n.Path] = true + + case *dst.GenDecl: + if n.Tok != token.IMPORT { + return true + } + // if this block has 1 spec and it's the "C" import, ignore it. + if len(n.Specs) == 1 && mustUnquote(n.Specs[0].(*dst.ImportSpec).Path.Value) == "C" { + hasCgoBlock = true + return true + } + blocks = append(blocks, n) + + case *dst.ImportSpec: + path := mustUnquote(n.Path.Value) + if n.Name == nil { + importsFound[path] = "" + } else { + importsFound[path] = n.Name.Name + } + if path == "C" { + // never remove the "C" import + importsRequired["C"] = true + } + } + return true + }) + + // resolved names of all packages in use + resolved := map[string]string{} + + // the effective alias requested - the manually supplied alias will override the alias from the + // import block + effectiveAlias := map[string]string{} + for path, alias := range importsFound { + if alias == "" { + continue + } + if a, ok := r.Alias[path]; ok && a == "" { + continue + } + if alias == "_" && packagesInUse[path] { + continue + } + effectiveAlias[path] = alias + } + for path, alias := range r.Alias { + if alias == "" { + continue + } + if alias == "_" && packagesInUse[path] { + continue + } + effectiveAlias[path] = alias + } + + // any anonymous imports + for path, alias := range effectiveAlias { + if alias == "_" { + importsRequired[path] = true + } + } + + for path := range packagesInUse { + if _, ok := effectiveAlias[path]; ok { + // no need to resolve the path of a package that has an alias + continue + } + name, err := r.Resolver.ResolvePackage(path) + if err != nil { + return fmt.Errorf("could not resolve package %s: %w", path, err) + } + resolved[path] = name + } + + // We sort the required imports so that the order going into the alias conflict detection + // routine is determinate. Without this, in a conflict, the package that receives the automatic + // renamed alias would be different every time. + importsRequiredOrdered := make([]string, len(importsRequired)) + i := 0 + for path := range importsRequired { + importsRequiredOrdered[i] = path + i++ + } + sort.Slice(importsRequiredOrdered, func(i, j int) bool { return packagePathOrderLess(importsRequiredOrdered[i], importsRequiredOrdered[j]) }) + + // alias in the imports block (alias, empty string, "_" or "." + aliases := map[string]string{} + + // name in the code (name or empty string for dot imports). This is consumed later by the + // restoreIdent method, so is a field on FileRestorer. + r.packageNames = map[string]string{} + + // conflict returns true if the provided name already exists in the packageNames list + conflict := func(name string) bool { + for _, n := range r.packageNames { + if name == n { + return true + } + } + return false + } + + // findAlias finds a unique alias given a path and a preferred alias + findAlias := func(path, preferred string) (name, alias string) { + + // if we pass in a preferred alias we should always return an alias even when the alias + // matches the package name. If for some reason the source file has aliased an import with + // the package name, we shouldn't remove this. + aliased := preferred != "" + + if !aliased { + // if there is no preferred alias, we look up the name of the package in the resolved + // names map. + preferred = resolved[path] + } + + // if the current name has a conflict, increment a modifier until a non-conflicting name is + // found + modifier := 1 + current := preferred + for conflict(current) { + current = fmt.Sprintf("%s%d", preferred, modifier) + modifier++ + } + + if !aliased && current == resolved[path] { + // if we didn't supply an alias and the resultant name matches the default package name, + // return empty string for alias indicating that no alias is required. + return current, "" + } + + return current, current + } + + for _, path := range importsRequiredOrdered { + + alias := effectiveAlias[path] + + if alias == "." || alias == "_" { + // no conflict checking for dot-imports or anonymous imports + r.packageNames[path], aliases[path] = "", alias + continue + } + + // regular imports have a unique name chosen. + r.packageNames[path], aliases[path] = findAlias(path, alias) + } + + // make any additions + var added bool + for _, path := range importsRequiredOrdered { + + if _, ok := importsFound[path]; ok { + continue + } + + added = true + + // if there's currently no import blocks, we must create one + if len(blocks) == 0 { + gd := &dst.GenDecl{ + Tok: token.IMPORT, + // make sure it has an empty line before and after + Decs: dst.GenDeclDecorations{ + NodeDecs: dst.NodeDecs{Before: dst.EmptyLine, After: dst.EmptyLine}, + }, + } + if hasCgoBlock { + // special case for if we have the "C" import + r.file.Decls = append([]dst.Decl{r.file.Decls[0], gd}, r.file.Decls[1:]...) + } else { + r.file.Decls = append([]dst.Decl{gd}, r.file.Decls...) + } + blocks = append(blocks, gd) + } + + is := &dst.ImportSpec{ + Path: &dst.BasicLit{Kind: token.STRING, Value: fmt.Sprintf("%q", path)}, + } + if aliases[path] != "" { + is.Name = &dst.Ident{ + Name: aliases[path], + } + } + blocks[0].Specs = append(blocks[0].Specs, is) + } + + if added { + // rearrange import block + sort.Slice(blocks[0].Specs, func(i, j int) bool { + return packagePathOrderLess( + mustUnquote(blocks[0].Specs[i].(*dst.ImportSpec).Path.Value), + mustUnquote(blocks[0].Specs[j].(*dst.ImportSpec).Path.Value), + ) + }) + } + + // import blocks that are empty will be removed from the File Decls list later + deleteBlocks := map[dst.Decl]bool{} + + // update / delete any import specs from all blocks + for _, block := range blocks { + specs := make([]dst.Spec, 0, len(block.Specs)) + for _, spec := range block.Specs { + spec := spec.(*dst.ImportSpec) + path := mustUnquote(spec.Path.Value) + if importsRequired[path] { + if spec.Name == nil && aliases[path] != "" { + // missing alias + spec.Name = &dst.Ident{Name: aliases[path]} + } else if spec.Name != nil && aliases[path] == "" { + // alias needs to be removed + spec.Name = nil + } else if spec.Name != nil && aliases[path] != spec.Name.Name { + // alias wrong + spec.Name.Name = aliases[path] + } + specs = append(specs, spec) + } + } + + count := len(specs) + + if count != len(block.Specs) { + + block.Specs = specs + + if count == 0 { + deleteBlocks[block] = true + } else if count == 1 { + block.Lparen = false + block.Rparen = false + } else { + block.Lparen = true + block.Rparen = true + } + } + } + + if added { + // imports with a period in the path are assumed to not be standard library packages, so + // get a newline separating them from standard library packages. We remove any other + // newlines found in this block. We do this after the deletions because the first non-stdlib + // import might be deleted. + var foundDomainImport bool + for _, spec := range blocks[0].Specs { + path := mustUnquote(spec.(*dst.ImportSpec).Path.Value) + if strings.Contains(path, ".") && !foundDomainImport { + // first non-std-lib import -> empty line above + spec.Decorations().Before = dst.EmptyLine + spec.Decorations().After = dst.NewLine + foundDomainImport = true + continue + } + // all other specs, just newlines + spec.Decorations().Before = dst.NewLine + spec.Decorations().After = dst.NewLine + } + + if len(blocks[0].Specs) == 1 { + blocks[0].Lparen = false + blocks[0].Rparen = false + } else { + blocks[0].Lparen = true + blocks[0].Rparen = true + } + } + + // finally remove any deleted blocks from the File Decls list + if len(deleteBlocks) > 0 { + decls := make([]dst.Decl, 0, len(r.file.Decls)) + for _, decl := range r.file.Decls { + if deleteBlocks[decl] { + continue + } + decls = append(decls, decl) + } + r.file.Decls = decls + } + + return nil +} + +// restoreIdent is a special case for restoring an ident. If the ident has a path and the imported +// package is not a dot-import, we restore the Ident to a *ast.SelectorExpr with the correct name +// in the X field. +func (r *FileRestorer) restoreIdent(n *dst.Ident, parentName, parentField, parentFieldType string, allowDuplicate bool) ast.Node { + + if r.Resolver == nil && n.Path != "" { + panic("This syntax has been decorated with import management enabled, but the restorer does not have import management enabled. Use NewRestorerWithImports to create a restorer with import management. See the Imports section of the readme for more information.") + } + + var name string + if r.Resolver != nil && n.Path != "" { + + if avoid[parentName+"."+parentField] { + panic(fmt.Sprintf("Path %s set on illegal Ident %s: parentName %s, parentField %s, parentFieldType %s", n.Path, n.Name, parentName, parentField, parentFieldType)) + } + + if n.Path != r.Path { + name = r.packageNames[n.Path] + } + + if name == "." { + name = "" + } + } + + if name == "" { + // continue to run standard Ident restore + return nil + } + + // restore to a SelectorExpr + out := &ast.SelectorExpr{} + r.Ast.Nodes[n] = out + r.Dst.Nodes[out] = n + r.Dst.Nodes[out.Sel] = n + r.Dst.Nodes[out.X] = n + r.applySpace(n, "Before", n.Decs.Before) + + // Decoration: Start + r.applyDecorations(out, "Start", n.Decs.Start, false) + + // Node: X + out.X = r.restoreNode(dst.NewIdent(name), "SelectorExpr", "X", "Expr", allowDuplicate).(ast.Expr) + + // Token: Period + r.cursor += token.Pos(len(token.PERIOD.String())) + + // Decoration: X + r.applyDecorations(out, "X", n.Decs.X, false) + + // Node: Sel + out.Sel = r.restoreNode(dst.NewIdent(n.Name), "SelectorExpr", "Sel", "Ident", allowDuplicate).(*ast.Ident) + + // Decoration: End + r.applyDecorations(out, "End", n.Decs.End, true) + r.applySpace(n, "After", n.Decs.After) + + return out + +} + +func packagePathOrderLess(pi, pj string) bool { + // package paths with a . should be ordered after those without + idot := strings.Contains(pi, ".") + jdot := strings.Contains(pj, ".") + if idot != jdot { + return jdot + } + return pi < pj +} + +func (r *FileRestorer) fileSize() int { + + // If a comment is at the end of a file, it will extend past the current cursor position... + + // end pos of file + end := int(r.cursor) + + // check that none of the comments or newlines extend past the file end position. If so, increment. + for _, cg := range r.comments { + if int(cg.End()) >= end { + end = int(cg.End()) + 1 + } + } + for _, lineOffset := range r.lines { + pos := lineOffset + r.base // remember lines are relative to the file base + if pos >= end { + end = pos + 1 + } + } + + return end - r.base +} + +func (r *FileRestorer) applyLiteral(text string) { + isMultiLine := strings.HasPrefix(text, "`") && strings.Contains(text, "\n") + if !isMultiLine { + return + } + for charIndex, char := range text { + if char == '\n' { + lineOffset := int(r.cursor) - r.base + charIndex // remember lines are relative to the file base + r.lines = append(r.lines, lineOffset) + } + } +} + +func (r *FileRestorer) hasCommentField(n ast.Node) bool { + switch n.(type) { + case *ast.Field, *ast.ValueSpec, *ast.TypeSpec, *ast.ImportSpec: + return true + } + return false +} + +func (r *FileRestorer) addCommentField(n ast.Node, slash token.Pos, text string) { + c := &ast.Comment{Slash: slash, Text: text} + switch n := n.(type) { + case *ast.Field: + if n.Comment == nil { + n.Comment = &ast.CommentGroup{} + r.comments = append(r.comments, n.Comment) + } + n.Comment.List = append(n.Comment.List, c) + case *ast.ImportSpec: + if n.Comment == nil { + n.Comment = &ast.CommentGroup{} + r.comments = append(r.comments, n.Comment) + } + n.Comment.List = append(n.Comment.List, c) + case *ast.ValueSpec: + if n.Comment == nil { + n.Comment = &ast.CommentGroup{} + r.comments = append(r.comments, n.Comment) + } + n.Comment.List = append(n.Comment.List, c) + case *ast.TypeSpec: + if n.Comment == nil { + n.Comment = &ast.CommentGroup{} + r.comments = append(r.comments, n.Comment) + } + n.Comment.List = append(n.Comment.List, c) + } +} + +func (r *FileRestorer) applyDecorations(node ast.Node, name string, decorations dst.Decorations, end bool) { + firstLine := true + _, isNodeFile := node.(*ast.File) + isPackageComment := isNodeFile && name == "Start" + + for _, d := range decorations { + + isNewline := d == "\n" + isLineComment := strings.HasPrefix(d, "//") + isInlineComment := strings.HasPrefix(d, "/*") + isComment := isLineComment || isInlineComment + isMultiLineComment := isInlineComment && strings.Contains(d, "\n") + + if end && r.cursorAtNewLine == r.cursor { + r.cursor++ // indent all comments in "End" decorations + } + + // for multi-line comments, add a newline for each \n + if isMultiLineComment { + for charIndex, char := range d { + if char == '\n' { + lineOffset := int(r.cursor) - r.base + charIndex // remember lines are relative to the file base + r.lines = append(r.lines, lineOffset) + } + } + } + + // if the decoration is a comment, add it and advance the cursor + if isComment { + if firstLine && end && r.hasCommentField(node) { + // for comments on the same line as the end of a node that has a Comment field, we + // add the comment to the node instead of the file. + r.addCommentField(node, r.cursor, d) + } else { + r.comments = append(r.comments, &ast.CommentGroup{List: []*ast.Comment{{Slash: r.cursor, Text: d}}}) + } + r.cursor += token.Pos(len(d)) + } + + // for newline decorations and also line-comments, add a newline + if isLineComment || isNewline { + lineOffset := int(r.cursor) - r.base // remember lines are relative to the file base + r.lines = append(r.lines, lineOffset) + r.cursor++ + + r.cursorAtNewLine = r.cursor + } + + if isNewline || isLineComment { + firstLine = false + } + } + if isPackageComment { + // This fixes https://github.com/dave/dst/issues/69 + r.cursor++ + } +} + +func (r *FileRestorer) applySpace(node dst.Node, position string, space dst.SpaceType) { + switch node.(type) { + case *dst.BadDecl, *dst.BadExpr, *dst.BadStmt: + if position == "After" { + // BadXXX are always followed by an empty line + space = dst.EmptyLine + } + } + var newlines int + switch space { + case dst.NewLine: + newlines = 1 + case dst.EmptyLine: + newlines = 2 + } + if r.cursor == r.cursorAtNewLine { + newlines-- + } + for i := 0; i < newlines; i++ { + + // Advance the cursor one more byte for all newlines, so we step over any required + // separator char - e.g. comma. See net-hook test + r.cursor++ + + lineOffset := int(r.cursor) - r.base // remember lines are relative to the file base + r.lines = append(r.lines, lineOffset) + r.cursor++ + r.cursorAtNewLine = r.cursor + } +} + +func (r *FileRestorer) restoreObject(o *dst.Object) *ast.Object { + if !r.Extras { + return nil + } + if o == nil { + return nil + } + if ro, ok := r.Ast.Objects[o]; ok { + return ro + } + /* + // An Object describes a named language entity such as a package, + // constant, type, variable, function (incl. methods), or label. + // + // The Data fields contains object-specific data: + // + // Kind Data type Data value + // Pkg *Scope package scope + // Con int iota for the respective declaration + // + type Object struct { + Kind ObjKind + Name string // declared name + Decl interface{} // corresponding Field, XxxSpec, FuncDecl, LabeledStmt, AssignStmt, Scope; or nil + Data interface{} // object-specific data; or nil + Type interface{} // placeholder for type information; may be nil + } + */ + out := &ast.Object{} + + r.Ast.Objects[o] = out + r.Dst.Objects[out] = o + + out.Kind = ast.ObjKind(o.Kind) + out.Name = o.Name + + switch decl := o.Decl.(type) { + case *dst.Scope: + out.Decl = r.restoreScope(decl) + case dst.Node: + // Can't use restoreNode here because we aren't at the right cursor position, so we store a link + // to the Object and Node so we can look the Nodes up in the cache after the file is fully processed. + r.nodeDecl[out] = decl + case nil: + default: + panic(fmt.Sprintf("o.Decl is %T", o.Decl)) + } + + switch data := o.Data.(type) { + case int: + out.Data = data + case *dst.Scope: + out.Data = r.restoreScope(data) + case dst.Node: + // Can't use restoreNode here because we aren't at the right cursor position, so we store a link + // to the Object and Node so we can look the Nodes up in the cache after the file is fully processed. + r.nodeData[out] = data + case nil: + default: + panic(fmt.Sprintf("o.Data is %T", o.Data)) + } + + return out +} + +func (r *FileRestorer) restoreScope(s *dst.Scope) *ast.Scope { + if !r.Extras { + return nil + } + if s == nil { + return nil + } + if rs, ok := r.Ast.Scopes[s]; ok { + return rs + } + /* + // A Scope maintains the set of named language entities declared + // in the scope and a link to the immediately surrounding (outer) + // scope. + // + type Scope struct { + Outer *Scope + Objects map[string]*Object + } + */ + out := &ast.Scope{} + + r.Ast.Scopes[s] = out + r.Dst.Scopes[out] = s + + out.Outer = r.restoreScope(s.Outer) + out.Objects = map[string]*ast.Object{} + for k, v := range s.Objects { + out.Objects[k] = r.restoreObject(v) + } + + return out +} + +func mustUnquote(s string) string { + out, err := strconv.Unquote(s) + if err != nil { + panic(err) + } + return out +} diff --git a/vendor/github.com/dave/dst/dst.go b/vendor/github.com/dave/dst/dst.go new file mode 100644 index 000000000..803eb9a87 --- /dev/null +++ b/vendor/github.com/dave/dst/dst.go @@ -0,0 +1,664 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package dst declares the types used to represent decorated syntax +// trees for Go packages. +package dst + +import ( + "go/token" +) + +// ---------------------------------------------------------------------------- +// Interfaces +// +// There are 3 main classes of nodes: Expressions and type nodes, +// statement nodes, and declaration nodes. The node names usually +// match the corresponding Go spec production names to which they +// correspond. The node fields correspond to the individual parts +// of the respective productions. +// +// All nodes contain position information marking the beginning of +// the corresponding source text segment; it is accessible via the +// Pos accessor method. Nodes may contain additional position info +// for language constructs where comments may be found between parts +// of the construct (typically any larger, parenthesized subpart). +// That position information is needed to properly position comments +// when printing the construct. + +// Node is satisfied by all nodes types. +type Node interface { + // Decorations returns the common Node decorations (Before, After, Start, End). This returns nil for Package nodes. + Decorations() *NodeDecs +} + +// All expression nodes implement the Expr interface. +type Expr interface { + Node + exprNode() +} + +// All statement nodes implement the Stmt interface. +type Stmt interface { + Node + stmtNode() +} + +// All declaration nodes implement the Decl interface. +type Decl interface { + Node + declNode() +} + +// ---------------------------------------------------------------------------- +// Expressions and types + +// A Field represents a Field declaration list in a struct type, +// a method list in an interface type, or a parameter/result declaration +// in a signature. +// Field.Names is nil for unnamed parameters (parameter lists which only contain types) +// and embedded struct fields. In the latter case, the field name is the type name. +// +type Field struct { + Names []*Ident // field/method/(type) parameter names; or nil + Type Expr // field/method/parameter type; or nil + Tag *BasicLit // field tag; or nil + Decs FieldDecorations +} + +// A FieldList represents a list of Fields, enclosed by parentheses, +// curly braces, or square brackets. +type FieldList struct { + Opening bool + List []*Field // field list; or nil + Closing bool + Decs FieldListDecorations +} + +// NumFields returns the number of parameters or struct fields represented by a FieldList. +func (f *FieldList) NumFields() int { + n := 0 + if f != nil { + for _, g := range f.List { + m := len(g.Names) + if m == 0 { + m = 1 + } + n += m + } + } + return n +} + +// An expression is represented by a tree consisting of one +// or more of the following concrete expression nodes. +type ( + // A BadExpr node is a placeholder for an expression containing + // syntax errors for which a correct expression node cannot be + // created. + BadExpr struct { + Length int // position range of bad expression + Decs BadExprDecorations + } + + // An Ident node represents an identifier. + Ident struct { + Name string // identifier name + Obj *Object // denoted object; or nil + Path string // path of the imported package, if this identifier is not local + Decs IdentDecorations + } + + // An Ellipsis node stands for the "..." type in a + // parameter list or the "..." length in an array type. + // + Ellipsis struct { + Elt Expr // ellipsis element type (parameter lists only); or nil + Decs EllipsisDecorations + } + + // A BasicLit node represents a literal of basic type. + BasicLit struct { + Kind token.Token // token.INT, token.FLOAT, token.IMAG, token.CHAR, or token.STRING + Value string // literal string; e.g. 42, 0x7f, 3.14, 1e-9, 2.4i, 'a', '\x7f', "foo" or `\m\n\o` + Decs BasicLitDecorations + } + + // A FuncLit node represents a function literal. + FuncLit struct { + Type *FuncType // function type + Body *BlockStmt // function body + Decs FuncLitDecorations + } + + // A CompositeLit node represents a composite literal. + CompositeLit struct { + Type Expr // literal type; or nil + Elts []Expr // list of composite elements; or nil + Incomplete bool // true if (source) expressions are missing in the Elts list + Decs CompositeLitDecorations + } + + // A ParenExpr node represents a parenthesized expression. + ParenExpr struct { + X Expr // parenthesized expression + Decs ParenExprDecorations + } + + // A SelectorExpr node represents an expression followed by a selector. + SelectorExpr struct { + X Expr // expression + Sel *Ident // field selector + Decs SelectorExprDecorations + } + + // An IndexExpr node represents an expression followed by an index. + IndexExpr struct { + X Expr // expression + Index Expr // index expression + Decs IndexExprDecorations + } + + // An IndexListExpr node represents an expression followed by multiple + // indices. + IndexListExpr struct { + X Expr // expression + Indices []Expr + Decs IndexListExprDecorations + } + + // An SliceExpr node represents an expression followed by slice indices. + SliceExpr struct { + X Expr // expression + Low Expr // begin of slice range; or nil + High Expr // end of slice range; or nil + Max Expr // maximum capacity of slice; or nil + Slice3 bool // true if 3-index slice (2 colons present) + Decs SliceExprDecorations + } + + // A TypeAssertExpr node represents an expression followed by a + // type assertion. + // + TypeAssertExpr struct { + X Expr // expression + Type Expr // asserted type; nil means type switch X.(type) + Decs TypeAssertExprDecorations + } + + // A CallExpr node represents an expression followed by an argument list. + CallExpr struct { + Fun Expr // function expression + Args []Expr // function arguments; or nil + Ellipsis bool + Decs CallExprDecorations + } + + // A StarExpr node represents an expression of the form "*" Expression. + // Semantically it could be a unary "*" expression, or a pointer type. + // + StarExpr struct { + X Expr // operand + Decs StarExprDecorations + } + + // A UnaryExpr node represents a unary expression. + // Unary "*" expressions are represented via StarExpr nodes. + // + UnaryExpr struct { + Op token.Token // operator + X Expr // operand + Decs UnaryExprDecorations + } + + // A BinaryExpr node represents a binary expression. + BinaryExpr struct { + X Expr // left operand + Op token.Token // operator + Y Expr // right operand + Decs BinaryExprDecorations + } + + // A KeyValueExpr node represents (key : value) pairs + // in composite literals. + // + KeyValueExpr struct { + Key Expr + Value Expr + Decs KeyValueExprDecorations + } +) + +// The direction of a channel type is indicated by a bit +// mask including one or both of the following constants. +type ChanDir int + +const ( + SEND ChanDir = 1 << iota + RECV +) + +// A type is represented by a tree consisting of one +// or more of the following type-specific expression +// nodes. +type ( + // An ArrayType node represents an array or slice type. + ArrayType struct { + Len Expr // Ellipsis node for [...]T array types, nil for slice types + Elt Expr // element type + Decs ArrayTypeDecorations + } + + // A StructType node represents a struct type. + StructType struct { + Fields *FieldList // list of field declarations + Incomplete bool // true if (source) fields are missing in the Fields list + Decs StructTypeDecorations + } + + // Pointer types are represented via StarExpr nodes. + + // A FuncType node represents a function type. + FuncType struct { + Func bool + TypeParams *FieldList // type parameters; or nil + Params *FieldList // (incoming) parameters; non-nil + Results *FieldList // (outgoing) results; or nil + Decs FuncTypeDecorations + } + + // An InterfaceType node represents an interface type. + InterfaceType struct { + Methods *FieldList // list of embedded interfaces, methods, or types + Incomplete bool // true if (source) methods or types are missing in the Methods list + Decs InterfaceTypeDecorations + } + + // A MapType node represents a map type. + MapType struct { + Key Expr + Value Expr + Decs MapTypeDecorations + } + + // A ChanType node represents a channel type. + ChanType struct { + Dir ChanDir // channel direction + Value Expr // value type + Decs ChanTypeDecorations + } +) + +// exprNode() ensures that only expression/type nodes can be +// assigned to an Expr. +func (*BadExpr) exprNode() {} +func (*Ident) exprNode() {} +func (*Ellipsis) exprNode() {} +func (*BasicLit) exprNode() {} +func (*FuncLit) exprNode() {} +func (*CompositeLit) exprNode() {} +func (*ParenExpr) exprNode() {} +func (*SelectorExpr) exprNode() {} +func (*IndexExpr) exprNode() {} +func (*IndexListExpr) exprNode() {} +func (*SliceExpr) exprNode() {} +func (*TypeAssertExpr) exprNode() {} +func (*CallExpr) exprNode() {} +func (*StarExpr) exprNode() {} +func (*UnaryExpr) exprNode() {} +func (*BinaryExpr) exprNode() {} +func (*KeyValueExpr) exprNode() {} + +func (*ArrayType) exprNode() {} +func (*StructType) exprNode() {} +func (*FuncType) exprNode() {} +func (*InterfaceType) exprNode() {} +func (*MapType) exprNode() {} +func (*ChanType) exprNode() {} + +// ---------------------------------------------------------------------------- +// Convenience functions for Idents + +// NewIdent creates a new Ident without position. +// Useful for ASTs generated by code other than the Go parser. +func NewIdent(name string) *Ident { return &Ident{name, nil, "", IdentDecorations{}} } + +// IsExported reports whether name starts with an upper-case letter. +func IsExported(name string) bool { return token.IsExported(name) } + +// IsExported reports whether id starts with an upper-case letter. +func (id *Ident) IsExported() bool { return token.IsExported(id.Name) } + +func (id *Ident) String() string { + if id != nil { + if id.Path != "" { + return id.Path + "." + id.Name + } + return id.Name + } + return "" +} + +// ---------------------------------------------------------------------------- +// Statements + +// A statement is represented by a tree consisting of one +// or more of the following concrete statement nodes. +type ( + // A BadStmt node is a placeholder for statements containing + // syntax errors for which no correct statement nodes can be + // created. + // + BadStmt struct { + Length int // position range of bad statement + Decs BadStmtDecorations + } + + // A DeclStmt node represents a declaration in a statement list. + DeclStmt struct { + Decl Decl // *GenDecl with CONST, TYPE, or VAR token + Decs DeclStmtDecorations + } + + // An EmptyStmt node represents an empty statement. + // The "position" of the empty statement is the position + // of the immediately following (explicit or implicit) semicolon. + // + EmptyStmt struct { + Implicit bool // if set, ";" was omitted in the source + Decs EmptyStmtDecorations + } + + // A LabeledStmt node represents a labeled statement. + LabeledStmt struct { + Label *Ident + Stmt Stmt + Decs LabeledStmtDecorations + } + + // An ExprStmt node represents a (stand-alone) expression + // in a statement list. + // + ExprStmt struct { + X Expr // expression + Decs ExprStmtDecorations + } + + // A SendStmt node represents a send statement. + SendStmt struct { + Chan Expr + Value Expr + Decs SendStmtDecorations + } + + // An IncDecStmt node represents an increment or decrement statement. + IncDecStmt struct { + X Expr + Tok token.Token // INC or DEC + Decs IncDecStmtDecorations + } + + // An AssignStmt node represents an assignment or + // a short variable declaration. + // + AssignStmt struct { + Lhs []Expr + Tok token.Token // assignment token, DEFINE + Rhs []Expr + Decs AssignStmtDecorations + } + + // A GoStmt node represents a go statement. + GoStmt struct { + Call *CallExpr + Decs GoStmtDecorations + } + + // A DeferStmt node represents a defer statement. + DeferStmt struct { + Call *CallExpr + Decs DeferStmtDecorations + } + + // A ReturnStmt node represents a return statement. + ReturnStmt struct { + Results []Expr // result expressions; or nil + Decs ReturnStmtDecorations + } + + // A BranchStmt node represents a break, continue, goto, + // or fallthrough statement. + // + BranchStmt struct { + Tok token.Token // keyword token (BREAK, CONTINUE, GOTO, FALLTHROUGH) + Label *Ident // label name; or nil + Decs BranchStmtDecorations + } + + // A BlockStmt node represents a braced statement list. + BlockStmt struct { + List []Stmt + RbraceHasNoPos bool // Rbrace may be absent due to syntax error, so we duplicate this in the output for compatibility. + Decs BlockStmtDecorations + } + + // An IfStmt node represents an if statement. + IfStmt struct { + Init Stmt // initialization statement; or nil + Cond Expr // condition + Body *BlockStmt + Else Stmt // else branch; or nil + Decs IfStmtDecorations + } + + // A CaseClause represents a case of an expression or type switch statement. + CaseClause struct { + List []Expr // list of expressions or types; nil means default case + Body []Stmt // statement list; or nil + Decs CaseClauseDecorations + } + + // A SwitchStmt node represents an expression switch statement. + SwitchStmt struct { + Init Stmt // initialization statement; or nil + Tag Expr // tag expression; or nil + Body *BlockStmt // CaseClauses only + Decs SwitchStmtDecorations + } + + // A TypeSwitchStmt node represents a type switch statement. + TypeSwitchStmt struct { + Init Stmt // initialization statement; or nil + Assign Stmt // x := y.(type) or y.(type) + Body *BlockStmt // CaseClauses only + Decs TypeSwitchStmtDecorations + } + + // A CommClause node represents a case of a select statement. + CommClause struct { + Comm Stmt // send or receive statement; nil means default case + Body []Stmt // statement list; or nil + Decs CommClauseDecorations + } + + // A SelectStmt node represents a select statement. + SelectStmt struct { + Body *BlockStmt // CommClauses only + Decs SelectStmtDecorations + } + + // A ForStmt represents a for statement. + ForStmt struct { + Init Stmt // initialization statement; or nil + Cond Expr // condition; or nil + Post Stmt // post iteration statement; or nil + Body *BlockStmt + Decs ForStmtDecorations + } + + // A RangeStmt represents a for statement with a range clause. + RangeStmt struct { + Key, Value Expr // Key, Value may be nil + Tok token.Token // ILLEGAL if Key == nil, ASSIGN, DEFINE + X Expr // value to range over + Body *BlockStmt + Decs RangeStmtDecorations + } +) + +// stmtNode() ensures that only statement nodes can be +// assigned to a Stmt. +func (*BadStmt) stmtNode() {} +func (*DeclStmt) stmtNode() {} +func (*EmptyStmt) stmtNode() {} +func (*LabeledStmt) stmtNode() {} +func (*ExprStmt) stmtNode() {} +func (*SendStmt) stmtNode() {} +func (*IncDecStmt) stmtNode() {} +func (*AssignStmt) stmtNode() {} +func (*GoStmt) stmtNode() {} +func (*DeferStmt) stmtNode() {} +func (*ReturnStmt) stmtNode() {} +func (*BranchStmt) stmtNode() {} +func (*BlockStmt) stmtNode() {} +func (*IfStmt) stmtNode() {} +func (*CaseClause) stmtNode() {} +func (*SwitchStmt) stmtNode() {} +func (*TypeSwitchStmt) stmtNode() {} +func (*CommClause) stmtNode() {} +func (*SelectStmt) stmtNode() {} +func (*ForStmt) stmtNode() {} +func (*RangeStmt) stmtNode() {} + +// ---------------------------------------------------------------------------- +// Declarations + +// A Spec node represents a single (non-parenthesized) import, +// constant, type, or variable declaration. +type ( + // The Spec type stands for any of *ImportSpec, *ValueSpec, and *TypeSpec. + Spec interface { + Node + specNode() + } + + // An ImportSpec node represents a single package import. + ImportSpec struct { + Name *Ident // local package name (including "."); or nil + Path *BasicLit // import path + Decs ImportSpecDecorations + } + + // A ValueSpec node represents a constant or variable declaration + // (ConstSpec or VarSpec production). + // + ValueSpec struct { + Names []*Ident // value names (len(Names) > 0) + Type Expr // value type; or nil + Values []Expr // initial values; or nil + Decs ValueSpecDecorations + } + + // A TypeSpec node represents a type declaration (TypeSpec production). + TypeSpec struct { + Name *Ident // type name + TypeParams *FieldList // type parameters; or nil + Assign bool // position of '=', if any + Type Expr // *Ident, *ParenExpr, *SelectorExpr, *StarExpr, or any of the *XxxTypes + Decs TypeSpecDecorations + } +) + +// Pos and End implementations for spec nodes. + +// specNode() ensures that only spec nodes can be +// assigned to a Spec. +func (*ImportSpec) specNode() {} +func (*ValueSpec) specNode() {} +func (*TypeSpec) specNode() {} + +// A declaration is represented by one of the following declaration nodes. +type ( + // A BadDecl node is a placeholder for a declaration containing + // syntax errors for which a correct declaration node cannot be + // created. + // + BadDecl struct { + Length int // position range of bad declaration + Decs BadDeclDecorations + } + + // A GenDecl node (generic declaration node) represents an import, + // constant, type or variable declaration. A valid Lparen position + // (Lparen.IsValid()) indicates a parenthesized declaration. + // + // Relationship between Tok value and Specs element type: + // + // token.IMPORT *ImportSpec + // token.CONST *ValueSpec + // token.TYPE *TypeSpec + // token.VAR *ValueSpec + // + GenDecl struct { + Tok token.Token // IMPORT, CONST, TYPE, or VAR + Lparen bool + Specs []Spec + Rparen bool + Decs GenDeclDecorations + } + + // A FuncDecl node represents a function declaration. + FuncDecl struct { + Recv *FieldList // receiver (methods); or nil (functions) + Name *Ident // function/method name + Type *FuncType // function signature: type and value parameters, results, and position of "func" keyword + Body *BlockStmt // function body; or nil for external (non-Go) function + Decs FuncDeclDecorations + } +) + +// declNode() ensures that only declaration nodes can be +// assigned to a Decl. +func (*BadDecl) declNode() {} +func (*GenDecl) declNode() {} +func (*FuncDecl) declNode() {} + +// ---------------------------------------------------------------------------- +// Files and packages + +// A File node represents a Go source file. +// +// The Comments list contains all comments in the source file in order of +// appearance, including the comments that are pointed to from other nodes +// via Doc and Comment fields. +// +// For correct printing of source code containing comments (using packages +// go/format and go/printer), special care must be taken to update comments +// when a File's syntax tree is modified: For printing, comments are interspersed +// between tokens based on their position. If syntax tree nodes are +// removed or moved, relevant comments in their vicinity must also be removed +// (from the File.Comments list) or moved accordingly (by updating their +// positions). A CommentMap may be used to facilitate some of these operations. +// +// Whether and how a comment is associated with a node depends on the +// interpretation of the syntax tree by the manipulating program: Except for Doc +// and Comment comments directly associated with nodes, the remaining comments +// are "free-floating" (see also issues #18593, #20744). +type File struct { + Name *Ident // package name + Decls []Decl // top-level declarations; or nil + Scope *Scope // package scope (this file only) + Imports []*ImportSpec // imports in this file + Unresolved []*Ident // unresolved identifiers in this file + Decs FileDecorations +} + +// A Package node represents a set of source files +// collectively building a Go package. +type Package struct { + Name string // package name + Scope *Scope // package scope across all files + Imports map[string]*Object // map of package id -> package object + Files map[string]*File // Go source files by filename +} diff --git a/vendor/github.com/dave/dst/dstutil/decorations-generated.go b/vendor/github.com/dave/dst/dstutil/decorations-generated.go new file mode 100644 index 000000000..b3e31579f --- /dev/null +++ b/vendor/github.com/dave/dst/dstutil/decorations-generated.go @@ -0,0 +1,369 @@ +package dstutil + +import "github.com/dave/dst" + +func decorations(n dst.Node) (before, after dst.SpaceType, points []DecorationPoint) { + switch n := n.(type) { + case *dst.ArrayType: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Lbrack", n.Decs.Lbrack}) + points = append(points, DecorationPoint{"Len", n.Decs.Len}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.AssignStmt: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Tok", n.Decs.Tok}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.BadDecl: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.BadExpr: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.BadStmt: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.BasicLit: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.BinaryExpr: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"X", n.Decs.X}) + points = append(points, DecorationPoint{"Op", n.Decs.Op}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.BlockStmt: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Lbrace", n.Decs.Lbrace}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.BranchStmt: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Tok", n.Decs.Tok}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.CallExpr: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Fun", n.Decs.Fun}) + points = append(points, DecorationPoint{"Lparen", n.Decs.Lparen}) + points = append(points, DecorationPoint{"Ellipsis", n.Decs.Ellipsis}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.CaseClause: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Case", n.Decs.Case}) + points = append(points, DecorationPoint{"Colon", n.Decs.Colon}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.ChanType: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Begin", n.Decs.Begin}) + points = append(points, DecorationPoint{"Arrow", n.Decs.Arrow}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.CommClause: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Case", n.Decs.Case}) + points = append(points, DecorationPoint{"Comm", n.Decs.Comm}) + points = append(points, DecorationPoint{"Colon", n.Decs.Colon}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.CompositeLit: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Type", n.Decs.Type}) + points = append(points, DecorationPoint{"Lbrace", n.Decs.Lbrace}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.DeclStmt: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.DeferStmt: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Defer", n.Decs.Defer}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.Ellipsis: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Ellipsis", n.Decs.Ellipsis}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.EmptyStmt: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.ExprStmt: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.Field: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Type", n.Decs.Type}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.FieldList: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Opening", n.Decs.Opening}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.File: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Package", n.Decs.Package}) + points = append(points, DecorationPoint{"Name", n.Decs.Name}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.ForStmt: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"For", n.Decs.For}) + points = append(points, DecorationPoint{"Init", n.Decs.Init}) + points = append(points, DecorationPoint{"Cond", n.Decs.Cond}) + points = append(points, DecorationPoint{"Post", n.Decs.Post}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.FuncDecl: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Func", n.Decs.Func}) + points = append(points, DecorationPoint{"Recv", n.Decs.Recv}) + points = append(points, DecorationPoint{"Name", n.Decs.Name}) + points = append(points, DecorationPoint{"TypeParams", n.Decs.TypeParams}) + points = append(points, DecorationPoint{"Params", n.Decs.Params}) + points = append(points, DecorationPoint{"Results", n.Decs.Results}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.FuncLit: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Type", n.Decs.Type}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.FuncType: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Func", n.Decs.Func}) + points = append(points, DecorationPoint{"TypeParams", n.Decs.TypeParams}) + points = append(points, DecorationPoint{"Params", n.Decs.Params}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.GenDecl: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Tok", n.Decs.Tok}) + points = append(points, DecorationPoint{"Lparen", n.Decs.Lparen}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.GoStmt: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Go", n.Decs.Go}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.Ident: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"X", n.Decs.X}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.IfStmt: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"If", n.Decs.If}) + points = append(points, DecorationPoint{"Init", n.Decs.Init}) + points = append(points, DecorationPoint{"Cond", n.Decs.Cond}) + points = append(points, DecorationPoint{"Else", n.Decs.Else}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.ImportSpec: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Name", n.Decs.Name}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.IncDecStmt: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"X", n.Decs.X}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.IndexExpr: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"X", n.Decs.X}) + points = append(points, DecorationPoint{"Lbrack", n.Decs.Lbrack}) + points = append(points, DecorationPoint{"Index", n.Decs.Index}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.IndexListExpr: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"X", n.Decs.X}) + points = append(points, DecorationPoint{"Lbrack", n.Decs.Lbrack}) + points = append(points, DecorationPoint{"Indices", n.Decs.Indices}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.InterfaceType: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Interface", n.Decs.Interface}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.KeyValueExpr: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Key", n.Decs.Key}) + points = append(points, DecorationPoint{"Colon", n.Decs.Colon}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.LabeledStmt: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Label", n.Decs.Label}) + points = append(points, DecorationPoint{"Colon", n.Decs.Colon}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.MapType: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Map", n.Decs.Map}) + points = append(points, DecorationPoint{"Key", n.Decs.Key}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.Package: + case *dst.ParenExpr: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Lparen", n.Decs.Lparen}) + points = append(points, DecorationPoint{"X", n.Decs.X}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.RangeStmt: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"For", n.Decs.For}) + points = append(points, DecorationPoint{"Key", n.Decs.Key}) + points = append(points, DecorationPoint{"Value", n.Decs.Value}) + points = append(points, DecorationPoint{"Range", n.Decs.Range}) + points = append(points, DecorationPoint{"X", n.Decs.X}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.ReturnStmt: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Return", n.Decs.Return}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.SelectStmt: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Select", n.Decs.Select}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.SelectorExpr: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"X", n.Decs.X}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.SendStmt: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Chan", n.Decs.Chan}) + points = append(points, DecorationPoint{"Arrow", n.Decs.Arrow}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.SliceExpr: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"X", n.Decs.X}) + points = append(points, DecorationPoint{"Lbrack", n.Decs.Lbrack}) + points = append(points, DecorationPoint{"Low", n.Decs.Low}) + points = append(points, DecorationPoint{"High", n.Decs.High}) + points = append(points, DecorationPoint{"Max", n.Decs.Max}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.StarExpr: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Star", n.Decs.Star}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.StructType: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Struct", n.Decs.Struct}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.SwitchStmt: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Switch", n.Decs.Switch}) + points = append(points, DecorationPoint{"Init", n.Decs.Init}) + points = append(points, DecorationPoint{"Tag", n.Decs.Tag}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.TypeAssertExpr: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"X", n.Decs.X}) + points = append(points, DecorationPoint{"Lparen", n.Decs.Lparen}) + points = append(points, DecorationPoint{"Type", n.Decs.Type}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.TypeSpec: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Name", n.Decs.Name}) + points = append(points, DecorationPoint{"TypeParams", n.Decs.TypeParams}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.TypeSwitchStmt: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Switch", n.Decs.Switch}) + points = append(points, DecorationPoint{"Init", n.Decs.Init}) + points = append(points, DecorationPoint{"Assign", n.Decs.Assign}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.UnaryExpr: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Op", n.Decs.Op}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + case *dst.ValueSpec: + before = n.Decs.Before + after = n.Decs.After + points = append(points, DecorationPoint{"Start", n.Decs.Start}) + points = append(points, DecorationPoint{"Assign", n.Decs.Assign}) + points = append(points, DecorationPoint{"End", n.Decs.End}) + } + return +} diff --git a/vendor/github.com/dave/dst/dstutil/decorations.go b/vendor/github.com/dave/dst/dstutil/decorations.go new file mode 100644 index 000000000..bb875fcd0 --- /dev/null +++ b/vendor/github.com/dave/dst/dstutil/decorations.go @@ -0,0 +1,14 @@ +package dstutil + +import "github.com/dave/dst" + +// Decorations returns information about all the decoration attachment points associated with a node +func Decorations(n dst.Node) (before, after dst.SpaceType, info []DecorationPoint) { + return decorations(n) +} + +// DecorationPoint contains the name of the decoration attachment point and a list of decorations attached there +type DecorationPoint struct { + Name string + Decs []string +} diff --git a/vendor/github.com/dave/dst/dstutil/rewrite.go b/vendor/github.com/dave/dst/dstutil/rewrite.go new file mode 100644 index 000000000..acb82c8a7 --- /dev/null +++ b/vendor/github.com/dave/dst/dstutil/rewrite.go @@ -0,0 +1,465 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package dstutil + +import ( + "fmt" + + "reflect" + "sort" + + "github.com/dave/dst" +) + +// An ApplyFunc is invoked by Apply for each node n, even if n is nil, +// before and/or after the node's children, using a Cursor describing +// the current node and providing operations on it. +// +// The return value of ApplyFunc controls the syntax tree traversal. +// See Apply for details. +type ApplyFunc func(*Cursor) bool + +// Apply traverses a syntax tree recursively, starting with root, +// and calling pre and post for each node as described below. +// Apply returns the syntax tree, possibly modified. +// +// If pre is not nil, it is called for each node before the node's +// children are traversed (pre-order). If pre returns false, no +// children are traversed, and post is not called for that node. +// +// If post is not nil, and a prior call of pre didn't return false, +// post is called for each node after its children are traversed +// (post-order). If post returns false, traversal is terminated and +// Apply returns immediately. +// +// Only fields that refer to AST nodes are considered children; +// i.e., token.Pos, Scopes, Objects, and fields of basic types +// (strings, etc.) are ignored. +// +// Children are traversed in the order in which they appear in the +// respective node's struct definition. A package's files are +// traversed in the filenames' alphabetical order. +// +func Apply(root dst.Node, pre, post ApplyFunc) (result dst.Node) { + parent := &struct{ dst.Node }{root} + defer func() { + if r := recover(); r != nil && r != abort { + panic(r) + } + result = parent.Node + }() + a := &application{pre: pre, post: post} + a.apply(parent, "Node", nil, root) + return +} + +var abort = new(int) // singleton, to signal termination of Apply + +// A Cursor describes a node encountered during Apply. +// Information about the node and its parent is available +// from the Node, Parent, Name, and Index methods. +// +// If p is a variable of type and value of the current parent node +// c.Parent(), and f is the field identifier with name c.Name(), +// the following invariants hold: +// +// p.f == c.Node() if c.Index() < 0 +// p.f[c.Index()] == c.Node() if c.Index() >= 0 +// +// The methods Replace, Delete, InsertBefore, and InsertAfter +// can be used to change the AST without disrupting Apply. +type Cursor struct { + parent dst.Node + name string + iter *iterator // valid if non-nil + node dst.Node +} + +// Node returns the current Node. +func (c *Cursor) Node() dst.Node { return c.node } + +// Parent returns the parent of the current Node. +func (c *Cursor) Parent() dst.Node { return c.parent } + +// Name returns the name of the parent Node field that contains the current Node. +// If the parent is a *dst.Package and the current Node is a *dst.File, Name returns +// the filename for the current Node. +func (c *Cursor) Name() string { return c.name } + +// Index reports the index >= 0 of the current Node in the slice of Nodes that +// contains it, or a value < 0 if the current Node is not part of a slice. +// The index of the current node changes if InsertBefore is called while +// processing the current node. +func (c *Cursor) Index() int { + if c.iter != nil { + return c.iter.index + } + return -1 +} + +// field returns the current node's parent field value. +func (c *Cursor) field() reflect.Value { + return reflect.Indirect(reflect.ValueOf(c.parent)).FieldByName(c.name) +} + +// Replace replaces the current Node with n. +// The replacement node is not walked by Apply. +func (c *Cursor) Replace(n dst.Node) { + if _, ok := c.node.(*dst.File); ok { + file, ok := n.(*dst.File) + if !ok { + panic("attempt to replace *dst.File with non-*dst.File") + } + c.parent.(*dst.Package).Files[c.name] = file + return + } + + v := c.field() + if i := c.Index(); i >= 0 { + v = v.Index(i) + } + v.Set(reflect.ValueOf(n)) +} + +// Delete deletes the current Node from its containing slice. +// If the current Node is not part of a slice, Delete panics. +// As a special case, if the current node is a package file, +// Delete removes it from the package's Files map. +func (c *Cursor) Delete() { + if _, ok := c.node.(*dst.File); ok { + delete(c.parent.(*dst.Package).Files, c.name) + return + } + + i := c.Index() + if i < 0 { + panic("Delete node not contained in slice") + } + v := c.field() + l := v.Len() + reflect.Copy(v.Slice(i, l), v.Slice(i+1, l)) + v.Index(l - 1).Set(reflect.Zero(v.Type().Elem())) + v.SetLen(l - 1) + c.iter.step-- +} + +// InsertAfter inserts n after the current Node in its containing slice. +// If the current Node is not part of a slice, InsertAfter panics. +// Apply does not walk n. +func (c *Cursor) InsertAfter(n dst.Node) { + i := c.Index() + if i < 0 { + panic("InsertAfter node not contained in slice") + } + v := c.field() + v.Set(reflect.Append(v, reflect.Zero(v.Type().Elem()))) + l := v.Len() + reflect.Copy(v.Slice(i+2, l), v.Slice(i+1, l)) + v.Index(i + 1).Set(reflect.ValueOf(n)) + c.iter.step++ +} + +// InsertBefore inserts n before the current Node in its containing slice. +// If the current Node is not part of a slice, InsertBefore panics. +// Apply will not walk n. +func (c *Cursor) InsertBefore(n dst.Node) { + i := c.Index() + if i < 0 { + panic("InsertBefore node not contained in slice") + } + v := c.field() + v.Set(reflect.Append(v, reflect.Zero(v.Type().Elem()))) + l := v.Len() + reflect.Copy(v.Slice(i+1, l), v.Slice(i, l)) + v.Index(i).Set(reflect.ValueOf(n)) + c.iter.index++ +} + +// application carries all the shared data so we can pass it around cheaply. +type application struct { + pre, post ApplyFunc + cursor Cursor + iter iterator +} + +func (a *application) apply(parent dst.Node, name string, iter *iterator, n dst.Node) { + // convert typed nil into untyped nil + if v := reflect.ValueOf(n); v.Kind() == reflect.Ptr && v.IsNil() { + n = nil + } + + // avoid heap-allocating a new cursor for each apply call; reuse a.cursor instead + saved := a.cursor + a.cursor.parent = parent + a.cursor.name = name + a.cursor.iter = iter + a.cursor.node = n + + if a.pre != nil && !a.pre(&a.cursor) { + a.cursor = saved + return + } + + // walk children + // (the order of the cases matches the order of the corresponding node types in go/ast) + switch n := n.(type) { + case nil: + // nothing to do + + case *dst.Field: + a.applyList(n, "Names") + a.apply(n, "Type", nil, n.Type) + a.apply(n, "Tag", nil, n.Tag) + + case *dst.FieldList: + a.applyList(n, "List") + + // Expressions + case *dst.BadExpr, *dst.Ident, *dst.BasicLit: + // nothing to do + + case *dst.Ellipsis: + a.apply(n, "Elt", nil, n.Elt) + + case *dst.FuncLit: + a.apply(n, "Type", nil, n.Type) + a.apply(n, "Body", nil, n.Body) + + case *dst.CompositeLit: + a.apply(n, "Type", nil, n.Type) + a.applyList(n, "Elts") + + case *dst.ParenExpr: + a.apply(n, "X", nil, n.X) + + case *dst.SelectorExpr: + a.apply(n, "X", nil, n.X) + a.apply(n, "Sel", nil, n.Sel) + + case *dst.IndexExpr: + a.apply(n, "X", nil, n.X) + a.apply(n, "Index", nil, n.Index) + + case *dst.IndexListExpr: + a.apply(n, "X", nil, n.X) + a.applyList(n, "Indices") + + case *dst.SliceExpr: + a.apply(n, "X", nil, n.X) + a.apply(n, "Low", nil, n.Low) + a.apply(n, "High", nil, n.High) + a.apply(n, "Max", nil, n.Max) + + case *dst.TypeAssertExpr: + a.apply(n, "X", nil, n.X) + a.apply(n, "Type", nil, n.Type) + + case *dst.CallExpr: + a.apply(n, "Fun", nil, n.Fun) + a.applyList(n, "Args") + + case *dst.StarExpr: + a.apply(n, "X", nil, n.X) + + case *dst.UnaryExpr: + a.apply(n, "X", nil, n.X) + + case *dst.BinaryExpr: + a.apply(n, "X", nil, n.X) + a.apply(n, "Y", nil, n.Y) + + case *dst.KeyValueExpr: + a.apply(n, "Key", nil, n.Key) + a.apply(n, "Value", nil, n.Value) + + // Types + case *dst.ArrayType: + a.apply(n, "Len", nil, n.Len) + a.apply(n, "Elt", nil, n.Elt) + + case *dst.StructType: + a.apply(n, "Fields", nil, n.Fields) + + case *dst.FuncType: + a.apply(n, "TypeParams", nil, n.TypeParams) + a.apply(n, "Params", nil, n.Params) + a.apply(n, "Results", nil, n.Results) + + case *dst.InterfaceType: + a.apply(n, "Methods", nil, n.Methods) + + case *dst.MapType: + a.apply(n, "Key", nil, n.Key) + a.apply(n, "Value", nil, n.Value) + + case *dst.ChanType: + a.apply(n, "Value", nil, n.Value) + + // Statements + case *dst.BadStmt: + // nothing to do + + case *dst.DeclStmt: + a.apply(n, "Decl", nil, n.Decl) + + case *dst.EmptyStmt: + // nothing to do + + case *dst.LabeledStmt: + a.apply(n, "Label", nil, n.Label) + a.apply(n, "Stmt", nil, n.Stmt) + + case *dst.ExprStmt: + a.apply(n, "X", nil, n.X) + + case *dst.SendStmt: + a.apply(n, "Chan", nil, n.Chan) + a.apply(n, "Value", nil, n.Value) + + case *dst.IncDecStmt: + a.apply(n, "X", nil, n.X) + + case *dst.AssignStmt: + a.applyList(n, "Lhs") + a.applyList(n, "Rhs") + + case *dst.GoStmt: + a.apply(n, "Call", nil, n.Call) + + case *dst.DeferStmt: + a.apply(n, "Call", nil, n.Call) + + case *dst.ReturnStmt: + a.applyList(n, "Results") + + case *dst.BranchStmt: + a.apply(n, "Label", nil, n.Label) + + case *dst.BlockStmt: + a.applyList(n, "List") + + case *dst.IfStmt: + a.apply(n, "Init", nil, n.Init) + a.apply(n, "Cond", nil, n.Cond) + a.apply(n, "Body", nil, n.Body) + a.apply(n, "Else", nil, n.Else) + + case *dst.CaseClause: + a.applyList(n, "List") + a.applyList(n, "Body") + + case *dst.SwitchStmt: + a.apply(n, "Init", nil, n.Init) + a.apply(n, "Tag", nil, n.Tag) + a.apply(n, "Body", nil, n.Body) + + case *dst.TypeSwitchStmt: + a.apply(n, "Init", nil, n.Init) + a.apply(n, "Assign", nil, n.Assign) + a.apply(n, "Body", nil, n.Body) + + case *dst.CommClause: + a.apply(n, "Comm", nil, n.Comm) + a.applyList(n, "Body") + + case *dst.SelectStmt: + a.apply(n, "Body", nil, n.Body) + + case *dst.ForStmt: + a.apply(n, "Init", nil, n.Init) + a.apply(n, "Cond", nil, n.Cond) + a.apply(n, "Post", nil, n.Post) + a.apply(n, "Body", nil, n.Body) + + case *dst.RangeStmt: + a.apply(n, "Key", nil, n.Key) + a.apply(n, "Value", nil, n.Value) + a.apply(n, "X", nil, n.X) + a.apply(n, "Body", nil, n.Body) + + // Declarations + case *dst.ImportSpec: + a.apply(n, "Name", nil, n.Name) + a.apply(n, "Path", nil, n.Path) + + case *dst.ValueSpec: + a.applyList(n, "Names") + a.apply(n, "Type", nil, n.Type) + a.applyList(n, "Values") + + case *dst.TypeSpec: + a.apply(n, "Name", nil, n.Name) + a.apply(n, "TypeParams", nil, n.TypeParams) + a.apply(n, "Type", nil, n.Type) + + case *dst.BadDecl: + // nothing to do + + case *dst.GenDecl: + a.applyList(n, "Specs") + + case *dst.FuncDecl: + a.apply(n, "Recv", nil, n.Recv) + a.apply(n, "Name", nil, n.Name) + a.apply(n, "Type", nil, n.Type) + a.apply(n, "Body", nil, n.Body) + + // Files and packages + case *dst.File: + a.apply(n, "Name", nil, n.Name) + a.applyList(n, "Decls") + // Don't walk n.Comments; they have either been walked already if + // they are Doc comments, or they can be easily walked explicitly. + + case *dst.Package: + // collect and sort names for reproducible behavior + var names []string + for name := range n.Files { + names = append(names, name) + } + sort.Strings(names) + for _, name := range names { + a.apply(n, name, nil, n.Files[name]) + } + + default: + panic(fmt.Sprintf("Apply: unexpected node type %T", n)) + } + + if a.post != nil && !a.post(&a.cursor) { + panic(abort) + } + + a.cursor = saved +} + +// An iterator controls iteration over a slice of nodes. +type iterator struct { + index, step int +} + +func (a *application) applyList(parent dst.Node, name string) { + // avoid heap-allocating a new iterator for each applyList call; reuse a.iter instead + saved := a.iter + a.iter.index = 0 + for { + // must reload parent.name each time, since cursor modifications might change it + v := reflect.Indirect(reflect.ValueOf(parent)).FieldByName(name) + if a.iter.index >= v.Len() { + break + } + + // element x may be nil in a bad AST - be cautious + var x dst.Node + if e := v.Index(a.iter.index); e.IsValid() { + x = e.Interface().(dst.Node) + } + + a.iter.step = 1 + a.apply(parent, name, &a.iter, x) + a.iter.index += a.iter.step + } + a.iter = saved +} diff --git a/vendor/github.com/dave/dst/dstutil/util.go b/vendor/github.com/dave/dst/dstutil/util.go new file mode 100644 index 000000000..984262278 --- /dev/null +++ b/vendor/github.com/dave/dst/dstutil/util.go @@ -0,0 +1,14 @@ +package dstutil + +import "github.com/dave/dst" + +// Unparen returns e with any enclosing parentheses stripped. +func Unparen(e dst.Expr) dst.Expr { + for { + p, ok := e.(*dst.ParenExpr) + if !ok { + return e + } + e = p.X + } +} diff --git a/vendor/github.com/dave/dst/print.go b/vendor/github.com/dave/dst/print.go new file mode 100644 index 000000000..0a4a35c41 --- /dev/null +++ b/vendor/github.com/dave/dst/print.go @@ -0,0 +1,245 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains printing support for ASTs. + +package dst + +import ( + "fmt" + "io" + "os" + "reflect" +) + +// A FieldFilter may be provided to Fprint to control the output. +type FieldFilter func(name string, value reflect.Value) bool + +// NotNilFilter returns true for field values that are not nil; +// it returns false otherwise. +func NotNilFilter(_ string, v reflect.Value) bool { + switch v.Kind() { + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: + return !v.IsNil() + } + return true +} + +// Fprint prints the (sub-)tree starting at AST node x to w. +// If fset != nil, position information is interpreted relative +// to that file set. Otherwise positions are printed as integer +// values (file set specific offsets). +// +// A non-nil FieldFilter f may be provided to control the output: +// struct fields for which f(fieldname, fieldvalue) is true are +// printed; all others are filtered from the output. Unexported +// struct fields are never printed. +func Fprint(w io.Writer, x interface{}, f FieldFilter) error { + return fprint(w, x, f) +} + +func fprint(w io.Writer, x interface{}, f FieldFilter) (err error) { + // setup printer + p := printer{ + output: w, + filter: f, + ptrmap: make(map[interface{}]int), + last: '\n', // force printing of line number on first line + } + + // install error handler + defer func() { + if e := recover(); e != nil { + err = e.(localError).err // re-panics if it's not a localError + } + }() + + // print x + if x == nil { + p.printf("nil\n") + return + } + p.print(reflect.ValueOf(x)) + p.printf("\n") + + return +} + +// Print prints x to standard output, skipping nil fields. +// Print(fset, x) is the same as Fprint(os.Stdout, fset, x, NotNilFilter). +func Print(x interface{}) error { + return Fprint(os.Stdout, x, NotNilFilter) +} + +type printer struct { + output io.Writer + filter FieldFilter + ptrmap map[interface{}]int // *T -> line number + indent int // current indentation level + last byte // the last byte processed by Write + line int // current line number +} + +var indent = []byte(". ") + +func (p *printer) Write(data []byte) (n int, err error) { + var m int + for i, b := range data { + // invariant: data[0:n] has been written + if b == '\n' { + m, err = p.output.Write(data[n : i+1]) + n += m + if err != nil { + return + } + p.line++ + } else if p.last == '\n' { + _, err = fmt.Fprintf(p.output, "%6d ", p.line) + if err != nil { + return + } + for j := p.indent; j > 0; j-- { + _, err = p.output.Write(indent) + if err != nil { + return + } + } + } + p.last = b + } + if len(data) > n { + m, err = p.output.Write(data[n:]) + n += m + } + return +} + +// localError wraps locally caught errors so we can distinguish +// them from genuine panics which we don't want to return as errors. +type localError struct { + err error +} + +// printf is a convenience wrapper that takes care of print errors. +func (p *printer) printf(format string, args ...interface{}) { + if _, err := fmt.Fprintf(p, format, args...); err != nil { + panic(localError{err}) + } +} + +// Implementation note: Print is written for AST nodes but could be +// used to print arbitrary data structures; such a version should +// probably be in a different package. +// +// Note: This code detects (some) cycles created via pointers but +// not cycles that are created via slices or maps containing the +// same slice or map. Code for general data structures probably +// should catch those as well. + +func (p *printer) print(x reflect.Value) { + if !NotNilFilter("", x) { + p.printf("nil") + return + } + + switch x.Kind() { + case reflect.Interface: + p.print(x.Elem()) + + case reflect.Map: + p.printf("%s (len = %d) {", x.Type(), x.Len()) + if x.Len() > 0 { + p.indent++ + p.printf("\n") + for _, key := range x.MapKeys() { + p.print(key) + p.printf(": ") + p.print(x.MapIndex(key)) + p.printf("\n") + } + p.indent-- + } + p.printf("}") + + case reflect.Ptr: + p.printf("*") + // type-checked ASTs may contain cycles - use ptrmap + // to keep track of objects that have been printed + // already and print the respective line number instead + ptr := x.Interface() + if line, exists := p.ptrmap[ptr]; exists { + p.printf("(obj @ %d)", line) + } else { + p.ptrmap[ptr] = p.line + p.print(x.Elem()) + } + + case reflect.Array: + p.printf("%s {", x.Type()) + if x.Len() > 0 { + p.indent++ + p.printf("\n") + for i, n := 0, x.Len(); i < n; i++ { + p.printf("%d: ", i) + p.print(x.Index(i)) + p.printf("\n") + } + p.indent-- + } + p.printf("}") + + case reflect.Slice: + if s, ok := x.Interface().([]byte); ok { + p.printf("%#q", s) + return + } + p.printf("%s (len = %d) {", x.Type(), x.Len()) + if x.Len() > 0 { + p.indent++ + p.printf("\n") + for i, n := 0, x.Len(); i < n; i++ { + p.printf("%d: ", i) + p.print(x.Index(i)) + p.printf("\n") + } + p.indent-- + } + p.printf("}") + + case reflect.Struct: + t := x.Type() + p.printf("%s {", t) + p.indent++ + first := true + for i, n := 0, t.NumField(); i < n; i++ { + // exclude non-exported fields because their + // values cannot be accessed via reflection + if name := t.Field(i).Name; IsExported(name) { + value := x.Field(i) + if p.filter == nil || p.filter(name, value) { + if first { + p.printf("\n") + first = false + } + p.printf("%s: ", name) + p.print(value) + p.printf("\n") + } + } + } + p.indent-- + p.printf("}") + + default: + v := x.Interface() + switch v := v.(type) { + case string: + // print strings in quotes + p.printf("%q", v) + return + } + // default + p.printf("%v", v) + } +} diff --git a/vendor/github.com/dave/dst/readme.go b/vendor/github.com/dave/dst/readme.go new file mode 100644 index 000000000..7bb53bdc1 --- /dev/null +++ b/vendor/github.com/dave/dst/readme.go @@ -0,0 +1,4 @@ +package dst + +//go:generate go get github.com/dave/rebecca/cmd/becca +//go:generate becca -package=github.com/dave/dst diff --git a/vendor/github.com/dave/dst/resolve.go b/vendor/github.com/dave/dst/resolve.go new file mode 100644 index 000000000..e247bafbe --- /dev/null +++ b/vendor/github.com/dave/dst/resolve.go @@ -0,0 +1,170 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements NewPackage. + +package dst + +import ( + "fmt" + "go/scanner" + "go/token" + "strconv" +) + +type pkgBuilder struct { + fset *token.FileSet + errors scanner.ErrorList +} + +func (p *pkgBuilder) error(msg string) { + p.errors.Add(p.fset.Position(token.NoPos), msg) +} + +func (p *pkgBuilder) errorf(format string, args ...interface{}) { + p.error(fmt.Sprintf(format, args...)) +} + +func (p *pkgBuilder) declare(scope, altScope *Scope, obj *Object) { + alt := scope.Insert(obj) + if alt == nil && altScope != nil { + // see if there is a conflicting declaration in altScope + alt = altScope.Lookup(obj.Name) + } + if alt != nil { + p.error(fmt.Sprintf("%s redeclared in this block", obj.Name)) + } +} + +func resolve(scope *Scope, ident *Ident) bool { + for ; scope != nil; scope = scope.Outer { + if obj := scope.Lookup(ident.Name); obj != nil { + ident.Obj = obj + return true + } + } + return false +} + +// An Importer resolves import paths to package Objects. +// The imports map records the packages already imported, +// indexed by package id (canonical import path). +// An Importer must determine the canonical import path and +// check the map to see if it is already present in the imports map. +// If so, the Importer can return the map entry. Otherwise, the +// Importer should load the package data for the given path into +// a new *Object (pkg), record pkg in the imports map, and then +// return pkg. +type Importer func(imports map[string]*Object, path string) (pkg *Object, err error) + +// NewPackage creates a new Package node from a set of File nodes. It resolves +// unresolved identifiers across files and updates each file's Unresolved list +// accordingly. If a non-nil importer and universe scope are provided, they are +// used to resolve identifiers not declared in any of the package files. Any +// remaining unresolved identifiers are reported as undeclared. If the files +// belong to different packages, one package name is selected and files with +// different package names are reported and then ignored. +// The result is a package node and a scanner.ErrorList if there were errors. +// +func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer, universe *Scope) (*Package, error) { + var p pkgBuilder + p.fset = fset + + // complete package scope + pkgName := "" + pkgScope := NewScope(universe) + for _, file := range files { + // package names must match + switch name := file.Name.Name; { + case pkgName == "": + pkgName = name + case name != pkgName: + p.errorf("package %s; expected %s", name, pkgName) + continue // ignore this file + } + + // collect top-level file objects in package scope + for _, obj := range file.Scope.Objects { + p.declare(pkgScope, nil, obj) + } + } + + // package global mapping of imported package ids to package objects + imports := make(map[string]*Object) + + // complete file scopes with imports and resolve identifiers + for _, file := range files { + // ignore file if it belongs to a different package + // (error has already been reported) + if file.Name.Name != pkgName { + continue + } + + // build file scope by processing all imports + importErrors := false + fileScope := NewScope(pkgScope) + for _, spec := range file.Imports { + if importer == nil { + importErrors = true + continue + } + path, _ := strconv.Unquote(spec.Path.Value) + pkg, err := importer(imports, path) + if err != nil { + p.errorf("could not import %s (%s)", path, err) + importErrors = true + continue + } + // TODO(gri) If a local package name != "." is provided, + // global identifier resolution could proceed even if the + // import failed. Consider adjusting the logic here a bit. + + // local name overrides imported package name + name := pkg.Name + if spec.Name != nil { + name = spec.Name.Name + } + + // add import to file scope + if name == "." { + // merge imported scope with file scope + for _, obj := range pkg.Data.(*Scope).Objects { + p.declare(fileScope, pkgScope, obj) + } + } else if name != "_" { + // declare imported package object in file scope + // (do not re-use pkg in the file scope but create + // a new object instead; the Decl field is different + // for different files) + obj := NewObj(Pkg, name) + obj.Decl = spec + obj.Data = pkg.Data + p.declare(fileScope, pkgScope, obj) + } + } + + // resolve identifiers + if importErrors { + // don't use the universe scope without correct imports + // (objects in the universe may be shadowed by imports; + // with missing imports, identifiers might get resolved + // incorrectly to universe objects) + pkgScope.Outer = nil + } + i := 0 + for _, ident := range file.Unresolved { + if !resolve(fileScope, ident) { + p.errorf("undeclared name: %s", ident.Name) + file.Unresolved[i] = ident + i++ + } + + } + file.Unresolved = file.Unresolved[0:i] + pkgScope.Outer = universe // reset universe scope + } + + p.errors.Sort() + return &Package{pkgName, pkgScope, imports, files}, p.errors.Err() +} diff --git a/vendor/github.com/dave/dst/scope.go b/vendor/github.com/dave/dst/scope.go new file mode 100644 index 000000000..c05ab7006 --- /dev/null +++ b/vendor/github.com/dave/dst/scope.go @@ -0,0 +1,112 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements scopes and the objects they contain. + +package dst + +import ( + "bytes" + "fmt" +) + +// A Scope maintains the set of named language entities declared +// in the scope and a link to the immediately surrounding (outer) +// scope. +// +type Scope struct { + Outer *Scope + Objects map[string]*Object +} + +// NewScope creates a new scope nested in the outer scope. +func NewScope(outer *Scope) *Scope { + const n = 4 // initial scope capacity + return &Scope{outer, make(map[string]*Object, n)} +} + +// Lookup returns the object with the given name if it is +// found in scope s, otherwise it returns nil. Outer scopes +// are ignored. +// +func (s *Scope) Lookup(name string) *Object { + return s.Objects[name] +} + +// Insert attempts to insert a named object obj into the scope s. +// If the scope already contains an object alt with the same name, +// Insert leaves the scope unchanged and returns alt. Otherwise +// it inserts obj and returns nil. +// +func (s *Scope) Insert(obj *Object) (alt *Object) { + if alt = s.Objects[obj.Name]; alt == nil { + s.Objects[obj.Name] = obj + } + return +} + +// Debugging support +func (s *Scope) String() string { + var buf bytes.Buffer + fmt.Fprintf(&buf, "scope %p {", s) + if s != nil && len(s.Objects) > 0 { + fmt.Fprintln(&buf) + for _, obj := range s.Objects { + fmt.Fprintf(&buf, "\t%s %s\n", obj.Kind, obj.Name) + } + } + fmt.Fprintf(&buf, "}\n") + return buf.String() +} + +// ---------------------------------------------------------------------------- +// Objects + +// An Object describes a named language entity such as a package, +// constant, type, variable, function (incl. methods), or label. +// +// The Data fields contains object-specific data: +// +// Kind Data type Data value +// Pkg *Scope package scope +// Con int iota for the respective declaration +// +type Object struct { + Kind ObjKind + Name string // declared name + Decl interface{} // corresponding Field, XxxSpec, FuncDecl, LabeledStmt, AssignStmt, Scope; or nil + Data interface{} // object-specific data; or nil + Type interface{} // placeholder for type information; may be nil +} + +// NewObj creates a new object of a given kind and name. +func NewObj(kind ObjKind, name string) *Object { + return &Object{Kind: kind, Name: name} +} + +// ObjKind describes what an object represents. +type ObjKind int + +// The list of possible Object kinds. +const ( + Bad ObjKind = iota // for error handling + Pkg // package + Con // constant + Typ // type + Var // variable + Fun // function or method + Lbl // label +) + +var objKindStrings = [...]string{ + Bad: "bad", + Pkg: "package", + Con: "const", + Typ: "type", + Var: "var", + Fun: "func", + Lbl: "label", +} + +func (kind ObjKind) String() string { return objKindStrings[kind] } diff --git a/vendor/github.com/dave/dst/walk.go b/vendor/github.com/dave/dst/walk.go new file mode 100644 index 000000000..da7f97b29 --- /dev/null +++ b/vendor/github.com/dave/dst/walk.go @@ -0,0 +1,354 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package dst + +import "fmt" + +// A Visitor's Visit method is invoked for each node encountered by Walk. +// If the result visitor w is not nil, Walk visits each of the children +// of node with the visitor w, followed by a call of w.Visit(nil). +type Visitor interface { + Visit(node Node) (w Visitor) +} + +// Helper functions for common node lists. They may be empty. + +func walkIdentList(v Visitor, list []*Ident) { + for _, x := range list { + Walk(v, x) + } +} + +func walkExprList(v Visitor, list []Expr) { + for _, x := range list { + Walk(v, x) + } +} + +func walkStmtList(v Visitor, list []Stmt) { + for _, x := range list { + Walk(v, x) + } +} + +func walkDeclList(v Visitor, list []Decl) { + for _, x := range list { + Walk(v, x) + } +} + +// TODO(gri): Investigate if providing a closure to Walk leads to +// simpler use (and may help eliminate Inspect in turn). + +// Walk traverses an AST in depth-first order: It starts by calling +// v.Visit(node); node must not be nil. If the visitor w returned by +// v.Visit(node) is not nil, Walk is invoked recursively with visitor +// w for each of the non-nil children of node, followed by a call of +// w.Visit(nil). +// +func Walk(v Visitor, node Node) { + if v = v.Visit(node); v == nil { + return + } + + // walk children + // (the order of the cases matches the order + // of the corresponding node types in ast.go) + switch n := node.(type) { + case *Field: + walkIdentList(v, n.Names) + Walk(v, n.Type) + if n.Tag != nil { + Walk(v, n.Tag) + } + + case *FieldList: + for _, f := range n.List { + Walk(v, f) + } + + // Expressions + case *BadExpr, *Ident, *BasicLit: + // nothing to do + + case *Ellipsis: + if n.Elt != nil { + Walk(v, n.Elt) + } + + case *FuncLit: + Walk(v, n.Type) + Walk(v, n.Body) + + case *CompositeLit: + if n.Type != nil { + Walk(v, n.Type) + } + walkExprList(v, n.Elts) + + case *ParenExpr: + Walk(v, n.X) + + case *SelectorExpr: + Walk(v, n.X) + Walk(v, n.Sel) + + case *IndexExpr: + Walk(v, n.X) + Walk(v, n.Index) + + case *IndexListExpr: + Walk(v, n.X) + walkExprList(v, n.Indices) + + case *SliceExpr: + Walk(v, n.X) + if n.Low != nil { + Walk(v, n.Low) + } + if n.High != nil { + Walk(v, n.High) + } + if n.Max != nil { + Walk(v, n.Max) + } + + case *TypeAssertExpr: + Walk(v, n.X) + if n.Type != nil { + Walk(v, n.Type) + } + + case *CallExpr: + Walk(v, n.Fun) + walkExprList(v, n.Args) + + case *StarExpr: + Walk(v, n.X) + + case *UnaryExpr: + Walk(v, n.X) + + case *BinaryExpr: + Walk(v, n.X) + Walk(v, n.Y) + + case *KeyValueExpr: + Walk(v, n.Key) + Walk(v, n.Value) + + // Types + case *ArrayType: + if n.Len != nil { + Walk(v, n.Len) + } + Walk(v, n.Elt) + + case *StructType: + Walk(v, n.Fields) + + case *FuncType: + if n.TypeParams != nil { + Walk(v, n.TypeParams) + } + if n.Params != nil { + Walk(v, n.Params) + } + if n.Results != nil { + Walk(v, n.Results) + } + + case *InterfaceType: + Walk(v, n.Methods) + + case *MapType: + Walk(v, n.Key) + Walk(v, n.Value) + + case *ChanType: + Walk(v, n.Value) + + // Statements + case *BadStmt: + // nothing to do + + case *DeclStmt: + Walk(v, n.Decl) + + case *EmptyStmt: + // nothing to do + + case *LabeledStmt: + Walk(v, n.Label) + Walk(v, n.Stmt) + + case *ExprStmt: + Walk(v, n.X) + + case *SendStmt: + Walk(v, n.Chan) + Walk(v, n.Value) + + case *IncDecStmt: + Walk(v, n.X) + + case *AssignStmt: + walkExprList(v, n.Lhs) + walkExprList(v, n.Rhs) + + case *GoStmt: + Walk(v, n.Call) + + case *DeferStmt: + Walk(v, n.Call) + + case *ReturnStmt: + walkExprList(v, n.Results) + + case *BranchStmt: + if n.Label != nil { + Walk(v, n.Label) + } + + case *BlockStmt: + walkStmtList(v, n.List) + + case *IfStmt: + if n.Init != nil { + Walk(v, n.Init) + } + Walk(v, n.Cond) + Walk(v, n.Body) + if n.Else != nil { + Walk(v, n.Else) + } + + case *CaseClause: + walkExprList(v, n.List) + walkStmtList(v, n.Body) + + case *SwitchStmt: + if n.Init != nil { + Walk(v, n.Init) + } + if n.Tag != nil { + Walk(v, n.Tag) + } + Walk(v, n.Body) + + case *TypeSwitchStmt: + if n.Init != nil { + Walk(v, n.Init) + } + Walk(v, n.Assign) + Walk(v, n.Body) + + case *CommClause: + if n.Comm != nil { + Walk(v, n.Comm) + } + walkStmtList(v, n.Body) + + case *SelectStmt: + Walk(v, n.Body) + + case *ForStmt: + if n.Init != nil { + Walk(v, n.Init) + } + if n.Cond != nil { + Walk(v, n.Cond) + } + if n.Post != nil { + Walk(v, n.Post) + } + Walk(v, n.Body) + + case *RangeStmt: + if n.Key != nil { + Walk(v, n.Key) + } + if n.Value != nil { + Walk(v, n.Value) + } + Walk(v, n.X) + Walk(v, n.Body) + + // Declarations + case *ImportSpec: + if n.Name != nil { + Walk(v, n.Name) + } + Walk(v, n.Path) + + case *ValueSpec: + walkIdentList(v, n.Names) + if n.Type != nil { + Walk(v, n.Type) + } + walkExprList(v, n.Values) + + case *TypeSpec: + Walk(v, n.Name) + if n.TypeParams != nil { + Walk(v, n.TypeParams) + } + Walk(v, n.Type) + + case *BadDecl: + // nothing to do + + case *GenDecl: + for _, s := range n.Specs { + Walk(v, s) + } + + case *FuncDecl: + if n.Recv != nil { + Walk(v, n.Recv) + } + Walk(v, n.Name) + Walk(v, n.Type) + if n.Body != nil { + Walk(v, n.Body) + } + + // Files and packages + case *File: + Walk(v, n.Name) + walkDeclList(v, n.Decls) + // don't walk n.Comments - they have been + // visited already through the individual + // nodes + + case *Package: + for _, f := range n.Files { + Walk(v, f) + } + + default: + panic(fmt.Sprintf("ast.Walk: unexpected node type %T", n)) + } + + v.Visit(nil) +} + +type inspector func(Node) bool + +func (f inspector) Visit(node Node) Visitor { + if f(node) { + return f + } + return nil +} + +// Inspect traverses an AST in depth-first order: It starts by calling +// f(node); node must not be nil. If f returns true, Inspect invokes f +// recursively for each of the non-nil children of node, followed by a +// call of f(nil). +// +func Inspect(node Node, f func(Node) bool) { + Walk(inspector(f), node) +} diff --git a/vendor/github.com/dlclark/regexp2/.gitignore b/vendor/github.com/dlclark/regexp2/.gitignore new file mode 100644 index 000000000..fb844c330 --- /dev/null +++ b/vendor/github.com/dlclark/regexp2/.gitignore @@ -0,0 +1,27 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof +*.out + +.DS_Store diff --git a/vendor/github.com/dlclark/regexp2/.travis.yml b/vendor/github.com/dlclark/regexp2/.travis.yml new file mode 100644 index 000000000..a2da6be47 --- /dev/null +++ b/vendor/github.com/dlclark/regexp2/.travis.yml @@ -0,0 +1,7 @@ +language: go +arch: + - AMD64 + - ppc64le +go: + - 1.9 + - tip diff --git a/vendor/github.com/dlclark/regexp2/ATTRIB b/vendor/github.com/dlclark/regexp2/ATTRIB new file mode 100644 index 000000000..cdf4560b9 --- /dev/null +++ b/vendor/github.com/dlclark/regexp2/ATTRIB @@ -0,0 +1,133 @@ +============ +These pieces of code were ported from dotnet/corefx: + +syntax/charclass.go (from RegexCharClass.cs): ported to use the built-in Go unicode classes. Canonicalize is + a direct port, but most of the other code required large changes because the C# implementation + used a string to represent the CharSet data structure and I cleaned that up in my implementation. + +syntax/code.go (from RegexCode.cs): ported literally with various cleanups and layout to make it more Go-ish. + +syntax/escape.go (from RegexParser.cs): ported Escape method and added some optimizations. Unescape is inspired by + the C# implementation but couldn't be directly ported because of the lack of do-while syntax in Go. + +syntax/parser.go (from RegexpParser.cs and RegexOptions.cs): ported parser struct and associated methods as + literally as possible. Several language differences required changes. E.g. lack pre/post-fix increments as + expressions, lack of do-while loops, lack of overloads, etc. + +syntax/prefix.go (from RegexFCD.cs and RegexBoyerMoore.cs): ported as literally as possible and added support + for unicode chars that are longer than the 16-bit char in C# for the 32-bit rune in Go. + +syntax/replacerdata.go (from RegexReplacement.cs): conceptually ported and re-organized to handle differences + in charclass implementation, and fix odd code layout between RegexParser.cs, Regex.cs, and RegexReplacement.cs. + +syntax/tree.go (from RegexTree.cs and RegexNode.cs): ported literally as possible. + +syntax/writer.go (from RegexWriter.cs): ported literally with minor changes to make it more Go-ish. + +match.go (from RegexMatch.cs): ported, simplified, and changed to handle Go's lack of inheritence. + +regexp.go (from Regex.cs and RegexOptions.cs): conceptually serves the same "starting point", but is simplified + and changed to handle differences in C# strings and Go strings/runes. + +replace.go (from RegexReplacement.cs): ported closely and then cleaned up to combine the MatchEvaluator and + simple string replace implementations. + +runner.go (from RegexRunner.cs): ported literally as possible. + +regexp_test.go (from CaptureTests.cs and GroupNamesAndNumbers.cs): conceptually ported, but the code was + manually structured like Go tests. + +replace_test.go (from RegexReplaceStringTest0.cs): conceptually ported + +rtl_test.go (from RightToLeft.cs): conceptually ported +--- +dotnet/corefx was released under this license: + +The MIT License (MIT) + +Copyright (c) Microsoft Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +============ +These pieces of code are copied from the Go framework: + +- The overall directory structure of regexp2 was inspired by the Go runtime regexp package. +- The optimization in the escape method of syntax/escape.go is from the Go runtime QuoteMeta() func in regexp/regexp.go +- The method signatures in regexp.go are designed to match the Go framework regexp methods closely +- func regexp2.MustCompile and func quote are almost identifical to the regexp package versions +- BenchmarkMatch* and TestProgramTooLong* funcs in regexp_performance_test.go were copied from the framework + regexp/exec_test.go +--- +The Go framework was released under this license: + +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +============ +Some test data were gathered from the Mono project. + +regexp_mono_test.go: ported from https://github.com/mono/mono/blob/master/mcs/class/System/Test/System.Text.RegularExpressions/PerlTrials.cs +--- +Mono tests released under this license: + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/vendor/github.com/shazow/go-diff/LICENSE b/vendor/github.com/dlclark/regexp2/LICENSE similarity index 96% rename from vendor/github.com/shazow/go-diff/LICENSE rename to vendor/github.com/dlclark/regexp2/LICENSE index 85e1e4b33..fe83dfdc9 100644 --- a/vendor/github.com/shazow/go-diff/LICENSE +++ b/vendor/github.com/dlclark/regexp2/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2015 Andrey Petrov +Copyright (c) Doug Clark Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -19,4 +19,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/vendor/github.com/dlclark/regexp2/README.md b/vendor/github.com/dlclark/regexp2/README.md new file mode 100644 index 000000000..9cbc1d8d0 --- /dev/null +++ b/vendor/github.com/dlclark/regexp2/README.md @@ -0,0 +1,174 @@ +# regexp2 - full featured regular expressions for Go +Regexp2 is a feature-rich RegExp engine for Go. It doesn't have constant time guarantees like the built-in `regexp` package, but it allows backtracking and is compatible with Perl5 and .NET. You'll likely be better off with the RE2 engine from the `regexp` package and should only use this if you need to write very complex patterns or require compatibility with .NET. + +## Basis of the engine +The engine is ported from the .NET framework's System.Text.RegularExpressions.Regex engine. That engine was open sourced in 2015 under the MIT license. There are some fundamental differences between .NET strings and Go strings that required a bit of borrowing from the Go framework regex engine as well. I cleaned up a couple of the dirtier bits during the port (regexcharclass.cs was terrible), but the parse tree, code emmitted, and therefore patterns matched should be identical. + +## New Code Generation +For extra performance use `regexp2` with [`regexp2cg`](https://github.com/dlclark/regexp2cg). It is a code generation utility for `regexp2` and you can likely improve your regexp runtime performance by 3-10x in hot code paths. As always you should benchmark your specifics to confirm the results. Give it a try! + +## Installing +This is a go-gettable library, so install is easy: + + go get github.com/dlclark/regexp2 + +To use the new Code Generation (while it's in beta) you'll need to use the `code_gen` branch: + + go get github.com/dlclark/regexp2@code_gen + +## Usage +Usage is similar to the Go `regexp` package. Just like in `regexp`, you start by converting a regex into a state machine via the `Compile` or `MustCompile` methods. They ultimately do the same thing, but `MustCompile` will panic if the regex is invalid. You can then use the provided `Regexp` struct to find matches repeatedly. A `Regexp` struct is safe to use across goroutines. + +```go +re := regexp2.MustCompile(`Your pattern`, 0) +if isMatch, _ := re.MatchString(`Something to match`); isMatch { + //do something +} +``` + +The only error that the `*Match*` methods *should* return is a Timeout if you set the `re.MatchTimeout` field. Any other error is a bug in the `regexp2` package. If you need more details about capture groups in a match then use the `FindStringMatch` method, like so: + +```go +if m, _ := re.FindStringMatch(`Something to match`); m != nil { + // the whole match is always group 0 + fmt.Printf("Group 0: %v\n", m.String()) + + // you can get all the groups too + gps := m.Groups() + + // a group can be captured multiple times, so each cap is separately addressable + fmt.Printf("Group 1, first capture", gps[1].Captures[0].String()) + fmt.Printf("Group 1, second capture", gps[1].Captures[1].String()) +} +``` + +Group 0 is embedded in the Match. Group 0 is an automatically-assigned group that encompasses the whole pattern. This means that `m.String()` is the same as `m.Group.String()` and `m.Groups()[0].String()` + +The __last__ capture is embedded in each group, so `g.String()` will return the same thing as `g.Capture.String()` and `g.Captures[len(g.Captures)-1].String()`. + +If you want to find multiple matches from a single input string you should use the `FindNextMatch` method. For example, to implement a function similar to `regexp.FindAllString`: + +```go +func regexp2FindAllString(re *regexp2.Regexp, s string) []string { + var matches []string + m, _ := re.FindStringMatch(s) + for m != nil { + matches = append(matches, m.String()) + m, _ = re.FindNextMatch(m) + } + return matches +} +``` + +`FindNextMatch` is optmized so that it re-uses the underlying string/rune slice. + +The internals of `regexp2` always operate on `[]rune` so `Index` and `Length` data in a `Match` always reference a position in `rune`s rather than `byte`s (even if the input was given as a string). This is a dramatic difference between `regexp` and `regexp2`. It's advisable to use the provided `String()` methods to avoid having to work with indices. + +## Compare `regexp` and `regexp2` +| Category | regexp | regexp2 | +| --- | --- | --- | +| Catastrophic backtracking possible | no, constant execution time guarantees | yes, if your pattern is at risk you can use the `re.MatchTimeout` field | +| Python-style capture groups `(?Pre)` | yes | no (yes in RE2 compat mode) | +| .NET-style capture groups `(?re)` or `(?'name're)` | no | yes | +| comments `(?#comment)` | no | yes | +| branch numbering reset `(?\|a\|b)` | no | no | +| possessive match `(?>re)` | no | yes | +| positive lookahead `(?=re)` | no | yes | +| negative lookahead `(?!re)` | no | yes | +| positive lookbehind `(?<=re)` | no | yes | +| negative lookbehind `(?re)`) +* change singleline behavior for `$` to only match end of string (like RE2) (see [#24](https://github.com/dlclark/regexp2/issues/24)) +* change the character classes `\d` `\s` and `\w` to match the same characters as RE2. NOTE: if you also use the `ECMAScript` option then this will change the `\s` character class to match ECMAScript instead of RE2. ECMAScript allows more whitespace characters in `\s` than RE2 (but still fewer than the the default behavior). +* allow character escape sequences to have defaults. For example, by default `\_` isn't a known character escape and will fail to compile, but in RE2 mode it will match the literal character `_` + +```go +re := regexp2.MustCompile(`Your RE2-compatible pattern`, regexp2.RE2) +if isMatch, _ := re.MatchString(`Something to match`); isMatch { + //do something +} +``` + +This feature is a work in progress and I'm open to ideas for more things to put here (maybe more relaxed character escaping rules?). + +## Catastrophic Backtracking and Timeouts + +`regexp2` supports features that can lead to catastrophic backtracking. +`Regexp.MatchTimeout` can be set to to limit the impact of such behavior; the +match will fail with an error after approximately MatchTimeout. No timeout +checks are done by default. + +Timeout checking is not free. The current timeout checking implementation starts +a background worker that updates a clock value approximately once every 100 +milliseconds. The matching code compares this value against the precomputed +deadline for the match. The performance impact is as follows. + +1. A match with a timeout runs almost as fast as a match without a timeout. +2. If any live matches have a timeout, there will be a background CPU load + (`~0.15%` currently on a modern machine). This load will remain constant + regardless of the number of matches done including matches done in parallel. +3. If no live matches are using a timeout, the background load will remain + until the longest deadline (match timeout + the time when the match started) + is reached. E.g., if you set a timeout of one minute the load will persist + for approximately a minute even if the match finishes quickly. + +See [PR #58](https://github.com/dlclark/regexp2/pull/58) for more details and +alternatives considered. + +## Goroutine leak error +If you're using a library during unit tests (e.g. https://github.com/uber-go/goleak) that validates all goroutines are exited then you'll likely get an error if you or any of your dependencies use regex's with a MatchTimeout. +To remedy the problem you'll need to tell the unit test to wait until the backgroup timeout goroutine is exited. + +```go +func TestSomething(t *testing.T) { + defer goleak.VerifyNone(t) + defer regexp2.StopTimeoutClock() + + // ... test +} + +//or + +func TestMain(m *testing.M) { + // setup + // ... + + // run + m.Run() + + //tear down + regexp2.StopTimeoutClock() + goleak.VerifyNone(t) +} +``` + +This will add ~100ms runtime to each test (or TestMain). If that's too much time you can set the clock cycle rate of the timeout goroutine in an init function in a test file. `regexp2.SetTimeoutCheckPeriod` isn't threadsafe so it must be setup before starting any regex's with Timeouts. + +```go +func init() { + //speed up testing by making the timeout clock 1ms + regexp2.SetTimeoutCheckPeriod(time.Millisecond) +} +``` + +## ECMAScript compatibility mode +In this mode the engine provides compatibility with the [regex engine](https://tc39.es/ecma262/multipage/text-processing.html#sec-regexp-regular-expression-objects) described in the ECMAScript specification. + +Additionally a Unicode mode is provided which allows parsing of `\u{CodePoint}` syntax that is only when both are provided. + +## Library features that I'm still working on +- Regex split + +## Potential bugs +I've run a battery of tests against regexp2 from various sources and found the debug output matches the .NET engine, but .NET and Go handle strings very differently. I've attempted to handle these differences, but most of my testing deals with basic ASCII with a little bit of multi-byte Unicode. There's a chance that there are bugs in the string handling related to character sets with supplementary Unicode chars. Right-to-Left support is coded, but not well tested either. + +## Find a bug? +I'm open to new issues and pull requests with tests if you find something odd! diff --git a/vendor/github.com/dlclark/regexp2/fastclock.go b/vendor/github.com/dlclark/regexp2/fastclock.go new file mode 100644 index 000000000..d256e63c7 --- /dev/null +++ b/vendor/github.com/dlclark/regexp2/fastclock.go @@ -0,0 +1,141 @@ +package regexp2 + +import ( + "sync" + "sync/atomic" + "time" +) + +// fasttime holds a time value (ticks since clock initialization) +type fasttime int64 + +// fastclock provides a fast clock implementation. +// +// A background goroutine periodically stores the current time +// into an atomic variable. +// +// A deadline can be quickly checked for expiration by comparing +// its value to the clock stored in the atomic variable. +// +// The goroutine automatically stops once clockEnd is reached. +// (clockEnd covers the largest deadline seen so far + some +// extra time). This ensures that if regexp2 with timeouts +// stops being used we will stop background work. +type fastclock struct { + // instances of atomicTime must be at the start of the struct (or at least 64-bit aligned) + // otherwise 32-bit architectures will panic + + current atomicTime // Current time (approximate) + clockEnd atomicTime // When clock updater is supposed to stop (>= any existing deadline) + + // current and clockEnd can be read via atomic loads. + // Reads and writes of other fields require mu to be held. + mu sync.Mutex + start time.Time // Time corresponding to fasttime(0) + running bool // Is a clock updater running? +} + +var fast fastclock + +// reached returns true if current time is at or past t. +func (t fasttime) reached() bool { + return fast.current.read() >= t +} + +// makeDeadline returns a time that is approximately time.Now().Add(d) +func makeDeadline(d time.Duration) fasttime { + // Increase the deadline since the clock we are reading may be + // just about to tick forwards. + end := fast.current.read() + durationToTicks(d+clockPeriod) + + // Start or extend clock if necessary. + if end > fast.clockEnd.read() { + // If time.Since(last use) > timeout, there's a chance that + // fast.current will no longer be updated, which can lead to + // incorrect 'end' calculations that can trigger a false timeout + fast.mu.Lock() + if !fast.running && !fast.start.IsZero() { + // update fast.current + fast.current.write(durationToTicks(time.Since(fast.start))) + // recalculate our end value + end = fast.current.read() + durationToTicks(d+clockPeriod) + } + fast.mu.Unlock() + extendClock(end) + } + + return end +} + +// extendClock ensures that clock is live and will run until at least end. +func extendClock(end fasttime) { + fast.mu.Lock() + defer fast.mu.Unlock() + + if fast.start.IsZero() { + fast.start = time.Now() + } + + // Extend the running time to cover end as well as a bit of slop. + if shutdown := end + durationToTicks(time.Second); shutdown > fast.clockEnd.read() { + fast.clockEnd.write(shutdown) + } + + // Start clock if necessary + if !fast.running { + fast.running = true + go runClock() + } +} + +// stop the timeout clock in the background +// should only used for unit tests to abandon the background goroutine +func stopClock() { + fast.mu.Lock() + if fast.running { + fast.clockEnd.write(fasttime(0)) + } + fast.mu.Unlock() + + // pause until not running + // get and release the lock + isRunning := true + for isRunning { + time.Sleep(clockPeriod / 2) + fast.mu.Lock() + isRunning = fast.running + fast.mu.Unlock() + } +} + +func durationToTicks(d time.Duration) fasttime { + // Downscale nanoseconds to approximately a millisecond so that we can avoid + // overflow even if the caller passes in math.MaxInt64. + return fasttime(d) >> 20 +} + +const DefaultClockPeriod = 100 * time.Millisecond + +// clockPeriod is the approximate interval between updates of approximateClock. +var clockPeriod = DefaultClockPeriod + +func runClock() { + fast.mu.Lock() + defer fast.mu.Unlock() + + for fast.current.read() <= fast.clockEnd.read() { + // Unlock while sleeping. + fast.mu.Unlock() + time.Sleep(clockPeriod) + fast.mu.Lock() + + newTime := durationToTicks(time.Since(fast.start)) + fast.current.write(newTime) + } + fast.running = false +} + +type atomicTime struct{ v int64 } // Should change to atomic.Int64 when we can use go 1.19 + +func (t *atomicTime) read() fasttime { return fasttime(atomic.LoadInt64(&t.v)) } +func (t *atomicTime) write(v fasttime) { atomic.StoreInt64(&t.v, int64(v)) } diff --git a/vendor/github.com/dlclark/regexp2/match.go b/vendor/github.com/dlclark/regexp2/match.go new file mode 100644 index 000000000..759cf8ccf --- /dev/null +++ b/vendor/github.com/dlclark/regexp2/match.go @@ -0,0 +1,349 @@ +package regexp2 + +import ( + "bytes" + "fmt" +) + +// Match is a single regex result match that contains groups and repeated captures +// +// -Groups +// -Capture +type Match struct { + Group //embeded group 0 + + regex *Regexp + otherGroups []Group + + // input to the match + textpos int + textstart int + + capcount int + caps []int + sparseCaps map[int]int + + // output from the match + matches [][]int + matchcount []int + + // whether we've done any balancing with this match. If we + // have done balancing, we'll need to do extra work in Tidy(). + balancing bool +} + +// Group is an explicit or implit (group 0) matched group within the pattern +type Group struct { + Capture // the last capture of this group is embeded for ease of use + + Name string // group name + Captures []Capture // captures of this group +} + +// Capture is a single capture of text within the larger original string +type Capture struct { + // the original string + text []rune + // Index is the position in the underlying rune slice where the first character of + // captured substring was found. Even if you pass in a string this will be in Runes. + Index int + // Length is the number of runes in the captured substring. + Length int +} + +// String returns the captured text as a String +func (c *Capture) String() string { + return string(c.text[c.Index : c.Index+c.Length]) +} + +// Runes returns the captured text as a rune slice +func (c *Capture) Runes() []rune { + return c.text[c.Index : c.Index+c.Length] +} + +func newMatch(regex *Regexp, capcount int, text []rune, startpos int) *Match { + m := Match{ + regex: regex, + matchcount: make([]int, capcount), + matches: make([][]int, capcount), + textstart: startpos, + balancing: false, + } + m.Name = "0" + m.text = text + m.matches[0] = make([]int, 2) + return &m +} + +func newMatchSparse(regex *Regexp, caps map[int]int, capcount int, text []rune, startpos int) *Match { + m := newMatch(regex, capcount, text, startpos) + m.sparseCaps = caps + return m +} + +func (m *Match) reset(text []rune, textstart int) { + m.text = text + m.textstart = textstart + for i := 0; i < len(m.matchcount); i++ { + m.matchcount[i] = 0 + } + m.balancing = false +} + +func (m *Match) tidy(textpos int) { + + interval := m.matches[0] + m.Index = interval[0] + m.Length = interval[1] + m.textpos = textpos + m.capcount = m.matchcount[0] + //copy our root capture to the list + m.Group.Captures = []Capture{m.Group.Capture} + + if m.balancing { + // The idea here is that we want to compact all of our unbalanced captures. To do that we + // use j basically as a count of how many unbalanced captures we have at any given time + // (really j is an index, but j/2 is the count). First we skip past all of the real captures + // until we find a balance captures. Then we check each subsequent entry. If it's a balance + // capture (it's negative), we decrement j. If it's a real capture, we increment j and copy + // it down to the last free position. + for cap := 0; cap < len(m.matchcount); cap++ { + limit := m.matchcount[cap] * 2 + matcharray := m.matches[cap] + + var i, j int + + for i = 0; i < limit; i++ { + if matcharray[i] < 0 { + break + } + } + + for j = i; i < limit; i++ { + if matcharray[i] < 0 { + // skip negative values + j-- + } else { + // but if we find something positive (an actual capture), copy it back to the last + // unbalanced position. + if i != j { + matcharray[j] = matcharray[i] + } + j++ + } + } + + m.matchcount[cap] = j / 2 + } + + m.balancing = false + } +} + +// isMatched tells if a group was matched by capnum +func (m *Match) isMatched(cap int) bool { + return cap < len(m.matchcount) && m.matchcount[cap] > 0 && m.matches[cap][m.matchcount[cap]*2-1] != (-3+1) +} + +// matchIndex returns the index of the last specified matched group by capnum +func (m *Match) matchIndex(cap int) int { + i := m.matches[cap][m.matchcount[cap]*2-2] + if i >= 0 { + return i + } + + return m.matches[cap][-3-i] +} + +// matchLength returns the length of the last specified matched group by capnum +func (m *Match) matchLength(cap int) int { + i := m.matches[cap][m.matchcount[cap]*2-1] + if i >= 0 { + return i + } + + return m.matches[cap][-3-i] +} + +// Nonpublic builder: add a capture to the group specified by "c" +func (m *Match) addMatch(c, start, l int) { + + if m.matches[c] == nil { + m.matches[c] = make([]int, 2) + } + + capcount := m.matchcount[c] + + if capcount*2+2 > len(m.matches[c]) { + oldmatches := m.matches[c] + newmatches := make([]int, capcount*8) + copy(newmatches, oldmatches[:capcount*2]) + m.matches[c] = newmatches + } + + m.matches[c][capcount*2] = start + m.matches[c][capcount*2+1] = l + m.matchcount[c] = capcount + 1 + //log.Printf("addMatch: c=%v, i=%v, l=%v ... matches: %v", c, start, l, m.matches) +} + +// Nonpublic builder: Add a capture to balance the specified group. This is used by the +// +// balanced match construct. (?...) +// +// If there were no such thing as backtracking, this would be as simple as calling RemoveMatch(c). +// However, since we have backtracking, we need to keep track of everything. +func (m *Match) balanceMatch(c int) { + m.balancing = true + + // we'll look at the last capture first + capcount := m.matchcount[c] + target := capcount*2 - 2 + + // first see if it is negative, and therefore is a reference to the next available + // capture group for balancing. If it is, we'll reset target to point to that capture. + if m.matches[c][target] < 0 { + target = -3 - m.matches[c][target] + } + + // move back to the previous capture + target -= 2 + + // if the previous capture is a reference, just copy that reference to the end. Otherwise, point to it. + if target >= 0 && m.matches[c][target] < 0 { + m.addMatch(c, m.matches[c][target], m.matches[c][target+1]) + } else { + m.addMatch(c, -3-target, -4-target /* == -3 - (target + 1) */) + } +} + +// Nonpublic builder: removes a group match by capnum +func (m *Match) removeMatch(c int) { + m.matchcount[c]-- +} + +// GroupCount returns the number of groups this match has matched +func (m *Match) GroupCount() int { + return len(m.matchcount) +} + +// GroupByName returns a group based on the name of the group, or nil if the group name does not exist +func (m *Match) GroupByName(name string) *Group { + num := m.regex.GroupNumberFromName(name) + if num < 0 { + return nil + } + return m.GroupByNumber(num) +} + +// GroupByNumber returns a group based on the number of the group, or nil if the group number does not exist +func (m *Match) GroupByNumber(num int) *Group { + // check our sparse map + if m.sparseCaps != nil { + if newNum, ok := m.sparseCaps[num]; ok { + num = newNum + } + } + if num >= len(m.matchcount) || num < 0 { + return nil + } + + if num == 0 { + return &m.Group + } + + m.populateOtherGroups() + + return &m.otherGroups[num-1] +} + +// Groups returns all the capture groups, starting with group 0 (the full match) +func (m *Match) Groups() []Group { + m.populateOtherGroups() + g := make([]Group, len(m.otherGroups)+1) + g[0] = m.Group + copy(g[1:], m.otherGroups) + return g +} + +func (m *Match) populateOtherGroups() { + // Construct all the Group objects first time called + if m.otherGroups == nil { + m.otherGroups = make([]Group, len(m.matchcount)-1) + for i := 0; i < len(m.otherGroups); i++ { + m.otherGroups[i] = newGroup(m.regex.GroupNameFromNumber(i+1), m.text, m.matches[i+1], m.matchcount[i+1]) + } + } +} + +func (m *Match) groupValueAppendToBuf(groupnum int, buf *bytes.Buffer) { + c := m.matchcount[groupnum] + if c == 0 { + return + } + + matches := m.matches[groupnum] + + index := matches[(c-1)*2] + last := index + matches[(c*2)-1] + + for ; index < last; index++ { + buf.WriteRune(m.text[index]) + } +} + +func newGroup(name string, text []rune, caps []int, capcount int) Group { + g := Group{} + g.text = text + if capcount > 0 { + g.Index = caps[(capcount-1)*2] + g.Length = caps[(capcount*2)-1] + } + g.Name = name + g.Captures = make([]Capture, capcount) + for i := 0; i < capcount; i++ { + g.Captures[i] = Capture{ + text: text, + Index: caps[i*2], + Length: caps[i*2+1], + } + } + //log.Printf("newGroup! capcount %v, %+v", capcount, g) + + return g +} + +func (m *Match) dump() string { + buf := &bytes.Buffer{} + buf.WriteRune('\n') + if len(m.sparseCaps) > 0 { + for k, v := range m.sparseCaps { + fmt.Fprintf(buf, "Slot %v -> %v\n", k, v) + } + } + + for i, g := range m.Groups() { + fmt.Fprintf(buf, "Group %v (%v), %v caps:\n", i, g.Name, len(g.Captures)) + + for _, c := range g.Captures { + fmt.Fprintf(buf, " (%v, %v) %v\n", c.Index, c.Length, c.String()) + } + } + /* + for i := 0; i < len(m.matchcount); i++ { + fmt.Fprintf(buf, "\nGroup %v (%v):\n", i, m.regex.GroupNameFromNumber(i)) + + for j := 0; j < m.matchcount[i]; j++ { + text := "" + + if m.matches[i][j*2] >= 0 { + start := m.matches[i][j*2] + text = m.text[start : start+m.matches[i][j*2+1]] + } + + fmt.Fprintf(buf, " (%v, %v) %v\n", m.matches[i][j*2], m.matches[i][j*2+1], text) + } + } + */ + return buf.String() +} diff --git a/vendor/github.com/dlclark/regexp2/regexp.go b/vendor/github.com/dlclark/regexp2/regexp.go new file mode 100644 index 000000000..a7ddbaf35 --- /dev/null +++ b/vendor/github.com/dlclark/regexp2/regexp.go @@ -0,0 +1,395 @@ +/* +Package regexp2 is a regexp package that has an interface similar to Go's framework regexp engine but uses a +more feature full regex engine behind the scenes. + +It doesn't have constant time guarantees, but it allows backtracking and is compatible with Perl5 and .NET. +You'll likely be better off with the RE2 engine from the regexp package and should only use this if you +need to write very complex patterns or require compatibility with .NET. +*/ +package regexp2 + +import ( + "errors" + "math" + "strconv" + "sync" + "time" + + "github.com/dlclark/regexp2/syntax" +) + +var ( + // DefaultMatchTimeout used when running regexp matches -- "forever" + DefaultMatchTimeout = time.Duration(math.MaxInt64) + // DefaultUnmarshalOptions used when unmarshaling a regex from text + DefaultUnmarshalOptions = None +) + +// Regexp is the representation of a compiled regular expression. +// A Regexp is safe for concurrent use by multiple goroutines. +type Regexp struct { + // A match will time out if it takes (approximately) more than + // MatchTimeout. This is a safety check in case the match + // encounters catastrophic backtracking. The default value + // (DefaultMatchTimeout) causes all time out checking to be + // suppressed. + MatchTimeout time.Duration + + // read-only after Compile + pattern string // as passed to Compile + options RegexOptions // options + + caps map[int]int // capnum->index + capnames map[string]int //capture group name -> index + capslist []string //sorted list of capture group names + capsize int // size of the capture array + + code *syntax.Code // compiled program + + // cache of machines for running regexp + muRun *sync.Mutex + runner []*runner +} + +// Compile parses a regular expression and returns, if successful, +// a Regexp object that can be used to match against text. +func Compile(expr string, opt RegexOptions) (*Regexp, error) { + // parse it + tree, err := syntax.Parse(expr, syntax.RegexOptions(opt)) + if err != nil { + return nil, err + } + + // translate it to code + code, err := syntax.Write(tree) + if err != nil { + return nil, err + } + + // return it + return &Regexp{ + pattern: expr, + options: opt, + caps: code.Caps, + capnames: tree.Capnames, + capslist: tree.Caplist, + capsize: code.Capsize, + code: code, + MatchTimeout: DefaultMatchTimeout, + muRun: &sync.Mutex{}, + }, nil +} + +// MustCompile is like Compile but panics if the expression cannot be parsed. +// It simplifies safe initialization of global variables holding compiled regular +// expressions. +func MustCompile(str string, opt RegexOptions) *Regexp { + regexp, error := Compile(str, opt) + if error != nil { + panic(`regexp2: Compile(` + quote(str) + `): ` + error.Error()) + } + return regexp +} + +// Escape adds backslashes to any special characters in the input string +func Escape(input string) string { + return syntax.Escape(input) +} + +// Unescape removes any backslashes from previously-escaped special characters in the input string +func Unescape(input string) (string, error) { + return syntax.Unescape(input) +} + +// SetTimeoutPeriod is a debug function that sets the frequency of the timeout goroutine's sleep cycle. +// Defaults to 100ms. The only benefit of setting this lower is that the 1 background goroutine that manages +// timeouts may exit slightly sooner after all the timeouts have expired. See Github issue #63 +func SetTimeoutCheckPeriod(d time.Duration) { + clockPeriod = d +} + +// StopTimeoutClock should only be used in unit tests to prevent the timeout clock goroutine +// from appearing like a leaking goroutine +func StopTimeoutClock() { + stopClock() +} + +// String returns the source text used to compile the regular expression. +func (re *Regexp) String() string { + return re.pattern +} + +func quote(s string) string { + if strconv.CanBackquote(s) { + return "`" + s + "`" + } + return strconv.Quote(s) +} + +// RegexOptions impact the runtime and parsing behavior +// for each specific regex. They are setable in code as well +// as in the regex pattern itself. +type RegexOptions int32 + +const ( + None RegexOptions = 0x0 + IgnoreCase = 0x0001 // "i" + Multiline = 0x0002 // "m" + ExplicitCapture = 0x0004 // "n" + Compiled = 0x0008 // "c" + Singleline = 0x0010 // "s" + IgnorePatternWhitespace = 0x0020 // "x" + RightToLeft = 0x0040 // "r" + Debug = 0x0080 // "d" + ECMAScript = 0x0100 // "e" + RE2 = 0x0200 // RE2 (regexp package) compatibility mode + Unicode = 0x0400 // "u" +) + +func (re *Regexp) RightToLeft() bool { + return re.options&RightToLeft != 0 +} + +func (re *Regexp) Debug() bool { + return re.options&Debug != 0 +} + +// Replace searches the input string and replaces each match found with the replacement text. +// Count will limit the number of matches attempted and startAt will allow +// us to skip past possible matches at the start of the input (left or right depending on RightToLeft option). +// Set startAt and count to -1 to go through the whole string +func (re *Regexp) Replace(input, replacement string, startAt, count int) (string, error) { + data, err := syntax.NewReplacerData(replacement, re.caps, re.capsize, re.capnames, syntax.RegexOptions(re.options)) + if err != nil { + return "", err + } + //TODO: cache ReplacerData + + return replace(re, data, nil, input, startAt, count) +} + +// ReplaceFunc searches the input string and replaces each match found using the string from the evaluator +// Count will limit the number of matches attempted and startAt will allow +// us to skip past possible matches at the start of the input (left or right depending on RightToLeft option). +// Set startAt and count to -1 to go through the whole string. +func (re *Regexp) ReplaceFunc(input string, evaluator MatchEvaluator, startAt, count int) (string, error) { + return replace(re, nil, evaluator, input, startAt, count) +} + +// FindStringMatch searches the input string for a Regexp match +func (re *Regexp) FindStringMatch(s string) (*Match, error) { + // convert string to runes + return re.run(false, -1, getRunes(s)) +} + +// FindRunesMatch searches the input rune slice for a Regexp match +func (re *Regexp) FindRunesMatch(r []rune) (*Match, error) { + return re.run(false, -1, r) +} + +// FindStringMatchStartingAt searches the input string for a Regexp match starting at the startAt index +func (re *Regexp) FindStringMatchStartingAt(s string, startAt int) (*Match, error) { + if startAt > len(s) { + return nil, errors.New("startAt must be less than the length of the input string") + } + r, startAt := re.getRunesAndStart(s, startAt) + if startAt == -1 { + // we didn't find our start index in the string -- that's a problem + return nil, errors.New("startAt must align to the start of a valid rune in the input string") + } + + return re.run(false, startAt, r) +} + +// FindRunesMatchStartingAt searches the input rune slice for a Regexp match starting at the startAt index +func (re *Regexp) FindRunesMatchStartingAt(r []rune, startAt int) (*Match, error) { + return re.run(false, startAt, r) +} + +// FindNextMatch returns the next match in the same input string as the match parameter. +// Will return nil if there is no next match or if given a nil match. +func (re *Regexp) FindNextMatch(m *Match) (*Match, error) { + if m == nil { + return nil, nil + } + + // If previous match was empty, advance by one before matching to prevent + // infinite loop + startAt := m.textpos + if m.Length == 0 { + if m.textpos == len(m.text) { + return nil, nil + } + + if re.RightToLeft() { + startAt-- + } else { + startAt++ + } + } + return re.run(false, startAt, m.text) +} + +// MatchString return true if the string matches the regex +// error will be set if a timeout occurs +func (re *Regexp) MatchString(s string) (bool, error) { + m, err := re.run(true, -1, getRunes(s)) + if err != nil { + return false, err + } + return m != nil, nil +} + +func (re *Regexp) getRunesAndStart(s string, startAt int) ([]rune, int) { + if startAt < 0 { + if re.RightToLeft() { + r := getRunes(s) + return r, len(r) + } + return getRunes(s), 0 + } + ret := make([]rune, len(s)) + i := 0 + runeIdx := -1 + for strIdx, r := range s { + if strIdx == startAt { + runeIdx = i + } + ret[i] = r + i++ + } + if startAt == len(s) { + runeIdx = i + } + return ret[:i], runeIdx +} + +func getRunes(s string) []rune { + return []rune(s) +} + +// MatchRunes return true if the runes matches the regex +// error will be set if a timeout occurs +func (re *Regexp) MatchRunes(r []rune) (bool, error) { + m, err := re.run(true, -1, r) + if err != nil { + return false, err + } + return m != nil, nil +} + +// GetGroupNames Returns the set of strings used to name capturing groups in the expression. +func (re *Regexp) GetGroupNames() []string { + var result []string + + if re.capslist == nil { + result = make([]string, re.capsize) + + for i := 0; i < len(result); i++ { + result[i] = strconv.Itoa(i) + } + } else { + result = make([]string, len(re.capslist)) + copy(result, re.capslist) + } + + return result +} + +// GetGroupNumbers returns the integer group numbers corresponding to a group name. +func (re *Regexp) GetGroupNumbers() []int { + var result []int + + if re.caps == nil { + result = make([]int, re.capsize) + + for i := 0; i < len(result); i++ { + result[i] = i + } + } else { + result = make([]int, len(re.caps)) + + for k, v := range re.caps { + result[v] = k + } + } + + return result +} + +// GroupNameFromNumber retrieves a group name that corresponds to a group number. +// It will return "" for and unknown group number. Unnamed groups automatically +// receive a name that is the decimal string equivalent of its number. +func (re *Regexp) GroupNameFromNumber(i int) string { + if re.capslist == nil { + if i >= 0 && i < re.capsize { + return strconv.Itoa(i) + } + + return "" + } + + if re.caps != nil { + var ok bool + if i, ok = re.caps[i]; !ok { + return "" + } + } + + if i >= 0 && i < len(re.capslist) { + return re.capslist[i] + } + + return "" +} + +// GroupNumberFromName returns a group number that corresponds to a group name. +// Returns -1 if the name is not a recognized group name. Numbered groups +// automatically get a group name that is the decimal string equivalent of its number. +func (re *Regexp) GroupNumberFromName(name string) int { + // look up name if we have a hashtable of names + if re.capnames != nil { + if k, ok := re.capnames[name]; ok { + return k + } + + return -1 + } + + // convert to an int if it looks like a number + result := 0 + for i := 0; i < len(name); i++ { + ch := name[i] + + if ch > '9' || ch < '0' { + return -1 + } + + result *= 10 + result += int(ch - '0') + } + + // return int if it's in range + if result >= 0 && result < re.capsize { + return result + } + + return -1 +} + +// MarshalText implements [encoding.TextMarshaler]. The output +// matches that of calling the [Regexp.String] method. +func (re *Regexp) MarshalText() ([]byte, error) { + return []byte(re.String()), nil +} + +// UnmarshalText implements [encoding.TextUnmarshaler] by calling +// [Compile] on the encoded value. +func (re *Regexp) UnmarshalText(text []byte) error { + newRE, err := Compile(string(text), DefaultUnmarshalOptions) + if err != nil { + return err + } + *re = *newRE + return nil +} diff --git a/vendor/github.com/dlclark/regexp2/replace.go b/vendor/github.com/dlclark/regexp2/replace.go new file mode 100644 index 000000000..0376bd9d3 --- /dev/null +++ b/vendor/github.com/dlclark/regexp2/replace.go @@ -0,0 +1,177 @@ +package regexp2 + +import ( + "bytes" + "errors" + + "github.com/dlclark/regexp2/syntax" +) + +const ( + replaceSpecials = 4 + replaceLeftPortion = -1 + replaceRightPortion = -2 + replaceLastGroup = -3 + replaceWholeString = -4 +) + +// MatchEvaluator is a function that takes a match and returns a replacement string to be used +type MatchEvaluator func(Match) string + +// Three very similar algorithms appear below: replace (pattern), +// replace (evaluator), and split. + +// Replace Replaces all occurrences of the regex in the string with the +// replacement pattern. +// +// Note that the special case of no matches is handled on its own: +// with no matches, the input string is returned unchanged. +// The right-to-left case is split out because StringBuilder +// doesn't handle right-to-left string building directly very well. +func replace(regex *Regexp, data *syntax.ReplacerData, evaluator MatchEvaluator, input string, startAt, count int) (string, error) { + if count < -1 { + return "", errors.New("Count too small") + } + if count == 0 { + return "", nil + } + + m, err := regex.FindStringMatchStartingAt(input, startAt) + + if err != nil { + return "", err + } + if m == nil { + return input, nil + } + + buf := &bytes.Buffer{} + text := m.text + + if !regex.RightToLeft() { + prevat := 0 + for m != nil { + if m.Index != prevat { + buf.WriteString(string(text[prevat:m.Index])) + } + prevat = m.Index + m.Length + if evaluator == nil { + replacementImpl(data, buf, m) + } else { + buf.WriteString(evaluator(*m)) + } + + count-- + if count == 0 { + break + } + m, err = regex.FindNextMatch(m) + if err != nil { + return "", nil + } + } + + if prevat < len(text) { + buf.WriteString(string(text[prevat:])) + } + } else { + prevat := len(text) + var al []string + + for m != nil { + if m.Index+m.Length != prevat { + al = append(al, string(text[m.Index+m.Length:prevat])) + } + prevat = m.Index + if evaluator == nil { + replacementImplRTL(data, &al, m) + } else { + al = append(al, evaluator(*m)) + } + + count-- + if count == 0 { + break + } + m, err = regex.FindNextMatch(m) + if err != nil { + return "", nil + } + } + + if prevat > 0 { + buf.WriteString(string(text[:prevat])) + } + + for i := len(al) - 1; i >= 0; i-- { + buf.WriteString(al[i]) + } + } + + return buf.String(), nil +} + +// Given a Match, emits into the StringBuilder the evaluated +// substitution pattern. +func replacementImpl(data *syntax.ReplacerData, buf *bytes.Buffer, m *Match) { + for _, r := range data.Rules { + + if r >= 0 { // string lookup + buf.WriteString(data.Strings[r]) + } else if r < -replaceSpecials { // group lookup + m.groupValueAppendToBuf(-replaceSpecials-1-r, buf) + } else { + switch -replaceSpecials - 1 - r { // special insertion patterns + case replaceLeftPortion: + for i := 0; i < m.Index; i++ { + buf.WriteRune(m.text[i]) + } + case replaceRightPortion: + for i := m.Index + m.Length; i < len(m.text); i++ { + buf.WriteRune(m.text[i]) + } + case replaceLastGroup: + m.groupValueAppendToBuf(m.GroupCount()-1, buf) + case replaceWholeString: + for i := 0; i < len(m.text); i++ { + buf.WriteRune(m.text[i]) + } + } + } + } +} + +func replacementImplRTL(data *syntax.ReplacerData, al *[]string, m *Match) { + l := *al + buf := &bytes.Buffer{} + + for _, r := range data.Rules { + buf.Reset() + if r >= 0 { // string lookup + l = append(l, data.Strings[r]) + } else if r < -replaceSpecials { // group lookup + m.groupValueAppendToBuf(-replaceSpecials-1-r, buf) + l = append(l, buf.String()) + } else { + switch -replaceSpecials - 1 - r { // special insertion patterns + case replaceLeftPortion: + for i := 0; i < m.Index; i++ { + buf.WriteRune(m.text[i]) + } + case replaceRightPortion: + for i := m.Index + m.Length; i < len(m.text); i++ { + buf.WriteRune(m.text[i]) + } + case replaceLastGroup: + m.groupValueAppendToBuf(m.GroupCount()-1, buf) + case replaceWholeString: + for i := 0; i < len(m.text); i++ { + buf.WriteRune(m.text[i]) + } + } + l = append(l, buf.String()) + } + } + + *al = l +} diff --git a/vendor/github.com/dlclark/regexp2/runner.go b/vendor/github.com/dlclark/regexp2/runner.go new file mode 100644 index 000000000..56759f147 --- /dev/null +++ b/vendor/github.com/dlclark/regexp2/runner.go @@ -0,0 +1,1613 @@ +package regexp2 + +import ( + "bytes" + "errors" + "fmt" + "math" + "strconv" + "strings" + "time" + "unicode" + + "github.com/dlclark/regexp2/syntax" +) + +type runner struct { + re *Regexp + code *syntax.Code + + runtextstart int // starting point for search + + runtext []rune // text to search + runtextpos int // current position in text + runtextend int + + // The backtracking stack. Opcodes use this to store data regarding + // what they have matched and where to backtrack to. Each "frame" on + // the stack takes the form of [CodePosition Data1 Data2...], where + // CodePosition is the position of the current opcode and + // the data values are all optional. The CodePosition can be negative, and + // these values (also called "back2") are used by the BranchMark family of opcodes + // to indicate whether they are backtracking after a successful or failed + // match. + // When we backtrack, we pop the CodePosition off the stack, set the current + // instruction pointer to that code position, and mark the opcode + // with a backtracking flag ("Back"). Each opcode then knows how to + // handle its own data. + runtrack []int + runtrackpos int + + // This stack is used to track text positions across different opcodes. + // For example, in /(a*b)+/, the parentheses result in a SetMark/CaptureMark + // pair. SetMark records the text position before we match a*b. Then + // CaptureMark uses that position to figure out where the capture starts. + // Opcodes which push onto this stack are always paired with other opcodes + // which will pop the value from it later. A successful match should mean + // that this stack is empty. + runstack []int + runstackpos int + + // The crawl stack is used to keep track of captures. Every time a group + // has a capture, we push its group number onto the runcrawl stack. In + // the case of a balanced match, we push BOTH groups onto the stack. + runcrawl []int + runcrawlpos int + + runtrackcount int // count of states that may do backtracking + + runmatch *Match // result object + + ignoreTimeout bool + timeout time.Duration // timeout in milliseconds (needed for actual) + deadline fasttime + + operator syntax.InstOp + codepos int + rightToLeft bool + caseInsensitive bool +} + +// run searches for matches and can continue from the previous match +// +// quick is usually false, but can be true to not return matches, just put it in caches +// textstart is -1 to start at the "beginning" (depending on Right-To-Left), otherwise an index in input +// input is the string to search for our regex pattern +func (re *Regexp) run(quick bool, textstart int, input []rune) (*Match, error) { + + // get a cached runner + runner := re.getRunner() + defer re.putRunner(runner) + + if textstart < 0 { + if re.RightToLeft() { + textstart = len(input) + } else { + textstart = 0 + } + } + + return runner.scan(input, textstart, quick, re.MatchTimeout) +} + +// Scans the string to find the first match. Uses the Match object +// both to feed text in and as a place to store matches that come out. +// +// All the action is in the Go() method. Our +// responsibility is to load up the class members before +// calling Go. +// +// The optimizer can compute a set of candidate starting characters, +// and we could use a separate method Skip() that will quickly scan past +// any characters that we know can't match. +func (r *runner) scan(rt []rune, textstart int, quick bool, timeout time.Duration) (*Match, error) { + r.timeout = timeout + r.ignoreTimeout = (time.Duration(math.MaxInt64) == timeout) + r.runtextstart = textstart + r.runtext = rt + r.runtextend = len(rt) + + stoppos := r.runtextend + bump := 1 + + if r.re.RightToLeft() { + bump = -1 + stoppos = 0 + } + + r.runtextpos = textstart + initted := false + + r.startTimeoutWatch() + for { + if r.re.Debug() { + //fmt.Printf("\nSearch content: %v\n", string(r.runtext)) + fmt.Printf("\nSearch range: from 0 to %v\n", r.runtextend) + fmt.Printf("Firstchar search starting at %v stopping at %v\n", r.runtextpos, stoppos) + } + + if r.findFirstChar() { + if err := r.checkTimeout(); err != nil { + return nil, err + } + + if !initted { + r.initMatch() + initted = true + } + + if r.re.Debug() { + fmt.Printf("Executing engine starting at %v\n\n", r.runtextpos) + } + + if err := r.execute(); err != nil { + return nil, err + } + + if r.runmatch.matchcount[0] > 0 { + // We'll return a match even if it touches a previous empty match + return r.tidyMatch(quick), nil + } + + // reset state for another go + r.runtrackpos = len(r.runtrack) + r.runstackpos = len(r.runstack) + r.runcrawlpos = len(r.runcrawl) + } + + // failure! + + if r.runtextpos == stoppos { + r.tidyMatch(true) + return nil, nil + } + + // Recognize leading []* and various anchors, and bump on failure accordingly + + // r.bump by one and start again + + r.runtextpos += bump + } + // We never get here +} + +func (r *runner) execute() error { + + r.goTo(0) + + for { + + if r.re.Debug() { + r.dumpState() + } + + if err := r.checkTimeout(); err != nil { + return err + } + + switch r.operator { + case syntax.Stop: + return nil + + case syntax.Nothing: + break + + case syntax.Goto: + r.goTo(r.operand(0)) + continue + + case syntax.Testref: + if !r.runmatch.isMatched(r.operand(0)) { + break + } + r.advance(1) + continue + + case syntax.Lazybranch: + r.trackPush1(r.textPos()) + r.advance(1) + continue + + case syntax.Lazybranch | syntax.Back: + r.trackPop() + r.textto(r.trackPeek()) + r.goTo(r.operand(0)) + continue + + case syntax.Setmark: + r.stackPush(r.textPos()) + r.trackPush() + r.advance(0) + continue + + case syntax.Nullmark: + r.stackPush(-1) + r.trackPush() + r.advance(0) + continue + + case syntax.Setmark | syntax.Back, syntax.Nullmark | syntax.Back: + r.stackPop() + break + + case syntax.Getmark: + r.stackPop() + r.trackPush1(r.stackPeek()) + r.textto(r.stackPeek()) + r.advance(0) + continue + + case syntax.Getmark | syntax.Back: + r.trackPop() + r.stackPush(r.trackPeek()) + break + + case syntax.Capturemark: + if r.operand(1) != -1 && !r.runmatch.isMatched(r.operand(1)) { + break + } + r.stackPop() + if r.operand(1) != -1 { + r.transferCapture(r.operand(0), r.operand(1), r.stackPeek(), r.textPos()) + } else { + r.capture(r.operand(0), r.stackPeek(), r.textPos()) + } + r.trackPush1(r.stackPeek()) + + r.advance(2) + + continue + + case syntax.Capturemark | syntax.Back: + r.trackPop() + r.stackPush(r.trackPeek()) + r.uncapture() + if r.operand(0) != -1 && r.operand(1) != -1 { + r.uncapture() + } + + break + + case syntax.Branchmark: + r.stackPop() + + matched := r.textPos() - r.stackPeek() + + if matched != 0 { // Nonempty match -> loop now + r.trackPush2(r.stackPeek(), r.textPos()) // Save old mark, textpos + r.stackPush(r.textPos()) // Make new mark + r.goTo(r.operand(0)) // Loop + } else { // Empty match -> straight now + r.trackPushNeg1(r.stackPeek()) // Save old mark + r.advance(1) // Straight + } + continue + + case syntax.Branchmark | syntax.Back: + r.trackPopN(2) + r.stackPop() + r.textto(r.trackPeekN(1)) // Recall position + r.trackPushNeg1(r.trackPeek()) // Save old mark + r.advance(1) // Straight + continue + + case syntax.Branchmark | syntax.Back2: + r.trackPop() + r.stackPush(r.trackPeek()) // Recall old mark + break // Backtrack + + case syntax.Lazybranchmark: + { + // We hit this the first time through a lazy loop and after each + // successful match of the inner expression. It simply continues + // on and doesn't loop. + r.stackPop() + + oldMarkPos := r.stackPeek() + + if r.textPos() != oldMarkPos { // Nonempty match -> try to loop again by going to 'back' state + if oldMarkPos != -1 { + r.trackPush2(oldMarkPos, r.textPos()) // Save old mark, textpos + } else { + r.trackPush2(r.textPos(), r.textPos()) + } + } else { + // The inner expression found an empty match, so we'll go directly to 'back2' if we + // backtrack. In this case, we need to push something on the stack, since back2 pops. + // However, in the case of ()+? or similar, this empty match may be legitimate, so push the text + // position associated with that empty match. + r.stackPush(oldMarkPos) + + r.trackPushNeg1(r.stackPeek()) // Save old mark + } + r.advance(1) + continue + } + + case syntax.Lazybranchmark | syntax.Back: + + // After the first time, Lazybranchmark | syntax.Back occurs + // with each iteration of the loop, and therefore with every attempted + // match of the inner expression. We'll try to match the inner expression, + // then go back to Lazybranchmark if successful. If the inner expression + // fails, we go to Lazybranchmark | syntax.Back2 + + r.trackPopN(2) + pos := r.trackPeekN(1) + r.trackPushNeg1(r.trackPeek()) // Save old mark + r.stackPush(pos) // Make new mark + r.textto(pos) // Recall position + r.goTo(r.operand(0)) // Loop + continue + + case syntax.Lazybranchmark | syntax.Back2: + // The lazy loop has failed. We'll do a true backtrack and + // start over before the lazy loop. + r.stackPop() + r.trackPop() + r.stackPush(r.trackPeek()) // Recall old mark + break + + case syntax.Setcount: + r.stackPush2(r.textPos(), r.operand(0)) + r.trackPush() + r.advance(1) + continue + + case syntax.Nullcount: + r.stackPush2(-1, r.operand(0)) + r.trackPush() + r.advance(1) + continue + + case syntax.Setcount | syntax.Back: + r.stackPopN(2) + break + + case syntax.Nullcount | syntax.Back: + r.stackPopN(2) + break + + case syntax.Branchcount: + // r.stackPush: + // 0: Mark + // 1: Count + + r.stackPopN(2) + mark := r.stackPeek() + count := r.stackPeekN(1) + matched := r.textPos() - mark + + if count >= r.operand(1) || (matched == 0 && count >= 0) { // Max loops or empty match -> straight now + r.trackPushNeg2(mark, count) // Save old mark, count + r.advance(2) // Straight + } else { // Nonempty match -> count+loop now + r.trackPush1(mark) // remember mark + r.stackPush2(r.textPos(), count+1) // Make new mark, incr count + r.goTo(r.operand(0)) // Loop + } + continue + + case syntax.Branchcount | syntax.Back: + // r.trackPush: + // 0: Previous mark + // r.stackPush: + // 0: Mark (= current pos, discarded) + // 1: Count + r.trackPop() + r.stackPopN(2) + if r.stackPeekN(1) > 0 { // Positive -> can go straight + r.textto(r.stackPeek()) // Zap to mark + r.trackPushNeg2(r.trackPeek(), r.stackPeekN(1)-1) // Save old mark, old count + r.advance(2) // Straight + continue + } + r.stackPush2(r.trackPeek(), r.stackPeekN(1)-1) // recall old mark, old count + break + + case syntax.Branchcount | syntax.Back2: + // r.trackPush: + // 0: Previous mark + // 1: Previous count + r.trackPopN(2) + r.stackPush2(r.trackPeek(), r.trackPeekN(1)) // Recall old mark, old count + break // Backtrack + + case syntax.Lazybranchcount: + // r.stackPush: + // 0: Mark + // 1: Count + + r.stackPopN(2) + mark := r.stackPeek() + count := r.stackPeekN(1) + + if count < 0 { // Negative count -> loop now + r.trackPushNeg1(mark) // Save old mark + r.stackPush2(r.textPos(), count+1) // Make new mark, incr count + r.goTo(r.operand(0)) // Loop + } else { // Nonneg count -> straight now + r.trackPush3(mark, count, r.textPos()) // Save mark, count, position + r.advance(2) // Straight + } + continue + + case syntax.Lazybranchcount | syntax.Back: + // r.trackPush: + // 0: Mark + // 1: Count + // 2: r.textPos + + r.trackPopN(3) + mark := r.trackPeek() + textpos := r.trackPeekN(2) + + if r.trackPeekN(1) < r.operand(1) && textpos != mark { // Under limit and not empty match -> loop + r.textto(textpos) // Recall position + r.stackPush2(textpos, r.trackPeekN(1)+1) // Make new mark, incr count + r.trackPushNeg1(mark) // Save old mark + r.goTo(r.operand(0)) // Loop + continue + } else { // Max loops or empty match -> backtrack + r.stackPush2(r.trackPeek(), r.trackPeekN(1)) // Recall old mark, count + break // backtrack + } + + case syntax.Lazybranchcount | syntax.Back2: + // r.trackPush: + // 0: Previous mark + // r.stackPush: + // 0: Mark (== current pos, discarded) + // 1: Count + r.trackPop() + r.stackPopN(2) + r.stackPush2(r.trackPeek(), r.stackPeekN(1)-1) // Recall old mark, count + break // Backtrack + + case syntax.Setjump: + r.stackPush2(r.trackpos(), r.crawlpos()) + r.trackPush() + r.advance(0) + continue + + case syntax.Setjump | syntax.Back: + r.stackPopN(2) + break + + case syntax.Backjump: + // r.stackPush: + // 0: Saved trackpos + // 1: r.crawlpos + r.stackPopN(2) + r.trackto(r.stackPeek()) + + for r.crawlpos() != r.stackPeekN(1) { + r.uncapture() + } + + break + + case syntax.Forejump: + // r.stackPush: + // 0: Saved trackpos + // 1: r.crawlpos + r.stackPopN(2) + r.trackto(r.stackPeek()) + r.trackPush1(r.stackPeekN(1)) + r.advance(0) + continue + + case syntax.Forejump | syntax.Back: + // r.trackPush: + // 0: r.crawlpos + r.trackPop() + + for r.crawlpos() != r.trackPeek() { + r.uncapture() + } + + break + + case syntax.Bol: + if r.leftchars() > 0 && r.charAt(r.textPos()-1) != '\n' { + break + } + r.advance(0) + continue + + case syntax.Eol: + if r.rightchars() > 0 && r.charAt(r.textPos()) != '\n' { + break + } + r.advance(0) + continue + + case syntax.Boundary: + if !r.isBoundary(r.textPos(), 0, r.runtextend) { + break + } + r.advance(0) + continue + + case syntax.Nonboundary: + if r.isBoundary(r.textPos(), 0, r.runtextend) { + break + } + r.advance(0) + continue + + case syntax.ECMABoundary: + if !r.isECMABoundary(r.textPos(), 0, r.runtextend) { + break + } + r.advance(0) + continue + + case syntax.NonECMABoundary: + if r.isECMABoundary(r.textPos(), 0, r.runtextend) { + break + } + r.advance(0) + continue + + case syntax.Beginning: + if r.leftchars() > 0 { + break + } + r.advance(0) + continue + + case syntax.Start: + if r.textPos() != r.textstart() { + break + } + r.advance(0) + continue + + case syntax.EndZ: + rchars := r.rightchars() + if rchars > 1 { + break + } + // RE2 and EcmaScript define $ as "asserts position at the end of the string" + // PCRE/.NET adds "or before the line terminator right at the end of the string (if any)" + if (r.re.options & (RE2 | ECMAScript)) != 0 { + // RE2/Ecmascript mode + if rchars > 0 { + break + } + } else if rchars == 1 && r.charAt(r.textPos()) != '\n' { + // "regular" mode + break + } + + r.advance(0) + continue + + case syntax.End: + if r.rightchars() > 0 { + break + } + r.advance(0) + continue + + case syntax.One: + if r.forwardchars() < 1 || r.forwardcharnext() != rune(r.operand(0)) { + break + } + + r.advance(1) + continue + + case syntax.Notone: + if r.forwardchars() < 1 || r.forwardcharnext() == rune(r.operand(0)) { + break + } + + r.advance(1) + continue + + case syntax.Set: + + if r.forwardchars() < 1 || !r.code.Sets[r.operand(0)].CharIn(r.forwardcharnext()) { + break + } + + r.advance(1) + continue + + case syntax.Multi: + if !r.runematch(r.code.Strings[r.operand(0)]) { + break + } + + r.advance(1) + continue + + case syntax.Ref: + + capnum := r.operand(0) + + if r.runmatch.isMatched(capnum) { + if !r.refmatch(r.runmatch.matchIndex(capnum), r.runmatch.matchLength(capnum)) { + break + } + } else { + if (r.re.options & ECMAScript) == 0 { + break + } + } + + r.advance(1) + continue + + case syntax.Onerep: + + c := r.operand(1) + + if r.forwardchars() < c { + break + } + + ch := rune(r.operand(0)) + + for c > 0 { + if r.forwardcharnext() != ch { + goto BreakBackward + } + c-- + } + + r.advance(2) + continue + + case syntax.Notonerep: + + c := r.operand(1) + + if r.forwardchars() < c { + break + } + ch := rune(r.operand(0)) + + for c > 0 { + if r.forwardcharnext() == ch { + goto BreakBackward + } + c-- + } + + r.advance(2) + continue + + case syntax.Setrep: + + c := r.operand(1) + + if r.forwardchars() < c { + break + } + + set := r.code.Sets[r.operand(0)] + + for c > 0 { + if !set.CharIn(r.forwardcharnext()) { + goto BreakBackward + } + c-- + } + + r.advance(2) + continue + + case syntax.Oneloop: + + c := r.operand(1) + + if c > r.forwardchars() { + c = r.forwardchars() + } + + ch := rune(r.operand(0)) + i := c + + for ; i > 0; i-- { + if r.forwardcharnext() != ch { + r.backwardnext() + break + } + } + + if c > i { + r.trackPush2(c-i-1, r.textPos()-r.bump()) + } + + r.advance(2) + continue + + case syntax.Notoneloop: + + c := r.operand(1) + + if c > r.forwardchars() { + c = r.forwardchars() + } + + ch := rune(r.operand(0)) + i := c + + for ; i > 0; i-- { + if r.forwardcharnext() == ch { + r.backwardnext() + break + } + } + + if c > i { + r.trackPush2(c-i-1, r.textPos()-r.bump()) + } + + r.advance(2) + continue + + case syntax.Setloop: + + c := r.operand(1) + + if c > r.forwardchars() { + c = r.forwardchars() + } + + set := r.code.Sets[r.operand(0)] + i := c + + for ; i > 0; i-- { + if !set.CharIn(r.forwardcharnext()) { + r.backwardnext() + break + } + } + + if c > i { + r.trackPush2(c-i-1, r.textPos()-r.bump()) + } + + r.advance(2) + continue + + case syntax.Oneloop | syntax.Back, syntax.Notoneloop | syntax.Back: + + r.trackPopN(2) + i := r.trackPeek() + pos := r.trackPeekN(1) + + r.textto(pos) + + if i > 0 { + r.trackPush2(i-1, pos-r.bump()) + } + + r.advance(2) + continue + + case syntax.Setloop | syntax.Back: + + r.trackPopN(2) + i := r.trackPeek() + pos := r.trackPeekN(1) + + r.textto(pos) + + if i > 0 { + r.trackPush2(i-1, pos-r.bump()) + } + + r.advance(2) + continue + + case syntax.Onelazy, syntax.Notonelazy: + + c := r.operand(1) + + if c > r.forwardchars() { + c = r.forwardchars() + } + + if c > 0 { + r.trackPush2(c-1, r.textPos()) + } + + r.advance(2) + continue + + case syntax.Setlazy: + + c := r.operand(1) + + if c > r.forwardchars() { + c = r.forwardchars() + } + + if c > 0 { + r.trackPush2(c-1, r.textPos()) + } + + r.advance(2) + continue + + case syntax.Onelazy | syntax.Back: + + r.trackPopN(2) + pos := r.trackPeekN(1) + r.textto(pos) + + if r.forwardcharnext() != rune(r.operand(0)) { + break + } + + i := r.trackPeek() + + if i > 0 { + r.trackPush2(i-1, pos+r.bump()) + } + + r.advance(2) + continue + + case syntax.Notonelazy | syntax.Back: + + r.trackPopN(2) + pos := r.trackPeekN(1) + r.textto(pos) + + if r.forwardcharnext() == rune(r.operand(0)) { + break + } + + i := r.trackPeek() + + if i > 0 { + r.trackPush2(i-1, pos+r.bump()) + } + + r.advance(2) + continue + + case syntax.Setlazy | syntax.Back: + + r.trackPopN(2) + pos := r.trackPeekN(1) + r.textto(pos) + + if !r.code.Sets[r.operand(0)].CharIn(r.forwardcharnext()) { + break + } + + i := r.trackPeek() + + if i > 0 { + r.trackPush2(i-1, pos+r.bump()) + } + + r.advance(2) + continue + + default: + return errors.New("unknown state in regex runner") + } + + BreakBackward: + ; + + // "break Backward" comes here: + r.backtrack() + } +} + +// increase the size of stack and track storage +func (r *runner) ensureStorage() { + if r.runstackpos < r.runtrackcount*4 { + doubleIntSlice(&r.runstack, &r.runstackpos) + } + if r.runtrackpos < r.runtrackcount*4 { + doubleIntSlice(&r.runtrack, &r.runtrackpos) + } +} + +func doubleIntSlice(s *[]int, pos *int) { + oldLen := len(*s) + newS := make([]int, oldLen*2) + + copy(newS[oldLen:], *s) + *pos += oldLen + *s = newS +} + +// Save a number on the longjump unrolling stack +func (r *runner) crawl(i int) { + if r.runcrawlpos == 0 { + doubleIntSlice(&r.runcrawl, &r.runcrawlpos) + } + r.runcrawlpos-- + r.runcrawl[r.runcrawlpos] = i +} + +// Remove a number from the longjump unrolling stack +func (r *runner) popcrawl() int { + val := r.runcrawl[r.runcrawlpos] + r.runcrawlpos++ + return val +} + +// Get the height of the stack +func (r *runner) crawlpos() int { + return len(r.runcrawl) - r.runcrawlpos +} + +func (r *runner) advance(i int) { + r.codepos += (i + 1) + r.setOperator(r.code.Codes[r.codepos]) +} + +func (r *runner) goTo(newpos int) { + // when branching backward or in place, ensure storage + if newpos <= r.codepos { + r.ensureStorage() + } + + r.setOperator(r.code.Codes[newpos]) + r.codepos = newpos +} + +func (r *runner) textto(newpos int) { + r.runtextpos = newpos +} + +func (r *runner) trackto(newpos int) { + r.runtrackpos = len(r.runtrack) - newpos +} + +func (r *runner) textstart() int { + return r.runtextstart +} + +func (r *runner) textPos() int { + return r.runtextpos +} + +// push onto the backtracking stack +func (r *runner) trackpos() int { + return len(r.runtrack) - r.runtrackpos +} + +func (r *runner) trackPush() { + r.runtrackpos-- + r.runtrack[r.runtrackpos] = r.codepos +} + +func (r *runner) trackPush1(I1 int) { + r.runtrackpos-- + r.runtrack[r.runtrackpos] = I1 + r.runtrackpos-- + r.runtrack[r.runtrackpos] = r.codepos +} + +func (r *runner) trackPush2(I1, I2 int) { + r.runtrackpos-- + r.runtrack[r.runtrackpos] = I1 + r.runtrackpos-- + r.runtrack[r.runtrackpos] = I2 + r.runtrackpos-- + r.runtrack[r.runtrackpos] = r.codepos +} + +func (r *runner) trackPush3(I1, I2, I3 int) { + r.runtrackpos-- + r.runtrack[r.runtrackpos] = I1 + r.runtrackpos-- + r.runtrack[r.runtrackpos] = I2 + r.runtrackpos-- + r.runtrack[r.runtrackpos] = I3 + r.runtrackpos-- + r.runtrack[r.runtrackpos] = r.codepos +} + +func (r *runner) trackPushNeg1(I1 int) { + r.runtrackpos-- + r.runtrack[r.runtrackpos] = I1 + r.runtrackpos-- + r.runtrack[r.runtrackpos] = -r.codepos +} + +func (r *runner) trackPushNeg2(I1, I2 int) { + r.runtrackpos-- + r.runtrack[r.runtrackpos] = I1 + r.runtrackpos-- + r.runtrack[r.runtrackpos] = I2 + r.runtrackpos-- + r.runtrack[r.runtrackpos] = -r.codepos +} + +func (r *runner) backtrack() { + newpos := r.runtrack[r.runtrackpos] + r.runtrackpos++ + + if r.re.Debug() { + if newpos < 0 { + fmt.Printf(" Backtracking (back2) to code position %v\n", -newpos) + } else { + fmt.Printf(" Backtracking to code position %v\n", newpos) + } + } + + if newpos < 0 { + newpos = -newpos + r.setOperator(r.code.Codes[newpos] | syntax.Back2) + } else { + r.setOperator(r.code.Codes[newpos] | syntax.Back) + } + + // When branching backward, ensure storage + if newpos < r.codepos { + r.ensureStorage() + } + + r.codepos = newpos +} + +func (r *runner) setOperator(op int) { + r.caseInsensitive = (0 != (op & syntax.Ci)) + r.rightToLeft = (0 != (op & syntax.Rtl)) + r.operator = syntax.InstOp(op & ^(syntax.Rtl | syntax.Ci)) +} + +func (r *runner) trackPop() { + r.runtrackpos++ +} + +// pop framesize items from the backtracking stack +func (r *runner) trackPopN(framesize int) { + r.runtrackpos += framesize +} + +// Technically we are actually peeking at items already popped. So if you want to +// get and pop the top item from the stack, you do +// r.trackPop(); +// r.trackPeek(); +func (r *runner) trackPeek() int { + return r.runtrack[r.runtrackpos-1] +} + +// get the ith element down on the backtracking stack +func (r *runner) trackPeekN(i int) int { + return r.runtrack[r.runtrackpos-i-1] +} + +// Push onto the grouping stack +func (r *runner) stackPush(I1 int) { + r.runstackpos-- + r.runstack[r.runstackpos] = I1 +} + +func (r *runner) stackPush2(I1, I2 int) { + r.runstackpos-- + r.runstack[r.runstackpos] = I1 + r.runstackpos-- + r.runstack[r.runstackpos] = I2 +} + +func (r *runner) stackPop() { + r.runstackpos++ +} + +// pop framesize items from the grouping stack +func (r *runner) stackPopN(framesize int) { + r.runstackpos += framesize +} + +// Technically we are actually peeking at items already popped. So if you want to +// get and pop the top item from the stack, you do +// r.stackPop(); +// r.stackPeek(); +func (r *runner) stackPeek() int { + return r.runstack[r.runstackpos-1] +} + +// get the ith element down on the grouping stack +func (r *runner) stackPeekN(i int) int { + return r.runstack[r.runstackpos-i-1] +} + +func (r *runner) operand(i int) int { + return r.code.Codes[r.codepos+i+1] +} + +func (r *runner) leftchars() int { + return r.runtextpos +} + +func (r *runner) rightchars() int { + return r.runtextend - r.runtextpos +} + +func (r *runner) bump() int { + if r.rightToLeft { + return -1 + } + return 1 +} + +func (r *runner) forwardchars() int { + if r.rightToLeft { + return r.runtextpos + } + return r.runtextend - r.runtextpos +} + +func (r *runner) forwardcharnext() rune { + var ch rune + if r.rightToLeft { + r.runtextpos-- + ch = r.runtext[r.runtextpos] + } else { + ch = r.runtext[r.runtextpos] + r.runtextpos++ + } + + if r.caseInsensitive { + return unicode.ToLower(ch) + } + return ch +} + +func (r *runner) runematch(str []rune) bool { + var pos int + + c := len(str) + if !r.rightToLeft { + if r.runtextend-r.runtextpos < c { + return false + } + + pos = r.runtextpos + c + } else { + if r.runtextpos-0 < c { + return false + } + + pos = r.runtextpos + } + + if !r.caseInsensitive { + for c != 0 { + c-- + pos-- + if str[c] != r.runtext[pos] { + return false + } + } + } else { + for c != 0 { + c-- + pos-- + if str[c] != unicode.ToLower(r.runtext[pos]) { + return false + } + } + } + + if !r.rightToLeft { + pos += len(str) + } + + r.runtextpos = pos + + return true +} + +func (r *runner) refmatch(index, len int) bool { + var c, pos, cmpos int + + if !r.rightToLeft { + if r.runtextend-r.runtextpos < len { + return false + } + + pos = r.runtextpos + len + } else { + if r.runtextpos-0 < len { + return false + } + + pos = r.runtextpos + } + cmpos = index + len + + c = len + + if !r.caseInsensitive { + for c != 0 { + c-- + cmpos-- + pos-- + if r.runtext[cmpos] != r.runtext[pos] { + return false + } + + } + } else { + for c != 0 { + c-- + cmpos-- + pos-- + + if unicode.ToLower(r.runtext[cmpos]) != unicode.ToLower(r.runtext[pos]) { + return false + } + } + } + + if !r.rightToLeft { + pos += len + } + + r.runtextpos = pos + + return true +} + +func (r *runner) backwardnext() { + if r.rightToLeft { + r.runtextpos++ + } else { + r.runtextpos-- + } +} + +func (r *runner) charAt(j int) rune { + return r.runtext[j] +} + +func (r *runner) findFirstChar() bool { + + if 0 != (r.code.Anchors & (syntax.AnchorBeginning | syntax.AnchorStart | syntax.AnchorEndZ | syntax.AnchorEnd)) { + if !r.code.RightToLeft { + if (0 != (r.code.Anchors&syntax.AnchorBeginning) && r.runtextpos > 0) || + (0 != (r.code.Anchors&syntax.AnchorStart) && r.runtextpos > r.runtextstart) { + r.runtextpos = r.runtextend + return false + } + if 0 != (r.code.Anchors&syntax.AnchorEndZ) && r.runtextpos < r.runtextend-1 { + r.runtextpos = r.runtextend - 1 + } else if 0 != (r.code.Anchors&syntax.AnchorEnd) && r.runtextpos < r.runtextend { + r.runtextpos = r.runtextend + } + } else { + if (0 != (r.code.Anchors&syntax.AnchorEnd) && r.runtextpos < r.runtextend) || + (0 != (r.code.Anchors&syntax.AnchorEndZ) && (r.runtextpos < r.runtextend-1 || + (r.runtextpos == r.runtextend-1 && r.charAt(r.runtextpos) != '\n'))) || + (0 != (r.code.Anchors&syntax.AnchorStart) && r.runtextpos < r.runtextstart) { + r.runtextpos = 0 + return false + } + if 0 != (r.code.Anchors&syntax.AnchorBeginning) && r.runtextpos > 0 { + r.runtextpos = 0 + } + } + + if r.code.BmPrefix != nil { + return r.code.BmPrefix.IsMatch(r.runtext, r.runtextpos, 0, r.runtextend) + } + + return true // found a valid start or end anchor + } else if r.code.BmPrefix != nil { + r.runtextpos = r.code.BmPrefix.Scan(r.runtext, r.runtextpos, 0, r.runtextend) + + if r.runtextpos == -1 { + if r.code.RightToLeft { + r.runtextpos = 0 + } else { + r.runtextpos = r.runtextend + } + return false + } + + return true + } else if r.code.FcPrefix == nil { + return true + } + + r.rightToLeft = r.code.RightToLeft + r.caseInsensitive = r.code.FcPrefix.CaseInsensitive + + set := r.code.FcPrefix.PrefixSet + if set.IsSingleton() { + ch := set.SingletonChar() + for i := r.forwardchars(); i > 0; i-- { + if ch == r.forwardcharnext() { + r.backwardnext() + return true + } + } + } else { + for i := r.forwardchars(); i > 0; i-- { + n := r.forwardcharnext() + //fmt.Printf("%v in %v: %v\n", string(n), set.String(), set.CharIn(n)) + if set.CharIn(n) { + r.backwardnext() + return true + } + } + } + + return false +} + +func (r *runner) initMatch() { + // Use a hashtable'ed Match object if the capture numbers are sparse + + if r.runmatch == nil { + if r.re.caps != nil { + r.runmatch = newMatchSparse(r.re, r.re.caps, r.re.capsize, r.runtext, r.runtextstart) + } else { + r.runmatch = newMatch(r.re, r.re.capsize, r.runtext, r.runtextstart) + } + } else { + r.runmatch.reset(r.runtext, r.runtextstart) + } + + // note we test runcrawl, because it is the last one to be allocated + // If there is an alloc failure in the middle of the three allocations, + // we may still return to reuse this instance, and we want to behave + // as if the allocations didn't occur. (we used to test _trackcount != 0) + + if r.runcrawl != nil { + r.runtrackpos = len(r.runtrack) + r.runstackpos = len(r.runstack) + r.runcrawlpos = len(r.runcrawl) + return + } + + r.initTrackCount() + + tracksize := r.runtrackcount * 8 + stacksize := r.runtrackcount * 8 + + if tracksize < 32 { + tracksize = 32 + } + if stacksize < 16 { + stacksize = 16 + } + + r.runtrack = make([]int, tracksize) + r.runtrackpos = tracksize + + r.runstack = make([]int, stacksize) + r.runstackpos = stacksize + + r.runcrawl = make([]int, 32) + r.runcrawlpos = 32 +} + +func (r *runner) tidyMatch(quick bool) *Match { + if !quick { + match := r.runmatch + + r.runmatch = nil + + match.tidy(r.runtextpos) + return match + } else { + // send back our match -- it's not leaving the package, so it's safe to not clean it up + // this reduces allocs for frequent calls to the "IsMatch" bool-only functions + return r.runmatch + } +} + +// capture captures a subexpression. Note that the +// capnum used here has already been mapped to a non-sparse +// index (by the code generator RegexWriter). +func (r *runner) capture(capnum, start, end int) { + if end < start { + T := end + end = start + start = T + } + + r.crawl(capnum) + r.runmatch.addMatch(capnum, start, end-start) +} + +// transferCapture captures a subexpression. Note that the +// capnum used here has already been mapped to a non-sparse +// index (by the code generator RegexWriter). +func (r *runner) transferCapture(capnum, uncapnum, start, end int) { + var start2, end2 int + + // these are the two intervals that are cancelling each other + + if end < start { + T := end + end = start + start = T + } + + start2 = r.runmatch.matchIndex(uncapnum) + end2 = start2 + r.runmatch.matchLength(uncapnum) + + // The new capture gets the innermost defined interval + + if start >= end2 { + end = start + start = end2 + } else if end <= start2 { + start = start2 + } else { + if end > end2 { + end = end2 + } + if start2 > start { + start = start2 + } + } + + r.crawl(uncapnum) + r.runmatch.balanceMatch(uncapnum) + + if capnum != -1 { + r.crawl(capnum) + r.runmatch.addMatch(capnum, start, end-start) + } +} + +// revert the last capture +func (r *runner) uncapture() { + capnum := r.popcrawl() + r.runmatch.removeMatch(capnum) +} + +//debug + +func (r *runner) dumpState() { + back := "" + if r.operator&syntax.Back != 0 { + back = " Back" + } + if r.operator&syntax.Back2 != 0 { + back += " Back2" + } + fmt.Printf("Text: %v\nTrack: %v\nStack: %v\n %s%s\n\n", + r.textposDescription(), + r.stackDescription(r.runtrack, r.runtrackpos), + r.stackDescription(r.runstack, r.runstackpos), + r.code.OpcodeDescription(r.codepos), + back) +} + +func (r *runner) stackDescription(a []int, index int) string { + buf := &bytes.Buffer{} + + fmt.Fprintf(buf, "%v/%v", len(a)-index, len(a)) + if buf.Len() < 8 { + buf.WriteString(strings.Repeat(" ", 8-buf.Len())) + } + + buf.WriteRune('(') + for i := index; i < len(a); i++ { + if i > index { + buf.WriteRune(' ') + } + + buf.WriteString(strconv.Itoa(a[i])) + } + + buf.WriteRune(')') + + return buf.String() +} + +func (r *runner) textposDescription() string { + buf := &bytes.Buffer{} + + buf.WriteString(strconv.Itoa(r.runtextpos)) + + if buf.Len() < 8 { + buf.WriteString(strings.Repeat(" ", 8-buf.Len())) + } + + if r.runtextpos > 0 { + buf.WriteString(syntax.CharDescription(r.runtext[r.runtextpos-1])) + } else { + buf.WriteRune('^') + } + + buf.WriteRune('>') + + for i := r.runtextpos; i < r.runtextend; i++ { + buf.WriteString(syntax.CharDescription(r.runtext[i])) + } + if buf.Len() >= 64 { + buf.Truncate(61) + buf.WriteString("...") + } else { + buf.WriteRune('$') + } + + return buf.String() +} + +// decide whether the pos +// at the specified index is a boundary or not. It's just not worth +// emitting inline code for this logic. +func (r *runner) isBoundary(index, startpos, endpos int) bool { + return (index > startpos && syntax.IsWordChar(r.runtext[index-1])) != + (index < endpos && syntax.IsWordChar(r.runtext[index])) +} + +func (r *runner) isECMABoundary(index, startpos, endpos int) bool { + return (index > startpos && syntax.IsECMAWordChar(r.runtext[index-1])) != + (index < endpos && syntax.IsECMAWordChar(r.runtext[index])) +} + +func (r *runner) startTimeoutWatch() { + if r.ignoreTimeout { + return + } + r.deadline = makeDeadline(r.timeout) +} + +func (r *runner) checkTimeout() error { + if r.ignoreTimeout || !r.deadline.reached() { + return nil + } + + if r.re.Debug() { + //Debug.WriteLine("") + //Debug.WriteLine("RegEx match timeout occurred!") + //Debug.WriteLine("Specified timeout: " + TimeSpan.FromMilliseconds(_timeout).ToString()) + //Debug.WriteLine("Timeout check frequency: " + TimeoutCheckFrequency) + //Debug.WriteLine("Search pattern: " + _runregex._pattern) + //Debug.WriteLine("Input: " + r.runtext) + //Debug.WriteLine("About to throw RegexMatchTimeoutException.") + } + + return fmt.Errorf("match timeout after %v on input `%v`", r.timeout, string(r.runtext)) +} + +func (r *runner) initTrackCount() { + r.runtrackcount = r.code.TrackCount +} + +// getRunner returns a run to use for matching re. +// It uses the re's runner cache if possible, to avoid +// unnecessary allocation. +func (re *Regexp) getRunner() *runner { + re.muRun.Lock() + if n := len(re.runner); n > 0 { + z := re.runner[n-1] + re.runner = re.runner[:n-1] + re.muRun.Unlock() + return z + } + re.muRun.Unlock() + z := &runner{ + re: re, + code: re.code, + } + return z +} + +// putRunner returns a runner to the re's cache. +// There is no attempt to limit the size of the cache, so it will +// grow to the maximum number of simultaneous matches +// run using re. (The cache empties when re gets garbage collected.) +func (re *Regexp) putRunner(r *runner) { + re.muRun.Lock() + r.runtext = nil + if r.runmatch != nil { + r.runmatch.text = nil + } + re.runner = append(re.runner, r) + re.muRun.Unlock() +} diff --git a/vendor/github.com/dlclark/regexp2/syntax/charclass.go b/vendor/github.com/dlclark/regexp2/syntax/charclass.go new file mode 100644 index 000000000..6881a0e29 --- /dev/null +++ b/vendor/github.com/dlclark/regexp2/syntax/charclass.go @@ -0,0 +1,865 @@ +package syntax + +import ( + "bytes" + "encoding/binary" + "fmt" + "sort" + "unicode" + "unicode/utf8" +) + +// CharSet combines start-end rune ranges and unicode categories representing a set of characters +type CharSet struct { + ranges []singleRange + categories []category + sub *CharSet //optional subtractor + negate bool + anything bool +} + +type category struct { + negate bool + cat string +} + +type singleRange struct { + first rune + last rune +} + +const ( + spaceCategoryText = " " + wordCategoryText = "W" +) + +var ( + ecmaSpace = []rune{0x0009, 0x000e, 0x0020, 0x0021, 0x00a0, 0x00a1, 0x1680, 0x1681, 0x2000, 0x200b, 0x2028, 0x202a, 0x202f, 0x2030, 0x205f, 0x2060, 0x3000, 0x3001, 0xfeff, 0xff00} + ecmaWord = []rune{0x0030, 0x003a, 0x0041, 0x005b, 0x005f, 0x0060, 0x0061, 0x007b} + ecmaDigit = []rune{0x0030, 0x003a} + + re2Space = []rune{0x0009, 0x000b, 0x000c, 0x000e, 0x0020, 0x0021} +) + +var ( + AnyClass = getCharSetFromOldString([]rune{0}, false) + ECMAAnyClass = getCharSetFromOldString([]rune{0, 0x000a, 0x000b, 0x000d, 0x000e}, false) + NoneClass = getCharSetFromOldString(nil, false) + ECMAWordClass = getCharSetFromOldString(ecmaWord, false) + NotECMAWordClass = getCharSetFromOldString(ecmaWord, true) + ECMASpaceClass = getCharSetFromOldString(ecmaSpace, false) + NotECMASpaceClass = getCharSetFromOldString(ecmaSpace, true) + ECMADigitClass = getCharSetFromOldString(ecmaDigit, false) + NotECMADigitClass = getCharSetFromOldString(ecmaDigit, true) + + WordClass = getCharSetFromCategoryString(false, false, wordCategoryText) + NotWordClass = getCharSetFromCategoryString(true, false, wordCategoryText) + SpaceClass = getCharSetFromCategoryString(false, false, spaceCategoryText) + NotSpaceClass = getCharSetFromCategoryString(true, false, spaceCategoryText) + DigitClass = getCharSetFromCategoryString(false, false, "Nd") + NotDigitClass = getCharSetFromCategoryString(false, true, "Nd") + + RE2SpaceClass = getCharSetFromOldString(re2Space, false) + NotRE2SpaceClass = getCharSetFromOldString(re2Space, true) +) + +var unicodeCategories = func() map[string]*unicode.RangeTable { + retVal := make(map[string]*unicode.RangeTable) + for k, v := range unicode.Scripts { + retVal[k] = v + } + for k, v := range unicode.Categories { + retVal[k] = v + } + for k, v := range unicode.Properties { + retVal[k] = v + } + return retVal +}() + +func getCharSetFromCategoryString(negateSet bool, negateCat bool, cats ...string) func() *CharSet { + if negateCat && negateSet { + panic("BUG! You should only negate the set OR the category in a constant setup, but not both") + } + + c := CharSet{negate: negateSet} + + c.categories = make([]category, len(cats)) + for i, cat := range cats { + c.categories[i] = category{cat: cat, negate: negateCat} + } + return func() *CharSet { + //make a copy each time + local := c + //return that address + return &local + } +} + +func getCharSetFromOldString(setText []rune, negate bool) func() *CharSet { + c := CharSet{} + if len(setText) > 0 { + fillFirst := false + l := len(setText) + if negate { + if setText[0] == 0 { + setText = setText[1:] + } else { + l++ + fillFirst = true + } + } + + if l%2 == 0 { + c.ranges = make([]singleRange, l/2) + } else { + c.ranges = make([]singleRange, l/2+1) + } + + first := true + if fillFirst { + c.ranges[0] = singleRange{first: 0} + first = false + } + + i := 0 + for _, r := range setText { + if first { + // lower bound in a new range + c.ranges[i] = singleRange{first: r} + first = false + } else { + c.ranges[i].last = r - 1 + i++ + first = true + } + } + if !first { + c.ranges[i].last = utf8.MaxRune + } + } + + return func() *CharSet { + local := c + return &local + } +} + +// Copy makes a deep copy to prevent accidental mutation of a set +func (c CharSet) Copy() CharSet { + ret := CharSet{ + anything: c.anything, + negate: c.negate, + } + + ret.ranges = append(ret.ranges, c.ranges...) + ret.categories = append(ret.categories, c.categories...) + + if c.sub != nil { + sub := c.sub.Copy() + ret.sub = &sub + } + + return ret +} + +// gets a human-readable description for a set string +func (c CharSet) String() string { + buf := &bytes.Buffer{} + buf.WriteRune('[') + + if c.IsNegated() { + buf.WriteRune('^') + } + + for _, r := range c.ranges { + + buf.WriteString(CharDescription(r.first)) + if r.first != r.last { + if r.last-r.first != 1 { + //groups that are 1 char apart skip the dash + buf.WriteRune('-') + } + buf.WriteString(CharDescription(r.last)) + } + } + + for _, c := range c.categories { + buf.WriteString(c.String()) + } + + if c.sub != nil { + buf.WriteRune('-') + buf.WriteString(c.sub.String()) + } + + buf.WriteRune(']') + + return buf.String() +} + +// mapHashFill converts a charset into a buffer for use in maps +func (c CharSet) mapHashFill(buf *bytes.Buffer) { + if c.negate { + buf.WriteByte(0) + } else { + buf.WriteByte(1) + } + + binary.Write(buf, binary.LittleEndian, len(c.ranges)) + binary.Write(buf, binary.LittleEndian, len(c.categories)) + for _, r := range c.ranges { + buf.WriteRune(r.first) + buf.WriteRune(r.last) + } + for _, ct := range c.categories { + buf.WriteString(ct.cat) + if ct.negate { + buf.WriteByte(1) + } else { + buf.WriteByte(0) + } + } + + if c.sub != nil { + c.sub.mapHashFill(buf) + } +} + +// CharIn returns true if the rune is in our character set (either ranges or categories). +// It handles negations and subtracted sub-charsets. +func (c CharSet) CharIn(ch rune) bool { + val := false + // in s && !s.subtracted + + //check ranges + for _, r := range c.ranges { + if ch < r.first { + continue + } + if ch <= r.last { + val = true + break + } + } + + //check categories if we haven't already found a range + if !val && len(c.categories) > 0 { + for _, ct := range c.categories { + // special categories...then unicode + if ct.cat == spaceCategoryText { + if unicode.IsSpace(ch) { + // we found a space so we're done + // negate means this is a "bad" thing + val = !ct.negate + break + } else if ct.negate { + val = true + break + } + } else if ct.cat == wordCategoryText { + if IsWordChar(ch) { + val = !ct.negate + break + } else if ct.negate { + val = true + break + } + } else if unicode.Is(unicodeCategories[ct.cat], ch) { + // if we're in this unicode category then we're done + // if negate=true on this category then we "failed" our test + // otherwise we're good that we found it + val = !ct.negate + break + } else if ct.negate { + val = true + break + } + } + } + + // negate the whole char set + if c.negate { + val = !val + } + + // get subtracted recurse + if val && c.sub != nil { + val = !c.sub.CharIn(ch) + } + + //log.Printf("Char '%v' in %v == %v", string(ch), c.String(), val) + return val +} + +func (c category) String() string { + switch c.cat { + case spaceCategoryText: + if c.negate { + return "\\S" + } + return "\\s" + case wordCategoryText: + if c.negate { + return "\\W" + } + return "\\w" + } + if _, ok := unicodeCategories[c.cat]; ok { + + if c.negate { + return "\\P{" + c.cat + "}" + } + return "\\p{" + c.cat + "}" + } + return "Unknown category: " + c.cat +} + +// CharDescription Produces a human-readable description for a single character. +func CharDescription(ch rune) string { + /*if ch == '\\' { + return "\\\\" + } + + if ch > ' ' && ch <= '~' { + return string(ch) + } else if ch == '\n' { + return "\\n" + } else if ch == ' ' { + return "\\ " + }*/ + + b := &bytes.Buffer{} + escape(b, ch, false) //fmt.Sprintf("%U", ch) + return b.String() +} + +// According to UTS#18 Unicode Regular Expressions (http://www.unicode.org/reports/tr18/) +// RL 1.4 Simple Word Boundaries The class of includes all Alphabetic +// values from the Unicode character database, from UnicodeData.txt [UData], plus the U+200C +// ZERO WIDTH NON-JOINER and U+200D ZERO WIDTH JOINER. +func IsWordChar(r rune) bool { + //"L", "Mn", "Nd", "Pc" + return unicode.In(r, + unicode.Categories["L"], unicode.Categories["Mn"], + unicode.Categories["Nd"], unicode.Categories["Pc"]) || r == '\u200D' || r == '\u200C' + //return 'A' <= r && r <= 'Z' || 'a' <= r && r <= 'z' || '0' <= r && r <= '9' || r == '_' +} + +func IsECMAWordChar(r rune) bool { + return unicode.In(r, + unicode.Categories["L"], unicode.Categories["Mn"], + unicode.Categories["Nd"], unicode.Categories["Pc"]) + + //return 'A' <= r && r <= 'Z' || 'a' <= r && r <= 'z' || '0' <= r && r <= '9' || r == '_' +} + +// SingletonChar will return the char from the first range without validation. +// It assumes you have checked for IsSingleton or IsSingletonInverse and will panic given bad input +func (c CharSet) SingletonChar() rune { + return c.ranges[0].first +} + +func (c CharSet) IsSingleton() bool { + return !c.negate && //negated is multiple chars + len(c.categories) == 0 && len(c.ranges) == 1 && // multiple ranges and unicode classes represent multiple chars + c.sub == nil && // subtraction means we've got multiple chars + c.ranges[0].first == c.ranges[0].last // first and last equal means we're just 1 char +} + +func (c CharSet) IsSingletonInverse() bool { + return c.negate && //same as above, but requires negated + len(c.categories) == 0 && len(c.ranges) == 1 && // multiple ranges and unicode classes represent multiple chars + c.sub == nil && // subtraction means we've got multiple chars + c.ranges[0].first == c.ranges[0].last // first and last equal means we're just 1 char +} + +func (c CharSet) IsMergeable() bool { + return !c.IsNegated() && !c.HasSubtraction() +} + +func (c CharSet) IsNegated() bool { + return c.negate +} + +func (c CharSet) HasSubtraction() bool { + return c.sub != nil +} + +func (c CharSet) IsEmpty() bool { + return len(c.ranges) == 0 && len(c.categories) == 0 && c.sub == nil +} + +func (c *CharSet) addDigit(ecma, negate bool, pattern string) { + if ecma { + if negate { + c.addRanges(NotECMADigitClass().ranges) + } else { + c.addRanges(ECMADigitClass().ranges) + } + } else { + c.addCategories(category{cat: "Nd", negate: negate}) + } +} + +func (c *CharSet) addChar(ch rune) { + c.addRange(ch, ch) +} + +func (c *CharSet) addSpace(ecma, re2, negate bool) { + if ecma { + if negate { + c.addRanges(NotECMASpaceClass().ranges) + } else { + c.addRanges(ECMASpaceClass().ranges) + } + } else if re2 { + if negate { + c.addRanges(NotRE2SpaceClass().ranges) + } else { + c.addRanges(RE2SpaceClass().ranges) + } + } else { + c.addCategories(category{cat: spaceCategoryText, negate: negate}) + } +} + +func (c *CharSet) addWord(ecma, negate bool) { + if ecma { + if negate { + c.addRanges(NotECMAWordClass().ranges) + } else { + c.addRanges(ECMAWordClass().ranges) + } + } else { + c.addCategories(category{cat: wordCategoryText, negate: negate}) + } +} + +// Add set ranges and categories into ours -- no deduping or anything +func (c *CharSet) addSet(set CharSet) { + if c.anything { + return + } + if set.anything { + c.makeAnything() + return + } + // just append here to prevent double-canon + c.ranges = append(c.ranges, set.ranges...) + c.addCategories(set.categories...) + c.canonicalize() +} + +func (c *CharSet) makeAnything() { + c.anything = true + c.categories = []category{} + c.ranges = AnyClass().ranges +} + +func (c *CharSet) addCategories(cats ...category) { + // don't add dupes and remove positive+negative + if c.anything { + // if we've had a previous positive+negative group then + // just return, we're as broad as we can get + return + } + + for _, ct := range cats { + found := false + for _, ct2 := range c.categories { + if ct.cat == ct2.cat { + if ct.negate != ct2.negate { + // oposite negations...this mean we just + // take us as anything and move on + c.makeAnything() + return + } + found = true + break + } + } + + if !found { + c.categories = append(c.categories, ct) + } + } +} + +// Merges new ranges to our own +func (c *CharSet) addRanges(ranges []singleRange) { + if c.anything { + return + } + c.ranges = append(c.ranges, ranges...) + c.canonicalize() +} + +// Merges everything but the new ranges into our own +func (c *CharSet) addNegativeRanges(ranges []singleRange) { + if c.anything { + return + } + + var hi rune + + // convert incoming ranges into opposites, assume they are in order + for _, r := range ranges { + if hi < r.first { + c.ranges = append(c.ranges, singleRange{hi, r.first - 1}) + } + hi = r.last + 1 + } + + if hi < utf8.MaxRune { + c.ranges = append(c.ranges, singleRange{hi, utf8.MaxRune}) + } + + c.canonicalize() +} + +func isValidUnicodeCat(catName string) bool { + _, ok := unicodeCategories[catName] + return ok +} + +func (c *CharSet) addCategory(categoryName string, negate, caseInsensitive bool, pattern string) { + if !isValidUnicodeCat(categoryName) { + // unknown unicode category, script, or property "blah" + panic(fmt.Errorf("Unknown unicode category, script, or property '%v'", categoryName)) + + } + + if caseInsensitive && (categoryName == "Ll" || categoryName == "Lu" || categoryName == "Lt") { + // when RegexOptions.IgnoreCase is specified then {Ll} {Lu} and {Lt} cases should all match + c.addCategories( + category{cat: "Ll", negate: negate}, + category{cat: "Lu", negate: negate}, + category{cat: "Lt", negate: negate}) + } + c.addCategories(category{cat: categoryName, negate: negate}) +} + +func (c *CharSet) addSubtraction(sub *CharSet) { + c.sub = sub +} + +func (c *CharSet) addRange(chMin, chMax rune) { + c.ranges = append(c.ranges, singleRange{first: chMin, last: chMax}) + c.canonicalize() +} + +func (c *CharSet) addNamedASCII(name string, negate bool) bool { + var rs []singleRange + + switch name { + case "alnum": + rs = []singleRange{singleRange{'0', '9'}, singleRange{'A', 'Z'}, singleRange{'a', 'z'}} + case "alpha": + rs = []singleRange{singleRange{'A', 'Z'}, singleRange{'a', 'z'}} + case "ascii": + rs = []singleRange{singleRange{0, 0x7f}} + case "blank": + rs = []singleRange{singleRange{'\t', '\t'}, singleRange{' ', ' '}} + case "cntrl": + rs = []singleRange{singleRange{0, 0x1f}, singleRange{0x7f, 0x7f}} + case "digit": + c.addDigit(false, negate, "") + case "graph": + rs = []singleRange{singleRange{'!', '~'}} + case "lower": + rs = []singleRange{singleRange{'a', 'z'}} + case "print": + rs = []singleRange{singleRange{' ', '~'}} + case "punct": //[!-/:-@[-`{-~] + rs = []singleRange{singleRange{'!', '/'}, singleRange{':', '@'}, singleRange{'[', '`'}, singleRange{'{', '~'}} + case "space": + c.addSpace(true, false, negate) + case "upper": + rs = []singleRange{singleRange{'A', 'Z'}} + case "word": + c.addWord(true, negate) + case "xdigit": + rs = []singleRange{singleRange{'0', '9'}, singleRange{'A', 'F'}, singleRange{'a', 'f'}} + default: + return false + } + + if len(rs) > 0 { + if negate { + c.addNegativeRanges(rs) + } else { + c.addRanges(rs) + } + } + + return true +} + +type singleRangeSorter []singleRange + +func (p singleRangeSorter) Len() int { return len(p) } +func (p singleRangeSorter) Less(i, j int) bool { return p[i].first < p[j].first } +func (p singleRangeSorter) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +// Logic to reduce a character class to a unique, sorted form. +func (c *CharSet) canonicalize() { + var i, j int + var last rune + + // + // Find and eliminate overlapping or abutting ranges + // + + if len(c.ranges) > 1 { + sort.Sort(singleRangeSorter(c.ranges)) + + done := false + + for i, j = 1, 0; ; i++ { + for last = c.ranges[j].last; ; i++ { + if i == len(c.ranges) || last == utf8.MaxRune { + done = true + break + } + + CurrentRange := c.ranges[i] + if CurrentRange.first > last+1 { + break + } + + if last < CurrentRange.last { + last = CurrentRange.last + } + } + + c.ranges[j] = singleRange{first: c.ranges[j].first, last: last} + + j++ + + if done { + break + } + + if j < i { + c.ranges[j] = c.ranges[i] + } + } + + c.ranges = append(c.ranges[:j], c.ranges[len(c.ranges):]...) + } +} + +// Adds to the class any lowercase versions of characters already +// in the class. Used for case-insensitivity. +func (c *CharSet) addLowercase() { + if c.anything { + return + } + toAdd := []singleRange{} + for i := 0; i < len(c.ranges); i++ { + r := c.ranges[i] + if r.first == r.last { + lower := unicode.ToLower(r.first) + c.ranges[i] = singleRange{first: lower, last: lower} + } else { + toAdd = append(toAdd, r) + } + } + + for _, r := range toAdd { + c.addLowercaseRange(r.first, r.last) + } + c.canonicalize() +} + +/************************************************************************** + Let U be the set of Unicode character values and let L be the lowercase + function, mapping from U to U. To perform case insensitive matching of + character sets, we need to be able to map an interval I in U, say + + I = [chMin, chMax] = { ch : chMin <= ch <= chMax } + + to a set A such that A contains L(I) and A is contained in the union of + I and L(I). + + The table below partitions U into intervals on which L is non-decreasing. + Thus, for any interval J = [a, b] contained in one of these intervals, + L(J) is contained in [L(a), L(b)]. + + It is also true that for any such J, [L(a), L(b)] is contained in the + union of J and L(J). This does not follow from L being non-decreasing on + these intervals. It follows from the nature of the L on each interval. + On each interval, L has one of the following forms: + + (1) L(ch) = constant (LowercaseSet) + (2) L(ch) = ch + offset (LowercaseAdd) + (3) L(ch) = ch | 1 (LowercaseBor) + (4) L(ch) = ch + (ch & 1) (LowercaseBad) + + It is easy to verify that for any of these forms [L(a), L(b)] is + contained in the union of [a, b] and L([a, b]). +***************************************************************************/ + +const ( + LowercaseSet = 0 // Set to arg. + LowercaseAdd = 1 // Add arg. + LowercaseBor = 2 // Bitwise or with 1. + LowercaseBad = 3 // Bitwise and with 1 and add original. +) + +type lcMap struct { + chMin, chMax rune + op, data int32 +} + +var lcTable = []lcMap{ + lcMap{'\u0041', '\u005A', LowercaseAdd, 32}, + lcMap{'\u00C0', '\u00DE', LowercaseAdd, 32}, + lcMap{'\u0100', '\u012E', LowercaseBor, 0}, + lcMap{'\u0130', '\u0130', LowercaseSet, 0x0069}, + lcMap{'\u0132', '\u0136', LowercaseBor, 0}, + lcMap{'\u0139', '\u0147', LowercaseBad, 0}, + lcMap{'\u014A', '\u0176', LowercaseBor, 0}, + lcMap{'\u0178', '\u0178', LowercaseSet, 0x00FF}, + lcMap{'\u0179', '\u017D', LowercaseBad, 0}, + lcMap{'\u0181', '\u0181', LowercaseSet, 0x0253}, + lcMap{'\u0182', '\u0184', LowercaseBor, 0}, + lcMap{'\u0186', '\u0186', LowercaseSet, 0x0254}, + lcMap{'\u0187', '\u0187', LowercaseSet, 0x0188}, + lcMap{'\u0189', '\u018A', LowercaseAdd, 205}, + lcMap{'\u018B', '\u018B', LowercaseSet, 0x018C}, + lcMap{'\u018E', '\u018E', LowercaseSet, 0x01DD}, + lcMap{'\u018F', '\u018F', LowercaseSet, 0x0259}, + lcMap{'\u0190', '\u0190', LowercaseSet, 0x025B}, + lcMap{'\u0191', '\u0191', LowercaseSet, 0x0192}, + lcMap{'\u0193', '\u0193', LowercaseSet, 0x0260}, + lcMap{'\u0194', '\u0194', LowercaseSet, 0x0263}, + lcMap{'\u0196', '\u0196', LowercaseSet, 0x0269}, + lcMap{'\u0197', '\u0197', LowercaseSet, 0x0268}, + lcMap{'\u0198', '\u0198', LowercaseSet, 0x0199}, + lcMap{'\u019C', '\u019C', LowercaseSet, 0x026F}, + lcMap{'\u019D', '\u019D', LowercaseSet, 0x0272}, + lcMap{'\u019F', '\u019F', LowercaseSet, 0x0275}, + lcMap{'\u01A0', '\u01A4', LowercaseBor, 0}, + lcMap{'\u01A7', '\u01A7', LowercaseSet, 0x01A8}, + lcMap{'\u01A9', '\u01A9', LowercaseSet, 0x0283}, + lcMap{'\u01AC', '\u01AC', LowercaseSet, 0x01AD}, + lcMap{'\u01AE', '\u01AE', LowercaseSet, 0x0288}, + lcMap{'\u01AF', '\u01AF', LowercaseSet, 0x01B0}, + lcMap{'\u01B1', '\u01B2', LowercaseAdd, 217}, + lcMap{'\u01B3', '\u01B5', LowercaseBad, 0}, + lcMap{'\u01B7', '\u01B7', LowercaseSet, 0x0292}, + lcMap{'\u01B8', '\u01B8', LowercaseSet, 0x01B9}, + lcMap{'\u01BC', '\u01BC', LowercaseSet, 0x01BD}, + lcMap{'\u01C4', '\u01C5', LowercaseSet, 0x01C6}, + lcMap{'\u01C7', '\u01C8', LowercaseSet, 0x01C9}, + lcMap{'\u01CA', '\u01CB', LowercaseSet, 0x01CC}, + lcMap{'\u01CD', '\u01DB', LowercaseBad, 0}, + lcMap{'\u01DE', '\u01EE', LowercaseBor, 0}, + lcMap{'\u01F1', '\u01F2', LowercaseSet, 0x01F3}, + lcMap{'\u01F4', '\u01F4', LowercaseSet, 0x01F5}, + lcMap{'\u01FA', '\u0216', LowercaseBor, 0}, + lcMap{'\u0386', '\u0386', LowercaseSet, 0x03AC}, + lcMap{'\u0388', '\u038A', LowercaseAdd, 37}, + lcMap{'\u038C', '\u038C', LowercaseSet, 0x03CC}, + lcMap{'\u038E', '\u038F', LowercaseAdd, 63}, + lcMap{'\u0391', '\u03AB', LowercaseAdd, 32}, + lcMap{'\u03E2', '\u03EE', LowercaseBor, 0}, + lcMap{'\u0401', '\u040F', LowercaseAdd, 80}, + lcMap{'\u0410', '\u042F', LowercaseAdd, 32}, + lcMap{'\u0460', '\u0480', LowercaseBor, 0}, + lcMap{'\u0490', '\u04BE', LowercaseBor, 0}, + lcMap{'\u04C1', '\u04C3', LowercaseBad, 0}, + lcMap{'\u04C7', '\u04C7', LowercaseSet, 0x04C8}, + lcMap{'\u04CB', '\u04CB', LowercaseSet, 0x04CC}, + lcMap{'\u04D0', '\u04EA', LowercaseBor, 0}, + lcMap{'\u04EE', '\u04F4', LowercaseBor, 0}, + lcMap{'\u04F8', '\u04F8', LowercaseSet, 0x04F9}, + lcMap{'\u0531', '\u0556', LowercaseAdd, 48}, + lcMap{'\u10A0', '\u10C5', LowercaseAdd, 48}, + lcMap{'\u1E00', '\u1EF8', LowercaseBor, 0}, + lcMap{'\u1F08', '\u1F0F', LowercaseAdd, -8}, + lcMap{'\u1F18', '\u1F1F', LowercaseAdd, -8}, + lcMap{'\u1F28', '\u1F2F', LowercaseAdd, -8}, + lcMap{'\u1F38', '\u1F3F', LowercaseAdd, -8}, + lcMap{'\u1F48', '\u1F4D', LowercaseAdd, -8}, + lcMap{'\u1F59', '\u1F59', LowercaseSet, 0x1F51}, + lcMap{'\u1F5B', '\u1F5B', LowercaseSet, 0x1F53}, + lcMap{'\u1F5D', '\u1F5D', LowercaseSet, 0x1F55}, + lcMap{'\u1F5F', '\u1F5F', LowercaseSet, 0x1F57}, + lcMap{'\u1F68', '\u1F6F', LowercaseAdd, -8}, + lcMap{'\u1F88', '\u1F8F', LowercaseAdd, -8}, + lcMap{'\u1F98', '\u1F9F', LowercaseAdd, -8}, + lcMap{'\u1FA8', '\u1FAF', LowercaseAdd, -8}, + lcMap{'\u1FB8', '\u1FB9', LowercaseAdd, -8}, + lcMap{'\u1FBA', '\u1FBB', LowercaseAdd, -74}, + lcMap{'\u1FBC', '\u1FBC', LowercaseSet, 0x1FB3}, + lcMap{'\u1FC8', '\u1FCB', LowercaseAdd, -86}, + lcMap{'\u1FCC', '\u1FCC', LowercaseSet, 0x1FC3}, + lcMap{'\u1FD8', '\u1FD9', LowercaseAdd, -8}, + lcMap{'\u1FDA', '\u1FDB', LowercaseAdd, -100}, + lcMap{'\u1FE8', '\u1FE9', LowercaseAdd, -8}, + lcMap{'\u1FEA', '\u1FEB', LowercaseAdd, -112}, + lcMap{'\u1FEC', '\u1FEC', LowercaseSet, 0x1FE5}, + lcMap{'\u1FF8', '\u1FF9', LowercaseAdd, -128}, + lcMap{'\u1FFA', '\u1FFB', LowercaseAdd, -126}, + lcMap{'\u1FFC', '\u1FFC', LowercaseSet, 0x1FF3}, + lcMap{'\u2160', '\u216F', LowercaseAdd, 16}, + lcMap{'\u24B6', '\u24D0', LowercaseAdd, 26}, + lcMap{'\uFF21', '\uFF3A', LowercaseAdd, 32}, +} + +func (c *CharSet) addLowercaseRange(chMin, chMax rune) { + var i, iMax, iMid int + var chMinT, chMaxT rune + var lc lcMap + + for i, iMax = 0, len(lcTable); i < iMax; { + iMid = (i + iMax) / 2 + if lcTable[iMid].chMax < chMin { + i = iMid + 1 + } else { + iMax = iMid + } + } + + for ; i < len(lcTable); i++ { + lc = lcTable[i] + if lc.chMin > chMax { + return + } + chMinT = lc.chMin + if chMinT < chMin { + chMinT = chMin + } + + chMaxT = lc.chMax + if chMaxT > chMax { + chMaxT = chMax + } + + switch lc.op { + case LowercaseSet: + chMinT = rune(lc.data) + chMaxT = rune(lc.data) + break + case LowercaseAdd: + chMinT += lc.data + chMaxT += lc.data + break + case LowercaseBor: + chMinT |= 1 + chMaxT |= 1 + break + case LowercaseBad: + chMinT += (chMinT & 1) + chMaxT += (chMaxT & 1) + break + } + + if chMinT < chMin || chMaxT > chMax { + c.addRange(chMinT, chMaxT) + } + } +} diff --git a/vendor/github.com/dlclark/regexp2/syntax/code.go b/vendor/github.com/dlclark/regexp2/syntax/code.go new file mode 100644 index 000000000..686e822af --- /dev/null +++ b/vendor/github.com/dlclark/regexp2/syntax/code.go @@ -0,0 +1,274 @@ +package syntax + +import ( + "bytes" + "fmt" + "math" +) + +// similar to prog.go in the go regex package...also with comment 'may not belong in this package' + +// File provides operator constants for use by the Builder and the Machine. + +// Implementation notes: +// +// Regexps are built into RegexCodes, which contain an operation array, +// a string table, and some constants. +// +// Each operation is one of the codes below, followed by the integer +// operands specified for each op. +// +// Strings and sets are indices into a string table. + +type InstOp int + +const ( + // lef/back operands description + + Onerep InstOp = 0 // lef,back char,min,max a {n} + Notonerep = 1 // lef,back char,min,max .{n} + Setrep = 2 // lef,back set,min,max [\d]{n} + + Oneloop = 3 // lef,back char,min,max a {,n} + Notoneloop = 4 // lef,back char,min,max .{,n} + Setloop = 5 // lef,back set,min,max [\d]{,n} + + Onelazy = 6 // lef,back char,min,max a {,n}? + Notonelazy = 7 // lef,back char,min,max .{,n}? + Setlazy = 8 // lef,back set,min,max [\d]{,n}? + + One = 9 // lef char a + Notone = 10 // lef char [^a] + Set = 11 // lef set [a-z\s] \w \s \d + + Multi = 12 // lef string abcd + Ref = 13 // lef group \# + + Bol = 14 // ^ + Eol = 15 // $ + Boundary = 16 // \b + Nonboundary = 17 // \B + Beginning = 18 // \A + Start = 19 // \G + EndZ = 20 // \Z + End = 21 // \Z + + Nothing = 22 // Reject! + + // Primitive control structures + + Lazybranch = 23 // back jump straight first + Branchmark = 24 // back jump branch first for loop + Lazybranchmark = 25 // back jump straight first for loop + Nullcount = 26 // back val set counter, null mark + Setcount = 27 // back val set counter, make mark + Branchcount = 28 // back jump,limit branch++ if zero<=c impl group slots + Capsize int // number of impl group slots + FcPrefix *Prefix // the set of candidate first characters (may be null) + BmPrefix *BmPrefix // the fixed prefix string as a Boyer-Moore machine (may be null) + Anchors AnchorLoc // the set of zero-length start anchors (RegexFCD.Bol, etc) + RightToLeft bool // true if right to left +} + +func opcodeBacktracks(op InstOp) bool { + op &= Mask + + switch op { + case Oneloop, Notoneloop, Setloop, Onelazy, Notonelazy, Setlazy, Lazybranch, Branchmark, Lazybranchmark, + Nullcount, Setcount, Branchcount, Lazybranchcount, Setmark, Capturemark, Getmark, Setjump, Backjump, + Forejump, Goto: + return true + + default: + return false + } +} + +func opcodeSize(op InstOp) int { + op &= Mask + + switch op { + case Nothing, Bol, Eol, Boundary, Nonboundary, ECMABoundary, NonECMABoundary, Beginning, Start, EndZ, + End, Nullmark, Setmark, Getmark, Setjump, Backjump, Forejump, Stop: + return 1 + + case One, Notone, Multi, Ref, Testref, Goto, Nullcount, Setcount, Lazybranch, Branchmark, Lazybranchmark, + Prune, Set: + return 2 + + case Capturemark, Branchcount, Lazybranchcount, Onerep, Notonerep, Oneloop, Notoneloop, Onelazy, Notonelazy, + Setlazy, Setrep, Setloop: + return 3 + + default: + panic(fmt.Errorf("Unexpected op code: %v", op)) + } +} + +var codeStr = []string{ + "Onerep", "Notonerep", "Setrep", + "Oneloop", "Notoneloop", "Setloop", + "Onelazy", "Notonelazy", "Setlazy", + "One", "Notone", "Set", + "Multi", "Ref", + "Bol", "Eol", "Boundary", "Nonboundary", "Beginning", "Start", "EndZ", "End", + "Nothing", + "Lazybranch", "Branchmark", "Lazybranchmark", + "Nullcount", "Setcount", "Branchcount", "Lazybranchcount", + "Nullmark", "Setmark", "Capturemark", "Getmark", + "Setjump", "Backjump", "Forejump", "Testref", "Goto", + "Prune", "Stop", + "ECMABoundary", "NonECMABoundary", +} + +func operatorDescription(op InstOp) string { + desc := codeStr[op&Mask] + if (op & Ci) != 0 { + desc += "-Ci" + } + if (op & Rtl) != 0 { + desc += "-Rtl" + } + if (op & Back) != 0 { + desc += "-Back" + } + if (op & Back2) != 0 { + desc += "-Back2" + } + + return desc +} + +// OpcodeDescription is a humman readable string of the specific offset +func (c *Code) OpcodeDescription(offset int) string { + buf := &bytes.Buffer{} + + op := InstOp(c.Codes[offset]) + fmt.Fprintf(buf, "%06d ", offset) + + if opcodeBacktracks(op & Mask) { + buf.WriteString("*") + } else { + buf.WriteString(" ") + } + buf.WriteString(operatorDescription(op)) + buf.WriteString("(") + op &= Mask + + switch op { + case One, Notone, Onerep, Notonerep, Oneloop, Notoneloop, Onelazy, Notonelazy: + buf.WriteString("Ch = ") + buf.WriteString(CharDescription(rune(c.Codes[offset+1]))) + + case Set, Setrep, Setloop, Setlazy: + buf.WriteString("Set = ") + buf.WriteString(c.Sets[c.Codes[offset+1]].String()) + + case Multi: + fmt.Fprintf(buf, "String = %s", string(c.Strings[c.Codes[offset+1]])) + + case Ref, Testref: + fmt.Fprintf(buf, "Index = %d", c.Codes[offset+1]) + + case Capturemark: + fmt.Fprintf(buf, "Index = %d", c.Codes[offset+1]) + if c.Codes[offset+2] != -1 { + fmt.Fprintf(buf, ", Unindex = %d", c.Codes[offset+2]) + } + + case Nullcount, Setcount: + fmt.Fprintf(buf, "Value = %d", c.Codes[offset+1]) + + case Goto, Lazybranch, Branchmark, Lazybranchmark, Branchcount, Lazybranchcount: + fmt.Fprintf(buf, "Addr = %d", c.Codes[offset+1]) + } + + switch op { + case Onerep, Notonerep, Oneloop, Notoneloop, Onelazy, Notonelazy, Setrep, Setloop, Setlazy: + buf.WriteString(", Rep = ") + if c.Codes[offset+2] == math.MaxInt32 { + buf.WriteString("inf") + } else { + fmt.Fprintf(buf, "%d", c.Codes[offset+2]) + } + + case Branchcount, Lazybranchcount: + buf.WriteString(", Limit = ") + if c.Codes[offset+2] == math.MaxInt32 { + buf.WriteString("inf") + } else { + fmt.Fprintf(buf, "%d", c.Codes[offset+2]) + } + + } + + buf.WriteString(")") + + return buf.String() +} + +func (c *Code) Dump() string { + buf := &bytes.Buffer{} + + if c.RightToLeft { + fmt.Fprintln(buf, "Direction: right-to-left") + } else { + fmt.Fprintln(buf, "Direction: left-to-right") + } + if c.FcPrefix == nil { + fmt.Fprintln(buf, "Firstchars: n/a") + } else { + fmt.Fprintf(buf, "Firstchars: %v\n", c.FcPrefix.PrefixSet.String()) + } + + if c.BmPrefix == nil { + fmt.Fprintln(buf, "Prefix: n/a") + } else { + fmt.Fprintf(buf, "Prefix: %v\n", Escape(c.BmPrefix.String())) + } + + fmt.Fprintf(buf, "Anchors: %v\n", c.Anchors) + fmt.Fprintln(buf) + + if c.BmPrefix != nil { + fmt.Fprintln(buf, "BoyerMoore:") + fmt.Fprintln(buf, c.BmPrefix.Dump(" ")) + } + for i := 0; i < len(c.Codes); i += opcodeSize(InstOp(c.Codes[i])) { + fmt.Fprintln(buf, c.OpcodeDescription(i)) + } + + return buf.String() +} diff --git a/vendor/github.com/dlclark/regexp2/syntax/escape.go b/vendor/github.com/dlclark/regexp2/syntax/escape.go new file mode 100644 index 000000000..609df1073 --- /dev/null +++ b/vendor/github.com/dlclark/regexp2/syntax/escape.go @@ -0,0 +1,94 @@ +package syntax + +import ( + "bytes" + "strconv" + "strings" + "unicode" +) + +func Escape(input string) string { + b := &bytes.Buffer{} + for _, r := range input { + escape(b, r, false) + } + return b.String() +} + +const meta = `\.+*?()|[]{}^$# ` + +func escape(b *bytes.Buffer, r rune, force bool) { + if unicode.IsPrint(r) { + if strings.IndexRune(meta, r) >= 0 || force { + b.WriteRune('\\') + } + b.WriteRune(r) + return + } + + switch r { + case '\a': + b.WriteString(`\a`) + case '\f': + b.WriteString(`\f`) + case '\n': + b.WriteString(`\n`) + case '\r': + b.WriteString(`\r`) + case '\t': + b.WriteString(`\t`) + case '\v': + b.WriteString(`\v`) + default: + if r < 0x100 { + b.WriteString(`\x`) + s := strconv.FormatInt(int64(r), 16) + if len(s) == 1 { + b.WriteRune('0') + } + b.WriteString(s) + break + } + b.WriteString(`\u`) + b.WriteString(strconv.FormatInt(int64(r), 16)) + } +} + +func Unescape(input string) (string, error) { + idx := strings.IndexRune(input, '\\') + // no slashes means no unescape needed + if idx == -1 { + return input, nil + } + + buf := bytes.NewBufferString(input[:idx]) + // get the runes for the rest of the string -- we're going full parser scan on this + + p := parser{} + p.setPattern(input[idx+1:]) + for { + if p.rightMost() { + return "", p.getErr(ErrIllegalEndEscape) + } + r, err := p.scanCharEscape() + if err != nil { + return "", err + } + buf.WriteRune(r) + // are we done? + if p.rightMost() { + return buf.String(), nil + } + + r = p.moveRightGetChar() + for r != '\\' { + buf.WriteRune(r) + if p.rightMost() { + // we're done, no more slashes + return buf.String(), nil + } + // keep scanning until we get another slash + r = p.moveRightGetChar() + } + } +} diff --git a/vendor/github.com/dlclark/regexp2/syntax/fuzz.go b/vendor/github.com/dlclark/regexp2/syntax/fuzz.go new file mode 100644 index 000000000..ee863866d --- /dev/null +++ b/vendor/github.com/dlclark/regexp2/syntax/fuzz.go @@ -0,0 +1,20 @@ +// +build gofuzz + +package syntax + +// Fuzz is the input point for go-fuzz +func Fuzz(data []byte) int { + sdata := string(data) + tree, err := Parse(sdata, RegexOptions(0)) + if err != nil { + return 0 + } + + // translate it to code + _, err = Write(tree) + if err != nil { + panic(err) + } + + return 1 +} diff --git a/vendor/github.com/dlclark/regexp2/syntax/parser.go b/vendor/github.com/dlclark/regexp2/syntax/parser.go new file mode 100644 index 000000000..4ff0aaa83 --- /dev/null +++ b/vendor/github.com/dlclark/regexp2/syntax/parser.go @@ -0,0 +1,2262 @@ +package syntax + +import ( + "fmt" + "math" + "os" + "sort" + "strconv" + "unicode" +) + +type RegexOptions int32 + +const ( + IgnoreCase RegexOptions = 0x0001 // "i" + Multiline = 0x0002 // "m" + ExplicitCapture = 0x0004 // "n" + Compiled = 0x0008 // "c" + Singleline = 0x0010 // "s" + IgnorePatternWhitespace = 0x0020 // "x" + RightToLeft = 0x0040 // "r" + Debug = 0x0080 // "d" + ECMAScript = 0x0100 // "e" + RE2 = 0x0200 // RE2 compat mode + Unicode = 0x0400 // "u" +) + +func optionFromCode(ch rune) RegexOptions { + // case-insensitive + switch ch { + case 'i', 'I': + return IgnoreCase + case 'r', 'R': + return RightToLeft + case 'm', 'M': + return Multiline + case 'n', 'N': + return ExplicitCapture + case 's', 'S': + return Singleline + case 'x', 'X': + return IgnorePatternWhitespace + case 'd', 'D': + return Debug + case 'e', 'E': + return ECMAScript + case 'u', 'U': + return Unicode + default: + return 0 + } +} + +// An Error describes a failure to parse a regular expression +// and gives the offending expression. +type Error struct { + Code ErrorCode + Expr string + Args []interface{} +} + +func (e *Error) Error() string { + if len(e.Args) == 0 { + return "error parsing regexp: " + e.Code.String() + " in `" + e.Expr + "`" + } + return "error parsing regexp: " + fmt.Sprintf(e.Code.String(), e.Args...) + " in `" + e.Expr + "`" +} + +// An ErrorCode describes a failure to parse a regular expression. +type ErrorCode string + +const ( + // internal issue + ErrInternalError ErrorCode = "regexp/syntax: internal error" + // Parser errors + ErrUnterminatedComment = "unterminated comment" + ErrInvalidCharRange = "invalid character class range" + ErrInvalidRepeatSize = "invalid repeat count" + ErrInvalidUTF8 = "invalid UTF-8" + ErrCaptureGroupOutOfRange = "capture group number out of range" + ErrUnexpectedParen = "unexpected )" + ErrMissingParen = "missing closing )" + ErrMissingBrace = "missing closing }" + ErrInvalidRepeatOp = "invalid nested repetition operator" + ErrMissingRepeatArgument = "missing argument to repetition operator" + ErrConditionalExpression = "illegal conditional (?(...)) expression" + ErrTooManyAlternates = "too many | in (?()|)" + ErrUnrecognizedGrouping = "unrecognized grouping construct: (%v" + ErrInvalidGroupName = "invalid group name: group names must begin with a word character and have a matching terminator" + ErrCapNumNotZero = "capture number cannot be zero" + ErrUndefinedBackRef = "reference to undefined group number %v" + ErrUndefinedNameRef = "reference to undefined group name %v" + ErrAlternationCantCapture = "alternation conditions do not capture and cannot be named" + ErrAlternationCantHaveComment = "alternation conditions cannot be comments" + ErrMalformedReference = "(?(%v) ) malformed" + ErrUndefinedReference = "(?(%v) ) reference to undefined group" + ErrIllegalEndEscape = "illegal \\ at end of pattern" + ErrMalformedSlashP = "malformed \\p{X} character escape" + ErrIncompleteSlashP = "incomplete \\p{X} character escape" + ErrUnknownSlashP = "unknown unicode category, script, or property '%v'" + ErrUnrecognizedEscape = "unrecognized escape sequence \\%v" + ErrMissingControl = "missing control character" + ErrUnrecognizedControl = "unrecognized control character" + ErrTooFewHex = "insufficient hexadecimal digits" + ErrInvalidHex = "hex values may not be larger than 0x10FFFF" + ErrMalformedNameRef = "malformed \\k<...> named back reference" + ErrBadClassInCharRange = "cannot include class \\%v in character range" + ErrUnterminatedBracket = "unterminated [] set" + ErrSubtractionMustBeLast = "a subtraction must be the last element in a character class" + ErrReversedCharRange = "[%c-%c] range in reverse order" +) + +func (e ErrorCode) String() string { + return string(e) +} + +type parser struct { + stack *regexNode + group *regexNode + alternation *regexNode + concatenation *regexNode + unit *regexNode + + patternRaw string + pattern []rune + + currentPos int + specialCase *unicode.SpecialCase + + autocap int + capcount int + captop int + capsize int + + caps map[int]int + capnames map[string]int + + capnumlist []int + capnamelist []string + + options RegexOptions + optionsStack []RegexOptions + ignoreNextParen bool +} + +const ( + maxValueDiv10 int = math.MaxInt32 / 10 + maxValueMod10 = math.MaxInt32 % 10 +) + +// Parse converts a regex string into a parse tree +func Parse(re string, op RegexOptions) (*RegexTree, error) { + p := parser{ + options: op, + caps: make(map[int]int), + } + p.setPattern(re) + + if err := p.countCaptures(); err != nil { + return nil, err + } + + p.reset(op) + root, err := p.scanRegex() + + if err != nil { + return nil, err + } + tree := &RegexTree{ + root: root, + caps: p.caps, + capnumlist: p.capnumlist, + captop: p.captop, + Capnames: p.capnames, + Caplist: p.capnamelist, + options: op, + } + + if tree.options&Debug > 0 { + os.Stdout.WriteString(tree.Dump()) + } + + return tree, nil +} + +func (p *parser) setPattern(pattern string) { + p.patternRaw = pattern + p.pattern = make([]rune, 0, len(pattern)) + + //populate our rune array to handle utf8 encoding + for _, r := range pattern { + p.pattern = append(p.pattern, r) + } +} +func (p *parser) getErr(code ErrorCode, args ...interface{}) error { + return &Error{Code: code, Expr: p.patternRaw, Args: args} +} + +func (p *parser) noteCaptureSlot(i, pos int) { + if _, ok := p.caps[i]; !ok { + // the rhs of the hashtable isn't used in the parser + p.caps[i] = pos + p.capcount++ + + if p.captop <= i { + if i == math.MaxInt32 { + p.captop = i + } else { + p.captop = i + 1 + } + } + } +} + +func (p *parser) noteCaptureName(name string, pos int) { + if p.capnames == nil { + p.capnames = make(map[string]int) + } + + if _, ok := p.capnames[name]; !ok { + p.capnames[name] = pos + p.capnamelist = append(p.capnamelist, name) + } +} + +func (p *parser) assignNameSlots() { + if p.capnames != nil { + for _, name := range p.capnamelist { + for p.isCaptureSlot(p.autocap) { + p.autocap++ + } + pos := p.capnames[name] + p.capnames[name] = p.autocap + p.noteCaptureSlot(p.autocap, pos) + + p.autocap++ + } + } + + // if the caps array has at least one gap, construct the list of used slots + if p.capcount < p.captop { + p.capnumlist = make([]int, p.capcount) + i := 0 + + for k := range p.caps { + p.capnumlist[i] = k + i++ + } + + sort.Ints(p.capnumlist) + } + + // merge capsnumlist into capnamelist + if p.capnames != nil || p.capnumlist != nil { + var oldcapnamelist []string + var next int + var k int + + if p.capnames == nil { + oldcapnamelist = nil + p.capnames = make(map[string]int) + p.capnamelist = []string{} + next = -1 + } else { + oldcapnamelist = p.capnamelist + p.capnamelist = []string{} + next = p.capnames[oldcapnamelist[0]] + } + + for i := 0; i < p.capcount; i++ { + j := i + if p.capnumlist != nil { + j = p.capnumlist[i] + } + + if next == j { + p.capnamelist = append(p.capnamelist, oldcapnamelist[k]) + k++ + + if k == len(oldcapnamelist) { + next = -1 + } else { + next = p.capnames[oldcapnamelist[k]] + } + + } else { + //feature: culture? + str := strconv.Itoa(j) + p.capnamelist = append(p.capnamelist, str) + p.capnames[str] = j + } + } + } +} + +func (p *parser) consumeAutocap() int { + r := p.autocap + p.autocap++ + return r +} + +// CountCaptures is a prescanner for deducing the slots used for +// captures by doing a partial tokenization of the pattern. +func (p *parser) countCaptures() error { + var ch rune + + p.noteCaptureSlot(0, 0) + + p.autocap = 1 + + for p.charsRight() > 0 { + pos := p.textpos() + ch = p.moveRightGetChar() + switch ch { + case '\\': + if p.charsRight() > 0 { + p.scanBackslash(true) + } + + case '#': + if p.useOptionX() { + p.moveLeft() + p.scanBlank() + } + + case '[': + p.scanCharSet(false, true) + + case ')': + if !p.emptyOptionsStack() { + p.popOptions() + } + + case '(': + if p.charsRight() >= 2 && p.rightChar(1) == '#' && p.rightChar(0) == '?' { + p.moveLeft() + p.scanBlank() + } else { + p.pushOptions() + if p.charsRight() > 0 && p.rightChar(0) == '?' { + // we have (?... + p.moveRight(1) + + if p.charsRight() > 1 && (p.rightChar(0) == '<' || p.rightChar(0) == '\'') { + // named group: (?<... or (?'... + + p.moveRight(1) + ch = p.rightChar(0) + + if ch != '0' && IsWordChar(ch) { + if ch >= '1' && ch <= '9' { + dec, err := p.scanDecimal() + if err != nil { + return err + } + p.noteCaptureSlot(dec, pos) + } else { + p.noteCaptureName(p.scanCapname(), pos) + } + } + } else if p.useRE2() && p.charsRight() > 2 && (p.rightChar(0) == 'P' && p.rightChar(1) == '<') { + // RE2-compat (?P<) + p.moveRight(2) + ch = p.rightChar(0) + if IsWordChar(ch) { + p.noteCaptureName(p.scanCapname(), pos) + } + + } else { + // (?... + + // get the options if it's an option construct (?cimsx-cimsx...) + p.scanOptions() + + if p.charsRight() > 0 { + if p.rightChar(0) == ')' { + // (?cimsx-cimsx) + p.moveRight(1) + p.popKeepOptions() + } else if p.rightChar(0) == '(' { + // alternation construct: (?(foo)yes|no) + // ignore the next paren so we don't capture the condition + p.ignoreNextParen = true + + // break from here so we don't reset ignoreNextParen + continue + } + } + } + } else { + if !p.useOptionN() && !p.ignoreNextParen { + p.noteCaptureSlot(p.consumeAutocap(), pos) + } + } + } + + p.ignoreNextParen = false + + } + } + + p.assignNameSlots() + return nil +} + +func (p *parser) reset(topopts RegexOptions) { + p.currentPos = 0 + p.autocap = 1 + p.ignoreNextParen = false + + if len(p.optionsStack) > 0 { + p.optionsStack = p.optionsStack[:0] + } + + p.options = topopts + p.stack = nil +} + +func (p *parser) scanRegex() (*regexNode, error) { + ch := '@' // nonspecial ch, means at beginning + isQuant := false + + p.startGroup(newRegexNodeMN(ntCapture, p.options, 0, -1)) + + for p.charsRight() > 0 { + wasPrevQuantifier := isQuant + isQuant = false + + if err := p.scanBlank(); err != nil { + return nil, err + } + + startpos := p.textpos() + + // move past all of the normal characters. We'll stop when we hit some kind of control character, + // or if IgnorePatternWhiteSpace is on, we'll stop when we see some whitespace. + if p.useOptionX() { + for p.charsRight() > 0 { + ch = p.rightChar(0) + //UGLY: clean up, this is ugly + if !(!isStopperX(ch) || (ch == '{' && !p.isTrueQuantifier())) { + break + } + p.moveRight(1) + } + } else { + for p.charsRight() > 0 { + ch = p.rightChar(0) + if !(!isSpecial(ch) || ch == '{' && !p.isTrueQuantifier()) { + break + } + p.moveRight(1) + } + } + + endpos := p.textpos() + + p.scanBlank() + + if p.charsRight() == 0 { + ch = '!' // nonspecial, means at end + } else if ch = p.rightChar(0); isSpecial(ch) { + isQuant = isQuantifier(ch) + p.moveRight(1) + } else { + ch = ' ' // nonspecial, means at ordinary char + } + + if startpos < endpos { + cchUnquantified := endpos - startpos + if isQuant { + cchUnquantified-- + } + wasPrevQuantifier = false + + if cchUnquantified > 0 { + p.addToConcatenate(startpos, cchUnquantified, false) + } + + if isQuant { + p.addUnitOne(p.charAt(endpos - 1)) + } + } + + switch ch { + case '!': + goto BreakOuterScan + + case ' ': + goto ContinueOuterScan + + case '[': + cc, err := p.scanCharSet(p.useOptionI(), false) + if err != nil { + return nil, err + } + p.addUnitSet(cc) + + case '(': + p.pushOptions() + + if grouper, err := p.scanGroupOpen(); err != nil { + return nil, err + } else if grouper == nil { + p.popKeepOptions() + } else { + p.pushGroup() + p.startGroup(grouper) + } + + continue + + case '|': + p.addAlternate() + goto ContinueOuterScan + + case ')': + if p.emptyStack() { + return nil, p.getErr(ErrUnexpectedParen) + } + + if err := p.addGroup(); err != nil { + return nil, err + } + if err := p.popGroup(); err != nil { + return nil, err + } + p.popOptions() + + if p.unit == nil { + goto ContinueOuterScan + } + + case '\\': + n, err := p.scanBackslash(false) + if err != nil { + return nil, err + } + p.addUnitNode(n) + + case '^': + if p.useOptionM() { + p.addUnitType(ntBol) + } else { + p.addUnitType(ntBeginning) + } + + case '$': + if p.useOptionM() { + p.addUnitType(ntEol) + } else { + p.addUnitType(ntEndZ) + } + + case '.': + if p.useOptionS() { + p.addUnitSet(AnyClass()) + } else if p.useOptionE() { + p.addUnitSet(ECMAAnyClass()) + } else { + p.addUnitNotone('\n') + } + + case '{', '*', '+', '?': + if p.unit == nil { + if wasPrevQuantifier { + return nil, p.getErr(ErrInvalidRepeatOp) + } else { + return nil, p.getErr(ErrMissingRepeatArgument) + } + } + p.moveLeft() + + default: + return nil, p.getErr(ErrInternalError) + } + + if err := p.scanBlank(); err != nil { + return nil, err + } + + if p.charsRight() > 0 { + isQuant = p.isTrueQuantifier() + } + if p.charsRight() == 0 || !isQuant { + //maintain odd C# assignment order -- not sure if required, could clean up? + p.addConcatenate() + goto ContinueOuterScan + } + + ch = p.moveRightGetChar() + + // Handle quantifiers + for p.unit != nil { + var min, max int + var lazy bool + + switch ch { + case '*': + min = 0 + max = math.MaxInt32 + + case '?': + min = 0 + max = 1 + + case '+': + min = 1 + max = math.MaxInt32 + + case '{': + { + var err error + startpos = p.textpos() + if min, err = p.scanDecimal(); err != nil { + return nil, err + } + max = min + if startpos < p.textpos() { + if p.charsRight() > 0 && p.rightChar(0) == ',' { + p.moveRight(1) + if p.charsRight() == 0 || p.rightChar(0) == '}' { + max = math.MaxInt32 + } else { + if max, err = p.scanDecimal(); err != nil { + return nil, err + } + } + } + } + + if startpos == p.textpos() || p.charsRight() == 0 || p.moveRightGetChar() != '}' { + p.addConcatenate() + p.textto(startpos - 1) + goto ContinueOuterScan + } + } + + default: + return nil, p.getErr(ErrInternalError) + } + + if err := p.scanBlank(); err != nil { + return nil, err + } + + if p.charsRight() == 0 || p.rightChar(0) != '?' { + lazy = false + } else { + p.moveRight(1) + lazy = true + } + + if min > max { + return nil, p.getErr(ErrInvalidRepeatSize) + } + + p.addConcatenate3(lazy, min, max) + } + + ContinueOuterScan: + } + +BreakOuterScan: + ; + + if !p.emptyStack() { + return nil, p.getErr(ErrMissingParen) + } + + if err := p.addGroup(); err != nil { + return nil, err + } + + return p.unit, nil + +} + +/* + * Simple parsing for replacement patterns + */ +func (p *parser) scanReplacement() (*regexNode, error) { + var c, startpos int + + p.concatenation = newRegexNode(ntConcatenate, p.options) + + for { + c = p.charsRight() + if c == 0 { + break + } + + startpos = p.textpos() + + for c > 0 && p.rightChar(0) != '$' { + p.moveRight(1) + c-- + } + + p.addToConcatenate(startpos, p.textpos()-startpos, true) + + if c > 0 { + if p.moveRightGetChar() == '$' { + n, err := p.scanDollar() + if err != nil { + return nil, err + } + p.addUnitNode(n) + } + p.addConcatenate() + } + } + + return p.concatenation, nil +} + +/* + * Scans $ patterns recognized within replacement patterns + */ +func (p *parser) scanDollar() (*regexNode, error) { + if p.charsRight() == 0 { + return newRegexNodeCh(ntOne, p.options, '$'), nil + } + + ch := p.rightChar(0) + angled := false + backpos := p.textpos() + lastEndPos := backpos + + // Note angle + + if ch == '{' && p.charsRight() > 1 { + angled = true + p.moveRight(1) + ch = p.rightChar(0) + } + + // Try to parse backreference: \1 or \{1} or \{cap} + + if ch >= '0' && ch <= '9' { + if !angled && p.useOptionE() { + capnum := -1 + newcapnum := int(ch - '0') + p.moveRight(1) + if p.isCaptureSlot(newcapnum) { + capnum = newcapnum + lastEndPos = p.textpos() + } + + for p.charsRight() > 0 { + ch = p.rightChar(0) + if ch < '0' || ch > '9' { + break + } + digit := int(ch - '0') + if newcapnum > maxValueDiv10 || (newcapnum == maxValueDiv10 && digit > maxValueMod10) { + return nil, p.getErr(ErrCaptureGroupOutOfRange) + } + + newcapnum = newcapnum*10 + digit + + p.moveRight(1) + if p.isCaptureSlot(newcapnum) { + capnum = newcapnum + lastEndPos = p.textpos() + } + } + p.textto(lastEndPos) + if capnum >= 0 { + return newRegexNodeM(ntRef, p.options, capnum), nil + } + } else { + capnum, err := p.scanDecimal() + if err != nil { + return nil, err + } + if !angled || p.charsRight() > 0 && p.moveRightGetChar() == '}' { + if p.isCaptureSlot(capnum) { + return newRegexNodeM(ntRef, p.options, capnum), nil + } + } + } + } else if angled && IsWordChar(ch) { + capname := p.scanCapname() + + if p.charsRight() > 0 && p.moveRightGetChar() == '}' { + if p.isCaptureName(capname) { + return newRegexNodeM(ntRef, p.options, p.captureSlotFromName(capname)), nil + } + } + } else if !angled { + capnum := 1 + + switch ch { + case '$': + p.moveRight(1) + return newRegexNodeCh(ntOne, p.options, '$'), nil + case '&': + capnum = 0 + case '`': + capnum = replaceLeftPortion + case '\'': + capnum = replaceRightPortion + case '+': + capnum = replaceLastGroup + case '_': + capnum = replaceWholeString + } + + if capnum != 1 { + p.moveRight(1) + return newRegexNodeM(ntRef, p.options, capnum), nil + } + } + + // unrecognized $: literalize + + p.textto(backpos) + return newRegexNodeCh(ntOne, p.options, '$'), nil +} + +// scanGroupOpen scans chars following a '(' (not counting the '('), and returns +// a RegexNode for the type of group scanned, or nil if the group +// simply changed options (?cimsx-cimsx) or was a comment (#...). +func (p *parser) scanGroupOpen() (*regexNode, error) { + var ch rune + var nt nodeType + var err error + close := '>' + start := p.textpos() + + // just return a RegexNode if we have: + // 1. "(" followed by nothing + // 2. "(x" where x != ? + // 3. "(?)" + if p.charsRight() == 0 || p.rightChar(0) != '?' || (p.rightChar(0) == '?' && (p.charsRight() > 1 && p.rightChar(1) == ')')) { + if p.useOptionN() || p.ignoreNextParen { + p.ignoreNextParen = false + return newRegexNode(ntGroup, p.options), nil + } + return newRegexNodeMN(ntCapture, p.options, p.consumeAutocap(), -1), nil + } + + p.moveRight(1) + + for { + if p.charsRight() == 0 { + break + } + + switch ch = p.moveRightGetChar(); ch { + case ':': + nt = ntGroup + + case '=': + p.options &= ^RightToLeft + nt = ntRequire + + case '!': + p.options &= ^RightToLeft + nt = ntPrevent + + case '>': + nt = ntGreedy + + case '\'': + close = '\'' + fallthrough + + case '<': + if p.charsRight() == 0 { + goto BreakRecognize + } + + switch ch = p.moveRightGetChar(); ch { + case '=': + if close == '\'' { + goto BreakRecognize + } + + p.options |= RightToLeft + nt = ntRequire + + case '!': + if close == '\'' { + goto BreakRecognize + } + + p.options |= RightToLeft + nt = ntPrevent + + default: + p.moveLeft() + capnum := -1 + uncapnum := -1 + proceed := false + + // grab part before - + + if ch >= '0' && ch <= '9' { + if capnum, err = p.scanDecimal(); err != nil { + return nil, err + } + + if !p.isCaptureSlot(capnum) { + capnum = -1 + } + + // check if we have bogus characters after the number + if p.charsRight() > 0 && !(p.rightChar(0) == close || p.rightChar(0) == '-') { + return nil, p.getErr(ErrInvalidGroupName) + } + if capnum == 0 { + return nil, p.getErr(ErrCapNumNotZero) + } + } else if IsWordChar(ch) { + capname := p.scanCapname() + + if p.isCaptureName(capname) { + capnum = p.captureSlotFromName(capname) + } + + // check if we have bogus character after the name + if p.charsRight() > 0 && !(p.rightChar(0) == close || p.rightChar(0) == '-') { + return nil, p.getErr(ErrInvalidGroupName) + } + } else if ch == '-' { + proceed = true + } else { + // bad group name - starts with something other than a word character and isn't a number + return nil, p.getErr(ErrInvalidGroupName) + } + + // grab part after - if any + + if (capnum != -1 || proceed == true) && p.charsRight() > 0 && p.rightChar(0) == '-' { + p.moveRight(1) + + //no more chars left, no closing char, etc + if p.charsRight() == 0 { + return nil, p.getErr(ErrInvalidGroupName) + } + + ch = p.rightChar(0) + if ch >= '0' && ch <= '9' { + if uncapnum, err = p.scanDecimal(); err != nil { + return nil, err + } + + if !p.isCaptureSlot(uncapnum) { + return nil, p.getErr(ErrUndefinedBackRef, uncapnum) + } + + // check if we have bogus characters after the number + if p.charsRight() > 0 && p.rightChar(0) != close { + return nil, p.getErr(ErrInvalidGroupName) + } + } else if IsWordChar(ch) { + uncapname := p.scanCapname() + + if !p.isCaptureName(uncapname) { + return nil, p.getErr(ErrUndefinedNameRef, uncapname) + } + uncapnum = p.captureSlotFromName(uncapname) + + // check if we have bogus character after the name + if p.charsRight() > 0 && p.rightChar(0) != close { + return nil, p.getErr(ErrInvalidGroupName) + } + } else { + // bad group name - starts with something other than a word character and isn't a number + return nil, p.getErr(ErrInvalidGroupName) + } + } + + // actually make the node + + if (capnum != -1 || uncapnum != -1) && p.charsRight() > 0 && p.moveRightGetChar() == close { + return newRegexNodeMN(ntCapture, p.options, capnum, uncapnum), nil + } + goto BreakRecognize + } + + case '(': + // alternation construct (?(...) | ) + + parenPos := p.textpos() + if p.charsRight() > 0 { + ch = p.rightChar(0) + + // check if the alternation condition is a backref + if ch >= '0' && ch <= '9' { + var capnum int + if capnum, err = p.scanDecimal(); err != nil { + return nil, err + } + if p.charsRight() > 0 && p.moveRightGetChar() == ')' { + if p.isCaptureSlot(capnum) { + return newRegexNodeM(ntTestref, p.options, capnum), nil + } + return nil, p.getErr(ErrUndefinedReference, capnum) + } + + return nil, p.getErr(ErrMalformedReference, capnum) + + } else if IsWordChar(ch) { + capname := p.scanCapname() + + if p.isCaptureName(capname) && p.charsRight() > 0 && p.moveRightGetChar() == ')' { + return newRegexNodeM(ntTestref, p.options, p.captureSlotFromName(capname)), nil + } + } + } + // not a backref + nt = ntTestgroup + p.textto(parenPos - 1) // jump to the start of the parentheses + p.ignoreNextParen = true // but make sure we don't try to capture the insides + + charsRight := p.charsRight() + if charsRight >= 3 && p.rightChar(1) == '?' { + rightchar2 := p.rightChar(2) + // disallow comments in the condition + if rightchar2 == '#' { + return nil, p.getErr(ErrAlternationCantHaveComment) + } + + // disallow named capture group (?<..>..) in the condition + if rightchar2 == '\'' { + return nil, p.getErr(ErrAlternationCantCapture) + } + + if charsRight >= 4 && (rightchar2 == '<' && p.rightChar(3) != '!' && p.rightChar(3) != '=') { + return nil, p.getErr(ErrAlternationCantCapture) + } + } + + case 'P': + if p.useRE2() { + // support for P syntax + if p.charsRight() < 3 { + goto BreakRecognize + } + + ch = p.moveRightGetChar() + if ch != '<' { + goto BreakRecognize + } + + ch = p.moveRightGetChar() + p.moveLeft() + + if IsWordChar(ch) { + capnum := -1 + capname := p.scanCapname() + + if p.isCaptureName(capname) { + capnum = p.captureSlotFromName(capname) + } + + // check if we have bogus character after the name + if p.charsRight() > 0 && p.rightChar(0) != '>' { + return nil, p.getErr(ErrInvalidGroupName) + } + + // actually make the node + + if capnum != -1 && p.charsRight() > 0 && p.moveRightGetChar() == '>' { + return newRegexNodeMN(ntCapture, p.options, capnum, -1), nil + } + goto BreakRecognize + + } else { + // bad group name - starts with something other than a word character and isn't a number + return nil, p.getErr(ErrInvalidGroupName) + } + } + // if we're not using RE2 compat mode then + // we just behave like normal + fallthrough + + default: + p.moveLeft() + + nt = ntGroup + // disallow options in the children of a testgroup node + if p.group.t != ntTestgroup { + p.scanOptions() + } + if p.charsRight() == 0 { + goto BreakRecognize + } + + if ch = p.moveRightGetChar(); ch == ')' { + return nil, nil + } + + if ch != ':' { + goto BreakRecognize + } + + } + + return newRegexNode(nt, p.options), nil + } + +BreakRecognize: + + // break Recognize comes here + + return nil, p.getErr(ErrUnrecognizedGrouping, string(p.pattern[start:p.textpos()])) +} + +// scans backslash specials and basics +func (p *parser) scanBackslash(scanOnly bool) (*regexNode, error) { + + if p.charsRight() == 0 { + return nil, p.getErr(ErrIllegalEndEscape) + } + + switch ch := p.rightChar(0); ch { + case 'b', 'B', 'A', 'G', 'Z', 'z': + p.moveRight(1) + return newRegexNode(p.typeFromCode(ch), p.options), nil + + case 'w': + p.moveRight(1) + if p.useOptionE() || p.useRE2() { + return newRegexNodeSet(ntSet, p.options, ECMAWordClass()), nil + } + return newRegexNodeSet(ntSet, p.options, WordClass()), nil + + case 'W': + p.moveRight(1) + if p.useOptionE() || p.useRE2() { + return newRegexNodeSet(ntSet, p.options, NotECMAWordClass()), nil + } + return newRegexNodeSet(ntSet, p.options, NotWordClass()), nil + + case 's': + p.moveRight(1) + if p.useOptionE() { + return newRegexNodeSet(ntSet, p.options, ECMASpaceClass()), nil + } else if p.useRE2() { + return newRegexNodeSet(ntSet, p.options, RE2SpaceClass()), nil + } + return newRegexNodeSet(ntSet, p.options, SpaceClass()), nil + + case 'S': + p.moveRight(1) + if p.useOptionE() { + return newRegexNodeSet(ntSet, p.options, NotECMASpaceClass()), nil + } else if p.useRE2() { + return newRegexNodeSet(ntSet, p.options, NotRE2SpaceClass()), nil + } + return newRegexNodeSet(ntSet, p.options, NotSpaceClass()), nil + + case 'd': + p.moveRight(1) + if p.useOptionE() || p.useRE2() { + return newRegexNodeSet(ntSet, p.options, ECMADigitClass()), nil + } + return newRegexNodeSet(ntSet, p.options, DigitClass()), nil + + case 'D': + p.moveRight(1) + if p.useOptionE() || p.useRE2() { + return newRegexNodeSet(ntSet, p.options, NotECMADigitClass()), nil + } + return newRegexNodeSet(ntSet, p.options, NotDigitClass()), nil + + case 'p', 'P': + p.moveRight(1) + prop, err := p.parseProperty() + if err != nil { + return nil, err + } + cc := &CharSet{} + cc.addCategory(prop, (ch != 'p'), p.useOptionI(), p.patternRaw) + if p.useOptionI() { + cc.addLowercase() + } + + return newRegexNodeSet(ntSet, p.options, cc), nil + + default: + return p.scanBasicBackslash(scanOnly) + } +} + +// Scans \-style backreferences and character escapes +func (p *parser) scanBasicBackslash(scanOnly bool) (*regexNode, error) { + if p.charsRight() == 0 { + return nil, p.getErr(ErrIllegalEndEscape) + } + angled := false + k := false + close := '\x00' + + backpos := p.textpos() + ch := p.rightChar(0) + + // Allow \k instead of \, which is now deprecated. + + // According to ECMAScript specification, \k is only parsed as a named group reference if + // there is at least one group name in the regexp. + // See https://www.ecma-international.org/ecma-262/#sec-isvalidregularexpressionliteral, step 7. + // Note, during the first (scanOnly) run we may not have all group names scanned, but that's ok. + if ch == 'k' && (!p.useOptionE() || len(p.capnames) > 0) { + if p.charsRight() >= 2 { + p.moveRight(1) + ch = p.moveRightGetChar() + + if ch == '<' || (!p.useOptionE() && ch == '\'') { // No support for \k'name' in ECMAScript + angled = true + if ch == '\'' { + close = '\'' + } else { + close = '>' + } + } + } + + if !angled || p.charsRight() <= 0 { + return nil, p.getErr(ErrMalformedNameRef) + } + + ch = p.rightChar(0) + k = true + + } else if !p.useOptionE() && (ch == '<' || ch == '\'') && p.charsRight() > 1 { // Note angle without \g + angled = true + if ch == '\'' { + close = '\'' + } else { + close = '>' + } + + p.moveRight(1) + ch = p.rightChar(0) + } + + // Try to parse backreference: \<1> or \ + + if angled && ch >= '0' && ch <= '9' { + capnum, err := p.scanDecimal() + if err != nil { + return nil, err + } + + if p.charsRight() > 0 && p.moveRightGetChar() == close { + if p.isCaptureSlot(capnum) { + return newRegexNodeM(ntRef, p.options, capnum), nil + } + return nil, p.getErr(ErrUndefinedBackRef, capnum) + } + } else if !angled && ch >= '1' && ch <= '9' { // Try to parse backreference or octal: \1 + capnum, err := p.scanDecimal() + if err != nil { + return nil, err + } + + if scanOnly { + return nil, nil + } + + if p.isCaptureSlot(capnum) { + return newRegexNodeM(ntRef, p.options, capnum), nil + } + if capnum <= 9 && !p.useOptionE() { + return nil, p.getErr(ErrUndefinedBackRef, capnum) + } + + } else if angled { + capname := p.scanCapname() + + if capname != "" && p.charsRight() > 0 && p.moveRightGetChar() == close { + + if scanOnly { + return nil, nil + } + + if p.isCaptureName(capname) { + return newRegexNodeM(ntRef, p.options, p.captureSlotFromName(capname)), nil + } + return nil, p.getErr(ErrUndefinedNameRef, capname) + } else { + if k { + return nil, p.getErr(ErrMalformedNameRef) + } + } + } + + // Not backreference: must be char code + + p.textto(backpos) + ch, err := p.scanCharEscape() + if err != nil { + return nil, err + } + + if scanOnly { + return nil, nil + } + + if p.useOptionI() { + ch = unicode.ToLower(ch) + } + + return newRegexNodeCh(ntOne, p.options, ch), nil +} + +// Scans X for \p{X} or \P{X} +func (p *parser) parseProperty() (string, error) { + // RE2 and PCRE supports \pX syntax (no {} and only 1 letter unicode cats supported) + // since this is purely additive syntax it's not behind a flag + if p.charsRight() >= 1 && p.rightChar(0) != '{' { + ch := string(p.moveRightGetChar()) + // check if it's a valid cat + if !isValidUnicodeCat(ch) { + return "", p.getErr(ErrUnknownSlashP, ch) + } + return ch, nil + } + + if p.charsRight() < 3 { + return "", p.getErr(ErrIncompleteSlashP) + } + ch := p.moveRightGetChar() + if ch != '{' { + return "", p.getErr(ErrMalformedSlashP) + } + + startpos := p.textpos() + for p.charsRight() > 0 { + ch = p.moveRightGetChar() + if !(IsWordChar(ch) || ch == '-') { + p.moveLeft() + break + } + } + capname := string(p.pattern[startpos:p.textpos()]) + + if p.charsRight() == 0 || p.moveRightGetChar() != '}' { + return "", p.getErr(ErrIncompleteSlashP) + } + + if !isValidUnicodeCat(capname) { + return "", p.getErr(ErrUnknownSlashP, capname) + } + + return capname, nil +} + +// Returns ReNode type for zero-length assertions with a \ code. +func (p *parser) typeFromCode(ch rune) nodeType { + switch ch { + case 'b': + if p.useOptionE() { + return ntECMABoundary + } + return ntBoundary + case 'B': + if p.useOptionE() { + return ntNonECMABoundary + } + return ntNonboundary + case 'A': + return ntBeginning + case 'G': + return ntStart + case 'Z': + return ntEndZ + case 'z': + return ntEnd + default: + return ntNothing + } +} + +// Scans whitespace or x-mode comments. +func (p *parser) scanBlank() error { + if p.useOptionX() { + for { + for p.charsRight() > 0 && isSpace(p.rightChar(0)) { + p.moveRight(1) + } + + if p.charsRight() == 0 { + break + } + + if p.rightChar(0) == '#' { + for p.charsRight() > 0 && p.rightChar(0) != '\n' { + p.moveRight(1) + } + } else if p.charsRight() >= 3 && p.rightChar(2) == '#' && + p.rightChar(1) == '?' && p.rightChar(0) == '(' { + for p.charsRight() > 0 && p.rightChar(0) != ')' { + p.moveRight(1) + } + if p.charsRight() == 0 { + return p.getErr(ErrUnterminatedComment) + } + p.moveRight(1) + } else { + break + } + } + } else { + for { + if p.charsRight() < 3 || p.rightChar(2) != '#' || + p.rightChar(1) != '?' || p.rightChar(0) != '(' { + return nil + } + + for p.charsRight() > 0 && p.rightChar(0) != ')' { + p.moveRight(1) + } + if p.charsRight() == 0 { + return p.getErr(ErrUnterminatedComment) + } + p.moveRight(1) + } + } + return nil +} + +func (p *parser) scanCapname() string { + startpos := p.textpos() + + for p.charsRight() > 0 { + if !IsWordChar(p.moveRightGetChar()) { + p.moveLeft() + break + } + } + + return string(p.pattern[startpos:p.textpos()]) +} + +// Scans contents of [] (not including []'s), and converts to a set. +func (p *parser) scanCharSet(caseInsensitive, scanOnly bool) (*CharSet, error) { + ch := '\x00' + chPrev := '\x00' + inRange := false + firstChar := true + closed := false + + var cc *CharSet + if !scanOnly { + cc = &CharSet{} + } + + if p.charsRight() > 0 && p.rightChar(0) == '^' { + p.moveRight(1) + if !scanOnly { + cc.negate = true + } + } + + for ; p.charsRight() > 0; firstChar = false { + fTranslatedChar := false + ch = p.moveRightGetChar() + if ch == ']' { + if !firstChar { + closed = true + break + } else if p.useOptionE() { + if !scanOnly { + cc.addRanges(NoneClass().ranges) + } + closed = true + break + } + + } else if ch == '\\' && p.charsRight() > 0 { + switch ch = p.moveRightGetChar(); ch { + case 'D', 'd': + if !scanOnly { + if inRange { + return nil, p.getErr(ErrBadClassInCharRange, ch) + } + cc.addDigit(p.useOptionE() || p.useRE2(), ch == 'D', p.patternRaw) + } + continue + + case 'S', 's': + if !scanOnly { + if inRange { + return nil, p.getErr(ErrBadClassInCharRange, ch) + } + cc.addSpace(p.useOptionE(), p.useRE2(), ch == 'S') + } + continue + + case 'W', 'w': + if !scanOnly { + if inRange { + return nil, p.getErr(ErrBadClassInCharRange, ch) + } + + cc.addWord(p.useOptionE() || p.useRE2(), ch == 'W') + } + continue + + case 'p', 'P': + if !scanOnly { + if inRange { + return nil, p.getErr(ErrBadClassInCharRange, ch) + } + prop, err := p.parseProperty() + if err != nil { + return nil, err + } + cc.addCategory(prop, (ch != 'p'), caseInsensitive, p.patternRaw) + } else { + p.parseProperty() + } + + continue + + case '-': + if !scanOnly { + cc.addRange(ch, ch) + } + continue + + default: + p.moveLeft() + var err error + ch, err = p.scanCharEscape() // non-literal character + if err != nil { + return nil, err + } + fTranslatedChar = true + break // this break will only break out of the switch + } + } else if ch == '[' { + // This is code for Posix style properties - [:Ll:] or [:IsTibetan:]. + // It currently doesn't do anything other than skip the whole thing! + if p.charsRight() > 0 && p.rightChar(0) == ':' && !inRange { + savePos := p.textpos() + + p.moveRight(1) + negate := false + if p.charsRight() > 1 && p.rightChar(0) == '^' { + negate = true + p.moveRight(1) + } + + nm := p.scanCapname() // snag the name + if !scanOnly && p.useRE2() { + // look up the name since these are valid for RE2 + // add the group based on the name + if ok := cc.addNamedASCII(nm, negate); !ok { + return nil, p.getErr(ErrInvalidCharRange) + } + } + if p.charsRight() < 2 || p.moveRightGetChar() != ':' || p.moveRightGetChar() != ']' { + p.textto(savePos) + } else if p.useRE2() { + // move on + continue + } + } + } + + if inRange { + inRange = false + if !scanOnly { + if ch == '[' && !fTranslatedChar && !firstChar { + // We thought we were in a range, but we're actually starting a subtraction. + // In that case, we'll add chPrev to our char class, skip the opening [, and + // scan the new character class recursively. + cc.addChar(chPrev) + sub, err := p.scanCharSet(caseInsensitive, false) + if err != nil { + return nil, err + } + cc.addSubtraction(sub) + + if p.charsRight() > 0 && p.rightChar(0) != ']' { + return nil, p.getErr(ErrSubtractionMustBeLast) + } + } else { + // a regular range, like a-z + if chPrev > ch { + return nil, p.getErr(ErrReversedCharRange, chPrev, ch) + } + cc.addRange(chPrev, ch) + } + } + } else if p.charsRight() >= 2 && p.rightChar(0) == '-' && p.rightChar(1) != ']' { + // this could be the start of a range + chPrev = ch + inRange = true + p.moveRight(1) + } else if p.charsRight() >= 1 && ch == '-' && !fTranslatedChar && p.rightChar(0) == '[' && !firstChar { + // we aren't in a range, and now there is a subtraction. Usually this happens + // only when a subtraction follows a range, like [a-z-[b]] + if !scanOnly { + p.moveRight(1) + sub, err := p.scanCharSet(caseInsensitive, false) + if err != nil { + return nil, err + } + cc.addSubtraction(sub) + + if p.charsRight() > 0 && p.rightChar(0) != ']' { + return nil, p.getErr(ErrSubtractionMustBeLast) + } + } else { + p.moveRight(1) + p.scanCharSet(caseInsensitive, true) + } + } else { + if !scanOnly { + cc.addRange(ch, ch) + } + } + } + + if !closed { + return nil, p.getErr(ErrUnterminatedBracket) + } + + if !scanOnly && caseInsensitive { + cc.addLowercase() + } + + return cc, nil +} + +// Scans any number of decimal digits (pegs value at 2^31-1 if too large) +func (p *parser) scanDecimal() (int, error) { + i := 0 + var d int + + for p.charsRight() > 0 { + d = int(p.rightChar(0) - '0') + if d < 0 || d > 9 { + break + } + p.moveRight(1) + + if i > maxValueDiv10 || (i == maxValueDiv10 && d > maxValueMod10) { + return 0, p.getErr(ErrCaptureGroupOutOfRange) + } + + i *= 10 + i += d + } + + return int(i), nil +} + +// Returns true for options allowed only at the top level +func isOnlyTopOption(option RegexOptions) bool { + return option == RightToLeft || option == ECMAScript || option == RE2 +} + +// Scans cimsx-cimsx option string, stops at the first unrecognized char. +func (p *parser) scanOptions() { + + for off := false; p.charsRight() > 0; p.moveRight(1) { + ch := p.rightChar(0) + + if ch == '-' { + off = true + } else if ch == '+' { + off = false + } else { + option := optionFromCode(ch) + if option == 0 || isOnlyTopOption(option) { + return + } + + if off { + p.options &= ^option + } else { + p.options |= option + } + } + } +} + +// Scans \ code for escape codes that map to single unicode chars. +func (p *parser) scanCharEscape() (r rune, err error) { + + ch := p.moveRightGetChar() + + if ch >= '0' && ch <= '7' { + p.moveLeft() + return p.scanOctal(), nil + } + + pos := p.textpos() + + switch ch { + case 'x': + // support for \x{HEX} syntax from Perl and PCRE + if p.charsRight() > 0 && p.rightChar(0) == '{' { + if p.useOptionE() { + return ch, nil + } + p.moveRight(1) + return p.scanHexUntilBrace() + } else { + r, err = p.scanHex(2) + } + case 'u': + // ECMAscript suppot \u{HEX} only if `u` is also set + if p.useOptionE() && p.useOptionU() && p.charsRight() > 0 && p.rightChar(0) == '{' { + p.moveRight(1) + return p.scanHexUntilBrace() + } else { + r, err = p.scanHex(4) + } + case 'a': + return '\u0007', nil + case 'b': + return '\b', nil + case 'e': + return '\u001B', nil + case 'f': + return '\f', nil + case 'n': + return '\n', nil + case 'r': + return '\r', nil + case 't': + return '\t', nil + case 'v': + return '\u000B', nil + case 'c': + r, err = p.scanControl() + default: + if !p.useOptionE() && !p.useRE2() && IsWordChar(ch) { + return 0, p.getErr(ErrUnrecognizedEscape, string(ch)) + } + return ch, nil + } + if err != nil && p.useOptionE() { + p.textto(pos) + return ch, nil + } + return +} + +// Grabs and converts an ascii control character +func (p *parser) scanControl() (rune, error) { + if p.charsRight() <= 0 { + return 0, p.getErr(ErrMissingControl) + } + + ch := p.moveRightGetChar() + + // \ca interpreted as \cA + + if ch >= 'a' && ch <= 'z' { + ch = (ch - ('a' - 'A')) + } + ch = (ch - '@') + if ch >= 0 && ch < ' ' { + return ch, nil + } + + return 0, p.getErr(ErrUnrecognizedControl) + +} + +// Scan hex digits until we hit a closing brace. +// Non-hex digits, hex value too large for UTF-8, or running out of chars are errors +func (p *parser) scanHexUntilBrace() (rune, error) { + // PCRE spec reads like unlimited hex digits are allowed, but unicode has a limit + // so we can enforce that + i := 0 + hasContent := false + + for p.charsRight() > 0 { + ch := p.moveRightGetChar() + if ch == '}' { + // hit our close brace, we're done here + // prevent \x{} + if !hasContent { + return 0, p.getErr(ErrTooFewHex) + } + return rune(i), nil + } + hasContent = true + // no brace needs to be hex digit + d := hexDigit(ch) + if d < 0 { + return 0, p.getErr(ErrMissingBrace) + } + + i *= 0x10 + i += d + + if i > unicode.MaxRune { + return 0, p.getErr(ErrInvalidHex) + } + } + + // we only make it here if we run out of digits without finding the brace + return 0, p.getErr(ErrMissingBrace) +} + +// Scans exactly c hex digits (c=2 for \xFF, c=4 for \uFFFF) +func (p *parser) scanHex(c int) (rune, error) { + + i := 0 + + if p.charsRight() >= c { + for c > 0 { + d := hexDigit(p.moveRightGetChar()) + if d < 0 { + break + } + i *= 0x10 + i += d + c-- + } + } + + if c > 0 { + return 0, p.getErr(ErrTooFewHex) + } + + return rune(i), nil +} + +// Returns n <= 0xF for a hex digit. +func hexDigit(ch rune) int { + + if d := uint(ch - '0'); d <= 9 { + return int(d) + } + + if d := uint(ch - 'a'); d <= 5 { + return int(d + 0xa) + } + + if d := uint(ch - 'A'); d <= 5 { + return int(d + 0xa) + } + + return -1 +} + +// Scans up to three octal digits (stops before exceeding 0377). +func (p *parser) scanOctal() rune { + // Consume octal chars only up to 3 digits and value 0377 + + c := 3 + + if c > p.charsRight() { + c = p.charsRight() + } + + //we know the first char is good because the caller had to check + i := 0 + d := int(p.rightChar(0) - '0') + for c > 0 && d <= 7 && d >= 0 { + if i >= 0x20 && p.useOptionE() { + break + } + i *= 8 + i += d + c-- + + p.moveRight(1) + if !p.rightMost() { + d = int(p.rightChar(0) - '0') + } + } + + // Octal codes only go up to 255. Any larger and the behavior that Perl follows + // is simply to truncate the high bits. + i &= 0xFF + + return rune(i) +} + +// Returns the current parsing position. +func (p *parser) textpos() int { + return p.currentPos +} + +// Zaps to a specific parsing position. +func (p *parser) textto(pos int) { + p.currentPos = pos +} + +// Returns the char at the right of the current parsing position and advances to the right. +func (p *parser) moveRightGetChar() rune { + ch := p.pattern[p.currentPos] + p.currentPos++ + return ch +} + +// Moves the current position to the right. +func (p *parser) moveRight(i int) { + // default would be 1 + p.currentPos += i +} + +// Moves the current parsing position one to the left. +func (p *parser) moveLeft() { + p.currentPos-- +} + +// Returns the char left of the current parsing position. +func (p *parser) charAt(i int) rune { + return p.pattern[i] +} + +// Returns the char i chars right of the current parsing position. +func (p *parser) rightChar(i int) rune { + // default would be 0 + return p.pattern[p.currentPos+i] +} + +// Number of characters to the right of the current parsing position. +func (p *parser) charsRight() int { + return len(p.pattern) - p.currentPos +} + +func (p *parser) rightMost() bool { + return p.currentPos == len(p.pattern) +} + +// Looks up the slot number for a given name +func (p *parser) captureSlotFromName(capname string) int { + return p.capnames[capname] +} + +// True if the capture slot was noted +func (p *parser) isCaptureSlot(i int) bool { + if p.caps != nil { + _, ok := p.caps[i] + return ok + } + + return (i >= 0 && i < p.capsize) +} + +// Looks up the slot number for a given name +func (p *parser) isCaptureName(capname string) bool { + if p.capnames == nil { + return false + } + + _, ok := p.capnames[capname] + return ok +} + +// option shortcuts + +// True if N option disabling '(' autocapture is on. +func (p *parser) useOptionN() bool { + return (p.options & ExplicitCapture) != 0 +} + +// True if I option enabling case-insensitivity is on. +func (p *parser) useOptionI() bool { + return (p.options & IgnoreCase) != 0 +} + +// True if M option altering meaning of $ and ^ is on. +func (p *parser) useOptionM() bool { + return (p.options & Multiline) != 0 +} + +// True if S option altering meaning of . is on. +func (p *parser) useOptionS() bool { + return (p.options & Singleline) != 0 +} + +// True if X option enabling whitespace/comment mode is on. +func (p *parser) useOptionX() bool { + return (p.options & IgnorePatternWhitespace) != 0 +} + +// True if E option enabling ECMAScript behavior on. +func (p *parser) useOptionE() bool { + return (p.options & ECMAScript) != 0 +} + +// true to use RE2 compatibility parsing behavior. +func (p *parser) useRE2() bool { + return (p.options & RE2) != 0 +} + +// True if U option enabling ECMAScript's Unicode behavior on. +func (p *parser) useOptionU() bool { + return (p.options & Unicode) != 0 +} + +// True if options stack is empty. +func (p *parser) emptyOptionsStack() bool { + return len(p.optionsStack) == 0 +} + +// Finish the current quantifiable (when a quantifier is not found or is not possible) +func (p *parser) addConcatenate() { + // The first (| inside a Testgroup group goes directly to the group + p.concatenation.addChild(p.unit) + p.unit = nil +} + +// Finish the current quantifiable (when a quantifier is found) +func (p *parser) addConcatenate3(lazy bool, min, max int) { + p.concatenation.addChild(p.unit.makeQuantifier(lazy, min, max)) + p.unit = nil +} + +// Sets the current unit to a single char node +func (p *parser) addUnitOne(ch rune) { + if p.useOptionI() { + ch = unicode.ToLower(ch) + } + + p.unit = newRegexNodeCh(ntOne, p.options, ch) +} + +// Sets the current unit to a single inverse-char node +func (p *parser) addUnitNotone(ch rune) { + if p.useOptionI() { + ch = unicode.ToLower(ch) + } + + p.unit = newRegexNodeCh(ntNotone, p.options, ch) +} + +// Sets the current unit to a single set node +func (p *parser) addUnitSet(set *CharSet) { + p.unit = newRegexNodeSet(ntSet, p.options, set) +} + +// Sets the current unit to a subtree +func (p *parser) addUnitNode(node *regexNode) { + p.unit = node +} + +// Sets the current unit to an assertion of the specified type +func (p *parser) addUnitType(t nodeType) { + p.unit = newRegexNode(t, p.options) +} + +// Finish the current group (in response to a ')' or end) +func (p *parser) addGroup() error { + if p.group.t == ntTestgroup || p.group.t == ntTestref { + p.group.addChild(p.concatenation.reverseLeft()) + if (p.group.t == ntTestref && len(p.group.children) > 2) || len(p.group.children) > 3 { + return p.getErr(ErrTooManyAlternates) + } + } else { + p.alternation.addChild(p.concatenation.reverseLeft()) + p.group.addChild(p.alternation) + } + + p.unit = p.group + return nil +} + +// Pops the option stack, but keeps the current options unchanged. +func (p *parser) popKeepOptions() { + lastIdx := len(p.optionsStack) - 1 + p.optionsStack = p.optionsStack[:lastIdx] +} + +// Recalls options from the stack. +func (p *parser) popOptions() { + lastIdx := len(p.optionsStack) - 1 + // get the last item on the stack and then remove it by reslicing + p.options = p.optionsStack[lastIdx] + p.optionsStack = p.optionsStack[:lastIdx] +} + +// Saves options on a stack. +func (p *parser) pushOptions() { + p.optionsStack = append(p.optionsStack, p.options) +} + +// Add a string to the last concatenate. +func (p *parser) addToConcatenate(pos, cch int, isReplacement bool) { + var node *regexNode + + if cch == 0 { + return + } + + if cch > 1 { + str := make([]rune, cch) + copy(str, p.pattern[pos:pos+cch]) + + if p.useOptionI() && !isReplacement { + // We do the ToLower character by character for consistency. With surrogate chars, doing + // a ToLower on the entire string could actually change the surrogate pair. This is more correct + // linguistically, but since Regex doesn't support surrogates, it's more important to be + // consistent. + for i := 0; i < len(str); i++ { + str[i] = unicode.ToLower(str[i]) + } + } + + node = newRegexNodeStr(ntMulti, p.options, str) + } else { + ch := p.charAt(pos) + + if p.useOptionI() && !isReplacement { + ch = unicode.ToLower(ch) + } + + node = newRegexNodeCh(ntOne, p.options, ch) + } + + p.concatenation.addChild(node) +} + +// Push the parser state (in response to an open paren) +func (p *parser) pushGroup() { + p.group.next = p.stack + p.alternation.next = p.group + p.concatenation.next = p.alternation + p.stack = p.concatenation +} + +// Remember the pushed state (in response to a ')') +func (p *parser) popGroup() error { + p.concatenation = p.stack + p.alternation = p.concatenation.next + p.group = p.alternation.next + p.stack = p.group.next + + // The first () inside a Testgroup group goes directly to the group + if p.group.t == ntTestgroup && len(p.group.children) == 0 { + if p.unit == nil { + return p.getErr(ErrConditionalExpression) + } + + p.group.addChild(p.unit) + p.unit = nil + } + return nil +} + +// True if the group stack is empty. +func (p *parser) emptyStack() bool { + return p.stack == nil +} + +// Start a new round for the parser state (in response to an open paren or string start) +func (p *parser) startGroup(openGroup *regexNode) { + p.group = openGroup + p.alternation = newRegexNode(ntAlternate, p.options) + p.concatenation = newRegexNode(ntConcatenate, p.options) +} + +// Finish the current concatenation (in response to a |) +func (p *parser) addAlternate() { + // The | parts inside a Testgroup group go directly to the group + + if p.group.t == ntTestgroup || p.group.t == ntTestref { + p.group.addChild(p.concatenation.reverseLeft()) + } else { + p.alternation.addChild(p.concatenation.reverseLeft()) + } + + p.concatenation = newRegexNode(ntConcatenate, p.options) +} + +// For categorizing ascii characters. + +const ( + Q byte = 5 // quantifier + S = 4 // ordinary stopper + Z = 3 // ScanBlank stopper + X = 2 // whitespace + E = 1 // should be escaped +) + +var _category = []byte{ + //01 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 0, 0, 0, 0, 0, 0, 0, 0, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? + X, 0, 0, Z, S, 0, 0, 0, S, S, Q, Q, 0, 0, S, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Q, + //@A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, S, S, 0, S, 0, + //'a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Q, S, 0, 0, 0, +} + +func isSpace(ch rune) bool { + return (ch <= ' ' && _category[ch] == X) +} + +// Returns true for those characters that terminate a string of ordinary chars. +func isSpecial(ch rune) bool { + return (ch <= '|' && _category[ch] >= S) +} + +// Returns true for those characters that terminate a string of ordinary chars. +func isStopperX(ch rune) bool { + return (ch <= '|' && _category[ch] >= X) +} + +// Returns true for those characters that begin a quantifier. +func isQuantifier(ch rune) bool { + return (ch <= '{' && _category[ch] >= Q) +} + +func (p *parser) isTrueQuantifier() bool { + nChars := p.charsRight() + if nChars == 0 { + return false + } + + startpos := p.textpos() + ch := p.charAt(startpos) + if ch != '{' { + return ch <= '{' && _category[ch] >= Q + } + + //UGLY: this is ugly -- the original code was ugly too + pos := startpos + for { + nChars-- + if nChars <= 0 { + break + } + pos++ + ch = p.charAt(pos) + if ch < '0' || ch > '9' { + break + } + } + + if nChars == 0 || pos-startpos == 1 { + return false + } + if ch == '}' { + return true + } + if ch != ',' { + return false + } + for { + nChars-- + if nChars <= 0 { + break + } + pos++ + ch = p.charAt(pos) + if ch < '0' || ch > '9' { + break + } + } + + return nChars > 0 && ch == '}' +} diff --git a/vendor/github.com/dlclark/regexp2/syntax/prefix.go b/vendor/github.com/dlclark/regexp2/syntax/prefix.go new file mode 100644 index 000000000..f67168862 --- /dev/null +++ b/vendor/github.com/dlclark/regexp2/syntax/prefix.go @@ -0,0 +1,896 @@ +package syntax + +import ( + "bytes" + "fmt" + "strconv" + "unicode" + "unicode/utf8" +) + +type Prefix struct { + PrefixStr []rune + PrefixSet CharSet + CaseInsensitive bool +} + +// It takes a RegexTree and computes the set of chars that can start it. +func getFirstCharsPrefix(tree *RegexTree) *Prefix { + s := regexFcd{ + fcStack: make([]regexFc, 32), + intStack: make([]int, 32), + } + fc := s.regexFCFromRegexTree(tree) + + if fc == nil || fc.nullable || fc.cc.IsEmpty() { + return nil + } + fcSet := fc.getFirstChars() + return &Prefix{PrefixSet: fcSet, CaseInsensitive: fc.caseInsensitive} +} + +type regexFcd struct { + intStack []int + intDepth int + fcStack []regexFc + fcDepth int + skipAllChildren bool // don't process any more children at the current level + skipchild bool // don't process the current child. + failed bool +} + +/* + * The main FC computation. It does a shortcutted depth-first walk + * through the tree and calls CalculateFC to emits code before + * and after each child of an interior node, and at each leaf. + */ +func (s *regexFcd) regexFCFromRegexTree(tree *RegexTree) *regexFc { + curNode := tree.root + curChild := 0 + + for { + if len(curNode.children) == 0 { + // This is a leaf node + s.calculateFC(curNode.t, curNode, 0) + } else if curChild < len(curNode.children) && !s.skipAllChildren { + // This is an interior node, and we have more children to analyze + s.calculateFC(curNode.t|beforeChild, curNode, curChild) + + if !s.skipchild { + curNode = curNode.children[curChild] + // this stack is how we get a depth first walk of the tree. + s.pushInt(curChild) + curChild = 0 + } else { + curChild++ + s.skipchild = false + } + continue + } + + // This is an interior node where we've finished analyzing all the children, or + // the end of a leaf node. + s.skipAllChildren = false + + if s.intIsEmpty() { + break + } + + curChild = s.popInt() + curNode = curNode.next + + s.calculateFC(curNode.t|afterChild, curNode, curChild) + if s.failed { + return nil + } + + curChild++ + } + + if s.fcIsEmpty() { + return nil + } + + return s.popFC() +} + +// To avoid recursion, we use a simple integer stack. +// This is the push. +func (s *regexFcd) pushInt(I int) { + if s.intDepth >= len(s.intStack) { + expanded := make([]int, s.intDepth*2) + copy(expanded, s.intStack) + s.intStack = expanded + } + + s.intStack[s.intDepth] = I + s.intDepth++ +} + +// True if the stack is empty. +func (s *regexFcd) intIsEmpty() bool { + return s.intDepth == 0 +} + +// This is the pop. +func (s *regexFcd) popInt() int { + s.intDepth-- + return s.intStack[s.intDepth] +} + +// We also use a stack of RegexFC objects. +// This is the push. +func (s *regexFcd) pushFC(fc regexFc) { + if s.fcDepth >= len(s.fcStack) { + expanded := make([]regexFc, s.fcDepth*2) + copy(expanded, s.fcStack) + s.fcStack = expanded + } + + s.fcStack[s.fcDepth] = fc + s.fcDepth++ +} + +// True if the stack is empty. +func (s *regexFcd) fcIsEmpty() bool { + return s.fcDepth == 0 +} + +// This is the pop. +func (s *regexFcd) popFC() *regexFc { + s.fcDepth-- + return &s.fcStack[s.fcDepth] +} + +// This is the top. +func (s *regexFcd) topFC() *regexFc { + return &s.fcStack[s.fcDepth-1] +} + +// Called in Beforechild to prevent further processing of the current child +func (s *regexFcd) skipChild() { + s.skipchild = true +} + +// FC computation and shortcut cases for each node type +func (s *regexFcd) calculateFC(nt nodeType, node *regexNode, CurIndex int) { + //fmt.Printf("NodeType: %v, CurIndex: %v, Desc: %v\n", nt, CurIndex, node.description()) + ci := false + rtl := false + + if nt <= ntRef { + if (node.options & IgnoreCase) != 0 { + ci = true + } + if (node.options & RightToLeft) != 0 { + rtl = true + } + } + + switch nt { + case ntConcatenate | beforeChild, ntAlternate | beforeChild, ntTestref | beforeChild, ntLoop | beforeChild, ntLazyloop | beforeChild: + break + + case ntTestgroup | beforeChild: + if CurIndex == 0 { + s.skipChild() + } + break + + case ntEmpty: + s.pushFC(regexFc{nullable: true}) + break + + case ntConcatenate | afterChild: + if CurIndex != 0 { + child := s.popFC() + cumul := s.topFC() + + s.failed = !cumul.addFC(*child, true) + } + + fc := s.topFC() + if !fc.nullable { + s.skipAllChildren = true + } + break + + case ntTestgroup | afterChild: + if CurIndex > 1 { + child := s.popFC() + cumul := s.topFC() + + s.failed = !cumul.addFC(*child, false) + } + break + + case ntAlternate | afterChild, ntTestref | afterChild: + if CurIndex != 0 { + child := s.popFC() + cumul := s.topFC() + + s.failed = !cumul.addFC(*child, false) + } + break + + case ntLoop | afterChild, ntLazyloop | afterChild: + if node.m == 0 { + fc := s.topFC() + fc.nullable = true + } + break + + case ntGroup | beforeChild, ntGroup | afterChild, ntCapture | beforeChild, ntCapture | afterChild, ntGreedy | beforeChild, ntGreedy | afterChild: + break + + case ntRequire | beforeChild, ntPrevent | beforeChild: + s.skipChild() + s.pushFC(regexFc{nullable: true}) + break + + case ntRequire | afterChild, ntPrevent | afterChild: + break + + case ntOne, ntNotone: + s.pushFC(newRegexFc(node.ch, nt == ntNotone, false, ci)) + break + + case ntOneloop, ntOnelazy: + s.pushFC(newRegexFc(node.ch, false, node.m == 0, ci)) + break + + case ntNotoneloop, ntNotonelazy: + s.pushFC(newRegexFc(node.ch, true, node.m == 0, ci)) + break + + case ntMulti: + if len(node.str) == 0 { + s.pushFC(regexFc{nullable: true}) + } else if !rtl { + s.pushFC(newRegexFc(node.str[0], false, false, ci)) + } else { + s.pushFC(newRegexFc(node.str[len(node.str)-1], false, false, ci)) + } + break + + case ntSet: + s.pushFC(regexFc{cc: node.set.Copy(), nullable: false, caseInsensitive: ci}) + break + + case ntSetloop, ntSetlazy: + s.pushFC(regexFc{cc: node.set.Copy(), nullable: node.m == 0, caseInsensitive: ci}) + break + + case ntRef: + s.pushFC(regexFc{cc: *AnyClass(), nullable: true, caseInsensitive: false}) + break + + case ntNothing, ntBol, ntEol, ntBoundary, ntNonboundary, ntECMABoundary, ntNonECMABoundary, ntBeginning, ntStart, ntEndZ, ntEnd: + s.pushFC(regexFc{nullable: true}) + break + + default: + panic(fmt.Sprintf("unexpected op code: %v", nt)) + } +} + +type regexFc struct { + cc CharSet + nullable bool + caseInsensitive bool +} + +func newRegexFc(ch rune, not, nullable, caseInsensitive bool) regexFc { + r := regexFc{ + caseInsensitive: caseInsensitive, + nullable: nullable, + } + if not { + if ch > 0 { + r.cc.addRange('\x00', ch-1) + } + if ch < 0xFFFF { + r.cc.addRange(ch+1, utf8.MaxRune) + } + } else { + r.cc.addRange(ch, ch) + } + return r +} + +func (r *regexFc) getFirstChars() CharSet { + if r.caseInsensitive { + r.cc.addLowercase() + } + + return r.cc +} + +func (r *regexFc) addFC(fc regexFc, concatenate bool) bool { + if !r.cc.IsMergeable() || !fc.cc.IsMergeable() { + return false + } + + if concatenate { + if !r.nullable { + return true + } + + if !fc.nullable { + r.nullable = false + } + } else { + if fc.nullable { + r.nullable = true + } + } + + r.caseInsensitive = r.caseInsensitive || fc.caseInsensitive + r.cc.addSet(fc.cc) + + return true +} + +// This is a related computation: it takes a RegexTree and computes the +// leading substring if it sees one. It's quite trivial and gives up easily. +func getPrefix(tree *RegexTree) *Prefix { + var concatNode *regexNode + nextChild := 0 + + curNode := tree.root + + for { + switch curNode.t { + case ntConcatenate: + if len(curNode.children) > 0 { + concatNode = curNode + nextChild = 0 + } + + case ntGreedy, ntCapture: + curNode = curNode.children[0] + concatNode = nil + continue + + case ntOneloop, ntOnelazy: + if curNode.m > 0 { + return &Prefix{ + PrefixStr: repeat(curNode.ch, curNode.m), + CaseInsensitive: (curNode.options & IgnoreCase) != 0, + } + } + return nil + + case ntOne: + return &Prefix{ + PrefixStr: []rune{curNode.ch}, + CaseInsensitive: (curNode.options & IgnoreCase) != 0, + } + + case ntMulti: + return &Prefix{ + PrefixStr: curNode.str, + CaseInsensitive: (curNode.options & IgnoreCase) != 0, + } + + case ntBol, ntEol, ntBoundary, ntECMABoundary, ntBeginning, ntStart, + ntEndZ, ntEnd, ntEmpty, ntRequire, ntPrevent: + + default: + return nil + } + + if concatNode == nil || nextChild >= len(concatNode.children) { + return nil + } + + curNode = concatNode.children[nextChild] + nextChild++ + } +} + +// repeat the rune r, c times... up to the max of MaxPrefixSize +func repeat(r rune, c int) []rune { + if c > MaxPrefixSize { + c = MaxPrefixSize + } + + ret := make([]rune, c) + + // binary growth using copy for speed + ret[0] = r + bp := 1 + for bp < len(ret) { + copy(ret[bp:], ret[:bp]) + bp *= 2 + } + + return ret +} + +// BmPrefix precomputes the Boyer-Moore +// tables for fast string scanning. These tables allow +// you to scan for the first occurrence of a string within +// a large body of text without examining every character. +// The performance of the heuristic depends on the actual +// string and the text being searched, but usually, the longer +// the string that is being searched for, the fewer characters +// need to be examined. +type BmPrefix struct { + positive []int + negativeASCII []int + negativeUnicode [][]int + pattern []rune + lowASCII rune + highASCII rune + rightToLeft bool + caseInsensitive bool +} + +func newBmPrefix(pattern []rune, caseInsensitive, rightToLeft bool) *BmPrefix { + + b := &BmPrefix{ + rightToLeft: rightToLeft, + caseInsensitive: caseInsensitive, + pattern: pattern, + } + + if caseInsensitive { + for i := 0; i < len(b.pattern); i++ { + // We do the ToLower character by character for consistency. With surrogate chars, doing + // a ToLower on the entire string could actually change the surrogate pair. This is more correct + // linguistically, but since Regex doesn't support surrogates, it's more important to be + // consistent. + + b.pattern[i] = unicode.ToLower(b.pattern[i]) + } + } + + var beforefirst, last, bump int + var scan, match int + + if !rightToLeft { + beforefirst = -1 + last = len(b.pattern) - 1 + bump = 1 + } else { + beforefirst = len(b.pattern) + last = 0 + bump = -1 + } + + // PART I - the good-suffix shift table + // + // compute the positive requirement: + // if char "i" is the first one from the right that doesn't match, + // then we know the matcher can advance by _positive[i]. + // + // This algorithm is a simplified variant of the standard + // Boyer-Moore good suffix calculation. + + b.positive = make([]int, len(b.pattern)) + + examine := last + ch := b.pattern[examine] + b.positive[examine] = bump + examine -= bump + +Outerloop: + for { + // find an internal char (examine) that matches the tail + + for { + if examine == beforefirst { + break Outerloop + } + if b.pattern[examine] == ch { + break + } + examine -= bump + } + + match = last + scan = examine + + // find the length of the match + for { + if scan == beforefirst || b.pattern[match] != b.pattern[scan] { + // at the end of the match, note the difference in _positive + // this is not the length of the match, but the distance from the internal match + // to the tail suffix. + if b.positive[match] == 0 { + b.positive[match] = match - scan + } + + // System.Diagnostics.Debug.WriteLine("Set positive[" + match + "] to " + (match - scan)); + + break + } + + scan -= bump + match -= bump + } + + examine -= bump + } + + match = last - bump + + // scan for the chars for which there are no shifts that yield a different candidate + + // The inside of the if statement used to say + // "_positive[match] = last - beforefirst;" + // This is slightly less aggressive in how much we skip, but at worst it + // should mean a little more work rather than skipping a potential match. + for match != beforefirst { + if b.positive[match] == 0 { + b.positive[match] = bump + } + + match -= bump + } + + // PART II - the bad-character shift table + // + // compute the negative requirement: + // if char "ch" is the reject character when testing position "i", + // we can slide up by _negative[ch]; + // (_negative[ch] = str.Length - 1 - str.LastIndexOf(ch)) + // + // the lookup table is divided into ASCII and Unicode portions; + // only those parts of the Unicode 16-bit code set that actually + // appear in the string are in the table. (Maximum size with + // Unicode is 65K; ASCII only case is 512 bytes.) + + b.negativeASCII = make([]int, 128) + + for i := 0; i < len(b.negativeASCII); i++ { + b.negativeASCII[i] = last - beforefirst + } + + b.lowASCII = 127 + b.highASCII = 0 + + for examine = last; examine != beforefirst; examine -= bump { + ch = b.pattern[examine] + + switch { + case ch < 128: + if b.lowASCII > ch { + b.lowASCII = ch + } + + if b.highASCII < ch { + b.highASCII = ch + } + + if b.negativeASCII[ch] == last-beforefirst { + b.negativeASCII[ch] = last - examine + } + case ch <= 0xffff: + i, j := ch>>8, ch&0xFF + + if b.negativeUnicode == nil { + b.negativeUnicode = make([][]int, 256) + } + + if b.negativeUnicode[i] == nil { + newarray := make([]int, 256) + + for k := 0; k < len(newarray); k++ { + newarray[k] = last - beforefirst + } + + if i == 0 { + copy(newarray, b.negativeASCII) + //TODO: this line needed? + b.negativeASCII = newarray + } + + b.negativeUnicode[i] = newarray + } + + if b.negativeUnicode[i][j] == last-beforefirst { + b.negativeUnicode[i][j] = last - examine + } + default: + // we can't do the filter because this algo doesn't support + // unicode chars >0xffff + return nil + } + } + + return b +} + +func (b *BmPrefix) String() string { + return string(b.pattern) +} + +// Dump returns the contents of the filter as a human readable string +func (b *BmPrefix) Dump(indent string) string { + buf := &bytes.Buffer{} + + fmt.Fprintf(buf, "%sBM Pattern: %s\n%sPositive: ", indent, string(b.pattern), indent) + for i := 0; i < len(b.positive); i++ { + buf.WriteString(strconv.Itoa(b.positive[i])) + buf.WriteRune(' ') + } + buf.WriteRune('\n') + + if b.negativeASCII != nil { + buf.WriteString(indent) + buf.WriteString("Negative table\n") + for i := 0; i < len(b.negativeASCII); i++ { + if b.negativeASCII[i] != len(b.pattern) { + fmt.Fprintf(buf, "%s %s %s\n", indent, Escape(string(rune(i))), strconv.Itoa(b.negativeASCII[i])) + } + } + } + + return buf.String() +} + +// Scan uses the Boyer-Moore algorithm to find the first occurrence +// of the specified string within text, beginning at index, and +// constrained within beglimit and endlimit. +// +// The direction and case-sensitivity of the match is determined +// by the arguments to the RegexBoyerMoore constructor. +func (b *BmPrefix) Scan(text []rune, index, beglimit, endlimit int) int { + var ( + defadv, test, test2 int + match, startmatch, endmatch int + bump, advance int + chTest rune + unicodeLookup []int + ) + + if !b.rightToLeft { + defadv = len(b.pattern) + startmatch = len(b.pattern) - 1 + endmatch = 0 + test = index + defadv - 1 + bump = 1 + } else { + defadv = -len(b.pattern) + startmatch = 0 + endmatch = -defadv - 1 + test = index + defadv + bump = -1 + } + + chMatch := b.pattern[startmatch] + + for { + if test >= endlimit || test < beglimit { + return -1 + } + + chTest = text[test] + + if b.caseInsensitive { + chTest = unicode.ToLower(chTest) + } + + if chTest != chMatch { + if chTest < 128 { + advance = b.negativeASCII[chTest] + } else if chTest < 0xffff && len(b.negativeUnicode) > 0 { + unicodeLookup = b.negativeUnicode[chTest>>8] + if len(unicodeLookup) > 0 { + advance = unicodeLookup[chTest&0xFF] + } else { + advance = defadv + } + } else { + advance = defadv + } + + test += advance + } else { // if (chTest == chMatch) + test2 = test + match = startmatch + + for { + if match == endmatch { + if b.rightToLeft { + return test2 + 1 + } else { + return test2 + } + } + + match -= bump + test2 -= bump + + chTest = text[test2] + + if b.caseInsensitive { + chTest = unicode.ToLower(chTest) + } + + if chTest != b.pattern[match] { + advance = b.positive[match] + if chTest < 128 { + test2 = (match - startmatch) + b.negativeASCII[chTest] + } else if chTest < 0xffff && len(b.negativeUnicode) > 0 { + unicodeLookup = b.negativeUnicode[chTest>>8] + if len(unicodeLookup) > 0 { + test2 = (match - startmatch) + unicodeLookup[chTest&0xFF] + } else { + test += advance + break + } + } else { + test += advance + break + } + + if b.rightToLeft { + if test2 < advance { + advance = test2 + } + } else if test2 > advance { + advance = test2 + } + + test += advance + break + } + } + } + } +} + +// When a regex is anchored, we can do a quick IsMatch test instead of a Scan +func (b *BmPrefix) IsMatch(text []rune, index, beglimit, endlimit int) bool { + if !b.rightToLeft { + if index < beglimit || endlimit-index < len(b.pattern) { + return false + } + + return b.matchPattern(text, index) + } else { + if index > endlimit || index-beglimit < len(b.pattern) { + return false + } + + return b.matchPattern(text, index-len(b.pattern)) + } +} + +func (b *BmPrefix) matchPattern(text []rune, index int) bool { + if len(text)-index < len(b.pattern) { + return false + } + + if b.caseInsensitive { + for i := 0; i < len(b.pattern); i++ { + //Debug.Assert(textinfo.ToLower(_pattern[i]) == _pattern[i], "pattern should be converted to lower case in constructor!"); + if unicode.ToLower(text[index+i]) != b.pattern[i] { + return false + } + } + return true + } else { + for i := 0; i < len(b.pattern); i++ { + if text[index+i] != b.pattern[i] { + return false + } + } + return true + } +} + +type AnchorLoc int16 + +// where the regex can be pegged +const ( + AnchorBeginning AnchorLoc = 0x0001 + AnchorBol = 0x0002 + AnchorStart = 0x0004 + AnchorEol = 0x0008 + AnchorEndZ = 0x0010 + AnchorEnd = 0x0020 + AnchorBoundary = 0x0040 + AnchorECMABoundary = 0x0080 +) + +func getAnchors(tree *RegexTree) AnchorLoc { + + var concatNode *regexNode + nextChild, result := 0, AnchorLoc(0) + + curNode := tree.root + + for { + switch curNode.t { + case ntConcatenate: + if len(curNode.children) > 0 { + concatNode = curNode + nextChild = 0 + } + + case ntGreedy, ntCapture: + curNode = curNode.children[0] + concatNode = nil + continue + + case ntBol, ntEol, ntBoundary, ntECMABoundary, ntBeginning, + ntStart, ntEndZ, ntEnd: + return result | anchorFromType(curNode.t) + + case ntEmpty, ntRequire, ntPrevent: + + default: + return result + } + + if concatNode == nil || nextChild >= len(concatNode.children) { + return result + } + + curNode = concatNode.children[nextChild] + nextChild++ + } +} + +func anchorFromType(t nodeType) AnchorLoc { + switch t { + case ntBol: + return AnchorBol + case ntEol: + return AnchorEol + case ntBoundary: + return AnchorBoundary + case ntECMABoundary: + return AnchorECMABoundary + case ntBeginning: + return AnchorBeginning + case ntStart: + return AnchorStart + case ntEndZ: + return AnchorEndZ + case ntEnd: + return AnchorEnd + default: + return 0 + } +} + +// anchorDescription returns a human-readable description of the anchors +func (anchors AnchorLoc) String() string { + buf := &bytes.Buffer{} + + if 0 != (anchors & AnchorBeginning) { + buf.WriteString(", Beginning") + } + if 0 != (anchors & AnchorStart) { + buf.WriteString(", Start") + } + if 0 != (anchors & AnchorBol) { + buf.WriteString(", Bol") + } + if 0 != (anchors & AnchorBoundary) { + buf.WriteString(", Boundary") + } + if 0 != (anchors & AnchorECMABoundary) { + buf.WriteString(", ECMABoundary") + } + if 0 != (anchors & AnchorEol) { + buf.WriteString(", Eol") + } + if 0 != (anchors & AnchorEnd) { + buf.WriteString(", End") + } + if 0 != (anchors & AnchorEndZ) { + buf.WriteString(", EndZ") + } + + // trim off comma + if buf.Len() >= 2 { + return buf.String()[2:] + } + return "None" +} diff --git a/vendor/github.com/dlclark/regexp2/syntax/replacerdata.go b/vendor/github.com/dlclark/regexp2/syntax/replacerdata.go new file mode 100644 index 000000000..bcf4d3f25 --- /dev/null +++ b/vendor/github.com/dlclark/regexp2/syntax/replacerdata.go @@ -0,0 +1,87 @@ +package syntax + +import ( + "bytes" + "errors" +) + +type ReplacerData struct { + Rep string + Strings []string + Rules []int +} + +const ( + replaceSpecials = 4 + replaceLeftPortion = -1 + replaceRightPortion = -2 + replaceLastGroup = -3 + replaceWholeString = -4 +) + +//ErrReplacementError is a general error during parsing the replacement text +var ErrReplacementError = errors.New("Replacement pattern error.") + +// NewReplacerData will populate a reusable replacer data struct based on the given replacement string +// and the capture group data from a regexp +func NewReplacerData(rep string, caps map[int]int, capsize int, capnames map[string]int, op RegexOptions) (*ReplacerData, error) { + p := parser{ + options: op, + caps: caps, + capsize: capsize, + capnames: capnames, + } + p.setPattern(rep) + concat, err := p.scanReplacement() + if err != nil { + return nil, err + } + + if concat.t != ntConcatenate { + panic(ErrReplacementError) + } + + sb := &bytes.Buffer{} + var ( + strings []string + rules []int + ) + + for _, child := range concat.children { + switch child.t { + case ntMulti: + child.writeStrToBuf(sb) + + case ntOne: + sb.WriteRune(child.ch) + + case ntRef: + if sb.Len() > 0 { + rules = append(rules, len(strings)) + strings = append(strings, sb.String()) + sb.Reset() + } + slot := child.m + + if len(caps) > 0 && slot >= 0 { + slot = caps[slot] + } + + rules = append(rules, -replaceSpecials-1-slot) + + default: + panic(ErrReplacementError) + } + } + + if sb.Len() > 0 { + rules = append(rules, len(strings)) + strings = append(strings, sb.String()) + } + + return &ReplacerData{ + Rep: rep, + Strings: strings, + Rules: rules, + }, nil +} diff --git a/vendor/github.com/dlclark/regexp2/syntax/tree.go b/vendor/github.com/dlclark/regexp2/syntax/tree.go new file mode 100644 index 000000000..ea2882931 --- /dev/null +++ b/vendor/github.com/dlclark/regexp2/syntax/tree.go @@ -0,0 +1,654 @@ +package syntax + +import ( + "bytes" + "fmt" + "math" + "strconv" +) + +type RegexTree struct { + root *regexNode + caps map[int]int + capnumlist []int + captop int + Capnames map[string]int + Caplist []string + options RegexOptions +} + +// It is built into a parsed tree for a regular expression. + +// Implementation notes: +// +// Since the node tree is a temporary data structure only used +// during compilation of the regexp to integer codes, it's +// designed for clarity and convenience rather than +// space efficiency. +// +// RegexNodes are built into a tree, linked by the n.children list. +// Each node also has a n.parent and n.ichild member indicating +// its parent and which child # it is in its parent's list. +// +// RegexNodes come in as many types as there are constructs in +// a regular expression, for example, "concatenate", "alternate", +// "one", "rept", "group". There are also node types for basic +// peephole optimizations, e.g., "onerep", "notsetrep", etc. +// +// Because perl 5 allows "lookback" groups that scan backwards, +// each node also gets a "direction". Normally the value of +// boolean n.backward = false. +// +// During parsing, top-level nodes are also stacked onto a parse +// stack (a stack of trees). For this purpose we have a n.next +// pointer. [Note that to save a few bytes, we could overload the +// n.parent pointer instead.] +// +// On the parse stack, each tree has a "role" - basically, the +// nonterminal in the grammar that the parser has currently +// assigned to the tree. That code is stored in n.role. +// +// Finally, some of the different kinds of nodes have data. +// Two integers (for the looping constructs) are stored in +// n.operands, an an object (either a string or a set) +// is stored in n.data +type regexNode struct { + t nodeType + children []*regexNode + str []rune + set *CharSet + ch rune + m int + n int + options RegexOptions + next *regexNode +} + +type nodeType int32 + +const ( + // The following are leaves, and correspond to primitive operations + + ntOnerep nodeType = 0 // lef,back char,min,max a {n} + ntNotonerep = 1 // lef,back char,min,max .{n} + ntSetrep = 2 // lef,back set,min,max [\d]{n} + ntOneloop = 3 // lef,back char,min,max a {,n} + ntNotoneloop = 4 // lef,back char,min,max .{,n} + ntSetloop = 5 // lef,back set,min,max [\d]{,n} + ntOnelazy = 6 // lef,back char,min,max a {,n}? + ntNotonelazy = 7 // lef,back char,min,max .{,n}? + ntSetlazy = 8 // lef,back set,min,max [\d]{,n}? + ntOne = 9 // lef char a + ntNotone = 10 // lef char [^a] + ntSet = 11 // lef set [a-z\s] \w \s \d + ntMulti = 12 // lef string abcd + ntRef = 13 // lef group \# + ntBol = 14 // ^ + ntEol = 15 // $ + ntBoundary = 16 // \b + ntNonboundary = 17 // \B + ntBeginning = 18 // \A + ntStart = 19 // \G + ntEndZ = 20 // \Z + ntEnd = 21 // \Z + + // Interior nodes do not correspond to primitive operations, but + // control structures compositing other operations + + // Concat and alternate take n children, and can run forward or backwards + + ntNothing = 22 // [] + ntEmpty = 23 // () + ntAlternate = 24 // a|b + ntConcatenate = 25 // ab + ntLoop = 26 // m,x * + ? {,} + ntLazyloop = 27 // m,x *? +? ?? {,}? + ntCapture = 28 // n () + ntGroup = 29 // (?:) + ntRequire = 30 // (?=) (?<=) + ntPrevent = 31 // (?!) (?) (?<) + ntTestref = 33 // (?(n) | ) + ntTestgroup = 34 // (?(...) | ) + + ntECMABoundary = 41 // \b + ntNonECMABoundary = 42 // \B +) + +func newRegexNode(t nodeType, opt RegexOptions) *regexNode { + return ®exNode{ + t: t, + options: opt, + } +} + +func newRegexNodeCh(t nodeType, opt RegexOptions, ch rune) *regexNode { + return ®exNode{ + t: t, + options: opt, + ch: ch, + } +} + +func newRegexNodeStr(t nodeType, opt RegexOptions, str []rune) *regexNode { + return ®exNode{ + t: t, + options: opt, + str: str, + } +} + +func newRegexNodeSet(t nodeType, opt RegexOptions, set *CharSet) *regexNode { + return ®exNode{ + t: t, + options: opt, + set: set, + } +} + +func newRegexNodeM(t nodeType, opt RegexOptions, m int) *regexNode { + return ®exNode{ + t: t, + options: opt, + m: m, + } +} +func newRegexNodeMN(t nodeType, opt RegexOptions, m, n int) *regexNode { + return ®exNode{ + t: t, + options: opt, + m: m, + n: n, + } +} + +func (n *regexNode) writeStrToBuf(buf *bytes.Buffer) { + for i := 0; i < len(n.str); i++ { + buf.WriteRune(n.str[i]) + } +} + +func (n *regexNode) addChild(child *regexNode) { + reduced := child.reduce() + n.children = append(n.children, reduced) + reduced.next = n +} + +func (n *regexNode) insertChildren(afterIndex int, nodes []*regexNode) { + newChildren := make([]*regexNode, 0, len(n.children)+len(nodes)) + n.children = append(append(append(newChildren, n.children[:afterIndex]...), nodes...), n.children[afterIndex:]...) +} + +// removes children including the start but not the end index +func (n *regexNode) removeChildren(startIndex, endIndex int) { + n.children = append(n.children[:startIndex], n.children[endIndex:]...) +} + +// Pass type as OneLazy or OneLoop +func (n *regexNode) makeRep(t nodeType, min, max int) { + n.t += (t - ntOne) + n.m = min + n.n = max +} + +func (n *regexNode) reduce() *regexNode { + switch n.t { + case ntAlternate: + return n.reduceAlternation() + + case ntConcatenate: + return n.reduceConcatenation() + + case ntLoop, ntLazyloop: + return n.reduceRep() + + case ntGroup: + return n.reduceGroup() + + case ntSet, ntSetloop: + return n.reduceSet() + + default: + return n + } +} + +// Basic optimization. Single-letter alternations can be replaced +// by faster set specifications, and nested alternations with no +// intervening operators can be flattened: +// +// a|b|c|def|g|h -> [a-c]|def|[gh] +// apple|(?:orange|pear)|grape -> apple|orange|pear|grape +func (n *regexNode) reduceAlternation() *regexNode { + if len(n.children) == 0 { + return newRegexNode(ntNothing, n.options) + } + + wasLastSet := false + lastNodeCannotMerge := false + var optionsLast RegexOptions + var i, j int + + for i, j = 0, 0; i < len(n.children); i, j = i+1, j+1 { + at := n.children[i] + + if j < i { + n.children[j] = at + } + + for { + if at.t == ntAlternate { + for k := 0; k < len(at.children); k++ { + at.children[k].next = n + } + n.insertChildren(i+1, at.children) + + j-- + } else if at.t == ntSet || at.t == ntOne { + // Cannot merge sets if L or I options differ, or if either are negated. + optionsAt := at.options & (RightToLeft | IgnoreCase) + + if at.t == ntSet { + if !wasLastSet || optionsLast != optionsAt || lastNodeCannotMerge || !at.set.IsMergeable() { + wasLastSet = true + lastNodeCannotMerge = !at.set.IsMergeable() + optionsLast = optionsAt + break + } + } else if !wasLastSet || optionsLast != optionsAt || lastNodeCannotMerge { + wasLastSet = true + lastNodeCannotMerge = false + optionsLast = optionsAt + break + } + + // The last node was a Set or a One, we're a Set or One and our options are the same. + // Merge the two nodes. + j-- + prev := n.children[j] + + var prevCharClass *CharSet + if prev.t == ntOne { + prevCharClass = &CharSet{} + prevCharClass.addChar(prev.ch) + } else { + prevCharClass = prev.set + } + + if at.t == ntOne { + prevCharClass.addChar(at.ch) + } else { + prevCharClass.addSet(*at.set) + } + + prev.t = ntSet + prev.set = prevCharClass + } else if at.t == ntNothing { + j-- + } else { + wasLastSet = false + lastNodeCannotMerge = false + } + break + } + } + + if j < i { + n.removeChildren(j, i) + } + + return n.stripEnation(ntNothing) +} + +// Basic optimization. Adjacent strings can be concatenated. +// +// (?:abc)(?:def) -> abcdef +func (n *regexNode) reduceConcatenation() *regexNode { + // Eliminate empties and concat adjacent strings/chars + + var optionsLast RegexOptions + var optionsAt RegexOptions + var i, j int + + if len(n.children) == 0 { + return newRegexNode(ntEmpty, n.options) + } + + wasLastString := false + + for i, j = 0, 0; i < len(n.children); i, j = i+1, j+1 { + var at, prev *regexNode + + at = n.children[i] + + if j < i { + n.children[j] = at + } + + if at.t == ntConcatenate && + ((at.options & RightToLeft) == (n.options & RightToLeft)) { + for k := 0; k < len(at.children); k++ { + at.children[k].next = n + } + + //insert at.children at i+1 index in n.children + n.insertChildren(i+1, at.children) + + j-- + } else if at.t == ntMulti || at.t == ntOne { + // Cannot merge strings if L or I options differ + optionsAt = at.options & (RightToLeft | IgnoreCase) + + if !wasLastString || optionsLast != optionsAt { + wasLastString = true + optionsLast = optionsAt + continue + } + + j-- + prev = n.children[j] + + if prev.t == ntOne { + prev.t = ntMulti + prev.str = []rune{prev.ch} + } + + if (optionsAt & RightToLeft) == 0 { + if at.t == ntOne { + prev.str = append(prev.str, at.ch) + } else { + prev.str = append(prev.str, at.str...) + } + } else { + if at.t == ntOne { + // insert at the front by expanding our slice, copying the data over, and then setting the value + prev.str = append(prev.str, 0) + copy(prev.str[1:], prev.str) + prev.str[0] = at.ch + } else { + //insert at the front...this one we'll make a new slice and copy both into it + merge := make([]rune, len(prev.str)+len(at.str)) + copy(merge, at.str) + copy(merge[len(at.str):], prev.str) + prev.str = merge + } + } + } else if at.t == ntEmpty { + j-- + } else { + wasLastString = false + } + } + + if j < i { + // remove indices j through i from the children + n.removeChildren(j, i) + } + + return n.stripEnation(ntEmpty) +} + +// Nested repeaters just get multiplied with each other if they're not +// too lumpy +func (n *regexNode) reduceRep() *regexNode { + + u := n + t := n.t + min := n.m + max := n.n + + for { + if len(u.children) == 0 { + break + } + + child := u.children[0] + + // multiply reps of the same type only + if child.t != t { + childType := child.t + + if !(childType >= ntOneloop && childType <= ntSetloop && t == ntLoop || + childType >= ntOnelazy && childType <= ntSetlazy && t == ntLazyloop) { + break + } + } + + // child can be too lumpy to blur, e.g., (a {100,105}) {3} or (a {2,})? + // [but things like (a {2,})+ are not too lumpy...] + if u.m == 0 && child.m > 1 || child.n < child.m*2 { + break + } + + u = child + if u.m > 0 { + if (math.MaxInt32-1)/u.m < min { + u.m = math.MaxInt32 + } else { + u.m = u.m * min + } + } + if u.n > 0 { + if (math.MaxInt32-1)/u.n < max { + u.n = math.MaxInt32 + } else { + u.n = u.n * max + } + } + } + + if math.MaxInt32 == min { + return newRegexNode(ntNothing, n.options) + } + return u + +} + +// Simple optimization. If a concatenation or alternation has only +// one child strip out the intermediate node. If it has zero children, +// turn it into an empty. +func (n *regexNode) stripEnation(emptyType nodeType) *regexNode { + switch len(n.children) { + case 0: + return newRegexNode(emptyType, n.options) + case 1: + return n.children[0] + default: + return n + } +} + +func (n *regexNode) reduceGroup() *regexNode { + u := n + + for u.t == ntGroup { + u = u.children[0] + } + + return u +} + +// Simple optimization. If a set is a singleton, an inverse singleton, +// or empty, it's transformed accordingly. +func (n *regexNode) reduceSet() *regexNode { + // Extract empty-set, one and not-one case as special + + if n.set == nil { + n.t = ntNothing + } else if n.set.IsSingleton() { + n.ch = n.set.SingletonChar() + n.set = nil + n.t += (ntOne - ntSet) + } else if n.set.IsSingletonInverse() { + n.ch = n.set.SingletonChar() + n.set = nil + n.t += (ntNotone - ntSet) + } + + return n +} + +func (n *regexNode) reverseLeft() *regexNode { + if n.options&RightToLeft != 0 && n.t == ntConcatenate && len(n.children) > 0 { + //reverse children order + for left, right := 0, len(n.children)-1; left < right; left, right = left+1, right-1 { + n.children[left], n.children[right] = n.children[right], n.children[left] + } + } + + return n +} + +func (n *regexNode) makeQuantifier(lazy bool, min, max int) *regexNode { + if min == 0 && max == 0 { + return newRegexNode(ntEmpty, n.options) + } + + if min == 1 && max == 1 { + return n + } + + switch n.t { + case ntOne, ntNotone, ntSet: + if lazy { + n.makeRep(Onelazy, min, max) + } else { + n.makeRep(Oneloop, min, max) + } + return n + + default: + var t nodeType + if lazy { + t = ntLazyloop + } else { + t = ntLoop + } + result := newRegexNodeMN(t, n.options, min, max) + result.addChild(n) + return result + } +} + +// debug functions + +var typeStr = []string{ + "Onerep", "Notonerep", "Setrep", + "Oneloop", "Notoneloop", "Setloop", + "Onelazy", "Notonelazy", "Setlazy", + "One", "Notone", "Set", + "Multi", "Ref", + "Bol", "Eol", "Boundary", "Nonboundary", + "Beginning", "Start", "EndZ", "End", + "Nothing", "Empty", + "Alternate", "Concatenate", + "Loop", "Lazyloop", + "Capture", "Group", "Require", "Prevent", "Greedy", + "Testref", "Testgroup", + "Unknown", "Unknown", "Unknown", + "Unknown", "Unknown", "Unknown", + "ECMABoundary", "NonECMABoundary", +} + +func (n *regexNode) description() string { + buf := &bytes.Buffer{} + + buf.WriteString(typeStr[n.t]) + + if (n.options & ExplicitCapture) != 0 { + buf.WriteString("-C") + } + if (n.options & IgnoreCase) != 0 { + buf.WriteString("-I") + } + if (n.options & RightToLeft) != 0 { + buf.WriteString("-L") + } + if (n.options & Multiline) != 0 { + buf.WriteString("-M") + } + if (n.options & Singleline) != 0 { + buf.WriteString("-S") + } + if (n.options & IgnorePatternWhitespace) != 0 { + buf.WriteString("-X") + } + if (n.options & ECMAScript) != 0 { + buf.WriteString("-E") + } + + switch n.t { + case ntOneloop, ntNotoneloop, ntOnelazy, ntNotonelazy, ntOne, ntNotone: + buf.WriteString("(Ch = " + CharDescription(n.ch) + ")") + break + case ntCapture: + buf.WriteString("(index = " + strconv.Itoa(n.m) + ", unindex = " + strconv.Itoa(n.n) + ")") + break + case ntRef, ntTestref: + buf.WriteString("(index = " + strconv.Itoa(n.m) + ")") + break + case ntMulti: + fmt.Fprintf(buf, "(String = %s)", string(n.str)) + break + case ntSet, ntSetloop, ntSetlazy: + buf.WriteString("(Set = " + n.set.String() + ")") + break + } + + switch n.t { + case ntOneloop, ntNotoneloop, ntOnelazy, ntNotonelazy, ntSetloop, ntSetlazy, ntLoop, ntLazyloop: + buf.WriteString("(Min = ") + buf.WriteString(strconv.Itoa(n.m)) + buf.WriteString(", Max = ") + if n.n == math.MaxInt32 { + buf.WriteString("inf") + } else { + buf.WriteString(strconv.Itoa(n.n)) + } + buf.WriteString(")") + + break + } + + return buf.String() +} + +var padSpace = []byte(" ") + +func (t *RegexTree) Dump() string { + return t.root.dump() +} + +func (n *regexNode) dump() string { + var stack []int + CurNode := n + CurChild := 0 + + buf := bytes.NewBufferString(CurNode.description()) + buf.WriteRune('\n') + + for { + if CurNode.children != nil && CurChild < len(CurNode.children) { + stack = append(stack, CurChild+1) + CurNode = CurNode.children[CurChild] + CurChild = 0 + + Depth := len(stack) + if Depth > 32 { + Depth = 32 + } + buf.Write(padSpace[:Depth]) + buf.WriteString(CurNode.description()) + buf.WriteRune('\n') + } else { + if len(stack) == 0 { + break + } + + CurChild = stack[len(stack)-1] + stack = stack[:len(stack)-1] + CurNode = CurNode.next + } + } + return buf.String() +} diff --git a/vendor/github.com/dlclark/regexp2/syntax/writer.go b/vendor/github.com/dlclark/regexp2/syntax/writer.go new file mode 100644 index 000000000..a5aa11ca0 --- /dev/null +++ b/vendor/github.com/dlclark/regexp2/syntax/writer.go @@ -0,0 +1,500 @@ +package syntax + +import ( + "bytes" + "fmt" + "math" + "os" +) + +func Write(tree *RegexTree) (*Code, error) { + w := writer{ + intStack: make([]int, 0, 32), + emitted: make([]int, 2), + stringhash: make(map[string]int), + sethash: make(map[string]int), + } + + code, err := w.codeFromTree(tree) + + if tree.options&Debug > 0 && code != nil { + os.Stdout.WriteString(code.Dump()) + os.Stdout.WriteString("\n") + } + + return code, err +} + +type writer struct { + emitted []int + + intStack []int + curpos int + stringhash map[string]int + stringtable [][]rune + sethash map[string]int + settable []*CharSet + counting bool + count int + trackcount int + caps map[int]int +} + +const ( + beforeChild nodeType = 64 + afterChild = 128 + //MaxPrefixSize is the largest number of runes we'll use for a BoyerMoyer prefix + MaxPrefixSize = 50 +) + +// The top level RegexCode generator. It does a depth-first walk +// through the tree and calls EmitFragment to emits code before +// and after each child of an interior node, and at each leaf. +// +// It runs two passes, first to count the size of the generated +// code, and second to generate the code. +// +// We should time it against the alternative, which is +// to just generate the code and grow the array as we go. +func (w *writer) codeFromTree(tree *RegexTree) (*Code, error) { + var ( + curNode *regexNode + curChild int + capsize int + ) + // construct sparse capnum mapping if some numbers are unused + + if tree.capnumlist == nil || tree.captop == len(tree.capnumlist) { + capsize = tree.captop + w.caps = nil + } else { + capsize = len(tree.capnumlist) + w.caps = tree.caps + for i := 0; i < len(tree.capnumlist); i++ { + w.caps[tree.capnumlist[i]] = i + } + } + + w.counting = true + + for { + if !w.counting { + w.emitted = make([]int, w.count) + } + + curNode = tree.root + curChild = 0 + + w.emit1(Lazybranch, 0) + + for { + if len(curNode.children) == 0 { + w.emitFragment(curNode.t, curNode, 0) + } else if curChild < len(curNode.children) { + w.emitFragment(curNode.t|beforeChild, curNode, curChild) + + curNode = curNode.children[curChild] + + w.pushInt(curChild) + curChild = 0 + continue + } + + if w.emptyStack() { + break + } + + curChild = w.popInt() + curNode = curNode.next + + w.emitFragment(curNode.t|afterChild, curNode, curChild) + curChild++ + } + + w.patchJump(0, w.curPos()) + w.emit(Stop) + + if !w.counting { + break + } + + w.counting = false + } + + fcPrefix := getFirstCharsPrefix(tree) + prefix := getPrefix(tree) + rtl := (tree.options & RightToLeft) != 0 + + var bmPrefix *BmPrefix + //TODO: benchmark string prefixes + if prefix != nil && len(prefix.PrefixStr) > 0 && MaxPrefixSize > 0 { + if len(prefix.PrefixStr) > MaxPrefixSize { + // limit prefix changes to 10k + prefix.PrefixStr = prefix.PrefixStr[:MaxPrefixSize] + } + bmPrefix = newBmPrefix(prefix.PrefixStr, prefix.CaseInsensitive, rtl) + } else { + bmPrefix = nil + } + + return &Code{ + Codes: w.emitted, + Strings: w.stringtable, + Sets: w.settable, + TrackCount: w.trackcount, + Caps: w.caps, + Capsize: capsize, + FcPrefix: fcPrefix, + BmPrefix: bmPrefix, + Anchors: getAnchors(tree), + RightToLeft: rtl, + }, nil +} + +// The main RegexCode generator. It does a depth-first walk +// through the tree and calls EmitFragment to emits code before +// and after each child of an interior node, and at each leaf. +func (w *writer) emitFragment(nodetype nodeType, node *regexNode, curIndex int) error { + bits := InstOp(0) + + if nodetype <= ntRef { + if (node.options & RightToLeft) != 0 { + bits |= Rtl + } + if (node.options & IgnoreCase) != 0 { + bits |= Ci + } + } + ntBits := nodeType(bits) + + switch nodetype { + case ntConcatenate | beforeChild, ntConcatenate | afterChild, ntEmpty: + break + + case ntAlternate | beforeChild: + if curIndex < len(node.children)-1 { + w.pushInt(w.curPos()) + w.emit1(Lazybranch, 0) + } + + case ntAlternate | afterChild: + if curIndex < len(node.children)-1 { + lbPos := w.popInt() + w.pushInt(w.curPos()) + w.emit1(Goto, 0) + w.patchJump(lbPos, w.curPos()) + } else { + for i := 0; i < curIndex; i++ { + w.patchJump(w.popInt(), w.curPos()) + } + } + break + + case ntTestref | beforeChild: + if curIndex == 0 { + w.emit(Setjump) + w.pushInt(w.curPos()) + w.emit1(Lazybranch, 0) + w.emit1(Testref, w.mapCapnum(node.m)) + w.emit(Forejump) + } + + case ntTestref | afterChild: + if curIndex == 0 { + branchpos := w.popInt() + w.pushInt(w.curPos()) + w.emit1(Goto, 0) + w.patchJump(branchpos, w.curPos()) + w.emit(Forejump) + if len(node.children) <= 1 { + w.patchJump(w.popInt(), w.curPos()) + } + } else if curIndex == 1 { + w.patchJump(w.popInt(), w.curPos()) + } + + case ntTestgroup | beforeChild: + if curIndex == 0 { + w.emit(Setjump) + w.emit(Setmark) + w.pushInt(w.curPos()) + w.emit1(Lazybranch, 0) + } + + case ntTestgroup | afterChild: + if curIndex == 0 { + w.emit(Getmark) + w.emit(Forejump) + } else if curIndex == 1 { + Branchpos := w.popInt() + w.pushInt(w.curPos()) + w.emit1(Goto, 0) + w.patchJump(Branchpos, w.curPos()) + w.emit(Getmark) + w.emit(Forejump) + if len(node.children) <= 2 { + w.patchJump(w.popInt(), w.curPos()) + } + } else if curIndex == 2 { + w.patchJump(w.popInt(), w.curPos()) + } + + case ntLoop | beforeChild, ntLazyloop | beforeChild: + + if node.n < math.MaxInt32 || node.m > 1 { + if node.m == 0 { + w.emit1(Nullcount, 0) + } else { + w.emit1(Setcount, 1-node.m) + } + } else if node.m == 0 { + w.emit(Nullmark) + } else { + w.emit(Setmark) + } + + if node.m == 0 { + w.pushInt(w.curPos()) + w.emit1(Goto, 0) + } + w.pushInt(w.curPos()) + + case ntLoop | afterChild, ntLazyloop | afterChild: + + startJumpPos := w.curPos() + lazy := (nodetype - (ntLoop | afterChild)) + + if node.n < math.MaxInt32 || node.m > 1 { + if node.n == math.MaxInt32 { + w.emit2(InstOp(Branchcount+lazy), w.popInt(), math.MaxInt32) + } else { + w.emit2(InstOp(Branchcount+lazy), w.popInt(), node.n-node.m) + } + } else { + w.emit1(InstOp(Branchmark+lazy), w.popInt()) + } + + if node.m == 0 { + w.patchJump(w.popInt(), startJumpPos) + } + + case ntGroup | beforeChild, ntGroup | afterChild: + + case ntCapture | beforeChild: + w.emit(Setmark) + + case ntCapture | afterChild: + w.emit2(Capturemark, w.mapCapnum(node.m), w.mapCapnum(node.n)) + + case ntRequire | beforeChild: + // NOTE: the following line causes lookahead/lookbehind to be + // NON-BACKTRACKING. It can be commented out with (*) + w.emit(Setjump) + + w.emit(Setmark) + + case ntRequire | afterChild: + w.emit(Getmark) + + // NOTE: the following line causes lookahead/lookbehind to be + // NON-BACKTRACKING. It can be commented out with (*) + w.emit(Forejump) + + case ntPrevent | beforeChild: + w.emit(Setjump) + w.pushInt(w.curPos()) + w.emit1(Lazybranch, 0) + + case ntPrevent | afterChild: + w.emit(Backjump) + w.patchJump(w.popInt(), w.curPos()) + w.emit(Forejump) + + case ntGreedy | beforeChild: + w.emit(Setjump) + + case ntGreedy | afterChild: + w.emit(Forejump) + + case ntOne, ntNotone: + w.emit1(InstOp(node.t|ntBits), int(node.ch)) + + case ntNotoneloop, ntNotonelazy, ntOneloop, ntOnelazy: + if node.m > 0 { + if node.t == ntOneloop || node.t == ntOnelazy { + w.emit2(Onerep|bits, int(node.ch), node.m) + } else { + w.emit2(Notonerep|bits, int(node.ch), node.m) + } + } + if node.n > node.m { + if node.n == math.MaxInt32 { + w.emit2(InstOp(node.t|ntBits), int(node.ch), math.MaxInt32) + } else { + w.emit2(InstOp(node.t|ntBits), int(node.ch), node.n-node.m) + } + } + + case ntSetloop, ntSetlazy: + if node.m > 0 { + w.emit2(Setrep|bits, w.setCode(node.set), node.m) + } + if node.n > node.m { + if node.n == math.MaxInt32 { + w.emit2(InstOp(node.t|ntBits), w.setCode(node.set), math.MaxInt32) + } else { + w.emit2(InstOp(node.t|ntBits), w.setCode(node.set), node.n-node.m) + } + } + + case ntMulti: + w.emit1(InstOp(node.t|ntBits), w.stringCode(node.str)) + + case ntSet: + w.emit1(InstOp(node.t|ntBits), w.setCode(node.set)) + + case ntRef: + w.emit1(InstOp(node.t|ntBits), w.mapCapnum(node.m)) + + case ntNothing, ntBol, ntEol, ntBoundary, ntNonboundary, ntECMABoundary, ntNonECMABoundary, ntBeginning, ntStart, ntEndZ, ntEnd: + w.emit(InstOp(node.t)) + + default: + return fmt.Errorf("unexpected opcode in regular expression generation: %v", nodetype) + } + + return nil +} + +// To avoid recursion, we use a simple integer stack. +// This is the push. +func (w *writer) pushInt(i int) { + w.intStack = append(w.intStack, i) +} + +// Returns true if the stack is empty. +func (w *writer) emptyStack() bool { + return len(w.intStack) == 0 +} + +// This is the pop. +func (w *writer) popInt() int { + //get our item + idx := len(w.intStack) - 1 + i := w.intStack[idx] + //trim our slice + w.intStack = w.intStack[:idx] + return i +} + +// Returns the current position in the emitted code. +func (w *writer) curPos() int { + return w.curpos +} + +// Fixes up a jump instruction at the specified offset +// so that it jumps to the specified jumpDest. +func (w *writer) patchJump(offset, jumpDest int) { + w.emitted[offset+1] = jumpDest +} + +// Returns an index in the set table for a charset +// uses a map to eliminate duplicates. +func (w *writer) setCode(set *CharSet) int { + if w.counting { + return 0 + } + + buf := &bytes.Buffer{} + + set.mapHashFill(buf) + hash := buf.String() + i, ok := w.sethash[hash] + if !ok { + i = len(w.sethash) + w.sethash[hash] = i + w.settable = append(w.settable, set) + } + return i +} + +// Returns an index in the string table for a string. +// uses a map to eliminate duplicates. +func (w *writer) stringCode(str []rune) int { + if w.counting { + return 0 + } + + hash := string(str) + i, ok := w.stringhash[hash] + if !ok { + i = len(w.stringhash) + w.stringhash[hash] = i + w.stringtable = append(w.stringtable, str) + } + + return i +} + +// When generating code on a regex that uses a sparse set +// of capture slots, we hash them to a dense set of indices +// for an array of capture slots. Instead of doing the hash +// at match time, it's done at compile time, here. +func (w *writer) mapCapnum(capnum int) int { + if capnum == -1 { + return -1 + } + + if w.caps != nil { + return w.caps[capnum] + } + + return capnum +} + +// Emits a zero-argument operation. Note that the emit +// functions all run in two modes: they can emit code, or +// they can just count the size of the code. +func (w *writer) emit(op InstOp) { + if w.counting { + w.count++ + if opcodeBacktracks(op) { + w.trackcount++ + } + return + } + w.emitted[w.curpos] = int(op) + w.curpos++ +} + +// Emits a one-argument operation. +func (w *writer) emit1(op InstOp, opd1 int) { + if w.counting { + w.count += 2 + if opcodeBacktracks(op) { + w.trackcount++ + } + return + } + w.emitted[w.curpos] = int(op) + w.curpos++ + w.emitted[w.curpos] = opd1 + w.curpos++ +} + +// Emits a two-argument operation. +func (w *writer) emit2(op InstOp, opd1, opd2 int) { + if w.counting { + w.count += 3 + if opcodeBacktracks(op) { + w.trackcount++ + } + return + } + w.emitted[w.curpos] = int(op) + w.curpos++ + w.emitted[w.curpos] = opd1 + w.curpos++ + w.emitted[w.curpos] = opd2 + w.curpos++ +} diff --git a/vendor/github.com/dlclark/regexp2/testoutput1 b/vendor/github.com/dlclark/regexp2/testoutput1 new file mode 100644 index 000000000..fbf63fdf2 --- /dev/null +++ b/vendor/github.com/dlclark/regexp2/testoutput1 @@ -0,0 +1,7061 @@ +# This set of tests is for features that are compatible with all versions of +# Perl >= 5.10, in non-UTF mode. It should run clean for the 8-bit, 16-bit, and +# 32-bit PCRE libraries, and also using the perltest.pl script. + +#forbid_utf +#newline_default lf any anycrlf +#perltest + +/the quick brown fox/ + the quick brown fox + 0: the quick brown fox + What do you know about the quick brown fox? + 0: the quick brown fox +\= Expect no match + The quick brown FOX +No match + What do you know about THE QUICK BROWN FOX? +No match + +/The quick brown fox/i + the quick brown fox + 0: the quick brown fox + The quick brown FOX + 0: The quick brown FOX + What do you know about the quick brown fox? + 0: the quick brown fox + What do you know about THE QUICK BROWN FOX? + 0: THE QUICK BROWN FOX + +/abcd\t\n\r\f\a\e\071\x3b\$\\\?caxyz/ + abcd\t\n\r\f\a\e9;\$\\?caxyz + 0: abcd\x09\x0a\x0d\x0c\x07\x1b9;$\?caxyz + +/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/ + abxyzpqrrrabbxyyyypqAzz + 0: abxyzpqrrrabbxyyyypqAzz + abxyzpqrrrabbxyyyypqAzz + 0: abxyzpqrrrabbxyyyypqAzz + aabxyzpqrrrabbxyyyypqAzz + 0: aabxyzpqrrrabbxyyyypqAzz + aaabxyzpqrrrabbxyyyypqAzz + 0: aaabxyzpqrrrabbxyyyypqAzz + aaaabxyzpqrrrabbxyyyypqAzz + 0: aaaabxyzpqrrrabbxyyyypqAzz + abcxyzpqrrrabbxyyyypqAzz + 0: abcxyzpqrrrabbxyyyypqAzz + aabcxyzpqrrrabbxyyyypqAzz + 0: aabcxyzpqrrrabbxyyyypqAzz + aaabcxyzpqrrrabbxyyyypAzz + 0: aaabcxyzpqrrrabbxyyyypAzz + aaabcxyzpqrrrabbxyyyypqAzz + 0: aaabcxyzpqrrrabbxyyyypqAzz + aaabcxyzpqrrrabbxyyyypqqAzz + 0: aaabcxyzpqrrrabbxyyyypqqAzz + aaabcxyzpqrrrabbxyyyypqqqAzz + 0: aaabcxyzpqrrrabbxyyyypqqqAzz + aaabcxyzpqrrrabbxyyyypqqqqAzz + 0: aaabcxyzpqrrrabbxyyyypqqqqAzz + aaabcxyzpqrrrabbxyyyypqqqqqAzz + 0: aaabcxyzpqrrrabbxyyyypqqqqqAzz + aaabcxyzpqrrrabbxyyyypqqqqqqAzz + 0: aaabcxyzpqrrrabbxyyyypqqqqqqAzz + aaaabcxyzpqrrrabbxyyyypqAzz + 0: aaaabcxyzpqrrrabbxyyyypqAzz + abxyzzpqrrrabbxyyyypqAzz + 0: abxyzzpqrrrabbxyyyypqAzz + aabxyzzzpqrrrabbxyyyypqAzz + 0: aabxyzzzpqrrrabbxyyyypqAzz + aaabxyzzzzpqrrrabbxyyyypqAzz + 0: aaabxyzzzzpqrrrabbxyyyypqAzz + aaaabxyzzzzpqrrrabbxyyyypqAzz + 0: aaaabxyzzzzpqrrrabbxyyyypqAzz + abcxyzzpqrrrabbxyyyypqAzz + 0: abcxyzzpqrrrabbxyyyypqAzz + aabcxyzzzpqrrrabbxyyyypqAzz + 0: aabcxyzzzpqrrrabbxyyyypqAzz + aaabcxyzzzzpqrrrabbxyyyypqAzz + 0: aaabcxyzzzzpqrrrabbxyyyypqAzz + aaaabcxyzzzzpqrrrabbxyyyypqAzz + 0: aaaabcxyzzzzpqrrrabbxyyyypqAzz + aaaabcxyzzzzpqrrrabbbxyyyypqAzz + 0: aaaabcxyzzzzpqrrrabbbxyyyypqAzz + aaaabcxyzzzzpqrrrabbbxyyyyypqAzz + 0: aaaabcxyzzzzpqrrrabbbxyyyyypqAzz + aaabcxyzpqrrrabbxyyyypABzz + 0: aaabcxyzpqrrrabbxyyyypABzz + aaabcxyzpqrrrabbxyyyypABBzz + 0: aaabcxyzpqrrrabbxyyyypABBzz + >>>aaabxyzpqrrrabbxyyyypqAzz + 0: aaabxyzpqrrrabbxyyyypqAzz + >aaaabxyzpqrrrabbxyyyypqAzz + 0: aaaabxyzpqrrrabbxyyyypqAzz + >>>>abcxyzpqrrrabbxyyyypqAzz + 0: abcxyzpqrrrabbxyyyypqAzz +\= Expect no match + abxyzpqrrabbxyyyypqAzz +No match + abxyzpqrrrrabbxyyyypqAzz +No match + abxyzpqrrrabxyyyypqAzz +No match + aaaabcxyzzzzpqrrrabbbxyyyyyypqAzz +No match + aaaabcxyzzzzpqrrrabbbxyyypqAzz +No match + aaabcxyzpqrrrabbxyyyypqqqqqqqAzz +No match + +/^(abc){1,2}zz/ + abczz + 0: abczz + 1: abc + abcabczz + 0: abcabczz + 1: abc +\= Expect no match + zz +No match + abcabcabczz +No match + >>abczz +No match + +/^(b+?|a){1,2}?c/ + bc + 0: bc + 1: b + bbc + 0: bbc + 1: b + bbbc + 0: bbbc + 1: bb + bac + 0: bac + 1: a + bbac + 0: bbac + 1: a + aac + 0: aac + 1: a + abbbbbbbbbbbc + 0: abbbbbbbbbbbc + 1: bbbbbbbbbbb + bbbbbbbbbbbac + 0: bbbbbbbbbbbac + 1: a +\= Expect no match + aaac +No match + abbbbbbbbbbbac +No match + +/^(b+|a){1,2}c/ + bc + 0: bc + 1: b + bbc + 0: bbc + 1: bb + bbbc + 0: bbbc + 1: bbb + bac + 0: bac + 1: a + bbac + 0: bbac + 1: a + aac + 0: aac + 1: a + abbbbbbbbbbbc + 0: abbbbbbbbbbbc + 1: bbbbbbbbbbb + bbbbbbbbbbbac + 0: bbbbbbbbbbbac + 1: a +\= Expect no match + aaac +No match + abbbbbbbbbbbac +No match + +/^(b+|a){1,2}?bc/ + bbc + 0: bbc + 1: b + +/^(b*|ba){1,2}?bc/ + babc + 0: babc + 1: ba + bbabc + 0: bbabc + 1: ba + bababc + 0: bababc + 1: ba +\= Expect no match + bababbc +No match + babababc +No match + +/^(ba|b*){1,2}?bc/ + babc + 0: babc + 1: ba + bbabc + 0: bbabc + 1: ba + bababc + 0: bababc + 1: ba +\= Expect no match + bababbc +No match + babababc +No match + +#/^\ca\cA\c[;\c:/ +# \x01\x01\e;z +# 0: \x01\x01\x1b;z + +/^[ab\]cde]/ + athing + 0: a + bthing + 0: b + ]thing + 0: ] + cthing + 0: c + dthing + 0: d + ething + 0: e +\= Expect no match + fthing +No match + [thing +No match + \\thing +No match + +/^[]cde]/ + ]thing + 0: ] + cthing + 0: c + dthing + 0: d + ething + 0: e +\= Expect no match + athing +No match + fthing +No match + +/^[^ab\]cde]/ + fthing + 0: f + [thing + 0: [ + \\thing + 0: \ +\= Expect no match + athing +No match + bthing +No match + ]thing +No match + cthing +No match + dthing +No match + ething +No match + +/^[^]cde]/ + athing + 0: a + fthing + 0: f +\= Expect no match + ]thing +No match + cthing +No match + dthing +No match + ething +No match + +# DLC - I don't get this one +#/^\/ +#  +# 0: \x81 + +#updated to handle 16-bits utf8 +/^ÿ/ + ÿ + 0: \xc3\xbf + +/^[0-9]+$/ + 0 + 0: 0 + 1 + 0: 1 + 2 + 0: 2 + 3 + 0: 3 + 4 + 0: 4 + 5 + 0: 5 + 6 + 0: 6 + 7 + 0: 7 + 8 + 0: 8 + 9 + 0: 9 + 10 + 0: 10 + 100 + 0: 100 +\= Expect no match + abc +No match + +/^.*nter/ + enter + 0: enter + inter + 0: inter + uponter + 0: uponter + +/^xxx[0-9]+$/ + xxx0 + 0: xxx0 + xxx1234 + 0: xxx1234 +\= Expect no match + xxx +No match + +/^.+[0-9][0-9][0-9]$/ + x123 + 0: x123 + x1234 + 0: x1234 + xx123 + 0: xx123 + 123456 + 0: 123456 +\= Expect no match + 123 +No match + +/^.+?[0-9][0-9][0-9]$/ + x123 + 0: x123 + x1234 + 0: x1234 + xx123 + 0: xx123 + 123456 + 0: 123456 +\= Expect no match + 123 +No match + +/^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$/ + abc!pqr=apquxz.ixr.zzz.ac.uk + 0: abc!pqr=apquxz.ixr.zzz.ac.uk + 1: abc + 2: pqr +\= Expect no match + !pqr=apquxz.ixr.zzz.ac.uk +No match + abc!=apquxz.ixr.zzz.ac.uk +No match + abc!pqr=apquxz:ixr.zzz.ac.uk +No match + abc!pqr=apquxz.ixr.zzz.ac.ukk +No match + +/:/ + Well, we need a colon: somewhere + 0: : +\= Expect no match + Fail without a colon +No match + +/([\da-f:]+)$/i + 0abc + 0: 0abc + 1: 0abc + abc + 0: abc + 1: abc + fed + 0: fed + 1: fed + E + 0: E + 1: E + :: + 0: :: + 1: :: + 5f03:12C0::932e + 0: 5f03:12C0::932e + 1: 5f03:12C0::932e + fed def + 0: def + 1: def + Any old stuff + 0: ff + 1: ff +\= Expect no match + 0zzz +No match + gzzz +No match + fed\x20 +No match + Any old rubbish +No match + +/^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/ + .1.2.3 + 0: .1.2.3 + 1: 1 + 2: 2 + 3: 3 + A.12.123.0 + 0: A.12.123.0 + 1: 12 + 2: 123 + 3: 0 +\= Expect no match + .1.2.3333 +No match + 1.2.3 +No match + 1234.2.3 +No match + +/^(\d+)\s+IN\s+SOA\s+(\S+)\s+(\S+)\s*\(\s*$/ + 1 IN SOA non-sp1 non-sp2( + 0: 1 IN SOA non-sp1 non-sp2( + 1: 1 + 2: non-sp1 + 3: non-sp2 + 1 IN SOA non-sp1 non-sp2 ( + 0: 1 IN SOA non-sp1 non-sp2 ( + 1: 1 + 2: non-sp1 + 3: non-sp2 +\= Expect no match + 1IN SOA non-sp1 non-sp2( +No match + +/^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$/ + a. + 0: a. + Z. + 0: Z. + 2. + 0: 2. + ab-c.pq-r. + 0: ab-c.pq-r. + 1: .pq-r + sxk.zzz.ac.uk. + 0: sxk.zzz.ac.uk. + 1: .uk + x-.y-. + 0: x-.y-. + 1: .y- +\= Expect no match + -abc.peq. +No match + +/^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$/ + *.a + 0: *.a + *.b0-a + 0: *.b0-a + 1: 0-a + *.c3-b.c + 0: *.c3-b.c + 1: 3-b + 2: .c + *.c-a.b-c + 0: *.c-a.b-c + 1: -a + 2: .b-c + 3: -c +\= Expect no match + *.0 +No match + *.a- +No match + *.a-b.c- +No match + *.c-a.0-c +No match + +/^(?=ab(de))(abd)(e)/ + abde + 0: abde + 1: de + 2: abd + 3: e + +/^(?!(ab)de|x)(abd)(f)/ + abdf + 0: abdf + 1: + 2: abd + 3: f + +/^(?=(ab(cd)))(ab)/ + abcd + 0: ab + 1: abcd + 2: cd + 3: ab + +/^[\da-f](\.[\da-f])*$/i + a.b.c.d + 0: a.b.c.d + 1: .d + A.B.C.D + 0: A.B.C.D + 1: .D + a.b.c.1.2.3.C + 0: a.b.c.1.2.3.C + 1: .C + +/^\".*\"\s*(;.*)?$/ + \"1234\" + 0: "1234" + \"abcd\" ; + 0: "abcd" ; + 1: ; + \"\" ; rhubarb + 0: "" ; rhubarb + 1: ; rhubarb +\= Expect no match + \"1234\" : things +No match + +/^$/ + \ + 0: +\= Expect no match + A non-empty line +No match + +/ ^ a (?# begins with a) b\sc (?# then b c) $ (?# then end)/x + ab c + 0: ab c +\= Expect no match + abc +No match + ab cde +No match + +/(?x) ^ a (?# begins with a) b\sc (?# then b c) $ (?# then end)/ + ab c + 0: ab c +\= Expect no match + abc +No match + ab cde +No match + +/^ a\ b[c ]d $/x + a bcd + 0: a bcd + a b d + 0: a b d +\= Expect no match + abcd +No match + ab d +No match + +/^(a(b(c)))(d(e(f)))(h(i(j)))(k(l(m)))$/ + abcdefhijklm + 0: abcdefhijklm + 1: abc + 2: bc + 3: c + 4: def + 5: ef + 6: f + 7: hij + 8: ij + 9: j +10: klm +11: lm +12: m + +/^(?:a(b(c)))(?:d(e(f)))(?:h(i(j)))(?:k(l(m)))$/ + abcdefhijklm + 0: abcdefhijklm + 1: bc + 2: c + 3: ef + 4: f + 5: ij + 6: j + 7: lm + 8: m + +#/^[\w][\W][\s][\S][\d][\D][\b][\n][\c]][\022]/ +# a+ Z0+\x08\n\x1d\x12 +# 0: a+ Z0+\x08\x0a\x1d\x12 + +/^[.^$|()*+?{,}]+/ + .^\$(*+)|{?,?} + 0: .^$(*+)|{?,?} + +/^a*\w/ + z + 0: z + az + 0: az + aaaz + 0: aaaz + a + 0: a + aa + 0: aa + aaaa + 0: aaaa + a+ + 0: a + aa+ + 0: aa + +/^a*?\w/ + z + 0: z + az + 0: a + aaaz + 0: a + a + 0: a + aa + 0: a + aaaa + 0: a + a+ + 0: a + aa+ + 0: a + +/^a+\w/ + az + 0: az + aaaz + 0: aaaz + aa + 0: aa + aaaa + 0: aaaa + aa+ + 0: aa + +/^a+?\w/ + az + 0: az + aaaz + 0: aa + aa + 0: aa + aaaa + 0: aa + aa+ + 0: aa + +/^\d{8}\w{2,}/ + 1234567890 + 0: 1234567890 + 12345678ab + 0: 12345678ab + 12345678__ + 0: 12345678__ +\= Expect no match + 1234567 +No match + +/^[aeiou\d]{4,5}$/ + uoie + 0: uoie + 1234 + 0: 1234 + 12345 + 0: 12345 + aaaaa + 0: aaaaa +\= Expect no match + 123456 +No match + +/^[aeiou\d]{4,5}?/ + uoie + 0: uoie + 1234 + 0: 1234 + 12345 + 0: 1234 + aaaaa + 0: aaaa + 123456 + 0: 1234 + +/\A(abc|def)=(\1){2,3}\Z/ + abc=abcabc + 0: abc=abcabc + 1: abc + 2: abc + def=defdefdef + 0: def=defdefdef + 1: def + 2: def +\= Expect no match + abc=defdef +No match + +/^(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\11*(\3\4)\1(?#)2$/ + abcdefghijkcda2 + 0: abcdefghijkcda2 + 1: a + 2: b + 3: c + 4: d + 5: e + 6: f + 7: g + 8: h + 9: i +10: j +11: k +12: cd + abcdefghijkkkkcda2 + 0: abcdefghijkkkkcda2 + 1: a + 2: b + 3: c + 4: d + 5: e + 6: f + 7: g + 8: h + 9: i +10: j +11: k +12: cd + +/(cat(a(ract|tonic)|erpillar)) \1()2(3)/ + cataract cataract23 + 0: cataract cataract23 + 1: cataract + 2: aract + 3: ract + 4: + 5: 3 + catatonic catatonic23 + 0: catatonic catatonic23 + 1: catatonic + 2: atonic + 3: tonic + 4: + 5: 3 + caterpillar caterpillar23 + 0: caterpillar caterpillar23 + 1: caterpillar + 2: erpillar + 3: + 4: + 5: 3 + + +/^From +([^ ]+) +[a-zA-Z][a-zA-Z][a-zA-Z] +[a-zA-Z][a-zA-Z][a-zA-Z] +[0-9]?[0-9] +[0-9][0-9]:[0-9][0-9]/ + From abcd Mon Sep 01 12:33:02 1997 + 0: From abcd Mon Sep 01 12:33 + 1: abcd + +/^From\s+\S+\s+([a-zA-Z]{3}\s+){2}\d{1,2}\s+\d\d:\d\d/ + From abcd Mon Sep 01 12:33:02 1997 + 0: From abcd Mon Sep 01 12:33 + 1: Sep + From abcd Mon Sep 1 12:33:02 1997 + 0: From abcd Mon Sep 1 12:33 + 1: Sep +\= Expect no match + From abcd Sep 01 12:33:02 1997 +No match + +/^12.34/s + 12\n34 + 0: 12\x0a34 + 12\r34 + 0: 12\x0d34 + +/\w+(?=\t)/ + the quick brown\t fox + 0: brown + +/foo(?!bar)(.*)/ + foobar is foolish see? + 0: foolish see? + 1: lish see? + +/(?:(?!foo)...|^.{0,2})bar(.*)/ + foobar crowbar etc + 0: rowbar etc + 1: etc + barrel + 0: barrel + 1: rel + 2barrel + 0: 2barrel + 1: rel + A barrel + 0: A barrel + 1: rel + +/^(\D*)(?=\d)(?!123)/ + abc456 + 0: abc + 1: abc +\= Expect no match + abc123 +No match + +/^1234(?# test newlines + inside)/ + 1234 + 0: 1234 + +/^1234 #comment in extended re + /x + 1234 + 0: 1234 + +/#rhubarb + abcd/x + abcd + 0: abcd + +/^abcd#rhubarb/x + abcd + 0: abcd + +/^(a)\1{2,3}(.)/ + aaab + 0: aaab + 1: a + 2: b + aaaab + 0: aaaab + 1: a + 2: b + aaaaab + 0: aaaaa + 1: a + 2: a + aaaaaab + 0: aaaaa + 1: a + 2: a + +/(?!^)abc/ + the abc + 0: abc +\= Expect no match + abc +No match + +/(?=^)abc/ + abc + 0: abc +\= Expect no match + the abc +No match + +/^[ab]{1,3}(ab*|b)/ + aabbbbb + 0: aabb + 1: b + +/^[ab]{1,3}?(ab*|b)/ + aabbbbb + 0: aabbbbb + 1: abbbbb + +/^[ab]{1,3}?(ab*?|b)/ + aabbbbb + 0: aa + 1: a + +/^[ab]{1,3}(ab*?|b)/ + aabbbbb + 0: aabb + 1: b + +/ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional leading comment +(?: (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # one word, optionally followed by.... +(?: +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] | # atom and space parts, or... +\( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) | # comments, or... + +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +# quoted strings +)* +< (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # leading < +(?: @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* + +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* , (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +)* # further okay, if led by comma +: # closing colon +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* )? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address spec +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* > # trailing > +# name and address +) (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional trailing comment +/x + Alan Other + 0: Alan Other + + 0: user@dom.ain + user\@dom.ain + 0: user@dom.ain + \"A. Other\" (a comment) + 0: "A. Other" (a comment) + A. Other (a comment) + 0: Other (a comment) + \"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"\@x400-re.lay + 0: "/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/"@x400-re.lay + A missing angle @,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +# leading word +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # "normal" atoms and or spaces +(?: +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +| +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +) # "special" comment or quoted string +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # more "normal" +)* +< +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# < +(?: +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +(?: , +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +)* # additional domains +: +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address spec +> # > +# name and address +) +/x + Alan Other + 0: Alan Other + + 0: user@dom.ain + user\@dom.ain + 0: user@dom.ain + \"A. Other\" (a comment) + 0: "A. Other" + A. Other (a comment) + 0: Other + \"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"\@x400-re.lay + 0: "/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/"@x400-re.lay + A missing angle ?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f + +/P[^*]TAIRE[^*]{1,6}?LL/ + xxxxxxxxxxxPSTAIREISLLxxxxxxxxx + 0: PSTAIREISLL + +/P[^*]TAIRE[^*]{1,}?LL/ + xxxxxxxxxxxPSTAIREISLLxxxxxxxxx + 0: PSTAIREISLL + +/(\.\d\d[1-9]?)\d+/ + 1.230003938 + 0: .230003938 + 1: .23 + 1.875000282 + 0: .875000282 + 1: .875 + 1.235 + 0: .235 + 1: .23 + +/(\.\d\d((?=0)|\d(?=\d)))/ + 1.230003938 + 0: .23 + 1: .23 + 2: + 1.875000282 + 0: .875 + 1: .875 + 2: 5 +\= Expect no match + 1.235 +No match + +/\b(foo)\s+(\w+)/i + Food is on the foo table + 0: foo table + 1: foo + 2: table + +/foo(.*)bar/ + The food is under the bar in the barn. + 0: food is under the bar in the bar + 1: d is under the bar in the + +/foo(.*?)bar/ + The food is under the bar in the barn. + 0: food is under the bar + 1: d is under the + +/(.*)(\d*)/ + I have 2 numbers: 53147 + 0: I have 2 numbers: 53147 + 1: I have 2 numbers: 53147 + 2: + +/(.*)(\d+)/ + I have 2 numbers: 53147 + 0: I have 2 numbers: 53147 + 1: I have 2 numbers: 5314 + 2: 7 + +/(.*?)(\d*)/ + I have 2 numbers: 53147 + 0: + 1: + 2: + +/(.*?)(\d+)/ + I have 2 numbers: 53147 + 0: I have 2 + 1: I have + 2: 2 + +/(.*)(\d+)$/ + I have 2 numbers: 53147 + 0: I have 2 numbers: 53147 + 1: I have 2 numbers: 5314 + 2: 7 + +/(.*?)(\d+)$/ + I have 2 numbers: 53147 + 0: I have 2 numbers: 53147 + 1: I have 2 numbers: + 2: 53147 + +/(.*)\b(\d+)$/ + I have 2 numbers: 53147 + 0: I have 2 numbers: 53147 + 1: I have 2 numbers: + 2: 53147 + +/(.*\D)(\d+)$/ + I have 2 numbers: 53147 + 0: I have 2 numbers: 53147 + 1: I have 2 numbers: + 2: 53147 + +/^\D*(?!123)/ + ABC123 + 0: AB + +/^(\D*)(?=\d)(?!123)/ + ABC445 + 0: ABC + 1: ABC +\= Expect no match + ABC123 +No match + +/^[W-]46]/ + W46]789 + 0: W46] + -46]789 + 0: -46] +\= Expect no match + Wall +No match + Zebra +No match + 42 +No match + [abcd] +No match + ]abcd[ +No match + +/^[W-\]46]/ + W46]789 + 0: W + Wall + 0: W + Zebra + 0: Z + Xylophone + 0: X + 42 + 0: 4 + [abcd] + 0: [ + ]abcd[ + 0: ] + \\backslash + 0: \ +\= Expect no match + -46]789 +No match + well +No match + +/\d\d\/\d\d\/\d\d\d\d/ + 01/01/2000 + 0: 01/01/2000 + +/word (?:[a-zA-Z0-9]+ ){0,10}otherword/ + word cat dog elephant mussel cow horse canary baboon snake shark otherword + 0: word cat dog elephant mussel cow horse canary baboon snake shark otherword +\= Expect no match + word cat dog elephant mussel cow horse canary baboon snake shark +No match + +/word (?:[a-zA-Z0-9]+ ){0,300}otherword/ +\= Expect no match + word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope +No match + +/^(a){0,0}/ + bcd + 0: + abc + 0: + aab + 0: + +/^(a){0,1}/ + bcd + 0: + abc + 0: a + 1: a + aab + 0: a + 1: a + +/^(a){0,2}/ + bcd + 0: + abc + 0: a + 1: a + aab + 0: aa + 1: a + +/^(a){0,3}/ + bcd + 0: + abc + 0: a + 1: a + aab + 0: aa + 1: a + aaa + 0: aaa + 1: a + +/^(a){0,}/ + bcd + 0: + abc + 0: a + 1: a + aab + 0: aa + 1: a + aaa + 0: aaa + 1: a + aaaaaaaa + 0: aaaaaaaa + 1: a + +/^(a){1,1}/ + abc + 0: a + 1: a + aab + 0: a + 1: a +\= Expect no match + bcd +No match + +/^(a){1,2}/ + abc + 0: a + 1: a + aab + 0: aa + 1: a +\= Expect no match + bcd +No match + +/^(a){1,3}/ + abc + 0: a + 1: a + aab + 0: aa + 1: a + aaa + 0: aaa + 1: a +\= Expect no match + bcd +No match + +/^(a){1,}/ + abc + 0: a + 1: a + aab + 0: aa + 1: a + aaa + 0: aaa + 1: a + aaaaaaaa + 0: aaaaaaaa + 1: a +\= Expect no match + bcd +No match + +/.*\.gif/ + borfle\nbib.gif\nno + 0: bib.gif + +/.{0,}\.gif/ + borfle\nbib.gif\nno + 0: bib.gif + +/.*\.gif/m + borfle\nbib.gif\nno + 0: bib.gif + +/.*\.gif/s + borfle\nbib.gif\nno + 0: borfle\x0abib.gif + +/.*\.gif/ms + borfle\nbib.gif\nno + 0: borfle\x0abib.gif + +/.*$/ + borfle\nbib.gif\nno + 0: no + +/.*$/m + borfle\nbib.gif\nno + 0: borfle + +/.*$/s + borfle\nbib.gif\nno + 0: borfle\x0abib.gif\x0ano + +/.*$/ms + borfle\nbib.gif\nno + 0: borfle\x0abib.gif\x0ano + +/.*$/ + borfle\nbib.gif\nno\n + 0: no + +/.*$/m + borfle\nbib.gif\nno\n + 0: borfle + +/.*$/s + borfle\nbib.gif\nno\n + 0: borfle\x0abib.gif\x0ano\x0a + +/.*$/ms + borfle\nbib.gif\nno\n + 0: borfle\x0abib.gif\x0ano\x0a + +/(.*X|^B)/ + abcde\n1234Xyz + 0: 1234X + 1: 1234X + BarFoo + 0: B + 1: B +\= Expect no match + abcde\nBar +No match + +/(.*X|^B)/m + abcde\n1234Xyz + 0: 1234X + 1: 1234X + BarFoo + 0: B + 1: B + abcde\nBar + 0: B + 1: B + +/(.*X|^B)/s + abcde\n1234Xyz + 0: abcde\x0a1234X + 1: abcde\x0a1234X + BarFoo + 0: B + 1: B +\= Expect no match + abcde\nBar +No match + +/(.*X|^B)/ms + abcde\n1234Xyz + 0: abcde\x0a1234X + 1: abcde\x0a1234X + BarFoo + 0: B + 1: B + abcde\nBar + 0: B + 1: B + +/(?s)(.*X|^B)/ + abcde\n1234Xyz + 0: abcde\x0a1234X + 1: abcde\x0a1234X + BarFoo + 0: B + 1: B +\= Expect no match + abcde\nBar +No match + +/(?s:.*X|^B)/ + abcde\n1234Xyz + 0: abcde\x0a1234X + BarFoo + 0: B +\= Expect no match + abcde\nBar +No match + +/^.*B/ +\= Expect no match + abc\nB +No match + +/(?s)^.*B/ + abc\nB + 0: abc\x0aB + +/(?m)^.*B/ + abc\nB + 0: B + +/(?ms)^.*B/ + abc\nB + 0: abc\x0aB + +/(?ms)^B/ + abc\nB + 0: B + +/(?s)B$/ + B\n + 0: B + +/^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]/ + 123456654321 + 0: 123456654321 + +/^\d\d\d\d\d\d\d\d\d\d\d\d/ + 123456654321 + 0: 123456654321 + +/^[\d][\d][\d][\d][\d][\d][\d][\d][\d][\d][\d][\d]/ + 123456654321 + 0: 123456654321 + +/^[abc]{12}/ + abcabcabcabc + 0: abcabcabcabc + +/^[a-c]{12}/ + abcabcabcabc + 0: abcabcabcabc + +/^(a|b|c){12}/ + abcabcabcabc + 0: abcabcabcabc + 1: c + +/^[abcdefghijklmnopqrstuvwxy0123456789]/ + n + 0: n +\= Expect no match + z +No match + +/abcde{0,0}/ + abcd + 0: abcd +\= Expect no match + abce +No match + +/ab[cd]{0,0}e/ + abe + 0: abe +\= Expect no match + abcde +No match + +/ab(c){0,0}d/ + abd + 0: abd +\= Expect no match + abcd +No match + +/a(b*)/ + a + 0: a + 1: + ab + 0: ab + 1: b + abbbb + 0: abbbb + 1: bbbb +\= Expect no match + bbbbb +No match + +/ab\d{0}e/ + abe + 0: abe +\= Expect no match + ab1e +No match + +/"([^\\"]+|\\.)*"/ + the \"quick\" brown fox + 0: "quick" + 1: quick + \"the \\\"quick\\\" brown fox\" + 0: "the \"quick\" brown fox" + 1: brown fox + +/]{0,})>]{0,})>([\d]{0,}\.)(.*)((
([\w\W\s\d][^<>]{0,})|[\s]{0,}))<\/a><\/TD>]{0,})>([\w\W\s\d][^<>]{0,})<\/TD>]{0,})>([\w\W\s\d][^<>]{0,})<\/TD><\/TR>/is + 43.Word Processor
(N-1286)
Lega lstaff.comCA - Statewide + 0: 43.Word Processor
(N-1286)
Lega lstaff.comCA - Statewide + 1: BGCOLOR='#DBE9E9' + 2: align=left valign=top + 3: 43. + 4: Word Processor
(N-1286) + 5: + 6: + 7: + 8: align=left valign=top + 9: Lega lstaff.com +10: align=left valign=top +11: CA - Statewide + +/a[^a]b/ + acb + 0: acb + a\nb + 0: a\x0ab + +/a.b/ + acb + 0: acb +\= Expect no match + a\nb +No match + +/a[^a]b/s + acb + 0: acb + a\nb + 0: a\x0ab + +/a.b/s + acb + 0: acb + a\nb + 0: a\x0ab + +/^(b+?|a){1,2}?c/ + bac + 0: bac + 1: a + bbac + 0: bbac + 1: a + bbbac + 0: bbbac + 1: a + bbbbac + 0: bbbbac + 1: a + bbbbbac + 0: bbbbbac + 1: a + +/^(b+|a){1,2}?c/ + bac + 0: bac + 1: a + bbac + 0: bbac + 1: a + bbbac + 0: bbbac + 1: a + bbbbac + 0: bbbbac + 1: a + bbbbbac + 0: bbbbbac + 1: a + +/(?!\A)x/m + a\bx\n + 0: x + a\nx\n + 0: x +\= Expect no match + x\nb\n +No match + +/(A|B)*?CD/ + CD + 0: CD + +/(A|B)*CD/ + CD + 0: CD + +/(AB)*?\1/ + ABABAB + 0: ABAB + 1: AB + +/(AB)*\1/ + ABABAB + 0: ABABAB + 1: AB + +/(?.*/)foo" + /this/is/a/very/long/line/in/deed/with/very/many/slashes/in/and/foo + 0: /this/is/a/very/long/line/in/deed/with/very/many/slashes/in/and/foo +\= Expect no match + /this/is/a/very/long/line/in/deed/with/very/many/slashes/in/it/you/see/ +No match + +/(?>(\.\d\d[1-9]?))\d+/ + 1.230003938 + 0: .230003938 + 1: .23 + 1.875000282 + 0: .875000282 + 1: .875 +\= Expect no match + 1.235 +No match + +/^((?>\w+)|(?>\s+))*$/ + now is the time for all good men to come to the aid of the party + 0: now is the time for all good men to come to the aid of the party + 1: party +\= Expect no match + this is not a line with only words and spaces! +No match + +/(\d+)(\w)/ + 12345a + 0: 12345a + 1: 12345 + 2: a + 12345+ + 0: 12345 + 1: 1234 + 2: 5 + +/((?>\d+))(\w)/ + 12345a + 0: 12345a + 1: 12345 + 2: a +\= Expect no match + 12345+ +No match + +/(?>a+)b/ + aaab + 0: aaab + +/((?>a+)b)/ + aaab + 0: aaab + 1: aaab + +/(?>(a+))b/ + aaab + 0: aaab + 1: aaa + +/(?>b)+/ + aaabbbccc + 0: bbb + +/(?>a+|b+|c+)*c/ + aaabbbbccccd + 0: aaabbbbc + +/((?>[^()]+)|\([^()]*\))+/ + ((abc(ade)ufh()()x + 0: abc(ade)ufh()()x + 1: x + +/\(((?>[^()]+)|\([^()]+\))+\)/ + (abc) + 0: (abc) + 1: abc + (abc(def)xyz) + 0: (abc(def)xyz) + 1: xyz +\= Expect no match + ((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +No match + +/a(?-i)b/i + ab + 0: ab + Ab + 0: Ab +\= Expect no match + aB +No match + AB +No match + +/(a (?x)b c)d e/ + a bcd e + 0: a bcd e + 1: a bc +\= Expect no match + a b cd e +No match + abcd e +No match + a bcde +No match + +/(a b(?x)c d (?-x)e f)/ + a bcde f + 0: a bcde f + 1: a bcde f +\= Expect no match + abcdef +No match + +/(a(?i)b)c/ + abc + 0: abc + 1: ab + aBc + 0: aBc + 1: aB +\= Expect no match + abC +No match + aBC +No match + Abc +No match + ABc +No match + ABC +No match + AbC +No match + +/a(?i:b)c/ + abc + 0: abc + aBc + 0: aBc +\= Expect no match + ABC +No match + abC +No match + aBC +No match + +/a(?i:b)*c/ + aBc + 0: aBc + aBBc + 0: aBBc +\= Expect no match + aBC +No match + aBBC +No match + +/a(?=b(?i)c)\w\wd/ + abcd + 0: abcd + abCd + 0: abCd +\= Expect no match + aBCd +No match + abcD +No match + +/(?s-i:more.*than).*million/i + more than million + 0: more than million + more than MILLION + 0: more than MILLION + more \n than Million + 0: more \x0a than Million +\= Expect no match + MORE THAN MILLION +No match + more \n than \n million +No match + +/(?:(?s-i)more.*than).*million/i + more than million + 0: more than million + more than MILLION + 0: more than MILLION + more \n than Million + 0: more \x0a than Million +\= Expect no match + MORE THAN MILLION +No match + more \n than \n million +No match + +/(?>a(?i)b+)+c/ + abc + 0: abc + aBbc + 0: aBbc + aBBc + 0: aBBc +\= Expect no match + Abc +No match + abAb +No match + abbC +No match + +/(?=a(?i)b)\w\wc/ + abc + 0: abc + aBc + 0: aBc +\= Expect no match + Ab +No match + abC +No match + aBC +No match + +/(?<=a(?i)b)(\w\w)c/ + abxxc + 0: xxc + 1: xx + aBxxc + 0: xxc + 1: xx +\= Expect no match + Abxxc +No match + ABxxc +No match + abxxC +No match + +/(?:(a)|b)(?(1)A|B)/ + aA + 0: aA + 1: a + bB + 0: bB +\= Expect no match + aB +No match + bA +No match + +/^(a)?(?(1)a|b)+$/ + aa + 0: aa + 1: a + b + 0: b + bb + 0: bb +\= Expect no match + ab +No match + +# Perl gets this next one wrong if the pattern ends with $; in that case it +# fails to match "12". + +/^(?(?=abc)\w{3}:|\d\d)/ + abc: + 0: abc: + 12 + 0: 12 + 123 + 0: 12 +\= Expect no match + xyz +No match + +/^(?(?!abc)\d\d|\w{3}:)$/ + abc: + 0: abc: + 12 + 0: 12 +\= Expect no match + 123 +No match + xyz +No match + +/(?(?<=foo)bar|cat)/ + foobar + 0: bar + cat + 0: cat + fcat + 0: cat + focat + 0: cat +\= Expect no match + foocat +No match + +/(?(?a*)*/ + a + 0: a + aa + 0: aa + aaaa + 0: aaaa + +/(abc|)+/ + abc + 0: abc + 1: + abcabc + 0: abcabc + 1: + abcabcabc + 0: abcabcabc + 1: + xyz + 0: + 1: + +/([a]*)*/ + a + 0: a + 1: + aaaaa + 0: aaaaa + 1: + +/([ab]*)*/ + a + 0: a + 1: + b + 0: b + 1: + ababab + 0: ababab + 1: + aaaabcde + 0: aaaab + 1: + bbbb + 0: bbbb + 1: + +/([^a]*)*/ + b + 0: b + 1: + bbbb + 0: bbbb + 1: + aaa + 0: + 1: + +/([^ab]*)*/ + cccc + 0: cccc + 1: + abab + 0: + 1: + +/([a]*?)*/ + a + 0: + 1: + aaaa + 0: + 1: + +/([ab]*?)*/ + a + 0: + 1: + b + 0: + 1: + abab + 0: + 1: + baba + 0: + 1: + +/([^a]*?)*/ + b + 0: + 1: + bbbb + 0: + 1: + aaa + 0: + 1: + +/([^ab]*?)*/ + c + 0: + 1: + cccc + 0: + 1: + baba + 0: + 1: + +/(?>a*)*/ + a + 0: a + aaabcde + 0: aaa + +/((?>a*))*/ + aaaaa + 0: aaaaa + 1: + aabbaa + 0: aa + 1: + +/((?>a*?))*/ + aaaaa + 0: + 1: + aabbaa + 0: + 1: + +/(?(?=[^a-z]+[a-z]) \d{2}-[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} ) /x + 12-sep-98 + 0: 12-sep-98 + 12-09-98 + 0: 12-09-98 +\= Expect no match + sep-12-98 +No match + +/(?<=(foo))bar\1/ + foobarfoo + 0: barfoo + 1: foo + foobarfootling + 0: barfoo + 1: foo +\= Expect no match + foobar +No match + barfoo +No match + +/(?i:saturday|sunday)/ + saturday + 0: saturday + sunday + 0: sunday + Saturday + 0: Saturday + Sunday + 0: Sunday + SATURDAY + 0: SATURDAY + SUNDAY + 0: SUNDAY + SunDay + 0: SunDay + +/(a(?i)bc|BB)x/ + abcx + 0: abcx + 1: abc + aBCx + 0: aBCx + 1: aBC + bbx + 0: bbx + 1: bb + BBx + 0: BBx + 1: BB +\= Expect no match + abcX +No match + aBCX +No match + bbX +No match + BBX +No match + +/^([ab](?i)[cd]|[ef])/ + ac + 0: ac + 1: ac + aC + 0: aC + 1: aC + bD + 0: bD + 1: bD + elephant + 0: e + 1: e + Europe + 0: E + 1: E + frog + 0: f + 1: f + France + 0: F + 1: F +\= Expect no match + Africa +No match + +/^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)/ + ab + 0: ab + 1: ab + aBd + 0: aBd + 1: aBd + xy + 0: xy + 1: xy + xY + 0: xY + 1: xY + zebra + 0: z + 1: z + Zambesi + 0: Z + 1: Z +\= Expect no match + aCD +No match + XY +No match + +/(?<=foo\n)^bar/m + foo\nbar + 0: bar +\= Expect no match + bar +No match + baz\nbar +No match + +/(?<=(?]&/ + <&OUT + 0: <& + +/^(a\1?){4}$/ + aaaaaaaaaa + 0: aaaaaaaaaa + 1: aaaa +\= Expect no match + AB +No match + aaaaaaaaa +No match + aaaaaaaaaaa +No match + +/^(a(?(1)\1)){4}$/ + aaaaaaaaaa + 0: aaaaaaaaaa + 1: aaaa +\= Expect no match + aaaaaaaaa +No match + aaaaaaaaaaa +No match + +/(?:(f)(o)(o)|(b)(a)(r))*/ + foobar + 0: foobar + 1: f + 2: o + 3: o + 4: b + 5: a + 6: r + +/(?<=a)b/ + ab + 0: b +\= Expect no match + cb +No match + b +No match + +/(? + 2: abcd + xy:z:::abcd + 0: xy:z:::abcd + 1: xy:z::: + 2: abcd + +/^[^bcd]*(c+)/ + aexycd + 0: aexyc + 1: c + +/(a*)b+/ + caab + 0: aab + 1: aa + +/([\w:]+::)?(\w+)$/ + abcd + 0: abcd + 1: + 2: abcd + xy:z:::abcd + 0: xy:z:::abcd + 1: xy:z::: + 2: abcd +\= Expect no match + abcd: +No match + abcd: +No match + +/^[^bcd]*(c+)/ + aexycd + 0: aexyc + 1: c + +/(>a+)ab/ + +/(?>a+)b/ + aaab + 0: aaab + +/([[:]+)/ + a:[b]: + 0: :[ + 1: :[ + +/([[=]+)/ + a=[b]= + 0: =[ + 1: =[ + +/([[.]+)/ + a.[b]. + 0: .[ + 1: .[ + +/((?>a+)b)/ + aaab + 0: aaab + 1: aaab + +/(?>(a+))b/ + aaab + 0: aaab + 1: aaa + +/((?>[^()]+)|\([^()]*\))+/ + ((abc(ade)ufh()()x + 0: abc(ade)ufh()()x + 1: x + +/a\Z/ +\= Expect no match + aaab +No match + a\nb\n +No match + +/b\Z/ + a\nb\n + 0: b + +/b\z/ + +/b\Z/ + a\nb + 0: b + +/b\z/ + a\nb + 0: b + +/^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/ + a + 0: a + 1: + abc + 0: abc + 1: + a-b + 0: a-b + 1: + 0-9 + 0: 0-9 + 1: + a.b + 0: a.b + 1: + 5.6.7 + 0: 5.6.7 + 1: + the.quick.brown.fox + 0: the.quick.brown.fox + 1: + a100.b200.300c + 0: a100.b200.300c + 1: + 12-ab.1245 + 0: 12-ab.1245 + 1: +\= Expect no match + \ +No match + .a +No match + -a +No match + a- +No match + a. +No match + a_b +No match + a.- +No match + a.. +No match + ab..bc +No match + the.quick.brown.fox- +No match + the.quick.brown.fox. +No match + the.quick.brown.fox_ +No match + the.quick.brown.fox+ +No match + +/(?>.*)(?<=(abcd|wxyz))/ + alphabetabcd + 0: alphabetabcd + 1: abcd + endingwxyz + 0: endingwxyz + 1: wxyz +\= Expect no match + a rather long string that doesn't end with one of them +No match + +/word (?>(?:(?!otherword)[a-zA-Z0-9]+ ){0,30})otherword/ + word cat dog elephant mussel cow horse canary baboon snake shark otherword + 0: word cat dog elephant mussel cow horse canary baboon snake shark otherword +\= Expect no match + word cat dog elephant mussel cow horse canary baboon snake shark +No match + +/word (?>[a-zA-Z0-9]+ ){0,30}otherword/ +\= Expect no match + word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope +No match + +/(?<=\d{3}(?!999))foo/ + 999foo + 0: foo + 123999foo + 0: foo +\= Expect no match + 123abcfoo +No match + +/(?<=(?!...999)\d{3})foo/ + 999foo + 0: foo + 123999foo + 0: foo +\= Expect no match + 123abcfoo +No match + +/(?<=\d{3}(?!999)...)foo/ + 123abcfoo + 0: foo + 123456foo + 0: foo +\= Expect no match + 123999foo +No match + +/(?<=\d{3}...)(? + 2: + 3: abcd +
+ 2: + 3: abcd + \s*)=(?>\s*) # find + 2: + 3: abcd + Z)+|A)*/ + ZABCDEFG + 0: ZA + 1: A + +/((?>)+|A)*/ + ZABCDEFG + 0: + 1: + +/^[\d-a]/ + abcde + 0: a + -things + 0: - + 0digit + 0: 0 +\= Expect no match + bcdef +No match + +/[\s]+/ + > \x09\x0a\x0c\x0d\x0b< + 0: \x09\x0a\x0c\x0d\x0b + +/\s+/ + > \x09\x0a\x0c\x0d\x0b< + 0: \x09\x0a\x0c\x0d\x0b + +/a b/x + ab + 0: ab + +/(?!\A)x/m + a\nxb\n + 0: x + +/(?!^)x/m +\= Expect no match + a\nxb\n +No match + +#/abc\Qabc\Eabc/ +# abcabcabc +# 0: abcabcabc + +#/abc\Q(*+|\Eabc/ +# abc(*+|abc +# 0: abc(*+|abc + +#/ abc\Q abc\Eabc/x +# abc abcabc +# 0: abc abcabc +#\= Expect no match +# abcabcabc +#No match + +#/abc#comment +# \Q#not comment +# literal\E/x +# abc#not comment\n literal +# 0: abc#not comment\x0a literal + +#/abc#comment +# \Q#not comment +# literal/x +# abc#not comment\n literal +# 0: abc#not comment\x0a literal + +#/abc#comment +# \Q#not comment +# literal\E #more comment +# /x +# abc#not comment\n literal +# 0: abc#not comment\x0a literal + +#/abc#comment +# \Q#not comment +# literal\E #more comment/x +# abc#not comment\n literal +# 0: abc#not comment\x0a literal + +#/\Qabc\$xyz\E/ +# abc\\\$xyz +# 0: abc\$xyz + +#/\Qabc\E\$\Qxyz\E/ +# abc\$xyz +# 0: abc$xyz + +/\Gabc/ + abc + 0: abc +\= Expect no match + xyzabc +No match + +/a(?x: b c )d/ + XabcdY + 0: abcd +\= Expect no match + Xa b c d Y +No match + +/((?x)x y z | a b c)/ + XabcY + 0: abc + 1: abc + AxyzB + 0: xyz + 1: xyz + +/(?i)AB(?-i)C/ + XabCY + 0: abC +\= Expect no match + XabcY +No match + +/((?i)AB(?-i)C|D)E/ + abCE + 0: abCE + 1: abC + DE + 0: DE + 1: D +\= Expect no match + abcE +No match + abCe +No match + dE +No match + De +No match + +/(.*)\d+\1/ + abc123abc + 0: abc123abc + 1: abc + abc123bc + 0: bc123bc + 1: bc + +/(.*)\d+\1/s + abc123abc + 0: abc123abc + 1: abc + abc123bc + 0: bc123bc + 1: bc + +/((.*))\d+\1/ + abc123abc + 0: abc123abc + 1: abc + 2: abc + abc123bc + 0: bc123bc + 1: bc + 2: bc + +# This tests for an IPv6 address in the form where it can have up to +# eight components, one and only one of which is empty. This must be +# an internal component. + +/^(?!:) # colon disallowed at start + (?: # start of item + (?: [0-9a-f]{1,4} | # 1-4 hex digits or + (?(1)0 | () ) ) # if null previously matched, fail; else null + : # followed by colon + ){1,7} # end item; 1-7 of them required + [0-9a-f]{1,4} $ # final hex number at end of string + (?(1)|.) # check that there was an empty component + /ix + a123::a123 + 0: a123::a123 + 1: + a123:b342::abcd + 0: a123:b342::abcd + 1: + a123:b342::324e:abcd + 0: a123:b342::324e:abcd + 1: + a123:ddde:b342::324e:abcd + 0: a123:ddde:b342::324e:abcd + 1: + a123:ddde:b342::324e:dcba:abcd + 0: a123:ddde:b342::324e:dcba:abcd + 1: + a123:ddde:9999:b342::324e:dcba:abcd + 0: a123:ddde:9999:b342::324e:dcba:abcd + 1: +\= Expect no match + 1:2:3:4:5:6:7:8 +No match + a123:bce:ddde:9999:b342::324e:dcba:abcd +No match + a123::9999:b342::324e:dcba:abcd +No match + abcde:2:3:4:5:6:7:8 +No match + ::1 +No match + abcd:fee0:123:: +No match + :1 +No match + 1: +No match + +#/[z\Qa-d]\E]/ +# z +# 0: z +# a +# 0: a +# - +# 0: - +# d +# 0: d +# ] +# 0: ] +#\= Expect no match +# b +#No match + +#TODO: PCRE has an optimization to make this workable, .NET does not +#/(a+)*b/ +#\= Expect no match +# aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +#No match + +# All these had to be updated because we understand unicode +# and this looks like it's expecting single byte matches + +# .NET generates \xe4...not sure what's up, might just be different code pages +/(?i)reg(?:ul(?:[aä]|ae)r|ex)/ + REGular + 0: REGular + regulaer + 0: regulaer + Regex + 0: Regex + regulär + 0: regul\xc3\xa4r + +#/Åæåä[à-ÿÀ-ß]+/ +# Åæåäà +# 0: \xc5\xe6\xe5\xe4\xe0 +# Åæåäÿ +# 0: \xc5\xe6\xe5\xe4\xff +# ÅæåäÀ +# 0: \xc5\xe6\xe5\xe4\xc0 +# Åæåäß +# 0: \xc5\xe6\xe5\xe4\xdf + +/(?<=Z)X./ + \x84XAZXB + 0: XB + +/ab cd (?x) de fg/ + ab cd defg + 0: ab cd defg + +/ab cd(?x) de fg/ + ab cddefg + 0: ab cddefg +\= Expect no match + abcddefg +No match + +/(? + 2: + D + 0: D + 1: + 2: + +# this is really long with debug -- removing for now +#/(a|)*\d/ +# aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4 +# 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4 +# 1: +#\= Expect no match +# aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +#No match + +/(?>a|)*\d/ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4 + 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4 +\= Expect no match + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +No match + +/(?:a|)*\d/ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4 + 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4 +\= Expect no match + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +No match + +/^(?s)(?>.*)(? + 2: a + +/(?>(a))b|(a)c/ + ac + 0: ac + 1: + 2: a + +/(?=(a))ab|(a)c/ + ac + 0: ac + 1: + 2: a + +/((?>(a))b|(a)c)/ + ac + 0: ac + 1: ac + 2: + 3: a + +/(?=(?>(a))b|(a)c)(..)/ + ac + 0: ac + 1: + 2: a + 3: ac + +/(?>(?>(a))b|(a)c)/ + ac + 0: ac + 1: + 2: a + +/((?>(a+)b)+(aabab))/ + aaaabaaabaabab + 0: aaaabaaabaabab + 1: aaaabaaabaabab + 2: aaa + 3: aabab + +/(?>a+|ab)+?c/ +\= Expect no match + aabc +No match + +/(?>a+|ab)+c/ +\= Expect no match + aabc +No match + +/(?:a+|ab)+c/ + aabc + 0: aabc + +/^(?:a|ab)+c/ + aaaabc + 0: aaaabc + +/(?=abc){0}xyz/ + xyz + 0: xyz + +/(?=abc){1}xyz/ +\= Expect no match + xyz +No match + +/(?=(a))?./ + ab + 0: a + 1: a + bc + 0: b + +/(?=(a))??./ + ab + 0: a + bc + 0: b + +/^(?!a){0}\w+/ + aaaaa + 0: aaaaa + +/(?<=(abc))?xyz/ + abcxyz + 0: xyz + 1: abc + pqrxyz + 0: xyz + +/^[g]+/ + ggg<<>> + 0: ggg<<>> +\= Expect no match + \\ga +No match + +/^[ga]+/ + gggagagaxyz + 0: gggagaga + +/[:a]xxx[b:]/ + :xxx: + 0: :xxx: + +/(?<=a{2})b/i + xaabc + 0: b +\= Expect no match + xabc +No match + +/(? +# 4: +# 5: c +# 6: d +# 7: Y + +#/^X(?7)(a)(?|(b|(?|(r)|(t))(s))|(q))(c)(d)(Y)/ +# XYabcdY +# 0: XYabcdY +# 1: a +# 2: b +# 3: +# 4: +# 5: c +# 6: d +# 7: Y + +/(?'abc'\w+):\k{2}/ + a:aaxyz + 0: a:aa + 1: a + ab:ababxyz + 0: ab:abab + 1: ab +\= Expect no match + a:axyz +No match + ab:abxyz +No match + +/^(?a)? (?(ab)b|c) (?(ab)d|e)/x + abd + 0: abd + 1: a + ce + 0: ce + +# .NET has more consistent grouping numbers with these dupe groups for the two options +/(?:a(? (?')|(?")) |b(? (?')|(?")) ) (?(quote)[a-z]+|[0-9]+)/x,dupnames + a\"aaaaa + 0: a"aaaaa + 1: " + 2: + 3: " + b\"aaaaa + 0: b"aaaaa + 1: " + 2: + 3: " +\= Expect no match + b\"11111 +No match + +#/(?P(?P0)(?P>L1)|(?P>L2))/ +# 0 +# 0: 0 +# 1: 0 +# 00 +# 0: 00 +# 1: 00 +# 2: 0 +# 0000 +# 0: 0000 +# 1: 0000 +# 2: 0 + +#/(?P(?P0)|(?P>L2)(?P>L1))/ +# 0 +# 0: 0 +# 1: 0 +# 2: 0 +# 00 +# 0: 0 +# 1: 0 +# 2: 0 +# 0000 +# 0: 0 +# 1: 0 +# 2: 0 + +# Check the use of names for failure + +# Check opening parens in comment when seeking forward reference. + +#/(?P(?P=abn)xxx|)+/ +# xxx +# 0: +# 1: + +#Posses +/^(a)?(\w)/ + aaaaX + 0: aa + 1: a + 2: a + YZ + 0: Y + 1: + 2: Y + +#Posses +/^(?:a)?(\w)/ + aaaaX + 0: aa + 1: a + YZ + 0: Y + 1: Y + +/\A.*?(a|bc)/ + ba + 0: ba + 1: a + +/\A.*?(?:a|bc|d)/ + ba + 0: ba + +# -------------------------- + +/(another)?(\1?)test/ + hello world test + 0: test + 1: + 2: + +/(another)?(\1+)test/ +\= Expect no match + hello world test +No match + +/((?:a?)*)*c/ + aac + 0: aac + 1: + +/((?>a?)*)*c/ + aac + 0: aac + 1: + +/(?>.*?a)(?<=ba)/ + aba + 0: ba + +/(?:.*?a)(?<=ba)/ + aba + 0: aba + +/(?>.*?a)b/s + aab + 0: ab + +/(?>.*?a)b/ + aab + 0: ab + +/(?>^a)b/s +\= Expect no match + aab +No match + +/(?>.*?)(?<=(abcd)|(wxyz))/ + alphabetabcd + 0: + 1: abcd + endingwxyz + 0: + 1: + 2: wxyz + +/(?>.*)(?<=(abcd)|(wxyz))/ + alphabetabcd + 0: alphabetabcd + 1: abcd + endingwxyz + 0: endingwxyz + 1: + 2: wxyz + +"(?>.*)foo" +\= Expect no match + abcdfooxyz +No match + +"(?>.*?)foo" + abcdfooxyz + 0: foo + +# Tests that try to figure out how Perl works. My hypothesis is that the first +# verb that is backtracked onto is the one that acts. This seems to be the case +# almost all the time, but there is one exception that is perhaps a bug. + +/a(?=bc).|abd/ + abd + 0: abd + abc + 0: ab + +/a(?>bc)d|abd/ + abceabd + 0: abd + +# These tests were formerly in test 2, but changes in PCRE and Perl have +# made them compatible. + +/^(a)?(?(1)a|b)+$/ +\= Expect no match + a +No match + +# ---- + +/^\d*\w{4}/ + 1234 + 0: 1234 +\= Expect no match + 123 +No match + +/^[^b]*\w{4}/ + aaaa + 0: aaaa +\= Expect no match + aaa +No match + +/^[^b]*\w{4}/i + aaaa + 0: aaaa +\= Expect no match + aaa +No match + +/^a*\w{4}/ + aaaa + 0: aaaa +\= Expect no match + aaa +No match + +/^a*\w{4}/i + aaaa + 0: aaaa +\= Expect no match + aaa +No match + +/(?:(?foo)|(?bar))\k/dupnames + foofoo + 0: foofoo + 1: foo + barbar + 0: barbar + 1: bar + +# A notable difference between PCRE and .NET. According to +# the PCRE docs: +# If you make a subroutine call to a non-unique named +# subpattern, the one that corresponds to the first +# occurrence of the name is used. In the absence of +# duplicate numbers (see the previous section) this is +# the one with the lowest number. +# .NET takes the most recently captured number according to MSDN: +# A backreference refers to the most recent definition of +# a group (the definition most immediately to the left, +# when matching left to right). When a group makes multiple +# captures, a backreference refers to the most recent capture. + +#/(?A)(?:(?foo)|(?bar))\k/dupnames +# AfooA +# 0: AfooA +# 1: A +# 2: foo +# AbarA +# 0: AbarA +# 1: A +# 2: +# 3: bar +#\= Expect no match +# Afoofoo +#No match +# Abarbar +#No match + +/^(\d+)\s+IN\s+SOA\s+(\S+)\s+(\S+)\s*\(\s*$/ + 1 IN SOA non-sp1 non-sp2( + 0: 1 IN SOA non-sp1 non-sp2( + 1: 1 + 2: non-sp1 + 3: non-sp2 + +# TODO: .NET's group number ordering here in the second example is a bit odd +/^ (?:(?A)|(?'B'B)(?A)) (?(A)x) (?(B)y)$/x,dupnames + Ax + 0: Ax + 1: A + BAxy + 0: BAxy + 1: A + 2: B + +/ ^ a + b $ /x + aaaab + 0: aaaab + +/ ^ a + #comment + b $ /x + aaaab + 0: aaaab + +/ ^ a + #comment + #comment + b $ /x + aaaab + 0: aaaab + +/ ^ (?> a + ) b $ /x + aaaab + 0: aaaab + +/ ^ ( a + ) + \w $ /x + aaaab + 0: aaaab + 1: aaaa + +/(?:x|(?:(xx|yy)+|x|x|x|x|x)|a|a|a)bc/ +\= Expect no match + acb +No match + +#Posses +#/\A(?:[^\"]+|\"(?:[^\"]*|\"\")*\")+/ +# NON QUOTED \"QUOT\"\"ED\" AFTER \"NOT MATCHED +# 0: NON QUOTED "QUOT""ED" AFTER + +#Posses +#/\A(?:[^\"]+|\"(?:[^\"]+|\"\")*\")+/ +# NON QUOTED \"QUOT\"\"ED\" AFTER \"NOT MATCHED +# 0: NON QUOTED "QUOT""ED" AFTER + +#Posses +#/\A(?:[^\"]+|\"(?:[^\"]+|\"\")+\")+/ +# NON QUOTED \"QUOT\"\"ED\" AFTER \"NOT MATCHED +# 0: NON QUOTED "QUOT""ED" AFTER + +#Posses +#/\A([^\"1]+|[\"2]([^\"3]*|[\"4][\"5])*[\"6])+/ +# NON QUOTED \"QUOT\"\"ED\" AFTER \"NOT MATCHED +# 0: NON QUOTED "QUOT""ED" AFTER +# 1: AFTER +# 2: + +/^\w+(?>\s*)(?<=\w)/ + test test + 0: tes + +#/(?Pa)?(?Pb)?(?()c|d)*l/ +# acl +# 0: acl +# 1: a +# bdl +# 0: bdl +# 1: +# 2: b +# adl +# 0: dl +# bcl +# 0: l + +/\sabc/ + \x0babc + 0: \x0babc + +#/[\Qa]\E]+/ +# aa]] +# 0: aa]] + +#/[\Q]a\E]+/ +# aa]] +# 0: aa]] + +/A((((((((a))))))))\8B/ + AaaB + 0: AaaB + 1: a + 2: a + 3: a + 4: a + 5: a + 6: a + 7: a + 8: a + +/A(((((((((a)))))))))\9B/ + AaaB + 0: AaaB + 1: a + 2: a + 3: a + 4: a + 5: a + 6: a + 7: a + 8: a + 9: a + +/(|ab)*?d/ + abd + 0: abd + 1: ab + xyd + 0: d + +/(\2|a)(\1)/ + aaa + 0: aa + 1: a + 2: a + +/(\2)(\1)/ + +"Z*(|d*){216}" + +/((((((((((((x))))))))))))\12/ + xx + 0: xx + 1: x + 2: x + 3: x + 4: x + 5: x + 6: x + 7: x + 8: x + 9: x +10: x +11: x +12: x + +#"(?|(\k'Pm')|(?'Pm'))" +# abcd +# 0: +# 1: + +#/(?|(aaa)|(b))\g{1}/ +# aaaaaa +# 0: aaaaaa +# 1: aaa +# bb +# 0: bb +# 1: b + +#/(?|(aaa)|(b))(?1)/ +# aaaaaa +# 0: aaaaaa +# 1: aaa +# baaa +# 0: baaa +# 1: b +#\= Expect no match +# bb +#No match + +#/(?|(aaa)|(b))/ +# xaaa +# 0: aaa +# 1: aaa +# xbc +# 0: b +# 1: b + +#/(?|(?'a'aaa)|(?'a'b))\k'a'/ +# aaaaaa +# 0: aaaaaa +# 1: aaa +# bb +# 0: bb +# 1: b + +#/(?|(?'a'aaa)|(?'a'b))(?'a'cccc)\k'a'/dupnames +# aaaccccaaa +# 0: aaaccccaaa +# 1: aaa +# 2: cccc +# bccccb +# 0: bccccb +# 1: b +# 2: cccc + +# End of testinput1 diff --git a/vendor/github.com/firefart/nonamedreturns/analyzer/analyzer.go b/vendor/github.com/firefart/nonamedreturns/analyzer/analyzer.go index ecd4915a8..a61899f0e 100644 --- a/vendor/github.com/firefart/nonamedreturns/analyzer/analyzer.go +++ b/vendor/github.com/firefart/nonamedreturns/analyzer/analyzer.go @@ -1,6 +1,7 @@ package analyzer import ( + "errors" "flag" "go/ast" "go/types" @@ -30,7 +31,10 @@ func run(pass *analysis.Pass) (interface{}, error) { reportErrorInDefer := pass.Analyzer.Flags.Lookup(FlagReportErrorInDefer).Value.String() == "true" errorType := types.Universe.Lookup("error").Type() - inspector := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + inspector, ok := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + if !ok { + return nil, errors.New("failed to get inspector") + } // only filter function defintions nodeFilter := []ast.Node{ @@ -87,7 +91,7 @@ func run(pass *analysis.Pass) (interface{}, error) { } }) - return nil, nil + return nil, nil // nolint:nilnil } func findDeferWithVariableAssignment(body *ast.BlockStmt, info *types.Info, variable types.Object) bool { diff --git a/vendor/github.com/ghostiam/protogetter/.goreleaser.yaml b/vendor/github.com/ghostiam/protogetter/.goreleaser.yaml index a70d0fb00..cc5d4cffb 100644 --- a/vendor/github.com/ghostiam/protogetter/.goreleaser.yaml +++ b/vendor/github.com/ghostiam/protogetter/.goreleaser.yaml @@ -1,3 +1,4 @@ +version: 2 before: hooks: - go mod tidy @@ -21,4 +22,4 @@ changelog: exclude: - '^docs:' - '^test:' - - '^ci:' \ No newline at end of file + - '^ci:' diff --git a/vendor/github.com/ghostiam/protogetter/README.md b/vendor/github.com/ghostiam/protogetter/README.md index c033e9597..9322d69b6 100644 --- a/vendor/github.com/ghostiam/protogetter/README.md +++ b/vendor/github.com/ghostiam/protogetter/README.md @@ -54,13 +54,35 @@ v := m.Foo.Bar.Baz.Int which simplifies the code and makes it more reliable. -## Installation +## Usage + +### Recommended way — via golangci-lint + +Protogetter is integrated into [golangci-lint](https://github.com/golangci/golangci-lint) and can be run together with other linters. This is the preferred way to use it in most projects. + +Example minimal `.golangci.yml` configuration: + +```yaml +linters: + enable: + - protogetter +``` + +Run: + +```bash +golangci-lint run ./... +``` + +## Standalone usage + +### Installation ```bash go install github.com/ghostiam/protogetter/cmd/protogetter@latest ``` -## Usage +### Direct run To run the linter: ```bash diff --git a/vendor/github.com/ghostiam/protogetter/flake.lock b/vendor/github.com/ghostiam/protogetter/flake.lock new file mode 100644 index 000000000..664ccdaa6 --- /dev/null +++ b/vendor/github.com/ghostiam/protogetter/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1759381078, + "narHash": "sha256-gTrEEp5gEspIcCOx9PD8kMaF1iEmfBcTbO0Jag2QhQs=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "7df7ff7d8e00218376575f0acdcc5d66741351ee", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/vendor/github.com/ghostiam/protogetter/flake.nix b/vendor/github.com/ghostiam/protogetter/flake.nix new file mode 100644 index 000000000..4bbe48500 --- /dev/null +++ b/vendor/github.com/ghostiam/protogetter/flake.nix @@ -0,0 +1,70 @@ +{ + description = "A flake that builds a repo"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = + inputs@{ + nixpkgs, + flake-utils, + ... + }: + flake-utils.lib.eachDefaultSystem ( + system: + let + pkgs = import nixpkgs { inherit system; }; + go = pkgs.go_1_24; + buildInputs = with pkgs; [ + go + coreutils + curl + xmlstarlet + + # Protobuf + gRPC + protobuf + protoc-gen-go + protoc-gen-go-grpc + grpc + ]; + + defaultShellHook = '' + export SHELL="${pkgs.bashInteractive}/bin/bash" + + export FLAKE_ROOT="$(nix flake metadata | grep 'Resolved URL' | awk '{print $3}' | sed 's/^path://' | sed 's/^git+file:\/\///')" + export HISTFILE="$FLAKE_ROOT/.nix_bash_history" + + export GOROOT="${go}/share/go" + ''; + in + { + # run: `nix develop` + devShells = { + default = pkgs.mkShell { + inherit buildInputs; + shellHook = defaultShellHook; + }; + + # Update IDEA paths. Use only if nix installed in whole system. + # run: `nix develop .#idea` + idea = pkgs.mkShell { + inherit buildInputs; + + shellHook = pkgs.lib.concatLines [ + defaultShellHook + '' + cd "$FLAKE_ROOT" + + echo "Replace GOPATH" + xmlstarlet ed -L -u '//project/component[@name="GOROOT"]/@url' -v 'file://${go}/share/go' .idea/workspace.xml + + exit 0 + '' + ]; + }; + }; + } + ); +} diff --git a/vendor/github.com/ghostiam/protogetter/processor.go b/vendor/github.com/ghostiam/protogetter/processor.go index 44f346e85..5279199ae 100644 --- a/vendor/github.com/ghostiam/protogetter/processor.go +++ b/vendor/github.com/ghostiam/protogetter/processor.go @@ -33,12 +33,21 @@ func (c *processor) process(n ast.Node) (*Result, error) { switch x := n.(type) { case *ast.AssignStmt: // Skip any assignment to the field. - for _, s := range x.Lhs { + for i, s := range x.Lhs { c.filter.AddPos(s.Pos()) if se, ok := s.(*ast.StarExpr); ok { c.filter.AddPos(se.X.Pos()) } + + if len(x.Rhs) > i { + value := x.Rhs[i] + if se, ok := value.(*ast.SelectorExpr); ok { + if hasPointerKeyWithoutPointerGetter(c.info, s, se) { + c.filter.AddPos(se.Sel.Pos()) + } + } + } } case *ast.IncDecStmt: @@ -52,6 +61,13 @@ func (c *processor) process(n ast.Node) (*Result, error) { c.filter.AddPos(x.X.Pos()) } + case *ast.KeyValueExpr: + if se, ok := x.Value.(*ast.SelectorExpr); ok { + if hasPointerKeyWithoutPointerGetter(c.info, x.Key, se) { + c.filter.AddPos(se.Sel.Pos()) + } + } + case *ast.CallExpr: if !c.cfg.ReplaceFirstArgInAppend && len(x.Args) > 0 { if v, ok := x.Fun.(*ast.Ident); ok && v.Name == "append" { @@ -61,17 +77,38 @@ func (c *processor) process(n ast.Node) (*Result, error) { } } - f, ok := x.Fun.(*ast.SelectorExpr) - if !ok { - return &Result{}, nil - } + switch fun := x.Fun.(type) { + case *ast.Ident: + // Allow passing optional parameters to the function without getter. - if !isProtoMessage(c.info, f.X) { + if len(x.Args) == 0 { + return &Result{}, nil + } + + if fun.Obj == nil || fun.Obj.Kind != ast.Fun { + return &Result{}, nil + } + + decl, ok := fun.Obj.Decl.(*ast.FuncDecl) + if !ok || decl.Type == nil { + return &Result{}, nil + } + + c.filterOptionalProtoSelectorExpr(x.Args) + + case *ast.SelectorExpr: + c.filterOptionalProtoSelectorExpr(x.Args) + + if !isProtoMessage(c.info, fun.X) { + return &Result{}, nil + } + + c.processInner(x) + + default: return &Result{}, nil } - c.processInner(x) - case *ast.SelectorExpr: if !isProtoMessage(c.info, x.X) { // If the selector is not on a proto message, skip it. @@ -141,6 +178,31 @@ func (c *processor) process(n ast.Node) (*Result, error) { c.filter.AddPos(x.X.Pos()) + case *ast.DeclStmt: + decl, ok := x.Decl.(*ast.GenDecl) + if !ok { + return &Result{}, nil + } + + for _, spec := range decl.Specs { + vSpec, ok := spec.(*ast.ValueSpec) + if !ok { + continue + } + + _, ok = vSpec.Type.(*ast.StarExpr) + if !ok { + continue + } + + for _, ve := range vSpec.Values { + c.filter.AddPos(ve.Pos()) + } + } + + case *ast.ReturnStmt: + c.filterOptionalProtoSelectorExpr(x.Results) + default: return nil, fmt.Errorf("not implemented for type: %s (%s)", reflect.TypeOf(x), formatNode(n)) } @@ -155,6 +217,25 @@ func (c *processor) process(n ast.Node) (*Result, error) { }, nil } +func (c *processor) filterOptionalProtoSelectorExpr(args []ast.Expr) { + for _, arg := range args { + a, ok := arg.(*ast.SelectorExpr) + if !ok { + continue + } + + if !isProtoMessage(c.info, a.X) { + continue + } + + if !isOptionalProto(c.info, a) { + continue + } + + c.filter.AddPos(a.Sel.Pos()) + } +} + func (c *processor) processInner(expr ast.Expr) { switch x := expr.(type) { case *ast.Ident: @@ -177,7 +258,11 @@ func (c *processor) processInner(expr ast.Expr) { c.write(".") // If getter exists, use it. - if methodIsExists(c.info, x.X, "Get"+x.Sel.Name) { + if methodIsExists(c.info, x.X, "Get"+x.Sel.Name) && + // Skip if the field is filtered. + !c.filter.IsFiltered(x.Sel.Pos()) && + // Check if the field is a proto-message. + isProtoMessage(c.info, x.X) { c.writeFrom(x.Sel.Name) c.writeTo("Get" + x.Sel.Name + "()") return @@ -218,7 +303,7 @@ func (c *processor) processInner(expr ast.Expr) { c.write("*") c.processInner(x.X) - case *ast.CompositeLit, *ast.TypeAssertExpr, *ast.ArrayType, *ast.FuncLit, *ast.SliceExpr: + case *ast.CompositeLit, *ast.TypeAssertExpr, *ast.ArrayType, *ast.FuncLit, *ast.SliceExpr, *ast.MapType: // Process the node as is. c.write(formatNode(x)) @@ -277,6 +362,20 @@ func isProtoMessage(info *types.Info, expr ast.Expr) bool { return false } +func isOptionalProto(info *types.Info, a *ast.SelectorExpr) bool { + _, isPtrArg := info.TypeOf(a).Underlying().(*types.Pointer) + if !isPtrArg { + return false + } + + getterHasPointer, _ := getterResultHasPointer(info, a.X, a.Sel.Name) + if getterHasPointer { + return false + } + + return true +} + func typesNamed(info *types.Info, x ast.Expr) (*types.Named, bool) { if info == nil { return nil, false @@ -349,3 +448,17 @@ func getterResultHasPointer(info *types.Info, x ast.Expr, name string) (hasPoint return false, false } + +func hasPointerKeyWithoutPointerGetter(info *types.Info, key ast.Expr, value *ast.SelectorExpr) bool { + _, isPtr := info.TypeOf(key).(*types.Pointer) + if !isPtr { + return false + } + + getterHasPointer, ok := getterResultHasPointer(info, value.X, value.Sel.Name) + if !ok { + return false + } + + return !getterHasPointer +} diff --git a/vendor/github.com/ghostiam/protogetter/protogetter.go b/vendor/github.com/ghostiam/protogetter/protogetter.go index 31eee8572..d0cb04278 100644 --- a/vendor/github.com/ghostiam/protogetter/protogetter.go +++ b/vendor/github.com/ghostiam/protogetter/protogetter.go @@ -16,13 +16,6 @@ import ( "golang.org/x/tools/go/ast/inspector" ) -type Mode int - -const ( - StandaloneMode Mode = iota - GolangciLintMode -) - const msgFormat = "avoid direct access to proto field %s, use %s instead" func NewAnalyzer(cfg *Config) *analysis.Analyzer { @@ -35,7 +28,7 @@ func NewAnalyzer(cfg *Config) *analysis.Analyzer { Doc: "Reports direct reads from proto message fields when getters should be used", Flags: flags(cfg), Run: func(pass *analysis.Pass) (any, error) { - _, err := Run(pass, cfg) + err := Run(pass, cfg) return nil, err }, } @@ -62,14 +55,13 @@ func flags(opts *Config) flag.FlagSet { } type Config struct { - Mode Mode // Zero value is StandaloneMode. SkipGeneratedBy []string SkipFiles []string SkipAnyGenerated bool ReplaceFirstArgInAppend bool } -func Run(pass *analysis.Pass, cfg *Config) ([]Issue, error) { +func Run(pass *analysis.Pass, cfg *Config) error { skipGeneratedBy := make([]string, 0, len(cfg.SkipGeneratedBy)+3) // Always skip files generated by protoc-gen-go, protoc-gen-go-grpc and protoc-gen-grpc-gateway. skipGeneratedBy = append(skipGeneratedBy, "protoc-gen-go", "protoc-gen-go-grpc", "protoc-gen-grpc-gateway") @@ -90,7 +82,7 @@ func Run(pass *analysis.Pass, cfg *Config) ([]Issue, error) { compile, err := glob.Compile(s) if err != nil { - return nil, fmt.Errorf("invalid glob pattern: %w", err) + return fmt.Errorf("invalid glob pattern: %w", err) } skipFilesGlobPatterns = append(skipFilesGlobPatterns, compile) @@ -104,6 +96,9 @@ func Run(pass *analysis.Pass, cfg *Config) ([]Issue, error) { (*ast.StarExpr)(nil), (*ast.IncDecStmt)(nil), (*ast.UnaryExpr)(nil), + (*ast.KeyValueExpr)(nil), + (*ast.DeclStmt)(nil), + (*ast.ReturnStmt)(nil), } // Skip filtered files. @@ -124,24 +119,16 @@ func Run(pass *analysis.Pass, cfg *Config) ([]Issue, error) { ins := inspector.New(files) - var issues []Issue - filter := NewPosFilter() ins.Preorder(nodeTypes, func(node ast.Node) { report := analyse(pass, filter, node, cfg) if report == nil { return } - - switch cfg.Mode { - case StandaloneMode: - pass.Report(report.ToDiagReport()) - case GolangciLintMode: - issues = append(issues, report.ToIssue(pass.Fset)) - } + pass.Report(report.ToDiagReport()) }) - return issues, nil + return nil } func analyse(pass *analysis.Pass, filter *PosFilter, n ast.Node, cfg *Config) *Report { @@ -185,19 +172,6 @@ func analyse(pass *analysis.Pass, filter *PosFilter, n ast.Node, cfg *Config) *R } } -// Issue is used to integrate with golangci-lint's inline auto fix. -type Issue struct { - Pos token.Position - Message string - InlineFix InlineFix -} - -type InlineFix struct { - StartCol int // zero-based - Length int - NewString string -} - type Report struct { node ast.Node result *Result @@ -225,27 +199,13 @@ func (r *Report) ToDiagReport() analysis.Diagnostic { } } -func (r *Report) ToIssue(fset *token.FileSet) Issue { - msg := fmt.Sprintf(msgFormat, r.result.From, r.result.To) - return Issue{ - Pos: fset.Position(r.node.Pos()), - Message: msg, - InlineFix: InlineFix{ - StartCol: fset.Position(r.node.Pos()).Column - 1, - Length: len(r.result.From), - NewString: r.result.To, - }, - } -} - func skipGeneratedFile(f *ast.File, prefixes []string, skipAny bool) bool { if len(f.Comments) == 0 { return false } firstComment := f.Comments[0].Text() - // https://golang.org/s/generatedcode - if skipAny && strings.HasPrefix(firstComment, "Code generated") { + if skipAny && ast.IsGenerated(f) { return true } diff --git a/vendor/github.com/go-critic/go-critic/checkers/badCond_checker.go b/vendor/github.com/go-critic/go-critic/checkers/badCond_checker.go index 9be45ccc7..22a6267fd 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/badCond_checker.go +++ b/vendor/github.com/go-critic/go-critic/checkers/badCond_checker.go @@ -87,7 +87,8 @@ func (c *badCondChecker) checkExpr(expr ast.Expr) { func (c *badCondChecker) equalToBoth(lhs, rhs *ast.BinaryExpr) bool { return lhs.Op == token.EQL && rhs.Op == token.EQL && - astequal.Expr(lhs.X, rhs.X) + astequal.Expr(lhs.X, rhs.X) && + typep.SideEffectFree(c.ctx.TypesInfo, lhs.Y) && typep.SideEffectFree(c.ctx.TypesInfo, rhs.Y) } func (c *badCondChecker) lessAndGreater(lhs, rhs *ast.BinaryExpr) bool { diff --git a/vendor/github.com/go-critic/go-critic/checkers/badRegexp_checker.go b/vendor/github.com/go-critic/go-critic/checkers/badRegexp_checker.go index 6c6845053..8f5cf97f6 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/badRegexp_checker.go +++ b/vendor/github.com/go-critic/go-critic/checkers/badRegexp_checker.go @@ -148,7 +148,7 @@ func (c *badRegexpChecker) walk(e syntax.Expr) { case syntax.OpCaret: if !c.isGoodAnchor(e) { - c.warn("dangling or redundant ^, maybe \\^ is intended?") + c.warnf("dangling or redundant ^, maybe \\^ is intended?") } default: @@ -176,11 +176,11 @@ func (c *badRegexpChecker) updateFlagState(state *regexpFlagState, e syntax.Expr if clearing { if !state[ch] { - c.warn("clearing unset flag %c in %s", ch, e.Value) + c.warnf("clearing unset flag %c in %s", ch, e.Value) } } else { if state[ch] { - c.warn("redundant flag %c in %s", ch, e.Value) + c.warnf("redundant flag %c in %s", ch, e.Value) } } state[ch] = !clearing @@ -198,7 +198,7 @@ func (c *badRegexpChecker) checkNestedQuantifier(e syntax.Expr) { switch x.Op { case syntax.OpPlus, syntax.OpStar: - c.warn("repeated greedy quantifier in %s", e.Value) + c.warnf("repeated greedy quantifier in %s", e.Value) } } @@ -208,7 +208,7 @@ func (c *badRegexpChecker) checkAltDups(alt syntax.Expr) { set := make(map[string]struct{}, len(alt.Args)) for _, a := range alt.Args { if _, ok := set[a.Value]; ok { - c.warn("`%s` is duplicated in %s", a.Value, alt.Value) + c.warnf("`%s` is duplicated in %s", a.Value, alt.Value) } set[a.Value] = struct{}{} } @@ -232,7 +232,7 @@ func (c *badRegexpChecker) checkAltAnchor(alt syntax.Expr) { } } if matched { - c.warn("^ applied only to `%s` in %s", first.Value[len(`^`):], alt.Value) + c.warnf("^ applied only to `%s` in %s", first.Value[len(`^`):], alt.Value) } } @@ -247,7 +247,7 @@ func (c *badRegexpChecker) checkAltAnchor(alt syntax.Expr) { } } if matched { - c.warn("$ applied only to `%s` in %s", last.Value[:len(last.Value)-len(`$`)], alt.Value) + c.warnf("$ applied only to `%s` in %s", last.Value[:len(last.Value)-len(`$`)], alt.Value) } } } @@ -429,7 +429,7 @@ func (c *badRegexpChecker) isGoodAnchor(e syntax.Expr) bool { return false } -func (c *badRegexpChecker) warn(format string, args ...interface{}) { +func (c *badRegexpChecker) warnf(format string, args ...interface{}) { c.ctx.Warn(c.cause, format, args...) } diff --git a/vendor/github.com/go-critic/go-critic/checkers/checkers.go b/vendor/github.com/go-critic/go-critic/checkers/checkers.go index 5797dafdf..751c71501 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/checkers.go +++ b/vendor/github.com/go-critic/go-critic/checkers/checkers.go @@ -1,4 +1,4 @@ -// Package checkers is a gocritic linter main checkers collection. +// Package checkers is a go-critic linter main checkers collection. package checkers import ( diff --git a/vendor/github.com/go-critic/go-critic/checkers/commentedOutCode_checker.go b/vendor/github.com/go-critic/go-critic/checkers/commentedOutCode_checker.go index 8595b7951..788355d7f 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/commentedOutCode_checker.go +++ b/vendor/github.com/go-critic/go-critic/checkers/commentedOutCode_checker.go @@ -93,6 +93,10 @@ func (c *commentedOutCodeChecker) VisitLocalComment(cg *ast.CommentGroup) { return } + if c.isExampleOutputComment(s) { + return + } + stmt := strparse.Stmt(s) if c.isPermittedStmt(stmt) { @@ -109,11 +113,6 @@ func (c *commentedOutCodeChecker) VisitLocalComment(cg *ast.CommentGroup) { return } - // Some attempts to avoid false positives. - if c.skipBlock(s) { - return - } - // Add braces to make block statement from // multiple statements. stmt = strparse.Stmt(fmt.Sprintf("{ %s }", s)) @@ -123,15 +122,18 @@ func (c *commentedOutCodeChecker) VisitLocalComment(cg *ast.CommentGroup) { } } -func (c *commentedOutCodeChecker) skipBlock(s string) bool { - lines := strings.Split(s, "\n") // There is at least 1 line, that's invariant - - // Special example test block. - if isExampleTestFunc(c.fn) && strings.Contains(lines[0], "Output:") { - return true - } - - return false +// An example output comment can be one of the following: +// +// Output: some output +// +// or +// +// Output: +// some output +// +// See https://go.dev/blog/examples +func (c *commentedOutCodeChecker) isExampleOutputComment(s string) bool { + return isExampleTestFunc(c.fn) && strings.Contains(s, "Output:") } func (c *commentedOutCodeChecker) isPermittedStmt(stmt ast.Stmt) bool { diff --git a/vendor/github.com/go-critic/go-critic/checkers/deprecatedComment_checker.go b/vendor/github.com/go-critic/go-critic/checkers/deprecatedComment_checker.go index c61d773da..bb41d478e 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/deprecatedComment_checker.go +++ b/vendor/github.com/go-critic/go-critic/checkers/deprecatedComment_checker.go @@ -8,6 +8,8 @@ import ( "github.com/go-critic/go-critic/linter" ) +const deprecatedPrefix = "Deprecated: " + func init() { var info linter.CheckerInfo info.Name = "deprecatedComment" @@ -91,20 +93,25 @@ func (c *deprecatedCommentChecker) VisitDocComment(doc *ast.CommentGroup) { // // TODO(quasilyte): there are also multi-line deprecation comments. + // prev stores the previous line after it was trimmed. + // It's used to check whether the deprecation prefix is at the beginning of a new paragraph. + var prev string + for _, comment := range doc.List { if strings.HasPrefix(comment.Text, "/*") { // TODO(quasilyte): handle multi-line doc comments. continue } - l := comment.Text[len("//"):] - if len(l) < len("Deprecated: ") { + rawLine := strings.TrimPrefix(comment.Text, "//") + l := strings.TrimSpace(rawLine) + if len(rawLine) < len(deprecatedPrefix) { + prev = l continue } - l = strings.TrimSpace(l) // Check whether someone messed up with a prefix casing. upcase := strings.ToUpper(l) - if strings.HasPrefix(upcase, "DEPRECATED: ") && !strings.HasPrefix(l, "Deprecated: ") { + if strings.HasPrefix(upcase, "DEPRECATED: ") && !strings.HasPrefix(l, deprecatedPrefix) { c.warnCasing(comment, l) return } @@ -134,6 +141,12 @@ func (c *deprecatedCommentChecker) VisitDocComment(doc *ast.CommentGroup) { return } } + + if strings.HasPrefix(l, deprecatedPrefix) && prev != "" { + c.warnParagraph(comment) + return + } + prev = l } } @@ -154,3 +167,7 @@ func (c *deprecatedCommentChecker) warnTypo(cause ast.Node, line string) { word := strings.Split(line, ":")[0] c.ctx.Warn(cause, "typo in `%s`; should be `Deprecated`", word) } + +func (c *deprecatedCommentChecker) warnParagraph(cause ast.Node) { + c.ctx.Warn(cause, "`Deprecated: ` notices should be in a dedicated paragraph, separated from the rest") +} diff --git a/vendor/github.com/go-critic/go-critic/checkers/dupOption_checker.go b/vendor/github.com/go-critic/go-critic/checkers/dupOption_checker.go new file mode 100644 index 000000000..5e7eeda16 --- /dev/null +++ b/vendor/github.com/go-critic/go-critic/checkers/dupOption_checker.go @@ -0,0 +1,118 @@ +package checkers + +import ( + "go/ast" + "go/token" + "go/types" + + "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/linter" + "github.com/go-toolsmith/astcast" + "github.com/go-toolsmith/astfmt" +) + +func init() { + var info linter.CheckerInfo + info.Name = "dupOption" + info.Tags = []string{linter.DiagnosticTag, linter.ExperimentalTag} + info.Summary = "Detects duplicated option function arguments in variadic function calls" + info.Before = `doSomething(name, + withWidth(w), + withHeight(h), + withWidth(w), +)` + info.After = `doSomething(name, + withWidth(w), + withHeight(h), +)` + + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + c := &dupOptionChecker{ctx: ctx} + return astwalk.WalkerForExpr(c), nil + }) +} + +type dupOptionChecker struct { + astwalk.WalkHandler + ctx *linter.CheckerContext +} + +func (c *dupOptionChecker) VisitExpr(expr ast.Expr) { + call := astcast.ToCallExpr(expr) + variadicArgs, argType := c.getVariadicArgs(call) + if len(variadicArgs) == 0 { + return + } + + if !c.isOptionType(argType) { + return + } + + dupArgs := c.findDupArgs(variadicArgs) + for _, arg := range dupArgs { + c.warn(arg) + } +} + +func (c *dupOptionChecker) getVariadicArgs(call *ast.CallExpr) ([]ast.Expr, types.Type) { + if len(call.Args) == 0 { + return nil, nil + } + + // skip for someFunc(a, b ...) + if call.Ellipsis != token.NoPos { + return nil, nil + } + + funType := c.ctx.TypeOf(call.Fun) + sign, ok := funType.(*types.Signature) + if !ok || !sign.Variadic() { + return nil, nil + } + + last := sign.Params().Len() - 1 + sliceType, ok := sign.Params().At(last).Type().(*types.Slice) + if !ok { + return nil, nil + } + + if last > len(call.Args) { + return nil, nil + } + + argType := sliceType.Elem() + return call.Args[last:], argType +} + +func (c *dupOptionChecker) isOptionType(typeInfo types.Type) bool { + typeInfo = typeInfo.Underlying() + + sign, ok := typeInfo.(*types.Signature) + if !ok { + return false + } + + if sign.Params().Len() == 0 { + return false + } + + return true +} + +func (c *dupOptionChecker) findDupArgs(args []ast.Expr) []ast.Expr { + codeMap := make(map[string]bool) + dupArgs := make([]ast.Expr, 0) + for _, arg := range args { + code := astfmt.Sprint(arg) + if codeMap[code] { + dupArgs = append(dupArgs, arg) + continue + } + codeMap[code] = true + } + return dupArgs +} + +func (c *dupOptionChecker) warn(arg ast.Node) { + c.ctx.Warn(arg, "function argument `%s` is duplicated", arg) +} diff --git a/vendor/github.com/go-critic/go-critic/checkers/embedded_rules.go b/vendor/github.com/go-critic/go-critic/checkers/embedded_rules.go index ad507425e..0d448399e 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/embedded_rules.go +++ b/vendor/github.com/go-critic/go-critic/checkers/embedded_rules.go @@ -6,6 +6,7 @@ import ( "go/build" "go/token" "os" + "sync" "github.com/go-critic/go-critic/checkers/rulesdata" "github.com/go-critic/go-critic/linter" @@ -15,6 +16,42 @@ import ( //go:generate go run ./rules/precompile.go -rules ./rules/rules.go -o ./rulesdata/rulesdata.go +// cachedEngine holds a pre-initialized ruleguard engine for a specific rule group. +// The engine is created once and reused for all checker instances. +type cachedEngine struct { + engine *ruleguard.Engine + once sync.Once + err error + + // Configuration needed to create the engine + fset *token.FileSet + buildContext *build.Context + groupName string + debug bool +} + +func (ce *cachedEngine) get() (*ruleguard.Engine, error) { + ce.once.Do(func() { + parseContext := &ruleguard.LoadContext{ + Fset: ce.fset, + GroupFilter: func(gr *ruleguard.GoRuleGroup) bool { + return gr.Name == ce.groupName + }, + DebugImports: ce.debug, + DebugPrint: func(s string) { + fmt.Println("debug:", s) + }, + } + engine := ruleguard.NewEngine() + engine.BuildContext = ce.buildContext + ce.err = engine.LoadFromIR(parseContext, "rules/rules.go", rulesdata.PrecompiledRules) + if ce.err == nil { + ce.engine = engine + } + }) + return ce.engine, ce.err +} + func InitEmbeddedRules() error { filename := "rules/rules.go" @@ -49,8 +86,8 @@ func InitEmbeddedRules() error { groups = rootEngine.LoadedGroups() } - // For every rules group we create a new checker and a separate engine. - // That dedicated ruleguard engine will contain rules only from one group. + // For every rules group we create a cached engine holder. + // The engine will be created lazily on first use and then reused. for i := range groups { g := groups[i] info := &linter.CheckerInfo{ @@ -63,20 +100,17 @@ func InitEmbeddedRules() error { EmbeddedRuleguard: true, } + + // Create a cached engine for this rule group + cache := &cachedEngine{ + fset: fset, + buildContext: buildContext, + groupName: g.Name, + debug: ruleguardDebug, + } + collection.AddChecker(info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { - parseContext := &ruleguard.LoadContext{ - Fset: fset, - GroupFilter: func(gr *ruleguard.GoRuleGroup) bool { - return gr.Name == g.Name - }, - DebugImports: ruleguardDebug, - DebugPrint: func(s string) { - fmt.Println("debug:", s) - }, - } - engine := ruleguard.NewEngine() - engine.BuildContext = buildContext - err := engine.LoadFromIR(parseContext, filename, rulesdata.PrecompiledRules) + engine, err := cache.get() if err != nil { return nil, err } diff --git a/vendor/github.com/go-critic/go-critic/checkers/exitAfterDefer_checker.go b/vendor/github.com/go-critic/go-critic/checkers/exitAfterDefer_checker.go index 9889f48e8..19b20e425 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/exitAfterDefer_checker.go +++ b/vendor/github.com/go-critic/go-critic/checkers/exitAfterDefer_checker.go @@ -45,6 +45,12 @@ func (c *exitAfterDeferChecker) VisitFuncDecl(fn *ast.FuncDecl) { var deferStmt *ast.DeferStmt pre := func(cur *astutil.Cursor) bool { + // If we found a defer statement in the function post traversal. + // and are looking at the Else branch during a pre traversal, stop seeking as it could be false positive. + if deferStmt != nil && cur.Name() == "Else" { + return false + } + // Don't recurse into local anonymous functions. return !astp.IsFuncLit(cur.Node()) } diff --git a/vendor/github.com/go-critic/go-critic/checkers/hugeParam_checker.go b/vendor/github.com/go-critic/go-critic/checkers/hugeParam_checker.go index 7b7a3c538..170c3f417 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/hugeParam_checker.go +++ b/vendor/github.com/go-critic/go-critic/checkers/hugeParam_checker.go @@ -57,6 +57,7 @@ func (*hugeParamChecker) isImplementStringer(decl *ast.FuncDecl) bool { decl.Name.Name == "String" && decl.Type != nil && len(decl.Type.Params.List) == 0 && + decl.Type.Results != nil && len(decl.Type.Results.List) == 1 && astcast.ToIdent(decl.Type.Results.List[0].Type).Name == "string" { return true diff --git a/vendor/github.com/go-critic/go-critic/checkers/rulesdata/rulesdata.go b/vendor/github.com/go-critic/go-critic/checkers/rulesdata/rulesdata.go index 4ab31076f..664145858 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/rulesdata/rulesdata.go +++ b/vendor/github.com/go-critic/go-critic/checkers/rulesdata/rulesdata.go @@ -1391,48 +1391,53 @@ var PrecompiledRules = &ir.File{ Line: 384, SyntaxPatterns: []ir.PatternString{ {Line: 384, Value: "copy($x, $x)"}, - {Line: 385, Value: "math.Max($x, $x)"}, - {Line: 386, Value: "math.Min($x, $x)"}, - {Line: 387, Value: "reflect.Copy($x, $x)"}, - {Line: 388, Value: "reflect.DeepEqual($x, $x)"}, - {Line: 389, Value: "strings.Contains($x, $x)"}, - {Line: 390, Value: "strings.Compare($x, $x)"}, - {Line: 391, Value: "strings.EqualFold($x, $x)"}, - {Line: 392, Value: "strings.HasPrefix($x, $x)"}, - {Line: 393, Value: "strings.HasSuffix($x, $x)"}, - {Line: 394, Value: "strings.Index($x, $x)"}, - {Line: 395, Value: "strings.LastIndex($x, $x)"}, - {Line: 396, Value: "strings.Split($x, $x)"}, - {Line: 397, Value: "strings.SplitAfter($x, $x)"}, - {Line: 398, Value: "strings.SplitAfterN($x, $x, $_)"}, - {Line: 399, Value: "strings.SplitN($x, $x, $_)"}, - {Line: 400, Value: "strings.Replace($_, $x, $x, $_)"}, - {Line: 401, Value: "strings.ReplaceAll($_, $x, $x)"}, - {Line: 402, Value: "bytes.Contains($x, $x)"}, - {Line: 403, Value: "bytes.Compare($x, $x)"}, - {Line: 404, Value: "bytes.Equal($x, $x)"}, - {Line: 405, Value: "bytes.EqualFold($x, $x)"}, - {Line: 406, Value: "bytes.HasPrefix($x, $x)"}, - {Line: 407, Value: "bytes.HasSuffix($x, $x)"}, - {Line: 408, Value: "bytes.Index($x, $x)"}, - {Line: 409, Value: "bytes.LastIndex($x, $x)"}, - {Line: 410, Value: "bytes.Split($x, $x)"}, - {Line: 411, Value: "bytes.SplitAfter($x, $x)"}, - {Line: 412, Value: "bytes.SplitAfterN($x, $x, $_)"}, - {Line: 413, Value: "bytes.SplitN($x, $x, $_)"}, - {Line: 414, Value: "bytes.Replace($_, $x, $x, $_)"}, - {Line: 415, Value: "bytes.ReplaceAll($_, $x, $x)"}, - {Line: 416, Value: "types.Identical($x, $x)"}, - {Line: 417, Value: "types.IdenticalIgnoreTags($x, $x)"}, - {Line: 418, Value: "draw.Draw($x, $_, $x, $_, $_)"}, + {Line: 385, Value: "cmp.Compare($x, $x)"}, + {Line: 386, Value: "maps.Equal($x, $x)"}, + {Line: 387, Value: "math.Dim($x, $x)"}, + {Line: 388, Value: "math.Max($x, $x)"}, + {Line: 389, Value: "math.Min($x, $x)"}, + {Line: 390, Value: "reflect.Copy($x, $x)"}, + {Line: 391, Value: "reflect.DeepEqual($x, $x)"}, + {Line: 392, Value: "slices.Compare($x, $x)"}, + {Line: 393, Value: "slices.Equal($x, $x)"}, + {Line: 394, Value: "strings.Contains($x, $x)"}, + {Line: 395, Value: "strings.Compare($x, $x)"}, + {Line: 396, Value: "strings.EqualFold($x, $x)"}, + {Line: 397, Value: "strings.HasPrefix($x, $x)"}, + {Line: 398, Value: "strings.HasSuffix($x, $x)"}, + {Line: 399, Value: "strings.Index($x, $x)"}, + {Line: 400, Value: "strings.LastIndex($x, $x)"}, + {Line: 401, Value: "strings.Split($x, $x)"}, + {Line: 402, Value: "strings.SplitAfter($x, $x)"}, + {Line: 403, Value: "strings.SplitAfterN($x, $x, $_)"}, + {Line: 404, Value: "strings.SplitN($x, $x, $_)"}, + {Line: 405, Value: "strings.Replace($_, $x, $x, $_)"}, + {Line: 406, Value: "strings.ReplaceAll($_, $x, $x)"}, + {Line: 407, Value: "bytes.Contains($x, $x)"}, + {Line: 408, Value: "bytes.Compare($x, $x)"}, + {Line: 409, Value: "bytes.Equal($x, $x)"}, + {Line: 410, Value: "bytes.EqualFold($x, $x)"}, + {Line: 411, Value: "bytes.HasPrefix($x, $x)"}, + {Line: 412, Value: "bytes.HasSuffix($x, $x)"}, + {Line: 413, Value: "bytes.Index($x, $x)"}, + {Line: 414, Value: "bytes.LastIndex($x, $x)"}, + {Line: 415, Value: "bytes.Split($x, $x)"}, + {Line: 416, Value: "bytes.SplitAfter($x, $x)"}, + {Line: 417, Value: "bytes.SplitAfterN($x, $x, $_)"}, + {Line: 418, Value: "bytes.SplitN($x, $x, $_)"}, + {Line: 419, Value: "bytes.Replace($_, $x, $x, $_)"}, + {Line: 420, Value: "bytes.ReplaceAll($_, $x, $x)"}, + {Line: 421, Value: "types.Identical($x, $x)"}, + {Line: 422, Value: "types.IdenticalIgnoreTags($x, $x)"}, + {Line: 423, Value: "draw.Draw($x, $_, $x, $_, $_)"}, }, ReportTemplate: "suspicious duplicated args in $$", - WhereExpr: ir.FilterExpr{Line: 419, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + WhereExpr: ir.FilterExpr{Line: 424, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, }, }, { - Line: 427, + Line: 432, Name: "returnAfterHttpError", MatcherName: "m", DocTags: []string{"diagnostic", "experimental"}, @@ -1440,14 +1445,14 @@ var PrecompiledRules = &ir.File{ DocBefore: "if err != nil { http.Error(...); }", DocAfter: "if err != nil { http.Error(...); return; }", Rules: []ir.Rule{{ - Line: 428, - SyntaxPatterns: []ir.PatternString{{Line: 428, Value: "if $_ { $*_; http.Error($w, $err, $code) }"}}, + Line: 433, + SyntaxPatterns: []ir.PatternString{{Line: 433, Value: "if $_ { $*_; http.Error($w, $err, $code) }"}}, ReportTemplate: "Possibly return is missed after the http.Error call", LocationVar: "w", }}, }, { - Line: 437, + Line: 442, Name: "preferFilepathJoin", MatcherName: "m", DocTags: []string{"style", "experimental"}, @@ -1455,35 +1460,35 @@ var PrecompiledRules = &ir.File{ DocBefore: "x + string(os.PathSeparator) + y", DocAfter: "filepath.Join(x, y)", Rules: []ir.Rule{{ - Line: 438, - SyntaxPatterns: []ir.PatternString{{Line: 438, Value: "$x + string(os.PathSeparator) + $y"}}, + Line: 443, + SyntaxPatterns: []ir.PatternString{{Line: 443, Value: "$x + string(os.PathSeparator) + $y"}}, ReportTemplate: "filepath.Join($x, $y) should be preferred to the $$", SuggestTemplate: "filepath.Join($x, $y)", WhereExpr: ir.FilterExpr{ - Line: 439, + Line: 444, Op: ir.FilterAndOp, Src: "m[\"x\"].Type.Is(`string`) && m[\"y\"].Type.Is(`string`)", Args: []ir.FilterExpr{ { - Line: 439, + Line: 444, Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`string`)", Value: "x", - Args: []ir.FilterExpr{{Line: 439, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, + Args: []ir.FilterExpr{{Line: 444, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, }, { - Line: 439, + Line: 444, Op: ir.FilterVarTypeIsOp, Src: "m[\"y\"].Type.Is(`string`)", Value: "y", - Args: []ir.FilterExpr{{Line: 439, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, + Args: []ir.FilterExpr{{Line: 444, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, }, }, }, }}, }, { - Line: 448, + Line: 453, Name: "preferStringWriter", MatcherName: "m", DocTags: []string{"performance", "experimental"}, @@ -1492,35 +1497,35 @@ var PrecompiledRules = &ir.File{ DocAfter: "w.WriteString(\"foo\")", Rules: []ir.Rule{ { - Line: 449, - SyntaxPatterns: []ir.PatternString{{Line: 449, Value: "$w.Write([]byte($s))"}}, + Line: 454, + SyntaxPatterns: []ir.PatternString{{Line: 454, Value: "$w.Write([]byte($s))"}}, ReportTemplate: "$w.WriteString($s) should be preferred to the $$", SuggestTemplate: "$w.WriteString($s)", WhereExpr: ir.FilterExpr{ - Line: 450, + Line: 455, Op: ir.FilterVarTypeImplementsOp, Src: "m[\"w\"].Type.Implements(\"io.StringWriter\")", Value: "w", - Args: []ir.FilterExpr{{Line: 450, Op: ir.FilterStringOp, Src: "\"io.StringWriter\"", Value: "io.StringWriter"}}, + Args: []ir.FilterExpr{{Line: 455, Op: ir.FilterStringOp, Src: "\"io.StringWriter\"", Value: "io.StringWriter"}}, }, }, { - Line: 454, - SyntaxPatterns: []ir.PatternString{{Line: 454, Value: "io.WriteString($w, $s)"}}, + Line: 459, + SyntaxPatterns: []ir.PatternString{{Line: 459, Value: "io.WriteString($w, $s)"}}, ReportTemplate: "$w.WriteString($s) should be preferred to the $$", SuggestTemplate: "$w.WriteString($s)", WhereExpr: ir.FilterExpr{ - Line: 455, + Line: 460, Op: ir.FilterVarTypeImplementsOp, Src: "m[\"w\"].Type.Implements(\"io.StringWriter\")", Value: "w", - Args: []ir.FilterExpr{{Line: 455, Op: ir.FilterStringOp, Src: "\"io.StringWriter\"", Value: "io.StringWriter"}}, + Args: []ir.FilterExpr{{Line: 460, Op: ir.FilterStringOp, Src: "\"io.StringWriter\"", Value: "io.StringWriter"}}, }, }, }, }, { - Line: 464, + Line: 469, Name: "sliceClear", MatcherName: "m", DocTags: []string{"performance", "experimental"}, @@ -1528,22 +1533,22 @@ var PrecompiledRules = &ir.File{ DocBefore: "for i := 0; i < len(buf); i++ { buf[i] = 0 }", DocAfter: "for i := range buf { buf[i] = 0 }", Rules: []ir.Rule{{ - Line: 465, - SyntaxPatterns: []ir.PatternString{{Line: 465, Value: "for $i := 0; $i < len($xs); $i++ { $xs[$i] = $zero }"}}, + Line: 470, + SyntaxPatterns: []ir.PatternString{{Line: 470, Value: "for $i := 0; $i < len($xs); $i++ { $xs[$i] = $zero }"}}, ReportTemplate: "rewrite as for-range so compiler can recognize this pattern", WhereExpr: ir.FilterExpr{ - Line: 466, + Line: 471, Op: ir.FilterEqOp, Src: "m[\"zero\"].Value.Int() == 0", Args: []ir.FilterExpr{ { - Line: 466, + Line: 471, Op: ir.FilterVarValueIntOp, Src: "m[\"zero\"].Value.Int()", Value: "zero", }, { - Line: 466, + Line: 471, Op: ir.FilterIntOp, Src: "0", Value: int64(0), @@ -1553,7 +1558,7 @@ var PrecompiledRules = &ir.File{ }}, }, { - Line: 474, + Line: 479, Name: "syncMapLoadAndDelete", MatcherName: "m", DocTags: []string{"diagnostic", "experimental"}, @@ -1561,33 +1566,33 @@ var PrecompiledRules = &ir.File{ DocBefore: "v, ok := m.Load(k); if ok { m.Delete($k); f(v); }", DocAfter: "v, deleted := m.LoadAndDelete(k); if deleted { f(v) }", Rules: []ir.Rule{{ - Line: 475, - SyntaxPatterns: []ir.PatternString{{Line: 475, Value: "$_, $ok := $m.Load($k); if $ok { $m.Delete($k); $*_ }"}}, + Line: 480, + SyntaxPatterns: []ir.PatternString{{Line: 480, Value: "$_, $ok := $m.Load($k); if $ok { $m.Delete($k); $*_ }"}}, ReportTemplate: "use $m.LoadAndDelete to perform load+delete operations atomically", WhereExpr: ir.FilterExpr{ - Line: 476, + Line: 481, Op: ir.FilterAndOp, Src: "m.GoVersion().GreaterEqThan(\"1.15\") &&\n\tm[\"m\"].Type.Is(`*sync.Map`)", Args: []ir.FilterExpr{ { - Line: 476, + Line: 481, Op: ir.FilterGoVersionGreaterEqThanOp, Src: "m.GoVersion().GreaterEqThan(\"1.15\")", Value: "1.15", }, { - Line: 477, + Line: 482, Op: ir.FilterVarTypeIsOp, Src: "m[\"m\"].Type.Is(`*sync.Map`)", Value: "m", - Args: []ir.FilterExpr{{Line: 477, Op: ir.FilterStringOp, Src: "`*sync.Map`", Value: "*sync.Map"}}, + Args: []ir.FilterExpr{{Line: 482, Op: ir.FilterStringOp, Src: "`*sync.Map`", Value: "*sync.Map"}}, }, }, }, }}, }, { - Line: 485, + Line: 490, Name: "sprintfQuotedString", MatcherName: "m", DocTags: []string{"diagnostic", "experimental"}, @@ -1595,34 +1600,34 @@ var PrecompiledRules = &ir.File{ DocBefore: "fmt.Sprintf(`\"%s\"`, s)", DocAfter: "fmt.Sprintf(`%q`, s)", Rules: []ir.Rule{{ - Line: 486, - SyntaxPatterns: []ir.PatternString{{Line: 486, Value: "fmt.Sprintf($s, $*_)"}}, + Line: 491, + SyntaxPatterns: []ir.PatternString{{Line: 491, Value: "fmt.Sprintf($s, $*_)"}}, ReportTemplate: "use %q instead of \"%s\" for quoted strings", WhereExpr: ir.FilterExpr{ - Line: 487, + Line: 492, Op: ir.FilterOrOp, Src: "m[\"s\"].Text.Matches(\"^`.*\\\"%s\\\".*`$\") ||\n\tm[\"s\"].Text.Matches(`^\".*\\\\\"%s\\\\\".*\"$`)", Args: []ir.FilterExpr{ { - Line: 487, + Line: 492, Op: ir.FilterVarTextMatchesOp, Src: "m[\"s\"].Text.Matches(\"^`.*\\\"%s\\\".*`$\")", Value: "s", - Args: []ir.FilterExpr{{Line: 487, Op: ir.FilterStringOp, Src: "\"^`.*\\\"%s\\\".*`$\"", Value: "^`.*\"%s\".*`$"}}, + Args: []ir.FilterExpr{{Line: 492, Op: ir.FilterStringOp, Src: "\"^`.*\\\"%s\\\".*`$\"", Value: "^`.*\"%s\".*`$"}}, }, { - Line: 488, + Line: 493, Op: ir.FilterVarTextMatchesOp, Src: "m[\"s\"].Text.Matches(`^\".*\\\\\"%s\\\\\".*\"$`)", Value: "s", - Args: []ir.FilterExpr{{Line: 488, Op: ir.FilterStringOp, Src: "`^\".*\\\\\"%s\\\\\".*\"$`", Value: "^\".*\\\\\"%s\\\\\".*\"$"}}, + Args: []ir.FilterExpr{{Line: 493, Op: ir.FilterStringOp, Src: "`^\".*\\\\\"%s\\\\\".*\"$`", Value: "^\".*\\\\\"%s\\\\\".*\"$"}}, }, }, }, }}, }, { - Line: 496, + Line: 501, Name: "offBy1", MatcherName: "m", DocTags: []string{"diagnostic"}, @@ -1631,80 +1636,80 @@ var PrecompiledRules = &ir.File{ DocAfter: "xs[len(xs)-1]", Rules: []ir.Rule{ { - Line: 497, - SyntaxPatterns: []ir.PatternString{{Line: 497, Value: "$x[len($x)]"}}, + Line: 502, + SyntaxPatterns: []ir.PatternString{{Line: 502, Value: "$x[len($x)]"}}, ReportTemplate: "index expr always panics; maybe you wanted $x[len($x)-1]?", SuggestTemplate: "$x[len($x)-1]", WhereExpr: ir.FilterExpr{ - Line: 498, + Line: 503, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"x\"].Type.Is(`[]$_`)", Args: []ir.FilterExpr{ - {Line: 498, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + {Line: 503, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, { - Line: 498, + Line: 503, Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`[]$_`)", Value: "x", - Args: []ir.FilterExpr{{Line: 498, Op: ir.FilterStringOp, Src: "`[]$_`", Value: "[]$_"}}, + Args: []ir.FilterExpr{{Line: 503, Op: ir.FilterStringOp, Src: "`[]$_`", Value: "[]$_"}}, }, }, }, }, { - Line: 505, + Line: 510, SyntaxPatterns: []ir.PatternString{ - {Line: 506, Value: "$i := strings.Index($s, $_); $_ := $slicing[$i:]"}, - {Line: 507, Value: "$i := strings.Index($s, $_); $_ = $slicing[$i:]"}, - {Line: 508, Value: "$i := bytes.Index($s, $_); $_ := $slicing[$i:]"}, - {Line: 509, Value: "$i := bytes.Index($s, $_); $_ = $slicing[$i:]"}, + {Line: 511, Value: "$i := strings.Index($s, $_); $_ := $slicing[$i:]"}, + {Line: 512, Value: "$i := strings.Index($s, $_); $_ = $slicing[$i:]"}, + {Line: 513, Value: "$i := bytes.Index($s, $_); $_ := $slicing[$i:]"}, + {Line: 514, Value: "$i := bytes.Index($s, $_); $_ = $slicing[$i:]"}, }, ReportTemplate: "Index() can return -1; maybe you wanted to do $s[$i+1:]", WhereExpr: ir.FilterExpr{ - Line: 510, + Line: 515, Op: ir.FilterEqOp, Src: "m[\"s\"].Text == m[\"slicing\"].Text", Args: []ir.FilterExpr{ - {Line: 510, Op: ir.FilterVarTextOp, Src: "m[\"s\"].Text", Value: "s"}, - {Line: 510, Op: ir.FilterVarTextOp, Src: "m[\"slicing\"].Text", Value: "slicing"}, + {Line: 515, Op: ir.FilterVarTextOp, Src: "m[\"s\"].Text", Value: "s"}, + {Line: 515, Op: ir.FilterVarTextOp, Src: "m[\"slicing\"].Text", Value: "slicing"}, }, }, LocationVar: "slicing", }, { - Line: 514, + Line: 519, SyntaxPatterns: []ir.PatternString{ - {Line: 515, Value: "$i := strings.Index($s, $_); $_ := $slicing[:$i]"}, - {Line: 516, Value: "$i := strings.Index($s, $_); $_ = $slicing[:$i]"}, - {Line: 517, Value: "$i := bytes.Index($s, $_); $_ := $slicing[:$i]"}, - {Line: 518, Value: "$i := bytes.Index($s, $_); $_ = $slicing[:$i]"}, + {Line: 520, Value: "$i := strings.Index($s, $_); $_ := $slicing[:$i]"}, + {Line: 521, Value: "$i := strings.Index($s, $_); $_ = $slicing[:$i]"}, + {Line: 522, Value: "$i := bytes.Index($s, $_); $_ := $slicing[:$i]"}, + {Line: 523, Value: "$i := bytes.Index($s, $_); $_ = $slicing[:$i]"}, }, ReportTemplate: "Index() can return -1; maybe you wanted to do $s[:$i+1]", WhereExpr: ir.FilterExpr{ - Line: 519, + Line: 524, Op: ir.FilterEqOp, Src: "m[\"s\"].Text == m[\"slicing\"].Text", Args: []ir.FilterExpr{ - {Line: 519, Op: ir.FilterVarTextOp, Src: "m[\"s\"].Text", Value: "s"}, - {Line: 519, Op: ir.FilterVarTextOp, Src: "m[\"slicing\"].Text", Value: "slicing"}, + {Line: 524, Op: ir.FilterVarTextOp, Src: "m[\"s\"].Text", Value: "s"}, + {Line: 524, Op: ir.FilterVarTextOp, Src: "m[\"slicing\"].Text", Value: "slicing"}, }, }, LocationVar: "slicing", }, { - Line: 523, + Line: 528, SyntaxPatterns: []ir.PatternString{ - {Line: 524, Value: "$s[strings.Index($s, $_):]"}, - {Line: 525, Value: "$s[:strings.Index($s, $_)]"}, - {Line: 526, Value: "$s[bytes.Index($s, $_):]"}, - {Line: 527, Value: "$s[:bytes.Index($s, $_)]"}, + {Line: 529, Value: "$s[strings.Index($s, $_):]"}, + {Line: 530, Value: "$s[:strings.Index($s, $_)]"}, + {Line: 531, Value: "$s[bytes.Index($s, $_):]"}, + {Line: 532, Value: "$s[:bytes.Index($s, $_)]"}, }, ReportTemplate: "Index() can return -1; maybe you wanted to do Index()+1", }, }, }, { - Line: 535, + Line: 540, Name: "unslice", MatcherName: "m", DocTags: []string{"style"}, @@ -1712,35 +1717,35 @@ var PrecompiledRules = &ir.File{ DocBefore: "copy(b[:], values...)", DocAfter: "copy(b, values...)", Rules: []ir.Rule{{ - Line: 536, - SyntaxPatterns: []ir.PatternString{{Line: 536, Value: "$s[:]"}}, + Line: 541, + SyntaxPatterns: []ir.PatternString{{Line: 541, Value: "$s[:]"}}, ReportTemplate: "could simplify $$ to $s", SuggestTemplate: "$s", WhereExpr: ir.FilterExpr{ - Line: 537, + Line: 542, Op: ir.FilterOrOp, Src: "m[\"s\"].Type.Is(`string`) || m[\"s\"].Type.Is(`[]$_`)", Args: []ir.FilterExpr{ { - Line: 537, + Line: 542, Op: ir.FilterVarTypeIsOp, Src: "m[\"s\"].Type.Is(`string`)", Value: "s", - Args: []ir.FilterExpr{{Line: 537, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, + Args: []ir.FilterExpr{{Line: 542, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, }, { - Line: 537, + Line: 542, Op: ir.FilterVarTypeIsOp, Src: "m[\"s\"].Type.Is(`[]$_`)", Value: "s", - Args: []ir.FilterExpr{{Line: 537, Op: ir.FilterStringOp, Src: "`[]$_`", Value: "[]$_"}}, + Args: []ir.FilterExpr{{Line: 542, Op: ir.FilterStringOp, Src: "`[]$_`", Value: "[]$_"}}, }, }, }, }}, }, { - Line: 546, + Line: 551, Name: "yodaStyleExpr", MatcherName: "m", DocTags: []string{"style", "experimental"}, @@ -1749,105 +1754,105 @@ var PrecompiledRules = &ir.File{ DocAfter: "return ptr != nil", Rules: []ir.Rule{ { - Line: 547, - SyntaxPatterns: []ir.PatternString{{Line: 547, Value: "$constval != $x"}}, + Line: 552, + SyntaxPatterns: []ir.PatternString{{Line: 552, Value: "$constval != $x"}}, ReportTemplate: "consider to change order in expression to $x != $constval", WhereExpr: ir.FilterExpr{ - Line: 547, + Line: 552, Op: ir.FilterAndOp, Src: "m[\"constval\"].Node.Is(`BasicLit`) && !m[\"x\"].Node.Is(`BasicLit`)", Args: []ir.FilterExpr{ { - Line: 547, + Line: 552, Op: ir.FilterVarNodeIsOp, Src: "m[\"constval\"].Node.Is(`BasicLit`)", Value: "constval", - Args: []ir.FilterExpr{{Line: 547, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, + Args: []ir.FilterExpr{{Line: 552, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, }, { - Line: 547, + Line: 552, Op: ir.FilterNotOp, Src: "!m[\"x\"].Node.Is(`BasicLit`)", Args: []ir.FilterExpr{{ - Line: 547, + Line: 552, Op: ir.FilterVarNodeIsOp, Src: "m[\"x\"].Node.Is(`BasicLit`)", Value: "x", - Args: []ir.FilterExpr{{Line: 547, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, + Args: []ir.FilterExpr{{Line: 552, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, }}, }, }, }, }, { - Line: 549, - SyntaxPatterns: []ir.PatternString{{Line: 549, Value: "$constval == $x"}}, + Line: 554, + SyntaxPatterns: []ir.PatternString{{Line: 554, Value: "$constval == $x"}}, ReportTemplate: "consider to change order in expression to $x == $constval", WhereExpr: ir.FilterExpr{ - Line: 549, + Line: 554, Op: ir.FilterAndOp, Src: "m[\"constval\"].Node.Is(`BasicLit`) && !m[\"x\"].Node.Is(`BasicLit`)", Args: []ir.FilterExpr{ { - Line: 549, + Line: 554, Op: ir.FilterVarNodeIsOp, Src: "m[\"constval\"].Node.Is(`BasicLit`)", Value: "constval", - Args: []ir.FilterExpr{{Line: 549, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, + Args: []ir.FilterExpr{{Line: 554, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, }, { - Line: 549, + Line: 554, Op: ir.FilterNotOp, Src: "!m[\"x\"].Node.Is(`BasicLit`)", Args: []ir.FilterExpr{{ - Line: 549, + Line: 554, Op: ir.FilterVarNodeIsOp, Src: "m[\"x\"].Node.Is(`BasicLit`)", Value: "x", - Args: []ir.FilterExpr{{Line: 549, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, + Args: []ir.FilterExpr{{Line: 554, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, }}, }, }, }, }, { - Line: 552, - SyntaxPatterns: []ir.PatternString{{Line: 552, Value: "nil != $x"}}, + Line: 557, + SyntaxPatterns: []ir.PatternString{{Line: 557, Value: "nil != $x"}}, ReportTemplate: "consider to change order in expression to $x != nil", WhereExpr: ir.FilterExpr{ - Line: 552, + Line: 557, Op: ir.FilterNotOp, Src: "!m[\"x\"].Node.Is(`BasicLit`)", Args: []ir.FilterExpr{{ - Line: 552, + Line: 557, Op: ir.FilterVarNodeIsOp, Src: "m[\"x\"].Node.Is(`BasicLit`)", Value: "x", - Args: []ir.FilterExpr{{Line: 552, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, + Args: []ir.FilterExpr{{Line: 557, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, }}, }, }, { - Line: 554, - SyntaxPatterns: []ir.PatternString{{Line: 554, Value: "nil == $x"}}, + Line: 559, + SyntaxPatterns: []ir.PatternString{{Line: 559, Value: "nil == $x"}}, ReportTemplate: "consider to change order in expression to $x == nil", WhereExpr: ir.FilterExpr{ - Line: 554, + Line: 559, Op: ir.FilterNotOp, Src: "!m[\"x\"].Node.Is(`BasicLit`)", Args: []ir.FilterExpr{{ - Line: 554, + Line: 559, Op: ir.FilterVarNodeIsOp, Src: "m[\"x\"].Node.Is(`BasicLit`)", Value: "x", - Args: []ir.FilterExpr{{Line: 554, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, + Args: []ir.FilterExpr{{Line: 559, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, }}, }, }, }, }, { - Line: 562, + Line: 567, Name: "equalFold", MatcherName: "m", DocTags: []string{"performance", "experimental"}, @@ -1856,114 +1861,114 @@ var PrecompiledRules = &ir.File{ DocAfter: "strings.EqualFold(x, y)", Rules: []ir.Rule{ { - Line: 571, + Line: 576, SyntaxPatterns: []ir.PatternString{ - {Line: 572, Value: "strings.ToLower($x) == $y"}, - {Line: 573, Value: "strings.ToLower($x) == strings.ToLower($y)"}, - {Line: 574, Value: "$x == strings.ToLower($y)"}, - {Line: 575, Value: "strings.ToUpper($x) == $y"}, - {Line: 576, Value: "strings.ToUpper($x) == strings.ToUpper($y)"}, - {Line: 577, Value: "$x == strings.ToUpper($y)"}, + {Line: 577, Value: "strings.ToLower($x) == $y"}, + {Line: 578, Value: "strings.ToLower($x) == strings.ToLower($y)"}, + {Line: 579, Value: "$x == strings.ToLower($y)"}, + {Line: 580, Value: "strings.ToUpper($x) == $y"}, + {Line: 581, Value: "strings.ToUpper($x) == strings.ToUpper($y)"}, + {Line: 582, Value: "$x == strings.ToUpper($y)"}, }, ReportTemplate: "consider replacing with strings.EqualFold($x, $y)", SuggestTemplate: "strings.EqualFold($x, $y)", WhereExpr: ir.FilterExpr{ - Line: 578, + Line: 583, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure && m[\"x\"].Text != m[\"y\"].Text", Args: []ir.FilterExpr{ { - Line: 578, + Line: 583, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure", Args: []ir.FilterExpr{ - {Line: 578, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, - {Line: 578, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, + {Line: 583, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + {Line: 583, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, }, }, { - Line: 578, + Line: 583, Op: ir.FilterNeqOp, Src: "m[\"x\"].Text != m[\"y\"].Text", Args: []ir.FilterExpr{ - {Line: 578, Op: ir.FilterVarTextOp, Src: "m[\"x\"].Text", Value: "x"}, - {Line: 578, Op: ir.FilterVarTextOp, Src: "m[\"y\"].Text", Value: "y"}, + {Line: 583, Op: ir.FilterVarTextOp, Src: "m[\"x\"].Text", Value: "x"}, + {Line: 583, Op: ir.FilterVarTextOp, Src: "m[\"y\"].Text", Value: "y"}, }, }, }, }, }, { - Line: 583, + Line: 588, SyntaxPatterns: []ir.PatternString{ - {Line: 584, Value: "strings.ToLower($x) != $y"}, - {Line: 585, Value: "strings.ToLower($x) != strings.ToLower($y)"}, - {Line: 586, Value: "$x != strings.ToLower($y)"}, - {Line: 587, Value: "strings.ToUpper($x) != $y"}, - {Line: 588, Value: "strings.ToUpper($x) != strings.ToUpper($y)"}, - {Line: 589, Value: "$x != strings.ToUpper($y)"}, + {Line: 589, Value: "strings.ToLower($x) != $y"}, + {Line: 590, Value: "strings.ToLower($x) != strings.ToLower($y)"}, + {Line: 591, Value: "$x != strings.ToLower($y)"}, + {Line: 592, Value: "strings.ToUpper($x) != $y"}, + {Line: 593, Value: "strings.ToUpper($x) != strings.ToUpper($y)"}, + {Line: 594, Value: "$x != strings.ToUpper($y)"}, }, ReportTemplate: "consider replacing with !strings.EqualFold($x, $y)", SuggestTemplate: "!strings.EqualFold($x, $y)", WhereExpr: ir.FilterExpr{ - Line: 590, + Line: 595, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure && m[\"x\"].Text != m[\"y\"].Text", Args: []ir.FilterExpr{ { - Line: 590, + Line: 595, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure", Args: []ir.FilterExpr{ - {Line: 590, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, - {Line: 590, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, + {Line: 595, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + {Line: 595, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, }, }, { - Line: 590, + Line: 595, Op: ir.FilterNeqOp, Src: "m[\"x\"].Text != m[\"y\"].Text", Args: []ir.FilterExpr{ - {Line: 590, Op: ir.FilterVarTextOp, Src: "m[\"x\"].Text", Value: "x"}, - {Line: 590, Op: ir.FilterVarTextOp, Src: "m[\"y\"].Text", Value: "y"}, + {Line: 595, Op: ir.FilterVarTextOp, Src: "m[\"x\"].Text", Value: "x"}, + {Line: 595, Op: ir.FilterVarTextOp, Src: "m[\"y\"].Text", Value: "y"}, }, }, }, }, }, { - Line: 595, + Line: 600, SyntaxPatterns: []ir.PatternString{ - {Line: 596, Value: "bytes.Equal(bytes.ToLower($x), $y)"}, - {Line: 597, Value: "bytes.Equal(bytes.ToLower($x), bytes.ToLower($y))"}, - {Line: 598, Value: "bytes.Equal($x, bytes.ToLower($y))"}, - {Line: 599, Value: "bytes.Equal(bytes.ToUpper($x), $y)"}, - {Line: 600, Value: "bytes.Equal(bytes.ToUpper($x), bytes.ToUpper($y))"}, - {Line: 601, Value: "bytes.Equal($x, bytes.ToUpper($y))"}, + {Line: 601, Value: "bytes.Equal(bytes.ToLower($x), $y)"}, + {Line: 602, Value: "bytes.Equal(bytes.ToLower($x), bytes.ToLower($y))"}, + {Line: 603, Value: "bytes.Equal($x, bytes.ToLower($y))"}, + {Line: 604, Value: "bytes.Equal(bytes.ToUpper($x), $y)"}, + {Line: 605, Value: "bytes.Equal(bytes.ToUpper($x), bytes.ToUpper($y))"}, + {Line: 606, Value: "bytes.Equal($x, bytes.ToUpper($y))"}, }, ReportTemplate: "consider replacing with bytes.EqualFold($x, $y)", SuggestTemplate: "bytes.EqualFold($x, $y)", WhereExpr: ir.FilterExpr{ - Line: 602, + Line: 607, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure && m[\"x\"].Text != m[\"y\"].Text", Args: []ir.FilterExpr{ { - Line: 602, + Line: 607, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure", Args: []ir.FilterExpr{ - {Line: 602, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, - {Line: 602, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, + {Line: 607, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + {Line: 607, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, }, }, { - Line: 602, + Line: 607, Op: ir.FilterNeqOp, Src: "m[\"x\"].Text != m[\"y\"].Text", Args: []ir.FilterExpr{ - {Line: 602, Op: ir.FilterVarTextOp, Src: "m[\"x\"].Text", Value: "x"}, - {Line: 602, Op: ir.FilterVarTextOp, Src: "m[\"y\"].Text", Value: "y"}, + {Line: 607, Op: ir.FilterVarTextOp, Src: "m[\"x\"].Text", Value: "x"}, + {Line: 607, Op: ir.FilterVarTextOp, Src: "m[\"y\"].Text", Value: "y"}, }, }, }, @@ -1972,7 +1977,7 @@ var PrecompiledRules = &ir.File{ }, }, { - Line: 611, + Line: 616, Name: "argOrder", MatcherName: "m", DocTags: []string{"diagnostic"}, @@ -1980,45 +1985,45 @@ var PrecompiledRules = &ir.File{ DocBefore: "strings.HasPrefix(\"#\", userpass)", DocAfter: "strings.HasPrefix(userpass, \"#\")", Rules: []ir.Rule{{ - Line: 612, + Line: 617, SyntaxPatterns: []ir.PatternString{ - {Line: 613, Value: "strings.HasPrefix($lit, $s)"}, - {Line: 614, Value: "bytes.HasPrefix($lit, $s)"}, - {Line: 615, Value: "strings.HasSuffix($lit, $s)"}, - {Line: 616, Value: "bytes.HasSuffix($lit, $s)"}, - {Line: 617, Value: "strings.Contains($lit, $s)"}, - {Line: 618, Value: "bytes.Contains($lit, $s)"}, - {Line: 619, Value: "strings.TrimPrefix($lit, $s)"}, - {Line: 620, Value: "bytes.TrimPrefix($lit, $s)"}, - {Line: 621, Value: "strings.TrimSuffix($lit, $s)"}, - {Line: 622, Value: "bytes.TrimSuffix($lit, $s)"}, - {Line: 623, Value: "strings.Split($lit, $s)"}, - {Line: 624, Value: "bytes.Split($lit, $s)"}, + {Line: 618, Value: "strings.HasPrefix($lit, $s)"}, + {Line: 619, Value: "bytes.HasPrefix($lit, $s)"}, + {Line: 620, Value: "strings.HasSuffix($lit, $s)"}, + {Line: 621, Value: "bytes.HasSuffix($lit, $s)"}, + {Line: 622, Value: "strings.Contains($lit, $s)"}, + {Line: 623, Value: "bytes.Contains($lit, $s)"}, + {Line: 624, Value: "strings.TrimPrefix($lit, $s)"}, + {Line: 625, Value: "bytes.TrimPrefix($lit, $s)"}, + {Line: 626, Value: "strings.TrimSuffix($lit, $s)"}, + {Line: 627, Value: "bytes.TrimSuffix($lit, $s)"}, + {Line: 628, Value: "strings.Split($lit, $s)"}, + {Line: 629, Value: "bytes.Split($lit, $s)"}, }, ReportTemplate: "$lit and $s arguments order looks reversed", WhereExpr: ir.FilterExpr{ - Line: 625, + Line: 630, Op: ir.FilterAndOp, Src: "(m[\"lit\"].Const || m[\"lit\"].ConstSlice) &&\n\t!(m[\"s\"].Const || m[\"s\"].ConstSlice) &&\n\t!m[\"lit\"].Node.Is(`Ident`)", Args: []ir.FilterExpr{ { - Line: 625, + Line: 630, Op: ir.FilterAndOp, Src: "(m[\"lit\"].Const || m[\"lit\"].ConstSlice) &&\n\t!(m[\"s\"].Const || m[\"s\"].ConstSlice)", Args: []ir.FilterExpr{ { - Line: 625, + Line: 630, Op: ir.FilterOrOp, Src: "(m[\"lit\"].Const || m[\"lit\"].ConstSlice)", Args: []ir.FilterExpr{ { - Line: 625, + Line: 630, Op: ir.FilterVarConstOp, Src: "m[\"lit\"].Const", Value: "lit", }, { - Line: 625, + Line: 630, Op: ir.FilterVarConstSliceOp, Src: "m[\"lit\"].ConstSlice", Value: "lit", @@ -2026,22 +2031,22 @@ var PrecompiledRules = &ir.File{ }, }, { - Line: 626, + Line: 631, Op: ir.FilterNotOp, Src: "!(m[\"s\"].Const || m[\"s\"].ConstSlice)", Args: []ir.FilterExpr{{ - Line: 626, + Line: 631, Op: ir.FilterOrOp, Src: "(m[\"s\"].Const || m[\"s\"].ConstSlice)", Args: []ir.FilterExpr{ { - Line: 626, + Line: 631, Op: ir.FilterVarConstOp, Src: "m[\"s\"].Const", Value: "s", }, { - Line: 626, + Line: 631, Op: ir.FilterVarConstSliceOp, Src: "m[\"s\"].ConstSlice", Value: "s", @@ -2052,15 +2057,15 @@ var PrecompiledRules = &ir.File{ }, }, { - Line: 627, + Line: 632, Op: ir.FilterNotOp, Src: "!m[\"lit\"].Node.Is(`Ident`)", Args: []ir.FilterExpr{{ - Line: 627, + Line: 632, Op: ir.FilterVarNodeIsOp, Src: "m[\"lit\"].Node.Is(`Ident`)", Value: "lit", - Args: []ir.FilterExpr{{Line: 627, Op: ir.FilterStringOp, Src: "`Ident`", Value: "Ident"}}, + Args: []ir.FilterExpr{{Line: 632, Op: ir.FilterStringOp, Src: "`Ident`", Value: "Ident"}}, }}, }, }, @@ -2068,7 +2073,7 @@ var PrecompiledRules = &ir.File{ }}, }, { - Line: 635, + Line: 640, Name: "stringConcatSimplify", MatcherName: "m", DocTags: []string{"style", "experimental"}, @@ -2077,27 +2082,27 @@ var PrecompiledRules = &ir.File{ DocAfter: "x + \"_\" + y", Rules: []ir.Rule{ { - Line: 636, - SyntaxPatterns: []ir.PatternString{{Line: 636, Value: "strings.Join([]string{$x, $y}, \"\")"}}, + Line: 641, + SyntaxPatterns: []ir.PatternString{{Line: 641, Value: "strings.Join([]string{$x, $y}, \"\")"}}, ReportTemplate: "suggestion: $x + $y", SuggestTemplate: "$x + $y", }, { - Line: 637, - SyntaxPatterns: []ir.PatternString{{Line: 637, Value: "strings.Join([]string{$x, $y, $z}, \"\")"}}, + Line: 642, + SyntaxPatterns: []ir.PatternString{{Line: 642, Value: "strings.Join([]string{$x, $y, $z}, \"\")"}}, ReportTemplate: "suggestion: $x + $y + $z", SuggestTemplate: "$x + $y + $z", }, { - Line: 638, - SyntaxPatterns: []ir.PatternString{{Line: 638, Value: "strings.Join([]string{$x, $y}, $glue)"}}, + Line: 643, + SyntaxPatterns: []ir.PatternString{{Line: 643, Value: "strings.Join([]string{$x, $y}, $glue)"}}, ReportTemplate: "suggestion: $x + $glue + $y", SuggestTemplate: "$x + $glue + $y", }, }, }, { - Line: 645, + Line: 650, Name: "timeExprSimplify", MatcherName: "m", DocTags: []string{"style", "experimental"}, @@ -2106,39 +2111,39 @@ var PrecompiledRules = &ir.File{ DocAfter: "t.UnixMilli()", Rules: []ir.Rule{ { - Line: 650, - SyntaxPatterns: []ir.PatternString{{Line: 650, Value: "$t.Unix() / 1000"}}, + Line: 655, + SyntaxPatterns: []ir.PatternString{{Line: 655, Value: "$t.Unix() / 1000"}}, ReportTemplate: "use $t.UnixMilli() instead of $$", SuggestTemplate: "$t.UnixMilli()", WhereExpr: ir.FilterExpr{ - Line: 651, + Line: 656, Op: ir.FilterAndOp, Src: "m.GoVersion().GreaterEqThan(\"1.17\") && isTime(m[\"t\"])", Args: []ir.FilterExpr{ { - Line: 651, + Line: 656, Op: ir.FilterGoVersionGreaterEqThanOp, Src: "m.GoVersion().GreaterEqThan(\"1.17\")", Value: "1.17", }, { - Line: 651, + Line: 656, Op: ir.FilterOrOp, Src: "isTime(m[\"t\"])", Args: []ir.FilterExpr{ { - Line: 651, + Line: 656, Op: ir.FilterVarTypeIsOp, Src: "m[\"t\"].Type.Is(`time.Time`)", Value: "t", - Args: []ir.FilterExpr{{Line: 647, Op: ir.FilterStringOp, Src: "`time.Time`", Value: "time.Time"}}, + Args: []ir.FilterExpr{{Line: 652, Op: ir.FilterStringOp, Src: "`time.Time`", Value: "time.Time"}}, }, { - Line: 651, + Line: 656, Op: ir.FilterVarTypeIsOp, Src: "m[\"t\"].Type.Is(`*time.Time`)", Value: "t", - Args: []ir.FilterExpr{{Line: 647, Op: ir.FilterStringOp, Src: "`*time.Time`", Value: "*time.Time"}}, + Args: []ir.FilterExpr{{Line: 652, Op: ir.FilterStringOp, Src: "`*time.Time`", Value: "*time.Time"}}, }, }, }, @@ -2146,39 +2151,39 @@ var PrecompiledRules = &ir.File{ }, }, { - Line: 655, - SyntaxPatterns: []ir.PatternString{{Line: 655, Value: "$t.UnixNano() * 1000"}}, + Line: 660, + SyntaxPatterns: []ir.PatternString{{Line: 660, Value: "$t.UnixNano() * 1000"}}, ReportTemplate: "use $t.UnixMicro() instead of $$", SuggestTemplate: "$t.UnixMicro()", WhereExpr: ir.FilterExpr{ - Line: 656, + Line: 661, Op: ir.FilterAndOp, Src: "m.GoVersion().GreaterEqThan(\"1.17\") && isTime(m[\"t\"])", Args: []ir.FilterExpr{ { - Line: 656, + Line: 661, Op: ir.FilterGoVersionGreaterEqThanOp, Src: "m.GoVersion().GreaterEqThan(\"1.17\")", Value: "1.17", }, { - Line: 656, + Line: 661, Op: ir.FilterOrOp, Src: "isTime(m[\"t\"])", Args: []ir.FilterExpr{ { - Line: 656, + Line: 661, Op: ir.FilterVarTypeIsOp, Src: "m[\"t\"].Type.Is(`time.Time`)", Value: "t", - Args: []ir.FilterExpr{{Line: 647, Op: ir.FilterStringOp, Src: "`time.Time`", Value: "time.Time"}}, + Args: []ir.FilterExpr{{Line: 652, Op: ir.FilterStringOp, Src: "`time.Time`", Value: "time.Time"}}, }, { - Line: 656, + Line: 661, Op: ir.FilterVarTypeIsOp, Src: "m[\"t\"].Type.Is(`*time.Time`)", Value: "t", - Args: []ir.FilterExpr{{Line: 647, Op: ir.FilterStringOp, Src: "`*time.Time`", Value: "*time.Time"}}, + Args: []ir.FilterExpr{{Line: 652, Op: ir.FilterStringOp, Src: "`*time.Time`", Value: "*time.Time"}}, }, }, }, @@ -2188,7 +2193,7 @@ var PrecompiledRules = &ir.File{ }, }, { - Line: 665, + Line: 670, Name: "exposedSyncMutex", MatcherName: "m", DocTags: []string{"style", "experimental"}, @@ -2197,57 +2202,57 @@ var PrecompiledRules = &ir.File{ DocAfter: "type Foo struct{ ...; mu sync.Mutex; ... }", Rules: []ir.Rule{ { - Line: 670, - SyntaxPatterns: []ir.PatternString{{Line: 670, Value: "type $x struct { $*_; sync.Mutex; $*_ }"}}, + Line: 675, + SyntaxPatterns: []ir.PatternString{{Line: 675, Value: "type $x struct { $*_; sync.Mutex; $*_ }"}}, ReportTemplate: "don't embed sync.Mutex", WhereExpr: ir.FilterExpr{ - Line: 671, + Line: 676, Op: ir.FilterVarTextMatchesOp, Src: "isExported(m[\"x\"])", Value: "x", - Args: []ir.FilterExpr{{Line: 667, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}}, + Args: []ir.FilterExpr{{Line: 672, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}}, }, }, { - Line: 674, - SyntaxPatterns: []ir.PatternString{{Line: 674, Value: "type $x struct { $*_; *sync.Mutex; $*_ }"}}, + Line: 679, + SyntaxPatterns: []ir.PatternString{{Line: 679, Value: "type $x struct { $*_; *sync.Mutex; $*_ }"}}, ReportTemplate: "don't embed *sync.Mutex", WhereExpr: ir.FilterExpr{ - Line: 675, + Line: 680, Op: ir.FilterVarTextMatchesOp, Src: "isExported(m[\"x\"])", Value: "x", - Args: []ir.FilterExpr{{Line: 667, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}}, + Args: []ir.FilterExpr{{Line: 672, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}}, }, }, { - Line: 678, - SyntaxPatterns: []ir.PatternString{{Line: 678, Value: "type $x struct { $*_; sync.RWMutex; $*_ }"}}, + Line: 683, + SyntaxPatterns: []ir.PatternString{{Line: 683, Value: "type $x struct { $*_; sync.RWMutex; $*_ }"}}, ReportTemplate: "don't embed sync.RWMutex", WhereExpr: ir.FilterExpr{ - Line: 679, + Line: 684, Op: ir.FilterVarTextMatchesOp, Src: "isExported(m[\"x\"])", Value: "x", - Args: []ir.FilterExpr{{Line: 667, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}}, + Args: []ir.FilterExpr{{Line: 672, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}}, }, }, { - Line: 682, - SyntaxPatterns: []ir.PatternString{{Line: 682, Value: "type $x struct { $*_; *sync.RWMutex; $*_ }"}}, + Line: 687, + SyntaxPatterns: []ir.PatternString{{Line: 687, Value: "type $x struct { $*_; *sync.RWMutex; $*_ }"}}, ReportTemplate: "don't embed *sync.RWMutex", WhereExpr: ir.FilterExpr{ - Line: 683, + Line: 688, Op: ir.FilterVarTextMatchesOp, Src: "isExported(m[\"x\"])", Value: "x", - Args: []ir.FilterExpr{{Line: 667, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}}, + Args: []ir.FilterExpr{{Line: 672, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}}, }, }, }, }, { - Line: 691, + Line: 696, Name: "badSorting", MatcherName: "m", DocTags: []string{"diagnostic", "experimental"}, @@ -2256,48 +2261,48 @@ var PrecompiledRules = &ir.File{ DocAfter: "sort.Strings(xs)", Rules: []ir.Rule{ { - Line: 692, - SyntaxPatterns: []ir.PatternString{{Line: 692, Value: "$x = sort.IntSlice($x)"}}, + Line: 697, + SyntaxPatterns: []ir.PatternString{{Line: 697, Value: "$x = sort.IntSlice($x)"}}, ReportTemplate: "suspicious sort.IntSlice usage, maybe sort.Ints was intended?", SuggestTemplate: "sort.Ints($x)", WhereExpr: ir.FilterExpr{ - Line: 693, + Line: 698, Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`[]int`)", Value: "x", - Args: []ir.FilterExpr{{Line: 693, Op: ir.FilterStringOp, Src: "`[]int`", Value: "[]int"}}, + Args: []ir.FilterExpr{{Line: 698, Op: ir.FilterStringOp, Src: "`[]int`", Value: "[]int"}}, }, }, { - Line: 697, - SyntaxPatterns: []ir.PatternString{{Line: 697, Value: "$x = sort.Float64Slice($x)"}}, + Line: 702, + SyntaxPatterns: []ir.PatternString{{Line: 702, Value: "$x = sort.Float64Slice($x)"}}, ReportTemplate: "suspicious sort.Float64s usage, maybe sort.Float64s was intended?", SuggestTemplate: "sort.Float64s($x)", WhereExpr: ir.FilterExpr{ - Line: 698, + Line: 703, Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`[]float64`)", Value: "x", - Args: []ir.FilterExpr{{Line: 698, Op: ir.FilterStringOp, Src: "`[]float64`", Value: "[]float64"}}, + Args: []ir.FilterExpr{{Line: 703, Op: ir.FilterStringOp, Src: "`[]float64`", Value: "[]float64"}}, }, }, { - Line: 702, - SyntaxPatterns: []ir.PatternString{{Line: 702, Value: "$x = sort.StringSlice($x)"}}, + Line: 707, + SyntaxPatterns: []ir.PatternString{{Line: 707, Value: "$x = sort.StringSlice($x)"}}, ReportTemplate: "suspicious sort.StringSlice usage, maybe sort.Strings was intended?", SuggestTemplate: "sort.Strings($x)", WhereExpr: ir.FilterExpr{ - Line: 703, + Line: 708, Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`[]string`)", Value: "x", - Args: []ir.FilterExpr{{Line: 703, Op: ir.FilterStringOp, Src: "`[]string`", Value: "[]string"}}, + Args: []ir.FilterExpr{{Line: 708, Op: ir.FilterStringOp, Src: "`[]string`", Value: "[]string"}}, }, }, }, }, { - Line: 712, + Line: 717, Name: "externalErrorReassign", MatcherName: "m", DocTags: []string{"diagnostic", "experimental"}, @@ -2305,34 +2310,34 @@ var PrecompiledRules = &ir.File{ DocBefore: "io.EOF = nil", DocAfter: "/* don't do it */", Rules: []ir.Rule{{ - Line: 713, - SyntaxPatterns: []ir.PatternString{{Line: 713, Value: "$pkg.$err = $x"}}, + Line: 718, + SyntaxPatterns: []ir.PatternString{{Line: 718, Value: "$pkg.$err = $x"}}, ReportTemplate: "suspicious reassignment of error from another package", WhereExpr: ir.FilterExpr{ - Line: 714, + Line: 719, Op: ir.FilterAndOp, Src: "m[\"err\"].Type.Is(`error`) && m[\"pkg\"].Object.Is(`PkgName`)", Args: []ir.FilterExpr{ { - Line: 714, + Line: 719, Op: ir.FilterVarTypeIsOp, Src: "m[\"err\"].Type.Is(`error`)", Value: "err", - Args: []ir.FilterExpr{{Line: 714, Op: ir.FilterStringOp, Src: "`error`", Value: "error"}}, + Args: []ir.FilterExpr{{Line: 719, Op: ir.FilterStringOp, Src: "`error`", Value: "error"}}, }, { - Line: 714, + Line: 719, Op: ir.FilterVarObjectIsOp, Src: "m[\"pkg\"].Object.Is(`PkgName`)", Value: "pkg", - Args: []ir.FilterExpr{{Line: 714, Op: ir.FilterStringOp, Src: "`PkgName`", Value: "PkgName"}}, + Args: []ir.FilterExpr{{Line: 719, Op: ir.FilterStringOp, Src: "`PkgName`", Value: "PkgName"}}, }, }, }, }}, }, { - Line: 722, + Line: 727, Name: "emptyDecl", MatcherName: "m", DocTags: []string{"diagnostic", "experimental"}, @@ -2341,42 +2346,42 @@ var PrecompiledRules = &ir.File{ DocAfter: "/* nothing */", Rules: []ir.Rule{ { - Line: 723, - SyntaxPatterns: []ir.PatternString{{Line: 723, Value: "var()"}}, + Line: 728, + SyntaxPatterns: []ir.PatternString{{Line: 728, Value: "var()"}}, ReportTemplate: "empty var() block", }, { - Line: 724, - SyntaxPatterns: []ir.PatternString{{Line: 724, Value: "const()"}}, + Line: 729, + SyntaxPatterns: []ir.PatternString{{Line: 729, Value: "const()"}}, ReportTemplate: "empty const() block", }, { - Line: 725, - SyntaxPatterns: []ir.PatternString{{Line: 725, Value: "type()"}}, + Line: 730, + SyntaxPatterns: []ir.PatternString{{Line: 730, Value: "type()"}}, ReportTemplate: "empty type() block", }, }, }, { - Line: 732, + Line: 737, Name: "dynamicFmtString", MatcherName: "m", DocTags: []string{"diagnostic", "experimental"}, DocSummary: "Detects suspicious formatting strings usage", DocBefore: "fmt.Errorf(msg)", - DocAfter: "fmt.Errorf(\"%s\", msg)", + DocAfter: "errors.New(msg) or fmt.Errorf(\"%s\", msg)", Rules: []ir.Rule{ { - Line: 733, - SyntaxPatterns: []ir.PatternString{{Line: 733, Value: "fmt.Errorf($f)"}}, + Line: 738, + SyntaxPatterns: []ir.PatternString{{Line: 738, Value: "fmt.Errorf($f)"}}, ReportTemplate: "use errors.New($f) or fmt.Errorf(\"%s\", $f) instead", SuggestTemplate: "errors.New($f)", WhereExpr: ir.FilterExpr{ - Line: 734, + Line: 739, Op: ir.FilterNotOp, Src: "!m[\"f\"].Const", Args: []ir.FilterExpr{{ - Line: 734, + Line: 739, Op: ir.FilterVarConstOp, Src: "m[\"f\"].Const", Value: "f", @@ -2384,15 +2389,15 @@ var PrecompiledRules = &ir.File{ }, }, { - Line: 738, - SyntaxPatterns: []ir.PatternString{{Line: 738, Value: "fmt.Errorf($f($*args))"}}, + Line: 743, + SyntaxPatterns: []ir.PatternString{{Line: 743, Value: "fmt.Errorf($f($*args))"}}, ReportTemplate: "use errors.New($f($*args)) or fmt.Errorf(\"%s\", $f($*args)) instead", SuggestTemplate: "errors.New($f($*args))", }, }, }, { - Line: 747, + Line: 752, Name: "stringsCompare", MatcherName: "m", DocTags: []string{"style", "experimental"}, @@ -2401,25 +2406,25 @@ var PrecompiledRules = &ir.File{ DocAfter: "x < y", Rules: []ir.Rule{ { - Line: 748, - SyntaxPatterns: []ir.PatternString{{Line: 748, Value: "strings.Compare($s1, $s2) == 0"}}, + Line: 753, + SyntaxPatterns: []ir.PatternString{{Line: 753, Value: "strings.Compare($s1, $s2) == 0"}}, ReportTemplate: "suggestion: $s1 == $s2", SuggestTemplate: "$s1 == $s2", }, { - Line: 751, + Line: 756, SyntaxPatterns: []ir.PatternString{ - {Line: 751, Value: "strings.Compare($s1, $s2) == -1"}, - {Line: 752, Value: "strings.Compare($s1, $s2) < 0"}, + {Line: 756, Value: "strings.Compare($s1, $s2) == -1"}, + {Line: 757, Value: "strings.Compare($s1, $s2) < 0"}, }, ReportTemplate: "suggestion: $s1 < $s2", SuggestTemplate: "$s1 < $s2", }, { - Line: 755, + Line: 760, SyntaxPatterns: []ir.PatternString{ - {Line: 755, Value: "strings.Compare($s1, $s2) == 1"}, - {Line: 756, Value: "strings.Compare($s1, $s2) > 0"}, + {Line: 760, Value: "strings.Compare($s1, $s2) == 1"}, + {Line: 761, Value: "strings.Compare($s1, $s2) > 0"}, }, ReportTemplate: "suggestion: $s1 > $s2", SuggestTemplate: "$s1 > $s2", @@ -2427,7 +2432,7 @@ var PrecompiledRules = &ir.File{ }, }, { - Line: 764, + Line: 769, Name: "uncheckedInlineErr", MatcherName: "m", DocTags: []string{"diagnostic", "experimental"}, @@ -2435,47 +2440,47 @@ var PrecompiledRules = &ir.File{ DocBefore: "if err := expr(); err2 != nil { /*...*/ }", DocAfter: "if err := expr(); err != nil { /*...*/ }", Rules: []ir.Rule{{ - Line: 765, + Line: 770, SyntaxPatterns: []ir.PatternString{ - {Line: 766, Value: "if $err := $_($*_); $err2 != nil { $*_ }"}, - {Line: 767, Value: "if $err = $_($*_); $err2 != nil { $*_ }"}, - {Line: 768, Value: "if $*_, $err := $_($*_); $err2 != nil { $*_ }"}, - {Line: 769, Value: "if $*_, $err = $_($*_); $err2 != nil { $*_ }"}, + {Line: 771, Value: "if $err := $_($*_); $err2 != nil { $*_ }"}, + {Line: 772, Value: "if $err = $_($*_); $err2 != nil { $*_ }"}, + {Line: 773, Value: "if $*_, $err := $_($*_); $err2 != nil { $*_ }"}, + {Line: 774, Value: "if $*_, $err = $_($*_); $err2 != nil { $*_ }"}, }, ReportTemplate: "$err error is unchecked, maybe intended to check it instead of $err2", WhereExpr: ir.FilterExpr{ - Line: 770, + Line: 775, Op: ir.FilterAndOp, Src: "m[\"err\"].Type.Implements(\"error\") && m[\"err2\"].Type.Implements(\"error\") &&\n\tm[\"err\"].Text != m[\"err2\"].Text", Args: []ir.FilterExpr{ { - Line: 770, + Line: 775, Op: ir.FilterAndOp, Src: "m[\"err\"].Type.Implements(\"error\") && m[\"err2\"].Type.Implements(\"error\")", Args: []ir.FilterExpr{ { - Line: 770, + Line: 775, Op: ir.FilterVarTypeImplementsOp, Src: "m[\"err\"].Type.Implements(\"error\")", Value: "err", - Args: []ir.FilterExpr{{Line: 770, Op: ir.FilterStringOp, Src: "\"error\"", Value: "error"}}, + Args: []ir.FilterExpr{{Line: 775, Op: ir.FilterStringOp, Src: "\"error\"", Value: "error"}}, }, { - Line: 770, + Line: 775, Op: ir.FilterVarTypeImplementsOp, Src: "m[\"err2\"].Type.Implements(\"error\")", Value: "err2", - Args: []ir.FilterExpr{{Line: 770, Op: ir.FilterStringOp, Src: "\"error\"", Value: "error"}}, + Args: []ir.FilterExpr{{Line: 775, Op: ir.FilterStringOp, Src: "\"error\"", Value: "error"}}, }, }, }, { - Line: 771, + Line: 776, Op: ir.FilterNeqOp, Src: "m[\"err\"].Text != m[\"err2\"].Text", Args: []ir.FilterExpr{ - {Line: 771, Op: ir.FilterVarTextOp, Src: "m[\"err\"].Text", Value: "err"}, - {Line: 771, Op: ir.FilterVarTextOp, Src: "m[\"err2\"].Text", Value: "err2"}, + {Line: 776, Op: ir.FilterVarTextOp, Src: "m[\"err\"].Text", Value: "err"}, + {Line: 776, Op: ir.FilterVarTextOp, Src: "m[\"err2\"].Text", Value: "err2"}, }, }, }, @@ -2484,7 +2489,7 @@ var PrecompiledRules = &ir.File{ }}, }, { - Line: 780, + Line: 785, Name: "badSyncOnceFunc", MatcherName: "m", DocTags: []string{"diagnostic", "experimental"}, @@ -2493,22 +2498,22 @@ var PrecompiledRules = &ir.File{ DocAfter: "fooOnce := sync.OnceFunc(foo); ...; fooOnce()", Rules: []ir.Rule{ { - Line: 781, - SyntaxPatterns: []ir.PatternString{{Line: 781, Value: "$*_; sync.OnceFunc($x); $*_;"}}, + Line: 786, + SyntaxPatterns: []ir.PatternString{{Line: 786, Value: "$*_; sync.OnceFunc($x); $*_;"}}, ReportTemplate: "possible sync.OnceFunc misuse, sync.OnceFunc($x) result is not used", WhereExpr: ir.FilterExpr{ - Line: 783, + Line: 788, Op: ir.FilterGoVersionGreaterEqThanOp, Src: "m.GoVersion().GreaterEqThan(\"1.21\")", Value: "1.21", }, }, { - Line: 785, - SyntaxPatterns: []ir.PatternString{{Line: 785, Value: "sync.OnceFunc($x)()"}}, + Line: 790, + SyntaxPatterns: []ir.PatternString{{Line: 790, Value: "sync.OnceFunc($x)()"}}, ReportTemplate: "possible sync.OnceFunc misuse, consider to assign sync.OnceFunc($x) to a variable", WhereExpr: ir.FilterExpr{ - Line: 787, + Line: 792, Op: ir.FilterGoVersionGreaterEqThanOp, Src: "m.GoVersion().GreaterEqThan(\"1.21\")", Value: "1.21", @@ -2516,6 +2521,61 @@ var PrecompiledRules = &ir.File{ }, }, }, + { + Line: 799, + Name: "zeroByteRepeat", + MatcherName: "m", + DocTags: []string{"performance"}, + DocSummary: "Detects bytes.Repeat with 0 value", + DocBefore: "bytes.Repeat([]byte{0}, x)", + DocAfter: "make([]byte, x)", + Rules: []ir.Rule{ + { + Line: 800, + SyntaxPatterns: []ir.PatternString{{Line: 800, Value: "bytes.Repeat([]byte{0}, $x)"}}, + ReportTemplate: "avoid bytes.Repeat([]byte{0}, $x); consider using make([]byte, $x) instead", + SuggestTemplate: "make([]byte, $x)", + }, + { + Line: 805, + SyntaxPatterns: []ir.PatternString{{Line: 805, Value: "bytes.Repeat([]byte{$x}, $n)"}}, + ReportTemplate: "avoid bytes.Repeat with a const 0; use make([]byte, $n) instead", + SuggestTemplate: "make([]byte, $n)", + WhereExpr: ir.FilterExpr{ + Line: 806, + Op: ir.FilterAndOp, + Src: "m[\"x\"].Const && m[\"x\"].Value.Int() == 0", + Args: []ir.FilterExpr{ + { + Line: 806, + Op: ir.FilterVarConstOp, + Src: "m[\"x\"].Const", + Value: "x", + }, + { + Line: 806, + Op: ir.FilterEqOp, + Src: "m[\"x\"].Value.Int() == 0", + Args: []ir.FilterExpr{ + { + Line: 806, + Op: ir.FilterVarValueIntOp, + Src: "m[\"x\"].Value.Int()", + Value: "x", + }, + { + Line: 806, + Op: ir.FilterIntOp, + Src: "0", + Value: int64(0), + }, + }, + }, + }, + }, + }, + }, + }, }, } diff --git a/vendor/github.com/go-critic/go-critic/checkers/sqlQuery_checker.go b/vendor/github.com/go-critic/go-critic/checkers/sqlQuery_checker.go index 8a132b586..02a2370d3 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/sqlQuery_checker.go +++ b/vendor/github.com/go-critic/go-critic/checkers/sqlQuery_checker.go @@ -125,6 +125,13 @@ func (c *sqlQueryChecker) typeHasExecMethod(typ types.Type) bool { return true } } + case *types.Alias: + switch typ := typ.Underlying().(type) { + case *types.Interface: + return c.typeHasExecMethod(typ) + default: + // TODO(cristaloleg): is there something else to handle? + } case *types.Interface: for i := 0; i < typ.NumMethods(); i++ { if c.funcIsExec(typ.Method(i)) { diff --git a/vendor/github.com/go-critic/go-critic/checkers/utils.go b/vendor/github.com/go-critic/go-critic/checkers/utils.go index 6e12cf9b3..5740f0d4d 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/utils.go +++ b/vendor/github.com/go-critic/go-critic/checkers/utils.go @@ -9,183 +9,183 @@ import ( ) // goStdlib contains `go list std` command output list. +// `internal` and `vendor` packages are excluded. // Used to detect packages that belong to standard Go packages distribution. var goStdlib = map[string]bool{ - "archive/tar": true, - "archive/zip": true, - "bufio": true, - "bytes": true, - "compress/bzip2": true, - "compress/flate": true, - "compress/gzip": true, - "compress/lzw": true, - "compress/zlib": true, - "container/heap": true, - "container/list": true, - "container/ring": true, - "context": true, - "crypto": true, - "crypto/aes": true, - "crypto/cipher": true, - "crypto/des": true, - "crypto/dsa": true, - "crypto/ecdsa": true, - "crypto/elliptic": true, - "crypto/hmac": true, - "crypto/internal/randutil": true, - "crypto/internal/subtle": true, - "crypto/md5": true, - "crypto/rand": true, - "crypto/rc4": true, - "crypto/rsa": true, - "crypto/sha1": true, - "crypto/sha256": true, - "crypto/sha512": true, - "crypto/subtle": true, - "crypto/tls": true, - "crypto/x509": true, - "crypto/x509/pkix": true, - "database/sql": true, - "database/sql/driver": true, - "debug/dwarf": true, - "debug/elf": true, - "debug/gosym": true, - "debug/macho": true, - "debug/pe": true, - "debug/plan9obj": true, - "encoding": true, - "encoding/ascii85": true, - "encoding/asn1": true, - "encoding/base32": true, - "encoding/base64": true, - "encoding/binary": true, - "encoding/csv": true, - "encoding/gob": true, - "encoding/hex": true, - "encoding/json": true, - "encoding/pem": true, - "encoding/xml": true, - "errors": true, - "expvar": true, - "flag": true, - "fmt": true, - "go/ast": true, - "go/build": true, - "go/constant": true, - "go/doc": true, - "go/format": true, - "go/importer": true, - "go/internal/gccgoimporter": true, - "go/internal/gcimporter": true, - "go/internal/srcimporter": true, - "go/parser": true, - "go/printer": true, - "go/scanner": true, - "go/token": true, - "go/types": true, - "hash": true, - "hash/adler32": true, - "hash/crc32": true, - "hash/crc64": true, - "hash/fnv": true, - "html": true, - "html/template": true, - "image": true, - "image/color": true, - "image/color/palette": true, - "image/draw": true, - "image/gif": true, - "image/internal/imageutil": true, - "image/jpeg": true, - "image/png": true, - "index/suffixarray": true, - "internal/bytealg": true, - "internal/cpu": true, - "internal/nettrace": true, - "internal/poll": true, - "internal/race": true, - "internal/singleflight": true, - "internal/syscall/unix": true, - "internal/syscall/windows": true, - "internal/syscall/windows/registry": true, - "internal/syscall/windows/sysdll": true, - "internal/testenv": true, - "internal/testlog": true, - "internal/trace": true, - "io": true, - "io/ioutil": true, - "log": true, - "log/syslog": true, - "math": true, - "math/big": true, - "math/bits": true, - "math/cmplx": true, - "math/rand": true, - "mime": true, - "mime/multipart": true, - "mime/quotedprintable": true, - "net": true, - "net/http": true, - "net/http/cgi": true, - "net/http/cookiejar": true, - "net/http/fcgi": true, - "net/http/httptest": true, - "net/http/httptrace": true, - "net/http/httputil": true, - "net/http/internal": true, - "net/http/pprof": true, - "net/internal/socktest": true, - "net/mail": true, - "net/rpc": true, - "net/rpc/jsonrpc": true, - "net/smtp": true, - "net/textproto": true, - "net/url": true, - "os": true, - "os/exec": true, - "os/signal": true, - "os/signal/internal/pty": true, - "os/user": true, - "path": true, - "path/filepath": true, - "plugin": true, - "reflect": true, - "regexp": true, - "regexp/syntax": true, - "runtime": true, - "runtime/cgo": true, - "runtime/debug": true, - "runtime/internal/atomic": true, - "runtime/internal/sys": true, - "runtime/pprof": true, - "runtime/pprof/internal/profile": true, - "runtime/race": true, - "runtime/trace": true, - "sort": true, - "strconv": true, - "strings": true, - "sync": true, - "sync/atomic": true, - "syscall": true, - "testing": true, - "testing/internal/testdeps": true, - "testing/iotest": true, - "testing/quick": true, - "text/scanner": true, - "text/tabwriter": true, - "text/template": true, - "text/template/parse": true, - "time": true, - "unicode": true, - "unicode/utf16": true, - "unicode/utf8": true, - "unsafe": true, + "archive/tar": true, + "archive/zip": true, + "bufio": true, + "bytes": true, + "cmp": true, + "compress/bzip2": true, + "compress/flate": true, + "compress/gzip": true, + "compress/lzw": true, + "compress/zlib": true, + "container/heap": true, + "container/list": true, + "container/ring": true, + "context": true, + "crypto": true, + "crypto/aes": true, + "crypto/cipher": true, + "crypto/des": true, + "crypto/dsa": true, + "crypto/ecdh": true, + "crypto/ecdsa": true, + "crypto/ed25519": true, + "crypto/elliptic": true, + "crypto/hmac": true, + "crypto/md5": true, + "crypto/rand": true, + "crypto/rc4": true, + "crypto/rsa": true, + "crypto/sha1": true, + "crypto/sha256": true, + "crypto/sha512": true, + "crypto/subtle": true, + "crypto/tls": true, + "crypto/x509": true, + "crypto/x509/pkix": true, + "database/sql": true, + "database/sql/driver": true, + "debug/buildinfo": true, + "debug/dwarf": true, + "debug/elf": true, + "debug/gosym": true, + "debug/macho": true, + "debug/pe": true, + "debug/plan9obj": true, + "embed": true, + "encoding": true, + "encoding/ascii85": true, + "encoding/asn1": true, + "encoding/base32": true, + "encoding/base64": true, + "encoding/binary": true, + "encoding/csv": true, + "encoding/gob": true, + "encoding/hex": true, + "encoding/json": true, + "encoding/pem": true, + "encoding/xml": true, + "errors": true, + "expvar": true, + "flag": true, + "fmt": true, + "go/ast": true, + "go/build": true, + "go/build/constraint": true, + "go/constant": true, + "go/doc": true, + "go/doc/comment": true, + "go/format": true, + "go/importer": true, + "go/parser": true, + "go/printer": true, + "go/scanner": true, + "go/token": true, + "go/types": true, + "go/version": true, + "hash": true, + "hash/adler32": true, + "hash/crc32": true, + "hash/crc64": true, + "hash/fnv": true, + "hash/maphash": true, + "html": true, + "html/template": true, + "image": true, + "image/color": true, + "image/color/palette": true, + "image/draw": true, + "image/gif": true, + "image/jpeg": true, + "image/png": true, + "index/suffixarray": true, + "io": true, + "io/fs": true, + "io/ioutil": true, + "iter": true, + "log": true, + "log/slog": true, + "log/syslog": true, + "maps": true, + "math": true, + "math/big": true, + "math/bits": true, + "math/cmplx": true, + "math/rand": true, + "math/rand/v2": true, + "mime": true, + "mime/multipart": true, + "mime/quotedprintable": true, + "net": true, + "net/http": true, + "net/http/cgi": true, + "net/http/cookiejar": true, + "net/http/fcgi": true, + "net/http/httptest": true, + "net/http/httptrace": true, + "net/http/httputil": true, + "net/http/pprof": true, + "net/mail": true, + "net/netip": true, + "net/rpc": true, + "net/rpc/jsonrpc": true, + "net/smtp": true, + "net/textproto": true, + "net/url": true, + "os": true, + "os/exec": true, + "os/signal": true, + "os/user": true, + "path": true, + "path/filepath": true, + "plugin": true, + "reflect": true, + "regexp": true, + "regexp/syntax": true, + "runtime": true, + "runtime/cgo": true, + "runtime/coverage": true, + "runtime/debug": true, + "runtime/metrics": true, + "runtime/pprof": true, + "runtime/race": true, + "runtime/trace": true, + "slices": true, + "sort": true, + "strconv": true, + "strings": true, + "structs": true, + "sync": true, + "sync/atomic": true, + "syscall": true, + "testing": true, + "testing/fstest": true, + "testing/iotest": true, + "testing/quick": true, + "testing/slogtest": true, + "text/scanner": true, + "text/tabwriter": true, + "text/template": true, + "text/template/parse": true, + "time": true, + "time/tzdata": true, + "unicode": true, + "unicode/utf16": true, + "unicode/utf8": true, + "unique": true, + "unsafe": true, } var goBuiltins = map[string]bool{ // Types + "any": true, "bool": true, "byte": true, + "comparable": true, "complex64": true, "complex128": true, "error": true, @@ -216,6 +216,7 @@ var goBuiltins = map[string]bool{ // Functions "append": true, "cap": true, + "clear": true, "close": true, "complex": true, "copy": true, diff --git a/vendor/github.com/go-critic/go-critic/linter/linter.go b/vendor/github.com/go-critic/go-critic/linter/linter.go index d4bc17536..c751d94cc 100644 --- a/vendor/github.com/go-critic/go-critic/linter/linter.go +++ b/vendor/github.com/go-critic/go-critic/linter/linter.go @@ -249,8 +249,8 @@ func NewContext(fset *token.FileSet, sizes types.Sizes) *Context { // It's permitted to have "go" prefix (e.g. "go1.5"). // // Empty string (the default) means that we make no -// Go version assumptions and (like gocritic does) behave -// like all features are available. To make gocritic +// Go version assumptions and (like go-critic does) behave +// like all features are available. To make go-critic // more conservative, the upper Go version level should be adjusted. func (c *Context) SetGoVersion(version string) { v, err := ParseGoVersion(version) diff --git a/vendor/github.com/go-viper/mapstructure/v2/.editorconfig b/vendor/github.com/go-viper/mapstructure/v2/.editorconfig index 1f664d13a..c37602a02 100644 --- a/vendor/github.com/go-viper/mapstructure/v2/.editorconfig +++ b/vendor/github.com/go-viper/mapstructure/v2/.editorconfig @@ -16,3 +16,9 @@ indent_style = tab [*.nix] indent_size = 2 + +[.golangci.yaml] +indent_size = 2 + +[devenv.yaml] +indent_size = 2 diff --git a/vendor/github.com/go-viper/mapstructure/v2/.envrc b/vendor/github.com/go-viper/mapstructure/v2/.envrc index 2e0f9f5f7..e2be8891c 100644 --- a/vendor/github.com/go-viper/mapstructure/v2/.envrc +++ b/vendor/github.com/go-viper/mapstructure/v2/.envrc @@ -1,4 +1,7 @@ -if ! has nix_direnv_version || ! nix_direnv_version 3.0.4; then - source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.0.4/direnvrc" "sha256-DzlYZ33mWF/Gs8DDeyjr8mnVmQGx7ASYqA5WlxwvBG4=" -fi -use flake . --impure +#!/usr/bin/env bash + +export DIRENV_WARN_TIMEOUT=20s + +eval "$(devenv direnvrc)" + +use devenv diff --git a/vendor/github.com/go-viper/mapstructure/v2/.gitignore b/vendor/github.com/go-viper/mapstructure/v2/.gitignore index 470e7ca2b..71caea19f 100644 --- a/vendor/github.com/go-viper/mapstructure/v2/.gitignore +++ b/vendor/github.com/go-viper/mapstructure/v2/.gitignore @@ -1,6 +1,10 @@ -/.devenv/ -/.direnv/ -/.pre-commit-config.yaml /bin/ /build/ /var/ + +# Devenv +.devenv* +devenv.local.nix +devenv.local.yaml +.direnv +.pre-commit-config.yaml diff --git a/vendor/github.com/go-viper/mapstructure/v2/.golangci.yaml b/vendor/github.com/go-viper/mapstructure/v2/.golangci.yaml index 763143aa7..bda962566 100644 --- a/vendor/github.com/go-viper/mapstructure/v2/.golangci.yaml +++ b/vendor/github.com/go-viper/mapstructure/v2/.golangci.yaml @@ -1,23 +1,48 @@ -run: - timeout: 5m +version: "2" -linters-settings: - gci: - sections: - - standard - - default - - prefix(github.com/go-viper/mapstructure) - golint: - min-confidence: 0 - goimports: - local-prefixes: github.com/go-viper/maptstructure +run: + timeout: 10m linters: - disable-all: true + enable: + - govet + - ineffassign + # - misspell + - nolintlint + # - revive + + disable: + - errcheck + - staticcheck + - unused + + settings: + misspell: + locale: US + nolintlint: + allow-unused: false # report any unused nolint directives + require-specific: false # don't require nolint directives to be specific about which linter is being skipped + +formatters: enable: - gci - gofmt - gofumpt - goimports - - staticcheck - # - stylecheck + # - golines + + settings: + gci: + sections: + - standard + - default + - localmodule + gofmt: + simplify: true + rewrite-rules: + - pattern: interface{} + replacement: any + + exclusions: + paths: + - internal/ diff --git a/vendor/github.com/go-viper/mapstructure/v2/README.md b/vendor/github.com/go-viper/mapstructure/v2/README.md index dd5ec69dd..45db71975 100644 --- a/vendor/github.com/go-viper/mapstructure/v2/README.md +++ b/vendor/github.com/go-viper/mapstructure/v2/README.md @@ -1,8 +1,9 @@ # mapstructure -[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/go-viper/mapstructure/ci.yaml?branch=main&style=flat-square)](https://github.com/go-viper/mapstructure/actions?query=workflow%3ACI) +[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/go-viper/mapstructure/ci.yaml?style=flat-square)](https://github.com/go-viper/mapstructure/actions/workflows/ci.yaml) [![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/mod/github.com/go-viper/mapstructure/v2) -![Go Version](https://img.shields.io/badge/go%20version-%3E=1.18-61CFDD.svg?style=flat-square) +![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/go-viper/mapstructure?style=flat-square&color=61CFDD) +[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/go-viper/mapstructure/badge?style=flat-square)](https://deps.dev/go/github.com%252Fgo-viper%252Fmapstructure%252Fv2) mapstructure is a Go library for decoding generic map values to structures and vice versa, while providing helpful error handling. @@ -29,7 +30,7 @@ The API is the same, so you don't need to change anything else. Here is a script that can help you with the migration: ```shell -sed -i 's/github.com\/mitchellh\/mapstructure/github.com\/go-viper\/mapstructure\/v2/g' $(find . -type f -name '*.go') +sed -i 's|github.com/mitchellh/mapstructure|github.com/go-viper/mapstructure/v2|g' $(find . -type f -name '*.go') ``` If you need more time to migrate your code, that is absolutely fine. diff --git a/vendor/github.com/go-viper/mapstructure/v2/decode_hooks.go b/vendor/github.com/go-viper/mapstructure/v2/decode_hooks.go index 1f3c69d4b..a852a0a04 100644 --- a/vendor/github.com/go-viper/mapstructure/v2/decode_hooks.go +++ b/vendor/github.com/go-viper/mapstructure/v2/decode_hooks.go @@ -13,7 +13,7 @@ import ( "time" ) -// typedDecodeHook takes a raw DecodeHookFunc (an interface{}) and turns +// typedDecodeHook takes a raw DecodeHookFunc (an any) and turns // it into the proper DecodeHookFunc type, such as DecodeHookFuncType. func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc { // Create variables here so we can reference them with the reflect pkg @@ -23,7 +23,7 @@ func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc { // Fill in the variables into this interface and the rest is done // automatically using the reflect package. - potential := []interface{}{f1, f2, f3} + potential := []any{f1, f2, f3} v := reflect.ValueOf(h) vt := v.Type() @@ -37,25 +37,25 @@ func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc { return nil } -// cachedDecodeHook takes a raw DecodeHookFunc (an interface{}) and turns +// cachedDecodeHook takes a raw DecodeHookFunc (an any) and turns // it into a closure to be used directly // if the type fails to convert we return a closure always erroring to keep the previous behaviour -func cachedDecodeHook(raw DecodeHookFunc) func(from reflect.Value, to reflect.Value) (interface{}, error) { +func cachedDecodeHook(raw DecodeHookFunc) func(from reflect.Value, to reflect.Value) (any, error) { switch f := typedDecodeHook(raw).(type) { case DecodeHookFuncType: - return func(from reflect.Value, to reflect.Value) (interface{}, error) { + return func(from reflect.Value, to reflect.Value) (any, error) { return f(from.Type(), to.Type(), from.Interface()) } case DecodeHookFuncKind: - return func(from reflect.Value, to reflect.Value) (interface{}, error) { + return func(from reflect.Value, to reflect.Value) (any, error) { return f(from.Kind(), to.Kind(), from.Interface()) } case DecodeHookFuncValue: - return func(from reflect.Value, to reflect.Value) (interface{}, error) { + return func(from reflect.Value, to reflect.Value) (any, error) { return f(from, to) } default: - return func(from reflect.Value, to reflect.Value) (interface{}, error) { + return func(from reflect.Value, to reflect.Value) (any, error) { return nil, errors.New("invalid decode hook signature") } } @@ -67,7 +67,7 @@ func cachedDecodeHook(raw DecodeHookFunc) func(from reflect.Value, to reflect.Va func DecodeHookExec( raw DecodeHookFunc, from reflect.Value, to reflect.Value, -) (interface{}, error) { +) (any, error) { switch f := typedDecodeHook(raw).(type) { case DecodeHookFuncType: return f(from.Type(), to.Type(), from.Interface()) @@ -86,11 +86,11 @@ func DecodeHookExec( // The composed funcs are called in order, with the result of the // previous transformation. func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc { - cached := make([]func(from reflect.Value, to reflect.Value) (interface{}, error), 0, len(fs)) + cached := make([]func(from reflect.Value, to reflect.Value) (any, error), 0, len(fs)) for _, f := range fs { cached = append(cached, cachedDecodeHook(f)) } - return func(f reflect.Value, t reflect.Value) (interface{}, error) { + return func(f reflect.Value, t reflect.Value) (any, error) { var err error data := f.Interface() @@ -100,7 +100,11 @@ func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc { if err != nil { return nil, err } - newFrom = reflect.ValueOf(data) + if v, ok := data.(reflect.Value); ok { + newFrom = v + } else { + newFrom = reflect.ValueOf(data) + } } return data, nil @@ -110,13 +114,13 @@ func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc { // OrComposeDecodeHookFunc executes all input hook functions until one of them returns no error. In that case its value is returned. // If all hooks return an error, OrComposeDecodeHookFunc returns an error concatenating all error messages. func OrComposeDecodeHookFunc(ff ...DecodeHookFunc) DecodeHookFunc { - cached := make([]func(from reflect.Value, to reflect.Value) (interface{}, error), 0, len(ff)) + cached := make([]func(from reflect.Value, to reflect.Value) (any, error), 0, len(ff)) for _, f := range ff { cached = append(cached, cachedDecodeHook(f)) } - return func(a, b reflect.Value) (interface{}, error) { + return func(a, b reflect.Value) (any, error) { var allErrs string - var out interface{} + var out any var err error for _, c := range cached { @@ -139,8 +143,8 @@ func StringToSliceHookFunc(sep string) DecodeHookFunc { return func( f reflect.Type, t reflect.Type, - data interface{}, - ) (interface{}, error) { + data any, + ) (any, error) { if f.Kind() != reflect.String { return data, nil } @@ -157,14 +161,37 @@ func StringToSliceHookFunc(sep string) DecodeHookFunc { } } +// StringToWeakSliceHookFunc brings back the old (pre-v2) behavior of [StringToSliceHookFunc]. +// +// As of mapstructure v2.0.0 [StringToSliceHookFunc] checks if the return type is a string slice. +// This function removes that check. +func StringToWeakSliceHookFunc(sep string) DecodeHookFunc { + return func( + f reflect.Type, + t reflect.Type, + data any, + ) (any, error) { + if f.Kind() != reflect.String || t.Kind() != reflect.Slice { + return data, nil + } + + raw := data.(string) + if raw == "" { + return []string{}, nil + } + + return strings.Split(raw, sep), nil + } +} + // StringToTimeDurationHookFunc returns a DecodeHookFunc that converts // strings to time.Duration. func StringToTimeDurationHookFunc() DecodeHookFunc { return func( f reflect.Type, t reflect.Type, - data interface{}, - ) (interface{}, error) { + data any, + ) (any, error) { if f.Kind() != reflect.String { return data, nil } @@ -173,7 +200,29 @@ func StringToTimeDurationHookFunc() DecodeHookFunc { } // Convert it by parsing - return time.ParseDuration(data.(string)) + d, err := time.ParseDuration(data.(string)) + + return d, wrapTimeParseDurationError(err) + } +} + +// StringToTimeLocationHookFunc returns a DecodeHookFunc that converts +// strings to *time.Location. +func StringToTimeLocationHookFunc() DecodeHookFunc { + return func( + f reflect.Type, + t reflect.Type, + data any, + ) (any, error) { + if f.Kind() != reflect.String { + return data, nil + } + if t != reflect.TypeOf(time.Local) { + return data, nil + } + d, err := time.LoadLocation(data.(string)) + + return d, wrapTimeParseLocationError(err) } } @@ -183,8 +232,8 @@ func StringToURLHookFunc() DecodeHookFunc { return func( f reflect.Type, t reflect.Type, - data interface{}, - ) (interface{}, error) { + data any, + ) (any, error) { if f.Kind() != reflect.String { return data, nil } @@ -193,7 +242,9 @@ func StringToURLHookFunc() DecodeHookFunc { } // Convert it by parsing - return url.Parse(data.(string)) + u, err := url.Parse(data.(string)) + + return u, wrapUrlError(err) } } @@ -203,8 +254,8 @@ func StringToIPHookFunc() DecodeHookFunc { return func( f reflect.Type, t reflect.Type, - data interface{}, - ) (interface{}, error) { + data any, + ) (any, error) { if f.Kind() != reflect.String { return data, nil } @@ -215,7 +266,7 @@ func StringToIPHookFunc() DecodeHookFunc { // Convert it by parsing ip := net.ParseIP(data.(string)) if ip == nil { - return net.IP{}, fmt.Errorf("failed parsing ip %v", data) + return net.IP{}, fmt.Errorf("failed parsing ip") } return ip, nil @@ -228,8 +279,8 @@ func StringToIPNetHookFunc() DecodeHookFunc { return func( f reflect.Type, t reflect.Type, - data interface{}, - ) (interface{}, error) { + data any, + ) (any, error) { if f.Kind() != reflect.String { return data, nil } @@ -239,7 +290,7 @@ func StringToIPNetHookFunc() DecodeHookFunc { // Convert it by parsing _, net, err := net.ParseCIDR(data.(string)) - return net, err + return net, wrapNetParseError(err) } } @@ -249,8 +300,8 @@ func StringToTimeHookFunc(layout string) DecodeHookFunc { return func( f reflect.Type, t reflect.Type, - data interface{}, - ) (interface{}, error) { + data any, + ) (any, error) { if f.Kind() != reflect.String { return data, nil } @@ -259,7 +310,9 @@ func StringToTimeHookFunc(layout string) DecodeHookFunc { } // Convert it by parsing - return time.Parse(layout, data.(string)) + ti, err := time.Parse(layout, data.(string)) + + return ti, wrapTimeParseError(err) } } @@ -271,8 +324,8 @@ func StringToTimeHookFunc(layout string) DecodeHookFunc { func WeaklyTypedHook( f reflect.Kind, t reflect.Kind, - data interface{}, -) (interface{}, error) { + data any, +) (any, error) { dataVal := reflect.ValueOf(data) switch t { case reflect.String: @@ -301,17 +354,17 @@ func WeaklyTypedHook( } func RecursiveStructToMapHookFunc() DecodeHookFunc { - return func(f reflect.Value, t reflect.Value) (interface{}, error) { + return func(f reflect.Value, t reflect.Value) (any, error) { if f.Kind() != reflect.Struct { return f.Interface(), nil } - var i interface{} = struct{}{} + var i any = struct{}{} if t.Type() != reflect.TypeOf(&i).Elem() { return f.Interface(), nil } - m := make(map[string]interface{}) + m := make(map[string]any) t.Set(reflect.ValueOf(m)) return f.Interface(), nil @@ -325,8 +378,8 @@ func TextUnmarshallerHookFunc() DecodeHookFuncType { return func( f reflect.Type, t reflect.Type, - data interface{}, - ) (interface{}, error) { + data any, + ) (any, error) { if f.Kind() != reflect.String { return data, nil } @@ -352,8 +405,8 @@ func StringToNetIPAddrHookFunc() DecodeHookFunc { return func( f reflect.Type, t reflect.Type, - data interface{}, - ) (interface{}, error) { + data any, + ) (any, error) { if f.Kind() != reflect.String { return data, nil } @@ -362,7 +415,9 @@ func StringToNetIPAddrHookFunc() DecodeHookFunc { } // Convert it by parsing - return netip.ParseAddr(data.(string)) + addr, err := netip.ParseAddr(data.(string)) + + return addr, wrapNetIPParseAddrError(err) } } @@ -372,8 +427,8 @@ func StringToNetIPAddrPortHookFunc() DecodeHookFunc { return func( f reflect.Type, t reflect.Type, - data interface{}, - ) (interface{}, error) { + data any, + ) (any, error) { if f.Kind() != reflect.String { return data, nil } @@ -382,7 +437,31 @@ func StringToNetIPAddrPortHookFunc() DecodeHookFunc { } // Convert it by parsing - return netip.ParseAddrPort(data.(string)) + addrPort, err := netip.ParseAddrPort(data.(string)) + + return addrPort, wrapNetIPParseAddrPortError(err) + } +} + +// StringToNetIPPrefixHookFunc returns a DecodeHookFunc that converts +// strings to netip.Prefix. +func StringToNetIPPrefixHookFunc() DecodeHookFunc { + return func( + f reflect.Type, + t reflect.Type, + data any, + ) (any, error) { + if f.Kind() != reflect.String { + return data, nil + } + if t != reflect.TypeOf(netip.Prefix{}) { + return data, nil + } + + // Convert it by parsing + prefix, err := netip.ParsePrefix(data.(string)) + + return prefix, wrapNetIPParsePrefixError(err) } } @@ -415,178 +494,182 @@ func StringToBasicTypeHookFunc() DecodeHookFunc { // StringToInt8HookFunc returns a DecodeHookFunc that converts // strings to int8. func StringToInt8HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Int8 { return data, nil } // Convert it by parsing i64, err := strconv.ParseInt(data.(string), 0, 8) - return int8(i64), err + return int8(i64), wrapStrconvNumError(err) } } // StringToUint8HookFunc returns a DecodeHookFunc that converts // strings to uint8. func StringToUint8HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Uint8 { return data, nil } // Convert it by parsing u64, err := strconv.ParseUint(data.(string), 0, 8) - return uint8(u64), err + return uint8(u64), wrapStrconvNumError(err) } } // StringToInt16HookFunc returns a DecodeHookFunc that converts // strings to int16. func StringToInt16HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Int16 { return data, nil } // Convert it by parsing i64, err := strconv.ParseInt(data.(string), 0, 16) - return int16(i64), err + return int16(i64), wrapStrconvNumError(err) } } // StringToUint16HookFunc returns a DecodeHookFunc that converts // strings to uint16. func StringToUint16HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Uint16 { return data, nil } // Convert it by parsing u64, err := strconv.ParseUint(data.(string), 0, 16) - return uint16(u64), err + return uint16(u64), wrapStrconvNumError(err) } } // StringToInt32HookFunc returns a DecodeHookFunc that converts // strings to int32. func StringToInt32HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Int32 { return data, nil } // Convert it by parsing i64, err := strconv.ParseInt(data.(string), 0, 32) - return int32(i64), err + return int32(i64), wrapStrconvNumError(err) } } // StringToUint32HookFunc returns a DecodeHookFunc that converts // strings to uint32. func StringToUint32HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Uint32 { return data, nil } // Convert it by parsing u64, err := strconv.ParseUint(data.(string), 0, 32) - return uint32(u64), err + return uint32(u64), wrapStrconvNumError(err) } } // StringToInt64HookFunc returns a DecodeHookFunc that converts // strings to int64. func StringToInt64HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Int64 { return data, nil } // Convert it by parsing - return strconv.ParseInt(data.(string), 0, 64) + i64, err := strconv.ParseInt(data.(string), 0, 64) + return int64(i64), wrapStrconvNumError(err) } } // StringToUint64HookFunc returns a DecodeHookFunc that converts // strings to uint64. func StringToUint64HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Uint64 { return data, nil } // Convert it by parsing - return strconv.ParseUint(data.(string), 0, 64) + u64, err := strconv.ParseUint(data.(string), 0, 64) + return uint64(u64), wrapStrconvNumError(err) } } // StringToIntHookFunc returns a DecodeHookFunc that converts // strings to int. func StringToIntHookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Int { return data, nil } // Convert it by parsing i64, err := strconv.ParseInt(data.(string), 0, 0) - return int(i64), err + return int(i64), wrapStrconvNumError(err) } } // StringToUintHookFunc returns a DecodeHookFunc that converts // strings to uint. func StringToUintHookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Uint { return data, nil } // Convert it by parsing u64, err := strconv.ParseUint(data.(string), 0, 0) - return uint(u64), err + return uint(u64), wrapStrconvNumError(err) } } // StringToFloat32HookFunc returns a DecodeHookFunc that converts // strings to float32. func StringToFloat32HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Float32 { return data, nil } // Convert it by parsing f64, err := strconv.ParseFloat(data.(string), 32) - return float32(f64), err + return float32(f64), wrapStrconvNumError(err) } } // StringToFloat64HookFunc returns a DecodeHookFunc that converts // strings to float64. func StringToFloat64HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Float64 { return data, nil } // Convert it by parsing - return strconv.ParseFloat(data.(string), 64) + f64, err := strconv.ParseFloat(data.(string), 64) + return f64, wrapStrconvNumError(err) } } // StringToBoolHookFunc returns a DecodeHookFunc that converts // strings to bool. func StringToBoolHookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Bool { return data, nil } // Convert it by parsing - return strconv.ParseBool(data.(string)) + b, err := strconv.ParseBool(data.(string)) + return b, wrapStrconvNumError(err) } } @@ -605,26 +688,27 @@ func StringToRuneHookFunc() DecodeHookFunc { // StringToComplex64HookFunc returns a DecodeHookFunc that converts // strings to complex64. func StringToComplex64HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Complex64 { return data, nil } // Convert it by parsing c128, err := strconv.ParseComplex(data.(string), 64) - return complex64(c128), err + return complex64(c128), wrapStrconvNumError(err) } } // StringToComplex128HookFunc returns a DecodeHookFunc that converts // strings to complex128. func StringToComplex128HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Complex128 { return data, nil } // Convert it by parsing - return strconv.ParseComplex(data.(string), 128) + c128, err := strconv.ParseComplex(data.(string), 128) + return c128, wrapStrconvNumError(err) } } diff --git a/vendor/github.com/go-viper/mapstructure/v2/devenv.lock b/vendor/github.com/go-viper/mapstructure/v2/devenv.lock new file mode 100644 index 000000000..72c2c9b4d --- /dev/null +++ b/vendor/github.com/go-viper/mapstructure/v2/devenv.lock @@ -0,0 +1,103 @@ +{ + "nodes": { + "devenv": { + "locked": { + "dir": "src/modules", + "lastModified": 1765288076, + "owner": "cachix", + "repo": "devenv", + "rev": "93c055af1e8fcac49251f1b2e1c57f78620ad351", + "type": "github" + }, + "original": { + "dir": "src/modules", + "owner": "cachix", + "repo": "devenv", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1765121682, + "owner": "edolstra", + "repo": "flake-compat", + "rev": "65f23138d8d09a92e30f1e5c87611b23ef451bf3", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "git-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1765016596, + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "548fc44fca28a5e81c5d6b846e555e6b9c2a5a3c", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "git-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1762808025, + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "cb5e3fdca1de58ccbc3ef53de65bd372b48f567c", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1764580874, + "owner": "cachix", + "repo": "devenv-nixpkgs", + "rev": "dcf61356c3ab25f1362b4a4428a6d871e84f1d1d", + "type": "github" + }, + "original": { + "owner": "cachix", + "ref": "rolling", + "repo": "devenv-nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "devenv": "devenv", + "git-hooks": "git-hooks", + "nixpkgs": "nixpkgs", + "pre-commit-hooks": [ + "git-hooks" + ] + } + } + }, + "root": "root", + "version": 7 +} diff --git a/vendor/github.com/go-viper/mapstructure/v2/devenv.nix b/vendor/github.com/go-viper/mapstructure/v2/devenv.nix new file mode 100644 index 000000000..b31ab7a1f --- /dev/null +++ b/vendor/github.com/go-viper/mapstructure/v2/devenv.nix @@ -0,0 +1,14 @@ +{ + pkgs, + ... +}: + +{ + languages = { + go.enable = true; + }; + + packages = with pkgs; [ + golangci-lint + ]; +} diff --git a/vendor/github.com/go-viper/mapstructure/v2/devenv.yaml b/vendor/github.com/go-viper/mapstructure/v2/devenv.yaml new file mode 100644 index 000000000..68616a49c --- /dev/null +++ b/vendor/github.com/go-viper/mapstructure/v2/devenv.yaml @@ -0,0 +1,4 @@ +# yaml-language-server: $schema=https://devenv.sh/devenv.schema.json +inputs: + nixpkgs: + url: github:cachix/devenv-nixpkgs/rolling diff --git a/vendor/github.com/go-viper/mapstructure/v2/errors.go b/vendor/github.com/go-viper/mapstructure/v2/errors.go new file mode 100644 index 000000000..07d31c22a --- /dev/null +++ b/vendor/github.com/go-viper/mapstructure/v2/errors.go @@ -0,0 +1,244 @@ +package mapstructure + +import ( + "errors" + "fmt" + "net" + "net/url" + "reflect" + "strconv" + "strings" + "time" +) + +// Error interface is implemented by all errors emitted by mapstructure. +// +// Use [errors.As] to check if an error implements this interface. +type Error interface { + error + + mapstructure() +} + +// DecodeError is a generic error type that holds information about +// a decoding error together with the name of the field that caused the error. +type DecodeError struct { + name string + err error +} + +func newDecodeError(name string, err error) *DecodeError { + return &DecodeError{ + name: name, + err: err, + } +} + +func (e *DecodeError) Name() string { + return e.name +} + +func (e *DecodeError) Unwrap() error { + return e.err +} + +func (e *DecodeError) Error() string { + return fmt.Sprintf("'%s' %s", e.name, e.err) +} + +func (*DecodeError) mapstructure() {} + +// ParseError is an error type that indicates a value could not be parsed +// into the expected type. +type ParseError struct { + Expected reflect.Value + Value any + Err error +} + +func (e *ParseError) Error() string { + return fmt.Sprintf("cannot parse value as '%s': %s", e.Expected.Type(), e.Err) +} + +func (*ParseError) mapstructure() {} + +// UnconvertibleTypeError is an error type that indicates a value could not be +// converted to the expected type. +type UnconvertibleTypeError struct { + Expected reflect.Value + Value any +} + +func (e *UnconvertibleTypeError) Error() string { + return fmt.Sprintf( + "expected type '%s', got unconvertible type '%s'", + e.Expected.Type(), + reflect.TypeOf(e.Value), + ) +} + +func (*UnconvertibleTypeError) mapstructure() {} + +func wrapStrconvNumError(err error) error { + if err == nil { + return nil + } + + if err, ok := err.(*strconv.NumError); ok { + return &strconvNumError{Err: err} + } + + return err +} + +type strconvNumError struct { + Err *strconv.NumError +} + +func (e *strconvNumError) Error() string { + return "strconv." + e.Err.Func + ": " + e.Err.Err.Error() +} + +func (e *strconvNumError) Unwrap() error { return e.Err } + +func wrapUrlError(err error) error { + if err == nil { + return nil + } + + if err, ok := err.(*url.Error); ok { + return &urlError{Err: err} + } + + return err +} + +type urlError struct { + Err *url.Error +} + +func (e *urlError) Error() string { + return fmt.Sprintf("%s", e.Err.Err) +} + +func (e *urlError) Unwrap() error { return e.Err } + +func wrapNetParseError(err error) error { + if err == nil { + return nil + } + + if err, ok := err.(*net.ParseError); ok { + return &netParseError{Err: err} + } + + return err +} + +type netParseError struct { + Err *net.ParseError +} + +func (e *netParseError) Error() string { + return "invalid " + e.Err.Type +} + +func (e *netParseError) Unwrap() error { return e.Err } + +func wrapTimeParseError(err error) error { + if err == nil { + return nil + } + + if err, ok := err.(*time.ParseError); ok { + return &timeParseError{Err: err} + } + + return err +} + +type timeParseError struct { + Err *time.ParseError +} + +func (e *timeParseError) Error() string { + if e.Err.Message == "" { + return fmt.Sprintf("parsing time as %q: cannot parse as %q", e.Err.Layout, e.Err.LayoutElem) + } + + return "parsing time " + e.Err.Message +} + +func (e *timeParseError) Unwrap() error { return e.Err } + +func wrapNetIPParseAddrError(err error) error { + if err == nil { + return nil + } + + if errMsg := err.Error(); strings.HasPrefix(errMsg, "ParseAddr") { + errPieces := strings.Split(errMsg, ": ") + + return fmt.Errorf("ParseAddr: %s", errPieces[len(errPieces)-1]) + } + + return err +} + +func wrapNetIPParseAddrPortError(err error) error { + if err == nil { + return nil + } + + errMsg := err.Error() + if strings.HasPrefix(errMsg, "invalid port ") { + return errors.New("invalid port") + } else if strings.HasPrefix(errMsg, "invalid ip:port ") { + return errors.New("invalid ip:port") + } + + return err +} + +func wrapNetIPParsePrefixError(err error) error { + if err == nil { + return nil + } + + if errMsg := err.Error(); strings.HasPrefix(errMsg, "netip.ParsePrefix") { + errPieces := strings.Split(errMsg, ": ") + + return fmt.Errorf("netip.ParsePrefix: %s", errPieces[len(errPieces)-1]) + } + + return err +} + +func wrapTimeParseDurationError(err error) error { + if err == nil { + return nil + } + + errMsg := err.Error() + if strings.HasPrefix(errMsg, "time: unknown unit ") { + return errors.New("time: unknown unit") + } else if strings.HasPrefix(errMsg, "time: ") { + idx := strings.LastIndex(errMsg, " ") + + return errors.New(errMsg[:idx]) + } + + return err +} + +func wrapTimeParseLocationError(err error) error { + if err == nil { + return nil + } + errMsg := err.Error() + if strings.Contains(errMsg, "unknown time zone") || strings.HasPrefix(errMsg, "time: unknown format") { + return fmt.Errorf("invalid time zone format: %w", err) + } + + return err +} diff --git a/vendor/github.com/go-viper/mapstructure/v2/flake.lock b/vendor/github.com/go-viper/mapstructure/v2/flake.lock deleted file mode 100644 index 4bea8154e..000000000 --- a/vendor/github.com/go-viper/mapstructure/v2/flake.lock +++ /dev/null @@ -1,472 +0,0 @@ -{ - "nodes": { - "cachix": { - "inputs": { - "devenv": "devenv_2", - "flake-compat": [ - "devenv", - "flake-compat" - ], - "nixpkgs": [ - "devenv", - "nixpkgs" - ], - "pre-commit-hooks": [ - "devenv", - "pre-commit-hooks" - ] - }, - "locked": { - "lastModified": 1712055811, - "narHash": "sha256-7FcfMm5A/f02yyzuavJe06zLa9hcMHsagE28ADcmQvk=", - "owner": "cachix", - "repo": "cachix", - "rev": "02e38da89851ec7fec3356a5c04bc8349cae0e30", - "type": "github" - }, - "original": { - "owner": "cachix", - "repo": "cachix", - "type": "github" - } - }, - "devenv": { - "inputs": { - "cachix": "cachix", - "flake-compat": "flake-compat_2", - "nix": "nix_2", - "nixpkgs": "nixpkgs_2", - "pre-commit-hooks": "pre-commit-hooks" - }, - "locked": { - "lastModified": 1717245169, - "narHash": "sha256-+mW3rTBjGU8p1THJN0lX/Dd/8FbnF+3dB+mJuSaxewE=", - "owner": "cachix", - "repo": "devenv", - "rev": "c3f9f053c077c6f88a3de5276d9178c62baa3fc3", - "type": "github" - }, - "original": { - "owner": "cachix", - "repo": "devenv", - "type": "github" - } - }, - "devenv_2": { - "inputs": { - "flake-compat": [ - "devenv", - "cachix", - "flake-compat" - ], - "nix": "nix", - "nixpkgs": "nixpkgs", - "poetry2nix": "poetry2nix", - "pre-commit-hooks": [ - "devenv", - "cachix", - "pre-commit-hooks" - ] - }, - "locked": { - "lastModified": 1708704632, - "narHash": "sha256-w+dOIW60FKMaHI1q5714CSibk99JfYxm0CzTinYWr+Q=", - "owner": "cachix", - "repo": "devenv", - "rev": "2ee4450b0f4b95a1b90f2eb5ffea98b90e48c196", - "type": "github" - }, - "original": { - "owner": "cachix", - "ref": "python-rewrite", - "repo": "devenv", - "type": "github" - } - }, - "flake-compat": { - "flake": false, - "locked": { - "lastModified": 1673956053, - "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", - "owner": "edolstra", - "repo": "flake-compat", - "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, - "flake-compat_2": { - "flake": false, - "locked": { - "lastModified": 1696426674, - "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", - "owner": "edolstra", - "repo": "flake-compat", - "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, - "flake-parts": { - "inputs": { - "nixpkgs-lib": "nixpkgs-lib" - }, - "locked": { - "lastModified": 1717285511, - "narHash": "sha256-iKzJcpdXih14qYVcZ9QC9XuZYnPc6T8YImb6dX166kw=", - "owner": "hercules-ci", - "repo": "flake-parts", - "rev": "2a55567fcf15b1b1c7ed712a2c6fadaec7412ea8", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "repo": "flake-parts", - "type": "github" - } - }, - "flake-utils": { - "inputs": { - "systems": "systems" - }, - "locked": { - "lastModified": 1689068808, - "narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "flake-utils_2": { - "inputs": { - "systems": "systems_2" - }, - "locked": { - "lastModified": 1710146030, - "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "gitignore": { - "inputs": { - "nixpkgs": [ - "devenv", - "pre-commit-hooks", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1709087332, - "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", - "owner": "hercules-ci", - "repo": "gitignore.nix", - "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "repo": "gitignore.nix", - "type": "github" - } - }, - "nix": { - "inputs": { - "flake-compat": "flake-compat", - "nixpkgs": [ - "devenv", - "cachix", - "devenv", - "nixpkgs" - ], - "nixpkgs-regression": "nixpkgs-regression" - }, - "locked": { - "lastModified": 1712911606, - "narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=", - "owner": "domenkozar", - "repo": "nix", - "rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12", - "type": "github" - }, - "original": { - "owner": "domenkozar", - "ref": "devenv-2.21", - "repo": "nix", - "type": "github" - } - }, - "nix-github-actions": { - "inputs": { - "nixpkgs": [ - "devenv", - "cachix", - "devenv", - "poetry2nix", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1688870561, - "narHash": "sha256-4UYkifnPEw1nAzqqPOTL2MvWtm3sNGw1UTYTalkTcGY=", - "owner": "nix-community", - "repo": "nix-github-actions", - "rev": "165b1650b753316aa7f1787f3005a8d2da0f5301", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "nix-github-actions", - "type": "github" - } - }, - "nix_2": { - "inputs": { - "flake-compat": [ - "devenv", - "flake-compat" - ], - "nixpkgs": [ - "devenv", - "nixpkgs" - ], - "nixpkgs-regression": "nixpkgs-regression_2" - }, - "locked": { - "lastModified": 1712911606, - "narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=", - "owner": "domenkozar", - "repo": "nix", - "rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12", - "type": "github" - }, - "original": { - "owner": "domenkozar", - "ref": "devenv-2.21", - "repo": "nix", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1692808169, - "narHash": "sha256-x9Opq06rIiwdwGeK2Ykj69dNc2IvUH1fY55Wm7atwrE=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "9201b5ff357e781bf014d0330d18555695df7ba8", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-lib": { - "locked": { - "lastModified": 1717284937, - "narHash": "sha256-lIbdfCsf8LMFloheeE6N31+BMIeixqyQWbSr2vk79EQ=", - "type": "tarball", - "url": "https://github.com/NixOS/nixpkgs/archive/eb9ceca17df2ea50a250b6b27f7bf6ab0186f198.tar.gz" - }, - "original": { - "type": "tarball", - "url": "https://github.com/NixOS/nixpkgs/archive/eb9ceca17df2ea50a250b6b27f7bf6ab0186f198.tar.gz" - } - }, - "nixpkgs-regression": { - "locked": { - "lastModified": 1643052045, - "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", - "type": "github" - }, - "original": { - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", - "type": "github" - } - }, - "nixpkgs-regression_2": { - "locked": { - "lastModified": 1643052045, - "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", - "type": "github" - }, - "original": { - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", - "type": "github" - } - }, - "nixpkgs-stable": { - "locked": { - "lastModified": 1710695816, - "narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "614b4613980a522ba49f0d194531beddbb7220d3", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-23.11", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1713361204, - "narHash": "sha256-TA6EDunWTkc5FvDCqU3W2T3SFn0gRZqh6D/hJnM02MM=", - "owner": "cachix", - "repo": "devenv-nixpkgs", - "rev": "285676e87ad9f0ca23d8714a6ab61e7e027020c6", - "type": "github" - }, - "original": { - "owner": "cachix", - "ref": "rolling", - "repo": "devenv-nixpkgs", - "type": "github" - } - }, - "nixpkgs_3": { - "locked": { - "lastModified": 1717112898, - "narHash": "sha256-7R2ZvOnvd9h8fDd65p0JnB7wXfUvreox3xFdYWd1BnY=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "6132b0f6e344ce2fe34fc051b72fb46e34f668e0", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "poetry2nix": { - "inputs": { - "flake-utils": "flake-utils", - "nix-github-actions": "nix-github-actions", - "nixpkgs": [ - "devenv", - "cachix", - "devenv", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1692876271, - "narHash": "sha256-IXfZEkI0Mal5y1jr6IRWMqK8GW2/f28xJenZIPQqkY0=", - "owner": "nix-community", - "repo": "poetry2nix", - "rev": "d5006be9c2c2417dafb2e2e5034d83fabd207ee3", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "poetry2nix", - "type": "github" - } - }, - "pre-commit-hooks": { - "inputs": { - "flake-compat": [ - "devenv", - "flake-compat" - ], - "flake-utils": "flake-utils_2", - "gitignore": "gitignore", - "nixpkgs": [ - "devenv", - "nixpkgs" - ], - "nixpkgs-stable": "nixpkgs-stable" - }, - "locked": { - "lastModified": 1713775815, - "narHash": "sha256-Wu9cdYTnGQQwtT20QQMg7jzkANKQjwBD9iccfGKkfls=", - "owner": "cachix", - "repo": "pre-commit-hooks.nix", - "rev": "2ac4dcbf55ed43f3be0bae15e181f08a57af24a4", - "type": "github" - }, - "original": { - "owner": "cachix", - "repo": "pre-commit-hooks.nix", - "type": "github" - } - }, - "root": { - "inputs": { - "devenv": "devenv", - "flake-parts": "flake-parts", - "nixpkgs": "nixpkgs_3" - } - }, - "systems": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, - "systems_2": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/vendor/github.com/go-viper/mapstructure/v2/flake.nix b/vendor/github.com/go-viper/mapstructure/v2/flake.nix deleted file mode 100644 index 4ed0f5331..000000000 --- a/vendor/github.com/go-viper/mapstructure/v2/flake.nix +++ /dev/null @@ -1,39 +0,0 @@ -{ - inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; - flake-parts.url = "github:hercules-ci/flake-parts"; - devenv.url = "github:cachix/devenv"; - }; - - outputs = inputs@{ flake-parts, ... }: - flake-parts.lib.mkFlake { inherit inputs; } { - imports = [ - inputs.devenv.flakeModule - ]; - - systems = [ "x86_64-linux" "x86_64-darwin" "aarch64-darwin" ]; - - perSystem = { config, self', inputs', pkgs, system, ... }: rec { - devenv.shells = { - default = { - languages = { - go.enable = true; - }; - - pre-commit.hooks = { - nixpkgs-fmt.enable = true; - }; - - packages = with pkgs; [ - golangci-lint - ]; - - # https://github.com/cachix/devenv/issues/528#issuecomment-1556108767 - containers = pkgs.lib.mkForce { }; - }; - - ci = devenv.shells.default; - }; - }; - }; -} diff --git a/vendor/github.com/go-viper/mapstructure/v2/mapstructure.go b/vendor/github.com/go-viper/mapstructure/v2/mapstructure.go index e77e63ba3..9087fd96c 100644 --- a/vendor/github.com/go-viper/mapstructure/v2/mapstructure.go +++ b/vendor/github.com/go-viper/mapstructure/v2/mapstructure.go @@ -1,5 +1,5 @@ // Package mapstructure exposes functionality to convert one arbitrary -// Go type into another, typically to convert a map[string]interface{} +// Go type into another, typically to convert a map[string]any // into a native Go structure. // // The Go structure can be arbitrarily complex, containing slices, @@ -54,8 +54,8 @@ // // This would require an input that looks like below: // -// map[string]interface{}{ -// "person": map[string]interface{}{"name": "alice"}, +// map[string]any{ +// "person": map[string]any{"name": "alice"}, // } // // If your "person" value is NOT nested, then you can append ",squash" to @@ -68,7 +68,7 @@ // // Now the following input would be accepted: // -// map[string]interface{}{ +// map[string]any{ // "name": "alice", // } // @@ -79,7 +79,7 @@ // // Will be decoded into a map: // -// map[string]interface{}{ +// map[string]any{ // "name": "alice", // } // @@ -95,18 +95,18 @@ // // You can also use the ",remain" suffix on your tag to collect all unused // values in a map. The field with this tag MUST be a map type and should -// probably be a "map[string]interface{}" or "map[interface{}]interface{}". +// probably be a "map[string]any" or "map[any]any". // See example below: // // type Friend struct { // Name string -// Other map[string]interface{} `mapstructure:",remain"` +// Other map[string]any `mapstructure:",remain"` // } // // Given the input below, Other would be populated with the other // values that weren't used (everything but "name"): // -// map[string]interface{}{ +// map[string]any{ // "name": "bob", // "address": "123 Maple St.", // } @@ -115,15 +115,36 @@ // // When decoding from a struct to any other value, you may use the // ",omitempty" suffix on your tag to omit that value if it equates to -// the zero value. The zero value of all types is specified in the Go -// specification. +// the zero value, or a zero-length element. The zero value of all types is +// specified in the Go specification. // // For example, the zero type of a numeric type is zero ("0"). If the struct // field value is zero and a numeric type, the field is empty, and it won't -// be encoded into the destination type. +// be encoded into the destination type. And likewise for the URLs field, if the +// slice is nil or empty, it won't be encoded into the destination type. // // type Source struct { -// Age int `mapstructure:",omitempty"` +// Age int `mapstructure:",omitempty"` +// URLs []string `mapstructure:",omitempty"` +// } +// +// # Omit Zero Values +// +// When decoding from a struct to any other value, you may use the +// ",omitzero" suffix on your tag to omit that value if it equates to the zero +// value. The zero value of all types is specified in the Go specification. +// +// For example, the zero type of a numeric type is zero ("0"). If the struct +// field value is zero and a numeric type, the field is empty, and it won't +// be encoded into the destination type. And likewise for the URLs field, if the +// slice is nil, it won't be encoded into the destination type. +// +// Note that if the field is a slice, and it is empty but not nil, it will +// still be encoded into the destination type. +// +// type Source struct { +// Age int `mapstructure:",omitzero"` +// URLs []string `mapstructure:",omitzero"` // } // // # Unexported fields @@ -140,7 +161,7 @@ // // Using this map as input: // -// map[string]interface{}{ +// map[string]any{ // "private": "I will be ignored", // "Public": "I made it through!", // } @@ -152,6 +173,25 @@ // Public: "I made it through!" // } // +// # Custom Decoding with Unmarshaler +// +// Types can implement the Unmarshaler interface to control their own decoding. The interface +// behaves similarly to how UnmarshalJSON does in the standard library. It can be used as an +// alternative or companion to a DecodeHook. +// +// type TrimmedString string +// +// func (t *TrimmedString) UnmarshalMapstructure(input any) error { +// str, ok := input.(string) +// if !ok { +// return fmt.Errorf("expected string, got %T", input) +// } +// *t = TrimmedString(strings.TrimSpace(str)) +// return nil +// } +// +// See the Unmarshaler interface documentation for more details. +// // # Other Configuration // // mapstructure is highly configurable. See the DecoderConfig struct @@ -183,19 +223,30 @@ import ( // we started with Kinds and then realized Types were the better solution, // but have a promise to not break backwards compat so we now support // both. -type DecodeHookFunc interface{} +type DecodeHookFunc any // DecodeHookFuncType is a DecodeHookFunc which has complete information about // the source and target types. -type DecodeHookFuncType func(reflect.Type, reflect.Type, interface{}) (interface{}, error) +type DecodeHookFuncType func(reflect.Type, reflect.Type, any) (any, error) // DecodeHookFuncKind is a DecodeHookFunc which knows only the Kinds of the // source and target types. -type DecodeHookFuncKind func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) +type DecodeHookFuncKind func(reflect.Kind, reflect.Kind, any) (any, error) // DecodeHookFuncValue is a DecodeHookFunc which has complete access to both the source and target // values. -type DecodeHookFuncValue func(from reflect.Value, to reflect.Value) (interface{}, error) +type DecodeHookFuncValue func(from reflect.Value, to reflect.Value) (any, error) + +// Unmarshaler is the interface implemented by types that can unmarshal +// themselves. UnmarshalMapstructure receives the input data (potentially +// transformed by DecodeHook) and should populate the receiver with the +// decoded values. +// +// The Unmarshaler interface takes precedence over the default decoding +// logic for any type (structs, slices, maps, primitives, etc.). +type Unmarshaler interface { + UnmarshalMapstructure(any) error +} // DecoderConfig is the configuration that is used to create a new decoder // and allows customization of various aspects of decoding. @@ -222,6 +273,12 @@ type DecoderConfig struct { // will affect all nested structs as well. ErrorUnset bool + // AllowUnsetPointer, if set to true, will prevent fields with pointer types + // from being reported as unset, even if ErrorUnset is true and the field was + // not present in the input data. This allows pointer fields to be optional + // without triggering an error when they are missing. + AllowUnsetPointer bool + // ZeroFields, if set to true, will zero fields before writing them. // For example, a map will be emptied before decoded values are put in // it. If this is false, a map will be merged. @@ -254,18 +311,31 @@ type DecoderConfig struct { // } Squash bool + // Deep will map structures in slices instead of copying them + // + // type Parent struct { + // Children []Child `mapstructure:",deep"` + // } + Deep bool + // Metadata is the struct that will contain extra metadata about // the decoding. If this is nil, then no metadata will be tracked. Metadata *Metadata // Result is a pointer to the struct that will contain the decoded // value. - Result interface{} + Result any // The tag name that mapstructure reads for field names. This - // defaults to "mapstructure" + // defaults to "mapstructure". Multiple tag names can be specified + // as a comma-separated list (e.g., "yaml,json"), and the first + // matching non-empty tag will be used. TagName string + // RootName specifies the name to use for the root element in error messages. For example: + // '' has unset fields: + RootName string + // The option of the value in the tag that indicates a field should // be squashed. This defaults to "squash". SquashTagOption string @@ -277,11 +347,34 @@ type DecoderConfig struct { // MatchName is the function used to match the map key to the struct // field name or tag. Defaults to `strings.EqualFold`. This can be used // to implement case-sensitive tag values, support snake casing, etc. + // + // MatchName is used as a fallback comparison when the direct key lookup fails. + // See also MapFieldName for transforming field names before lookup. MatchName func(mapKey, fieldName string) bool // DecodeNil, if set to true, will cause the DecodeHook (if present) to run // even if the input is nil. This can be used to provide default values. DecodeNil bool + + // MapFieldName is the function used to convert the struct field name to the map's key name. + // + // This is useful for automatically converting between naming conventions without + // explicitly tagging each field. For example, to convert Go's PascalCase field names + // to snake_case map keys: + // + // MapFieldName: func(s string) string { + // return strcase.ToSnake(s) + // } + // + // When decoding from a map to a struct, the transformed field name is used for + // the initial lookup. If not found, MatchName is used as a fallback comparison. + // Explicit struct tags always take precedence over MapFieldName. + MapFieldName func(string) string + + // DisableUnmarshaler, if set to true, disables the use of the Unmarshaler + // interface. Types implementing Unmarshaler will be decoded using the + // standard struct decoding logic instead. + DisableUnmarshaler bool } // A Decoder takes a raw interface value and turns it into structured @@ -292,7 +385,7 @@ type DecoderConfig struct { // up the most basic Decoder. type Decoder struct { config *DecoderConfig - cachedDecodeHook func(from reflect.Value, to reflect.Value) (interface{}, error) + cachedDecodeHook func(from reflect.Value, to reflect.Value) (any, error) } // Metadata contains information about decoding a structure that @@ -313,7 +406,7 @@ type Metadata struct { // Decode takes an input structure and uses reflection to translate it to // the output structure. output must be a pointer to a map or struct. -func Decode(input interface{}, output interface{}) error { +func Decode(input any, output any) error { config := &DecoderConfig{ Metadata: nil, Result: output, @@ -329,7 +422,7 @@ func Decode(input interface{}, output interface{}) error { // WeakDecode is the same as Decode but is shorthand to enable // WeaklyTypedInput. See DecoderConfig for more info. -func WeakDecode(input, output interface{}) error { +func WeakDecode(input, output any) error { config := &DecoderConfig{ Metadata: nil, Result: output, @@ -346,7 +439,7 @@ func WeakDecode(input, output interface{}) error { // DecodeMetadata is the same as Decode, but is shorthand to // enable metadata collection. See DecoderConfig for more info. -func DecodeMetadata(input interface{}, output interface{}, metadata *Metadata) error { +func DecodeMetadata(input any, output any, metadata *Metadata) error { config := &DecoderConfig{ Metadata: metadata, Result: output, @@ -363,7 +456,7 @@ func DecodeMetadata(input interface{}, output interface{}, metadata *Metadata) e // WeakDecodeMetadata is the same as Decode, but is shorthand to // enable both WeaklyTypedInput and metadata collection. See // DecoderConfig for more info. -func WeakDecodeMetadata(input interface{}, output interface{}, metadata *Metadata) error { +func WeakDecodeMetadata(input any, output any, metadata *Metadata) error { config := &DecoderConfig{ Metadata: metadata, Result: output, @@ -418,6 +511,12 @@ func NewDecoder(config *DecoderConfig) (*Decoder, error) { config.MatchName = strings.EqualFold } + if config.MapFieldName == nil { + config.MapFieldName = func(s string) string { + return s + } + } + result := &Decoder{ config: config, } @@ -430,8 +529,8 @@ func NewDecoder(config *DecoderConfig) (*Decoder, error) { // Decode decodes the given raw interface to the target pointer specified // by the configuration. -func (d *Decoder) Decode(input interface{}) error { - err := d.decode("", input, reflect.ValueOf(d.config.Result).Elem()) +func (d *Decoder) Decode(input any) error { + err := d.decode(d.config.RootName, input, reflect.ValueOf(d.config.Result).Elem()) // Retain some of the original behavior when multiple errors ocurr var joinedErr interface{ Unwrap() []error } @@ -443,7 +542,7 @@ func (d *Decoder) Decode(input interface{}) error { } // isNil returns true if the input is nil or a typed nil pointer. -func isNil(input interface{}) bool { +func isNil(input any) bool { if input == nil { return true } @@ -452,7 +551,7 @@ func isNil(input interface{}) bool { } // Decodes an unknown data type into a specific reflection value. -func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) error { +func (d *Decoder) decode(name string, input any, outVal reflect.Value) error { var ( inputVal = reflect.ValueOf(input) outputKind = getKind(outVal) @@ -489,10 +588,10 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e // Hooks need a valid inputVal, so reset it to zero value of outVal type. switch outputKind { case reflect.Struct, reflect.Map: - var mapVal map[string]interface{} + var mapVal map[string]any inputVal = reflect.ValueOf(mapVal) // create nil map pointer case reflect.Slice, reflect.Array: - var sliceVal []interface{} + var sliceVal []any inputVal = reflect.ValueOf(sliceVal) // create nil slice pointer default: inputVal = reflect.Zero(outVal.Type()) @@ -504,7 +603,7 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e var err error input, err = d.cachedDecodeHook(inputVal, outVal) if err != nil { - return fmt.Errorf("error decoding '%s': %w", name, err) + return newDecodeError(name, err) } } if isNil(input) { @@ -513,36 +612,50 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e var err error addMetaKey := true - switch outputKind { - case reflect.Bool: - err = d.decodeBool(name, input, outVal) - case reflect.Interface: - err = d.decodeBasic(name, input, outVal) - case reflect.String: - err = d.decodeString(name, input, outVal) - case reflect.Int: - err = d.decodeInt(name, input, outVal) - case reflect.Uint: - err = d.decodeUint(name, input, outVal) - case reflect.Float32: - err = d.decodeFloat(name, input, outVal) - case reflect.Complex64: - err = d.decodeComplex(name, input, outVal) - case reflect.Struct: - err = d.decodeStruct(name, input, outVal) - case reflect.Map: - err = d.decodeMap(name, input, outVal) - case reflect.Ptr: - addMetaKey, err = d.decodePtr(name, input, outVal) - case reflect.Slice: - err = d.decodeSlice(name, input, outVal) - case reflect.Array: - err = d.decodeArray(name, input, outVal) - case reflect.Func: - err = d.decodeFunc(name, input, outVal) - default: - // If we reached this point then we weren't able to decode it - return fmt.Errorf("%s: unsupported type: %s", name, outputKind) + + // Check if the target implements Unmarshaler and use it if not disabled + unmarshaled := false + if !d.config.DisableUnmarshaler { + if unmarshaler, ok := getUnmarshaler(outVal); ok { + if err = unmarshaler.UnmarshalMapstructure(input); err != nil { + err = newDecodeError(name, err) + } + unmarshaled = true + } + } + + if !unmarshaled { + switch outputKind { + case reflect.Bool: + err = d.decodeBool(name, input, outVal) + case reflect.Interface: + err = d.decodeBasic(name, input, outVal) + case reflect.String: + err = d.decodeString(name, input, outVal) + case reflect.Int: + err = d.decodeInt(name, input, outVal) + case reflect.Uint: + err = d.decodeUint(name, input, outVal) + case reflect.Float32: + err = d.decodeFloat(name, input, outVal) + case reflect.Complex64: + err = d.decodeComplex(name, input, outVal) + case reflect.Struct: + err = d.decodeStruct(name, input, outVal) + case reflect.Map: + err = d.decodeMap(name, input, outVal) + case reflect.Ptr: + addMetaKey, err = d.decodePtr(name, input, outVal) + case reflect.Slice: + err = d.decodeSlice(name, input, outVal) + case reflect.Array: + err = d.decodeArray(name, input, outVal) + case reflect.Func: + err = d.decodeFunc(name, input, outVal) + default: + // If we reached this point then we weren't able to decode it + return newDecodeError(name, fmt.Errorf("unsupported type: %s", outputKind)) + } } // If we reached here, then we successfully decoded SOMETHING, so @@ -556,7 +669,7 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e // This decodes a basic type (bool, int, string, etc.) and sets the // value to "data" of that type. -func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value) error { +func (d *Decoder) decodeBasic(name string, data any, val reflect.Value) error { if val.IsValid() && val.Elem().IsValid() { elem := val.Elem() @@ -603,16 +716,17 @@ func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value) dataValType := dataVal.Type() if !dataValType.AssignableTo(val.Type()) { - return fmt.Errorf( - "'%s' expected type '%s', got '%s'", - name, val.Type(), dataValType) + return newDecodeError(name, &UnconvertibleTypeError{ + Expected: val, + Value: data, + }) } val.Set(dataVal) return nil } -func (d *Decoder) decodeString(name string, data interface{}, val reflect.Value) error { +func (d *Decoder) decodeString(name string, data any, val reflect.Value) error { dataVal := reflect.Indirect(reflect.ValueOf(data)) dataKind := getKind(dataVal) @@ -640,7 +754,7 @@ func (d *Decoder) decodeString(name string, data interface{}, val reflect.Value) case reflect.Uint8: var uints []uint8 if dataKind == reflect.Array { - uints = make([]uint8, dataVal.Len(), dataVal.Len()) + uints = make([]uint8, dataVal.Len()) for i := range uints { uints[i] = dataVal.Index(i).Interface().(uint8) } @@ -656,15 +770,16 @@ func (d *Decoder) decodeString(name string, data interface{}, val reflect.Value) } if !converted { - return fmt.Errorf( - "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", - name, val.Type(), dataVal.Type(), data) + return newDecodeError(name, &UnconvertibleTypeError{ + Expected: val, + Value: data, + }) } return nil } -func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) error { +func (d *Decoder) decodeInt(name string, data any, val reflect.Value) error { dataVal := reflect.Indirect(reflect.ValueOf(data)) dataKind := getKind(dataVal) dataType := dataVal.Type() @@ -692,26 +807,34 @@ func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) er if err == nil { val.SetInt(i) } else { - return fmt.Errorf("cannot parse '%s' as int: %s", name, err) + return newDecodeError(name, &ParseError{ + Expected: val, + Value: data, + Err: wrapStrconvNumError(err), + }) } case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number": jn := data.(json.Number) i, err := jn.Int64() if err != nil { - return fmt.Errorf( - "error decoding json.Number into %s: %s", name, err) + return newDecodeError(name, &ParseError{ + Expected: val, + Value: data, + Err: err, + }) } val.SetInt(i) default: - return fmt.Errorf( - "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", - name, val.Type(), dataVal.Type(), data) + return newDecodeError(name, &UnconvertibleTypeError{ + Expected: val, + Value: data, + }) } return nil } -func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) error { +func (d *Decoder) decodeUint(name string, data any, val reflect.Value) error { dataVal := reflect.Indirect(reflect.ValueOf(data)) dataKind := getKind(dataVal) dataType := dataVal.Type() @@ -720,8 +843,11 @@ func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) e case dataKind == reflect.Int: i := dataVal.Int() if i < 0 && !d.config.WeaklyTypedInput { - return fmt.Errorf("cannot parse '%s', %d overflows uint", - name, i) + return newDecodeError(name, &ParseError{ + Expected: val, + Value: data, + Err: fmt.Errorf("%d overflows uint", i), + }) } val.SetUint(uint64(i)) case dataKind == reflect.Uint: @@ -729,8 +855,11 @@ func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) e case dataKind == reflect.Float32: f := dataVal.Float() if f < 0 && !d.config.WeaklyTypedInput { - return fmt.Errorf("cannot parse '%s', %f overflows uint", - name, f) + return newDecodeError(name, &ParseError{ + Expected: val, + Value: data, + Err: fmt.Errorf("%f overflows uint", f), + }) } val.SetUint(uint64(f)) case dataKind == reflect.Bool && d.config.WeaklyTypedInput: @@ -749,26 +878,34 @@ func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) e if err == nil { val.SetUint(i) } else { - return fmt.Errorf("cannot parse '%s' as uint: %s", name, err) + return newDecodeError(name, &ParseError{ + Expected: val, + Value: data, + Err: wrapStrconvNumError(err), + }) } case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number": jn := data.(json.Number) i, err := strconv.ParseUint(string(jn), 0, 64) if err != nil { - return fmt.Errorf( - "error decoding json.Number into %s: %s", name, err) + return newDecodeError(name, &ParseError{ + Expected: val, + Value: data, + Err: wrapStrconvNumError(err), + }) } val.SetUint(i) default: - return fmt.Errorf( - "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", - name, val.Type(), dataVal.Type(), data) + return newDecodeError(name, &UnconvertibleTypeError{ + Expected: val, + Value: data, + }) } return nil } -func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) error { +func (d *Decoder) decodeBool(name string, data any, val reflect.Value) error { dataVal := reflect.Indirect(reflect.ValueOf(data)) dataKind := getKind(dataVal) @@ -788,18 +925,23 @@ func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) e } else if dataVal.String() == "" { val.SetBool(false) } else { - return fmt.Errorf("cannot parse '%s' as bool: %s", name, err) + return newDecodeError(name, &ParseError{ + Expected: val, + Value: data, + Err: wrapStrconvNumError(err), + }) } default: - return fmt.Errorf( - "'%s' expected type '%s', got unconvertible type '%#v', value: '%#v'", - name, val, dataVal, data) + return newDecodeError(name, &UnconvertibleTypeError{ + Expected: val, + Value: data, + }) } return nil } -func (d *Decoder) decodeFloat(name string, data interface{}, val reflect.Value) error { +func (d *Decoder) decodeFloat(name string, data any, val reflect.Value) error { dataVal := reflect.Indirect(reflect.ValueOf(data)) dataKind := getKind(dataVal) dataType := dataVal.Type() @@ -827,26 +969,34 @@ func (d *Decoder) decodeFloat(name string, data interface{}, val reflect.Value) if err == nil { val.SetFloat(f) } else { - return fmt.Errorf("cannot parse '%s' as float: %s", name, err) + return newDecodeError(name, &ParseError{ + Expected: val, + Value: data, + Err: wrapStrconvNumError(err), + }) } case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number": jn := data.(json.Number) i, err := jn.Float64() if err != nil { - return fmt.Errorf( - "error decoding json.Number into %s: %s", name, err) + return newDecodeError(name, &ParseError{ + Expected: val, + Value: data, + Err: err, + }) } val.SetFloat(i) default: - return fmt.Errorf( - "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", - name, val.Type(), dataVal.Type(), data) + return newDecodeError(name, &UnconvertibleTypeError{ + Expected: val, + Value: data, + }) } return nil } -func (d *Decoder) decodeComplex(name string, data interface{}, val reflect.Value) error { +func (d *Decoder) decodeComplex(name string, data any, val reflect.Value) error { dataVal := reflect.Indirect(reflect.ValueOf(data)) dataKind := getKind(dataVal) @@ -854,15 +1004,16 @@ func (d *Decoder) decodeComplex(name string, data interface{}, val reflect.Value case dataKind == reflect.Complex64: val.SetComplex(dataVal.Complex()) default: - return fmt.Errorf( - "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", - name, val.Type(), dataVal.Type(), data) + return newDecodeError(name, &UnconvertibleTypeError{ + Expected: val, + Value: data, + }) } return nil } -func (d *Decoder) decodeMap(name string, data interface{}, val reflect.Value) error { +func (d *Decoder) decodeMap(name string, data any, val reflect.Value) error { valType := val.Type() valKeyType := valType.Key() valElemType := valType.Elem() @@ -900,7 +1051,10 @@ func (d *Decoder) decodeMap(name string, data interface{}, val reflect.Value) er fallthrough default: - return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind()) + return newDecodeError(name, &UnconvertibleTypeError{ + Expected: val, + Value: data, + }) } } @@ -986,11 +1140,14 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re // to the map value. v := dataVal.Field(i) if !v.Type().AssignableTo(valMap.Type().Elem()) { - return fmt.Errorf("cannot assign type '%s' to map value field of type '%s'", v.Type(), valMap.Type().Elem()) + return newDecodeError( + name+"."+f.Name, + fmt.Errorf("cannot assign type %q to map value field of type %q", v.Type(), valMap.Type().Elem()), + ) } - tagValue := f.Tag.Get(d.config.TagName) - keyName := f.Name + tagValue, _ := getTagValue(f, d.config.TagName) + keyName := d.config.MapFieldName(f.Name) if tagValue == "" && d.config.IgnoreUntaggedFields { continue @@ -999,6 +1156,9 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re // If Squash is set in the config, we squash the field down. squash := d.config.Squash && v.Kind() == reflect.Struct && f.Anonymous + // If Deep is set in the config, set as default value. + deep := d.config.Deep + v = dereferencePtrToStructIfNeeded(v, d.config.TagName) // Determine the name of the key in the map @@ -1007,7 +1167,12 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re continue } // If "omitempty" is specified in the tag, it ignores empty values. - if strings.Index(tagValue[index+1:], "omitempty") != -1 && isEmptyValue(v) { + if strings.Contains(tagValue[index+1:], "omitempty") && isEmptyValue(v) { + continue + } + + // If "omitzero" is specified in the tag, it ignores zero values. + if strings.Contains(tagValue[index+1:], "omitzero") && v.IsZero() { continue } @@ -1021,12 +1186,18 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re // The final type must be a struct if v.Kind() != reflect.Struct { - return fmt.Errorf("cannot squash non-struct type '%s'", v.Type()) + return newDecodeError( + name+"."+f.Name, + fmt.Errorf("cannot squash non-struct type %q", v.Type()), + ) } } else { - if strings.Index(tagValue[index+1:], "remain") != -1 { + if strings.Contains(tagValue[index+1:], "remain") { if v.Kind() != reflect.Map { - return fmt.Errorf("error remain-tag field with invalid type: '%s'", v.Type()) + return newDecodeError( + name+"."+f.Name, + fmt.Errorf("error remain-tag field with invalid type: %q", v.Type()), + ) } ptr := v.MapRange() @@ -1036,6 +1207,9 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re continue } } + + deep = deep || strings.Contains(tagValue[index+1:], "deep") + if keyNameTagValue := tagValue[:index]; keyNameTagValue != "" { keyName = keyNameTagValue } @@ -1082,6 +1256,41 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re valMap.SetMapIndex(reflect.ValueOf(keyName), vMap) } + case reflect.Slice: + if deep { + var childType reflect.Type + switch v.Type().Elem().Kind() { + case reflect.Struct: + childType = reflect.TypeOf(map[string]any{}) + default: + childType = v.Type().Elem() + } + + sType := reflect.SliceOf(childType) + + addrVal := reflect.New(sType) + + vSlice := reflect.MakeSlice(sType, v.Len(), v.Cap()) + + if v.Len() > 0 { + reflect.Indirect(addrVal).Set(vSlice) + + err := d.decode(keyName, v.Interface(), reflect.Indirect(addrVal)) + if err != nil { + return err + } + } + + vSlice = reflect.Indirect(addrVal) + + valMap.SetMapIndex(reflect.ValueOf(keyName), vSlice) + + break + } + + // When deep mapping is not needed, fallthrough to normal copy + fallthrough + default: valMap.SetMapIndex(reflect.ValueOf(keyName), v) } @@ -1094,7 +1303,7 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re return nil } -func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) (bool, error) { +func (d *Decoder) decodePtr(name string, data any, val reflect.Value) (bool, error) { // If the input data is nil, then we want to just set the output // pointer to be nil as well. isNil := data == nil @@ -1141,20 +1350,21 @@ func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) (b return false, nil } -func (d *Decoder) decodeFunc(name string, data interface{}, val reflect.Value) error { +func (d *Decoder) decodeFunc(name string, data any, val reflect.Value) error { // Create an element of the concrete (non pointer) type and decode // into that. Then set the value of the pointer to this type. dataVal := reflect.Indirect(reflect.ValueOf(data)) if val.Type() != dataVal.Type() { - return fmt.Errorf( - "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", - name, val.Type(), dataVal.Type(), data) + return newDecodeError(name, &UnconvertibleTypeError{ + Expected: val, + Value: data, + }) } val.Set(dataVal) return nil } -func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) error { +func (d *Decoder) decodeSlice(name string, data any, val reflect.Value) error { dataVal := reflect.Indirect(reflect.ValueOf(data)) dataValKind := dataVal.Kind() valType := val.Type() @@ -1176,7 +1386,7 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) return nil } // Create slice of maps of other sizes - return d.decodeSlice(name, []interface{}{data}, val) + return d.decodeSlice(name, []any{data}, val) case dataValKind == reflect.String && valElemType.Kind() == reflect.Uint8: return d.decodeSlice(name, []byte(dataVal.String()), val) @@ -1185,12 +1395,12 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) // and "lift" it into it. i.e. a string becomes a string slice. default: // Just re-try this function with data as a slice. - return d.decodeSlice(name, []interface{}{data}, val) + return d.decodeSlice(name, []any{data}, val) } } - return fmt.Errorf( - "'%s': source data must be an array or slice, got %s", name, dataValKind) + return newDecodeError(name, + fmt.Errorf("source data must be an array or slice, got %s", dataValKind)) } // If the input value is nil, then don't allocate since empty != nil @@ -1228,7 +1438,7 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) return errors.Join(errs...) } -func (d *Decoder) decodeArray(name string, data interface{}, val reflect.Value) error { +func (d *Decoder) decodeArray(name string, data any, val reflect.Value) error { dataVal := reflect.Indirect(reflect.ValueOf(data)) dataValKind := dataVal.Kind() valType := val.Type() @@ -1253,17 +1463,17 @@ func (d *Decoder) decodeArray(name string, data interface{}, val reflect.Value) // and "lift" it into it. i.e. a string becomes a string array. default: // Just re-try this function with data as a slice. - return d.decodeArray(name, []interface{}{data}, val) + return d.decodeArray(name, []any{data}, val) } } - return fmt.Errorf( - "'%s': source data must be an array or slice, got %s", name, dataValKind) + return newDecodeError(name, + fmt.Errorf("source data must be an array or slice, got %s", dataValKind)) } if dataVal.Len() > arrayType.Len() { - return fmt.Errorf( - "'%s': expected source data to have length less or equal to %d, got %d", name, arrayType.Len(), dataVal.Len()) + return newDecodeError(name, + fmt.Errorf("expected source data to have length less or equal to %d, got %d", arrayType.Len(), dataVal.Len())) } // Make a new array to hold our result, same size as the original data. @@ -1289,7 +1499,7 @@ func (d *Decoder) decodeArray(name string, data interface{}, val reflect.Value) return errors.Join(errs...) } -func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value) error { +func (d *Decoder) decodeStruct(name string, data any, val reflect.Value) error { dataVal := reflect.Indirect(reflect.ValueOf(data)) // If the type of the value to write to and the data match directly, @@ -1310,7 +1520,7 @@ func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value) // as an intermediary. // Make a new map to hold our result - mapType := reflect.TypeOf((map[string]interface{})(nil)) + mapType := reflect.TypeOf((map[string]any)(nil)) mval := reflect.MakeMap(mapType) // Creating a pointer to a map so that other methods can completely @@ -1328,26 +1538,26 @@ func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value) return result default: - return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind()) + return newDecodeError(name, + fmt.Errorf("expected a map or struct, got %q", dataValKind)) } } func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) error { dataValType := dataVal.Type() if kind := dataValType.Key().Kind(); kind != reflect.String && kind != reflect.Interface { - return fmt.Errorf( - "'%s' needs a map with string keys, has '%s' keys", - name, dataValType.Key().Kind()) + return newDecodeError(name, + fmt.Errorf("needs a map with string keys, has %q keys", kind)) } dataValKeys := make(map[reflect.Value]struct{}) - dataValKeysUnused := make(map[interface{}]struct{}) + dataValKeysUnused := make(map[any]struct{}) for _, dataValKey := range dataVal.MapKeys() { dataValKeys[dataValKey] = struct{}{} dataValKeysUnused[dataValKey.Interface()] = struct{}{} } - targetValKeysUnused := make(map[interface{}]struct{}) + targetValKeysUnused := make(map[any]struct{}) var errs []error @@ -1388,7 +1598,10 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e remain := false // We always parse the tags cause we're looking for other tags too - tagParts := strings.Split(fieldType.Tag.Get(d.config.TagName), ",") + tagParts := getTagParts(fieldType, d.config.TagName) + if len(tagParts) == 0 { + tagParts = []string{""} + } for _, tag := range tagParts[1:] { if tag == d.config.SquashTagOption { squash = true @@ -1409,8 +1622,23 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e if !fieldVal.IsNil() { structs = append(structs, fieldVal.Elem().Elem()) } + case reflect.Ptr: + if fieldVal.Type().Elem().Kind() == reflect.Struct { + if fieldVal.IsNil() { + fieldVal.Set(reflect.New(fieldVal.Type().Elem())) + } + structs = append(structs, fieldVal.Elem()) + } else { + errs = append(errs, newDecodeError( + name+"."+fieldType.Name, + fmt.Errorf("unsupported type for squashed pointer: %s", fieldVal.Type().Elem().Kind()), + )) + } default: - errs = append(errs, fmt.Errorf("%s: unsupported type for squash: %s", fieldType.Name, fieldVal.Kind())) + errs = append(errs, newDecodeError( + name+"."+fieldType.Name, + fmt.Errorf("unsupported type for squash: %s", fieldVal.Kind()), + )) } continue } @@ -1430,13 +1658,15 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e field, fieldValue := f.field, f.val fieldName := field.Name - tagValue := field.Tag.Get(d.config.TagName) + tagValue, _ := getTagValue(field, d.config.TagName) if tagValue == "" && d.config.IgnoreUntaggedFields { continue } tagValue = strings.SplitN(tagValue, ",", 2)[0] if tagValue != "" { fieldName = tagValue + } else { + fieldName = d.config.MapFieldName(fieldName) } rawMapKey := reflect.ValueOf(fieldName) @@ -1461,7 +1691,9 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e if !rawMapVal.IsValid() { // There was no matching key in the map for the value in // the struct. Remember it for potential errors and metadata. - targetValKeysUnused[fieldName] = struct{}{} + if !(d.config.AllowUnsetPointer && fieldValue.Kind() == reflect.Ptr) { + targetValKeysUnused[fieldName] = struct{}{} + } continue } } @@ -1495,7 +1727,7 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e // we put the unused keys directly into the remain field. if remainField != nil && len(dataValKeysUnused) > 0 { // Build a map of only the unused values - remain := map[interface{}]interface{}{} + remain := map[any]any{} for key := range dataValKeysUnused { remain[key] = dataVal.MapIndex(reflect.ValueOf(key)).Interface() } @@ -1517,8 +1749,16 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e } sort.Strings(keys) - err := fmt.Errorf("'%s' has invalid keys: %s", name, strings.Join(keys, ", ")) - errs = append(errs, err) + // Improve error message when name is empty by showing the target struct type + // in the case where it is empty for embedded structs. + errorName := name + if errorName == "" { + errorName = val.Type().String() + } + errs = append(errs, newDecodeError( + errorName, + fmt.Errorf("has invalid keys: %s", strings.Join(keys, ", ")), + )) } if d.config.ErrorUnset && len(targetValKeysUnused) > 0 { @@ -1528,8 +1768,10 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e } sort.Strings(keys) - err := fmt.Errorf("'%s' has unset fields: %s", name, strings.Join(keys, ", ")) - errs = append(errs, err) + errs = append(errs, newDecodeError( + name, + fmt.Errorf("has unset fields: %s", strings.Join(keys, ", ")), + )) } if err := errors.Join(errs...); err != nil { @@ -1600,7 +1842,7 @@ func isStructTypeConvertibleToMap(typ reflect.Type, checkMapstructureTags bool, if f.PkgPath == "" && !checkMapstructureTags { // check for unexported fields return true } - if checkMapstructureTags && f.Tag.Get(tagName) != "" { // check for mapstructure tags inside + if checkMapstructureTags && hasAnyTag(f, tagName) { // check for mapstructure tags inside return true } } @@ -1608,13 +1850,99 @@ func isStructTypeConvertibleToMap(typ reflect.Type, checkMapstructureTags bool, } func dereferencePtrToStructIfNeeded(v reflect.Value, tagName string) reflect.Value { - if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct { + if v.Kind() != reflect.Ptr { + return v + } + + switch v.Elem().Kind() { + case reflect.Slice: + return v.Elem() + + case reflect.Struct: + deref := v.Elem() + derefT := deref.Type() + if isStructTypeConvertibleToMap(derefT, true, tagName) { + return deref + } return v + + default: + return v + } +} + +func hasAnyTag(field reflect.StructField, tagName string) bool { + _, ok := getTagValue(field, tagName) + return ok +} + +func getTagParts(field reflect.StructField, tagName string) []string { + tagValue, ok := getTagValue(field, tagName) + if !ok { + return nil } - deref := v.Elem() - derefT := deref.Type() - if isStructTypeConvertibleToMap(derefT, true, tagName) { - return deref + return strings.Split(tagValue, ",") +} + +func getTagValue(field reflect.StructField, tagName string) (string, bool) { + for _, name := range splitTagNames(tagName) { + if tag := field.Tag.Get(name); tag != "" { + return tag, true + } } - return v + return "", false +} + +func splitTagNames(tagName string) []string { + if tagName == "" { + return []string{"mapstructure"} + } + parts := strings.Split(tagName, ",") + result := make([]string, 0, len(parts)) + + for _, name := range parts { + name = strings.TrimSpace(name) + if name != "" { + result = append(result, name) + } + } + + return result +} + +// unmarshalerType is cached for performance +var unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() + +// getUnmarshaler checks if the value implements Unmarshaler and returns +// the Unmarshaler and a boolean indicating if it was found. It handles both +// pointer and value receivers. +func getUnmarshaler(val reflect.Value) (Unmarshaler, bool) { + // Skip invalid or nil values + if !val.IsValid() { + return nil, false + } + + switch val.Kind() { + case reflect.Pointer, reflect.Interface: + if val.IsNil() { + return nil, false + } + } + + // Check pointer receiver first (most common case) + if val.CanAddr() { + ptrVal := val.Addr() + // Quick check: if no methods, can't implement any interface + if ptrVal.Type().NumMethod() > 0 && ptrVal.Type().Implements(unmarshalerType) { + return ptrVal.Interface().(Unmarshaler), true + } + } + + // Check value receiver + // Quick check: if no methods, can't implement any interface + if val.Type().NumMethod() > 0 && val.CanInterface() && val.Type().Implements(unmarshalerType) { + return val.Interface().(Unmarshaler), true + } + + return nil, false } diff --git a/vendor/github.com/go-xmlfmt/xmlfmt/xmlfmt.go b/vendor/github.com/go-xmlfmt/xmlfmt/xmlfmt.go index 4245e5ad7..365a1d047 100644 --- a/vendor/github.com/go-xmlfmt/xmlfmt/xmlfmt.go +++ b/vendor/github.com/go-xmlfmt/xmlfmt/xmlfmt.go @@ -14,7 +14,10 @@ import ( ) var ( - reg = regexp.MustCompile(`<([/!]?)([^>]+?)(/?)>`) + reg = regexp.MustCompile(`<([/!]?)([^>]+?)(/?)>`) + reXMLComments = regexp.MustCompile(`(?s)()`) + reSpaces = regexp.MustCompile(`(?s)>\s+<`) + reNewlines = regexp.MustCompile(`\r*\n`) // NL is the newline string used in XML output. NL = "\n" ) @@ -33,20 +36,19 @@ func FormatXML(xmls, prefix, indent string, nestedTagsInComments ...bool) string if len(nestedTagsInComments) > 0 { nestedTagsInComment = nestedTagsInComments[0] } - reXmlComments := regexp.MustCompile(`(?s)()`) - src := regexp.MustCompile(`(?s)>\s+<`).ReplaceAllString(xmls, "><") + src := reSpaces.ReplaceAllString(xmls, "><") if nestedTagsInComment { - src = reXmlComments.ReplaceAllStringFunc(src, func(m string) string { - parts := reXmlComments.FindStringSubmatch(m) - p2 := regexp.MustCompile(`\r*\n`).ReplaceAllString(parts[2], " ") + src = reXMLComments.ReplaceAllStringFunc(src, func(m string) string { + parts := reXMLComments.FindStringSubmatch(m) + p2 := reNewlines.ReplaceAllString(parts[2], " ") return parts[1] + html.EscapeString(p2) + parts[3] }) } rf := replaceTag(prefix, indent) r := prefix + reg.ReplaceAllStringFunc(src, rf) if nestedTagsInComment { - r = reXmlComments.ReplaceAllStringFunc(r, func(m string) string { - parts := reXmlComments.FindStringSubmatch(m) + r = reXMLComments.ReplaceAllStringFunc(r, func(m string) string { + parts := reXMLComments.FindStringSubmatch(m) return parts[1] + html.UnescapeString(parts[2]) + parts[3] }) } diff --git a/vendor/github.com/godoc-lint/godoc-lint/LICENSE b/vendor/github.com/godoc-lint/godoc-lint/LICENSE new file mode 100644 index 000000000..f51a8f9b5 --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Babak K. Shandiz + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/analysis/analyzer.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/analysis/analyzer.go new file mode 100644 index 000000000..052390058 --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/analysis/analyzer.go @@ -0,0 +1,108 @@ +// Package analysis provides the main analyzer implementation. +package analysis + +import ( + "errors" + "fmt" + "path/filepath" + + "golang.org/x/tools/go/analysis" + + "github.com/godoc-lint/godoc-lint/pkg/model" + "github.com/godoc-lint/godoc-lint/pkg/util" +) + +const ( + metaName = "godoclint" + metaDoc = "Checks Golang's documentation practice (godoc)" + metaURL = "https://github.com/godoc-lint/godoc-lint" +) + +// Analyzer implements the godoc-lint analyzer. +type Analyzer struct { + baseDir string + cb model.ConfigBuilder + inspector model.Inspector + reg model.Registry + exitFunc func(int, error) + + analyzer *analysis.Analyzer +} + +// NewAnalyzer returns a new instance of the corresponding analyzer. +func NewAnalyzer(baseDir string, cb model.ConfigBuilder, reg model.Registry, inspector model.Inspector, exitFunc func(int, error)) *Analyzer { + result := &Analyzer{ + baseDir: baseDir, + cb: cb, + reg: reg, + inspector: inspector, + exitFunc: exitFunc, + analyzer: &analysis.Analyzer{ + Name: metaName, + Doc: metaDoc, + URL: metaURL, + Requires: []*analysis.Analyzer{inspector.GetAnalyzer()}, + }, + } + + result.analyzer.Run = result.run + return result +} + +// GetAnalyzer returns the underlying analyzer. +func (a *Analyzer) GetAnalyzer() *analysis.Analyzer { + return a.analyzer +} + +func (a *Analyzer) run(pass *analysis.Pass) (any, error) { + if len(pass.Files) == 0 { + return nil, nil + } + + ft := util.GetPassFileToken(pass.Files[0], pass) + if ft == nil { + err := errors.New("cannot prepare config") + if a.exitFunc != nil { + a.exitFunc(2, err) + } + return nil, err + } + + if !util.IsPathUnderBaseDir(a.baseDir, ft.Name()) { + return nil, nil + } + + pkgDir := filepath.Dir(ft.Name()) + cfg, err := a.cb.GetConfig(pkgDir) + if err != nil { + err := fmt.Errorf("cannot prepare config: %w", err) + if a.exitFunc != nil { + a.exitFunc(2, err) + } + return nil, err + } + + ir := pass.ResultOf[a.inspector.GetAnalyzer()].(*model.InspectorResult) + if ir == nil || ir.Files == nil { + return nil, nil + } + + actx := &model.AnalysisContext{ + Config: cfg, + InspectorResult: ir, + Pass: pass, + } + + for _, checker := range a.reg.List() { + // TODO(babakks): This can be done once to improve performance. + ruleSet := checker.GetCoveredRules() + if !actx.Config.IsAnyRuleApplicable(ruleSet) { + continue + } + + if err := checker.Apply(actx); err != nil { + return nil, fmt.Errorf("checker error: %w", err) + } + } + return nil, nil +} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/check/deprecated/deprecated.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/check/deprecated/deprecated.go new file mode 100644 index 000000000..08915f6c7 --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/check/deprecated/deprecated.go @@ -0,0 +1,114 @@ +// Package deprecated provides a checker for correct usage of deprecation +// markers. +package deprecated + +import ( + "go/ast" + "go/doc/comment" + "regexp" + + "github.com/godoc-lint/godoc-lint/pkg/model" + "github.com/godoc-lint/godoc-lint/pkg/util" +) + +const deprecatedRule = model.DeprecatedRule + +var ruleSet = model.RuleSet{}.Add(deprecatedRule) + +// DeprecatedChecker checks correct usage of "Deprecated:" markers. +type DeprecatedChecker struct{} + +// NewDeprecatedChecker returns a new instance of the corresponding checker. +func NewDeprecatedChecker() *DeprecatedChecker { + return &DeprecatedChecker{} +} + +// GetCoveredRules implements the corresponding interface method. +func (r *DeprecatedChecker) GetCoveredRules() model.RuleSet { + return ruleSet +} + +// Apply implements the corresponding interface method. +func (r *DeprecatedChecker) Apply(actx *model.AnalysisContext) error { + docs := make(map[*model.CommentGroup]struct{}, 10*len(actx.InspectorResult.Files)) + + for _, ir := range util.AnalysisApplicableFiles(actx, false, model.RuleSet{}.Add(deprecatedRule)) { + if ir.PackageDoc != nil { + docs[ir.PackageDoc] = struct{}{} + } + + for _, sd := range ir.SymbolDecl { + isExported := ast.IsExported(sd.Name) + if !isExported { + continue + } + + if sd.ParentDoc != nil { + docs[sd.ParentDoc] = struct{}{} + } + if sd.Doc == nil { + continue + } + docs[sd.Doc] = struct{}{} + } + } + + for doc := range docs { + checkDeprecations(actx, doc) + } + return nil +} + +// probableDeprecationRE finds probable deprecation markers, including the +// correct usage. +var probableDeprecationRE = regexp.MustCompile(`(?i)^deprecated:.?`) + +const correctDeprecationMarker = "Deprecated: " + +func checkDeprecations(actx *model.AnalysisContext, doc *model.CommentGroup) { + if doc.DisabledRules.All || doc.DisabledRules.Rules.Has(deprecatedRule) { + return + } + + for _, block := range doc.Parsed.Content { + // The correct usage of deprecation markers is to put them at the beginning + // of a paragraph (i.e. not a heading, code block, etc). Also the syntax is + // strict and must only be "Deprecated: " (case-sensitive and with the + // trailing whitespace). + // + // However, not all wrong usages are reliably discoverable. For example: + // + // // Foo is a symbol. + // // deprecated: use Bar. + // // func Foo() {} + // + // In this cases, the "deprecated: " marker is at the beginning of a new + // line, but as of godoc parser, it's just in the middle of the paragraph + // started at the top line. There might be some smart ways to detect these + // cases, but the problem is there will be false-positives to them. For + // instance, a valid case like this should never be detected as a wrong + // usage: + // + // // Foo is a symbol but here are the reasons why it's + // // deprecated: blah, blah, ... + // // func Foo() {} + // + // Needless to say we don't want to deal with human language complexities. + + par, ok := block.(*comment.Paragraph) + if !ok || len(par.Text) == 0 { + continue + } + text, ok := (par.Text[0]).(comment.Plain) + if !ok { + continue + } + + if match := probableDeprecationRE.FindString(string(text)); match == "" || match == correctDeprecationMarker { + continue + } + + actx.Pass.ReportRangef(&doc.CG, "deprecation note should be formatted as %q", correctDeprecationMarker) + break + } +} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/check/max_len/max_len.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/check/max_len/max_len.go new file mode 100644 index 000000000..a0ba371b2 --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/check/max_len/max_len.go @@ -0,0 +1,155 @@ +// Package max_len provides a checker for maximum line length of godocs. +package max_len + +import ( + "fmt" + gdc "go/doc/comment" + "regexp" + "slices" + "strings" + "unicode/utf8" + + "golang.org/x/tools/go/analysis" + + "github.com/godoc-lint/godoc-lint/pkg/model" + "github.com/godoc-lint/godoc-lint/pkg/util" +) + +const maxLenRule = model.MaxLenRule + +var ruleSet = model.RuleSet{}.Add(maxLenRule) + +// MaxLenChecker checks maximum line length of godocs. +type MaxLenChecker struct{} + +// NewMaxLenChecker returns a new instance of the corresponding checker. +func NewMaxLenChecker() *MaxLenChecker { + return &MaxLenChecker{} +} + +// GetCoveredRules implements the corresponding interface method. +func (r *MaxLenChecker) GetCoveredRules() model.RuleSet { + return ruleSet +} + +// Apply implements the corresponding interface method. +func (r *MaxLenChecker) Apply(actx *model.AnalysisContext) error { + includeTests := actx.Config.GetRuleOptions().MaxLenIncludeTests + maxLen := int(actx.Config.GetRuleOptions().MaxLenLength) + ignoreRegexps := actx.Config.GetRuleOptions().MaxLenIgnorePatterns + + docs := make(map[*model.CommentGroup]struct{}, 10*len(actx.InspectorResult.Files)) + + for _, ir := range util.AnalysisApplicableFiles(actx, includeTests, model.RuleSet{}.Add(maxLenRule)) { + if ir.PackageDoc != nil { + docs[ir.PackageDoc] = struct{}{} + } + + for _, sd := range ir.SymbolDecl { + if sd.ParentDoc != nil { + docs[sd.ParentDoc] = struct{}{} + } + if sd.Doc == nil { + continue + } + docs[sd.Doc] = struct{}{} + } + } + + for doc := range docs { + checkMaxLen(actx, doc, maxLen, ignoreRegexps) + } + return nil +} + +func checkMaxLen(actx *model.AnalysisContext, doc *model.CommentGroup, maxLen int, ignoreRegexps []*regexp.Regexp) { + if doc.DisabledRules.All || doc.DisabledRules.Rules.Has(maxLenRule) { + return + } + + linkDefsMap := make(map[string]struct{}, len(doc.Parsed.Links)) + for _, linkDef := range doc.Parsed.Links { + linkDefLine := fmt.Sprintf("[%s]: %s", linkDef.Text, linkDef.URL) + linkDefsMap[linkDefLine] = struct{}{} + } + + nonCodeBlocks := make([]gdc.Block, 0, len(doc.Parsed.Content)) + for _, b := range doc.Parsed.Content { + if _, ok := b.(*gdc.Code); ok { + continue + } + nonCodeBlocks = append(nonCodeBlocks, b) + } + strippedCodeAndLinks := &gdc.Doc{ + Content: nonCodeBlocks, + } + text := string((&gdc.Printer{}).Comment(strippedCodeAndLinks)) + linesIter := strings.SplitSeq(removeCarriageReturn(text), "\n") + + // This is a clone of the original comment list since we need to remove + // elements from it, if needed. The main purpose of this is to don't miss + // duplicate long lines. + cgl := slices.Clone(doc.CG.List) + + for l := range linesIter { + lineLen := utf8.RuneCountInString(l) + if lineLen <= maxLen { + continue + } + if shouldIgnoreLine(l, ignoreRegexps) { + continue + } + + // Here we try to find the accurate position of the line within the + // original comment group. Historically, we would use the entire godoc + // block range to report the issue (See #55). + // + // However, the following approach does not work with /*..*/ comment + // blocks, since for them individual lines are not separately available, + // i.e. all lines would be in a single ast.Comment instance and + // therefore the ast.Comment.Pos will always point to the starting /* + // token. + + foundAt := -1 + for i, c := range cgl { + // As of [ast.Comment] docs, c.Text does not include carriage + // returns (\r) that may have been present in the source. This is + // good, since we have already stripped them from the lines. + // + // If the comment is a //-style one, c.Text starts with "// ". Since + // we're only interested in //-style cases, it's enough to check for + // that prefix. + if c.Text == "// "+l { + foundAt = i + break + } + } + + var rng analysis.Range + if foundAt != -1 { + rng = cgl[foundAt] + // Remove the found comment line from the list so that we don't miss + // duplicate long lines, or even reporting the same line number more + // than once while leaving the other(s). + cgl = slices.Delete(cgl, foundAt, foundAt+1) + } else { + // Fallback to reporting the entire godoc block. + rng = &doc.CG + } + + actx.Pass.ReportRangef(rng, "godoc line is too long (%d > %d)", lineLen, maxLen) + } +} + +func shouldIgnoreLine(line string, ignoreRegexps []*regexp.Regexp) bool { + for _, re := range ignoreRegexps { + if re.MatchString(line) { + return true + } + } + return false +} + +func removeCarriageReturn(s string) string { + return strings.ReplaceAll(s, "\r", "") +} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/check/no_unused_link/no_unused_link.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/check/no_unused_link/no_unused_link.go new file mode 100644 index 000000000..8910204be --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/check/no_unused_link/no_unused_link.go @@ -0,0 +1,69 @@ +// Package no_unused_link provides a checker for unused links in godocs. +package no_unused_link + +import ( + "github.com/godoc-lint/godoc-lint/pkg/model" + "github.com/godoc-lint/godoc-lint/pkg/util" +) + +const noUnusedLinkRule = model.NoUnusedLinkRule + +var ruleSet = model.RuleSet{}.Add(noUnusedLinkRule) + +// NoUnusedLinkChecker checks for unused links. +type NoUnusedLinkChecker struct{} + +// NewNoUnusedLinkChecker returns a new instance of the corresponding checker. +func NewNoUnusedLinkChecker() *NoUnusedLinkChecker { + return &NoUnusedLinkChecker{} +} + +// GetCoveredRules implements the corresponding interface method. +func (r *NoUnusedLinkChecker) GetCoveredRules() model.RuleSet { + return ruleSet +} + +// Apply implements the corresponding interface method. +func (r *NoUnusedLinkChecker) Apply(actx *model.AnalysisContext) error { + includeTests := actx.Config.GetRuleOptions().NoUnusedLinkIncludeTests + + docs := make(map[*model.CommentGroup]struct{}, 10*len(actx.InspectorResult.Files)) + + for _, ir := range util.AnalysisApplicableFiles(actx, includeTests, model.RuleSet{}.Add(noUnusedLinkRule)) { + if ir.PackageDoc != nil { + docs[ir.PackageDoc] = struct{}{} + } + + for _, sd := range ir.SymbolDecl { + if sd.ParentDoc != nil { + docs[sd.ParentDoc] = struct{}{} + } + if sd.Doc == nil { + continue + } + docs[sd.Doc] = struct{}{} + } + } + + for doc := range docs { + checkNoUnusedLink(actx, doc) + } + return nil +} + +func checkNoUnusedLink(actx *model.AnalysisContext, doc *model.CommentGroup) { + if doc.DisabledRules.All || doc.DisabledRules.Rules.Has(noUnusedLinkRule) { + return + } + + if doc.Text == "" { + return + } + + for _, linkDef := range doc.Parsed.Links { + if linkDef.Used { + continue + } + actx.Pass.ReportRangef(&doc.CG, "godoc has unused link (%q)", linkDef.Text) + } +} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/check/pkg_doc/pkg_doc.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/check/pkg_doc/pkg_doc.go new file mode 100644 index 000000000..e339ab33d --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/check/pkg_doc/pkg_doc.go @@ -0,0 +1,206 @@ +// Package pkg_doc provides a checker for package godocs. +package pkg_doc + +import ( + "go/ast" + "strings" + + "github.com/godoc-lint/godoc-lint/pkg/check/shared" + "github.com/godoc-lint/godoc-lint/pkg/model" + "github.com/godoc-lint/godoc-lint/pkg/util" +) + +const ( + pkgDocRule = model.PkgDocRule + singlePkgDocRule = model.SinglePkgDocRule + requirePkgDocRule = model.RequirePkgDocRule +) + +var ruleSet = model.RuleSet{}.Add( + pkgDocRule, + singlePkgDocRule, + requirePkgDocRule, +) + +// PkgDocChecker checks package godocs. +type PkgDocChecker struct{} + +// NewPkgDocChecker returns a new instance of the corresponding checker. +func NewPkgDocChecker() *PkgDocChecker { + return &PkgDocChecker{} +} + +// GetCoveredRules implements the corresponding interface method. +func (r *PkgDocChecker) GetCoveredRules() model.RuleSet { + return ruleSet +} + +// Apply implements the corresponding interface method. +func (r *PkgDocChecker) Apply(actx *model.AnalysisContext) error { + checkPkgDocRule(actx) + checkSinglePkgDocRule(actx) + checkRequirePkgDocRule(actx) + return nil +} + +const ( + commandPkgName = "main" + commandTestPkgName = "main_test" +) + +func checkPkgDocRule(actx *model.AnalysisContext) { + if !actx.Config.IsAnyRuleApplicable(model.RuleSet{}.Add(pkgDocRule)) { + return + } + + includeTests := actx.Config.GetRuleOptions().PkgDocIncludeTests + + for f, ir := range util.AnalysisApplicableFiles(actx, includeTests, model.RuleSet{}.Add(pkgDocRule)) { + if ir.PackageDoc == nil { + continue + } + + if ir.PackageDoc.DisabledRules.All || ir.PackageDoc.DisabledRules.Rules.Has(pkgDocRule) { + continue + } + + if f.Name.Name == commandPkgName || f.Name.Name == commandTestPkgName { + // Skip command packages, as they are not required to start with + // "Package main" or "Package main_test". + // + // See for more details: + // - https://github.com/godoc-lint/godoc-lint/issues/10 + // - https://go.dev/doc/comment#cmd + continue + } + + if ir.PackageDoc.Text == "" { + continue + } + + if shared.HasDeprecatedParagraph(ir.PackageDoc.Parsed.Content) { + // If there's a paragraph starting with "Deprecated:", we skip the + // entire godoc. The reason is a deprecated symbol will not appear + // when docs are rendered. + // + // Another reason is that we cannot just skip those paragraphs and + // look for the symbol in the remaining text. To do that, we need + // to iterate over all comment.Block nodes, and check if a block + // is a paragraph AND starts with the deprecation marker. This is + // simple, but the challenge appears when we get to the first block + // that does not have the marker and we want to check if it starts + // with the symbol name. We'd expect that to be a paragraph, but + // that is not always the case. For example, take this decl: + // + // // Deprecated: blah blah + // // + // // Foo is integer + // // + // // Deprecation: blah blah + // type Foo int + // + // The first block is a paragraph which we can easily skip due to + // the "Deprecated:" marker. However, the second block is actually + // parsed as a heading. One can verify this by copy/pasting it in + // a Go file and check the gopls hover. + // + // There might be a workaround for this, but this also means the + // godoc parser behaves in unexpected ways, and until we don't + // really know the extent of its quirks, it's safer to just skip + // further checks on such godocs. + continue + } + + if expectedPrefix, ok := checkPkgDocPrefix(ir.PackageDoc.Text, f.Name.Name); !ok { + actx.Pass.Reportf(ir.PackageDoc.CG.Pos(), "package godoc should start with %q", expectedPrefix+" ") + } + } +} + +func checkPkgDocPrefix(text, packageName string) (string, bool) { + expectedPrefix := "Package " + packageName + if !strings.HasPrefix(text, expectedPrefix) { + return expectedPrefix, false + } + rest := text[len(expectedPrefix):] + return expectedPrefix, rest == "" || rest[0] == ' ' || rest[0] == '\t' || rest[0] == '\r' || rest[0] == '\n' +} + +func checkSinglePkgDocRule(actx *model.AnalysisContext) { + if !actx.Config.IsAnyRuleApplicable(model.RuleSet{}.Add(singlePkgDocRule)) { + return + } + + includeTests := actx.Config.GetRuleOptions().SinglePkgDocIncludeTests + + documentedPkgs := make(map[string][]*ast.File, 2) + + for f, ir := range util.AnalysisApplicableFiles(actx, includeTests, model.RuleSet{}.Add(singlePkgDocRule)) { + if ir.PackageDoc == nil || ir.PackageDoc.Text == "" { + continue + } + + if ir.PackageDoc.DisabledRules.All || ir.PackageDoc.DisabledRules.Rules.Has(singlePkgDocRule) { + continue + } + + pkg := f.Name.Name + if _, ok := documentedPkgs[pkg]; !ok { + documentedPkgs[pkg] = make([]*ast.File, 0, 2) + } + documentedPkgs[pkg] = append(documentedPkgs[pkg], f) + } + + for pkg, fs := range documentedPkgs { + if len(fs) < 2 { + continue + } + for _, f := range fs { + ir := actx.InspectorResult.Files[f] + actx.Pass.Reportf(ir.PackageDoc.CG.Pos(), "package has more than one godoc (%q)", pkg) + } + } +} + +func checkRequirePkgDocRule(actx *model.AnalysisContext) { + if !actx.Config.IsAnyRuleApplicable(model.RuleSet{}.Add(requirePkgDocRule)) { + return + } + + includeTests := actx.Config.GetRuleOptions().RequirePkgDocIncludeTests + + pkgFiles := make(map[string][]*ast.File, 2) + + for f := range util.AnalysisApplicableFiles(actx, includeTests, model.RuleSet{}.Add(requirePkgDocRule)) { + pkg := f.Name.Name + if _, ok := pkgFiles[pkg]; !ok { + pkgFiles[pkg] = make([]*ast.File, 0, len(actx.Pass.Files)) + } + pkgFiles[pkg] = append(pkgFiles[pkg], f) + } + + for pkg, fs := range pkgFiles { + pkgHasGodoc := false + for _, f := range fs { + ir := actx.InspectorResult.Files[f] + + if ir.PackageDoc == nil || ir.PackageDoc.Text == "" { + continue + } + + if ir.PackageDoc.DisabledRules.All || ir.PackageDoc.DisabledRules.Rules.Has(requirePkgDocRule) { + continue + } + + pkgHasGodoc = true + break + } + + if pkgHasGodoc { + continue + } + + // Add a diagnostic message to the first file of the package. + actx.Pass.Reportf(fs[0].Name.Pos(), "package should have a godoc (%q)", pkg) + } +} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/check/registry.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/check/registry.go new file mode 100644 index 000000000..657fa8bc4 --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/check/registry.go @@ -0,0 +1,66 @@ +// Package check provides a registry of checkers. +package check + +import ( + "github.com/godoc-lint/godoc-lint/pkg/check/deprecated" + "github.com/godoc-lint/godoc-lint/pkg/check/max_len" + "github.com/godoc-lint/godoc-lint/pkg/check/no_unused_link" + "github.com/godoc-lint/godoc-lint/pkg/check/pkg_doc" + "github.com/godoc-lint/godoc-lint/pkg/check/require_doc" + "github.com/godoc-lint/godoc-lint/pkg/check/start_with_name" + "github.com/godoc-lint/godoc-lint/pkg/check/stdlib_doclink" + "github.com/godoc-lint/godoc-lint/pkg/model" +) + +// Registry implements a registry of rules. +type Registry struct { + checkers map[model.Checker]struct{} + coveredRules model.RuleSet +} + +// NewRegistry returns a new rule registry instance. +func NewRegistry(checkers ...model.Checker) *Registry { + registry := Registry{ + checkers: make(map[model.Checker]struct{}, len(checkers)+10), + } + for _, c := range checkers { + registry.Add(c) + } + return ®istry +} + +// NewPopulatedRegistry returns a registry with all supported rules registered. +func NewPopulatedRegistry() *Registry { + return NewRegistry( + max_len.NewMaxLenChecker(), + pkg_doc.NewPkgDocChecker(), + require_doc.NewRequireDocChecker(), + start_with_name.NewStartWithNameChecker(), + no_unused_link.NewNoUnusedLinkChecker(), + deprecated.NewDeprecatedChecker(), + stdlib_doclink.NewStdlibDoclinkChecker(), + ) +} + +// Add implements the corresponding interface method. +func (r *Registry) Add(checker model.Checker) { + if _, ok := r.checkers[checker]; ok { + return + } + r.coveredRules = r.coveredRules.Merge(checker.GetCoveredRules()) + r.checkers[checker] = struct{}{} +} + +// List implements the corresponding interface method. +func (r *Registry) List() []model.Checker { + all := make([]model.Checker, 0, len(r.checkers)) + for c := range r.checkers { + all = append(all, c) + } + return all +} + +// GetCoveredRules implements the corresponding interface method. +func (r *Registry) GetCoveredRules() model.RuleSet { + return r.coveredRules +} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/check/require_doc/require_doc.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/check/require_doc/require_doc.go new file mode 100644 index 000000000..de2436b7b --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/check/require_doc/require_doc.go @@ -0,0 +1,179 @@ +// Package require_doc provides a checker that requires symbols to have godocs. +package require_doc + +import ( + "go/ast" + + "golang.org/x/tools/go/analysis" + + "github.com/godoc-lint/godoc-lint/pkg/model" + "github.com/godoc-lint/godoc-lint/pkg/util" +) + +const requireDocRule = model.RequireDocRule + +var ruleSet = model.RuleSet{}.Add(requireDocRule) + +// RequireDocChecker checks required godocs. +type RequireDocChecker struct{} + +// NewRequireDocChecker returns a new instance of the corresponding checker. +func NewRequireDocChecker() *RequireDocChecker { + return &RequireDocChecker{} +} + +// GetCoveredRules implements the corresponding interface method. +func (r *RequireDocChecker) GetCoveredRules() model.RuleSet { + return ruleSet +} + +// Apply implements the corresponding interface method. +func (r *RequireDocChecker) Apply(actx *model.AnalysisContext) error { + includeTests := actx.Config.GetRuleOptions().RequireDocIncludeTests + requirePublic := !actx.Config.GetRuleOptions().RequireDocIgnoreExported + requirePrivate := !actx.Config.GetRuleOptions().RequireDocIgnoreUnexported + + if !requirePublic && !requirePrivate { + return nil + } + + for _, ir := range util.AnalysisApplicableFiles(actx, includeTests, model.RuleSet{}.Add(requireDocRule)) { + for _, decl := range ir.SymbolDecl { + isExported := ast.IsExported(decl.Name) + if decl.IsMethod && decl.MethodRecvBaseTypeName != "" { + // A method is considered exported (in terms of godoc visibility) + // only if both the method name and the base type name are exported. + isExported = isExported && ast.IsExported(decl.MethodRecvBaseTypeName) + } + + if isExported && !requirePublic || !isExported && !requirePrivate { + continue + } + + if decl.Name == "_" { + // Blank identifiers should be ignored; e.g.: + // + // var _ = 0 + continue + } + + if decl.Doc != nil && (decl.Doc.DisabledRules.All || decl.Doc.DisabledRules.Rules.Has(requireDocRule)) { + continue + } + + if decl.Kind == model.SymbolDeclKindBad { + continue + } + + if decl.Kind == model.SymbolDeclKindFunc { + if decl.Doc == nil || decl.Doc.Text == "" { + reportRange(actx.Pass, decl.Ident) + } + continue + } + + // Now we only have const/var/type declarations. + + if decl.Doc != nil && decl.Doc.Text != "" { + // cases: + // + // // godoc + // const foo = 0 + // + // // godoc + // const foo, bar = 0, 0 + // + // const ( + // // godoc + // foo = 0 + // ) + // + // const ( + // // godoc + // foo, bar = 0, 0 + // ) + // + // // godoc + // type foo int + // + // type ( + // // godoc + // foo int + // ) + continue + } + + if decl.TrailingDoc != nil && decl.TrailingDoc.Text != "" { + // cases: + // + // const foo = 0 // godoc + // + // const foo, bar = 0, 0 // godoc + // + // const ( + // foo = 0 // godoc + // ) + // + // const ( + // foo, bar = 0, 0 // godoc + // ) + // + // type foo int // godoc + // + // type ( + // foo int // godoc + // ) + continue + } + + if decl.ParentDoc != nil && decl.ParentDoc.Text != "" { + // cases: + // + // // godoc + // const ( + // foo = 0 + // ) + // + // // godoc + // const ( + // foo, bar = 0, 0 + // ) + // + // // godoc + // type ( + // foo int + // ) + continue + } + + // At this point there is no godoc for the symbol. + // + // cases: + // + // const foo = 0 + // + // const foo, bar = 0, 0 + // + // const ( + // foo = 0 + // ) + // + // const ( + // foo, bar = 0, 0 + // ) + // + // type foo int + // + // type ( + // foo int + // ) + + reportRange(actx.Pass, decl.Ident) + } + } + return nil +} + +func reportRange(pass *analysis.Pass, ident *ast.Ident) { + pass.ReportRangef(ident, "symbol should have a godoc (%q)", ident.Name) +} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/check/shared/deprecated.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/check/shared/deprecated.go new file mode 100644 index 000000000..8ebed0e2b --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/check/shared/deprecated.go @@ -0,0 +1,29 @@ +// Package shared provides shared utilities for checkers. +package shared + +import ( + "go/doc/comment" + "strings" +) + +// HasDeprecatedParagraph reports whether the given comment blocks contain a +// paragraph starting with deprecation marker. +func HasDeprecatedParagraph(blocks []comment.Block) bool { + for _, block := range blocks { + par, ok := block.(*comment.Paragraph) + if !ok || len(par.Text) == 0 { + continue + } + text, ok := (par.Text[0]).(comment.Plain) + if !ok { + continue + } + + // Only an exact match (casing and the trailing whitespace) is considered + // a valid deprecation marker. + if strings.HasPrefix(string(text), "Deprecated: ") { + return true + } + } + return false +} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/check/start_with_name/start_with_name.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/check/start_with_name/start_with_name.go new file mode 100644 index 000000000..70301709c --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/check/start_with_name/start_with_name.go @@ -0,0 +1,140 @@ +// Package start_with_name provides a checker for godocs starting with the +// symbol name. +package start_with_name + +import ( + "go/ast" + "regexp" + "strings" + + "github.com/godoc-lint/godoc-lint/pkg/check/shared" + "github.com/godoc-lint/godoc-lint/pkg/model" + "github.com/godoc-lint/godoc-lint/pkg/util" +) + +const startWithNameRule = model.StartWithNameRule + +var ruleSet = model.RuleSet{}.Add(startWithNameRule) + +// StartWithNameChecker checks starter of godocs. +type StartWithNameChecker struct{} + +// NewStartWithNameChecker returns a new instance of the corresponding checker. +func NewStartWithNameChecker() *StartWithNameChecker { + return &StartWithNameChecker{} +} + +// GetCoveredRules implements the corresponding interface method. +func (r *StartWithNameChecker) GetCoveredRules() model.RuleSet { + return ruleSet +} + +// Apply implements the corresponding interface method. +func (r *StartWithNameChecker) Apply(actx *model.AnalysisContext) error { + if !actx.Config.IsAnyRuleApplicable(model.RuleSet{}.Add(startWithNameRule)) { + return nil + } + + includeTests := actx.Config.GetRuleOptions().StartWithNameIncludeTests + includePrivate := actx.Config.GetRuleOptions().StartWithNameIncludeUnexported + + for _, ir := range util.AnalysisApplicableFiles(actx, includeTests, model.RuleSet{}.Add(startWithNameRule)) { + for _, decl := range ir.SymbolDecl { + isExported := ast.IsExported(decl.Name) + if decl.IsMethod && decl.MethodRecvBaseTypeName != "" { + // A method is considered exported (in terms of godoc visibility) + // only if both the method name and the base type name are exported. + isExported = isExported && ast.IsExported(decl.MethodRecvBaseTypeName) + } + + if !isExported && !includePrivate { + continue + } + + if decl.Name == "_" { + // Blank identifiers should be ignored; e.g.: + // + // var _ = 0 + continue + } + + if decl.Kind == model.SymbolDeclKindBad { + continue + } + + if decl.Doc == nil || decl.Doc.Text == "" { + continue + } + + if decl.Doc.DisabledRules.All || decl.Doc.DisabledRules.Rules.Has(startWithNameRule) { + continue + } + + if decl.MultiNameDecl { + continue + } + + if shared.HasDeprecatedParagraph(decl.Doc.Parsed.Content) { + // If there's a paragraph starting with "Deprecated:", we skip the + // entire godoc. The reason is a deprecated symbol will not appear + // when docs are rendered. + // + // Another reason is that we cannot just skip those paragraphs and + // look for the symbol in the remaining text. To do that, we need + // to iterate over all comment.Block nodes, and check if a block + // is a paragraph AND starts with the deprecation marker. This is + // simple, but the challenge appears when we get to the first block + // that does not have the marker and we want to check if it starts + // with the symbol name. We'd expect that to be a paragraph, but + // that is not always the case. For example, take this decl: + // + // // Deprecated: blah blah + // // + // // Foo is integer + // // + // // Deprecation: blah blah + // type Foo int + // + // The first block is a paragraph which we can easily skip due to + // the "Deprecated:" marker. However, the second block is actually + // parsed as a heading. One can verify this by copy/pasting it in + // a Go file and check the gopls hover. + // + // There might be a workaround for this, but this also means the + // godoc parser behaves in unexpected ways, and until we don't + // really know the extent of its quirks, it's safer to just skip + // further checks on such godocs. + continue + } + + if matchSymbolName(decl.Doc.Text, decl.Name) { + continue + } + + actx.Pass.ReportRangef(&decl.Doc.CG, "godoc should start with symbol name (%q)", decl.Name) + } + } + return nil +} + +var ( + startPattern = regexp.MustCompile(`^(?:(A|a|AN|An|an|THE|The|the) )?(?P.+?)\b`) + startPatternSymbolNameIndex = startPattern.SubexpIndex("symbol_name") +) + +func matchSymbolName(text, symbol string) bool { + head := strings.SplitN(text, "\n", 2)[0] + head, _ = strings.CutPrefix(head, "\r") + head = strings.SplitN(head, " ", 2)[0] + head = strings.SplitN(head, "\t", 2)[0] + + if head == symbol { + return true + } + + match := startPattern.FindStringSubmatch(text) + if match == nil { + return false + } + return match[startPatternSymbolNameIndex] == symbol +} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/check/stdlib_doclink/data.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/check/stdlib_doclink/data.go new file mode 100644 index 000000000..92fb8b1bc --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/check/stdlib_doclink/data.go @@ -0,0 +1,27 @@ +package stdlib_doclink + +import ( + "bytes" + _ "embed" + "encoding/json" + "sync" + + "github.com/godoc-lint/godoc-lint/pkg/check/stdlib_doclink/internal" +) + +//go:embed stdlib.json +var stdlibRaw []byte + +var stdlib = sync.OnceValue(func() internal.Stdlib { + v, _ := parseStdlib() + return v +}) + +func parseStdlib() (internal.Stdlib, error) { + result := internal.Stdlib{} + if err := json.NewDecoder(bytes.NewReader(stdlibRaw)).Decode(&result); err != nil { + // This never happens + return internal.Stdlib{}, err + } + return result, nil +} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/check/stdlib_doclink/internal/type.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/check/stdlib_doclink/internal/type.go new file mode 100644 index 000000000..4197695e1 --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/check/stdlib_doclink/internal/type.go @@ -0,0 +1,30 @@ +// Package internal contains internal types for stdlib_doclink checker. +package internal + +import ( + _ "embed" +) + +// SymbolKind represents the kind of a symbol in the standard library. +type SymbolKind string + +// Kinds of symbols. +const ( + SymbolKindNA SymbolKind = "" + SymbolKindConst SymbolKind = "c" + SymbolKindVar SymbolKind = "v" + SymbolKindFunc SymbolKind = "f" + SymbolKindMethod SymbolKind = "m" + SymbolKindType SymbolKind = "t" +) + +// StdlibPackage represents a standard library package with its path, name, and +// symbols. +type StdlibPackage struct { + Path string `json:"path"` + Name string `json:"name"` + Symbols map[string]SymbolKind `json:"symbols"` +} + +// Stdlib represents a collection of standard library packages. +type Stdlib map[string]*StdlibPackage diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/check/stdlib_doclink/stdlib.json b/vendor/github.com/godoc-lint/godoc-lint/pkg/check/stdlib_doclink/stdlib.json new file mode 100644 index 000000000..cbf8206d0 --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/check/stdlib_doclink/stdlib.json @@ -0,0 +1 @@ +{"archive/tar":{"path":"archive/tar","name":"tar","symbols":{"ErrFieldTooLong":"v","ErrHeader":"v","ErrInsecurePath":"v","ErrWriteAfterClose":"v","ErrWriteTooLong":"v","FileInfoHeader":"f","FileInfoNames":"t","Format":"t","Format.String":"m","FormatGNU":"c","FormatPAX":"c","FormatUSTAR":"c","FormatUnknown":"c","Header":"t","Header.FileInfo":"m","NewReader":"f","NewWriter":"f","Reader":"t","Reader.Next":"m","Reader.Read":"m","TypeBlock":"c","TypeChar":"c","TypeCont":"c","TypeDir":"c","TypeFifo":"c","TypeGNULongLink":"c","TypeGNULongName":"c","TypeGNUSparse":"c","TypeLink":"c","TypeReg":"c","TypeRegA":"c","TypeSymlink":"c","TypeXGlobalHeader":"c","TypeXHeader":"c","Writer":"t","Writer.AddFS":"m","Writer.Close":"m","Writer.Flush":"m","Writer.Write":"m","Writer.WriteHeader":"m"}},"archive/zip":{"path":"archive/zip","name":"zip","symbols":{"Compressor":"t","Decompressor":"t","Deflate":"c","ErrAlgorithm":"v","ErrChecksum":"v","ErrFormat":"v","ErrInsecurePath":"v","File":"t","File.DataOffset":"m","File.Open":"m","File.OpenRaw":"m","FileHeader":"t","FileHeader.FileInfo":"m","FileHeader.ModTime":"m","FileHeader.Mode":"m","FileHeader.SetModTime":"m","FileHeader.SetMode":"m","FileInfoHeader":"f","NewReader":"f","NewWriter":"f","OpenReader":"f","ReadCloser":"t","ReadCloser.Close":"m","Reader":"t","Reader.Open":"m","Reader.RegisterDecompressor":"m","RegisterCompressor":"f","RegisterDecompressor":"f","Store":"c","Writer":"t","Writer.AddFS":"m","Writer.Close":"m","Writer.Copy":"m","Writer.Create":"m","Writer.CreateHeader":"m","Writer.CreateRaw":"m","Writer.Flush":"m","Writer.RegisterCompressor":"m","Writer.SetComment":"m","Writer.SetOffset":"m"}},"bufio":{"path":"bufio","name":"bufio","symbols":{"ErrAdvanceTooFar":"v","ErrBadReadCount":"v","ErrBufferFull":"v","ErrFinalToken":"v","ErrInvalidUnreadByte":"v","ErrInvalidUnreadRune":"v","ErrNegativeAdvance":"v","ErrNegativeCount":"v","ErrTooLong":"v","MaxScanTokenSize":"c","NewReadWriter":"f","NewReader":"f","NewReaderSize":"f","NewScanner":"f","NewWriter":"f","NewWriterSize":"f","ReadWriter":"t","Reader":"t","Reader.Buffered":"m","Reader.Discard":"m","Reader.Peek":"m","Reader.Read":"m","Reader.ReadByte":"m","Reader.ReadBytes":"m","Reader.ReadLine":"m","Reader.ReadRune":"m","Reader.ReadSlice":"m","Reader.ReadString":"m","Reader.Reset":"m","Reader.Size":"m","Reader.UnreadByte":"m","Reader.UnreadRune":"m","Reader.WriteTo":"m","ScanBytes":"f","ScanLines":"f","ScanRunes":"f","ScanWords":"f","Scanner":"t","Scanner.Buffer":"m","Scanner.Bytes":"m","Scanner.Err":"m","Scanner.Scan":"m","Scanner.Split":"m","Scanner.Text":"m","SplitFunc":"t","Writer":"t","Writer.Available":"m","Writer.AvailableBuffer":"m","Writer.Buffered":"m","Writer.Flush":"m","Writer.ReadFrom":"m","Writer.Reset":"m","Writer.Size":"m","Writer.Write":"m","Writer.WriteByte":"m","Writer.WriteRune":"m","Writer.WriteString":"m"}},"builtin":{"path":"builtin","name":"builtin","symbols":{"ComplexType":"t","FloatType":"t","IntegerType":"t","Type":"t","Type1":"t"}},"bytes":{"path":"bytes","name":"bytes","symbols":{"Buffer":"t","Buffer.Available":"m","Buffer.AvailableBuffer":"m","Buffer.Bytes":"m","Buffer.Cap":"m","Buffer.Grow":"m","Buffer.Len":"m","Buffer.Next":"m","Buffer.Peek":"m","Buffer.Read":"m","Buffer.ReadByte":"m","Buffer.ReadBytes":"m","Buffer.ReadFrom":"m","Buffer.ReadRune":"m","Buffer.ReadString":"m","Buffer.Reset":"m","Buffer.String":"m","Buffer.Truncate":"m","Buffer.UnreadByte":"m","Buffer.UnreadRune":"m","Buffer.Write":"m","Buffer.WriteByte":"m","Buffer.WriteRune":"m","Buffer.WriteString":"m","Buffer.WriteTo":"m","Clone":"f","Compare":"f","Contains":"f","ContainsAny":"f","ContainsFunc":"f","ContainsRune":"f","Count":"f","Cut":"f","CutPrefix":"f","CutSuffix":"f","Equal":"f","EqualFold":"f","ErrTooLarge":"v","Fields":"f","FieldsFunc":"f","FieldsFuncSeq":"f","FieldsSeq":"f","HasPrefix":"f","HasSuffix":"f","Index":"f","IndexAny":"f","IndexByte":"f","IndexFunc":"f","IndexRune":"f","Join":"f","LastIndex":"f","LastIndexAny":"f","LastIndexByte":"f","LastIndexFunc":"f","Lines":"f","Map":"f","MinRead":"c","NewBuffer":"f","NewBufferString":"f","NewReader":"f","Reader":"t","Reader.Len":"m","Reader.Read":"m","Reader.ReadAt":"m","Reader.ReadByte":"m","Reader.ReadRune":"m","Reader.Reset":"m","Reader.Seek":"m","Reader.Size":"m","Reader.UnreadByte":"m","Reader.UnreadRune":"m","Reader.WriteTo":"m","Repeat":"f","Replace":"f","ReplaceAll":"f","Runes":"f","Split":"f","SplitAfter":"f","SplitAfterN":"f","SplitAfterSeq":"f","SplitN":"f","SplitSeq":"f","Title":"f","ToLower":"f","ToLowerSpecial":"f","ToTitle":"f","ToTitleSpecial":"f","ToUpper":"f","ToUpperSpecial":"f","ToValidUTF8":"f","Trim":"f","TrimFunc":"f","TrimLeft":"f","TrimLeftFunc":"f","TrimPrefix":"f","TrimRight":"f","TrimRightFunc":"f","TrimSpace":"f","TrimSuffix":"f"}},"cmp":{"path":"cmp","name":"cmp","symbols":{"Compare":"f","Less":"f","Or":"f","Ordered":"t"}},"compress/bzip2":{"path":"compress/bzip2","name":"bzip2","symbols":{"NewReader":"f","StructuralError":"t","StructuralError.Error":"m"}},"compress/flate":{"path":"compress/flate","name":"flate","symbols":{"BestCompression":"c","BestSpeed":"c","CorruptInputError":"t","CorruptInputError.Error":"m","DefaultCompression":"c","HuffmanOnly":"c","InternalError":"t","InternalError.Error":"m","NewReader":"f","NewReaderDict":"f","NewWriter":"f","NewWriterDict":"f","NoCompression":"c","ReadError":"t","ReadError.Error":"m","Reader":"t","Resetter":"t","WriteError":"t","WriteError.Error":"m","Writer":"t","Writer.Close":"m","Writer.Flush":"m","Writer.Reset":"m","Writer.Write":"m"}},"compress/gzip":{"path":"compress/gzip","name":"gzip","symbols":{"BestCompression":"c","BestSpeed":"c","DefaultCompression":"c","ErrChecksum":"v","ErrHeader":"v","Header":"t","HuffmanOnly":"c","NewReader":"f","NewWriter":"f","NewWriterLevel":"f","NoCompression":"c","Reader":"t","Reader.Close":"m","Reader.Multistream":"m","Reader.Read":"m","Reader.Reset":"m","Writer":"t","Writer.Close":"m","Writer.Flush":"m","Writer.Reset":"m","Writer.Write":"m"}},"compress/lzw":{"path":"compress/lzw","name":"lzw","symbols":{"LSB":"c","MSB":"c","NewReader":"f","NewWriter":"f","Order":"t","Reader":"t","Reader.Close":"m","Reader.Read":"m","Reader.Reset":"m","Writer":"t","Writer.Close":"m","Writer.Reset":"m","Writer.Write":"m"}},"compress/zlib":{"path":"compress/zlib","name":"zlib","symbols":{"BestCompression":"c","BestSpeed":"c","DefaultCompression":"c","ErrChecksum":"v","ErrDictionary":"v","ErrHeader":"v","HuffmanOnly":"c","NewReader":"f","NewReaderDict":"f","NewWriter":"f","NewWriterLevel":"f","NewWriterLevelDict":"f","NoCompression":"c","Resetter":"t","Writer":"t","Writer.Close":"m","Writer.Flush":"m","Writer.Reset":"m","Writer.Write":"m"}},"container/heap":{"path":"container/heap","name":"heap","symbols":{"Fix":"f","Init":"f","Interface":"t","Pop":"f","Push":"f","Remove":"f"}},"container/list":{"path":"container/list","name":"list","symbols":{"Element":"t","Element.Next":"m","Element.Prev":"m","List":"t","List.Back":"m","List.Front":"m","List.Init":"m","List.InsertAfter":"m","List.InsertBefore":"m","List.Len":"m","List.MoveAfter":"m","List.MoveBefore":"m","List.MoveToBack":"m","List.MoveToFront":"m","List.PushBack":"m","List.PushBackList":"m","List.PushFront":"m","List.PushFrontList":"m","List.Remove":"m","New":"f"}},"container/ring":{"path":"container/ring","name":"ring","symbols":{"New":"f","Ring":"t","Ring.Do":"m","Ring.Len":"m","Ring.Link":"m","Ring.Move":"m","Ring.Next":"m","Ring.Prev":"m","Ring.Unlink":"m"}},"context":{"path":"context","name":"context","symbols":{"AfterFunc":"f","Background":"f","CancelCauseFunc":"t","CancelFunc":"t","Canceled":"v","Cause":"f","Context":"t","DeadlineExceeded":"v","TODO":"f","WithCancel":"f","WithCancelCause":"f","WithDeadline":"f","WithDeadlineCause":"f","WithTimeout":"f","WithTimeoutCause":"f","WithValue":"f","WithoutCancel":"f"}},"crypto":{"path":"crypto","name":"crypto","symbols":{"BLAKE2b_256":"c","BLAKE2b_384":"c","BLAKE2b_512":"c","BLAKE2s_256":"c","Decapsulator":"t","Decrypter":"t","DecrypterOpts":"t","Encapsulator":"t","Hash":"t","Hash.Available":"m","Hash.HashFunc":"m","Hash.New":"m","Hash.Size":"m","Hash.String":"m","MD4":"c","MD5":"c","MD5SHA1":"c","MessageSigner":"t","PrivateKey":"t","PublicKey":"t","RIPEMD160":"c","RegisterHash":"f","SHA1":"c","SHA224":"c","SHA256":"c","SHA384":"c","SHA3_224":"c","SHA3_256":"c","SHA3_384":"c","SHA3_512":"c","SHA512":"c","SHA512_224":"c","SHA512_256":"c","SignMessage":"f","Signer":"t","SignerOpts":"t"}},"crypto/aes":{"path":"crypto/aes","name":"aes","symbols":{"BlockSize":"c","KeySizeError":"t","KeySizeError.Error":"m","NewCipher":"f"}},"crypto/cipher":{"path":"crypto/cipher","name":"cipher","symbols":{"AEAD":"t","Block":"t","BlockMode":"t","NewCBCDecrypter":"f","NewCBCEncrypter":"f","NewCFBDecrypter":"f","NewCFBEncrypter":"f","NewCTR":"f","NewGCM":"f","NewGCMWithNonceSize":"f","NewGCMWithRandomNonce":"f","NewGCMWithTagSize":"f","NewOFB":"f","Stream":"t","StreamReader":"t","StreamReader.Read":"m","StreamWriter":"t","StreamWriter.Close":"m","StreamWriter.Write":"m"}},"crypto/des":{"path":"crypto/des","name":"des","symbols":{"BlockSize":"c","KeySizeError":"t","KeySizeError.Error":"m","NewCipher":"f","NewTripleDESCipher":"f"}},"crypto/dsa":{"path":"crypto/dsa","name":"dsa","symbols":{"ErrInvalidPublicKey":"v","GenerateKey":"f","GenerateParameters":"f","L1024N160":"c","L2048N224":"c","L2048N256":"c","L3072N256":"c","ParameterSizes":"t","Parameters":"t","PrivateKey":"t","PublicKey":"t","Sign":"f","Verify":"f"}},"crypto/ecdh":{"path":"crypto/ecdh","name":"ecdh","symbols":{"Curve":"t","KeyExchanger":"t","P256":"f","P384":"f","P521":"f","PrivateKey":"t","PrivateKey.Bytes":"m","PrivateKey.Curve":"m","PrivateKey.ECDH":"m","PrivateKey.Equal":"m","PrivateKey.Public":"m","PrivateKey.PublicKey":"m","PublicKey":"t","PublicKey.Bytes":"m","PublicKey.Curve":"m","PublicKey.Equal":"m","X25519":"f"}},"crypto/ecdsa":{"path":"crypto/ecdsa","name":"ecdsa","symbols":{"GenerateKey":"f","ParseRawPrivateKey":"f","ParseUncompressedPublicKey":"f","PrivateKey":"t","PrivateKey.Bytes":"m","PrivateKey.ECDH":"m","PrivateKey.Equal":"m","PrivateKey.Public":"m","PrivateKey.Sign":"m","PublicKey":"t","PublicKey.Bytes":"m","PublicKey.ECDH":"m","PublicKey.Equal":"m","Sign":"f","SignASN1":"f","Verify":"f","VerifyASN1":"f"}},"crypto/ed25519":{"path":"crypto/ed25519","name":"ed25519","symbols":{"GenerateKey":"f","NewKeyFromSeed":"f","Options":"t","Options.HashFunc":"m","PrivateKey":"t","PrivateKey.Equal":"m","PrivateKey.Public":"m","PrivateKey.Seed":"m","PrivateKey.Sign":"m","PrivateKeySize":"c","PublicKey":"t","PublicKey.Equal":"m","PublicKeySize":"c","SeedSize":"c","Sign":"f","SignatureSize":"c","Verify":"f","VerifyWithOptions":"f"}},"crypto/elliptic":{"path":"crypto/elliptic","name":"elliptic","symbols":{"Curve":"t","CurveParams":"t","CurveParams.Add":"m","CurveParams.Double":"m","CurveParams.IsOnCurve":"m","CurveParams.Params":"m","CurveParams.ScalarBaseMult":"m","CurveParams.ScalarMult":"m","GenerateKey":"f","Marshal":"f","MarshalCompressed":"f","P224":"f","P256":"f","P384":"f","P521":"f","Unmarshal":"f","UnmarshalCompressed":"f"}},"crypto/fips140":{"path":"crypto/fips140","name":"fips140","symbols":{"Enabled":"f","Enforced":"f","Version":"f","WithoutEnforcement":"f"}},"crypto/hkdf":{"path":"crypto/hkdf","name":"hkdf","symbols":{"Expand":"f","Extract":"f","Key":"f"}},"crypto/hmac":{"path":"crypto/hmac","name":"hmac","symbols":{"Equal":"f","New":"f"}},"crypto/hpke":{"path":"crypto/hpke","name":"hpke","symbols":{"AEAD":"t","AES128GCM":"f","AES256GCM":"f","ChaCha20Poly1305":"f","DHKEM":"f","ExportOnly":"f","HKDFSHA256":"f","HKDFSHA384":"f","HKDFSHA512":"f","KDF":"t","KEM":"t","MLKEM1024":"f","MLKEM1024P384":"f","MLKEM768":"f","MLKEM768P256":"f","MLKEM768X25519":"f","NewAEAD":"f","NewDHKEMPrivateKey":"f","NewDHKEMPublicKey":"f","NewHybridPrivateKey":"f","NewHybridPublicKey":"f","NewKDF":"f","NewKEM":"f","NewMLKEMPrivateKey":"f","NewMLKEMPublicKey":"f","NewRecipient":"f","NewSender":"f","Open":"f","PrivateKey":"t","PublicKey":"t","Recipient":"t","Recipient.Export":"m","Recipient.Open":"m","SHAKE128":"f","SHAKE256":"f","Seal":"f","Sender":"t","Sender.Export":"m","Sender.Seal":"m"}},"crypto/md5":{"path":"crypto/md5","name":"md5","symbols":{"BlockSize":"c","New":"f","Size":"c","Sum":"f"}},"crypto/mlkem":{"path":"crypto/mlkem","name":"mlkem","symbols":{"CiphertextSize1024":"c","CiphertextSize768":"c","DecapsulationKey1024":"t","DecapsulationKey1024.Bytes":"m","DecapsulationKey1024.Decapsulate":"m","DecapsulationKey1024.EncapsulationKey":"m","DecapsulationKey1024.Encapsulator":"m","DecapsulationKey768":"t","DecapsulationKey768.Bytes":"m","DecapsulationKey768.Decapsulate":"m","DecapsulationKey768.EncapsulationKey":"m","DecapsulationKey768.Encapsulator":"m","EncapsulationKey1024":"t","EncapsulationKey1024.Bytes":"m","EncapsulationKey1024.Encapsulate":"m","EncapsulationKey768":"t","EncapsulationKey768.Bytes":"m","EncapsulationKey768.Encapsulate":"m","EncapsulationKeySize1024":"c","EncapsulationKeySize768":"c","GenerateKey1024":"f","GenerateKey768":"f","NewDecapsulationKey1024":"f","NewDecapsulationKey768":"f","NewEncapsulationKey1024":"f","NewEncapsulationKey768":"f","SeedSize":"c","SharedKeySize":"c"}},"crypto/mlkem/mlkemtest":{"path":"crypto/mlkem/mlkemtest","name":"mlkemtest","symbols":{"Encapsulate1024":"f","Encapsulate768":"f"}},"crypto/pbkdf2":{"path":"crypto/pbkdf2","name":"pbkdf2","symbols":{"Key":"f"}},"crypto/rand":{"path":"crypto/rand","name":"rand","symbols":{"Int":"f","Prime":"f","Read":"f","Reader":"v","Text":"f"}},"crypto/rc4":{"path":"crypto/rc4","name":"rc4","symbols":{"Cipher":"t","Cipher.Reset":"m","Cipher.XORKeyStream":"m","KeySizeError":"t","KeySizeError.Error":"m","NewCipher":"f"}},"crypto/rsa":{"path":"crypto/rsa","name":"rsa","symbols":{"CRTValue":"t","DecryptOAEP":"f","DecryptPKCS1v15":"f","DecryptPKCS1v15SessionKey":"f","EncryptOAEP":"f","EncryptOAEPWithOptions":"f","EncryptPKCS1v15":"f","ErrDecryption":"v","ErrMessageTooLong":"v","ErrVerification":"v","GenerateKey":"f","GenerateMultiPrimeKey":"f","OAEPOptions":"t","PKCS1v15DecryptOptions":"t","PSSOptions":"t","PSSOptions.HashFunc":"m","PSSSaltLengthAuto":"c","PSSSaltLengthEqualsHash":"c","PrecomputedValues":"t","PrivateKey":"t","PrivateKey.Decrypt":"m","PrivateKey.Equal":"m","PrivateKey.Precompute":"m","PrivateKey.Public":"m","PrivateKey.Sign":"m","PrivateKey.Validate":"m","PublicKey":"t","PublicKey.Equal":"m","PublicKey.Size":"m","SignPKCS1v15":"f","SignPSS":"f","VerifyPKCS1v15":"f","VerifyPSS":"f"}},"crypto/sha1":{"path":"crypto/sha1","name":"sha1","symbols":{"BlockSize":"c","New":"f","Size":"c","Sum":"f"}},"crypto/sha256":{"path":"crypto/sha256","name":"sha256","symbols":{"BlockSize":"c","New":"f","New224":"f","Size":"c","Size224":"c","Sum224":"f","Sum256":"f"}},"crypto/sha3":{"path":"crypto/sha3","name":"sha3","symbols":{"New224":"f","New256":"f","New384":"f","New512":"f","NewCSHAKE128":"f","NewCSHAKE256":"f","NewSHAKE128":"f","NewSHAKE256":"f","SHA3":"t","SHA3.AppendBinary":"m","SHA3.BlockSize":"m","SHA3.Clone":"m","SHA3.MarshalBinary":"m","SHA3.Reset":"m","SHA3.Size":"m","SHA3.Sum":"m","SHA3.UnmarshalBinary":"m","SHA3.Write":"m","SHAKE":"t","SHAKE.AppendBinary":"m","SHAKE.BlockSize":"m","SHAKE.MarshalBinary":"m","SHAKE.Read":"m","SHAKE.Reset":"m","SHAKE.UnmarshalBinary":"m","SHAKE.Write":"m","Sum224":"f","Sum256":"f","Sum384":"f","Sum512":"f","SumSHAKE128":"f","SumSHAKE256":"f"}},"crypto/sha512":{"path":"crypto/sha512","name":"sha512","symbols":{"BlockSize":"c","New":"f","New384":"f","New512_224":"f","New512_256":"f","Size":"c","Size224":"c","Size256":"c","Size384":"c","Sum384":"f","Sum512":"f","Sum512_224":"f","Sum512_256":"f"}},"crypto/subtle":{"path":"crypto/subtle","name":"subtle","symbols":{"ConstantTimeByteEq":"f","ConstantTimeCompare":"f","ConstantTimeCopy":"f","ConstantTimeEq":"f","ConstantTimeLessOrEq":"f","ConstantTimeSelect":"f","WithDataIndependentTiming":"f","XORBytes":"f"}},"crypto/tls":{"path":"crypto/tls","name":"tls","symbols":{"AlertError":"t","AlertError.Error":"m","Certificate":"t","CertificateRequestInfo":"t","CertificateRequestInfo.Context":"m","CertificateRequestInfo.SupportsCertificate":"m","CertificateVerificationError":"t","CertificateVerificationError.Error":"m","CertificateVerificationError.Unwrap":"m","CipherSuite":"t","CipherSuiteName":"f","CipherSuites":"f","Client":"f","ClientAuthType":"t","ClientAuthType.String":"m","ClientHelloInfo":"t","ClientHelloInfo.Context":"m","ClientHelloInfo.SupportsCertificate":"m","ClientSessionCache":"t","ClientSessionState":"t","ClientSessionState.ResumptionState":"m","Config":"t","Config.BuildNameToCertificate":"m","Config.Clone":"m","Config.DecryptTicket":"m","Config.EncryptTicket":"m","Config.SetSessionTicketKeys":"m","Conn":"t","Conn.Close":"m","Conn.CloseWrite":"m","Conn.ConnectionState":"m","Conn.Handshake":"m","Conn.HandshakeContext":"m","Conn.LocalAddr":"m","Conn.NetConn":"m","Conn.OCSPResponse":"m","Conn.Read":"m","Conn.RemoteAddr":"m","Conn.SetDeadline":"m","Conn.SetReadDeadline":"m","Conn.SetWriteDeadline":"m","Conn.VerifyHostname":"m","Conn.Write":"m","ConnectionState":"t","ConnectionState.ExportKeyingMaterial":"m","CurveID":"t","CurveID.String":"m","CurveP256":"c","CurveP384":"c","CurveP521":"c","Dial":"f","DialWithDialer":"f","Dialer":"t","Dialer.Dial":"m","Dialer.DialContext":"m","ECDSAWithP256AndSHA256":"c","ECDSAWithP384AndSHA384":"c","ECDSAWithP521AndSHA512":"c","ECDSAWithSHA1":"c","ECHRejectionError":"t","ECHRejectionError.Error":"m","Ed25519":"c","EncryptedClientHelloKey":"t","InsecureCipherSuites":"f","Listen":"f","LoadX509KeyPair":"f","NewLRUClientSessionCache":"f","NewListener":"f","NewResumptionState":"f","NoClientCert":"c","PKCS1WithSHA1":"c","PKCS1WithSHA256":"c","PKCS1WithSHA384":"c","PKCS1WithSHA512":"c","PSSWithSHA256":"c","PSSWithSHA384":"c","PSSWithSHA512":"c","ParseSessionState":"f","QUICClient":"f","QUICConfig":"t","QUICConn":"t","QUICConn.Close":"m","QUICConn.ConnectionState":"m","QUICConn.HandleData":"m","QUICConn.NextEvent":"m","QUICConn.SendSessionTicket":"m","QUICConn.SetTransportParameters":"m","QUICConn.Start":"m","QUICConn.StoreSession":"m","QUICEncryptionLevel":"t","QUICEncryptionLevel.String":"m","QUICEncryptionLevelApplication":"c","QUICEncryptionLevelEarly":"c","QUICEncryptionLevelHandshake":"c","QUICEncryptionLevelInitial":"c","QUICErrorEvent":"c","QUICEvent":"t","QUICEventKind":"t","QUICHandshakeDone":"c","QUICNoEvent":"c","QUICRejectedEarlyData":"c","QUICResumeSession":"c","QUICServer":"f","QUICSessionTicketOptions":"t","QUICSetReadSecret":"c","QUICSetWriteSecret":"c","QUICStoreSession":"c","QUICTransportParameters":"c","QUICTransportParametersRequired":"c","QUICWriteData":"c","RecordHeaderError":"t","RecordHeaderError.Error":"m","RenegotiateFreelyAsClient":"c","RenegotiateNever":"c","RenegotiateOnceAsClient":"c","RenegotiationSupport":"t","RequestClientCert":"c","RequireAndVerifyClientCert":"c","RequireAnyClientCert":"c","SecP256r1MLKEM768":"c","SecP384r1MLKEM1024":"c","Server":"f","SessionState":"t","SessionState.Bytes":"m","SignatureScheme":"t","SignatureScheme.String":"m","TLS_AES_128_GCM_SHA256":"c","TLS_AES_256_GCM_SHA384":"c","TLS_CHACHA20_POLY1305_SHA256":"c","TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA":"c","TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256":"c","TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256":"c","TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA":"c","TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384":"c","TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305":"c","TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256":"c","TLS_ECDHE_ECDSA_WITH_RC4_128_SHA":"c","TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA":"c","TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA":"c","TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256":"c","TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256":"c","TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA":"c","TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384":"c","TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305":"c","TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256":"c","TLS_ECDHE_RSA_WITH_RC4_128_SHA":"c","TLS_FALLBACK_SCSV":"c","TLS_RSA_WITH_3DES_EDE_CBC_SHA":"c","TLS_RSA_WITH_AES_128_CBC_SHA":"c","TLS_RSA_WITH_AES_128_CBC_SHA256":"c","TLS_RSA_WITH_AES_128_GCM_SHA256":"c","TLS_RSA_WITH_AES_256_CBC_SHA":"c","TLS_RSA_WITH_AES_256_GCM_SHA384":"c","TLS_RSA_WITH_RC4_128_SHA":"c","VerifyClientCertIfGiven":"c","VersionName":"f","VersionSSL30":"c","VersionTLS10":"c","VersionTLS11":"c","VersionTLS12":"c","VersionTLS13":"c","X25519":"c","X25519MLKEM768":"c","X509KeyPair":"f"}},"crypto/x509":{"path":"crypto/x509","name":"x509","symbols":{"CANotAuthorizedForExtKeyUsage":"c","CANotAuthorizedForThisName":"c","CertPool":"t","CertPool.AddCert":"m","CertPool.AddCertWithConstraint":"m","CertPool.AppendCertsFromPEM":"m","CertPool.Clone":"m","CertPool.Equal":"m","CertPool.Subjects":"m","Certificate":"t","Certificate.CheckCRLSignature":"m","Certificate.CheckSignature":"m","Certificate.CheckSignatureFrom":"m","Certificate.CreateCRL":"m","Certificate.Equal":"m","Certificate.Verify":"m","Certificate.VerifyHostname":"m","CertificateInvalidError":"t","CertificateInvalidError.Error":"m","CertificateRequest":"t","CertificateRequest.CheckSignature":"m","ConstraintViolationError":"t","ConstraintViolationError.Error":"m","CreateCertificate":"f","CreateCertificateRequest":"f","CreateRevocationList":"f","DSA":"c","DSAWithSHA1":"c","DSAWithSHA256":"c","DecryptPEMBlock":"f","ECDSA":"c","ECDSAWithSHA1":"c","ECDSAWithSHA256":"c","ECDSAWithSHA384":"c","ECDSAWithSHA512":"c","Ed25519":"c","EncryptPEMBlock":"f","ErrUnsupportedAlgorithm":"v","Expired":"c","ExtKeyUsage":"t","ExtKeyUsage.OID":"m","ExtKeyUsage.String":"m","ExtKeyUsageAny":"c","ExtKeyUsageClientAuth":"c","ExtKeyUsageCodeSigning":"c","ExtKeyUsageEmailProtection":"c","ExtKeyUsageIPSECEndSystem":"c","ExtKeyUsageIPSECTunnel":"c","ExtKeyUsageIPSECUser":"c","ExtKeyUsageMicrosoftCommercialCodeSigning":"c","ExtKeyUsageMicrosoftKernelCodeSigning":"c","ExtKeyUsageMicrosoftServerGatedCrypto":"c","ExtKeyUsageNetscapeServerGatedCrypto":"c","ExtKeyUsageOCSPSigning":"c","ExtKeyUsageServerAuth":"c","ExtKeyUsageTimeStamping":"c","HostnameError":"t","HostnameError.Error":"m","IncompatibleUsage":"c","IncorrectPasswordError":"v","InsecureAlgorithmError":"t","InsecureAlgorithmError.Error":"m","InvalidReason":"t","IsEncryptedPEMBlock":"f","KeyUsage":"t","KeyUsage.String":"m","KeyUsageCRLSign":"c","KeyUsageCertSign":"c","KeyUsageContentCommitment":"c","KeyUsageDataEncipherment":"c","KeyUsageDecipherOnly":"c","KeyUsageDigitalSignature":"c","KeyUsageEncipherOnly":"c","KeyUsageKeyAgreement":"c","KeyUsageKeyEncipherment":"c","MD2WithRSA":"c","MD5WithRSA":"c","MarshalECPrivateKey":"f","MarshalPKCS1PrivateKey":"f","MarshalPKCS1PublicKey":"f","MarshalPKCS8PrivateKey":"f","MarshalPKIXPublicKey":"f","NameConstraintsWithoutSANs":"c","NameMismatch":"c","NewCertPool":"f","NoValidChains":"c","NotAuthorizedToSign":"c","OID":"t","OID.AppendBinary":"m","OID.AppendText":"m","OID.Equal":"m","OID.EqualASN1OID":"m","OID.MarshalBinary":"m","OID.MarshalText":"m","OID.String":"m","OID.UnmarshalBinary":"m","OID.UnmarshalText":"m","OIDFromASN1OID":"f","OIDFromInts":"f","PEMCipher":"t","PEMCipher3DES":"c","PEMCipherAES128":"c","PEMCipherAES192":"c","PEMCipherAES256":"c","PEMCipherDES":"c","ParseCRL":"f","ParseCertificate":"f","ParseCertificateRequest":"f","ParseCertificates":"f","ParseDERCRL":"f","ParseECPrivateKey":"f","ParseOID":"f","ParsePKCS1PrivateKey":"f","ParsePKCS1PublicKey":"f","ParsePKCS8PrivateKey":"f","ParsePKIXPublicKey":"f","ParseRevocationList":"f","PolicyMapping":"t","PublicKeyAlgorithm":"t","PublicKeyAlgorithm.String":"m","PureEd25519":"c","RSA":"c","RevocationList":"t","RevocationList.CheckSignatureFrom":"m","RevocationListEntry":"t","SHA1WithRSA":"c","SHA256WithRSA":"c","SHA256WithRSAPSS":"c","SHA384WithRSA":"c","SHA384WithRSAPSS":"c","SHA512WithRSA":"c","SHA512WithRSAPSS":"c","SetFallbackRoots":"f","SignatureAlgorithm":"t","SignatureAlgorithm.String":"m","SystemCertPool":"f","SystemRootsError":"t","SystemRootsError.Error":"m","SystemRootsError.Unwrap":"m","TooManyConstraints":"c","TooManyIntermediates":"c","UnconstrainedName":"c","UnhandledCriticalExtension":"t","UnhandledCriticalExtension.Error":"m","UnknownAuthorityError":"t","UnknownAuthorityError.Error":"m","UnknownPublicKeyAlgorithm":"c","UnknownSignatureAlgorithm":"c","VerifyOptions":"t"}},"crypto/x509/pkix":{"path":"crypto/x509/pkix","name":"pkix","symbols":{"AlgorithmIdentifier":"t","AttributeTypeAndValue":"t","AttributeTypeAndValueSET":"t","CertificateList":"t","CertificateList.HasExpired":"m","Extension":"t","Name":"t","Name.FillFromRDNSequence":"m","Name.String":"m","Name.ToRDNSequence":"m","RDNSequence":"t","RDNSequence.String":"m","RelativeDistinguishedNameSET":"t","RevokedCertificate":"t","TBSCertificateList":"t"}},"database/sql":{"path":"database/sql","name":"sql","symbols":{"ColumnType":"t","ColumnType.DatabaseTypeName":"m","ColumnType.DecimalSize":"m","ColumnType.Length":"m","ColumnType.Name":"m","ColumnType.Nullable":"m","ColumnType.ScanType":"m","Conn":"t","Conn.BeginTx":"m","Conn.Close":"m","Conn.ExecContext":"m","Conn.PingContext":"m","Conn.PrepareContext":"m","Conn.QueryContext":"m","Conn.QueryRowContext":"m","Conn.Raw":"m","DB":"t","DB.Begin":"m","DB.BeginTx":"m","DB.Close":"m","DB.Conn":"m","DB.Driver":"m","DB.Exec":"m","DB.ExecContext":"m","DB.Ping":"m","DB.PingContext":"m","DB.Prepare":"m","DB.PrepareContext":"m","DB.Query":"m","DB.QueryContext":"m","DB.QueryRow":"m","DB.QueryRowContext":"m","DB.SetConnMaxIdleTime":"m","DB.SetConnMaxLifetime":"m","DB.SetMaxIdleConns":"m","DB.SetMaxOpenConns":"m","DB.Stats":"m","DBStats":"t","Drivers":"f","ErrConnDone":"v","ErrNoRows":"v","ErrTxDone":"v","IsolationLevel":"t","IsolationLevel.String":"m","LevelDefault":"c","LevelLinearizable":"c","LevelReadCommitted":"c","LevelReadUncommitted":"c","LevelRepeatableRead":"c","LevelSerializable":"c","LevelSnapshot":"c","LevelWriteCommitted":"c","Named":"f","NamedArg":"t","Null":"t","NullBool":"t","NullBool.Scan":"m","NullBool.Value":"m","NullByte":"t","NullByte.Scan":"m","NullByte.Value":"m","NullFloat64":"t","NullFloat64.Scan":"m","NullFloat64.Value":"m","NullInt16":"t","NullInt16.Scan":"m","NullInt16.Value":"m","NullInt32":"t","NullInt32.Scan":"m","NullInt32.Value":"m","NullInt64":"t","NullInt64.Scan":"m","NullInt64.Value":"m","NullString":"t","NullString.Scan":"m","NullString.Value":"m","NullTime":"t","NullTime.Scan":"m","NullTime.Value":"m","Open":"f","OpenDB":"f","Out":"t","RawBytes":"t","Register":"f","Result":"t","Row":"t","Row.Err":"m","Row.Scan":"m","Rows":"t","Rows.Close":"m","Rows.ColumnTypes":"m","Rows.Columns":"m","Rows.Err":"m","Rows.Next":"m","Rows.NextResultSet":"m","Rows.Scan":"m","Scanner":"t","Stmt":"t","Stmt.Close":"m","Stmt.Exec":"m","Stmt.ExecContext":"m","Stmt.Query":"m","Stmt.QueryContext":"m","Stmt.QueryRow":"m","Stmt.QueryRowContext":"m","Tx":"t","Tx.Commit":"m","Tx.Exec":"m","Tx.ExecContext":"m","Tx.Prepare":"m","Tx.PrepareContext":"m","Tx.Query":"m","Tx.QueryContext":"m","Tx.QueryRow":"m","Tx.QueryRowContext":"m","Tx.Rollback":"m","Tx.Stmt":"m","Tx.StmtContext":"m","TxOptions":"t"}},"database/sql/driver":{"path":"database/sql/driver","name":"driver","symbols":{"Bool":"v","ColumnConverter":"t","Conn":"t","ConnBeginTx":"t","ConnPrepareContext":"t","Connector":"t","DefaultParameterConverter":"v","Driver":"t","DriverContext":"t","ErrBadConn":"v","ErrRemoveArgument":"v","ErrSkip":"v","Execer":"t","ExecerContext":"t","Int32":"v","IsScanValue":"f","IsValue":"f","IsolationLevel":"t","NamedValue":"t","NamedValueChecker":"t","NotNull":"t","NotNull.ConvertValue":"m","Null":"t","Null.ConvertValue":"m","Pinger":"t","Queryer":"t","QueryerContext":"t","Result":"t","ResultNoRows":"v","Rows":"t","RowsAffected":"t","RowsAffected.LastInsertId":"m","RowsAffected.RowsAffected":"m","RowsColumnTypeDatabaseTypeName":"t","RowsColumnTypeLength":"t","RowsColumnTypeNullable":"t","RowsColumnTypePrecisionScale":"t","RowsColumnTypeScanType":"t","RowsNextResultSet":"t","SessionResetter":"t","Stmt":"t","StmtExecContext":"t","StmtQueryContext":"t","String":"v","Tx":"t","TxOptions":"t","Validator":"t","Value":"t","ValueConverter":"t","Valuer":"t"}},"debug/buildinfo":{"path":"debug/buildinfo","name":"buildinfo","symbols":{"BuildInfo":"t","Read":"f","ReadFile":"f"}},"debug/dwarf":{"path":"debug/dwarf","name":"dwarf","symbols":{"AddrType":"t","ArrayType":"t","ArrayType.Size":"m","ArrayType.String":"m","Attr":"t","Attr.GoString":"m","Attr.String":"m","AttrAbstractOrigin":"c","AttrAccessibility":"c","AttrAddrBase":"c","AttrAddrClass":"c","AttrAlignment":"c","AttrAllocated":"c","AttrArtificial":"c","AttrAssociated":"c","AttrBaseTypes":"c","AttrBinaryScale":"c","AttrBitOffset":"c","AttrBitSize":"c","AttrByteSize":"c","AttrCallAllCalls":"c","AttrCallAllSourceCalls":"c","AttrCallAllTailCalls":"c","AttrCallColumn":"c","AttrCallDataLocation":"c","AttrCallDataValue":"c","AttrCallFile":"c","AttrCallLine":"c","AttrCallOrigin":"c","AttrCallPC":"c","AttrCallParameter":"c","AttrCallReturnPC":"c","AttrCallTailCall":"c","AttrCallTarget":"c","AttrCallTargetClobbered":"c","AttrCallValue":"c","AttrCalling":"c","AttrCommonRef":"c","AttrCompDir":"c","AttrConstExpr":"c","AttrConstValue":"c","AttrContainingType":"c","AttrCount":"c","AttrDataBitOffset":"c","AttrDataLocation":"c","AttrDataMemberLoc":"c","AttrDecimalScale":"c","AttrDecimalSign":"c","AttrDeclColumn":"c","AttrDeclFile":"c","AttrDeclLine":"c","AttrDeclaration":"c","AttrDefaultValue":"c","AttrDefaulted":"c","AttrDeleted":"c","AttrDescription":"c","AttrDigitCount":"c","AttrDiscr":"c","AttrDiscrList":"c","AttrDiscrValue":"c","AttrDwoName":"c","AttrElemental":"c","AttrEncoding":"c","AttrEndianity":"c","AttrEntrypc":"c","AttrEnumClass":"c","AttrExplicit":"c","AttrExportSymbols":"c","AttrExtension":"c","AttrExternal":"c","AttrFrameBase":"c","AttrFriend":"c","AttrHighpc":"c","AttrIdentifierCase":"c","AttrImport":"c","AttrInline":"c","AttrIsOptional":"c","AttrLanguage":"c","AttrLinkageName":"c","AttrLocation":"c","AttrLoclistsBase":"c","AttrLowerBound":"c","AttrLowpc":"c","AttrMacroInfo":"c","AttrMacros":"c","AttrMainSubprogram":"c","AttrMutable":"c","AttrName":"c","AttrNamelistItem":"c","AttrNoreturn":"c","AttrObjectPointer":"c","AttrOrdering":"c","AttrPictureString":"c","AttrPriority":"c","AttrProducer":"c","AttrPrototyped":"c","AttrPure":"c","AttrRanges":"c","AttrRank":"c","AttrRecursive":"c","AttrReference":"c","AttrReturnAddr":"c","AttrRnglistsBase":"c","AttrRvalueReference":"c","AttrSegment":"c","AttrSibling":"c","AttrSignature":"c","AttrSmall":"c","AttrSpecification":"c","AttrStartScope":"c","AttrStaticLink":"c","AttrStmtList":"c","AttrStrOffsetsBase":"c","AttrStride":"c","AttrStrideSize":"c","AttrStringLength":"c","AttrStringLengthBitSize":"c","AttrStringLengthByteSize":"c","AttrThreadsScaled":"c","AttrTrampoline":"c","AttrType":"c","AttrUpperBound":"c","AttrUseLocation":"c","AttrUseUTF8":"c","AttrVarParam":"c","AttrVirtuality":"c","AttrVisibility":"c","AttrVtableElemLoc":"c","BasicType":"t","BasicType.Basic":"m","BasicType.String":"m","BoolType":"t","CharType":"t","Class":"t","Class.GoString":"m","Class.String":"m","ClassAddrPtr":"c","ClassAddress":"c","ClassBlock":"c","ClassConstant":"c","ClassExprLoc":"c","ClassFlag":"c","ClassLinePtr":"c","ClassLocList":"c","ClassLocListPtr":"c","ClassMacPtr":"c","ClassRangeListPtr":"c","ClassReference":"c","ClassReferenceAlt":"c","ClassReferenceSig":"c","ClassRngList":"c","ClassRngListsPtr":"c","ClassStrOffsetsPtr":"c","ClassString":"c","ClassStringAlt":"c","ClassUnknown":"c","CommonType":"t","CommonType.Common":"m","CommonType.Size":"m","ComplexType":"t","Data":"t","Data.AddSection":"m","Data.AddTypes":"m","Data.LineReader":"m","Data.Ranges":"m","Data.Reader":"m","Data.Type":"m","DecodeError":"t","DecodeError.Error":"m","DotDotDotType":"t","DotDotDotType.String":"m","Entry":"t","Entry.AttrField":"m","Entry.Val":"m","EnumType":"t","EnumType.String":"m","EnumValue":"t","ErrUnknownPC":"v","Field":"t","FloatType":"t","FuncType":"t","FuncType.String":"m","IntType":"t","LineEntry":"t","LineFile":"t","LineReader":"t","LineReader.Files":"m","LineReader.Next":"m","LineReader.Reset":"m","LineReader.Seek":"m","LineReader.SeekPC":"m","LineReader.Tell":"m","LineReaderPos":"t","New":"f","Offset":"t","PtrType":"t","PtrType.String":"m","QualType":"t","QualType.Size":"m","QualType.String":"m","Reader":"t","Reader.AddressSize":"m","Reader.ByteOrder":"m","Reader.Next":"m","Reader.Seek":"m","Reader.SeekPC":"m","Reader.SkipChildren":"m","StructField":"t","StructType":"t","StructType.Defn":"m","StructType.String":"m","Tag":"t","Tag.GoString":"m","Tag.String":"m","TagAccessDeclaration":"c","TagArrayType":"c","TagAtomicType":"c","TagBaseType":"c","TagCallSite":"c","TagCallSiteParameter":"c","TagCatchDwarfBlock":"c","TagClassType":"c","TagCoarrayType":"c","TagCommonDwarfBlock":"c","TagCommonInclusion":"c","TagCompileUnit":"c","TagCondition":"c","TagConstType":"c","TagConstant":"c","TagDwarfProcedure":"c","TagDynamicType":"c","TagEntryPoint":"c","TagEnumerationType":"c","TagEnumerator":"c","TagFileType":"c","TagFormalParameter":"c","TagFriend":"c","TagGenericSubrange":"c","TagImmutableType":"c","TagImportedDeclaration":"c","TagImportedModule":"c","TagImportedUnit":"c","TagInheritance":"c","TagInlinedSubroutine":"c","TagInterfaceType":"c","TagLabel":"c","TagLexDwarfBlock":"c","TagMember":"c","TagModule":"c","TagMutableType":"c","TagNamelist":"c","TagNamelistItem":"c","TagNamespace":"c","TagPackedType":"c","TagPartialUnit":"c","TagPointerType":"c","TagPtrToMemberType":"c","TagReferenceType":"c","TagRestrictType":"c","TagRvalueReferenceType":"c","TagSetType":"c","TagSharedType":"c","TagSkeletonUnit":"c","TagStringType":"c","TagStructType":"c","TagSubprogram":"c","TagSubrangeType":"c","TagSubroutineType":"c","TagTemplateAlias":"c","TagTemplateTypeParameter":"c","TagTemplateValueParameter":"c","TagThrownType":"c","TagTryDwarfBlock":"c","TagTypeUnit":"c","TagTypedef":"c","TagUnionType":"c","TagUnspecifiedParameters":"c","TagUnspecifiedType":"c","TagVariable":"c","TagVariant":"c","TagVariantPart":"c","TagVolatileType":"c","TagWithStmt":"c","Type":"t","TypedefType":"t","TypedefType.Size":"m","TypedefType.String":"m","UcharType":"t","UintType":"t","UnspecifiedType":"t","UnsupportedType":"t","UnsupportedType.String":"m","VoidType":"t","VoidType.String":"m"}},"debug/elf":{"path":"debug/elf","name":"elf","symbols":{"ARM_MAGIC_TRAMP_NUMBER":"c","COMPRESS_HIOS":"c","COMPRESS_HIPROC":"c","COMPRESS_LOOS":"c","COMPRESS_LOPROC":"c","COMPRESS_ZLIB":"c","COMPRESS_ZSTD":"c","Chdr32":"t","Chdr64":"t","Class":"t","Class.GoString":"m","Class.String":"m","CompressionType":"t","CompressionType.GoString":"m","CompressionType.String":"m","DF_1_CONFALT":"c","DF_1_DIRECT":"c","DF_1_DISPRELDNE":"c","DF_1_DISPRELPND":"c","DF_1_EDITED":"c","DF_1_ENDFILTEE":"c","DF_1_GLOBAL":"c","DF_1_GLOBAUDIT":"c","DF_1_GROUP":"c","DF_1_IGNMULDEF":"c","DF_1_INITFIRST":"c","DF_1_INTERPOSE":"c","DF_1_KMOD":"c","DF_1_LOADFLTR":"c","DF_1_NOCOMMON":"c","DF_1_NODEFLIB":"c","DF_1_NODELETE":"c","DF_1_NODIRECT":"c","DF_1_NODUMP":"c","DF_1_NOHDR":"c","DF_1_NOKSYMS":"c","DF_1_NOOPEN":"c","DF_1_NORELOC":"c","DF_1_NOW":"c","DF_1_ORIGIN":"c","DF_1_PIE":"c","DF_1_SINGLETON":"c","DF_1_STUB":"c","DF_1_SYMINTPOSE":"c","DF_1_TRANS":"c","DF_1_WEAKFILTER":"c","DF_BIND_NOW":"c","DF_ORIGIN":"c","DF_STATIC_TLS":"c","DF_SYMBOLIC":"c","DF_TEXTREL":"c","DT_ADDRRNGHI":"c","DT_ADDRRNGLO":"c","DT_AUDIT":"c","DT_AUXILIARY":"c","DT_BIND_NOW":"c","DT_CHECKSUM":"c","DT_CONFIG":"c","DT_DEBUG":"c","DT_DEPAUDIT":"c","DT_ENCODING":"c","DT_FEATURE":"c","DT_FILTER":"c","DT_FINI":"c","DT_FINI_ARRAY":"c","DT_FINI_ARRAYSZ":"c","DT_FLAGS":"c","DT_FLAGS_1":"c","DT_GNU_CONFLICT":"c","DT_GNU_CONFLICTSZ":"c","DT_GNU_HASH":"c","DT_GNU_LIBLIST":"c","DT_GNU_LIBLISTSZ":"c","DT_GNU_PRELINKED":"c","DT_HASH":"c","DT_HIOS":"c","DT_HIPROC":"c","DT_INIT":"c","DT_INIT_ARRAY":"c","DT_INIT_ARRAYSZ":"c","DT_JMPREL":"c","DT_LOOS":"c","DT_LOPROC":"c","DT_MIPS_AUX_DYNAMIC":"c","DT_MIPS_BASE_ADDRESS":"c","DT_MIPS_COMPACT_SIZE":"c","DT_MIPS_CONFLICT":"c","DT_MIPS_CONFLICTNO":"c","DT_MIPS_CXX_FLAGS":"c","DT_MIPS_DELTA_CLASS":"c","DT_MIPS_DELTA_CLASSSYM":"c","DT_MIPS_DELTA_CLASSSYM_NO":"c","DT_MIPS_DELTA_CLASS_NO":"c","DT_MIPS_DELTA_INSTANCE":"c","DT_MIPS_DELTA_INSTANCE_NO":"c","DT_MIPS_DELTA_RELOC":"c","DT_MIPS_DELTA_RELOC_NO":"c","DT_MIPS_DELTA_SYM":"c","DT_MIPS_DELTA_SYM_NO":"c","DT_MIPS_DYNSTR_ALIGN":"c","DT_MIPS_FLAGS":"c","DT_MIPS_GOTSYM":"c","DT_MIPS_GP_VALUE":"c","DT_MIPS_HIDDEN_GOTIDX":"c","DT_MIPS_HIPAGENO":"c","DT_MIPS_ICHECKSUM":"c","DT_MIPS_INTERFACE":"c","DT_MIPS_INTERFACE_SIZE":"c","DT_MIPS_IVERSION":"c","DT_MIPS_LIBLIST":"c","DT_MIPS_LIBLISTNO":"c","DT_MIPS_LOCALPAGE_GOTIDX":"c","DT_MIPS_LOCAL_GOTIDX":"c","DT_MIPS_LOCAL_GOTNO":"c","DT_MIPS_MSYM":"c","DT_MIPS_OPTIONS":"c","DT_MIPS_PERF_SUFFIX":"c","DT_MIPS_PIXIE_INIT":"c","DT_MIPS_PLTGOT":"c","DT_MIPS_PROTECTED_GOTIDX":"c","DT_MIPS_RLD_MAP":"c","DT_MIPS_RLD_MAP_REL":"c","DT_MIPS_RLD_TEXT_RESOLVE_ADDR":"c","DT_MIPS_RLD_VERSION":"c","DT_MIPS_RWPLT":"c","DT_MIPS_SYMBOL_LIB":"c","DT_MIPS_SYMTABNO":"c","DT_MIPS_TIME_STAMP":"c","DT_MIPS_UNREFEXTNO":"c","DT_MOVEENT":"c","DT_MOVESZ":"c","DT_MOVETAB":"c","DT_NEEDED":"c","DT_NULL":"c","DT_PLTGOT":"c","DT_PLTPAD":"c","DT_PLTPADSZ":"c","DT_PLTREL":"c","DT_PLTRELSZ":"c","DT_POSFLAG_1":"c","DT_PPC64_GLINK":"c","DT_PPC64_OPD":"c","DT_PPC64_OPDSZ":"c","DT_PPC64_OPT":"c","DT_PPC_GOT":"c","DT_PPC_OPT":"c","DT_PREINIT_ARRAY":"c","DT_PREINIT_ARRAYSZ":"c","DT_REL":"c","DT_RELA":"c","DT_RELACOUNT":"c","DT_RELAENT":"c","DT_RELASZ":"c","DT_RELCOUNT":"c","DT_RELENT":"c","DT_RELSZ":"c","DT_RPATH":"c","DT_RUNPATH":"c","DT_SONAME":"c","DT_SPARC_REGISTER":"c","DT_STRSZ":"c","DT_STRTAB":"c","DT_SYMBOLIC":"c","DT_SYMENT":"c","DT_SYMINENT":"c","DT_SYMINFO":"c","DT_SYMINSZ":"c","DT_SYMTAB":"c","DT_SYMTAB_SHNDX":"c","DT_TEXTREL":"c","DT_TLSDESC_GOT":"c","DT_TLSDESC_PLT":"c","DT_USED":"c","DT_VALRNGHI":"c","DT_VALRNGLO":"c","DT_VERDEF":"c","DT_VERDEFNUM":"c","DT_VERNEED":"c","DT_VERNEEDNUM":"c","DT_VERSYM":"c","Data":"t","Data.GoString":"m","Data.String":"m","Dyn32":"t","Dyn64":"t","DynFlag":"t","DynFlag.GoString":"m","DynFlag.String":"m","DynFlag1":"t","DynFlag1.GoString":"m","DynFlag1.String":"m","DynTag":"t","DynTag.GoString":"m","DynTag.String":"m","DynamicVersion":"t","DynamicVersionDep":"t","DynamicVersionFlag":"t","DynamicVersionNeed":"t","EI_ABIVERSION":"c","EI_CLASS":"c","EI_DATA":"c","EI_NIDENT":"c","EI_OSABI":"c","EI_PAD":"c","EI_VERSION":"c","ELFCLASS32":"c","ELFCLASS64":"c","ELFCLASSNONE":"c","ELFDATA2LSB":"c","ELFDATA2MSB":"c","ELFDATANONE":"c","ELFMAG":"c","ELFOSABI_86OPEN":"c","ELFOSABI_AIX":"c","ELFOSABI_ARM":"c","ELFOSABI_AROS":"c","ELFOSABI_CLOUDABI":"c","ELFOSABI_FENIXOS":"c","ELFOSABI_FREEBSD":"c","ELFOSABI_HPUX":"c","ELFOSABI_HURD":"c","ELFOSABI_IRIX":"c","ELFOSABI_LINUX":"c","ELFOSABI_MODESTO":"c","ELFOSABI_NETBSD":"c","ELFOSABI_NONE":"c","ELFOSABI_NSK":"c","ELFOSABI_OPENBSD":"c","ELFOSABI_OPENVMS":"c","ELFOSABI_SOLARIS":"c","ELFOSABI_STANDALONE":"c","ELFOSABI_TRU64":"c","EM_386":"c","EM_486":"c","EM_56800EX":"c","EM_68HC05":"c","EM_68HC08":"c","EM_68HC11":"c","EM_68HC12":"c","EM_68HC16":"c","EM_68K":"c","EM_78KOR":"c","EM_8051":"c","EM_860":"c","EM_88K":"c","EM_960":"c","EM_AARCH64":"c","EM_ALPHA":"c","EM_ALPHA_STD":"c","EM_ALTERA_NIOS2":"c","EM_AMDGPU":"c","EM_ARC":"c","EM_ARCA":"c","EM_ARC_COMPACT":"c","EM_ARC_COMPACT2":"c","EM_ARM":"c","EM_AVR":"c","EM_AVR32":"c","EM_BA1":"c","EM_BA2":"c","EM_BLACKFIN":"c","EM_BPF":"c","EM_C166":"c","EM_CDP":"c","EM_CE":"c","EM_CLOUDSHIELD":"c","EM_COGE":"c","EM_COLDFIRE":"c","EM_COOL":"c","EM_COREA_1ST":"c","EM_COREA_2ND":"c","EM_CR":"c","EM_CR16":"c","EM_CRAYNV2":"c","EM_CRIS":"c","EM_CRX":"c","EM_CSR_KALIMBA":"c","EM_CUDA":"c","EM_CYPRESS_M8C":"c","EM_D10V":"c","EM_D30V":"c","EM_DSP24":"c","EM_DSPIC30F":"c","EM_DXP":"c","EM_ECOG1":"c","EM_ECOG16":"c","EM_ECOG1X":"c","EM_ECOG2":"c","EM_ETPU":"c","EM_EXCESS":"c","EM_F2MC16":"c","EM_FIREPATH":"c","EM_FR20":"c","EM_FR30":"c","EM_FT32":"c","EM_FX66":"c","EM_H8S":"c","EM_H8_300":"c","EM_H8_300H":"c","EM_H8_500":"c","EM_HUANY":"c","EM_IA_64":"c","EM_INTEL205":"c","EM_INTEL206":"c","EM_INTEL207":"c","EM_INTEL208":"c","EM_INTEL209":"c","EM_IP2K":"c","EM_JAVELIN":"c","EM_K10M":"c","EM_KM32":"c","EM_KMX16":"c","EM_KMX32":"c","EM_KMX8":"c","EM_KVARC":"c","EM_L10M":"c","EM_LANAI":"c","EM_LATTICEMICO32":"c","EM_LOONGARCH":"c","EM_M16C":"c","EM_M32":"c","EM_M32C":"c","EM_M32R":"c","EM_MANIK":"c","EM_MAX":"c","EM_MAXQ30":"c","EM_MCHP_PIC":"c","EM_MCST_ELBRUS":"c","EM_ME16":"c","EM_METAG":"c","EM_MICROBLAZE":"c","EM_MIPS":"c","EM_MIPS_RS3_LE":"c","EM_MIPS_RS4_BE":"c","EM_MIPS_X":"c","EM_MMA":"c","EM_MMDSP_PLUS":"c","EM_MMIX":"c","EM_MN10200":"c","EM_MN10300":"c","EM_MOXIE":"c","EM_MSP430":"c","EM_NCPU":"c","EM_NDR1":"c","EM_NDS32":"c","EM_NONE":"c","EM_NORC":"c","EM_NS32K":"c","EM_OPEN8":"c","EM_OPENRISC":"c","EM_PARISC":"c","EM_PCP":"c","EM_PDP10":"c","EM_PDP11":"c","EM_PDSP":"c","EM_PJ":"c","EM_PPC":"c","EM_PPC64":"c","EM_PRISM":"c","EM_QDSP6":"c","EM_R32C":"c","EM_RCE":"c","EM_RH32":"c","EM_RISCV":"c","EM_RL78":"c","EM_RS08":"c","EM_RX":"c","EM_S370":"c","EM_S390":"c","EM_SCORE7":"c","EM_SEP":"c","EM_SE_C17":"c","EM_SE_C33":"c","EM_SH":"c","EM_SHARC":"c","EM_SLE9X":"c","EM_SNP1K":"c","EM_SPARC":"c","EM_SPARC32PLUS":"c","EM_SPARCV9":"c","EM_ST100":"c","EM_ST19":"c","EM_ST200":"c","EM_ST7":"c","EM_ST9PLUS":"c","EM_STARCORE":"c","EM_STM8":"c","EM_STXP7X":"c","EM_SVX":"c","EM_TILE64":"c","EM_TILEGX":"c","EM_TILEPRO":"c","EM_TINYJ":"c","EM_TI_ARP32":"c","EM_TI_C2000":"c","EM_TI_C5500":"c","EM_TI_C6000":"c","EM_TI_PRU":"c","EM_TMM_GPP":"c","EM_TPC":"c","EM_TRICORE":"c","EM_TRIMEDIA":"c","EM_TSK3000":"c","EM_UNICORE":"c","EM_V800":"c","EM_V850":"c","EM_VAX":"c","EM_VIDEOCORE":"c","EM_VIDEOCORE3":"c","EM_VIDEOCORE5":"c","EM_VISIUM":"c","EM_VPP500":"c","EM_X86_64":"c","EM_XCORE":"c","EM_XGATE":"c","EM_XIMO16":"c","EM_XTENSA":"c","EM_Z80":"c","EM_ZSP":"c","ET_CORE":"c","ET_DYN":"c","ET_EXEC":"c","ET_HIOS":"c","ET_HIPROC":"c","ET_LOOS":"c","ET_LOPROC":"c","ET_NONE":"c","ET_REL":"c","EV_CURRENT":"c","EV_NONE":"c","ErrNoSymbols":"v","File":"t","File.Close":"m","File.DWARF":"m","File.DynString":"m","File.DynValue":"m","File.DynamicSymbols":"m","File.DynamicVersionNeeds":"m","File.DynamicVersions":"m","File.ImportedLibraries":"m","File.ImportedSymbols":"m","File.Section":"m","File.SectionByType":"m","File.Symbols":"m","FileHeader":"t","FormatError":"t","FormatError.Error":"m","Header32":"t","Header64":"t","ImportedSymbol":"t","Machine":"t","Machine.GoString":"m","Machine.String":"m","NT_FPREGSET":"c","NT_PRPSINFO":"c","NT_PRSTATUS":"c","NType":"t","NType.GoString":"m","NType.String":"m","NewFile":"f","OSABI":"t","OSABI.GoString":"m","OSABI.String":"m","Open":"f","PF_MASKOS":"c","PF_MASKPROC":"c","PF_R":"c","PF_W":"c","PF_X":"c","PT_AARCH64_ARCHEXT":"c","PT_AARCH64_UNWIND":"c","PT_ARM_ARCHEXT":"c","PT_ARM_EXIDX":"c","PT_DYNAMIC":"c","PT_GNU_EH_FRAME":"c","PT_GNU_MBIND_HI":"c","PT_GNU_MBIND_LO":"c","PT_GNU_PROPERTY":"c","PT_GNU_RELRO":"c","PT_GNU_STACK":"c","PT_HIOS":"c","PT_HIPROC":"c","PT_INTERP":"c","PT_LOAD":"c","PT_LOOS":"c","PT_LOPROC":"c","PT_MIPS_ABIFLAGS":"c","PT_MIPS_OPTIONS":"c","PT_MIPS_REGINFO":"c","PT_MIPS_RTPROC":"c","PT_NOTE":"c","PT_NULL":"c","PT_OPENBSD_BOOTDATA":"c","PT_OPENBSD_NOBTCFI":"c","PT_OPENBSD_RANDOMIZE":"c","PT_OPENBSD_WXNEEDED":"c","PT_PAX_FLAGS":"c","PT_PHDR":"c","PT_RISCV_ATTRIBUTES":"c","PT_S390_PGSTE":"c","PT_SHLIB":"c","PT_SUNWSTACK":"c","PT_SUNW_EH_FRAME":"c","PT_TLS":"c","Prog":"t","Prog.Open":"m","Prog32":"t","Prog64":"t","ProgFlag":"t","ProgFlag.GoString":"m","ProgFlag.String":"m","ProgHeader":"t","ProgType":"t","ProgType.GoString":"m","ProgType.String":"m","R_386":"t","R_386.GoString":"m","R_386.String":"m","R_386_16":"c","R_386_32":"c","R_386_32PLT":"c","R_386_8":"c","R_386_COPY":"c","R_386_GLOB_DAT":"c","R_386_GOT32":"c","R_386_GOT32X":"c","R_386_GOTOFF":"c","R_386_GOTPC":"c","R_386_IRELATIVE":"c","R_386_JMP_SLOT":"c","R_386_NONE":"c","R_386_PC16":"c","R_386_PC32":"c","R_386_PC8":"c","R_386_PLT32":"c","R_386_RELATIVE":"c","R_386_SIZE32":"c","R_386_TLS_DESC":"c","R_386_TLS_DESC_CALL":"c","R_386_TLS_DTPMOD32":"c","R_386_TLS_DTPOFF32":"c","R_386_TLS_GD":"c","R_386_TLS_GD_32":"c","R_386_TLS_GD_CALL":"c","R_386_TLS_GD_POP":"c","R_386_TLS_GD_PUSH":"c","R_386_TLS_GOTDESC":"c","R_386_TLS_GOTIE":"c","R_386_TLS_IE":"c","R_386_TLS_IE_32":"c","R_386_TLS_LDM":"c","R_386_TLS_LDM_32":"c","R_386_TLS_LDM_CALL":"c","R_386_TLS_LDM_POP":"c","R_386_TLS_LDM_PUSH":"c","R_386_TLS_LDO_32":"c","R_386_TLS_LE":"c","R_386_TLS_LE_32":"c","R_386_TLS_TPOFF":"c","R_386_TLS_TPOFF32":"c","R_390":"t","R_390.GoString":"m","R_390.String":"m","R_390_12":"c","R_390_16":"c","R_390_20":"c","R_390_32":"c","R_390_64":"c","R_390_8":"c","R_390_COPY":"c","R_390_GLOB_DAT":"c","R_390_GOT12":"c","R_390_GOT16":"c","R_390_GOT20":"c","R_390_GOT32":"c","R_390_GOT64":"c","R_390_GOTENT":"c","R_390_GOTOFF":"c","R_390_GOTOFF16":"c","R_390_GOTOFF64":"c","R_390_GOTPC":"c","R_390_GOTPCDBL":"c","R_390_GOTPLT12":"c","R_390_GOTPLT16":"c","R_390_GOTPLT20":"c","R_390_GOTPLT32":"c","R_390_GOTPLT64":"c","R_390_GOTPLTENT":"c","R_390_GOTPLTOFF16":"c","R_390_GOTPLTOFF32":"c","R_390_GOTPLTOFF64":"c","R_390_JMP_SLOT":"c","R_390_NONE":"c","R_390_PC16":"c","R_390_PC16DBL":"c","R_390_PC32":"c","R_390_PC32DBL":"c","R_390_PC64":"c","R_390_PLT16DBL":"c","R_390_PLT32":"c","R_390_PLT32DBL":"c","R_390_PLT64":"c","R_390_RELATIVE":"c","R_390_TLS_DTPMOD":"c","R_390_TLS_DTPOFF":"c","R_390_TLS_GD32":"c","R_390_TLS_GD64":"c","R_390_TLS_GDCALL":"c","R_390_TLS_GOTIE12":"c","R_390_TLS_GOTIE20":"c","R_390_TLS_GOTIE32":"c","R_390_TLS_GOTIE64":"c","R_390_TLS_IE32":"c","R_390_TLS_IE64":"c","R_390_TLS_IEENT":"c","R_390_TLS_LDCALL":"c","R_390_TLS_LDM32":"c","R_390_TLS_LDM64":"c","R_390_TLS_LDO32":"c","R_390_TLS_LDO64":"c","R_390_TLS_LE32":"c","R_390_TLS_LE64":"c","R_390_TLS_LOAD":"c","R_390_TLS_TPOFF":"c","R_AARCH64":"t","R_AARCH64.GoString":"m","R_AARCH64.String":"m","R_AARCH64_ABS16":"c","R_AARCH64_ABS32":"c","R_AARCH64_ABS64":"c","R_AARCH64_ADD_ABS_LO12_NC":"c","R_AARCH64_ADR_GOT_PAGE":"c","R_AARCH64_ADR_PREL_LO21":"c","R_AARCH64_ADR_PREL_PG_HI21":"c","R_AARCH64_ADR_PREL_PG_HI21_NC":"c","R_AARCH64_CALL26":"c","R_AARCH64_CONDBR19":"c","R_AARCH64_COPY":"c","R_AARCH64_GLOB_DAT":"c","R_AARCH64_GOT_LD_PREL19":"c","R_AARCH64_IRELATIVE":"c","R_AARCH64_JUMP26":"c","R_AARCH64_JUMP_SLOT":"c","R_AARCH64_LD64_GOTOFF_LO15":"c","R_AARCH64_LD64_GOTPAGE_LO15":"c","R_AARCH64_LD64_GOT_LO12_NC":"c","R_AARCH64_LDST128_ABS_LO12_NC":"c","R_AARCH64_LDST16_ABS_LO12_NC":"c","R_AARCH64_LDST32_ABS_LO12_NC":"c","R_AARCH64_LDST64_ABS_LO12_NC":"c","R_AARCH64_LDST8_ABS_LO12_NC":"c","R_AARCH64_LD_PREL_LO19":"c","R_AARCH64_MOVW_SABS_G0":"c","R_AARCH64_MOVW_SABS_G1":"c","R_AARCH64_MOVW_SABS_G2":"c","R_AARCH64_MOVW_UABS_G0":"c","R_AARCH64_MOVW_UABS_G0_NC":"c","R_AARCH64_MOVW_UABS_G1":"c","R_AARCH64_MOVW_UABS_G1_NC":"c","R_AARCH64_MOVW_UABS_G2":"c","R_AARCH64_MOVW_UABS_G2_NC":"c","R_AARCH64_MOVW_UABS_G3":"c","R_AARCH64_NONE":"c","R_AARCH64_NULL":"c","R_AARCH64_P32_ABS16":"c","R_AARCH64_P32_ABS32":"c","R_AARCH64_P32_ADD_ABS_LO12_NC":"c","R_AARCH64_P32_ADR_GOT_PAGE":"c","R_AARCH64_P32_ADR_PREL_LO21":"c","R_AARCH64_P32_ADR_PREL_PG_HI21":"c","R_AARCH64_P32_CALL26":"c","R_AARCH64_P32_CONDBR19":"c","R_AARCH64_P32_COPY":"c","R_AARCH64_P32_GLOB_DAT":"c","R_AARCH64_P32_GOT_LD_PREL19":"c","R_AARCH64_P32_IRELATIVE":"c","R_AARCH64_P32_JUMP26":"c","R_AARCH64_P32_JUMP_SLOT":"c","R_AARCH64_P32_LD32_GOT_LO12_NC":"c","R_AARCH64_P32_LDST128_ABS_LO12_NC":"c","R_AARCH64_P32_LDST16_ABS_LO12_NC":"c","R_AARCH64_P32_LDST32_ABS_LO12_NC":"c","R_AARCH64_P32_LDST64_ABS_LO12_NC":"c","R_AARCH64_P32_LDST8_ABS_LO12_NC":"c","R_AARCH64_P32_LD_PREL_LO19":"c","R_AARCH64_P32_MOVW_SABS_G0":"c","R_AARCH64_P32_MOVW_UABS_G0":"c","R_AARCH64_P32_MOVW_UABS_G0_NC":"c","R_AARCH64_P32_MOVW_UABS_G1":"c","R_AARCH64_P32_PREL16":"c","R_AARCH64_P32_PREL32":"c","R_AARCH64_P32_RELATIVE":"c","R_AARCH64_P32_TLSDESC":"c","R_AARCH64_P32_TLSDESC_ADD_LO12_NC":"c","R_AARCH64_P32_TLSDESC_ADR_PAGE21":"c","R_AARCH64_P32_TLSDESC_ADR_PREL21":"c","R_AARCH64_P32_TLSDESC_CALL":"c","R_AARCH64_P32_TLSDESC_LD32_LO12_NC":"c","R_AARCH64_P32_TLSDESC_LD_PREL19":"c","R_AARCH64_P32_TLSGD_ADD_LO12_NC":"c","R_AARCH64_P32_TLSGD_ADR_PAGE21":"c","R_AARCH64_P32_TLSIE_ADR_GOTTPREL_PAGE21":"c","R_AARCH64_P32_TLSIE_LD32_GOTTPREL_LO12_NC":"c","R_AARCH64_P32_TLSIE_LD_GOTTPREL_PREL19":"c","R_AARCH64_P32_TLSLE_ADD_TPREL_HI12":"c","R_AARCH64_P32_TLSLE_ADD_TPREL_LO12":"c","R_AARCH64_P32_TLSLE_ADD_TPREL_LO12_NC":"c","R_AARCH64_P32_TLSLE_MOVW_TPREL_G0":"c","R_AARCH64_P32_TLSLE_MOVW_TPREL_G0_NC":"c","R_AARCH64_P32_TLSLE_MOVW_TPREL_G1":"c","R_AARCH64_P32_TLS_DTPMOD":"c","R_AARCH64_P32_TLS_DTPREL":"c","R_AARCH64_P32_TLS_TPREL":"c","R_AARCH64_P32_TSTBR14":"c","R_AARCH64_PREL16":"c","R_AARCH64_PREL32":"c","R_AARCH64_PREL64":"c","R_AARCH64_RELATIVE":"c","R_AARCH64_TLSDESC":"c","R_AARCH64_TLSDESC_ADD":"c","R_AARCH64_TLSDESC_ADD_LO12_NC":"c","R_AARCH64_TLSDESC_ADR_PAGE21":"c","R_AARCH64_TLSDESC_ADR_PREL21":"c","R_AARCH64_TLSDESC_CALL":"c","R_AARCH64_TLSDESC_LD64_LO12_NC":"c","R_AARCH64_TLSDESC_LDR":"c","R_AARCH64_TLSDESC_LD_PREL19":"c","R_AARCH64_TLSDESC_OFF_G0_NC":"c","R_AARCH64_TLSDESC_OFF_G1":"c","R_AARCH64_TLSGD_ADD_LO12_NC":"c","R_AARCH64_TLSGD_ADR_PAGE21":"c","R_AARCH64_TLSGD_ADR_PREL21":"c","R_AARCH64_TLSGD_MOVW_G0_NC":"c","R_AARCH64_TLSGD_MOVW_G1":"c","R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21":"c","R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC":"c","R_AARCH64_TLSIE_LD_GOTTPREL_PREL19":"c","R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC":"c","R_AARCH64_TLSIE_MOVW_GOTTPREL_G1":"c","R_AARCH64_TLSLD_ADR_PAGE21":"c","R_AARCH64_TLSLD_ADR_PREL21":"c","R_AARCH64_TLSLD_LDST128_DTPREL_LO12":"c","R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC":"c","R_AARCH64_TLSLE_ADD_TPREL_HI12":"c","R_AARCH64_TLSLE_ADD_TPREL_LO12":"c","R_AARCH64_TLSLE_ADD_TPREL_LO12_NC":"c","R_AARCH64_TLSLE_LDST128_TPREL_LO12":"c","R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC":"c","R_AARCH64_TLSLE_MOVW_TPREL_G0":"c","R_AARCH64_TLSLE_MOVW_TPREL_G0_NC":"c","R_AARCH64_TLSLE_MOVW_TPREL_G1":"c","R_AARCH64_TLSLE_MOVW_TPREL_G1_NC":"c","R_AARCH64_TLSLE_MOVW_TPREL_G2":"c","R_AARCH64_TLS_DTPMOD64":"c","R_AARCH64_TLS_DTPREL64":"c","R_AARCH64_TLS_TPREL64":"c","R_AARCH64_TSTBR14":"c","R_ALPHA":"t","R_ALPHA.GoString":"m","R_ALPHA.String":"m","R_ALPHA_BRADDR":"c","R_ALPHA_COPY":"c","R_ALPHA_GLOB_DAT":"c","R_ALPHA_GPDISP":"c","R_ALPHA_GPREL32":"c","R_ALPHA_GPRELHIGH":"c","R_ALPHA_GPRELLOW":"c","R_ALPHA_GPVALUE":"c","R_ALPHA_HINT":"c","R_ALPHA_IMMED_BR_HI32":"c","R_ALPHA_IMMED_GP_16":"c","R_ALPHA_IMMED_GP_HI32":"c","R_ALPHA_IMMED_LO32":"c","R_ALPHA_IMMED_SCN_HI32":"c","R_ALPHA_JMP_SLOT":"c","R_ALPHA_LITERAL":"c","R_ALPHA_LITUSE":"c","R_ALPHA_NONE":"c","R_ALPHA_OP_PRSHIFT":"c","R_ALPHA_OP_PSUB":"c","R_ALPHA_OP_PUSH":"c","R_ALPHA_OP_STORE":"c","R_ALPHA_REFLONG":"c","R_ALPHA_REFQUAD":"c","R_ALPHA_RELATIVE":"c","R_ALPHA_SREL16":"c","R_ALPHA_SREL32":"c","R_ALPHA_SREL64":"c","R_ARM":"t","R_ARM.GoString":"m","R_ARM.String":"m","R_ARM_ABS12":"c","R_ARM_ABS16":"c","R_ARM_ABS32":"c","R_ARM_ABS32_NOI":"c","R_ARM_ABS8":"c","R_ARM_ALU_PCREL_15_8":"c","R_ARM_ALU_PCREL_23_15":"c","R_ARM_ALU_PCREL_7_0":"c","R_ARM_ALU_PC_G0":"c","R_ARM_ALU_PC_G0_NC":"c","R_ARM_ALU_PC_G1":"c","R_ARM_ALU_PC_G1_NC":"c","R_ARM_ALU_PC_G2":"c","R_ARM_ALU_SBREL_19_12_NC":"c","R_ARM_ALU_SBREL_27_20_CK":"c","R_ARM_ALU_SB_G0":"c","R_ARM_ALU_SB_G0_NC":"c","R_ARM_ALU_SB_G1":"c","R_ARM_ALU_SB_G1_NC":"c","R_ARM_ALU_SB_G2":"c","R_ARM_AMP_VCALL9":"c","R_ARM_BASE_ABS":"c","R_ARM_CALL":"c","R_ARM_COPY":"c","R_ARM_GLOB_DAT":"c","R_ARM_GNU_VTENTRY":"c","R_ARM_GNU_VTINHERIT":"c","R_ARM_GOT32":"c","R_ARM_GOTOFF":"c","R_ARM_GOTOFF12":"c","R_ARM_GOTPC":"c","R_ARM_GOTRELAX":"c","R_ARM_GOT_ABS":"c","R_ARM_GOT_BREL12":"c","R_ARM_GOT_PREL":"c","R_ARM_IRELATIVE":"c","R_ARM_JUMP24":"c","R_ARM_JUMP_SLOT":"c","R_ARM_LDC_PC_G0":"c","R_ARM_LDC_PC_G1":"c","R_ARM_LDC_PC_G2":"c","R_ARM_LDC_SB_G0":"c","R_ARM_LDC_SB_G1":"c","R_ARM_LDC_SB_G2":"c","R_ARM_LDRS_PC_G0":"c","R_ARM_LDRS_PC_G1":"c","R_ARM_LDRS_PC_G2":"c","R_ARM_LDRS_SB_G0":"c","R_ARM_LDRS_SB_G1":"c","R_ARM_LDRS_SB_G2":"c","R_ARM_LDR_PC_G1":"c","R_ARM_LDR_PC_G2":"c","R_ARM_LDR_SBREL_11_10_NC":"c","R_ARM_LDR_SB_G0":"c","R_ARM_LDR_SB_G1":"c","R_ARM_LDR_SB_G2":"c","R_ARM_ME_TOO":"c","R_ARM_MOVT_ABS":"c","R_ARM_MOVT_BREL":"c","R_ARM_MOVT_PREL":"c","R_ARM_MOVW_ABS_NC":"c","R_ARM_MOVW_BREL":"c","R_ARM_MOVW_BREL_NC":"c","R_ARM_MOVW_PREL_NC":"c","R_ARM_NONE":"c","R_ARM_PC13":"c","R_ARM_PC24":"c","R_ARM_PLT32":"c","R_ARM_PLT32_ABS":"c","R_ARM_PREL31":"c","R_ARM_PRIVATE_0":"c","R_ARM_PRIVATE_1":"c","R_ARM_PRIVATE_10":"c","R_ARM_PRIVATE_11":"c","R_ARM_PRIVATE_12":"c","R_ARM_PRIVATE_13":"c","R_ARM_PRIVATE_14":"c","R_ARM_PRIVATE_15":"c","R_ARM_PRIVATE_2":"c","R_ARM_PRIVATE_3":"c","R_ARM_PRIVATE_4":"c","R_ARM_PRIVATE_5":"c","R_ARM_PRIVATE_6":"c","R_ARM_PRIVATE_7":"c","R_ARM_PRIVATE_8":"c","R_ARM_PRIVATE_9":"c","R_ARM_RABS32":"c","R_ARM_RBASE":"c","R_ARM_REL32":"c","R_ARM_REL32_NOI":"c","R_ARM_RELATIVE":"c","R_ARM_RPC24":"c","R_ARM_RREL32":"c","R_ARM_RSBREL32":"c","R_ARM_RXPC25":"c","R_ARM_SBREL31":"c","R_ARM_SBREL32":"c","R_ARM_SWI24":"c","R_ARM_TARGET1":"c","R_ARM_TARGET2":"c","R_ARM_THM_ABS5":"c","R_ARM_THM_ALU_ABS_G0_NC":"c","R_ARM_THM_ALU_ABS_G1_NC":"c","R_ARM_THM_ALU_ABS_G2_NC":"c","R_ARM_THM_ALU_ABS_G3":"c","R_ARM_THM_ALU_PREL_11_0":"c","R_ARM_THM_GOT_BREL12":"c","R_ARM_THM_JUMP11":"c","R_ARM_THM_JUMP19":"c","R_ARM_THM_JUMP24":"c","R_ARM_THM_JUMP6":"c","R_ARM_THM_JUMP8":"c","R_ARM_THM_MOVT_ABS":"c","R_ARM_THM_MOVT_BREL":"c","R_ARM_THM_MOVT_PREL":"c","R_ARM_THM_MOVW_ABS_NC":"c","R_ARM_THM_MOVW_BREL":"c","R_ARM_THM_MOVW_BREL_NC":"c","R_ARM_THM_MOVW_PREL_NC":"c","R_ARM_THM_PC12":"c","R_ARM_THM_PC22":"c","R_ARM_THM_PC8":"c","R_ARM_THM_RPC22":"c","R_ARM_THM_SWI8":"c","R_ARM_THM_TLS_CALL":"c","R_ARM_THM_TLS_DESCSEQ16":"c","R_ARM_THM_TLS_DESCSEQ32":"c","R_ARM_THM_XPC22":"c","R_ARM_TLS_CALL":"c","R_ARM_TLS_DESCSEQ":"c","R_ARM_TLS_DTPMOD32":"c","R_ARM_TLS_DTPOFF32":"c","R_ARM_TLS_GD32":"c","R_ARM_TLS_GOTDESC":"c","R_ARM_TLS_IE12GP":"c","R_ARM_TLS_IE32":"c","R_ARM_TLS_LDM32":"c","R_ARM_TLS_LDO12":"c","R_ARM_TLS_LDO32":"c","R_ARM_TLS_LE12":"c","R_ARM_TLS_LE32":"c","R_ARM_TLS_TPOFF32":"c","R_ARM_V4BX":"c","R_ARM_XPC25":"c","R_INFO":"f","R_INFO32":"f","R_LARCH":"t","R_LARCH.GoString":"m","R_LARCH.String":"m","R_LARCH_32":"c","R_LARCH_32_PCREL":"c","R_LARCH_64":"c","R_LARCH_64_PCREL":"c","R_LARCH_ABS64_HI12":"c","R_LARCH_ABS64_LO20":"c","R_LARCH_ABS_HI20":"c","R_LARCH_ABS_LO12":"c","R_LARCH_ADD16":"c","R_LARCH_ADD24":"c","R_LARCH_ADD32":"c","R_LARCH_ADD6":"c","R_LARCH_ADD64":"c","R_LARCH_ADD8":"c","R_LARCH_ADD_ULEB128":"c","R_LARCH_ALIGN":"c","R_LARCH_B16":"c","R_LARCH_B21":"c","R_LARCH_B26":"c","R_LARCH_CALL36":"c","R_LARCH_CFA":"c","R_LARCH_COPY":"c","R_LARCH_DELETE":"c","R_LARCH_GNU_VTENTRY":"c","R_LARCH_GNU_VTINHERIT":"c","R_LARCH_GOT64_HI12":"c","R_LARCH_GOT64_LO20":"c","R_LARCH_GOT64_PC_HI12":"c","R_LARCH_GOT64_PC_LO20":"c","R_LARCH_GOT_HI20":"c","R_LARCH_GOT_LO12":"c","R_LARCH_GOT_PC_HI20":"c","R_LARCH_GOT_PC_LO12":"c","R_LARCH_IRELATIVE":"c","R_LARCH_JUMP_SLOT":"c","R_LARCH_MARK_LA":"c","R_LARCH_MARK_PCREL":"c","R_LARCH_NONE":"c","R_LARCH_PCALA64_HI12":"c","R_LARCH_PCALA64_LO20":"c","R_LARCH_PCALA_HI20":"c","R_LARCH_PCALA_LO12":"c","R_LARCH_PCREL20_S2":"c","R_LARCH_RELATIVE":"c","R_LARCH_RELAX":"c","R_LARCH_SOP_ADD":"c","R_LARCH_SOP_AND":"c","R_LARCH_SOP_ASSERT":"c","R_LARCH_SOP_IF_ELSE":"c","R_LARCH_SOP_NOT":"c","R_LARCH_SOP_POP_32_S_0_10_10_16_S2":"c","R_LARCH_SOP_POP_32_S_0_5_10_16_S2":"c","R_LARCH_SOP_POP_32_S_10_12":"c","R_LARCH_SOP_POP_32_S_10_16":"c","R_LARCH_SOP_POP_32_S_10_16_S2":"c","R_LARCH_SOP_POP_32_S_10_5":"c","R_LARCH_SOP_POP_32_S_5_20":"c","R_LARCH_SOP_POP_32_U":"c","R_LARCH_SOP_POP_32_U_10_12":"c","R_LARCH_SOP_PUSH_ABSOLUTE":"c","R_LARCH_SOP_PUSH_DUP":"c","R_LARCH_SOP_PUSH_GPREL":"c","R_LARCH_SOP_PUSH_PCREL":"c","R_LARCH_SOP_PUSH_PLT_PCREL":"c","R_LARCH_SOP_PUSH_TLS_GD":"c","R_LARCH_SOP_PUSH_TLS_GOT":"c","R_LARCH_SOP_PUSH_TLS_TPREL":"c","R_LARCH_SOP_SL":"c","R_LARCH_SOP_SR":"c","R_LARCH_SOP_SUB":"c","R_LARCH_SUB16":"c","R_LARCH_SUB24":"c","R_LARCH_SUB32":"c","R_LARCH_SUB6":"c","R_LARCH_SUB64":"c","R_LARCH_SUB8":"c","R_LARCH_SUB_ULEB128":"c","R_LARCH_TLS_DESC32":"c","R_LARCH_TLS_DESC64":"c","R_LARCH_TLS_DESC64_HI12":"c","R_LARCH_TLS_DESC64_LO20":"c","R_LARCH_TLS_DESC64_PC_HI12":"c","R_LARCH_TLS_DESC64_PC_LO20":"c","R_LARCH_TLS_DESC_CALL":"c","R_LARCH_TLS_DESC_HI20":"c","R_LARCH_TLS_DESC_LD":"c","R_LARCH_TLS_DESC_LO12":"c","R_LARCH_TLS_DESC_PCREL20_S2":"c","R_LARCH_TLS_DESC_PC_HI20":"c","R_LARCH_TLS_DESC_PC_LO12":"c","R_LARCH_TLS_DTPMOD32":"c","R_LARCH_TLS_DTPMOD64":"c","R_LARCH_TLS_DTPREL32":"c","R_LARCH_TLS_DTPREL64":"c","R_LARCH_TLS_GD_HI20":"c","R_LARCH_TLS_GD_PCREL20_S2":"c","R_LARCH_TLS_GD_PC_HI20":"c","R_LARCH_TLS_IE64_HI12":"c","R_LARCH_TLS_IE64_LO20":"c","R_LARCH_TLS_IE64_PC_HI12":"c","R_LARCH_TLS_IE64_PC_LO20":"c","R_LARCH_TLS_IE_HI20":"c","R_LARCH_TLS_IE_LO12":"c","R_LARCH_TLS_IE_PC_HI20":"c","R_LARCH_TLS_IE_PC_LO12":"c","R_LARCH_TLS_LD_HI20":"c","R_LARCH_TLS_LD_PCREL20_S2":"c","R_LARCH_TLS_LD_PC_HI20":"c","R_LARCH_TLS_LE64_HI12":"c","R_LARCH_TLS_LE64_LO20":"c","R_LARCH_TLS_LE_ADD_R":"c","R_LARCH_TLS_LE_HI20":"c","R_LARCH_TLS_LE_HI20_R":"c","R_LARCH_TLS_LE_LO12":"c","R_LARCH_TLS_LE_LO12_R":"c","R_LARCH_TLS_TPREL32":"c","R_LARCH_TLS_TPREL64":"c","R_MIPS":"t","R_MIPS.GoString":"m","R_MIPS.String":"m","R_MIPS_16":"c","R_MIPS_26":"c","R_MIPS_32":"c","R_MIPS_64":"c","R_MIPS_ADD_IMMEDIATE":"c","R_MIPS_CALL16":"c","R_MIPS_CALL_HI16":"c","R_MIPS_CALL_LO16":"c","R_MIPS_DELETE":"c","R_MIPS_GOT16":"c","R_MIPS_GOT_DISP":"c","R_MIPS_GOT_HI16":"c","R_MIPS_GOT_LO16":"c","R_MIPS_GOT_OFST":"c","R_MIPS_GOT_PAGE":"c","R_MIPS_GPREL16":"c","R_MIPS_GPREL32":"c","R_MIPS_HI16":"c","R_MIPS_HIGHER":"c","R_MIPS_HIGHEST":"c","R_MIPS_INSERT_A":"c","R_MIPS_INSERT_B":"c","R_MIPS_JALR":"c","R_MIPS_LITERAL":"c","R_MIPS_LO16":"c","R_MIPS_NONE":"c","R_MIPS_PC16":"c","R_MIPS_PC32":"c","R_MIPS_PJUMP":"c","R_MIPS_REL16":"c","R_MIPS_REL32":"c","R_MIPS_RELGOT":"c","R_MIPS_SCN_DISP":"c","R_MIPS_SHIFT5":"c","R_MIPS_SHIFT6":"c","R_MIPS_SUB":"c","R_MIPS_TLS_DTPMOD32":"c","R_MIPS_TLS_DTPMOD64":"c","R_MIPS_TLS_DTPREL32":"c","R_MIPS_TLS_DTPREL64":"c","R_MIPS_TLS_DTPREL_HI16":"c","R_MIPS_TLS_DTPREL_LO16":"c","R_MIPS_TLS_GD":"c","R_MIPS_TLS_GOTTPREL":"c","R_MIPS_TLS_LDM":"c","R_MIPS_TLS_TPREL32":"c","R_MIPS_TLS_TPREL64":"c","R_MIPS_TLS_TPREL_HI16":"c","R_MIPS_TLS_TPREL_LO16":"c","R_PPC":"t","R_PPC.GoString":"m","R_PPC.String":"m","R_PPC64":"t","R_PPC64.GoString":"m","R_PPC64.String":"m","R_PPC64_ADDR14":"c","R_PPC64_ADDR14_BRNTAKEN":"c","R_PPC64_ADDR14_BRTAKEN":"c","R_PPC64_ADDR16":"c","R_PPC64_ADDR16_DS":"c","R_PPC64_ADDR16_HA":"c","R_PPC64_ADDR16_HI":"c","R_PPC64_ADDR16_HIGH":"c","R_PPC64_ADDR16_HIGHA":"c","R_PPC64_ADDR16_HIGHER":"c","R_PPC64_ADDR16_HIGHER34":"c","R_PPC64_ADDR16_HIGHERA":"c","R_PPC64_ADDR16_HIGHERA34":"c","R_PPC64_ADDR16_HIGHEST":"c","R_PPC64_ADDR16_HIGHEST34":"c","R_PPC64_ADDR16_HIGHESTA":"c","R_PPC64_ADDR16_HIGHESTA34":"c","R_PPC64_ADDR16_LO":"c","R_PPC64_ADDR16_LO_DS":"c","R_PPC64_ADDR24":"c","R_PPC64_ADDR32":"c","R_PPC64_ADDR64":"c","R_PPC64_ADDR64_LOCAL":"c","R_PPC64_COPY":"c","R_PPC64_D28":"c","R_PPC64_D34":"c","R_PPC64_D34_HA30":"c","R_PPC64_D34_HI30":"c","R_PPC64_D34_LO":"c","R_PPC64_DTPMOD64":"c","R_PPC64_DTPREL16":"c","R_PPC64_DTPREL16_DS":"c","R_PPC64_DTPREL16_HA":"c","R_PPC64_DTPREL16_HI":"c","R_PPC64_DTPREL16_HIGH":"c","R_PPC64_DTPREL16_HIGHA":"c","R_PPC64_DTPREL16_HIGHER":"c","R_PPC64_DTPREL16_HIGHERA":"c","R_PPC64_DTPREL16_HIGHEST":"c","R_PPC64_DTPREL16_HIGHESTA":"c","R_PPC64_DTPREL16_LO":"c","R_PPC64_DTPREL16_LO_DS":"c","R_PPC64_DTPREL34":"c","R_PPC64_DTPREL64":"c","R_PPC64_ENTRY":"c","R_PPC64_GLOB_DAT":"c","R_PPC64_GNU_VTENTRY":"c","R_PPC64_GNU_VTINHERIT":"c","R_PPC64_GOT16":"c","R_PPC64_GOT16_DS":"c","R_PPC64_GOT16_HA":"c","R_PPC64_GOT16_HI":"c","R_PPC64_GOT16_LO":"c","R_PPC64_GOT16_LO_DS":"c","R_PPC64_GOT_DTPREL16_DS":"c","R_PPC64_GOT_DTPREL16_HA":"c","R_PPC64_GOT_DTPREL16_HI":"c","R_PPC64_GOT_DTPREL16_LO_DS":"c","R_PPC64_GOT_DTPREL_PCREL34":"c","R_PPC64_GOT_PCREL34":"c","R_PPC64_GOT_TLSGD16":"c","R_PPC64_GOT_TLSGD16_HA":"c","R_PPC64_GOT_TLSGD16_HI":"c","R_PPC64_GOT_TLSGD16_LO":"c","R_PPC64_GOT_TLSGD_PCREL34":"c","R_PPC64_GOT_TLSLD16":"c","R_PPC64_GOT_TLSLD16_HA":"c","R_PPC64_GOT_TLSLD16_HI":"c","R_PPC64_GOT_TLSLD16_LO":"c","R_PPC64_GOT_TLSLD_PCREL34":"c","R_PPC64_GOT_TPREL16_DS":"c","R_PPC64_GOT_TPREL16_HA":"c","R_PPC64_GOT_TPREL16_HI":"c","R_PPC64_GOT_TPREL16_LO_DS":"c","R_PPC64_GOT_TPREL_PCREL34":"c","R_PPC64_IRELATIVE":"c","R_PPC64_JMP_IREL":"c","R_PPC64_JMP_SLOT":"c","R_PPC64_NONE":"c","R_PPC64_PCREL28":"c","R_PPC64_PCREL34":"c","R_PPC64_PCREL_OPT":"c","R_PPC64_PLT16_HA":"c","R_PPC64_PLT16_HI":"c","R_PPC64_PLT16_LO":"c","R_PPC64_PLT16_LO_DS":"c","R_PPC64_PLT32":"c","R_PPC64_PLT64":"c","R_PPC64_PLTCALL":"c","R_PPC64_PLTCALL_NOTOC":"c","R_PPC64_PLTGOT16":"c","R_PPC64_PLTGOT16_DS":"c","R_PPC64_PLTGOT16_HA":"c","R_PPC64_PLTGOT16_HI":"c","R_PPC64_PLTGOT16_LO":"c","R_PPC64_PLTGOT_LO_DS":"c","R_PPC64_PLTREL32":"c","R_PPC64_PLTREL64":"c","R_PPC64_PLTSEQ":"c","R_PPC64_PLTSEQ_NOTOC":"c","R_PPC64_PLT_PCREL34":"c","R_PPC64_PLT_PCREL34_NOTOC":"c","R_PPC64_REL14":"c","R_PPC64_REL14_BRNTAKEN":"c","R_PPC64_REL14_BRTAKEN":"c","R_PPC64_REL16":"c","R_PPC64_REL16DX_HA":"c","R_PPC64_REL16_HA":"c","R_PPC64_REL16_HI":"c","R_PPC64_REL16_HIGH":"c","R_PPC64_REL16_HIGHA":"c","R_PPC64_REL16_HIGHER":"c","R_PPC64_REL16_HIGHER34":"c","R_PPC64_REL16_HIGHERA":"c","R_PPC64_REL16_HIGHERA34":"c","R_PPC64_REL16_HIGHEST":"c","R_PPC64_REL16_HIGHEST34":"c","R_PPC64_REL16_HIGHESTA":"c","R_PPC64_REL16_HIGHESTA34":"c","R_PPC64_REL16_LO":"c","R_PPC64_REL24":"c","R_PPC64_REL24_NOTOC":"c","R_PPC64_REL24_P9NOTOC":"c","R_PPC64_REL30":"c","R_PPC64_REL32":"c","R_PPC64_REL64":"c","R_PPC64_RELATIVE":"c","R_PPC64_SECTOFF":"c","R_PPC64_SECTOFF_DS":"c","R_PPC64_SECTOFF_HA":"c","R_PPC64_SECTOFF_HI":"c","R_PPC64_SECTOFF_LO":"c","R_PPC64_SECTOFF_LO_DS":"c","R_PPC64_TLS":"c","R_PPC64_TLSGD":"c","R_PPC64_TLSLD":"c","R_PPC64_TOC":"c","R_PPC64_TOC16":"c","R_PPC64_TOC16_DS":"c","R_PPC64_TOC16_HA":"c","R_PPC64_TOC16_HI":"c","R_PPC64_TOC16_LO":"c","R_PPC64_TOC16_LO_DS":"c","R_PPC64_TOCSAVE":"c","R_PPC64_TPREL16":"c","R_PPC64_TPREL16_DS":"c","R_PPC64_TPREL16_HA":"c","R_PPC64_TPREL16_HI":"c","R_PPC64_TPREL16_HIGH":"c","R_PPC64_TPREL16_HIGHA":"c","R_PPC64_TPREL16_HIGHER":"c","R_PPC64_TPREL16_HIGHERA":"c","R_PPC64_TPREL16_HIGHEST":"c","R_PPC64_TPREL16_HIGHESTA":"c","R_PPC64_TPREL16_LO":"c","R_PPC64_TPREL16_LO_DS":"c","R_PPC64_TPREL34":"c","R_PPC64_TPREL64":"c","R_PPC64_UADDR16":"c","R_PPC64_UADDR32":"c","R_PPC64_UADDR64":"c","R_PPC_ADDR14":"c","R_PPC_ADDR14_BRNTAKEN":"c","R_PPC_ADDR14_BRTAKEN":"c","R_PPC_ADDR16":"c","R_PPC_ADDR16_HA":"c","R_PPC_ADDR16_HI":"c","R_PPC_ADDR16_LO":"c","R_PPC_ADDR24":"c","R_PPC_ADDR32":"c","R_PPC_COPY":"c","R_PPC_DTPMOD32":"c","R_PPC_DTPREL16":"c","R_PPC_DTPREL16_HA":"c","R_PPC_DTPREL16_HI":"c","R_PPC_DTPREL16_LO":"c","R_PPC_DTPREL32":"c","R_PPC_EMB_BIT_FLD":"c","R_PPC_EMB_MRKREF":"c","R_PPC_EMB_NADDR16":"c","R_PPC_EMB_NADDR16_HA":"c","R_PPC_EMB_NADDR16_HI":"c","R_PPC_EMB_NADDR16_LO":"c","R_PPC_EMB_NADDR32":"c","R_PPC_EMB_RELSDA":"c","R_PPC_EMB_RELSEC16":"c","R_PPC_EMB_RELST_HA":"c","R_PPC_EMB_RELST_HI":"c","R_PPC_EMB_RELST_LO":"c","R_PPC_EMB_SDA21":"c","R_PPC_EMB_SDA2I16":"c","R_PPC_EMB_SDA2REL":"c","R_PPC_EMB_SDAI16":"c","R_PPC_GLOB_DAT":"c","R_PPC_GOT16":"c","R_PPC_GOT16_HA":"c","R_PPC_GOT16_HI":"c","R_PPC_GOT16_LO":"c","R_PPC_GOT_TLSGD16":"c","R_PPC_GOT_TLSGD16_HA":"c","R_PPC_GOT_TLSGD16_HI":"c","R_PPC_GOT_TLSGD16_LO":"c","R_PPC_GOT_TLSLD16":"c","R_PPC_GOT_TLSLD16_HA":"c","R_PPC_GOT_TLSLD16_HI":"c","R_PPC_GOT_TLSLD16_LO":"c","R_PPC_GOT_TPREL16":"c","R_PPC_GOT_TPREL16_HA":"c","R_PPC_GOT_TPREL16_HI":"c","R_PPC_GOT_TPREL16_LO":"c","R_PPC_JMP_SLOT":"c","R_PPC_LOCAL24PC":"c","R_PPC_NONE":"c","R_PPC_PLT16_HA":"c","R_PPC_PLT16_HI":"c","R_PPC_PLT16_LO":"c","R_PPC_PLT32":"c","R_PPC_PLTREL24":"c","R_PPC_PLTREL32":"c","R_PPC_REL14":"c","R_PPC_REL14_BRNTAKEN":"c","R_PPC_REL14_BRTAKEN":"c","R_PPC_REL24":"c","R_PPC_REL32":"c","R_PPC_RELATIVE":"c","R_PPC_SDAREL16":"c","R_PPC_SECTOFF":"c","R_PPC_SECTOFF_HA":"c","R_PPC_SECTOFF_HI":"c","R_PPC_SECTOFF_LO":"c","R_PPC_TLS":"c","R_PPC_TPREL16":"c","R_PPC_TPREL16_HA":"c","R_PPC_TPREL16_HI":"c","R_PPC_TPREL16_LO":"c","R_PPC_TPREL32":"c","R_PPC_UADDR16":"c","R_PPC_UADDR32":"c","R_RISCV":"t","R_RISCV.GoString":"m","R_RISCV.String":"m","R_RISCV_32":"c","R_RISCV_32_PCREL":"c","R_RISCV_64":"c","R_RISCV_ADD16":"c","R_RISCV_ADD32":"c","R_RISCV_ADD64":"c","R_RISCV_ADD8":"c","R_RISCV_ALIGN":"c","R_RISCV_BRANCH":"c","R_RISCV_CALL":"c","R_RISCV_CALL_PLT":"c","R_RISCV_COPY":"c","R_RISCV_GNU_VTENTRY":"c","R_RISCV_GNU_VTINHERIT":"c","R_RISCV_GOT_HI20":"c","R_RISCV_GPREL_I":"c","R_RISCV_GPREL_S":"c","R_RISCV_HI20":"c","R_RISCV_JAL":"c","R_RISCV_JUMP_SLOT":"c","R_RISCV_LO12_I":"c","R_RISCV_LO12_S":"c","R_RISCV_NONE":"c","R_RISCV_PCREL_HI20":"c","R_RISCV_PCREL_LO12_I":"c","R_RISCV_PCREL_LO12_S":"c","R_RISCV_RELATIVE":"c","R_RISCV_RELAX":"c","R_RISCV_RVC_BRANCH":"c","R_RISCV_RVC_JUMP":"c","R_RISCV_RVC_LUI":"c","R_RISCV_SET16":"c","R_RISCV_SET32":"c","R_RISCV_SET6":"c","R_RISCV_SET8":"c","R_RISCV_SUB16":"c","R_RISCV_SUB32":"c","R_RISCV_SUB6":"c","R_RISCV_SUB64":"c","R_RISCV_SUB8":"c","R_RISCV_TLS_DTPMOD32":"c","R_RISCV_TLS_DTPMOD64":"c","R_RISCV_TLS_DTPREL32":"c","R_RISCV_TLS_DTPREL64":"c","R_RISCV_TLS_GD_HI20":"c","R_RISCV_TLS_GOT_HI20":"c","R_RISCV_TLS_TPREL32":"c","R_RISCV_TLS_TPREL64":"c","R_RISCV_TPREL_ADD":"c","R_RISCV_TPREL_HI20":"c","R_RISCV_TPREL_I":"c","R_RISCV_TPREL_LO12_I":"c","R_RISCV_TPREL_LO12_S":"c","R_RISCV_TPREL_S":"c","R_SPARC":"t","R_SPARC.GoString":"m","R_SPARC.String":"m","R_SPARC_10":"c","R_SPARC_11":"c","R_SPARC_13":"c","R_SPARC_16":"c","R_SPARC_22":"c","R_SPARC_32":"c","R_SPARC_5":"c","R_SPARC_6":"c","R_SPARC_64":"c","R_SPARC_7":"c","R_SPARC_8":"c","R_SPARC_COPY":"c","R_SPARC_DISP16":"c","R_SPARC_DISP32":"c","R_SPARC_DISP64":"c","R_SPARC_DISP8":"c","R_SPARC_GLOB_DAT":"c","R_SPARC_GLOB_JMP":"c","R_SPARC_GOT10":"c","R_SPARC_GOT13":"c","R_SPARC_GOT22":"c","R_SPARC_H44":"c","R_SPARC_HH22":"c","R_SPARC_HI22":"c","R_SPARC_HIPLT22":"c","R_SPARC_HIX22":"c","R_SPARC_HM10":"c","R_SPARC_JMP_SLOT":"c","R_SPARC_L44":"c","R_SPARC_LM22":"c","R_SPARC_LO10":"c","R_SPARC_LOPLT10":"c","R_SPARC_LOX10":"c","R_SPARC_M44":"c","R_SPARC_NONE":"c","R_SPARC_OLO10":"c","R_SPARC_PC10":"c","R_SPARC_PC22":"c","R_SPARC_PCPLT10":"c","R_SPARC_PCPLT22":"c","R_SPARC_PCPLT32":"c","R_SPARC_PC_HH22":"c","R_SPARC_PC_HM10":"c","R_SPARC_PC_LM22":"c","R_SPARC_PLT32":"c","R_SPARC_PLT64":"c","R_SPARC_REGISTER":"c","R_SPARC_RELATIVE":"c","R_SPARC_UA16":"c","R_SPARC_UA32":"c","R_SPARC_UA64":"c","R_SPARC_WDISP16":"c","R_SPARC_WDISP19":"c","R_SPARC_WDISP22":"c","R_SPARC_WDISP30":"c","R_SPARC_WPLT30":"c","R_SYM32":"f","R_SYM64":"f","R_TYPE32":"f","R_TYPE64":"f","R_X86_64":"t","R_X86_64.GoString":"m","R_X86_64.String":"m","R_X86_64_16":"c","R_X86_64_32":"c","R_X86_64_32S":"c","R_X86_64_64":"c","R_X86_64_8":"c","R_X86_64_COPY":"c","R_X86_64_DTPMOD64":"c","R_X86_64_DTPOFF32":"c","R_X86_64_DTPOFF64":"c","R_X86_64_GLOB_DAT":"c","R_X86_64_GOT32":"c","R_X86_64_GOT64":"c","R_X86_64_GOTOFF64":"c","R_X86_64_GOTPC32":"c","R_X86_64_GOTPC32_TLSDESC":"c","R_X86_64_GOTPC64":"c","R_X86_64_GOTPCREL":"c","R_X86_64_GOTPCREL64":"c","R_X86_64_GOTPCRELX":"c","R_X86_64_GOTPLT64":"c","R_X86_64_GOTTPOFF":"c","R_X86_64_IRELATIVE":"c","R_X86_64_JMP_SLOT":"c","R_X86_64_NONE":"c","R_X86_64_PC16":"c","R_X86_64_PC32":"c","R_X86_64_PC32_BND":"c","R_X86_64_PC64":"c","R_X86_64_PC8":"c","R_X86_64_PLT32":"c","R_X86_64_PLT32_BND":"c","R_X86_64_PLTOFF64":"c","R_X86_64_RELATIVE":"c","R_X86_64_RELATIVE64":"c","R_X86_64_REX_GOTPCRELX":"c","R_X86_64_SIZE32":"c","R_X86_64_SIZE64":"c","R_X86_64_TLSDESC":"c","R_X86_64_TLSDESC_CALL":"c","R_X86_64_TLSGD":"c","R_X86_64_TLSLD":"c","R_X86_64_TPOFF32":"c","R_X86_64_TPOFF64":"c","Rel32":"t","Rel64":"t","Rela32":"t","Rela64":"t","SHF_ALLOC":"c","SHF_COMPRESSED":"c","SHF_EXECINSTR":"c","SHF_GROUP":"c","SHF_INFO_LINK":"c","SHF_LINK_ORDER":"c","SHF_MASKOS":"c","SHF_MASKPROC":"c","SHF_MERGE":"c","SHF_OS_NONCONFORMING":"c","SHF_STRINGS":"c","SHF_TLS":"c","SHF_WRITE":"c","SHN_ABS":"c","SHN_COMMON":"c","SHN_HIOS":"c","SHN_HIPROC":"c","SHN_HIRESERVE":"c","SHN_LOOS":"c","SHN_LOPROC":"c","SHN_LORESERVE":"c","SHN_UNDEF":"c","SHN_XINDEX":"c","SHT_DYNAMIC":"c","SHT_DYNSYM":"c","SHT_FINI_ARRAY":"c","SHT_GNU_ATTRIBUTES":"c","SHT_GNU_HASH":"c","SHT_GNU_LIBLIST":"c","SHT_GNU_VERDEF":"c","SHT_GNU_VERNEED":"c","SHT_GNU_VERSYM":"c","SHT_GROUP":"c","SHT_HASH":"c","SHT_HIOS":"c","SHT_HIPROC":"c","SHT_HIUSER":"c","SHT_INIT_ARRAY":"c","SHT_LOOS":"c","SHT_LOPROC":"c","SHT_LOUSER":"c","SHT_MIPS_ABIFLAGS":"c","SHT_NOBITS":"c","SHT_NOTE":"c","SHT_NULL":"c","SHT_PREINIT_ARRAY":"c","SHT_PROGBITS":"c","SHT_REL":"c","SHT_RELA":"c","SHT_RISCV_ATTRIBUTES":"c","SHT_SHLIB":"c","SHT_STRTAB":"c","SHT_SYMTAB":"c","SHT_SYMTAB_SHNDX":"c","STB_GLOBAL":"c","STB_HIOS":"c","STB_HIPROC":"c","STB_LOCAL":"c","STB_LOOS":"c","STB_LOPROC":"c","STB_WEAK":"c","STT_COMMON":"c","STT_FILE":"c","STT_FUNC":"c","STT_GNU_IFUNC":"c","STT_HIOS":"c","STT_HIPROC":"c","STT_LOOS":"c","STT_LOPROC":"c","STT_NOTYPE":"c","STT_OBJECT":"c","STT_RELC":"c","STT_SECTION":"c","STT_SRELC":"c","STT_TLS":"c","STV_DEFAULT":"c","STV_HIDDEN":"c","STV_INTERNAL":"c","STV_PROTECTED":"c","ST_BIND":"f","ST_INFO":"f","ST_TYPE":"f","ST_VISIBILITY":"f","Section":"t","Section.Data":"m","Section.Open":"m","Section32":"t","Section64":"t","SectionFlag":"t","SectionFlag.GoString":"m","SectionFlag.String":"m","SectionHeader":"t","SectionIndex":"t","SectionIndex.GoString":"m","SectionIndex.String":"m","SectionType":"t","SectionType.GoString":"m","SectionType.String":"m","Sym32":"t","Sym32Size":"c","Sym64":"t","Sym64Size":"c","SymBind":"t","SymBind.GoString":"m","SymBind.String":"m","SymType":"t","SymType.GoString":"m","SymType.String":"m","SymVis":"t","SymVis.GoString":"m","SymVis.String":"m","Symbol":"t","Type":"t","Type.GoString":"m","Type.String":"m","VER_FLG_BASE":"c","VER_FLG_INFO":"c","VER_FLG_WEAK":"c","Version":"t","Version.GoString":"m","Version.String":"m","VersionIndex":"t","VersionIndex.Index":"m","VersionIndex.IsHidden":"m"}},"debug/gosym":{"path":"debug/gosym","name":"gosym","symbols":{"DecodingError":"t","DecodingError.Error":"m","Func":"t","LineTable":"t","LineTable.LineToPC":"m","LineTable.PCToLine":"m","NewLineTable":"f","NewTable":"f","Obj":"t","Sym":"t","Sym.BaseName":"m","Sym.PackageName":"m","Sym.ReceiverName":"m","Sym.Static":"m","Table":"t","Table.LineToPC":"m","Table.LookupFunc":"m","Table.LookupSym":"m","Table.PCToFunc":"m","Table.PCToLine":"m","Table.SymByAddr":"m","UnknownFileError":"t","UnknownFileError.Error":"m","UnknownLineError":"t","UnknownLineError.Error":"m"}},"debug/macho":{"path":"debug/macho","name":"macho","symbols":{"ARM64_RELOC_ADDEND":"c","ARM64_RELOC_BRANCH26":"c","ARM64_RELOC_GOT_LOAD_PAGE21":"c","ARM64_RELOC_GOT_LOAD_PAGEOFF12":"c","ARM64_RELOC_PAGE21":"c","ARM64_RELOC_PAGEOFF12":"c","ARM64_RELOC_POINTER_TO_GOT":"c","ARM64_RELOC_SUBTRACTOR":"c","ARM64_RELOC_TLVP_LOAD_PAGE21":"c","ARM64_RELOC_TLVP_LOAD_PAGEOFF12":"c","ARM64_RELOC_UNSIGNED":"c","ARM_RELOC_BR24":"c","ARM_RELOC_HALF":"c","ARM_RELOC_HALF_SECTDIFF":"c","ARM_RELOC_LOCAL_SECTDIFF":"c","ARM_RELOC_PAIR":"c","ARM_RELOC_PB_LA_PTR":"c","ARM_RELOC_SECTDIFF":"c","ARM_RELOC_VANILLA":"c","ARM_THUMB_32BIT_BRANCH":"c","ARM_THUMB_RELOC_BR22":"c","Cpu":"t","Cpu.GoString":"m","Cpu.String":"m","Cpu386":"c","CpuAmd64":"c","CpuArm":"c","CpuArm64":"c","CpuPpc":"c","CpuPpc64":"c","Dylib":"t","DylibCmd":"t","Dysymtab":"t","DysymtabCmd":"t","ErrNotFat":"v","FatArch":"t","FatArchHeader":"t","FatFile":"t","FatFile.Close":"m","File":"t","File.Close":"m","File.DWARF":"m","File.ImportedLibraries":"m","File.ImportedSymbols":"m","File.Section":"m","File.Segment":"m","FileHeader":"t","FlagAllModsBound":"c","FlagAllowStackExecution":"c","FlagAppExtensionSafe":"c","FlagBindAtLoad":"c","FlagBindsToWeak":"c","FlagCanonical":"c","FlagDeadStrippableDylib":"c","FlagDyldLink":"c","FlagForceFlat":"c","FlagHasTLVDescriptors":"c","FlagIncrLink":"c","FlagLazyInit":"c","FlagNoFixPrebinding":"c","FlagNoHeapExecution":"c","FlagNoMultiDefs":"c","FlagNoReexportedDylibs":"c","FlagNoUndefs":"c","FlagPIE":"c","FlagPrebindable":"c","FlagPrebound":"c","FlagRootSafe":"c","FlagSetuidSafe":"c","FlagSplitSegs":"c","FlagSubsectionsViaSymbols":"c","FlagTwoLevel":"c","FlagWeakDefines":"c","FormatError":"t","FormatError.Error":"m","GENERIC_RELOC_LOCAL_SECTDIFF":"c","GENERIC_RELOC_PAIR":"c","GENERIC_RELOC_PB_LA_PTR":"c","GENERIC_RELOC_SECTDIFF":"c","GENERIC_RELOC_TLV":"c","GENERIC_RELOC_VANILLA":"c","Load":"t","LoadBytes":"t","LoadBytes.Raw":"m","LoadCmd":"t","LoadCmd.GoString":"m","LoadCmd.String":"m","LoadCmdDylib":"c","LoadCmdDylinker":"c","LoadCmdDysymtab":"c","LoadCmdRpath":"c","LoadCmdSegment":"c","LoadCmdSegment64":"c","LoadCmdSymtab":"c","LoadCmdThread":"c","LoadCmdUnixThread":"c","Magic32":"c","Magic64":"c","MagicFat":"c","NewFatFile":"f","NewFile":"f","Nlist32":"t","Nlist64":"t","Open":"f","OpenFat":"f","Regs386":"t","RegsAMD64":"t","Reloc":"t","RelocTypeARM":"t","RelocTypeARM.GoString":"m","RelocTypeARM.String":"m","RelocTypeARM64":"t","RelocTypeARM64.GoString":"m","RelocTypeARM64.String":"m","RelocTypeGeneric":"t","RelocTypeGeneric.GoString":"m","RelocTypeGeneric.String":"m","RelocTypeX86_64":"t","RelocTypeX86_64.GoString":"m","RelocTypeX86_64.String":"m","Rpath":"t","RpathCmd":"t","Section":"t","Section.Data":"m","Section.Open":"m","Section32":"t","Section64":"t","SectionHeader":"t","Segment":"t","Segment.Data":"m","Segment.Open":"m","Segment32":"t","Segment64":"t","SegmentHeader":"t","Symbol":"t","Symtab":"t","SymtabCmd":"t","Thread":"t","Type":"t","Type.GoString":"m","Type.String":"m","TypeBundle":"c","TypeDylib":"c","TypeExec":"c","TypeObj":"c","X86_64_RELOC_BRANCH":"c","X86_64_RELOC_GOT":"c","X86_64_RELOC_GOT_LOAD":"c","X86_64_RELOC_SIGNED":"c","X86_64_RELOC_SIGNED_1":"c","X86_64_RELOC_SIGNED_2":"c","X86_64_RELOC_SIGNED_4":"c","X86_64_RELOC_SUBTRACTOR":"c","X86_64_RELOC_TLV":"c","X86_64_RELOC_UNSIGNED":"c"}},"debug/pe":{"path":"debug/pe","name":"pe","symbols":{"COFFSymbol":"t","COFFSymbol.FullName":"m","COFFSymbolAuxFormat5":"t","COFFSymbolSize":"c","DataDirectory":"t","File":"t","File.COFFSymbolReadSectionDefAux":"m","File.Close":"m","File.DWARF":"m","File.ImportedLibraries":"m","File.ImportedSymbols":"m","File.Section":"m","FileHeader":"t","FormatError":"t","FormatError.Error":"m","IMAGE_COMDAT_SELECT_ANY":"c","IMAGE_COMDAT_SELECT_ASSOCIATIVE":"c","IMAGE_COMDAT_SELECT_EXACT_MATCH":"c","IMAGE_COMDAT_SELECT_LARGEST":"c","IMAGE_COMDAT_SELECT_NODUPLICATES":"c","IMAGE_COMDAT_SELECT_SAME_SIZE":"c","IMAGE_DIRECTORY_ENTRY_ARCHITECTURE":"c","IMAGE_DIRECTORY_ENTRY_BASERELOC":"c","IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT":"c","IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR":"c","IMAGE_DIRECTORY_ENTRY_DEBUG":"c","IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT":"c","IMAGE_DIRECTORY_ENTRY_EXCEPTION":"c","IMAGE_DIRECTORY_ENTRY_EXPORT":"c","IMAGE_DIRECTORY_ENTRY_GLOBALPTR":"c","IMAGE_DIRECTORY_ENTRY_IAT":"c","IMAGE_DIRECTORY_ENTRY_IMPORT":"c","IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG":"c","IMAGE_DIRECTORY_ENTRY_RESOURCE":"c","IMAGE_DIRECTORY_ENTRY_SECURITY":"c","IMAGE_DIRECTORY_ENTRY_TLS":"c","IMAGE_DLLCHARACTERISTICS_APPCONTAINER":"c","IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE":"c","IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY":"c","IMAGE_DLLCHARACTERISTICS_GUARD_CF":"c","IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA":"c","IMAGE_DLLCHARACTERISTICS_NO_BIND":"c","IMAGE_DLLCHARACTERISTICS_NO_ISOLATION":"c","IMAGE_DLLCHARACTERISTICS_NO_SEH":"c","IMAGE_DLLCHARACTERISTICS_NX_COMPAT":"c","IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE":"c","IMAGE_DLLCHARACTERISTICS_WDM_DRIVER":"c","IMAGE_FILE_32BIT_MACHINE":"c","IMAGE_FILE_AGGRESIVE_WS_TRIM":"c","IMAGE_FILE_BYTES_REVERSED_HI":"c","IMAGE_FILE_BYTES_REVERSED_LO":"c","IMAGE_FILE_DEBUG_STRIPPED":"c","IMAGE_FILE_DLL":"c","IMAGE_FILE_EXECUTABLE_IMAGE":"c","IMAGE_FILE_LARGE_ADDRESS_AWARE":"c","IMAGE_FILE_LINE_NUMS_STRIPPED":"c","IMAGE_FILE_LOCAL_SYMS_STRIPPED":"c","IMAGE_FILE_MACHINE_AM33":"c","IMAGE_FILE_MACHINE_AMD64":"c","IMAGE_FILE_MACHINE_ARM":"c","IMAGE_FILE_MACHINE_ARM64":"c","IMAGE_FILE_MACHINE_ARMNT":"c","IMAGE_FILE_MACHINE_EBC":"c","IMAGE_FILE_MACHINE_I386":"c","IMAGE_FILE_MACHINE_IA64":"c","IMAGE_FILE_MACHINE_LOONGARCH32":"c","IMAGE_FILE_MACHINE_LOONGARCH64":"c","IMAGE_FILE_MACHINE_M32R":"c","IMAGE_FILE_MACHINE_MIPS16":"c","IMAGE_FILE_MACHINE_MIPSFPU":"c","IMAGE_FILE_MACHINE_MIPSFPU16":"c","IMAGE_FILE_MACHINE_POWERPC":"c","IMAGE_FILE_MACHINE_POWERPCFP":"c","IMAGE_FILE_MACHINE_R4000":"c","IMAGE_FILE_MACHINE_RISCV128":"c","IMAGE_FILE_MACHINE_RISCV32":"c","IMAGE_FILE_MACHINE_RISCV64":"c","IMAGE_FILE_MACHINE_SH3":"c","IMAGE_FILE_MACHINE_SH3DSP":"c","IMAGE_FILE_MACHINE_SH4":"c","IMAGE_FILE_MACHINE_SH5":"c","IMAGE_FILE_MACHINE_THUMB":"c","IMAGE_FILE_MACHINE_UNKNOWN":"c","IMAGE_FILE_MACHINE_WCEMIPSV2":"c","IMAGE_FILE_NET_RUN_FROM_SWAP":"c","IMAGE_FILE_RELOCS_STRIPPED":"c","IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP":"c","IMAGE_FILE_SYSTEM":"c","IMAGE_FILE_UP_SYSTEM_ONLY":"c","IMAGE_SCN_CNT_CODE":"c","IMAGE_SCN_CNT_INITIALIZED_DATA":"c","IMAGE_SCN_CNT_UNINITIALIZED_DATA":"c","IMAGE_SCN_LNK_COMDAT":"c","IMAGE_SCN_MEM_DISCARDABLE":"c","IMAGE_SCN_MEM_EXECUTE":"c","IMAGE_SCN_MEM_READ":"c","IMAGE_SCN_MEM_WRITE":"c","IMAGE_SUBSYSTEM_EFI_APPLICATION":"c","IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER":"c","IMAGE_SUBSYSTEM_EFI_ROM":"c","IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER":"c","IMAGE_SUBSYSTEM_NATIVE":"c","IMAGE_SUBSYSTEM_NATIVE_WINDOWS":"c","IMAGE_SUBSYSTEM_OS2_CUI":"c","IMAGE_SUBSYSTEM_POSIX_CUI":"c","IMAGE_SUBSYSTEM_UNKNOWN":"c","IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION":"c","IMAGE_SUBSYSTEM_WINDOWS_CE_GUI":"c","IMAGE_SUBSYSTEM_WINDOWS_CUI":"c","IMAGE_SUBSYSTEM_WINDOWS_GUI":"c","IMAGE_SUBSYSTEM_XBOX":"c","ImportDirectory":"t","NewFile":"f","Open":"f","OptionalHeader32":"t","OptionalHeader64":"t","Reloc":"t","Section":"t","Section.Data":"m","Section.Open":"m","SectionHeader":"t","SectionHeader32":"t","StringTable":"t","StringTable.String":"m","Symbol":"t"}},"debug/plan9obj":{"path":"debug/plan9obj","name":"plan9obj","symbols":{"ErrNoSymbols":"v","File":"t","File.Close":"m","File.Section":"m","File.Symbols":"m","FileHeader":"t","Magic386":"c","Magic64":"c","MagicAMD64":"c","MagicARM":"c","NewFile":"f","Open":"f","Section":"t","Section.Data":"m","Section.Open":"m","SectionHeader":"t","Sym":"t"}},"embed":{"path":"embed","name":"embed","symbols":{"FS":"t","FS.Open":"m","FS.ReadDir":"m","FS.ReadFile":"m"}},"encoding":{"path":"encoding","name":"encoding","symbols":{"BinaryAppender":"t","BinaryMarshaler":"t","BinaryUnmarshaler":"t","TextAppender":"t","TextMarshaler":"t","TextUnmarshaler":"t"}},"encoding/ascii85":{"path":"encoding/ascii85","name":"ascii85","symbols":{"CorruptInputError":"t","CorruptInputError.Error":"m","Decode":"f","Encode":"f","MaxEncodedLen":"f","NewDecoder":"f","NewEncoder":"f"}},"encoding/asn1":{"path":"encoding/asn1","name":"asn1","symbols":{"BitString":"t","BitString.At":"m","BitString.RightAlign":"m","ClassApplication":"c","ClassContextSpecific":"c","ClassPrivate":"c","ClassUniversal":"c","Enumerated":"t","Flag":"t","Marshal":"f","MarshalWithParams":"f","NullBytes":"v","NullRawValue":"v","ObjectIdentifier":"t","ObjectIdentifier.Equal":"m","ObjectIdentifier.String":"m","RawContent":"t","RawValue":"t","StructuralError":"t","StructuralError.Error":"m","SyntaxError":"t","SyntaxError.Error":"m","TagBMPString":"c","TagBitString":"c","TagBoolean":"c","TagEnum":"c","TagGeneralString":"c","TagGeneralizedTime":"c","TagIA5String":"c","TagInteger":"c","TagNull":"c","TagNumericString":"c","TagOID":"c","TagOctetString":"c","TagPrintableString":"c","TagSequence":"c","TagSet":"c","TagT61String":"c","TagUTCTime":"c","TagUTF8String":"c","Unmarshal":"f","UnmarshalWithParams":"f"}},"encoding/base32":{"path":"encoding/base32","name":"base32","symbols":{"CorruptInputError":"t","CorruptInputError.Error":"m","Encoding":"t","Encoding.AppendDecode":"m","Encoding.AppendEncode":"m","Encoding.Decode":"m","Encoding.DecodeString":"m","Encoding.DecodedLen":"m","Encoding.Encode":"m","Encoding.EncodeToString":"m","Encoding.EncodedLen":"m","Encoding.WithPadding":"m","HexEncoding":"v","NewDecoder":"f","NewEncoder":"f","NewEncoding":"f","NoPadding":"c","StdEncoding":"v","StdPadding":"c"}},"encoding/base64":{"path":"encoding/base64","name":"base64","symbols":{"CorruptInputError":"t","CorruptInputError.Error":"m","Encoding":"t","Encoding.AppendDecode":"m","Encoding.AppendEncode":"m","Encoding.Decode":"m","Encoding.DecodeString":"m","Encoding.DecodedLen":"m","Encoding.Encode":"m","Encoding.EncodeToString":"m","Encoding.EncodedLen":"m","Encoding.Strict":"m","Encoding.WithPadding":"m","NewDecoder":"f","NewEncoder":"f","NewEncoding":"f","NoPadding":"c","RawStdEncoding":"v","RawURLEncoding":"v","StdEncoding":"v","StdPadding":"c","URLEncoding":"v"}},"encoding/binary":{"path":"encoding/binary","name":"binary","symbols":{"Append":"f","AppendByteOrder":"t","AppendUvarint":"f","AppendVarint":"f","BigEndian":"v","ByteOrder":"t","Decode":"f","Encode":"f","LittleEndian":"v","MaxVarintLen16":"c","MaxVarintLen32":"c","MaxVarintLen64":"c","NativeEndian":"v","PutUvarint":"f","PutVarint":"f","Read":"f","ReadUvarint":"f","ReadVarint":"f","Size":"f","Uvarint":"f","Varint":"f","Write":"f"}},"encoding/csv":{"path":"encoding/csv","name":"csv","symbols":{"ErrBareQuote":"v","ErrFieldCount":"v","ErrQuote":"v","ErrTrailingComma":"v","NewReader":"f","NewWriter":"f","ParseError":"t","ParseError.Error":"m","ParseError.Unwrap":"m","Reader":"t","Reader.FieldPos":"m","Reader.InputOffset":"m","Reader.Read":"m","Reader.ReadAll":"m","Writer":"t","Writer.Error":"m","Writer.Flush":"m","Writer.Write":"m","Writer.WriteAll":"m"}},"encoding/gob":{"path":"encoding/gob","name":"gob","symbols":{"CommonType":"t","Decoder":"t","Decoder.Decode":"m","Decoder.DecodeValue":"m","Encoder":"t","Encoder.Encode":"m","Encoder.EncodeValue":"m","GobDecoder":"t","GobEncoder":"t","NewDecoder":"f","NewEncoder":"f","Register":"f","RegisterName":"f"}},"encoding/hex":{"path":"encoding/hex","name":"hex","symbols":{"AppendDecode":"f","AppendEncode":"f","Decode":"f","DecodeString":"f","DecodedLen":"f","Dump":"f","Dumper":"f","Encode":"f","EncodeToString":"f","EncodedLen":"f","ErrLength":"v","InvalidByteError":"t","InvalidByteError.Error":"m","NewDecoder":"f","NewEncoder":"f"}},"encoding/json":{"path":"encoding/json","name":"json","symbols":{"Compact":"f","Decoder":"t","Decoder.Buffered":"m","Decoder.Decode":"m","Decoder.DisallowUnknownFields":"m","Decoder.InputOffset":"m","Decoder.More":"m","Decoder.Token":"m","Decoder.UseNumber":"m","Delim":"t","Delim.String":"m","Encoder":"t","Encoder.Encode":"m","Encoder.SetEscapeHTML":"m","Encoder.SetIndent":"m","HTMLEscape":"f","Indent":"f","InvalidUTF8Error":"t","InvalidUTF8Error.Error":"m","InvalidUnmarshalError":"t","InvalidUnmarshalError.Error":"m","Marshal":"f","MarshalIndent":"f","Marshaler":"t","MarshalerError":"t","MarshalerError.Error":"m","MarshalerError.Unwrap":"m","NewDecoder":"f","NewEncoder":"f","Number":"t","Number.Float64":"m","Number.Int64":"m","Number.String":"m","RawMessage":"t","RawMessage.MarshalJSON":"m","RawMessage.UnmarshalJSON":"m","SyntaxError":"t","SyntaxError.Error":"m","Token":"t","Unmarshal":"f","UnmarshalFieldError":"t","UnmarshalFieldError.Error":"m","UnmarshalTypeError":"t","UnmarshalTypeError.Error":"m","Unmarshaler":"t","UnsupportedTypeError":"t","UnsupportedTypeError.Error":"m","UnsupportedValueError":"t","UnsupportedValueError.Error":"m","Valid":"f"}},"encoding/pem":{"path":"encoding/pem","name":"pem","symbols":{"Block":"t","Decode":"f","Encode":"f","EncodeToMemory":"f"}},"encoding/xml":{"path":"encoding/xml","name":"xml","symbols":{"Attr":"t","CharData":"t","CharData.Copy":"m","Comment":"t","Comment.Copy":"m","CopyToken":"f","Decoder":"t","Decoder.Decode":"m","Decoder.DecodeElement":"m","Decoder.InputOffset":"m","Decoder.InputPos":"m","Decoder.RawToken":"m","Decoder.Skip":"m","Decoder.Token":"m","Directive":"t","Directive.Copy":"m","Encoder":"t","Encoder.Close":"m","Encoder.Encode":"m","Encoder.EncodeElement":"m","Encoder.EncodeToken":"m","Encoder.Flush":"m","Encoder.Indent":"m","EndElement":"t","Escape":"f","EscapeText":"f","HTMLAutoClose":"v","HTMLEntity":"v","Header":"c","Marshal":"f","MarshalIndent":"f","Marshaler":"t","MarshalerAttr":"t","Name":"t","NewDecoder":"f","NewEncoder":"f","NewTokenDecoder":"f","ProcInst":"t","ProcInst.Copy":"m","StartElement":"t","StartElement.Copy":"m","StartElement.End":"m","SyntaxError":"t","SyntaxError.Error":"m","TagPathError":"t","TagPathError.Error":"m","Token":"t","TokenReader":"t","Unmarshal":"f","UnmarshalError":"t","UnmarshalError.Error":"m","Unmarshaler":"t","UnmarshalerAttr":"t","UnsupportedTypeError":"t","UnsupportedTypeError.Error":"m"}},"errors":{"path":"errors","name":"errors","symbols":{"As":"f","AsType":"f","ErrUnsupported":"v","Is":"f","Join":"f","New":"f","Unwrap":"f"}},"expvar":{"path":"expvar","name":"expvar","symbols":{"Do":"f","Float":"t","Float.Add":"m","Float.Set":"m","Float.String":"m","Float.Value":"m","Func":"t","Func.String":"m","Func.Value":"m","Get":"f","Handler":"f","Int":"t","Int.Add":"m","Int.Set":"m","Int.String":"m","Int.Value":"m","KeyValue":"t","Map":"t","Map.Add":"m","Map.AddFloat":"m","Map.Delete":"m","Map.Do":"m","Map.Get":"m","Map.Init":"m","Map.Set":"m","Map.String":"m","NewFloat":"f","NewInt":"f","NewMap":"f","NewString":"f","Publish":"f","String":"t","String.Set":"m","String.String":"m","String.Value":"m","Var":"t"}},"flag":{"path":"flag","name":"flag","symbols":{"Arg":"f","Args":"f","Bool":"f","BoolFunc":"f","BoolVar":"f","CommandLine":"v","ContinueOnError":"c","Duration":"f","DurationVar":"f","ErrHelp":"v","ErrorHandling":"t","ExitOnError":"c","Flag":"t","FlagSet":"t","FlagSet.Arg":"m","FlagSet.Args":"m","FlagSet.Bool":"m","FlagSet.BoolFunc":"m","FlagSet.BoolVar":"m","FlagSet.Duration":"m","FlagSet.DurationVar":"m","FlagSet.ErrorHandling":"m","FlagSet.Float64":"m","FlagSet.Float64Var":"m","FlagSet.Func":"m","FlagSet.Init":"m","FlagSet.Int":"m","FlagSet.Int64":"m","FlagSet.Int64Var":"m","FlagSet.IntVar":"m","FlagSet.Lookup":"m","FlagSet.NArg":"m","FlagSet.NFlag":"m","FlagSet.Name":"m","FlagSet.Output":"m","FlagSet.Parse":"m","FlagSet.Parsed":"m","FlagSet.PrintDefaults":"m","FlagSet.Set":"m","FlagSet.SetOutput":"m","FlagSet.String":"m","FlagSet.StringVar":"m","FlagSet.TextVar":"m","FlagSet.Uint":"m","FlagSet.Uint64":"m","FlagSet.Uint64Var":"m","FlagSet.UintVar":"m","FlagSet.Var":"m","FlagSet.Visit":"m","FlagSet.VisitAll":"m","Float64":"f","Float64Var":"f","Func":"f","Getter":"t","Int":"f","Int64":"f","Int64Var":"f","IntVar":"f","Lookup":"f","NArg":"f","NFlag":"f","NewFlagSet":"f","PanicOnError":"c","Parse":"f","Parsed":"f","PrintDefaults":"f","Set":"f","String":"f","StringVar":"f","TextVar":"f","Uint":"f","Uint64":"f","Uint64Var":"f","UintVar":"f","UnquoteUsage":"f","Usage":"v","Value":"t","Var":"f","Visit":"f","VisitAll":"f"}},"fmt":{"path":"fmt","name":"fmt","symbols":{"Append":"f","Appendf":"f","Appendln":"f","Errorf":"f","FormatString":"f","Formatter":"t","Fprint":"f","Fprintf":"f","Fprintln":"f","Fscan":"f","Fscanf":"f","Fscanln":"f","GoStringer":"t","Print":"f","Printf":"f","Println":"f","Scan":"f","ScanState":"t","Scanf":"f","Scanln":"f","Scanner":"t","Sprint":"f","Sprintf":"f","Sprintln":"f","Sscan":"f","Sscanf":"f","Sscanln":"f","State":"t","Stringer":"t"}},"go/ast":{"path":"go/ast","name":"ast","symbols":{"ArrayType":"t","ArrayType.End":"m","ArrayType.Pos":"m","AssignStmt":"t","AssignStmt.End":"m","AssignStmt.Pos":"m","Bad":"c","BadDecl":"t","BadDecl.End":"m","BadDecl.Pos":"m","BadExpr":"t","BadExpr.End":"m","BadExpr.Pos":"m","BadStmt":"t","BadStmt.End":"m","BadStmt.Pos":"m","BasicLit":"t","BasicLit.End":"m","BasicLit.Pos":"m","BinaryExpr":"t","BinaryExpr.End":"m","BinaryExpr.Pos":"m","BlockStmt":"t","BlockStmt.End":"m","BlockStmt.Pos":"m","BranchStmt":"t","BranchStmt.End":"m","BranchStmt.Pos":"m","CallExpr":"t","CallExpr.End":"m","CallExpr.Pos":"m","CaseClause":"t","CaseClause.End":"m","CaseClause.Pos":"m","ChanDir":"t","ChanType":"t","ChanType.End":"m","ChanType.Pos":"m","CommClause":"t","CommClause.End":"m","CommClause.Pos":"m","Comment":"t","Comment.End":"m","Comment.Pos":"m","CommentGroup":"t","CommentGroup.End":"m","CommentGroup.Pos":"m","CommentGroup.Text":"m","CommentMap":"t","CommentMap.Comments":"m","CommentMap.Filter":"m","CommentMap.String":"m","CommentMap.Update":"m","CompositeLit":"t","CompositeLit.End":"m","CompositeLit.Pos":"m","Con":"c","Decl":"t","DeclStmt":"t","DeclStmt.End":"m","DeclStmt.Pos":"m","DeferStmt":"t","DeferStmt.End":"m","DeferStmt.Pos":"m","Directive":"t","Directive.End":"m","Directive.ParseArgs":"m","Directive.Pos":"m","DirectiveArg":"t","Ellipsis":"t","Ellipsis.End":"m","Ellipsis.Pos":"m","EmptyStmt":"t","EmptyStmt.End":"m","EmptyStmt.Pos":"m","Expr":"t","ExprStmt":"t","ExprStmt.End":"m","ExprStmt.Pos":"m","Field":"t","Field.End":"m","Field.Pos":"m","FieldFilter":"t","FieldList":"t","FieldList.End":"m","FieldList.NumFields":"m","FieldList.Pos":"m","File":"t","File.End":"m","File.Pos":"m","FileExports":"f","Filter":"t","FilterDecl":"f","FilterFile":"f","FilterFuncDuplicates":"c","FilterImportDuplicates":"c","FilterPackage":"f","FilterUnassociatedComments":"c","ForStmt":"t","ForStmt.End":"m","ForStmt.Pos":"m","Fprint":"f","Fun":"c","FuncDecl":"t","FuncDecl.End":"m","FuncDecl.Pos":"m","FuncLit":"t","FuncLit.End":"m","FuncLit.Pos":"m","FuncType":"t","FuncType.End":"m","FuncType.Pos":"m","GenDecl":"t","GenDecl.End":"m","GenDecl.Pos":"m","GoStmt":"t","GoStmt.End":"m","GoStmt.Pos":"m","Ident":"t","Ident.End":"m","Ident.IsExported":"m","Ident.Pos":"m","Ident.String":"m","IfStmt":"t","IfStmt.End":"m","IfStmt.Pos":"m","ImportSpec":"t","ImportSpec.End":"m","ImportSpec.Pos":"m","Importer":"t","IncDecStmt":"t","IncDecStmt.End":"m","IncDecStmt.Pos":"m","IndexExpr":"t","IndexExpr.End":"m","IndexExpr.Pos":"m","IndexListExpr":"t","IndexListExpr.End":"m","IndexListExpr.Pos":"m","Inspect":"f","InterfaceType":"t","InterfaceType.End":"m","InterfaceType.Pos":"m","IsExported":"f","IsGenerated":"f","KeyValueExpr":"t","KeyValueExpr.End":"m","KeyValueExpr.Pos":"m","LabeledStmt":"t","LabeledStmt.End":"m","LabeledStmt.Pos":"m","Lbl":"c","MapType":"t","MapType.End":"m","MapType.Pos":"m","MergeMode":"t","MergePackageFiles":"f","NewCommentMap":"f","NewIdent":"f","NewObj":"f","NewPackage":"f","NewScope":"f","Node":"t","NotNilFilter":"f","ObjKind":"t","ObjKind.String":"m","Object":"t","Object.Pos":"m","Package":"t","Package.End":"m","Package.Pos":"m","PackageExports":"f","ParenExpr":"t","ParenExpr.End":"m","ParenExpr.Pos":"m","ParseDirective":"f","Pkg":"c","Preorder":"f","PreorderStack":"f","Print":"f","RECV":"c","RangeStmt":"t","RangeStmt.End":"m","RangeStmt.Pos":"m","ReturnStmt":"t","ReturnStmt.End":"m","ReturnStmt.Pos":"m","SEND":"c","Scope":"t","Scope.Insert":"m","Scope.Lookup":"m","Scope.String":"m","SelectStmt":"t","SelectStmt.End":"m","SelectStmt.Pos":"m","SelectorExpr":"t","SelectorExpr.End":"m","SelectorExpr.Pos":"m","SendStmt":"t","SendStmt.End":"m","SendStmt.Pos":"m","SliceExpr":"t","SliceExpr.End":"m","SliceExpr.Pos":"m","SortImports":"f","Spec":"t","StarExpr":"t","StarExpr.End":"m","StarExpr.Pos":"m","Stmt":"t","StructType":"t","StructType.End":"m","StructType.Pos":"m","SwitchStmt":"t","SwitchStmt.End":"m","SwitchStmt.Pos":"m","Typ":"c","TypeAssertExpr":"t","TypeAssertExpr.End":"m","TypeAssertExpr.Pos":"m","TypeSpec":"t","TypeSpec.End":"m","TypeSpec.Pos":"m","TypeSwitchStmt":"t","TypeSwitchStmt.End":"m","TypeSwitchStmt.Pos":"m","UnaryExpr":"t","UnaryExpr.End":"m","UnaryExpr.Pos":"m","Unparen":"f","ValueSpec":"t","ValueSpec.End":"m","ValueSpec.Pos":"m","Var":"c","Visitor":"t","Walk":"f"}},"go/build":{"path":"go/build","name":"build","symbols":{"AllowBinary":"c","ArchChar":"f","Context":"t","Context.Import":"m","Context.ImportDir":"m","Context.MatchFile":"m","Context.SrcDirs":"m","Default":"v","Directive":"t","FindOnly":"c","IgnoreVendor":"c","Import":"f","ImportComment":"c","ImportDir":"f","ImportMode":"t","IsLocalImport":"f","MultiplePackageError":"t","MultiplePackageError.Error":"m","NoGoError":"t","NoGoError.Error":"m","Package":"t","Package.IsCommand":"m","ToolDir":"v"}},"go/build/constraint":{"path":"go/build/constraint","name":"constraint","symbols":{"AndExpr":"t","AndExpr.Eval":"m","AndExpr.String":"m","Expr":"t","GoVersion":"f","IsGoBuild":"f","IsPlusBuild":"f","NotExpr":"t","NotExpr.Eval":"m","NotExpr.String":"m","OrExpr":"t","OrExpr.Eval":"m","OrExpr.String":"m","Parse":"f","PlusBuildLines":"f","SyntaxError":"t","SyntaxError.Error":"m","TagExpr":"t","TagExpr.Eval":"m","TagExpr.String":"m"}},"go/constant":{"path":"go/constant","name":"constant","symbols":{"BinaryOp":"f","BitLen":"f","Bool":"c","BoolVal":"f","Bytes":"f","Compare":"f","Complex":"c","Denom":"f","Float":"c","Float32Val":"f","Float64Val":"f","Imag":"f","Int":"c","Int64Val":"f","Kind":"t","Kind.String":"m","Make":"f","MakeBool":"f","MakeFloat64":"f","MakeFromBytes":"f","MakeFromLiteral":"f","MakeImag":"f","MakeInt64":"f","MakeString":"f","MakeUint64":"f","MakeUnknown":"f","Num":"f","Real":"f","Shift":"f","Sign":"f","String":"c","StringVal":"f","ToComplex":"f","ToFloat":"f","ToInt":"f","Uint64Val":"f","UnaryOp":"f","Unknown":"c","Val":"f","Value":"t"}},"go/doc":{"path":"go/doc","name":"doc","symbols":{"AllDecls":"c","AllMethods":"c","Example":"t","Examples":"f","Filter":"t","Func":"t","IllegalPrefixes":"v","IsPredeclared":"f","Mode":"t","New":"f","NewFromFiles":"f","Note":"t","Package":"t","Package.Filter":"m","Package.HTML":"m","Package.Markdown":"m","Package.Parser":"m","Package.Printer":"m","Package.Synopsis":"m","Package.Text":"m","PreserveAST":"c","Synopsis":"f","ToHTML":"f","ToText":"f","Type":"t","Value":"t"}},"go/doc/comment":{"path":"go/doc/comment","name":"comment","symbols":{"Block":"t","Code":"t","DefaultLookupPackage":"f","Doc":"t","DocLink":"t","DocLink.DefaultURL":"m","Heading":"t","Heading.DefaultID":"m","Italic":"t","Link":"t","LinkDef":"t","List":"t","List.BlankBefore":"m","List.BlankBetween":"m","ListItem":"t","Paragraph":"t","Parser":"t","Parser.Parse":"m","Plain":"t","Printer":"t","Printer.Comment":"m","Printer.HTML":"m","Printer.Markdown":"m","Printer.Text":"m","Text":"t"}},"go/format":{"path":"go/format","name":"format","symbols":{"Node":"f","Source":"f"}},"go/importer":{"path":"go/importer","name":"importer","symbols":{"Default":"f","For":"f","ForCompiler":"f","Lookup":"t"}},"go/parser":{"path":"go/parser","name":"parser","symbols":{"AllErrors":"c","DeclarationErrors":"c","ImportsOnly":"c","Mode":"t","PackageClauseOnly":"c","ParseComments":"c","ParseDir":"f","ParseExpr":"f","ParseExprFrom":"f","ParseFile":"f","SkipObjectResolution":"c","SpuriousErrors":"c","Trace":"c"}},"go/printer":{"path":"go/printer","name":"printer","symbols":{"CommentedNode":"t","Config":"t","Config.Fprint":"m","Fprint":"f","Mode":"t","RawFormat":"c","SourcePos":"c","TabIndent":"c","UseSpaces":"c"}},"go/scanner":{"path":"go/scanner","name":"scanner","symbols":{"Error":"t","Error.Error":"m","ErrorHandler":"t","ErrorList":"t","ErrorList.Add":"m","ErrorList.Err":"m","ErrorList.Error":"m","ErrorList.Len":"m","ErrorList.Less":"m","ErrorList.RemoveMultiples":"m","ErrorList.Reset":"m","ErrorList.Sort":"m","ErrorList.Swap":"m","Mode":"t","PrintError":"f","ScanComments":"c","Scanner":"t","Scanner.Init":"m","Scanner.Scan":"m"}},"go/token":{"path":"go/token","name":"token","symbols":{"ADD":"c","ADD_ASSIGN":"c","AND":"c","AND_ASSIGN":"c","AND_NOT":"c","AND_NOT_ASSIGN":"c","ARROW":"c","ASSIGN":"c","BREAK":"c","CASE":"c","CHAN":"c","CHAR":"c","COLON":"c","COMMA":"c","COMMENT":"c","CONST":"c","CONTINUE":"c","DEC":"c","DEFAULT":"c","DEFER":"c","DEFINE":"c","ELLIPSIS":"c","ELSE":"c","EOF":"c","EQL":"c","FALLTHROUGH":"c","FLOAT":"c","FOR":"c","FUNC":"c","File":"t","File.AddLine":"m","File.AddLineColumnInfo":"m","File.AddLineInfo":"m","File.Base":"m","File.End":"m","File.Line":"m","File.LineCount":"m","File.LineStart":"m","File.Lines":"m","File.MergeLine":"m","File.Name":"m","File.Offset":"m","File.Pos":"m","File.Position":"m","File.PositionFor":"m","File.SetLines":"m","File.SetLinesForContent":"m","File.Size":"m","FileSet":"t","FileSet.AddExistingFiles":"m","FileSet.AddFile":"m","FileSet.Base":"m","FileSet.File":"m","FileSet.Iterate":"m","FileSet.Position":"m","FileSet.PositionFor":"m","FileSet.Read":"m","FileSet.RemoveFile":"m","FileSet.Write":"m","GEQ":"c","GO":"c","GOTO":"c","GTR":"c","HighestPrec":"c","IDENT":"c","IF":"c","ILLEGAL":"c","IMAG":"c","IMPORT":"c","INC":"c","INT":"c","INTERFACE":"c","IsExported":"f","IsIdentifier":"f","IsKeyword":"f","LAND":"c","LBRACE":"c","LBRACK":"c","LEQ":"c","LOR":"c","LPAREN":"c","LSS":"c","Lookup":"f","LowestPrec":"c","MAP":"c","MUL":"c","MUL_ASSIGN":"c","NEQ":"c","NOT":"c","NewFileSet":"f","NoPos":"c","OR":"c","OR_ASSIGN":"c","PACKAGE":"c","PERIOD":"c","Pos":"t","Pos.IsValid":"m","Position":"t","Position.IsValid":"m","Position.String":"m","QUO":"c","QUO_ASSIGN":"c","RANGE":"c","RBRACE":"c","RBRACK":"c","REM":"c","REM_ASSIGN":"c","RETURN":"c","RPAREN":"c","SELECT":"c","SEMICOLON":"c","SHL":"c","SHL_ASSIGN":"c","SHR":"c","SHR_ASSIGN":"c","STRING":"c","STRUCT":"c","SUB":"c","SUB_ASSIGN":"c","SWITCH":"c","TILDE":"c","TYPE":"c","Token":"t","Token.IsKeyword":"m","Token.IsLiteral":"m","Token.IsOperator":"m","Token.Precedence":"m","Token.String":"m","UnaryPrec":"c","VAR":"c","XOR":"c","XOR_ASSIGN":"c"}},"go/types":{"path":"go/types","name":"types","symbols":{"Alias":"t","Alias.Obj":"m","Alias.Origin":"m","Alias.Rhs":"m","Alias.SetTypeParams":"m","Alias.String":"m","Alias.TypeArgs":"m","Alias.TypeParams":"m","Alias.Underlying":"m","ArgumentError":"t","ArgumentError.Error":"m","ArgumentError.Unwrap":"m","Array":"t","Array.Elem":"m","Array.Len":"m","Array.String":"m","Array.Underlying":"m","AssertableTo":"f","AssignableTo":"f","Basic":"t","Basic.Info":"m","Basic.Kind":"m","Basic.Name":"m","Basic.String":"m","Basic.Underlying":"m","BasicInfo":"t","BasicKind":"t","Bool":"c","Builtin":"t","Builtin.String":"m","Byte":"c","Chan":"t","Chan.Dir":"m","Chan.Elem":"m","Chan.String":"m","Chan.Underlying":"m","ChanDir":"t","CheckExpr":"f","Checker":"t","Checker.Files":"m","Comparable":"f","Complex128":"c","Complex64":"c","Config":"t","Config.Check":"m","Const":"t","Const.String":"m","Const.Val":"m","Context":"t","ConvertibleTo":"f","DefPredeclaredTestFuncs":"f","Default":"f","Error":"t","Error.Error":"m","Eval":"f","ExprString":"f","FieldVal":"c","FieldVar":"c","Float32":"c","Float64":"c","Func":"t","Func.FullName":"m","Func.Origin":"m","Func.Pkg":"m","Func.Scope":"m","Func.Signature":"m","Func.String":"m","Id":"f","Identical":"f","IdenticalIgnoreTags":"f","Implements":"f","ImportMode":"t","Importer":"t","ImporterFrom":"t","Info":"t","Info.ObjectOf":"m","Info.PkgNameOf":"m","Info.TypeOf":"m","Initializer":"t","Initializer.String":"m","Instance":"t","Instantiate":"f","Int":"c","Int16":"c","Int32":"c","Int64":"c","Int8":"c","Interface":"t","Interface.Complete":"m","Interface.Embedded":"m","Interface.EmbeddedType":"m","Interface.EmbeddedTypes":"m","Interface.Empty":"m","Interface.ExplicitMethod":"m","Interface.ExplicitMethods":"m","Interface.IsComparable":"m","Interface.IsImplicit":"m","Interface.IsMethodSet":"m","Interface.MarkImplicit":"m","Interface.Method":"m","Interface.Methods":"m","Interface.NumEmbeddeds":"m","Interface.NumExplicitMethods":"m","Interface.NumMethods":"m","Interface.String":"m","Interface.Underlying":"m","Invalid":"c","IsBoolean":"c","IsComplex":"c","IsConstType":"c","IsFloat":"c","IsInteger":"c","IsInterface":"f","IsNumeric":"c","IsOrdered":"c","IsString":"c","IsUnsigned":"c","IsUntyped":"c","Label":"t","Label.String":"m","LocalVar":"c","LookupFieldOrMethod":"f","LookupSelection":"f","Map":"t","Map.Elem":"m","Map.Key":"m","Map.String":"m","Map.Underlying":"m","MethodExpr":"c","MethodSet":"t","MethodSet.At":"m","MethodSet.Len":"m","MethodSet.Lookup":"m","MethodSet.Methods":"m","MethodSet.String":"m","MethodVal":"c","MissingMethod":"f","Named":"t","Named.AddMethod":"m","Named.Method":"m","Named.Methods":"m","Named.NumMethods":"m","Named.Obj":"m","Named.Origin":"m","Named.SetTypeParams":"m","Named.SetUnderlying":"m","Named.String":"m","Named.TypeArgs":"m","Named.TypeParams":"m","Named.Underlying":"m","NewAlias":"f","NewArray":"f","NewChan":"f","NewChecker":"f","NewConst":"f","NewContext":"f","NewField":"f","NewFunc":"f","NewInterface":"f","NewInterfaceType":"f","NewLabel":"f","NewMap":"f","NewMethodSet":"f","NewNamed":"f","NewPackage":"f","NewParam":"f","NewPkgName":"f","NewPointer":"f","NewScope":"f","NewSignature":"f","NewSignatureType":"f","NewSlice":"f","NewStruct":"f","NewTerm":"f","NewTuple":"f","NewTypeName":"f","NewTypeParam":"f","NewUnion":"f","NewVar":"f","Nil":"t","Nil.String":"m","Object":"t","ObjectString":"f","Package":"t","Package.Complete":"m","Package.GoVersion":"m","Package.Imports":"m","Package.MarkComplete":"m","Package.Name":"m","Package.Path":"m","Package.Scope":"m","Package.SetImports":"m","Package.SetName":"m","Package.String":"m","PackageVar":"c","ParamVar":"c","PkgName":"t","PkgName.Imported":"m","PkgName.String":"m","Pointer":"t","Pointer.Elem":"m","Pointer.String":"m","Pointer.Underlying":"m","Qualifier":"t","RecvOnly":"c","RecvVar":"c","RelativeTo":"f","ResultVar":"c","Rune":"c","Satisfies":"f","Scope":"t","Scope.Child":"m","Scope.Children":"m","Scope.Contains":"m","Scope.End":"m","Scope.Innermost":"m","Scope.Insert":"m","Scope.Len":"m","Scope.Lookup":"m","Scope.LookupParent":"m","Scope.Names":"m","Scope.NumChildren":"m","Scope.Parent":"m","Scope.Pos":"m","Scope.String":"m","Scope.WriteTo":"m","Selection":"t","Selection.Index":"m","Selection.Indirect":"m","Selection.Kind":"m","Selection.Obj":"m","Selection.Recv":"m","Selection.String":"m","Selection.Type":"m","SelectionKind":"t","SelectionString":"f","SendOnly":"c","SendRecv":"c","Signature":"t","Signature.Params":"m","Signature.Recv":"m","Signature.RecvTypeParams":"m","Signature.Results":"m","Signature.String":"m","Signature.TypeParams":"m","Signature.Underlying":"m","Signature.Variadic":"m","Sizes":"t","SizesFor":"f","Slice":"t","Slice.Elem":"m","Slice.String":"m","Slice.Underlying":"m","StdSizes":"t","StdSizes.Alignof":"m","StdSizes.Offsetsof":"m","StdSizes.Sizeof":"m","String":"c","Struct":"t","Struct.Field":"m","Struct.Fields":"m","Struct.NumFields":"m","Struct.String":"m","Struct.Tag":"m","Struct.Underlying":"m","Term":"t","Term.String":"m","Term.Tilde":"m","Term.Type":"m","Tuple":"t","Tuple.At":"m","Tuple.Len":"m","Tuple.String":"m","Tuple.Underlying":"m","Tuple.Variables":"m","Typ":"v","Type":"t","TypeAndValue":"t","TypeAndValue.Addressable":"m","TypeAndValue.Assignable":"m","TypeAndValue.HasOk":"m","TypeAndValue.IsBuiltin":"m","TypeAndValue.IsNil":"m","TypeAndValue.IsType":"m","TypeAndValue.IsValue":"m","TypeAndValue.IsVoid":"m","TypeList":"t","TypeList.At":"m","TypeList.Len":"m","TypeList.Types":"m","TypeName":"t","TypeName.IsAlias":"m","TypeName.String":"m","TypeParam":"t","TypeParam.Constraint":"m","TypeParam.Index":"m","TypeParam.Obj":"m","TypeParam.SetConstraint":"m","TypeParam.String":"m","TypeParam.Underlying":"m","TypeParamList":"t","TypeParamList.At":"m","TypeParamList.Len":"m","TypeParamList.TypeParams":"m","TypeString":"f","Uint":"c","Uint16":"c","Uint32":"c","Uint64":"c","Uint8":"c","Uintptr":"c","Unalias":"f","Union":"t","Union.Len":"m","Union.String":"m","Union.Term":"m","Union.Terms":"m","Union.Underlying":"m","Universe":"v","Unsafe":"v","UnsafePointer":"c","UntypedBool":"c","UntypedComplex":"c","UntypedFloat":"c","UntypedInt":"c","UntypedNil":"c","UntypedRune":"c","UntypedString":"c","Var":"t","Var.Anonymous":"m","Var.Embedded":"m","Var.IsField":"m","Var.Kind":"m","Var.Origin":"m","Var.SetKind":"m","Var.String":"m","VarKind":"t","VarKind.String":"m","WriteExpr":"f","WriteSignature":"f","WriteType":"f"}},"go/version":{"path":"go/version","name":"version","symbols":{"Compare":"f","IsValid":"f","Lang":"f"}},"hash":{"path":"hash","name":"hash","symbols":{"Cloner":"t","Hash":"t","Hash32":"t","Hash64":"t","XOF":"t"}},"hash/adler32":{"path":"hash/adler32","name":"adler32","symbols":{"Checksum":"f","New":"f","Size":"c"}},"hash/crc32":{"path":"hash/crc32","name":"crc32","symbols":{"Castagnoli":"c","Checksum":"f","ChecksumIEEE":"f","IEEE":"c","IEEETable":"v","Koopman":"c","MakeTable":"f","New":"f","NewIEEE":"f","Size":"c","Table":"t","Update":"f"}},"hash/crc64":{"path":"hash/crc64","name":"crc64","symbols":{"Checksum":"f","ECMA":"c","ISO":"c","MakeTable":"f","New":"f","Size":"c","Table":"t","Update":"f"}},"hash/fnv":{"path":"hash/fnv","name":"fnv","symbols":{"New128":"f","New128a":"f","New32":"f","New32a":"f","New64":"f","New64a":"f"}},"hash/maphash":{"path":"hash/maphash","name":"maphash","symbols":{"Bytes":"f","Comparable":"f","Hash":"t","Hash.BlockSize":"m","Hash.Clone":"m","Hash.Reset":"m","Hash.Seed":"m","Hash.SetSeed":"m","Hash.Size":"m","Hash.Sum":"m","Hash.Sum64":"m","Hash.Write":"m","Hash.WriteByte":"m","Hash.WriteString":"m","MakeSeed":"f","Seed":"t","String":"f","WriteComparable":"f"}},"html":{"path":"html","name":"html","symbols":{"EscapeString":"f","UnescapeString":"f"}},"html/template":{"path":"html/template","name":"template","symbols":{"CSS":"t","ErrAmbigContext":"c","ErrBadHTML":"c","ErrBranchEnd":"c","ErrEndContext":"c","ErrJSTemplate":"c","ErrNoSuchTemplate":"c","ErrOutputContext":"c","ErrPartialCharset":"c","ErrPartialEscape":"c","ErrPredefinedEscaper":"c","ErrRangeLoopReentry":"c","ErrSlashAmbig":"c","Error":"t","Error.Error":"m","ErrorCode":"t","FuncMap":"t","HTML":"t","HTMLAttr":"t","HTMLEscape":"f","HTMLEscapeString":"f","HTMLEscaper":"f","IsTrue":"f","JS":"t","JSEscape":"f","JSEscapeString":"f","JSEscaper":"f","JSStr":"t","Must":"f","New":"f","OK":"c","ParseFS":"f","ParseFiles":"f","ParseGlob":"f","Srcset":"t","Template":"t","Template.AddParseTree":"m","Template.Clone":"m","Template.DefinedTemplates":"m","Template.Delims":"m","Template.Execute":"m","Template.ExecuteTemplate":"m","Template.Funcs":"m","Template.Lookup":"m","Template.Name":"m","Template.New":"m","Template.Option":"m","Template.Parse":"m","Template.ParseFS":"m","Template.ParseFiles":"m","Template.ParseGlob":"m","Template.Templates":"m","URL":"t","URLQueryEscaper":"f"}},"image":{"path":"image","name":"image","symbols":{"Alpha":"t","Alpha.AlphaAt":"m","Alpha.At":"m","Alpha.Bounds":"m","Alpha.ColorModel":"m","Alpha.Opaque":"m","Alpha.PixOffset":"m","Alpha.RGBA64At":"m","Alpha.Set":"m","Alpha.SetAlpha":"m","Alpha.SetRGBA64":"m","Alpha.SubImage":"m","Alpha16":"t","Alpha16.Alpha16At":"m","Alpha16.At":"m","Alpha16.Bounds":"m","Alpha16.ColorModel":"m","Alpha16.Opaque":"m","Alpha16.PixOffset":"m","Alpha16.RGBA64At":"m","Alpha16.Set":"m","Alpha16.SetAlpha16":"m","Alpha16.SetRGBA64":"m","Alpha16.SubImage":"m","Black":"v","CMYK":"t","CMYK.At":"m","CMYK.Bounds":"m","CMYK.CMYKAt":"m","CMYK.ColorModel":"m","CMYK.Opaque":"m","CMYK.PixOffset":"m","CMYK.RGBA64At":"m","CMYK.Set":"m","CMYK.SetCMYK":"m","CMYK.SetRGBA64":"m","CMYK.SubImage":"m","Config":"t","Decode":"f","DecodeConfig":"f","ErrFormat":"v","Gray":"t","Gray.At":"m","Gray.Bounds":"m","Gray.ColorModel":"m","Gray.GrayAt":"m","Gray.Opaque":"m","Gray.PixOffset":"m","Gray.RGBA64At":"m","Gray.Set":"m","Gray.SetGray":"m","Gray.SetRGBA64":"m","Gray.SubImage":"m","Gray16":"t","Gray16.At":"m","Gray16.Bounds":"m","Gray16.ColorModel":"m","Gray16.Gray16At":"m","Gray16.Opaque":"m","Gray16.PixOffset":"m","Gray16.RGBA64At":"m","Gray16.Set":"m","Gray16.SetGray16":"m","Gray16.SetRGBA64":"m","Gray16.SubImage":"m","Image":"t","NRGBA":"t","NRGBA.At":"m","NRGBA.Bounds":"m","NRGBA.ColorModel":"m","NRGBA.NRGBAAt":"m","NRGBA.Opaque":"m","NRGBA.PixOffset":"m","NRGBA.RGBA64At":"m","NRGBA.Set":"m","NRGBA.SetNRGBA":"m","NRGBA.SetRGBA64":"m","NRGBA.SubImage":"m","NRGBA64":"t","NRGBA64.At":"m","NRGBA64.Bounds":"m","NRGBA64.ColorModel":"m","NRGBA64.NRGBA64At":"m","NRGBA64.Opaque":"m","NRGBA64.PixOffset":"m","NRGBA64.RGBA64At":"m","NRGBA64.Set":"m","NRGBA64.SetNRGBA64":"m","NRGBA64.SetRGBA64":"m","NRGBA64.SubImage":"m","NYCbCrA":"t","NYCbCrA.AOffset":"m","NYCbCrA.At":"m","NYCbCrA.ColorModel":"m","NYCbCrA.NYCbCrAAt":"m","NYCbCrA.Opaque":"m","NYCbCrA.RGBA64At":"m","NYCbCrA.SubImage":"m","NewAlpha":"f","NewAlpha16":"f","NewCMYK":"f","NewGray":"f","NewGray16":"f","NewNRGBA":"f","NewNRGBA64":"f","NewNYCbCrA":"f","NewPaletted":"f","NewRGBA":"f","NewRGBA64":"f","NewUniform":"f","NewYCbCr":"f","Opaque":"v","Paletted":"t","Paletted.At":"m","Paletted.Bounds":"m","Paletted.ColorIndexAt":"m","Paletted.ColorModel":"m","Paletted.Opaque":"m","Paletted.PixOffset":"m","Paletted.RGBA64At":"m","Paletted.Set":"m","Paletted.SetColorIndex":"m","Paletted.SetRGBA64":"m","Paletted.SubImage":"m","PalettedImage":"t","Point":"t","Point.Add":"m","Point.Div":"m","Point.Eq":"m","Point.In":"m","Point.Mod":"m","Point.Mul":"m","Point.String":"m","Point.Sub":"m","Pt":"f","RGBA":"t","RGBA.At":"m","RGBA.Bounds":"m","RGBA.ColorModel":"m","RGBA.Opaque":"m","RGBA.PixOffset":"m","RGBA.RGBA64At":"m","RGBA.RGBAAt":"m","RGBA.Set":"m","RGBA.SetRGBA":"m","RGBA.SetRGBA64":"m","RGBA.SubImage":"m","RGBA64":"t","RGBA64.At":"m","RGBA64.Bounds":"m","RGBA64.ColorModel":"m","RGBA64.Opaque":"m","RGBA64.PixOffset":"m","RGBA64.RGBA64At":"m","RGBA64.Set":"m","RGBA64.SetRGBA64":"m","RGBA64.SubImage":"m","RGBA64Image":"t","Rect":"f","Rectangle":"t","Rectangle.Add":"m","Rectangle.At":"m","Rectangle.Bounds":"m","Rectangle.Canon":"m","Rectangle.ColorModel":"m","Rectangle.Dx":"m","Rectangle.Dy":"m","Rectangle.Empty":"m","Rectangle.Eq":"m","Rectangle.In":"m","Rectangle.Inset":"m","Rectangle.Intersect":"m","Rectangle.Overlaps":"m","Rectangle.RGBA64At":"m","Rectangle.Size":"m","Rectangle.String":"m","Rectangle.Sub":"m","Rectangle.Union":"m","RegisterFormat":"f","Transparent":"v","Uniform":"t","Uniform.At":"m","Uniform.Bounds":"m","Uniform.ColorModel":"m","Uniform.Convert":"m","Uniform.Opaque":"m","Uniform.RGBA":"m","Uniform.RGBA64At":"m","White":"v","YCbCr":"t","YCbCr.At":"m","YCbCr.Bounds":"m","YCbCr.COffset":"m","YCbCr.ColorModel":"m","YCbCr.Opaque":"m","YCbCr.RGBA64At":"m","YCbCr.SubImage":"m","YCbCr.YCbCrAt":"m","YCbCr.YOffset":"m","YCbCrSubsampleRatio":"t","YCbCrSubsampleRatio.String":"m","YCbCrSubsampleRatio410":"c","YCbCrSubsampleRatio411":"c","YCbCrSubsampleRatio420":"c","YCbCrSubsampleRatio422":"c","YCbCrSubsampleRatio440":"c","YCbCrSubsampleRatio444":"c","ZP":"v","ZR":"v"}},"image/color":{"path":"image/color","name":"color","symbols":{"Alpha":"t","Alpha.RGBA":"m","Alpha16":"t","Alpha16.RGBA":"m","Alpha16Model":"v","AlphaModel":"v","Black":"v","CMYK":"t","CMYK.RGBA":"m","CMYKModel":"v","CMYKToRGB":"f","Color":"t","Gray":"t","Gray.RGBA":"m","Gray16":"t","Gray16.RGBA":"m","Gray16Model":"v","GrayModel":"v","Model":"t","ModelFunc":"f","NRGBA":"t","NRGBA.RGBA":"m","NRGBA64":"t","NRGBA64.RGBA":"m","NRGBA64Model":"v","NRGBAModel":"v","NYCbCrA":"t","NYCbCrA.RGBA":"m","NYCbCrAModel":"v","Opaque":"v","Palette":"t","Palette.Convert":"m","Palette.Index":"m","RGBA":"t","RGBA.RGBA":"m","RGBA64":"t","RGBA64.RGBA":"m","RGBA64Model":"v","RGBAModel":"v","RGBToCMYK":"f","RGBToYCbCr":"f","Transparent":"v","White":"v","YCbCr":"t","YCbCr.RGBA":"m","YCbCrModel":"v","YCbCrToRGB":"f"}},"image/color/palette":{"path":"image/color/palette","name":"palette","symbols":{"Plan9":"v","WebSafe":"v"}},"image/draw":{"path":"image/draw","name":"draw","symbols":{"Draw":"f","DrawMask":"f","Drawer":"t","FloydSteinberg":"v","Image":"t","Op":"t","Op.Draw":"m","Over":"c","Quantizer":"t","RGBA64Image":"t","Src":"c"}},"image/gif":{"path":"image/gif","name":"gif","symbols":{"Decode":"f","DecodeAll":"f","DecodeConfig":"f","DisposalBackground":"c","DisposalNone":"c","DisposalPrevious":"c","Encode":"f","EncodeAll":"f","GIF":"t","Options":"t"}},"image/jpeg":{"path":"image/jpeg","name":"jpeg","symbols":{"Decode":"f","DecodeConfig":"f","DefaultQuality":"c","Encode":"f","FormatError":"t","FormatError.Error":"m","Options":"t","Reader":"t","UnsupportedError":"t","UnsupportedError.Error":"m"}},"image/png":{"path":"image/png","name":"png","symbols":{"BestCompression":"c","BestSpeed":"c","CompressionLevel":"t","Decode":"f","DecodeConfig":"f","DefaultCompression":"c","Encode":"f","Encoder":"t","Encoder.Encode":"m","EncoderBuffer":"t","EncoderBufferPool":"t","FormatError":"t","FormatError.Error":"m","NoCompression":"c","UnsupportedError":"t","UnsupportedError.Error":"m"}},"index/suffixarray":{"path":"index/suffixarray","name":"suffixarray","symbols":{"Index":"t","Index.Bytes":"m","Index.FindAllIndex":"m","Index.Lookup":"m","Index.Read":"m","Index.Write":"m","New":"f"}},"io":{"path":"io","name":"io","symbols":{"ByteReader":"t","ByteScanner":"t","ByteWriter":"t","Closer":"t","Copy":"f","CopyBuffer":"f","CopyN":"f","Discard":"v","EOF":"v","ErrClosedPipe":"v","ErrNoProgress":"v","ErrShortBuffer":"v","ErrShortWrite":"v","ErrUnexpectedEOF":"v","LimitReader":"f","LimitedReader":"t","LimitedReader.Read":"m","MultiReader":"f","MultiWriter":"f","NewOffsetWriter":"f","NewSectionReader":"f","NopCloser":"f","OffsetWriter":"t","OffsetWriter.Seek":"m","OffsetWriter.Write":"m","OffsetWriter.WriteAt":"m","Pipe":"f","PipeReader":"t","PipeReader.Close":"m","PipeReader.CloseWithError":"m","PipeReader.Read":"m","PipeWriter":"t","PipeWriter.Close":"m","PipeWriter.CloseWithError":"m","PipeWriter.Write":"m","ReadAll":"f","ReadAtLeast":"f","ReadCloser":"t","ReadFull":"f","ReadSeekCloser":"t","ReadSeeker":"t","ReadWriteCloser":"t","ReadWriteSeeker":"t","ReadWriter":"t","Reader":"t","ReaderAt":"t","ReaderFrom":"t","RuneReader":"t","RuneScanner":"t","SectionReader":"t","SectionReader.Outer":"m","SectionReader.Read":"m","SectionReader.ReadAt":"m","SectionReader.Seek":"m","SectionReader.Size":"m","SeekCurrent":"c","SeekEnd":"c","SeekStart":"c","Seeker":"t","StringWriter":"t","TeeReader":"f","WriteCloser":"t","WriteSeeker":"t","WriteString":"f","Writer":"t","WriterAt":"t","WriterTo":"t"}},"io/fs":{"path":"io/fs","name":"fs","symbols":{"DirEntry":"t","ErrClosed":"v","ErrExist":"v","ErrInvalid":"v","ErrNotExist":"v","ErrPermission":"v","FS":"t","File":"t","FileInfo":"t","FileInfoToDirEntry":"f","FileMode":"t","FileMode.IsDir":"m","FileMode.IsRegular":"m","FileMode.Perm":"m","FileMode.String":"m","FileMode.Type":"m","FormatDirEntry":"f","FormatFileInfo":"f","Glob":"f","GlobFS":"t","Lstat":"f","ModeAppend":"c","ModeCharDevice":"c","ModeDevice":"c","ModeDir":"c","ModeExclusive":"c","ModeIrregular":"c","ModeNamedPipe":"c","ModePerm":"c","ModeSetgid":"c","ModeSetuid":"c","ModeSocket":"c","ModeSticky":"c","ModeSymlink":"c","ModeTemporary":"c","ModeType":"c","PathError":"t","PathError.Error":"m","PathError.Timeout":"m","PathError.Unwrap":"m","ReadDir":"f","ReadDirFS":"t","ReadDirFile":"t","ReadFile":"f","ReadFileFS":"t","ReadLink":"f","ReadLinkFS":"t","SkipAll":"v","SkipDir":"v","Stat":"f","StatFS":"t","Sub":"f","SubFS":"t","ValidPath":"f","WalkDir":"f","WalkDirFunc":"t"}},"io/ioutil":{"path":"io/ioutil","name":"ioutil","symbols":{"Discard":"v","NopCloser":"f","ReadAll":"f","ReadDir":"f","ReadFile":"f","TempDir":"f","TempFile":"f","WriteFile":"f"}},"iter":{"path":"iter","name":"iter","symbols":{"Pull":"f","Pull2":"f","Seq":"t","Seq2":"t"}},"log":{"path":"log","name":"log","symbols":{"Default":"f","Fatal":"f","Fatalf":"f","Fatalln":"f","Flags":"f","LUTC":"c","Ldate":"c","Llongfile":"c","Lmicroseconds":"c","Lmsgprefix":"c","Logger":"t","Logger.Fatal":"m","Logger.Fatalf":"m","Logger.Fatalln":"m","Logger.Flags":"m","Logger.Output":"m","Logger.Panic":"m","Logger.Panicf":"m","Logger.Panicln":"m","Logger.Prefix":"m","Logger.Print":"m","Logger.Printf":"m","Logger.Println":"m","Logger.SetFlags":"m","Logger.SetOutput":"m","Logger.SetPrefix":"m","Logger.Writer":"m","Lshortfile":"c","LstdFlags":"c","Ltime":"c","New":"f","Output":"f","Panic":"f","Panicf":"f","Panicln":"f","Prefix":"f","Print":"f","Printf":"f","Println":"f","SetFlags":"f","SetOutput":"f","SetPrefix":"f","Writer":"f"}},"log/slog":{"path":"log/slog","name":"slog","symbols":{"Any":"f","AnyValue":"f","Attr":"t","Attr.Equal":"m","Attr.String":"m","Bool":"f","BoolValue":"f","Debug":"f","DebugContext":"f","Default":"f","DiscardHandler":"v","Duration":"f","DurationValue":"f","Error":"f","ErrorContext":"f","Float64":"f","Float64Value":"f","Group":"f","GroupAttrs":"f","GroupValue":"f","Handler":"t","HandlerOptions":"t","Info":"f","InfoContext":"f","Int":"f","Int64":"f","Int64Value":"f","IntValue":"f","JSONHandler":"t","JSONHandler.Enabled":"m","JSONHandler.Handle":"m","JSONHandler.WithAttrs":"m","JSONHandler.WithGroup":"m","Kind":"t","Kind.String":"m","KindAny":"c","KindBool":"c","KindDuration":"c","KindFloat64":"c","KindGroup":"c","KindInt64":"c","KindLogValuer":"c","KindString":"c","KindTime":"c","KindUint64":"c","Level":"t","Level.AppendText":"m","Level.Level":"m","Level.MarshalJSON":"m","Level.MarshalText":"m","Level.String":"m","Level.UnmarshalJSON":"m","Level.UnmarshalText":"m","LevelDebug":"c","LevelError":"c","LevelInfo":"c","LevelKey":"c","LevelVar":"t","LevelVar.AppendText":"m","LevelVar.Level":"m","LevelVar.MarshalText":"m","LevelVar.Set":"m","LevelVar.String":"m","LevelVar.UnmarshalText":"m","LevelWarn":"c","Leveler":"t","Log":"f","LogAttrs":"f","LogValuer":"t","Logger":"t","Logger.Debug":"m","Logger.DebugContext":"m","Logger.Enabled":"m","Logger.Error":"m","Logger.ErrorContext":"m","Logger.Handler":"m","Logger.Info":"m","Logger.InfoContext":"m","Logger.Log":"m","Logger.LogAttrs":"m","Logger.Warn":"m","Logger.WarnContext":"m","Logger.With":"m","Logger.WithGroup":"m","MessageKey":"c","MultiHandler":"t","MultiHandler.Enabled":"m","MultiHandler.Handle":"m","MultiHandler.WithAttrs":"m","MultiHandler.WithGroup":"m","New":"f","NewJSONHandler":"f","NewLogLogger":"f","NewMultiHandler":"f","NewRecord":"f","NewTextHandler":"f","Record":"t","Record.Add":"m","Record.AddAttrs":"m","Record.Attrs":"m","Record.Clone":"m","Record.NumAttrs":"m","Record.Source":"m","SetDefault":"f","SetLogLoggerLevel":"f","Source":"t","SourceKey":"c","String":"f","StringValue":"f","TextHandler":"t","TextHandler.Enabled":"m","TextHandler.Handle":"m","TextHandler.WithAttrs":"m","TextHandler.WithGroup":"m","Time":"f","TimeKey":"c","TimeValue":"f","Uint64":"f","Uint64Value":"f","Value":"t","Value.Any":"m","Value.Bool":"m","Value.Duration":"m","Value.Equal":"m","Value.Float64":"m","Value.Group":"m","Value.Int64":"m","Value.Kind":"m","Value.LogValuer":"m","Value.Resolve":"m","Value.String":"m","Value.Time":"m","Value.Uint64":"m","Warn":"f","WarnContext":"f","With":"f"}},"log/syslog":{"path":"log/syslog","name":"syslog","symbols":{"Dial":"f","LOG_ALERT":"c","LOG_AUTH":"c","LOG_AUTHPRIV":"c","LOG_CRIT":"c","LOG_CRON":"c","LOG_DAEMON":"c","LOG_DEBUG":"c","LOG_EMERG":"c","LOG_ERR":"c","LOG_FTP":"c","LOG_INFO":"c","LOG_KERN":"c","LOG_LOCAL0":"c","LOG_LOCAL1":"c","LOG_LOCAL2":"c","LOG_LOCAL3":"c","LOG_LOCAL4":"c","LOG_LOCAL5":"c","LOG_LOCAL6":"c","LOG_LOCAL7":"c","LOG_LPR":"c","LOG_MAIL":"c","LOG_NEWS":"c","LOG_NOTICE":"c","LOG_SYSLOG":"c","LOG_USER":"c","LOG_UUCP":"c","LOG_WARNING":"c","New":"f","NewLogger":"f","Priority":"t","Writer":"t","Writer.Alert":"m","Writer.Close":"m","Writer.Crit":"m","Writer.Debug":"m","Writer.Emerg":"m","Writer.Err":"m","Writer.Info":"m","Writer.Notice":"m","Writer.Warning":"m","Writer.Write":"m"}},"maps":{"path":"maps","name":"maps","symbols":{"All":"f","Clone":"f","Collect":"f","Copy":"f","DeleteFunc":"f","Equal":"f","EqualFunc":"f","Insert":"f","Keys":"f","Values":"f"}},"math":{"path":"math","name":"math","symbols":{"Abs":"f","Acos":"f","Acosh":"f","Asin":"f","Asinh":"f","Atan":"f","Atan2":"f","Atanh":"f","Cbrt":"f","Ceil":"f","Copysign":"f","Cos":"f","Cosh":"f","Dim":"f","E":"c","Erf":"f","Erfc":"f","Erfcinv":"f","Erfinv":"f","Exp":"f","Exp2":"f","Expm1":"f","FMA":"f","Float32bits":"f","Float32frombits":"f","Float64bits":"f","Float64frombits":"f","Floor":"f","Frexp":"f","Gamma":"f","Hypot":"f","Ilogb":"f","Inf":"f","IsInf":"f","IsNaN":"f","J0":"f","J1":"f","Jn":"f","Ldexp":"f","Lgamma":"f","Ln10":"c","Ln2":"c","Log":"f","Log10":"f","Log10E":"c","Log1p":"f","Log2":"f","Log2E":"c","Logb":"f","Max":"f","MaxFloat32":"c","MaxFloat64":"c","MaxInt":"c","MaxInt16":"c","MaxInt32":"c","MaxInt64":"c","MaxInt8":"c","MaxUint":"c","MaxUint16":"c","MaxUint32":"c","MaxUint64":"c","MaxUint8":"c","Min":"f","MinInt":"c","MinInt16":"c","MinInt32":"c","MinInt64":"c","MinInt8":"c","Mod":"f","Modf":"f","NaN":"f","Nextafter":"f","Nextafter32":"f","Phi":"c","Pi":"c","Pow":"f","Pow10":"f","Remainder":"f","Round":"f","RoundToEven":"f","Signbit":"f","Sin":"f","Sincos":"f","Sinh":"f","SmallestNonzeroFloat32":"c","SmallestNonzeroFloat64":"c","Sqrt":"f","Sqrt2":"c","SqrtE":"c","SqrtPhi":"c","SqrtPi":"c","Tan":"f","Tanh":"f","Trunc":"f","Y0":"f","Y1":"f","Yn":"f"}},"math/big":{"path":"math/big","name":"big","symbols":{"Above":"c","Accuracy":"t","Accuracy.String":"m","AwayFromZero":"c","Below":"c","ErrNaN":"t","ErrNaN.Error":"m","Exact":"c","Float":"t","Float.Abs":"m","Float.Acc":"m","Float.Add":"m","Float.Append":"m","Float.AppendText":"m","Float.Cmp":"m","Float.Copy":"m","Float.Float32":"m","Float.Float64":"m","Float.Format":"m","Float.GobDecode":"m","Float.GobEncode":"m","Float.Int":"m","Float.Int64":"m","Float.IsInf":"m","Float.IsInt":"m","Float.MantExp":"m","Float.MarshalText":"m","Float.MinPrec":"m","Float.Mode":"m","Float.Mul":"m","Float.Neg":"m","Float.Parse":"m","Float.Prec":"m","Float.Quo":"m","Float.Rat":"m","Float.Scan":"m","Float.Set":"m","Float.SetFloat64":"m","Float.SetInf":"m","Float.SetInt":"m","Float.SetInt64":"m","Float.SetMantExp":"m","Float.SetMode":"m","Float.SetPrec":"m","Float.SetRat":"m","Float.SetString":"m","Float.SetUint64":"m","Float.Sign":"m","Float.Signbit":"m","Float.Sqrt":"m","Float.String":"m","Float.Sub":"m","Float.Text":"m","Float.Uint64":"m","Float.UnmarshalText":"m","Int":"t","Int.Abs":"m","Int.Add":"m","Int.And":"m","Int.AndNot":"m","Int.Append":"m","Int.AppendText":"m","Int.Binomial":"m","Int.Bit":"m","Int.BitLen":"m","Int.Bits":"m","Int.Bytes":"m","Int.Cmp":"m","Int.CmpAbs":"m","Int.Div":"m","Int.DivMod":"m","Int.Exp":"m","Int.FillBytes":"m","Int.Float64":"m","Int.Format":"m","Int.GCD":"m","Int.GobDecode":"m","Int.GobEncode":"m","Int.Int64":"m","Int.IsInt64":"m","Int.IsUint64":"m","Int.Lsh":"m","Int.MarshalJSON":"m","Int.MarshalText":"m","Int.Mod":"m","Int.ModInverse":"m","Int.ModSqrt":"m","Int.Mul":"m","Int.MulRange":"m","Int.Neg":"m","Int.Not":"m","Int.Or":"m","Int.ProbablyPrime":"m","Int.Quo":"m","Int.QuoRem":"m","Int.Rand":"m","Int.Rem":"m","Int.Rsh":"m","Int.Scan":"m","Int.Set":"m","Int.SetBit":"m","Int.SetBits":"m","Int.SetBytes":"m","Int.SetInt64":"m","Int.SetString":"m","Int.SetUint64":"m","Int.Sign":"m","Int.Sqrt":"m","Int.String":"m","Int.Sub":"m","Int.Text":"m","Int.TrailingZeroBits":"m","Int.Uint64":"m","Int.UnmarshalJSON":"m","Int.UnmarshalText":"m","Int.Xor":"m","Jacobi":"f","MaxBase":"c","MaxExp":"c","MaxPrec":"c","MinExp":"c","NewFloat":"f","NewInt":"f","NewRat":"f","ParseFloat":"f","Rat":"t","Rat.Abs":"m","Rat.Add":"m","Rat.AppendText":"m","Rat.Cmp":"m","Rat.Denom":"m","Rat.Float32":"m","Rat.Float64":"m","Rat.FloatPrec":"m","Rat.FloatString":"m","Rat.GobDecode":"m","Rat.GobEncode":"m","Rat.Inv":"m","Rat.IsInt":"m","Rat.MarshalText":"m","Rat.Mul":"m","Rat.Neg":"m","Rat.Num":"m","Rat.Quo":"m","Rat.RatString":"m","Rat.Scan":"m","Rat.Set":"m","Rat.SetFloat64":"m","Rat.SetFrac":"m","Rat.SetFrac64":"m","Rat.SetInt":"m","Rat.SetInt64":"m","Rat.SetString":"m","Rat.SetUint64":"m","Rat.Sign":"m","Rat.String":"m","Rat.Sub":"m","Rat.UnmarshalText":"m","RoundingMode":"t","RoundingMode.String":"m","ToNearestAway":"c","ToNearestEven":"c","ToNegativeInf":"c","ToPositiveInf":"c","ToZero":"c","Word":"t"}},"math/bits":{"path":"math/bits","name":"bits","symbols":{"Add":"f","Add32":"f","Add64":"f","Div":"f","Div32":"f","Div64":"f","LeadingZeros":"f","LeadingZeros16":"f","LeadingZeros32":"f","LeadingZeros64":"f","LeadingZeros8":"f","Len":"f","Len16":"f","Len32":"f","Len64":"f","Len8":"f","Mul":"f","Mul32":"f","Mul64":"f","OnesCount":"f","OnesCount16":"f","OnesCount32":"f","OnesCount64":"f","OnesCount8":"f","Rem":"f","Rem32":"f","Rem64":"f","Reverse":"f","Reverse16":"f","Reverse32":"f","Reverse64":"f","Reverse8":"f","ReverseBytes":"f","ReverseBytes16":"f","ReverseBytes32":"f","ReverseBytes64":"f","RotateLeft":"f","RotateLeft16":"f","RotateLeft32":"f","RotateLeft64":"f","RotateLeft8":"f","Sub":"f","Sub32":"f","Sub64":"f","TrailingZeros":"f","TrailingZeros16":"f","TrailingZeros32":"f","TrailingZeros64":"f","TrailingZeros8":"f","UintSize":"c"}},"math/cmplx":{"path":"math/cmplx","name":"cmplx","symbols":{"Abs":"f","Acos":"f","Acosh":"f","Asin":"f","Asinh":"f","Atan":"f","Atanh":"f","Conj":"f","Cos":"f","Cosh":"f","Cot":"f","Exp":"f","Inf":"f","IsInf":"f","IsNaN":"f","Log":"f","Log10":"f","NaN":"f","Phase":"f","Polar":"f","Pow":"f","Rect":"f","Sin":"f","Sinh":"f","Sqrt":"f","Tan":"f","Tanh":"f"}},"math/rand":{"path":"math/rand","name":"rand","symbols":{"ExpFloat64":"f","Float32":"f","Float64":"f","Int":"f","Int31":"f","Int31n":"f","Int63":"f","Int63n":"f","Intn":"f","New":"f","NewSource":"f","NewZipf":"f","NormFloat64":"f","Perm":"f","Rand":"t","Rand.ExpFloat64":"m","Rand.Float32":"m","Rand.Float64":"m","Rand.Int":"m","Rand.Int31":"m","Rand.Int31n":"m","Rand.Int63":"m","Rand.Int63n":"m","Rand.Intn":"m","Rand.NormFloat64":"m","Rand.Perm":"m","Rand.Read":"m","Rand.Seed":"m","Rand.Shuffle":"m","Rand.Uint32":"m","Rand.Uint64":"m","Read":"f","Seed":"f","Shuffle":"f","Source":"t","Source64":"t","Uint32":"f","Uint64":"f","Zipf":"t","Zipf.Uint64":"m"}},"math/rand/v2":{"path":"math/rand/v2","name":"rand","symbols":{"ChaCha8":"t","ChaCha8.AppendBinary":"m","ChaCha8.MarshalBinary":"m","ChaCha8.Read":"m","ChaCha8.Seed":"m","ChaCha8.Uint64":"m","ChaCha8.UnmarshalBinary":"m","ExpFloat64":"f","Float32":"f","Float64":"f","Int":"f","Int32":"f","Int32N":"f","Int64":"f","Int64N":"f","IntN":"f","N":"f","New":"f","NewChaCha8":"f","NewPCG":"f","NewZipf":"f","NormFloat64":"f","PCG":"t","PCG.AppendBinary":"m","PCG.MarshalBinary":"m","PCG.Seed":"m","PCG.Uint64":"m","PCG.UnmarshalBinary":"m","Perm":"f","Rand":"t","Rand.ExpFloat64":"m","Rand.Float32":"m","Rand.Float64":"m","Rand.Int":"m","Rand.Int32":"m","Rand.Int32N":"m","Rand.Int64":"m","Rand.Int64N":"m","Rand.IntN":"m","Rand.NormFloat64":"m","Rand.Perm":"m","Rand.Shuffle":"m","Rand.Uint":"m","Rand.Uint32":"m","Rand.Uint32N":"m","Rand.Uint64":"m","Rand.Uint64N":"m","Rand.UintN":"m","Shuffle":"f","Source":"t","Uint":"f","Uint32":"f","Uint32N":"f","Uint64":"f","Uint64N":"f","UintN":"f","Zipf":"t","Zipf.Uint64":"m"}},"mime":{"path":"mime","name":"mime","symbols":{"AddExtensionType":"f","BEncoding":"c","ErrInvalidMediaParameter":"v","ExtensionsByType":"f","FormatMediaType":"f","ParseMediaType":"f","QEncoding":"c","TypeByExtension":"f","WordDecoder":"t","WordDecoder.Decode":"m","WordDecoder.DecodeHeader":"m","WordEncoder":"t","WordEncoder.Encode":"m"}},"mime/multipart":{"path":"mime/multipart","name":"multipart","symbols":{"ErrMessageTooLarge":"v","File":"t","FileContentDisposition":"f","FileHeader":"t","FileHeader.Open":"m","Form":"t","Form.RemoveAll":"m","NewReader":"f","NewWriter":"f","Part":"t","Part.Close":"m","Part.FileName":"m","Part.FormName":"m","Part.Read":"m","Reader":"t","Reader.NextPart":"m","Reader.NextRawPart":"m","Reader.ReadForm":"m","Writer":"t","Writer.Boundary":"m","Writer.Close":"m","Writer.CreateFormField":"m","Writer.CreateFormFile":"m","Writer.CreatePart":"m","Writer.FormDataContentType":"m","Writer.SetBoundary":"m","Writer.WriteField":"m"}},"mime/quotedprintable":{"path":"mime/quotedprintable","name":"quotedprintable","symbols":{"NewReader":"f","NewWriter":"f","Reader":"t","Reader.Read":"m","Writer":"t","Writer.Close":"m","Writer.Write":"m"}},"net":{"path":"net","name":"net","symbols":{"Addr":"t","AddrError":"t","AddrError.Error":"m","AddrError.Temporary":"m","AddrError.Timeout":"m","Buffers":"t","Buffers.Read":"m","Buffers.WriteTo":"m","CIDRMask":"f","Conn":"t","DNSConfigError":"t","DNSConfigError.Error":"m","DNSConfigError.Temporary":"m","DNSConfigError.Timeout":"m","DNSConfigError.Unwrap":"m","DNSError":"t","DNSError.Error":"m","DNSError.Temporary":"m","DNSError.Timeout":"m","DNSError.Unwrap":"m","DefaultResolver":"v","Dial":"f","DialIP":"f","DialTCP":"f","DialTimeout":"f","DialUDP":"f","DialUnix":"f","Dialer":"t","Dialer.Dial":"m","Dialer.DialContext":"m","Dialer.DialIP":"m","Dialer.DialTCP":"m","Dialer.DialUDP":"m","Dialer.DialUnix":"m","Dialer.MultipathTCP":"m","Dialer.SetMultipathTCP":"m","ErrClosed":"v","ErrWriteToConnected":"v","Error":"t","FileConn":"f","FileListener":"f","FilePacketConn":"f","FlagBroadcast":"c","FlagLoopback":"c","FlagMulticast":"c","FlagPointToPoint":"c","FlagRunning":"c","FlagUp":"c","Flags":"t","Flags.String":"m","HardwareAddr":"t","HardwareAddr.String":"m","IP":"t","IP.AppendText":"m","IP.DefaultMask":"m","IP.Equal":"m","IP.IsGlobalUnicast":"m","IP.IsInterfaceLocalMulticast":"m","IP.IsLinkLocalMulticast":"m","IP.IsLinkLocalUnicast":"m","IP.IsLoopback":"m","IP.IsMulticast":"m","IP.IsPrivate":"m","IP.IsUnspecified":"m","IP.MarshalText":"m","IP.Mask":"m","IP.String":"m","IP.To16":"m","IP.To4":"m","IP.UnmarshalText":"m","IPAddr":"t","IPAddr.Network":"m","IPAddr.String":"m","IPConn":"t","IPConn.ReadFrom":"m","IPConn.ReadFromIP":"m","IPConn.ReadMsgIP":"m","IPConn.SyscallConn":"m","IPConn.WriteMsgIP":"m","IPConn.WriteTo":"m","IPConn.WriteToIP":"m","IPMask":"t","IPMask.Size":"m","IPMask.String":"m","IPNet":"t","IPNet.Contains":"m","IPNet.Network":"m","IPNet.String":"m","IPv4":"f","IPv4Mask":"f","IPv4allrouter":"v","IPv4allsys":"v","IPv4bcast":"v","IPv4len":"c","IPv4zero":"v","IPv6interfacelocalallnodes":"v","IPv6len":"c","IPv6linklocalallnodes":"v","IPv6linklocalallrouters":"v","IPv6loopback":"v","IPv6unspecified":"v","IPv6zero":"v","Interface":"t","Interface.Addrs":"m","Interface.MulticastAddrs":"m","InterfaceAddrs":"f","InterfaceByIndex":"f","InterfaceByName":"f","Interfaces":"f","InvalidAddrError":"t","InvalidAddrError.Error":"m","InvalidAddrError.Temporary":"m","InvalidAddrError.Timeout":"m","JoinHostPort":"f","KeepAliveConfig":"t","Listen":"f","ListenConfig":"t","ListenConfig.Listen":"m","ListenConfig.ListenPacket":"m","ListenConfig.MultipathTCP":"m","ListenConfig.SetMultipathTCP":"m","ListenIP":"f","ListenMulticastUDP":"f","ListenPacket":"f","ListenTCP":"f","ListenUDP":"f","ListenUnix":"f","ListenUnixgram":"f","Listener":"t","LookupAddr":"f","LookupCNAME":"f","LookupHost":"f","LookupIP":"f","LookupMX":"f","LookupNS":"f","LookupPort":"f","LookupSRV":"f","LookupTXT":"f","MX":"t","NS":"t","OpError":"t","OpError.Error":"m","OpError.Temporary":"m","OpError.Timeout":"m","OpError.Unwrap":"m","PacketConn":"t","ParseCIDR":"f","ParseError":"t","ParseError.Error":"m","ParseError.Temporary":"m","ParseError.Timeout":"m","ParseIP":"f","ParseMAC":"f","Pipe":"f","ResolveIPAddr":"f","ResolveTCPAddr":"f","ResolveUDPAddr":"f","ResolveUnixAddr":"f","Resolver":"t","Resolver.LookupAddr":"m","Resolver.LookupCNAME":"m","Resolver.LookupHost":"m","Resolver.LookupIP":"m","Resolver.LookupIPAddr":"m","Resolver.LookupMX":"m","Resolver.LookupNS":"m","Resolver.LookupNetIP":"m","Resolver.LookupPort":"m","Resolver.LookupSRV":"m","Resolver.LookupTXT":"m","SRV":"t","SplitHostPort":"f","TCPAddr":"t","TCPAddr.AddrPort":"m","TCPAddr.Network":"m","TCPAddr.String":"m","TCPAddrFromAddrPort":"f","TCPConn":"t","TCPConn.CloseRead":"m","TCPConn.CloseWrite":"m","TCPConn.MultipathTCP":"m","TCPConn.ReadFrom":"m","TCPConn.SetKeepAlive":"m","TCPConn.SetKeepAliveConfig":"m","TCPConn.SetKeepAlivePeriod":"m","TCPConn.SetLinger":"m","TCPConn.SetNoDelay":"m","TCPConn.SyscallConn":"m","TCPConn.WriteTo":"m","TCPListener":"t","TCPListener.Accept":"m","TCPListener.AcceptTCP":"m","TCPListener.Addr":"m","TCPListener.Close":"m","TCPListener.File":"m","TCPListener.SetDeadline":"m","TCPListener.SyscallConn":"m","UDPAddr":"t","UDPAddr.AddrPort":"m","UDPAddr.Network":"m","UDPAddr.String":"m","UDPAddrFromAddrPort":"f","UDPConn":"t","UDPConn.ReadFrom":"m","UDPConn.ReadFromUDP":"m","UDPConn.ReadFromUDPAddrPort":"m","UDPConn.ReadMsgUDP":"m","UDPConn.ReadMsgUDPAddrPort":"m","UDPConn.SyscallConn":"m","UDPConn.WriteMsgUDP":"m","UDPConn.WriteMsgUDPAddrPort":"m","UDPConn.WriteTo":"m","UDPConn.WriteToUDP":"m","UDPConn.WriteToUDPAddrPort":"m","UnixAddr":"t","UnixAddr.Network":"m","UnixAddr.String":"m","UnixConn":"t","UnixConn.CloseRead":"m","UnixConn.CloseWrite":"m","UnixConn.ReadFrom":"m","UnixConn.ReadFromUnix":"m","UnixConn.ReadMsgUnix":"m","UnixConn.SyscallConn":"m","UnixConn.WriteMsgUnix":"m","UnixConn.WriteTo":"m","UnixConn.WriteToUnix":"m","UnixListener":"t","UnixListener.Accept":"m","UnixListener.AcceptUnix":"m","UnixListener.Addr":"m","UnixListener.Close":"m","UnixListener.File":"m","UnixListener.SetDeadline":"m","UnixListener.SetUnlinkOnClose":"m","UnixListener.SyscallConn":"m","UnknownNetworkError":"t","UnknownNetworkError.Error":"m","UnknownNetworkError.Temporary":"m","UnknownNetworkError.Timeout":"m"}},"net/http":{"path":"net/http","name":"http","symbols":{"AllowQuerySemicolons":"f","CanonicalHeaderKey":"f","Client":"t","Client.CloseIdleConnections":"m","Client.Do":"m","Client.Get":"m","Client.Head":"m","Client.Post":"m","Client.PostForm":"m","ClientConn":"t","ClientConn.Available":"m","ClientConn.Close":"m","ClientConn.Err":"m","ClientConn.InFlight":"m","ClientConn.Release":"m","ClientConn.Reserve":"m","ClientConn.RoundTrip":"m","ClientConn.SetStateHook":"m","CloseNotifier":"t","ConnState":"t","ConnState.String":"m","Cookie":"t","Cookie.String":"m","Cookie.Valid":"m","CookieJar":"t","CrossOriginProtection":"t","CrossOriginProtection.AddInsecureBypassPattern":"m","CrossOriginProtection.AddTrustedOrigin":"m","CrossOriginProtection.Check":"m","CrossOriginProtection.Handler":"m","CrossOriginProtection.SetDenyHandler":"m","DefaultClient":"v","DefaultMaxHeaderBytes":"c","DefaultMaxIdleConnsPerHost":"c","DefaultServeMux":"v","DefaultTransport":"v","DetectContentType":"f","Dir":"t","Dir.Open":"m","ErrAbortHandler":"v","ErrBodyNotAllowed":"v","ErrBodyReadAfterClose":"v","ErrContentLength":"v","ErrHandlerTimeout":"v","ErrHeaderTooLong":"v","ErrHijacked":"v","ErrLineTooLong":"v","ErrMissingBoundary":"v","ErrMissingContentLength":"v","ErrMissingFile":"v","ErrNoCookie":"v","ErrNoLocation":"v","ErrNotMultipart":"v","ErrNotSupported":"v","ErrSchemeMismatch":"v","ErrServerClosed":"v","ErrShortBody":"v","ErrSkipAltProtocol":"v","ErrUnexpectedTrailer":"v","ErrUseLastResponse":"v","ErrWriteAfterFlush":"v","Error":"f","FS":"f","File":"t","FileServer":"f","FileServerFS":"f","FileSystem":"t","Flusher":"t","Get":"f","HTTP2Config":"t","Handle":"f","HandleFunc":"f","Handler":"t","HandlerFunc":"t","HandlerFunc.ServeHTTP":"m","Head":"f","Header":"t","Header.Add":"m","Header.Clone":"m","Header.Del":"m","Header.Get":"m","Header.Set":"m","Header.Values":"m","Header.Write":"m","Header.WriteSubset":"m","Hijacker":"t","ListenAndServe":"f","ListenAndServeTLS":"f","LocalAddrContextKey":"v","MaxBytesError":"t","MaxBytesError.Error":"m","MaxBytesHandler":"f","MaxBytesReader":"f","MethodConnect":"c","MethodDelete":"c","MethodGet":"c","MethodHead":"c","MethodOptions":"c","MethodPatch":"c","MethodPost":"c","MethodPut":"c","MethodTrace":"c","NewCrossOriginProtection":"f","NewFileTransport":"f","NewFileTransportFS":"f","NewRequest":"f","NewRequestWithContext":"f","NewResponseController":"f","NewServeMux":"f","NoBody":"v","NotFound":"f","NotFoundHandler":"f","ParseCookie":"f","ParseHTTPVersion":"f","ParseSetCookie":"f","ParseTime":"f","Post":"f","PostForm":"f","ProtocolError":"t","ProtocolError.Error":"m","ProtocolError.Is":"m","Protocols":"t","Protocols.HTTP1":"m","Protocols.HTTP2":"m","Protocols.SetHTTP1":"m","Protocols.SetHTTP2":"m","Protocols.SetUnencryptedHTTP2":"m","Protocols.String":"m","Protocols.UnencryptedHTTP2":"m","ProxyFromEnvironment":"f","ProxyURL":"f","PushOptions":"t","Pusher":"t","ReadRequest":"f","ReadResponse":"f","Redirect":"f","RedirectHandler":"f","Request":"t","Request.AddCookie":"m","Request.BasicAuth":"m","Request.Clone":"m","Request.Context":"m","Request.Cookie":"m","Request.Cookies":"m","Request.CookiesNamed":"m","Request.FormFile":"m","Request.FormValue":"m","Request.MultipartReader":"m","Request.ParseForm":"m","Request.ParseMultipartForm":"m","Request.PathValue":"m","Request.PostFormValue":"m","Request.ProtoAtLeast":"m","Request.Referer":"m","Request.SetBasicAuth":"m","Request.SetPathValue":"m","Request.UserAgent":"m","Request.WithContext":"m","Request.Write":"m","Request.WriteProxy":"m","Response":"t","Response.Cookies":"m","Response.Location":"m","Response.ProtoAtLeast":"m","Response.Write":"m","ResponseController":"t","ResponseController.EnableFullDuplex":"m","ResponseController.Flush":"m","ResponseController.Hijack":"m","ResponseController.SetReadDeadline":"m","ResponseController.SetWriteDeadline":"m","ResponseWriter":"t","RoundTripper":"t","SameSite":"t","SameSiteDefaultMode":"c","SameSiteLaxMode":"c","SameSiteNoneMode":"c","SameSiteStrictMode":"c","Serve":"f","ServeContent":"f","ServeFile":"f","ServeFileFS":"f","ServeMux":"t","ServeMux.Handle":"m","ServeMux.HandleFunc":"m","ServeMux.Handler":"m","ServeMux.ServeHTTP":"m","ServeTLS":"f","Server":"t","Server.Close":"m","Server.ListenAndServe":"m","Server.ListenAndServeTLS":"m","Server.RegisterOnShutdown":"m","Server.Serve":"m","Server.ServeTLS":"m","Server.SetKeepAlivesEnabled":"m","Server.Shutdown":"m","ServerContextKey":"v","SetCookie":"f","StateActive":"c","StateClosed":"c","StateHijacked":"c","StateIdle":"c","StateNew":"c","StatusAccepted":"c","StatusAlreadyReported":"c","StatusBadGateway":"c","StatusBadRequest":"c","StatusConflict":"c","StatusContinue":"c","StatusCreated":"c","StatusEarlyHints":"c","StatusExpectationFailed":"c","StatusFailedDependency":"c","StatusForbidden":"c","StatusFound":"c","StatusGatewayTimeout":"c","StatusGone":"c","StatusHTTPVersionNotSupported":"c","StatusIMUsed":"c","StatusInsufficientStorage":"c","StatusInternalServerError":"c","StatusLengthRequired":"c","StatusLocked":"c","StatusLoopDetected":"c","StatusMethodNotAllowed":"c","StatusMisdirectedRequest":"c","StatusMovedPermanently":"c","StatusMultiStatus":"c","StatusMultipleChoices":"c","StatusNetworkAuthenticationRequired":"c","StatusNoContent":"c","StatusNonAuthoritativeInfo":"c","StatusNotAcceptable":"c","StatusNotExtended":"c","StatusNotFound":"c","StatusNotImplemented":"c","StatusNotModified":"c","StatusOK":"c","StatusPartialContent":"c","StatusPaymentRequired":"c","StatusPermanentRedirect":"c","StatusPreconditionFailed":"c","StatusPreconditionRequired":"c","StatusProcessing":"c","StatusProxyAuthRequired":"c","StatusRequestEntityTooLarge":"c","StatusRequestHeaderFieldsTooLarge":"c","StatusRequestTimeout":"c","StatusRequestURITooLong":"c","StatusRequestedRangeNotSatisfiable":"c","StatusResetContent":"c","StatusSeeOther":"c","StatusServiceUnavailable":"c","StatusSwitchingProtocols":"c","StatusTeapot":"c","StatusTemporaryRedirect":"c","StatusText":"f","StatusTooEarly":"c","StatusTooManyRequests":"c","StatusUnauthorized":"c","StatusUnavailableForLegalReasons":"c","StatusUnprocessableEntity":"c","StatusUnsupportedMediaType":"c","StatusUpgradeRequired":"c","StatusUseProxy":"c","StatusVariantAlsoNegotiates":"c","StripPrefix":"f","TimeFormat":"c","TimeoutHandler":"f","TrailerPrefix":"c","Transport":"t","Transport.CancelRequest":"m","Transport.Clone":"m","Transport.CloseIdleConnections":"m","Transport.NewClientConn":"m","Transport.RegisterProtocol":"m","Transport.RoundTrip":"m"}},"net/http/cgi":{"path":"net/http/cgi","name":"cgi","symbols":{"Handler":"t","Handler.ServeHTTP":"m","Request":"f","RequestFromMap":"f","Serve":"f"}},"net/http/cookiejar":{"path":"net/http/cookiejar","name":"cookiejar","symbols":{"Jar":"t","Jar.Cookies":"m","Jar.SetCookies":"m","New":"f","Options":"t","PublicSuffixList":"t"}},"net/http/fcgi":{"path":"net/http/fcgi","name":"fcgi","symbols":{"ErrConnClosed":"v","ErrRequestAborted":"v","ProcessEnv":"f","Serve":"f"}},"net/http/httptest":{"path":"net/http/httptest","name":"httptest","symbols":{"DefaultRemoteAddr":"c","NewRecorder":"f","NewRequest":"f","NewRequestWithContext":"f","NewServer":"f","NewTLSServer":"f","NewUnstartedServer":"f","ResponseRecorder":"t","ResponseRecorder.Flush":"m","ResponseRecorder.Header":"m","ResponseRecorder.Result":"m","ResponseRecorder.Write":"m","ResponseRecorder.WriteHeader":"m","ResponseRecorder.WriteString":"m","Server":"t","Server.Certificate":"m","Server.Client":"m","Server.Close":"m","Server.CloseClientConnections":"m","Server.Start":"m","Server.StartTLS":"m"}},"net/http/httptrace":{"path":"net/http/httptrace","name":"httptrace","symbols":{"ClientTrace":"t","ContextClientTrace":"f","DNSDoneInfo":"t","DNSStartInfo":"t","GotConnInfo":"t","WithClientTrace":"f","WroteRequestInfo":"t"}},"net/http/httputil":{"path":"net/http/httputil","name":"httputil","symbols":{"BufferPool":"t","ClientConn":"t","ClientConn.Close":"m","ClientConn.Do":"m","ClientConn.Hijack":"m","ClientConn.Pending":"m","ClientConn.Read":"m","ClientConn.Write":"m","DumpRequest":"f","DumpRequestOut":"f","DumpResponse":"f","ErrClosed":"v","ErrLineTooLong":"v","ErrPersistEOF":"v","ErrPipeline":"v","NewChunkedReader":"f","NewChunkedWriter":"f","NewClientConn":"f","NewProxyClientConn":"f","NewServerConn":"f","NewSingleHostReverseProxy":"f","ProxyRequest":"t","ProxyRequest.SetURL":"m","ProxyRequest.SetXForwarded":"m","ReverseProxy":"t","ReverseProxy.ServeHTTP":"m","ServerConn":"t","ServerConn.Close":"m","ServerConn.Hijack":"m","ServerConn.Pending":"m","ServerConn.Read":"m","ServerConn.Write":"m"}},"net/http/pprof":{"path":"net/http/pprof","name":"pprof","symbols":{"Cmdline":"f","Handler":"f","Index":"f","Profile":"f","Symbol":"f","Trace":"f"}},"net/mail":{"path":"net/mail","name":"mail","symbols":{"Address":"t","Address.String":"m","AddressParser":"t","AddressParser.Parse":"m","AddressParser.ParseList":"m","ErrHeaderNotPresent":"v","Header":"t","Header.AddressList":"m","Header.Date":"m","Header.Get":"m","Message":"t","ParseAddress":"f","ParseAddressList":"f","ParseDate":"f","ReadMessage":"f"}},"net/netip":{"path":"net/netip","name":"netip","symbols":{"Addr":"t","Addr.AppendBinary":"m","Addr.AppendText":"m","Addr.AppendTo":"m","Addr.As16":"m","Addr.As4":"m","Addr.AsSlice":"m","Addr.BitLen":"m","Addr.Compare":"m","Addr.Is4":"m","Addr.Is4In6":"m","Addr.Is6":"m","Addr.IsGlobalUnicast":"m","Addr.IsInterfaceLocalMulticast":"m","Addr.IsLinkLocalMulticast":"m","Addr.IsLinkLocalUnicast":"m","Addr.IsLoopback":"m","Addr.IsMulticast":"m","Addr.IsPrivate":"m","Addr.IsUnspecified":"m","Addr.IsValid":"m","Addr.Less":"m","Addr.MarshalBinary":"m","Addr.MarshalText":"m","Addr.Next":"m","Addr.Prefix":"m","Addr.Prev":"m","Addr.String":"m","Addr.StringExpanded":"m","Addr.Unmap":"m","Addr.UnmarshalBinary":"m","Addr.UnmarshalText":"m","Addr.WithZone":"m","Addr.Zone":"m","AddrFrom16":"f","AddrFrom4":"f","AddrFromSlice":"f","AddrPort":"t","AddrPort.Addr":"m","AddrPort.AppendBinary":"m","AddrPort.AppendText":"m","AddrPort.AppendTo":"m","AddrPort.Compare":"m","AddrPort.IsValid":"m","AddrPort.MarshalBinary":"m","AddrPort.MarshalText":"m","AddrPort.Port":"m","AddrPort.String":"m","AddrPort.UnmarshalBinary":"m","AddrPort.UnmarshalText":"m","AddrPortFrom":"f","IPv4Unspecified":"f","IPv6LinkLocalAllNodes":"f","IPv6LinkLocalAllRouters":"f","IPv6Loopback":"f","IPv6Unspecified":"f","MustParseAddr":"f","MustParseAddrPort":"f","MustParsePrefix":"f","ParseAddr":"f","ParseAddrPort":"f","ParsePrefix":"f","Prefix":"t","Prefix.Addr":"m","Prefix.AppendBinary":"m","Prefix.AppendText":"m","Prefix.AppendTo":"m","Prefix.Bits":"m","Prefix.Compare":"m","Prefix.Contains":"m","Prefix.IsSingleIP":"m","Prefix.IsValid":"m","Prefix.MarshalBinary":"m","Prefix.MarshalText":"m","Prefix.Masked":"m","Prefix.Overlaps":"m","Prefix.String":"m","Prefix.UnmarshalBinary":"m","Prefix.UnmarshalText":"m","PrefixFrom":"f"}},"net/rpc":{"path":"net/rpc","name":"rpc","symbols":{"Accept":"f","Call":"t","Client":"t","Client.Call":"m","Client.Close":"m","Client.Go":"m","ClientCodec":"t","DefaultDebugPath":"c","DefaultRPCPath":"c","DefaultServer":"v","Dial":"f","DialHTTP":"f","DialHTTPPath":"f","ErrShutdown":"v","HandleHTTP":"f","NewClient":"f","NewClientWithCodec":"f","NewServer":"f","Register":"f","RegisterName":"f","Request":"t","Response":"t","ServeCodec":"f","ServeConn":"f","ServeRequest":"f","Server":"t","Server.Accept":"m","Server.HandleHTTP":"m","Server.Register":"m","Server.RegisterName":"m","Server.ServeCodec":"m","Server.ServeConn":"m","Server.ServeHTTP":"m","Server.ServeRequest":"m","ServerCodec":"t","ServerError":"t","ServerError.Error":"m"}},"net/rpc/jsonrpc":{"path":"net/rpc/jsonrpc","name":"jsonrpc","symbols":{"Dial":"f","NewClient":"f","NewClientCodec":"f","NewServerCodec":"f","ServeConn":"f"}},"net/smtp":{"path":"net/smtp","name":"smtp","symbols":{"Auth":"t","CRAMMD5Auth":"f","Client":"t","Client.Auth":"m","Client.Close":"m","Client.Data":"m","Client.Extension":"m","Client.Hello":"m","Client.Mail":"m","Client.Noop":"m","Client.Quit":"m","Client.Rcpt":"m","Client.Reset":"m","Client.StartTLS":"m","Client.TLSConnectionState":"m","Client.Verify":"m","Dial":"f","NewClient":"f","PlainAuth":"f","SendMail":"f","ServerInfo":"t"}},"net/textproto":{"path":"net/textproto","name":"textproto","symbols":{"CanonicalMIMEHeaderKey":"f","Conn":"t","Conn.Close":"m","Conn.Cmd":"m","Dial":"f","Error":"t","Error.Error":"m","MIMEHeader":"t","MIMEHeader.Add":"m","MIMEHeader.Del":"m","MIMEHeader.Get":"m","MIMEHeader.Set":"m","MIMEHeader.Values":"m","NewConn":"f","NewReader":"f","NewWriter":"f","Pipeline":"t","Pipeline.EndRequest":"m","Pipeline.EndResponse":"m","Pipeline.Next":"m","Pipeline.StartRequest":"m","Pipeline.StartResponse":"m","ProtocolError":"t","ProtocolError.Error":"m","Reader":"t","Reader.DotReader":"m","Reader.ReadCodeLine":"m","Reader.ReadContinuedLine":"m","Reader.ReadContinuedLineBytes":"m","Reader.ReadDotBytes":"m","Reader.ReadDotLines":"m","Reader.ReadLine":"m","Reader.ReadLineBytes":"m","Reader.ReadMIMEHeader":"m","Reader.ReadResponse":"m","TrimBytes":"f","TrimString":"f","Writer":"t","Writer.DotWriter":"m","Writer.PrintfLine":"m"}},"net/url":{"path":"net/url","name":"url","symbols":{"Error":"t","Error.Error":"m","Error.Temporary":"m","Error.Timeout":"m","Error.Unwrap":"m","EscapeError":"t","EscapeError.Error":"m","InvalidHostError":"t","InvalidHostError.Error":"m","JoinPath":"f","Parse":"f","ParseQuery":"f","ParseRequestURI":"f","PathEscape":"f","PathUnescape":"f","QueryEscape":"f","QueryUnescape":"f","URL":"t","URL.AppendBinary":"m","URL.EscapedFragment":"m","URL.EscapedPath":"m","URL.Hostname":"m","URL.IsAbs":"m","URL.JoinPath":"m","URL.MarshalBinary":"m","URL.Parse":"m","URL.Port":"m","URL.Query":"m","URL.Redacted":"m","URL.RequestURI":"m","URL.ResolveReference":"m","URL.String":"m","URL.UnmarshalBinary":"m","User":"f","UserPassword":"f","Userinfo":"t","Userinfo.Password":"m","Userinfo.String":"m","Userinfo.Username":"m","Values":"t","Values.Add":"m","Values.Del":"m","Values.Encode":"m","Values.Get":"m","Values.Has":"m","Values.Set":"m"}},"os":{"path":"os","name":"os","symbols":{"Args":"v","Chdir":"f","Chmod":"f","Chown":"f","Chtimes":"f","Clearenv":"f","CopyFS":"f","Create":"f","CreateTemp":"f","DevNull":"c","DirEntry":"t","DirFS":"f","Environ":"f","ErrClosed":"v","ErrDeadlineExceeded":"v","ErrExist":"v","ErrInvalid":"v","ErrNoDeadline":"v","ErrNoHandle":"v","ErrNotExist":"v","ErrPermission":"v","ErrProcessDone":"v","Executable":"f","Exit":"f","Expand":"f","ExpandEnv":"f","File":"t","File.Chdir":"m","File.Chmod":"m","File.Chown":"m","File.Close":"m","File.Fd":"m","File.Name":"m","File.Read":"m","File.ReadAt":"m","File.ReadDir":"m","File.ReadFrom":"m","File.Readdir":"m","File.Readdirnames":"m","File.Seek":"m","File.SetDeadline":"m","File.SetReadDeadline":"m","File.SetWriteDeadline":"m","File.Stat":"m","File.Sync":"m","File.SyscallConn":"m","File.Truncate":"m","File.Write":"m","File.WriteAt":"m","File.WriteString":"m","File.WriteTo":"m","FileInfo":"t","FileMode":"t","FindProcess":"f","Getegid":"f","Getenv":"f","Geteuid":"f","Getgid":"f","Getgroups":"f","Getpagesize":"f","Getpid":"f","Getppid":"f","Getuid":"f","Getwd":"f","Hostname":"f","Interrupt":"v","IsExist":"f","IsNotExist":"f","IsPathSeparator":"f","IsPermission":"f","IsTimeout":"f","Kill":"v","Lchown":"f","Link":"f","LinkError":"t","LinkError.Error":"m","LinkError.Unwrap":"m","LookupEnv":"f","Lstat":"f","Mkdir":"f","MkdirAll":"f","MkdirTemp":"f","ModeAppend":"c","ModeCharDevice":"c","ModeDevice":"c","ModeDir":"c","ModeExclusive":"c","ModeIrregular":"c","ModeNamedPipe":"c","ModePerm":"c","ModeSetgid":"c","ModeSetuid":"c","ModeSocket":"c","ModeSticky":"c","ModeSymlink":"c","ModeTemporary":"c","ModeType":"c","NewFile":"f","NewSyscallError":"f","O_APPEND":"c","O_CREATE":"c","O_EXCL":"c","O_RDONLY":"c","O_RDWR":"c","O_SYNC":"c","O_TRUNC":"c","O_WRONLY":"c","Open":"f","OpenFile":"f","OpenInRoot":"f","OpenRoot":"f","PathError":"t","PathListSeparator":"c","PathSeparator":"c","Pipe":"f","ProcAttr":"t","Process":"t","Process.Kill":"m","Process.Release":"m","Process.Signal":"m","Process.Wait":"m","Process.WithHandle":"m","ProcessState":"t","ProcessState.ExitCode":"m","ProcessState.Exited":"m","ProcessState.Pid":"m","ProcessState.String":"m","ProcessState.Success":"m","ProcessState.Sys":"m","ProcessState.SysUsage":"m","ProcessState.SystemTime":"m","ProcessState.UserTime":"m","ReadDir":"f","ReadFile":"f","Readlink":"f","Remove":"f","RemoveAll":"f","Rename":"f","Root":"t","Root.Chmod":"m","Root.Chown":"m","Root.Chtimes":"m","Root.Close":"m","Root.Create":"m","Root.FS":"m","Root.Lchown":"m","Root.Link":"m","Root.Lstat":"m","Root.Mkdir":"m","Root.MkdirAll":"m","Root.Name":"m","Root.Open":"m","Root.OpenFile":"m","Root.OpenRoot":"m","Root.ReadFile":"m","Root.Readlink":"m","Root.Remove":"m","Root.RemoveAll":"m","Root.Rename":"m","Root.Stat":"m","Root.Symlink":"m","Root.WriteFile":"m","SEEK_CUR":"c","SEEK_END":"c","SEEK_SET":"c","SameFile":"f","Setenv":"f","Signal":"t","StartProcess":"f","Stat":"f","Stderr":"v","Stdin":"v","Stdout":"v","Symlink":"f","SyscallError":"t","SyscallError.Error":"m","SyscallError.Timeout":"m","SyscallError.Unwrap":"m","TempDir":"f","Truncate":"f","Unsetenv":"f","UserCacheDir":"f","UserConfigDir":"f","UserHomeDir":"f","WriteFile":"f"}},"os/exec":{"path":"os/exec","name":"exec","symbols":{"Cmd":"t","Cmd.CombinedOutput":"m","Cmd.Environ":"m","Cmd.Output":"m","Cmd.Run":"m","Cmd.Start":"m","Cmd.StderrPipe":"m","Cmd.StdinPipe":"m","Cmd.StdoutPipe":"m","Cmd.String":"m","Cmd.Wait":"m","Command":"f","CommandContext":"f","ErrDot":"v","ErrNotFound":"v","ErrWaitDelay":"v","Error":"t","Error.Error":"m","Error.Unwrap":"m","ExitError":"t","ExitError.Error":"m","LookPath":"f"}},"os/signal":{"path":"os/signal","name":"signal","symbols":{"Ignore":"f","Ignored":"f","Notify":"f","NotifyContext":"f","Reset":"f","Stop":"f"}},"os/user":{"path":"os/user","name":"user","symbols":{"Current":"f","Group":"t","Lookup":"f","LookupGroup":"f","LookupGroupId":"f","LookupId":"f","UnknownGroupError":"t","UnknownGroupError.Error":"m","UnknownGroupIdError":"t","UnknownGroupIdError.Error":"m","UnknownUserError":"t","UnknownUserError.Error":"m","UnknownUserIdError":"t","UnknownUserIdError.Error":"m","User":"t","User.GroupIds":"m"}},"path":{"path":"path","name":"path","symbols":{"Base":"f","Clean":"f","Dir":"f","ErrBadPattern":"v","Ext":"f","IsAbs":"f","Join":"f","Match":"f","Split":"f"}},"path/filepath":{"path":"path/filepath","name":"filepath","symbols":{"Abs":"f","Base":"f","Clean":"f","Dir":"f","ErrBadPattern":"v","EvalSymlinks":"f","Ext":"f","FromSlash":"f","Glob":"f","HasPrefix":"f","IsAbs":"f","IsLocal":"f","Join":"f","ListSeparator":"c","Localize":"f","Match":"f","Rel":"f","Separator":"c","SkipAll":"v","SkipDir":"v","Split":"f","SplitList":"f","ToSlash":"f","VolumeName":"f","Walk":"f","WalkDir":"f","WalkFunc":"t"}},"plugin":{"path":"plugin","name":"plugin","symbols":{"Open":"f","Plugin":"t","Plugin.Lookup":"m","Symbol":"t"}},"reflect":{"path":"reflect","name":"reflect","symbols":{"Append":"f","AppendSlice":"f","Array":"c","ArrayOf":"f","Bool":"c","BothDir":"c","Chan":"c","ChanDir":"t","ChanDir.String":"m","ChanOf":"f","Complex128":"c","Complex64":"c","Copy":"f","DeepEqual":"f","Float32":"c","Float64":"c","Func":"c","FuncOf":"f","Indirect":"f","Int":"c","Int16":"c","Int32":"c","Int64":"c","Int8":"c","Interface":"c","Invalid":"c","Kind":"t","Kind.String":"m","MakeChan":"f","MakeFunc":"f","MakeMap":"f","MakeMapWithSize":"f","MakeSlice":"f","Map":"c","MapIter":"t","MapIter.Key":"m","MapIter.Next":"m","MapIter.Reset":"m","MapIter.Value":"m","MapOf":"f","Method":"t","Method.IsExported":"m","New":"f","NewAt":"f","Pointer":"c","PointerTo":"f","Ptr":"c","PtrTo":"f","RecvDir":"c","Select":"f","SelectCase":"t","SelectDefault":"c","SelectDir":"t","SelectRecv":"c","SelectSend":"c","SendDir":"c","Slice":"c","SliceAt":"f","SliceHeader":"t","SliceOf":"f","String":"c","StringHeader":"t","Struct":"c","StructField":"t","StructField.IsExported":"m","StructOf":"f","StructTag":"t","StructTag.Get":"m","StructTag.Lookup":"m","Swapper":"f","Type":"t","TypeAssert":"f","TypeFor":"f","TypeOf":"f","Uint":"c","Uint16":"c","Uint32":"c","Uint64":"c","Uint8":"c","Uintptr":"c","UnsafePointer":"c","Value":"t","Value.Addr":"m","Value.Bool":"m","Value.Bytes":"m","Value.Call":"m","Value.CallSlice":"m","Value.CanAddr":"m","Value.CanComplex":"m","Value.CanConvert":"m","Value.CanFloat":"m","Value.CanInt":"m","Value.CanInterface":"m","Value.CanSet":"m","Value.CanUint":"m","Value.Cap":"m","Value.Clear":"m","Value.Close":"m","Value.Comparable":"m","Value.Complex":"m","Value.Convert":"m","Value.Elem":"m","Value.Equal":"m","Value.Field":"m","Value.FieldByIndex":"m","Value.FieldByIndexErr":"m","Value.FieldByName":"m","Value.FieldByNameFunc":"m","Value.Fields":"m","Value.Float":"m","Value.Grow":"m","Value.Index":"m","Value.Int":"m","Value.Interface":"m","Value.InterfaceData":"m","Value.IsNil":"m","Value.IsValid":"m","Value.IsZero":"m","Value.Kind":"m","Value.Len":"m","Value.MapIndex":"m","Value.MapKeys":"m","Value.MapRange":"m","Value.Method":"m","Value.MethodByName":"m","Value.Methods":"m","Value.NumField":"m","Value.NumMethod":"m","Value.OverflowComplex":"m","Value.OverflowFloat":"m","Value.OverflowInt":"m","Value.OverflowUint":"m","Value.Pointer":"m","Value.Recv":"m","Value.Send":"m","Value.Seq":"m","Value.Seq2":"m","Value.Set":"m","Value.SetBool":"m","Value.SetBytes":"m","Value.SetCap":"m","Value.SetComplex":"m","Value.SetFloat":"m","Value.SetInt":"m","Value.SetIterKey":"m","Value.SetIterValue":"m","Value.SetLen":"m","Value.SetMapIndex":"m","Value.SetPointer":"m","Value.SetString":"m","Value.SetUint":"m","Value.SetZero":"m","Value.Slice":"m","Value.Slice3":"m","Value.String":"m","Value.TryRecv":"m","Value.TrySend":"m","Value.Type":"m","Value.Uint":"m","Value.UnsafeAddr":"m","Value.UnsafePointer":"m","ValueError":"t","ValueError.Error":"m","ValueOf":"f","VisibleFields":"f","Zero":"f"}},"regexp":{"path":"regexp","name":"regexp","symbols":{"Compile":"f","CompilePOSIX":"f","Match":"f","MatchReader":"f","MatchString":"f","MustCompile":"f","MustCompilePOSIX":"f","QuoteMeta":"f","Regexp":"t","Regexp.AppendText":"m","Regexp.Copy":"m","Regexp.Expand":"m","Regexp.ExpandString":"m","Regexp.Find":"m","Regexp.FindAll":"m","Regexp.FindAllIndex":"m","Regexp.FindAllString":"m","Regexp.FindAllStringIndex":"m","Regexp.FindAllStringSubmatch":"m","Regexp.FindAllStringSubmatchIndex":"m","Regexp.FindAllSubmatch":"m","Regexp.FindAllSubmatchIndex":"m","Regexp.FindIndex":"m","Regexp.FindReaderIndex":"m","Regexp.FindReaderSubmatchIndex":"m","Regexp.FindString":"m","Regexp.FindStringIndex":"m","Regexp.FindStringSubmatch":"m","Regexp.FindStringSubmatchIndex":"m","Regexp.FindSubmatch":"m","Regexp.FindSubmatchIndex":"m","Regexp.LiteralPrefix":"m","Regexp.Longest":"m","Regexp.MarshalText":"m","Regexp.Match":"m","Regexp.MatchReader":"m","Regexp.MatchString":"m","Regexp.NumSubexp":"m","Regexp.ReplaceAll":"m","Regexp.ReplaceAllFunc":"m","Regexp.ReplaceAllLiteral":"m","Regexp.ReplaceAllLiteralString":"m","Regexp.ReplaceAllString":"m","Regexp.ReplaceAllStringFunc":"m","Regexp.Split":"m","Regexp.String":"m","Regexp.SubexpIndex":"m","Regexp.SubexpNames":"m","Regexp.UnmarshalText":"m"}},"regexp/syntax":{"path":"regexp/syntax","name":"syntax","symbols":{"ClassNL":"c","Compile":"f","DotNL":"c","EmptyBeginLine":"c","EmptyBeginText":"c","EmptyEndLine":"c","EmptyEndText":"c","EmptyNoWordBoundary":"c","EmptyOp":"t","EmptyOpContext":"f","EmptyWordBoundary":"c","ErrInternalError":"c","ErrInvalidCharClass":"c","ErrInvalidCharRange":"c","ErrInvalidEscape":"c","ErrInvalidNamedCapture":"c","ErrInvalidPerlOp":"c","ErrInvalidRepeatOp":"c","ErrInvalidRepeatSize":"c","ErrInvalidUTF8":"c","ErrLarge":"c","ErrMissingBracket":"c","ErrMissingParen":"c","ErrMissingRepeatArgument":"c","ErrNestingDepth":"c","ErrTrailingBackslash":"c","ErrUnexpectedParen":"c","Error":"t","Error.Error":"m","ErrorCode":"t","ErrorCode.String":"m","Flags":"t","FoldCase":"c","Inst":"t","Inst.MatchEmptyWidth":"m","Inst.MatchRune":"m","Inst.MatchRunePos":"m","Inst.String":"m","InstAlt":"c","InstAltMatch":"c","InstCapture":"c","InstEmptyWidth":"c","InstFail":"c","InstMatch":"c","InstNop":"c","InstOp":"t","InstOp.String":"m","InstRune":"c","InstRune1":"c","InstRuneAny":"c","InstRuneAnyNotNL":"c","IsWordChar":"f","Literal":"c","MatchNL":"c","NonGreedy":"c","OneLine":"c","Op":"t","Op.String":"m","OpAlternate":"c","OpAnyChar":"c","OpAnyCharNotNL":"c","OpBeginLine":"c","OpBeginText":"c","OpCapture":"c","OpCharClass":"c","OpConcat":"c","OpEmptyMatch":"c","OpEndLine":"c","OpEndText":"c","OpLiteral":"c","OpNoMatch":"c","OpNoWordBoundary":"c","OpPlus":"c","OpQuest":"c","OpRepeat":"c","OpStar":"c","OpWordBoundary":"c","POSIX":"c","Parse":"f","Perl":"c","PerlX":"c","Prog":"t","Prog.Prefix":"m","Prog.StartCond":"m","Prog.String":"m","Regexp":"t","Regexp.CapNames":"m","Regexp.Equal":"m","Regexp.MaxCap":"m","Regexp.Simplify":"m","Regexp.String":"m","Simple":"c","UnicodeGroups":"c","WasDollar":"c"}},"runtime":{"path":"runtime","name":"runtime","symbols":{"AddCleanup":"f","BlockProfile":"f","BlockProfileRecord":"t","Breakpoint":"f","CPUProfile":"f","Caller":"f","Callers":"f","CallersFrames":"f","Cleanup":"t","Cleanup.Stop":"m","Compiler":"c","Error":"t","Frame":"t","Frames":"t","Frames.Next":"m","Func":"t","Func.Entry":"m","Func.FileLine":"m","Func.Name":"m","FuncForPC":"f","GC":"f","GOARCH":"c","GOMAXPROCS":"f","GOOS":"c","GOROOT":"f","Goexit":"f","GoroutineProfile":"f","Gosched":"f","KeepAlive":"f","LockOSThread":"f","MemProfile":"f","MemProfileRate":"v","MemProfileRecord":"t","MemProfileRecord.InUseBytes":"m","MemProfileRecord.InUseObjects":"m","MemProfileRecord.Stack":"m","MemStats":"t","MutexProfile":"f","NumCPU":"f","NumCgoCall":"f","NumGoroutine":"f","PanicNilError":"t","PanicNilError.Error":"m","PanicNilError.RuntimeError":"m","Pinner":"t","Pinner.Pin":"m","Pinner.Unpin":"m","ReadMemStats":"f","ReadTrace":"f","SetBlockProfileRate":"f","SetCPUProfileRate":"f","SetCgoTraceback":"f","SetDefaultGOMAXPROCS":"f","SetFinalizer":"f","SetMutexProfileFraction":"f","Stack":"f","StackRecord":"t","StackRecord.Stack":"m","StartTrace":"f","StopTrace":"f","ThreadCreateProfile":"f","TypeAssertionError":"t","TypeAssertionError.Error":"m","TypeAssertionError.RuntimeError":"m","UnlockOSThread":"f","Version":"f"}},"runtime/cgo":{"path":"runtime/cgo","name":"cgo","symbols":{"Handle":"t","Handle.Delete":"m","Handle.Value":"m","Incomplete":"t","NewHandle":"f"}},"runtime/coverage":{"path":"runtime/coverage","name":"coverage","symbols":{"ClearCounters":"f","WriteCounters":"f","WriteCountersDir":"f","WriteMeta":"f","WriteMetaDir":"f"}},"runtime/debug":{"path":"runtime/debug","name":"debug","symbols":{"BuildInfo":"t","BuildInfo.String":"m","BuildSetting":"t","CrashOptions":"t","FreeOSMemory":"f","GCStats":"t","Module":"t","ParseBuildInfo":"f","PrintStack":"f","ReadBuildInfo":"f","ReadGCStats":"f","SetCrashOutput":"f","SetGCPercent":"f","SetMaxStack":"f","SetMaxThreads":"f","SetMemoryLimit":"f","SetPanicOnFault":"f","SetTraceback":"f","Stack":"f","WriteHeapDump":"f"}},"runtime/metrics":{"path":"runtime/metrics","name":"metrics","symbols":{"All":"f","Description":"t","Float64Histogram":"t","KindBad":"c","KindFloat64":"c","KindFloat64Histogram":"c","KindUint64":"c","Read":"f","Sample":"t","Value":"t","Value.Float64":"m","Value.Float64Histogram":"m","Value.Kind":"m","Value.Uint64":"m","ValueKind":"t"}},"runtime/pprof":{"path":"runtime/pprof","name":"pprof","symbols":{"Do":"f","ForLabels":"f","Label":"f","LabelSet":"t","Labels":"f","Lookup":"f","NewProfile":"f","Profile":"t","Profile.Add":"m","Profile.Count":"m","Profile.Name":"m","Profile.Remove":"m","Profile.WriteTo":"m","Profiles":"f","SetGoroutineLabels":"f","StartCPUProfile":"f","StopCPUProfile":"f","WithLabels":"f","WriteHeapProfile":"f"}},"runtime/trace":{"path":"runtime/trace","name":"trace","symbols":{"FlightRecorder":"t","FlightRecorder.Enabled":"m","FlightRecorder.Start":"m","FlightRecorder.Stop":"m","FlightRecorder.WriteTo":"m","FlightRecorderConfig":"t","IsEnabled":"f","Log":"f","Logf":"f","NewFlightRecorder":"f","NewTask":"f","Region":"t","Region.End":"m","Start":"f","StartRegion":"f","Stop":"f","Task":"t","Task.End":"m","WithRegion":"f"}},"slices":{"path":"slices","name":"slices","symbols":{"All":"f","AppendSeq":"f","Backward":"f","BinarySearch":"f","BinarySearchFunc":"f","Chunk":"f","Clip":"f","Clone":"f","Collect":"f","Compact":"f","CompactFunc":"f","Compare":"f","CompareFunc":"f","Concat":"f","Contains":"f","ContainsFunc":"f","Delete":"f","DeleteFunc":"f","Equal":"f","EqualFunc":"f","Grow":"f","Index":"f","IndexFunc":"f","Insert":"f","IsSorted":"f","IsSortedFunc":"f","Max":"f","MaxFunc":"f","Min":"f","MinFunc":"f","Repeat":"f","Replace":"f","Reverse":"f","Sort":"f","SortFunc":"f","SortStableFunc":"f","Sorted":"f","SortedFunc":"f","SortedStableFunc":"f","Values":"f"}},"sort":{"path":"sort","name":"sort","symbols":{"Find":"f","Float64Slice":"t","Float64Slice.Len":"m","Float64Slice.Less":"m","Float64Slice.Search":"m","Float64Slice.Sort":"m","Float64Slice.Swap":"m","Float64s":"f","Float64sAreSorted":"f","IntSlice":"t","IntSlice.Len":"m","IntSlice.Less":"m","IntSlice.Search":"m","IntSlice.Sort":"m","IntSlice.Swap":"m","Interface":"t","Ints":"f","IntsAreSorted":"f","IsSorted":"f","Reverse":"f","Search":"f","SearchFloat64s":"f","SearchInts":"f","SearchStrings":"f","Slice":"f","SliceIsSorted":"f","SliceStable":"f","Sort":"f","Stable":"f","StringSlice":"t","StringSlice.Len":"m","StringSlice.Less":"m","StringSlice.Search":"m","StringSlice.Sort":"m","StringSlice.Swap":"m","Strings":"f","StringsAreSorted":"f"}},"strconv":{"path":"strconv","name":"strconv","symbols":{"AppendBool":"f","AppendFloat":"f","AppendInt":"f","AppendQuote":"f","AppendQuoteRune":"f","AppendQuoteRuneToASCII":"f","AppendQuoteRuneToGraphic":"f","AppendQuoteToASCII":"f","AppendQuoteToGraphic":"f","AppendUint":"f","Atoi":"f","CanBackquote":"f","ErrRange":"v","ErrSyntax":"v","FormatBool":"f","FormatComplex":"f","FormatFloat":"f","FormatInt":"f","FormatUint":"f","IntSize":"c","IsGraphic":"f","IsPrint":"f","Itoa":"f","NumError":"t","NumError.Error":"m","NumError.Unwrap":"m","ParseBool":"f","ParseComplex":"f","ParseFloat":"f","ParseInt":"f","ParseUint":"f","Quote":"f","QuoteRune":"f","QuoteRuneToASCII":"f","QuoteRuneToGraphic":"f","QuoteToASCII":"f","QuoteToGraphic":"f","QuotedPrefix":"f","Unquote":"f","UnquoteChar":"f"}},"strings":{"path":"strings","name":"strings","symbols":{"Builder":"t","Builder.Cap":"m","Builder.Grow":"m","Builder.Len":"m","Builder.Reset":"m","Builder.String":"m","Builder.Write":"m","Builder.WriteByte":"m","Builder.WriteRune":"m","Builder.WriteString":"m","Clone":"f","Compare":"f","Contains":"f","ContainsAny":"f","ContainsFunc":"f","ContainsRune":"f","Count":"f","Cut":"f","CutPrefix":"f","CutSuffix":"f","EqualFold":"f","Fields":"f","FieldsFunc":"f","FieldsFuncSeq":"f","FieldsSeq":"f","HasPrefix":"f","HasSuffix":"f","Index":"f","IndexAny":"f","IndexByte":"f","IndexFunc":"f","IndexRune":"f","Join":"f","LastIndex":"f","LastIndexAny":"f","LastIndexByte":"f","LastIndexFunc":"f","Lines":"f","Map":"f","NewReader":"f","NewReplacer":"f","Reader":"t","Reader.Len":"m","Reader.Read":"m","Reader.ReadAt":"m","Reader.ReadByte":"m","Reader.ReadRune":"m","Reader.Reset":"m","Reader.Seek":"m","Reader.Size":"m","Reader.UnreadByte":"m","Reader.UnreadRune":"m","Reader.WriteTo":"m","Repeat":"f","Replace":"f","ReplaceAll":"f","Replacer":"t","Replacer.Replace":"m","Replacer.WriteString":"m","Split":"f","SplitAfter":"f","SplitAfterN":"f","SplitAfterSeq":"f","SplitN":"f","SplitSeq":"f","Title":"f","ToLower":"f","ToLowerSpecial":"f","ToTitle":"f","ToTitleSpecial":"f","ToUpper":"f","ToUpperSpecial":"f","ToValidUTF8":"f","Trim":"f","TrimFunc":"f","TrimLeft":"f","TrimLeftFunc":"f","TrimPrefix":"f","TrimRight":"f","TrimRightFunc":"f","TrimSpace":"f","TrimSuffix":"f"}},"structs":{"path":"structs","name":"structs","symbols":{"HostLayout":"t"}},"sync":{"path":"sync","name":"sync","symbols":{"Cond":"t","Cond.Broadcast":"m","Cond.Signal":"m","Cond.Wait":"m","Locker":"t","Map":"t","Map.Clear":"m","Map.CompareAndDelete":"m","Map.CompareAndSwap":"m","Map.Delete":"m","Map.Load":"m","Map.LoadAndDelete":"m","Map.LoadOrStore":"m","Map.Range":"m","Map.Store":"m","Map.Swap":"m","Mutex":"t","Mutex.Lock":"m","Mutex.TryLock":"m","Mutex.Unlock":"m","NewCond":"f","Once":"t","Once.Do":"m","OnceFunc":"f","OnceValue":"f","OnceValues":"f","Pool":"t","Pool.Get":"m","Pool.Put":"m","RWMutex":"t","RWMutex.Lock":"m","RWMutex.RLock":"m","RWMutex.RLocker":"m","RWMutex.RUnlock":"m","RWMutex.TryLock":"m","RWMutex.TryRLock":"m","RWMutex.Unlock":"m","WaitGroup":"t","WaitGroup.Add":"m","WaitGroup.Done":"m","WaitGroup.Go":"m","WaitGroup.Wait":"m"}},"sync/atomic":{"path":"sync/atomic","name":"atomic","symbols":{"AddInt32":"f","AddInt64":"f","AddUint32":"f","AddUint64":"f","AddUintptr":"f","AndInt32":"f","AndInt64":"f","AndUint32":"f","AndUint64":"f","AndUintptr":"f","Bool":"t","Bool.CompareAndSwap":"m","Bool.Load":"m","Bool.Store":"m","Bool.Swap":"m","CompareAndSwapInt32":"f","CompareAndSwapInt64":"f","CompareAndSwapPointer":"f","CompareAndSwapUint32":"f","CompareAndSwapUint64":"f","CompareAndSwapUintptr":"f","Int32":"t","Int32.Add":"m","Int32.And":"m","Int32.CompareAndSwap":"m","Int32.Load":"m","Int32.Or":"m","Int32.Store":"m","Int32.Swap":"m","Int64":"t","Int64.Add":"m","Int64.And":"m","Int64.CompareAndSwap":"m","Int64.Load":"m","Int64.Or":"m","Int64.Store":"m","Int64.Swap":"m","LoadInt32":"f","LoadInt64":"f","LoadPointer":"f","LoadUint32":"f","LoadUint64":"f","LoadUintptr":"f","OrInt32":"f","OrInt64":"f","OrUint32":"f","OrUint64":"f","OrUintptr":"f","Pointer":"t","StoreInt32":"f","StoreInt64":"f","StorePointer":"f","StoreUint32":"f","StoreUint64":"f","StoreUintptr":"f","SwapInt32":"f","SwapInt64":"f","SwapPointer":"f","SwapUint32":"f","SwapUint64":"f","SwapUintptr":"f","Uint32":"t","Uint32.Add":"m","Uint32.And":"m","Uint32.CompareAndSwap":"m","Uint32.Load":"m","Uint32.Or":"m","Uint32.Store":"m","Uint32.Swap":"m","Uint64":"t","Uint64.Add":"m","Uint64.And":"m","Uint64.CompareAndSwap":"m","Uint64.Load":"m","Uint64.Or":"m","Uint64.Store":"m","Uint64.Swap":"m","Uintptr":"t","Uintptr.Add":"m","Uintptr.And":"m","Uintptr.CompareAndSwap":"m","Uintptr.Load":"m","Uintptr.Or":"m","Uintptr.Store":"m","Uintptr.Swap":"m","Value":"t","Value.CompareAndSwap":"m","Value.Load":"m","Value.Store":"m","Value.Swap":"m"}},"syscall":{"path":"syscall","name":"syscall","symbols":{"AF_ALG":"c","AF_APPLETALK":"c","AF_ASH":"c","AF_ATMPVC":"c","AF_ATMSVC":"c","AF_AX25":"c","AF_BLUETOOTH":"c","AF_BRIDGE":"c","AF_CAIF":"c","AF_CAN":"c","AF_DECnet":"c","AF_ECONET":"c","AF_FILE":"c","AF_IEEE802154":"c","AF_INET":"c","AF_INET6":"c","AF_IPX":"c","AF_IRDA":"c","AF_ISDN":"c","AF_IUCV":"c","AF_KEY":"c","AF_LLC":"c","AF_LOCAL":"c","AF_MAX":"c","AF_NETBEUI":"c","AF_NETLINK":"c","AF_NETROM":"c","AF_PACKET":"c","AF_PHONET":"c","AF_PPPOX":"c","AF_RDS":"c","AF_ROSE":"c","AF_ROUTE":"c","AF_RXRPC":"c","AF_SECURITY":"c","AF_SNA":"c","AF_TIPC":"c","AF_UNIX":"c","AF_UNSPEC":"c","AF_WANPIPE":"c","AF_X25":"c","ARPHRD_ADAPT":"c","ARPHRD_APPLETLK":"c","ARPHRD_ARCNET":"c","ARPHRD_ASH":"c","ARPHRD_ATM":"c","ARPHRD_AX25":"c","ARPHRD_BIF":"c","ARPHRD_CHAOS":"c","ARPHRD_CISCO":"c","ARPHRD_CSLIP":"c","ARPHRD_CSLIP6":"c","ARPHRD_DDCMP":"c","ARPHRD_DLCI":"c","ARPHRD_ECONET":"c","ARPHRD_EETHER":"c","ARPHRD_ETHER":"c","ARPHRD_EUI64":"c","ARPHRD_FCAL":"c","ARPHRD_FCFABRIC":"c","ARPHRD_FCPL":"c","ARPHRD_FCPP":"c","ARPHRD_FDDI":"c","ARPHRD_FRAD":"c","ARPHRD_HDLC":"c","ARPHRD_HIPPI":"c","ARPHRD_HWX25":"c","ARPHRD_IEEE1394":"c","ARPHRD_IEEE802":"c","ARPHRD_IEEE80211":"c","ARPHRD_IEEE80211_PRISM":"c","ARPHRD_IEEE80211_RADIOTAP":"c","ARPHRD_IEEE802154":"c","ARPHRD_IEEE802154_PHY":"c","ARPHRD_IEEE802_TR":"c","ARPHRD_INFINIBAND":"c","ARPHRD_IPDDP":"c","ARPHRD_IPGRE":"c","ARPHRD_IRDA":"c","ARPHRD_LAPB":"c","ARPHRD_LOCALTLK":"c","ARPHRD_LOOPBACK":"c","ARPHRD_METRICOM":"c","ARPHRD_NETROM":"c","ARPHRD_NONE":"c","ARPHRD_PIMREG":"c","ARPHRD_PPP":"c","ARPHRD_PRONET":"c","ARPHRD_RAWHDLC":"c","ARPHRD_ROSE":"c","ARPHRD_RSRVD":"c","ARPHRD_SIT":"c","ARPHRD_SKIP":"c","ARPHRD_SLIP":"c","ARPHRD_SLIP6":"c","ARPHRD_TUNNEL":"c","ARPHRD_TUNNEL6":"c","ARPHRD_VOID":"c","ARPHRD_X25":"c","Accept":"f","Accept4":"f","Access":"f","Acct":"f","Adjtimex":"f","AllThreadsSyscall":"f","AllThreadsSyscall6":"f","AttachLsf":"f","B0":"c","B1000000":"c","B110":"c","B115200":"c","B1152000":"c","B1200":"c","B134":"c","B150":"c","B1500000":"c","B1800":"c","B19200":"c","B200":"c","B2000000":"c","B230400":"c","B2400":"c","B2500000":"c","B300":"c","B3000000":"c","B3500000":"c","B38400":"c","B4000000":"c","B460800":"c","B4800":"c","B50":"c","B500000":"c","B57600":"c","B576000":"c","B600":"c","B75":"c","B921600":"c","B9600":"c","BPF_A":"c","BPF_ABS":"c","BPF_ADD":"c","BPF_ALU":"c","BPF_AND":"c","BPF_B":"c","BPF_DIV":"c","BPF_H":"c","BPF_IMM":"c","BPF_IND":"c","BPF_JA":"c","BPF_JEQ":"c","BPF_JGE":"c","BPF_JGT":"c","BPF_JMP":"c","BPF_JSET":"c","BPF_K":"c","BPF_LD":"c","BPF_LDX":"c","BPF_LEN":"c","BPF_LSH":"c","BPF_MAJOR_VERSION":"c","BPF_MAXINSNS":"c","BPF_MEM":"c","BPF_MEMWORDS":"c","BPF_MINOR_VERSION":"c","BPF_MISC":"c","BPF_MSH":"c","BPF_MUL":"c","BPF_NEG":"c","BPF_OR":"c","BPF_RET":"c","BPF_RSH":"c","BPF_ST":"c","BPF_STX":"c","BPF_SUB":"c","BPF_TAX":"c","BPF_TXA":"c","BPF_W":"c","BPF_X":"c","BRKINT":"c","Bind":"f","BindToDevice":"f","BytePtrFromString":"f","ByteSliceFromString":"f","CLOCAL":"c","CLONE_CHILD_CLEARTID":"c","CLONE_CHILD_SETTID":"c","CLONE_CLEAR_SIGHAND":"c","CLONE_DETACHED":"c","CLONE_FILES":"c","CLONE_FS":"c","CLONE_INTO_CGROUP":"c","CLONE_IO":"c","CLONE_NEWCGROUP":"c","CLONE_NEWIPC":"c","CLONE_NEWNET":"c","CLONE_NEWNS":"c","CLONE_NEWPID":"c","CLONE_NEWTIME":"c","CLONE_NEWUSER":"c","CLONE_NEWUTS":"c","CLONE_PARENT":"c","CLONE_PARENT_SETTID":"c","CLONE_PIDFD":"c","CLONE_PTRACE":"c","CLONE_SETTLS":"c","CLONE_SIGHAND":"c","CLONE_SYSVSEM":"c","CLONE_THREAD":"c","CLONE_UNTRACED":"c","CLONE_VFORK":"c","CLONE_VM":"c","CREAD":"c","CS5":"c","CS6":"c","CS7":"c","CS8":"c","CSIZE":"c","CSTOPB":"c","Chdir":"f","Chmod":"f","Chown":"f","Chroot":"f","Clearenv":"f","Close":"f","CloseOnExec":"f","CmsgLen":"f","CmsgSpace":"f","Cmsghdr":"t","Cmsghdr.SetLen":"m","Conn":"t","Connect":"f","Creat":"f","Credential":"t","DT_BLK":"c","DT_CHR":"c","DT_DIR":"c","DT_FIFO":"c","DT_LNK":"c","DT_REG":"c","DT_SOCK":"c","DT_UNKNOWN":"c","DT_WHT":"c","DetachLsf":"f","Dirent":"t","Dup":"f","Dup2":"f","Dup3":"f","E2BIG":"c","EACCES":"c","EADDRINUSE":"c","EADDRNOTAVAIL":"c","EADV":"c","EAFNOSUPPORT":"c","EAGAIN":"c","EALREADY":"c","EBADE":"c","EBADF":"c","EBADFD":"c","EBADMSG":"c","EBADR":"c","EBADRQC":"c","EBADSLT":"c","EBFONT":"c","EBUSY":"c","ECANCELED":"c","ECHILD":"c","ECHO":"c","ECHOCTL":"c","ECHOE":"c","ECHOK":"c","ECHOKE":"c","ECHONL":"c","ECHOPRT":"c","ECHRNG":"c","ECOMM":"c","ECONNABORTED":"c","ECONNREFUSED":"c","ECONNRESET":"c","EDEADLK":"c","EDEADLOCK":"c","EDESTADDRREQ":"c","EDOM":"c","EDOTDOT":"c","EDQUOT":"c","EEXIST":"c","EFAULT":"c","EFBIG":"c","EHOSTDOWN":"c","EHOSTUNREACH":"c","EIDRM":"c","EILSEQ":"c","EINPROGRESS":"c","EINTR":"c","EINVAL":"c","EIO":"c","EISCONN":"c","EISDIR":"c","EISNAM":"c","EKEYEXPIRED":"c","EKEYREJECTED":"c","EKEYREVOKED":"c","EL2HLT":"c","EL2NSYNC":"c","EL3HLT":"c","EL3RST":"c","ELIBACC":"c","ELIBBAD":"c","ELIBEXEC":"c","ELIBMAX":"c","ELIBSCN":"c","ELNRNG":"c","ELOOP":"c","EMEDIUMTYPE":"c","EMFILE":"c","EMLINK":"c","EMSGSIZE":"c","EMULTIHOP":"c","ENAMETOOLONG":"c","ENAVAIL":"c","ENETDOWN":"c","ENETRESET":"c","ENETUNREACH":"c","ENFILE":"c","ENOANO":"c","ENOBUFS":"c","ENOCSI":"c","ENODATA":"c","ENODEV":"c","ENOENT":"c","ENOEXEC":"c","ENOKEY":"c","ENOLCK":"c","ENOLINK":"c","ENOMEDIUM":"c","ENOMEM":"c","ENOMSG":"c","ENONET":"c","ENOPKG":"c","ENOPROTOOPT":"c","ENOSPC":"c","ENOSR":"c","ENOSTR":"c","ENOSYS":"c","ENOTBLK":"c","ENOTCONN":"c","ENOTDIR":"c","ENOTEMPTY":"c","ENOTNAM":"c","ENOTRECOVERABLE":"c","ENOTSOCK":"c","ENOTSUP":"c","ENOTTY":"c","ENOTUNIQ":"c","ENXIO":"c","EOPNOTSUPP":"c","EOVERFLOW":"c","EOWNERDEAD":"c","EPERM":"c","EPFNOSUPPORT":"c","EPIPE":"c","EPOLLERR":"c","EPOLLET":"c","EPOLLHUP":"c","EPOLLIN":"c","EPOLLMSG":"c","EPOLLONESHOT":"c","EPOLLOUT":"c","EPOLLPRI":"c","EPOLLRDBAND":"c","EPOLLRDHUP":"c","EPOLLRDNORM":"c","EPOLLWRBAND":"c","EPOLLWRNORM":"c","EPOLL_CLOEXEC":"c","EPOLL_CTL_ADD":"c","EPOLL_CTL_DEL":"c","EPOLL_CTL_MOD":"c","EPOLL_NONBLOCK":"c","EPROTO":"c","EPROTONOSUPPORT":"c","EPROTOTYPE":"c","ERANGE":"c","EREMCHG":"c","EREMOTE":"c","EREMOTEIO":"c","ERESTART":"c","ERFKILL":"c","EROFS":"c","ESHUTDOWN":"c","ESOCKTNOSUPPORT":"c","ESPIPE":"c","ESRCH":"c","ESRMNT":"c","ESTALE":"c","ESTRPIPE":"c","ETH_P_1588":"c","ETH_P_8021Q":"c","ETH_P_802_2":"c","ETH_P_802_3":"c","ETH_P_AARP":"c","ETH_P_ALL":"c","ETH_P_AOE":"c","ETH_P_ARCNET":"c","ETH_P_ARP":"c","ETH_P_ATALK":"c","ETH_P_ATMFATE":"c","ETH_P_ATMMPOA":"c","ETH_P_AX25":"c","ETH_P_BPQ":"c","ETH_P_CAIF":"c","ETH_P_CAN":"c","ETH_P_CONTROL":"c","ETH_P_CUST":"c","ETH_P_DDCMP":"c","ETH_P_DEC":"c","ETH_P_DIAG":"c","ETH_P_DNA_DL":"c","ETH_P_DNA_RC":"c","ETH_P_DNA_RT":"c","ETH_P_DSA":"c","ETH_P_ECONET":"c","ETH_P_EDSA":"c","ETH_P_FCOE":"c","ETH_P_FIP":"c","ETH_P_HDLC":"c","ETH_P_IEEE802154":"c","ETH_P_IEEEPUP":"c","ETH_P_IEEEPUPAT":"c","ETH_P_IP":"c","ETH_P_IPV6":"c","ETH_P_IPX":"c","ETH_P_IRDA":"c","ETH_P_LAT":"c","ETH_P_LINK_CTL":"c","ETH_P_LOCALTALK":"c","ETH_P_LOOP":"c","ETH_P_MOBITEX":"c","ETH_P_MPLS_MC":"c","ETH_P_MPLS_UC":"c","ETH_P_PAE":"c","ETH_P_PAUSE":"c","ETH_P_PHONET":"c","ETH_P_PPPTALK":"c","ETH_P_PPP_DISC":"c","ETH_P_PPP_MP":"c","ETH_P_PPP_SES":"c","ETH_P_PUP":"c","ETH_P_PUPAT":"c","ETH_P_RARP":"c","ETH_P_SCA":"c","ETH_P_SLOW":"c","ETH_P_SNAP":"c","ETH_P_TEB":"c","ETH_P_TIPC":"c","ETH_P_TRAILER":"c","ETH_P_TR_802_2":"c","ETH_P_WAN_PPP":"c","ETH_P_WCCP":"c","ETH_P_X25":"c","ETIME":"c","ETIMEDOUT":"c","ETOOMANYREFS":"c","ETXTBSY":"c","EUCLEAN":"c","EUNATCH":"c","EUSERS":"c","EWOULDBLOCK":"c","EXDEV":"c","EXFULL":"c","Environ":"f","EpollCreate":"f","EpollCreate1":"f","EpollCtl":"f","EpollEvent":"t","EpollWait":"f","Errno":"t","Errno.Error":"m","Errno.Is":"m","Errno.Temporary":"m","Errno.Timeout":"m","Exec":"f","Exit":"f","FD_CLOEXEC":"c","FD_SETSIZE":"c","FLUSHO":"c","F_DUPFD":"c","F_DUPFD_CLOEXEC":"c","F_EXLCK":"c","F_GETFD":"c","F_GETFL":"c","F_GETLEASE":"c","F_GETLK":"c","F_GETLK64":"c","F_GETOWN":"c","F_GETOWN_EX":"c","F_GETPIPE_SZ":"c","F_GETSIG":"c","F_LOCK":"c","F_NOTIFY":"c","F_OK":"c","F_RDLCK":"c","F_SETFD":"c","F_SETFL":"c","F_SETLEASE":"c","F_SETLK":"c","F_SETLK64":"c","F_SETLKW":"c","F_SETLKW64":"c","F_SETOWN":"c","F_SETOWN_EX":"c","F_SETPIPE_SZ":"c","F_SETSIG":"c","F_SHLCK":"c","F_TEST":"c","F_TLOCK":"c","F_ULOCK":"c","F_UNLCK":"c","F_WRLCK":"c","Faccessat":"f","Fallocate":"f","Fchdir":"f","Fchmod":"f","Fchmodat":"f","Fchown":"f","Fchownat":"f","FcntlFlock":"f","FdSet":"t","Fdatasync":"f","Flock":"f","Flock_t":"t","ForkExec":"f","ForkLock":"v","Fsid":"t","Fstat":"f","Fstatfs":"f","Fsync":"f","Ftruncate":"f","Futimes":"f","Futimesat":"f","Getcwd":"f","Getdents":"f","Getegid":"f","Getenv":"f","Geteuid":"f","Getgid":"f","Getgroups":"f","Getpagesize":"f","Getpeername":"f","Getpgid":"f","Getpgrp":"f","Getpid":"f","Getppid":"f","Getpriority":"f","Getrlimit":"f","Getrusage":"f","Getsockname":"f","GetsockoptICMPv6Filter":"f","GetsockoptIPMreq":"f","GetsockoptIPMreqn":"f","GetsockoptIPv6MTUInfo":"f","GetsockoptIPv6Mreq":"f","GetsockoptInet4Addr":"f","GetsockoptInt":"f","GetsockoptUcred":"f","Gettid":"f","Gettimeofday":"f","Getuid":"f","Getwd":"f","Getxattr":"f","HUPCL":"c","ICANON":"c","ICMPV6_FILTER":"c","ICMPv6Filter":"t","ICRNL":"c","IEXTEN":"c","IFA_ADDRESS":"c","IFA_ANYCAST":"c","IFA_BROADCAST":"c","IFA_CACHEINFO":"c","IFA_F_DADFAILED":"c","IFA_F_DEPRECATED":"c","IFA_F_HOMEADDRESS":"c","IFA_F_NODAD":"c","IFA_F_OPTIMISTIC":"c","IFA_F_PERMANENT":"c","IFA_F_SECONDARY":"c","IFA_F_TEMPORARY":"c","IFA_F_TENTATIVE":"c","IFA_LABEL":"c","IFA_LOCAL":"c","IFA_MAX":"c","IFA_MULTICAST":"c","IFA_UNSPEC":"c","IFF_ALLMULTI":"c","IFF_AUTOMEDIA":"c","IFF_BROADCAST":"c","IFF_DEBUG":"c","IFF_DYNAMIC":"c","IFF_LOOPBACK":"c","IFF_MASTER":"c","IFF_MULTICAST":"c","IFF_NOARP":"c","IFF_NOTRAILERS":"c","IFF_NO_PI":"c","IFF_ONE_QUEUE":"c","IFF_POINTOPOINT":"c","IFF_PORTSEL":"c","IFF_PROMISC":"c","IFF_RUNNING":"c","IFF_SLAVE":"c","IFF_TAP":"c","IFF_TUN":"c","IFF_TUN_EXCL":"c","IFF_UP":"c","IFF_VNET_HDR":"c","IFLA_ADDRESS":"c","IFLA_BROADCAST":"c","IFLA_COST":"c","IFLA_IFALIAS":"c","IFLA_IFNAME":"c","IFLA_LINK":"c","IFLA_LINKINFO":"c","IFLA_LINKMODE":"c","IFLA_MAP":"c","IFLA_MASTER":"c","IFLA_MAX":"c","IFLA_MTU":"c","IFLA_NET_NS_PID":"c","IFLA_OPERSTATE":"c","IFLA_PRIORITY":"c","IFLA_PROTINFO":"c","IFLA_QDISC":"c","IFLA_STATS":"c","IFLA_TXQLEN":"c","IFLA_UNSPEC":"c","IFLA_WEIGHT":"c","IFLA_WIRELESS":"c","IFNAMSIZ":"c","IGNBRK":"c","IGNCR":"c","IGNPAR":"c","IMAXBEL":"c","INLCR":"c","INPCK":"c","IN_ACCESS":"c","IN_ALL_EVENTS":"c","IN_ATTRIB":"c","IN_CLASSA_HOST":"c","IN_CLASSA_MAX":"c","IN_CLASSA_NET":"c","IN_CLASSA_NSHIFT":"c","IN_CLASSB_HOST":"c","IN_CLASSB_MAX":"c","IN_CLASSB_NET":"c","IN_CLASSB_NSHIFT":"c","IN_CLASSC_HOST":"c","IN_CLASSC_NET":"c","IN_CLASSC_NSHIFT":"c","IN_CLOEXEC":"c","IN_CLOSE":"c","IN_CLOSE_NOWRITE":"c","IN_CLOSE_WRITE":"c","IN_CREATE":"c","IN_DELETE":"c","IN_DELETE_SELF":"c","IN_DONT_FOLLOW":"c","IN_EXCL_UNLINK":"c","IN_IGNORED":"c","IN_ISDIR":"c","IN_LOOPBACKNET":"c","IN_MASK_ADD":"c","IN_MODIFY":"c","IN_MOVE":"c","IN_MOVED_FROM":"c","IN_MOVED_TO":"c","IN_MOVE_SELF":"c","IN_NONBLOCK":"c","IN_ONESHOT":"c","IN_ONLYDIR":"c","IN_OPEN":"c","IN_Q_OVERFLOW":"c","IN_UNMOUNT":"c","IPMreq":"t","IPMreqn":"t","IPPROTO_AH":"c","IPPROTO_COMP":"c","IPPROTO_DCCP":"c","IPPROTO_DSTOPTS":"c","IPPROTO_EGP":"c","IPPROTO_ENCAP":"c","IPPROTO_ESP":"c","IPPROTO_FRAGMENT":"c","IPPROTO_GRE":"c","IPPROTO_HOPOPTS":"c","IPPROTO_ICMP":"c","IPPROTO_ICMPV6":"c","IPPROTO_IDP":"c","IPPROTO_IGMP":"c","IPPROTO_IP":"c","IPPROTO_IPIP":"c","IPPROTO_IPV6":"c","IPPROTO_MTP":"c","IPPROTO_NONE":"c","IPPROTO_PIM":"c","IPPROTO_PUP":"c","IPPROTO_RAW":"c","IPPROTO_ROUTING":"c","IPPROTO_RSVP":"c","IPPROTO_SCTP":"c","IPPROTO_TCP":"c","IPPROTO_TP":"c","IPPROTO_UDP":"c","IPPROTO_UDPLITE":"c","IPV6_2292DSTOPTS":"c","IPV6_2292HOPLIMIT":"c","IPV6_2292HOPOPTS":"c","IPV6_2292PKTINFO":"c","IPV6_2292PKTOPTIONS":"c","IPV6_2292RTHDR":"c","IPV6_ADDRFORM":"c","IPV6_ADD_MEMBERSHIP":"c","IPV6_AUTHHDR":"c","IPV6_CHECKSUM":"c","IPV6_DROP_MEMBERSHIP":"c","IPV6_DSTOPTS":"c","IPV6_HOPLIMIT":"c","IPV6_HOPOPTS":"c","IPV6_IPSEC_POLICY":"c","IPV6_JOIN_ANYCAST":"c","IPV6_JOIN_GROUP":"c","IPV6_LEAVE_ANYCAST":"c","IPV6_LEAVE_GROUP":"c","IPV6_MTU":"c","IPV6_MTU_DISCOVER":"c","IPV6_MULTICAST_HOPS":"c","IPV6_MULTICAST_IF":"c","IPV6_MULTICAST_LOOP":"c","IPV6_NEXTHOP":"c","IPV6_PKTINFO":"c","IPV6_PMTUDISC_DO":"c","IPV6_PMTUDISC_DONT":"c","IPV6_PMTUDISC_PROBE":"c","IPV6_PMTUDISC_WANT":"c","IPV6_RECVDSTOPTS":"c","IPV6_RECVERR":"c","IPV6_RECVHOPLIMIT":"c","IPV6_RECVHOPOPTS":"c","IPV6_RECVPKTINFO":"c","IPV6_RECVRTHDR":"c","IPV6_RECVTCLASS":"c","IPV6_ROUTER_ALERT":"c","IPV6_RTHDR":"c","IPV6_RTHDRDSTOPTS":"c","IPV6_RTHDR_LOOSE":"c","IPV6_RTHDR_STRICT":"c","IPV6_RTHDR_TYPE_0":"c","IPV6_RXDSTOPTS":"c","IPV6_RXHOPOPTS":"c","IPV6_TCLASS":"c","IPV6_UNICAST_HOPS":"c","IPV6_V6ONLY":"c","IPV6_XFRM_POLICY":"c","IP_ADD_MEMBERSHIP":"c","IP_ADD_SOURCE_MEMBERSHIP":"c","IP_BLOCK_SOURCE":"c","IP_DEFAULT_MULTICAST_LOOP":"c","IP_DEFAULT_MULTICAST_TTL":"c","IP_DF":"c","IP_DROP_MEMBERSHIP":"c","IP_DROP_SOURCE_MEMBERSHIP":"c","IP_FREEBIND":"c","IP_HDRINCL":"c","IP_IPSEC_POLICY":"c","IP_MAXPACKET":"c","IP_MAX_MEMBERSHIPS":"c","IP_MF":"c","IP_MINTTL":"c","IP_MSFILTER":"c","IP_MSS":"c","IP_MTU":"c","IP_MTU_DISCOVER":"c","IP_MULTICAST_IF":"c","IP_MULTICAST_LOOP":"c","IP_MULTICAST_TTL":"c","IP_OFFMASK":"c","IP_OPTIONS":"c","IP_ORIGDSTADDR":"c","IP_PASSSEC":"c","IP_PKTINFO":"c","IP_PKTOPTIONS":"c","IP_PMTUDISC":"c","IP_PMTUDISC_DO":"c","IP_PMTUDISC_DONT":"c","IP_PMTUDISC_PROBE":"c","IP_PMTUDISC_WANT":"c","IP_RECVERR":"c","IP_RECVOPTS":"c","IP_RECVORIGDSTADDR":"c","IP_RECVRETOPTS":"c","IP_RECVTOS":"c","IP_RECVTTL":"c","IP_RETOPTS":"c","IP_RF":"c","IP_ROUTER_ALERT":"c","IP_TOS":"c","IP_TRANSPARENT":"c","IP_TTL":"c","IP_UNBLOCK_SOURCE":"c","IP_XFRM_POLICY":"c","IPv6MTUInfo":"t","IPv6Mreq":"t","ISIG":"c","ISTRIP":"c","IUCLC":"c","IUTF8":"c","IXANY":"c","IXOFF":"c","IXON":"c","IfAddrmsg":"t","IfInfomsg":"t","ImplementsGetwd":"c","Inet4Pktinfo":"t","Inet6Pktinfo":"t","InotifyAddWatch":"f","InotifyEvent":"t","InotifyInit":"f","InotifyInit1":"f","InotifyRmWatch":"f","Ioperm":"f","Iopl":"f","Iovec":"t","Iovec.SetLen":"m","Kill":"f","Klogctl":"f","LINUX_REBOOT_CMD_CAD_OFF":"c","LINUX_REBOOT_CMD_CAD_ON":"c","LINUX_REBOOT_CMD_HALT":"c","LINUX_REBOOT_CMD_KEXEC":"c","LINUX_REBOOT_CMD_POWER_OFF":"c","LINUX_REBOOT_CMD_RESTART":"c","LINUX_REBOOT_CMD_RESTART2":"c","LINUX_REBOOT_CMD_SW_SUSPEND":"c","LINUX_REBOOT_MAGIC1":"c","LINUX_REBOOT_MAGIC2":"c","LOCK_EX":"c","LOCK_NB":"c","LOCK_SH":"c","LOCK_UN":"c","Lchown":"f","Linger":"t","Link":"f","Listen":"f","Listxattr":"f","LsfJump":"f","LsfSocket":"f","LsfStmt":"f","Lstat":"f","MADV_DOFORK":"c","MADV_DONTFORK":"c","MADV_DONTNEED":"c","MADV_HUGEPAGE":"c","MADV_HWPOISON":"c","MADV_MERGEABLE":"c","MADV_NOHUGEPAGE":"c","MADV_NORMAL":"c","MADV_RANDOM":"c","MADV_REMOVE":"c","MADV_SEQUENTIAL":"c","MADV_UNMERGEABLE":"c","MADV_WILLNEED":"c","MAP_32BIT":"c","MAP_ANON":"c","MAP_ANONYMOUS":"c","MAP_DENYWRITE":"c","MAP_EXECUTABLE":"c","MAP_FILE":"c","MAP_FIXED":"c","MAP_GROWSDOWN":"c","MAP_HUGETLB":"c","MAP_LOCKED":"c","MAP_NONBLOCK":"c","MAP_NORESERVE":"c","MAP_POPULATE":"c","MAP_PRIVATE":"c","MAP_SHARED":"c","MAP_STACK":"c","MAP_TYPE":"c","MCL_CURRENT":"c","MCL_FUTURE":"c","MNT_DETACH":"c","MNT_EXPIRE":"c","MNT_FORCE":"c","MSG_CMSG_CLOEXEC":"c","MSG_CONFIRM":"c","MSG_CTRUNC":"c","MSG_DONTROUTE":"c","MSG_DONTWAIT":"c","MSG_EOR":"c","MSG_ERRQUEUE":"c","MSG_FASTOPEN":"c","MSG_FIN":"c","MSG_MORE":"c","MSG_NOSIGNAL":"c","MSG_OOB":"c","MSG_PEEK":"c","MSG_PROXY":"c","MSG_RST":"c","MSG_SYN":"c","MSG_TRUNC":"c","MSG_TRYHARD":"c","MSG_WAITALL":"c","MSG_WAITFORONE":"c","MS_ACTIVE":"c","MS_ASYNC":"c","MS_BIND":"c","MS_DIRSYNC":"c","MS_INVALIDATE":"c","MS_I_VERSION":"c","MS_KERNMOUNT":"c","MS_MANDLOCK":"c","MS_MGC_MSK":"c","MS_MGC_VAL":"c","MS_MOVE":"c","MS_NOATIME":"c","MS_NODEV":"c","MS_NODIRATIME":"c","MS_NOEXEC":"c","MS_NOSUID":"c","MS_NOUSER":"c","MS_POSIXACL":"c","MS_PRIVATE":"c","MS_RDONLY":"c","MS_REC":"c","MS_RELATIME":"c","MS_REMOUNT":"c","MS_RMT_MASK":"c","MS_SHARED":"c","MS_SILENT":"c","MS_SLAVE":"c","MS_STRICTATIME":"c","MS_SYNC":"c","MS_SYNCHRONOUS":"c","MS_UNBINDABLE":"c","Madvise":"f","Mkdir":"f","Mkdirat":"f","Mkfifo":"f","Mknod":"f","Mknodat":"f","Mlock":"f","Mlockall":"f","Mmap":"f","Mount":"f","Mprotect":"f","Msghdr":"t","Msghdr.SetControllen":"m","Munlock":"f","Munlockall":"f","Munmap":"f","NAME_MAX":"c","NETLINK_ADD_MEMBERSHIP":"c","NETLINK_AUDIT":"c","NETLINK_BROADCAST_ERROR":"c","NETLINK_CONNECTOR":"c","NETLINK_DNRTMSG":"c","NETLINK_DROP_MEMBERSHIP":"c","NETLINK_ECRYPTFS":"c","NETLINK_FIB_LOOKUP":"c","NETLINK_FIREWALL":"c","NETLINK_GENERIC":"c","NETLINK_INET_DIAG":"c","NETLINK_IP6_FW":"c","NETLINK_ISCSI":"c","NETLINK_KOBJECT_UEVENT":"c","NETLINK_NETFILTER":"c","NETLINK_NFLOG":"c","NETLINK_NO_ENOBUFS":"c","NETLINK_PKTINFO":"c","NETLINK_ROUTE":"c","NETLINK_SCSITRANSPORT":"c","NETLINK_SELINUX":"c","NETLINK_UNUSED":"c","NETLINK_USERSOCK":"c","NETLINK_XFRM":"c","NLA_ALIGNTO":"c","NLA_F_NESTED":"c","NLA_F_NET_BYTEORDER":"c","NLA_HDRLEN":"c","NLMSG_ALIGNTO":"c","NLMSG_DONE":"c","NLMSG_ERROR":"c","NLMSG_HDRLEN":"c","NLMSG_MIN_TYPE":"c","NLMSG_NOOP":"c","NLMSG_OVERRUN":"c","NLM_F_ACK":"c","NLM_F_APPEND":"c","NLM_F_ATOMIC":"c","NLM_F_CREATE":"c","NLM_F_DUMP":"c","NLM_F_ECHO":"c","NLM_F_EXCL":"c","NLM_F_MATCH":"c","NLM_F_MULTI":"c","NLM_F_REPLACE":"c","NLM_F_REQUEST":"c","NLM_F_ROOT":"c","NOFLSH":"c","Nanosleep":"f","NetlinkMessage":"t","NetlinkRIB":"f","NetlinkRouteAttr":"t","NetlinkRouteRequest":"t","NlAttr":"t","NlMsgerr":"t","NlMsghdr":"t","NsecToTimespec":"f","NsecToTimeval":"f","OCRNL":"c","OFDEL":"c","OFILL":"c","OLCUC":"c","ONLCR":"c","ONLRET":"c","ONOCR":"c","OPOST":"c","O_ACCMODE":"c","O_APPEND":"c","O_ASYNC":"c","O_CLOEXEC":"c","O_CREAT":"c","O_DIRECT":"c","O_DIRECTORY":"c","O_DSYNC":"c","O_EXCL":"c","O_FSYNC":"c","O_LARGEFILE":"c","O_NDELAY":"c","O_NOATIME":"c","O_NOCTTY":"c","O_NOFOLLOW":"c","O_NONBLOCK":"c","O_RDONLY":"c","O_RDWR":"c","O_RSYNC":"c","O_SYNC":"c","O_TRUNC":"c","O_WRONLY":"c","Open":"f","Openat":"f","PACKET_ADD_MEMBERSHIP":"c","PACKET_BROADCAST":"c","PACKET_DROP_MEMBERSHIP":"c","PACKET_FASTROUTE":"c","PACKET_HOST":"c","PACKET_LOOPBACK":"c","PACKET_MR_ALLMULTI":"c","PACKET_MR_MULTICAST":"c","PACKET_MR_PROMISC":"c","PACKET_MULTICAST":"c","PACKET_OTHERHOST":"c","PACKET_OUTGOING":"c","PACKET_RECV_OUTPUT":"c","PACKET_RX_RING":"c","PACKET_STATISTICS":"c","PARENB":"c","PARMRK":"c","PARODD":"c","PENDIN":"c","PRIO_PGRP":"c","PRIO_PROCESS":"c","PRIO_USER":"c","PROT_EXEC":"c","PROT_GROWSDOWN":"c","PROT_GROWSUP":"c","PROT_NONE":"c","PROT_READ":"c","PROT_WRITE":"c","PR_CAPBSET_DROP":"c","PR_CAPBSET_READ":"c","PR_ENDIAN_BIG":"c","PR_ENDIAN_LITTLE":"c","PR_ENDIAN_PPC_LITTLE":"c","PR_FPEMU_NOPRINT":"c","PR_FPEMU_SIGFPE":"c","PR_FP_EXC_ASYNC":"c","PR_FP_EXC_DISABLED":"c","PR_FP_EXC_DIV":"c","PR_FP_EXC_INV":"c","PR_FP_EXC_NONRECOV":"c","PR_FP_EXC_OVF":"c","PR_FP_EXC_PRECISE":"c","PR_FP_EXC_RES":"c","PR_FP_EXC_SW_ENABLE":"c","PR_FP_EXC_UND":"c","PR_GET_DUMPABLE":"c","PR_GET_ENDIAN":"c","PR_GET_FPEMU":"c","PR_GET_FPEXC":"c","PR_GET_KEEPCAPS":"c","PR_GET_NAME":"c","PR_GET_PDEATHSIG":"c","PR_GET_SECCOMP":"c","PR_GET_SECUREBITS":"c","PR_GET_TIMERSLACK":"c","PR_GET_TIMING":"c","PR_GET_TSC":"c","PR_GET_UNALIGN":"c","PR_MCE_KILL":"c","PR_MCE_KILL_CLEAR":"c","PR_MCE_KILL_DEFAULT":"c","PR_MCE_KILL_EARLY":"c","PR_MCE_KILL_GET":"c","PR_MCE_KILL_LATE":"c","PR_MCE_KILL_SET":"c","PR_SET_DUMPABLE":"c","PR_SET_ENDIAN":"c","PR_SET_FPEMU":"c","PR_SET_FPEXC":"c","PR_SET_KEEPCAPS":"c","PR_SET_NAME":"c","PR_SET_PDEATHSIG":"c","PR_SET_PTRACER":"c","PR_SET_SECCOMP":"c","PR_SET_SECUREBITS":"c","PR_SET_TIMERSLACK":"c","PR_SET_TIMING":"c","PR_SET_TSC":"c","PR_SET_UNALIGN":"c","PR_TASK_PERF_EVENTS_DISABLE":"c","PR_TASK_PERF_EVENTS_ENABLE":"c","PR_TIMING_STATISTICAL":"c","PR_TIMING_TIMESTAMP":"c","PR_TSC_ENABLE":"c","PR_TSC_SIGSEGV":"c","PR_UNALIGN_NOPRINT":"c","PR_UNALIGN_SIGBUS":"c","PTRACE_ARCH_PRCTL":"c","PTRACE_ATTACH":"c","PTRACE_CONT":"c","PTRACE_DETACH":"c","PTRACE_EVENT_CLONE":"c","PTRACE_EVENT_EXEC":"c","PTRACE_EVENT_EXIT":"c","PTRACE_EVENT_FORK":"c","PTRACE_EVENT_VFORK":"c","PTRACE_EVENT_VFORK_DONE":"c","PTRACE_GETEVENTMSG":"c","PTRACE_GETFPREGS":"c","PTRACE_GETFPXREGS":"c","PTRACE_GETREGS":"c","PTRACE_GETREGSET":"c","PTRACE_GETSIGINFO":"c","PTRACE_GET_THREAD_AREA":"c","PTRACE_KILL":"c","PTRACE_OLDSETOPTIONS":"c","PTRACE_O_MASK":"c","PTRACE_O_TRACECLONE":"c","PTRACE_O_TRACEEXEC":"c","PTRACE_O_TRACEEXIT":"c","PTRACE_O_TRACEFORK":"c","PTRACE_O_TRACESYSGOOD":"c","PTRACE_O_TRACEVFORK":"c","PTRACE_O_TRACEVFORKDONE":"c","PTRACE_PEEKDATA":"c","PTRACE_PEEKTEXT":"c","PTRACE_PEEKUSR":"c","PTRACE_POKEDATA":"c","PTRACE_POKETEXT":"c","PTRACE_POKEUSR":"c","PTRACE_SETFPREGS":"c","PTRACE_SETFPXREGS":"c","PTRACE_SETOPTIONS":"c","PTRACE_SETREGS":"c","PTRACE_SETREGSET":"c","PTRACE_SETSIGINFO":"c","PTRACE_SET_THREAD_AREA":"c","PTRACE_SINGLEBLOCK":"c","PTRACE_SINGLESTEP":"c","PTRACE_SYSCALL":"c","PTRACE_SYSEMU":"c","PTRACE_SYSEMU_SINGLESTEP":"c","PTRACE_TRACEME":"c","ParseDirent":"f","ParseNetlinkMessage":"f","ParseNetlinkRouteAttr":"f","ParseSocketControlMessage":"f","ParseUnixCredentials":"f","ParseUnixRights":"f","PathMax":"c","Pause":"f","Pipe":"f","Pipe2":"f","PivotRoot":"f","Pread":"f","ProcAttr":"t","PtraceAttach":"f","PtraceCont":"f","PtraceDetach":"f","PtraceGetEventMsg":"f","PtraceGetRegs":"f","PtracePeekData":"f","PtracePeekText":"f","PtracePokeData":"f","PtracePokeText":"f","PtraceRegs":"t","PtraceRegs.PC":"m","PtraceRegs.SetPC":"m","PtraceSetOptions":"f","PtraceSetRegs":"f","PtraceSingleStep":"f","PtraceSyscall":"f","Pwrite":"f","RLIMIT_AS":"c","RLIMIT_CORE":"c","RLIMIT_CPU":"c","RLIMIT_DATA":"c","RLIMIT_FSIZE":"c","RLIMIT_NOFILE":"c","RLIMIT_STACK":"c","RLIM_INFINITY":"c","RTAX_ADVMSS":"c","RTAX_CWND":"c","RTAX_FEATURES":"c","RTAX_FEATURE_ALLFRAG":"c","RTAX_FEATURE_ECN":"c","RTAX_FEATURE_SACK":"c","RTAX_FEATURE_TIMESTAMP":"c","RTAX_HOPLIMIT":"c","RTAX_INITCWND":"c","RTAX_INITRWND":"c","RTAX_LOCK":"c","RTAX_MAX":"c","RTAX_MTU":"c","RTAX_REORDERING":"c","RTAX_RTO_MIN":"c","RTAX_RTT":"c","RTAX_RTTVAR":"c","RTAX_SSTHRESH":"c","RTAX_UNSPEC":"c","RTAX_WINDOW":"c","RTA_ALIGNTO":"c","RTA_CACHEINFO":"c","RTA_DST":"c","RTA_FLOW":"c","RTA_GATEWAY":"c","RTA_IIF":"c","RTA_MAX":"c","RTA_METRICS":"c","RTA_MULTIPATH":"c","RTA_OIF":"c","RTA_PREFSRC":"c","RTA_PRIORITY":"c","RTA_SRC":"c","RTA_TABLE":"c","RTA_UNSPEC":"c","RTCF_DIRECTSRC":"c","RTCF_DOREDIRECT":"c","RTCF_LOG":"c","RTCF_MASQ":"c","RTCF_NAT":"c","RTCF_VALVE":"c","RTF_ADDRCLASSMASK":"c","RTF_ADDRCONF":"c","RTF_ALLONLINK":"c","RTF_BROADCAST":"c","RTF_CACHE":"c","RTF_DEFAULT":"c","RTF_DYNAMIC":"c","RTF_FLOW":"c","RTF_GATEWAY":"c","RTF_HOST":"c","RTF_INTERFACE":"c","RTF_IRTT":"c","RTF_LINKRT":"c","RTF_LOCAL":"c","RTF_MODIFIED":"c","RTF_MSS":"c","RTF_MTU":"c","RTF_MULTICAST":"c","RTF_NAT":"c","RTF_NOFORWARD":"c","RTF_NONEXTHOP":"c","RTF_NOPMTUDISC":"c","RTF_POLICY":"c","RTF_REINSTATE":"c","RTF_REJECT":"c","RTF_STATIC":"c","RTF_THROW":"c","RTF_UP":"c","RTF_WINDOW":"c","RTF_XRESOLVE":"c","RTM_BASE":"c","RTM_DELACTION":"c","RTM_DELADDR":"c","RTM_DELADDRLABEL":"c","RTM_DELLINK":"c","RTM_DELNEIGH":"c","RTM_DELQDISC":"c","RTM_DELROUTE":"c","RTM_DELRULE":"c","RTM_DELTCLASS":"c","RTM_DELTFILTER":"c","RTM_F_CLONED":"c","RTM_F_EQUALIZE":"c","RTM_F_NOTIFY":"c","RTM_F_PREFIX":"c","RTM_GETACTION":"c","RTM_GETADDR":"c","RTM_GETADDRLABEL":"c","RTM_GETANYCAST":"c","RTM_GETDCB":"c","RTM_GETLINK":"c","RTM_GETMULTICAST":"c","RTM_GETNEIGH":"c","RTM_GETNEIGHTBL":"c","RTM_GETQDISC":"c","RTM_GETROUTE":"c","RTM_GETRULE":"c","RTM_GETTCLASS":"c","RTM_GETTFILTER":"c","RTM_MAX":"c","RTM_NEWACTION":"c","RTM_NEWADDR":"c","RTM_NEWADDRLABEL":"c","RTM_NEWLINK":"c","RTM_NEWNDUSEROPT":"c","RTM_NEWNEIGH":"c","RTM_NEWNEIGHTBL":"c","RTM_NEWPREFIX":"c","RTM_NEWQDISC":"c","RTM_NEWROUTE":"c","RTM_NEWRULE":"c","RTM_NEWTCLASS":"c","RTM_NEWTFILTER":"c","RTM_NR_FAMILIES":"c","RTM_NR_MSGTYPES":"c","RTM_SETDCB":"c","RTM_SETLINK":"c","RTM_SETNEIGHTBL":"c","RTNH_ALIGNTO":"c","RTNH_F_DEAD":"c","RTNH_F_ONLINK":"c","RTNH_F_PERVASIVE":"c","RTNLGRP_IPV4_IFADDR":"c","RTNLGRP_IPV4_MROUTE":"c","RTNLGRP_IPV4_ROUTE":"c","RTNLGRP_IPV4_RULE":"c","RTNLGRP_IPV6_IFADDR":"c","RTNLGRP_IPV6_IFINFO":"c","RTNLGRP_IPV6_MROUTE":"c","RTNLGRP_IPV6_PREFIX":"c","RTNLGRP_IPV6_ROUTE":"c","RTNLGRP_IPV6_RULE":"c","RTNLGRP_LINK":"c","RTNLGRP_ND_USEROPT":"c","RTNLGRP_NEIGH":"c","RTNLGRP_NONE":"c","RTNLGRP_NOTIFY":"c","RTNLGRP_TC":"c","RTN_ANYCAST":"c","RTN_BLACKHOLE":"c","RTN_BROADCAST":"c","RTN_LOCAL":"c","RTN_MAX":"c","RTN_MULTICAST":"c","RTN_NAT":"c","RTN_PROHIBIT":"c","RTN_THROW":"c","RTN_UNICAST":"c","RTN_UNREACHABLE":"c","RTN_UNSPEC":"c","RTN_XRESOLVE":"c","RTPROT_BIRD":"c","RTPROT_BOOT":"c","RTPROT_DHCP":"c","RTPROT_DNROUTED":"c","RTPROT_GATED":"c","RTPROT_KERNEL":"c","RTPROT_MRT":"c","RTPROT_NTK":"c","RTPROT_RA":"c","RTPROT_REDIRECT":"c","RTPROT_STATIC":"c","RTPROT_UNSPEC":"c","RTPROT_XORP":"c","RTPROT_ZEBRA":"c","RT_CLASS_DEFAULT":"c","RT_CLASS_LOCAL":"c","RT_CLASS_MAIN":"c","RT_CLASS_MAX":"c","RT_CLASS_UNSPEC":"c","RT_SCOPE_HOST":"c","RT_SCOPE_LINK":"c","RT_SCOPE_NOWHERE":"c","RT_SCOPE_SITE":"c","RT_SCOPE_UNIVERSE":"c","RT_TABLE_COMPAT":"c","RT_TABLE_DEFAULT":"c","RT_TABLE_LOCAL":"c","RT_TABLE_MAIN":"c","RT_TABLE_MAX":"c","RT_TABLE_UNSPEC":"c","RUSAGE_CHILDREN":"c","RUSAGE_SELF":"c","RUSAGE_THREAD":"c","RawConn":"t","RawSockaddr":"t","RawSockaddrAny":"t","RawSockaddrInet4":"t","RawSockaddrInet6":"t","RawSockaddrLinklayer":"t","RawSockaddrNetlink":"t","RawSockaddrUnix":"t","RawSyscall":"f","RawSyscall6":"f","Read":"f","ReadDirent":"f","Readlink":"f","Reboot":"f","Recvfrom":"f","Recvmsg":"f","Removexattr":"f","Rename":"f","Renameat":"f","Rlimit":"t","Rmdir":"f","RtAttr":"t","RtGenmsg":"t","RtMsg":"t","RtNexthop":"t","Rusage":"t","SCM_CREDENTIALS":"c","SCM_RIGHTS":"c","SCM_TIMESTAMP":"c","SCM_TIMESTAMPING":"c","SCM_TIMESTAMPNS":"c","SHUT_RD":"c","SHUT_RDWR":"c","SHUT_WR":"c","SIGABRT":"c","SIGALRM":"c","SIGBUS":"c","SIGCHLD":"c","SIGCLD":"c","SIGCONT":"c","SIGFPE":"c","SIGHUP":"c","SIGILL":"c","SIGINT":"c","SIGIO":"c","SIGIOT":"c","SIGKILL":"c","SIGPIPE":"c","SIGPOLL":"c","SIGPROF":"c","SIGPWR":"c","SIGQUIT":"c","SIGSEGV":"c","SIGSTKFLT":"c","SIGSTOP":"c","SIGSYS":"c","SIGTERM":"c","SIGTRAP":"c","SIGTSTP":"c","SIGTTIN":"c","SIGTTOU":"c","SIGUNUSED":"c","SIGURG":"c","SIGUSR1":"c","SIGUSR2":"c","SIGVTALRM":"c","SIGWINCH":"c","SIGXCPU":"c","SIGXFSZ":"c","SIOCADDDLCI":"c","SIOCADDMULTI":"c","SIOCADDRT":"c","SIOCATMARK":"c","SIOCDARP":"c","SIOCDELDLCI":"c","SIOCDELMULTI":"c","SIOCDELRT":"c","SIOCDEVPRIVATE":"c","SIOCDIFADDR":"c","SIOCDRARP":"c","SIOCGARP":"c","SIOCGIFADDR":"c","SIOCGIFBR":"c","SIOCGIFBRDADDR":"c","SIOCGIFCONF":"c","SIOCGIFCOUNT":"c","SIOCGIFDSTADDR":"c","SIOCGIFENCAP":"c","SIOCGIFFLAGS":"c","SIOCGIFHWADDR":"c","SIOCGIFINDEX":"c","SIOCGIFMAP":"c","SIOCGIFMEM":"c","SIOCGIFMETRIC":"c","SIOCGIFMTU":"c","SIOCGIFNAME":"c","SIOCGIFNETMASK":"c","SIOCGIFPFLAGS":"c","SIOCGIFSLAVE":"c","SIOCGIFTXQLEN":"c","SIOCGPGRP":"c","SIOCGRARP":"c","SIOCGSTAMP":"c","SIOCGSTAMPNS":"c","SIOCPROTOPRIVATE":"c","SIOCRTMSG":"c","SIOCSARP":"c","SIOCSIFADDR":"c","SIOCSIFBR":"c","SIOCSIFBRDADDR":"c","SIOCSIFDSTADDR":"c","SIOCSIFENCAP":"c","SIOCSIFFLAGS":"c","SIOCSIFHWADDR":"c","SIOCSIFHWBROADCAST":"c","SIOCSIFLINK":"c","SIOCSIFMAP":"c","SIOCSIFMEM":"c","SIOCSIFMETRIC":"c","SIOCSIFMTU":"c","SIOCSIFNAME":"c","SIOCSIFNETMASK":"c","SIOCSIFPFLAGS":"c","SIOCSIFSLAVE":"c","SIOCSIFTXQLEN":"c","SIOCSPGRP":"c","SIOCSRARP":"c","SOCK_CLOEXEC":"c","SOCK_DCCP":"c","SOCK_DGRAM":"c","SOCK_NONBLOCK":"c","SOCK_PACKET":"c","SOCK_RAW":"c","SOCK_RDM":"c","SOCK_SEQPACKET":"c","SOCK_STREAM":"c","SOL_AAL":"c","SOL_ATM":"c","SOL_DECNET":"c","SOL_ICMPV6":"c","SOL_IP":"c","SOL_IPV6":"c","SOL_IRDA":"c","SOL_PACKET":"c","SOL_RAW":"c","SOL_SOCKET":"c","SOL_TCP":"c","SOL_X25":"c","SOMAXCONN":"c","SO_ACCEPTCONN":"c","SO_ATTACH_FILTER":"c","SO_BINDTODEVICE":"c","SO_BROADCAST":"c","SO_BSDCOMPAT":"c","SO_DEBUG":"c","SO_DETACH_FILTER":"c","SO_DOMAIN":"c","SO_DONTROUTE":"c","SO_ERROR":"c","SO_KEEPALIVE":"c","SO_LINGER":"c","SO_MARK":"c","SO_NO_CHECK":"c","SO_OOBINLINE":"c","SO_PASSCRED":"c","SO_PASSSEC":"c","SO_PEERCRED":"c","SO_PEERNAME":"c","SO_PEERSEC":"c","SO_PRIORITY":"c","SO_PROTOCOL":"c","SO_RCVBUF":"c","SO_RCVBUFFORCE":"c","SO_RCVLOWAT":"c","SO_RCVTIMEO":"c","SO_REUSEADDR":"c","SO_RXQ_OVFL":"c","SO_SECURITY_AUTHENTICATION":"c","SO_SECURITY_ENCRYPTION_NETWORK":"c","SO_SECURITY_ENCRYPTION_TRANSPORT":"c","SO_SNDBUF":"c","SO_SNDBUFFORCE":"c","SO_SNDLOWAT":"c","SO_SNDTIMEO":"c","SO_TIMESTAMP":"c","SO_TIMESTAMPING":"c","SO_TIMESTAMPNS":"c","SO_TYPE":"c","SYS_ACCEPT":"c","SYS_ACCEPT4":"c","SYS_ACCESS":"c","SYS_ACCT":"c","SYS_ADD_KEY":"c","SYS_ADJTIMEX":"c","SYS_AFS_SYSCALL":"c","SYS_ALARM":"c","SYS_ARCH_PRCTL":"c","SYS_BIND":"c","SYS_BRK":"c","SYS_CAPGET":"c","SYS_CAPSET":"c","SYS_CHDIR":"c","SYS_CHMOD":"c","SYS_CHOWN":"c","SYS_CHROOT":"c","SYS_CLOCK_GETRES":"c","SYS_CLOCK_GETTIME":"c","SYS_CLOCK_NANOSLEEP":"c","SYS_CLOCK_SETTIME":"c","SYS_CLONE":"c","SYS_CLOSE":"c","SYS_CONNECT":"c","SYS_CREAT":"c","SYS_CREATE_MODULE":"c","SYS_DELETE_MODULE":"c","SYS_DUP":"c","SYS_DUP2":"c","SYS_DUP3":"c","SYS_EPOLL_CREATE":"c","SYS_EPOLL_CREATE1":"c","SYS_EPOLL_CTL":"c","SYS_EPOLL_CTL_OLD":"c","SYS_EPOLL_PWAIT":"c","SYS_EPOLL_WAIT":"c","SYS_EPOLL_WAIT_OLD":"c","SYS_EVENTFD":"c","SYS_EVENTFD2":"c","SYS_EXECVE":"c","SYS_EXIT":"c","SYS_EXIT_GROUP":"c","SYS_FACCESSAT":"c","SYS_FADVISE64":"c","SYS_FALLOCATE":"c","SYS_FANOTIFY_INIT":"c","SYS_FANOTIFY_MARK":"c","SYS_FCHDIR":"c","SYS_FCHMOD":"c","SYS_FCHMODAT":"c","SYS_FCHOWN":"c","SYS_FCHOWNAT":"c","SYS_FCNTL":"c","SYS_FDATASYNC":"c","SYS_FGETXATTR":"c","SYS_FLISTXATTR":"c","SYS_FLOCK":"c","SYS_FORK":"c","SYS_FREMOVEXATTR":"c","SYS_FSETXATTR":"c","SYS_FSTAT":"c","SYS_FSTATFS":"c","SYS_FSYNC":"c","SYS_FTRUNCATE":"c","SYS_FUTEX":"c","SYS_FUTIMESAT":"c","SYS_GETCWD":"c","SYS_GETDENTS":"c","SYS_GETDENTS64":"c","SYS_GETEGID":"c","SYS_GETEUID":"c","SYS_GETGID":"c","SYS_GETGROUPS":"c","SYS_GETITIMER":"c","SYS_GETPEERNAME":"c","SYS_GETPGID":"c","SYS_GETPGRP":"c","SYS_GETPID":"c","SYS_GETPMSG":"c","SYS_GETPPID":"c","SYS_GETPRIORITY":"c","SYS_GETRESGID":"c","SYS_GETRESUID":"c","SYS_GETRLIMIT":"c","SYS_GETRUSAGE":"c","SYS_GETSID":"c","SYS_GETSOCKNAME":"c","SYS_GETSOCKOPT":"c","SYS_GETTID":"c","SYS_GETTIMEOFDAY":"c","SYS_GETUID":"c","SYS_GETXATTR":"c","SYS_GET_KERNEL_SYMS":"c","SYS_GET_MEMPOLICY":"c","SYS_GET_ROBUST_LIST":"c","SYS_GET_THREAD_AREA":"c","SYS_INIT_MODULE":"c","SYS_INOTIFY_ADD_WATCH":"c","SYS_INOTIFY_INIT":"c","SYS_INOTIFY_INIT1":"c","SYS_INOTIFY_RM_WATCH":"c","SYS_IOCTL":"c","SYS_IOPERM":"c","SYS_IOPL":"c","SYS_IOPRIO_GET":"c","SYS_IOPRIO_SET":"c","SYS_IO_CANCEL":"c","SYS_IO_DESTROY":"c","SYS_IO_GETEVENTS":"c","SYS_IO_SETUP":"c","SYS_IO_SUBMIT":"c","SYS_KEXEC_LOAD":"c","SYS_KEYCTL":"c","SYS_KILL":"c","SYS_LCHOWN":"c","SYS_LGETXATTR":"c","SYS_LINK":"c","SYS_LINKAT":"c","SYS_LISTEN":"c","SYS_LISTXATTR":"c","SYS_LLISTXATTR":"c","SYS_LOOKUP_DCOOKIE":"c","SYS_LREMOVEXATTR":"c","SYS_LSEEK":"c","SYS_LSETXATTR":"c","SYS_LSTAT":"c","SYS_MADVISE":"c","SYS_MBIND":"c","SYS_MIGRATE_PAGES":"c","SYS_MINCORE":"c","SYS_MKDIR":"c","SYS_MKDIRAT":"c","SYS_MKNOD":"c","SYS_MKNODAT":"c","SYS_MLOCK":"c","SYS_MLOCKALL":"c","SYS_MMAP":"c","SYS_MODIFY_LDT":"c","SYS_MOUNT":"c","SYS_MOVE_PAGES":"c","SYS_MPROTECT":"c","SYS_MQ_GETSETATTR":"c","SYS_MQ_NOTIFY":"c","SYS_MQ_OPEN":"c","SYS_MQ_TIMEDRECEIVE":"c","SYS_MQ_TIMEDSEND":"c","SYS_MQ_UNLINK":"c","SYS_MREMAP":"c","SYS_MSGCTL":"c","SYS_MSGGET":"c","SYS_MSGRCV":"c","SYS_MSGSND":"c","SYS_MSYNC":"c","SYS_MUNLOCK":"c","SYS_MUNLOCKALL":"c","SYS_MUNMAP":"c","SYS_NANOSLEEP":"c","SYS_NEWFSTATAT":"c","SYS_NFSSERVCTL":"c","SYS_OPEN":"c","SYS_OPENAT":"c","SYS_PAUSE":"c","SYS_PERF_EVENT_OPEN":"c","SYS_PERSONALITY":"c","SYS_PIPE":"c","SYS_PIPE2":"c","SYS_PIVOT_ROOT":"c","SYS_POLL":"c","SYS_PPOLL":"c","SYS_PRCTL":"c","SYS_PREAD64":"c","SYS_PREADV":"c","SYS_PRLIMIT64":"c","SYS_PSELECT6":"c","SYS_PTRACE":"c","SYS_PUTPMSG":"c","SYS_PWRITE64":"c","SYS_PWRITEV":"c","SYS_QUERY_MODULE":"c","SYS_QUOTACTL":"c","SYS_READ":"c","SYS_READAHEAD":"c","SYS_READLINK":"c","SYS_READLINKAT":"c","SYS_READV":"c","SYS_REBOOT":"c","SYS_RECVFROM":"c","SYS_RECVMMSG":"c","SYS_RECVMSG":"c","SYS_REMAP_FILE_PAGES":"c","SYS_REMOVEXATTR":"c","SYS_RENAME":"c","SYS_RENAMEAT":"c","SYS_REQUEST_KEY":"c","SYS_RESTART_SYSCALL":"c","SYS_RMDIR":"c","SYS_RT_SIGACTION":"c","SYS_RT_SIGPENDING":"c","SYS_RT_SIGPROCMASK":"c","SYS_RT_SIGQUEUEINFO":"c","SYS_RT_SIGRETURN":"c","SYS_RT_SIGSUSPEND":"c","SYS_RT_SIGTIMEDWAIT":"c","SYS_RT_TGSIGQUEUEINFO":"c","SYS_SCHED_GETAFFINITY":"c","SYS_SCHED_GETPARAM":"c","SYS_SCHED_GETSCHEDULER":"c","SYS_SCHED_GET_PRIORITY_MAX":"c","SYS_SCHED_GET_PRIORITY_MIN":"c","SYS_SCHED_RR_GET_INTERVAL":"c","SYS_SCHED_SETAFFINITY":"c","SYS_SCHED_SETPARAM":"c","SYS_SCHED_SETSCHEDULER":"c","SYS_SCHED_YIELD":"c","SYS_SECURITY":"c","SYS_SELECT":"c","SYS_SEMCTL":"c","SYS_SEMGET":"c","SYS_SEMOP":"c","SYS_SEMTIMEDOP":"c","SYS_SENDFILE":"c","SYS_SENDMSG":"c","SYS_SENDTO":"c","SYS_SETDOMAINNAME":"c","SYS_SETFSGID":"c","SYS_SETFSUID":"c","SYS_SETGID":"c","SYS_SETGROUPS":"c","SYS_SETHOSTNAME":"c","SYS_SETITIMER":"c","SYS_SETPGID":"c","SYS_SETPRIORITY":"c","SYS_SETREGID":"c","SYS_SETRESGID":"c","SYS_SETRESUID":"c","SYS_SETREUID":"c","SYS_SETRLIMIT":"c","SYS_SETSID":"c","SYS_SETSOCKOPT":"c","SYS_SETTIMEOFDAY":"c","SYS_SETUID":"c","SYS_SETXATTR":"c","SYS_SET_MEMPOLICY":"c","SYS_SET_ROBUST_LIST":"c","SYS_SET_THREAD_AREA":"c","SYS_SET_TID_ADDRESS":"c","SYS_SHMAT":"c","SYS_SHMCTL":"c","SYS_SHMDT":"c","SYS_SHMGET":"c","SYS_SHUTDOWN":"c","SYS_SIGALTSTACK":"c","SYS_SIGNALFD":"c","SYS_SIGNALFD4":"c","SYS_SOCKET":"c","SYS_SOCKETPAIR":"c","SYS_SPLICE":"c","SYS_STAT":"c","SYS_STATFS":"c","SYS_SWAPOFF":"c","SYS_SWAPON":"c","SYS_SYMLINK":"c","SYS_SYMLINKAT":"c","SYS_SYNC":"c","SYS_SYNC_FILE_RANGE":"c","SYS_SYSFS":"c","SYS_SYSINFO":"c","SYS_SYSLOG":"c","SYS_TEE":"c","SYS_TGKILL":"c","SYS_TIME":"c","SYS_TIMERFD_CREATE":"c","SYS_TIMERFD_GETTIME":"c","SYS_TIMERFD_SETTIME":"c","SYS_TIMER_CREATE":"c","SYS_TIMER_DELETE":"c","SYS_TIMER_GETOVERRUN":"c","SYS_TIMER_GETTIME":"c","SYS_TIMER_SETTIME":"c","SYS_TIMES":"c","SYS_TKILL":"c","SYS_TRUNCATE":"c","SYS_TUXCALL":"c","SYS_UMASK":"c","SYS_UMOUNT2":"c","SYS_UNAME":"c","SYS_UNLINK":"c","SYS_UNLINKAT":"c","SYS_UNSHARE":"c","SYS_USELIB":"c","SYS_USTAT":"c","SYS_UTIME":"c","SYS_UTIMENSAT":"c","SYS_UTIMES":"c","SYS_VFORK":"c","SYS_VHANGUP":"c","SYS_VMSPLICE":"c","SYS_VSERVER":"c","SYS_WAIT4":"c","SYS_WAITID":"c","SYS_WRITE":"c","SYS_WRITEV":"c","SYS__SYSCTL":"c","S_BLKSIZE":"c","S_IEXEC":"c","S_IFBLK":"c","S_IFCHR":"c","S_IFDIR":"c","S_IFIFO":"c","S_IFLNK":"c","S_IFMT":"c","S_IFREG":"c","S_IFSOCK":"c","S_IREAD":"c","S_IRGRP":"c","S_IROTH":"c","S_IRUSR":"c","S_IRWXG":"c","S_IRWXO":"c","S_IRWXU":"c","S_ISGID":"c","S_ISUID":"c","S_ISVTX":"c","S_IWGRP":"c","S_IWOTH":"c","S_IWRITE":"c","S_IWUSR":"c","S_IXGRP":"c","S_IXOTH":"c","S_IXUSR":"c","Seek":"f","Select":"f","Sendfile":"f","Sendmsg":"f","SendmsgN":"f","Sendto":"f","SetLsfPromisc":"f","SetNonblock":"f","Setdomainname":"f","Setegid":"f","Setenv":"f","Seteuid":"f","Setfsgid":"f","Setfsuid":"f","Setgid":"f","Setgroups":"f","Sethostname":"f","Setpgid":"f","Setpriority":"f","Setregid":"f","Setresgid":"f","Setresuid":"f","Setreuid":"f","Setrlimit":"f","Setsid":"f","SetsockoptByte":"f","SetsockoptICMPv6Filter":"f","SetsockoptIPMreq":"f","SetsockoptIPMreqn":"f","SetsockoptIPv6Mreq":"f","SetsockoptInet4Addr":"f","SetsockoptInt":"f","SetsockoptLinger":"f","SetsockoptString":"f","SetsockoptTimeval":"f","Settimeofday":"f","Setuid":"f","Setxattr":"f","Shutdown":"f","Signal":"t","Signal.Signal":"m","Signal.String":"m","SizeofCmsghdr":"c","SizeofICMPv6Filter":"c","SizeofIPMreq":"c","SizeofIPMreqn":"c","SizeofIPv6MTUInfo":"c","SizeofIPv6Mreq":"c","SizeofIfAddrmsg":"c","SizeofIfInfomsg":"c","SizeofInet4Pktinfo":"c","SizeofInet6Pktinfo":"c","SizeofInotifyEvent":"c","SizeofLinger":"c","SizeofMsghdr":"c","SizeofNlAttr":"c","SizeofNlMsgerr":"c","SizeofNlMsghdr":"c","SizeofRtAttr":"c","SizeofRtGenmsg":"c","SizeofRtMsg":"c","SizeofRtNexthop":"c","SizeofSockFilter":"c","SizeofSockFprog":"c","SizeofSockaddrAny":"c","SizeofSockaddrInet4":"c","SizeofSockaddrInet6":"c","SizeofSockaddrLinklayer":"c","SizeofSockaddrNetlink":"c","SizeofSockaddrUnix":"c","SizeofTCPInfo":"c","SizeofUcred":"c","SlicePtrFromStrings":"f","SockFilter":"t","SockFprog":"t","Sockaddr":"t","SockaddrInet4":"t","SockaddrInet6":"t","SockaddrLinklayer":"t","SockaddrNetlink":"t","SockaddrUnix":"t","Socket":"f","SocketControlMessage":"t","SocketDisableIPv6":"v","Socketpair":"f","Splice":"f","StartProcess":"f","Stat":"f","Stat_t":"t","Statfs":"f","Statfs_t":"t","Stderr":"v","Stdin":"v","Stdout":"v","StringBytePtr":"f","StringByteSlice":"f","StringSlicePtr":"f","Symlink":"f","Sync":"f","SyncFileRange":"f","SysProcAttr":"t","SysProcIDMap":"t","Syscall":"f","Syscall6":"f","Sysinfo":"f","Sysinfo_t":"t","TCGETS":"c","TCIFLUSH":"c","TCIOFLUSH":"c","TCOFLUSH":"c","TCPInfo":"t","TCP_CONGESTION":"c","TCP_CORK":"c","TCP_DEFER_ACCEPT":"c","TCP_INFO":"c","TCP_KEEPCNT":"c","TCP_KEEPIDLE":"c","TCP_KEEPINTVL":"c","TCP_LINGER2":"c","TCP_MAXSEG":"c","TCP_MAXWIN":"c","TCP_MAX_WINSHIFT":"c","TCP_MD5SIG":"c","TCP_MD5SIG_MAXKEYLEN":"c","TCP_MSS":"c","TCP_NODELAY":"c","TCP_QUICKACK":"c","TCP_SYNCNT":"c","TCP_WINDOW_CLAMP":"c","TCSETS":"c","TIOCCBRK":"c","TIOCCONS":"c","TIOCEXCL":"c","TIOCGDEV":"c","TIOCGETD":"c","TIOCGICOUNT":"c","TIOCGLCKTRMIOS":"c","TIOCGPGRP":"c","TIOCGPTN":"c","TIOCGRS485":"c","TIOCGSERIAL":"c","TIOCGSID":"c","TIOCGSOFTCAR":"c","TIOCGWINSZ":"c","TIOCINQ":"c","TIOCLINUX":"c","TIOCMBIC":"c","TIOCMBIS":"c","TIOCMGET":"c","TIOCMIWAIT":"c","TIOCMSET":"c","TIOCM_CAR":"c","TIOCM_CD":"c","TIOCM_CTS":"c","TIOCM_DSR":"c","TIOCM_DTR":"c","TIOCM_LE":"c","TIOCM_RI":"c","TIOCM_RNG":"c","TIOCM_RTS":"c","TIOCM_SR":"c","TIOCM_ST":"c","TIOCNOTTY":"c","TIOCNXCL":"c","TIOCOUTQ":"c","TIOCPKT":"c","TIOCPKT_DATA":"c","TIOCPKT_DOSTOP":"c","TIOCPKT_FLUSHREAD":"c","TIOCPKT_FLUSHWRITE":"c","TIOCPKT_IOCTL":"c","TIOCPKT_NOSTOP":"c","TIOCPKT_START":"c","TIOCPKT_STOP":"c","TIOCSBRK":"c","TIOCSCTTY":"c","TIOCSERCONFIG":"c","TIOCSERGETLSR":"c","TIOCSERGETMULTI":"c","TIOCSERGSTRUCT":"c","TIOCSERGWILD":"c","TIOCSERSETMULTI":"c","TIOCSERSWILD":"c","TIOCSER_TEMT":"c","TIOCSETD":"c","TIOCSIG":"c","TIOCSLCKTRMIOS":"c","TIOCSPGRP":"c","TIOCSPTLCK":"c","TIOCSRS485":"c","TIOCSSERIAL":"c","TIOCSSOFTCAR":"c","TIOCSTI":"c","TIOCSWINSZ":"c","TOSTOP":"c","TUNATTACHFILTER":"c","TUNDETACHFILTER":"c","TUNGETFEATURES":"c","TUNGETIFF":"c","TUNGETSNDBUF":"c","TUNGETVNETHDRSZ":"c","TUNSETDEBUG":"c","TUNSETGROUP":"c","TUNSETIFF":"c","TUNSETLINK":"c","TUNSETNOCSUM":"c","TUNSETOFFLOAD":"c","TUNSETOWNER":"c","TUNSETPERSIST":"c","TUNSETSNDBUF":"c","TUNSETTXFILTER":"c","TUNSETVNETHDRSZ":"c","Tee":"f","Termios":"t","Tgkill":"f","Time":"f","Time_t":"t","Times":"f","Timespec":"t","Timespec.Nano":"m","Timespec.Unix":"m","TimespecToNsec":"f","Timeval":"t","Timeval.Nano":"m","Timeval.Unix":"m","TimevalToNsec":"f","Timex":"t","Tms":"t","Truncate":"f","Ucred":"t","Umask":"f","Uname":"f","UnixCredentials":"f","UnixRights":"f","Unlink":"f","Unlinkat":"f","Unmount":"f","Unsetenv":"f","Unshare":"f","Ustat":"f","Ustat_t":"t","Utimbuf":"t","Utime":"f","Utimes":"f","UtimesNano":"f","Utsname":"t","VDISCARD":"c","VEOF":"c","VEOL":"c","VEOL2":"c","VERASE":"c","VINTR":"c","VKILL":"c","VLNEXT":"c","VMIN":"c","VQUIT":"c","VREPRINT":"c","VSTART":"c","VSTOP":"c","VSUSP":"c","VSWTC":"c","VTIME":"c","VWERASE":"c","WALL":"c","WCLONE":"c","WCONTINUED":"c","WEXITED":"c","WNOHANG":"c","WNOTHREAD":"c","WNOWAIT":"c","WORDSIZE":"c","WSTOPPED":"c","WUNTRACED":"c","Wait4":"f","WaitStatus":"t","WaitStatus.Continued":"m","WaitStatus.CoreDump":"m","WaitStatus.ExitStatus":"m","WaitStatus.Exited":"m","WaitStatus.Signal":"m","WaitStatus.Signaled":"m","WaitStatus.StopSignal":"m","WaitStatus.Stopped":"m","WaitStatus.TrapCause":"m","Write":"f","XCASE":"c"}},"testing":{"path":"testing","name":"testing","symbols":{"AllocsPerRun":"f","B":"t","B.Elapsed":"m","B.Loop":"m","B.ReportAllocs":"m","B.ReportMetric":"m","B.ResetTimer":"m","B.Run":"m","B.RunParallel":"m","B.SetBytes":"m","B.SetParallelism":"m","B.StartTimer":"m","B.StopTimer":"m","Benchmark":"f","BenchmarkResult":"t","BenchmarkResult.AllocedBytesPerOp":"m","BenchmarkResult.AllocsPerOp":"m","BenchmarkResult.MemString":"m","BenchmarkResult.NsPerOp":"m","BenchmarkResult.String":"m","Cover":"t","CoverBlock":"t","CoverMode":"f","Coverage":"f","F":"t","F.Add":"m","F.Fail":"m","F.Fuzz":"m","F.Helper":"m","F.Skipped":"m","Init":"f","InternalBenchmark":"t","InternalExample":"t","InternalFuzzTarget":"t","InternalTest":"t","M":"t","M.Run":"m","Main":"f","MainStart":"f","PB":"t","PB.Next":"m","RegisterCover":"f","RunBenchmarks":"f","RunExamples":"f","RunTests":"f","Short":"f","T":"t","T.Chdir":"m","T.Deadline":"m","T.Parallel":"m","T.Run":"m","T.Setenv":"m","TB":"t","Testing":"f","Verbose":"f"}},"testing/cryptotest":{"path":"testing/cryptotest","name":"cryptotest","symbols":{"SetGlobalRandom":"f"}},"testing/fstest":{"path":"testing/fstest","name":"fstest","symbols":{"MapFS":"t","MapFS.Glob":"m","MapFS.Lstat":"m","MapFS.Open":"m","MapFS.ReadDir":"m","MapFS.ReadFile":"m","MapFS.ReadLink":"m","MapFS.Stat":"m","MapFS.Sub":"m","MapFile":"t","TestFS":"f"}},"testing/iotest":{"path":"testing/iotest","name":"iotest","symbols":{"DataErrReader":"f","ErrReader":"f","ErrTimeout":"v","HalfReader":"f","NewReadLogger":"f","NewWriteLogger":"f","OneByteReader":"f","TestReader":"f","TimeoutReader":"f","TruncateWriter":"f"}},"testing/quick":{"path":"testing/quick","name":"quick","symbols":{"Check":"f","CheckEqual":"f","CheckEqualError":"t","CheckEqualError.Error":"m","CheckError":"t","CheckError.Error":"m","Config":"t","Generator":"t","SetupError":"t","SetupError.Error":"m","Value":"f"}},"testing/slogtest":{"path":"testing/slogtest","name":"slogtest","symbols":{"Run":"f","TestHandler":"f"}},"testing/synctest":{"path":"testing/synctest","name":"synctest","symbols":{"Test":"f","Wait":"f"}},"text/scanner":{"path":"text/scanner","name":"scanner","symbols":{"Char":"c","Comment":"c","EOF":"c","Float":"c","GoTokens":"c","GoWhitespace":"c","Ident":"c","Int":"c","Position":"t","Position.IsValid":"m","Position.String":"m","RawString":"c","ScanChars":"c","ScanComments":"c","ScanFloats":"c","ScanIdents":"c","ScanInts":"c","ScanRawStrings":"c","ScanStrings":"c","Scanner":"t","Scanner.Init":"m","Scanner.Next":"m","Scanner.Peek":"m","Scanner.Pos":"m","Scanner.Scan":"m","Scanner.TokenText":"m","SkipComments":"c","String":"c","TokenString":"f"}},"text/tabwriter":{"path":"text/tabwriter","name":"tabwriter","symbols":{"AlignRight":"c","Debug":"c","DiscardEmptyColumns":"c","Escape":"c","FilterHTML":"c","NewWriter":"f","StripEscape":"c","TabIndent":"c","Writer":"t","Writer.Flush":"m","Writer.Init":"m","Writer.Write":"m"}},"text/template":{"path":"text/template","name":"template","symbols":{"ExecError":"t","ExecError.Error":"m","ExecError.Unwrap":"m","FuncMap":"t","HTMLEscape":"f","HTMLEscapeString":"f","HTMLEscaper":"f","IsTrue":"f","JSEscape":"f","JSEscapeString":"f","JSEscaper":"f","Must":"f","New":"f","ParseFS":"f","ParseFiles":"f","ParseGlob":"f","Template":"t","Template.AddParseTree":"m","Template.Clone":"m","Template.DefinedTemplates":"m","Template.Delims":"m","Template.Execute":"m","Template.ExecuteTemplate":"m","Template.Funcs":"m","Template.Lookup":"m","Template.Name":"m","Template.New":"m","Template.Option":"m","Template.Parse":"m","Template.ParseFS":"m","Template.ParseFiles":"m","Template.ParseGlob":"m","Template.Templates":"m","URLQueryEscaper":"f"}},"text/template/parse":{"path":"text/template/parse","name":"parse","symbols":{"ActionNode":"t","ActionNode.Copy":"m","ActionNode.String":"m","BoolNode":"t","BoolNode.Copy":"m","BoolNode.String":"m","BranchNode":"t","BranchNode.Copy":"m","BranchNode.String":"m","BreakNode":"t","BreakNode.Copy":"m","BreakNode.String":"m","ChainNode":"t","ChainNode.Add":"m","ChainNode.Copy":"m","ChainNode.String":"m","CommandNode":"t","CommandNode.Copy":"m","CommandNode.String":"m","CommentNode":"t","CommentNode.Copy":"m","CommentNode.String":"m","ContinueNode":"t","ContinueNode.Copy":"m","ContinueNode.String":"m","DotNode":"t","DotNode.Copy":"m","DotNode.String":"m","DotNode.Type":"m","FieldNode":"t","FieldNode.Copy":"m","FieldNode.String":"m","IdentifierNode":"t","IdentifierNode.Copy":"m","IdentifierNode.SetPos":"m","IdentifierNode.SetTree":"m","IdentifierNode.String":"m","IfNode":"t","IfNode.Copy":"m","IsEmptyTree":"f","ListNode":"t","ListNode.Copy":"m","ListNode.CopyList":"m","ListNode.String":"m","Mode":"t","New":"f","NewIdentifier":"f","NilNode":"t","NilNode.Copy":"m","NilNode.String":"m","NilNode.Type":"m","Node":"t","NodeAction":"c","NodeBool":"c","NodeBreak":"c","NodeChain":"c","NodeCommand":"c","NodeComment":"c","NodeContinue":"c","NodeDot":"c","NodeField":"c","NodeIdentifier":"c","NodeIf":"c","NodeList":"c","NodeNil":"c","NodeNumber":"c","NodePipe":"c","NodeRange":"c","NodeString":"c","NodeTemplate":"c","NodeText":"c","NodeType":"t","NodeType.Type":"m","NodeVariable":"c","NodeWith":"c","NumberNode":"t","NumberNode.Copy":"m","NumberNode.String":"m","Parse":"f","ParseComments":"c","PipeNode":"t","PipeNode.Copy":"m","PipeNode.CopyPipe":"m","PipeNode.String":"m","Pos":"t","Pos.Position":"m","RangeNode":"t","RangeNode.Copy":"m","SkipFuncCheck":"c","StringNode":"t","StringNode.Copy":"m","StringNode.String":"m","TemplateNode":"t","TemplateNode.Copy":"m","TemplateNode.String":"m","TextNode":"t","TextNode.Copy":"m","TextNode.String":"m","Tree":"t","Tree.Copy":"m","Tree.ErrorContext":"m","Tree.Parse":"m","VariableNode":"t","VariableNode.Copy":"m","VariableNode.String":"m","WithNode":"t","WithNode.Copy":"m"}},"time":{"path":"time","name":"time","symbols":{"ANSIC":"c","After":"f","AfterFunc":"f","April":"c","August":"c","Date":"f","DateOnly":"c","DateTime":"c","December":"c","Duration":"t","Duration.Abs":"m","Duration.Hours":"m","Duration.Microseconds":"m","Duration.Milliseconds":"m","Duration.Minutes":"m","Duration.Nanoseconds":"m","Duration.Round":"m","Duration.Seconds":"m","Duration.String":"m","Duration.Truncate":"m","February":"c","FixedZone":"f","Friday":"c","Hour":"c","January":"c","July":"c","June":"c","Kitchen":"c","Layout":"c","LoadLocation":"f","LoadLocationFromTZData":"f","Local":"v","Location":"t","Location.String":"m","March":"c","May":"c","Microsecond":"c","Millisecond":"c","Minute":"c","Monday":"c","Month":"t","Month.String":"m","Nanosecond":"c","NewTicker":"f","NewTimer":"f","November":"c","Now":"f","October":"c","Parse":"f","ParseDuration":"f","ParseError":"t","ParseError.Error":"m","ParseInLocation":"f","RFC1123":"c","RFC1123Z":"c","RFC3339":"c","RFC3339Nano":"c","RFC822":"c","RFC822Z":"c","RFC850":"c","RubyDate":"c","Saturday":"c","Second":"c","September":"c","Since":"f","Sleep":"f","Stamp":"c","StampMicro":"c","StampMilli":"c","StampNano":"c","Sunday":"c","Thursday":"c","Tick":"f","Ticker":"t","Ticker.Reset":"m","Ticker.Stop":"m","Time":"t","Time.Add":"m","Time.AddDate":"m","Time.After":"m","Time.AppendBinary":"m","Time.AppendFormat":"m","Time.AppendText":"m","Time.Before":"m","Time.Clock":"m","Time.Compare":"m","Time.Date":"m","Time.Day":"m","Time.Equal":"m","Time.Format":"m","Time.GoString":"m","Time.GobDecode":"m","Time.GobEncode":"m","Time.Hour":"m","Time.ISOWeek":"m","Time.In":"m","Time.IsDST":"m","Time.IsZero":"m","Time.Local":"m","Time.Location":"m","Time.MarshalBinary":"m","Time.MarshalJSON":"m","Time.MarshalText":"m","Time.Minute":"m","Time.Month":"m","Time.Nanosecond":"m","Time.Round":"m","Time.Second":"m","Time.String":"m","Time.Sub":"m","Time.Truncate":"m","Time.UTC":"m","Time.Unix":"m","Time.UnixMicro":"m","Time.UnixMilli":"m","Time.UnixNano":"m","Time.UnmarshalBinary":"m","Time.UnmarshalJSON":"m","Time.UnmarshalText":"m","Time.Weekday":"m","Time.Year":"m","Time.YearDay":"m","Time.Zone":"m","Time.ZoneBounds":"m","TimeOnly":"c","Timer":"t","Timer.Reset":"m","Timer.Stop":"m","Tuesday":"c","UTC":"v","Unix":"f","UnixDate":"c","UnixMicro":"f","UnixMilli":"f","Until":"f","Wednesday":"c","Weekday":"t","Weekday.String":"m"}},"unicode":{"path":"unicode","name":"unicode","symbols":{"ASCII_Hex_Digit":"v","Adlam":"v","Ahom":"v","Anatolian_Hieroglyphs":"v","Arabic":"v","Armenian":"v","Avestan":"v","AzeriCase":"v","Balinese":"v","Bamum":"v","Bassa_Vah":"v","Batak":"v","Bengali":"v","Bhaiksuki":"v","Bidi_Control":"v","Bopomofo":"v","Brahmi":"v","Braille":"v","Buginese":"v","Buhid":"v","C":"v","Canadian_Aboriginal":"v","Carian":"v","CaseRange":"t","CaseRanges":"v","Categories":"v","CategoryAliases":"v","Caucasian_Albanian":"v","Cc":"v","Cf":"v","Chakma":"v","Cham":"v","Cherokee":"v","Chorasmian":"v","Cn":"v","Co":"v","Common":"v","Coptic":"v","Cs":"v","Cuneiform":"v","Cypriot":"v","Cypro_Minoan":"v","Cyrillic":"v","Dash":"v","Deprecated":"v","Deseret":"v","Devanagari":"v","Diacritic":"v","Digit":"v","Dives_Akuru":"v","Dogra":"v","Duployan":"v","Egyptian_Hieroglyphs":"v","Elbasan":"v","Elymaic":"v","Ethiopic":"v","Extender":"v","FoldCategory":"v","FoldScript":"v","Georgian":"v","Glagolitic":"v","Gothic":"v","Grantha":"v","GraphicRanges":"v","Greek":"v","Gujarati":"v","Gunjala_Gondi":"v","Gurmukhi":"v","Han":"v","Hangul":"v","Hanifi_Rohingya":"v","Hanunoo":"v","Hatran":"v","Hebrew":"v","Hex_Digit":"v","Hiragana":"v","Hyphen":"v","IDS_Binary_Operator":"v","IDS_Trinary_Operator":"v","Ideographic":"v","Imperial_Aramaic":"v","In":"f","Inherited":"v","Inscriptional_Pahlavi":"v","Inscriptional_Parthian":"v","Is":"f","IsControl":"f","IsDigit":"f","IsGraphic":"f","IsLetter":"f","IsLower":"f","IsMark":"f","IsNumber":"f","IsOneOf":"f","IsPrint":"f","IsPunct":"f","IsSpace":"f","IsSymbol":"f","IsTitle":"f","IsUpper":"f","Javanese":"v","Join_Control":"v","Kaithi":"v","Kannada":"v","Katakana":"v","Kawi":"v","Kayah_Li":"v","Kharoshthi":"v","Khitan_Small_Script":"v","Khmer":"v","Khojki":"v","Khudawadi":"v","L":"v","LC":"v","Lao":"v","Latin":"v","Lepcha":"v","Letter":"v","Limbu":"v","Linear_A":"v","Linear_B":"v","Lisu":"v","Ll":"v","Lm":"v","Lo":"v","Logical_Order_Exception":"v","Lower":"v","LowerCase":"c","Lt":"v","Lu":"v","Lycian":"v","Lydian":"v","M":"v","Mahajani":"v","Makasar":"v","Malayalam":"v","Mandaic":"v","Manichaean":"v","Marchen":"v","Mark":"v","Masaram_Gondi":"v","MaxASCII":"c","MaxCase":"c","MaxLatin1":"c","MaxRune":"c","Mc":"v","Me":"v","Medefaidrin":"v","Meetei_Mayek":"v","Mende_Kikakui":"v","Meroitic_Cursive":"v","Meroitic_Hieroglyphs":"v","Miao":"v","Mn":"v","Modi":"v","Mongolian":"v","Mro":"v","Multani":"v","Myanmar":"v","N":"v","Nabataean":"v","Nag_Mundari":"v","Nandinagari":"v","Nd":"v","New_Tai_Lue":"v","Newa":"v","Nko":"v","Nl":"v","No":"v","Noncharacter_Code_Point":"v","Number":"v","Nushu":"v","Nyiakeng_Puachue_Hmong":"v","Ogham":"v","Ol_Chiki":"v","Old_Hungarian":"v","Old_Italic":"v","Old_North_Arabian":"v","Old_Permic":"v","Old_Persian":"v","Old_Sogdian":"v","Old_South_Arabian":"v","Old_Turkic":"v","Old_Uyghur":"v","Oriya":"v","Osage":"v","Osmanya":"v","Other":"v","Other_Alphabetic":"v","Other_Default_Ignorable_Code_Point":"v","Other_Grapheme_Extend":"v","Other_ID_Continue":"v","Other_ID_Start":"v","Other_Lowercase":"v","Other_Math":"v","Other_Uppercase":"v","P":"v","Pahawh_Hmong":"v","Palmyrene":"v","Pattern_Syntax":"v","Pattern_White_Space":"v","Pau_Cin_Hau":"v","Pc":"v","Pd":"v","Pe":"v","Pf":"v","Phags_Pa":"v","Phoenician":"v","Pi":"v","Po":"v","Prepended_Concatenation_Mark":"v","PrintRanges":"v","Properties":"v","Ps":"v","Psalter_Pahlavi":"v","Punct":"v","Quotation_Mark":"v","Radical":"v","Range16":"t","Range32":"t","RangeTable":"t","Regional_Indicator":"v","Rejang":"v","ReplacementChar":"c","Runic":"v","S":"v","STerm":"v","Samaritan":"v","Saurashtra":"v","Sc":"v","Scripts":"v","Sentence_Terminal":"v","Sharada":"v","Shavian":"v","Siddham":"v","SignWriting":"v","SimpleFold":"f","Sinhala":"v","Sk":"v","Sm":"v","So":"v","Soft_Dotted":"v","Sogdian":"v","Sora_Sompeng":"v","Soyombo":"v","Space":"v","SpecialCase":"t","SpecialCase.ToLower":"m","SpecialCase.ToTitle":"m","SpecialCase.ToUpper":"m","Sundanese":"v","Syloti_Nagri":"v","Symbol":"v","Syriac":"v","Tagalog":"v","Tagbanwa":"v","Tai_Le":"v","Tai_Tham":"v","Tai_Viet":"v","Takri":"v","Tamil":"v","Tangsa":"v","Tangut":"v","Telugu":"v","Terminal_Punctuation":"v","Thaana":"v","Thai":"v","Tibetan":"v","Tifinagh":"v","Tirhuta":"v","Title":"v","TitleCase":"c","To":"f","ToLower":"f","ToTitle":"f","ToUpper":"f","Toto":"v","TurkishCase":"v","Ugaritic":"v","Unified_Ideograph":"v","Upper":"v","UpperCase":"c","UpperLower":"c","Vai":"v","Variation_Selector":"v","Version":"c","Vithkuqi":"v","Wancho":"v","Warang_Citi":"v","White_Space":"v","Yezidi":"v","Yi":"v","Z":"v","Zanabazar_Square":"v","Zl":"v","Zp":"v","Zs":"v"}},"unicode/utf16":{"path":"unicode/utf16","name":"utf16","symbols":{"AppendRune":"f","Decode":"f","DecodeRune":"f","Encode":"f","EncodeRune":"f","IsSurrogate":"f","RuneLen":"f"}},"unicode/utf8":{"path":"unicode/utf8","name":"utf8","symbols":{"AppendRune":"f","DecodeLastRune":"f","DecodeLastRuneInString":"f","DecodeRune":"f","DecodeRuneInString":"f","EncodeRune":"f","FullRune":"f","FullRuneInString":"f","MaxRune":"c","RuneCount":"f","RuneCountInString":"f","RuneError":"c","RuneLen":"f","RuneSelf":"c","RuneStart":"f","UTFMax":"c","Valid":"f","ValidRune":"f","ValidString":"f"}},"unique":{"path":"unique","name":"unique","symbols":{"Handle":"t","Make":"f"}},"unsafe":{"path":"unsafe","name":"unsafe","symbols":{"Add":"f","Alignof":"f","ArbitraryType":"t","IntegerType":"t","Offsetof":"f","Pointer":"t","Sizeof":"f","Slice":"f","SliceData":"f","String":"f","StringData":"f"}},"weak":{"path":"weak","name":"weak","symbols":{"Make":"f","Pointer":"t"}}} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/check/stdlib_doclink/stdlib_doclink.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/check/stdlib_doclink/stdlib_doclink.go new file mode 100644 index 000000000..03252c43e --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/check/stdlib_doclink/stdlib_doclink.go @@ -0,0 +1,315 @@ +// Package stdlib_doclink provides a checker for detecting potential doc links +// to standard library symbols. +package stdlib_doclink + +import ( + "fmt" + gdc "go/doc/comment" + "maps" + "regexp" + "slices" + "strconv" + "strings" + + "github.com/godoc-lint/godoc-lint/pkg/check/stdlib_doclink/internal" + "github.com/godoc-lint/godoc-lint/pkg/model" + "github.com/godoc-lint/godoc-lint/pkg/util" +) + +// RequireStdlibDoclinkRule is the corresponding rule name. +const RequireStdlibDoclinkRule = model.RequireStdlibDoclinkRule + +var ruleSet = model.RuleSet{}.Add(RequireStdlibDoclinkRule) + +// StdlibDoclinkChecker checks for proper doc links to stdlib symbols. +type StdlibDoclinkChecker struct{} + +// NewStdlibDoclinkChecker returns a new instance of the corresponding checker. +func NewStdlibDoclinkChecker() *StdlibDoclinkChecker { + return &StdlibDoclinkChecker{} +} + +// GetCoveredRules implements the corresponding interface method. +func (r *StdlibDoclinkChecker) GetCoveredRules() model.RuleSet { + return ruleSet +} + +// Apply implements the corresponding interface method. +func (r *StdlibDoclinkChecker) Apply(actx *model.AnalysisContext) error { + includeTests := actx.Config.GetRuleOptions().RequireStdlibDoclinkIncludeTests + + docs := make(map[*model.CommentGroup]struct{}, 10*len(actx.InspectorResult.Files)) + + for _, ir := range util.AnalysisApplicableFiles(actx, includeTests, model.RuleSet{}.Add(RequireStdlibDoclinkRule)) { + if ir.PackageDoc != nil { + docs[ir.PackageDoc] = struct{}{} + } + + for _, sd := range ir.SymbolDecl { + if sd.ParentDoc != nil { + docs[sd.ParentDoc] = struct{}{} + } + if sd.Doc == nil { + continue + } + docs[sd.Doc] = struct{}{} + } + } + + if len(docs) == 0 { + return nil + } + + stdlib := stdlib() + pi := packageImports{ + importAsMap: make(map[string]string, 10), + badImportAs: make(map[string]struct{}, 10), + } + + for _, f := range actx.Pass.Files { + ft := util.GetPassFileToken(f, actx.Pass) + if ft == nil { + continue + } + + for _, imp := range f.Imports { + path, _ := strconv.Unquote(imp.Path.Value) + s, ok := stdlib[path] + if !ok { + // It's not a stdlib package. + continue + } + + var importedAs string + if imp.Name != nil { + alias := imp.Name.Name + if alias == "" || alias == "." || alias == "_" { + // We don't support _ or . imports. + continue + } + importedAs = alias + } else { + importedAs = s.Name + } + + if alreadyImportedPath, ok := pi.importAsMap[importedAs]; ok && alreadyImportedPath != path { + // Different import paths with the same alias(es); we don't support this case. + // It happens when people do aliasing like this: + // + // (foo.go) + // import blah "path/to/package" + // + // (bar.go) + // import blah "path/to/another/package" + // + // It's not inherently wrong, but due to the go doc tool's package-wide way of + // resolving package names in doc links (i.e. pkg in [pkg.name] or [pkg.recv.name]) + // it'll not work in such collision cases. As a result, doc links with colliding + // package aliases get rendered as plain text instead of links. + pi.badImportAs[importedAs] = struct{}{} + continue + } + + pi.importAsMap[importedAs] = path + } + } + + for doc := range docs { + checkStdlibDoclink(actx, &pi, doc) + } + return nil +} + +type packageImports struct { + importAsMap map[string]string + badImportAs map[string]struct{} +} + +func checkStdlibDoclink( + actx *model.AnalysisContext, + pi *packageImports, + doc *model.CommentGroup, +) { + if doc.DisabledRules.All || doc.DisabledRules.Rules.Has(RequireStdlibDoclinkRule) { + return + } + + applicableBlocks := make([]gdc.Block, 0, len(doc.Parsed.Content)) + for _, b := range doc.Parsed.Content { + if _, ok := b.(*gdc.Code); ok { + continue + } + // Doc links are not picked up in headings. + if _, ok := b.(*gdc.Heading); ok { + continue + } + applicableBlocks = append(applicableBlocks, b) + } + strippedCodeAndLinks := &gdc.Doc{ + Content: applicableBlocks, + } + text := string((&gdc.Printer{}).Comment(strippedCodeAndLinks)) + + pds := findPotentialDoclinks(pi, text) + if len(pds) == 0 { + return + } + + for _, pd := range pds { + var count string + if pd.count > 1 { + count = fmt.Sprintf(" (%d instances)", pd.count) + } + + actx.Pass.ReportRangef(&doc.CG, "text %q should be replaced with %q to link to stdlib %s%s", pd.originalNoStar, pd.doclink, kindTitle(pd.kind), count) + } +} + +func kindTitle(kind internal.SymbolKind) string { + switch kind { + case internal.SymbolKindType: + return "type" + case internal.SymbolKindFunc: + return "function" + case internal.SymbolKindVar: + return "variable" + case internal.SymbolKindConst: + return "constant" + case internal.SymbolKindMethod: + return "method" + default: + return "symbol" + } +} + +type potentialDoclink struct { + originalNoStar string // e.g. "encoding/json.Encoder" or "json.Encoder" (if imported as such) + count int + doclink string + kind internal.SymbolKind +} + +var potentialDoclinkRE = regexp.MustCompile(`(?m)(?:^|\s)(\*?)([a-zA-Z_][a-zA-Z0-9_]*(?:/[a-zA-Z_][a-zA-Z0-9_]*)*)\.([a-zA-Z0-9_]+)(?:\.([a-zA-Z0-9_]+))?\b`) + +func findPotentialDoclinks(pi *packageImports, text string) []*potentialDoclink { + stdlib := stdlib() + + m := make(map[string]*potentialDoclink, 5) + + matches := potentialDoclinkRE.FindAllStringSubmatch(text, -1) + for _, match := range matches { + _ = match[1] // star, if any + pkg := match[2] + name1 := match[3] + name2 := match[4] + + if pkg != "" && name1 != "" && name2 != "" { + // pkg.recv.name (= pkg.name1.name2) + + path := pi.tryResolveImportPath(pkg) + if path == "" { + // Colliding import alias/name; skip. + continue + } + + s, ok := stdlib[path] + if !ok { + continue + } + + kind, ok := s.Symbols[name1+"."+name2] + if !ok { + continue + } + + originalNoStar := fmt.Sprintf("%s.%s.%s", pkg, name1, name2) + if _, ok := m[originalNoStar]; !ok { + doclink := fmt.Sprintf("[%s]", originalNoStar) + m[originalNoStar] = &potentialDoclink{ + originalNoStar: originalNoStar, + doclink: doclink, + kind: kind, + } + } + m[originalNoStar].count++ + } else if pkg != "" && name1 != "" && name2 == "" { + // pkg.name (= pkg.name1) + + path := pi.tryResolveImportPath(pkg) + if path == "" { + // Colliding import alias/name; skip. + continue + } + + s, ok := stdlib[path] + if !ok { + continue + } + + kind, ok := s.Symbols[name1] + if !ok { + continue + } + + originalNoStar := fmt.Sprintf("%s.%s", pkg, name1) + if _, ok := m[originalNoStar]; !ok { + doclink := fmt.Sprintf("[%s]", originalNoStar) + m[originalNoStar] = &potentialDoclink{ + originalNoStar: originalNoStar, + doclink: doclink, + kind: kind, + } + } + m[originalNoStar].count++ + } + } + + if len(m) == 0 { + return nil + } + + return slices.SortedFunc(maps.Values(m), func(a, b *potentialDoclink) int { + return strings.Compare(a.originalNoStar, b.originalNoStar) + }) +} + +// tryResolveImportPath tries to resolve the given package alias/name to its +// import path (package-wide lookup of imports). If the alias/name was among the +// existing imports, the method will return the underlying import path; +// otherwise it'll return the given argument as is. +// +// If the package alias/name is among bad/colliding imports, an empty string is +// returned. +// +// When spotting potential doc links like "pkg.name" or "pkg.recv.name", we +// should resolve the "pkg" part to the underlying import path. Not only that +// users can have a totally new/unknown alias for a stdlib package import, like: +// +// import blah "encoding/json" +// +// they can also use another stdlib package's name as the alias, like: +// +// import fmt "encoding/json" +// +// This is obviously rare, but still a valid use of language. +// +// Additionally, when importing slashed package paths, like "encoding/json", +// the package will be available as "json" by default; i.e.: +// +// import "encoding/json" +// +// So, the actual package is not always evident from the import alias/name, so +// we need to carefully resolve the "pkg" part. +func (pi *packageImports) tryResolveImportPath(pkg string) string { + path, ok := pi.importAsMap[pkg] + if ok { + if _, isBad := pi.badImportAs[pkg]; isBad { + // We have different import paths with the same alias. + return "" + } + return path + } + + // Given "pkg" is not among existing imports. + return pkg +} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/compose/compose.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/compose/compose.go new file mode 100644 index 000000000..7ec04e349 --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/compose/compose.go @@ -0,0 +1,53 @@ +// Package compose provides composition of the linter components. +package compose + +import ( + "os" + + "github.com/godoc-lint/godoc-lint/pkg/analysis" + "github.com/godoc-lint/godoc-lint/pkg/check" + "github.com/godoc-lint/godoc-lint/pkg/config" + "github.com/godoc-lint/godoc-lint/pkg/inspect" + "github.com/godoc-lint/godoc-lint/pkg/model" +) + +// Composition holds the composed components of the linter. +type Composition struct { + Registry model.Registry + ConfigBuilder model.ConfigBuilder + Inspector model.Inspector + Analyzer model.Analyzer +} + +// CompositionConfig holds the configuration for composing the linter. +type CompositionConfig struct { + BaseDir string + ExitFunc func(int, error) + + // BaseDirPlainConfig holds the plain configuration for the base directory. + // + // This is meant to be used for integrating with umbrella linters (e.g. + // golangci-lint) where the root config comes from a different source/format. + BaseDirPlainConfig *config.PlainConfig +} + +// Compose composes the linter components based on the given configuration. +func Compose(c CompositionConfig) *Composition { + if c.BaseDir == "" { + // It's a best effort to use the current working directory if not set. + c.BaseDir, _ = os.Getwd() + } + + reg := check.NewPopulatedRegistry() + cb := config.NewConfigBuilder(c.BaseDir).WithBaseDirPlainConfig(c.BaseDirPlainConfig) + ocb := config.NewOnceConfigBuilder(cb) + inspector := inspect.NewInspector(ocb, c.ExitFunc) + analyzer := analysis.NewAnalyzer(c.BaseDir, ocb, reg, inspector, c.ExitFunc) + + return &Composition{ + Registry: reg, + ConfigBuilder: cb, + Inspector: inspector, + Analyzer: analyzer, + } +} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/config/builder.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/config/builder.go new file mode 100644 index 000000000..6bee946a7 --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/config/builder.go @@ -0,0 +1,327 @@ +package config + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "regexp" + "slices" + + "github.com/godoc-lint/godoc-lint/pkg/model" + "github.com/godoc-lint/godoc-lint/pkg/util" +) + +// ConfigBuilder implements a configuration builder. +type ConfigBuilder struct { + baseDir string + override *model.ConfigOverride + + // baseDirPlainConfig holds the plain config for the base directory. + // + // This is meant to be used for integrating with umbrella linters (e.g. + // golangci-lint) where the root config comes from a different + // source/format. + baseDirPlainConfig *PlainConfig +} + +// NewConfigBuilder crates a new instance of the corresponding struct. +func NewConfigBuilder(baseDir string) *ConfigBuilder { + return &ConfigBuilder{ + baseDir: baseDir, + } +} + +// WithBaseDirPlainConfig sets the plain config for the base directory. This is +// meant to be used for integrating with umbrella linters (e.g. golangci-lint) +// where the root config comes from a different source/format. +func (cb *ConfigBuilder) WithBaseDirPlainConfig(baseDirPlainConfig *PlainConfig) *ConfigBuilder { + cb.baseDirPlainConfig = baseDirPlainConfig + return cb +} + +// GetConfig implements the corresponding interface method. +func (cb *ConfigBuilder) GetConfig(cwd string) (model.Config, error) { + return cb.build(cwd) +} + +func (cb *ConfigBuilder) resolvePlainConfig(cwd string) (*PlainConfig, *PlainConfig, string, string, error) { + def := getDefaultPlainConfig() + + if !util.IsPathUnderBaseDir(cb.baseDir, cwd) { + if pcfg, filePath, err := cb.resolvePlainConfigAtBaseDir(); err != nil { + return nil, nil, "", "", err + } else if pcfg != nil { + return pcfg, def, cb.baseDir, filePath, nil + } + return def, def, cb.baseDir, "", nil + } + + path := cwd + for { + rel, err := filepath.Rel(cb.baseDir, path) + if err != nil { + return nil, nil, "", "", err + } + + if rel == "." { + if pcfg, filePath, err := cb.resolvePlainConfigAtBaseDir(); err != nil { + return nil, nil, "", "", err + } else if pcfg != nil { + return pcfg, def, cb.baseDir, filePath, nil + } + return def, def, cb.baseDir, "", nil + } + + if pcfg, filePath, err := findConventionalConfigFile(path); err != nil { + return nil, nil, "", "", err + } else if pcfg != nil { + return pcfg, def, path, filePath, nil + } + + path = filepath.Dir(path) + } +} + +func (cb *ConfigBuilder) resolvePlainConfigAtBaseDir() (*PlainConfig, string, error) { + // TODO(babakks): refactor this to a sync.OnceValue for performance + + if cb.override != nil && cb.override.ConfigFilePath != nil { + pcfg, err := FromYAMLFile(*cb.override.ConfigFilePath) + if err != nil { + return nil, "", err + } + return pcfg, *cb.override.ConfigFilePath, nil + } + + if pcfg, filePath, err := findConventionalConfigFile(cb.baseDir); err != nil { + return nil, "", err + } else if pcfg != nil { + return pcfg, filePath, nil + } + + if cb.baseDirPlainConfig != nil { + return cb.baseDirPlainConfig, "", nil + } + return nil, "", nil +} + +func findConventionalConfigFile(dir string) (*PlainConfig, string, error) { + for _, dcf := range defaultConfigFiles { + path := filepath.Join(dir, dcf) + if fi, err := os.Stat(path); err != nil || fi.IsDir() { + continue + } + pcfg, err := FromYAMLFile(path) + if err != nil { + return nil, "", err + } + return pcfg, path, nil + } + return nil, "", nil +} + +// build creates the configuration struct. +// +// It checks a sequence of sources: +// 1. Custom config file path +// 2. Default configuration files (e.g., `.godoc-lint.yaml`) +// +// If none was available, the default configuration will be returned. +// +// The method also does the following: +// - Applies override flags (e.g., enable, or disable). +// - Validates the final configuration. +func (cb *ConfigBuilder) build(cwd string) (*config, error) { + pcfg, def, configCWD, configFilePath, err := cb.resolvePlainConfig(cwd) + if err != nil { + return nil, err + } + + if err := pcfg.Validate(); err != nil { + return nil, fmt.Errorf("invalid config at %q: %w", configFilePath, err) + } + + toValidRuleSet := func(s []string) (*model.RuleSet, []string) { + if s == nil { + return nil, nil + } + invalids := make([]string, 0, len(s)) + rules := make([]model.Rule, 0, len(s)) + for _, v := range s { + if !model.AllRules.Has(model.Rule(v)) { + invalids = append(invalids, v) + continue + } + rules = append(rules, model.Rule(v)) + } + set := model.RuleSet{}.Add(rules...) + return &set, invalids + } + + toValidRegexpSlice := func(s []string) ([]*regexp.Regexp, []string) { + if s == nil { + return nil, nil + } + var invalids []string + var regexps []*regexp.Regexp + for _, v := range s { + re, err := regexp.Compile(v) + if err != nil { + invalids = append(invalids, v) + continue + } + regexps = append(regexps, re) + } + return regexps, invalids + } + + var errs []error + + result := &config{ + cwd: configCWD, + configFilePath: configFilePath, + } + + var enabledRules *model.RuleSet + if cb.override != nil && cb.override.Enable != nil { + enabledRules = cb.override.Enable + } else { + raw := pcfg.Enable + if raw == nil { + raw = def.Enable + } + rs, invalids := toValidRuleSet(raw) + if len(invalids) > 0 { + errs = append(errs, fmt.Errorf("invalid rule(s) name to enable: %q", invalids)) + } else { + enabledRules = rs + } + } + + var disabledRules *model.RuleSet + if cb.override != nil && cb.override.Disable != nil { + disabledRules = cb.override.Disable + } else { + raw := pcfg.Disable + if raw == nil { + raw = def.Disable + } + rs, invalids := toValidRuleSet(raw) + if len(invalids) > 0 { + errs = append(errs, fmt.Errorf("invalid rule(s) name to disable: %q", invalids)) + } else { + disabledRules = rs + } + } + + if cb.override != nil && cb.override.Include != nil { + result.includeAsRegexp = cb.override.Include + } else { + raw := pcfg.Include + if raw == nil { + raw = def.Include + } + rs, invalids := toValidRegexpSlice(raw) + if len(invalids) > 0 { + errs = append(errs, fmt.Errorf("invalid path pattern(s) to include: %q", invalids)) + } else { + result.includeAsRegexp = rs + } + } + + if cb.override != nil && cb.override.Exclude != nil { + result.excludeAsRegexp = cb.override.Exclude + } else { + raw := pcfg.Exclude + if raw == nil { + raw = def.Exclude + } + rs, invalids := toValidRegexpSlice(raw) + if len(invalids) > 0 { + errs = append(errs, fmt.Errorf("invalid path pattern(s) to exclude: %q", invalids)) + } else { + result.excludeAsRegexp = rs + } + } + + if cb.override != nil && cb.override.Default != nil { + result.rulesToApply = model.DefaultSetToRules[*cb.override.Default] + } else { + raw := pcfg.Default + if raw == nil { + raw = def.Default // never nil + } + + if !slices.Contains(model.DefaultSetValues, model.DefaultSet(*raw)) { + errs = append(errs, fmt.Errorf("invalid default set %q; must be one of %q", *raw, model.DefaultSetValues)) + } else { + result.rulesToApply = model.DefaultSetToRules[model.DefaultSet(*raw)] + } + } + + var maxLenIgnore []*regexp.Regexp + rawMaxLenIgnore := def.Options.MaxLenIgnorePatterns + if pcfg.Options != nil && pcfg.Options.MaxLenIgnorePatterns != nil { + rawMaxLenIgnore = pcfg.Options.MaxLenIgnorePatterns + } + if len(rawMaxLenIgnore) > 0 { + rs, invalids := toValidRegexpSlice(rawMaxLenIgnore) + if len(invalids) > 0 { + errs = append(errs, fmt.Errorf("invalid max-len ignore pattern(s): %q", invalids)) + } else { + maxLenIgnore = rs + } + } + + if errs != nil { + return nil, errors.Join(errs...) + } + + if enabledRules != nil { + result.rulesToApply = result.rulesToApply.Merge(*enabledRules) + } + if disabledRules != nil { + result.rulesToApply = result.rulesToApply.Remove(disabledRules.List()...) + } + + // To avoid being too strict, we don't complain if a rule is enabled and disabled at the same time. + + resolvedOptions := &model.RuleOptions{} + transferPrimitiveOptions(resolvedOptions, def.Options) // def.Options is never nil + if pcfg.Options != nil { + transferPrimitiveOptions(resolvedOptions, pcfg.Options) + } + resolvedOptions.MaxLenIgnorePatterns = maxLenIgnore + + result.options = resolvedOptions + + return result, nil +} + +// SetOverride implements the corresponding interface method. +func (cb *ConfigBuilder) SetOverride(override *model.ConfigOverride) { + cb.override = override +} + +func transferPrimitiveOptions(target *model.RuleOptions, source *PlainRuleOptions) { + transferIfNotNil(&target.MaxLenLength, source.MaxLenLength) + transferIfNotNil(&target.MaxLenIncludeTests, source.MaxLenIncludeTests) + transferIfNotNil(&target.PkgDocIncludeTests, source.PkgDocIncludeTests) + transferIfNotNil(&target.SinglePkgDocIncludeTests, source.SinglePkgDocIncludeTests) + transferIfNotNil(&target.RequirePkgDocIncludeTests, source.RequirePkgDocIncludeTests) + transferIfNotNil(&target.RequireDocIncludeTests, source.RequireDocIncludeTests) + transferIfNotNil(&target.RequireDocIgnoreExported, source.RequireDocIgnoreExported) + transferIfNotNil(&target.RequireDocIgnoreUnexported, source.RequireDocIgnoreUnexported) + transferIfNotNil(&target.StartWithNameIncludeTests, source.StartWithNameIncludeTests) + transferIfNotNil(&target.StartWithNameIncludeUnexported, source.StartWithNameIncludeUnexported) + transferIfNotNil(&target.RequireStdlibDoclinkIncludeTests, source.RequireStdlibDoclinkIncludeTests) + transferIfNotNil(&target.NoUnusedLinkIncludeTests, source.NoUnusedLinkIncludeTests) +} + +func transferIfNotNil[T any](dst, src *T) { + if src == nil { + return + } + *dst = *src +} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/config/config.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/config/config.go new file mode 100644 index 000000000..9a2cdfc60 --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/config/config.go @@ -0,0 +1,73 @@ +package config + +import ( + "path/filepath" + "regexp" + + "github.com/godoc-lint/godoc-lint/pkg/model" +) + +// config represents the godoc-lint analyzer configuration. +type config struct { + // cwd holds the directory that the configuration is applied to. This is the + // way to find out relative paths to include/exclude based on the config + // file. + cwd string + + // configFilePath holds the path to the configuration file. If there is no + // configuration file, which is the case when the default is used, this will + // be an empty string. + configFilePath string + + includeAsRegexp []*regexp.Regexp + excludeAsRegexp []*regexp.Regexp + rulesToApply model.RuleSet + options *model.RuleOptions +} + +// GetConfigFilePath implements the corresponding interface method. +func (c *config) GetConfigFilePath() string { + return c.configFilePath +} + +// GetCWD implements the corresponding interface method. +func (c *config) GetCWD() string { + return c.cwd +} + +// IsAnyRuleApplicable implements the corresponding interface method. +func (c *config) IsAnyRuleApplicable(rs model.RuleSet) bool { + return c.rulesToApply.HasCommonsWith(rs) +} + +// IsPathApplicable implements the corresponding interface method. +func (c *config) IsPathApplicable(path string) bool { + p, err := filepath.Rel(c.cwd, path) + if err != nil { + p = path + } + + // To ensure a consistent behavior on different platform (with the same + // configuration), we convert the path to a Unix-style path. + asUnixPath := filepath.ToSlash(p) + + for _, re := range c.excludeAsRegexp { + if re.MatchString(asUnixPath) { + return false + } + } + if c.includeAsRegexp == nil { + return true + } + for _, re := range c.includeAsRegexp { + if re.MatchString(asUnixPath) { + return true + } + } + return false +} + +// GetRuleOptions implements the corresponding interface method. +func (c *config) GetRuleOptions() *model.RuleOptions { + return c.options +} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/config/default.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/config/default.go new file mode 100644 index 000000000..79ba8b670 --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/config/default.go @@ -0,0 +1,28 @@ +package config + +import ( + _ "embed" + "sync" +) + +// defaultConfigFiles is the list of default configuration file names. +var defaultConfigFiles = []string{ + ".godoc-lint.yaml", + ".godoc-lint.yml", + ".godoc-lint.json", + ".godoclint.yaml", + ".godoclint.yml", + ".godoclint.json", +} + +// defaultConfigYAML is the default configuration (as YAML). +// +//go:embed default.yaml +var defaultConfigYAML []byte + +// getDefaultPlainConfig returns the parsed default configuration. +var getDefaultPlainConfig = sync.OnceValue(func() *PlainConfig { + // Error is nil due to tests. + pcfg, _ := FromYAML(defaultConfigYAML) + return pcfg +}) diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/config/default.yaml b/vendor/github.com/godoc-lint/godoc-lint/pkg/config/default.yaml new file mode 100644 index 000000000..967897836 --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/config/default.yaml @@ -0,0 +1,17 @@ +# Default configuration +version: "1.0" +default: basic +options: + max-len/length: 77 + max-len/include-tests: false + max-len/ignore-patterns: [] + pkg-doc/include-tests: false + single-pkg-doc/include-tests: false + require-pkg-doc/include-tests: false + require-doc/include-tests: false + require-doc/ignore-exported: false + require-doc/ignore-unexported: true + start-with-name/include-tests: false + start-with-name/include-unexported: false + require-stdlib-doclink/include-tests: false + no-unused-link/include-tests: false \ No newline at end of file diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/config/doc.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/config/doc.go new file mode 100644 index 000000000..3a015d989 --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/config/doc.go @@ -0,0 +1,2 @@ +// Package config provides configuration building and management. +package config diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/config/once.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/config/once.go new file mode 100644 index 000000000..2d865d557 --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/config/once.go @@ -0,0 +1,59 @@ +package config + +import ( + "sync" + + "github.com/godoc-lint/godoc-lint/pkg/model" +) + +// OnceConfigBuilder wraps a config builder and make it a one-time builder, so +// that further attempts to build will return the same result. +// +// This type is concurrent-safe. +type OnceConfigBuilder struct { + builder model.ConfigBuilder + + mu sync.Mutex + m map[string]built +} + +type built struct { + value model.Config + err error +} + +// NewOnceConfigBuilder crates a new instance of the corresponding struct. +func NewOnceConfigBuilder(builder model.ConfigBuilder) *OnceConfigBuilder { + return &OnceConfigBuilder{ + builder: builder, + } +} + +// GetConfig implements the corresponding interface method. +func (ocb *OnceConfigBuilder) GetConfig(cwd string) (model.Config, error) { + ocb.mu.Lock() + defer ocb.mu.Unlock() + + if b, ok := ocb.m[cwd]; ok { + return b.value, b.err + } + + b := built{} + b.value, b.err = ocb.builder.GetConfig(cwd) + if ocb.m == nil { + ocb.m = make(map[string]built, 10) + } + ocb.m[cwd] = b + return b.value, b.err +} + +// SetOverride implements the corresponding interface method. +func (ocb *OnceConfigBuilder) SetOverride(override *model.ConfigOverride) { + ocb.mu.Lock() + defer ocb.mu.Unlock() + + if len(ocb.m) > 0 { + return + } + ocb.builder.SetOverride(override) +} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/config/parser.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/config/parser.go new file mode 100644 index 000000000..3db9398c2 --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/config/parser.go @@ -0,0 +1,42 @@ +package config + +import ( + "fmt" + "os" + "strings" + + "go.yaml.in/yaml/v3" +) + +// FromYAML parses configuration from given YAML content. +func FromYAML(in []byte) (*PlainConfig, error) { + raw := PlainConfig{} + if err := yaml.Unmarshal(in, &raw); err != nil { + return nil, fmt.Errorf("cannot parse config from YAML file: %w", err) + } + + if raw.Version != nil && !strings.HasPrefix(*raw.Version, "1.") { + return nil, fmt.Errorf("unsupported config version: %s", *raw.Version) + } + + return &raw, nil +} + +// FromYAMLFile parses configuration from given file path. +func FromYAMLFile(path string) (*PlainConfig, error) { + in, err := os.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("cannot read file (%s): %w", path, err) + } + + raw := PlainConfig{} + if err := yaml.Unmarshal(in, &raw); err != nil { + return nil, fmt.Errorf("cannot parse config from YAML file: %w", err) + } + + if raw.Version != nil && !strings.HasPrefix(*raw.Version, "1.") { + return nil, fmt.Errorf("unsupported config version: %s", *raw.Version) + } + + return &raw, nil +} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/config/plain.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/config/plain.go new file mode 100644 index 000000000..0ff094855 --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/config/plain.go @@ -0,0 +1,98 @@ +package config + +import ( + "errors" + "fmt" + "regexp" + "slices" + + "github.com/godoc-lint/godoc-lint/pkg/model" +) + +// PlainConfig represents the plain configuration type as users would provide +// via a config file (e.g., a YAML file). +type PlainConfig struct { + Version *string `yaml:"version" mapstructure:"version"` + Exclude []string `yaml:"exclude" mapstructure:"exclude"` + Include []string `yaml:"include" mapstructure:"include"` + Default *string `yaml:"default" mapstructure:"default"` + Enable []string `yaml:"enable" mapstructure:"enable"` + Disable []string `yaml:"disable" mapstructure:"disable"` + Options *PlainRuleOptions `yaml:"options" mapstructure:"options"` +} + +// PlainRuleOptions represents the plain rule options as users would provide via +// a config file (e.g., a YAML file). +type PlainRuleOptions struct { + MaxLenLength *uint `yaml:"max-len/length" mapstructure:"max-len/length"` + MaxLenIncludeTests *bool `yaml:"max-len/include-tests" mapstructure:"max-len/include-tests"` + MaxLenIgnorePatterns []string `yaml:"max-len/ignore-patterns" mapstructure:"max-len/ignore-patterns"` + PkgDocIncludeTests *bool `yaml:"pkg-doc/include-tests" mapstructure:"pkg-doc/include-tests"` + SinglePkgDocIncludeTests *bool `yaml:"single-pkg-doc/include-tests" mapstructure:"single-pkg-doc/include-tests"` + RequirePkgDocIncludeTests *bool `yaml:"require-pkg-doc/include-tests" mapstructure:"require-pkg-doc/include-tests"` + RequireDocIncludeTests *bool `yaml:"require-doc/include-tests" mapstructure:"require-doc/include-tests"` + RequireDocIgnoreExported *bool `yaml:"require-doc/ignore-exported" mapstructure:"require-doc/ignore-exported"` + RequireDocIgnoreUnexported *bool `yaml:"require-doc/ignore-unexported" mapstructure:"require-doc/ignore-unexported"` + StartWithNameIncludeTests *bool `yaml:"start-with-name/include-tests" mapstructure:"start-with-name/include-tests"` + StartWithNameIncludeUnexported *bool `yaml:"start-with-name/include-unexported" mapstructure:"start-with-name/include-unexported"` + RequireStdlibDoclinkIncludeTests *bool `yaml:"require-stdlib-doclink/include-tests" mapstructure:"require-stdlib-doclink/include-tests"` + NoUnusedLinkIncludeTests *bool `yaml:"no-unused-link/include-tests" mapstructure:"no-unused-link/include-tests"` +} + +// Validate validates the plain configuration. +func (pcfg *PlainConfig) Validate() error { + var errs []error + + if pcfg.Default != nil && !slices.Contains(model.DefaultSetValues, model.DefaultSet(*pcfg.Default)) { + errs = append(errs, fmt.Errorf("invalid default set %q; must be one of %q", *pcfg.Default, model.DefaultSetValues)) + } + + if invalids := getInvalidRules(pcfg.Enable); len(invalids) > 0 { + errs = append(errs, fmt.Errorf("invalid rule name(s) to enable: %q", invalids)) + } + + if invalids := getInvalidRules(pcfg.Disable); len(invalids) > 0 { + errs = append(errs, fmt.Errorf("invalid rule name(s) to disable: %q", invalids)) + } + + // To avoid being too strict, we don't complain if a rule is enabled and disabled at the same time. + + if invalids := getInvalidRegexps(pcfg.Include); len(invalids) > 0 { + errs = append(errs, fmt.Errorf("invalid inclusion pattern(s): %q", invalids)) + } + + if invalids := getInvalidRegexps(pcfg.Exclude); len(invalids) > 0 { + errs = append(errs, fmt.Errorf("invalid exclusion pattern(s): %q", invalids)) + } + + if pcfg.Options != nil { + if invalids := getInvalidRegexps(pcfg.Options.MaxLenIgnorePatterns); len(invalids) > 0 { + errs = append(errs, fmt.Errorf("invalid max-len ignore pattern(s): %q", invalids)) + } + } + + if len(errs) > 0 { + return errors.Join(errs...) + } + return nil +} + +func getInvalidRules(names []string) []string { + invalids := make([]string, 0, len(names)) + for _, element := range names { + if !model.AllRules.Has(model.Rule(element)) { + invalids = append(invalids, element) + } + } + return invalids +} + +func getInvalidRegexps(values []string) []string { + invalids := make([]string, 0, len(values)) + for _, element := range values { + if _, err := regexp.Compile(element); err != nil { + invalids = append(invalids, element) + } + } + return invalids +} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/inspect/inspector.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/inspect/inspector.go new file mode 100644 index 000000000..cdddbcf9b --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/inspect/inspector.go @@ -0,0 +1,340 @@ +// Package inspect provides the pre-run inspection analyzer. +package inspect + +import ( + "errors" + "fmt" + "go/ast" + gdc "go/doc/comment" + "go/token" + "path/filepath" + "reflect" + "regexp" + "strings" + + "golang.org/x/tools/go/analysis" + + "github.com/godoc-lint/godoc-lint/pkg/model" + "github.com/godoc-lint/godoc-lint/pkg/util" +) + +const ( + metaName = "godoclint_inspect" + metaDoc = "Pre-run inspector for godoclint" + metaURL = "https://github.com/godoc-lint/godoc-lint" +) + +// Inspector implements the godoc-lint pre-run inspector. +type Inspector struct { + cb model.ConfigBuilder + exitFunc func(int, error) + + analyzer *analysis.Analyzer + parser gdc.Parser +} + +// NewInspector returns a new instance of the inspector. +func NewInspector(cb model.ConfigBuilder, exitFunc func(int, error)) *Inspector { + result := &Inspector{ + cb: cb, + exitFunc: exitFunc, + analyzer: &analysis.Analyzer{ + Name: metaName, + Doc: metaDoc, + URL: metaURL, + ResultType: reflect.TypeFor[*model.InspectorResult](), + }, + } + result.analyzer.Run = result.run + return result +} + +// GetAnalyzer returns the underlying analyzer. +func (i *Inspector) GetAnalyzer() *analysis.Analyzer { + return i.analyzer +} + +var ( + topLevelOrphanCommentGroupPattern = regexp.MustCompile(`(?m)(?:^//.*\r?\n)+(?:\r?\n|\z)`) + disableDirectivePattern = regexp.MustCompile(`(?m)//godoclint:disable(?: *([^\r\n]+))?\r?$`) +) + +func (i *Inspector) run(pass *analysis.Pass) (any, error) { + if len(pass.Files) == 0 { + return &model.InspectorResult{}, nil + } + + ft := util.GetPassFileToken(pass.Files[0], pass) + if ft == nil { + err := errors.New("cannot prepare config") + if i.exitFunc != nil { + i.exitFunc(2, err) + } + return nil, err + } + + pkgDir := filepath.Dir(ft.Name()) + cfg, err := i.cb.GetConfig(pkgDir) + if err != nil { + if i.exitFunc != nil { + i.exitFunc(2, err) + } + return nil, err + } + + inspect := func(f *ast.File) (*model.FileInspection, error) { + ft := util.GetPassFileToken(f, pass) + if ft == nil { + return nil, nil + } + + raw, err := pass.ReadFile(ft.Name()) + if err != nil { + return nil, fmt.Errorf("cannot read file %q: %v", ft.Name(), err) + } + + // Extract package godoc, if any. + packageDoc := i.extractCommentGroup(f.Doc) + + // Extract top-level //godoclint:disable directives. + disabledRules := model.InspectorResultDisableRules{} + for _, match := range topLevelOrphanCommentGroupPattern.FindAll(raw, -1) { + d := extractDisableDirectivesInComment(string(match)) + disabledRules.All = disabledRules.All || d.All + disabledRules.Rules = disabledRules.Rules.Merge(d.Rules) + } + + // Extract top-level symbol declarations. + decls := make([]model.SymbolDecl, 0, len(f.Decls)) + for _, d := range f.Decls { + switch dt := d.(type) { + case *ast.FuncDecl: + var recvBaseTypeName string + var isMethod bool + + if dt.Recv != nil { + isMethod = true + if len(dt.Recv.List) > 0 { + recvBaseTypeName = extractMethodRecvBaseTypeName(dt.Recv.List[0].Type) + } + } + + decls = append(decls, model.SymbolDecl{ + Decl: d, + Kind: model.SymbolDeclKindFunc, + Name: dt.Name.Name, + Ident: dt.Name, + IsMethod: isMethod, + MethodRecvBaseTypeName: recvBaseTypeName, + Doc: i.extractCommentGroup(dt.Doc), + }) + case *ast.BadDecl: + decls = append(decls, model.SymbolDecl{ + Decl: d, + Kind: model.SymbolDeclKindBad, + }) + case *ast.GenDecl: + switch dt.Tok { + case token.CONST, token.VAR: + kind := model.SymbolDeclKindConst + if dt.Tok == token.VAR { + kind = model.SymbolDeclKindVar + } + if dt.Lparen == token.NoPos { + // cases: + // const ... (single line) + // var ... (single line) + + spec := dt.Specs[0].(*ast.ValueSpec) + if len(spec.Names) == 1 { + // cases: + // const foo = 0 + // var foo = 0 + decls = append(decls, model.SymbolDecl{ + Decl: d, + Kind: kind, + Name: spec.Names[0].Name, + Ident: spec.Names[0], + Doc: i.extractCommentGroup(dt.Doc), + TrailingDoc: i.extractCommentGroup(spec.Comment), + }) + } else { + // cases: + // const foo, bar = 0, 0 + // var foo, bar = 0, 0 + doc := i.extractCommentGroup(dt.Doc) + trailingDoc := i.extractCommentGroup(spec.Comment) + for ix, n := range spec.Names { + decls = append(decls, model.SymbolDecl{ + Decl: d, + Kind: kind, + Name: n.Name, + Ident: n, + Doc: doc, + TrailingDoc: trailingDoc, + MultiNameDecl: true, + MultiNameIndex: ix, + }) + } + } + } else { + // cases: + // const ( + // foo = 0 + // ) + // var ( + // foo = 0 + // ) + // const ( + // foo, bar = 0, 0 + // ) + // var ( + // foo, bar = 0, 0 + // ) + + parentDoc := i.extractCommentGroup(dt.Doc) + for spix, s := range dt.Specs { + spec := s.(*ast.ValueSpec) + doc := i.extractCommentGroup(spec.Doc) + trailingDoc := i.extractCommentGroup(spec.Comment) + for ix, n := range spec.Names { + decls = append(decls, model.SymbolDecl{ + Decl: d, + Kind: kind, + Name: n.Name, + Ident: n, + Doc: doc, + TrailingDoc: trailingDoc, + ParentDoc: parentDoc, + MultiNameDecl: len(spec.Names) > 1, + MultiNameIndex: ix, + MultiSpecDecl: true, + MultiSpecIndex: spix, + }) + } + } + } + case token.TYPE: + if dt.Lparen == token.NoPos { + // case: + // type foo int + + spec := dt.Specs[0].(*ast.TypeSpec) + decls = append(decls, model.SymbolDecl{ + Decl: d, + Kind: model.SymbolDeclKindType, + IsTypeAlias: spec.Assign != token.NoPos, + Name: spec.Name.Name, + Ident: spec.Name, + Doc: i.extractCommentGroup(dt.Doc), + TrailingDoc: i.extractCommentGroup(spec.Comment), + }) + } else { + // case: + // type ( + // foo int + // ) + + parentDoc := i.extractCommentGroup(dt.Doc) + for spix, s := range dt.Specs { + spec := s.(*ast.TypeSpec) + decls = append(decls, model.SymbolDecl{ + Decl: d, + Kind: model.SymbolDeclKindType, + IsTypeAlias: spec.Assign != token.NoPos, + Name: spec.Name.Name, + Ident: spec.Name, + Doc: i.extractCommentGroup(spec.Doc), + TrailingDoc: i.extractCommentGroup(spec.Comment), + ParentDoc: parentDoc, + MultiSpecDecl: true, + MultiSpecIndex: spix, + }) + } + } + default: + continue + } + } + } + + return &model.FileInspection{ + DisabledRules: disabledRules, + PackageDoc: packageDoc, + SymbolDecl: decls, + }, nil + } + + result := &model.InspectorResult{ + Files: make(map[*ast.File]*model.FileInspection, len(pass.Files)), + } + + for _, f := range pass.Files { + ft := util.GetPassFileToken(f, pass) + if ft == nil { + continue + } + if !cfg.IsPathApplicable(ft.Name()) { + continue + } + + if fi, err := inspect(f); err != nil { + return nil, fmt.Errorf("inspector failed: %w", err) + } else { + result.Files[f] = fi + } + } + return result, nil +} + +func (i *Inspector) extractCommentGroup(cg *ast.CommentGroup) *model.CommentGroup { + if cg == nil { + return nil + } + + lines := make([]string, 0, len(cg.List)) + for _, l := range cg.List { + lines = append(lines, l.Text) + } + rawText := strings.Join(lines, "\n") + + text := cg.Text() + return &model.CommentGroup{ + CG: *cg, + Parsed: *i.parser.Parse(text), + Text: text, + DisabledRules: extractDisableDirectivesInComment(rawText), + } +} + +func extractDisableDirectivesInComment(s string) model.InspectorResultDisableRules { + result := model.InspectorResultDisableRules{} + for _, directive := range disableDirectivePattern.FindAllStringSubmatch(s, -1) { + args := directive[1] + if args == "" { + result.All = true + continue + } + + for name := range strings.SplitSeq(strings.TrimSpace(args), " ") { + if model.AllRules.Has(model.Rule(name)) { + result.Rules = result.Rules.Add(model.Rule(name)) + } + } + } + return result +} + +func extractMethodRecvBaseTypeName(expr ast.Expr) string { + switch tt := expr.(type) { + case *ast.Ident: + return tt.Name + case *ast.StarExpr: + return extractMethodRecvBaseTypeName(tt.X) + case *ast.IndexExpr: + return extractMethodRecvBaseTypeName(tt.X) + case *ast.IndexListExpr: + return extractMethodRecvBaseTypeName(tt.X) + } + return "" +} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/model/analyzer.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/model/analyzer.go new file mode 100644 index 000000000..ded44c4e7 --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/model/analyzer.go @@ -0,0 +1,11 @@ +package model + +import ( + "golang.org/x/tools/go/analysis" +) + +// Analyzer defines an analyzer. +type Analyzer interface { + // GetAnalyzer returns the underlying analyzer. + GetAnalyzer() *analysis.Analyzer +} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/model/checker.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/model/checker.go new file mode 100644 index 000000000..dca42e279 --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/model/checker.go @@ -0,0 +1,24 @@ +package model + +import "golang.org/x/tools/go/analysis" + +// AnalysisContext provides contextual information about the running analysis. +type AnalysisContext struct { + // Config provides analyzer configuration. + Config Config + + // InspectorResult is the analysis result of the pre-run inspector. + InspectorResult *InspectorResult + + // Pass is the analysis Pass instance. + Pass *analysis.Pass +} + +// Checker defines a rule checker. +type Checker interface { + // GetCoveredRules returns the set of rules applied by the checker. + GetCoveredRules() RuleSet + + // Apply checks for the rule(s). + Apply(actx *AnalysisContext) error +} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/model/config.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/model/config.go new file mode 100644 index 000000000..5ba271a3c --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/model/config.go @@ -0,0 +1,125 @@ +package model + +import ( + "maps" + "regexp" + "slices" +) + +// ConfigBuilder defines a configuration builder. +type ConfigBuilder interface { + // SetOverride sets the configuration override. + SetOverride(override *ConfigOverride) + + // GetConfig builds and returns the configuration object for the given path. + GetConfig(cwd string) (Config, error) +} + +// DefaultSet defines the default set of rules to enable. +type DefaultSet string + +const ( + // DefaultSetAll enables all rules. + DefaultSetAll DefaultSet = "all" + // DefaultSetNone disables all rules. + DefaultSetNone DefaultSet = "none" + // DefaultSetBasic enables a basic set of rules. + DefaultSetBasic DefaultSet = "basic" + + // DefaultDefaultSet is the default set of rules to enable. + DefaultDefaultSet = DefaultSetBasic +) + +// DefaultSetToRules maps default sets to the corresponding rule sets. +var DefaultSetToRules = map[DefaultSet]RuleSet{ + DefaultSetAll: AllRules, + DefaultSetNone: {}, + DefaultSetBasic: func() RuleSet { + return RuleSet{}.Add( + PkgDocRule, + SinglePkgDocRule, + StartWithNameRule, + DeprecatedRule, + ) + }(), +} + +// DefaultSetValues holds the valid values for DefaultSet. +var DefaultSetValues = func() []DefaultSet { + values := slices.Collect(maps.Keys(DefaultSetToRules)) + slices.Sort(values) + return values +}() + +// ConfigOverride represents a configuration override. +// +// Non-nil values (including empty slices) indicate that the corresponding field +// is overridden. +type ConfigOverride struct { + // ConfigFilePath is the path to config file. + ConfigFilePath *string + + // Include is the overridden list of regexp patterns matching the files that + // the linter should include. + Include []*regexp.Regexp + + // Exclude is the overridden list of regexp patterns matching the files that + // the linter should exclude. + Exclude []*regexp.Regexp + + // Default is the default set of rules to enable. + Default *DefaultSet + + // Enable is the overridden list of rules to enable. + Enable *RuleSet + + // Disable is the overridden list of rules to disable. + Disable *RuleSet +} + +// NewConfigOverride returns a new config override instance. +func NewConfigOverride() *ConfigOverride { + return &ConfigOverride{} +} + +// Config defines an analyzer configuration. +type Config interface { + // GetCWD returns the directory that the configuration is applied to. This + // is the base to compute relative paths to include/exclude files. + GetCWD() string + + // GetConfigFilePath returns the path to the configuration file. If there is + // no configuration file, which is the case when the default is used, this + // will be an empty string. + GetConfigFilePath() string + + // IsAnyRuleEnabled determines if any of the given rule names is among + // enabled rules, or not among disabled rules. + IsAnyRuleApplicable(RuleSet) bool + + // IsPathApplicable determines if the given path matches the included path + // patterns, or does not match the excluded path patterns. + IsPathApplicable(path string) bool + + // Returns the rule-specific options. + // + // It never returns a nil pointer. + GetRuleOptions() *RuleOptions +} + +// RuleOptions represents individual linter rule configurations. +type RuleOptions struct { + MaxLenLength uint + MaxLenIncludeTests bool + MaxLenIgnorePatterns []*regexp.Regexp + PkgDocIncludeTests bool + SinglePkgDocIncludeTests bool + RequirePkgDocIncludeTests bool + RequireDocIncludeTests bool + RequireDocIgnoreExported bool + RequireDocIgnoreUnexported bool + StartWithNameIncludeTests bool + StartWithNameIncludeUnexported bool + RequireStdlibDoclinkIncludeTests bool + NoUnusedLinkIncludeTests bool +} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/model/doc.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/model/doc.go new file mode 100644 index 000000000..b4afa8d46 --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/model/doc.go @@ -0,0 +1,2 @@ +// Package model provides data models for the linter. +package model diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/model/inspector.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/model/inspector.go new file mode 100644 index 000000000..9b4846634 --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/model/inspector.go @@ -0,0 +1,217 @@ +package model + +import ( + "go/ast" + "go/doc/comment" + + "golang.org/x/tools/go/analysis" +) + +// Inspector defines a pre-run inspector. +type Inspector interface { + // GetAnalyzer returns the underlying analyzer. + GetAnalyzer() *analysis.Analyzer +} + +// InspectorResult represents the result of the inspector analysis. +type InspectorResult struct { + // Files provides extracted information per AST file. + Files map[*ast.File]*FileInspection +} + +// FileInspection represents the inspection result for a single file. +type FileInspection struct { + // DisabledRules contains information about rules disabled at top level. + DisabledRules InspectorResultDisableRules + + // PackageDoc represents the package godoc, if any. + PackageDoc *CommentGroup + + // SymbolDecl represents symbols declared in the package file. + SymbolDecl []SymbolDecl +} + +// InspectorResultDisableRules contains the list of disabled rules. +type InspectorResultDisableRules struct { + // All indicates whether all rules are disabled. + All bool + + // Rules is the set of rules disabled. + Rules RuleSet +} + +// SymbolDeclKind is the enum type for the symbol declarations. +type SymbolDeclKind string + +const ( + // SymbolDeclKindBad represents an unknown declaration kind. + SymbolDeclKindBad SymbolDeclKind = "bad" + // SymbolDeclKindFunc represents a function declaration kind. + SymbolDeclKindFunc SymbolDeclKind = "func" + // SymbolDeclKindConst represents a const declaration kind. + SymbolDeclKindConst SymbolDeclKind = "const" + // SymbolDeclKindType represents a type declaration kind. + SymbolDeclKindType SymbolDeclKind = "type" + // SymbolDeclKindVar represents a var declaration kind. + SymbolDeclKindVar SymbolDeclKind = "var" +) + +// SymbolDecl represents a top level declaration. +type SymbolDecl struct { + // Decl is the underlying declaration node. + Decl ast.Decl + + // Kind is the declaration kind (e.g., func or type). + Kind SymbolDeclKind + + // IsTypeAlias indicates that the type symbol is an alias. For example: + // + // type Foo = int + // + // This is always false for non-type declaration (e.g., const or var). + IsTypeAlias bool + + // IsMethod indicates whether the symbol is a method. For example: + // + // func (Foo) Bar() {} + // func (*Foo) Bar() {} + // func (Foo[T]) Bar() {} + // func (*Foo[T]) Bar() {} + // + // This field is false for non-function declarations. + IsMethod bool + + // Name is the name of the declared symbol. + Name string + + // Ident is the symbol identifier node. + Ident *ast.Ident + + // MethodRecvBaseTypeName is the base type name of the method receiver, if + // the symbol is a method (See [Go spec]). + // + // Note that although an empty value is unexpected for method declarations, + // it's still possible (e.g. due to new language features that we don't yet + // support). So, users of this field should always check for empty values. + // + // In the examples below the base type name is "Foo": + // + // func (Foo) Bar() {} + // func (*Foo) Bar() {} + // func (Foo[T]) BarFoo() {} + // + // This field is empty for non-method symbols. + // + // [Go spec]: https://go.dev/ref/spec#Method_declarations + MethodRecvBaseTypeName string + + // MultiNameDecl determines whether the symbol is declared as part of a + // multi-name declaration spec; For example: + // + // const foo, bar = 0, 0 + // + // This field is only valid for const, var, or type declarations. + MultiNameDecl bool + + // MultiNameIndex is the index of the declared symbol within the spec. For + // example, in the below declaration, the index of "foo" and "bar" are 0 and + // 1, respectively: + // + // const foo, bar = 0, 0 + // + // In single-name specs, this will be 0. + MultiNameIndex int + + // MultiSpecDecl determines whether the symbol is declared as part of a + // multi-spec declaration. A multi spec declaration is const/var/type + // declaration with a pair of grouping brackets, even if there is only one + // spec between the brackets. For example, these are multi-spec + // declarations: + // + // const ( + // foo = 0 + // ) + // + // const ( + // foo, bar = 0, 0 + // ) + // + // const ( + // foo = 0 + // bar = 0 + // ) + // + // const ( + // foo, bar = 0, 0 + // baz = 0 + // ) + // + MultiSpecDecl bool + + // SpecIndex is the index of the spec where the symbol is declared. For + // example, in the below declaration, the index of "foo" and "bar" are 0 and + // 1, respectively: + // + // const ( + // foo = 0 + // bar = 0 + // ) + // + // In single-spec declarations, this will be 0. + MultiSpecIndex int + + // Doc is the comment group associated to the symbol. For example: + // + // // godoc + // const foo = 0 + // + // const ( + // // godoc + // foo = 0 + // ) + // + // Note that, as in the first example above, for single-spec declarations + // (i.e., single line declarations), the godoc above the const/var/type + // keyword is considered as the declaration doc, and the parent doc will be + // nil. + Doc *CommentGroup + + // TrailingDoc is the comment group that is following the symbol + // declaration. For example, this is a trailing comment group: + // + // const ( + // foo = 0 // trailing comment group. + // ) + // + TrailingDoc *CommentGroup + + // Doc is the comment group associated to the parent declaration. For + // instance: + // + // // parent godoc + // const ( + // // godoc + // Foo = 0 + // ) + // + // Note that for single-spec declarations (i.e., single line declarations), + // the godoc above the const/var/type keyword is considered as the + // declaration doc, and the parent doc will be nil. + ParentDoc *CommentGroup +} + +// CommentGroup represents an [ast.CommentGroup] and its parsed godoc instance. +type CommentGroup struct { + // CG represents the AST comment group. + CG ast.CommentGroup + + // Parsed represents the comment group parsed into a godoc. + Parsed comment.Doc + + // Test is the comment group text. + Text string + + // DisabledRules contains information about rules disabled in the comment + // group. + DisabledRules InspectorResultDisableRules +} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/model/registry.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/model/registry.go new file mode 100644 index 000000000..64512291d --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/model/registry.go @@ -0,0 +1,14 @@ +package model + +// Registry defines a registry of checkers. +type Registry interface { + // Add registers a new checker. + Add(Checker) + + // List returns a slice of the registered checkers. + List() []Checker + + // GetCoveredRules returns the set of rules covered by the registered + // checkers. + GetCoveredRules() RuleSet +} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/model/rule.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/model/rule.go new file mode 100644 index 000000000..eb7a67ff4 --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/model/rule.go @@ -0,0 +1,40 @@ +package model + +// Rule represents a rule. +type Rule string + +const ( + // PkgDocRule represents the "pkg-doc" rule. + PkgDocRule Rule = "pkg-doc" + // SinglePkgDocRule represents the "single-pkg-doc" rule. + SinglePkgDocRule Rule = "single-pkg-doc" + // RequirePkgDocRule represents the "require-pkg-doc" rule. + RequirePkgDocRule Rule = "require-pkg-doc" + // StartWithNameRule represents the "start-with-name" rule. + StartWithNameRule Rule = "start-with-name" + // RequireDocRule represents the "require-doc" rule. + RequireDocRule Rule = "require-doc" + // DeprecatedRule represents the "deprecated" rule. + DeprecatedRule Rule = "deprecated" + // RequireStdlibDoclinkRule represents the "require-stdlib-doclink" rule. + RequireStdlibDoclinkRule Rule = "require-stdlib-doclink" + // MaxLenRule represents the "max-len" rule. + MaxLenRule Rule = "max-len" + // NoUnusedLinkRule represents the "no-unused-link" rule. + NoUnusedLinkRule Rule = "no-unused-link" +) + +// AllRules is the set of all supported rules. +var AllRules = func() RuleSet { + return RuleSet{}.Add( + PkgDocRule, + SinglePkgDocRule, + RequirePkgDocRule, + StartWithNameRule, + RequireDocRule, + DeprecatedRule, + RequireStdlibDoclinkRule, + MaxLenRule, + NoUnusedLinkRule, + ) +}() diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/model/ruleset.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/model/ruleset.go new file mode 100644 index 000000000..0cf195447 --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/model/ruleset.go @@ -0,0 +1,97 @@ +package model + +import "slices" + +// RuleSet represents an immutable set of rule names. +// +// A zero rule set represents an empty set. +type RuleSet struct { + m map[Rule]struct{} +} + +// Merge combines the rules in the current and the given rule sets into a new +// set. +func (rs RuleSet) Merge(another RuleSet) RuleSet { + result := RuleSet{ + m: make(map[Rule]struct{}, len(rs.m)+len(another.m)), + } + for r := range rs.m { + result.m[r] = struct{}{} + } + for r := range another.m { + result.m[r] = struct{}{} + } + return result +} + +// Add returns a new rule set containing the rules in the current set and the +// rules provided as arguments. +func (rs RuleSet) Add(rules ...Rule) RuleSet { + result := RuleSet{ + m: make(map[Rule]struct{}, len(rs.m)+len(rules)), + } + for r := range rs.m { + result.m[r] = struct{}{} + } + for _, r := range rules { + result.m[r] = struct{}{} + } + return result +} + +// Remove returns a new rule set containing the rules in the current set +// excluding those provided as arguments. +func (rs RuleSet) Remove(rules ...Rule) RuleSet { + result := RuleSet{ + m: make(map[Rule]struct{}, len(rs.m)), + } + for r := range rs.m { + result.m[r] = struct{}{} + } + for _, r := range rules { + delete(result.m, r) + } + return result +} + +// Has determines whether the given rule is in the set. +func (rs RuleSet) Has(rule Rule) bool { + _, ok := rs.m[rule] + return ok +} + +// HasCommonsWith indicates at least one rule is in common with the given rule +// set. +// +// If the given set is empty/zero, the method will return false. +func (rs RuleSet) HasCommonsWith(another RuleSet) bool { + for r := range another.m { + if _, ok := rs.m[r]; ok { + return true + } + } + return false +} + +// IsSupersetOf indicates that all rules in the given set are in the current +// set. +// +// If the given set is empty/zero, the method will return true. +func (rs RuleSet) IsSupersetOf(another RuleSet) bool { + for r := range another.m { + if _, ok := rs.m[r]; !ok { + return false + } + } + return true +} + +// List returns a slice of the rules in the set. +func (rs RuleSet) List() []Rule { + rules := make([]Rule, 0, len(rs.m)) + for r := range rs.m { + rules = append(rules, r) + } + slices.Sort(rules) + return rules +} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/util/ast.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/util/ast.go new file mode 100644 index 000000000..1441001d0 --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/util/ast.go @@ -0,0 +1,66 @@ +package util + +import ( + "go/ast" + "go/token" + "iter" + "strings" + + "golang.org/x/tools/go/analysis" + + "github.com/godoc-lint/godoc-lint/pkg/model" +) + +// GetPassFileToken is a helper function to return the file token associated +// with the given AST file. +func GetPassFileToken(f *ast.File, pass *analysis.Pass) *token.File { + if f.Pos() == token.NoPos { + return nil + } + ft := pass.Fset.File(f.Pos()) + if ft == nil { + return nil + } + return ft +} + +// AnalysisApplicableFiles returns an iterator looping over files that are ready +// to be analyzed. +// +// The yield-ed arguments are never nil. +func AnalysisApplicableFiles(actx *model.AnalysisContext, includeTests bool, ruleSet model.RuleSet) iter.Seq2[*ast.File, *model.FileInspection] { + return func(yield func(*ast.File, *model.FileInspection) bool) { + if actx.InspectorResult == nil { + return + } + + for _, f := range actx.Pass.Files { + ir := actx.InspectorResult.Files[f] + + if ir == nil { + continue + } + + ft := GetPassFileToken(f, actx.Pass) + if ft == nil { + continue + } + + if !actx.Config.IsPathApplicable(ft.Name()) { + continue + } + + if !includeTests && strings.HasSuffix(ft.Name(), "_test.go") { + continue + } + + if ir.DisabledRules.All || ir.DisabledRules.Rules.IsSupersetOf(ruleSet) { + continue + } + + if !yield(f, ir) { + return + } + } + } +} diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/util/doc.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/util/doc.go new file mode 100644 index 000000000..1c40b7468 --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/util/doc.go @@ -0,0 +1,2 @@ +// Package util provides utility functions for the linter. +package util diff --git a/vendor/github.com/godoc-lint/godoc-lint/pkg/util/path.go b/vendor/github.com/godoc-lint/godoc-lint/pkg/util/path.go new file mode 100644 index 000000000..b7dd451e2 --- /dev/null +++ b/vendor/github.com/godoc-lint/godoc-lint/pkg/util/path.go @@ -0,0 +1,16 @@ +package util + +import ( + "path/filepath" + "strings" +) + +// IsPathUnderBaseDir determines whether the given path is a sub-directory of +// the given base, lexicographically. +func IsPathUnderBaseDir(baseDir, path string) bool { + rel, err := filepath.Rel(baseDir, path) + if err != nil { + return false + } + return rel == "." || rel != ".." && !strings.HasPrefix(filepath.ToSlash(rel), "../") +} diff --git a/vendor/github.com/gofrs/flock/.golangci.yml b/vendor/github.com/gofrs/flock/.golangci.yml index 3ad88a38f..bc837b266 100644 --- a/vendor/github.com/gofrs/flock/.golangci.yml +++ b/vendor/github.com/gofrs/flock/.golangci.yml @@ -1,5 +1,12 @@ -run: - timeout: 10m +version: "2" + +formatters: + enable: + - gofumpt + - goimports + settings: + gofumpt: + extra-rules: true linters: enable: @@ -18,9 +25,7 @@ linters: - gocritic - godot - godox - - gofumpt - goheader - - goimports - gomoddirectives - goprintffuncname - gosec @@ -31,84 +36,81 @@ linters: - misspell - nolintlint - revive - - stylecheck - - tenv + - staticcheck - testifylint - thelper - unconvert - unparam - usestdlibvars - whitespace - -linters-settings: - misspell: - locale: US - godox: - keywords: - - FIXME - goheader: - template: |- - Copyright 2015 Tim Heckman. All rights reserved. - Copyright 2018-{{ YEAR }} The Gofrs. All rights reserved. - Use of this source code is governed by the BSD 3-Clause - license that can be found in the LICENSE file. - gofumpt: - extra-rules: true - gocritic: - enabled-tags: - - diagnostic - - style - - performance - disabled-checks: - - paramTypeCombine # already handle by gofumpt.extra-rules - - whyNoLint # already handle by nonolint - - unnamedResult - - hugeParam - - sloppyReassign - - rangeValCopy - - octalLiteral - - ptrToRefParam - - appendAssign - - ruleguard - - httpNoBody - - exposedSyncMutex - - revive: - rules: - - name: struct-tag - - name: blank-imports - - name: context-as-argument - - name: context-keys-type - - name: dot-imports - - name: error-return - - name: error-strings - - name: error-naming - - name: exported - - name: if-return - - name: increment-decrement - - name: var-naming - - name: var-declaration - - name: package-comments - - name: range - - name: receiver-naming - - name: time-naming - - name: unexported-return - - name: indent-error-flow - - name: errorf - - name: empty-block - - name: superfluous-else - - name: unused-parameter - - name: unreachable-code - - name: redefines-builtin-id + - wsl_v5 + settings: + gocritic: + disabled-checks: + - paramTypeCombine # already handle by gofumpt.extra-rules + - whyNoLint # already handle by nonolint + - unnamedResult + - hugeParam + - sloppyReassign + - rangeValCopy + - octalLiteral + - ptrToRefParam + - appendAssign + - ruleguard + - httpNoBody + - exposedSyncMutex + enabled-tags: + - diagnostic + - style + - performance + godox: + keywords: + - FIXME + goheader: + template: |- + Copyright 2015 Tim Heckman. All rights reserved. + Copyright 2018-{{ YEAR }} The Gofrs. All rights reserved. + Use of this source code is governed by the BSD 3-Clause + license that can be found in the LICENSE file. + gosec: + excludes: + - G115 + misspell: + locale: US + revive: + rules: + - name: struct-tag + - name: blank-imports + - name: context-as-argument + - name: context-keys-type + - name: dot-imports + - name: error-return + - name: error-strings + - name: error-naming + - name: exported + - name: if-return + - name: increment-decrement + - name: var-naming + - name: var-declaration + - name: package-comments + - name: range + - name: receiver-naming + - name: time-naming + - name: unexported-return + - name: indent-error-flow + - name: errorf + - name: empty-block + - name: superfluous-else + - name: unused-parameter + - name: unreachable-code + - name: redefines-builtin-id + exclusions: + presets: + - comments + - common-false-positives + - std-error-handling issues: - exclude-use-default: true max-issues-per-linter: 0 max-same-issues: 0 -output: - show-stats: true - sort-results: true - sort-order: - - linter - - file diff --git a/vendor/github.com/gofrs/flock/LICENSE b/vendor/github.com/gofrs/flock/LICENSE index 7de525bf0..c785e5e4b 100644 --- a/vendor/github.com/gofrs/flock/LICENSE +++ b/vendor/github.com/gofrs/flock/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018-2024, The Gofrs +Copyright (c) 2018-2025, The Gofrs Copyright (c) 2015-2020, Tim Heckman All rights reserved. diff --git a/vendor/github.com/gofrs/flock/flock.go b/vendor/github.com/gofrs/flock/flock.go index ff942b228..4cb0746a7 100644 --- a/vendor/github.com/gofrs/flock/flock.go +++ b/vendor/github.com/gofrs/flock/flock.go @@ -1,5 +1,5 @@ // Copyright 2015 Tim Heckman. All rights reserved. -// Copyright 2018-2024 The Gofrs. All rights reserved. +// Copyright 2018-2025 The Gofrs. All rights reserved. // Use of this source code is governed by the BSD 3-Clause // license that can be found in the LICENSE file. @@ -62,6 +62,7 @@ type Flock struct { func New(path string, opts ...Option) *Flock { // create it if it doesn't exist, and open the file read-only. flags := os.O_CREATE + switch runtime.GOOS { case "aix", "solaris", "illumos": // AIX cannot preform write-lock (i.e. exclusive) on a read-only file. @@ -124,6 +125,22 @@ func (f *Flock) RLocked() bool { return f.r } +// Stat returns the FileInfo structure describing the lock file. +// If the lock file does not exist or cannot be accessed, an error is returned. +// +// This can be used to check the modification time of the lock file, +// which is useful for detecting stale locks. +func (f *Flock) Stat() (fs.FileInfo, error) { + f.m.RLock() + defer f.m.RUnlock() + + if f.fh != nil { + return f.fh.Stat() + } + + return os.Stat(f.path) +} + func (f *Flock) String() string { return f.path } @@ -158,7 +175,6 @@ func tryCtx(ctx context.Context, fn func() (bool, error), retryDelay time.Durati case <-ctx.Done(): return false, ctx.Err() case <-time.After(retryDelay): - // try again } } } diff --git a/vendor/github.com/gofrs/flock/flock_others.go b/vendor/github.com/gofrs/flock/flock_others.go index 18b14f1bd..92d0f7e95 100644 --- a/vendor/github.com/gofrs/flock/flock_others.go +++ b/vendor/github.com/gofrs/flock/flock_others.go @@ -1,3 +1,8 @@ +// Copyright 2015 Tim Heckman. All rights reserved. +// Copyright 2018-2025 The Gofrs. All rights reserved. +// Use of this source code is governed by the BSD 3-Clause +// license that can be found in the LICENSE file. + //go:build (!unix && !windows) || plan9 package flock diff --git a/vendor/github.com/gofrs/flock/flock_unix.go b/vendor/github.com/gofrs/flock/flock_unix.go index cf8919c7a..77de7a883 100644 --- a/vendor/github.com/gofrs/flock/flock_unix.go +++ b/vendor/github.com/gofrs/flock/flock_unix.go @@ -1,5 +1,5 @@ // Copyright 2015 Tim Heckman. All rights reserved. -// Copyright 2018-2024 The Gofrs. All rights reserved. +// Copyright 2018-2025 The Gofrs. All rights reserved. // Use of this source code is governed by the BSD 3-Clause // license that can be found in the LICENSE file. @@ -155,6 +155,7 @@ func (f *Flock) try(locked *bool, flag int) (bool, error) { } var retried bool + retry: err := unix.Flock(int(f.fh.Fd()), flag|unix.LOCK_NB) diff --git a/vendor/github.com/gofrs/flock/flock_unix_fcntl.go b/vendor/github.com/gofrs/flock/flock_unix_fcntl.go index ea007b47d..05c2f88c6 100644 --- a/vendor/github.com/gofrs/flock/flock_unix_fcntl.go +++ b/vendor/github.com/gofrs/flock/flock_unix_fcntl.go @@ -1,5 +1,5 @@ // Copyright 2015 Tim Heckman. All rights reserved. -// Copyright 2018-2024 The Gofrs. All rights reserved. +// Copyright 2018-2025 The Gofrs. All rights reserved. // Use of this source code is governed by the BSD 3-Clause // license that can be found in the LICENSE file. diff --git a/vendor/github.com/gofrs/flock/flock_windows.go b/vendor/github.com/gofrs/flock/flock_windows.go index dfd31e15f..aa144f156 100644 --- a/vendor/github.com/gofrs/flock/flock_windows.go +++ b/vendor/github.com/gofrs/flock/flock_windows.go @@ -1,5 +1,5 @@ // Copyright 2015 Tim Heckman. All rights reserved. -// Copyright 2018-2024 The Gofrs. All rights reserved. +// Copyright 2018-2025 The Gofrs. All rights reserved. // Use of this source code is governed by the BSD 3-Clause // license that can be found in the LICENSE file. @@ -23,6 +23,8 @@ const winLockfileSharedLock = 0x00000000 // ErrorLockViolation is the error code returned from the Windows syscall when a lock would block, // and you ask to fail immediately. +// +//nolint:errname // It should be renamed to `ErrLockViolation`. const ErrorLockViolation windows.Errno = 0x21 // 33 // Lock is a blocking call to try and take an exclusive file lock. diff --git a/vendor/github.com/gogo/protobuf/AUTHORS b/vendor/github.com/gogo/protobuf/AUTHORS deleted file mode 100644 index 3d97fc7a2..000000000 --- a/vendor/github.com/gogo/protobuf/AUTHORS +++ /dev/null @@ -1,15 +0,0 @@ -# This is the official list of GoGo authors for copyright purposes. -# This file is distinct from the CONTRIBUTORS file, which -# lists people. For example, employees are listed in CONTRIBUTORS, -# but not in AUTHORS, because the employer holds the copyright. - -# Names should be added to this file as one of -# Organization's name -# Individual's name -# Individual's name - -# Please keep the list sorted. - -Sendgrid, Inc -Vastech SA (PTY) LTD -Walter Schulze diff --git a/vendor/github.com/gogo/protobuf/CONTRIBUTORS b/vendor/github.com/gogo/protobuf/CONTRIBUTORS deleted file mode 100644 index 1b4f6c208..000000000 --- a/vendor/github.com/gogo/protobuf/CONTRIBUTORS +++ /dev/null @@ -1,23 +0,0 @@ -Anton Povarov -Brian Goff -Clayton Coleman -Denis Smirnov -DongYun Kang -Dwayne Schultz -Georg Apitz -Gustav Paul -Johan Brandhorst -John Shahid -John Tuley -Laurent -Patrick Lee -Peter Edge -Roger Johansson -Sam Nguyen -Sergio Arbeo -Stephen J Day -Tamir Duberstein -Todd Eisenberger -Tormod Erevik Lea -Vyacheslav Kim -Walter Schulze diff --git a/vendor/github.com/gogo/protobuf/LICENSE b/vendor/github.com/gogo/protobuf/LICENSE deleted file mode 100644 index f57de90da..000000000 --- a/vendor/github.com/gogo/protobuf/LICENSE +++ /dev/null @@ -1,35 +0,0 @@ -Copyright (c) 2013, The GoGo Authors. All rights reserved. - -Protocol Buffers for Go with Gadgets - -Go support for Protocol Buffers - Google's data interchange format - -Copyright 2010 The Go Authors. All rights reserved. -https://github.com/golang/protobuf - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - diff --git a/vendor/github.com/gogo/protobuf/proto/Makefile b/vendor/github.com/gogo/protobuf/proto/Makefile deleted file mode 100644 index 00d65f327..000000000 --- a/vendor/github.com/gogo/protobuf/proto/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -# Go support for Protocol Buffers - Google's data interchange format -# -# Copyright 2010 The Go Authors. All rights reserved. -# https://github.com/golang/protobuf -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -install: - go install - -test: install generate-test-pbs - go test - - -generate-test-pbs: - make install - make -C test_proto - make -C proto3_proto - make diff --git a/vendor/github.com/gogo/protobuf/proto/clone.go b/vendor/github.com/gogo/protobuf/proto/clone.go deleted file mode 100644 index a26b046d9..000000000 --- a/vendor/github.com/gogo/protobuf/proto/clone.go +++ /dev/null @@ -1,258 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2011 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Protocol buffer deep copy and merge. -// TODO: RawMessage. - -package proto - -import ( - "fmt" - "log" - "reflect" - "strings" -) - -// Clone returns a deep copy of a protocol buffer. -func Clone(src Message) Message { - in := reflect.ValueOf(src) - if in.IsNil() { - return src - } - out := reflect.New(in.Type().Elem()) - dst := out.Interface().(Message) - Merge(dst, src) - return dst -} - -// Merger is the interface representing objects that can merge messages of the same type. -type Merger interface { - // Merge merges src into this message. - // Required and optional fields that are set in src will be set to that value in dst. - // Elements of repeated fields will be appended. - // - // Merge may panic if called with a different argument type than the receiver. - Merge(src Message) -} - -// generatedMerger is the custom merge method that generated protos will have. -// We must add this method since a generate Merge method will conflict with -// many existing protos that have a Merge data field already defined. -type generatedMerger interface { - XXX_Merge(src Message) -} - -// Merge merges src into dst. -// Required and optional fields that are set in src will be set to that value in dst. -// Elements of repeated fields will be appended. -// Merge panics if src and dst are not the same type, or if dst is nil. -func Merge(dst, src Message) { - if m, ok := dst.(Merger); ok { - m.Merge(src) - return - } - - in := reflect.ValueOf(src) - out := reflect.ValueOf(dst) - if out.IsNil() { - panic("proto: nil destination") - } - if in.Type() != out.Type() { - panic(fmt.Sprintf("proto.Merge(%T, %T) type mismatch", dst, src)) - } - if in.IsNil() { - return // Merge from nil src is a noop - } - if m, ok := dst.(generatedMerger); ok { - m.XXX_Merge(src) - return - } - mergeStruct(out.Elem(), in.Elem()) -} - -func mergeStruct(out, in reflect.Value) { - sprop := GetProperties(in.Type()) - for i := 0; i < in.NumField(); i++ { - f := in.Type().Field(i) - if strings.HasPrefix(f.Name, "XXX_") { - continue - } - mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i]) - } - - if emIn, ok := in.Addr().Interface().(extensionsBytes); ok { - emOut := out.Addr().Interface().(extensionsBytes) - bIn := emIn.GetExtensions() - bOut := emOut.GetExtensions() - *bOut = append(*bOut, *bIn...) - } else if emIn, err := extendable(in.Addr().Interface()); err == nil { - emOut, _ := extendable(out.Addr().Interface()) - mIn, muIn := emIn.extensionsRead() - if mIn != nil { - mOut := emOut.extensionsWrite() - muIn.Lock() - mergeExtension(mOut, mIn) - muIn.Unlock() - } - } - - uf := in.FieldByName("XXX_unrecognized") - if !uf.IsValid() { - return - } - uin := uf.Bytes() - if len(uin) > 0 { - out.FieldByName("XXX_unrecognized").SetBytes(append([]byte(nil), uin...)) - } -} - -// mergeAny performs a merge between two values of the same type. -// viaPtr indicates whether the values were indirected through a pointer (implying proto2). -// prop is set if this is a struct field (it may be nil). -func mergeAny(out, in reflect.Value, viaPtr bool, prop *Properties) { - if in.Type() == protoMessageType { - if !in.IsNil() { - if out.IsNil() { - out.Set(reflect.ValueOf(Clone(in.Interface().(Message)))) - } else { - Merge(out.Interface().(Message), in.Interface().(Message)) - } - } - return - } - switch in.Kind() { - case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, - reflect.String, reflect.Uint32, reflect.Uint64: - if !viaPtr && isProto3Zero(in) { - return - } - out.Set(in) - case reflect.Interface: - // Probably a oneof field; copy non-nil values. - if in.IsNil() { - return - } - // Allocate destination if it is not set, or set to a different type. - // Otherwise we will merge as normal. - if out.IsNil() || out.Elem().Type() != in.Elem().Type() { - out.Set(reflect.New(in.Elem().Elem().Type())) // interface -> *T -> T -> new(T) - } - mergeAny(out.Elem(), in.Elem(), false, nil) - case reflect.Map: - if in.Len() == 0 { - return - } - if out.IsNil() { - out.Set(reflect.MakeMap(in.Type())) - } - // For maps with value types of *T or []byte we need to deep copy each value. - elemKind := in.Type().Elem().Kind() - for _, key := range in.MapKeys() { - var val reflect.Value - switch elemKind { - case reflect.Ptr: - val = reflect.New(in.Type().Elem().Elem()) - mergeAny(val, in.MapIndex(key), false, nil) - case reflect.Slice: - val = in.MapIndex(key) - val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) - default: - val = in.MapIndex(key) - } - out.SetMapIndex(key, val) - } - case reflect.Ptr: - if in.IsNil() { - return - } - if out.IsNil() { - out.Set(reflect.New(in.Elem().Type())) - } - mergeAny(out.Elem(), in.Elem(), true, nil) - case reflect.Slice: - if in.IsNil() { - return - } - if in.Type().Elem().Kind() == reflect.Uint8 { - // []byte is a scalar bytes field, not a repeated field. - - // Edge case: if this is in a proto3 message, a zero length - // bytes field is considered the zero value, and should not - // be merged. - if prop != nil && prop.proto3 && in.Len() == 0 { - return - } - - // Make a deep copy. - // Append to []byte{} instead of []byte(nil) so that we never end up - // with a nil result. - out.SetBytes(append([]byte{}, in.Bytes()...)) - return - } - n := in.Len() - if out.IsNil() { - out.Set(reflect.MakeSlice(in.Type(), 0, n)) - } - switch in.Type().Elem().Kind() { - case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, - reflect.String, reflect.Uint32, reflect.Uint64: - out.Set(reflect.AppendSlice(out, in)) - default: - for i := 0; i < n; i++ { - x := reflect.Indirect(reflect.New(in.Type().Elem())) - mergeAny(x, in.Index(i), false, nil) - out.Set(reflect.Append(out, x)) - } - } - case reflect.Struct: - mergeStruct(out, in) - default: - // unknown type, so not a protocol buffer - log.Printf("proto: don't know how to copy %v", in) - } -} - -func mergeExtension(out, in map[int32]Extension) { - for extNum, eIn := range in { - eOut := Extension{desc: eIn.desc} - if eIn.value != nil { - v := reflect.New(reflect.TypeOf(eIn.value)).Elem() - mergeAny(v, reflect.ValueOf(eIn.value), false, nil) - eOut.value = v.Interface() - } - if eIn.enc != nil { - eOut.enc = make([]byte, len(eIn.enc)) - copy(eOut.enc, eIn.enc) - } - - out[extNum] = eOut - } -} diff --git a/vendor/github.com/gogo/protobuf/proto/custom_gogo.go b/vendor/github.com/gogo/protobuf/proto/custom_gogo.go deleted file mode 100644 index 24552483c..000000000 --- a/vendor/github.com/gogo/protobuf/proto/custom_gogo.go +++ /dev/null @@ -1,39 +0,0 @@ -// Protocol Buffers for Go with Gadgets -// -// Copyright (c) 2018, The GoGo Authors. All rights reserved. -// http://github.com/gogo/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -import "reflect" - -type custom interface { - Marshal() ([]byte, error) - Unmarshal(data []byte) error - Size() int -} - -var customType = reflect.TypeOf((*custom)(nil)).Elem() diff --git a/vendor/github.com/gogo/protobuf/proto/decode.go b/vendor/github.com/gogo/protobuf/proto/decode.go deleted file mode 100644 index 63b0f08be..000000000 --- a/vendor/github.com/gogo/protobuf/proto/decode.go +++ /dev/null @@ -1,427 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -/* - * Routines for decoding protocol buffer data to construct in-memory representations. - */ - -import ( - "errors" - "fmt" - "io" -) - -// errOverflow is returned when an integer is too large to be represented. -var errOverflow = errors.New("proto: integer overflow") - -// ErrInternalBadWireType is returned by generated code when an incorrect -// wire type is encountered. It does not get returned to user code. -var ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof") - -// DecodeVarint reads a varint-encoded integer from the slice. -// It returns the integer and the number of bytes consumed, or -// zero if there is not enough. -// This is the format for the -// int32, int64, uint32, uint64, bool, and enum -// protocol buffer types. -func DecodeVarint(buf []byte) (x uint64, n int) { - for shift := uint(0); shift < 64; shift += 7 { - if n >= len(buf) { - return 0, 0 - } - b := uint64(buf[n]) - n++ - x |= (b & 0x7F) << shift - if (b & 0x80) == 0 { - return x, n - } - } - - // The number is too large to represent in a 64-bit value. - return 0, 0 -} - -func (p *Buffer) decodeVarintSlow() (x uint64, err error) { - i := p.index - l := len(p.buf) - - for shift := uint(0); shift < 64; shift += 7 { - if i >= l { - err = io.ErrUnexpectedEOF - return - } - b := p.buf[i] - i++ - x |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - p.index = i - return - } - } - - // The number is too large to represent in a 64-bit value. - err = errOverflow - return -} - -// DecodeVarint reads a varint-encoded integer from the Buffer. -// This is the format for the -// int32, int64, uint32, uint64, bool, and enum -// protocol buffer types. -func (p *Buffer) DecodeVarint() (x uint64, err error) { - i := p.index - buf := p.buf - - if i >= len(buf) { - return 0, io.ErrUnexpectedEOF - } else if buf[i] < 0x80 { - p.index++ - return uint64(buf[i]), nil - } else if len(buf)-i < 10 { - return p.decodeVarintSlow() - } - - var b uint64 - // we already checked the first byte - x = uint64(buf[i]) - 0x80 - i++ - - b = uint64(buf[i]) - i++ - x += b << 7 - if b&0x80 == 0 { - goto done - } - x -= 0x80 << 7 - - b = uint64(buf[i]) - i++ - x += b << 14 - if b&0x80 == 0 { - goto done - } - x -= 0x80 << 14 - - b = uint64(buf[i]) - i++ - x += b << 21 - if b&0x80 == 0 { - goto done - } - x -= 0x80 << 21 - - b = uint64(buf[i]) - i++ - x += b << 28 - if b&0x80 == 0 { - goto done - } - x -= 0x80 << 28 - - b = uint64(buf[i]) - i++ - x += b << 35 - if b&0x80 == 0 { - goto done - } - x -= 0x80 << 35 - - b = uint64(buf[i]) - i++ - x += b << 42 - if b&0x80 == 0 { - goto done - } - x -= 0x80 << 42 - - b = uint64(buf[i]) - i++ - x += b << 49 - if b&0x80 == 0 { - goto done - } - x -= 0x80 << 49 - - b = uint64(buf[i]) - i++ - x += b << 56 - if b&0x80 == 0 { - goto done - } - x -= 0x80 << 56 - - b = uint64(buf[i]) - i++ - x += b << 63 - if b&0x80 == 0 { - goto done - } - - return 0, errOverflow - -done: - p.index = i - return x, nil -} - -// DecodeFixed64 reads a 64-bit integer from the Buffer. -// This is the format for the -// fixed64, sfixed64, and double protocol buffer types. -func (p *Buffer) DecodeFixed64() (x uint64, err error) { - // x, err already 0 - i := p.index + 8 - if i < 0 || i > len(p.buf) { - err = io.ErrUnexpectedEOF - return - } - p.index = i - - x = uint64(p.buf[i-8]) - x |= uint64(p.buf[i-7]) << 8 - x |= uint64(p.buf[i-6]) << 16 - x |= uint64(p.buf[i-5]) << 24 - x |= uint64(p.buf[i-4]) << 32 - x |= uint64(p.buf[i-3]) << 40 - x |= uint64(p.buf[i-2]) << 48 - x |= uint64(p.buf[i-1]) << 56 - return -} - -// DecodeFixed32 reads a 32-bit integer from the Buffer. -// This is the format for the -// fixed32, sfixed32, and float protocol buffer types. -func (p *Buffer) DecodeFixed32() (x uint64, err error) { - // x, err already 0 - i := p.index + 4 - if i < 0 || i > len(p.buf) { - err = io.ErrUnexpectedEOF - return - } - p.index = i - - x = uint64(p.buf[i-4]) - x |= uint64(p.buf[i-3]) << 8 - x |= uint64(p.buf[i-2]) << 16 - x |= uint64(p.buf[i-1]) << 24 - return -} - -// DecodeZigzag64 reads a zigzag-encoded 64-bit integer -// from the Buffer. -// This is the format used for the sint64 protocol buffer type. -func (p *Buffer) DecodeZigzag64() (x uint64, err error) { - x, err = p.DecodeVarint() - if err != nil { - return - } - x = (x >> 1) ^ uint64((int64(x&1)<<63)>>63) - return -} - -// DecodeZigzag32 reads a zigzag-encoded 32-bit integer -// from the Buffer. -// This is the format used for the sint32 protocol buffer type. -func (p *Buffer) DecodeZigzag32() (x uint64, err error) { - x, err = p.DecodeVarint() - if err != nil { - return - } - x = uint64((uint32(x) >> 1) ^ uint32((int32(x&1)<<31)>>31)) - return -} - -// DecodeRawBytes reads a count-delimited byte buffer from the Buffer. -// This is the format used for the bytes protocol buffer -// type and for embedded messages. -func (p *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) { - n, err := p.DecodeVarint() - if err != nil { - return nil, err - } - - nb := int(n) - if nb < 0 { - return nil, fmt.Errorf("proto: bad byte length %d", nb) - } - end := p.index + nb - if end < p.index || end > len(p.buf) { - return nil, io.ErrUnexpectedEOF - } - - if !alloc { - // todo: check if can get more uses of alloc=false - buf = p.buf[p.index:end] - p.index += nb - return - } - - buf = make([]byte, nb) - copy(buf, p.buf[p.index:]) - p.index += nb - return -} - -// DecodeStringBytes reads an encoded string from the Buffer. -// This is the format used for the proto2 string type. -func (p *Buffer) DecodeStringBytes() (s string, err error) { - buf, err := p.DecodeRawBytes(false) - if err != nil { - return - } - return string(buf), nil -} - -// Unmarshaler is the interface representing objects that can -// unmarshal themselves. The argument points to data that may be -// overwritten, so implementations should not keep references to the -// buffer. -// Unmarshal implementations should not clear the receiver. -// Any unmarshaled data should be merged into the receiver. -// Callers of Unmarshal that do not want to retain existing data -// should Reset the receiver before calling Unmarshal. -type Unmarshaler interface { - Unmarshal([]byte) error -} - -// newUnmarshaler is the interface representing objects that can -// unmarshal themselves. The semantics are identical to Unmarshaler. -// -// This exists to support protoc-gen-go generated messages. -// The proto package will stop type-asserting to this interface in the future. -// -// DO NOT DEPEND ON THIS. -type newUnmarshaler interface { - XXX_Unmarshal([]byte) error -} - -// Unmarshal parses the protocol buffer representation in buf and places the -// decoded result in pb. If the struct underlying pb does not match -// the data in buf, the results can be unpredictable. -// -// Unmarshal resets pb before starting to unmarshal, so any -// existing data in pb is always removed. Use UnmarshalMerge -// to preserve and append to existing data. -func Unmarshal(buf []byte, pb Message) error { - pb.Reset() - if u, ok := pb.(newUnmarshaler); ok { - return u.XXX_Unmarshal(buf) - } - if u, ok := pb.(Unmarshaler); ok { - return u.Unmarshal(buf) - } - return NewBuffer(buf).Unmarshal(pb) -} - -// UnmarshalMerge parses the protocol buffer representation in buf and -// writes the decoded result to pb. If the struct underlying pb does not match -// the data in buf, the results can be unpredictable. -// -// UnmarshalMerge merges into existing data in pb. -// Most code should use Unmarshal instead. -func UnmarshalMerge(buf []byte, pb Message) error { - if u, ok := pb.(newUnmarshaler); ok { - return u.XXX_Unmarshal(buf) - } - if u, ok := pb.(Unmarshaler); ok { - // NOTE: The history of proto have unfortunately been inconsistent - // whether Unmarshaler should or should not implicitly clear itself. - // Some implementations do, most do not. - // Thus, calling this here may or may not do what people want. - // - // See https://github.com/golang/protobuf/issues/424 - return u.Unmarshal(buf) - } - return NewBuffer(buf).Unmarshal(pb) -} - -// DecodeMessage reads a count-delimited message from the Buffer. -func (p *Buffer) DecodeMessage(pb Message) error { - enc, err := p.DecodeRawBytes(false) - if err != nil { - return err - } - return NewBuffer(enc).Unmarshal(pb) -} - -// DecodeGroup reads a tag-delimited group from the Buffer. -// StartGroup tag is already consumed. This function consumes -// EndGroup tag. -func (p *Buffer) DecodeGroup(pb Message) error { - b := p.buf[p.index:] - x, y := findEndGroup(b) - if x < 0 { - return io.ErrUnexpectedEOF - } - err := Unmarshal(b[:x], pb) - p.index += y - return err -} - -// Unmarshal parses the protocol buffer representation in the -// Buffer and places the decoded result in pb. If the struct -// underlying pb does not match the data in the buffer, the results can be -// unpredictable. -// -// Unlike proto.Unmarshal, this does not reset pb before starting to unmarshal. -func (p *Buffer) Unmarshal(pb Message) error { - // If the object can unmarshal itself, let it. - if u, ok := pb.(newUnmarshaler); ok { - err := u.XXX_Unmarshal(p.buf[p.index:]) - p.index = len(p.buf) - return err - } - if u, ok := pb.(Unmarshaler); ok { - // NOTE: The history of proto have unfortunately been inconsistent - // whether Unmarshaler should or should not implicitly clear itself. - // Some implementations do, most do not. - // Thus, calling this here may or may not do what people want. - // - // See https://github.com/golang/protobuf/issues/424 - err := u.Unmarshal(p.buf[p.index:]) - p.index = len(p.buf) - return err - } - - // Slow workaround for messages that aren't Unmarshalers. - // This includes some hand-coded .pb.go files and - // bootstrap protos. - // TODO: fix all of those and then add Unmarshal to - // the Message interface. Then: - // The cast above and code below can be deleted. - // The old unmarshaler can be deleted. - // Clients can call Unmarshal directly (can already do that, actually). - var info InternalMessageInfo - err := info.Unmarshal(pb, p.buf[p.index:]) - p.index = len(p.buf) - return err -} diff --git a/vendor/github.com/gogo/protobuf/proto/deprecated.go b/vendor/github.com/gogo/protobuf/proto/deprecated.go deleted file mode 100644 index 35b882c09..000000000 --- a/vendor/github.com/gogo/protobuf/proto/deprecated.go +++ /dev/null @@ -1,63 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2018 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -import "errors" - -// Deprecated: do not use. -type Stats struct{ Emalloc, Dmalloc, Encode, Decode, Chit, Cmiss, Size uint64 } - -// Deprecated: do not use. -func GetStats() Stats { return Stats{} } - -// Deprecated: do not use. -func MarshalMessageSet(interface{}) ([]byte, error) { - return nil, errors.New("proto: not implemented") -} - -// Deprecated: do not use. -func UnmarshalMessageSet([]byte, interface{}) error { - return errors.New("proto: not implemented") -} - -// Deprecated: do not use. -func MarshalMessageSetJSON(interface{}) ([]byte, error) { - return nil, errors.New("proto: not implemented") -} - -// Deprecated: do not use. -func UnmarshalMessageSetJSON([]byte, interface{}) error { - return errors.New("proto: not implemented") -} - -// Deprecated: do not use. -func RegisterMessageSetType(Message, int32, string) {} diff --git a/vendor/github.com/gogo/protobuf/proto/discard.go b/vendor/github.com/gogo/protobuf/proto/discard.go deleted file mode 100644 index fe1bd7d90..000000000 --- a/vendor/github.com/gogo/protobuf/proto/discard.go +++ /dev/null @@ -1,350 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2017 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -import ( - "fmt" - "reflect" - "strings" - "sync" - "sync/atomic" -) - -type generatedDiscarder interface { - XXX_DiscardUnknown() -} - -// DiscardUnknown recursively discards all unknown fields from this message -// and all embedded messages. -// -// When unmarshaling a message with unrecognized fields, the tags and values -// of such fields are preserved in the Message. This allows a later call to -// marshal to be able to produce a message that continues to have those -// unrecognized fields. To avoid this, DiscardUnknown is used to -// explicitly clear the unknown fields after unmarshaling. -// -// For proto2 messages, the unknown fields of message extensions are only -// discarded from messages that have been accessed via GetExtension. -func DiscardUnknown(m Message) { - if m, ok := m.(generatedDiscarder); ok { - m.XXX_DiscardUnknown() - return - } - // TODO: Dynamically populate a InternalMessageInfo for legacy messages, - // but the master branch has no implementation for InternalMessageInfo, - // so it would be more work to replicate that approach. - discardLegacy(m) -} - -// DiscardUnknown recursively discards all unknown fields. -func (a *InternalMessageInfo) DiscardUnknown(m Message) { - di := atomicLoadDiscardInfo(&a.discard) - if di == nil { - di = getDiscardInfo(reflect.TypeOf(m).Elem()) - atomicStoreDiscardInfo(&a.discard, di) - } - di.discard(toPointer(&m)) -} - -type discardInfo struct { - typ reflect.Type - - initialized int32 // 0: only typ is valid, 1: everything is valid - lock sync.Mutex - - fields []discardFieldInfo - unrecognized field -} - -type discardFieldInfo struct { - field field // Offset of field, guaranteed to be valid - discard func(src pointer) -} - -var ( - discardInfoMap = map[reflect.Type]*discardInfo{} - discardInfoLock sync.Mutex -) - -func getDiscardInfo(t reflect.Type) *discardInfo { - discardInfoLock.Lock() - defer discardInfoLock.Unlock() - di := discardInfoMap[t] - if di == nil { - di = &discardInfo{typ: t} - discardInfoMap[t] = di - } - return di -} - -func (di *discardInfo) discard(src pointer) { - if src.isNil() { - return // Nothing to do. - } - - if atomic.LoadInt32(&di.initialized) == 0 { - di.computeDiscardInfo() - } - - for _, fi := range di.fields { - sfp := src.offset(fi.field) - fi.discard(sfp) - } - - // For proto2 messages, only discard unknown fields in message extensions - // that have been accessed via GetExtension. - if em, err := extendable(src.asPointerTo(di.typ).Interface()); err == nil { - // Ignore lock since DiscardUnknown is not concurrency safe. - emm, _ := em.extensionsRead() - for _, mx := range emm { - if m, ok := mx.value.(Message); ok { - DiscardUnknown(m) - } - } - } - - if di.unrecognized.IsValid() { - *src.offset(di.unrecognized).toBytes() = nil - } -} - -func (di *discardInfo) computeDiscardInfo() { - di.lock.Lock() - defer di.lock.Unlock() - if di.initialized != 0 { - return - } - t := di.typ - n := t.NumField() - - for i := 0; i < n; i++ { - f := t.Field(i) - if strings.HasPrefix(f.Name, "XXX_") { - continue - } - - dfi := discardFieldInfo{field: toField(&f)} - tf := f.Type - - // Unwrap tf to get its most basic type. - var isPointer, isSlice bool - if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 { - isSlice = true - tf = tf.Elem() - } - if tf.Kind() == reflect.Ptr { - isPointer = true - tf = tf.Elem() - } - if isPointer && isSlice && tf.Kind() != reflect.Struct { - panic(fmt.Sprintf("%v.%s cannot be a slice of pointers to primitive types", t, f.Name)) - } - - switch tf.Kind() { - case reflect.Struct: - switch { - case !isPointer: - panic(fmt.Sprintf("%v.%s cannot be a direct struct value", t, f.Name)) - case isSlice: // E.g., []*pb.T - discardInfo := getDiscardInfo(tf) - dfi.discard = func(src pointer) { - sps := src.getPointerSlice() - for _, sp := range sps { - if !sp.isNil() { - discardInfo.discard(sp) - } - } - } - default: // E.g., *pb.T - discardInfo := getDiscardInfo(tf) - dfi.discard = func(src pointer) { - sp := src.getPointer() - if !sp.isNil() { - discardInfo.discard(sp) - } - } - } - case reflect.Map: - switch { - case isPointer || isSlice: - panic(fmt.Sprintf("%v.%s cannot be a pointer to a map or a slice of map values", t, f.Name)) - default: // E.g., map[K]V - if tf.Elem().Kind() == reflect.Ptr { // Proto struct (e.g., *T) - dfi.discard = func(src pointer) { - sm := src.asPointerTo(tf).Elem() - if sm.Len() == 0 { - return - } - for _, key := range sm.MapKeys() { - val := sm.MapIndex(key) - DiscardUnknown(val.Interface().(Message)) - } - } - } else { - dfi.discard = func(pointer) {} // Noop - } - } - case reflect.Interface: - // Must be oneof field. - switch { - case isPointer || isSlice: - panic(fmt.Sprintf("%v.%s cannot be a pointer to a interface or a slice of interface values", t, f.Name)) - default: // E.g., interface{} - // TODO: Make this faster? - dfi.discard = func(src pointer) { - su := src.asPointerTo(tf).Elem() - if !su.IsNil() { - sv := su.Elem().Elem().Field(0) - if sv.Kind() == reflect.Ptr && sv.IsNil() { - return - } - switch sv.Type().Kind() { - case reflect.Ptr: // Proto struct (e.g., *T) - DiscardUnknown(sv.Interface().(Message)) - } - } - } - } - default: - continue - } - di.fields = append(di.fields, dfi) - } - - di.unrecognized = invalidField - if f, ok := t.FieldByName("XXX_unrecognized"); ok { - if f.Type != reflect.TypeOf([]byte{}) { - panic("expected XXX_unrecognized to be of type []byte") - } - di.unrecognized = toField(&f) - } - - atomic.StoreInt32(&di.initialized, 1) -} - -func discardLegacy(m Message) { - v := reflect.ValueOf(m) - if v.Kind() != reflect.Ptr || v.IsNil() { - return - } - v = v.Elem() - if v.Kind() != reflect.Struct { - return - } - t := v.Type() - - for i := 0; i < v.NumField(); i++ { - f := t.Field(i) - if strings.HasPrefix(f.Name, "XXX_") { - continue - } - vf := v.Field(i) - tf := f.Type - - // Unwrap tf to get its most basic type. - var isPointer, isSlice bool - if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 { - isSlice = true - tf = tf.Elem() - } - if tf.Kind() == reflect.Ptr { - isPointer = true - tf = tf.Elem() - } - if isPointer && isSlice && tf.Kind() != reflect.Struct { - panic(fmt.Sprintf("%T.%s cannot be a slice of pointers to primitive types", m, f.Name)) - } - - switch tf.Kind() { - case reflect.Struct: - switch { - case !isPointer: - panic(fmt.Sprintf("%T.%s cannot be a direct struct value", m, f.Name)) - case isSlice: // E.g., []*pb.T - for j := 0; j < vf.Len(); j++ { - discardLegacy(vf.Index(j).Interface().(Message)) - } - default: // E.g., *pb.T - discardLegacy(vf.Interface().(Message)) - } - case reflect.Map: - switch { - case isPointer || isSlice: - panic(fmt.Sprintf("%T.%s cannot be a pointer to a map or a slice of map values", m, f.Name)) - default: // E.g., map[K]V - tv := vf.Type().Elem() - if tv.Kind() == reflect.Ptr && tv.Implements(protoMessageType) { // Proto struct (e.g., *T) - for _, key := range vf.MapKeys() { - val := vf.MapIndex(key) - discardLegacy(val.Interface().(Message)) - } - } - } - case reflect.Interface: - // Must be oneof field. - switch { - case isPointer || isSlice: - panic(fmt.Sprintf("%T.%s cannot be a pointer to a interface or a slice of interface values", m, f.Name)) - default: // E.g., test_proto.isCommunique_Union interface - if !vf.IsNil() && f.Tag.Get("protobuf_oneof") != "" { - vf = vf.Elem() // E.g., *test_proto.Communique_Msg - if !vf.IsNil() { - vf = vf.Elem() // E.g., test_proto.Communique_Msg - vf = vf.Field(0) // E.g., Proto struct (e.g., *T) or primitive value - if vf.Kind() == reflect.Ptr { - discardLegacy(vf.Interface().(Message)) - } - } - } - } - } - } - - if vf := v.FieldByName("XXX_unrecognized"); vf.IsValid() { - if vf.Type() != reflect.TypeOf([]byte{}) { - panic("expected XXX_unrecognized to be of type []byte") - } - vf.Set(reflect.ValueOf([]byte(nil))) - } - - // For proto2 messages, only discard unknown fields in message extensions - // that have been accessed via GetExtension. - if em, err := extendable(m); err == nil { - // Ignore lock since discardLegacy is not concurrency safe. - emm, _ := em.extensionsRead() - for _, mx := range emm { - if m, ok := mx.value.(Message); ok { - discardLegacy(m) - } - } - } -} diff --git a/vendor/github.com/gogo/protobuf/proto/duration.go b/vendor/github.com/gogo/protobuf/proto/duration.go deleted file mode 100644 index 93464c91c..000000000 --- a/vendor/github.com/gogo/protobuf/proto/duration.go +++ /dev/null @@ -1,100 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2016 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -// This file implements conversions between google.protobuf.Duration -// and time.Duration. - -import ( - "errors" - "fmt" - "time" -) - -const ( - // Range of a Duration in seconds, as specified in - // google/protobuf/duration.proto. This is about 10,000 years in seconds. - maxSeconds = int64(10000 * 365.25 * 24 * 60 * 60) - minSeconds = -maxSeconds -) - -// validateDuration determines whether the Duration is valid according to the -// definition in google/protobuf/duration.proto. A valid Duration -// may still be too large to fit into a time.Duration (the range of Duration -// is about 10,000 years, and the range of time.Duration is about 290). -func validateDuration(d *duration) error { - if d == nil { - return errors.New("duration: nil Duration") - } - if d.Seconds < minSeconds || d.Seconds > maxSeconds { - return fmt.Errorf("duration: %#v: seconds out of range", d) - } - if d.Nanos <= -1e9 || d.Nanos >= 1e9 { - return fmt.Errorf("duration: %#v: nanos out of range", d) - } - // Seconds and Nanos must have the same sign, unless d.Nanos is zero. - if (d.Seconds < 0 && d.Nanos > 0) || (d.Seconds > 0 && d.Nanos < 0) { - return fmt.Errorf("duration: %#v: seconds and nanos have different signs", d) - } - return nil -} - -// DurationFromProto converts a Duration to a time.Duration. DurationFromProto -// returns an error if the Duration is invalid or is too large to be -// represented in a time.Duration. -func durationFromProto(p *duration) (time.Duration, error) { - if err := validateDuration(p); err != nil { - return 0, err - } - d := time.Duration(p.Seconds) * time.Second - if int64(d/time.Second) != p.Seconds { - return 0, fmt.Errorf("duration: %#v is out of range for time.Duration", p) - } - if p.Nanos != 0 { - d += time.Duration(p.Nanos) - if (d < 0) != (p.Nanos < 0) { - return 0, fmt.Errorf("duration: %#v is out of range for time.Duration", p) - } - } - return d, nil -} - -// DurationProto converts a time.Duration to a Duration. -func durationProto(d time.Duration) *duration { - nanos := d.Nanoseconds() - secs := nanos / 1e9 - nanos -= secs * 1e9 - return &duration{ - Seconds: secs, - Nanos: int32(nanos), - } -} diff --git a/vendor/github.com/gogo/protobuf/proto/duration_gogo.go b/vendor/github.com/gogo/protobuf/proto/duration_gogo.go deleted file mode 100644 index e748e1730..000000000 --- a/vendor/github.com/gogo/protobuf/proto/duration_gogo.go +++ /dev/null @@ -1,49 +0,0 @@ -// Protocol Buffers for Go with Gadgets -// -// Copyright (c) 2016, The GoGo Authors. All rights reserved. -// http://github.com/gogo/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -import ( - "reflect" - "time" -) - -var durationType = reflect.TypeOf((*time.Duration)(nil)).Elem() - -type duration struct { - Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"` - Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"` -} - -func (m *duration) Reset() { *m = duration{} } -func (*duration) ProtoMessage() {} -func (*duration) String() string { return "duration" } - -func init() { - RegisterType((*duration)(nil), "gogo.protobuf.proto.duration") -} diff --git a/vendor/github.com/gogo/protobuf/proto/encode.go b/vendor/github.com/gogo/protobuf/proto/encode.go deleted file mode 100644 index 9581ccd30..000000000 --- a/vendor/github.com/gogo/protobuf/proto/encode.go +++ /dev/null @@ -1,205 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -/* - * Routines for encoding data into the wire format for protocol buffers. - */ - -import ( - "errors" - "reflect" -) - -var ( - // errRepeatedHasNil is the error returned if Marshal is called with - // a struct with a repeated field containing a nil element. - errRepeatedHasNil = errors.New("proto: repeated field has nil element") - - // errOneofHasNil is the error returned if Marshal is called with - // a struct with a oneof field containing a nil element. - errOneofHasNil = errors.New("proto: oneof field has nil value") - - // ErrNil is the error returned if Marshal is called with nil. - ErrNil = errors.New("proto: Marshal called with nil") - - // ErrTooLarge is the error returned if Marshal is called with a - // message that encodes to >2GB. - ErrTooLarge = errors.New("proto: message encodes to over 2 GB") -) - -// The fundamental encoders that put bytes on the wire. -// Those that take integer types all accept uint64 and are -// therefore of type valueEncoder. - -const maxVarintBytes = 10 // maximum length of a varint - -// EncodeVarint returns the varint encoding of x. -// This is the format for the -// int32, int64, uint32, uint64, bool, and enum -// protocol buffer types. -// Not used by the package itself, but helpful to clients -// wishing to use the same encoding. -func EncodeVarint(x uint64) []byte { - var buf [maxVarintBytes]byte - var n int - for n = 0; x > 127; n++ { - buf[n] = 0x80 | uint8(x&0x7F) - x >>= 7 - } - buf[n] = uint8(x) - n++ - return buf[0:n] -} - -// EncodeVarint writes a varint-encoded integer to the Buffer. -// This is the format for the -// int32, int64, uint32, uint64, bool, and enum -// protocol buffer types. -func (p *Buffer) EncodeVarint(x uint64) error { - for x >= 1<<7 { - p.buf = append(p.buf, uint8(x&0x7f|0x80)) - x >>= 7 - } - p.buf = append(p.buf, uint8(x)) - return nil -} - -// SizeVarint returns the varint encoding size of an integer. -func SizeVarint(x uint64) int { - switch { - case x < 1<<7: - return 1 - case x < 1<<14: - return 2 - case x < 1<<21: - return 3 - case x < 1<<28: - return 4 - case x < 1<<35: - return 5 - case x < 1<<42: - return 6 - case x < 1<<49: - return 7 - case x < 1<<56: - return 8 - case x < 1<<63: - return 9 - } - return 10 -} - -// EncodeFixed64 writes a 64-bit integer to the Buffer. -// This is the format for the -// fixed64, sfixed64, and double protocol buffer types. -func (p *Buffer) EncodeFixed64(x uint64) error { - p.buf = append(p.buf, - uint8(x), - uint8(x>>8), - uint8(x>>16), - uint8(x>>24), - uint8(x>>32), - uint8(x>>40), - uint8(x>>48), - uint8(x>>56)) - return nil -} - -// EncodeFixed32 writes a 32-bit integer to the Buffer. -// This is the format for the -// fixed32, sfixed32, and float protocol buffer types. -func (p *Buffer) EncodeFixed32(x uint64) error { - p.buf = append(p.buf, - uint8(x), - uint8(x>>8), - uint8(x>>16), - uint8(x>>24)) - return nil -} - -// EncodeZigzag64 writes a zigzag-encoded 64-bit integer -// to the Buffer. -// This is the format used for the sint64 protocol buffer type. -func (p *Buffer) EncodeZigzag64(x uint64) error { - // use signed number to get arithmetic right shift. - return p.EncodeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} - -// EncodeZigzag32 writes a zigzag-encoded 32-bit integer -// to the Buffer. -// This is the format used for the sint32 protocol buffer type. -func (p *Buffer) EncodeZigzag32(x uint64) error { - // use signed number to get arithmetic right shift. - return p.EncodeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) -} - -// EncodeRawBytes writes a count-delimited byte buffer to the Buffer. -// This is the format used for the bytes protocol buffer -// type and for embedded messages. -func (p *Buffer) EncodeRawBytes(b []byte) error { - p.EncodeVarint(uint64(len(b))) - p.buf = append(p.buf, b...) - return nil -} - -// EncodeStringBytes writes an encoded string to the Buffer. -// This is the format used for the proto2 string type. -func (p *Buffer) EncodeStringBytes(s string) error { - p.EncodeVarint(uint64(len(s))) - p.buf = append(p.buf, s...) - return nil -} - -// Marshaler is the interface representing objects that can marshal themselves. -type Marshaler interface { - Marshal() ([]byte, error) -} - -// EncodeMessage writes the protocol buffer to the Buffer, -// prefixed by a varint-encoded length. -func (p *Buffer) EncodeMessage(pb Message) error { - siz := Size(pb) - sizVar := SizeVarint(uint64(siz)) - p.grow(siz + sizVar) - p.EncodeVarint(uint64(siz)) - return p.Marshal(pb) -} - -// All protocol buffer fields are nillable, but be careful. -func isNil(v reflect.Value) bool { - switch v.Kind() { - case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: - return v.IsNil() - } - return false -} diff --git a/vendor/github.com/gogo/protobuf/proto/encode_gogo.go b/vendor/github.com/gogo/protobuf/proto/encode_gogo.go deleted file mode 100644 index 0f5fb173e..000000000 --- a/vendor/github.com/gogo/protobuf/proto/encode_gogo.go +++ /dev/null @@ -1,33 +0,0 @@ -// Protocol Buffers for Go with Gadgets -// -// Copyright (c) 2013, The GoGo Authors. All rights reserved. -// http://github.com/gogo/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -func NewRequiredNotSetError(field string) *RequiredNotSetError { - return &RequiredNotSetError{field} -} diff --git a/vendor/github.com/gogo/protobuf/proto/equal.go b/vendor/github.com/gogo/protobuf/proto/equal.go deleted file mode 100644 index d4db5a1c1..000000000 --- a/vendor/github.com/gogo/protobuf/proto/equal.go +++ /dev/null @@ -1,300 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2011 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Protocol buffer comparison. - -package proto - -import ( - "bytes" - "log" - "reflect" - "strings" -) - -/* -Equal returns true iff protocol buffers a and b are equal. -The arguments must both be pointers to protocol buffer structs. - -Equality is defined in this way: - - Two messages are equal iff they are the same type, - corresponding fields are equal, unknown field sets - are equal, and extensions sets are equal. - - Two set scalar fields are equal iff their values are equal. - If the fields are of a floating-point type, remember that - NaN != x for all x, including NaN. If the message is defined - in a proto3 .proto file, fields are not "set"; specifically, - zero length proto3 "bytes" fields are equal (nil == {}). - - Two repeated fields are equal iff their lengths are the same, - and their corresponding elements are equal. Note a "bytes" field, - although represented by []byte, is not a repeated field and the - rule for the scalar fields described above applies. - - Two unset fields are equal. - - Two unknown field sets are equal if their current - encoded state is equal. - - Two extension sets are equal iff they have corresponding - elements that are pairwise equal. - - Two map fields are equal iff their lengths are the same, - and they contain the same set of elements. Zero-length map - fields are equal. - - Every other combination of things are not equal. - -The return value is undefined if a and b are not protocol buffers. -*/ -func Equal(a, b Message) bool { - if a == nil || b == nil { - return a == b - } - v1, v2 := reflect.ValueOf(a), reflect.ValueOf(b) - if v1.Type() != v2.Type() { - return false - } - if v1.Kind() == reflect.Ptr { - if v1.IsNil() { - return v2.IsNil() - } - if v2.IsNil() { - return false - } - v1, v2 = v1.Elem(), v2.Elem() - } - if v1.Kind() != reflect.Struct { - return false - } - return equalStruct(v1, v2) -} - -// v1 and v2 are known to have the same type. -func equalStruct(v1, v2 reflect.Value) bool { - sprop := GetProperties(v1.Type()) - for i := 0; i < v1.NumField(); i++ { - f := v1.Type().Field(i) - if strings.HasPrefix(f.Name, "XXX_") { - continue - } - f1, f2 := v1.Field(i), v2.Field(i) - if f.Type.Kind() == reflect.Ptr { - if n1, n2 := f1.IsNil(), f2.IsNil(); n1 && n2 { - // both unset - continue - } else if n1 != n2 { - // set/unset mismatch - return false - } - f1, f2 = f1.Elem(), f2.Elem() - } - if !equalAny(f1, f2, sprop.Prop[i]) { - return false - } - } - - if em1 := v1.FieldByName("XXX_InternalExtensions"); em1.IsValid() { - em2 := v2.FieldByName("XXX_InternalExtensions") - if !equalExtensions(v1.Type(), em1.Interface().(XXX_InternalExtensions), em2.Interface().(XXX_InternalExtensions)) { - return false - } - } - - if em1 := v1.FieldByName("XXX_extensions"); em1.IsValid() { - em2 := v2.FieldByName("XXX_extensions") - if !equalExtMap(v1.Type(), em1.Interface().(map[int32]Extension), em2.Interface().(map[int32]Extension)) { - return false - } - } - - uf := v1.FieldByName("XXX_unrecognized") - if !uf.IsValid() { - return true - } - - u1 := uf.Bytes() - u2 := v2.FieldByName("XXX_unrecognized").Bytes() - return bytes.Equal(u1, u2) -} - -// v1 and v2 are known to have the same type. -// prop may be nil. -func equalAny(v1, v2 reflect.Value, prop *Properties) bool { - if v1.Type() == protoMessageType { - m1, _ := v1.Interface().(Message) - m2, _ := v2.Interface().(Message) - return Equal(m1, m2) - } - switch v1.Kind() { - case reflect.Bool: - return v1.Bool() == v2.Bool() - case reflect.Float32, reflect.Float64: - return v1.Float() == v2.Float() - case reflect.Int32, reflect.Int64: - return v1.Int() == v2.Int() - case reflect.Interface: - // Probably a oneof field; compare the inner values. - n1, n2 := v1.IsNil(), v2.IsNil() - if n1 || n2 { - return n1 == n2 - } - e1, e2 := v1.Elem(), v2.Elem() - if e1.Type() != e2.Type() { - return false - } - return equalAny(e1, e2, nil) - case reflect.Map: - if v1.Len() != v2.Len() { - return false - } - for _, key := range v1.MapKeys() { - val2 := v2.MapIndex(key) - if !val2.IsValid() { - // This key was not found in the second map. - return false - } - if !equalAny(v1.MapIndex(key), val2, nil) { - return false - } - } - return true - case reflect.Ptr: - // Maps may have nil values in them, so check for nil. - if v1.IsNil() && v2.IsNil() { - return true - } - if v1.IsNil() != v2.IsNil() { - return false - } - return equalAny(v1.Elem(), v2.Elem(), prop) - case reflect.Slice: - if v1.Type().Elem().Kind() == reflect.Uint8 { - // short circuit: []byte - - // Edge case: if this is in a proto3 message, a zero length - // bytes field is considered the zero value. - if prop != nil && prop.proto3 && v1.Len() == 0 && v2.Len() == 0 { - return true - } - if v1.IsNil() != v2.IsNil() { - return false - } - return bytes.Equal(v1.Interface().([]byte), v2.Interface().([]byte)) - } - - if v1.Len() != v2.Len() { - return false - } - for i := 0; i < v1.Len(); i++ { - if !equalAny(v1.Index(i), v2.Index(i), prop) { - return false - } - } - return true - case reflect.String: - return v1.Interface().(string) == v2.Interface().(string) - case reflect.Struct: - return equalStruct(v1, v2) - case reflect.Uint32, reflect.Uint64: - return v1.Uint() == v2.Uint() - } - - // unknown type, so not a protocol buffer - log.Printf("proto: don't know how to compare %v", v1) - return false -} - -// base is the struct type that the extensions are based on. -// x1 and x2 are InternalExtensions. -func equalExtensions(base reflect.Type, x1, x2 XXX_InternalExtensions) bool { - em1, _ := x1.extensionsRead() - em2, _ := x2.extensionsRead() - return equalExtMap(base, em1, em2) -} - -func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool { - if len(em1) != len(em2) { - return false - } - - for extNum, e1 := range em1 { - e2, ok := em2[extNum] - if !ok { - return false - } - - m1, m2 := e1.value, e2.value - - if m1 == nil && m2 == nil { - // Both have only encoded form. - if bytes.Equal(e1.enc, e2.enc) { - continue - } - // The bytes are different, but the extensions might still be - // equal. We need to decode them to compare. - } - - if m1 != nil && m2 != nil { - // Both are unencoded. - if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { - return false - } - continue - } - - // At least one is encoded. To do a semantically correct comparison - // we need to unmarshal them first. - var desc *ExtensionDesc - if m := extensionMaps[base]; m != nil { - desc = m[extNum] - } - if desc == nil { - // If both have only encoded form and the bytes are the same, - // it is handled above. We get here when the bytes are different. - // We don't know how to decode it, so just compare them as byte - // slices. - log.Printf("proto: don't know how to compare extension %d of %v", extNum, base) - return false - } - var err error - if m1 == nil { - m1, err = decodeExtension(e1.enc, desc) - } - if m2 == nil && err == nil { - m2, err = decodeExtension(e2.enc, desc) - } - if err != nil { - // The encoded form is invalid. - log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err) - return false - } - if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { - return false - } - } - - return true -} diff --git a/vendor/github.com/gogo/protobuf/proto/extensions.go b/vendor/github.com/gogo/protobuf/proto/extensions.go deleted file mode 100644 index 341c6f57f..000000000 --- a/vendor/github.com/gogo/protobuf/proto/extensions.go +++ /dev/null @@ -1,605 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -/* - * Types and routines for supporting protocol buffer extensions. - */ - -import ( - "errors" - "fmt" - "io" - "reflect" - "strconv" - "sync" -) - -// ErrMissingExtension is the error returned by GetExtension if the named extension is not in the message. -var ErrMissingExtension = errors.New("proto: missing extension") - -// ExtensionRange represents a range of message extensions for a protocol buffer. -// Used in code generated by the protocol compiler. -type ExtensionRange struct { - Start, End int32 // both inclusive -} - -// extendableProto is an interface implemented by any protocol buffer generated by the current -// proto compiler that may be extended. -type extendableProto interface { - Message - ExtensionRangeArray() []ExtensionRange - extensionsWrite() map[int32]Extension - extensionsRead() (map[int32]Extension, sync.Locker) -} - -// extendableProtoV1 is an interface implemented by a protocol buffer generated by the previous -// version of the proto compiler that may be extended. -type extendableProtoV1 interface { - Message - ExtensionRangeArray() []ExtensionRange - ExtensionMap() map[int32]Extension -} - -// extensionAdapter is a wrapper around extendableProtoV1 that implements extendableProto. -type extensionAdapter struct { - extendableProtoV1 -} - -func (e extensionAdapter) extensionsWrite() map[int32]Extension { - return e.ExtensionMap() -} - -func (e extensionAdapter) extensionsRead() (map[int32]Extension, sync.Locker) { - return e.ExtensionMap(), notLocker{} -} - -// notLocker is a sync.Locker whose Lock and Unlock methods are nops. -type notLocker struct{} - -func (n notLocker) Lock() {} -func (n notLocker) Unlock() {} - -// extendable returns the extendableProto interface for the given generated proto message. -// If the proto message has the old extension format, it returns a wrapper that implements -// the extendableProto interface. -func extendable(p interface{}) (extendableProto, error) { - switch p := p.(type) { - case extendableProto: - if isNilPtr(p) { - return nil, fmt.Errorf("proto: nil %T is not extendable", p) - } - return p, nil - case extendableProtoV1: - if isNilPtr(p) { - return nil, fmt.Errorf("proto: nil %T is not extendable", p) - } - return extensionAdapter{p}, nil - case extensionsBytes: - return slowExtensionAdapter{p}, nil - } - // Don't allocate a specific error containing %T: - // this is the hot path for Clone and MarshalText. - return nil, errNotExtendable -} - -var errNotExtendable = errors.New("proto: not an extendable proto.Message") - -func isNilPtr(x interface{}) bool { - v := reflect.ValueOf(x) - return v.Kind() == reflect.Ptr && v.IsNil() -} - -// XXX_InternalExtensions is an internal representation of proto extensions. -// -// Each generated message struct type embeds an anonymous XXX_InternalExtensions field, -// thus gaining the unexported 'extensions' method, which can be called only from the proto package. -// -// The methods of XXX_InternalExtensions are not concurrency safe in general, -// but calls to logically read-only methods such as has and get may be executed concurrently. -type XXX_InternalExtensions struct { - // The struct must be indirect so that if a user inadvertently copies a - // generated message and its embedded XXX_InternalExtensions, they - // avoid the mayhem of a copied mutex. - // - // The mutex serializes all logically read-only operations to p.extensionMap. - // It is up to the client to ensure that write operations to p.extensionMap are - // mutually exclusive with other accesses. - p *struct { - mu sync.Mutex - extensionMap map[int32]Extension - } -} - -// extensionsWrite returns the extension map, creating it on first use. -func (e *XXX_InternalExtensions) extensionsWrite() map[int32]Extension { - if e.p == nil { - e.p = new(struct { - mu sync.Mutex - extensionMap map[int32]Extension - }) - e.p.extensionMap = make(map[int32]Extension) - } - return e.p.extensionMap -} - -// extensionsRead returns the extensions map for read-only use. It may be nil. -// The caller must hold the returned mutex's lock when accessing Elements within the map. -func (e *XXX_InternalExtensions) extensionsRead() (map[int32]Extension, sync.Locker) { - if e.p == nil { - return nil, nil - } - return e.p.extensionMap, &e.p.mu -} - -// ExtensionDesc represents an extension specification. -// Used in generated code from the protocol compiler. -type ExtensionDesc struct { - ExtendedType Message // nil pointer to the type that is being extended - ExtensionType interface{} // nil pointer to the extension type - Field int32 // field number - Name string // fully-qualified name of extension, for text formatting - Tag string // protobuf tag style - Filename string // name of the file in which the extension is defined -} - -func (ed *ExtensionDesc) repeated() bool { - t := reflect.TypeOf(ed.ExtensionType) - return t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 -} - -// Extension represents an extension in a message. -type Extension struct { - // When an extension is stored in a message using SetExtension - // only desc and value are set. When the message is marshaled - // enc will be set to the encoded form of the message. - // - // When a message is unmarshaled and contains extensions, each - // extension will have only enc set. When such an extension is - // accessed using GetExtension (or GetExtensions) desc and value - // will be set. - desc *ExtensionDesc - value interface{} - enc []byte -} - -// SetRawExtension is for testing only. -func SetRawExtension(base Message, id int32, b []byte) { - if ebase, ok := base.(extensionsBytes); ok { - clearExtension(base, id) - ext := ebase.GetExtensions() - *ext = append(*ext, b...) - return - } - epb, err := extendable(base) - if err != nil { - return - } - extmap := epb.extensionsWrite() - extmap[id] = Extension{enc: b} -} - -// isExtensionField returns true iff the given field number is in an extension range. -func isExtensionField(pb extendableProto, field int32) bool { - for _, er := range pb.ExtensionRangeArray() { - if er.Start <= field && field <= er.End { - return true - } - } - return false -} - -// checkExtensionTypes checks that the given extension is valid for pb. -func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error { - var pbi interface{} = pb - // Check the extended type. - if ea, ok := pbi.(extensionAdapter); ok { - pbi = ea.extendableProtoV1 - } - if ea, ok := pbi.(slowExtensionAdapter); ok { - pbi = ea.extensionsBytes - } - if a, b := reflect.TypeOf(pbi), reflect.TypeOf(extension.ExtendedType); a != b { - return fmt.Errorf("proto: bad extended type; %v does not extend %v", b, a) - } - // Check the range. - if !isExtensionField(pb, extension.Field) { - return errors.New("proto: bad extension number; not in declared ranges") - } - return nil -} - -// extPropKey is sufficient to uniquely identify an extension. -type extPropKey struct { - base reflect.Type - field int32 -} - -var extProp = struct { - sync.RWMutex - m map[extPropKey]*Properties -}{ - m: make(map[extPropKey]*Properties), -} - -func extensionProperties(ed *ExtensionDesc) *Properties { - key := extPropKey{base: reflect.TypeOf(ed.ExtendedType), field: ed.Field} - - extProp.RLock() - if prop, ok := extProp.m[key]; ok { - extProp.RUnlock() - return prop - } - extProp.RUnlock() - - extProp.Lock() - defer extProp.Unlock() - // Check again. - if prop, ok := extProp.m[key]; ok { - return prop - } - - prop := new(Properties) - prop.Init(reflect.TypeOf(ed.ExtensionType), "unknown_name", ed.Tag, nil) - extProp.m[key] = prop - return prop -} - -// HasExtension returns whether the given extension is present in pb. -func HasExtension(pb Message, extension *ExtensionDesc) bool { - if epb, doki := pb.(extensionsBytes); doki { - ext := epb.GetExtensions() - buf := *ext - o := 0 - for o < len(buf) { - tag, n := DecodeVarint(buf[o:]) - fieldNum := int32(tag >> 3) - if int32(fieldNum) == extension.Field { - return true - } - wireType := int(tag & 0x7) - o += n - l, err := size(buf[o:], wireType) - if err != nil { - return false - } - o += l - } - return false - } - // TODO: Check types, field numbers, etc.? - epb, err := extendable(pb) - if err != nil { - return false - } - extmap, mu := epb.extensionsRead() - if extmap == nil { - return false - } - mu.Lock() - _, ok := extmap[extension.Field] - mu.Unlock() - return ok -} - -// ClearExtension removes the given extension from pb. -func ClearExtension(pb Message, extension *ExtensionDesc) { - clearExtension(pb, extension.Field) -} - -func clearExtension(pb Message, fieldNum int32) { - if epb, ok := pb.(extensionsBytes); ok { - offset := 0 - for offset != -1 { - offset = deleteExtension(epb, fieldNum, offset) - } - return - } - epb, err := extendable(pb) - if err != nil { - return - } - // TODO: Check types, field numbers, etc.? - extmap := epb.extensionsWrite() - delete(extmap, fieldNum) -} - -// GetExtension retrieves a proto2 extended field from pb. -// -// If the descriptor is type complete (i.e., ExtensionDesc.ExtensionType is non-nil), -// then GetExtension parses the encoded field and returns a Go value of the specified type. -// If the field is not present, then the default value is returned (if one is specified), -// otherwise ErrMissingExtension is reported. -// -// If the descriptor is not type complete (i.e., ExtensionDesc.ExtensionType is nil), -// then GetExtension returns the raw encoded bytes of the field extension. -func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) { - if epb, doki := pb.(extensionsBytes); doki { - ext := epb.GetExtensions() - return decodeExtensionFromBytes(extension, *ext) - } - - epb, err := extendable(pb) - if err != nil { - return nil, err - } - - if extension.ExtendedType != nil { - // can only check type if this is a complete descriptor - if cerr := checkExtensionTypes(epb, extension); cerr != nil { - return nil, cerr - } - } - - emap, mu := epb.extensionsRead() - if emap == nil { - return defaultExtensionValue(extension) - } - mu.Lock() - defer mu.Unlock() - e, ok := emap[extension.Field] - if !ok { - // defaultExtensionValue returns the default value or - // ErrMissingExtension if there is no default. - return defaultExtensionValue(extension) - } - - if e.value != nil { - // Already decoded. Check the descriptor, though. - if e.desc != extension { - // This shouldn't happen. If it does, it means that - // GetExtension was called twice with two different - // descriptors with the same field number. - return nil, errors.New("proto: descriptor conflict") - } - return e.value, nil - } - - if extension.ExtensionType == nil { - // incomplete descriptor - return e.enc, nil - } - - v, err := decodeExtension(e.enc, extension) - if err != nil { - return nil, err - } - - // Remember the decoded version and drop the encoded version. - // That way it is safe to mutate what we return. - e.value = v - e.desc = extension - e.enc = nil - emap[extension.Field] = e - return e.value, nil -} - -// defaultExtensionValue returns the default value for extension. -// If no default for an extension is defined ErrMissingExtension is returned. -func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) { - if extension.ExtensionType == nil { - // incomplete descriptor, so no default - return nil, ErrMissingExtension - } - - t := reflect.TypeOf(extension.ExtensionType) - props := extensionProperties(extension) - - sf, _, err := fieldDefault(t, props) - if err != nil { - return nil, err - } - - if sf == nil || sf.value == nil { - // There is no default value. - return nil, ErrMissingExtension - } - - if t.Kind() != reflect.Ptr { - // We do not need to return a Ptr, we can directly return sf.value. - return sf.value, nil - } - - // We need to return an interface{} that is a pointer to sf.value. - value := reflect.New(t).Elem() - value.Set(reflect.New(value.Type().Elem())) - if sf.kind == reflect.Int32 { - // We may have an int32 or an enum, but the underlying data is int32. - // Since we can't set an int32 into a non int32 reflect.value directly - // set it as a int32. - value.Elem().SetInt(int64(sf.value.(int32))) - } else { - value.Elem().Set(reflect.ValueOf(sf.value)) - } - return value.Interface(), nil -} - -// decodeExtension decodes an extension encoded in b. -func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) { - t := reflect.TypeOf(extension.ExtensionType) - unmarshal := typeUnmarshaler(t, extension.Tag) - - // t is a pointer to a struct, pointer to basic type or a slice. - // Allocate space to store the pointer/slice. - value := reflect.New(t).Elem() - - var err error - for { - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - wire := int(x) & 7 - - b, err = unmarshal(b, valToPointer(value.Addr()), wire) - if err != nil { - return nil, err - } - - if len(b) == 0 { - break - } - } - return value.Interface(), nil -} - -// GetExtensions returns a slice of the extensions present in pb that are also listed in es. -// The returned slice has the same length as es; missing extensions will appear as nil elements. -func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) { - epb, err := extendable(pb) - if err != nil { - return nil, err - } - extensions = make([]interface{}, len(es)) - for i, e := range es { - extensions[i], err = GetExtension(epb, e) - if err == ErrMissingExtension { - err = nil - } - if err != nil { - return - } - } - return -} - -// ExtensionDescs returns a new slice containing pb's extension descriptors, in undefined order. -// For non-registered extensions, ExtensionDescs returns an incomplete descriptor containing -// just the Field field, which defines the extension's field number. -func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) { - epb, err := extendable(pb) - if err != nil { - return nil, err - } - registeredExtensions := RegisteredExtensions(pb) - - emap, mu := epb.extensionsRead() - if emap == nil { - return nil, nil - } - mu.Lock() - defer mu.Unlock() - extensions := make([]*ExtensionDesc, 0, len(emap)) - for extid, e := range emap { - desc := e.desc - if desc == nil { - desc = registeredExtensions[extid] - if desc == nil { - desc = &ExtensionDesc{Field: extid} - } - } - - extensions = append(extensions, desc) - } - return extensions, nil -} - -// SetExtension sets the specified extension of pb to the specified value. -func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error { - if epb, ok := pb.(extensionsBytes); ok { - ClearExtension(pb, extension) - newb, err := encodeExtension(extension, value) - if err != nil { - return err - } - bb := epb.GetExtensions() - *bb = append(*bb, newb...) - return nil - } - epb, err := extendable(pb) - if err != nil { - return err - } - if err := checkExtensionTypes(epb, extension); err != nil { - return err - } - typ := reflect.TypeOf(extension.ExtensionType) - if typ != reflect.TypeOf(value) { - return fmt.Errorf("proto: bad extension value type. got: %T, want: %T", value, extension.ExtensionType) - } - // nil extension values need to be caught early, because the - // encoder can't distinguish an ErrNil due to a nil extension - // from an ErrNil due to a missing field. Extensions are - // always optional, so the encoder would just swallow the error - // and drop all the extensions from the encoded message. - if reflect.ValueOf(value).IsNil() { - return fmt.Errorf("proto: SetExtension called with nil value of type %T", value) - } - - extmap := epb.extensionsWrite() - extmap[extension.Field] = Extension{desc: extension, value: value} - return nil -} - -// ClearAllExtensions clears all extensions from pb. -func ClearAllExtensions(pb Message) { - if epb, doki := pb.(extensionsBytes); doki { - ext := epb.GetExtensions() - *ext = []byte{} - return - } - epb, err := extendable(pb) - if err != nil { - return - } - m := epb.extensionsWrite() - for k := range m { - delete(m, k) - } -} - -// A global registry of extensions. -// The generated code will register the generated descriptors by calling RegisterExtension. - -var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc) - -// RegisterExtension is called from the generated code. -func RegisterExtension(desc *ExtensionDesc) { - st := reflect.TypeOf(desc.ExtendedType).Elem() - m := extensionMaps[st] - if m == nil { - m = make(map[int32]*ExtensionDesc) - extensionMaps[st] = m - } - if _, ok := m[desc.Field]; ok { - panic("proto: duplicate extension registered: " + st.String() + " " + strconv.Itoa(int(desc.Field))) - } - m[desc.Field] = desc -} - -// RegisteredExtensions returns a map of the registered extensions of a -// protocol buffer struct, indexed by the extension number. -// The argument pb should be a nil pointer to the struct type. -func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc { - return extensionMaps[reflect.TypeOf(pb).Elem()] -} diff --git a/vendor/github.com/gogo/protobuf/proto/extensions_gogo.go b/vendor/github.com/gogo/protobuf/proto/extensions_gogo.go deleted file mode 100644 index 6f1ae120e..000000000 --- a/vendor/github.com/gogo/protobuf/proto/extensions_gogo.go +++ /dev/null @@ -1,389 +0,0 @@ -// Protocol Buffers for Go with Gadgets -// -// Copyright (c) 2013, The GoGo Authors. All rights reserved. -// http://github.com/gogo/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -import ( - "bytes" - "errors" - "fmt" - "io" - "reflect" - "sort" - "strings" - "sync" -) - -type extensionsBytes interface { - Message - ExtensionRangeArray() []ExtensionRange - GetExtensions() *[]byte -} - -type slowExtensionAdapter struct { - extensionsBytes -} - -func (s slowExtensionAdapter) extensionsWrite() map[int32]Extension { - panic("Please report a bug to github.com/gogo/protobuf if you see this message: Writing extensions is not supported for extensions stored in a byte slice field.") -} - -func (s slowExtensionAdapter) extensionsRead() (map[int32]Extension, sync.Locker) { - b := s.GetExtensions() - m, err := BytesToExtensionsMap(*b) - if err != nil { - panic(err) - } - return m, notLocker{} -} - -func GetBoolExtension(pb Message, extension *ExtensionDesc, ifnotset bool) bool { - if reflect.ValueOf(pb).IsNil() { - return ifnotset - } - value, err := GetExtension(pb, extension) - if err != nil { - return ifnotset - } - if value == nil { - return ifnotset - } - if value.(*bool) == nil { - return ifnotset - } - return *(value.(*bool)) -} - -func (this *Extension) Equal(that *Extension) bool { - if err := this.Encode(); err != nil { - return false - } - if err := that.Encode(); err != nil { - return false - } - return bytes.Equal(this.enc, that.enc) -} - -func (this *Extension) Compare(that *Extension) int { - if err := this.Encode(); err != nil { - return 1 - } - if err := that.Encode(); err != nil { - return -1 - } - return bytes.Compare(this.enc, that.enc) -} - -func SizeOfInternalExtension(m extendableProto) (n int) { - info := getMarshalInfo(reflect.TypeOf(m)) - return info.sizeV1Extensions(m.extensionsWrite()) -} - -type sortableMapElem struct { - field int32 - ext Extension -} - -func newSortableExtensionsFromMap(m map[int32]Extension) sortableExtensions { - s := make(sortableExtensions, 0, len(m)) - for k, v := range m { - s = append(s, &sortableMapElem{field: k, ext: v}) - } - return s -} - -type sortableExtensions []*sortableMapElem - -func (this sortableExtensions) Len() int { return len(this) } - -func (this sortableExtensions) Swap(i, j int) { this[i], this[j] = this[j], this[i] } - -func (this sortableExtensions) Less(i, j int) bool { return this[i].field < this[j].field } - -func (this sortableExtensions) String() string { - sort.Sort(this) - ss := make([]string, len(this)) - for i := range this { - ss[i] = fmt.Sprintf("%d: %v", this[i].field, this[i].ext) - } - return "map[" + strings.Join(ss, ",") + "]" -} - -func StringFromInternalExtension(m extendableProto) string { - return StringFromExtensionsMap(m.extensionsWrite()) -} - -func StringFromExtensionsMap(m map[int32]Extension) string { - return newSortableExtensionsFromMap(m).String() -} - -func StringFromExtensionsBytes(ext []byte) string { - m, err := BytesToExtensionsMap(ext) - if err != nil { - panic(err) - } - return StringFromExtensionsMap(m) -} - -func EncodeInternalExtension(m extendableProto, data []byte) (n int, err error) { - return EncodeExtensionMap(m.extensionsWrite(), data) -} - -func EncodeInternalExtensionBackwards(m extendableProto, data []byte) (n int, err error) { - return EncodeExtensionMapBackwards(m.extensionsWrite(), data) -} - -func EncodeExtensionMap(m map[int32]Extension, data []byte) (n int, err error) { - o := 0 - for _, e := range m { - if err := e.Encode(); err != nil { - return 0, err - } - n := copy(data[o:], e.enc) - if n != len(e.enc) { - return 0, io.ErrShortBuffer - } - o += n - } - return o, nil -} - -func EncodeExtensionMapBackwards(m map[int32]Extension, data []byte) (n int, err error) { - o := 0 - end := len(data) - for _, e := range m { - if err := e.Encode(); err != nil { - return 0, err - } - n := copy(data[end-len(e.enc):], e.enc) - if n != len(e.enc) { - return 0, io.ErrShortBuffer - } - end -= n - o += n - } - return o, nil -} - -func GetRawExtension(m map[int32]Extension, id int32) ([]byte, error) { - e := m[id] - if err := e.Encode(); err != nil { - return nil, err - } - return e.enc, nil -} - -func size(buf []byte, wire int) (int, error) { - switch wire { - case WireVarint: - _, n := DecodeVarint(buf) - return n, nil - case WireFixed64: - return 8, nil - case WireBytes: - v, n := DecodeVarint(buf) - return int(v) + n, nil - case WireFixed32: - return 4, nil - case WireStartGroup: - offset := 0 - for { - u, n := DecodeVarint(buf[offset:]) - fwire := int(u & 0x7) - offset += n - if fwire == WireEndGroup { - return offset, nil - } - s, err := size(buf[offset:], wire) - if err != nil { - return 0, err - } - offset += s - } - } - return 0, fmt.Errorf("proto: can't get size for unknown wire type %d", wire) -} - -func BytesToExtensionsMap(buf []byte) (map[int32]Extension, error) { - m := make(map[int32]Extension) - i := 0 - for i < len(buf) { - tag, n := DecodeVarint(buf[i:]) - if n <= 0 { - return nil, fmt.Errorf("unable to decode varint") - } - fieldNum := int32(tag >> 3) - wireType := int(tag & 0x7) - l, err := size(buf[i+n:], wireType) - if err != nil { - return nil, err - } - end := i + int(l) + n - m[int32(fieldNum)] = Extension{enc: buf[i:end]} - i = end - } - return m, nil -} - -func NewExtension(e []byte) Extension { - ee := Extension{enc: make([]byte, len(e))} - copy(ee.enc, e) - return ee -} - -func AppendExtension(e Message, tag int32, buf []byte) { - if ee, eok := e.(extensionsBytes); eok { - ext := ee.GetExtensions() - *ext = append(*ext, buf...) - return - } - if ee, eok := e.(extendableProto); eok { - m := ee.extensionsWrite() - ext := m[int32(tag)] // may be missing - ext.enc = append(ext.enc, buf...) - m[int32(tag)] = ext - } -} - -func encodeExtension(extension *ExtensionDesc, value interface{}) ([]byte, error) { - u := getMarshalInfo(reflect.TypeOf(extension.ExtendedType)) - ei := u.getExtElemInfo(extension) - v := value - p := toAddrPointer(&v, ei.isptr) - siz := ei.sizer(p, SizeVarint(ei.wiretag)) - buf := make([]byte, 0, siz) - return ei.marshaler(buf, p, ei.wiretag, false) -} - -func decodeExtensionFromBytes(extension *ExtensionDesc, buf []byte) (interface{}, error) { - o := 0 - for o < len(buf) { - tag, n := DecodeVarint((buf)[o:]) - fieldNum := int32(tag >> 3) - wireType := int(tag & 0x7) - if o+n > len(buf) { - return nil, fmt.Errorf("unable to decode extension") - } - l, err := size((buf)[o+n:], wireType) - if err != nil { - return nil, err - } - if int32(fieldNum) == extension.Field { - if o+n+l > len(buf) { - return nil, fmt.Errorf("unable to decode extension") - } - v, err := decodeExtension((buf)[o:o+n+l], extension) - if err != nil { - return nil, err - } - return v, nil - } - o += n + l - } - return defaultExtensionValue(extension) -} - -func (this *Extension) Encode() error { - if this.enc == nil { - var err error - this.enc, err = encodeExtension(this.desc, this.value) - if err != nil { - return err - } - } - return nil -} - -func (this Extension) GoString() string { - if err := this.Encode(); err != nil { - return fmt.Sprintf("error encoding extension: %v", err) - } - return fmt.Sprintf("proto.NewExtension(%#v)", this.enc) -} - -func SetUnsafeExtension(pb Message, fieldNum int32, value interface{}) error { - typ := reflect.TypeOf(pb).Elem() - ext, ok := extensionMaps[typ] - if !ok { - return fmt.Errorf("proto: bad extended type; %s is not extendable", typ.String()) - } - desc, ok := ext[fieldNum] - if !ok { - return errors.New("proto: bad extension number; not in declared ranges") - } - return SetExtension(pb, desc, value) -} - -func GetUnsafeExtension(pb Message, fieldNum int32) (interface{}, error) { - typ := reflect.TypeOf(pb).Elem() - ext, ok := extensionMaps[typ] - if !ok { - return nil, fmt.Errorf("proto: bad extended type; %s is not extendable", typ.String()) - } - desc, ok := ext[fieldNum] - if !ok { - return nil, fmt.Errorf("unregistered field number %d", fieldNum) - } - return GetExtension(pb, desc) -} - -func NewUnsafeXXX_InternalExtensions(m map[int32]Extension) XXX_InternalExtensions { - x := &XXX_InternalExtensions{ - p: new(struct { - mu sync.Mutex - extensionMap map[int32]Extension - }), - } - x.p.extensionMap = m - return *x -} - -func GetUnsafeExtensionsMap(extendable Message) map[int32]Extension { - pb := extendable.(extendableProto) - return pb.extensionsWrite() -} - -func deleteExtension(pb extensionsBytes, theFieldNum int32, offset int) int { - ext := pb.GetExtensions() - for offset < len(*ext) { - tag, n1 := DecodeVarint((*ext)[offset:]) - fieldNum := int32(tag >> 3) - wireType := int(tag & 0x7) - n2, err := size((*ext)[offset+n1:], wireType) - if err != nil { - panic(err) - } - newOffset := offset + n1 + n2 - if fieldNum == theFieldNum { - *ext = append((*ext)[:offset], (*ext)[newOffset:]...) - return offset - } - offset = newOffset - } - return -1 -} diff --git a/vendor/github.com/gogo/protobuf/proto/lib.go b/vendor/github.com/gogo/protobuf/proto/lib.go deleted file mode 100644 index 80db1c155..000000000 --- a/vendor/github.com/gogo/protobuf/proto/lib.go +++ /dev/null @@ -1,973 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -/* -Package proto converts data structures to and from the wire format of -protocol buffers. It works in concert with the Go source code generated -for .proto files by the protocol compiler. - -A summary of the properties of the protocol buffer interface -for a protocol buffer variable v: - - - Names are turned from camel_case to CamelCase for export. - - There are no methods on v to set fields; just treat - them as structure fields. - - There are getters that return a field's value if set, - and return the field's default value if unset. - The getters work even if the receiver is a nil message. - - The zero value for a struct is its correct initialization state. - All desired fields must be set before marshaling. - - A Reset() method will restore a protobuf struct to its zero state. - - Non-repeated fields are pointers to the values; nil means unset. - That is, optional or required field int32 f becomes F *int32. - - Repeated fields are slices. - - Helper functions are available to aid the setting of fields. - msg.Foo = proto.String("hello") // set field - - Constants are defined to hold the default values of all fields that - have them. They have the form Default_StructName_FieldName. - Because the getter methods handle defaulted values, - direct use of these constants should be rare. - - Enums are given type names and maps from names to values. - Enum values are prefixed by the enclosing message's name, or by the - enum's type name if it is a top-level enum. Enum types have a String - method, and a Enum method to assist in message construction. - - Nested messages, groups and enums have type names prefixed with the name of - the surrounding message type. - - Extensions are given descriptor names that start with E_, - followed by an underscore-delimited list of the nested messages - that contain it (if any) followed by the CamelCased name of the - extension field itself. HasExtension, ClearExtension, GetExtension - and SetExtension are functions for manipulating extensions. - - Oneof field sets are given a single field in their message, - with distinguished wrapper types for each possible field value. - - Marshal and Unmarshal are functions to encode and decode the wire format. - -When the .proto file specifies `syntax="proto3"`, there are some differences: - - - Non-repeated fields of non-message type are values instead of pointers. - - Enum types do not get an Enum method. - -The simplest way to describe this is to see an example. -Given file test.proto, containing - - package example; - - enum FOO { X = 17; } - - message Test { - required string label = 1; - optional int32 type = 2 [default=77]; - repeated int64 reps = 3; - optional group OptionalGroup = 4 { - required string RequiredField = 5; - } - oneof union { - int32 number = 6; - string name = 7; - } - } - -The resulting file, test.pb.go, is: - - package example - - import proto "github.com/gogo/protobuf/proto" - import math "math" - - type FOO int32 - const ( - FOO_X FOO = 17 - ) - var FOO_name = map[int32]string{ - 17: "X", - } - var FOO_value = map[string]int32{ - "X": 17, - } - - func (x FOO) Enum() *FOO { - p := new(FOO) - *p = x - return p - } - func (x FOO) String() string { - return proto.EnumName(FOO_name, int32(x)) - } - func (x *FOO) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(FOO_value, data) - if err != nil { - return err - } - *x = FOO(value) - return nil - } - - type Test struct { - Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"` - Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"` - Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"` - Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"` - // Types that are valid to be assigned to Union: - // *Test_Number - // *Test_Name - Union isTest_Union `protobuf_oneof:"union"` - XXX_unrecognized []byte `json:"-"` - } - func (m *Test) Reset() { *m = Test{} } - func (m *Test) String() string { return proto.CompactTextString(m) } - func (*Test) ProtoMessage() {} - - type isTest_Union interface { - isTest_Union() - } - - type Test_Number struct { - Number int32 `protobuf:"varint,6,opt,name=number"` - } - type Test_Name struct { - Name string `protobuf:"bytes,7,opt,name=name"` - } - - func (*Test_Number) isTest_Union() {} - func (*Test_Name) isTest_Union() {} - - func (m *Test) GetUnion() isTest_Union { - if m != nil { - return m.Union - } - return nil - } - const Default_Test_Type int32 = 77 - - func (m *Test) GetLabel() string { - if m != nil && m.Label != nil { - return *m.Label - } - return "" - } - - func (m *Test) GetType() int32 { - if m != nil && m.Type != nil { - return *m.Type - } - return Default_Test_Type - } - - func (m *Test) GetOptionalgroup() *Test_OptionalGroup { - if m != nil { - return m.Optionalgroup - } - return nil - } - - type Test_OptionalGroup struct { - RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"` - } - func (m *Test_OptionalGroup) Reset() { *m = Test_OptionalGroup{} } - func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) } - - func (m *Test_OptionalGroup) GetRequiredField() string { - if m != nil && m.RequiredField != nil { - return *m.RequiredField - } - return "" - } - - func (m *Test) GetNumber() int32 { - if x, ok := m.GetUnion().(*Test_Number); ok { - return x.Number - } - return 0 - } - - func (m *Test) GetName() string { - if x, ok := m.GetUnion().(*Test_Name); ok { - return x.Name - } - return "" - } - - func init() { - proto.RegisterEnum("example.FOO", FOO_name, FOO_value) - } - -To create and play with a Test object: - - package main - - import ( - "log" - - "github.com/gogo/protobuf/proto" - pb "./example.pb" - ) - - func main() { - test := &pb.Test{ - Label: proto.String("hello"), - Type: proto.Int32(17), - Reps: []int64{1, 2, 3}, - Optionalgroup: &pb.Test_OptionalGroup{ - RequiredField: proto.String("good bye"), - }, - Union: &pb.Test_Name{"fred"}, - } - data, err := proto.Marshal(test) - if err != nil { - log.Fatal("marshaling error: ", err) - } - newTest := &pb.Test{} - err = proto.Unmarshal(data, newTest) - if err != nil { - log.Fatal("unmarshaling error: ", err) - } - // Now test and newTest contain the same data. - if test.GetLabel() != newTest.GetLabel() { - log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel()) - } - // Use a type switch to determine which oneof was set. - switch u := test.Union.(type) { - case *pb.Test_Number: // u.Number contains the number. - case *pb.Test_Name: // u.Name contains the string. - } - // etc. - } -*/ -package proto - -import ( - "encoding/json" - "fmt" - "log" - "reflect" - "sort" - "strconv" - "sync" -) - -// RequiredNotSetError is an error type returned by either Marshal or Unmarshal. -// Marshal reports this when a required field is not initialized. -// Unmarshal reports this when a required field is missing from the wire data. -type RequiredNotSetError struct{ field string } - -func (e *RequiredNotSetError) Error() string { - if e.field == "" { - return fmt.Sprintf("proto: required field not set") - } - return fmt.Sprintf("proto: required field %q not set", e.field) -} -func (e *RequiredNotSetError) RequiredNotSet() bool { - return true -} - -type invalidUTF8Error struct{ field string } - -func (e *invalidUTF8Error) Error() string { - if e.field == "" { - return "proto: invalid UTF-8 detected" - } - return fmt.Sprintf("proto: field %q contains invalid UTF-8", e.field) -} -func (e *invalidUTF8Error) InvalidUTF8() bool { - return true -} - -// errInvalidUTF8 is a sentinel error to identify fields with invalid UTF-8. -// This error should not be exposed to the external API as such errors should -// be recreated with the field information. -var errInvalidUTF8 = &invalidUTF8Error{} - -// isNonFatal reports whether the error is either a RequiredNotSet error -// or a InvalidUTF8 error. -func isNonFatal(err error) bool { - if re, ok := err.(interface{ RequiredNotSet() bool }); ok && re.RequiredNotSet() { - return true - } - if re, ok := err.(interface{ InvalidUTF8() bool }); ok && re.InvalidUTF8() { - return true - } - return false -} - -type nonFatal struct{ E error } - -// Merge merges err into nf and reports whether it was successful. -// Otherwise it returns false for any fatal non-nil errors. -func (nf *nonFatal) Merge(err error) (ok bool) { - if err == nil { - return true // not an error - } - if !isNonFatal(err) { - return false // fatal error - } - if nf.E == nil { - nf.E = err // store first instance of non-fatal error - } - return true -} - -// Message is implemented by generated protocol buffer messages. -type Message interface { - Reset() - String() string - ProtoMessage() -} - -// A Buffer is a buffer manager for marshaling and unmarshaling -// protocol buffers. It may be reused between invocations to -// reduce memory usage. It is not necessary to use a Buffer; -// the global functions Marshal and Unmarshal create a -// temporary Buffer and are fine for most applications. -type Buffer struct { - buf []byte // encode/decode byte stream - index int // read point - - deterministic bool -} - -// NewBuffer allocates a new Buffer and initializes its internal data to -// the contents of the argument slice. -func NewBuffer(e []byte) *Buffer { - return &Buffer{buf: e} -} - -// Reset resets the Buffer, ready for marshaling a new protocol buffer. -func (p *Buffer) Reset() { - p.buf = p.buf[0:0] // for reading/writing - p.index = 0 // for reading -} - -// SetBuf replaces the internal buffer with the slice, -// ready for unmarshaling the contents of the slice. -func (p *Buffer) SetBuf(s []byte) { - p.buf = s - p.index = 0 -} - -// Bytes returns the contents of the Buffer. -func (p *Buffer) Bytes() []byte { return p.buf } - -// SetDeterministic sets whether to use deterministic serialization. -// -// Deterministic serialization guarantees that for a given binary, equal -// messages will always be serialized to the same bytes. This implies: -// -// - Repeated serialization of a message will return the same bytes. -// - Different processes of the same binary (which may be executing on -// different machines) will serialize equal messages to the same bytes. -// -// Note that the deterministic serialization is NOT canonical across -// languages. It is not guaranteed to remain stable over time. It is unstable -// across different builds with schema changes due to unknown fields. -// Users who need canonical serialization (e.g., persistent storage in a -// canonical form, fingerprinting, etc.) should define their own -// canonicalization specification and implement their own serializer rather -// than relying on this API. -// -// If deterministic serialization is requested, map entries will be sorted -// by keys in lexographical order. This is an implementation detail and -// subject to change. -func (p *Buffer) SetDeterministic(deterministic bool) { - p.deterministic = deterministic -} - -/* - * Helper routines for simplifying the creation of optional fields of basic type. - */ - -// Bool is a helper routine that allocates a new bool value -// to store v and returns a pointer to it. -func Bool(v bool) *bool { - return &v -} - -// Int32 is a helper routine that allocates a new int32 value -// to store v and returns a pointer to it. -func Int32(v int32) *int32 { - return &v -} - -// Int is a helper routine that allocates a new int32 value -// to store v and returns a pointer to it, but unlike Int32 -// its argument value is an int. -func Int(v int) *int32 { - p := new(int32) - *p = int32(v) - return p -} - -// Int64 is a helper routine that allocates a new int64 value -// to store v and returns a pointer to it. -func Int64(v int64) *int64 { - return &v -} - -// Float32 is a helper routine that allocates a new float32 value -// to store v and returns a pointer to it. -func Float32(v float32) *float32 { - return &v -} - -// Float64 is a helper routine that allocates a new float64 value -// to store v and returns a pointer to it. -func Float64(v float64) *float64 { - return &v -} - -// Uint32 is a helper routine that allocates a new uint32 value -// to store v and returns a pointer to it. -func Uint32(v uint32) *uint32 { - return &v -} - -// Uint64 is a helper routine that allocates a new uint64 value -// to store v and returns a pointer to it. -func Uint64(v uint64) *uint64 { - return &v -} - -// String is a helper routine that allocates a new string value -// to store v and returns a pointer to it. -func String(v string) *string { - return &v -} - -// EnumName is a helper function to simplify printing protocol buffer enums -// by name. Given an enum map and a value, it returns a useful string. -func EnumName(m map[int32]string, v int32) string { - s, ok := m[v] - if ok { - return s - } - return strconv.Itoa(int(v)) -} - -// UnmarshalJSONEnum is a helper function to simplify recovering enum int values -// from their JSON-encoded representation. Given a map from the enum's symbolic -// names to its int values, and a byte buffer containing the JSON-encoded -// value, it returns an int32 that can be cast to the enum type by the caller. -// -// The function can deal with both JSON representations, numeric and symbolic. -func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) { - if data[0] == '"' { - // New style: enums are strings. - var repr string - if err := json.Unmarshal(data, &repr); err != nil { - return -1, err - } - val, ok := m[repr] - if !ok { - return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr) - } - return val, nil - } - // Old style: enums are ints. - var val int32 - if err := json.Unmarshal(data, &val); err != nil { - return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName) - } - return val, nil -} - -// DebugPrint dumps the encoded data in b in a debugging format with a header -// including the string s. Used in testing but made available for general debugging. -func (p *Buffer) DebugPrint(s string, b []byte) { - var u uint64 - - obuf := p.buf - sindex := p.index - p.buf = b - p.index = 0 - depth := 0 - - fmt.Printf("\n--- %s ---\n", s) - -out: - for { - for i := 0; i < depth; i++ { - fmt.Print(" ") - } - - index := p.index - if index == len(p.buf) { - break - } - - op, err := p.DecodeVarint() - if err != nil { - fmt.Printf("%3d: fetching op err %v\n", index, err) - break out - } - tag := op >> 3 - wire := op & 7 - - switch wire { - default: - fmt.Printf("%3d: t=%3d unknown wire=%d\n", - index, tag, wire) - break out - - case WireBytes: - var r []byte - - r, err = p.DecodeRawBytes(false) - if err != nil { - break out - } - fmt.Printf("%3d: t=%3d bytes [%d]", index, tag, len(r)) - if len(r) <= 6 { - for i := 0; i < len(r); i++ { - fmt.Printf(" %.2x", r[i]) - } - } else { - for i := 0; i < 3; i++ { - fmt.Printf(" %.2x", r[i]) - } - fmt.Printf(" ..") - for i := len(r) - 3; i < len(r); i++ { - fmt.Printf(" %.2x", r[i]) - } - } - fmt.Printf("\n") - - case WireFixed32: - u, err = p.DecodeFixed32() - if err != nil { - fmt.Printf("%3d: t=%3d fix32 err %v\n", index, tag, err) - break out - } - fmt.Printf("%3d: t=%3d fix32 %d\n", index, tag, u) - - case WireFixed64: - u, err = p.DecodeFixed64() - if err != nil { - fmt.Printf("%3d: t=%3d fix64 err %v\n", index, tag, err) - break out - } - fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u) - - case WireVarint: - u, err = p.DecodeVarint() - if err != nil { - fmt.Printf("%3d: t=%3d varint err %v\n", index, tag, err) - break out - } - fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u) - - case WireStartGroup: - fmt.Printf("%3d: t=%3d start\n", index, tag) - depth++ - - case WireEndGroup: - depth-- - fmt.Printf("%3d: t=%3d end\n", index, tag) - } - } - - if depth != 0 { - fmt.Printf("%3d: start-end not balanced %d\n", p.index, depth) - } - fmt.Printf("\n") - - p.buf = obuf - p.index = sindex -} - -// SetDefaults sets unset protocol buffer fields to their default values. -// It only modifies fields that are both unset and have defined defaults. -// It recursively sets default values in any non-nil sub-messages. -func SetDefaults(pb Message) { - setDefaults(reflect.ValueOf(pb), true, false) -} - -// v is a struct. -func setDefaults(v reflect.Value, recur, zeros bool) { - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - - defaultMu.RLock() - dm, ok := defaults[v.Type()] - defaultMu.RUnlock() - if !ok { - dm = buildDefaultMessage(v.Type()) - defaultMu.Lock() - defaults[v.Type()] = dm - defaultMu.Unlock() - } - - for _, sf := range dm.scalars { - f := v.Field(sf.index) - if !f.IsNil() { - // field already set - continue - } - dv := sf.value - if dv == nil && !zeros { - // no explicit default, and don't want to set zeros - continue - } - fptr := f.Addr().Interface() // **T - // TODO: Consider batching the allocations we do here. - switch sf.kind { - case reflect.Bool: - b := new(bool) - if dv != nil { - *b = dv.(bool) - } - *(fptr.(**bool)) = b - case reflect.Float32: - f := new(float32) - if dv != nil { - *f = dv.(float32) - } - *(fptr.(**float32)) = f - case reflect.Float64: - f := new(float64) - if dv != nil { - *f = dv.(float64) - } - *(fptr.(**float64)) = f - case reflect.Int32: - // might be an enum - if ft := f.Type(); ft != int32PtrType { - // enum - f.Set(reflect.New(ft.Elem())) - if dv != nil { - f.Elem().SetInt(int64(dv.(int32))) - } - } else { - // int32 field - i := new(int32) - if dv != nil { - *i = dv.(int32) - } - *(fptr.(**int32)) = i - } - case reflect.Int64: - i := new(int64) - if dv != nil { - *i = dv.(int64) - } - *(fptr.(**int64)) = i - case reflect.String: - s := new(string) - if dv != nil { - *s = dv.(string) - } - *(fptr.(**string)) = s - case reflect.Uint8: - // exceptional case: []byte - var b []byte - if dv != nil { - db := dv.([]byte) - b = make([]byte, len(db)) - copy(b, db) - } else { - b = []byte{} - } - *(fptr.(*[]byte)) = b - case reflect.Uint32: - u := new(uint32) - if dv != nil { - *u = dv.(uint32) - } - *(fptr.(**uint32)) = u - case reflect.Uint64: - u := new(uint64) - if dv != nil { - *u = dv.(uint64) - } - *(fptr.(**uint64)) = u - default: - log.Printf("proto: can't set default for field %v (sf.kind=%v)", f, sf.kind) - } - } - - for _, ni := range dm.nested { - f := v.Field(ni) - // f is *T or T or []*T or []T - switch f.Kind() { - case reflect.Struct: - setDefaults(f, recur, zeros) - - case reflect.Ptr: - if f.IsNil() { - continue - } - setDefaults(f, recur, zeros) - - case reflect.Slice: - for i := 0; i < f.Len(); i++ { - e := f.Index(i) - if e.Kind() == reflect.Ptr && e.IsNil() { - continue - } - setDefaults(e, recur, zeros) - } - - case reflect.Map: - for _, k := range f.MapKeys() { - e := f.MapIndex(k) - if e.IsNil() { - continue - } - setDefaults(e, recur, zeros) - } - } - } -} - -var ( - // defaults maps a protocol buffer struct type to a slice of the fields, - // with its scalar fields set to their proto-declared non-zero default values. - defaultMu sync.RWMutex - defaults = make(map[reflect.Type]defaultMessage) - - int32PtrType = reflect.TypeOf((*int32)(nil)) -) - -// defaultMessage represents information about the default values of a message. -type defaultMessage struct { - scalars []scalarField - nested []int // struct field index of nested messages -} - -type scalarField struct { - index int // struct field index - kind reflect.Kind // element type (the T in *T or []T) - value interface{} // the proto-declared default value, or nil -} - -// t is a struct type. -func buildDefaultMessage(t reflect.Type) (dm defaultMessage) { - sprop := GetProperties(t) - for _, prop := range sprop.Prop { - fi, ok := sprop.decoderTags.get(prop.Tag) - if !ok { - // XXX_unrecognized - continue - } - ft := t.Field(fi).Type - - sf, nested, err := fieldDefault(ft, prop) - switch { - case err != nil: - log.Print(err) - case nested: - dm.nested = append(dm.nested, fi) - case sf != nil: - sf.index = fi - dm.scalars = append(dm.scalars, *sf) - } - } - - return dm -} - -// fieldDefault returns the scalarField for field type ft. -// sf will be nil if the field can not have a default. -// nestedMessage will be true if this is a nested message. -// Note that sf.index is not set on return. -func fieldDefault(ft reflect.Type, prop *Properties) (sf *scalarField, nestedMessage bool, err error) { - var canHaveDefault bool - switch ft.Kind() { - case reflect.Struct: - nestedMessage = true // non-nullable - - case reflect.Ptr: - if ft.Elem().Kind() == reflect.Struct { - nestedMessage = true - } else { - canHaveDefault = true // proto2 scalar field - } - - case reflect.Slice: - switch ft.Elem().Kind() { - case reflect.Ptr, reflect.Struct: - nestedMessage = true // repeated message - case reflect.Uint8: - canHaveDefault = true // bytes field - } - - case reflect.Map: - if ft.Elem().Kind() == reflect.Ptr { - nestedMessage = true // map with message values - } - } - - if !canHaveDefault { - if nestedMessage { - return nil, true, nil - } - return nil, false, nil - } - - // We now know that ft is a pointer or slice. - sf = &scalarField{kind: ft.Elem().Kind()} - - // scalar fields without defaults - if !prop.HasDefault { - return sf, false, nil - } - - // a scalar field: either *T or []byte - switch ft.Elem().Kind() { - case reflect.Bool: - x, err := strconv.ParseBool(prop.Default) - if err != nil { - return nil, false, fmt.Errorf("proto: bad default bool %q: %v", prop.Default, err) - } - sf.value = x - case reflect.Float32: - x, err := strconv.ParseFloat(prop.Default, 32) - if err != nil { - return nil, false, fmt.Errorf("proto: bad default float32 %q: %v", prop.Default, err) - } - sf.value = float32(x) - case reflect.Float64: - x, err := strconv.ParseFloat(prop.Default, 64) - if err != nil { - return nil, false, fmt.Errorf("proto: bad default float64 %q: %v", prop.Default, err) - } - sf.value = x - case reflect.Int32: - x, err := strconv.ParseInt(prop.Default, 10, 32) - if err != nil { - return nil, false, fmt.Errorf("proto: bad default int32 %q: %v", prop.Default, err) - } - sf.value = int32(x) - case reflect.Int64: - x, err := strconv.ParseInt(prop.Default, 10, 64) - if err != nil { - return nil, false, fmt.Errorf("proto: bad default int64 %q: %v", prop.Default, err) - } - sf.value = x - case reflect.String: - sf.value = prop.Default - case reflect.Uint8: - // []byte (not *uint8) - sf.value = []byte(prop.Default) - case reflect.Uint32: - x, err := strconv.ParseUint(prop.Default, 10, 32) - if err != nil { - return nil, false, fmt.Errorf("proto: bad default uint32 %q: %v", prop.Default, err) - } - sf.value = uint32(x) - case reflect.Uint64: - x, err := strconv.ParseUint(prop.Default, 10, 64) - if err != nil { - return nil, false, fmt.Errorf("proto: bad default uint64 %q: %v", prop.Default, err) - } - sf.value = x - default: - return nil, false, fmt.Errorf("proto: unhandled def kind %v", ft.Elem().Kind()) - } - - return sf, false, nil -} - -// mapKeys returns a sort.Interface to be used for sorting the map keys. -// Map fields may have key types of non-float scalars, strings and enums. -func mapKeys(vs []reflect.Value) sort.Interface { - s := mapKeySorter{vs: vs} - - // Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps. - if len(vs) == 0 { - return s - } - switch vs[0].Kind() { - case reflect.Int32, reflect.Int64: - s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() } - case reflect.Uint32, reflect.Uint64: - s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() } - case reflect.Bool: - s.less = func(a, b reflect.Value) bool { return !a.Bool() && b.Bool() } // false < true - case reflect.String: - s.less = func(a, b reflect.Value) bool { return a.String() < b.String() } - default: - panic(fmt.Sprintf("unsupported map key type: %v", vs[0].Kind())) - } - - return s -} - -type mapKeySorter struct { - vs []reflect.Value - less func(a, b reflect.Value) bool -} - -func (s mapKeySorter) Len() int { return len(s.vs) } -func (s mapKeySorter) Swap(i, j int) { s.vs[i], s.vs[j] = s.vs[j], s.vs[i] } -func (s mapKeySorter) Less(i, j int) bool { - return s.less(s.vs[i], s.vs[j]) -} - -// isProto3Zero reports whether v is a zero proto3 value. -func isProto3Zero(v reflect.Value) bool { - switch v.Kind() { - case reflect.Bool: - return !v.Bool() - case reflect.Int32, reflect.Int64: - return v.Int() == 0 - case reflect.Uint32, reflect.Uint64: - return v.Uint() == 0 - case reflect.Float32, reflect.Float64: - return v.Float() == 0 - case reflect.String: - return v.String() == "" - } - return false -} - -const ( - // ProtoPackageIsVersion3 is referenced from generated protocol buffer files - // to assert that that code is compatible with this version of the proto package. - GoGoProtoPackageIsVersion3 = true - - // ProtoPackageIsVersion2 is referenced from generated protocol buffer files - // to assert that that code is compatible with this version of the proto package. - GoGoProtoPackageIsVersion2 = true - - // ProtoPackageIsVersion1 is referenced from generated protocol buffer files - // to assert that that code is compatible with this version of the proto package. - GoGoProtoPackageIsVersion1 = true -) - -// InternalMessageInfo is a type used internally by generated .pb.go files. -// This type is not intended to be used by non-generated code. -// This type is not subject to any compatibility guarantee. -type InternalMessageInfo struct { - marshal *marshalInfo - unmarshal *unmarshalInfo - merge *mergeInfo - discard *discardInfo -} diff --git a/vendor/github.com/gogo/protobuf/proto/lib_gogo.go b/vendor/github.com/gogo/protobuf/proto/lib_gogo.go deleted file mode 100644 index b3aa39190..000000000 --- a/vendor/github.com/gogo/protobuf/proto/lib_gogo.go +++ /dev/null @@ -1,50 +0,0 @@ -// Protocol Buffers for Go with Gadgets -// -// Copyright (c) 2013, The GoGo Authors. All rights reserved. -// http://github.com/gogo/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -import ( - "encoding/json" - "strconv" -) - -type Sizer interface { - Size() int -} - -type ProtoSizer interface { - ProtoSize() int -} - -func MarshalJSONEnum(m map[int32]string, value int32) ([]byte, error) { - s, ok := m[value] - if !ok { - s = strconv.Itoa(int(value)) - } - return json.Marshal(s) -} diff --git a/vendor/github.com/gogo/protobuf/proto/message_set.go b/vendor/github.com/gogo/protobuf/proto/message_set.go deleted file mode 100644 index f48a75676..000000000 --- a/vendor/github.com/gogo/protobuf/proto/message_set.go +++ /dev/null @@ -1,181 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -/* - * Support for message sets. - */ - -import ( - "errors" -) - -// errNoMessageTypeID occurs when a protocol buffer does not have a message type ID. -// A message type ID is required for storing a protocol buffer in a message set. -var errNoMessageTypeID = errors.New("proto does not have a message type ID") - -// The first two types (_MessageSet_Item and messageSet) -// model what the protocol compiler produces for the following protocol message: -// message MessageSet { -// repeated group Item = 1 { -// required int32 type_id = 2; -// required string message = 3; -// }; -// } -// That is the MessageSet wire format. We can't use a proto to generate these -// because that would introduce a circular dependency between it and this package. - -type _MessageSet_Item struct { - TypeId *int32 `protobuf:"varint,2,req,name=type_id"` - Message []byte `protobuf:"bytes,3,req,name=message"` -} - -type messageSet struct { - Item []*_MessageSet_Item `protobuf:"group,1,rep"` - XXX_unrecognized []byte - // TODO: caching? -} - -// Make sure messageSet is a Message. -var _ Message = (*messageSet)(nil) - -// messageTypeIder is an interface satisfied by a protocol buffer type -// that may be stored in a MessageSet. -type messageTypeIder interface { - MessageTypeId() int32 -} - -func (ms *messageSet) find(pb Message) *_MessageSet_Item { - mti, ok := pb.(messageTypeIder) - if !ok { - return nil - } - id := mti.MessageTypeId() - for _, item := range ms.Item { - if *item.TypeId == id { - return item - } - } - return nil -} - -func (ms *messageSet) Has(pb Message) bool { - return ms.find(pb) != nil -} - -func (ms *messageSet) Unmarshal(pb Message) error { - if item := ms.find(pb); item != nil { - return Unmarshal(item.Message, pb) - } - if _, ok := pb.(messageTypeIder); !ok { - return errNoMessageTypeID - } - return nil // TODO: return error instead? -} - -func (ms *messageSet) Marshal(pb Message) error { - msg, err := Marshal(pb) - if err != nil { - return err - } - if item := ms.find(pb); item != nil { - // reuse existing item - item.Message = msg - return nil - } - - mti, ok := pb.(messageTypeIder) - if !ok { - return errNoMessageTypeID - } - - mtid := mti.MessageTypeId() - ms.Item = append(ms.Item, &_MessageSet_Item{ - TypeId: &mtid, - Message: msg, - }) - return nil -} - -func (ms *messageSet) Reset() { *ms = messageSet{} } -func (ms *messageSet) String() string { return CompactTextString(ms) } -func (*messageSet) ProtoMessage() {} - -// Support for the message_set_wire_format message option. - -func skipVarint(buf []byte) []byte { - i := 0 - for ; buf[i]&0x80 != 0; i++ { - } - return buf[i+1:] -} - -// unmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. -// It is called by Unmarshal methods on protocol buffer messages with the message_set_wire_format option. -func unmarshalMessageSet(buf []byte, exts interface{}) error { - var m map[int32]Extension - switch exts := exts.(type) { - case *XXX_InternalExtensions: - m = exts.extensionsWrite() - case map[int32]Extension: - m = exts - default: - return errors.New("proto: not an extension map") - } - - ms := new(messageSet) - if err := Unmarshal(buf, ms); err != nil { - return err - } - for _, item := range ms.Item { - id := *item.TypeId - msg := item.Message - - // Restore wire type and field number varint, plus length varint. - // Be careful to preserve duplicate items. - b := EncodeVarint(uint64(id)<<3 | WireBytes) - if ext, ok := m[id]; ok { - // Existing data; rip off the tag and length varint - // so we join the new data correctly. - // We can assume that ext.enc is set because we are unmarshaling. - o := ext.enc[len(b):] // skip wire type and field number - _, n := DecodeVarint(o) // calculate length of length varint - o = o[n:] // skip length varint - msg = append(o, msg...) // join old data and new data - } - b = append(b, EncodeVarint(uint64(len(msg)))...) - b = append(b, msg...) - - m[id] = Extension{enc: b} - } - return nil -} diff --git a/vendor/github.com/gogo/protobuf/proto/pointer_reflect.go b/vendor/github.com/gogo/protobuf/proto/pointer_reflect.go deleted file mode 100644 index b6cad9083..000000000 --- a/vendor/github.com/gogo/protobuf/proto/pointer_reflect.go +++ /dev/null @@ -1,357 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2012 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// +build purego appengine js - -// This file contains an implementation of proto field accesses using package reflect. -// It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can -// be used on App Engine. - -package proto - -import ( - "reflect" - "sync" -) - -const unsafeAllowed = false - -// A field identifies a field in a struct, accessible from a pointer. -// In this implementation, a field is identified by the sequence of field indices -// passed to reflect's FieldByIndex. -type field []int - -// toField returns a field equivalent to the given reflect field. -func toField(f *reflect.StructField) field { - return f.Index -} - -// invalidField is an invalid field identifier. -var invalidField = field(nil) - -// zeroField is a noop when calling pointer.offset. -var zeroField = field([]int{}) - -// IsValid reports whether the field identifier is valid. -func (f field) IsValid() bool { return f != nil } - -// The pointer type is for the table-driven decoder. -// The implementation here uses a reflect.Value of pointer type to -// create a generic pointer. In pointer_unsafe.go we use unsafe -// instead of reflect to implement the same (but faster) interface. -type pointer struct { - v reflect.Value -} - -// toPointer converts an interface of pointer type to a pointer -// that points to the same target. -func toPointer(i *Message) pointer { - return pointer{v: reflect.ValueOf(*i)} -} - -// toAddrPointer converts an interface to a pointer that points to -// the interface data. -func toAddrPointer(i *interface{}, isptr bool) pointer { - v := reflect.ValueOf(*i) - u := reflect.New(v.Type()) - u.Elem().Set(v) - return pointer{v: u} -} - -// valToPointer converts v to a pointer. v must be of pointer type. -func valToPointer(v reflect.Value) pointer { - return pointer{v: v} -} - -// offset converts from a pointer to a structure to a pointer to -// one of its fields. -func (p pointer) offset(f field) pointer { - return pointer{v: p.v.Elem().FieldByIndex(f).Addr()} -} - -func (p pointer) isNil() bool { - return p.v.IsNil() -} - -// grow updates the slice s in place to make it one element longer. -// s must be addressable. -// Returns the (addressable) new element. -func grow(s reflect.Value) reflect.Value { - n, m := s.Len(), s.Cap() - if n < m { - s.SetLen(n + 1) - } else { - s.Set(reflect.Append(s, reflect.Zero(s.Type().Elem()))) - } - return s.Index(n) -} - -func (p pointer) toInt64() *int64 { - return p.v.Interface().(*int64) -} -func (p pointer) toInt64Ptr() **int64 { - return p.v.Interface().(**int64) -} -func (p pointer) toInt64Slice() *[]int64 { - return p.v.Interface().(*[]int64) -} - -var int32ptr = reflect.TypeOf((*int32)(nil)) - -func (p pointer) toInt32() *int32 { - return p.v.Convert(int32ptr).Interface().(*int32) -} - -// The toInt32Ptr/Slice methods don't work because of enums. -// Instead, we must use set/get methods for the int32ptr/slice case. -/* - func (p pointer) toInt32Ptr() **int32 { - return p.v.Interface().(**int32) -} - func (p pointer) toInt32Slice() *[]int32 { - return p.v.Interface().(*[]int32) -} -*/ -func (p pointer) getInt32Ptr() *int32 { - if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) { - // raw int32 type - return p.v.Elem().Interface().(*int32) - } - // an enum - return p.v.Elem().Convert(int32PtrType).Interface().(*int32) -} -func (p pointer) setInt32Ptr(v int32) { - // Allocate value in a *int32. Possibly convert that to a *enum. - // Then assign it to a **int32 or **enum. - // Note: we can convert *int32 to *enum, but we can't convert - // **int32 to **enum! - p.v.Elem().Set(reflect.ValueOf(&v).Convert(p.v.Type().Elem())) -} - -// getInt32Slice copies []int32 from p as a new slice. -// This behavior differs from the implementation in pointer_unsafe.go. -func (p pointer) getInt32Slice() []int32 { - if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) { - // raw int32 type - return p.v.Elem().Interface().([]int32) - } - // an enum - // Allocate a []int32, then assign []enum's values into it. - // Note: we can't convert []enum to []int32. - slice := p.v.Elem() - s := make([]int32, slice.Len()) - for i := 0; i < slice.Len(); i++ { - s[i] = int32(slice.Index(i).Int()) - } - return s -} - -// setInt32Slice copies []int32 into p as a new slice. -// This behavior differs from the implementation in pointer_unsafe.go. -func (p pointer) setInt32Slice(v []int32) { - if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) { - // raw int32 type - p.v.Elem().Set(reflect.ValueOf(v)) - return - } - // an enum - // Allocate a []enum, then assign []int32's values into it. - // Note: we can't convert []enum to []int32. - slice := reflect.MakeSlice(p.v.Type().Elem(), len(v), cap(v)) - for i, x := range v { - slice.Index(i).SetInt(int64(x)) - } - p.v.Elem().Set(slice) -} -func (p pointer) appendInt32Slice(v int32) { - grow(p.v.Elem()).SetInt(int64(v)) -} - -func (p pointer) toUint64() *uint64 { - return p.v.Interface().(*uint64) -} -func (p pointer) toUint64Ptr() **uint64 { - return p.v.Interface().(**uint64) -} -func (p pointer) toUint64Slice() *[]uint64 { - return p.v.Interface().(*[]uint64) -} -func (p pointer) toUint32() *uint32 { - return p.v.Interface().(*uint32) -} -func (p pointer) toUint32Ptr() **uint32 { - return p.v.Interface().(**uint32) -} -func (p pointer) toUint32Slice() *[]uint32 { - return p.v.Interface().(*[]uint32) -} -func (p pointer) toBool() *bool { - return p.v.Interface().(*bool) -} -func (p pointer) toBoolPtr() **bool { - return p.v.Interface().(**bool) -} -func (p pointer) toBoolSlice() *[]bool { - return p.v.Interface().(*[]bool) -} -func (p pointer) toFloat64() *float64 { - return p.v.Interface().(*float64) -} -func (p pointer) toFloat64Ptr() **float64 { - return p.v.Interface().(**float64) -} -func (p pointer) toFloat64Slice() *[]float64 { - return p.v.Interface().(*[]float64) -} -func (p pointer) toFloat32() *float32 { - return p.v.Interface().(*float32) -} -func (p pointer) toFloat32Ptr() **float32 { - return p.v.Interface().(**float32) -} -func (p pointer) toFloat32Slice() *[]float32 { - return p.v.Interface().(*[]float32) -} -func (p pointer) toString() *string { - return p.v.Interface().(*string) -} -func (p pointer) toStringPtr() **string { - return p.v.Interface().(**string) -} -func (p pointer) toStringSlice() *[]string { - return p.v.Interface().(*[]string) -} -func (p pointer) toBytes() *[]byte { - return p.v.Interface().(*[]byte) -} -func (p pointer) toBytesSlice() *[][]byte { - return p.v.Interface().(*[][]byte) -} -func (p pointer) toExtensions() *XXX_InternalExtensions { - return p.v.Interface().(*XXX_InternalExtensions) -} -func (p pointer) toOldExtensions() *map[int32]Extension { - return p.v.Interface().(*map[int32]Extension) -} -func (p pointer) getPointer() pointer { - return pointer{v: p.v.Elem()} -} -func (p pointer) setPointer(q pointer) { - p.v.Elem().Set(q.v) -} -func (p pointer) appendPointer(q pointer) { - grow(p.v.Elem()).Set(q.v) -} - -// getPointerSlice copies []*T from p as a new []pointer. -// This behavior differs from the implementation in pointer_unsafe.go. -func (p pointer) getPointerSlice() []pointer { - if p.v.IsNil() { - return nil - } - n := p.v.Elem().Len() - s := make([]pointer, n) - for i := 0; i < n; i++ { - s[i] = pointer{v: p.v.Elem().Index(i)} - } - return s -} - -// setPointerSlice copies []pointer into p as a new []*T. -// This behavior differs from the implementation in pointer_unsafe.go. -func (p pointer) setPointerSlice(v []pointer) { - if v == nil { - p.v.Elem().Set(reflect.New(p.v.Elem().Type()).Elem()) - return - } - s := reflect.MakeSlice(p.v.Elem().Type(), 0, len(v)) - for _, p := range v { - s = reflect.Append(s, p.v) - } - p.v.Elem().Set(s) -} - -// getInterfacePointer returns a pointer that points to the -// interface data of the interface pointed by p. -func (p pointer) getInterfacePointer() pointer { - if p.v.Elem().IsNil() { - return pointer{v: p.v.Elem()} - } - return pointer{v: p.v.Elem().Elem().Elem().Field(0).Addr()} // *interface -> interface -> *struct -> struct -} - -func (p pointer) asPointerTo(t reflect.Type) reflect.Value { - // TODO: check that p.v.Type().Elem() == t? - return p.v -} - -func atomicLoadUnmarshalInfo(p **unmarshalInfo) *unmarshalInfo { - atomicLock.Lock() - defer atomicLock.Unlock() - return *p -} -func atomicStoreUnmarshalInfo(p **unmarshalInfo, v *unmarshalInfo) { - atomicLock.Lock() - defer atomicLock.Unlock() - *p = v -} -func atomicLoadMarshalInfo(p **marshalInfo) *marshalInfo { - atomicLock.Lock() - defer atomicLock.Unlock() - return *p -} -func atomicStoreMarshalInfo(p **marshalInfo, v *marshalInfo) { - atomicLock.Lock() - defer atomicLock.Unlock() - *p = v -} -func atomicLoadMergeInfo(p **mergeInfo) *mergeInfo { - atomicLock.Lock() - defer atomicLock.Unlock() - return *p -} -func atomicStoreMergeInfo(p **mergeInfo, v *mergeInfo) { - atomicLock.Lock() - defer atomicLock.Unlock() - *p = v -} -func atomicLoadDiscardInfo(p **discardInfo) *discardInfo { - atomicLock.Lock() - defer atomicLock.Unlock() - return *p -} -func atomicStoreDiscardInfo(p **discardInfo, v *discardInfo) { - atomicLock.Lock() - defer atomicLock.Unlock() - *p = v -} - -var atomicLock sync.Mutex diff --git a/vendor/github.com/gogo/protobuf/proto/pointer_reflect_gogo.go b/vendor/github.com/gogo/protobuf/proto/pointer_reflect_gogo.go deleted file mode 100644 index 7ffd3c29d..000000000 --- a/vendor/github.com/gogo/protobuf/proto/pointer_reflect_gogo.go +++ /dev/null @@ -1,59 +0,0 @@ -// Protocol Buffers for Go with Gadgets -// -// Copyright (c) 2018, The GoGo Authors. All rights reserved. -// http://github.com/gogo/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// +build purego appengine js - -// This file contains an implementation of proto field accesses using package reflect. -// It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can -// be used on App Engine. - -package proto - -import ( - "reflect" -) - -// TODO: untested, so probably incorrect. - -func (p pointer) getRef() pointer { - return pointer{v: p.v.Addr()} -} - -func (p pointer) appendRef(v pointer, typ reflect.Type) { - slice := p.getSlice(typ) - elem := v.asPointerTo(typ).Elem() - newSlice := reflect.Append(slice, elem) - slice.Set(newSlice) -} - -func (p pointer) getSlice(typ reflect.Type) reflect.Value { - sliceTyp := reflect.SliceOf(typ) - slice := p.asPointerTo(sliceTyp) - slice = slice.Elem() - return slice -} diff --git a/vendor/github.com/gogo/protobuf/proto/pointer_unsafe.go b/vendor/github.com/gogo/protobuf/proto/pointer_unsafe.go deleted file mode 100644 index d55a335d9..000000000 --- a/vendor/github.com/gogo/protobuf/proto/pointer_unsafe.go +++ /dev/null @@ -1,308 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2012 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// +build !purego,!appengine,!js - -// This file contains the implementation of the proto field accesses using package unsafe. - -package proto - -import ( - "reflect" - "sync/atomic" - "unsafe" -) - -const unsafeAllowed = true - -// A field identifies a field in a struct, accessible from a pointer. -// In this implementation, a field is identified by its byte offset from the start of the struct. -type field uintptr - -// toField returns a field equivalent to the given reflect field. -func toField(f *reflect.StructField) field { - return field(f.Offset) -} - -// invalidField is an invalid field identifier. -const invalidField = ^field(0) - -// zeroField is a noop when calling pointer.offset. -const zeroField = field(0) - -// IsValid reports whether the field identifier is valid. -func (f field) IsValid() bool { - return f != invalidField -} - -// The pointer type below is for the new table-driven encoder/decoder. -// The implementation here uses unsafe.Pointer to create a generic pointer. -// In pointer_reflect.go we use reflect instead of unsafe to implement -// the same (but slower) interface. -type pointer struct { - p unsafe.Pointer -} - -// size of pointer -var ptrSize = unsafe.Sizeof(uintptr(0)) - -// toPointer converts an interface of pointer type to a pointer -// that points to the same target. -func toPointer(i *Message) pointer { - // Super-tricky - read pointer out of data word of interface value. - // Saves ~25ns over the equivalent: - // return valToPointer(reflect.ValueOf(*i)) - return pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]} -} - -// toAddrPointer converts an interface to a pointer that points to -// the interface data. -func toAddrPointer(i *interface{}, isptr bool) pointer { - // Super-tricky - read or get the address of data word of interface value. - if isptr { - // The interface is of pointer type, thus it is a direct interface. - // The data word is the pointer data itself. We take its address. - return pointer{p: unsafe.Pointer(uintptr(unsafe.Pointer(i)) + ptrSize)} - } - // The interface is not of pointer type. The data word is the pointer - // to the data. - return pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]} -} - -// valToPointer converts v to a pointer. v must be of pointer type. -func valToPointer(v reflect.Value) pointer { - return pointer{p: unsafe.Pointer(v.Pointer())} -} - -// offset converts from a pointer to a structure to a pointer to -// one of its fields. -func (p pointer) offset(f field) pointer { - // For safety, we should panic if !f.IsValid, however calling panic causes - // this to no longer be inlineable, which is a serious performance cost. - /* - if !f.IsValid() { - panic("invalid field") - } - */ - return pointer{p: unsafe.Pointer(uintptr(p.p) + uintptr(f))} -} - -func (p pointer) isNil() bool { - return p.p == nil -} - -func (p pointer) toInt64() *int64 { - return (*int64)(p.p) -} -func (p pointer) toInt64Ptr() **int64 { - return (**int64)(p.p) -} -func (p pointer) toInt64Slice() *[]int64 { - return (*[]int64)(p.p) -} -func (p pointer) toInt32() *int32 { - return (*int32)(p.p) -} - -// See pointer_reflect.go for why toInt32Ptr/Slice doesn't exist. -/* - func (p pointer) toInt32Ptr() **int32 { - return (**int32)(p.p) - } - func (p pointer) toInt32Slice() *[]int32 { - return (*[]int32)(p.p) - } -*/ -func (p pointer) getInt32Ptr() *int32 { - return *(**int32)(p.p) -} -func (p pointer) setInt32Ptr(v int32) { - *(**int32)(p.p) = &v -} - -// getInt32Slice loads a []int32 from p. -// The value returned is aliased with the original slice. -// This behavior differs from the implementation in pointer_reflect.go. -func (p pointer) getInt32Slice() []int32 { - return *(*[]int32)(p.p) -} - -// setInt32Slice stores a []int32 to p. -// The value set is aliased with the input slice. -// This behavior differs from the implementation in pointer_reflect.go. -func (p pointer) setInt32Slice(v []int32) { - *(*[]int32)(p.p) = v -} - -// TODO: Can we get rid of appendInt32Slice and use setInt32Slice instead? -func (p pointer) appendInt32Slice(v int32) { - s := (*[]int32)(p.p) - *s = append(*s, v) -} - -func (p pointer) toUint64() *uint64 { - return (*uint64)(p.p) -} -func (p pointer) toUint64Ptr() **uint64 { - return (**uint64)(p.p) -} -func (p pointer) toUint64Slice() *[]uint64 { - return (*[]uint64)(p.p) -} -func (p pointer) toUint32() *uint32 { - return (*uint32)(p.p) -} -func (p pointer) toUint32Ptr() **uint32 { - return (**uint32)(p.p) -} -func (p pointer) toUint32Slice() *[]uint32 { - return (*[]uint32)(p.p) -} -func (p pointer) toBool() *bool { - return (*bool)(p.p) -} -func (p pointer) toBoolPtr() **bool { - return (**bool)(p.p) -} -func (p pointer) toBoolSlice() *[]bool { - return (*[]bool)(p.p) -} -func (p pointer) toFloat64() *float64 { - return (*float64)(p.p) -} -func (p pointer) toFloat64Ptr() **float64 { - return (**float64)(p.p) -} -func (p pointer) toFloat64Slice() *[]float64 { - return (*[]float64)(p.p) -} -func (p pointer) toFloat32() *float32 { - return (*float32)(p.p) -} -func (p pointer) toFloat32Ptr() **float32 { - return (**float32)(p.p) -} -func (p pointer) toFloat32Slice() *[]float32 { - return (*[]float32)(p.p) -} -func (p pointer) toString() *string { - return (*string)(p.p) -} -func (p pointer) toStringPtr() **string { - return (**string)(p.p) -} -func (p pointer) toStringSlice() *[]string { - return (*[]string)(p.p) -} -func (p pointer) toBytes() *[]byte { - return (*[]byte)(p.p) -} -func (p pointer) toBytesSlice() *[][]byte { - return (*[][]byte)(p.p) -} -func (p pointer) toExtensions() *XXX_InternalExtensions { - return (*XXX_InternalExtensions)(p.p) -} -func (p pointer) toOldExtensions() *map[int32]Extension { - return (*map[int32]Extension)(p.p) -} - -// getPointerSlice loads []*T from p as a []pointer. -// The value returned is aliased with the original slice. -// This behavior differs from the implementation in pointer_reflect.go. -func (p pointer) getPointerSlice() []pointer { - // Super-tricky - p should point to a []*T where T is a - // message type. We load it as []pointer. - return *(*[]pointer)(p.p) -} - -// setPointerSlice stores []pointer into p as a []*T. -// The value set is aliased with the input slice. -// This behavior differs from the implementation in pointer_reflect.go. -func (p pointer) setPointerSlice(v []pointer) { - // Super-tricky - p should point to a []*T where T is a - // message type. We store it as []pointer. - *(*[]pointer)(p.p) = v -} - -// getPointer loads the pointer at p and returns it. -func (p pointer) getPointer() pointer { - return pointer{p: *(*unsafe.Pointer)(p.p)} -} - -// setPointer stores the pointer q at p. -func (p pointer) setPointer(q pointer) { - *(*unsafe.Pointer)(p.p) = q.p -} - -// append q to the slice pointed to by p. -func (p pointer) appendPointer(q pointer) { - s := (*[]unsafe.Pointer)(p.p) - *s = append(*s, q.p) -} - -// getInterfacePointer returns a pointer that points to the -// interface data of the interface pointed by p. -func (p pointer) getInterfacePointer() pointer { - // Super-tricky - read pointer out of data word of interface value. - return pointer{p: (*(*[2]unsafe.Pointer)(p.p))[1]} -} - -// asPointerTo returns a reflect.Value that is a pointer to an -// object of type t stored at p. -func (p pointer) asPointerTo(t reflect.Type) reflect.Value { - return reflect.NewAt(t, p.p) -} - -func atomicLoadUnmarshalInfo(p **unmarshalInfo) *unmarshalInfo { - return (*unmarshalInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) -} -func atomicStoreUnmarshalInfo(p **unmarshalInfo, v *unmarshalInfo) { - atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) -} -func atomicLoadMarshalInfo(p **marshalInfo) *marshalInfo { - return (*marshalInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) -} -func atomicStoreMarshalInfo(p **marshalInfo, v *marshalInfo) { - atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) -} -func atomicLoadMergeInfo(p **mergeInfo) *mergeInfo { - return (*mergeInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) -} -func atomicStoreMergeInfo(p **mergeInfo, v *mergeInfo) { - atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) -} -func atomicLoadDiscardInfo(p **discardInfo) *discardInfo { - return (*discardInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) -} -func atomicStoreDiscardInfo(p **discardInfo, v *discardInfo) { - atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) -} diff --git a/vendor/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go b/vendor/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go deleted file mode 100644 index aca8eed02..000000000 --- a/vendor/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go +++ /dev/null @@ -1,56 +0,0 @@ -// Protocol Buffers for Go with Gadgets -// -// Copyright (c) 2018, The GoGo Authors. All rights reserved. -// http://github.com/gogo/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// +build !purego,!appengine,!js - -// This file contains the implementation of the proto field accesses using package unsafe. - -package proto - -import ( - "reflect" - "unsafe" -) - -func (p pointer) getRef() pointer { - return pointer{p: (unsafe.Pointer)(&p.p)} -} - -func (p pointer) appendRef(v pointer, typ reflect.Type) { - slice := p.getSlice(typ) - elem := v.asPointerTo(typ).Elem() - newSlice := reflect.Append(slice, elem) - slice.Set(newSlice) -} - -func (p pointer) getSlice(typ reflect.Type) reflect.Value { - sliceTyp := reflect.SliceOf(typ) - slice := p.asPointerTo(sliceTyp) - slice = slice.Elem() - return slice -} diff --git a/vendor/github.com/gogo/protobuf/proto/properties.go b/vendor/github.com/gogo/protobuf/proto/properties.go deleted file mode 100644 index 28da1475f..000000000 --- a/vendor/github.com/gogo/protobuf/proto/properties.go +++ /dev/null @@ -1,610 +0,0 @@ -// Protocol Buffers for Go with Gadgets -// -// Copyright (c) 2013, The GoGo Authors. All rights reserved. -// http://github.com/gogo/protobuf -// -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -/* - * Routines for encoding data into the wire format for protocol buffers. - */ - -import ( - "fmt" - "log" - "reflect" - "sort" - "strconv" - "strings" - "sync" -) - -const debug bool = false - -// Constants that identify the encoding of a value on the wire. -const ( - WireVarint = 0 - WireFixed64 = 1 - WireBytes = 2 - WireStartGroup = 3 - WireEndGroup = 4 - WireFixed32 = 5 -) - -// tagMap is an optimization over map[int]int for typical protocol buffer -// use-cases. Encoded protocol buffers are often in tag order with small tag -// numbers. -type tagMap struct { - fastTags []int - slowTags map[int]int -} - -// tagMapFastLimit is the upper bound on the tag number that will be stored in -// the tagMap slice rather than its map. -const tagMapFastLimit = 1024 - -func (p *tagMap) get(t int) (int, bool) { - if t > 0 && t < tagMapFastLimit { - if t >= len(p.fastTags) { - return 0, false - } - fi := p.fastTags[t] - return fi, fi >= 0 - } - fi, ok := p.slowTags[t] - return fi, ok -} - -func (p *tagMap) put(t int, fi int) { - if t > 0 && t < tagMapFastLimit { - for len(p.fastTags) < t+1 { - p.fastTags = append(p.fastTags, -1) - } - p.fastTags[t] = fi - return - } - if p.slowTags == nil { - p.slowTags = make(map[int]int) - } - p.slowTags[t] = fi -} - -// StructProperties represents properties for all the fields of a struct. -// decoderTags and decoderOrigNames should only be used by the decoder. -type StructProperties struct { - Prop []*Properties // properties for each field - reqCount int // required count - decoderTags tagMap // map from proto tag to struct field number - decoderOrigNames map[string]int // map from original name to struct field number - order []int // list of struct field numbers in tag order - - // OneofTypes contains information about the oneof fields in this message. - // It is keyed by the original name of a field. - OneofTypes map[string]*OneofProperties -} - -// OneofProperties represents information about a specific field in a oneof. -type OneofProperties struct { - Type reflect.Type // pointer to generated struct type for this oneof field - Field int // struct field number of the containing oneof in the message - Prop *Properties -} - -// Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec. -// See encode.go, (*Buffer).enc_struct. - -func (sp *StructProperties) Len() int { return len(sp.order) } -func (sp *StructProperties) Less(i, j int) bool { - return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag -} -func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] } - -// Properties represents the protocol-specific behavior of a single struct field. -type Properties struct { - Name string // name of the field, for error messages - OrigName string // original name before protocol compiler (always set) - JSONName string // name to use for JSON; determined by protoc - Wire string - WireType int - Tag int - Required bool - Optional bool - Repeated bool - Packed bool // relevant for repeated primitives only - Enum string // set for enum types only - proto3 bool // whether this is known to be a proto3 field - oneof bool // whether this is a oneof field - - Default string // default value - HasDefault bool // whether an explicit default was provided - CustomType string - CastType string - StdTime bool - StdDuration bool - WktPointer bool - - stype reflect.Type // set for struct types only - ctype reflect.Type // set for custom types only - sprop *StructProperties // set for struct types only - - mtype reflect.Type // set for map types only - MapKeyProp *Properties // set for map types only - MapValProp *Properties // set for map types only -} - -// String formats the properties in the protobuf struct field tag style. -func (p *Properties) String() string { - s := p.Wire - s += "," - s += strconv.Itoa(p.Tag) - if p.Required { - s += ",req" - } - if p.Optional { - s += ",opt" - } - if p.Repeated { - s += ",rep" - } - if p.Packed { - s += ",packed" - } - s += ",name=" + p.OrigName - if p.JSONName != p.OrigName { - s += ",json=" + p.JSONName - } - if p.proto3 { - s += ",proto3" - } - if p.oneof { - s += ",oneof" - } - if len(p.Enum) > 0 { - s += ",enum=" + p.Enum - } - if p.HasDefault { - s += ",def=" + p.Default - } - return s -} - -// Parse populates p by parsing a string in the protobuf struct field tag style. -func (p *Properties) Parse(s string) { - // "bytes,49,opt,name=foo,def=hello!" - fields := strings.Split(s, ",") // breaks def=, but handled below. - if len(fields) < 2 { - log.Printf("proto: tag has too few fields: %q", s) - return - } - - p.Wire = fields[0] - switch p.Wire { - case "varint": - p.WireType = WireVarint - case "fixed32": - p.WireType = WireFixed32 - case "fixed64": - p.WireType = WireFixed64 - case "zigzag32": - p.WireType = WireVarint - case "zigzag64": - p.WireType = WireVarint - case "bytes", "group": - p.WireType = WireBytes - // no numeric converter for non-numeric types - default: - log.Printf("proto: tag has unknown wire type: %q", s) - return - } - - var err error - p.Tag, err = strconv.Atoi(fields[1]) - if err != nil { - return - } - -outer: - for i := 2; i < len(fields); i++ { - f := fields[i] - switch { - case f == "req": - p.Required = true - case f == "opt": - p.Optional = true - case f == "rep": - p.Repeated = true - case f == "packed": - p.Packed = true - case strings.HasPrefix(f, "name="): - p.OrigName = f[5:] - case strings.HasPrefix(f, "json="): - p.JSONName = f[5:] - case strings.HasPrefix(f, "enum="): - p.Enum = f[5:] - case f == "proto3": - p.proto3 = true - case f == "oneof": - p.oneof = true - case strings.HasPrefix(f, "def="): - p.HasDefault = true - p.Default = f[4:] // rest of string - if i+1 < len(fields) { - // Commas aren't escaped, and def is always last. - p.Default += "," + strings.Join(fields[i+1:], ",") - break outer - } - case strings.HasPrefix(f, "embedded="): - p.OrigName = strings.Split(f, "=")[1] - case strings.HasPrefix(f, "customtype="): - p.CustomType = strings.Split(f, "=")[1] - case strings.HasPrefix(f, "casttype="): - p.CastType = strings.Split(f, "=")[1] - case f == "stdtime": - p.StdTime = true - case f == "stdduration": - p.StdDuration = true - case f == "wktptr": - p.WktPointer = true - } - } -} - -var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem() - -// setFieldProps initializes the field properties for submessages and maps. -func (p *Properties) setFieldProps(typ reflect.Type, f *reflect.StructField, lockGetProp bool) { - isMap := typ.Kind() == reflect.Map - if len(p.CustomType) > 0 && !isMap { - p.ctype = typ - p.setTag(lockGetProp) - return - } - if p.StdTime && !isMap { - p.setTag(lockGetProp) - return - } - if p.StdDuration && !isMap { - p.setTag(lockGetProp) - return - } - if p.WktPointer && !isMap { - p.setTag(lockGetProp) - return - } - switch t1 := typ; t1.Kind() { - case reflect.Struct: - p.stype = typ - case reflect.Ptr: - if t1.Elem().Kind() == reflect.Struct { - p.stype = t1.Elem() - } - case reflect.Slice: - switch t2 := t1.Elem(); t2.Kind() { - case reflect.Ptr: - switch t3 := t2.Elem(); t3.Kind() { - case reflect.Struct: - p.stype = t3 - } - case reflect.Struct: - p.stype = t2 - } - - case reflect.Map: - - p.mtype = t1 - p.MapKeyProp = &Properties{} - p.MapKeyProp.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp) - p.MapValProp = &Properties{} - vtype := p.mtype.Elem() - if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice { - // The value type is not a message (*T) or bytes ([]byte), - // so we need encoders for the pointer to this type. - vtype = reflect.PtrTo(vtype) - } - - p.MapValProp.CustomType = p.CustomType - p.MapValProp.StdDuration = p.StdDuration - p.MapValProp.StdTime = p.StdTime - p.MapValProp.WktPointer = p.WktPointer - p.MapValProp.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp) - } - p.setTag(lockGetProp) -} - -func (p *Properties) setTag(lockGetProp bool) { - if p.stype != nil { - if lockGetProp { - p.sprop = GetProperties(p.stype) - } else { - p.sprop = getPropertiesLocked(p.stype) - } - } -} - -var ( - marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() -) - -// Init populates the properties from a protocol buffer struct tag. -func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) { - p.init(typ, name, tag, f, true) -} - -func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) { - // "bytes,49,opt,def=hello!" - p.Name = name - p.OrigName = name - if tag == "" { - return - } - p.Parse(tag) - p.setFieldProps(typ, f, lockGetProp) -} - -var ( - propertiesMu sync.RWMutex - propertiesMap = make(map[reflect.Type]*StructProperties) -) - -// GetProperties returns the list of properties for the type represented by t. -// t must represent a generated struct type of a protocol message. -func GetProperties(t reflect.Type) *StructProperties { - if t.Kind() != reflect.Struct { - panic("proto: type must have kind struct") - } - - // Most calls to GetProperties in a long-running program will be - // retrieving details for types we have seen before. - propertiesMu.RLock() - sprop, ok := propertiesMap[t] - propertiesMu.RUnlock() - if ok { - return sprop - } - - propertiesMu.Lock() - sprop = getPropertiesLocked(t) - propertiesMu.Unlock() - return sprop -} - -type ( - oneofFuncsIface interface { - XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{}) - } - oneofWrappersIface interface { - XXX_OneofWrappers() []interface{} - } -) - -// getPropertiesLocked requires that propertiesMu is held. -func getPropertiesLocked(t reflect.Type) *StructProperties { - if prop, ok := propertiesMap[t]; ok { - return prop - } - - prop := new(StructProperties) - // in case of recursive protos, fill this in now. - propertiesMap[t] = prop - - // build properties - prop.Prop = make([]*Properties, t.NumField()) - prop.order = make([]int, t.NumField()) - - isOneofMessage := false - for i := 0; i < t.NumField(); i++ { - f := t.Field(i) - p := new(Properties) - name := f.Name - p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false) - - oneof := f.Tag.Get("protobuf_oneof") // special case - if oneof != "" { - isOneofMessage = true - // Oneof fields don't use the traditional protobuf tag. - p.OrigName = oneof - } - prop.Prop[i] = p - prop.order[i] = i - if debug { - print(i, " ", f.Name, " ", t.String(), " ") - if p.Tag > 0 { - print(p.String()) - } - print("\n") - } - } - - // Re-order prop.order. - sort.Sort(prop) - - if isOneofMessage { - var oots []interface{} - switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) { - case oneofFuncsIface: - _, _, _, oots = m.XXX_OneofFuncs() - case oneofWrappersIface: - oots = m.XXX_OneofWrappers() - } - if len(oots) > 0 { - // Interpret oneof metadata. - prop.OneofTypes = make(map[string]*OneofProperties) - for _, oot := range oots { - oop := &OneofProperties{ - Type: reflect.ValueOf(oot).Type(), // *T - Prop: new(Properties), - } - sft := oop.Type.Elem().Field(0) - oop.Prop.Name = sft.Name - oop.Prop.Parse(sft.Tag.Get("protobuf")) - // There will be exactly one interface field that - // this new value is assignable to. - for i := 0; i < t.NumField(); i++ { - f := t.Field(i) - if f.Type.Kind() != reflect.Interface { - continue - } - if !oop.Type.AssignableTo(f.Type) { - continue - } - oop.Field = i - break - } - prop.OneofTypes[oop.Prop.OrigName] = oop - } - } - } - - // build required counts - // build tags - reqCount := 0 - prop.decoderOrigNames = make(map[string]int) - for i, p := range prop.Prop { - if strings.HasPrefix(p.Name, "XXX_") { - // Internal fields should not appear in tags/origNames maps. - // They are handled specially when encoding and decoding. - continue - } - if p.Required { - reqCount++ - } - prop.decoderTags.put(p.Tag, i) - prop.decoderOrigNames[p.OrigName] = i - } - prop.reqCount = reqCount - - return prop -} - -// A global registry of enum types. -// The generated code will register the generated maps by calling RegisterEnum. - -var enumValueMaps = make(map[string]map[string]int32) -var enumStringMaps = make(map[string]map[int32]string) - -// RegisterEnum is called from the generated code to install the enum descriptor -// maps into the global table to aid parsing text format protocol buffers. -func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[string]int32) { - if _, ok := enumValueMaps[typeName]; ok { - panic("proto: duplicate enum registered: " + typeName) - } - enumValueMaps[typeName] = valueMap - if _, ok := enumStringMaps[typeName]; ok { - panic("proto: duplicate enum registered: " + typeName) - } - enumStringMaps[typeName] = unusedNameMap -} - -// EnumValueMap returns the mapping from names to integers of the -// enum type enumType, or a nil if not found. -func EnumValueMap(enumType string) map[string]int32 { - return enumValueMaps[enumType] -} - -// A registry of all linked message types. -// The string is a fully-qualified proto name ("pkg.Message"). -var ( - protoTypedNils = make(map[string]Message) // a map from proto names to typed nil pointers - protoMapTypes = make(map[string]reflect.Type) // a map from proto names to map types - revProtoTypes = make(map[reflect.Type]string) -) - -// RegisterType is called from generated code and maps from the fully qualified -// proto name to the type (pointer to struct) of the protocol buffer. -func RegisterType(x Message, name string) { - if _, ok := protoTypedNils[name]; ok { - // TODO: Some day, make this a panic. - log.Printf("proto: duplicate proto type registered: %s", name) - return - } - t := reflect.TypeOf(x) - if v := reflect.ValueOf(x); v.Kind() == reflect.Ptr && v.Pointer() == 0 { - // Generated code always calls RegisterType with nil x. - // This check is just for extra safety. - protoTypedNils[name] = x - } else { - protoTypedNils[name] = reflect.Zero(t).Interface().(Message) - } - revProtoTypes[t] = name -} - -// RegisterMapType is called from generated code and maps from the fully qualified -// proto name to the native map type of the proto map definition. -func RegisterMapType(x interface{}, name string) { - if reflect.TypeOf(x).Kind() != reflect.Map { - panic(fmt.Sprintf("RegisterMapType(%T, %q); want map", x, name)) - } - if _, ok := protoMapTypes[name]; ok { - log.Printf("proto: duplicate proto type registered: %s", name) - return - } - t := reflect.TypeOf(x) - protoMapTypes[name] = t - revProtoTypes[t] = name -} - -// MessageName returns the fully-qualified proto name for the given message type. -func MessageName(x Message) string { - type xname interface { - XXX_MessageName() string - } - if m, ok := x.(xname); ok { - return m.XXX_MessageName() - } - return revProtoTypes[reflect.TypeOf(x)] -} - -// MessageType returns the message type (pointer to struct) for a named message. -// The type is not guaranteed to implement proto.Message if the name refers to a -// map entry. -func MessageType(name string) reflect.Type { - if t, ok := protoTypedNils[name]; ok { - return reflect.TypeOf(t) - } - return protoMapTypes[name] -} - -// A registry of all linked proto files. -var ( - protoFiles = make(map[string][]byte) // file name => fileDescriptor -) - -// RegisterFile is called from generated code and maps from the -// full file name of a .proto file to its compressed FileDescriptorProto. -func RegisterFile(filename string, fileDescriptor []byte) { - protoFiles[filename] = fileDescriptor -} - -// FileDescriptor returns the compressed FileDescriptorProto for a .proto file. -func FileDescriptor(filename string) []byte { return protoFiles[filename] } diff --git a/vendor/github.com/gogo/protobuf/proto/properties_gogo.go b/vendor/github.com/gogo/protobuf/proto/properties_gogo.go deleted file mode 100644 index 40ea3dd93..000000000 --- a/vendor/github.com/gogo/protobuf/proto/properties_gogo.go +++ /dev/null @@ -1,36 +0,0 @@ -// Protocol Buffers for Go with Gadgets -// -// Copyright (c) 2018, The GoGo Authors. All rights reserved. -// http://github.com/gogo/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -import ( - "reflect" -) - -var sizerType = reflect.TypeOf((*Sizer)(nil)).Elem() -var protosizerType = reflect.TypeOf((*ProtoSizer)(nil)).Elem() diff --git a/vendor/github.com/gogo/protobuf/proto/skip_gogo.go b/vendor/github.com/gogo/protobuf/proto/skip_gogo.go deleted file mode 100644 index 5a5fd93f7..000000000 --- a/vendor/github.com/gogo/protobuf/proto/skip_gogo.go +++ /dev/null @@ -1,119 +0,0 @@ -// Protocol Buffers for Go with Gadgets -// -// Copyright (c) 2013, The GoGo Authors. All rights reserved. -// http://github.com/gogo/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -import ( - "fmt" - "io" -) - -func Skip(data []byte) (n int, err error) { - l := len(data) - index := 0 - for index < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if index >= l { - return 0, io.ErrUnexpectedEOF - } - b := data[index] - index++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for { - if index >= l { - return 0, io.ErrUnexpectedEOF - } - index++ - if data[index-1] < 0x80 { - break - } - } - return index, nil - case 1: - index += 8 - return index, nil - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if index >= l { - return 0, io.ErrUnexpectedEOF - } - b := data[index] - index++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - index += length - return index, nil - case 3: - for { - var innerWire uint64 - var start int = index - for shift := uint(0); ; shift += 7 { - if index >= l { - return 0, io.ErrUnexpectedEOF - } - b := data[index] - index++ - innerWire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - innerWireType := int(innerWire & 0x7) - if innerWireType == 4 { - break - } - next, err := Skip(data[start:]) - if err != nil { - return 0, err - } - index = start + next - } - return index, nil - case 4: - return index, nil - case 5: - index += 4 - return index, nil - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - } - panic("unreachable") -} diff --git a/vendor/github.com/gogo/protobuf/proto/table_marshal.go b/vendor/github.com/gogo/protobuf/proto/table_marshal.go deleted file mode 100644 index f8babdefa..000000000 --- a/vendor/github.com/gogo/protobuf/proto/table_marshal.go +++ /dev/null @@ -1,3009 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2016 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -import ( - "errors" - "fmt" - "math" - "reflect" - "sort" - "strconv" - "strings" - "sync" - "sync/atomic" - "unicode/utf8" -) - -// a sizer takes a pointer to a field and the size of its tag, computes the size of -// the encoded data. -type sizer func(pointer, int) int - -// a marshaler takes a byte slice, a pointer to a field, and its tag (in wire format), -// marshals the field to the end of the slice, returns the slice and error (if any). -type marshaler func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) - -// marshalInfo is the information used for marshaling a message. -type marshalInfo struct { - typ reflect.Type - fields []*marshalFieldInfo - unrecognized field // offset of XXX_unrecognized - extensions field // offset of XXX_InternalExtensions - v1extensions field // offset of XXX_extensions - sizecache field // offset of XXX_sizecache - initialized int32 // 0 -- only typ is set, 1 -- fully initialized - messageset bool // uses message set wire format - hasmarshaler bool // has custom marshaler - sync.RWMutex // protect extElems map, also for initialization - extElems map[int32]*marshalElemInfo // info of extension elements - - hassizer bool // has custom sizer - hasprotosizer bool // has custom protosizer - - bytesExtensions field // offset of XXX_extensions where the field type is []byte -} - -// marshalFieldInfo is the information used for marshaling a field of a message. -type marshalFieldInfo struct { - field field - wiretag uint64 // tag in wire format - tagsize int // size of tag in wire format - sizer sizer - marshaler marshaler - isPointer bool - required bool // field is required - name string // name of the field, for error reporting - oneofElems map[reflect.Type]*marshalElemInfo // info of oneof elements -} - -// marshalElemInfo is the information used for marshaling an extension or oneof element. -type marshalElemInfo struct { - wiretag uint64 // tag in wire format - tagsize int // size of tag in wire format - sizer sizer - marshaler marshaler - isptr bool // elem is pointer typed, thus interface of this type is a direct interface (extension only) -} - -var ( - marshalInfoMap = map[reflect.Type]*marshalInfo{} - marshalInfoLock sync.Mutex - - uint8SliceType = reflect.TypeOf(([]uint8)(nil)).Kind() -) - -// getMarshalInfo returns the information to marshal a given type of message. -// The info it returns may not necessarily initialized. -// t is the type of the message (NOT the pointer to it). -func getMarshalInfo(t reflect.Type) *marshalInfo { - marshalInfoLock.Lock() - u, ok := marshalInfoMap[t] - if !ok { - u = &marshalInfo{typ: t} - marshalInfoMap[t] = u - } - marshalInfoLock.Unlock() - return u -} - -// Size is the entry point from generated code, -// and should be ONLY called by generated code. -// It computes the size of encoded data of msg. -// a is a pointer to a place to store cached marshal info. -func (a *InternalMessageInfo) Size(msg Message) int { - u := getMessageMarshalInfo(msg, a) - ptr := toPointer(&msg) - if ptr.isNil() { - // We get here if msg is a typed nil ((*SomeMessage)(nil)), - // so it satisfies the interface, and msg == nil wouldn't - // catch it. We don't want crash in this case. - return 0 - } - return u.size(ptr) -} - -// Marshal is the entry point from generated code, -// and should be ONLY called by generated code. -// It marshals msg to the end of b. -// a is a pointer to a place to store cached marshal info. -func (a *InternalMessageInfo) Marshal(b []byte, msg Message, deterministic bool) ([]byte, error) { - u := getMessageMarshalInfo(msg, a) - ptr := toPointer(&msg) - if ptr.isNil() { - // We get here if msg is a typed nil ((*SomeMessage)(nil)), - // so it satisfies the interface, and msg == nil wouldn't - // catch it. We don't want crash in this case. - return b, ErrNil - } - return u.marshal(b, ptr, deterministic) -} - -func getMessageMarshalInfo(msg interface{}, a *InternalMessageInfo) *marshalInfo { - // u := a.marshal, but atomically. - // We use an atomic here to ensure memory consistency. - u := atomicLoadMarshalInfo(&a.marshal) - if u == nil { - // Get marshal information from type of message. - t := reflect.ValueOf(msg).Type() - if t.Kind() != reflect.Ptr { - panic(fmt.Sprintf("cannot handle non-pointer message type %v", t)) - } - u = getMarshalInfo(t.Elem()) - // Store it in the cache for later users. - // a.marshal = u, but atomically. - atomicStoreMarshalInfo(&a.marshal, u) - } - return u -} - -// size is the main function to compute the size of the encoded data of a message. -// ptr is the pointer to the message. -func (u *marshalInfo) size(ptr pointer) int { - if atomic.LoadInt32(&u.initialized) == 0 { - u.computeMarshalInfo() - } - - // If the message can marshal itself, let it do it, for compatibility. - // NOTE: This is not efficient. - if u.hasmarshaler { - // Uses the message's Size method if available - if u.hassizer { - s := ptr.asPointerTo(u.typ).Interface().(Sizer) - return s.Size() - } - // Uses the message's ProtoSize method if available - if u.hasprotosizer { - s := ptr.asPointerTo(u.typ).Interface().(ProtoSizer) - return s.ProtoSize() - } - - m := ptr.asPointerTo(u.typ).Interface().(Marshaler) - b, _ := m.Marshal() - return len(b) - } - - n := 0 - for _, f := range u.fields { - if f.isPointer && ptr.offset(f.field).getPointer().isNil() { - // nil pointer always marshals to nothing - continue - } - n += f.sizer(ptr.offset(f.field), f.tagsize) - } - if u.extensions.IsValid() { - e := ptr.offset(u.extensions).toExtensions() - if u.messageset { - n += u.sizeMessageSet(e) - } else { - n += u.sizeExtensions(e) - } - } - if u.v1extensions.IsValid() { - m := *ptr.offset(u.v1extensions).toOldExtensions() - n += u.sizeV1Extensions(m) - } - if u.bytesExtensions.IsValid() { - s := *ptr.offset(u.bytesExtensions).toBytes() - n += len(s) - } - if u.unrecognized.IsValid() { - s := *ptr.offset(u.unrecognized).toBytes() - n += len(s) - } - - // cache the result for use in marshal - if u.sizecache.IsValid() { - atomic.StoreInt32(ptr.offset(u.sizecache).toInt32(), int32(n)) - } - return n -} - -// cachedsize gets the size from cache. If there is no cache (i.e. message is not generated), -// fall back to compute the size. -func (u *marshalInfo) cachedsize(ptr pointer) int { - if u.sizecache.IsValid() { - return int(atomic.LoadInt32(ptr.offset(u.sizecache).toInt32())) - } - return u.size(ptr) -} - -// marshal is the main function to marshal a message. It takes a byte slice and appends -// the encoded data to the end of the slice, returns the slice and error (if any). -// ptr is the pointer to the message. -// If deterministic is true, map is marshaled in deterministic order. -func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte, error) { - if atomic.LoadInt32(&u.initialized) == 0 { - u.computeMarshalInfo() - } - - // If the message can marshal itself, let it do it, for compatibility. - // NOTE: This is not efficient. - if u.hasmarshaler { - m := ptr.asPointerTo(u.typ).Interface().(Marshaler) - b1, err := m.Marshal() - b = append(b, b1...) - return b, err - } - - var err, errLater error - // The old marshaler encodes extensions at beginning. - if u.extensions.IsValid() { - e := ptr.offset(u.extensions).toExtensions() - if u.messageset { - b, err = u.appendMessageSet(b, e, deterministic) - } else { - b, err = u.appendExtensions(b, e, deterministic) - } - if err != nil { - return b, err - } - } - if u.v1extensions.IsValid() { - m := *ptr.offset(u.v1extensions).toOldExtensions() - b, err = u.appendV1Extensions(b, m, deterministic) - if err != nil { - return b, err - } - } - if u.bytesExtensions.IsValid() { - s := *ptr.offset(u.bytesExtensions).toBytes() - b = append(b, s...) - } - for _, f := range u.fields { - if f.required { - if f.isPointer && ptr.offset(f.field).getPointer().isNil() { - // Required field is not set. - // We record the error but keep going, to give a complete marshaling. - if errLater == nil { - errLater = &RequiredNotSetError{f.name} - } - continue - } - } - if f.isPointer && ptr.offset(f.field).getPointer().isNil() { - // nil pointer always marshals to nothing - continue - } - b, err = f.marshaler(b, ptr.offset(f.field), f.wiretag, deterministic) - if err != nil { - if err1, ok := err.(*RequiredNotSetError); ok { - // Required field in submessage is not set. - // We record the error but keep going, to give a complete marshaling. - if errLater == nil { - errLater = &RequiredNotSetError{f.name + "." + err1.field} - } - continue - } - if err == errRepeatedHasNil { - err = errors.New("proto: repeated field " + f.name + " has nil element") - } - if err == errInvalidUTF8 { - if errLater == nil { - fullName := revProtoTypes[reflect.PtrTo(u.typ)] + "." + f.name - errLater = &invalidUTF8Error{fullName} - } - continue - } - return b, err - } - } - if u.unrecognized.IsValid() { - s := *ptr.offset(u.unrecognized).toBytes() - b = append(b, s...) - } - return b, errLater -} - -// computeMarshalInfo initializes the marshal info. -func (u *marshalInfo) computeMarshalInfo() { - u.Lock() - defer u.Unlock() - if u.initialized != 0 { // non-atomic read is ok as it is protected by the lock - return - } - - t := u.typ - u.unrecognized = invalidField - u.extensions = invalidField - u.v1extensions = invalidField - u.bytesExtensions = invalidField - u.sizecache = invalidField - isOneofMessage := false - - if reflect.PtrTo(t).Implements(sizerType) { - u.hassizer = true - } - if reflect.PtrTo(t).Implements(protosizerType) { - u.hasprotosizer = true - } - // If the message can marshal itself, let it do it, for compatibility. - // NOTE: This is not efficient. - if reflect.PtrTo(t).Implements(marshalerType) { - u.hasmarshaler = true - atomic.StoreInt32(&u.initialized, 1) - return - } - - n := t.NumField() - - // deal with XXX fields first - for i := 0; i < t.NumField(); i++ { - f := t.Field(i) - if f.Tag.Get("protobuf_oneof") != "" { - isOneofMessage = true - } - if !strings.HasPrefix(f.Name, "XXX_") { - continue - } - switch f.Name { - case "XXX_sizecache": - u.sizecache = toField(&f) - case "XXX_unrecognized": - u.unrecognized = toField(&f) - case "XXX_InternalExtensions": - u.extensions = toField(&f) - u.messageset = f.Tag.Get("protobuf_messageset") == "1" - case "XXX_extensions": - if f.Type.Kind() == reflect.Map { - u.v1extensions = toField(&f) - } else { - u.bytesExtensions = toField(&f) - } - case "XXX_NoUnkeyedLiteral": - // nothing to do - default: - panic("unknown XXX field: " + f.Name) - } - n-- - } - - // get oneof implementers - var oneofImplementers []interface{} - // gogo: isOneofMessage is needed for embedded oneof messages, without a marshaler and unmarshaler - if isOneofMessage { - switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) { - case oneofFuncsIface: - _, _, _, oneofImplementers = m.XXX_OneofFuncs() - case oneofWrappersIface: - oneofImplementers = m.XXX_OneofWrappers() - } - } - - // normal fields - fields := make([]marshalFieldInfo, n) // batch allocation - u.fields = make([]*marshalFieldInfo, 0, n) - for i, j := 0, 0; i < t.NumField(); i++ { - f := t.Field(i) - - if strings.HasPrefix(f.Name, "XXX_") { - continue - } - field := &fields[j] - j++ - field.name = f.Name - u.fields = append(u.fields, field) - if f.Tag.Get("protobuf_oneof") != "" { - field.computeOneofFieldInfo(&f, oneofImplementers) - continue - } - if f.Tag.Get("protobuf") == "" { - // field has no tag (not in generated message), ignore it - u.fields = u.fields[:len(u.fields)-1] - j-- - continue - } - field.computeMarshalFieldInfo(&f) - } - - // fields are marshaled in tag order on the wire. - sort.Sort(byTag(u.fields)) - - atomic.StoreInt32(&u.initialized, 1) -} - -// helper for sorting fields by tag -type byTag []*marshalFieldInfo - -func (a byTag) Len() int { return len(a) } -func (a byTag) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a byTag) Less(i, j int) bool { return a[i].wiretag < a[j].wiretag } - -// getExtElemInfo returns the information to marshal an extension element. -// The info it returns is initialized. -func (u *marshalInfo) getExtElemInfo(desc *ExtensionDesc) *marshalElemInfo { - // get from cache first - u.RLock() - e, ok := u.extElems[desc.Field] - u.RUnlock() - if ok { - return e - } - - t := reflect.TypeOf(desc.ExtensionType) // pointer or slice to basic type or struct - tags := strings.Split(desc.Tag, ",") - tag, err := strconv.Atoi(tags[1]) - if err != nil { - panic("tag is not an integer") - } - wt := wiretype(tags[0]) - sizr, marshalr := typeMarshaler(t, tags, false, false) - e = &marshalElemInfo{ - wiretag: uint64(tag)<<3 | wt, - tagsize: SizeVarint(uint64(tag) << 3), - sizer: sizr, - marshaler: marshalr, - isptr: t.Kind() == reflect.Ptr, - } - - // update cache - u.Lock() - if u.extElems == nil { - u.extElems = make(map[int32]*marshalElemInfo) - } - u.extElems[desc.Field] = e - u.Unlock() - return e -} - -// computeMarshalFieldInfo fills up the information to marshal a field. -func (fi *marshalFieldInfo) computeMarshalFieldInfo(f *reflect.StructField) { - // parse protobuf tag of the field. - // tag has format of "bytes,49,opt,name=foo,def=hello!" - tags := strings.Split(f.Tag.Get("protobuf"), ",") - if tags[0] == "" { - return - } - tag, err := strconv.Atoi(tags[1]) - if err != nil { - panic("tag is not an integer") - } - wt := wiretype(tags[0]) - if tags[2] == "req" { - fi.required = true - } - fi.setTag(f, tag, wt) - fi.setMarshaler(f, tags) -} - -func (fi *marshalFieldInfo) computeOneofFieldInfo(f *reflect.StructField, oneofImplementers []interface{}) { - fi.field = toField(f) - fi.wiretag = math.MaxInt32 // Use a large tag number, make oneofs sorted at the end. This tag will not appear on the wire. - fi.isPointer = true - fi.sizer, fi.marshaler = makeOneOfMarshaler(fi, f) - fi.oneofElems = make(map[reflect.Type]*marshalElemInfo) - - ityp := f.Type // interface type - for _, o := range oneofImplementers { - t := reflect.TypeOf(o) - if !t.Implements(ityp) { - continue - } - sf := t.Elem().Field(0) // oneof implementer is a struct with a single field - tags := strings.Split(sf.Tag.Get("protobuf"), ",") - tag, err := strconv.Atoi(tags[1]) - if err != nil { - panic("tag is not an integer") - } - wt := wiretype(tags[0]) - sizr, marshalr := typeMarshaler(sf.Type, tags, false, true) // oneof should not omit any zero value - fi.oneofElems[t.Elem()] = &marshalElemInfo{ - wiretag: uint64(tag)<<3 | wt, - tagsize: SizeVarint(uint64(tag) << 3), - sizer: sizr, - marshaler: marshalr, - } - } -} - -// wiretype returns the wire encoding of the type. -func wiretype(encoding string) uint64 { - switch encoding { - case "fixed32": - return WireFixed32 - case "fixed64": - return WireFixed64 - case "varint", "zigzag32", "zigzag64": - return WireVarint - case "bytes": - return WireBytes - case "group": - return WireStartGroup - } - panic("unknown wire type " + encoding) -} - -// setTag fills up the tag (in wire format) and its size in the info of a field. -func (fi *marshalFieldInfo) setTag(f *reflect.StructField, tag int, wt uint64) { - fi.field = toField(f) - fi.wiretag = uint64(tag)<<3 | wt - fi.tagsize = SizeVarint(uint64(tag) << 3) -} - -// setMarshaler fills up the sizer and marshaler in the info of a field. -func (fi *marshalFieldInfo) setMarshaler(f *reflect.StructField, tags []string) { - switch f.Type.Kind() { - case reflect.Map: - // map field - fi.isPointer = true - fi.sizer, fi.marshaler = makeMapMarshaler(f) - return - case reflect.Ptr, reflect.Slice: - fi.isPointer = true - } - fi.sizer, fi.marshaler = typeMarshaler(f.Type, tags, true, false) -} - -// typeMarshaler returns the sizer and marshaler of a given field. -// t is the type of the field. -// tags is the generated "protobuf" tag of the field. -// If nozero is true, zero value is not marshaled to the wire. -// If oneof is true, it is a oneof field. -func typeMarshaler(t reflect.Type, tags []string, nozero, oneof bool) (sizer, marshaler) { - encoding := tags[0] - - pointer := false - slice := false - if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 { - slice = true - t = t.Elem() - } - if t.Kind() == reflect.Ptr { - pointer = true - t = t.Elem() - } - - packed := false - proto3 := false - ctype := false - isTime := false - isDuration := false - isWktPointer := false - validateUTF8 := true - for i := 2; i < len(tags); i++ { - if tags[i] == "packed" { - packed = true - } - if tags[i] == "proto3" { - proto3 = true - } - if strings.HasPrefix(tags[i], "customtype=") { - ctype = true - } - if tags[i] == "stdtime" { - isTime = true - } - if tags[i] == "stdduration" { - isDuration = true - } - if tags[i] == "wktptr" { - isWktPointer = true - } - } - validateUTF8 = validateUTF8 && proto3 - if !proto3 && !pointer && !slice { - nozero = false - } - - if ctype { - if reflect.PtrTo(t).Implements(customType) { - if slice { - return makeMessageRefSliceMarshaler(getMarshalInfo(t)) - } - if pointer { - return makeCustomPtrMarshaler(getMarshalInfo(t)) - } - return makeCustomMarshaler(getMarshalInfo(t)) - } else { - panic(fmt.Sprintf("custom type: type: %v, does not implement the proto.custom interface", t)) - } - } - - if isTime { - if pointer { - if slice { - return makeTimePtrSliceMarshaler(getMarshalInfo(t)) - } - return makeTimePtrMarshaler(getMarshalInfo(t)) - } - if slice { - return makeTimeSliceMarshaler(getMarshalInfo(t)) - } - return makeTimeMarshaler(getMarshalInfo(t)) - } - - if isDuration { - if pointer { - if slice { - return makeDurationPtrSliceMarshaler(getMarshalInfo(t)) - } - return makeDurationPtrMarshaler(getMarshalInfo(t)) - } - if slice { - return makeDurationSliceMarshaler(getMarshalInfo(t)) - } - return makeDurationMarshaler(getMarshalInfo(t)) - } - - if isWktPointer { - switch t.Kind() { - case reflect.Float64: - if pointer { - if slice { - return makeStdDoubleValuePtrSliceMarshaler(getMarshalInfo(t)) - } - return makeStdDoubleValuePtrMarshaler(getMarshalInfo(t)) - } - if slice { - return makeStdDoubleValueSliceMarshaler(getMarshalInfo(t)) - } - return makeStdDoubleValueMarshaler(getMarshalInfo(t)) - case reflect.Float32: - if pointer { - if slice { - return makeStdFloatValuePtrSliceMarshaler(getMarshalInfo(t)) - } - return makeStdFloatValuePtrMarshaler(getMarshalInfo(t)) - } - if slice { - return makeStdFloatValueSliceMarshaler(getMarshalInfo(t)) - } - return makeStdFloatValueMarshaler(getMarshalInfo(t)) - case reflect.Int64: - if pointer { - if slice { - return makeStdInt64ValuePtrSliceMarshaler(getMarshalInfo(t)) - } - return makeStdInt64ValuePtrMarshaler(getMarshalInfo(t)) - } - if slice { - return makeStdInt64ValueSliceMarshaler(getMarshalInfo(t)) - } - return makeStdInt64ValueMarshaler(getMarshalInfo(t)) - case reflect.Uint64: - if pointer { - if slice { - return makeStdUInt64ValuePtrSliceMarshaler(getMarshalInfo(t)) - } - return makeStdUInt64ValuePtrMarshaler(getMarshalInfo(t)) - } - if slice { - return makeStdUInt64ValueSliceMarshaler(getMarshalInfo(t)) - } - return makeStdUInt64ValueMarshaler(getMarshalInfo(t)) - case reflect.Int32: - if pointer { - if slice { - return makeStdInt32ValuePtrSliceMarshaler(getMarshalInfo(t)) - } - return makeStdInt32ValuePtrMarshaler(getMarshalInfo(t)) - } - if slice { - return makeStdInt32ValueSliceMarshaler(getMarshalInfo(t)) - } - return makeStdInt32ValueMarshaler(getMarshalInfo(t)) - case reflect.Uint32: - if pointer { - if slice { - return makeStdUInt32ValuePtrSliceMarshaler(getMarshalInfo(t)) - } - return makeStdUInt32ValuePtrMarshaler(getMarshalInfo(t)) - } - if slice { - return makeStdUInt32ValueSliceMarshaler(getMarshalInfo(t)) - } - return makeStdUInt32ValueMarshaler(getMarshalInfo(t)) - case reflect.Bool: - if pointer { - if slice { - return makeStdBoolValuePtrSliceMarshaler(getMarshalInfo(t)) - } - return makeStdBoolValuePtrMarshaler(getMarshalInfo(t)) - } - if slice { - return makeStdBoolValueSliceMarshaler(getMarshalInfo(t)) - } - return makeStdBoolValueMarshaler(getMarshalInfo(t)) - case reflect.String: - if pointer { - if slice { - return makeStdStringValuePtrSliceMarshaler(getMarshalInfo(t)) - } - return makeStdStringValuePtrMarshaler(getMarshalInfo(t)) - } - if slice { - return makeStdStringValueSliceMarshaler(getMarshalInfo(t)) - } - return makeStdStringValueMarshaler(getMarshalInfo(t)) - case uint8SliceType: - if pointer { - if slice { - return makeStdBytesValuePtrSliceMarshaler(getMarshalInfo(t)) - } - return makeStdBytesValuePtrMarshaler(getMarshalInfo(t)) - } - if slice { - return makeStdBytesValueSliceMarshaler(getMarshalInfo(t)) - } - return makeStdBytesValueMarshaler(getMarshalInfo(t)) - default: - panic(fmt.Sprintf("unknown wktpointer type %#v", t)) - } - } - - switch t.Kind() { - case reflect.Bool: - if pointer { - return sizeBoolPtr, appendBoolPtr - } - if slice { - if packed { - return sizeBoolPackedSlice, appendBoolPackedSlice - } - return sizeBoolSlice, appendBoolSlice - } - if nozero { - return sizeBoolValueNoZero, appendBoolValueNoZero - } - return sizeBoolValue, appendBoolValue - case reflect.Uint32: - switch encoding { - case "fixed32": - if pointer { - return sizeFixed32Ptr, appendFixed32Ptr - } - if slice { - if packed { - return sizeFixed32PackedSlice, appendFixed32PackedSlice - } - return sizeFixed32Slice, appendFixed32Slice - } - if nozero { - return sizeFixed32ValueNoZero, appendFixed32ValueNoZero - } - return sizeFixed32Value, appendFixed32Value - case "varint": - if pointer { - return sizeVarint32Ptr, appendVarint32Ptr - } - if slice { - if packed { - return sizeVarint32PackedSlice, appendVarint32PackedSlice - } - return sizeVarint32Slice, appendVarint32Slice - } - if nozero { - return sizeVarint32ValueNoZero, appendVarint32ValueNoZero - } - return sizeVarint32Value, appendVarint32Value - } - case reflect.Int32: - switch encoding { - case "fixed32": - if pointer { - return sizeFixedS32Ptr, appendFixedS32Ptr - } - if slice { - if packed { - return sizeFixedS32PackedSlice, appendFixedS32PackedSlice - } - return sizeFixedS32Slice, appendFixedS32Slice - } - if nozero { - return sizeFixedS32ValueNoZero, appendFixedS32ValueNoZero - } - return sizeFixedS32Value, appendFixedS32Value - case "varint": - if pointer { - return sizeVarintS32Ptr, appendVarintS32Ptr - } - if slice { - if packed { - return sizeVarintS32PackedSlice, appendVarintS32PackedSlice - } - return sizeVarintS32Slice, appendVarintS32Slice - } - if nozero { - return sizeVarintS32ValueNoZero, appendVarintS32ValueNoZero - } - return sizeVarintS32Value, appendVarintS32Value - case "zigzag32": - if pointer { - return sizeZigzag32Ptr, appendZigzag32Ptr - } - if slice { - if packed { - return sizeZigzag32PackedSlice, appendZigzag32PackedSlice - } - return sizeZigzag32Slice, appendZigzag32Slice - } - if nozero { - return sizeZigzag32ValueNoZero, appendZigzag32ValueNoZero - } - return sizeZigzag32Value, appendZigzag32Value - } - case reflect.Uint64: - switch encoding { - case "fixed64": - if pointer { - return sizeFixed64Ptr, appendFixed64Ptr - } - if slice { - if packed { - return sizeFixed64PackedSlice, appendFixed64PackedSlice - } - return sizeFixed64Slice, appendFixed64Slice - } - if nozero { - return sizeFixed64ValueNoZero, appendFixed64ValueNoZero - } - return sizeFixed64Value, appendFixed64Value - case "varint": - if pointer { - return sizeVarint64Ptr, appendVarint64Ptr - } - if slice { - if packed { - return sizeVarint64PackedSlice, appendVarint64PackedSlice - } - return sizeVarint64Slice, appendVarint64Slice - } - if nozero { - return sizeVarint64ValueNoZero, appendVarint64ValueNoZero - } - return sizeVarint64Value, appendVarint64Value - } - case reflect.Int64: - switch encoding { - case "fixed64": - if pointer { - return sizeFixedS64Ptr, appendFixedS64Ptr - } - if slice { - if packed { - return sizeFixedS64PackedSlice, appendFixedS64PackedSlice - } - return sizeFixedS64Slice, appendFixedS64Slice - } - if nozero { - return sizeFixedS64ValueNoZero, appendFixedS64ValueNoZero - } - return sizeFixedS64Value, appendFixedS64Value - case "varint": - if pointer { - return sizeVarintS64Ptr, appendVarintS64Ptr - } - if slice { - if packed { - return sizeVarintS64PackedSlice, appendVarintS64PackedSlice - } - return sizeVarintS64Slice, appendVarintS64Slice - } - if nozero { - return sizeVarintS64ValueNoZero, appendVarintS64ValueNoZero - } - return sizeVarintS64Value, appendVarintS64Value - case "zigzag64": - if pointer { - return sizeZigzag64Ptr, appendZigzag64Ptr - } - if slice { - if packed { - return sizeZigzag64PackedSlice, appendZigzag64PackedSlice - } - return sizeZigzag64Slice, appendZigzag64Slice - } - if nozero { - return sizeZigzag64ValueNoZero, appendZigzag64ValueNoZero - } - return sizeZigzag64Value, appendZigzag64Value - } - case reflect.Float32: - if pointer { - return sizeFloat32Ptr, appendFloat32Ptr - } - if slice { - if packed { - return sizeFloat32PackedSlice, appendFloat32PackedSlice - } - return sizeFloat32Slice, appendFloat32Slice - } - if nozero { - return sizeFloat32ValueNoZero, appendFloat32ValueNoZero - } - return sizeFloat32Value, appendFloat32Value - case reflect.Float64: - if pointer { - return sizeFloat64Ptr, appendFloat64Ptr - } - if slice { - if packed { - return sizeFloat64PackedSlice, appendFloat64PackedSlice - } - return sizeFloat64Slice, appendFloat64Slice - } - if nozero { - return sizeFloat64ValueNoZero, appendFloat64ValueNoZero - } - return sizeFloat64Value, appendFloat64Value - case reflect.String: - if validateUTF8 { - if pointer { - return sizeStringPtr, appendUTF8StringPtr - } - if slice { - return sizeStringSlice, appendUTF8StringSlice - } - if nozero { - return sizeStringValueNoZero, appendUTF8StringValueNoZero - } - return sizeStringValue, appendUTF8StringValue - } - if pointer { - return sizeStringPtr, appendStringPtr - } - if slice { - return sizeStringSlice, appendStringSlice - } - if nozero { - return sizeStringValueNoZero, appendStringValueNoZero - } - return sizeStringValue, appendStringValue - case reflect.Slice: - if slice { - return sizeBytesSlice, appendBytesSlice - } - if oneof { - // Oneof bytes field may also have "proto3" tag. - // We want to marshal it as a oneof field. Do this - // check before the proto3 check. - return sizeBytesOneof, appendBytesOneof - } - if proto3 { - return sizeBytes3, appendBytes3 - } - return sizeBytes, appendBytes - case reflect.Struct: - switch encoding { - case "group": - if slice { - return makeGroupSliceMarshaler(getMarshalInfo(t)) - } - return makeGroupMarshaler(getMarshalInfo(t)) - case "bytes": - if pointer { - if slice { - return makeMessageSliceMarshaler(getMarshalInfo(t)) - } - return makeMessageMarshaler(getMarshalInfo(t)) - } else { - if slice { - return makeMessageRefSliceMarshaler(getMarshalInfo(t)) - } - return makeMessageRefMarshaler(getMarshalInfo(t)) - } - } - } - panic(fmt.Sprintf("unknown or mismatched type: type: %v, wire type: %v", t, encoding)) -} - -// Below are functions to size/marshal a specific type of a field. -// They are stored in the field's info, and called by function pointers. -// They have type sizer or marshaler. - -func sizeFixed32Value(_ pointer, tagsize int) int { - return 4 + tagsize -} -func sizeFixed32ValueNoZero(ptr pointer, tagsize int) int { - v := *ptr.toUint32() - if v == 0 { - return 0 - } - return 4 + tagsize -} -func sizeFixed32Ptr(ptr pointer, tagsize int) int { - p := *ptr.toUint32Ptr() - if p == nil { - return 0 - } - return 4 + tagsize -} -func sizeFixed32Slice(ptr pointer, tagsize int) int { - s := *ptr.toUint32Slice() - return (4 + tagsize) * len(s) -} -func sizeFixed32PackedSlice(ptr pointer, tagsize int) int { - s := *ptr.toUint32Slice() - if len(s) == 0 { - return 0 - } - return 4*len(s) + SizeVarint(uint64(4*len(s))) + tagsize -} -func sizeFixedS32Value(_ pointer, tagsize int) int { - return 4 + tagsize -} -func sizeFixedS32ValueNoZero(ptr pointer, tagsize int) int { - v := *ptr.toInt32() - if v == 0 { - return 0 - } - return 4 + tagsize -} -func sizeFixedS32Ptr(ptr pointer, tagsize int) int { - p := ptr.getInt32Ptr() - if p == nil { - return 0 - } - return 4 + tagsize -} -func sizeFixedS32Slice(ptr pointer, tagsize int) int { - s := ptr.getInt32Slice() - return (4 + tagsize) * len(s) -} -func sizeFixedS32PackedSlice(ptr pointer, tagsize int) int { - s := ptr.getInt32Slice() - if len(s) == 0 { - return 0 - } - return 4*len(s) + SizeVarint(uint64(4*len(s))) + tagsize -} -func sizeFloat32Value(_ pointer, tagsize int) int { - return 4 + tagsize -} -func sizeFloat32ValueNoZero(ptr pointer, tagsize int) int { - v := math.Float32bits(*ptr.toFloat32()) - if v == 0 { - return 0 - } - return 4 + tagsize -} -func sizeFloat32Ptr(ptr pointer, tagsize int) int { - p := *ptr.toFloat32Ptr() - if p == nil { - return 0 - } - return 4 + tagsize -} -func sizeFloat32Slice(ptr pointer, tagsize int) int { - s := *ptr.toFloat32Slice() - return (4 + tagsize) * len(s) -} -func sizeFloat32PackedSlice(ptr pointer, tagsize int) int { - s := *ptr.toFloat32Slice() - if len(s) == 0 { - return 0 - } - return 4*len(s) + SizeVarint(uint64(4*len(s))) + tagsize -} -func sizeFixed64Value(_ pointer, tagsize int) int { - return 8 + tagsize -} -func sizeFixed64ValueNoZero(ptr pointer, tagsize int) int { - v := *ptr.toUint64() - if v == 0 { - return 0 - } - return 8 + tagsize -} -func sizeFixed64Ptr(ptr pointer, tagsize int) int { - p := *ptr.toUint64Ptr() - if p == nil { - return 0 - } - return 8 + tagsize -} -func sizeFixed64Slice(ptr pointer, tagsize int) int { - s := *ptr.toUint64Slice() - return (8 + tagsize) * len(s) -} -func sizeFixed64PackedSlice(ptr pointer, tagsize int) int { - s := *ptr.toUint64Slice() - if len(s) == 0 { - return 0 - } - return 8*len(s) + SizeVarint(uint64(8*len(s))) + tagsize -} -func sizeFixedS64Value(_ pointer, tagsize int) int { - return 8 + tagsize -} -func sizeFixedS64ValueNoZero(ptr pointer, tagsize int) int { - v := *ptr.toInt64() - if v == 0 { - return 0 - } - return 8 + tagsize -} -func sizeFixedS64Ptr(ptr pointer, tagsize int) int { - p := *ptr.toInt64Ptr() - if p == nil { - return 0 - } - return 8 + tagsize -} -func sizeFixedS64Slice(ptr pointer, tagsize int) int { - s := *ptr.toInt64Slice() - return (8 + tagsize) * len(s) -} -func sizeFixedS64PackedSlice(ptr pointer, tagsize int) int { - s := *ptr.toInt64Slice() - if len(s) == 0 { - return 0 - } - return 8*len(s) + SizeVarint(uint64(8*len(s))) + tagsize -} -func sizeFloat64Value(_ pointer, tagsize int) int { - return 8 + tagsize -} -func sizeFloat64ValueNoZero(ptr pointer, tagsize int) int { - v := math.Float64bits(*ptr.toFloat64()) - if v == 0 { - return 0 - } - return 8 + tagsize -} -func sizeFloat64Ptr(ptr pointer, tagsize int) int { - p := *ptr.toFloat64Ptr() - if p == nil { - return 0 - } - return 8 + tagsize -} -func sizeFloat64Slice(ptr pointer, tagsize int) int { - s := *ptr.toFloat64Slice() - return (8 + tagsize) * len(s) -} -func sizeFloat64PackedSlice(ptr pointer, tagsize int) int { - s := *ptr.toFloat64Slice() - if len(s) == 0 { - return 0 - } - return 8*len(s) + SizeVarint(uint64(8*len(s))) + tagsize -} -func sizeVarint32Value(ptr pointer, tagsize int) int { - v := *ptr.toUint32() - return SizeVarint(uint64(v)) + tagsize -} -func sizeVarint32ValueNoZero(ptr pointer, tagsize int) int { - v := *ptr.toUint32() - if v == 0 { - return 0 - } - return SizeVarint(uint64(v)) + tagsize -} -func sizeVarint32Ptr(ptr pointer, tagsize int) int { - p := *ptr.toUint32Ptr() - if p == nil { - return 0 - } - return SizeVarint(uint64(*p)) + tagsize -} -func sizeVarint32Slice(ptr pointer, tagsize int) int { - s := *ptr.toUint32Slice() - n := 0 - for _, v := range s { - n += SizeVarint(uint64(v)) + tagsize - } - return n -} -func sizeVarint32PackedSlice(ptr pointer, tagsize int) int { - s := *ptr.toUint32Slice() - if len(s) == 0 { - return 0 - } - n := 0 - for _, v := range s { - n += SizeVarint(uint64(v)) - } - return n + SizeVarint(uint64(n)) + tagsize -} -func sizeVarintS32Value(ptr pointer, tagsize int) int { - v := *ptr.toInt32() - return SizeVarint(uint64(v)) + tagsize -} -func sizeVarintS32ValueNoZero(ptr pointer, tagsize int) int { - v := *ptr.toInt32() - if v == 0 { - return 0 - } - return SizeVarint(uint64(v)) + tagsize -} -func sizeVarintS32Ptr(ptr pointer, tagsize int) int { - p := ptr.getInt32Ptr() - if p == nil { - return 0 - } - return SizeVarint(uint64(*p)) + tagsize -} -func sizeVarintS32Slice(ptr pointer, tagsize int) int { - s := ptr.getInt32Slice() - n := 0 - for _, v := range s { - n += SizeVarint(uint64(v)) + tagsize - } - return n -} -func sizeVarintS32PackedSlice(ptr pointer, tagsize int) int { - s := ptr.getInt32Slice() - if len(s) == 0 { - return 0 - } - n := 0 - for _, v := range s { - n += SizeVarint(uint64(v)) - } - return n + SizeVarint(uint64(n)) + tagsize -} -func sizeVarint64Value(ptr pointer, tagsize int) int { - v := *ptr.toUint64() - return SizeVarint(v) + tagsize -} -func sizeVarint64ValueNoZero(ptr pointer, tagsize int) int { - v := *ptr.toUint64() - if v == 0 { - return 0 - } - return SizeVarint(v) + tagsize -} -func sizeVarint64Ptr(ptr pointer, tagsize int) int { - p := *ptr.toUint64Ptr() - if p == nil { - return 0 - } - return SizeVarint(*p) + tagsize -} -func sizeVarint64Slice(ptr pointer, tagsize int) int { - s := *ptr.toUint64Slice() - n := 0 - for _, v := range s { - n += SizeVarint(v) + tagsize - } - return n -} -func sizeVarint64PackedSlice(ptr pointer, tagsize int) int { - s := *ptr.toUint64Slice() - if len(s) == 0 { - return 0 - } - n := 0 - for _, v := range s { - n += SizeVarint(v) - } - return n + SizeVarint(uint64(n)) + tagsize -} -func sizeVarintS64Value(ptr pointer, tagsize int) int { - v := *ptr.toInt64() - return SizeVarint(uint64(v)) + tagsize -} -func sizeVarintS64ValueNoZero(ptr pointer, tagsize int) int { - v := *ptr.toInt64() - if v == 0 { - return 0 - } - return SizeVarint(uint64(v)) + tagsize -} -func sizeVarintS64Ptr(ptr pointer, tagsize int) int { - p := *ptr.toInt64Ptr() - if p == nil { - return 0 - } - return SizeVarint(uint64(*p)) + tagsize -} -func sizeVarintS64Slice(ptr pointer, tagsize int) int { - s := *ptr.toInt64Slice() - n := 0 - for _, v := range s { - n += SizeVarint(uint64(v)) + tagsize - } - return n -} -func sizeVarintS64PackedSlice(ptr pointer, tagsize int) int { - s := *ptr.toInt64Slice() - if len(s) == 0 { - return 0 - } - n := 0 - for _, v := range s { - n += SizeVarint(uint64(v)) - } - return n + SizeVarint(uint64(n)) + tagsize -} -func sizeZigzag32Value(ptr pointer, tagsize int) int { - v := *ptr.toInt32() - return SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize -} -func sizeZigzag32ValueNoZero(ptr pointer, tagsize int) int { - v := *ptr.toInt32() - if v == 0 { - return 0 - } - return SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize -} -func sizeZigzag32Ptr(ptr pointer, tagsize int) int { - p := ptr.getInt32Ptr() - if p == nil { - return 0 - } - v := *p - return SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize -} -func sizeZigzag32Slice(ptr pointer, tagsize int) int { - s := ptr.getInt32Slice() - n := 0 - for _, v := range s { - n += SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize - } - return n -} -func sizeZigzag32PackedSlice(ptr pointer, tagsize int) int { - s := ptr.getInt32Slice() - if len(s) == 0 { - return 0 - } - n := 0 - for _, v := range s { - n += SizeVarint(uint64((uint32(v) << 1) ^ uint32((int32(v) >> 31)))) - } - return n + SizeVarint(uint64(n)) + tagsize -} -func sizeZigzag64Value(ptr pointer, tagsize int) int { - v := *ptr.toInt64() - return SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize -} -func sizeZigzag64ValueNoZero(ptr pointer, tagsize int) int { - v := *ptr.toInt64() - if v == 0 { - return 0 - } - return SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize -} -func sizeZigzag64Ptr(ptr pointer, tagsize int) int { - p := *ptr.toInt64Ptr() - if p == nil { - return 0 - } - v := *p - return SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize -} -func sizeZigzag64Slice(ptr pointer, tagsize int) int { - s := *ptr.toInt64Slice() - n := 0 - for _, v := range s { - n += SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize - } - return n -} -func sizeZigzag64PackedSlice(ptr pointer, tagsize int) int { - s := *ptr.toInt64Slice() - if len(s) == 0 { - return 0 - } - n := 0 - for _, v := range s { - n += SizeVarint(uint64(v<<1) ^ uint64((int64(v) >> 63))) - } - return n + SizeVarint(uint64(n)) + tagsize -} -func sizeBoolValue(_ pointer, tagsize int) int { - return 1 + tagsize -} -func sizeBoolValueNoZero(ptr pointer, tagsize int) int { - v := *ptr.toBool() - if !v { - return 0 - } - return 1 + tagsize -} -func sizeBoolPtr(ptr pointer, tagsize int) int { - p := *ptr.toBoolPtr() - if p == nil { - return 0 - } - return 1 + tagsize -} -func sizeBoolSlice(ptr pointer, tagsize int) int { - s := *ptr.toBoolSlice() - return (1 + tagsize) * len(s) -} -func sizeBoolPackedSlice(ptr pointer, tagsize int) int { - s := *ptr.toBoolSlice() - if len(s) == 0 { - return 0 - } - return len(s) + SizeVarint(uint64(len(s))) + tagsize -} -func sizeStringValue(ptr pointer, tagsize int) int { - v := *ptr.toString() - return len(v) + SizeVarint(uint64(len(v))) + tagsize -} -func sizeStringValueNoZero(ptr pointer, tagsize int) int { - v := *ptr.toString() - if v == "" { - return 0 - } - return len(v) + SizeVarint(uint64(len(v))) + tagsize -} -func sizeStringPtr(ptr pointer, tagsize int) int { - p := *ptr.toStringPtr() - if p == nil { - return 0 - } - v := *p - return len(v) + SizeVarint(uint64(len(v))) + tagsize -} -func sizeStringSlice(ptr pointer, tagsize int) int { - s := *ptr.toStringSlice() - n := 0 - for _, v := range s { - n += len(v) + SizeVarint(uint64(len(v))) + tagsize - } - return n -} -func sizeBytes(ptr pointer, tagsize int) int { - v := *ptr.toBytes() - if v == nil { - return 0 - } - return len(v) + SizeVarint(uint64(len(v))) + tagsize -} -func sizeBytes3(ptr pointer, tagsize int) int { - v := *ptr.toBytes() - if len(v) == 0 { - return 0 - } - return len(v) + SizeVarint(uint64(len(v))) + tagsize -} -func sizeBytesOneof(ptr pointer, tagsize int) int { - v := *ptr.toBytes() - return len(v) + SizeVarint(uint64(len(v))) + tagsize -} -func sizeBytesSlice(ptr pointer, tagsize int) int { - s := *ptr.toBytesSlice() - n := 0 - for _, v := range s { - n += len(v) + SizeVarint(uint64(len(v))) + tagsize - } - return n -} - -// appendFixed32 appends an encoded fixed32 to b. -func appendFixed32(b []byte, v uint32) []byte { - b = append(b, - byte(v), - byte(v>>8), - byte(v>>16), - byte(v>>24)) - return b -} - -// appendFixed64 appends an encoded fixed64 to b. -func appendFixed64(b []byte, v uint64) []byte { - b = append(b, - byte(v), - byte(v>>8), - byte(v>>16), - byte(v>>24), - byte(v>>32), - byte(v>>40), - byte(v>>48), - byte(v>>56)) - return b -} - -// appendVarint appends an encoded varint to b. -func appendVarint(b []byte, v uint64) []byte { - // TODO: make 1-byte (maybe 2-byte) case inline-able, once we - // have non-leaf inliner. - switch { - case v < 1<<7: - b = append(b, byte(v)) - case v < 1<<14: - b = append(b, - byte(v&0x7f|0x80), - byte(v>>7)) - case v < 1<<21: - b = append(b, - byte(v&0x7f|0x80), - byte((v>>7)&0x7f|0x80), - byte(v>>14)) - case v < 1<<28: - b = append(b, - byte(v&0x7f|0x80), - byte((v>>7)&0x7f|0x80), - byte((v>>14)&0x7f|0x80), - byte(v>>21)) - case v < 1<<35: - b = append(b, - byte(v&0x7f|0x80), - byte((v>>7)&0x7f|0x80), - byte((v>>14)&0x7f|0x80), - byte((v>>21)&0x7f|0x80), - byte(v>>28)) - case v < 1<<42: - b = append(b, - byte(v&0x7f|0x80), - byte((v>>7)&0x7f|0x80), - byte((v>>14)&0x7f|0x80), - byte((v>>21)&0x7f|0x80), - byte((v>>28)&0x7f|0x80), - byte(v>>35)) - case v < 1<<49: - b = append(b, - byte(v&0x7f|0x80), - byte((v>>7)&0x7f|0x80), - byte((v>>14)&0x7f|0x80), - byte((v>>21)&0x7f|0x80), - byte((v>>28)&0x7f|0x80), - byte((v>>35)&0x7f|0x80), - byte(v>>42)) - case v < 1<<56: - b = append(b, - byte(v&0x7f|0x80), - byte((v>>7)&0x7f|0x80), - byte((v>>14)&0x7f|0x80), - byte((v>>21)&0x7f|0x80), - byte((v>>28)&0x7f|0x80), - byte((v>>35)&0x7f|0x80), - byte((v>>42)&0x7f|0x80), - byte(v>>49)) - case v < 1<<63: - b = append(b, - byte(v&0x7f|0x80), - byte((v>>7)&0x7f|0x80), - byte((v>>14)&0x7f|0x80), - byte((v>>21)&0x7f|0x80), - byte((v>>28)&0x7f|0x80), - byte((v>>35)&0x7f|0x80), - byte((v>>42)&0x7f|0x80), - byte((v>>49)&0x7f|0x80), - byte(v>>56)) - default: - b = append(b, - byte(v&0x7f|0x80), - byte((v>>7)&0x7f|0x80), - byte((v>>14)&0x7f|0x80), - byte((v>>21)&0x7f|0x80), - byte((v>>28)&0x7f|0x80), - byte((v>>35)&0x7f|0x80), - byte((v>>42)&0x7f|0x80), - byte((v>>49)&0x7f|0x80), - byte((v>>56)&0x7f|0x80), - 1) - } - return b -} - -func appendFixed32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toUint32() - b = appendVarint(b, wiretag) - b = appendFixed32(b, v) - return b, nil -} -func appendFixed32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toUint32() - if v == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendFixed32(b, v) - return b, nil -} -func appendFixed32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := *ptr.toUint32Ptr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendFixed32(b, *p) - return b, nil -} -func appendFixed32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toUint32Slice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendFixed32(b, v) - } - return b, nil -} -func appendFixed32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toUint32Slice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - b = appendVarint(b, uint64(4*len(s))) - for _, v := range s { - b = appendFixed32(b, v) - } - return b, nil -} -func appendFixedS32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toInt32() - b = appendVarint(b, wiretag) - b = appendFixed32(b, uint32(v)) - return b, nil -} -func appendFixedS32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toInt32() - if v == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendFixed32(b, uint32(v)) - return b, nil -} -func appendFixedS32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := ptr.getInt32Ptr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendFixed32(b, uint32(*p)) - return b, nil -} -func appendFixedS32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := ptr.getInt32Slice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendFixed32(b, uint32(v)) - } - return b, nil -} -func appendFixedS32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := ptr.getInt32Slice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - b = appendVarint(b, uint64(4*len(s))) - for _, v := range s { - b = appendFixed32(b, uint32(v)) - } - return b, nil -} -func appendFloat32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := math.Float32bits(*ptr.toFloat32()) - b = appendVarint(b, wiretag) - b = appendFixed32(b, v) - return b, nil -} -func appendFloat32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := math.Float32bits(*ptr.toFloat32()) - if v == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendFixed32(b, v) - return b, nil -} -func appendFloat32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := *ptr.toFloat32Ptr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendFixed32(b, math.Float32bits(*p)) - return b, nil -} -func appendFloat32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toFloat32Slice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendFixed32(b, math.Float32bits(v)) - } - return b, nil -} -func appendFloat32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toFloat32Slice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - b = appendVarint(b, uint64(4*len(s))) - for _, v := range s { - b = appendFixed32(b, math.Float32bits(v)) - } - return b, nil -} -func appendFixed64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toUint64() - b = appendVarint(b, wiretag) - b = appendFixed64(b, v) - return b, nil -} -func appendFixed64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toUint64() - if v == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendFixed64(b, v) - return b, nil -} -func appendFixed64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := *ptr.toUint64Ptr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendFixed64(b, *p) - return b, nil -} -func appendFixed64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toUint64Slice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendFixed64(b, v) - } - return b, nil -} -func appendFixed64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toUint64Slice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - b = appendVarint(b, uint64(8*len(s))) - for _, v := range s { - b = appendFixed64(b, v) - } - return b, nil -} -func appendFixedS64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toInt64() - b = appendVarint(b, wiretag) - b = appendFixed64(b, uint64(v)) - return b, nil -} -func appendFixedS64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toInt64() - if v == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendFixed64(b, uint64(v)) - return b, nil -} -func appendFixedS64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := *ptr.toInt64Ptr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendFixed64(b, uint64(*p)) - return b, nil -} -func appendFixedS64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toInt64Slice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendFixed64(b, uint64(v)) - } - return b, nil -} -func appendFixedS64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toInt64Slice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - b = appendVarint(b, uint64(8*len(s))) - for _, v := range s { - b = appendFixed64(b, uint64(v)) - } - return b, nil -} -func appendFloat64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := math.Float64bits(*ptr.toFloat64()) - b = appendVarint(b, wiretag) - b = appendFixed64(b, v) - return b, nil -} -func appendFloat64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := math.Float64bits(*ptr.toFloat64()) - if v == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendFixed64(b, v) - return b, nil -} -func appendFloat64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := *ptr.toFloat64Ptr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendFixed64(b, math.Float64bits(*p)) - return b, nil -} -func appendFloat64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toFloat64Slice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendFixed64(b, math.Float64bits(v)) - } - return b, nil -} -func appendFloat64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toFloat64Slice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - b = appendVarint(b, uint64(8*len(s))) - for _, v := range s { - b = appendFixed64(b, math.Float64bits(v)) - } - return b, nil -} -func appendVarint32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toUint32() - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(v)) - return b, nil -} -func appendVarint32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toUint32() - if v == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(v)) - return b, nil -} -func appendVarint32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := *ptr.toUint32Ptr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(*p)) - return b, nil -} -func appendVarint32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toUint32Slice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(v)) - } - return b, nil -} -func appendVarint32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toUint32Slice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - // compute size - n := 0 - for _, v := range s { - n += SizeVarint(uint64(v)) - } - b = appendVarint(b, uint64(n)) - for _, v := range s { - b = appendVarint(b, uint64(v)) - } - return b, nil -} -func appendVarintS32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toInt32() - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(v)) - return b, nil -} -func appendVarintS32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toInt32() - if v == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(v)) - return b, nil -} -func appendVarintS32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := ptr.getInt32Ptr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(*p)) - return b, nil -} -func appendVarintS32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := ptr.getInt32Slice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(v)) - } - return b, nil -} -func appendVarintS32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := ptr.getInt32Slice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - // compute size - n := 0 - for _, v := range s { - n += SizeVarint(uint64(v)) - } - b = appendVarint(b, uint64(n)) - for _, v := range s { - b = appendVarint(b, uint64(v)) - } - return b, nil -} -func appendVarint64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toUint64() - b = appendVarint(b, wiretag) - b = appendVarint(b, v) - return b, nil -} -func appendVarint64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toUint64() - if v == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, v) - return b, nil -} -func appendVarint64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := *ptr.toUint64Ptr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, *p) - return b, nil -} -func appendVarint64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toUint64Slice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendVarint(b, v) - } - return b, nil -} -func appendVarint64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toUint64Slice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - // compute size - n := 0 - for _, v := range s { - n += SizeVarint(v) - } - b = appendVarint(b, uint64(n)) - for _, v := range s { - b = appendVarint(b, v) - } - return b, nil -} -func appendVarintS64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toInt64() - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(v)) - return b, nil -} -func appendVarintS64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toInt64() - if v == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(v)) - return b, nil -} -func appendVarintS64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := *ptr.toInt64Ptr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(*p)) - return b, nil -} -func appendVarintS64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toInt64Slice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(v)) - } - return b, nil -} -func appendVarintS64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toInt64Slice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - // compute size - n := 0 - for _, v := range s { - n += SizeVarint(uint64(v)) - } - b = appendVarint(b, uint64(n)) - for _, v := range s { - b = appendVarint(b, uint64(v)) - } - return b, nil -} -func appendZigzag32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toInt32() - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) - return b, nil -} -func appendZigzag32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toInt32() - if v == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) - return b, nil -} -func appendZigzag32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := ptr.getInt32Ptr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - v := *p - b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) - return b, nil -} -func appendZigzag32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := ptr.getInt32Slice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) - } - return b, nil -} -func appendZigzag32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := ptr.getInt32Slice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - // compute size - n := 0 - for _, v := range s { - n += SizeVarint(uint64((uint32(v) << 1) ^ uint32((int32(v) >> 31)))) - } - b = appendVarint(b, uint64(n)) - for _, v := range s { - b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) - } - return b, nil -} -func appendZigzag64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toInt64() - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) - return b, nil -} -func appendZigzag64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toInt64() - if v == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) - return b, nil -} -func appendZigzag64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := *ptr.toInt64Ptr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - v := *p - b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) - return b, nil -} -func appendZigzag64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toInt64Slice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) - } - return b, nil -} -func appendZigzag64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toInt64Slice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - // compute size - n := 0 - for _, v := range s { - n += SizeVarint(uint64(v<<1) ^ uint64((int64(v) >> 63))) - } - b = appendVarint(b, uint64(n)) - for _, v := range s { - b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) - } - return b, nil -} -func appendBoolValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toBool() - b = appendVarint(b, wiretag) - if v { - b = append(b, 1) - } else { - b = append(b, 0) - } - return b, nil -} -func appendBoolValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toBool() - if !v { - return b, nil - } - b = appendVarint(b, wiretag) - b = append(b, 1) - return b, nil -} - -func appendBoolPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := *ptr.toBoolPtr() - if p == nil { - return b, nil - } - b = appendVarint(b, wiretag) - if *p { - b = append(b, 1) - } else { - b = append(b, 0) - } - return b, nil -} -func appendBoolSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toBoolSlice() - for _, v := range s { - b = appendVarint(b, wiretag) - if v { - b = append(b, 1) - } else { - b = append(b, 0) - } - } - return b, nil -} -func appendBoolPackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toBoolSlice() - if len(s) == 0 { - return b, nil - } - b = appendVarint(b, wiretag&^7|WireBytes) - b = appendVarint(b, uint64(len(s))) - for _, v := range s { - if v { - b = append(b, 1) - } else { - b = append(b, 0) - } - } - return b, nil -} -func appendStringValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toString() - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(v))) - b = append(b, v...) - return b, nil -} -func appendStringValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toString() - if v == "" { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(v))) - b = append(b, v...) - return b, nil -} -func appendStringPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - p := *ptr.toStringPtr() - if p == nil { - return b, nil - } - v := *p - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(v))) - b = append(b, v...) - return b, nil -} -func appendStringSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toStringSlice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(v))) - b = append(b, v...) - } - return b, nil -} -func appendUTF8StringValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - var invalidUTF8 bool - v := *ptr.toString() - if !utf8.ValidString(v) { - invalidUTF8 = true - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(v))) - b = append(b, v...) - if invalidUTF8 { - return b, errInvalidUTF8 - } - return b, nil -} -func appendUTF8StringValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - var invalidUTF8 bool - v := *ptr.toString() - if v == "" { - return b, nil - } - if !utf8.ValidString(v) { - invalidUTF8 = true - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(v))) - b = append(b, v...) - if invalidUTF8 { - return b, errInvalidUTF8 - } - return b, nil -} -func appendUTF8StringPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - var invalidUTF8 bool - p := *ptr.toStringPtr() - if p == nil { - return b, nil - } - v := *p - if !utf8.ValidString(v) { - invalidUTF8 = true - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(v))) - b = append(b, v...) - if invalidUTF8 { - return b, errInvalidUTF8 - } - return b, nil -} -func appendUTF8StringSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - var invalidUTF8 bool - s := *ptr.toStringSlice() - for _, v := range s { - if !utf8.ValidString(v) { - invalidUTF8 = true - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(v))) - b = append(b, v...) - } - if invalidUTF8 { - return b, errInvalidUTF8 - } - return b, nil -} -func appendBytes(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toBytes() - if v == nil { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(v))) - b = append(b, v...) - return b, nil -} -func appendBytes3(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toBytes() - if len(v) == 0 { - return b, nil - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(v))) - b = append(b, v...) - return b, nil -} -func appendBytesOneof(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - v := *ptr.toBytes() - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(v))) - b = append(b, v...) - return b, nil -} -func appendBytesSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { - s := *ptr.toBytesSlice() - for _, v := range s { - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(v))) - b = append(b, v...) - } - return b, nil -} - -// makeGroupMarshaler returns the sizer and marshaler for a group. -// u is the marshal info of the underlying message. -func makeGroupMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - p := ptr.getPointer() - if p.isNil() { - return 0 - } - return u.size(p) + 2*tagsize - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - p := ptr.getPointer() - if p.isNil() { - return b, nil - } - var err error - b = appendVarint(b, wiretag) // start group - b, err = u.marshal(b, p, deterministic) - b = appendVarint(b, wiretag+(WireEndGroup-WireStartGroup)) // end group - return b, err - } -} - -// makeGroupSliceMarshaler returns the sizer and marshaler for a group slice. -// u is the marshal info of the underlying message. -func makeGroupSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getPointerSlice() - n := 0 - for _, v := range s { - if v.isNil() { - continue - } - n += u.size(v) + 2*tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getPointerSlice() - var err error - var nerr nonFatal - for _, v := range s { - if v.isNil() { - return b, errRepeatedHasNil - } - b = appendVarint(b, wiretag) // start group - b, err = u.marshal(b, v, deterministic) - b = appendVarint(b, wiretag+(WireEndGroup-WireStartGroup)) // end group - if !nerr.Merge(err) { - if err == ErrNil { - err = errRepeatedHasNil - } - return b, err - } - } - return b, nerr.E - } -} - -// makeMessageMarshaler returns the sizer and marshaler for a message field. -// u is the marshal info of the message. -func makeMessageMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - p := ptr.getPointer() - if p.isNil() { - return 0 - } - siz := u.size(p) - return siz + SizeVarint(uint64(siz)) + tagsize - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - p := ptr.getPointer() - if p.isNil() { - return b, nil - } - b = appendVarint(b, wiretag) - siz := u.cachedsize(p) - b = appendVarint(b, uint64(siz)) - return u.marshal(b, p, deterministic) - } -} - -// makeMessageSliceMarshaler returns the sizer and marshaler for a message slice. -// u is the marshal info of the message. -func makeMessageSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getPointerSlice() - n := 0 - for _, v := range s { - if v.isNil() { - continue - } - siz := u.size(v) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getPointerSlice() - var err error - var nerr nonFatal - for _, v := range s { - if v.isNil() { - return b, errRepeatedHasNil - } - b = appendVarint(b, wiretag) - siz := u.cachedsize(v) - b = appendVarint(b, uint64(siz)) - b, err = u.marshal(b, v, deterministic) - - if !nerr.Merge(err) { - if err == ErrNil { - err = errRepeatedHasNil - } - return b, err - } - } - return b, nerr.E - } -} - -// makeMapMarshaler returns the sizer and marshaler for a map field. -// f is the pointer to the reflect data structure of the field. -func makeMapMarshaler(f *reflect.StructField) (sizer, marshaler) { - // figure out key and value type - t := f.Type - keyType := t.Key() - valType := t.Elem() - tags := strings.Split(f.Tag.Get("protobuf"), ",") - keyTags := strings.Split(f.Tag.Get("protobuf_key"), ",") - valTags := strings.Split(f.Tag.Get("protobuf_val"), ",") - stdOptions := false - for _, t := range tags { - if strings.HasPrefix(t, "customtype=") { - valTags = append(valTags, t) - } - if t == "stdtime" { - valTags = append(valTags, t) - stdOptions = true - } - if t == "stdduration" { - valTags = append(valTags, t) - stdOptions = true - } - if t == "wktptr" { - valTags = append(valTags, t) - } - } - keySizer, keyMarshaler := typeMarshaler(keyType, keyTags, false, false) // don't omit zero value in map - valSizer, valMarshaler := typeMarshaler(valType, valTags, false, false) // don't omit zero value in map - keyWireTag := 1<<3 | wiretype(keyTags[0]) - valWireTag := 2<<3 | wiretype(valTags[0]) - - // We create an interface to get the addresses of the map key and value. - // If value is pointer-typed, the interface is a direct interface, the - // idata itself is the value. Otherwise, the idata is the pointer to the - // value. - // Key cannot be pointer-typed. - valIsPtr := valType.Kind() == reflect.Ptr - - // If value is a message with nested maps, calling - // valSizer in marshal may be quadratic. We should use - // cached version in marshal (but not in size). - // If value is not message type, we don't have size cache, - // but it cannot be nested either. Just use valSizer. - valCachedSizer := valSizer - if valIsPtr && !stdOptions && valType.Elem().Kind() == reflect.Struct { - u := getMarshalInfo(valType.Elem()) - valCachedSizer = func(ptr pointer, tagsize int) int { - // Same as message sizer, but use cache. - p := ptr.getPointer() - if p.isNil() { - return 0 - } - siz := u.cachedsize(p) - return siz + SizeVarint(uint64(siz)) + tagsize - } - } - return func(ptr pointer, tagsize int) int { - m := ptr.asPointerTo(t).Elem() // the map - n := 0 - for _, k := range m.MapKeys() { - ki := k.Interface() - vi := m.MapIndex(k).Interface() - kaddr := toAddrPointer(&ki, false) // pointer to key - vaddr := toAddrPointer(&vi, valIsPtr) // pointer to value - siz := keySizer(kaddr, 1) + valSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, tag uint64, deterministic bool) ([]byte, error) { - m := ptr.asPointerTo(t).Elem() // the map - var err error - keys := m.MapKeys() - if len(keys) > 1 && deterministic { - sort.Sort(mapKeys(keys)) - } - - var nerr nonFatal - for _, k := range keys { - ki := k.Interface() - vi := m.MapIndex(k).Interface() - kaddr := toAddrPointer(&ki, false) // pointer to key - vaddr := toAddrPointer(&vi, valIsPtr) // pointer to value - b = appendVarint(b, tag) - siz := keySizer(kaddr, 1) + valCachedSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1) - b = appendVarint(b, uint64(siz)) - b, err = keyMarshaler(b, kaddr, keyWireTag, deterministic) - if !nerr.Merge(err) { - return b, err - } - b, err = valMarshaler(b, vaddr, valWireTag, deterministic) - if err != ErrNil && !nerr.Merge(err) { // allow nil value in map - return b, err - } - } - return b, nerr.E - } -} - -// makeOneOfMarshaler returns the sizer and marshaler for a oneof field. -// fi is the marshal info of the field. -// f is the pointer to the reflect data structure of the field. -func makeOneOfMarshaler(fi *marshalFieldInfo, f *reflect.StructField) (sizer, marshaler) { - // Oneof field is an interface. We need to get the actual data type on the fly. - t := f.Type - return func(ptr pointer, _ int) int { - p := ptr.getInterfacePointer() - if p.isNil() { - return 0 - } - v := ptr.asPointerTo(t).Elem().Elem().Elem() // *interface -> interface -> *struct -> struct - telem := v.Type() - e := fi.oneofElems[telem] - return e.sizer(p, e.tagsize) - }, - func(b []byte, ptr pointer, _ uint64, deterministic bool) ([]byte, error) { - p := ptr.getInterfacePointer() - if p.isNil() { - return b, nil - } - v := ptr.asPointerTo(t).Elem().Elem().Elem() // *interface -> interface -> *struct -> struct - telem := v.Type() - if telem.Field(0).Type.Kind() == reflect.Ptr && p.getPointer().isNil() { - return b, errOneofHasNil - } - e := fi.oneofElems[telem] - return e.marshaler(b, p, e.wiretag, deterministic) - } -} - -// sizeExtensions computes the size of encoded data for a XXX_InternalExtensions field. -func (u *marshalInfo) sizeExtensions(ext *XXX_InternalExtensions) int { - m, mu := ext.extensionsRead() - if m == nil { - return 0 - } - mu.Lock() - - n := 0 - for _, e := range m { - if e.value == nil || e.desc == nil { - // Extension is only in its encoded form. - n += len(e.enc) - continue - } - - // We don't skip extensions that have an encoded form set, - // because the extension value may have been mutated after - // the last time this function was called. - ei := u.getExtElemInfo(e.desc) - v := e.value - p := toAddrPointer(&v, ei.isptr) - n += ei.sizer(p, ei.tagsize) - } - mu.Unlock() - return n -} - -// appendExtensions marshals a XXX_InternalExtensions field to the end of byte slice b. -func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, deterministic bool) ([]byte, error) { - m, mu := ext.extensionsRead() - if m == nil { - return b, nil - } - mu.Lock() - defer mu.Unlock() - - var err error - var nerr nonFatal - - // Fast-path for common cases: zero or one extensions. - // Don't bother sorting the keys. - if len(m) <= 1 { - for _, e := range m { - if e.value == nil || e.desc == nil { - // Extension is only in its encoded form. - b = append(b, e.enc...) - continue - } - - // We don't skip extensions that have an encoded form set, - // because the extension value may have been mutated after - // the last time this function was called. - - ei := u.getExtElemInfo(e.desc) - v := e.value - p := toAddrPointer(&v, ei.isptr) - b, err = ei.marshaler(b, p, ei.wiretag, deterministic) - if !nerr.Merge(err) { - return b, err - } - } - return b, nerr.E - } - - // Sort the keys to provide a deterministic encoding. - // Not sure this is required, but the old code does it. - keys := make([]int, 0, len(m)) - for k := range m { - keys = append(keys, int(k)) - } - sort.Ints(keys) - - for _, k := range keys { - e := m[int32(k)] - if e.value == nil || e.desc == nil { - // Extension is only in its encoded form. - b = append(b, e.enc...) - continue - } - - // We don't skip extensions that have an encoded form set, - // because the extension value may have been mutated after - // the last time this function was called. - - ei := u.getExtElemInfo(e.desc) - v := e.value - p := toAddrPointer(&v, ei.isptr) - b, err = ei.marshaler(b, p, ei.wiretag, deterministic) - if !nerr.Merge(err) { - return b, err - } - } - return b, nerr.E -} - -// message set format is: -// message MessageSet { -// repeated group Item = 1 { -// required int32 type_id = 2; -// required string message = 3; -// }; -// } - -// sizeMessageSet computes the size of encoded data for a XXX_InternalExtensions field -// in message set format (above). -func (u *marshalInfo) sizeMessageSet(ext *XXX_InternalExtensions) int { - m, mu := ext.extensionsRead() - if m == nil { - return 0 - } - mu.Lock() - - n := 0 - for id, e := range m { - n += 2 // start group, end group. tag = 1 (size=1) - n += SizeVarint(uint64(id)) + 1 // type_id, tag = 2 (size=1) - - if e.value == nil || e.desc == nil { - // Extension is only in its encoded form. - msgWithLen := skipVarint(e.enc) // skip old tag, but leave the length varint - siz := len(msgWithLen) - n += siz + 1 // message, tag = 3 (size=1) - continue - } - - // We don't skip extensions that have an encoded form set, - // because the extension value may have been mutated after - // the last time this function was called. - - ei := u.getExtElemInfo(e.desc) - v := e.value - p := toAddrPointer(&v, ei.isptr) - n += ei.sizer(p, 1) // message, tag = 3 (size=1) - } - mu.Unlock() - return n -} - -// appendMessageSet marshals a XXX_InternalExtensions field in message set format (above) -// to the end of byte slice b. -func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, deterministic bool) ([]byte, error) { - m, mu := ext.extensionsRead() - if m == nil { - return b, nil - } - mu.Lock() - defer mu.Unlock() - - var err error - var nerr nonFatal - - // Fast-path for common cases: zero or one extensions. - // Don't bother sorting the keys. - if len(m) <= 1 { - for id, e := range m { - b = append(b, 1<<3|WireStartGroup) - b = append(b, 2<<3|WireVarint) - b = appendVarint(b, uint64(id)) - - if e.value == nil || e.desc == nil { - // Extension is only in its encoded form. - msgWithLen := skipVarint(e.enc) // skip old tag, but leave the length varint - b = append(b, 3<<3|WireBytes) - b = append(b, msgWithLen...) - b = append(b, 1<<3|WireEndGroup) - continue - } - - // We don't skip extensions that have an encoded form set, - // because the extension value may have been mutated after - // the last time this function was called. - - ei := u.getExtElemInfo(e.desc) - v := e.value - p := toAddrPointer(&v, ei.isptr) - b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic) - if !nerr.Merge(err) { - return b, err - } - b = append(b, 1<<3|WireEndGroup) - } - return b, nerr.E - } - - // Sort the keys to provide a deterministic encoding. - keys := make([]int, 0, len(m)) - for k := range m { - keys = append(keys, int(k)) - } - sort.Ints(keys) - - for _, id := range keys { - e := m[int32(id)] - b = append(b, 1<<3|WireStartGroup) - b = append(b, 2<<3|WireVarint) - b = appendVarint(b, uint64(id)) - - if e.value == nil || e.desc == nil { - // Extension is only in its encoded form. - msgWithLen := skipVarint(e.enc) // skip old tag, but leave the length varint - b = append(b, 3<<3|WireBytes) - b = append(b, msgWithLen...) - b = append(b, 1<<3|WireEndGroup) - continue - } - - // We don't skip extensions that have an encoded form set, - // because the extension value may have been mutated after - // the last time this function was called. - - ei := u.getExtElemInfo(e.desc) - v := e.value - p := toAddrPointer(&v, ei.isptr) - b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic) - b = append(b, 1<<3|WireEndGroup) - if !nerr.Merge(err) { - return b, err - } - } - return b, nerr.E -} - -// sizeV1Extensions computes the size of encoded data for a V1-API extension field. -func (u *marshalInfo) sizeV1Extensions(m map[int32]Extension) int { - if m == nil { - return 0 - } - - n := 0 - for _, e := range m { - if e.value == nil || e.desc == nil { - // Extension is only in its encoded form. - n += len(e.enc) - continue - } - - // We don't skip extensions that have an encoded form set, - // because the extension value may have been mutated after - // the last time this function was called. - - ei := u.getExtElemInfo(e.desc) - v := e.value - p := toAddrPointer(&v, ei.isptr) - n += ei.sizer(p, ei.tagsize) - } - return n -} - -// appendV1Extensions marshals a V1-API extension field to the end of byte slice b. -func (u *marshalInfo) appendV1Extensions(b []byte, m map[int32]Extension, deterministic bool) ([]byte, error) { - if m == nil { - return b, nil - } - - // Sort the keys to provide a deterministic encoding. - keys := make([]int, 0, len(m)) - for k := range m { - keys = append(keys, int(k)) - } - sort.Ints(keys) - - var err error - var nerr nonFatal - for _, k := range keys { - e := m[int32(k)] - if e.value == nil || e.desc == nil { - // Extension is only in its encoded form. - b = append(b, e.enc...) - continue - } - - // We don't skip extensions that have an encoded form set, - // because the extension value may have been mutated after - // the last time this function was called. - - ei := u.getExtElemInfo(e.desc) - v := e.value - p := toAddrPointer(&v, ei.isptr) - b, err = ei.marshaler(b, p, ei.wiretag, deterministic) - if !nerr.Merge(err) { - return b, err - } - } - return b, nerr.E -} - -// newMarshaler is the interface representing objects that can marshal themselves. -// -// This exists to support protoc-gen-go generated messages. -// The proto package will stop type-asserting to this interface in the future. -// -// DO NOT DEPEND ON THIS. -type newMarshaler interface { - XXX_Size() int - XXX_Marshal(b []byte, deterministic bool) ([]byte, error) -} - -// Size returns the encoded size of a protocol buffer message. -// This is the main entry point. -func Size(pb Message) int { - if m, ok := pb.(newMarshaler); ok { - return m.XXX_Size() - } - if m, ok := pb.(Marshaler); ok { - // If the message can marshal itself, let it do it, for compatibility. - // NOTE: This is not efficient. - b, _ := m.Marshal() - return len(b) - } - // in case somehow we didn't generate the wrapper - if pb == nil { - return 0 - } - var info InternalMessageInfo - return info.Size(pb) -} - -// Marshal takes a protocol buffer message -// and encodes it into the wire format, returning the data. -// This is the main entry point. -func Marshal(pb Message) ([]byte, error) { - if m, ok := pb.(newMarshaler); ok { - siz := m.XXX_Size() - b := make([]byte, 0, siz) - return m.XXX_Marshal(b, false) - } - if m, ok := pb.(Marshaler); ok { - // If the message can marshal itself, let it do it, for compatibility. - // NOTE: This is not efficient. - return m.Marshal() - } - // in case somehow we didn't generate the wrapper - if pb == nil { - return nil, ErrNil - } - var info InternalMessageInfo - siz := info.Size(pb) - b := make([]byte, 0, siz) - return info.Marshal(b, pb, false) -} - -// Marshal takes a protocol buffer message -// and encodes it into the wire format, writing the result to the -// Buffer. -// This is an alternative entry point. It is not necessary to use -// a Buffer for most applications. -func (p *Buffer) Marshal(pb Message) error { - var err error - if p.deterministic { - if _, ok := pb.(Marshaler); ok { - return fmt.Errorf("proto: deterministic not supported by the Marshal method of %T", pb) - } - } - if m, ok := pb.(newMarshaler); ok { - siz := m.XXX_Size() - p.grow(siz) // make sure buf has enough capacity - pp := p.buf[len(p.buf) : len(p.buf) : len(p.buf)+siz] - pp, err = m.XXX_Marshal(pp, p.deterministic) - p.buf = append(p.buf, pp...) - return err - } - if m, ok := pb.(Marshaler); ok { - // If the message can marshal itself, let it do it, for compatibility. - // NOTE: This is not efficient. - var b []byte - b, err = m.Marshal() - p.buf = append(p.buf, b...) - return err - } - // in case somehow we didn't generate the wrapper - if pb == nil { - return ErrNil - } - var info InternalMessageInfo - siz := info.Size(pb) - p.grow(siz) // make sure buf has enough capacity - p.buf, err = info.Marshal(p.buf, pb, p.deterministic) - return err -} - -// grow grows the buffer's capacity, if necessary, to guarantee space for -// another n bytes. After grow(n), at least n bytes can be written to the -// buffer without another allocation. -func (p *Buffer) grow(n int) { - need := len(p.buf) + n - if need <= cap(p.buf) { - return - } - newCap := len(p.buf) * 2 - if newCap < need { - newCap = need - } - p.buf = append(make([]byte, 0, newCap), p.buf...) -} diff --git a/vendor/github.com/gogo/protobuf/proto/table_marshal_gogo.go b/vendor/github.com/gogo/protobuf/proto/table_marshal_gogo.go deleted file mode 100644 index 997f57c1e..000000000 --- a/vendor/github.com/gogo/protobuf/proto/table_marshal_gogo.go +++ /dev/null @@ -1,388 +0,0 @@ -// Protocol Buffers for Go with Gadgets -// -// Copyright (c) 2018, The GoGo Authors. All rights reserved. -// http://github.com/gogo/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -import ( - "reflect" - "time" -) - -// makeMessageRefMarshaler differs a bit from makeMessageMarshaler -// It marshal a message T instead of a *T -func makeMessageRefMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - siz := u.size(ptr) - return siz + SizeVarint(uint64(siz)) + tagsize - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - b = appendVarint(b, wiretag) - siz := u.cachedsize(ptr) - b = appendVarint(b, uint64(siz)) - return u.marshal(b, ptr, deterministic) - } -} - -// makeMessageRefSliceMarshaler differs quite a lot from makeMessageSliceMarshaler -// It marshals a slice of messages []T instead of []*T -func makeMessageRefSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getSlice(u.typ) - n := 0 - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - e := elem.Interface() - v := toAddrPointer(&e, false) - siz := u.size(v) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getSlice(u.typ) - var err, errreq error - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - e := elem.Interface() - v := toAddrPointer(&e, false) - b = appendVarint(b, wiretag) - siz := u.size(v) - b = appendVarint(b, uint64(siz)) - b, err = u.marshal(b, v, deterministic) - - if err != nil { - if _, ok := err.(*RequiredNotSetError); ok { - // Required field in submessage is not set. - // We record the error but keep going, to give a complete marshaling. - if errreq == nil { - errreq = err - } - continue - } - if err == ErrNil { - err = errRepeatedHasNil - } - return b, err - } - } - - return b, errreq - } -} - -func makeCustomPtrMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - if ptr.isNil() { - return 0 - } - m := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(custom) - siz := m.Size() - return tagsize + SizeVarint(uint64(siz)) + siz - }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - if ptr.isNil() { - return b, nil - } - m := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(custom) - siz := m.Size() - buf, err := m.Marshal() - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(siz)) - b = append(b, buf...) - return b, nil - } -} - -func makeCustomMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - m := ptr.asPointerTo(u.typ).Interface().(custom) - siz := m.Size() - return tagsize + SizeVarint(uint64(siz)) + siz - }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - m := ptr.asPointerTo(u.typ).Interface().(custom) - siz := m.Size() - buf, err := m.Marshal() - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(siz)) - b = append(b, buf...) - return b, nil - } -} - -func makeTimeMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - t := ptr.asPointerTo(u.typ).Interface().(*time.Time) - ts, err := timestampProto(*t) - if err != nil { - return 0 - } - siz := Size(ts) - return tagsize + SizeVarint(uint64(siz)) + siz - }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - t := ptr.asPointerTo(u.typ).Interface().(*time.Time) - ts, err := timestampProto(*t) - if err != nil { - return nil, err - } - buf, err := Marshal(ts) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(buf))) - b = append(b, buf...) - return b, nil - } -} - -func makeTimePtrMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - if ptr.isNil() { - return 0 - } - t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*time.Time) - ts, err := timestampProto(*t) - if err != nil { - return 0 - } - siz := Size(ts) - return tagsize + SizeVarint(uint64(siz)) + siz - }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - if ptr.isNil() { - return b, nil - } - t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*time.Time) - ts, err := timestampProto(*t) - if err != nil { - return nil, err - } - buf, err := Marshal(ts) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(buf))) - b = append(b, buf...) - return b, nil - } -} - -func makeTimeSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getSlice(u.typ) - n := 0 - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(time.Time) - ts, err := timestampProto(t) - if err != nil { - return 0 - } - siz := Size(ts) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getSlice(u.typ) - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(time.Time) - ts, err := timestampProto(t) - if err != nil { - return nil, err - } - siz := Size(ts) - buf, err := Marshal(ts) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(siz)) - b = append(b, buf...) - } - - return b, nil - } -} - -func makeTimePtrSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getSlice(reflect.PtrTo(u.typ)) - n := 0 - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(*time.Time) - ts, err := timestampProto(*t) - if err != nil { - return 0 - } - siz := Size(ts) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getSlice(reflect.PtrTo(u.typ)) - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(*time.Time) - ts, err := timestampProto(*t) - if err != nil { - return nil, err - } - siz := Size(ts) - buf, err := Marshal(ts) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(siz)) - b = append(b, buf...) - } - - return b, nil - } -} - -func makeDurationMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - d := ptr.asPointerTo(u.typ).Interface().(*time.Duration) - dur := durationProto(*d) - siz := Size(dur) - return tagsize + SizeVarint(uint64(siz)) + siz - }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - d := ptr.asPointerTo(u.typ).Interface().(*time.Duration) - dur := durationProto(*d) - buf, err := Marshal(dur) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(buf))) - b = append(b, buf...) - return b, nil - } -} - -func makeDurationPtrMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - if ptr.isNil() { - return 0 - } - d := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*time.Duration) - dur := durationProto(*d) - siz := Size(dur) - return tagsize + SizeVarint(uint64(siz)) + siz - }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - if ptr.isNil() { - return b, nil - } - d := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*time.Duration) - dur := durationProto(*d) - buf, err := Marshal(dur) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(buf))) - b = append(b, buf...) - return b, nil - } -} - -func makeDurationSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getSlice(u.typ) - n := 0 - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - d := elem.Interface().(time.Duration) - dur := durationProto(d) - siz := Size(dur) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getSlice(u.typ) - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - d := elem.Interface().(time.Duration) - dur := durationProto(d) - siz := Size(dur) - buf, err := Marshal(dur) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(siz)) - b = append(b, buf...) - } - - return b, nil - } -} - -func makeDurationPtrSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getSlice(reflect.PtrTo(u.typ)) - n := 0 - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - d := elem.Interface().(*time.Duration) - dur := durationProto(*d) - siz := Size(dur) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getSlice(reflect.PtrTo(u.typ)) - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - d := elem.Interface().(*time.Duration) - dur := durationProto(*d) - siz := Size(dur) - buf, err := Marshal(dur) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(siz)) - b = append(b, buf...) - } - - return b, nil - } -} diff --git a/vendor/github.com/gogo/protobuf/proto/table_merge.go b/vendor/github.com/gogo/protobuf/proto/table_merge.go deleted file mode 100644 index 60dcf70d1..000000000 --- a/vendor/github.com/gogo/protobuf/proto/table_merge.go +++ /dev/null @@ -1,676 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2016 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -import ( - "fmt" - "reflect" - "strings" - "sync" - "sync/atomic" -) - -// Merge merges the src message into dst. -// This assumes that dst and src of the same type and are non-nil. -func (a *InternalMessageInfo) Merge(dst, src Message) { - mi := atomicLoadMergeInfo(&a.merge) - if mi == nil { - mi = getMergeInfo(reflect.TypeOf(dst).Elem()) - atomicStoreMergeInfo(&a.merge, mi) - } - mi.merge(toPointer(&dst), toPointer(&src)) -} - -type mergeInfo struct { - typ reflect.Type - - initialized int32 // 0: only typ is valid, 1: everything is valid - lock sync.Mutex - - fields []mergeFieldInfo - unrecognized field // Offset of XXX_unrecognized -} - -type mergeFieldInfo struct { - field field // Offset of field, guaranteed to be valid - - // isPointer reports whether the value in the field is a pointer. - // This is true for the following situations: - // * Pointer to struct - // * Pointer to basic type (proto2 only) - // * Slice (first value in slice header is a pointer) - // * String (first value in string header is a pointer) - isPointer bool - - // basicWidth reports the width of the field assuming that it is directly - // embedded in the struct (as is the case for basic types in proto3). - // The possible values are: - // 0: invalid - // 1: bool - // 4: int32, uint32, float32 - // 8: int64, uint64, float64 - basicWidth int - - // Where dst and src are pointers to the types being merged. - merge func(dst, src pointer) -} - -var ( - mergeInfoMap = map[reflect.Type]*mergeInfo{} - mergeInfoLock sync.Mutex -) - -func getMergeInfo(t reflect.Type) *mergeInfo { - mergeInfoLock.Lock() - defer mergeInfoLock.Unlock() - mi := mergeInfoMap[t] - if mi == nil { - mi = &mergeInfo{typ: t} - mergeInfoMap[t] = mi - } - return mi -} - -// merge merges src into dst assuming they are both of type *mi.typ. -func (mi *mergeInfo) merge(dst, src pointer) { - if dst.isNil() { - panic("proto: nil destination") - } - if src.isNil() { - return // Nothing to do. - } - - if atomic.LoadInt32(&mi.initialized) == 0 { - mi.computeMergeInfo() - } - - for _, fi := range mi.fields { - sfp := src.offset(fi.field) - - // As an optimization, we can avoid the merge function call cost - // if we know for sure that the source will have no effect - // by checking if it is the zero value. - if unsafeAllowed { - if fi.isPointer && sfp.getPointer().isNil() { // Could be slice or string - continue - } - if fi.basicWidth > 0 { - switch { - case fi.basicWidth == 1 && !*sfp.toBool(): - continue - case fi.basicWidth == 4 && *sfp.toUint32() == 0: - continue - case fi.basicWidth == 8 && *sfp.toUint64() == 0: - continue - } - } - } - - dfp := dst.offset(fi.field) - fi.merge(dfp, sfp) - } - - // TODO: Make this faster? - out := dst.asPointerTo(mi.typ).Elem() - in := src.asPointerTo(mi.typ).Elem() - if emIn, err := extendable(in.Addr().Interface()); err == nil { - emOut, _ := extendable(out.Addr().Interface()) - mIn, muIn := emIn.extensionsRead() - if mIn != nil { - mOut := emOut.extensionsWrite() - muIn.Lock() - mergeExtension(mOut, mIn) - muIn.Unlock() - } - } - - if mi.unrecognized.IsValid() { - if b := *src.offset(mi.unrecognized).toBytes(); len(b) > 0 { - *dst.offset(mi.unrecognized).toBytes() = append([]byte(nil), b...) - } - } -} - -func (mi *mergeInfo) computeMergeInfo() { - mi.lock.Lock() - defer mi.lock.Unlock() - if mi.initialized != 0 { - return - } - t := mi.typ - n := t.NumField() - - props := GetProperties(t) - for i := 0; i < n; i++ { - f := t.Field(i) - if strings.HasPrefix(f.Name, "XXX_") { - continue - } - - mfi := mergeFieldInfo{field: toField(&f)} - tf := f.Type - - // As an optimization, we can avoid the merge function call cost - // if we know for sure that the source will have no effect - // by checking if it is the zero value. - if unsafeAllowed { - switch tf.Kind() { - case reflect.Ptr, reflect.Slice, reflect.String: - // As a special case, we assume slices and strings are pointers - // since we know that the first field in the SliceSlice or - // StringHeader is a data pointer. - mfi.isPointer = true - case reflect.Bool: - mfi.basicWidth = 1 - case reflect.Int32, reflect.Uint32, reflect.Float32: - mfi.basicWidth = 4 - case reflect.Int64, reflect.Uint64, reflect.Float64: - mfi.basicWidth = 8 - } - } - - // Unwrap tf to get at its most basic type. - var isPointer, isSlice bool - if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 { - isSlice = true - tf = tf.Elem() - } - if tf.Kind() == reflect.Ptr { - isPointer = true - tf = tf.Elem() - } - if isPointer && isSlice && tf.Kind() != reflect.Struct { - panic("both pointer and slice for basic type in " + tf.Name()) - } - - switch tf.Kind() { - case reflect.Int32: - switch { - case isSlice: // E.g., []int32 - mfi.merge = func(dst, src pointer) { - // NOTE: toInt32Slice is not defined (see pointer_reflect.go). - /* - sfsp := src.toInt32Slice() - if *sfsp != nil { - dfsp := dst.toInt32Slice() - *dfsp = append(*dfsp, *sfsp...) - if *dfsp == nil { - *dfsp = []int64{} - } - } - */ - sfs := src.getInt32Slice() - if sfs != nil { - dfs := dst.getInt32Slice() - dfs = append(dfs, sfs...) - if dfs == nil { - dfs = []int32{} - } - dst.setInt32Slice(dfs) - } - } - case isPointer: // E.g., *int32 - mfi.merge = func(dst, src pointer) { - // NOTE: toInt32Ptr is not defined (see pointer_reflect.go). - /* - sfpp := src.toInt32Ptr() - if *sfpp != nil { - dfpp := dst.toInt32Ptr() - if *dfpp == nil { - *dfpp = Int32(**sfpp) - } else { - **dfpp = **sfpp - } - } - */ - sfp := src.getInt32Ptr() - if sfp != nil { - dfp := dst.getInt32Ptr() - if dfp == nil { - dst.setInt32Ptr(*sfp) - } else { - *dfp = *sfp - } - } - } - default: // E.g., int32 - mfi.merge = func(dst, src pointer) { - if v := *src.toInt32(); v != 0 { - *dst.toInt32() = v - } - } - } - case reflect.Int64: - switch { - case isSlice: // E.g., []int64 - mfi.merge = func(dst, src pointer) { - sfsp := src.toInt64Slice() - if *sfsp != nil { - dfsp := dst.toInt64Slice() - *dfsp = append(*dfsp, *sfsp...) - if *dfsp == nil { - *dfsp = []int64{} - } - } - } - case isPointer: // E.g., *int64 - mfi.merge = func(dst, src pointer) { - sfpp := src.toInt64Ptr() - if *sfpp != nil { - dfpp := dst.toInt64Ptr() - if *dfpp == nil { - *dfpp = Int64(**sfpp) - } else { - **dfpp = **sfpp - } - } - } - default: // E.g., int64 - mfi.merge = func(dst, src pointer) { - if v := *src.toInt64(); v != 0 { - *dst.toInt64() = v - } - } - } - case reflect.Uint32: - switch { - case isSlice: // E.g., []uint32 - mfi.merge = func(dst, src pointer) { - sfsp := src.toUint32Slice() - if *sfsp != nil { - dfsp := dst.toUint32Slice() - *dfsp = append(*dfsp, *sfsp...) - if *dfsp == nil { - *dfsp = []uint32{} - } - } - } - case isPointer: // E.g., *uint32 - mfi.merge = func(dst, src pointer) { - sfpp := src.toUint32Ptr() - if *sfpp != nil { - dfpp := dst.toUint32Ptr() - if *dfpp == nil { - *dfpp = Uint32(**sfpp) - } else { - **dfpp = **sfpp - } - } - } - default: // E.g., uint32 - mfi.merge = func(dst, src pointer) { - if v := *src.toUint32(); v != 0 { - *dst.toUint32() = v - } - } - } - case reflect.Uint64: - switch { - case isSlice: // E.g., []uint64 - mfi.merge = func(dst, src pointer) { - sfsp := src.toUint64Slice() - if *sfsp != nil { - dfsp := dst.toUint64Slice() - *dfsp = append(*dfsp, *sfsp...) - if *dfsp == nil { - *dfsp = []uint64{} - } - } - } - case isPointer: // E.g., *uint64 - mfi.merge = func(dst, src pointer) { - sfpp := src.toUint64Ptr() - if *sfpp != nil { - dfpp := dst.toUint64Ptr() - if *dfpp == nil { - *dfpp = Uint64(**sfpp) - } else { - **dfpp = **sfpp - } - } - } - default: // E.g., uint64 - mfi.merge = func(dst, src pointer) { - if v := *src.toUint64(); v != 0 { - *dst.toUint64() = v - } - } - } - case reflect.Float32: - switch { - case isSlice: // E.g., []float32 - mfi.merge = func(dst, src pointer) { - sfsp := src.toFloat32Slice() - if *sfsp != nil { - dfsp := dst.toFloat32Slice() - *dfsp = append(*dfsp, *sfsp...) - if *dfsp == nil { - *dfsp = []float32{} - } - } - } - case isPointer: // E.g., *float32 - mfi.merge = func(dst, src pointer) { - sfpp := src.toFloat32Ptr() - if *sfpp != nil { - dfpp := dst.toFloat32Ptr() - if *dfpp == nil { - *dfpp = Float32(**sfpp) - } else { - **dfpp = **sfpp - } - } - } - default: // E.g., float32 - mfi.merge = func(dst, src pointer) { - if v := *src.toFloat32(); v != 0 { - *dst.toFloat32() = v - } - } - } - case reflect.Float64: - switch { - case isSlice: // E.g., []float64 - mfi.merge = func(dst, src pointer) { - sfsp := src.toFloat64Slice() - if *sfsp != nil { - dfsp := dst.toFloat64Slice() - *dfsp = append(*dfsp, *sfsp...) - if *dfsp == nil { - *dfsp = []float64{} - } - } - } - case isPointer: // E.g., *float64 - mfi.merge = func(dst, src pointer) { - sfpp := src.toFloat64Ptr() - if *sfpp != nil { - dfpp := dst.toFloat64Ptr() - if *dfpp == nil { - *dfpp = Float64(**sfpp) - } else { - **dfpp = **sfpp - } - } - } - default: // E.g., float64 - mfi.merge = func(dst, src pointer) { - if v := *src.toFloat64(); v != 0 { - *dst.toFloat64() = v - } - } - } - case reflect.Bool: - switch { - case isSlice: // E.g., []bool - mfi.merge = func(dst, src pointer) { - sfsp := src.toBoolSlice() - if *sfsp != nil { - dfsp := dst.toBoolSlice() - *dfsp = append(*dfsp, *sfsp...) - if *dfsp == nil { - *dfsp = []bool{} - } - } - } - case isPointer: // E.g., *bool - mfi.merge = func(dst, src pointer) { - sfpp := src.toBoolPtr() - if *sfpp != nil { - dfpp := dst.toBoolPtr() - if *dfpp == nil { - *dfpp = Bool(**sfpp) - } else { - **dfpp = **sfpp - } - } - } - default: // E.g., bool - mfi.merge = func(dst, src pointer) { - if v := *src.toBool(); v { - *dst.toBool() = v - } - } - } - case reflect.String: - switch { - case isSlice: // E.g., []string - mfi.merge = func(dst, src pointer) { - sfsp := src.toStringSlice() - if *sfsp != nil { - dfsp := dst.toStringSlice() - *dfsp = append(*dfsp, *sfsp...) - if *dfsp == nil { - *dfsp = []string{} - } - } - } - case isPointer: // E.g., *string - mfi.merge = func(dst, src pointer) { - sfpp := src.toStringPtr() - if *sfpp != nil { - dfpp := dst.toStringPtr() - if *dfpp == nil { - *dfpp = String(**sfpp) - } else { - **dfpp = **sfpp - } - } - } - default: // E.g., string - mfi.merge = func(dst, src pointer) { - if v := *src.toString(); v != "" { - *dst.toString() = v - } - } - } - case reflect.Slice: - isProto3 := props.Prop[i].proto3 - switch { - case isPointer: - panic("bad pointer in byte slice case in " + tf.Name()) - case tf.Elem().Kind() != reflect.Uint8: - panic("bad element kind in byte slice case in " + tf.Name()) - case isSlice: // E.g., [][]byte - mfi.merge = func(dst, src pointer) { - sbsp := src.toBytesSlice() - if *sbsp != nil { - dbsp := dst.toBytesSlice() - for _, sb := range *sbsp { - if sb == nil { - *dbsp = append(*dbsp, nil) - } else { - *dbsp = append(*dbsp, append([]byte{}, sb...)) - } - } - if *dbsp == nil { - *dbsp = [][]byte{} - } - } - } - default: // E.g., []byte - mfi.merge = func(dst, src pointer) { - sbp := src.toBytes() - if *sbp != nil { - dbp := dst.toBytes() - if !isProto3 || len(*sbp) > 0 { - *dbp = append([]byte{}, *sbp...) - } - } - } - } - case reflect.Struct: - switch { - case isSlice && !isPointer: // E.g. []pb.T - mergeInfo := getMergeInfo(tf) - zero := reflect.Zero(tf) - mfi.merge = func(dst, src pointer) { - // TODO: Make this faster? - dstsp := dst.asPointerTo(f.Type) - dsts := dstsp.Elem() - srcs := src.asPointerTo(f.Type).Elem() - for i := 0; i < srcs.Len(); i++ { - dsts = reflect.Append(dsts, zero) - srcElement := srcs.Index(i).Addr() - dstElement := dsts.Index(dsts.Len() - 1).Addr() - mergeInfo.merge(valToPointer(dstElement), valToPointer(srcElement)) - } - if dsts.IsNil() { - dsts = reflect.MakeSlice(f.Type, 0, 0) - } - dstsp.Elem().Set(dsts) - } - case !isPointer: - mergeInfo := getMergeInfo(tf) - mfi.merge = func(dst, src pointer) { - mergeInfo.merge(dst, src) - } - case isSlice: // E.g., []*pb.T - mergeInfo := getMergeInfo(tf) - mfi.merge = func(dst, src pointer) { - sps := src.getPointerSlice() - if sps != nil { - dps := dst.getPointerSlice() - for _, sp := range sps { - var dp pointer - if !sp.isNil() { - dp = valToPointer(reflect.New(tf)) - mergeInfo.merge(dp, sp) - } - dps = append(dps, dp) - } - if dps == nil { - dps = []pointer{} - } - dst.setPointerSlice(dps) - } - } - default: // E.g., *pb.T - mergeInfo := getMergeInfo(tf) - mfi.merge = func(dst, src pointer) { - sp := src.getPointer() - if !sp.isNil() { - dp := dst.getPointer() - if dp.isNil() { - dp = valToPointer(reflect.New(tf)) - dst.setPointer(dp) - } - mergeInfo.merge(dp, sp) - } - } - } - case reflect.Map: - switch { - case isPointer || isSlice: - panic("bad pointer or slice in map case in " + tf.Name()) - default: // E.g., map[K]V - mfi.merge = func(dst, src pointer) { - sm := src.asPointerTo(tf).Elem() - if sm.Len() == 0 { - return - } - dm := dst.asPointerTo(tf).Elem() - if dm.IsNil() { - dm.Set(reflect.MakeMap(tf)) - } - - switch tf.Elem().Kind() { - case reflect.Ptr: // Proto struct (e.g., *T) - for _, key := range sm.MapKeys() { - val := sm.MapIndex(key) - val = reflect.ValueOf(Clone(val.Interface().(Message))) - dm.SetMapIndex(key, val) - } - case reflect.Slice: // E.g. Bytes type (e.g., []byte) - for _, key := range sm.MapKeys() { - val := sm.MapIndex(key) - val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) - dm.SetMapIndex(key, val) - } - default: // Basic type (e.g., string) - for _, key := range sm.MapKeys() { - val := sm.MapIndex(key) - dm.SetMapIndex(key, val) - } - } - } - } - case reflect.Interface: - // Must be oneof field. - switch { - case isPointer || isSlice: - panic("bad pointer or slice in interface case in " + tf.Name()) - default: // E.g., interface{} - // TODO: Make this faster? - mfi.merge = func(dst, src pointer) { - su := src.asPointerTo(tf).Elem() - if !su.IsNil() { - du := dst.asPointerTo(tf).Elem() - typ := su.Elem().Type() - if du.IsNil() || du.Elem().Type() != typ { - du.Set(reflect.New(typ.Elem())) // Initialize interface if empty - } - sv := su.Elem().Elem().Field(0) - if sv.Kind() == reflect.Ptr && sv.IsNil() { - return - } - dv := du.Elem().Elem().Field(0) - if dv.Kind() == reflect.Ptr && dv.IsNil() { - dv.Set(reflect.New(sv.Type().Elem())) // Initialize proto message if empty - } - switch sv.Type().Kind() { - case reflect.Ptr: // Proto struct (e.g., *T) - Merge(dv.Interface().(Message), sv.Interface().(Message)) - case reflect.Slice: // E.g. Bytes type (e.g., []byte) - dv.Set(reflect.ValueOf(append([]byte{}, sv.Bytes()...))) - default: // Basic type (e.g., string) - dv.Set(sv) - } - } - } - } - default: - panic(fmt.Sprintf("merger not found for type:%s", tf)) - } - mi.fields = append(mi.fields, mfi) - } - - mi.unrecognized = invalidField - if f, ok := t.FieldByName("XXX_unrecognized"); ok { - if f.Type != reflect.TypeOf([]byte{}) { - panic("expected XXX_unrecognized to be of type []byte") - } - mi.unrecognized = toField(&f) - } - - atomic.StoreInt32(&mi.initialized, 1) -} diff --git a/vendor/github.com/gogo/protobuf/proto/table_unmarshal.go b/vendor/github.com/gogo/protobuf/proto/table_unmarshal.go deleted file mode 100644 index 937229386..000000000 --- a/vendor/github.com/gogo/protobuf/proto/table_unmarshal.go +++ /dev/null @@ -1,2249 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2016 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -import ( - "errors" - "fmt" - "io" - "math" - "reflect" - "strconv" - "strings" - "sync" - "sync/atomic" - "unicode/utf8" -) - -// Unmarshal is the entry point from the generated .pb.go files. -// This function is not intended to be used by non-generated code. -// This function is not subject to any compatibility guarantee. -// msg contains a pointer to a protocol buffer struct. -// b is the data to be unmarshaled into the protocol buffer. -// a is a pointer to a place to store cached unmarshal information. -func (a *InternalMessageInfo) Unmarshal(msg Message, b []byte) error { - // Load the unmarshal information for this message type. - // The atomic load ensures memory consistency. - u := atomicLoadUnmarshalInfo(&a.unmarshal) - if u == nil { - // Slow path: find unmarshal info for msg, update a with it. - u = getUnmarshalInfo(reflect.TypeOf(msg).Elem()) - atomicStoreUnmarshalInfo(&a.unmarshal, u) - } - // Then do the unmarshaling. - err := u.unmarshal(toPointer(&msg), b) - return err -} - -type unmarshalInfo struct { - typ reflect.Type // type of the protobuf struct - - // 0 = only typ field is initialized - // 1 = completely initialized - initialized int32 - lock sync.Mutex // prevents double initialization - dense []unmarshalFieldInfo // fields indexed by tag # - sparse map[uint64]unmarshalFieldInfo // fields indexed by tag # - reqFields []string // names of required fields - reqMask uint64 // 1< 0 { - // Read tag and wire type. - // Special case 1 and 2 byte varints. - var x uint64 - if b[0] < 128 { - x = uint64(b[0]) - b = b[1:] - } else if len(b) >= 2 && b[1] < 128 { - x = uint64(b[0]&0x7f) + uint64(b[1])<<7 - b = b[2:] - } else { - var n int - x, n = decodeVarint(b) - if n == 0 { - return io.ErrUnexpectedEOF - } - b = b[n:] - } - tag := x >> 3 - wire := int(x) & 7 - - // Dispatch on the tag to one of the unmarshal* functions below. - var f unmarshalFieldInfo - if tag < uint64(len(u.dense)) { - f = u.dense[tag] - } else { - f = u.sparse[tag] - } - if fn := f.unmarshal; fn != nil { - var err error - b, err = fn(b, m.offset(f.field), wire) - if err == nil { - reqMask |= f.reqMask - continue - } - if r, ok := err.(*RequiredNotSetError); ok { - // Remember this error, but keep parsing. We need to produce - // a full parse even if a required field is missing. - if errLater == nil { - errLater = r - } - reqMask |= f.reqMask - continue - } - if err != errInternalBadWireType { - if err == errInvalidUTF8 { - if errLater == nil { - fullName := revProtoTypes[reflect.PtrTo(u.typ)] + "." + f.name - errLater = &invalidUTF8Error{fullName} - } - continue - } - return err - } - // Fragments with bad wire type are treated as unknown fields. - } - - // Unknown tag. - if !u.unrecognized.IsValid() { - // Don't keep unrecognized data; just skip it. - var err error - b, err = skipField(b, wire) - if err != nil { - return err - } - continue - } - // Keep unrecognized data around. - // maybe in extensions, maybe in the unrecognized field. - z := m.offset(u.unrecognized).toBytes() - var emap map[int32]Extension - var e Extension - for _, r := range u.extensionRanges { - if uint64(r.Start) <= tag && tag <= uint64(r.End) { - if u.extensions.IsValid() { - mp := m.offset(u.extensions).toExtensions() - emap = mp.extensionsWrite() - e = emap[int32(tag)] - z = &e.enc - break - } - if u.oldExtensions.IsValid() { - p := m.offset(u.oldExtensions).toOldExtensions() - emap = *p - if emap == nil { - emap = map[int32]Extension{} - *p = emap - } - e = emap[int32(tag)] - z = &e.enc - break - } - if u.bytesExtensions.IsValid() { - z = m.offset(u.bytesExtensions).toBytes() - break - } - panic("no extensions field available") - } - } - // Use wire type to skip data. - var err error - b0 := b - b, err = skipField(b, wire) - if err != nil { - return err - } - *z = encodeVarint(*z, tag<<3|uint64(wire)) - *z = append(*z, b0[:len(b0)-len(b)]...) - - if emap != nil { - emap[int32(tag)] = e - } - } - if reqMask != u.reqMask && errLater == nil { - // A required field of this message is missing. - for _, n := range u.reqFields { - if reqMask&1 == 0 { - errLater = &RequiredNotSetError{n} - } - reqMask >>= 1 - } - } - return errLater -} - -// computeUnmarshalInfo fills in u with information for use -// in unmarshaling protocol buffers of type u.typ. -func (u *unmarshalInfo) computeUnmarshalInfo() { - u.lock.Lock() - defer u.lock.Unlock() - if u.initialized != 0 { - return - } - t := u.typ - n := t.NumField() - - // Set up the "not found" value for the unrecognized byte buffer. - // This is the default for proto3. - u.unrecognized = invalidField - u.extensions = invalidField - u.oldExtensions = invalidField - u.bytesExtensions = invalidField - - // List of the generated type and offset for each oneof field. - type oneofField struct { - ityp reflect.Type // interface type of oneof field - field field // offset in containing message - } - var oneofFields []oneofField - - for i := 0; i < n; i++ { - f := t.Field(i) - if f.Name == "XXX_unrecognized" { - // The byte slice used to hold unrecognized input is special. - if f.Type != reflect.TypeOf(([]byte)(nil)) { - panic("bad type for XXX_unrecognized field: " + f.Type.Name()) - } - u.unrecognized = toField(&f) - continue - } - if f.Name == "XXX_InternalExtensions" { - // Ditto here. - if f.Type != reflect.TypeOf(XXX_InternalExtensions{}) { - panic("bad type for XXX_InternalExtensions field: " + f.Type.Name()) - } - u.extensions = toField(&f) - if f.Tag.Get("protobuf_messageset") == "1" { - u.isMessageSet = true - } - continue - } - if f.Name == "XXX_extensions" { - // An older form of the extensions field. - if f.Type == reflect.TypeOf((map[int32]Extension)(nil)) { - u.oldExtensions = toField(&f) - continue - } else if f.Type == reflect.TypeOf(([]byte)(nil)) { - u.bytesExtensions = toField(&f) - continue - } - panic("bad type for XXX_extensions field: " + f.Type.Name()) - } - if f.Name == "XXX_NoUnkeyedLiteral" || f.Name == "XXX_sizecache" { - continue - } - - oneof := f.Tag.Get("protobuf_oneof") - if oneof != "" { - oneofFields = append(oneofFields, oneofField{f.Type, toField(&f)}) - // The rest of oneof processing happens below. - continue - } - - tags := f.Tag.Get("protobuf") - tagArray := strings.Split(tags, ",") - if len(tagArray) < 2 { - panic("protobuf tag not enough fields in " + t.Name() + "." + f.Name + ": " + tags) - } - tag, err := strconv.Atoi(tagArray[1]) - if err != nil { - panic("protobuf tag field not an integer: " + tagArray[1]) - } - - name := "" - for _, tag := range tagArray[3:] { - if strings.HasPrefix(tag, "name=") { - name = tag[5:] - } - } - - // Extract unmarshaling function from the field (its type and tags). - unmarshal := fieldUnmarshaler(&f) - - // Required field? - var reqMask uint64 - if tagArray[2] == "req" { - bit := len(u.reqFields) - u.reqFields = append(u.reqFields, name) - reqMask = uint64(1) << uint(bit) - // TODO: if we have more than 64 required fields, we end up - // not verifying that all required fields are present. - // Fix this, perhaps using a count of required fields? - } - - // Store the info in the correct slot in the message. - u.setTag(tag, toField(&f), unmarshal, reqMask, name) - } - - // Find any types associated with oneof fields. - // gogo: len(oneofFields) > 0 is needed for embedded oneof messages, without a marshaler and unmarshaler - if len(oneofFields) > 0 { - var oneofImplementers []interface{} - switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) { - case oneofFuncsIface: - _, _, _, oneofImplementers = m.XXX_OneofFuncs() - case oneofWrappersIface: - oneofImplementers = m.XXX_OneofWrappers() - } - for _, v := range oneofImplementers { - tptr := reflect.TypeOf(v) // *Msg_X - typ := tptr.Elem() // Msg_X - - f := typ.Field(0) // oneof implementers have one field - baseUnmarshal := fieldUnmarshaler(&f) - tags := strings.Split(f.Tag.Get("protobuf"), ",") - fieldNum, err := strconv.Atoi(tags[1]) - if err != nil { - panic("protobuf tag field not an integer: " + tags[1]) - } - var name string - for _, tag := range tags { - if strings.HasPrefix(tag, "name=") { - name = strings.TrimPrefix(tag, "name=") - break - } - } - - // Find the oneof field that this struct implements. - // Might take O(n^2) to process all of the oneofs, but who cares. - for _, of := range oneofFields { - if tptr.Implements(of.ityp) { - // We have found the corresponding interface for this struct. - // That lets us know where this struct should be stored - // when we encounter it during unmarshaling. - unmarshal := makeUnmarshalOneof(typ, of.ityp, baseUnmarshal) - u.setTag(fieldNum, of.field, unmarshal, 0, name) - } - } - - } - } - - // Get extension ranges, if any. - fn := reflect.Zero(reflect.PtrTo(t)).MethodByName("ExtensionRangeArray") - if fn.IsValid() { - if !u.extensions.IsValid() && !u.oldExtensions.IsValid() && !u.bytesExtensions.IsValid() { - panic("a message with extensions, but no extensions field in " + t.Name()) - } - u.extensionRanges = fn.Call(nil)[0].Interface().([]ExtensionRange) - } - - // Explicitly disallow tag 0. This will ensure we flag an error - // when decoding a buffer of all zeros. Without this code, we - // would decode and skip an all-zero buffer of even length. - // [0 0] is [tag=0/wiretype=varint varint-encoded-0]. - u.setTag(0, zeroField, func(b []byte, f pointer, w int) ([]byte, error) { - return nil, fmt.Errorf("proto: %s: illegal tag 0 (wire type %d)", t, w) - }, 0, "") - - // Set mask for required field check. - u.reqMask = uint64(1)<= 0 && (tag < 16 || tag < 2*n) { // TODO: what are the right numbers here? - for len(u.dense) <= tag { - u.dense = append(u.dense, unmarshalFieldInfo{}) - } - u.dense[tag] = i - return - } - if u.sparse == nil { - u.sparse = map[uint64]unmarshalFieldInfo{} - } - u.sparse[uint64(tag)] = i -} - -// fieldUnmarshaler returns an unmarshaler for the given field. -func fieldUnmarshaler(f *reflect.StructField) unmarshaler { - if f.Type.Kind() == reflect.Map { - return makeUnmarshalMap(f) - } - return typeUnmarshaler(f.Type, f.Tag.Get("protobuf")) -} - -// typeUnmarshaler returns an unmarshaler for the given field type / field tag pair. -func typeUnmarshaler(t reflect.Type, tags string) unmarshaler { - tagArray := strings.Split(tags, ",") - encoding := tagArray[0] - name := "unknown" - ctype := false - isTime := false - isDuration := false - isWktPointer := false - proto3 := false - validateUTF8 := true - for _, tag := range tagArray[3:] { - if strings.HasPrefix(tag, "name=") { - name = tag[5:] - } - if tag == "proto3" { - proto3 = true - } - if strings.HasPrefix(tag, "customtype=") { - ctype = true - } - if tag == "stdtime" { - isTime = true - } - if tag == "stdduration" { - isDuration = true - } - if tag == "wktptr" { - isWktPointer = true - } - } - validateUTF8 = validateUTF8 && proto3 - - // Figure out packaging (pointer, slice, or both) - slice := false - pointer := false - if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 { - slice = true - t = t.Elem() - } - if t.Kind() == reflect.Ptr { - pointer = true - t = t.Elem() - } - - if ctype { - if reflect.PtrTo(t).Implements(customType) { - if slice { - return makeUnmarshalCustomSlice(getUnmarshalInfo(t), name) - } - if pointer { - return makeUnmarshalCustomPtr(getUnmarshalInfo(t), name) - } - return makeUnmarshalCustom(getUnmarshalInfo(t), name) - } else { - panic(fmt.Sprintf("custom type: type: %v, does not implement the proto.custom interface", t)) - } - } - - if isTime { - if pointer { - if slice { - return makeUnmarshalTimePtrSlice(getUnmarshalInfo(t), name) - } - return makeUnmarshalTimePtr(getUnmarshalInfo(t), name) - } - if slice { - return makeUnmarshalTimeSlice(getUnmarshalInfo(t), name) - } - return makeUnmarshalTime(getUnmarshalInfo(t), name) - } - - if isDuration { - if pointer { - if slice { - return makeUnmarshalDurationPtrSlice(getUnmarshalInfo(t), name) - } - return makeUnmarshalDurationPtr(getUnmarshalInfo(t), name) - } - if slice { - return makeUnmarshalDurationSlice(getUnmarshalInfo(t), name) - } - return makeUnmarshalDuration(getUnmarshalInfo(t), name) - } - - if isWktPointer { - switch t.Kind() { - case reflect.Float64: - if pointer { - if slice { - return makeStdDoubleValuePtrSliceUnmarshaler(getUnmarshalInfo(t), name) - } - return makeStdDoubleValuePtrUnmarshaler(getUnmarshalInfo(t), name) - } - if slice { - return makeStdDoubleValueSliceUnmarshaler(getUnmarshalInfo(t), name) - } - return makeStdDoubleValueUnmarshaler(getUnmarshalInfo(t), name) - case reflect.Float32: - if pointer { - if slice { - return makeStdFloatValuePtrSliceUnmarshaler(getUnmarshalInfo(t), name) - } - return makeStdFloatValuePtrUnmarshaler(getUnmarshalInfo(t), name) - } - if slice { - return makeStdFloatValueSliceUnmarshaler(getUnmarshalInfo(t), name) - } - return makeStdFloatValueUnmarshaler(getUnmarshalInfo(t), name) - case reflect.Int64: - if pointer { - if slice { - return makeStdInt64ValuePtrSliceUnmarshaler(getUnmarshalInfo(t), name) - } - return makeStdInt64ValuePtrUnmarshaler(getUnmarshalInfo(t), name) - } - if slice { - return makeStdInt64ValueSliceUnmarshaler(getUnmarshalInfo(t), name) - } - return makeStdInt64ValueUnmarshaler(getUnmarshalInfo(t), name) - case reflect.Uint64: - if pointer { - if slice { - return makeStdUInt64ValuePtrSliceUnmarshaler(getUnmarshalInfo(t), name) - } - return makeStdUInt64ValuePtrUnmarshaler(getUnmarshalInfo(t), name) - } - if slice { - return makeStdUInt64ValueSliceUnmarshaler(getUnmarshalInfo(t), name) - } - return makeStdUInt64ValueUnmarshaler(getUnmarshalInfo(t), name) - case reflect.Int32: - if pointer { - if slice { - return makeStdInt32ValuePtrSliceUnmarshaler(getUnmarshalInfo(t), name) - } - return makeStdInt32ValuePtrUnmarshaler(getUnmarshalInfo(t), name) - } - if slice { - return makeStdInt32ValueSliceUnmarshaler(getUnmarshalInfo(t), name) - } - return makeStdInt32ValueUnmarshaler(getUnmarshalInfo(t), name) - case reflect.Uint32: - if pointer { - if slice { - return makeStdUInt32ValuePtrSliceUnmarshaler(getUnmarshalInfo(t), name) - } - return makeStdUInt32ValuePtrUnmarshaler(getUnmarshalInfo(t), name) - } - if slice { - return makeStdUInt32ValueSliceUnmarshaler(getUnmarshalInfo(t), name) - } - return makeStdUInt32ValueUnmarshaler(getUnmarshalInfo(t), name) - case reflect.Bool: - if pointer { - if slice { - return makeStdBoolValuePtrSliceUnmarshaler(getUnmarshalInfo(t), name) - } - return makeStdBoolValuePtrUnmarshaler(getUnmarshalInfo(t), name) - } - if slice { - return makeStdBoolValueSliceUnmarshaler(getUnmarshalInfo(t), name) - } - return makeStdBoolValueUnmarshaler(getUnmarshalInfo(t), name) - case reflect.String: - if pointer { - if slice { - return makeStdStringValuePtrSliceUnmarshaler(getUnmarshalInfo(t), name) - } - return makeStdStringValuePtrUnmarshaler(getUnmarshalInfo(t), name) - } - if slice { - return makeStdStringValueSliceUnmarshaler(getUnmarshalInfo(t), name) - } - return makeStdStringValueUnmarshaler(getUnmarshalInfo(t), name) - case uint8SliceType: - if pointer { - if slice { - return makeStdBytesValuePtrSliceUnmarshaler(getUnmarshalInfo(t), name) - } - return makeStdBytesValuePtrUnmarshaler(getUnmarshalInfo(t), name) - } - if slice { - return makeStdBytesValueSliceUnmarshaler(getUnmarshalInfo(t), name) - } - return makeStdBytesValueUnmarshaler(getUnmarshalInfo(t), name) - default: - panic(fmt.Sprintf("unknown wktpointer type %#v", t)) - } - } - - // We'll never have both pointer and slice for basic types. - if pointer && slice && t.Kind() != reflect.Struct { - panic("both pointer and slice for basic type in " + t.Name()) - } - - switch t.Kind() { - case reflect.Bool: - if pointer { - return unmarshalBoolPtr - } - if slice { - return unmarshalBoolSlice - } - return unmarshalBoolValue - case reflect.Int32: - switch encoding { - case "fixed32": - if pointer { - return unmarshalFixedS32Ptr - } - if slice { - return unmarshalFixedS32Slice - } - return unmarshalFixedS32Value - case "varint": - // this could be int32 or enum - if pointer { - return unmarshalInt32Ptr - } - if slice { - return unmarshalInt32Slice - } - return unmarshalInt32Value - case "zigzag32": - if pointer { - return unmarshalSint32Ptr - } - if slice { - return unmarshalSint32Slice - } - return unmarshalSint32Value - } - case reflect.Int64: - switch encoding { - case "fixed64": - if pointer { - return unmarshalFixedS64Ptr - } - if slice { - return unmarshalFixedS64Slice - } - return unmarshalFixedS64Value - case "varint": - if pointer { - return unmarshalInt64Ptr - } - if slice { - return unmarshalInt64Slice - } - return unmarshalInt64Value - case "zigzag64": - if pointer { - return unmarshalSint64Ptr - } - if slice { - return unmarshalSint64Slice - } - return unmarshalSint64Value - } - case reflect.Uint32: - switch encoding { - case "fixed32": - if pointer { - return unmarshalFixed32Ptr - } - if slice { - return unmarshalFixed32Slice - } - return unmarshalFixed32Value - case "varint": - if pointer { - return unmarshalUint32Ptr - } - if slice { - return unmarshalUint32Slice - } - return unmarshalUint32Value - } - case reflect.Uint64: - switch encoding { - case "fixed64": - if pointer { - return unmarshalFixed64Ptr - } - if slice { - return unmarshalFixed64Slice - } - return unmarshalFixed64Value - case "varint": - if pointer { - return unmarshalUint64Ptr - } - if slice { - return unmarshalUint64Slice - } - return unmarshalUint64Value - } - case reflect.Float32: - if pointer { - return unmarshalFloat32Ptr - } - if slice { - return unmarshalFloat32Slice - } - return unmarshalFloat32Value - case reflect.Float64: - if pointer { - return unmarshalFloat64Ptr - } - if slice { - return unmarshalFloat64Slice - } - return unmarshalFloat64Value - case reflect.Map: - panic("map type in typeUnmarshaler in " + t.Name()) - case reflect.Slice: - if pointer { - panic("bad pointer in slice case in " + t.Name()) - } - if slice { - return unmarshalBytesSlice - } - return unmarshalBytesValue - case reflect.String: - if validateUTF8 { - if pointer { - return unmarshalUTF8StringPtr - } - if slice { - return unmarshalUTF8StringSlice - } - return unmarshalUTF8StringValue - } - if pointer { - return unmarshalStringPtr - } - if slice { - return unmarshalStringSlice - } - return unmarshalStringValue - case reflect.Struct: - // message or group field - if !pointer { - switch encoding { - case "bytes": - if slice { - return makeUnmarshalMessageSlice(getUnmarshalInfo(t), name) - } - return makeUnmarshalMessage(getUnmarshalInfo(t), name) - } - } - switch encoding { - case "bytes": - if slice { - return makeUnmarshalMessageSlicePtr(getUnmarshalInfo(t), name) - } - return makeUnmarshalMessagePtr(getUnmarshalInfo(t), name) - case "group": - if slice { - return makeUnmarshalGroupSlicePtr(getUnmarshalInfo(t), name) - } - return makeUnmarshalGroupPtr(getUnmarshalInfo(t), name) - } - } - panic(fmt.Sprintf("unmarshaler not found type:%s encoding:%s", t, encoding)) -} - -// Below are all the unmarshalers for individual fields of various types. - -func unmarshalInt64Value(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int64(x) - *f.toInt64() = v - return b, nil -} - -func unmarshalInt64Ptr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int64(x) - *f.toInt64Ptr() = &v - return b, nil -} - -func unmarshalInt64Slice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - x, n = decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int64(x) - s := f.toInt64Slice() - *s = append(*s, v) - } - return res, nil - } - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int64(x) - s := f.toInt64Slice() - *s = append(*s, v) - return b, nil -} - -func unmarshalSint64Value(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int64(x>>1) ^ int64(x)<<63>>63 - *f.toInt64() = v - return b, nil -} - -func unmarshalSint64Ptr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int64(x>>1) ^ int64(x)<<63>>63 - *f.toInt64Ptr() = &v - return b, nil -} - -func unmarshalSint64Slice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - x, n = decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int64(x>>1) ^ int64(x)<<63>>63 - s := f.toInt64Slice() - *s = append(*s, v) - } - return res, nil - } - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int64(x>>1) ^ int64(x)<<63>>63 - s := f.toInt64Slice() - *s = append(*s, v) - return b, nil -} - -func unmarshalUint64Value(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := uint64(x) - *f.toUint64() = v - return b, nil -} - -func unmarshalUint64Ptr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := uint64(x) - *f.toUint64Ptr() = &v - return b, nil -} - -func unmarshalUint64Slice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - x, n = decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := uint64(x) - s := f.toUint64Slice() - *s = append(*s, v) - } - return res, nil - } - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := uint64(x) - s := f.toUint64Slice() - *s = append(*s, v) - return b, nil -} - -func unmarshalInt32Value(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int32(x) - *f.toInt32() = v - return b, nil -} - -func unmarshalInt32Ptr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int32(x) - f.setInt32Ptr(v) - return b, nil -} - -func unmarshalInt32Slice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - x, n = decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int32(x) - f.appendInt32Slice(v) - } - return res, nil - } - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int32(x) - f.appendInt32Slice(v) - return b, nil -} - -func unmarshalSint32Value(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int32(x>>1) ^ int32(x)<<31>>31 - *f.toInt32() = v - return b, nil -} - -func unmarshalSint32Ptr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int32(x>>1) ^ int32(x)<<31>>31 - f.setInt32Ptr(v) - return b, nil -} - -func unmarshalSint32Slice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - x, n = decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int32(x>>1) ^ int32(x)<<31>>31 - f.appendInt32Slice(v) - } - return res, nil - } - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := int32(x>>1) ^ int32(x)<<31>>31 - f.appendInt32Slice(v) - return b, nil -} - -func unmarshalUint32Value(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := uint32(x) - *f.toUint32() = v - return b, nil -} - -func unmarshalUint32Ptr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := uint32(x) - *f.toUint32Ptr() = &v - return b, nil -} - -func unmarshalUint32Slice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - x, n = decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := uint32(x) - s := f.toUint32Slice() - *s = append(*s, v) - } - return res, nil - } - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - v := uint32(x) - s := f.toUint32Slice() - *s = append(*s, v) - return b, nil -} - -func unmarshalFixed64Value(b []byte, f pointer, w int) ([]byte, error) { - if w != WireFixed64 { - return b, errInternalBadWireType - } - if len(b) < 8 { - return nil, io.ErrUnexpectedEOF - } - v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 - *f.toUint64() = v - return b[8:], nil -} - -func unmarshalFixed64Ptr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireFixed64 { - return b, errInternalBadWireType - } - if len(b) < 8 { - return nil, io.ErrUnexpectedEOF - } - v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 - *f.toUint64Ptr() = &v - return b[8:], nil -} - -func unmarshalFixed64Slice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - if len(b) < 8 { - return nil, io.ErrUnexpectedEOF - } - v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 - s := f.toUint64Slice() - *s = append(*s, v) - b = b[8:] - } - return res, nil - } - if w != WireFixed64 { - return b, errInternalBadWireType - } - if len(b) < 8 { - return nil, io.ErrUnexpectedEOF - } - v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 - s := f.toUint64Slice() - *s = append(*s, v) - return b[8:], nil -} - -func unmarshalFixedS64Value(b []byte, f pointer, w int) ([]byte, error) { - if w != WireFixed64 { - return b, errInternalBadWireType - } - if len(b) < 8 { - return nil, io.ErrUnexpectedEOF - } - v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56 - *f.toInt64() = v - return b[8:], nil -} - -func unmarshalFixedS64Ptr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireFixed64 { - return b, errInternalBadWireType - } - if len(b) < 8 { - return nil, io.ErrUnexpectedEOF - } - v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56 - *f.toInt64Ptr() = &v - return b[8:], nil -} - -func unmarshalFixedS64Slice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - if len(b) < 8 { - return nil, io.ErrUnexpectedEOF - } - v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56 - s := f.toInt64Slice() - *s = append(*s, v) - b = b[8:] - } - return res, nil - } - if w != WireFixed64 { - return b, errInternalBadWireType - } - if len(b) < 8 { - return nil, io.ErrUnexpectedEOF - } - v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56 - s := f.toInt64Slice() - *s = append(*s, v) - return b[8:], nil -} - -func unmarshalFixed32Value(b []byte, f pointer, w int) ([]byte, error) { - if w != WireFixed32 { - return b, errInternalBadWireType - } - if len(b) < 4 { - return nil, io.ErrUnexpectedEOF - } - v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 - *f.toUint32() = v - return b[4:], nil -} - -func unmarshalFixed32Ptr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireFixed32 { - return b, errInternalBadWireType - } - if len(b) < 4 { - return nil, io.ErrUnexpectedEOF - } - v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 - *f.toUint32Ptr() = &v - return b[4:], nil -} - -func unmarshalFixed32Slice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - if len(b) < 4 { - return nil, io.ErrUnexpectedEOF - } - v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 - s := f.toUint32Slice() - *s = append(*s, v) - b = b[4:] - } - return res, nil - } - if w != WireFixed32 { - return b, errInternalBadWireType - } - if len(b) < 4 { - return nil, io.ErrUnexpectedEOF - } - v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 - s := f.toUint32Slice() - *s = append(*s, v) - return b[4:], nil -} - -func unmarshalFixedS32Value(b []byte, f pointer, w int) ([]byte, error) { - if w != WireFixed32 { - return b, errInternalBadWireType - } - if len(b) < 4 { - return nil, io.ErrUnexpectedEOF - } - v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24 - *f.toInt32() = v - return b[4:], nil -} - -func unmarshalFixedS32Ptr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireFixed32 { - return b, errInternalBadWireType - } - if len(b) < 4 { - return nil, io.ErrUnexpectedEOF - } - v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24 - f.setInt32Ptr(v) - return b[4:], nil -} - -func unmarshalFixedS32Slice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - if len(b) < 4 { - return nil, io.ErrUnexpectedEOF - } - v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24 - f.appendInt32Slice(v) - b = b[4:] - } - return res, nil - } - if w != WireFixed32 { - return b, errInternalBadWireType - } - if len(b) < 4 { - return nil, io.ErrUnexpectedEOF - } - v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24 - f.appendInt32Slice(v) - return b[4:], nil -} - -func unmarshalBoolValue(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - // Note: any length varint is allowed, even though any sane - // encoder will use one byte. - // See https://github.com/golang/protobuf/issues/76 - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - // TODO: check if x>1? Tests seem to indicate no. - v := x != 0 - *f.toBool() = v - return b[n:], nil -} - -func unmarshalBoolPtr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - v := x != 0 - *f.toBoolPtr() = &v - return b[n:], nil -} - -func unmarshalBoolSlice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - x, n = decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - v := x != 0 - s := f.toBoolSlice() - *s = append(*s, v) - b = b[n:] - } - return res, nil - } - if w != WireVarint { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - v := x != 0 - s := f.toBoolSlice() - *s = append(*s, v) - return b[n:], nil -} - -func unmarshalFloat64Value(b []byte, f pointer, w int) ([]byte, error) { - if w != WireFixed64 { - return b, errInternalBadWireType - } - if len(b) < 8 { - return nil, io.ErrUnexpectedEOF - } - v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56) - *f.toFloat64() = v - return b[8:], nil -} - -func unmarshalFloat64Ptr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireFixed64 { - return b, errInternalBadWireType - } - if len(b) < 8 { - return nil, io.ErrUnexpectedEOF - } - v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56) - *f.toFloat64Ptr() = &v - return b[8:], nil -} - -func unmarshalFloat64Slice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - if len(b) < 8 { - return nil, io.ErrUnexpectedEOF - } - v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56) - s := f.toFloat64Slice() - *s = append(*s, v) - b = b[8:] - } - return res, nil - } - if w != WireFixed64 { - return b, errInternalBadWireType - } - if len(b) < 8 { - return nil, io.ErrUnexpectedEOF - } - v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56) - s := f.toFloat64Slice() - *s = append(*s, v) - return b[8:], nil -} - -func unmarshalFloat32Value(b []byte, f pointer, w int) ([]byte, error) { - if w != WireFixed32 { - return b, errInternalBadWireType - } - if len(b) < 4 { - return nil, io.ErrUnexpectedEOF - } - v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24) - *f.toFloat32() = v - return b[4:], nil -} - -func unmarshalFloat32Ptr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireFixed32 { - return b, errInternalBadWireType - } - if len(b) < 4 { - return nil, io.ErrUnexpectedEOF - } - v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24) - *f.toFloat32Ptr() = &v - return b[4:], nil -} - -func unmarshalFloat32Slice(b []byte, f pointer, w int) ([]byte, error) { - if w == WireBytes { // packed - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - res := b[x:] - b = b[:x] - for len(b) > 0 { - if len(b) < 4 { - return nil, io.ErrUnexpectedEOF - } - v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24) - s := f.toFloat32Slice() - *s = append(*s, v) - b = b[4:] - } - return res, nil - } - if w != WireFixed32 { - return b, errInternalBadWireType - } - if len(b) < 4 { - return nil, io.ErrUnexpectedEOF - } - v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24) - s := f.toFloat32Slice() - *s = append(*s, v) - return b[4:], nil -} - -func unmarshalStringValue(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - v := string(b[:x]) - *f.toString() = v - return b[x:], nil -} - -func unmarshalStringPtr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - v := string(b[:x]) - *f.toStringPtr() = &v - return b[x:], nil -} - -func unmarshalStringSlice(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - v := string(b[:x]) - s := f.toStringSlice() - *s = append(*s, v) - return b[x:], nil -} - -func unmarshalUTF8StringValue(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - v := string(b[:x]) - *f.toString() = v - if !utf8.ValidString(v) { - return b[x:], errInvalidUTF8 - } - return b[x:], nil -} - -func unmarshalUTF8StringPtr(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - v := string(b[:x]) - *f.toStringPtr() = &v - if !utf8.ValidString(v) { - return b[x:], errInvalidUTF8 - } - return b[x:], nil -} - -func unmarshalUTF8StringSlice(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - v := string(b[:x]) - s := f.toStringSlice() - *s = append(*s, v) - if !utf8.ValidString(v) { - return b[x:], errInvalidUTF8 - } - return b[x:], nil -} - -var emptyBuf [0]byte - -func unmarshalBytesValue(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - // The use of append here is a trick which avoids the zeroing - // that would be required if we used a make/copy pair. - // We append to emptyBuf instead of nil because we want - // a non-nil result even when the length is 0. - v := append(emptyBuf[:], b[:x]...) - *f.toBytes() = v - return b[x:], nil -} - -func unmarshalBytesSlice(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - v := append(emptyBuf[:], b[:x]...) - s := f.toBytesSlice() - *s = append(*s, v) - return b[x:], nil -} - -func makeUnmarshalMessagePtr(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - // First read the message field to see if something is there. - // The semantics of multiple submessages are weird. Instead of - // the last one winning (as it is for all other fields), multiple - // submessages are merged. - v := f.getPointer() - if v.isNil() { - v = valToPointer(reflect.New(sub.typ)) - f.setPointer(v) - } - err := sub.unmarshal(v, b[:x]) - if err != nil { - if r, ok := err.(*RequiredNotSetError); ok { - r.field = name + "." + r.field - } else { - return nil, err - } - } - return b[x:], err - } -} - -func makeUnmarshalMessageSlicePtr(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return b, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - v := valToPointer(reflect.New(sub.typ)) - err := sub.unmarshal(v, b[:x]) - if err != nil { - if r, ok := err.(*RequiredNotSetError); ok { - r.field = name + "." + r.field - } else { - return nil, err - } - } - f.appendPointer(v) - return b[x:], err - } -} - -func makeUnmarshalGroupPtr(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireStartGroup { - return b, errInternalBadWireType - } - x, y := findEndGroup(b) - if x < 0 { - return nil, io.ErrUnexpectedEOF - } - v := f.getPointer() - if v.isNil() { - v = valToPointer(reflect.New(sub.typ)) - f.setPointer(v) - } - err := sub.unmarshal(v, b[:x]) - if err != nil { - if r, ok := err.(*RequiredNotSetError); ok { - r.field = name + "." + r.field - } else { - return nil, err - } - } - return b[y:], err - } -} - -func makeUnmarshalGroupSlicePtr(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireStartGroup { - return b, errInternalBadWireType - } - x, y := findEndGroup(b) - if x < 0 { - return nil, io.ErrUnexpectedEOF - } - v := valToPointer(reflect.New(sub.typ)) - err := sub.unmarshal(v, b[:x]) - if err != nil { - if r, ok := err.(*RequiredNotSetError); ok { - r.field = name + "." + r.field - } else { - return nil, err - } - } - f.appendPointer(v) - return b[y:], err - } -} - -func makeUnmarshalMap(f *reflect.StructField) unmarshaler { - t := f.Type - kt := t.Key() - vt := t.Elem() - tagArray := strings.Split(f.Tag.Get("protobuf"), ",") - valTags := strings.Split(f.Tag.Get("protobuf_val"), ",") - for _, t := range tagArray { - if strings.HasPrefix(t, "customtype=") { - valTags = append(valTags, t) - } - if t == "stdtime" { - valTags = append(valTags, t) - } - if t == "stdduration" { - valTags = append(valTags, t) - } - if t == "wktptr" { - valTags = append(valTags, t) - } - } - unmarshalKey := typeUnmarshaler(kt, f.Tag.Get("protobuf_key")) - unmarshalVal := typeUnmarshaler(vt, strings.Join(valTags, ",")) - return func(b []byte, f pointer, w int) ([]byte, error) { - // The map entry is a submessage. Figure out how big it is. - if w != WireBytes { - return nil, fmt.Errorf("proto: bad wiretype for map field: got %d want %d", w, WireBytes) - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - r := b[x:] // unused data to return - b = b[:x] // data for map entry - - // Note: we could use #keys * #values ~= 200 functions - // to do map decoding without reflection. Probably not worth it. - // Maps will be somewhat slow. Oh well. - - // Read key and value from data. - var nerr nonFatal - k := reflect.New(kt) - v := reflect.New(vt) - for len(b) > 0 { - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - wire := int(x) & 7 - b = b[n:] - - var err error - switch x >> 3 { - case 1: - b, err = unmarshalKey(b, valToPointer(k), wire) - case 2: - b, err = unmarshalVal(b, valToPointer(v), wire) - default: - err = errInternalBadWireType // skip unknown tag - } - - if nerr.Merge(err) { - continue - } - if err != errInternalBadWireType { - return nil, err - } - - // Skip past unknown fields. - b, err = skipField(b, wire) - if err != nil { - return nil, err - } - } - - // Get map, allocate if needed. - m := f.asPointerTo(t).Elem() // an addressable map[K]T - if m.IsNil() { - m.Set(reflect.MakeMap(t)) - } - - // Insert into map. - m.SetMapIndex(k.Elem(), v.Elem()) - - return r, nerr.E - } -} - -// makeUnmarshalOneof makes an unmarshaler for oneof fields. -// for: -// message Msg { -// oneof F { -// int64 X = 1; -// float64 Y = 2; -// } -// } -// typ is the type of the concrete entry for a oneof case (e.g. Msg_X). -// ityp is the interface type of the oneof field (e.g. isMsg_F). -// unmarshal is the unmarshaler for the base type of the oneof case (e.g. int64). -// Note that this function will be called once for each case in the oneof. -func makeUnmarshalOneof(typ, ityp reflect.Type, unmarshal unmarshaler) unmarshaler { - sf := typ.Field(0) - field0 := toField(&sf) - return func(b []byte, f pointer, w int) ([]byte, error) { - // Allocate holder for value. - v := reflect.New(typ) - - // Unmarshal data into holder. - // We unmarshal into the first field of the holder object. - var err error - var nerr nonFatal - b, err = unmarshal(b, valToPointer(v).offset(field0), w) - if !nerr.Merge(err) { - return nil, err - } - - // Write pointer to holder into target field. - f.asPointerTo(ityp).Elem().Set(v) - - return b, nerr.E - } -} - -// Error used by decode internally. -var errInternalBadWireType = errors.New("proto: internal error: bad wiretype") - -// skipField skips past a field of type wire and returns the remaining bytes. -func skipField(b []byte, wire int) ([]byte, error) { - switch wire { - case WireVarint: - _, k := decodeVarint(b) - if k == 0 { - return b, io.ErrUnexpectedEOF - } - b = b[k:] - case WireFixed32: - if len(b) < 4 { - return b, io.ErrUnexpectedEOF - } - b = b[4:] - case WireFixed64: - if len(b) < 8 { - return b, io.ErrUnexpectedEOF - } - b = b[8:] - case WireBytes: - m, k := decodeVarint(b) - if k == 0 || uint64(len(b)-k) < m { - return b, io.ErrUnexpectedEOF - } - b = b[uint64(k)+m:] - case WireStartGroup: - _, i := findEndGroup(b) - if i == -1 { - return b, io.ErrUnexpectedEOF - } - b = b[i:] - default: - return b, fmt.Errorf("proto: can't skip unknown wire type %d", wire) - } - return b, nil -} - -// findEndGroup finds the index of the next EndGroup tag. -// Groups may be nested, so the "next" EndGroup tag is the first -// unpaired EndGroup. -// findEndGroup returns the indexes of the start and end of the EndGroup tag. -// Returns (-1,-1) if it can't find one. -func findEndGroup(b []byte) (int, int) { - depth := 1 - i := 0 - for { - x, n := decodeVarint(b[i:]) - if n == 0 { - return -1, -1 - } - j := i - i += n - switch x & 7 { - case WireVarint: - _, k := decodeVarint(b[i:]) - if k == 0 { - return -1, -1 - } - i += k - case WireFixed32: - if len(b)-4 < i { - return -1, -1 - } - i += 4 - case WireFixed64: - if len(b)-8 < i { - return -1, -1 - } - i += 8 - case WireBytes: - m, k := decodeVarint(b[i:]) - if k == 0 { - return -1, -1 - } - i += k - if uint64(len(b)-i) < m { - return -1, -1 - } - i += int(m) - case WireStartGroup: - depth++ - case WireEndGroup: - depth-- - if depth == 0 { - return j, i - } - default: - return -1, -1 - } - } -} - -// encodeVarint appends a varint-encoded integer to b and returns the result. -func encodeVarint(b []byte, x uint64) []byte { - for x >= 1<<7 { - b = append(b, byte(x&0x7f|0x80)) - x >>= 7 - } - return append(b, byte(x)) -} - -// decodeVarint reads a varint-encoded integer from b. -// Returns the decoded integer and the number of bytes read. -// If there is an error, it returns 0,0. -func decodeVarint(b []byte) (uint64, int) { - var x, y uint64 - if len(b) == 0 { - goto bad - } - x = uint64(b[0]) - if x < 0x80 { - return x, 1 - } - x -= 0x80 - - if len(b) <= 1 { - goto bad - } - y = uint64(b[1]) - x += y << 7 - if y < 0x80 { - return x, 2 - } - x -= 0x80 << 7 - - if len(b) <= 2 { - goto bad - } - y = uint64(b[2]) - x += y << 14 - if y < 0x80 { - return x, 3 - } - x -= 0x80 << 14 - - if len(b) <= 3 { - goto bad - } - y = uint64(b[3]) - x += y << 21 - if y < 0x80 { - return x, 4 - } - x -= 0x80 << 21 - - if len(b) <= 4 { - goto bad - } - y = uint64(b[4]) - x += y << 28 - if y < 0x80 { - return x, 5 - } - x -= 0x80 << 28 - - if len(b) <= 5 { - goto bad - } - y = uint64(b[5]) - x += y << 35 - if y < 0x80 { - return x, 6 - } - x -= 0x80 << 35 - - if len(b) <= 6 { - goto bad - } - y = uint64(b[6]) - x += y << 42 - if y < 0x80 { - return x, 7 - } - x -= 0x80 << 42 - - if len(b) <= 7 { - goto bad - } - y = uint64(b[7]) - x += y << 49 - if y < 0x80 { - return x, 8 - } - x -= 0x80 << 49 - - if len(b) <= 8 { - goto bad - } - y = uint64(b[8]) - x += y << 56 - if y < 0x80 { - return x, 9 - } - x -= 0x80 << 56 - - if len(b) <= 9 { - goto bad - } - y = uint64(b[9]) - x += y << 63 - if y < 2 { - return x, 10 - } - -bad: - return 0, 0 -} diff --git a/vendor/github.com/gogo/protobuf/proto/table_unmarshal_gogo.go b/vendor/github.com/gogo/protobuf/proto/table_unmarshal_gogo.go deleted file mode 100644 index 00d6c7ad9..000000000 --- a/vendor/github.com/gogo/protobuf/proto/table_unmarshal_gogo.go +++ /dev/null @@ -1,385 +0,0 @@ -// Protocol Buffers for Go with Gadgets -// -// Copyright (c) 2018, The GoGo Authors. All rights reserved. -// http://github.com/gogo/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -import ( - "io" - "reflect" -) - -func makeUnmarshalMessage(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - // First read the message field to see if something is there. - // The semantics of multiple submessages are weird. Instead of - // the last one winning (as it is for all other fields), multiple - // submessages are merged. - v := f // gogo: changed from v := f.getPointer() - if v.isNil() { - v = valToPointer(reflect.New(sub.typ)) - f.setPointer(v) - } - err := sub.unmarshal(v, b[:x]) - if err != nil { - if r, ok := err.(*RequiredNotSetError); ok { - r.field = name + "." + r.field - } else { - return nil, err - } - } - return b[x:], err - } -} - -func makeUnmarshalMessageSlice(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - v := valToPointer(reflect.New(sub.typ)) - err := sub.unmarshal(v, b[:x]) - if err != nil { - if r, ok := err.(*RequiredNotSetError); ok { - r.field = name + "." + r.field - } else { - return nil, err - } - } - f.appendRef(v, sub.typ) // gogo: changed from f.appendPointer(v) - return b[x:], err - } -} - -func makeUnmarshalCustomPtr(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - - s := f.asPointerTo(reflect.PtrTo(sub.typ)).Elem() - s.Set(reflect.New(sub.typ)) - m := s.Interface().(custom) - if err := m.Unmarshal(b[:x]); err != nil { - return nil, err - } - return b[x:], nil - } -} - -func makeUnmarshalCustomSlice(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := reflect.New(sub.typ) - c := m.Interface().(custom) - if err := c.Unmarshal(b[:x]); err != nil { - return nil, err - } - v := valToPointer(m) - f.appendRef(v, sub.typ) - return b[x:], nil - } -} - -func makeUnmarshalCustom(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - - m := f.asPointerTo(sub.typ).Interface().(custom) - if err := m.Unmarshal(b[:x]); err != nil { - return nil, err - } - return b[x:], nil - } -} - -func makeUnmarshalTime(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := ×tamp{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - t, err := timestampFromProto(m) - if err != nil { - return nil, err - } - s := f.asPointerTo(sub.typ).Elem() - s.Set(reflect.ValueOf(t)) - return b[x:], nil - } -} - -func makeUnmarshalTimePtr(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := ×tamp{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - t, err := timestampFromProto(m) - if err != nil { - return nil, err - } - s := f.asPointerTo(reflect.PtrTo(sub.typ)).Elem() - s.Set(reflect.ValueOf(&t)) - return b[x:], nil - } -} - -func makeUnmarshalTimePtrSlice(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := ×tamp{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - t, err := timestampFromProto(m) - if err != nil { - return nil, err - } - slice := f.getSlice(reflect.PtrTo(sub.typ)) - newSlice := reflect.Append(slice, reflect.ValueOf(&t)) - slice.Set(newSlice) - return b[x:], nil - } -} - -func makeUnmarshalTimeSlice(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := ×tamp{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - t, err := timestampFromProto(m) - if err != nil { - return nil, err - } - slice := f.getSlice(sub.typ) - newSlice := reflect.Append(slice, reflect.ValueOf(t)) - slice.Set(newSlice) - return b[x:], nil - } -} - -func makeUnmarshalDurationPtr(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &duration{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - d, err := durationFromProto(m) - if err != nil { - return nil, err - } - s := f.asPointerTo(reflect.PtrTo(sub.typ)).Elem() - s.Set(reflect.ValueOf(&d)) - return b[x:], nil - } -} - -func makeUnmarshalDuration(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &duration{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - d, err := durationFromProto(m) - if err != nil { - return nil, err - } - s := f.asPointerTo(sub.typ).Elem() - s.Set(reflect.ValueOf(d)) - return b[x:], nil - } -} - -func makeUnmarshalDurationPtrSlice(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &duration{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - d, err := durationFromProto(m) - if err != nil { - return nil, err - } - slice := f.getSlice(reflect.PtrTo(sub.typ)) - newSlice := reflect.Append(slice, reflect.ValueOf(&d)) - slice.Set(newSlice) - return b[x:], nil - } -} - -func makeUnmarshalDurationSlice(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &duration{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - d, err := durationFromProto(m) - if err != nil { - return nil, err - } - slice := f.getSlice(sub.typ) - newSlice := reflect.Append(slice, reflect.ValueOf(d)) - slice.Set(newSlice) - return b[x:], nil - } -} diff --git a/vendor/github.com/gogo/protobuf/proto/text.go b/vendor/github.com/gogo/protobuf/proto/text.go deleted file mode 100644 index 87416afe9..000000000 --- a/vendor/github.com/gogo/protobuf/proto/text.go +++ /dev/null @@ -1,930 +0,0 @@ -// Protocol Buffers for Go with Gadgets -// -// Copyright (c) 2013, The GoGo Authors. All rights reserved. -// http://github.com/gogo/protobuf -// -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -// Functions for writing the text protocol buffer format. - -import ( - "bufio" - "bytes" - "encoding" - "errors" - "fmt" - "io" - "log" - "math" - "reflect" - "sort" - "strings" - "sync" - "time" -) - -var ( - newline = []byte("\n") - spaces = []byte(" ") - endBraceNewline = []byte("}\n") - backslashN = []byte{'\\', 'n'} - backslashR = []byte{'\\', 'r'} - backslashT = []byte{'\\', 't'} - backslashDQ = []byte{'\\', '"'} - backslashBS = []byte{'\\', '\\'} - posInf = []byte("inf") - negInf = []byte("-inf") - nan = []byte("nan") -) - -type writer interface { - io.Writer - WriteByte(byte) error -} - -// textWriter is an io.Writer that tracks its indentation level. -type textWriter struct { - ind int - complete bool // if the current position is a complete line - compact bool // whether to write out as a one-liner - w writer -} - -func (w *textWriter) WriteString(s string) (n int, err error) { - if !strings.Contains(s, "\n") { - if !w.compact && w.complete { - w.writeIndent() - } - w.complete = false - return io.WriteString(w.w, s) - } - // WriteString is typically called without newlines, so this - // codepath and its copy are rare. We copy to avoid - // duplicating all of Write's logic here. - return w.Write([]byte(s)) -} - -func (w *textWriter) Write(p []byte) (n int, err error) { - newlines := bytes.Count(p, newline) - if newlines == 0 { - if !w.compact && w.complete { - w.writeIndent() - } - n, err = w.w.Write(p) - w.complete = false - return n, err - } - - frags := bytes.SplitN(p, newline, newlines+1) - if w.compact { - for i, frag := range frags { - if i > 0 { - if err := w.w.WriteByte(' '); err != nil { - return n, err - } - n++ - } - nn, err := w.w.Write(frag) - n += nn - if err != nil { - return n, err - } - } - return n, nil - } - - for i, frag := range frags { - if w.complete { - w.writeIndent() - } - nn, err := w.w.Write(frag) - n += nn - if err != nil { - return n, err - } - if i+1 < len(frags) { - if err := w.w.WriteByte('\n'); err != nil { - return n, err - } - n++ - } - } - w.complete = len(frags[len(frags)-1]) == 0 - return n, nil -} - -func (w *textWriter) WriteByte(c byte) error { - if w.compact && c == '\n' { - c = ' ' - } - if !w.compact && w.complete { - w.writeIndent() - } - err := w.w.WriteByte(c) - w.complete = c == '\n' - return err -} - -func (w *textWriter) indent() { w.ind++ } - -func (w *textWriter) unindent() { - if w.ind == 0 { - log.Print("proto: textWriter unindented too far") - return - } - w.ind-- -} - -func writeName(w *textWriter, props *Properties) error { - if _, err := w.WriteString(props.OrigName); err != nil { - return err - } - if props.Wire != "group" { - return w.WriteByte(':') - } - return nil -} - -func requiresQuotes(u string) bool { - // When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted. - for _, ch := range u { - switch { - case ch == '.' || ch == '/' || ch == '_': - continue - case '0' <= ch && ch <= '9': - continue - case 'A' <= ch && ch <= 'Z': - continue - case 'a' <= ch && ch <= 'z': - continue - default: - return true - } - } - return false -} - -// isAny reports whether sv is a google.protobuf.Any message -func isAny(sv reflect.Value) bool { - type wkt interface { - XXX_WellKnownType() string - } - t, ok := sv.Addr().Interface().(wkt) - return ok && t.XXX_WellKnownType() == "Any" -} - -// writeProto3Any writes an expanded google.protobuf.Any message. -// -// It returns (false, nil) if sv value can't be unmarshaled (e.g. because -// required messages are not linked in). -// -// It returns (true, error) when sv was written in expanded format or an error -// was encountered. -func (tm *TextMarshaler) writeProto3Any(w *textWriter, sv reflect.Value) (bool, error) { - turl := sv.FieldByName("TypeUrl") - val := sv.FieldByName("Value") - if !turl.IsValid() || !val.IsValid() { - return true, errors.New("proto: invalid google.protobuf.Any message") - } - - b, ok := val.Interface().([]byte) - if !ok { - return true, errors.New("proto: invalid google.protobuf.Any message") - } - - parts := strings.Split(turl.String(), "/") - mt := MessageType(parts[len(parts)-1]) - if mt == nil { - return false, nil - } - m := reflect.New(mt.Elem()) - if err := Unmarshal(b, m.Interface().(Message)); err != nil { - return false, nil - } - w.Write([]byte("[")) - u := turl.String() - if requiresQuotes(u) { - writeString(w, u) - } else { - w.Write([]byte(u)) - } - if w.compact { - w.Write([]byte("]:<")) - } else { - w.Write([]byte("]: <\n")) - w.ind++ - } - if err := tm.writeStruct(w, m.Elem()); err != nil { - return true, err - } - if w.compact { - w.Write([]byte("> ")) - } else { - w.ind-- - w.Write([]byte(">\n")) - } - return true, nil -} - -func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { - if tm.ExpandAny && isAny(sv) { - if canExpand, err := tm.writeProto3Any(w, sv); canExpand { - return err - } - } - st := sv.Type() - sprops := GetProperties(st) - for i := 0; i < sv.NumField(); i++ { - fv := sv.Field(i) - props := sprops.Prop[i] - name := st.Field(i).Name - - if name == "XXX_NoUnkeyedLiteral" { - continue - } - - if strings.HasPrefix(name, "XXX_") { - // There are two XXX_ fields: - // XXX_unrecognized []byte - // XXX_extensions map[int32]proto.Extension - // The first is handled here; - // the second is handled at the bottom of this function. - if name == "XXX_unrecognized" && !fv.IsNil() { - if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil { - return err - } - } - continue - } - if fv.Kind() == reflect.Ptr && fv.IsNil() { - // Field not filled in. This could be an optional field or - // a required field that wasn't filled in. Either way, there - // isn't anything we can show for it. - continue - } - if fv.Kind() == reflect.Slice && fv.IsNil() { - // Repeated field that is empty, or a bytes field that is unused. - continue - } - - if props.Repeated && fv.Kind() == reflect.Slice { - // Repeated field. - for j := 0; j < fv.Len(); j++ { - if err := writeName(w, props); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte(' '); err != nil { - return err - } - } - v := fv.Index(j) - if v.Kind() == reflect.Ptr && v.IsNil() { - // A nil message in a repeated field is not valid, - // but we can handle that more gracefully than panicking. - if _, err := w.Write([]byte("\n")); err != nil { - return err - } - continue - } - if len(props.Enum) > 0 { - if err := tm.writeEnum(w, v, props); err != nil { - return err - } - } else if err := tm.writeAny(w, v, props); err != nil { - return err - } - if err := w.WriteByte('\n'); err != nil { - return err - } - } - continue - } - if fv.Kind() == reflect.Map { - // Map fields are rendered as a repeated struct with key/value fields. - keys := fv.MapKeys() - sort.Sort(mapKeys(keys)) - for _, key := range keys { - val := fv.MapIndex(key) - if err := writeName(w, props); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte(' '); err != nil { - return err - } - } - // open struct - if err := w.WriteByte('<'); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte('\n'); err != nil { - return err - } - } - w.indent() - // key - if _, err := w.WriteString("key:"); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte(' '); err != nil { - return err - } - } - if err := tm.writeAny(w, key, props.MapKeyProp); err != nil { - return err - } - if err := w.WriteByte('\n'); err != nil { - return err - } - // nil values aren't legal, but we can avoid panicking because of them. - if val.Kind() != reflect.Ptr || !val.IsNil() { - // value - if _, err := w.WriteString("value:"); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte(' '); err != nil { - return err - } - } - if err := tm.writeAny(w, val, props.MapValProp); err != nil { - return err - } - if err := w.WriteByte('\n'); err != nil { - return err - } - } - // close struct - w.unindent() - if err := w.WriteByte('>'); err != nil { - return err - } - if err := w.WriteByte('\n'); err != nil { - return err - } - } - continue - } - if props.proto3 && fv.Kind() == reflect.Slice && fv.Len() == 0 { - // empty bytes field - continue - } - if props.proto3 && fv.Kind() != reflect.Ptr && fv.Kind() != reflect.Slice { - // proto3 non-repeated scalar field; skip if zero value - if isProto3Zero(fv) { - continue - } - } - - if fv.Kind() == reflect.Interface { - // Check if it is a oneof. - if st.Field(i).Tag.Get("protobuf_oneof") != "" { - // fv is nil, or holds a pointer to generated struct. - // That generated struct has exactly one field, - // which has a protobuf struct tag. - if fv.IsNil() { - continue - } - inner := fv.Elem().Elem() // interface -> *T -> T - tag := inner.Type().Field(0).Tag.Get("protobuf") - props = new(Properties) // Overwrite the outer props var, but not its pointee. - props.Parse(tag) - // Write the value in the oneof, not the oneof itself. - fv = inner.Field(0) - - // Special case to cope with malformed messages gracefully: - // If the value in the oneof is a nil pointer, don't panic - // in writeAny. - if fv.Kind() == reflect.Ptr && fv.IsNil() { - // Use errors.New so writeAny won't render quotes. - msg := errors.New("/* nil */") - fv = reflect.ValueOf(&msg).Elem() - } - } - } - - if err := writeName(w, props); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte(' '); err != nil { - return err - } - } - - if len(props.Enum) > 0 { - if err := tm.writeEnum(w, fv, props); err != nil { - return err - } - } else if err := tm.writeAny(w, fv, props); err != nil { - return err - } - - if err := w.WriteByte('\n'); err != nil { - return err - } - } - - // Extensions (the XXX_extensions field). - pv := sv - if pv.CanAddr() { - pv = sv.Addr() - } else { - pv = reflect.New(sv.Type()) - pv.Elem().Set(sv) - } - if _, err := extendable(pv.Interface()); err == nil { - if err := tm.writeExtensions(w, pv); err != nil { - return err - } - } - - return nil -} - -var textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() - -// writeAny writes an arbitrary field. -func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error { - v = reflect.Indirect(v) - - if props != nil { - if len(props.CustomType) > 0 { - custom, ok := v.Interface().(Marshaler) - if ok { - data, err := custom.Marshal() - if err != nil { - return err - } - if err := writeString(w, string(data)); err != nil { - return err - } - return nil - } - } else if len(props.CastType) > 0 { - if _, ok := v.Interface().(interface { - String() string - }); ok { - switch v.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - _, err := fmt.Fprintf(w, "%d", v.Interface()) - return err - } - } - } else if props.StdTime { - t, ok := v.Interface().(time.Time) - if !ok { - return fmt.Errorf("stdtime is not time.Time, but %T", v.Interface()) - } - tproto, err := timestampProto(t) - if err != nil { - return err - } - propsCopy := *props // Make a copy so that this is goroutine-safe - propsCopy.StdTime = false - err = tm.writeAny(w, reflect.ValueOf(tproto), &propsCopy) - return err - } else if props.StdDuration { - d, ok := v.Interface().(time.Duration) - if !ok { - return fmt.Errorf("stdtime is not time.Duration, but %T", v.Interface()) - } - dproto := durationProto(d) - propsCopy := *props // Make a copy so that this is goroutine-safe - propsCopy.StdDuration = false - err := tm.writeAny(w, reflect.ValueOf(dproto), &propsCopy) - return err - } - } - - // Floats have special cases. - if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 { - x := v.Float() - var b []byte - switch { - case math.IsInf(x, 1): - b = posInf - case math.IsInf(x, -1): - b = negInf - case math.IsNaN(x): - b = nan - } - if b != nil { - _, err := w.Write(b) - return err - } - // Other values are handled below. - } - - // We don't attempt to serialise every possible value type; only those - // that can occur in protocol buffers. - switch v.Kind() { - case reflect.Slice: - // Should only be a []byte; repeated fields are handled in writeStruct. - if err := writeString(w, string(v.Bytes())); err != nil { - return err - } - case reflect.String: - if err := writeString(w, v.String()); err != nil { - return err - } - case reflect.Struct: - // Required/optional group/message. - var bra, ket byte = '<', '>' - if props != nil && props.Wire == "group" { - bra, ket = '{', '}' - } - if err := w.WriteByte(bra); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte('\n'); err != nil { - return err - } - } - w.indent() - if v.CanAddr() { - // Calling v.Interface on a struct causes the reflect package to - // copy the entire struct. This is racy with the new Marshaler - // since we atomically update the XXX_sizecache. - // - // Thus, we retrieve a pointer to the struct if possible to avoid - // a race since v.Interface on the pointer doesn't copy the struct. - // - // If v is not addressable, then we are not worried about a race - // since it implies that the binary Marshaler cannot possibly be - // mutating this value. - v = v.Addr() - } - if v.Type().Implements(textMarshalerType) { - text, err := v.Interface().(encoding.TextMarshaler).MarshalText() - if err != nil { - return err - } - if _, err = w.Write(text); err != nil { - return err - } - } else { - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - if err := tm.writeStruct(w, v); err != nil { - return err - } - } - w.unindent() - if err := w.WriteByte(ket); err != nil { - return err - } - default: - _, err := fmt.Fprint(w, v.Interface()) - return err - } - return nil -} - -// equivalent to C's isprint. -func isprint(c byte) bool { - return c >= 0x20 && c < 0x7f -} - -// writeString writes a string in the protocol buffer text format. -// It is similar to strconv.Quote except we don't use Go escape sequences, -// we treat the string as a byte sequence, and we use octal escapes. -// These differences are to maintain interoperability with the other -// languages' implementations of the text format. -func writeString(w *textWriter, s string) error { - // use WriteByte here to get any needed indent - if err := w.WriteByte('"'); err != nil { - return err - } - // Loop over the bytes, not the runes. - for i := 0; i < len(s); i++ { - var err error - // Divergence from C++: we don't escape apostrophes. - // There's no need to escape them, and the C++ parser - // copes with a naked apostrophe. - switch c := s[i]; c { - case '\n': - _, err = w.w.Write(backslashN) - case '\r': - _, err = w.w.Write(backslashR) - case '\t': - _, err = w.w.Write(backslashT) - case '"': - _, err = w.w.Write(backslashDQ) - case '\\': - _, err = w.w.Write(backslashBS) - default: - if isprint(c) { - err = w.w.WriteByte(c) - } else { - _, err = fmt.Fprintf(w.w, "\\%03o", c) - } - } - if err != nil { - return err - } - } - return w.WriteByte('"') -} - -func writeUnknownStruct(w *textWriter, data []byte) (err error) { - if !w.compact { - if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil { - return err - } - } - b := NewBuffer(data) - for b.index < len(b.buf) { - x, err := b.DecodeVarint() - if err != nil { - _, ferr := fmt.Fprintf(w, "/* %v */\n", err) - return ferr - } - wire, tag := x&7, x>>3 - if wire == WireEndGroup { - w.unindent() - if _, werr := w.Write(endBraceNewline); werr != nil { - return werr - } - continue - } - if _, ferr := fmt.Fprint(w, tag); ferr != nil { - return ferr - } - if wire != WireStartGroup { - if err = w.WriteByte(':'); err != nil { - return err - } - } - if !w.compact || wire == WireStartGroup { - if err = w.WriteByte(' '); err != nil { - return err - } - } - switch wire { - case WireBytes: - buf, e := b.DecodeRawBytes(false) - if e == nil { - _, err = fmt.Fprintf(w, "%q", buf) - } else { - _, err = fmt.Fprintf(w, "/* %v */", e) - } - case WireFixed32: - x, err = b.DecodeFixed32() - err = writeUnknownInt(w, x, err) - case WireFixed64: - x, err = b.DecodeFixed64() - err = writeUnknownInt(w, x, err) - case WireStartGroup: - err = w.WriteByte('{') - w.indent() - case WireVarint: - x, err = b.DecodeVarint() - err = writeUnknownInt(w, x, err) - default: - _, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire) - } - if err != nil { - return err - } - if err := w.WriteByte('\n'); err != nil { - return err - } - } - return nil -} - -func writeUnknownInt(w *textWriter, x uint64, err error) error { - if err == nil { - _, err = fmt.Fprint(w, x) - } else { - _, err = fmt.Fprintf(w, "/* %v */", err) - } - return err -} - -type int32Slice []int32 - -func (s int32Slice) Len() int { return len(s) } -func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] } -func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - -// writeExtensions writes all the extensions in pv. -// pv is assumed to be a pointer to a protocol message struct that is extendable. -func (tm *TextMarshaler) writeExtensions(w *textWriter, pv reflect.Value) error { - emap := extensionMaps[pv.Type().Elem()] - e := pv.Interface().(Message) - - var m map[int32]Extension - var mu sync.Locker - if em, ok := e.(extensionsBytes); ok { - eb := em.GetExtensions() - var err error - m, err = BytesToExtensionsMap(*eb) - if err != nil { - return err - } - mu = notLocker{} - } else if _, ok := e.(extendableProto); ok { - ep, _ := extendable(e) - m, mu = ep.extensionsRead() - if m == nil { - return nil - } - } - - // Order the extensions by ID. - // This isn't strictly necessary, but it will give us - // canonical output, which will also make testing easier. - - mu.Lock() - ids := make([]int32, 0, len(m)) - for id := range m { - ids = append(ids, id) - } - sort.Sort(int32Slice(ids)) - mu.Unlock() - - for _, extNum := range ids { - ext := m[extNum] - var desc *ExtensionDesc - if emap != nil { - desc = emap[extNum] - } - if desc == nil { - // Unknown extension. - if err := writeUnknownStruct(w, ext.enc); err != nil { - return err - } - continue - } - - pb, err := GetExtension(e, desc) - if err != nil { - return fmt.Errorf("failed getting extension: %v", err) - } - - // Repeated extensions will appear as a slice. - if !desc.repeated() { - if err := tm.writeExtension(w, desc.Name, pb); err != nil { - return err - } - } else { - v := reflect.ValueOf(pb) - for i := 0; i < v.Len(); i++ { - if err := tm.writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil { - return err - } - } - } - } - return nil -} - -func (tm *TextMarshaler) writeExtension(w *textWriter, name string, pb interface{}) error { - if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil { - return err - } - if !w.compact { - if err := w.WriteByte(' '); err != nil { - return err - } - } - if err := tm.writeAny(w, reflect.ValueOf(pb), nil); err != nil { - return err - } - if err := w.WriteByte('\n'); err != nil { - return err - } - return nil -} - -func (w *textWriter) writeIndent() { - if !w.complete { - return - } - remain := w.ind * 2 - for remain > 0 { - n := remain - if n > len(spaces) { - n = len(spaces) - } - w.w.Write(spaces[:n]) - remain -= n - } - w.complete = false -} - -// TextMarshaler is a configurable text format marshaler. -type TextMarshaler struct { - Compact bool // use compact text format (one line). - ExpandAny bool // expand google.protobuf.Any messages of known types -} - -// Marshal writes a given protocol buffer in text format. -// The only errors returned are from w. -func (tm *TextMarshaler) Marshal(w io.Writer, pb Message) error { - val := reflect.ValueOf(pb) - if pb == nil || val.IsNil() { - w.Write([]byte("")) - return nil - } - var bw *bufio.Writer - ww, ok := w.(writer) - if !ok { - bw = bufio.NewWriter(w) - ww = bw - } - aw := &textWriter{ - w: ww, - complete: true, - compact: tm.Compact, - } - - if etm, ok := pb.(encoding.TextMarshaler); ok { - text, err := etm.MarshalText() - if err != nil { - return err - } - if _, err = aw.Write(text); err != nil { - return err - } - if bw != nil { - return bw.Flush() - } - return nil - } - // Dereference the received pointer so we don't have outer < and >. - v := reflect.Indirect(val) - if err := tm.writeStruct(aw, v); err != nil { - return err - } - if bw != nil { - return bw.Flush() - } - return nil -} - -// Text is the same as Marshal, but returns the string directly. -func (tm *TextMarshaler) Text(pb Message) string { - var buf bytes.Buffer - tm.Marshal(&buf, pb) - return buf.String() -} - -var ( - defaultTextMarshaler = TextMarshaler{} - compactTextMarshaler = TextMarshaler{Compact: true} -) - -// TODO: consider removing some of the Marshal functions below. - -// MarshalText writes a given protocol buffer in text format. -// The only errors returned are from w. -func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) } - -// MarshalTextString is the same as MarshalText, but returns the string directly. -func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) } - -// CompactText writes a given protocol buffer in compact text format (one line). -func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) } - -// CompactTextString is the same as CompactText, but returns the string directly. -func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) } diff --git a/vendor/github.com/gogo/protobuf/proto/text_gogo.go b/vendor/github.com/gogo/protobuf/proto/text_gogo.go deleted file mode 100644 index 1d6c6aa0e..000000000 --- a/vendor/github.com/gogo/protobuf/proto/text_gogo.go +++ /dev/null @@ -1,57 +0,0 @@ -// Protocol Buffers for Go with Gadgets -// -// Copyright (c) 2013, The GoGo Authors. All rights reserved. -// http://github.com/gogo/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -import ( - "fmt" - "reflect" -) - -func (tm *TextMarshaler) writeEnum(w *textWriter, v reflect.Value, props *Properties) error { - m, ok := enumStringMaps[props.Enum] - if !ok { - if err := tm.writeAny(w, v, props); err != nil { - return err - } - } - key := int32(0) - if v.Kind() == reflect.Ptr { - key = int32(v.Elem().Int()) - } else { - key = int32(v.Int()) - } - s, ok := m[key] - if !ok { - if err := tm.writeAny(w, v, props); err != nil { - return err - } - } - _, err := fmt.Fprint(w, s) - return err -} diff --git a/vendor/github.com/gogo/protobuf/proto/text_parser.go b/vendor/github.com/gogo/protobuf/proto/text_parser.go deleted file mode 100644 index f85c0cc81..000000000 --- a/vendor/github.com/gogo/protobuf/proto/text_parser.go +++ /dev/null @@ -1,1018 +0,0 @@ -// Protocol Buffers for Go with Gadgets -// -// Copyright (c) 2013, The GoGo Authors. All rights reserved. -// http://github.com/gogo/protobuf -// -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -// Functions for parsing the Text protocol buffer format. -// TODO: message sets. - -import ( - "encoding" - "errors" - "fmt" - "reflect" - "strconv" - "strings" - "time" - "unicode/utf8" -) - -// Error string emitted when deserializing Any and fields are already set -const anyRepeatedlyUnpacked = "Any message unpacked multiple times, or %q already set" - -type ParseError struct { - Message string - Line int // 1-based line number - Offset int // 0-based byte offset from start of input -} - -func (p *ParseError) Error() string { - if p.Line == 1 { - // show offset only for first line - return fmt.Sprintf("line 1.%d: %v", p.Offset, p.Message) - } - return fmt.Sprintf("line %d: %v", p.Line, p.Message) -} - -type token struct { - value string - err *ParseError - line int // line number - offset int // byte number from start of input, not start of line - unquoted string // the unquoted version of value, if it was a quoted string -} - -func (t *token) String() string { - if t.err == nil { - return fmt.Sprintf("%q (line=%d, offset=%d)", t.value, t.line, t.offset) - } - return fmt.Sprintf("parse error: %v", t.err) -} - -type textParser struct { - s string // remaining input - done bool // whether the parsing is finished (success or error) - backed bool // whether back() was called - offset, line int - cur token -} - -func newTextParser(s string) *textParser { - p := new(textParser) - p.s = s - p.line = 1 - p.cur.line = 1 - return p -} - -func (p *textParser) errorf(format string, a ...interface{}) *ParseError { - pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset} - p.cur.err = pe - p.done = true - return pe -} - -// Numbers and identifiers are matched by [-+._A-Za-z0-9] -func isIdentOrNumberChar(c byte) bool { - switch { - case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z': - return true - case '0' <= c && c <= '9': - return true - } - switch c { - case '-', '+', '.', '_': - return true - } - return false -} - -func isWhitespace(c byte) bool { - switch c { - case ' ', '\t', '\n', '\r': - return true - } - return false -} - -func isQuote(c byte) bool { - switch c { - case '"', '\'': - return true - } - return false -} - -func (p *textParser) skipWhitespace() { - i := 0 - for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') { - if p.s[i] == '#' { - // comment; skip to end of line or input - for i < len(p.s) && p.s[i] != '\n' { - i++ - } - if i == len(p.s) { - break - } - } - if p.s[i] == '\n' { - p.line++ - } - i++ - } - p.offset += i - p.s = p.s[i:len(p.s)] - if len(p.s) == 0 { - p.done = true - } -} - -func (p *textParser) advance() { - // Skip whitespace - p.skipWhitespace() - if p.done { - return - } - - // Start of non-whitespace - p.cur.err = nil - p.cur.offset, p.cur.line = p.offset, p.line - p.cur.unquoted = "" - switch p.s[0] { - case '<', '>', '{', '}', ':', '[', ']', ';', ',', '/': - // Single symbol - p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)] - case '"', '\'': - // Quoted string - i := 1 - for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' { - if p.s[i] == '\\' && i+1 < len(p.s) { - // skip escaped char - i++ - } - i++ - } - if i >= len(p.s) || p.s[i] != p.s[0] { - p.errorf("unmatched quote") - return - } - unq, err := unquoteC(p.s[1:i], rune(p.s[0])) - if err != nil { - p.errorf("invalid quoted string %s: %v", p.s[0:i+1], err) - return - } - p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)] - p.cur.unquoted = unq - default: - i := 0 - for i < len(p.s) && isIdentOrNumberChar(p.s[i]) { - i++ - } - if i == 0 { - p.errorf("unexpected byte %#x", p.s[0]) - return - } - p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)] - } - p.offset += len(p.cur.value) -} - -var ( - errBadUTF8 = errors.New("proto: bad UTF-8") -) - -func unquoteC(s string, quote rune) (string, error) { - // This is based on C++'s tokenizer.cc. - // Despite its name, this is *not* parsing C syntax. - // For instance, "\0" is an invalid quoted string. - - // Avoid allocation in trivial cases. - simple := true - for _, r := range s { - if r == '\\' || r == quote { - simple = false - break - } - } - if simple { - return s, nil - } - - buf := make([]byte, 0, 3*len(s)/2) - for len(s) > 0 { - r, n := utf8.DecodeRuneInString(s) - if r == utf8.RuneError && n == 1 { - return "", errBadUTF8 - } - s = s[n:] - if r != '\\' { - if r < utf8.RuneSelf { - buf = append(buf, byte(r)) - } else { - buf = append(buf, string(r)...) - } - continue - } - - ch, tail, err := unescape(s) - if err != nil { - return "", err - } - buf = append(buf, ch...) - s = tail - } - return string(buf), nil -} - -func unescape(s string) (ch string, tail string, err error) { - r, n := utf8.DecodeRuneInString(s) - if r == utf8.RuneError && n == 1 { - return "", "", errBadUTF8 - } - s = s[n:] - switch r { - case 'a': - return "\a", s, nil - case 'b': - return "\b", s, nil - case 'f': - return "\f", s, nil - case 'n': - return "\n", s, nil - case 'r': - return "\r", s, nil - case 't': - return "\t", s, nil - case 'v': - return "\v", s, nil - case '?': - return "?", s, nil // trigraph workaround - case '\'', '"', '\\': - return string(r), s, nil - case '0', '1', '2', '3', '4', '5', '6', '7': - if len(s) < 2 { - return "", "", fmt.Errorf(`\%c requires 2 following digits`, r) - } - ss := string(r) + s[:2] - s = s[2:] - i, err := strconv.ParseUint(ss, 8, 8) - if err != nil { - return "", "", fmt.Errorf(`\%s contains non-octal digits`, ss) - } - return string([]byte{byte(i)}), s, nil - case 'x', 'X', 'u', 'U': - var n int - switch r { - case 'x', 'X': - n = 2 - case 'u': - n = 4 - case 'U': - n = 8 - } - if len(s) < n { - return "", "", fmt.Errorf(`\%c requires %d following digits`, r, n) - } - ss := s[:n] - s = s[n:] - i, err := strconv.ParseUint(ss, 16, 64) - if err != nil { - return "", "", fmt.Errorf(`\%c%s contains non-hexadecimal digits`, r, ss) - } - if r == 'x' || r == 'X' { - return string([]byte{byte(i)}), s, nil - } - if i > utf8.MaxRune { - return "", "", fmt.Errorf(`\%c%s is not a valid Unicode code point`, r, ss) - } - return string(rune(i)), s, nil - } - return "", "", fmt.Errorf(`unknown escape \%c`, r) -} - -// Back off the parser by one token. Can only be done between calls to next(). -// It makes the next advance() a no-op. -func (p *textParser) back() { p.backed = true } - -// Advances the parser and returns the new current token. -func (p *textParser) next() *token { - if p.backed || p.done { - p.backed = false - return &p.cur - } - p.advance() - if p.done { - p.cur.value = "" - } else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) { - // Look for multiple quoted strings separated by whitespace, - // and concatenate them. - cat := p.cur - for { - p.skipWhitespace() - if p.done || !isQuote(p.s[0]) { - break - } - p.advance() - if p.cur.err != nil { - return &p.cur - } - cat.value += " " + p.cur.value - cat.unquoted += p.cur.unquoted - } - p.done = false // parser may have seen EOF, but we want to return cat - p.cur = cat - } - return &p.cur -} - -func (p *textParser) consumeToken(s string) error { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value != s { - p.back() - return p.errorf("expected %q, found %q", s, tok.value) - } - return nil -} - -// Return a RequiredNotSetError indicating which required field was not set. -func (p *textParser) missingRequiredFieldError(sv reflect.Value) *RequiredNotSetError { - st := sv.Type() - sprops := GetProperties(st) - for i := 0; i < st.NumField(); i++ { - if !isNil(sv.Field(i)) { - continue - } - - props := sprops.Prop[i] - if props.Required { - return &RequiredNotSetError{fmt.Sprintf("%v.%v", st, props.OrigName)} - } - } - return &RequiredNotSetError{fmt.Sprintf("%v.", st)} // should not happen -} - -// Returns the index in the struct for the named field, as well as the parsed tag properties. -func structFieldByName(sprops *StructProperties, name string) (int, *Properties, bool) { - i, ok := sprops.decoderOrigNames[name] - if ok { - return i, sprops.Prop[i], true - } - return -1, nil, false -} - -// Consume a ':' from the input stream (if the next token is a colon), -// returning an error if a colon is needed but not present. -func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseError { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value != ":" { - // Colon is optional when the field is a group or message. - needColon := true - switch props.Wire { - case "group": - needColon = false - case "bytes": - // A "bytes" field is either a message, a string, or a repeated field; - // those three become *T, *string and []T respectively, so we can check for - // this field being a pointer to a non-string. - if typ.Kind() == reflect.Ptr { - // *T or *string - if typ.Elem().Kind() == reflect.String { - break - } - } else if typ.Kind() == reflect.Slice { - // []T or []*T - if typ.Elem().Kind() != reflect.Ptr { - break - } - } else if typ.Kind() == reflect.String { - // The proto3 exception is for a string field, - // which requires a colon. - break - } - needColon = false - } - if needColon { - return p.errorf("expected ':', found %q", tok.value) - } - p.back() - } - return nil -} - -func (p *textParser) readStruct(sv reflect.Value, terminator string) error { - st := sv.Type() - sprops := GetProperties(st) - reqCount := sprops.reqCount - var reqFieldErr error - fieldSet := make(map[string]bool) - // A struct is a sequence of "name: value", terminated by one of - // '>' or '}', or the end of the input. A name may also be - // "[extension]" or "[type/url]". - // - // The whole struct can also be an expanded Any message, like: - // [type/url] < ... struct contents ... > - for { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value == terminator { - break - } - if tok.value == "[" { - // Looks like an extension or an Any. - // - // TODO: Check whether we need to handle - // namespace rooted names (e.g. ".something.Foo"). - extName, err := p.consumeExtName() - if err != nil { - return err - } - - if s := strings.LastIndex(extName, "/"); s >= 0 { - // If it contains a slash, it's an Any type URL. - messageName := extName[s+1:] - mt := MessageType(messageName) - if mt == nil { - return p.errorf("unrecognized message %q in google.protobuf.Any", messageName) - } - tok = p.next() - if tok.err != nil { - return tok.err - } - // consume an optional colon - if tok.value == ":" { - tok = p.next() - if tok.err != nil { - return tok.err - } - } - var terminator string - switch tok.value { - case "<": - terminator = ">" - case "{": - terminator = "}" - default: - return p.errorf("expected '{' or '<', found %q", tok.value) - } - v := reflect.New(mt.Elem()) - if pe := p.readStruct(v.Elem(), terminator); pe != nil { - return pe - } - b, err := Marshal(v.Interface().(Message)) - if err != nil { - return p.errorf("failed to marshal message of type %q: %v", messageName, err) - } - if fieldSet["type_url"] { - return p.errorf(anyRepeatedlyUnpacked, "type_url") - } - if fieldSet["value"] { - return p.errorf(anyRepeatedlyUnpacked, "value") - } - sv.FieldByName("TypeUrl").SetString(extName) - sv.FieldByName("Value").SetBytes(b) - fieldSet["type_url"] = true - fieldSet["value"] = true - continue - } - - var desc *ExtensionDesc - // This could be faster, but it's functional. - // TODO: Do something smarter than a linear scan. - for _, d := range RegisteredExtensions(reflect.New(st).Interface().(Message)) { - if d.Name == extName { - desc = d - break - } - } - if desc == nil { - return p.errorf("unrecognized extension %q", extName) - } - - props := &Properties{} - props.Parse(desc.Tag) - - typ := reflect.TypeOf(desc.ExtensionType) - if err := p.checkForColon(props, typ); err != nil { - return err - } - - rep := desc.repeated() - - // Read the extension structure, and set it in - // the value we're constructing. - var ext reflect.Value - if !rep { - ext = reflect.New(typ).Elem() - } else { - ext = reflect.New(typ.Elem()).Elem() - } - if err := p.readAny(ext, props); err != nil { - if _, ok := err.(*RequiredNotSetError); !ok { - return err - } - reqFieldErr = err - } - ep := sv.Addr().Interface().(Message) - if !rep { - SetExtension(ep, desc, ext.Interface()) - } else { - old, err := GetExtension(ep, desc) - var sl reflect.Value - if err == nil { - sl = reflect.ValueOf(old) // existing slice - } else { - sl = reflect.MakeSlice(typ, 0, 1) - } - sl = reflect.Append(sl, ext) - SetExtension(ep, desc, sl.Interface()) - } - if err := p.consumeOptionalSeparator(); err != nil { - return err - } - continue - } - - // This is a normal, non-extension field. - name := tok.value - var dst reflect.Value - fi, props, ok := structFieldByName(sprops, name) - if ok { - dst = sv.Field(fi) - } else if oop, ok := sprops.OneofTypes[name]; ok { - // It is a oneof. - props = oop.Prop - nv := reflect.New(oop.Type.Elem()) - dst = nv.Elem().Field(0) - field := sv.Field(oop.Field) - if !field.IsNil() { - return p.errorf("field '%s' would overwrite already parsed oneof '%s'", name, sv.Type().Field(oop.Field).Name) - } - field.Set(nv) - } - if !dst.IsValid() { - return p.errorf("unknown field name %q in %v", name, st) - } - - if dst.Kind() == reflect.Map { - // Consume any colon. - if err := p.checkForColon(props, dst.Type()); err != nil { - return err - } - - // Construct the map if it doesn't already exist. - if dst.IsNil() { - dst.Set(reflect.MakeMap(dst.Type())) - } - key := reflect.New(dst.Type().Key()).Elem() - val := reflect.New(dst.Type().Elem()).Elem() - - // The map entry should be this sequence of tokens: - // < key : KEY value : VALUE > - // However, implementations may omit key or value, and technically - // we should support them in any order. See b/28924776 for a time - // this went wrong. - - tok := p.next() - var terminator string - switch tok.value { - case "<": - terminator = ">" - case "{": - terminator = "}" - default: - return p.errorf("expected '{' or '<', found %q", tok.value) - } - for { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value == terminator { - break - } - switch tok.value { - case "key": - if err := p.consumeToken(":"); err != nil { - return err - } - if err := p.readAny(key, props.MapKeyProp); err != nil { - return err - } - if err := p.consumeOptionalSeparator(); err != nil { - return err - } - case "value": - if err := p.checkForColon(props.MapValProp, dst.Type().Elem()); err != nil { - return err - } - if err := p.readAny(val, props.MapValProp); err != nil { - return err - } - if err := p.consumeOptionalSeparator(); err != nil { - return err - } - default: - p.back() - return p.errorf(`expected "key", "value", or %q, found %q`, terminator, tok.value) - } - } - - dst.SetMapIndex(key, val) - continue - } - - // Check that it's not already set if it's not a repeated field. - if !props.Repeated && fieldSet[name] { - return p.errorf("non-repeated field %q was repeated", name) - } - - if err := p.checkForColon(props, dst.Type()); err != nil { - return err - } - - // Parse into the field. - fieldSet[name] = true - if err := p.readAny(dst, props); err != nil { - if _, ok := err.(*RequiredNotSetError); !ok { - return err - } - reqFieldErr = err - } - if props.Required { - reqCount-- - } - - if err := p.consumeOptionalSeparator(); err != nil { - return err - } - - } - - if reqCount > 0 { - return p.missingRequiredFieldError(sv) - } - return reqFieldErr -} - -// consumeExtName consumes extension name or expanded Any type URL and the -// following ']'. It returns the name or URL consumed. -func (p *textParser) consumeExtName() (string, error) { - tok := p.next() - if tok.err != nil { - return "", tok.err - } - - // If extension name or type url is quoted, it's a single token. - if len(tok.value) > 2 && isQuote(tok.value[0]) && tok.value[len(tok.value)-1] == tok.value[0] { - name, err := unquoteC(tok.value[1:len(tok.value)-1], rune(tok.value[0])) - if err != nil { - return "", err - } - return name, p.consumeToken("]") - } - - // Consume everything up to "]" - var parts []string - for tok.value != "]" { - parts = append(parts, tok.value) - tok = p.next() - if tok.err != nil { - return "", p.errorf("unrecognized type_url or extension name: %s", tok.err) - } - if p.done && tok.value != "]" { - return "", p.errorf("unclosed type_url or extension name") - } - } - return strings.Join(parts, ""), nil -} - -// consumeOptionalSeparator consumes an optional semicolon or comma. -// It is used in readStruct to provide backward compatibility. -func (p *textParser) consumeOptionalSeparator() error { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value != ";" && tok.value != "," { - p.back() - } - return nil -} - -func (p *textParser) readAny(v reflect.Value, props *Properties) error { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value == "" { - return p.errorf("unexpected EOF") - } - if len(props.CustomType) > 0 { - if props.Repeated { - t := reflect.TypeOf(v.Interface()) - if t.Kind() == reflect.Slice { - tc := reflect.TypeOf(new(Marshaler)) - ok := t.Elem().Implements(tc.Elem()) - if ok { - fv := v - flen := fv.Len() - if flen == fv.Cap() { - nav := reflect.MakeSlice(v.Type(), flen, 2*flen+1) - reflect.Copy(nav, fv) - fv.Set(nav) - } - fv.SetLen(flen + 1) - - // Read one. - p.back() - return p.readAny(fv.Index(flen), props) - } - } - } - if reflect.TypeOf(v.Interface()).Kind() == reflect.Ptr { - custom := reflect.New(props.ctype.Elem()).Interface().(Unmarshaler) - err := custom.Unmarshal([]byte(tok.unquoted)) - if err != nil { - return p.errorf("%v %v: %v", err, v.Type(), tok.value) - } - v.Set(reflect.ValueOf(custom)) - } else { - custom := reflect.New(reflect.TypeOf(v.Interface())).Interface().(Unmarshaler) - err := custom.Unmarshal([]byte(tok.unquoted)) - if err != nil { - return p.errorf("%v %v: %v", err, v.Type(), tok.value) - } - v.Set(reflect.Indirect(reflect.ValueOf(custom))) - } - return nil - } - if props.StdTime { - fv := v - p.back() - props.StdTime = false - tproto := ×tamp{} - err := p.readAny(reflect.ValueOf(tproto).Elem(), props) - props.StdTime = true - if err != nil { - return err - } - tim, err := timestampFromProto(tproto) - if err != nil { - return err - } - if props.Repeated { - t := reflect.TypeOf(v.Interface()) - if t.Kind() == reflect.Slice { - if t.Elem().Kind() == reflect.Ptr { - ts := fv.Interface().([]*time.Time) - ts = append(ts, &tim) - fv.Set(reflect.ValueOf(ts)) - return nil - } else { - ts := fv.Interface().([]time.Time) - ts = append(ts, tim) - fv.Set(reflect.ValueOf(ts)) - return nil - } - } - } - if reflect.TypeOf(v.Interface()).Kind() == reflect.Ptr { - v.Set(reflect.ValueOf(&tim)) - } else { - v.Set(reflect.Indirect(reflect.ValueOf(&tim))) - } - return nil - } - if props.StdDuration { - fv := v - p.back() - props.StdDuration = false - dproto := &duration{} - err := p.readAny(reflect.ValueOf(dproto).Elem(), props) - props.StdDuration = true - if err != nil { - return err - } - dur, err := durationFromProto(dproto) - if err != nil { - return err - } - if props.Repeated { - t := reflect.TypeOf(v.Interface()) - if t.Kind() == reflect.Slice { - if t.Elem().Kind() == reflect.Ptr { - ds := fv.Interface().([]*time.Duration) - ds = append(ds, &dur) - fv.Set(reflect.ValueOf(ds)) - return nil - } else { - ds := fv.Interface().([]time.Duration) - ds = append(ds, dur) - fv.Set(reflect.ValueOf(ds)) - return nil - } - } - } - if reflect.TypeOf(v.Interface()).Kind() == reflect.Ptr { - v.Set(reflect.ValueOf(&dur)) - } else { - v.Set(reflect.Indirect(reflect.ValueOf(&dur))) - } - return nil - } - switch fv := v; fv.Kind() { - case reflect.Slice: - at := v.Type() - if at.Elem().Kind() == reflect.Uint8 { - // Special case for []byte - if tok.value[0] != '"' && tok.value[0] != '\'' { - // Deliberately written out here, as the error after - // this switch statement would write "invalid []byte: ...", - // which is not as user-friendly. - return p.errorf("invalid string: %v", tok.value) - } - bytes := []byte(tok.unquoted) - fv.Set(reflect.ValueOf(bytes)) - return nil - } - // Repeated field. - if tok.value == "[" { - // Repeated field with list notation, like [1,2,3]. - for { - fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) - err := p.readAny(fv.Index(fv.Len()-1), props) - if err != nil { - return err - } - ntok := p.next() - if ntok.err != nil { - return ntok.err - } - if ntok.value == "]" { - break - } - if ntok.value != "," { - return p.errorf("Expected ']' or ',' found %q", ntok.value) - } - } - return nil - } - // One value of the repeated field. - p.back() - fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) - return p.readAny(fv.Index(fv.Len()-1), props) - case reflect.Bool: - // true/1/t/True or false/f/0/False. - switch tok.value { - case "true", "1", "t", "True": - fv.SetBool(true) - return nil - case "false", "0", "f", "False": - fv.SetBool(false) - return nil - } - case reflect.Float32, reflect.Float64: - v := tok.value - // Ignore 'f' for compatibility with output generated by C++, but don't - // remove 'f' when the value is "-inf" or "inf". - if strings.HasSuffix(v, "f") && tok.value != "-inf" && tok.value != "inf" { - v = v[:len(v)-1] - } - if f, err := strconv.ParseFloat(v, fv.Type().Bits()); err == nil { - fv.SetFloat(f) - return nil - } - case reflect.Int8: - if x, err := strconv.ParseInt(tok.value, 0, 8); err == nil { - fv.SetInt(x) - return nil - } - case reflect.Int16: - if x, err := strconv.ParseInt(tok.value, 0, 16); err == nil { - fv.SetInt(x) - return nil - } - case reflect.Int32: - if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil { - fv.SetInt(x) - return nil - } - - if len(props.Enum) == 0 { - break - } - m, ok := enumValueMaps[props.Enum] - if !ok { - break - } - x, ok := m[tok.value] - if !ok { - break - } - fv.SetInt(int64(x)) - return nil - case reflect.Int64: - if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil { - fv.SetInt(x) - return nil - } - - case reflect.Ptr: - // A basic field (indirected through pointer), or a repeated message/group - p.back() - fv.Set(reflect.New(fv.Type().Elem())) - return p.readAny(fv.Elem(), props) - case reflect.String: - if tok.value[0] == '"' || tok.value[0] == '\'' { - fv.SetString(tok.unquoted) - return nil - } - case reflect.Struct: - var terminator string - switch tok.value { - case "{": - terminator = "}" - case "<": - terminator = ">" - default: - return p.errorf("expected '{' or '<', found %q", tok.value) - } - // TODO: Handle nested messages which implement encoding.TextUnmarshaler. - return p.readStruct(fv, terminator) - case reflect.Uint8: - if x, err := strconv.ParseUint(tok.value, 0, 8); err == nil { - fv.SetUint(x) - return nil - } - case reflect.Uint16: - if x, err := strconv.ParseUint(tok.value, 0, 16); err == nil { - fv.SetUint(x) - return nil - } - case reflect.Uint32: - if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil { - fv.SetUint(uint64(x)) - return nil - } - case reflect.Uint64: - if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil { - fv.SetUint(x) - return nil - } - } - return p.errorf("invalid %v: %v", v.Type(), tok.value) -} - -// UnmarshalText reads a protocol buffer in Text format. UnmarshalText resets pb -// before starting to unmarshal, so any existing data in pb is always removed. -// If a required field is not set and no other error occurs, -// UnmarshalText returns *RequiredNotSetError. -func UnmarshalText(s string, pb Message) error { - if um, ok := pb.(encoding.TextUnmarshaler); ok { - return um.UnmarshalText([]byte(s)) - } - pb.Reset() - v := reflect.ValueOf(pb) - return newTextParser(s).readStruct(v.Elem(), "") -} diff --git a/vendor/github.com/gogo/protobuf/proto/timestamp.go b/vendor/github.com/gogo/protobuf/proto/timestamp.go deleted file mode 100644 index 9324f6542..000000000 --- a/vendor/github.com/gogo/protobuf/proto/timestamp.go +++ /dev/null @@ -1,113 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2016 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -// This file implements operations on google.protobuf.Timestamp. - -import ( - "errors" - "fmt" - "time" -) - -const ( - // Seconds field of the earliest valid Timestamp. - // This is time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC).Unix(). - minValidSeconds = -62135596800 - // Seconds field just after the latest valid Timestamp. - // This is time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC).Unix(). - maxValidSeconds = 253402300800 -) - -// validateTimestamp determines whether a Timestamp is valid. -// A valid timestamp represents a time in the range -// [0001-01-01, 10000-01-01) and has a Nanos field -// in the range [0, 1e9). -// -// If the Timestamp is valid, validateTimestamp returns nil. -// Otherwise, it returns an error that describes -// the problem. -// -// Every valid Timestamp can be represented by a time.Time, but the converse is not true. -func validateTimestamp(ts *timestamp) error { - if ts == nil { - return errors.New("timestamp: nil Timestamp") - } - if ts.Seconds < minValidSeconds { - return fmt.Errorf("timestamp: %#v before 0001-01-01", ts) - } - if ts.Seconds >= maxValidSeconds { - return fmt.Errorf("timestamp: %#v after 10000-01-01", ts) - } - if ts.Nanos < 0 || ts.Nanos >= 1e9 { - return fmt.Errorf("timestamp: %#v: nanos not in range [0, 1e9)", ts) - } - return nil -} - -// TimestampFromProto converts a google.protobuf.Timestamp proto to a time.Time. -// It returns an error if the argument is invalid. -// -// Unlike most Go functions, if Timestamp returns an error, the first return value -// is not the zero time.Time. Instead, it is the value obtained from the -// time.Unix function when passed the contents of the Timestamp, in the UTC -// locale. This may or may not be a meaningful time; many invalid Timestamps -// do map to valid time.Times. -// -// A nil Timestamp returns an error. The first return value in that case is -// undefined. -func timestampFromProto(ts *timestamp) (time.Time, error) { - // Don't return the zero value on error, because corresponds to a valid - // timestamp. Instead return whatever time.Unix gives us. - var t time.Time - if ts == nil { - t = time.Unix(0, 0).UTC() // treat nil like the empty Timestamp - } else { - t = time.Unix(ts.Seconds, int64(ts.Nanos)).UTC() - } - return t, validateTimestamp(ts) -} - -// TimestampProto converts the time.Time to a google.protobuf.Timestamp proto. -// It returns an error if the resulting Timestamp is invalid. -func timestampProto(t time.Time) (*timestamp, error) { - seconds := t.Unix() - nanos := int32(t.Sub(time.Unix(seconds, 0))) - ts := ×tamp{ - Seconds: seconds, - Nanos: nanos, - } - if err := validateTimestamp(ts); err != nil { - return nil, err - } - return ts, nil -} diff --git a/vendor/github.com/gogo/protobuf/proto/timestamp_gogo.go b/vendor/github.com/gogo/protobuf/proto/timestamp_gogo.go deleted file mode 100644 index 38439fa99..000000000 --- a/vendor/github.com/gogo/protobuf/proto/timestamp_gogo.go +++ /dev/null @@ -1,49 +0,0 @@ -// Protocol Buffers for Go with Gadgets -// -// Copyright (c) 2016, The GoGo Authors. All rights reserved. -// http://github.com/gogo/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -import ( - "reflect" - "time" -) - -var timeType = reflect.TypeOf((*time.Time)(nil)).Elem() - -type timestamp struct { - Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"` - Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"` -} - -func (m *timestamp) Reset() { *m = timestamp{} } -func (*timestamp) ProtoMessage() {} -func (*timestamp) String() string { return "timestamp" } - -func init() { - RegisterType((*timestamp)(nil), "gogo.protobuf.proto.timestamp") -} diff --git a/vendor/github.com/gogo/protobuf/proto/wrappers.go b/vendor/github.com/gogo/protobuf/proto/wrappers.go deleted file mode 100644 index b175d1b64..000000000 --- a/vendor/github.com/gogo/protobuf/proto/wrappers.go +++ /dev/null @@ -1,1888 +0,0 @@ -// Protocol Buffers for Go with Gadgets -// -// Copyright (c) 2018, The GoGo Authors. All rights reserved. -// http://github.com/gogo/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -import ( - "io" - "reflect" -) - -func makeStdDoubleValueMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - t := ptr.asPointerTo(u.typ).Interface().(*float64) - v := &float64Value{*t} - siz := Size(v) - return tagsize + SizeVarint(uint64(siz)) + siz - }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - t := ptr.asPointerTo(u.typ).Interface().(*float64) - v := &float64Value{*t} - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(buf))) - b = append(b, buf...) - return b, nil - } -} - -func makeStdDoubleValuePtrMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - if ptr.isNil() { - return 0 - } - t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*float64) - v := &float64Value{*t} - siz := Size(v) - return tagsize + SizeVarint(uint64(siz)) + siz - }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - if ptr.isNil() { - return b, nil - } - t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*float64) - v := &float64Value{*t} - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(buf))) - b = append(b, buf...) - return b, nil - } -} - -func makeStdDoubleValueSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getSlice(u.typ) - n := 0 - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(float64) - v := &float64Value{t} - siz := Size(v) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getSlice(u.typ) - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(float64) - v := &float64Value{t} - siz := Size(v) - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(siz)) - b = append(b, buf...) - } - - return b, nil - } -} - -func makeStdDoubleValuePtrSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getSlice(reflect.PtrTo(u.typ)) - n := 0 - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(*float64) - v := &float64Value{*t} - siz := Size(v) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getSlice(reflect.PtrTo(u.typ)) - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(*float64) - v := &float64Value{*t} - siz := Size(v) - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(siz)) - b = append(b, buf...) - } - - return b, nil - } -} - -func makeStdDoubleValueUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &float64Value{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - s := f.asPointerTo(sub.typ).Elem() - s.Set(reflect.ValueOf(m.Value)) - return b[x:], nil - } -} - -func makeStdDoubleValuePtrUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &float64Value{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - s := f.asPointerTo(reflect.PtrTo(sub.typ)).Elem() - s.Set(reflect.ValueOf(&m.Value)) - return b[x:], nil - } -} - -func makeStdDoubleValuePtrSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &float64Value{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - slice := f.getSlice(reflect.PtrTo(sub.typ)) - newSlice := reflect.Append(slice, reflect.ValueOf(&m.Value)) - slice.Set(newSlice) - return b[x:], nil - } -} - -func makeStdDoubleValueSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &float64Value{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - slice := f.getSlice(sub.typ) - newSlice := reflect.Append(slice, reflect.ValueOf(m.Value)) - slice.Set(newSlice) - return b[x:], nil - } -} - -func makeStdFloatValueMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - t := ptr.asPointerTo(u.typ).Interface().(*float32) - v := &float32Value{*t} - siz := Size(v) - return tagsize + SizeVarint(uint64(siz)) + siz - }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - t := ptr.asPointerTo(u.typ).Interface().(*float32) - v := &float32Value{*t} - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(buf))) - b = append(b, buf...) - return b, nil - } -} - -func makeStdFloatValuePtrMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - if ptr.isNil() { - return 0 - } - t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*float32) - v := &float32Value{*t} - siz := Size(v) - return tagsize + SizeVarint(uint64(siz)) + siz - }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - if ptr.isNil() { - return b, nil - } - t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*float32) - v := &float32Value{*t} - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(buf))) - b = append(b, buf...) - return b, nil - } -} - -func makeStdFloatValueSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getSlice(u.typ) - n := 0 - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(float32) - v := &float32Value{t} - siz := Size(v) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getSlice(u.typ) - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(float32) - v := &float32Value{t} - siz := Size(v) - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(siz)) - b = append(b, buf...) - } - - return b, nil - } -} - -func makeStdFloatValuePtrSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getSlice(reflect.PtrTo(u.typ)) - n := 0 - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(*float32) - v := &float32Value{*t} - siz := Size(v) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getSlice(reflect.PtrTo(u.typ)) - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(*float32) - v := &float32Value{*t} - siz := Size(v) - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(siz)) - b = append(b, buf...) - } - - return b, nil - } -} - -func makeStdFloatValueUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &float32Value{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - s := f.asPointerTo(sub.typ).Elem() - s.Set(reflect.ValueOf(m.Value)) - return b[x:], nil - } -} - -func makeStdFloatValuePtrUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &float32Value{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - s := f.asPointerTo(reflect.PtrTo(sub.typ)).Elem() - s.Set(reflect.ValueOf(&m.Value)) - return b[x:], nil - } -} - -func makeStdFloatValuePtrSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &float32Value{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - slice := f.getSlice(reflect.PtrTo(sub.typ)) - newSlice := reflect.Append(slice, reflect.ValueOf(&m.Value)) - slice.Set(newSlice) - return b[x:], nil - } -} - -func makeStdFloatValueSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &float32Value{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - slice := f.getSlice(sub.typ) - newSlice := reflect.Append(slice, reflect.ValueOf(m.Value)) - slice.Set(newSlice) - return b[x:], nil - } -} - -func makeStdInt64ValueMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - t := ptr.asPointerTo(u.typ).Interface().(*int64) - v := &int64Value{*t} - siz := Size(v) - return tagsize + SizeVarint(uint64(siz)) + siz - }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - t := ptr.asPointerTo(u.typ).Interface().(*int64) - v := &int64Value{*t} - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(buf))) - b = append(b, buf...) - return b, nil - } -} - -func makeStdInt64ValuePtrMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - if ptr.isNil() { - return 0 - } - t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*int64) - v := &int64Value{*t} - siz := Size(v) - return tagsize + SizeVarint(uint64(siz)) + siz - }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - if ptr.isNil() { - return b, nil - } - t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*int64) - v := &int64Value{*t} - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(buf))) - b = append(b, buf...) - return b, nil - } -} - -func makeStdInt64ValueSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getSlice(u.typ) - n := 0 - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(int64) - v := &int64Value{t} - siz := Size(v) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getSlice(u.typ) - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(int64) - v := &int64Value{t} - siz := Size(v) - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(siz)) - b = append(b, buf...) - } - - return b, nil - } -} - -func makeStdInt64ValuePtrSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getSlice(reflect.PtrTo(u.typ)) - n := 0 - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(*int64) - v := &int64Value{*t} - siz := Size(v) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getSlice(reflect.PtrTo(u.typ)) - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(*int64) - v := &int64Value{*t} - siz := Size(v) - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(siz)) - b = append(b, buf...) - } - - return b, nil - } -} - -func makeStdInt64ValueUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &int64Value{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - s := f.asPointerTo(sub.typ).Elem() - s.Set(reflect.ValueOf(m.Value)) - return b[x:], nil - } -} - -func makeStdInt64ValuePtrUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &int64Value{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - s := f.asPointerTo(reflect.PtrTo(sub.typ)).Elem() - s.Set(reflect.ValueOf(&m.Value)) - return b[x:], nil - } -} - -func makeStdInt64ValuePtrSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &int64Value{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - slice := f.getSlice(reflect.PtrTo(sub.typ)) - newSlice := reflect.Append(slice, reflect.ValueOf(&m.Value)) - slice.Set(newSlice) - return b[x:], nil - } -} - -func makeStdInt64ValueSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &int64Value{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - slice := f.getSlice(sub.typ) - newSlice := reflect.Append(slice, reflect.ValueOf(m.Value)) - slice.Set(newSlice) - return b[x:], nil - } -} - -func makeStdUInt64ValueMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - t := ptr.asPointerTo(u.typ).Interface().(*uint64) - v := &uint64Value{*t} - siz := Size(v) - return tagsize + SizeVarint(uint64(siz)) + siz - }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - t := ptr.asPointerTo(u.typ).Interface().(*uint64) - v := &uint64Value{*t} - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(buf))) - b = append(b, buf...) - return b, nil - } -} - -func makeStdUInt64ValuePtrMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - if ptr.isNil() { - return 0 - } - t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*uint64) - v := &uint64Value{*t} - siz := Size(v) - return tagsize + SizeVarint(uint64(siz)) + siz - }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - if ptr.isNil() { - return b, nil - } - t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*uint64) - v := &uint64Value{*t} - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(buf))) - b = append(b, buf...) - return b, nil - } -} - -func makeStdUInt64ValueSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getSlice(u.typ) - n := 0 - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(uint64) - v := &uint64Value{t} - siz := Size(v) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getSlice(u.typ) - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(uint64) - v := &uint64Value{t} - siz := Size(v) - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(siz)) - b = append(b, buf...) - } - - return b, nil - } -} - -func makeStdUInt64ValuePtrSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getSlice(reflect.PtrTo(u.typ)) - n := 0 - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(*uint64) - v := &uint64Value{*t} - siz := Size(v) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getSlice(reflect.PtrTo(u.typ)) - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(*uint64) - v := &uint64Value{*t} - siz := Size(v) - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(siz)) - b = append(b, buf...) - } - - return b, nil - } -} - -func makeStdUInt64ValueUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &uint64Value{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - s := f.asPointerTo(sub.typ).Elem() - s.Set(reflect.ValueOf(m.Value)) - return b[x:], nil - } -} - -func makeStdUInt64ValuePtrUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &uint64Value{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - s := f.asPointerTo(reflect.PtrTo(sub.typ)).Elem() - s.Set(reflect.ValueOf(&m.Value)) - return b[x:], nil - } -} - -func makeStdUInt64ValuePtrSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &uint64Value{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - slice := f.getSlice(reflect.PtrTo(sub.typ)) - newSlice := reflect.Append(slice, reflect.ValueOf(&m.Value)) - slice.Set(newSlice) - return b[x:], nil - } -} - -func makeStdUInt64ValueSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &uint64Value{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - slice := f.getSlice(sub.typ) - newSlice := reflect.Append(slice, reflect.ValueOf(m.Value)) - slice.Set(newSlice) - return b[x:], nil - } -} - -func makeStdInt32ValueMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - t := ptr.asPointerTo(u.typ).Interface().(*int32) - v := &int32Value{*t} - siz := Size(v) - return tagsize + SizeVarint(uint64(siz)) + siz - }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - t := ptr.asPointerTo(u.typ).Interface().(*int32) - v := &int32Value{*t} - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(buf))) - b = append(b, buf...) - return b, nil - } -} - -func makeStdInt32ValuePtrMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - if ptr.isNil() { - return 0 - } - t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*int32) - v := &int32Value{*t} - siz := Size(v) - return tagsize + SizeVarint(uint64(siz)) + siz - }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - if ptr.isNil() { - return b, nil - } - t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*int32) - v := &int32Value{*t} - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(buf))) - b = append(b, buf...) - return b, nil - } -} - -func makeStdInt32ValueSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getSlice(u.typ) - n := 0 - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(int32) - v := &int32Value{t} - siz := Size(v) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getSlice(u.typ) - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(int32) - v := &int32Value{t} - siz := Size(v) - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(siz)) - b = append(b, buf...) - } - - return b, nil - } -} - -func makeStdInt32ValuePtrSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getSlice(reflect.PtrTo(u.typ)) - n := 0 - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(*int32) - v := &int32Value{*t} - siz := Size(v) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getSlice(reflect.PtrTo(u.typ)) - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(*int32) - v := &int32Value{*t} - siz := Size(v) - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(siz)) - b = append(b, buf...) - } - - return b, nil - } -} - -func makeStdInt32ValueUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &int32Value{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - s := f.asPointerTo(sub.typ).Elem() - s.Set(reflect.ValueOf(m.Value)) - return b[x:], nil - } -} - -func makeStdInt32ValuePtrUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &int32Value{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - s := f.asPointerTo(reflect.PtrTo(sub.typ)).Elem() - s.Set(reflect.ValueOf(&m.Value)) - return b[x:], nil - } -} - -func makeStdInt32ValuePtrSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &int32Value{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - slice := f.getSlice(reflect.PtrTo(sub.typ)) - newSlice := reflect.Append(slice, reflect.ValueOf(&m.Value)) - slice.Set(newSlice) - return b[x:], nil - } -} - -func makeStdInt32ValueSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &int32Value{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - slice := f.getSlice(sub.typ) - newSlice := reflect.Append(slice, reflect.ValueOf(m.Value)) - slice.Set(newSlice) - return b[x:], nil - } -} - -func makeStdUInt32ValueMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - t := ptr.asPointerTo(u.typ).Interface().(*uint32) - v := &uint32Value{*t} - siz := Size(v) - return tagsize + SizeVarint(uint64(siz)) + siz - }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - t := ptr.asPointerTo(u.typ).Interface().(*uint32) - v := &uint32Value{*t} - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(buf))) - b = append(b, buf...) - return b, nil - } -} - -func makeStdUInt32ValuePtrMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - if ptr.isNil() { - return 0 - } - t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*uint32) - v := &uint32Value{*t} - siz := Size(v) - return tagsize + SizeVarint(uint64(siz)) + siz - }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - if ptr.isNil() { - return b, nil - } - t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*uint32) - v := &uint32Value{*t} - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(buf))) - b = append(b, buf...) - return b, nil - } -} - -func makeStdUInt32ValueSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getSlice(u.typ) - n := 0 - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(uint32) - v := &uint32Value{t} - siz := Size(v) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getSlice(u.typ) - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(uint32) - v := &uint32Value{t} - siz := Size(v) - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(siz)) - b = append(b, buf...) - } - - return b, nil - } -} - -func makeStdUInt32ValuePtrSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getSlice(reflect.PtrTo(u.typ)) - n := 0 - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(*uint32) - v := &uint32Value{*t} - siz := Size(v) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getSlice(reflect.PtrTo(u.typ)) - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(*uint32) - v := &uint32Value{*t} - siz := Size(v) - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(siz)) - b = append(b, buf...) - } - - return b, nil - } -} - -func makeStdUInt32ValueUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &uint32Value{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - s := f.asPointerTo(sub.typ).Elem() - s.Set(reflect.ValueOf(m.Value)) - return b[x:], nil - } -} - -func makeStdUInt32ValuePtrUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &uint32Value{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - s := f.asPointerTo(reflect.PtrTo(sub.typ)).Elem() - s.Set(reflect.ValueOf(&m.Value)) - return b[x:], nil - } -} - -func makeStdUInt32ValuePtrSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &uint32Value{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - slice := f.getSlice(reflect.PtrTo(sub.typ)) - newSlice := reflect.Append(slice, reflect.ValueOf(&m.Value)) - slice.Set(newSlice) - return b[x:], nil - } -} - -func makeStdUInt32ValueSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &uint32Value{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - slice := f.getSlice(sub.typ) - newSlice := reflect.Append(slice, reflect.ValueOf(m.Value)) - slice.Set(newSlice) - return b[x:], nil - } -} - -func makeStdBoolValueMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - t := ptr.asPointerTo(u.typ).Interface().(*bool) - v := &boolValue{*t} - siz := Size(v) - return tagsize + SizeVarint(uint64(siz)) + siz - }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - t := ptr.asPointerTo(u.typ).Interface().(*bool) - v := &boolValue{*t} - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(buf))) - b = append(b, buf...) - return b, nil - } -} - -func makeStdBoolValuePtrMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - if ptr.isNil() { - return 0 - } - t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*bool) - v := &boolValue{*t} - siz := Size(v) - return tagsize + SizeVarint(uint64(siz)) + siz - }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - if ptr.isNil() { - return b, nil - } - t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*bool) - v := &boolValue{*t} - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(buf))) - b = append(b, buf...) - return b, nil - } -} - -func makeStdBoolValueSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getSlice(u.typ) - n := 0 - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(bool) - v := &boolValue{t} - siz := Size(v) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getSlice(u.typ) - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(bool) - v := &boolValue{t} - siz := Size(v) - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(siz)) - b = append(b, buf...) - } - - return b, nil - } -} - -func makeStdBoolValuePtrSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getSlice(reflect.PtrTo(u.typ)) - n := 0 - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(*bool) - v := &boolValue{*t} - siz := Size(v) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getSlice(reflect.PtrTo(u.typ)) - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(*bool) - v := &boolValue{*t} - siz := Size(v) - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(siz)) - b = append(b, buf...) - } - - return b, nil - } -} - -func makeStdBoolValueUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &boolValue{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - s := f.asPointerTo(sub.typ).Elem() - s.Set(reflect.ValueOf(m.Value)) - return b[x:], nil - } -} - -func makeStdBoolValuePtrUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &boolValue{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - s := f.asPointerTo(reflect.PtrTo(sub.typ)).Elem() - s.Set(reflect.ValueOf(&m.Value)) - return b[x:], nil - } -} - -func makeStdBoolValuePtrSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &boolValue{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - slice := f.getSlice(reflect.PtrTo(sub.typ)) - newSlice := reflect.Append(slice, reflect.ValueOf(&m.Value)) - slice.Set(newSlice) - return b[x:], nil - } -} - -func makeStdBoolValueSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &boolValue{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - slice := f.getSlice(sub.typ) - newSlice := reflect.Append(slice, reflect.ValueOf(m.Value)) - slice.Set(newSlice) - return b[x:], nil - } -} - -func makeStdStringValueMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - t := ptr.asPointerTo(u.typ).Interface().(*string) - v := &stringValue{*t} - siz := Size(v) - return tagsize + SizeVarint(uint64(siz)) + siz - }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - t := ptr.asPointerTo(u.typ).Interface().(*string) - v := &stringValue{*t} - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(buf))) - b = append(b, buf...) - return b, nil - } -} - -func makeStdStringValuePtrMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - if ptr.isNil() { - return 0 - } - t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*string) - v := &stringValue{*t} - siz := Size(v) - return tagsize + SizeVarint(uint64(siz)) + siz - }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - if ptr.isNil() { - return b, nil - } - t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*string) - v := &stringValue{*t} - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(buf))) - b = append(b, buf...) - return b, nil - } -} - -func makeStdStringValueSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getSlice(u.typ) - n := 0 - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(string) - v := &stringValue{t} - siz := Size(v) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getSlice(u.typ) - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(string) - v := &stringValue{t} - siz := Size(v) - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(siz)) - b = append(b, buf...) - } - - return b, nil - } -} - -func makeStdStringValuePtrSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getSlice(reflect.PtrTo(u.typ)) - n := 0 - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(*string) - v := &stringValue{*t} - siz := Size(v) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getSlice(reflect.PtrTo(u.typ)) - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(*string) - v := &stringValue{*t} - siz := Size(v) - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(siz)) - b = append(b, buf...) - } - - return b, nil - } -} - -func makeStdStringValueUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &stringValue{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - s := f.asPointerTo(sub.typ).Elem() - s.Set(reflect.ValueOf(m.Value)) - return b[x:], nil - } -} - -func makeStdStringValuePtrUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &stringValue{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - s := f.asPointerTo(reflect.PtrTo(sub.typ)).Elem() - s.Set(reflect.ValueOf(&m.Value)) - return b[x:], nil - } -} - -func makeStdStringValuePtrSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &stringValue{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - slice := f.getSlice(reflect.PtrTo(sub.typ)) - newSlice := reflect.Append(slice, reflect.ValueOf(&m.Value)) - slice.Set(newSlice) - return b[x:], nil - } -} - -func makeStdStringValueSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &stringValue{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - slice := f.getSlice(sub.typ) - newSlice := reflect.Append(slice, reflect.ValueOf(m.Value)) - slice.Set(newSlice) - return b[x:], nil - } -} - -func makeStdBytesValueMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - t := ptr.asPointerTo(u.typ).Interface().(*[]byte) - v := &bytesValue{*t} - siz := Size(v) - return tagsize + SizeVarint(uint64(siz)) + siz - }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - t := ptr.asPointerTo(u.typ).Interface().(*[]byte) - v := &bytesValue{*t} - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(buf))) - b = append(b, buf...) - return b, nil - } -} - -func makeStdBytesValuePtrMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - if ptr.isNil() { - return 0 - } - t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*[]byte) - v := &bytesValue{*t} - siz := Size(v) - return tagsize + SizeVarint(uint64(siz)) + siz - }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - if ptr.isNil() { - return b, nil - } - t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*[]byte) - v := &bytesValue{*t} - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(len(buf))) - b = append(b, buf...) - return b, nil - } -} - -func makeStdBytesValueSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getSlice(u.typ) - n := 0 - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().([]byte) - v := &bytesValue{t} - siz := Size(v) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getSlice(u.typ) - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().([]byte) - v := &bytesValue{t} - siz := Size(v) - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(siz)) - b = append(b, buf...) - } - - return b, nil - } -} - -func makeStdBytesValuePtrSliceMarshaler(u *marshalInfo) (sizer, marshaler) { - return func(ptr pointer, tagsize int) int { - s := ptr.getSlice(reflect.PtrTo(u.typ)) - n := 0 - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(*[]byte) - v := &bytesValue{*t} - siz := Size(v) - n += siz + SizeVarint(uint64(siz)) + tagsize - } - return n - }, - func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { - s := ptr.getSlice(reflect.PtrTo(u.typ)) - for i := 0; i < s.Len(); i++ { - elem := s.Index(i) - t := elem.Interface().(*[]byte) - v := &bytesValue{*t} - siz := Size(v) - buf, err := Marshal(v) - if err != nil { - return nil, err - } - b = appendVarint(b, wiretag) - b = appendVarint(b, uint64(siz)) - b = append(b, buf...) - } - - return b, nil - } -} - -func makeStdBytesValueUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &bytesValue{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - s := f.asPointerTo(sub.typ).Elem() - s.Set(reflect.ValueOf(m.Value)) - return b[x:], nil - } -} - -func makeStdBytesValuePtrUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &bytesValue{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - s := f.asPointerTo(reflect.PtrTo(sub.typ)).Elem() - s.Set(reflect.ValueOf(&m.Value)) - return b[x:], nil - } -} - -func makeStdBytesValuePtrSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &bytesValue{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - slice := f.getSlice(reflect.PtrTo(sub.typ)) - newSlice := reflect.Append(slice, reflect.ValueOf(&m.Value)) - slice.Set(newSlice) - return b[x:], nil - } -} - -func makeStdBytesValueSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { - return func(b []byte, f pointer, w int) ([]byte, error) { - if w != WireBytes { - return nil, errInternalBadWireType - } - x, n := decodeVarint(b) - if n == 0 { - return nil, io.ErrUnexpectedEOF - } - b = b[n:] - if x > uint64(len(b)) { - return nil, io.ErrUnexpectedEOF - } - m := &bytesValue{} - if err := Unmarshal(b[:x], m); err != nil { - return nil, err - } - slice := f.getSlice(sub.typ) - newSlice := reflect.Append(slice, reflect.ValueOf(m.Value)) - slice.Set(newSlice) - return b[x:], nil - } -} diff --git a/vendor/github.com/gogo/protobuf/proto/wrappers_gogo.go b/vendor/github.com/gogo/protobuf/proto/wrappers_gogo.go deleted file mode 100644 index c1cf7bf85..000000000 --- a/vendor/github.com/gogo/protobuf/proto/wrappers_gogo.go +++ /dev/null @@ -1,113 +0,0 @@ -// Protocol Buffers for Go with Gadgets -// -// Copyright (c) 2018, The GoGo Authors. All rights reserved. -// http://github.com/gogo/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package proto - -type float64Value struct { - Value float64 `protobuf:"fixed64,1,opt,name=value,proto3" json:"value,omitempty"` -} - -func (m *float64Value) Reset() { *m = float64Value{} } -func (*float64Value) ProtoMessage() {} -func (*float64Value) String() string { return "float64" } - -type float32Value struct { - Value float32 `protobuf:"fixed32,1,opt,name=value,proto3" json:"value,omitempty"` -} - -func (m *float32Value) Reset() { *m = float32Value{} } -func (*float32Value) ProtoMessage() {} -func (*float32Value) String() string { return "float32" } - -type int64Value struct { - Value int64 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` -} - -func (m *int64Value) Reset() { *m = int64Value{} } -func (*int64Value) ProtoMessage() {} -func (*int64Value) String() string { return "int64" } - -type uint64Value struct { - Value uint64 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` -} - -func (m *uint64Value) Reset() { *m = uint64Value{} } -func (*uint64Value) ProtoMessage() {} -func (*uint64Value) String() string { return "uint64" } - -type int32Value struct { - Value int32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` -} - -func (m *int32Value) Reset() { *m = int32Value{} } -func (*int32Value) ProtoMessage() {} -func (*int32Value) String() string { return "int32" } - -type uint32Value struct { - Value uint32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` -} - -func (m *uint32Value) Reset() { *m = uint32Value{} } -func (*uint32Value) ProtoMessage() {} -func (*uint32Value) String() string { return "uint32" } - -type boolValue struct { - Value bool `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` -} - -func (m *boolValue) Reset() { *m = boolValue{} } -func (*boolValue) ProtoMessage() {} -func (*boolValue) String() string { return "bool" } - -type stringValue struct { - Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` -} - -func (m *stringValue) Reset() { *m = stringValue{} } -func (*stringValue) ProtoMessage() {} -func (*stringValue) String() string { return "string" } - -type bytesValue struct { - Value []byte `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` -} - -func (m *bytesValue) Reset() { *m = bytesValue{} } -func (*bytesValue) ProtoMessage() {} -func (*bytesValue) String() string { return "[]byte" } - -func init() { - RegisterType((*float64Value)(nil), "gogo.protobuf.proto.DoubleValue") - RegisterType((*float32Value)(nil), "gogo.protobuf.proto.FloatValue") - RegisterType((*int64Value)(nil), "gogo.protobuf.proto.Int64Value") - RegisterType((*uint64Value)(nil), "gogo.protobuf.proto.UInt64Value") - RegisterType((*int32Value)(nil), "gogo.protobuf.proto.Int32Value") - RegisterType((*uint32Value)(nil), "gogo.protobuf.proto.UInt32Value") - RegisterType((*boolValue)(nil), "gogo.protobuf.proto.BoolValue") - RegisterType((*stringValue)(nil), "gogo.protobuf.proto.StringValue") - RegisterType((*bytesValue)(nil), "gogo.protobuf.proto.BytesValue") -} diff --git a/vendor/github.com/gogo/protobuf/sortkeys/sortkeys.go b/vendor/github.com/gogo/protobuf/sortkeys/sortkeys.go deleted file mode 100644 index ceadde6a5..000000000 --- a/vendor/github.com/gogo/protobuf/sortkeys/sortkeys.go +++ /dev/null @@ -1,101 +0,0 @@ -// Protocol Buffers for Go with Gadgets -// -// Copyright (c) 2013, The GoGo Authors. All rights reserved. -// http://github.com/gogo/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package sortkeys - -import ( - "sort" -) - -func Strings(l []string) { - sort.Strings(l) -} - -func Float64s(l []float64) { - sort.Float64s(l) -} - -func Float32s(l []float32) { - sort.Sort(Float32Slice(l)) -} - -func Int64s(l []int64) { - sort.Sort(Int64Slice(l)) -} - -func Int32s(l []int32) { - sort.Sort(Int32Slice(l)) -} - -func Uint64s(l []uint64) { - sort.Sort(Uint64Slice(l)) -} - -func Uint32s(l []uint32) { - sort.Sort(Uint32Slice(l)) -} - -func Bools(l []bool) { - sort.Sort(BoolSlice(l)) -} - -type BoolSlice []bool - -func (p BoolSlice) Len() int { return len(p) } -func (p BoolSlice) Less(i, j int) bool { return p[j] } -func (p BoolSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } - -type Int64Slice []int64 - -func (p Int64Slice) Len() int { return len(p) } -func (p Int64Slice) Less(i, j int) bool { return p[i] < p[j] } -func (p Int64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } - -type Int32Slice []int32 - -func (p Int32Slice) Len() int { return len(p) } -func (p Int32Slice) Less(i, j int) bool { return p[i] < p[j] } -func (p Int32Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } - -type Uint64Slice []uint64 - -func (p Uint64Slice) Len() int { return len(p) } -func (p Uint64Slice) Less(i, j int) bool { return p[i] < p[j] } -func (p Uint64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } - -type Uint32Slice []uint32 - -func (p Uint32Slice) Len() int { return len(p) } -func (p Uint32Slice) Less(i, j int) bool { return p[i] < p[j] } -func (p Uint32Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } - -type Float32Slice []float32 - -func (p Float32Slice) Len() int { return len(p) } -func (p Float32Slice) Less(i, j int) bool { return p[i] < p[j] } -func (p Float32Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } diff --git a/vendor/github.com/olekukonko/tablewriter/.gitignore b/vendor/github.com/golangci/asciicheck/.gitignore similarity index 58% rename from vendor/github.com/olekukonko/tablewriter/.gitignore rename to vendor/github.com/golangci/asciicheck/.gitignore index b66cec635..26938fd81 100644 --- a/vendor/github.com/olekukonko/tablewriter/.gitignore +++ b/vendor/github.com/golangci/asciicheck/.gitignore @@ -1,5 +1,10 @@ -# Created by .ignore support plugin (hsz.mobi) -### Go template +# IntelliJ project files +.idea +*.iml +out +gen + +# Go template # Binaries for programs and plugins *.exe *.exe~ @@ -7,9 +12,10 @@ *.so *.dylib -# Test binary, build with `go test -c` +# Test binary, built with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out +/asciicheck diff --git a/vendor/github.com/golangci/asciicheck/.golangci.yml b/vendor/github.com/golangci/asciicheck/.golangci.yml new file mode 100644 index 000000000..e28845eb5 --- /dev/null +++ b/vendor/github.com/golangci/asciicheck/.golangci.yml @@ -0,0 +1,87 @@ +version: "2" + +formatters: + enable: + - gci + - gofumpt + settings: + gofumpt: + extra-rules: true + +linters: + default: all + disable: + - cyclop # duplicate of gocyclo + - dupl + - errchkjson + - exhaustive + - exhaustruct + - lll + - mnd + - nilnil + - nlreturn + - nonamedreturns + - paralleltest + - prealloc + - rowserrcheck # not relevant (SQL) + - sqlclosecheck # not relevant (SQL) + - testpackage + - tparallel + - varnamelen + - wsl # Deprecated + - forcetypeassert # recheck in the future. + + settings: + depguard: + rules: + main: + deny: + - pkg: github.com/instana/testify + desc: not allowed + - pkg: github.com/pkg/errors + desc: Should be replaced by standard lib errors package + funlen: + lines: -1 + statements: 40 + goconst: + min-len: 5 + min-occurrences: 3 + gocritic: + disabled-checks: + - sloppyReassign + - rangeValCopy + - octalLiteral + - paramTypeCombine # already handle by gofumpt.extra-rules + enabled-tags: + - diagnostic + - style + - performance + settings: + hugeParam: + sizeThreshold: 100 + gocyclo: + min-complexity: 20 + godox: + keywords: + - FIXME + govet: + disable: + - fieldalignment + enable-all: true + misspell: + locale: US + mnd: + ignored-numbers: + - "124" + wsl: + force-case-trailing-whitespace: 1 + allow-trailing-comment: true + exclusions: + presets: + - comments + - std-error-handling + - common-false-positives + +issues: + max-issues-per-linter: 0 + max-same-issues: 0 diff --git a/vendor/github.com/tdakkota/asciicheck/LICENSE b/vendor/github.com/golangci/asciicheck/LICENSE similarity index 100% rename from vendor/github.com/tdakkota/asciicheck/LICENSE rename to vendor/github.com/golangci/asciicheck/LICENSE diff --git a/vendor/github.com/golangci/asciicheck/Makefile b/vendor/github.com/golangci/asciicheck/Makefile new file mode 100644 index 000000000..cdfc26114 --- /dev/null +++ b/vendor/github.com/golangci/asciicheck/Makefile @@ -0,0 +1,15 @@ +.PHONY: clean check test build + +default: clean check test build + +clean: + rm -rf dist/ cover.out + +test: clean + go test -v -cover ./... + +check: + golangci-lint run + +build: + go build -ldflags "-s -w" -trimpath ./cmd/asciicheck/ diff --git a/vendor/github.com/tdakkota/asciicheck/README.md b/vendor/github.com/golangci/asciicheck/README.md similarity index 75% rename from vendor/github.com/tdakkota/asciicheck/README.md rename to vendor/github.com/golangci/asciicheck/README.md index a7ff5884f..0d1da4b97 100644 --- a/vendor/github.com/tdakkota/asciicheck/README.md +++ b/vendor/github.com/golangci/asciicheck/README.md @@ -1,13 +1,19 @@ -# asciicheck [![Go Report Card](https://goreportcard.com/badge/github.com/tdakkota/asciicheck)](https://goreportcard.com/report/github.com/tdakkota/asciicheck) [![codecov](https://codecov.io/gh/tdakkota/asciicheck/branch/master/graph/badge.svg)](https://codecov.io/gh/tdakkota/asciicheck) ![Go](https://github.com/tdakkota/asciicheck/workflows/Go/badge.svg) +# asciicheck + +[![Go Report Card](https://goreportcard.com/badge/github.com/golangci/asciicheck)](https://goreportcard.com/report/github.com/golangci/asciicheck) + Simple linter to check that your code does not contain non-ASCII identifiers -# Install +The project has been moved to the golangci organization because the GitHub account of the original author (@tdakkota) is no longer available. + +## Install +```bash +go install github.com/golangci/asciicheck/cmd/asciicheck@latest ``` -go get -u github.com/tdakkota/asciicheck/cmd/asciicheck -``` -# Reason to use +## Reason to use + So, do you see this code? Looks correct, isn't it? ```go @@ -22,20 +28,24 @@ func main() { fmt.Println(s) } ``` + But if you try to run it, you will get an error: + ``` ./prog.go:8:7: undefined: TestStruct ``` What? `TestStruct` is defined above, but compiler thinks diffrent. Why? **Answer**: + Because `TestStruct` is not `TеstStruct`. ``` type TеstStruct struct{} ^ this 'e' (U+0435) is not 'e' (U+0065) ``` -# Usage +## Usage + asciicheck uses [`singlechecker`](https://pkg.go.dev/golang.org/x/tools/go/analysis/singlechecker) package to run: ``` diff --git a/vendor/github.com/tdakkota/asciicheck/ascii.go b/vendor/github.com/golangci/asciicheck/ascii.go similarity index 100% rename from vendor/github.com/tdakkota/asciicheck/ascii.go rename to vendor/github.com/golangci/asciicheck/ascii.go diff --git a/vendor/github.com/golangci/asciicheck/asciicheck.go b/vendor/github.com/golangci/asciicheck/asciicheck.go new file mode 100644 index 000000000..0983c7270 --- /dev/null +++ b/vendor/github.com/golangci/asciicheck/asciicheck.go @@ -0,0 +1,104 @@ +package asciicheck + +import ( + "fmt" + "go/ast" + "go/token" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/ast/inspector" +) + +func NewAnalyzer() *analysis.Analyzer { + return &analysis.Analyzer{ + Name: "asciicheck", + Doc: "checks that all code identifiers does not have non-ASCII symbols in the name", + Requires: []*analysis.Analyzer{inspect.Analyzer}, + Run: run, + } +} + +func run(pass *analysis.Pass) (any, error) { + insp := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + + nodeFilter := []ast.Node{ + (*ast.File)(nil), + (*ast.ImportSpec)(nil), + (*ast.TypeSpec)(nil), + (*ast.ValueSpec)(nil), + (*ast.FuncDecl)(nil), + (*ast.StructType)(nil), + (*ast.FuncType)(nil), + (*ast.InterfaceType)(nil), + (*ast.LabeledStmt)(nil), + (*ast.AssignStmt)(nil), + } + + insp.Preorder(nodeFilter, func(n ast.Node) { + switch n := n.(type) { + case *ast.File: + checkIdent(pass, n.Name) + case *ast.ImportSpec: + checkIdent(pass, n.Name) + case *ast.TypeSpec: + checkIdent(pass, n.Name) + checkFieldList(pass, n.TypeParams) + case *ast.ValueSpec: + for _, name := range n.Names { + checkIdent(pass, name) + } + case *ast.FuncDecl: + checkIdent(pass, n.Name) + checkFieldList(pass, n.Recv) + case *ast.StructType: + checkFieldList(pass, n.Fields) + case *ast.FuncType: + checkFieldList(pass, n.TypeParams) + checkFieldList(pass, n.Params) + checkFieldList(pass, n.Results) + case *ast.InterfaceType: + checkFieldList(pass, n.Methods) + case *ast.LabeledStmt: + checkIdent(pass, n.Label) + case *ast.AssignStmt: + if n.Tok == token.DEFINE { + for _, expr := range n.Lhs { + if ident, ok := expr.(*ast.Ident); ok { + checkIdent(pass, ident) + } + } + } + } + }) + + return nil, nil +} + +func checkIdent(pass *analysis.Pass, v *ast.Ident) { + if v == nil { + return + } + + ch, ascii := isASCII(v.Name) + if !ascii { + pass.Report( + analysis.Diagnostic{ + Pos: v.Pos(), + Message: fmt.Sprintf("identifier %q contain non-ASCII character: %#U", v.Name, ch), + }, + ) + } +} + +func checkFieldList(pass *analysis.Pass, f *ast.FieldList) { + if f == nil { + return + } + + for _, f := range f.List { + for _, name := range f.Names { + checkIdent(pass, name) + } + } +} diff --git a/vendor/github.com/golangci/dupl/.travis.yml b/vendor/github.com/golangci/dupl/.travis.yml deleted file mode 100644 index 33de24c0f..000000000 --- a/vendor/github.com/golangci/dupl/.travis.yml +++ /dev/null @@ -1,5 +0,0 @@ -language: go -go: - - 1.3 - - 1.8 - - 1.9 diff --git a/vendor/github.com/golangci/dupl/README.md b/vendor/github.com/golangci/dupl/README.md deleted file mode 100644 index f34901d7a..000000000 --- a/vendor/github.com/golangci/dupl/README.md +++ /dev/null @@ -1,63 +0,0 @@ -# dupl [![Build Status](https://travis-ci.org/mibk/dupl.png)](https://travis-ci.org/mibk/dupl) - -**dupl** is a tool written in Go for finding code clones. So far it can find clones only -in the Go source files. The method uses suffix tree for serialized ASTs. It ignores values -of AST nodes. It just operates with their types (e.g. `if a == 13 {}` and `if x == 100 {}` are -considered the same provided it exceeds the minimal token sequence size). - -Due to the used method dupl can report so called "false positives" on the output. These are -the ones we do not consider clones (whether they are too small, or the values of the matched -tokens are completely different). - -## Installation - -```bash -go get -u github.com/golangci/dupl -``` - -## Usage - -``` -Usage of dupl: - dupl [flags] [paths] - -Paths: - If the given path is a file, dupl will use it regardless of - the file extension. If it is a directory it will recursively - search for *.go files in that directory. - - If no path is given dupl will recursively search for *.go - files in the current directory. - -Flags: - -files - read file names from stdin one at each line - -html - output the results as HTML, including duplicate code fragments - -plumbing - plumbing (easy-to-parse) output for consumption by scripts or tools - -t, -threshold size - minimum token sequence size as a clone (default 15) - -vendor - check files in vendor directory - -v, -verbose - explain what is being done - -Examples: - dupl -t 100 - Search clones in the current directory of size at least - 100 tokens. - dupl $(find app/ -name '*_test.go') - Search for clones in tests in the app directory. - find app/ -name '*_test.go' |dupl -files - The same as above. -``` - -## Example - -The reduced output of this command with the following parameters for the [Docker](https://www.docker.com) source code -looks like [this](http://htmlpreview.github.io/?https://github.com/golangci/dupl/blob/master/_output_example/docker.html). - -```bash -$ dupl -t 200 -html >docker.html -``` diff --git a/vendor/github.com/golangci/dupl/main.go b/vendor/github.com/golangci/dupl/lib/lib.go similarity index 51% rename from vendor/github.com/golangci/dupl/main.go rename to vendor/github.com/golangci/dupl/lib/lib.go index 3030a97ae..3000a8f38 100644 --- a/vendor/github.com/golangci/dupl/main.go +++ b/vendor/github.com/golangci/dupl/lib/lib.go @@ -1,11 +1,8 @@ -package dupl +// Package lib Golangci-lint: altered version of main.go +package lib import ( - "flag" - "fmt" - "io/ioutil" "os" - "path/filepath" "sort" "github.com/golangci/dupl/job" @@ -13,27 +10,6 @@ import ( "github.com/golangci/dupl/syntax" ) -const defaultThreshold = 15 - -var ( - paths = []string{"."} - vendor = flag.Bool("dupl.vendor", false, "") - verbose = flag.Bool("dupl.verbose", false, "") - files = flag.Bool("dupl.files", false, "") - - html = flag.Bool("dupl.html", false, "") - plumbing = flag.Bool("dupl.plumbing", false, "") -) - -const ( - vendorDirPrefix = "vendor" + string(filepath.Separator) - vendorDirInPath = string(filepath.Separator) + vendorDirPrefix -) - -func init() { - flag.BoolVar(verbose, "dupl.v", false, "alias for -verbose") -} - func Run(files []string, threshold int) ([]printer.Issue, error) { fchan := make(chan string, 1024) go func() { @@ -75,7 +51,7 @@ func makeIssues(duplChan <-chan syntax.Match) ([]printer.Issue, error) { } sort.Strings(keys) - p := printer.NewPlumbing(ioutil.ReadFile) + p := printer.NewIssuer(os.ReadFile) var issues []printer.Issue for _, k := range keys { @@ -110,39 +86,3 @@ func unique(group [][]*syntax.Node) [][]*syntax.Node { } return newGroup } - -func usage() { - fmt.Fprintln(os.Stderr, `Usage: dupl [flags] [paths] - -Paths: - If the given path is a file, dupl will use it regardless of - the file extension. If it is a directory, it will recursively - search for *.go files in that directory. - - If no path is given, dupl will recursively search for *.go - files in the current directory. - -Flags: - -files - read file names from stdin one at each line - -html - output the results as HTML, including duplicate code fragments - -plumbing - plumbing (easy-to-parse) output for consumption by scripts or tools - -t, -threshold size - minimum token sequence size as a clone (default 15) - -vendor - check files in vendor directory - -v, -verbose - explain what is being done - -Examples: - dupl -t 100 - Search clones in the current directory of size at least - 100 tokens. - dupl $(find app/ -name '*_test.go') - Search for clones in tests in the app directory. - find app/ -name '*_test.go' |dupl -files - The same as above.`) - os.Exit(2) -} diff --git a/vendor/github.com/golangci/dupl/printer/html.go b/vendor/github.com/golangci/dupl/printer/html.go index 5ad9e25c7..ac1474141 100644 --- a/vendor/github.com/golangci/dupl/printer/html.go +++ b/vendor/github.com/golangci/dupl/printer/html.go @@ -3,6 +3,7 @@ package printer import ( "bytes" "fmt" + "html" "io" "regexp" "sort" @@ -10,17 +11,17 @@ import ( "github.com/golangci/dupl/syntax" ) -type html struct { +type htmlprinter struct { iota int w io.Writer ReadFile } func NewHTML(w io.Writer, fread ReadFile) Printer { - return &html{w: w, ReadFile: fread} + return &htmlprinter{w: w, ReadFile: fread} } -func (p *html) PrintHeader() error { +func (p *htmlprinter) PrintHeader() error { _, err := fmt.Fprint(p.w, ` Duplicates @@ -35,7 +36,7 @@ func (p *html) PrintHeader() error { return err } -func (p *html) PrintClones(dups [][]*syntax.Node) error { +func (p *htmlprinter) PrintClones(dups [][]*syntax.Node) error { p.iota++ fmt.Fprintf(p.w, "

#%d found %d clones

\n", p.iota, len(dups)) @@ -63,12 +64,13 @@ func (p *html) PrintClones(dups [][]*syntax.Node) error { sort.Sort(byNameAndLine(clones)) for _, cl := range clones { - fmt.Fprintf(p.w, "

%s:%d

\n
%s
\n", cl.filename, cl.lineStart, cl.fragment) + fmt.Fprintf(p.w, "

%s:%d

\n
%s
\n", cl.filename, cl.lineStart, + html.EscapeString(string(cl.fragment))) } return nil } -func (*html) PrintFooter() error { return nil } +func (*htmlprinter) PrintFooter() error { return nil } func findLineBeg(file []byte, index int) int { for i := index; i >= 0; i-- { diff --git a/vendor/github.com/golangci/dupl/printer/issuer.go b/vendor/github.com/golangci/dupl/printer/issuer.go new file mode 100644 index 000000000..9b79f5705 --- /dev/null +++ b/vendor/github.com/golangci/dupl/printer/issuer.go @@ -0,0 +1,56 @@ +package printer + +// Golangci-lint: altered version of plumbing.go + +import ( + "sort" + + "github.com/golangci/dupl/syntax" +) + +type Clone clone + +func (c Clone) Filename() string { + return c.filename +} + +func (c Clone) LineStart() int { + return c.lineStart +} + +func (c Clone) LineEnd() int { + return c.lineEnd +} + +type Issue struct { + From, To Clone +} + +type Issuer struct { + ReadFile +} + +func NewIssuer(fread ReadFile) *Issuer { + return &Issuer{fread} +} + +func (p *Issuer) MakeIssues(dups [][]*syntax.Node) ([]Issue, error) { + clones, err := prepareClonesInfo(p.ReadFile, dups) + if err != nil { + return nil, err + } + + sort.Sort(byNameAndLine(clones)) + + var issues []Issue + + for i, cl := range clones { + nextCl := clones[(i+1)%len(clones)] + issues = append(issues, Issue{ + From: Clone(cl), + To: Clone(nextCl), + }) + } + + return issues, nil +} diff --git a/vendor/github.com/golangci/dupl/printer/plumbing.go b/vendor/github.com/golangci/dupl/printer/plumbing.go index cf39d01b7..b0577ddd5 100644 --- a/vendor/github.com/golangci/dupl/printer/plumbing.go +++ b/vendor/github.com/golangci/dupl/printer/plumbing.go @@ -1,50 +1,36 @@ package printer import ( + "fmt" + "io" "sort" "github.com/golangci/dupl/syntax" ) -type Clone clone - -func (c Clone) Filename() string { - return c.filename -} - -func (c Clone) LineStart() int { - return c.lineStart -} - -func (c Clone) LineEnd() int { - return c.lineEnd -} - -type Issue struct { - From, To Clone -} - -type Plumbing struct { +type plumbing struct { + w io.Writer ReadFile } -func NewPlumbing(fread ReadFile) *Plumbing { - return &Plumbing{fread} +func NewPlumbing(w io.Writer, fread ReadFile) Printer { + return &plumbing{w, fread} } -func (p *Plumbing) MakeIssues(dups [][]*syntax.Node) ([]Issue, error) { +func (p *plumbing) PrintHeader() error { return nil } + +func (p *plumbing) PrintClones(dups [][]*syntax.Node) error { clones, err := prepareClonesInfo(p.ReadFile, dups) if err != nil { - return nil, err + return err } sort.Sort(byNameAndLine(clones)) - var issues []Issue for i, cl := range clones { nextCl := clones[(i+1)%len(clones)] - issues = append(issues, Issue{ - From: Clone(cl), - To: Clone(nextCl), - }) + fmt.Fprintf(p.w, "%s:%d-%d: duplicate of %s:%d-%d\n", cl.filename, cl.lineStart, cl.lineEnd, + nextCl.filename, nextCl.lineStart, nextCl.lineEnd) } - return issues, nil + return nil } + +func (p *plumbing) PrintFooter() error { return nil } diff --git a/vendor/github.com/golangci/dupl/suffixtree/suffixtree.go b/vendor/github.com/golangci/dupl/suffixtree/suffixtree.go index 738015025..871469e8d 100644 --- a/vendor/github.com/golangci/dupl/suffixtree/suffixtree.go +++ b/vendor/github.com/golangci/dupl/suffixtree/suffixtree.go @@ -41,7 +41,7 @@ func New() *STree { // Update refreshes the suffix tree to by new data. func (t *STree) Update(data ...Token) { t.data = append(t.data, data...) - for _ = range data { + for range data { t.update() t.s, t.start = t.canonize(t.s, t.start, t.end) t.end++ diff --git a/vendor/github.com/golangci/dupl/syntax/syntax.go b/vendor/github.com/golangci/dupl/syntax/syntax.go index e2c750afd..9b11d3119 100644 --- a/vendor/github.com/golangci/dupl/syntax/syntax.go +++ b/vendor/github.com/golangci/dupl/syntax/syntax.go @@ -6,6 +6,19 @@ import ( "github.com/golangci/dupl/suffixtree" ) +// To avoid "goroutine stack exceeds" with gigantic slices (Composite Literals). +// 10_000 => 0.89s +// 20_000 => 1.53s +// 30_000 => 2.57s +// 40_000 => 3.89s +// 50_000 => 5.58s +// 60_000 => 7.95s +// 70_000 => 10.15s +// 80_000 => 13.11s +// 90_000 => 16.62s +// 100_000 => 21.42s +const maxChildrenSerial = 10_000 + type Node struct { Type int Filename string @@ -40,7 +53,12 @@ func Serialize(n *Node) []*Node { func serial(n *Node, stream *[]*Node) int { *stream = append(*stream, n) var count int - for _, child := range n.Children { + for i, child := range n.Children { + // To avoid "goroutine stack exceeds" with gigantic slices (Composite Literals). + if i > maxChildrenSerial { + break + } + count += serial(child, stream) } n.Owns = count diff --git a/vendor/github.com/golangci/go-printf-func-name/pkg/analyzer/analyzer.go b/vendor/github.com/golangci/go-printf-func-name/pkg/analyzer/analyzer.go index bce4b242e..0b41500f2 100644 --- a/vendor/github.com/golangci/go-printf-func-name/pkg/analyzer/analyzer.go +++ b/vendor/github.com/golangci/go-printf-func-name/pkg/analyzer/analyzer.go @@ -16,7 +16,7 @@ var Analyzer = &analysis.Analyzer{ Requires: []*analysis.Analyzer{inspect.Analyzer}, } -func run(pass *analysis.Pass) (interface{}, error) { +func run(pass *analysis.Pass) (any, error) { insp := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) nodeFilter := []ast.Node{ @@ -44,24 +44,21 @@ func run(pass *analysis.Pass) (interface{}, error) { return } - if formatParamNames := params[len(params)-2].Names; len(formatParamNames) == 0 || formatParamNames[len(formatParamNames)-1].Name != "format" { + formatParamNames := params[len(params)-2].Names + if len(formatParamNames) == 0 || formatParamNames[len(formatParamNames)-1].Name != "format" { return } argsParamType, ok := params[len(params)-1].Type.(*ast.Ellipsis) - if !ok { // args are not ellipsis (...args) + if !ok { + // args are not ellipsis (...args) return } - elementType, ok := argsParamType.Elt.(*ast.InterfaceType) - if !ok { // args are not of interface type, but we need interface{} + if !isAny(argsParamType) { return } - if elementType.Methods != nil && len(elementType.Methods.List) != 0 { - return // has >= 1 method in interface, but we need an empty interface "interface{}" - } - if strings.HasSuffix(funcDecl.Name.Name, "f") { return } @@ -72,3 +69,22 @@ func run(pass *analysis.Pass) (interface{}, error) { return nil, nil } + +func isAny(ell *ast.Ellipsis) bool { + switch elt := ell.Elt.(type) { + case *ast.InterfaceType: + if elt.Methods != nil && len(elt.Methods.List) != 0 { + // has >= 1 method in interface, but we need an empty interface "interface{}" + return false + } + + return true + + case *ast.Ident: + if elt.Name == "any" { + return true + } + } + + return false +} diff --git a/vendor/github.com/golangci/gofmt/gofmt/gofmt.go b/vendor/github.com/golangci/gofmt/gofmt/gofmt.go index 909d37657..a4f252e86 100644 --- a/vendor/github.com/golangci/gofmt/gofmt/gofmt.go +++ b/vendor/github.com/golangci/gofmt/gofmt/gofmt.go @@ -24,7 +24,7 @@ import ( "strconv" "strings" - "github.com/golangci/gofmt/gofmt/internal/diff" + "github.com/rogpeppe/go-internal/diff" "golang.org/x/sync/semaphore" ) diff --git a/vendor/github.com/golangci/gofmt/gofmt/golangci.go b/vendor/github.com/golangci/gofmt/gofmt/golangci.go index a69611e1d..a7f3ef6e7 100644 --- a/vendor/github.com/golangci/gofmt/gofmt/golangci.go +++ b/vendor/github.com/golangci/gofmt/gofmt/golangci.go @@ -11,9 +11,14 @@ import ( "path/filepath" "sync" - "github.com/golangci/gofmt/gofmt/internal/diff" + "github.com/rogpeppe/go-internal/diff" ) +type Options struct { + NeedSimplify bool + RewriteRules []RewriteRule +} + var parserModeMu sync.RWMutex type RewriteRule struct { @@ -22,13 +27,13 @@ type RewriteRule struct { } // Run runs gofmt. -// Deprecated: use RunRewrite instead. +// Deprecated: use [Source] instead. func Run(filename string, needSimplify bool) ([]byte, error) { return RunRewrite(filename, needSimplify, nil) } // RunRewrite runs gofmt. -// empty string `rewrite` will be ignored. +// Deprecated: use [Source] instead. func RunRewrite(filename string, needSimplify bool, rewriteRules []RewriteRule) ([]byte, error) { src, err := os.ReadFile(filename) if err != nil { @@ -73,6 +78,34 @@ func RunRewrite(filename string, needSimplify bool, rewriteRules []RewriteRule) return diff.Diff(oldName, src, newName, res), nil } +// Source formats the code like gofmt. +// Empty string `rewrite` will be ignored. +func Source(filename string, src []byte, opts Options) ([]byte, error) { + fset := token.NewFileSet() + + parserModeMu.Lock() + initParserMode() + parserModeMu.Unlock() + + file, sourceAdj, indentAdj, err := parse(fset, filename, src, false) + if err != nil { + return nil, err + } + + file, err = rewriteFileContent(fset, file, opts.RewriteRules) + if err != nil { + return nil, err + } + + ast.SortImports(fset, file) + + if opts.NeedSimplify { + simplify(file) + } + + return format(fset, file, sourceAdj, indentAdj, src, printer.Config{Mode: printerMode, Tabwidth: tabWidth}) +} + func rewriteFileContent(fset *token.FileSet, file *ast.File, rewriteRules []RewriteRule) (*ast.File, error) { for _, rewriteRule := range rewriteRules { pattern, err := parseExpression(rewriteRule.Pattern, "pattern") diff --git a/vendor/github.com/golangci/gofmt/gofmt/readme.md b/vendor/github.com/golangci/gofmt/gofmt/readme.md index be08179e6..907973116 100644 --- a/vendor/github.com/golangci/gofmt/gofmt/readme.md +++ b/vendor/github.com/golangci/gofmt/gofmt/readme.md @@ -3,8 +3,7 @@ - https://github.com/golang/go/blob/master/src/cmd/gofmt/ - https://github.com/golang/go/blob/master/src/internal/testenv - https://github.com/golang/go/blob/master/src/internal/platform -- https://github.com/golang/go/blob/master/src/internal/txtar -- https://github.com/golang/go/blob/master/src/internal/diff +- https://github.com/golang/go/blob/master/src/internal/diff -> replaced by `github.com/rogpeppe/go-internal/diff` - https://github.com/golang/go/blob/master/src/internal/cfg ## Updates diff --git a/vendor/github.com/golangci/gofmt/goimports/goimports.go b/vendor/github.com/golangci/gofmt/goimports/goimports.go deleted file mode 100644 index 556f2bd7e..000000000 --- a/vendor/github.com/golangci/gofmt/goimports/goimports.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package goimports - -import ( - "bytes" - "fmt" - "os" - "os/exec" - "path/filepath" - "runtime" -) - -// Extracted from golang.org/x/tools@v0.24.0/cmd/goimports/goimports.go - -func writeTempFile(dir, prefix string, data []byte) (string, error) { - file, err := os.CreateTemp(dir, prefix) - if err != nil { - return "", err - } - _, err = file.Write(data) - if err1 := file.Close(); err == nil { - err = err1 - } - if err != nil { - os.Remove(file.Name()) - return "", err - } - return file.Name(), nil -} - -func diff(b1, b2 []byte, filename string) (data []byte, err error) { - f1, err := writeTempFile("", "gofmt", b1) - if err != nil { - return - } - defer os.Remove(f1) - - f2, err := writeTempFile("", "gofmt", b2) - if err != nil { - return - } - defer os.Remove(f2) - - cmd := "diff" - if runtime.GOOS == "plan9" { - cmd = "/bin/ape/diff" - } - - data, err = exec.Command(cmd, "-u", f1, f2).CombinedOutput() - if len(data) > 0 { - // diff exits with a non-zero status when the files don't match. - // Ignore that failure as long as we get output. - return replaceTempFilename(data, filename) - } - return -} - -// replaceTempFilename replaces temporary filenames in diff with actual one. -// -// --- /tmp/gofmt316145376 2017-02-03 19:13:00.280468375 -0500 -// +++ /tmp/gofmt617882815 2017-02-03 19:13:00.280468375 -0500 -// ... -// -> -// --- path/to/file.go.orig 2017-02-03 19:13:00.280468375 -0500 -// +++ path/to/file.go 2017-02-03 19:13:00.280468375 -0500 -// ... -func replaceTempFilename(diff []byte, filename string) ([]byte, error) { - bs := bytes.SplitN(diff, []byte{'\n'}, 3) - if len(bs) < 3 { - return nil, fmt.Errorf("got unexpected diff for %s", filename) - } - // Preserve timestamps. - var t0, t1 []byte - if i := bytes.LastIndexByte(bs[0], '\t'); i != -1 { - t0 = bs[0][i:] - } - if i := bytes.LastIndexByte(bs[1], '\t'); i != -1 { - t1 = bs[1][i:] - } - // Always print filepath with slash separator. - f := filepath.ToSlash(filename) - bs[0] = []byte(fmt.Sprintf("--- %s%s", f+".orig", t0)) - bs[1] = []byte(fmt.Sprintf("+++ %s%s", f, t1)) - return bytes.Join(bs, []byte{'\n'}), nil -} diff --git a/vendor/github.com/golangci/gofmt/goimports/golangci.go b/vendor/github.com/golangci/gofmt/goimports/golangci.go deleted file mode 100644 index 6ff286ae0..000000000 --- a/vendor/github.com/golangci/gofmt/goimports/golangci.go +++ /dev/null @@ -1,35 +0,0 @@ -package goimports - -import ( - "bytes" - "fmt" - "os" - - "golang.org/x/tools/imports" -) - -// Run runs goimports. -// The local prefixes (comma separated) must be defined through the global variable imports.LocalPrefix. -func Run(filename string) ([]byte, error) { - src, err := os.ReadFile(filename) - if err != nil { - return nil, err - } - - res, err := imports.Process(filename, src, nil) - if err != nil { - return nil, err - } - - if bytes.Equal(src, res) { - return nil, nil - } - - // formatting has changed - data, err := diff(src, res, filename) - if err != nil { - return nil, fmt.Errorf("error computing diff: %s", err) - } - - return data, nil -} diff --git a/vendor/github.com/golangci/gofmt/goimports/readme.md b/vendor/github.com/golangci/gofmt/goimports/readme.md deleted file mode 100644 index 23eecf82f..000000000 --- a/vendor/github.com/golangci/gofmt/goimports/readme.md +++ /dev/null @@ -1,10 +0,0 @@ -# Hard Fork of goimports - -- https://github.com/golang/tools/tree/master/cmd/goimports - -## Updates - -- 2024-08-17: Sync with golang.org/x/tools v0.24.0 -- 2024-02-28: Sync with golang.org/x/tools v0.18.0 -- 2023-10-04: Sync with golang.org/x/tools v0.13.0 -- 2022-08-31: Sync with golang.org/x/tools v0.1.12 diff --git a/vendor/github.com/golangci/golangci-lint/internal/go/robustio/readme.md b/vendor/github.com/golangci/golangci-lint/internal/go/robustio/readme.md deleted file mode 100644 index f4dbc1626..000000000 --- a/vendor/github.com/golangci/golangci-lint/internal/go/robustio/readme.md +++ /dev/null @@ -1,11 +0,0 @@ -# robustio - -Extracted from go1.19.1/src/cmd/go/internal/robustio - -There is only one modification: -- ERROR_SHARING_VIOLATION extracted from go1.19.1/src/internal/syscall/windows/syscall_windows.go to remove the dependencies to `internal/syscall/windows` - -## History - -- https://github.com/golangci/golangci-lint/pull/5100 - - Move package from `internal/robustio` to `internal/go/robustio` diff --git a/vendor/github.com/golangci/golangci-lint/pkg/commands/help.go b/vendor/github.com/golangci/golangci-lint/pkg/commands/help.go deleted file mode 100644 index 094e5d190..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/commands/help.go +++ /dev/null @@ -1,142 +0,0 @@ -package commands - -import ( - "fmt" - "slices" - "sort" - "strings" - - "github.com/fatih/color" - "github.com/spf13/cobra" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/lint/lintersdb" - "github.com/golangci/golangci-lint/pkg/logutils" -) - -type helpCommand struct { - cmd *cobra.Command - - dbManager *lintersdb.Manager - - log logutils.Log -} - -func newHelpCommand(logger logutils.Log) *helpCommand { - c := &helpCommand{log: logger} - - helpCmd := &cobra.Command{ - Use: "help", - Short: "Help", - Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, _ []string) error { - return cmd.Help() - }, - } - - helpCmd.AddCommand( - &cobra.Command{ - Use: "linters", - Short: "Help about linters", - Args: cobra.NoArgs, - ValidArgsFunction: cobra.NoFileCompletions, - Run: c.execute, - PreRunE: c.preRunE, - }, - ) - - c.cmd = helpCmd - - return c -} - -func (c *helpCommand) preRunE(_ *cobra.Command, _ []string) error { - // The command doesn't depend on the real configuration. - // It just needs the list of all plugins and all presets. - dbManager, err := lintersdb.NewManager(c.log.Child(logutils.DebugKeyLintersDB), config.NewDefault(), lintersdb.NewLinterBuilder()) - if err != nil { - return err - } - - c.dbManager = dbManager - - return nil -} - -func (c *helpCommand) execute(_ *cobra.Command, _ []string) { - var enabledLCs, disabledLCs []*linter.Config - for _, lc := range c.dbManager.GetAllSupportedLinterConfigs() { - if lc.Internal { - continue - } - - if lc.EnabledByDefault { - enabledLCs = append(enabledLCs, lc) - } else { - disabledLCs = append(disabledLCs, lc) - } - } - - color.Green("Enabled by default linters:\n") - printLinters(enabledLCs) - - color.Red("\nDisabled by default linters:\n") - printLinters(disabledLCs) - - color.Green("\nLinters presets:") - c.printPresets() -} - -func (c *helpCommand) printPresets() { - for _, p := range lintersdb.AllPresets() { - linters := c.dbManager.GetAllLinterConfigsForPreset(p) - - var linterNames []string - for _, lc := range linters { - if lc.Internal { - continue - } - - linterNames = append(linterNames, lc.Name()) - } - sort.Strings(linterNames) - - _, _ = fmt.Fprintf(logutils.StdOut, "%s: %s\n", color.YellowString(p), strings.Join(linterNames, ", ")) - } -} - -func printLinters(lcs []*linter.Config) { - slices.SortFunc(lcs, func(a, b *linter.Config) int { - if a.IsDeprecated() && b.IsDeprecated() { - return strings.Compare(a.Name(), b.Name()) - } - - if a.IsDeprecated() { - return 1 - } - - if b.IsDeprecated() { - return -1 - } - - return strings.Compare(a.Name(), b.Name()) - }) - - for _, lc := range lcs { - // If the linter description spans multiple lines, truncate everything following the first newline - linterDescription := lc.Linter.Desc() - firstNewline := strings.IndexRune(linterDescription, '\n') - if firstNewline > 0 { - linterDescription = linterDescription[:firstNewline] - } - - deprecatedMark := "" - if lc.IsDeprecated() { - deprecatedMark = " [" + color.RedString("deprecated") + "]" - } - - _, _ = fmt.Fprintf(logutils.StdOut, "%s%s: %s [fast: %t, auto-fix: %t]\n", - color.YellowString(lc.Name()), deprecatedMark, linterDescription, !lc.IsSlowLinter(), lc.CanAutoFix) - } -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/config/config.go b/vendor/github.com/golangci/golangci-lint/pkg/config/config.go deleted file mode 100644 index b863b329f..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/config/config.go +++ /dev/null @@ -1,112 +0,0 @@ -package config - -import ( - "os" - "strings" - - hcversion "github.com/hashicorp/go-version" - "github.com/ldez/gomoddirectives" -) - -// Config encapsulates the config data specified in the golangci-lint YAML config file. -type Config struct { - cfgDir string // The directory containing the golangci-lint config file. - - Run Run `mapstructure:"run"` - - Output Output `mapstructure:"output"` - - LintersSettings LintersSettings `mapstructure:"linters-settings"` - Linters Linters `mapstructure:"linters"` - Issues Issues `mapstructure:"issues"` - Severity Severity `mapstructure:"severity"` - - InternalCmdTest bool // Option is used only for testing golangci-lint command, don't use it - InternalTest bool // Option is used only for testing golangci-lint code, don't use it -} - -// GetConfigDir returns the directory that contains golangci config file. -func (c *Config) GetConfigDir() string { - return c.cfgDir -} - -func (c *Config) Validate() error { - validators := []func() error{ - c.Run.Validate, - c.Output.Validate, - c.LintersSettings.Validate, - c.Linters.Validate, - c.Issues.Validate, - c.Severity.Validate, - } - - for _, v := range validators { - if err := v(); err != nil { - return err - } - } - - return nil -} - -func NewDefault() *Config { - return &Config{ - LintersSettings: defaultLintersSettings, - } -} - -type Version struct { - Format string `mapstructure:"format"` - Debug bool `mapstructure:"debug"` -} - -func IsGoGreaterThanOrEqual(current, limit string) bool { - v1, err := hcversion.NewVersion(strings.TrimPrefix(current, "go")) - if err != nil { - return false - } - - l, err := hcversion.NewVersion(limit) - if err != nil { - return false - } - - return v1.GreaterThanOrEqual(l) -} - -func detectGoVersion() string { - goVersion := detectGoVersionFromGoMod() - if goVersion != "" { - return goVersion - } - - v := os.Getenv("GOVERSION") - if v != "" { - return v - } - - return "1.17" -} - -// detectGoVersionFromGoMod tries to get Go version from go.mod. -// It returns `toolchain` version if present, -// else it returns `go` version if present, -// else it returns empty. -func detectGoVersionFromGoMod() string { - file, _ := gomoddirectives.GetModuleFile() - if file == nil { - return "" - } - - // The toolchain exists only if 'toolchain' version > 'go' version. - // If 'toolchain' version <= 'go' version, `go mod tidy` will remove 'toolchain' version from go.mod. - if file.Toolchain != nil && file.Toolchain.Name != "" { - return strings.TrimPrefix(file.Toolchain.Name, "go") - } - - if file.Go != nil && file.Go.Version != "" { - return file.Go.Version - } - - return "" -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/config/issues.go b/vendor/github.com/golangci/golangci-lint/pkg/config/issues.go deleted file mode 100644 index 2ee9364aa..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/config/issues.go +++ /dev/null @@ -1,246 +0,0 @@ -package config - -import ( - "errors" - "fmt" - "regexp" -) - -const excludeRuleMinConditionsCount = 2 - -var DefaultExcludePatterns = []ExcludePattern{ - { - ID: "EXC0001", - Pattern: "Error return value of .((os\\.)?std(out|err)\\..*|.*Close" + - "|.*Flush|os\\.Remove(All)?|.*print(f|ln)?|os\\.(Un)?Setenv). is not checked", - Linter: "errcheck", - Why: "Almost all programs ignore errors on these functions and in most cases it's ok.", - }, - { - ID: "EXC0002", // TODO(ldez): should be remove in v2 - Pattern: "(comment on exported (method|function|type|const)|" + - "should have( a package)? comment|comment should be of the form)", - Linter: "golint", - Why: "Annoying issue about not having a comment. The rare codebase has such comments.", - }, - { - ID: "EXC0003", // TODO(ldez): should be remove in v2 - Pattern: "func name will be used as test\\.Test.* by other packages, and that stutters; consider calling this", - Linter: "golint", - Why: "False positive when tests are defined in package 'test'.", - }, - { - ID: "EXC0004", - Pattern: "(possible misuse of unsafe.Pointer|should have signature)", - Linter: "govet", - Why: "Common false positives.", - }, - { - ID: "EXC0005", - Pattern: "SA4011", // CheckScopedBreak - Linter: "staticcheck", - Why: "Developers tend to write in C-style with an explicit 'break' in a 'switch', so it's ok to ignore.", - }, - { - ID: "EXC0006", - Pattern: "G103: Use of unsafe calls should be audited", - Linter: "gosec", - Why: "Too many false-positives on 'unsafe' usage.", - }, - { - ID: "EXC0007", - Pattern: "G204: Subprocess launched with variable", - Linter: "gosec", - Why: "Too many false-positives for parametrized shell calls.", - }, - { - ID: "EXC0008", - Pattern: "G104", // Errors unhandled. - Linter: "gosec", - Why: "Duplicated errcheck checks.", - }, - { - ID: "EXC0009", - Pattern: "(G301|G302|G307): Expect (directory permissions to be 0750|file permissions to be 0600) or less", - Linter: "gosec", - Why: "Too many issues in popular repos.", - }, - { - ID: "EXC0010", - Pattern: "G304: Potential file inclusion via variable", - Linter: "gosec", - Why: "False positive is triggered by 'src, err := ioutil.ReadFile(filename)'.", - }, - { - ID: "EXC0011", - Pattern: "(ST1000|ST1020|ST1021|ST1022)", // CheckPackageComment, CheckExportedFunctionDocs, CheckExportedTypeDocs, CheckExportedVarDocs - Linter: "stylecheck", - Why: "Annoying issue about not having a comment. The rare codebase has such comments.", - }, - { - ID: "EXC0012", - Pattern: `exported (.+) should have comment( \(or a comment on this block\))? or be unexported`, // rule: exported - Linter: "revive", - Why: "Annoying issue about not having a comment. The rare codebase has such comments.", - }, - { - ID: "EXC0013", - Pattern: `package comment should be of the form "(.+)..."`, // rule: package-comments - Linter: "revive", - Why: "Annoying issue about not having a comment. The rare codebase has such comments.", - }, - { - ID: "EXC0014", - Pattern: `comment on exported (.+) should be of the form "(.+)..."`, // rule: exported - Linter: "revive", - Why: "Annoying issue about not having a comment. The rare codebase has such comments.", - }, - { - ID: "EXC0015", - Pattern: `should have a package comment`, // rule: package-comments - Linter: "revive", - Why: "Annoying issue about not having a comment. The rare codebase has such comments.", - }, -} - -type Issues struct { - IncludeDefaultExcludes []string `mapstructure:"include"` - ExcludeCaseSensitive bool `mapstructure:"exclude-case-sensitive"` - ExcludePatterns []string `mapstructure:"exclude"` - ExcludeRules []ExcludeRule `mapstructure:"exclude-rules"` - UseDefaultExcludes bool `mapstructure:"exclude-use-default"` - - ExcludeGenerated string `mapstructure:"exclude-generated"` - - ExcludeFiles []string `mapstructure:"exclude-files"` - ExcludeDirs []string `mapstructure:"exclude-dirs"` - - UseDefaultExcludeDirs bool `mapstructure:"exclude-dirs-use-default"` - - MaxIssuesPerLinter int `mapstructure:"max-issues-per-linter"` - MaxSameIssues int `mapstructure:"max-same-issues"` - - DiffFromRevision string `mapstructure:"new-from-rev"` - DiffPatchFilePath string `mapstructure:"new-from-patch"` - WholeFiles bool `mapstructure:"whole-files"` - Diff bool `mapstructure:"new"` - - NeedFix bool `mapstructure:"fix"` - - ExcludeGeneratedStrict bool `mapstructure:"exclude-generated-strict"` // Deprecated: use ExcludeGenerated instead. -} - -func (i *Issues) Validate() error { - for i, rule := range i.ExcludeRules { - if err := rule.Validate(); err != nil { - return fmt.Errorf("error in exclude rule #%d: %w", i, err) - } - } - - return nil -} - -type ExcludeRule struct { - BaseRule `mapstructure:",squash"` -} - -func (e *ExcludeRule) Validate() error { - return e.BaseRule.Validate(excludeRuleMinConditionsCount) -} - -type BaseRule struct { - Linters []string - Path string - PathExcept string `mapstructure:"path-except"` - Text string - Source string -} - -func (b *BaseRule) Validate(minConditionsCount int) error { - if err := validateOptionalRegex(b.Path); err != nil { - return fmt.Errorf("invalid path regex: %w", err) - } - - if err := validateOptionalRegex(b.PathExcept); err != nil { - return fmt.Errorf("invalid path-except regex: %w", err) - } - - if err := validateOptionalRegex(b.Text); err != nil { - return fmt.Errorf("invalid text regex: %w", err) - } - - if err := validateOptionalRegex(b.Source); err != nil { - return fmt.Errorf("invalid source regex: %w", err) - } - - if b.Path != "" && b.PathExcept != "" { - return errors.New("path and path-except should not be set at the same time") - } - - nonBlank := 0 - if len(b.Linters) > 0 { - nonBlank++ - } - - // Filtering by path counts as one condition, regardless how it is done (one or both). - // Otherwise, a rule with Path and PathExcept set would pass validation - // whereas before the introduction of path-except that wouldn't have been precise enough. - if b.Path != "" || b.PathExcept != "" { - nonBlank++ - } - - if b.Text != "" { - nonBlank++ - } - - if b.Source != "" { - nonBlank++ - } - - if nonBlank < minConditionsCount { - return fmt.Errorf("at least %d of (text, source, path[-except], linters) should be set", minConditionsCount) - } - - return nil -} - -func validateOptionalRegex(value string) error { - if value == "" { - return nil - } - - _, err := regexp.Compile(value) - return err -} - -type ExcludePattern struct { - ID string - Pattern string - Linter string - Why string -} - -func GetDefaultExcludePatternsStrings() []string { - ret := make([]string, len(DefaultExcludePatterns)) - for i, p := range DefaultExcludePatterns { - ret[i] = p.Pattern - } - return ret -} - -// TODO(ldez): this behavior must be changed in v2, because this is confusing. -func GetExcludePatterns(include []string) []ExcludePattern { - includeMap := make(map[string]struct{}, len(include)) - for _, inc := range include { - includeMap[inc] = struct{}{} - } - - var ret []ExcludePattern - for _, p := range DefaultExcludePatterns { - if _, ok := includeMap[p.ID]; !ok { - ret = append(ret, p) - } - } - - return ret -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/config/linters.go b/vendor/github.com/golangci/golangci-lint/pkg/config/linters.go deleted file mode 100644 index 5c2628272..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/config/linters.go +++ /dev/null @@ -1,65 +0,0 @@ -package config - -import ( - "errors" - "fmt" -) - -type Linters struct { - Enable []string - Disable []string - EnableAll bool `mapstructure:"enable-all"` - DisableAll bool `mapstructure:"disable-all"` - Fast bool - - Presets []string -} - -func (l *Linters) Validate() error { - if err := l.validateAllDisableEnableOptions(); err != nil { - return err - } - - if err := l.validateDisabledAndEnabledAtOneMoment(); err != nil { - return err - } - - return nil -} - -func (l *Linters) validateAllDisableEnableOptions() error { - if l.EnableAll && l.DisableAll { - return errors.New("--enable-all and --disable-all options must not be combined") - } - - if l.DisableAll { - if len(l.Enable) == 0 && len(l.Presets) == 0 { - return errors.New("all linters were disabled, but no one linter was enabled: must enable at least one") - } - - if len(l.Disable) != 0 { - return errors.New("can't combine options --disable-all and --disable") - } - } - - if l.EnableAll && len(l.Enable) != 0 && !l.Fast { - return errors.New("can't combine options --enable-all and --enable") - } - - return nil -} - -func (l *Linters) validateDisabledAndEnabledAtOneMoment() error { - enabledLintersSet := map[string]bool{} - for _, name := range l.Enable { - enabledLintersSet[name] = true - } - - for _, name := range l.Disable { - if enabledLintersSet[name] { - return fmt.Errorf("linter %q can't be disabled and enabled at one moment", name) - } - } - - return nil -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/config/loader.go b/vendor/github.com/golangci/golangci-lint/pkg/config/loader.go deleted file mode 100644 index efeed3ca4..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/config/loader.go +++ /dev/null @@ -1,479 +0,0 @@ -package config - -import ( - "errors" - "fmt" - "os" - "path/filepath" - "slices" - - "github.com/go-viper/mapstructure/v2" - "github.com/mitchellh/go-homedir" - "github.com/spf13/pflag" - "github.com/spf13/viper" - - "github.com/golangci/golangci-lint/pkg/exitcodes" - "github.com/golangci/golangci-lint/pkg/fsutils" - "github.com/golangci/golangci-lint/pkg/goutil" - "github.com/golangci/golangci-lint/pkg/logutils" -) - -var errConfigDisabled = errors.New("config is disabled by --no-config") - -type LoaderOptions struct { - Config string // Flag only. The path to the golangci config file, as specified with the --config argument. - NoConfig bool // Flag only. -} - -type LoadOptions struct { - CheckDeprecation bool - Validation bool -} - -type Loader struct { - opts LoaderOptions - - viper *viper.Viper - fs *pflag.FlagSet - - log logutils.Log - - cfg *Config - args []string -} - -func NewLoader(log logutils.Log, v *viper.Viper, fs *pflag.FlagSet, opts LoaderOptions, cfg *Config, args []string) *Loader { - return &Loader{ - opts: opts, - viper: v, - fs: fs, - log: log, - cfg: cfg, - args: args, - } -} - -func (l *Loader) Load(opts LoadOptions) error { - err := l.setConfigFile() - if err != nil { - return err - } - - err = l.parseConfig() - if err != nil { - return err - } - - l.applyStringSliceHack() - - if opts.CheckDeprecation { - err = l.handleDeprecation() - if err != nil { - return err - } - } - - l.handleGoVersion() - - err = goutil.CheckGoVersion(l.cfg.Run.Go) - if err != nil { - return err - } - - err = l.handleEnableOnlyOption() - if err != nil { - return err - } - - if opts.Validation { - err = l.cfg.Validate() - if err != nil { - return err - } - } - - return nil -} - -func (l *Loader) setConfigFile() error { - configFile, err := l.evaluateOptions() - if err != nil { - if errors.Is(err, errConfigDisabled) { - return nil - } - - return fmt.Errorf("can't parse --config option: %w", err) - } - - if configFile != "" { - l.viper.SetConfigFile(configFile) - - // Assume YAML if the file has no extension. - if filepath.Ext(configFile) == "" { - l.viper.SetConfigType("yaml") - } - } else { - l.setupConfigFileSearch() - } - - return nil -} - -func (l *Loader) evaluateOptions() (string, error) { - if l.opts.NoConfig && l.opts.Config != "" { - return "", errors.New("can't combine option --config and --no-config") - } - - if l.opts.NoConfig { - return "", errConfigDisabled - } - - configFile, err := homedir.Expand(l.opts.Config) - if err != nil { - return "", errors.New("failed to expand configuration path") - } - - return configFile, nil -} - -func (l *Loader) setupConfigFileSearch() { - l.viper.SetConfigName(".golangci") - - configSearchPaths := l.getConfigSearchPaths() - - l.log.Infof("Config search paths: %s", configSearchPaths) - - for _, p := range configSearchPaths { - l.viper.AddConfigPath(p) - } -} - -func (l *Loader) getConfigSearchPaths() []string { - firstArg := "./..." - if len(l.args) > 0 { - firstArg = l.args[0] - } - - absPath, err := filepath.Abs(firstArg) - if err != nil { - l.log.Warnf("Can't make abs path for %q: %s", firstArg, err) - absPath = filepath.Clean(firstArg) - } - - // start from it - var currentDir string - if fsutils.IsDir(absPath) { - currentDir = absPath - } else { - currentDir = filepath.Dir(absPath) - } - - // find all dirs from it up to the root - searchPaths := []string{"./"} - - for { - searchPaths = append(searchPaths, currentDir) - - parent := filepath.Dir(currentDir) - if currentDir == parent || parent == "" { - break - } - - currentDir = parent - } - - // find home directory for global config - if home, err := homedir.Dir(); err != nil { - l.log.Warnf("Can't get user's home directory: %v", err) - } else if !slices.Contains(searchPaths, home) { - searchPaths = append(searchPaths, home) - } - - return searchPaths -} - -func (l *Loader) parseConfig() error { - if err := l.viper.ReadInConfig(); err != nil { - var configFileNotFoundError viper.ConfigFileNotFoundError - if errors.As(err, &configFileNotFoundError) { - // Load configuration from flags only. - err = l.viper.Unmarshal(l.cfg, customDecoderHook()) - if err != nil { - return fmt.Errorf("can't unmarshal config by viper (flags): %w", err) - } - - return nil - } - - return fmt.Errorf("can't read viper config: %w", err) - } - - err := l.setConfigDir() - if err != nil { - return err - } - - // Load configuration from all sources (flags, file). - if err := l.viper.Unmarshal(l.cfg, customDecoderHook()); err != nil { - return fmt.Errorf("can't unmarshal config by viper (flags, file): %w", err) - } - - if l.cfg.InternalTest { // just for testing purposes: to detect config file usage - _, _ = fmt.Fprintln(logutils.StdOut, "test") - os.Exit(exitcodes.Success) - } - - return nil -} - -func (l *Loader) setConfigDir() error { - usedConfigFile := l.viper.ConfigFileUsed() - if usedConfigFile == "" { - return nil - } - - if usedConfigFile == os.Stdin.Name() { - usedConfigFile = "" - l.log.Infof("Reading config file stdin") - } else { - var err error - usedConfigFile, err = fsutils.ShortestRelPath(usedConfigFile, "") - if err != nil { - l.log.Warnf("Can't pretty print config file path: %v", err) - } - - l.log.Infof("Used config file %s", usedConfigFile) - } - - usedConfigDir, err := filepath.Abs(filepath.Dir(usedConfigFile)) - if err != nil { - return errors.New("can't get config directory") - } - - l.cfg.cfgDir = usedConfigDir - - return nil -} - -// Hack to append values from StringSlice flags. -// Viper always overrides StringSlice values. -// https://github.com/spf13/viper/issues/1448 -// So StringSlice flags are not bind to Viper like that their values are obtain via Cobra Flags. -func (l *Loader) applyStringSliceHack() { - if l.fs == nil { - return - } - - l.appendStringSlice("enable", &l.cfg.Linters.Enable) - l.appendStringSlice("disable", &l.cfg.Linters.Disable) - l.appendStringSlice("presets", &l.cfg.Linters.Presets) - l.appendStringSlice("build-tags", &l.cfg.Run.BuildTags) - l.appendStringSlice("exclude", &l.cfg.Issues.ExcludePatterns) - - l.appendStringSlice("skip-dirs", &l.cfg.Run.SkipDirs) - l.appendStringSlice("skip-files", &l.cfg.Run.SkipFiles) - l.appendStringSlice("exclude-dirs", &l.cfg.Issues.ExcludeDirs) - l.appendStringSlice("exclude-files", &l.cfg.Issues.ExcludeFiles) -} - -func (l *Loader) appendStringSlice(name string, current *[]string) { - if l.fs.Changed(name) { - val, _ := l.fs.GetStringSlice(name) - *current = append(*current, val...) - } -} - -func (l *Loader) handleGoVersion() { - if l.cfg.Run.Go == "" { - l.cfg.Run.Go = detectGoVersion() - } - - l.cfg.LintersSettings.Govet.Go = l.cfg.Run.Go - - l.cfg.LintersSettings.ParallelTest.Go = l.cfg.Run.Go - - if l.cfg.LintersSettings.Gofumpt.LangVersion == "" { - l.cfg.LintersSettings.Gofumpt.LangVersion = l.cfg.Run.Go - } - - trimmedGoVersion := goutil.TrimGoVersion(l.cfg.Run.Go) - - l.cfg.LintersSettings.Revive.Go = trimmedGoVersion - - l.cfg.LintersSettings.Gocritic.Go = trimmedGoVersion - - os.Setenv("GOSECGOVERSION", l.cfg.Run.Go) -} - -func (l *Loader) handleDeprecation() error { - if l.cfg.InternalTest || l.cfg.InternalCmdTest || os.Getenv(logutils.EnvTestRun) == "1" { - return nil - } - - // Deprecated since v1.57.0 - if len(l.cfg.Run.SkipFiles) > 0 { - l.log.Warnf("The configuration option `run.skip-files` is deprecated, please use `issues.exclude-files`.") - l.cfg.Issues.ExcludeFiles = l.cfg.Run.SkipFiles - } - - // Deprecated since v1.57.0 - if len(l.cfg.Run.SkipDirs) > 0 { - l.log.Warnf("The configuration option `run.skip-dirs` is deprecated, please use `issues.exclude-dirs`.") - l.cfg.Issues.ExcludeDirs = l.cfg.Run.SkipDirs - } - - // The 2 options are true by default. - // Deprecated since v1.57.0 - if !l.cfg.Run.UseDefaultSkipDirs { - l.log.Warnf("The configuration option `run.skip-dirs-use-default` is deprecated, please use `issues.exclude-dirs-use-default`.") - } - l.cfg.Issues.UseDefaultExcludeDirs = l.cfg.Run.UseDefaultSkipDirs && l.cfg.Issues.UseDefaultExcludeDirs - - // The 2 options are false by default. - // Deprecated since v1.57.0 - if l.cfg.Run.ShowStats { - l.log.Warnf("The configuration option `run.show-stats` is deprecated, please use `output.show-stats`") - } - l.cfg.Output.ShowStats = l.cfg.Run.ShowStats || l.cfg.Output.ShowStats - - // Deprecated since v1.57.0 - if l.cfg.Output.Format != "" { - l.log.Warnf("The configuration option `output.format` is deprecated, please use `output.formats`") - - var f OutputFormats - err := f.UnmarshalText([]byte(l.cfg.Output.Format)) - if err != nil { - return fmt.Errorf("unmarshal output format: %w", err) - } - - l.cfg.Output.Formats = f - } - - for _, format := range l.cfg.Output.Formats { - if format.Format == OutFormatGithubActions { - l.log.Warnf("The output format `%s` is deprecated, please use `%s`", OutFormatGithubActions, OutFormatColoredLineNumber) - break // To avoid repeating the message if there are several usages of github-actions format. - } - } - - // Deprecated since v1.59.0 - if l.cfg.Issues.ExcludeGeneratedStrict { - l.log.Warnf("The configuration option `issues.exclude-generated-strict` is deprecated, please use `issues.exclude-generated`") - l.cfg.Issues.ExcludeGenerated = "strict" // Don't use the constants to avoid cyclic dependencies. - } - - l.handleLinterOptionDeprecations() - - return nil -} - -//nolint:gocyclo // the complexity cannot be reduced. -func (l *Loader) handleLinterOptionDeprecations() { - // Deprecated since v1.57.0, - // but it was unofficially deprecated since v1.19 (2019) (https://github.com/golangci/golangci-lint/pull/697). - if l.cfg.LintersSettings.Govet.CheckShadowing { - l.log.Warnf("The configuration option `linters.govet.check-shadowing` is deprecated. " + - "Please enable `shadow` instead, if you are not using `enable-all`.") - } - - if l.cfg.LintersSettings.CopyLoopVar.IgnoreAlias { - l.log.Warnf("The configuration option `linters.copyloopvar.ignore-alias` is deprecated and ignored," + - "please use `linters.copyloopvar.check-alias`.") - } - - // Deprecated since v1.42.0. - if l.cfg.LintersSettings.Errcheck.Exclude != "" { - l.log.Warnf("The configuration option `linters.errcheck.exclude` is deprecated, please use `linters.errcheck.exclude-functions`.") - } - - // Deprecated since v1.59.0, - // but it was unofficially deprecated since v1.13 (2018) (https://github.com/golangci/golangci-lint/pull/332). - if l.cfg.LintersSettings.Errcheck.Ignore != "" { - l.log.Warnf("The configuration option `linters.errcheck.ignore` is deprecated, please use `linters.errcheck.exclude-functions`.") - } - - // Deprecated since v1.44.0. - if l.cfg.LintersSettings.Gci.LocalPrefixes != "" { - l.log.Warnf("The configuration option `linters.gci.local-prefixes` is deprecated, please use `prefix()` inside `linters.gci.sections`.") - } - - // Deprecated since v1.33.0. - if l.cfg.LintersSettings.Godot.CheckAll { - l.log.Warnf("The configuration option `linters.godot.check-all` is deprecated, please use `linters.godot.scope: all`.") - } - - // Deprecated since v1.47.0 - if l.cfg.LintersSettings.Gofumpt.LangVersion != "" { - l.log.Warnf("The configuration option `linters.gofumpt.lang-version` is deprecated, please use global `run.go`.") - } - - // Deprecated since v1.47.0 - if l.cfg.LintersSettings.Staticcheck.GoVersion != "" { - l.log.Warnf("The configuration option `linters.staticcheck.go` is deprecated, please use global `run.go`.") - } - - // Deprecated since v1.47.0 - if l.cfg.LintersSettings.Gosimple.GoVersion != "" { - l.log.Warnf("The configuration option `linters.gosimple.go` is deprecated, please use global `run.go`.") - } - - // Deprecated since v1.47.0 - if l.cfg.LintersSettings.Stylecheck.GoVersion != "" { - l.log.Warnf("The configuration option `linters.stylecheck.go` is deprecated, please use global `run.go`.") - } - - // Deprecated since v1.60.0 - if !l.cfg.LintersSettings.Unused.ExportedIsUsed { - l.log.Warnf("The configuration option `linters.unused.exported-is-used` is deprecated.") - } - - // Deprecated since v1.58.0 - if l.cfg.LintersSettings.SlogLint.ContextOnly { - l.log.Warnf("The configuration option `linters.sloglint.context-only` is deprecated, please use `linters.sloglint.context`.") - if l.cfg.LintersSettings.SlogLint.Context == "" { - l.cfg.LintersSettings.SlogLint.Context = "all" - } - } - - // Deprecated since v1.51.0 - if l.cfg.LintersSettings.UseStdlibVars.OSDevNull { - l.log.Warnf("The configuration option `linters.usestdlibvars.os-dev-null` is deprecated.") - } - - // Deprecated since v1.51.0 - if l.cfg.LintersSettings.UseStdlibVars.SyslogPriority { - l.log.Warnf("The configuration option `linters.usestdlibvars.syslog-priority` is deprecated.") - } -} - -func (l *Loader) handleEnableOnlyOption() error { - lookup := l.fs.Lookup("enable-only") - if lookup == nil { - return nil - } - - only, err := l.fs.GetStringSlice("enable-only") - if err != nil { - return err - } - - if len(only) > 0 { - l.cfg.Linters = Linters{ - Enable: only, - DisableAll: true, - } - } - - return nil -} - -func customDecoderHook() viper.DecoderConfigOption { - return viper.DecodeHook(mapstructure.ComposeDecodeHookFunc( - // Default hooks (https://github.com/spf13/viper/blob/518241257478c557633ab36e474dfcaeb9a3c623/viper.go#L135-L138). - mapstructure.StringToTimeDurationHookFunc(), - mapstructure.StringToSliceHookFunc(","), - - // Needed for forbidigo, and output.formats. - mapstructure.TextUnmarshallerHookFunc(), - )) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/config/output.go b/vendor/github.com/golangci/golangci-lint/pkg/config/output.go deleted file mode 100644 index 6a26d5773..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/config/output.go +++ /dev/null @@ -1,117 +0,0 @@ -package config - -import ( - "errors" - "fmt" - "slices" - "strings" -) - -const ( - OutFormatJSON = "json" - OutFormatLineNumber = "line-number" - OutFormatColoredLineNumber = "colored-line-number" - OutFormatTab = "tab" - OutFormatColoredTab = "colored-tab" - OutFormatCheckstyle = "checkstyle" - OutFormatCodeClimate = "code-climate" - OutFormatHTML = "html" - OutFormatJunitXML = "junit-xml" - OutFormatJunitXMLExtended = "junit-xml-extended" - OutFormatGithubActions = "github-actions" // Deprecated - OutFormatTeamCity = "teamcity" - OutFormatSarif = "sarif" -) - -var AllOutputFormats = []string{ - OutFormatJSON, - OutFormatLineNumber, - OutFormatColoredLineNumber, - OutFormatTab, - OutFormatColoredTab, - OutFormatCheckstyle, - OutFormatCodeClimate, - OutFormatHTML, - OutFormatJunitXML, - OutFormatJunitXMLExtended, - OutFormatGithubActions, - OutFormatTeamCity, - OutFormatSarif, -} - -type Output struct { - Formats OutputFormats `mapstructure:"formats"` - PrintIssuedLine bool `mapstructure:"print-issued-lines"` - PrintLinterName bool `mapstructure:"print-linter-name"` - UniqByLine bool `mapstructure:"uniq-by-line"` - SortResults bool `mapstructure:"sort-results"` - SortOrder []string `mapstructure:"sort-order"` - PathPrefix string `mapstructure:"path-prefix"` - ShowStats bool `mapstructure:"show-stats"` - - // Deprecated: use Formats instead. - Format string `mapstructure:"format"` -} - -func (o *Output) Validate() error { - if !o.SortResults && len(o.SortOrder) > 0 { - return errors.New("sort-results should be 'true' to use sort-order") - } - - validOrders := []string{"linter", "file", "severity"} - - all := strings.Join(o.SortOrder, " ") - - for _, order := range o.SortOrder { - if strings.Count(all, order) > 1 { - return fmt.Errorf("the sort-order name %q is repeated several times", order) - } - - if !slices.Contains(validOrders, order) { - return fmt.Errorf("unsupported sort-order name %q", order) - } - } - - for _, format := range o.Formats { - err := format.Validate() - if err != nil { - return err - } - } - - return nil -} - -type OutputFormat struct { - Format string `mapstructure:"format"` - Path string `mapstructure:"path"` -} - -func (o *OutputFormat) Validate() error { - if o.Format == "" { - return errors.New("the format is required") - } - - if !slices.Contains(AllOutputFormats, o.Format) { - return fmt.Errorf("unsupported output format %q", o.Format) - } - - return nil -} - -type OutputFormats []OutputFormat - -func (p *OutputFormats) UnmarshalText(text []byte) error { - formats := strings.Split(string(text), ",") - - for _, item := range formats { - format, path, _ := strings.Cut(item, ":") - - *p = append(*p, OutputFormat{ - Path: path, - Format: format, - }) - } - - return nil -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/fsutils/files.go b/vendor/github.com/golangci/golangci-lint/pkg/fsutils/files.go deleted file mode 100644 index 4398ab9fc..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/fsutils/files.go +++ /dev/null @@ -1,33 +0,0 @@ -package fsutils - -import "path/filepath" - -// Files combines different operations related to handling file paths and content. -type Files struct { - *LineCache - pathPrefix string -} - -func NewFiles(lc *LineCache, pathPrefix string) *Files { - return &Files{ - LineCache: lc, - pathPrefix: pathPrefix, - } -} - -// WithPathPrefix takes a path that is relative to the current directory (as used in issues) -// and adds the configured path prefix, if there is one. -// The resulting path then can be shown to the user or compared against paths specified in the configuration. -func (f *Files) WithPathPrefix(relativePath string) string { - return WithPathPrefix(f.pathPrefix, relativePath) -} - -// WithPathPrefix takes a path that is relative to the current directory (as used in issues) -// and adds the configured path prefix, if there is one. -// The resulting path then can be shown to the user or compared against paths specified in the configuration. -func WithPathPrefix(pathPrefix, relativePath string) string { - if pathPrefix == "" { - return relativePath - } - return filepath.Join(pathPrefix, relativePath) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/runners.go b/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/runners.go deleted file mode 100644 index a9aee03a2..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/runners.go +++ /dev/null @@ -1,114 +0,0 @@ -package goanalysis - -import ( - "fmt" - - "golang.org/x/tools/go/analysis" - "golang.org/x/tools/go/packages" - - "github.com/golangci/golangci-lint/pkg/goanalysis/pkgerrors" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/logutils" - "github.com/golangci/golangci-lint/pkg/result" - "github.com/golangci/golangci-lint/pkg/timeutils" -) - -type runAnalyzersConfig interface { - getName() string - getLinterNameForDiagnostic(*Diagnostic) string - getAnalyzers() []*analysis.Analyzer - useOriginalPackages() bool - reportIssues(*linter.Context) []Issue - getLoadMode() LoadMode -} - -func runAnalyzers(cfg runAnalyzersConfig, lintCtx *linter.Context) ([]result.Issue, error) { - log := lintCtx.Log.Child(logutils.DebugKeyGoAnalysis) - sw := timeutils.NewStopwatch("analyzers", log) - - const stagesToPrint = 10 - defer sw.PrintTopStages(stagesToPrint) - - runner := newRunner(cfg.getName(), log, lintCtx.PkgCache, lintCtx.LoadGuard, cfg.getLoadMode(), sw) - - pkgs := lintCtx.Packages - if cfg.useOriginalPackages() { - pkgs = lintCtx.OriginalPackages - } - - issues, pkgsFromCache := loadIssuesFromCache(pkgs, lintCtx, cfg.getAnalyzers()) - var pkgsToAnalyze []*packages.Package - for _, pkg := range pkgs { - if !pkgsFromCache[pkg] { - pkgsToAnalyze = append(pkgsToAnalyze, pkg) - } - } - - diags, errs, passToPkg := runner.run(cfg.getAnalyzers(), pkgsToAnalyze) - - defer func() { - if len(errs) == 0 { - // If we try to save to cache even if we have compilation errors - // we won't see them on repeated runs. - saveIssuesToCache(pkgs, pkgsFromCache, issues, lintCtx, cfg.getAnalyzers()) - } - }() - - buildAllIssues := func() []result.Issue { - var retIssues []result.Issue - reportedIssues := cfg.reportIssues(lintCtx) - for i := range reportedIssues { - issue := &reportedIssues[i].Issue - if issue.Pkg == nil { - issue.Pkg = passToPkg[reportedIssues[i].Pass] - } - retIssues = append(retIssues, *issue) - } - retIssues = append(retIssues, buildIssues(diags, cfg.getLinterNameForDiagnostic)...) - return retIssues - } - - errIssues, err := pkgerrors.BuildIssuesFromIllTypedError(errs, lintCtx) - if err != nil { - return nil, err - } - - issues = append(issues, errIssues...) - issues = append(issues, buildAllIssues()...) - - return issues, nil -} - -func buildIssues(diags []Diagnostic, linterNameBuilder func(diag *Diagnostic) string) []result.Issue { - var issues []result.Issue - for i := range diags { - diag := &diags[i] - linterName := linterNameBuilder(diag) - - var text string - if diag.Analyzer.Name == linterName { - text = diag.Message - } else { - text = fmt.Sprintf("%s: %s", diag.Analyzer.Name, diag.Message) - } - - issues = append(issues, result.Issue{ - FromLinter: linterName, - Text: text, - Pos: diag.Position, - Pkg: diag.Pkg, - }) - - if len(diag.Related) > 0 { - for _, info := range diag.Related { - issues = append(issues, result.Issue{ - FromLinter: linterName, - Text: fmt.Sprintf("%s(related information): %s", diag.Analyzer.Name, info.Message), - Pos: diag.Pkg.Fset.Position(info.Pos), - Pkg: diag.Pkg, - }) - } - } - } - return issues -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/asasalint/asasalint.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/asasalint/asasalint.go deleted file mode 100644 index 653a2d514..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/asasalint/asasalint.go +++ /dev/null @@ -1,31 +0,0 @@ -package asasalint - -import ( - "github.com/alingse/asasalint" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/golinters/internal" -) - -func New(setting *config.AsasalintSettings) *goanalysis.Linter { - cfg := asasalint.LinterSetting{} - if setting != nil { - cfg.Exclude = setting.Exclude - cfg.NoBuiltinExclusions = !setting.UseBuiltinExclusions - cfg.IgnoreTest = setting.IgnoreTest - } - - a, err := asasalint.NewAnalyzer(cfg) - if err != nil { - internal.LinterLogger.Fatalf("asasalint: create analyzer: %v", err) - } - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/asciicheck/asciicheck.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/asciicheck/asciicheck.go deleted file mode 100644 index 675dfc478..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/asciicheck/asciicheck.go +++ /dev/null @@ -1,19 +0,0 @@ -package asciicheck - -import ( - "github.com/tdakkota/asciicheck" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New() *goanalysis.Linter { - a := asciicheck.NewAnalyzer() - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/bidichk/bidichk.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/bidichk/bidichk.go deleted file mode 100644 index 4ced901e8..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/bidichk/bidichk.go +++ /dev/null @@ -1,59 +0,0 @@ -package bidichk - -import ( - "strings" - - "github.com/breml/bidichk/pkg/bidichk" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(cfg *config.BiDiChkSettings) *goanalysis.Linter { - a := bidichk.NewAnalyzer() - - cfgMap := map[string]map[string]any{} - if cfg != nil { - var opts []string - - if cfg.LeftToRightEmbedding { - opts = append(opts, "LEFT-TO-RIGHT-EMBEDDING") - } - if cfg.RightToLeftEmbedding { - opts = append(opts, "RIGHT-TO-LEFT-EMBEDDING") - } - if cfg.PopDirectionalFormatting { - opts = append(opts, "POP-DIRECTIONAL-FORMATTING") - } - if cfg.LeftToRightOverride { - opts = append(opts, "LEFT-TO-RIGHT-OVERRIDE") - } - if cfg.RightToLeftOverride { - opts = append(opts, "RIGHT-TO-LEFT-OVERRIDE") - } - if cfg.LeftToRightIsolate { - opts = append(opts, "LEFT-TO-RIGHT-ISOLATE") - } - if cfg.RightToLeftIsolate { - opts = append(opts, "RIGHT-TO-LEFT-ISOLATE") - } - if cfg.FirstStrongIsolate { - opts = append(opts, "FIRST-STRONG-ISOLATE") - } - if cfg.PopDirectionalIsolate { - opts = append(opts, "POP-DIRECTIONAL-ISOLATE") - } - - cfgMap[a.Name] = map[string]any{ - "disallowed-runes": strings.Join(opts, ","), - } - } - - return goanalysis.NewLinter( - a.Name, - "Checks for dangerous unicode character sequences", - []*analysis.Analyzer{a}, - cfgMap, - ).WithLoadMode(goanalysis.LoadModeSyntax) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/bodyclose/bodyclose.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/bodyclose/bodyclose.go deleted file mode 100644 index f39814edc..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/bodyclose/bodyclose.go +++ /dev/null @@ -1,19 +0,0 @@ -package bodyclose - -import ( - "github.com/timakin/bodyclose/passes/bodyclose" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New() *goanalysis.Linter { - a := bodyclose.Analyzer - - return goanalysis.NewLinter( - a.Name, - "checks whether HTTP response body is closed successfully", - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/canonicalheader/canonicalheader.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/canonicalheader/canonicalheader.go deleted file mode 100644 index d721916a4..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/canonicalheader/canonicalheader.go +++ /dev/null @@ -1,19 +0,0 @@ -package canonicalheader - -import ( - "github.com/lasiar/canonicalheader" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New() *goanalysis.Linter { - a := canonicalheader.Analyzer - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/containedctx/containedctx.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/containedctx/containedctx.go deleted file mode 100644 index 6fdb4ea6e..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/containedctx/containedctx.go +++ /dev/null @@ -1,19 +0,0 @@ -package containedctx - -import ( - "github.com/sivchari/containedctx" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New() *goanalysis.Linter { - a := containedctx.Analyzer - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/contextcheck/contextcheck.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/contextcheck/contextcheck.go deleted file mode 100644 index a34c518b2..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/contextcheck/contextcheck.go +++ /dev/null @@ -1,22 +0,0 @@ -package contextcheck - -import ( - "github.com/kkHAIKE/contextcheck" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" -) - -func New() *goanalysis.Linter { - analyzer := contextcheck.NewAnalyzer(contextcheck.Configuration{}) - - return goanalysis.NewLinter( - analyzer.Name, - analyzer.Doc, - []*analysis.Analyzer{analyzer}, - nil, - ).WithContextSetter(func(lintCtx *linter.Context) { - analyzer.Run = contextcheck.NewRun(lintCtx.Packages, false) - }).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/copyloopvar/copyloopvar.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/copyloopvar/copyloopvar.go deleted file mode 100644 index adb4ee728..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/copyloopvar/copyloopvar.go +++ /dev/null @@ -1,29 +0,0 @@ -package copyloopvar - -import ( - "github.com/karamaru-alpha/copyloopvar" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(settings *config.CopyLoopVarSettings) *goanalysis.Linter { - a := copyloopvar.NewAnalyzer() - - var cfg map[string]map[string]any - if settings != nil { - cfg = map[string]map[string]any{ - a.Name: { - "check-alias": settings.CheckAlias, - }, - } - } - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeSyntax) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/cyclop/cyclop.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/cyclop/cyclop.go deleted file mode 100644 index 13baba5a6..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/cyclop/cyclop.go +++ /dev/null @@ -1,37 +0,0 @@ -package cyclop - -import ( - "github.com/bkielbasa/cyclop/pkg/analyzer" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(settings *config.Cyclop) *goanalysis.Linter { - a := analyzer.NewAnalyzer() - - var cfg map[string]map[string]any - if settings != nil { - d := map[string]any{ - "skipTests": settings.SkipTests, - } - - if settings.MaxComplexity != 0 { - d["maxComplexity"] = settings.MaxComplexity - } - - if settings.PackageAverage != 0 { - d["packageAverage"] = settings.PackageAverage - } - - cfg = map[string]map[string]any{a.Name: d} - } - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/depguard/depguard.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/depguard/depguard.go deleted file mode 100644 index d2aedf252..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/depguard/depguard.go +++ /dev/null @@ -1,50 +0,0 @@ -package depguard - -import ( - "github.com/OpenPeeDeeP/depguard/v2" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" -) - -func New(settings *config.DepGuardSettings) *goanalysis.Linter { - conf := depguard.LinterSettings{} - - if settings != nil { - for s, rule := range settings.Rules { - list := &depguard.List{ - ListMode: rule.ListMode, - Files: rule.Files, - Allow: rule.Allow, - } - - // because of bug with Viper parsing (split on dot) we use a list of struct instead of a map. - // https://github.com/spf13/viper/issues/324 - // https://github.com/golangci/golangci-lint/issues/3749#issuecomment-1492536630 - - deny := map[string]string{} - for _, r := range rule.Deny { - deny[r.Pkg] = r.Desc - } - list.Deny = deny - - conf[s] = list - } - } - - a := depguard.NewUncompiledAnalyzer(&conf) - - return goanalysis.NewLinter( - a.Analyzer.Name, - a.Analyzer.Doc, - []*analysis.Analyzer{a.Analyzer}, - nil, - ).WithContextSetter(func(lintCtx *linter.Context) { - err := a.Compile() - if err != nil { - lintCtx.Log.Errorf("create analyzer: %v", err) - } - }).WithLoadMode(goanalysis.LoadModeSyntax) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/dogsled/dogsled.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/dogsled/dogsled.go deleted file mode 100644 index 49108f4f1..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/dogsled/dogsled.go +++ /dev/null @@ -1,110 +0,0 @@ -package dogsled - -import ( - "fmt" - "go/ast" - "go/token" - "sync" - - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -const linterName = "dogsled" - -func New(settings *config.DogsledSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues := runDogsled(pass, settings) - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f())", - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) -} - -func runDogsled(pass *analysis.Pass, settings *config.DogsledSettings) []goanalysis.Issue { - var reports []goanalysis.Issue - for _, f := range pass.Files { - v := &returnsVisitor{ - maxBlanks: settings.MaxBlankIdentifiers, - f: pass.Fset, - } - - ast.Walk(v, f) - - for i := range v.issues { - reports = append(reports, goanalysis.NewIssue(&v.issues[i], pass)) - } - } - - return reports -} - -type returnsVisitor struct { - f *token.FileSet - maxBlanks int - issues []result.Issue -} - -func (v *returnsVisitor) Visit(node ast.Node) ast.Visitor { - funcDecl, ok := node.(*ast.FuncDecl) - if !ok { - return v - } - if funcDecl.Body == nil { - return v - } - - for _, expr := range funcDecl.Body.List { - assgnStmt, ok := expr.(*ast.AssignStmt) - if !ok { - continue - } - - numBlank := 0 - for _, left := range assgnStmt.Lhs { - ident, ok := left.(*ast.Ident) - if !ok { - continue - } - if ident.Name == "_" { - numBlank++ - } - } - - if numBlank > v.maxBlanks { - v.issues = append(v.issues, result.Issue{ - FromLinter: linterName, - Text: fmt.Sprintf("declaration has %v blank identifiers", numBlank), - Pos: v.f.Position(assgnStmt.Pos()), - }) - } - } - return v -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/dupl/dupl.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/dupl/dupl.go deleted file mode 100644 index 7abcb4c4f..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/dupl/dupl.go +++ /dev/null @@ -1,96 +0,0 @@ -package dupl - -import ( - "fmt" - "go/token" - "sync" - - duplAPI "github.com/golangci/dupl" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/fsutils" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/golinters/internal" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -const linterName = "dupl" - -func New(settings *config.DuplSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues, err := runDupl(pass, settings) - if err != nil { - return nil, err - } - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Tool for code clone detection", - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) -} - -func runDupl(pass *analysis.Pass, settings *config.DuplSettings) ([]goanalysis.Issue, error) { - fileNames := internal.GetFileNames(pass) - - issues, err := duplAPI.Run(fileNames, settings.Threshold) - if err != nil { - return nil, err - } - - if len(issues) == 0 { - return nil, nil - } - - res := make([]goanalysis.Issue, 0, len(issues)) - - for _, i := range issues { - toFilename, err := fsutils.ShortestRelPath(i.To.Filename(), "") - if err != nil { - return nil, fmt.Errorf("failed to get shortest rel path for %q: %w", i.To.Filename(), err) - } - - dupl := fmt.Sprintf("%s:%d-%d", toFilename, i.To.LineStart(), i.To.LineEnd()) - text := fmt.Sprintf("%d-%d lines are duplicate of %s", - i.From.LineStart(), i.From.LineEnd(), - internal.FormatCode(dupl, nil)) - - res = append(res, goanalysis.NewIssue(&result.Issue{ - Pos: token.Position{ - Filename: i.From.Filename(), - Line: i.From.LineStart(), - }, - LineRange: &result.Range{ - From: i.From.LineStart(), - To: i.From.LineEnd(), - }, - Text: text, - FromLinter: linterName, - }, pass)) - } - - return res, nil -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/dupword/dupword.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/dupword/dupword.go deleted file mode 100644 index bba4fc9e1..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/dupword/dupword.go +++ /dev/null @@ -1,30 +0,0 @@ -package dupword - -import ( - "strings" - - "github.com/Abirdcfly/dupword" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(setting *config.DupWordSettings) *goanalysis.Linter { - a := dupword.NewAnalyzer() - - cfgMap := map[string]map[string]any{} - if setting != nil { - cfgMap[a.Name] = map[string]any{ - "keyword": strings.Join(setting.Keywords, ","), - "ignore": strings.Join(setting.Ignore, ","), - } - } - - return goanalysis.NewLinter( - a.Name, - "checks for duplicate words in the source code", - []*analysis.Analyzer{a}, - cfgMap, - ).WithLoadMode(goanalysis.LoadModeSyntax) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/durationcheck/durationcheck.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/durationcheck/durationcheck.go deleted file mode 100644 index 88f22c27c..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/durationcheck/durationcheck.go +++ /dev/null @@ -1,19 +0,0 @@ -package durationcheck - -import ( - "github.com/charithe/durationcheck" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New() *goanalysis.Linter { - a := durationcheck.Analyzer - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/err113/err113.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/err113/err113.go deleted file mode 100644 index 2600128be..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/err113/err113.go +++ /dev/null @@ -1,19 +0,0 @@ -package err113 - -import ( - "github.com/Djarvur/go-err113" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New() *goanalysis.Linter { - a := err113.NewAnalyzer() - - return goanalysis.NewLinter( - a.Name, - "Go linter to check the errors handling expressions", - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/errcheck/errcheck.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/errcheck/errcheck.go deleted file mode 100644 index 9a8a2aa87..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/errcheck/errcheck.go +++ /dev/null @@ -1,271 +0,0 @@ -package errcheck - -import ( - "bufio" - "fmt" - "os" - "os/user" - "path/filepath" - "regexp" - "strings" - "sync" - - "github.com/kisielk/errcheck/errcheck" - "golang.org/x/tools/go/analysis" - "golang.org/x/tools/go/packages" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/fsutils" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/golinters/internal" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -const linterName = "errcheck" - -func New(settings *config.ErrcheckSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: goanalysis.DummyRun, - } - - return goanalysis.NewLinter( - linterName, - "errcheck is a program for checking for unchecked errors in Go code. "+ - "These unchecked errors can be critical bugs in some cases", - []*analysis.Analyzer{analyzer}, - nil, - ).WithContextSetter(func(lintCtx *linter.Context) { - // copied from errcheck - checker, err := getChecker(settings) - if err != nil { - lintCtx.Log.Errorf("failed to get checker: %v", err) - return - } - - checker.Tags = lintCtx.Cfg.Run.BuildTags - - analyzer.Run = func(pass *analysis.Pass) (any, error) { - issues := runErrCheck(lintCtx, pass, checker) - if err != nil { - return nil, err - } - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - } - }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeTypesInfo) -} - -func runErrCheck(lintCtx *linter.Context, pass *analysis.Pass, checker *errcheck.Checker) []goanalysis.Issue { - pkg := &packages.Package{ - Fset: pass.Fset, - Syntax: pass.Files, - Types: pass.Pkg, - TypesInfo: pass.TypesInfo, - } - - lintIssues := checker.CheckPackage(pkg).Unique() - if len(lintIssues.UncheckedErrors) == 0 { - return nil - } - - issues := make([]goanalysis.Issue, len(lintIssues.UncheckedErrors)) - - for i, err := range lintIssues.UncheckedErrors { - text := "Error return value is not checked" - - if err.FuncName != "" { - code := err.SelectorName - if err.SelectorName == "" { - code = err.FuncName - } - - text = fmt.Sprintf("Error return value of %s is not checked", internal.FormatCode(code, lintCtx.Cfg)) - } - - issues[i] = goanalysis.NewIssue( - &result.Issue{ - FromLinter: linterName, - Text: text, - Pos: err.Pos, - }, - pass, - ) - } - - return issues -} - -// parseIgnoreConfig was taken from errcheck in order to keep the API identical. -// https://github.com/kisielk/errcheck/blob/1787c4bee836470bf45018cfbc783650db3c6501/main.go#L25-L60 -func parseIgnoreConfig(s string) (map[string]*regexp.Regexp, error) { - if s == "" { - return nil, nil - } - - cfg := map[string]*regexp.Regexp{} - - for _, pair := range strings.Split(s, ",") { - colonIndex := strings.Index(pair, ":") - var pkg, re string - if colonIndex == -1 { - pkg = "" - re = pair - } else { - pkg = pair[:colonIndex] - re = pair[colonIndex+1:] - } - regex, err := regexp.Compile(re) - if err != nil { - return nil, err - } - cfg[pkg] = regex - } - - return cfg, nil -} - -func getChecker(errCfg *config.ErrcheckSettings) (*errcheck.Checker, error) { - ignoreConfig, err := parseIgnoreConfig(errCfg.Ignore) - if err != nil { - return nil, fmt.Errorf("failed to parse 'ignore' directive: %w", err) - } - - checker := errcheck.Checker{ - Exclusions: errcheck.Exclusions{ - BlankAssignments: !errCfg.CheckAssignToBlank, - TypeAssertions: !errCfg.CheckTypeAssertions, - SymbolRegexpsByPackage: map[string]*regexp.Regexp{}, - }, - } - - if !errCfg.DisableDefaultExclusions { - checker.Exclusions.Symbols = append(checker.Exclusions.Symbols, errcheck.DefaultExcludedSymbols...) - } - - for pkg, re := range ignoreConfig { - checker.Exclusions.SymbolRegexpsByPackage[pkg] = re - } - - if errCfg.Exclude != "" { - exclude, err := readExcludeFile(errCfg.Exclude) - if err != nil { - return nil, err - } - - checker.Exclusions.Symbols = append(checker.Exclusions.Symbols, exclude...) - } - - checker.Exclusions.Symbols = append(checker.Exclusions.Symbols, errCfg.ExcludeFunctions...) - - return &checker, nil -} - -func getFirstPathArg() string { - args := os.Args - - // skip all args ([golangci-lint, run/linters]) before files/dirs list - for len(args) != 0 { - if args[0] == "run" { - args = args[1:] - break - } - - args = args[1:] - } - - // find first file/dir arg - firstArg := "./..." - for _, arg := range args { - if !strings.HasPrefix(arg, "-") { - firstArg = arg - break - } - } - - return firstArg -} - -func setupConfigFileSearch(name string) []string { - if strings.HasPrefix(name, "~") { - if u, err := user.Current(); err == nil { - name = strings.Replace(name, "~", u.HomeDir, 1) - } - } - - if filepath.IsAbs(name) { - return []string{name} - } - - firstArg := getFirstPathArg() - - absStartPath, err := filepath.Abs(firstArg) - if err != nil { - absStartPath = filepath.Clean(firstArg) - } - - // start from it - var curDir string - if fsutils.IsDir(absStartPath) { - curDir = absStartPath - } else { - curDir = filepath.Dir(absStartPath) - } - - // find all dirs from it up to the root - configSearchPaths := []string{filepath.Join(".", name)} - for { - configSearchPaths = append(configSearchPaths, filepath.Join(curDir, name)) - newCurDir := filepath.Dir(curDir) - if curDir == newCurDir || newCurDir == "" { - break - } - curDir = newCurDir - } - - return configSearchPaths -} - -func readExcludeFile(name string) ([]string, error) { - var err error - var fh *os.File - - for _, path := range setupConfigFileSearch(name) { - if fh, err = os.Open(path); err == nil { - break - } - } - - if fh == nil { - return nil, fmt.Errorf("failed reading exclude file: %s: %w", name, err) - } - defer func() { _ = fh.Close() }() - - scanner := bufio.NewScanner(fh) - - var excludes []string - for scanner.Scan() { - excludes = append(excludes, scanner.Text()) - } - - if err := scanner.Err(); err != nil { - return nil, fmt.Errorf("failed scanning file: %s: %w", name, err) - } - - return excludes, nil -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/errchkjson/errchkjson.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/errchkjson/errchkjson.go deleted file mode 100644 index 8389a750c..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/errchkjson/errchkjson.go +++ /dev/null @@ -1,31 +0,0 @@ -package errchkjson - -import ( - "github.com/breml/errchkjson" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(cfg *config.ErrChkJSONSettings) *goanalysis.Linter { - a := errchkjson.NewAnalyzer() - - cfgMap := map[string]map[string]any{} - cfgMap[a.Name] = map[string]any{ - "omit-safe": true, - } - if cfg != nil { - cfgMap[a.Name] = map[string]any{ - "omit-safe": !cfg.CheckErrorFreeEncoding, - "report-no-exported": cfg.ReportNoExported, - } - } - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfgMap, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/errname/errname.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/errname/errname.go deleted file mode 100644 index f868854c1..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/errname/errname.go +++ /dev/null @@ -1,19 +0,0 @@ -package errname - -import ( - "github.com/Antonboom/errname/pkg/analyzer" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New() *goanalysis.Linter { - a := analyzer.New() - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/errorlint/errorlint.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/errorlint/errorlint.go deleted file mode 100644 index 86db8552d..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/errorlint/errorlint.go +++ /dev/null @@ -1,54 +0,0 @@ -package errorlint - -import ( - "github.com/polyfloyd/go-errorlint/errorlint" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(cfg *config.ErrorLintSettings) *goanalysis.Linter { - var opts []errorlint.Option - - if cfg != nil { - ae := toAllowPairs(cfg.AllowedErrors) - if len(ae) > 0 { - opts = append(opts, errorlint.WithAllowedErrors(ae)) - } - - aew := toAllowPairs(cfg.AllowedErrorsWildcard) - if len(aew) > 0 { - opts = append(opts, errorlint.WithAllowedWildcard(aew)) - } - } - - a := errorlint.NewAnalyzer(opts...) - - cfgMap := map[string]map[string]any{} - - if cfg != nil { - cfgMap[a.Name] = map[string]any{ - "errorf": cfg.Errorf, - "errorf-multi": cfg.ErrorfMulti, - "asserts": cfg.Asserts, - "comparison": cfg.Comparison, - } - } - - return goanalysis.NewLinter( - a.Name, - "errorlint is a linter for that can be used to find code "+ - "that will cause problems with the error wrapping scheme introduced in Go 1.13.", - []*analysis.Analyzer{a}, - cfgMap, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} - -func toAllowPairs(data []config.ErrorLintAllowPair) []errorlint.AllowPair { - var pairs []errorlint.AllowPair - for _, allowedError := range data { - pairs = append(pairs, errorlint.AllowPair(allowedError)) - } - return pairs -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/exhaustive/exhaustive.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/exhaustive/exhaustive.go deleted file mode 100644 index 9249efb69..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/exhaustive/exhaustive.go +++ /dev/null @@ -1,37 +0,0 @@ -package exhaustive - -import ( - "github.com/nishanths/exhaustive" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(settings *config.ExhaustiveSettings) *goanalysis.Linter { - a := exhaustive.Analyzer - - var cfg map[string]map[string]any - if settings != nil { - cfg = map[string]map[string]any{ - a.Name: { - exhaustive.CheckFlag: settings.Check, - exhaustive.CheckGeneratedFlag: settings.CheckGenerated, - exhaustive.DefaultSignifiesExhaustiveFlag: settings.DefaultSignifiesExhaustive, - exhaustive.IgnoreEnumMembersFlag: settings.IgnoreEnumMembers, - exhaustive.IgnoreEnumTypesFlag: settings.IgnoreEnumTypes, - exhaustive.PackageScopeOnlyFlag: settings.PackageScopeOnly, - exhaustive.ExplicitExhaustiveMapFlag: settings.ExplicitExhaustiveMap, - exhaustive.ExplicitExhaustiveSwitchFlag: settings.ExplicitExhaustiveSwitch, - exhaustive.DefaultCaseRequiredFlag: settings.DefaultCaseRequired, - }, - } - } - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/exhaustruct/exhaustruct.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/exhaustruct/exhaustruct.go deleted file mode 100644 index 53ad87154..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/exhaustruct/exhaustruct.go +++ /dev/null @@ -1,30 +0,0 @@ -package exhaustruct - -import ( - "github.com/GaijinEntertainment/go-exhaustruct/v3/analyzer" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/golinters/internal" -) - -func New(settings *config.ExhaustructSettings) *goanalysis.Linter { - var include, exclude []string - if settings != nil { - include = settings.Include - exclude = settings.Exclude - } - - a, err := analyzer.NewAnalyzer(include, exclude) - if err != nil { - internal.LinterLogger.Fatalf("exhaustruct configuration: %v", err) - } - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/exportloopref/exportloopref.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/exportloopref/exportloopref.go deleted file mode 100644 index e232f8045..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/exportloopref/exportloopref.go +++ /dev/null @@ -1,19 +0,0 @@ -package exportloopref - -import ( - "github.com/kyoh86/exportloopref" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New() *goanalysis.Linter { - a := exportloopref.Analyzer - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/fatcontext/fatcontext.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/fatcontext/fatcontext.go deleted file mode 100644 index 378025a8c..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/fatcontext/fatcontext.go +++ /dev/null @@ -1,19 +0,0 @@ -package fatcontext - -import ( - "github.com/Crocmagnon/fatcontext/pkg/analyzer" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New() *goanalysis.Linter { - a := analyzer.Analyzer - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/forbidigo/forbidigo.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/forbidigo/forbidigo.go deleted file mode 100644 index 3572b60c2..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/forbidigo/forbidigo.go +++ /dev/null @@ -1,103 +0,0 @@ -package forbidigo - -import ( - "fmt" - "sync" - - "github.com/ashanbrown/forbidigo/forbidigo" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/logutils" - "github.com/golangci/golangci-lint/pkg/result" -) - -const linterName = "forbidigo" - -func New(settings *config.ForbidigoSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues, err := runForbidigo(pass, settings) - if err != nil { - return nil, err - } - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - return nil, nil - }, - } - - // Without AnalyzeTypes, LoadModeSyntax is enough. - // But we cannot make this depend on the settings and have to mirror the mode chosen in GetAllSupportedLinterConfigs, - // therefore we have to use LoadModeTypesInfo in all cases. - return goanalysis.NewLinter( - linterName, - "Forbids identifiers", - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeTypesInfo) -} - -func runForbidigo(pass *analysis.Pass, settings *config.ForbidigoSettings) ([]goanalysis.Issue, error) { - options := []forbidigo.Option{ - forbidigo.OptionExcludeGodocExamples(settings.ExcludeGodocExamples), - // disable "//permit" directives so only "//nolint" directives matters within golangci-lint - forbidigo.OptionIgnorePermitDirectives(true), - forbidigo.OptionAnalyzeTypes(settings.AnalyzeTypes), - } - - // Convert patterns back to strings because that is what NewLinter accepts. - var patterns []string - for _, pattern := range settings.Forbid { - buffer, err := pattern.MarshalString() - if err != nil { - return nil, err - } - patterns = append(patterns, string(buffer)) - } - - forbid, err := forbidigo.NewLinter(patterns, options...) - if err != nil { - return nil, fmt.Errorf("failed to create linter %q: %w", linterName, err) - } - - var issues []goanalysis.Issue - for _, file := range pass.Files { - runConfig := forbidigo.RunConfig{ - Fset: pass.Fset, - DebugLog: logutils.Debug(logutils.DebugKeyForbidigo), - } - if settings != nil && settings.AnalyzeTypes { - runConfig.TypesInfo = pass.TypesInfo - } - hints, err := forbid.RunWithConfig(runConfig, file) - if err != nil { - return nil, fmt.Errorf("forbidigo linter failed on file %q: %w", file.Name.String(), err) - } - - for _, hint := range hints { - issues = append(issues, goanalysis.NewIssue(&result.Issue{ - Pos: hint.Position(), - Text: hint.Details(), - FromLinter: linterName, - }, pass)) - } - } - - return issues, nil -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/forcetypeassert/forcetypeassert.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/forcetypeassert/forcetypeassert.go deleted file mode 100644 index 741b57cea..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/forcetypeassert/forcetypeassert.go +++ /dev/null @@ -1,19 +0,0 @@ -package forcetypeassert - -import ( - "github.com/gostaticanalysis/forcetypeassert" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New() *goanalysis.Linter { - a := forcetypeassert.Analyzer - - return goanalysis.NewLinter( - a.Name, - "finds forced type assertions", - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/funlen/funlen.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/funlen/funlen.go deleted file mode 100644 index e43339394..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/funlen/funlen.go +++ /dev/null @@ -1,75 +0,0 @@ -package funlen - -import ( - "go/token" - "strings" - "sync" - - "github.com/ultraware/funlen" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -const linterName = "funlen" - -func New(settings *config.FunlenSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues := runFunlen(pass, settings) - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Tool for detection of long functions", - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) -} - -func runFunlen(pass *analysis.Pass, settings *config.FunlenSettings) []goanalysis.Issue { - var lintIssues []funlen.Message - for _, file := range pass.Files { - fileIssues := funlen.Run(file, pass.Fset, settings.Lines, settings.Statements, settings.IgnoreComments) - lintIssues = append(lintIssues, fileIssues...) - } - - if len(lintIssues) == 0 { - return nil - } - - issues := make([]goanalysis.Issue, len(lintIssues)) - for k, i := range lintIssues { - issues[k] = goanalysis.NewIssue(&result.Issue{ - Pos: token.Position{ - Filename: i.Pos.Filename, - Line: i.Pos.Line, - }, - Text: strings.TrimRight(i.Message, "\n"), - FromLinter: linterName, - }, pass) - } - - return issues -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gci/gci.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gci/gci.go deleted file mode 100644 index a9afb6c89..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gci/gci.go +++ /dev/null @@ -1,250 +0,0 @@ -package gci - -import ( - "fmt" - "sort" - "strings" - "sync" - - gcicfg "github.com/daixiang0/gci/pkg/config" - "github.com/daixiang0/gci/pkg/gci" - "github.com/daixiang0/gci/pkg/io" - "github.com/daixiang0/gci/pkg/log" - "github.com/daixiang0/gci/pkg/section" - "github.com/golangci/modinfo" - "github.com/hexops/gotextdiff" - "github.com/hexops/gotextdiff/myers" - "github.com/hexops/gotextdiff/span" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/golinters/internal" - "github.com/golangci/golangci-lint/pkg/lint/linter" -) - -const linterName = "gci" - -func New(settings *config.GciSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: goanalysis.DummyRun, - Requires: []*analysis.Analyzer{ - modinfo.Analyzer, - }, - } - - var cfg *gcicfg.Config - if settings != nil { - rawCfg := gcicfg.YamlConfig{ - Cfg: gcicfg.BoolConfig{ - SkipGenerated: settings.SkipGenerated, - CustomOrder: settings.CustomOrder, - NoLexOrder: settings.NoLexOrder, - }, - SectionStrings: settings.Sections, - } - - if settings.LocalPrefixes != "" { - prefix := []string{"standard", "default", fmt.Sprintf("prefix(%s)", settings.LocalPrefixes)} - rawCfg.SectionStrings = prefix - } - - var err error - cfg, err = YamlConfig{origin: rawCfg}.Parse() - if err != nil { - internal.LinterLogger.Fatalf("gci: configuration parsing: %v", err) - } - } - - var lock sync.Mutex - - return goanalysis.NewLinter( - linterName, - "Gci controls Go package import order and makes it always deterministic.", - []*analysis.Analyzer{analyzer}, - nil, - ).WithContextSetter(func(lintCtx *linter.Context) { - analyzer.Run = func(pass *analysis.Pass) (any, error) { - var err error - cfg.Sections, err = hackSectionList(pass, cfg) - if err != nil { - return nil, err - } - - issues, err := runGci(pass, lintCtx, cfg, &lock) - if err != nil { - return nil, err - } - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - } - }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) -} - -func runGci(pass *analysis.Pass, lintCtx *linter.Context, cfg *gcicfg.Config, lock *sync.Mutex) ([]goanalysis.Issue, error) { - fileNames := internal.GetFileNames(pass) - - var diffs []string - err := diffFormattedFilesToArray(fileNames, *cfg, &diffs, lock) - if err != nil { - return nil, err - } - - var issues []goanalysis.Issue - - for _, diff := range diffs { - if diff == "" { - continue - } - - is, err := internal.ExtractIssuesFromPatch(diff, lintCtx, linterName, getIssuedTextGci) - if err != nil { - return nil, fmt.Errorf("can't extract issues from gci diff output %s: %w", diff, err) - } - - for i := range is { - issues = append(issues, goanalysis.NewIssue(&is[i], pass)) - } - } - - return issues, nil -} - -func getIssuedTextGci(settings *config.LintersSettings) string { - text := "File is not `gci`-ed" - - hasOptions := settings.Gci.SkipGenerated || len(settings.Gci.Sections) > 0 - if !hasOptions { - return text - } - - text += " with" - - if settings.Gci.SkipGenerated { - text += " --skip-generated" - } - - if len(settings.Gci.Sections) > 0 { - for _, sect := range settings.Gci.Sections { - text += " -s " + sect - } - } - - if settings.Gci.CustomOrder { - text += " --custom-order" - } - - return text -} - -func hackSectionList(pass *analysis.Pass, cfg *gcicfg.Config) (section.SectionList, error) { - var sections section.SectionList - - for _, sect := range cfg.Sections { - // local module hack - if v, ok := sect.(*section.LocalModule); ok { - info, err := modinfo.FindModuleFromPass(pass) - if err != nil { - return nil, err - } - - if info.Path == "" { - continue - } - - v.Path = info.Path - } - - sections = append(sections, sect) - } - - return sections, nil -} - -// diffFormattedFilesToArray is a copy of gci.DiffFormattedFilesToArray without io.StdInGenerator. -// gci.DiffFormattedFilesToArray uses gci.processStdInAndGoFilesInPaths that uses io.StdInGenerator but stdin is not active on CI. -// https://github.com/daixiang0/gci/blob/6f5cb16718ba07f0342a58de9b830ec5a6d58790/pkg/gci/gci.go#L63-L75 -// https://github.com/daixiang0/gci/blob/6f5cb16718ba07f0342a58de9b830ec5a6d58790/pkg/gci/gci.go#L80 -func diffFormattedFilesToArray(paths []string, cfg gcicfg.Config, diffs *[]string, lock *sync.Mutex) error { - log.InitLogger() - defer func() { _ = log.L().Sync() }() - - return gci.ProcessFiles(io.GoFilesInPathsGenerator(paths, true), cfg, func(filePath string, unmodifiedFile, formattedFile []byte) error { - fileURI := span.URIFromPath(filePath) - edits := myers.ComputeEdits(fileURI, string(unmodifiedFile), string(formattedFile)) - unifiedEdits := gotextdiff.ToUnified(filePath, filePath, string(unmodifiedFile), edits) - lock.Lock() - *diffs = append(*diffs, fmt.Sprint(unifiedEdits)) - lock.Unlock() - return nil - }) -} - -// Code below this comment is borrowed and modified from gci. -// https://github.com/daixiang0/gci/blob/v0.13.5/pkg/config/config.go - -var defaultOrder = map[string]int{ - section.StandardType: 0, - section.DefaultType: 1, - section.CustomType: 2, - section.BlankType: 3, - section.DotType: 4, - section.AliasType: 5, - section.LocalModuleType: 6, -} - -type YamlConfig struct { - origin gcicfg.YamlConfig -} - -//nolint:gocritic // code borrowed from gci and modified to fix LocalModule section behavior. -func (g YamlConfig) Parse() (*gcicfg.Config, error) { - var err error - - sections, err := section.Parse(g.origin.SectionStrings) - if err != nil { - return nil, err - } - - if sections == nil { - sections = section.DefaultSections() - } - - // if default order sorted sections - if !g.origin.Cfg.CustomOrder { - sort.Slice(sections, func(i, j int) bool { - sectionI, sectionJ := sections[i].Type(), sections[j].Type() - - if g.origin.Cfg.NoLexOrder || strings.Compare(sectionI, sectionJ) != 0 { - return defaultOrder[sectionI] < defaultOrder[sectionJ] - } - - return strings.Compare(sections[i].String(), sections[j].String()) < 0 - }) - } - - sectionSeparators, err := section.Parse(g.origin.SectionSeparatorStrings) - if err != nil { - return nil, err - } - if sectionSeparators == nil { - sectionSeparators = section.DefaultSectionSeparators() - } - - return &gcicfg.Config{BoolConfig: g.origin.Cfg, Sections: sections, SectionSeparators: sectionSeparators}, nil -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/ginkgolinter/ginkgolinter.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/ginkgolinter/ginkgolinter.go deleted file mode 100644 index 9873c9ba4..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/ginkgolinter/ginkgolinter.go +++ /dev/null @@ -1,40 +0,0 @@ -package ginkgolinter - -import ( - "github.com/nunnatsa/ginkgolinter" - "github.com/nunnatsa/ginkgolinter/types" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(settings *config.GinkgoLinterSettings) *goanalysis.Linter { - cfg := &types.Config{} - - if settings != nil { - cfg = &types.Config{ - SuppressLen: types.Boolean(settings.SuppressLenAssertion), - SuppressNil: types.Boolean(settings.SuppressNilAssertion), - SuppressErr: types.Boolean(settings.SuppressErrAssertion), - SuppressCompare: types.Boolean(settings.SuppressCompareAssertion), - SuppressAsync: types.Boolean(settings.SuppressAsyncAssertion), - ForbidFocus: types.Boolean(settings.ForbidFocusContainer), - SuppressTypeCompare: types.Boolean(settings.SuppressTypeCompareWarning), - AllowHaveLen0: types.Boolean(settings.AllowHaveLenZero), - ForceExpectTo: types.Boolean(settings.ForceExpectTo), - ValidateAsyncIntervals: types.Boolean(settings.ValidateAsyncIntervals), - ForbidSpecPollution: types.Boolean(settings.ForbidSpecPollution), - ForceSucceedForFuncs: types.Boolean(settings.ForceSucceedForFuncs), - } - } - - a := ginkgolinter.NewAnalyzerWithConfig(cfg) - - return goanalysis.NewLinter( - a.Name, - "enforces standards of using ginkgo and gomega", - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocheckcompilerdirectives/gocheckcompilerdirectives.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocheckcompilerdirectives/gocheckcompilerdirectives.go deleted file mode 100644 index be604d805..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocheckcompilerdirectives/gocheckcompilerdirectives.go +++ /dev/null @@ -1,19 +0,0 @@ -package gocheckcompilerdirectives - -import ( - "4d63.com/gocheckcompilerdirectives/checkcompilerdirectives" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New() *goanalysis.Linter { - a := checkcompilerdirectives.Analyzer() - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gochecknoglobals/gochecknoglobals.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gochecknoglobals/gochecknoglobals.go deleted file mode 100644 index af22b2f8e..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gochecknoglobals/gochecknoglobals.go +++ /dev/null @@ -1,26 +0,0 @@ -package gochecknoglobals - -import ( - "4d63.com/gochecknoglobals/checknoglobals" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New() *goanalysis.Linter { - a := checknoglobals.Analyzer() - - // gochecknoglobals only lints test files if the `-t` flag is passed, - // so we pass the `t` flag as true to the analyzer before running it. - // This can be turned off by using the regular golangci-lint flags such as `--tests` or `--exclude-files`. - linterConfig := map[string]map[string]any{ - a.Name: {"t": true}, - } - - return goanalysis.NewLinter( - a.Name, - "Check that no global variables exist.", - []*analysis.Analyzer{a}, - linterConfig, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gochecknoinits/gochecknoinits.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gochecknoinits/gochecknoinits.go deleted file mode 100644 index 1345eb8c2..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gochecknoinits/gochecknoinits.go +++ /dev/null @@ -1,75 +0,0 @@ -package gochecknoinits - -import ( - "fmt" - "go/ast" - "go/token" - "sync" - - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/golinters/internal" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -const linterName = "gochecknoinits" - -func New() *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - var res []goanalysis.Issue - for _, file := range pass.Files { - fileIssues := checkFileForInits(file, pass.Fset) - for i := range fileIssues { - res = append(res, goanalysis.NewIssue(&fileIssues[i], pass)) - } - } - if len(res) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, res...) - mu.Unlock() - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Checks that no init functions are present in Go code", - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) -} - -func checkFileForInits(f *ast.File, fset *token.FileSet) []result.Issue { - var res []result.Issue - for _, decl := range f.Decls { - funcDecl, ok := decl.(*ast.FuncDecl) - if !ok { - continue - } - - fnName := funcDecl.Name.Name - if fnName == "init" && funcDecl.Recv.NumFields() == 0 { - res = append(res, result.Issue{ - Pos: fset.Position(funcDecl.Pos()), - Text: fmt.Sprintf("don't use %s function", internal.FormatCode(fnName, nil)), - FromLinter: linterName, - }) - } - } - - return res -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gochecksumtype/gochecksumtype.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gochecksumtype/gochecksumtype.go deleted file mode 100644 index 7aab0efeb..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gochecksumtype/gochecksumtype.go +++ /dev/null @@ -1,82 +0,0 @@ -package gochecksumtype - -import ( - "strings" - "sync" - - gochecksumtype "github.com/alecthomas/go-check-sumtype" - "golang.org/x/tools/go/analysis" - "golang.org/x/tools/go/packages" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -const linterName = "gochecksumtype" - -func New(settings *config.GoChecksumTypeSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues, err := runGoCheckSumType(pass, settings) - if err != nil { - return nil, err - } - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - `Run exhaustiveness checks on Go "sum types"`, - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(_ *linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeTypesInfo) -} - -func runGoCheckSumType(pass *analysis.Pass, settings *config.GoChecksumTypeSettings) ([]goanalysis.Issue, error) { - var resIssues []goanalysis.Issue - - pkg := &packages.Package{ - Fset: pass.Fset, - Syntax: pass.Files, - Types: pass.Pkg, - TypesInfo: pass.TypesInfo, - } - - var unknownError error - errors := gochecksumtype.Run([]*packages.Package{pkg}, - gochecksumtype.Config{DefaultSignifiesExhaustive: settings.DefaultSignifiesExhaustive}) - for _, err := range errors { - err, ok := err.(gochecksumtype.Error) - if !ok { - unknownError = err - continue - } - - resIssues = append(resIssues, goanalysis.NewIssue(&result.Issue{ - FromLinter: linterName, - Text: strings.TrimPrefix(err.Error(), err.Pos().String()+": "), - Pos: err.Pos(), - }, pass)) - } - - return resIssues, unknownError -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocognit/gocognit.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocognit/gocognit.go deleted file mode 100644 index 5fe0f90f0..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocognit/gocognit.go +++ /dev/null @@ -1,80 +0,0 @@ -package gocognit - -import ( - "fmt" - "sort" - "sync" - - "github.com/uudashr/gocognit" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/golinters/internal" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -const linterName = "gocognit" - -func New(settings *config.GocognitSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - analyzer := &analysis.Analyzer{ - Name: goanalysis.TheOnlyAnalyzerName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues := runGocognit(pass, settings) - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Computes and checks the cognitive complexity of functions", - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) -} - -func runGocognit(pass *analysis.Pass, settings *config.GocognitSettings) []goanalysis.Issue { - var stats []gocognit.Stat - for _, f := range pass.Files { - stats = gocognit.ComplexityStats(f, pass.Fset, stats) - } - if len(stats) == 0 { - return nil - } - - sort.SliceStable(stats, func(i, j int) bool { - return stats[i].Complexity > stats[j].Complexity - }) - - issues := make([]goanalysis.Issue, 0, len(stats)) - for _, s := range stats { - if s.Complexity <= settings.MinComplexity { - break // Break as the stats is already sorted from greatest to least - } - - issues = append(issues, goanalysis.NewIssue(&result.Issue{ - Pos: s.Pos, - Text: fmt.Sprintf("cognitive complexity %d of func %s is high (> %d)", - s.Complexity, internal.FormatCode(s.FuncName, nil), settings.MinComplexity), - FromLinter: linterName, - }, pass)) - } - - return issues -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goconst/goconst.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/goconst/goconst.go deleted file mode 100644 index 07bed301f..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goconst/goconst.go +++ /dev/null @@ -1,98 +0,0 @@ -package goconst - -import ( - "fmt" - "sync" - - goconstAPI "github.com/jgautheron/goconst" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/golinters/internal" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -const linterName = "goconst" - -func New(settings *config.GoConstSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues, err := runGoconst(pass, settings) - if err != nil { - return nil, err - } - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Finds repeated strings that could be replaced by a constant", - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) -} - -func runGoconst(pass *analysis.Pass, settings *config.GoConstSettings) ([]goanalysis.Issue, error) { - cfg := goconstAPI.Config{ - IgnoreStrings: settings.IgnoreStrings, - IgnoreTests: settings.IgnoreTests, - MatchWithConstants: settings.MatchWithConstants, - MinStringLength: settings.MinStringLen, - MinOccurrences: settings.MinOccurrencesCount, - ParseNumbers: settings.ParseNumbers, - NumberMin: settings.NumberMin, - NumberMax: settings.NumberMax, - ExcludeTypes: map[goconstAPI.Type]bool{}, - } - - if settings.IgnoreCalls { - cfg.ExcludeTypes[goconstAPI.Call] = true - } - - lintIssues, err := goconstAPI.Run(pass.Files, pass.Fset, &cfg) - if err != nil { - return nil, err - } - - if len(lintIssues) == 0 { - return nil, nil - } - - res := make([]goanalysis.Issue, 0, len(lintIssues)) - for _, i := range lintIssues { - text := fmt.Sprintf("string %s has %d occurrences", internal.FormatCode(i.Str, nil), i.OccurrencesCount) - - if i.MatchingConst == "" { - text += ", make it a constant" - } else { - text += fmt.Sprintf(", but such constant %s already exists", internal.FormatCode(i.MatchingConst, nil)) - } - - res = append(res, goanalysis.NewIssue(&result.Issue{ - Pos: i.Pos, - Text: text, - FromLinter: linterName, - }, pass)) - } - - return res, nil -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocyclo/gocyclo.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocyclo/gocyclo.go deleted file mode 100644 index 51333dc15..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocyclo/gocyclo.go +++ /dev/null @@ -1,76 +0,0 @@ -package gocyclo - -import ( - "fmt" - "sync" - - "github.com/fzipp/gocyclo" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/golinters/internal" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -const linterName = "gocyclo" - -func New(settings *config.GoCycloSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues := runGoCyclo(pass, settings) - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Computes and checks the cyclomatic complexity of functions", - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) -} - -func runGoCyclo(pass *analysis.Pass, settings *config.GoCycloSettings) []goanalysis.Issue { - var stats gocyclo.Stats - for _, f := range pass.Files { - stats = gocyclo.AnalyzeASTFile(f, pass.Fset, stats) - } - if len(stats) == 0 { - return nil - } - - stats = stats.SortAndFilter(-1, settings.MinComplexity) - - issues := make([]goanalysis.Issue, 0, len(stats)) - - for _, s := range stats { - text := fmt.Sprintf("cyclomatic complexity %d of func %s is high (> %d)", - s.Complexity, internal.FormatCode(s.FuncName, nil), settings.MinComplexity) - - issues = append(issues, goanalysis.NewIssue(&result.Issue{ - Pos: s.Pos, - Text: text, - FromLinter: linterName, - }, pass)) - } - - return issues -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/godot/godot.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/godot/godot.go deleted file mode 100644 index fc51b5bb8..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/godot/godot.go +++ /dev/null @@ -1,101 +0,0 @@ -package godot - -import ( - "sync" - - "github.com/tetafro/godot" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -const linterName = "godot" - -func New(settings *config.GodotSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - var dotSettings godot.Settings - - if settings != nil { - dotSettings = godot.Settings{ - Scope: godot.Scope(settings.Scope), - Exclude: settings.Exclude, - Period: settings.Period, - Capital: settings.Capital, - } - - // Convert deprecated setting - if settings.CheckAll { - dotSettings.Scope = godot.AllScope - } - } - - if dotSettings.Scope == "" { - dotSettings.Scope = godot.DeclScope - } - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues, err := runGodot(pass, dotSettings) - if err != nil { - return nil, err - } - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Check if comments end in a period", - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) -} - -func runGodot(pass *analysis.Pass, settings godot.Settings) ([]goanalysis.Issue, error) { - var lintIssues []godot.Issue - for _, file := range pass.Files { - iss, err := godot.Run(file, pass.Fset, settings) - if err != nil { - return nil, err - } - lintIssues = append(lintIssues, iss...) - } - - if len(lintIssues) == 0 { - return nil, nil - } - - issues := make([]goanalysis.Issue, len(lintIssues)) - for k, i := range lintIssues { - issue := result.Issue{ - Pos: i.Pos, - Text: i.Message, - FromLinter: linterName, - Replacement: &result.Replacement{ - NewLines: []string{i.Replacement}, - }, - } - - issues[k] = goanalysis.NewIssue(&issue, pass) - } - - return issues, nil -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/godox/godox.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/godox/godox.go deleted file mode 100644 index d8de026ba..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/godox/godox.go +++ /dev/null @@ -1,75 +0,0 @@ -package godox - -import ( - "go/token" - "strings" - "sync" - - "github.com/matoous/godox" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -const linterName = "godox" - -func New(settings *config.GodoxSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues := runGodox(pass, settings) - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Tool for detection of FIXME, TODO and other comment keywords", - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) -} - -func runGodox(pass *analysis.Pass, settings *config.GodoxSettings) []goanalysis.Issue { - var messages []godox.Message - for _, file := range pass.Files { - messages = append(messages, godox.Run(file, pass.Fset, settings.Keywords...)...) - } - - if len(messages) == 0 { - return nil - } - - issues := make([]goanalysis.Issue, len(messages)) - - for k, i := range messages { - issues[k] = goanalysis.NewIssue(&result.Issue{ - Pos: token.Position{ - Filename: i.Pos.Filename, - Line: i.Pos.Line, - }, - Text: strings.TrimRight(i.Message, "\n"), - FromLinter: linterName, - }, pass) - } - - return issues -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt/gofmt.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt/gofmt.go deleted file mode 100644 index 289ceab8a..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt/gofmt.go +++ /dev/null @@ -1,98 +0,0 @@ -package gofmt - -import ( - "fmt" - "sync" - - gofmtAPI "github.com/golangci/gofmt/gofmt" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/golinters/internal" - "github.com/golangci/golangci-lint/pkg/lint/linter" -) - -const linterName = "gofmt" - -func New(settings *config.GoFmtSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: goanalysis.DummyRun, - } - - return goanalysis.NewLinter( - linterName, - "Gofmt checks whether code was gofmt-ed. By default "+ - "this tool runs with -s option to check for code simplification", - []*analysis.Analyzer{analyzer}, - nil, - ).WithContextSetter(func(lintCtx *linter.Context) { - analyzer.Run = func(pass *analysis.Pass) (any, error) { - issues, err := runGofmt(lintCtx, pass, settings) - if err != nil { - return nil, err - } - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - } - }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) -} - -func runGofmt(lintCtx *linter.Context, pass *analysis.Pass, settings *config.GoFmtSettings) ([]goanalysis.Issue, error) { - fileNames := internal.GetFileNames(pass) - - var rewriteRules []gofmtAPI.RewriteRule - for _, rule := range settings.RewriteRules { - rewriteRules = append(rewriteRules, gofmtAPI.RewriteRule(rule)) - } - - var issues []goanalysis.Issue - - for _, f := range fileNames { - diff, err := gofmtAPI.RunRewrite(f, settings.Simplify, rewriteRules) - if err != nil { // TODO: skip - return nil, err - } - if diff == nil { - continue - } - - is, err := internal.ExtractIssuesFromPatch(string(diff), lintCtx, linterName, getIssuedTextGoFmt) - if err != nil { - return nil, fmt.Errorf("can't extract issues from gofmt diff output %q: %w", string(diff), err) - } - - for i := range is { - issues = append(issues, goanalysis.NewIssue(&is[i], pass)) - } - } - - return issues, nil -} - -func getIssuedTextGoFmt(settings *config.LintersSettings) string { - text := "File is not `gofmt`-ed" - if settings.Gofmt.Simplify { - text += " with `-s`" - } - for _, rule := range settings.Gofmt.RewriteRules { - text += fmt.Sprintf(" `-r '%s -> %s'`", rule.Pattern, rule.Replacement) - } - - return text -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofumpt/gofumpt.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofumpt/gofumpt.go deleted file mode 100644 index 3bb7df12e..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofumpt/gofumpt.go +++ /dev/null @@ -1,132 +0,0 @@ -package gofumpt - -import ( - "bytes" - "fmt" - "io" - "os" - "strings" - "sync" - - "github.com/shazow/go-diff/difflib" - "golang.org/x/tools/go/analysis" - "mvdan.cc/gofumpt/format" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/golinters/internal" - "github.com/golangci/golangci-lint/pkg/lint/linter" -) - -const linterName = "gofumpt" - -type differ interface { - Diff(out io.Writer, a io.ReadSeeker, b io.ReadSeeker) error -} - -func New(settings *config.GofumptSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - diff := difflib.New() - - var options format.Options - - if settings != nil { - options = format.Options{ - LangVersion: getLangVersion(settings), - ModulePath: settings.ModulePath, - ExtraRules: settings.ExtraRules, - } - } - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: goanalysis.DummyRun, - } - - return goanalysis.NewLinter( - linterName, - "Gofumpt checks whether code was gofumpt-ed.", - []*analysis.Analyzer{analyzer}, - nil, - ).WithContextSetter(func(lintCtx *linter.Context) { - analyzer.Run = func(pass *analysis.Pass) (any, error) { - issues, err := runGofumpt(lintCtx, pass, diff, options) - if err != nil { - return nil, err - } - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - } - }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) -} - -func runGofumpt(lintCtx *linter.Context, pass *analysis.Pass, diff differ, options format.Options) ([]goanalysis.Issue, error) { - fileNames := internal.GetFileNames(pass) - - var issues []goanalysis.Issue - - for _, f := range fileNames { - input, err := os.ReadFile(f) - if err != nil { - return nil, fmt.Errorf("unable to open file %s: %w", f, err) - } - - output, err := format.Source(input, options) - if err != nil { - return nil, fmt.Errorf("error while running gofumpt: %w", err) - } - - if !bytes.Equal(input, output) { - out := bytes.NewBufferString(fmt.Sprintf("--- %[1]s\n+++ %[1]s\n", f)) - - err := diff.Diff(out, bytes.NewReader(input), bytes.NewReader(output)) - if err != nil { - return nil, fmt.Errorf("error while running gofumpt: %w", err) - } - - diff := out.String() - is, err := internal.ExtractIssuesFromPatch(diff, lintCtx, linterName, getIssuedTextGoFumpt) - if err != nil { - return nil, fmt.Errorf("can't extract issues from gofumpt diff output %q: %w", diff, err) - } - - for i := range is { - issues = append(issues, goanalysis.NewIssue(&is[i], pass)) - } - } - } - - return issues, nil -} - -func getLangVersion(settings *config.GofumptSettings) string { - if settings == nil || settings.LangVersion == "" { - // TODO: defaults to "1.15", in the future (v2) must be removed. - return "go1.15" - } - - return "go" + strings.TrimPrefix(settings.LangVersion, "go") -} - -func getIssuedTextGoFumpt(settings *config.LintersSettings) string { - text := "File is not `gofumpt`-ed" - - if settings.Gofumpt.ExtraRules { - text += " with `-extra`" - } - - return text -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goheader/goheader.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/goheader/goheader.go deleted file mode 100644 index c6b1aae6b..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goheader/goheader.go +++ /dev/null @@ -1,115 +0,0 @@ -package goheader - -import ( - "go/token" - "sync" - - goheader "github.com/denis-tingaikin/go-header" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -const linterName = "goheader" - -func New(settings *config.GoHeaderSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - conf := &goheader.Configuration{} - if settings != nil { - conf = &goheader.Configuration{ - Values: settings.Values, - Template: settings.Template, - TemplatePath: settings.TemplatePath, - } - } - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues, err := runGoHeader(pass, conf) - if err != nil { - return nil, err - } - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Checks if file header matches to pattern", - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) -} - -func runGoHeader(pass *analysis.Pass, conf *goheader.Configuration) ([]goanalysis.Issue, error) { - if conf.TemplatePath == "" && conf.Template == "" { - // User did not pass template, so then do not run go-header linter - return nil, nil - } - - template, err := conf.GetTemplate() - if err != nil { - return nil, err - } - - values, err := conf.GetValues() - if err != nil { - return nil, err - } - - a := goheader.New(goheader.WithTemplate(template), goheader.WithValues(values)) - - var issues []goanalysis.Issue - for _, file := range pass.Files { - path := pass.Fset.Position(file.Pos()).Filename - - i := a.Analyze(&goheader.Target{File: file, Path: path}) - - if i == nil { - continue - } - - issue := result.Issue{ - Pos: token.Position{ - Line: i.Location().Line + 1, - Column: i.Location().Position, - Filename: path, - }, - Text: i.Message(), - FromLinter: linterName, - } - - if fix := i.Fix(); fix != nil { - issue.LineRange = &result.Range{ - From: issue.Line(), - To: issue.Line() + len(fix.Actual) - 1, - } - issue.Replacement = &result.Replacement{ - NeedOnlyDelete: len(fix.Expected) == 0, - NewLines: fix.Expected, - } - } - - issues = append(issues, goanalysis.NewIssue(&issue, pass)) - } - - return issues, nil -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goimports/goimports.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/goimports/goimports.go deleted file mode 100644 index de965d5c8..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goimports/goimports.go +++ /dev/null @@ -1,94 +0,0 @@ -package goimports - -import ( - "fmt" - "sync" - - goimportsAPI "github.com/golangci/gofmt/goimports" - "golang.org/x/tools/go/analysis" - "golang.org/x/tools/imports" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/golinters/internal" - "github.com/golangci/golangci-lint/pkg/lint/linter" -) - -const linterName = "goimports" - -func New(settings *config.GoImportsSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: goanalysis.DummyRun, - } - - return goanalysis.NewLinter( - linterName, - "Check import statements are formatted according to the 'goimport' command. "+ - "Reformat imports in autofix mode.", - []*analysis.Analyzer{analyzer}, - nil, - ).WithContextSetter(func(lintCtx *linter.Context) { - imports.LocalPrefix = settings.LocalPrefixes - - analyzer.Run = func(pass *analysis.Pass) (any, error) { - issues, err := runGoImports(lintCtx, pass) - if err != nil { - return nil, err - } - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - } - }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) -} - -func runGoImports(lintCtx *linter.Context, pass *analysis.Pass) ([]goanalysis.Issue, error) { - fileNames := internal.GetFileNames(pass) - - var issues []goanalysis.Issue - - for _, f := range fileNames { - diff, err := goimportsAPI.Run(f) - if err != nil { // TODO: skip - return nil, err - } - if diff == nil { - continue - } - - is, err := internal.ExtractIssuesFromPatch(string(diff), lintCtx, linterName, getIssuedTextGoImports) - if err != nil { - return nil, fmt.Errorf("can't extract issues from gofmt diff output %q: %w", string(diff), err) - } - - for i := range is { - issues = append(issues, goanalysis.NewIssue(&is[i], pass)) - } - } - - return issues, nil -} - -func getIssuedTextGoImports(settings *config.LintersSettings) string { - text := "File is not `goimports`-ed" - - if settings.Goimports.LocalPrefixes != "" { - text += " with -local " + settings.Goimports.LocalPrefixes - } - - return text -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gomoddirectives/gomoddirectives.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gomoddirectives/gomoddirectives.go deleted file mode 100644 index 9cde7e26c..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gomoddirectives/gomoddirectives.go +++ /dev/null @@ -1,64 +0,0 @@ -package gomoddirectives - -import ( - "sync" - - "github.com/ldez/gomoddirectives" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -const linterName = "gomoddirectives" - -func New(settings *config.GoModDirectivesSettings) *goanalysis.Linter { - var issues []goanalysis.Issue - var once sync.Once - - var opts gomoddirectives.Options - if settings != nil { - opts.ReplaceAllowLocal = settings.ReplaceLocal - opts.ReplaceAllowList = settings.ReplaceAllowList - opts.RetractAllowNoExplanation = settings.RetractAllowNoExplanation - opts.ExcludeForbidden = settings.ExcludeForbidden - } - - analyzer := &analysis.Analyzer{ - Name: goanalysis.TheOnlyAnalyzerName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: goanalysis.DummyRun, - } - - return goanalysis.NewLinter( - linterName, - "Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod.", - []*analysis.Analyzer{analyzer}, - nil, - ).WithContextSetter(func(lintCtx *linter.Context) { - analyzer.Run = func(pass *analysis.Pass) (any, error) { - once.Do(func() { - results, err := gomoddirectives.Analyze(opts) - if err != nil { - lintCtx.Log.Warnf("running %s failed: %s: "+ - "if you are not using go modules it is suggested to disable this linter", linterName, err) - return - } - - for _, p := range results { - issues = append(issues, goanalysis.NewIssue(&result.Issue{ - FromLinter: linterName, - Pos: p.Start, - Text: p.Reason, - }, pass)) - } - }) - - return nil, nil - } - }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return issues - }).WithLoadMode(goanalysis.LoadModeSyntax) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gomodguard/gomodguard.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gomodguard/gomodguard.go deleted file mode 100644 index 8f1036b0f..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gomodguard/gomodguard.go +++ /dev/null @@ -1,94 +0,0 @@ -package gomodguard - -import ( - "sync" - - "github.com/ryancurrah/gomodguard" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/golinters/internal" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -const ( - name = "gomodguard" - desc = "Allow and block list linter for direct Go module dependencies. " + - "This is different from depguard where there are different block " + - "types for example version constraints and module recommendations." -) - -func New(settings *config.GoModGuardSettings) *goanalysis.Linter { - var issues []goanalysis.Issue - var mu sync.Mutex - - processorCfg := &gomodguard.Configuration{} - if settings != nil { - processorCfg.Allowed.Modules = settings.Allowed.Modules - processorCfg.Allowed.Domains = settings.Allowed.Domains - processorCfg.Blocked.LocalReplaceDirectives = settings.Blocked.LocalReplaceDirectives - - for n := range settings.Blocked.Modules { - for k, v := range settings.Blocked.Modules[n] { - m := map[string]gomodguard.BlockedModule{k: { - Recommendations: v.Recommendations, - Reason: v.Reason, - }} - processorCfg.Blocked.Modules = append(processorCfg.Blocked.Modules, m) - break - } - } - - for n := range settings.Blocked.Versions { - for k, v := range settings.Blocked.Versions[n] { - m := map[string]gomodguard.BlockedVersion{k: { - Version: v.Version, - Reason: v.Reason, - }} - processorCfg.Blocked.Versions = append(processorCfg.Blocked.Versions, m) - break - } - } - } - - analyzer := &analysis.Analyzer{ - Name: goanalysis.TheOnlyAnalyzerName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: goanalysis.DummyRun, - } - - return goanalysis.NewLinter( - name, - desc, - []*analysis.Analyzer{analyzer}, - nil, - ).WithContextSetter(func(lintCtx *linter.Context) { - processor, err := gomodguard.NewProcessor(processorCfg) - if err != nil { - lintCtx.Log.Warnf("running gomodguard failed: %s: if you are not using go modules "+ - "it is suggested to disable this linter", err) - return - } - - analyzer.Run = func(pass *analysis.Pass) (any, error) { - gomodguardIssues := processor.ProcessFiles(internal.GetFileNames(pass)) - - mu.Lock() - defer mu.Unlock() - - for _, gomodguardIssue := range gomodguardIssues { - issues = append(issues, goanalysis.NewIssue(&result.Issue{ - FromLinter: name, - Pos: gomodguardIssue.Position, - Text: gomodguardIssue.Reason, - }, pass)) - } - - return nil, nil - } - }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return issues - }).WithLoadMode(goanalysis.LoadModeSyntax) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goprintffuncname/goprintffuncname.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/goprintffuncname/goprintffuncname.go deleted file mode 100644 index c206ffaa3..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goprintffuncname/goprintffuncname.go +++ /dev/null @@ -1,19 +0,0 @@ -package goprintffuncname - -import ( - "github.com/golangci/go-printf-func-name/pkg/analyzer" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New() *goanalysis.Linter { - a := analyzer.Analyzer - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gosimple/gosimple.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gosimple/gosimple.go deleted file mode 100644 index c03871adf..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gosimple/gosimple.go +++ /dev/null @@ -1,22 +0,0 @@ -package gosimple - -import ( - "honnef.co/go/tools/simple" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/golinters/internal" -) - -func New(settings *config.StaticCheckSettings) *goanalysis.Linter { - cfg := internal.StaticCheckConfig(settings) - - analyzers := internal.SetupStaticCheckAnalyzers(simple.Analyzers, cfg.Checks) - - return goanalysis.NewLinter( - "gosimple", - "Linter for Go source code that specializes in simplifying code", - analyzers, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gosmopolitan/gosmopolitan.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gosmopolitan/gosmopolitan.go deleted file mode 100644 index 4f6fb8035..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gosmopolitan/gosmopolitan.go +++ /dev/null @@ -1,32 +0,0 @@ -package gosmopolitan - -import ( - "strings" - - "github.com/xen0n/gosmopolitan" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(s *config.GosmopolitanSettings) *goanalysis.Linter { - a := gosmopolitan.NewAnalyzer() - - cfgMap := map[string]map[string]any{} - if s != nil { - cfgMap[a.Name] = map[string]any{ - "allowtimelocal": s.AllowTimeLocal, - "escapehatches": strings.Join(s.EscapeHatches, ","), - "lookattests": !s.IgnoreTests, - "watchforscripts": strings.Join(s.WatchForScripts, ","), - } - } - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfgMap, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/importas/importas.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/importas/importas.go deleted file mode 100644 index 45117c9a4..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/importas/importas.go +++ /dev/null @@ -1,67 +0,0 @@ -package importas - -import ( - "fmt" - "strconv" - "strings" - - "github.com/julz/importas" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" -) - -func New(settings *config.ImportAsSettings) *goanalysis.Linter { - analyzer := importas.Analyzer - - return goanalysis.NewLinter( - analyzer.Name, - analyzer.Doc, - []*analysis.Analyzer{analyzer}, - nil, - ).WithContextSetter(func(lintCtx *linter.Context) { - if settings == nil { - return - } - if len(settings.Alias) == 0 { - lintCtx.Log.Infof("importas settings found, but no aliases listed. List aliases under alias: key.") - } - - if err := analyzer.Flags.Set("no-unaliased", strconv.FormatBool(settings.NoUnaliased)); err != nil { - lintCtx.Log.Errorf("failed to parse configuration: %v", err) - } - - if err := analyzer.Flags.Set("no-extra-aliases", strconv.FormatBool(settings.NoExtraAliases)); err != nil { - lintCtx.Log.Errorf("failed to parse configuration: %v", err) - } - - uniqPackages := make(map[string]config.ImportAsAlias) - uniqAliases := make(map[string]config.ImportAsAlias) - for _, a := range settings.Alias { - if a.Pkg == "" { - lintCtx.Log.Errorf("invalid configuration, empty package: pkg=%s alias=%s", a.Pkg, a.Alias) - continue - } - - if v, ok := uniqPackages[a.Pkg]; ok { - lintCtx.Log.Errorf("invalid configuration, multiple aliases for the same package: pkg=%s aliases=[%s,%s]", a.Pkg, a.Alias, v.Alias) - } else { - uniqPackages[a.Pkg] = a - } - - // skip the duplication check when the alias is a regular expression replacement pattern (ie. contains `$`). - if v, ok := uniqAliases[a.Alias]; ok && !strings.Contains(a.Alias, "$") { - lintCtx.Log.Errorf("invalid configuration, multiple packages with the same alias: alias=%s packages=[%s,%s]", a.Alias, a.Pkg, v.Pkg) - } else { - uniqAliases[a.Alias] = a - } - - err := analyzer.Flags.Set("alias", fmt.Sprintf("%s:%s", a.Pkg, a.Alias)) - if err != nil { - lintCtx.Log.Errorf("failed to parse configuration: %v", err) - } - } - }).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/inamedparam/inamedparam.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/inamedparam/inamedparam.go deleted file mode 100644 index 5cf06a08c..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/inamedparam/inamedparam.go +++ /dev/null @@ -1,30 +0,0 @@ -package inamedparam - -import ( - "github.com/macabu/inamedparam" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(settings *config.INamedParamSettings) *goanalysis.Linter { - a := inamedparam.Analyzer - - var cfg map[string]map[string]any - - if settings != nil { - cfg = map[string]map[string]any{ - a.Name: { - "skip-single-param": settings.SkipSingleParam, - }, - } - } - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeSyntax) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/ineffassign/ineffassign.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/ineffassign/ineffassign.go deleted file mode 100644 index ba86fb90e..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/ineffassign/ineffassign.go +++ /dev/null @@ -1,19 +0,0 @@ -package ineffassign - -import ( - "github.com/gordonklaus/ineffassign/pkg/ineffassign" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New() *goanalysis.Linter { - a := ineffassign.Analyzer - - return goanalysis.NewLinter( - a.Name, - "Detects when assignments to existing variables are not used", - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/interfacebloat/interfacebloat.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/interfacebloat/interfacebloat.go deleted file mode 100644 index 88927a3d9..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/interfacebloat/interfacebloat.go +++ /dev/null @@ -1,29 +0,0 @@ -package interfacebloat - -import ( - "github.com/sashamelentyev/interfacebloat/pkg/analyzer" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(settings *config.InterfaceBloatSettings) *goanalysis.Linter { - a := analyzer.New() - - var cfg map[string]map[string]any - if settings != nil { - cfg = map[string]map[string]any{ - a.Name: { - analyzer.InterfaceMaxMethodsFlag: settings.Max, - }, - } - } - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeSyntax) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/internal/diff.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/internal/diff.go deleted file mode 100644 index f919c5b2a..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/internal/diff.go +++ /dev/null @@ -1,264 +0,0 @@ -package internal - -import ( - "bytes" - "fmt" - "go/token" - "strings" - - diffpkg "github.com/sourcegraph/go-diff/diff" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/logutils" - "github.com/golangci/golangci-lint/pkg/result" -) - -type Change struct { - LineRange result.Range - Replacement result.Replacement -} - -type diffLineType string - -const ( - diffLineAdded diffLineType = "added" - diffLineOriginal diffLineType = "original" - diffLineDeleted diffLineType = "deleted" -) - -type fmtTextFormatter func(settings *config.LintersSettings) string - -type diffLine struct { - originalNumber int // 1-based original line number - typ diffLineType - data string // "+" or "-" stripped line -} - -type hunkChangesParser struct { - // needed because we merge currently added lines with the last original line - lastOriginalLine *diffLine - - // if the first line of diff is an adding we save all additions to replacementLinesToPrepend - replacementLinesToPrepend []string - - log logutils.Log - - lines []diffLine - - ret []Change -} - -func (p *hunkChangesParser) parseDiffLines(h *diffpkg.Hunk) { - lines := bytes.Split(h.Body, []byte{'\n'}) - currentOriginalLineNumber := int(h.OrigStartLine) - var ret []diffLine - - for i, line := range lines { - dl := diffLine{ - originalNumber: currentOriginalLineNumber, - } - - lineStr := string(line) - - if strings.HasPrefix(lineStr, "-") { - dl.typ = diffLineDeleted - dl.data = strings.TrimPrefix(lineStr, "-") - currentOriginalLineNumber++ - } else if strings.HasPrefix(lineStr, "+") { - dl.typ = diffLineAdded - dl.data = strings.TrimPrefix(lineStr, "+") - } else { - if i == len(lines)-1 && lineStr == "" { - // handle last \n: don't add an empty original line - break - } - - dl.typ = diffLineOriginal - dl.data = strings.TrimPrefix(lineStr, " ") - currentOriginalLineNumber++ - } - - ret = append(ret, dl) - } - - // if > 0, then the original file had a 'No newline at end of file' mark - if h.OrigNoNewlineAt > 0 { - dl := diffLine{ - originalNumber: currentOriginalLineNumber + 1, - typ: diffLineAdded, - data: "", - } - ret = append(ret, dl) - } - - p.lines = ret -} - -func (p *hunkChangesParser) handleOriginalLine(line diffLine, i *int) { - if len(p.replacementLinesToPrepend) == 0 { - p.lastOriginalLine = &line - *i++ - return - } - - // check following added lines for the case: - // + added line 1 - // original line - // + added line 2 - - *i++ - var followingAddedLines []string - for ; *i < len(p.lines) && p.lines[*i].typ == diffLineAdded; *i++ { - followingAddedLines = append(followingAddedLines, p.lines[*i].data) - } - - p.ret = append(p.ret, Change{ - LineRange: result.Range{ - From: line.originalNumber, - To: line.originalNumber, - }, - Replacement: result.Replacement{ - NewLines: append(p.replacementLinesToPrepend, append([]string{line.data}, followingAddedLines...)...), - }, - }) - p.replacementLinesToPrepend = nil - p.lastOriginalLine = &line -} - -func (p *hunkChangesParser) handleDeletedLines(deletedLines []diffLine, addedLines []string) { - change := Change{ - LineRange: result.Range{ - From: deletedLines[0].originalNumber, - To: deletedLines[len(deletedLines)-1].originalNumber, - }, - } - - if len(addedLines) != 0 { - change.Replacement.NewLines = append([]string{}, p.replacementLinesToPrepend...) - change.Replacement.NewLines = append(change.Replacement.NewLines, addedLines...) - if len(p.replacementLinesToPrepend) != 0 { - p.replacementLinesToPrepend = nil - } - - p.ret = append(p.ret, change) - return - } - - // delete-only change with possible prepending - if len(p.replacementLinesToPrepend) != 0 { - change.Replacement.NewLines = p.replacementLinesToPrepend - p.replacementLinesToPrepend = nil - } else { - change.Replacement.NeedOnlyDelete = true - } - - p.ret = append(p.ret, change) -} - -func (p *hunkChangesParser) handleAddedOnlyLines(addedLines []string) { - if p.lastOriginalLine == nil { - // the first line is added; the diff looks like: - // 1. + ... - // 2. - ... - // or - // 1. + ... - // 2. ... - - p.replacementLinesToPrepend = addedLines - return - } - - // add-only change merged into the last original line with possible prepending - p.ret = append(p.ret, Change{ - LineRange: result.Range{ - From: p.lastOriginalLine.originalNumber, - To: p.lastOriginalLine.originalNumber, - }, - Replacement: result.Replacement{ - NewLines: append(p.replacementLinesToPrepend, append([]string{p.lastOriginalLine.data}, addedLines...)...), - }, - }) - p.replacementLinesToPrepend = nil -} - -func (p *hunkChangesParser) parse(h *diffpkg.Hunk) []Change { - p.parseDiffLines(h) - - for i := 0; i < len(p.lines); { - line := p.lines[i] - if line.typ == diffLineOriginal { - p.handleOriginalLine(line, &i) - continue - } - - var deletedLines []diffLine - for ; i < len(p.lines) && p.lines[i].typ == diffLineDeleted; i++ { - deletedLines = append(deletedLines, p.lines[i]) - } - - var addedLines []string - for ; i < len(p.lines) && p.lines[i].typ == diffLineAdded; i++ { - addedLines = append(addedLines, p.lines[i].data) - } - - if len(deletedLines) != 0 { - p.handleDeletedLines(deletedLines, addedLines) - continue - } - - // no deletions, only additions - p.handleAddedOnlyLines(addedLines) - } - - if len(p.replacementLinesToPrepend) != 0 { - p.log.Infof("The diff contains only additions: no original or deleted lines: %#v", p.lines) - return nil - } - - return p.ret -} - -func ExtractIssuesFromPatch(patch string, lintCtx *linter.Context, linterName string, formatter fmtTextFormatter) ([]result.Issue, error) { - diffs, err := diffpkg.ParseMultiFileDiff([]byte(patch)) - if err != nil { - return nil, fmt.Errorf("can't parse patch: %w", err) - } - - if len(diffs) == 0 { - return nil, fmt.Errorf("got no diffs from patch parser: %v", patch) - } - - var issues []result.Issue - for _, d := range diffs { - if len(d.Hunks) == 0 { - lintCtx.Log.Warnf("Got no hunks in diff %+v", d) - continue - } - - for _, hunk := range d.Hunks { - p := hunkChangesParser{log: lintCtx.Log} - - changes := p.parse(hunk) - - for _, change := range changes { - i := result.Issue{ - FromLinter: linterName, - Pos: token.Position{ - Filename: d.NewName, - Line: change.LineRange.From, - }, - Text: formatter(lintCtx.Settings()), - Replacement: &change.Replacement, - } - if change.LineRange.From != change.LineRange.To { - i.LineRange = &change.LineRange - } - - issues = append(issues, i) - } - } - } - - return issues, nil -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/internal/util.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/internal/util.go deleted file mode 100644 index 80b194dd2..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/internal/util.go +++ /dev/null @@ -1,33 +0,0 @@ -package internal - -import ( - "fmt" - "path/filepath" - "strings" - - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" -) - -func FormatCode(code string, _ *config.Config) string { - if strings.Contains(code, "`") { - return code // TODO: properly escape or remove - } - - return fmt.Sprintf("`%s`", code) -} - -func GetFileNames(pass *analysis.Pass) []string { - var fileNames []string - for _, f := range pass.Files { - fileName := pass.Fset.PositionFor(f.Pos(), true).Filename - ext := filepath.Ext(fileName) - if ext != "" && ext != ".go" { - // position has been adjusted to a non-go file, revert to original file - fileName = pass.Fset.PositionFor(f.Pos(), false).Filename - } - fileNames = append(fileNames, fileName) - } - return fileNames -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/intrange/intrange.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/intrange/intrange.go deleted file mode 100644 index d5ffd4345..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/intrange/intrange.go +++ /dev/null @@ -1,19 +0,0 @@ -package intrange - -import ( - "github.com/ckaznocha/intrange" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New() *goanalysis.Linter { - a := intrange.Analyzer - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/ireturn/ireturn.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/ireturn/ireturn.go deleted file mode 100644 index 57de57111..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/ireturn/ireturn.go +++ /dev/null @@ -1,31 +0,0 @@ -package ireturn - -import ( - "strings" - - "github.com/butuzov/ireturn/analyzer" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(settings *config.IreturnSettings) *goanalysis.Linter { - a := analyzer.NewAnalyzer() - - cfg := map[string]map[string]any{} - if settings != nil { - cfg[a.Name] = map[string]any{ - "allow": strings.Join(settings.Allow, ","), - "reject": strings.Join(settings.Reject, ","), - "nonolint": true, - } - } - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/lll/lll.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/lll/lll.go deleted file mode 100644 index 67f89eecb..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/lll/lll.go +++ /dev/null @@ -1,157 +0,0 @@ -package lll - -import ( - "bufio" - "errors" - "fmt" - "go/token" - "os" - "strings" - "sync" - "unicode/utf8" - - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/golinters/internal" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -const linterName = "lll" - -const goCommentDirectivePrefix = "//go:" - -func New(settings *config.LllSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues, err := runLll(pass, settings) - if err != nil { - return nil, err - } - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Reports long lines", - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) -} - -func runLll(pass *analysis.Pass, settings *config.LllSettings) ([]goanalysis.Issue, error) { - fileNames := internal.GetFileNames(pass) - - spaces := strings.Repeat(" ", settings.TabWidth) - - var issues []goanalysis.Issue - for _, f := range fileNames { - lintIssues, err := getLLLIssuesForFile(f, settings.LineLength, spaces) - if err != nil { - return nil, err - } - - for i := range lintIssues { - issues = append(issues, goanalysis.NewIssue(&lintIssues[i], pass)) - } - } - - return issues, nil -} - -func getLLLIssuesForFile(filename string, maxLineLen int, tabSpaces string) ([]result.Issue, error) { - var res []result.Issue - - f, err := os.Open(filename) - if err != nil { - return nil, fmt.Errorf("can't open file %s: %w", filename, err) - } - defer f.Close() - - lineNumber := 0 - multiImportEnabled := false - - scanner := bufio.NewScanner(f) - for scanner.Scan() { - lineNumber++ - - line := scanner.Text() - line = strings.ReplaceAll(line, "\t", tabSpaces) - - if strings.HasPrefix(line, goCommentDirectivePrefix) { - continue - } - - if strings.HasPrefix(line, "import") { - multiImportEnabled = strings.HasSuffix(line, "(") - continue - } - - if multiImportEnabled { - if line == ")" { - multiImportEnabled = false - } - - continue - } - - lineLen := utf8.RuneCountInString(line) - if lineLen > maxLineLen { - res = append(res, result.Issue{ - Pos: token.Position{ - Filename: filename, - Line: lineNumber, - }, - Text: fmt.Sprintf("the line is %d characters long, which exceeds the maximum of %d characters.", lineLen, maxLineLen), - FromLinter: linterName, - }) - } - } - - if err := scanner.Err(); err != nil { - if errors.Is(err, bufio.ErrTooLong) && maxLineLen < bufio.MaxScanTokenSize { - // scanner.Scan() might fail if the line is longer than bufio.MaxScanTokenSize - // In the case where the specified maxLineLen is smaller than bufio.MaxScanTokenSize - // we can return this line as a long line instead of returning an error. - // The reason for this change is that this case might happen with autogenerated files - // The go-bindata tool for instance might generate a file with a very long line. - // In this case, as it's an auto generated file, the warning returned by lll will - // be ignored. - // But if we return a linter error here, and this error happens for an autogenerated - // file the error will be discarded (fine), but all the subsequent errors for lll will - // be discarded for other files, and we'll miss legit error. - res = append(res, result.Issue{ - Pos: token.Position{ - Filename: filename, - Line: lineNumber, - Column: 1, - }, - Text: fmt.Sprintf("line is more than %d characters", bufio.MaxScanTokenSize), - FromLinter: linterName, - }) - } else { - return nil, fmt.Errorf("can't scan file %s: %w", filename, err) - } - } - - return res, nil -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/maintidx/maintidx.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/maintidx/maintidx.go deleted file mode 100644 index 08f12369e..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/maintidx/maintidx.go +++ /dev/null @@ -1,30 +0,0 @@ -package maintidx - -import ( - "github.com/yagipy/maintidx" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(cfg *config.MaintIdxSettings) *goanalysis.Linter { - analyzer := maintidx.Analyzer - - cfgMap := map[string]map[string]any{ - analyzer.Name: {"under": 20}, - } - - if cfg != nil { - cfgMap[analyzer.Name] = map[string]any{ - "under": cfg.Under, - } - } - - return goanalysis.NewLinter( - analyzer.Name, - analyzer.Doc, - []*analysis.Analyzer{analyzer}, - cfgMap, - ).WithLoadMode(goanalysis.LoadModeSyntax) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/makezero/makezero.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/makezero/makezero.go deleted file mode 100644 index ae4bf2184..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/makezero/makezero.go +++ /dev/null @@ -1,74 +0,0 @@ -package makezero - -import ( - "fmt" - "sync" - - "github.com/ashanbrown/makezero/makezero" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -const linterName = "makezero" - -func New(settings *config.MakezeroSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues, err := runMakeZero(pass, settings) - if err != nil { - return nil, err - } - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Finds slice declarations with non-zero initial length", - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeTypesInfo) -} - -func runMakeZero(pass *analysis.Pass, settings *config.MakezeroSettings) ([]goanalysis.Issue, error) { - zero := makezero.NewLinter(settings.Always) - - var issues []goanalysis.Issue - - for _, file := range pass.Files { - hints, err := zero.Run(pass.Fset, pass.TypesInfo, file) - if err != nil { - return nil, fmt.Errorf("makezero linter failed on file %q: %w", file.Name.String(), err) - } - - for _, hint := range hints { - issues = append(issues, goanalysis.NewIssue(&result.Issue{ - Pos: hint.Position(), - Text: hint.Details(), - FromLinter: linterName, - }, pass)) - } - } - - return issues, nil -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/mirror/mirror.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/mirror/mirror.go deleted file mode 100644 index 34b880b52..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/mirror/mirror.go +++ /dev/null @@ -1,70 +0,0 @@ -package mirror - -import ( - "sync" - - "github.com/butuzov/mirror" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -func New() *goanalysis.Linter { - var ( - mu sync.Mutex - issues []goanalysis.Issue - ) - - a := mirror.NewAnalyzer() - a.Run = func(pass *analysis.Pass) (any, error) { - // mirror only lints test files if the `--with-tests` flag is passed, - // so we pass the `with-tests` flag as true to the analyzer before running it. - // This can be turned off by using the regular golangci-lint flags such as `--tests` or `--skip-files` - // or can be disabled per linter via exclude rules. - // (see https://github.com/golangci/golangci-lint/issues/2527#issuecomment-1023707262) - violations := mirror.Run(pass, true) - - if len(violations) == 0 { - return nil, nil - } - - for index := range violations { - i := violations[index].Issue(pass.Fset) - - issue := result.Issue{ - FromLinter: a.Name, - Text: i.Message, - Pos: i.Start, - } - - if i.InlineFix != "" { - issue.Replacement = &result.Replacement{ - Inline: &result.InlineFix{ - StartCol: i.Start.Column - 1, - Length: len(i.Original), - NewString: i.InlineFix, - }, - } - } - - mu.Lock() - issues = append(issues, goanalysis.NewIssue(&issue, pass)) - mu.Unlock() - } - - return nil, nil - } - - analyzer := goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return issues - }).WithLoadMode(goanalysis.LoadModeTypesInfo) - - return analyzer -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/mnd/mnd.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/mnd/mnd.go deleted file mode 100644 index fe64653b9..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/mnd/mnd.go +++ /dev/null @@ -1,42 +0,0 @@ -package mnd - -import ( - mnd "github.com/tommy-muehle/go-mnd/v2" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(settings *config.MndSettings) *goanalysis.Linter { - return newMND(mnd.Analyzer, settings, nil) -} - -func newMND(a *analysis.Analyzer, settings *config.MndSettings, linterCfg map[string]map[string]any) *goanalysis.Linter { - if len(linterCfg) == 0 && settings != nil { - cfg := make(map[string]any) - if len(settings.Checks) > 0 { - cfg["checks"] = settings.Checks - } - if len(settings.IgnoredNumbers) > 0 { - cfg["ignored-numbers"] = settings.IgnoredNumbers - } - if len(settings.IgnoredFiles) > 0 { - cfg["ignored-files"] = settings.IgnoredFiles - } - if len(settings.IgnoredFunctions) > 0 { - cfg["ignored-functions"] = settings.IgnoredFunctions - } - - linterCfg = map[string]map[string]any{ - a.Name: cfg, - } - } - - return goanalysis.NewLinter( - a.Name, - "An analyzer to detect magic numbers.", - []*analysis.Analyzer{a}, - linterCfg, - ).WithLoadMode(goanalysis.LoadModeSyntax) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/musttag/musttag.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/musttag/musttag.go deleted file mode 100644 index 30047abfc..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/musttag/musttag.go +++ /dev/null @@ -1,29 +0,0 @@ -package musttag - -import ( - "go-simpler.org/musttag" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(setting *config.MustTagSettings) *goanalysis.Linter { - var funcs []musttag.Func - - if setting != nil { - for _, fn := range setting.Functions { - funcs = append(funcs, musttag.Func{ - Name: fn.Name, - Tag: fn.Tag, - ArgPos: fn.ArgPos, - }) - } - } - - a := musttag.New(funcs...) - - return goanalysis. - NewLinter(a.Name, a.Doc, []*analysis.Analyzer{a}, nil). - WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nakedret/nakedret.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/nakedret/nakedret.go deleted file mode 100644 index e69fa5e9f..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nakedret/nakedret.go +++ /dev/null @@ -1,25 +0,0 @@ -package nakedret - -import ( - "github.com/alexkohler/nakedret/v2" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(settings *config.NakedretSettings) *goanalysis.Linter { - var maxLines uint - if settings != nil { - maxLines = settings.MaxFuncLines - } - - a := nakedret.NakedReturnAnalyzer(maxLines, false) - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nestif/nestif.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/nestif/nestif.go deleted file mode 100644 index 43be973b0..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nestif/nestif.go +++ /dev/null @@ -1,78 +0,0 @@ -package nestif - -import ( - "sort" - "sync" - - "github.com/nakabonne/nestif" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -const linterName = "nestif" - -func New(settings *config.NestifSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - analyzer := &analysis.Analyzer{ - Name: goanalysis.TheOnlyAnalyzerName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues := runNestIf(pass, settings) - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Reports deeply nested if statements", - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) -} - -func runNestIf(pass *analysis.Pass, settings *config.NestifSettings) []goanalysis.Issue { - checker := &nestif.Checker{ - MinComplexity: settings.MinComplexity, - } - - var lintIssues []nestif.Issue - for _, f := range pass.Files { - lintIssues = append(lintIssues, checker.Check(f, pass.Fset)...) - } - - if len(lintIssues) == 0 { - return nil - } - - sort.SliceStable(lintIssues, func(i, j int) bool { - return lintIssues[i].Complexity > lintIssues[j].Complexity - }) - - issues := make([]goanalysis.Issue, 0, len(lintIssues)) - for _, i := range lintIssues { - issues = append(issues, goanalysis.NewIssue(&result.Issue{ - Pos: i.Pos, - Text: i.Message, - FromLinter: linterName, - }, pass)) - } - - return issues -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nilerr/nilerr.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/nilerr/nilerr.go deleted file mode 100644 index c9e466905..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nilerr/nilerr.go +++ /dev/null @@ -1,19 +0,0 @@ -package nilerr - -import ( - "github.com/gostaticanalysis/nilerr" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New() *goanalysis.Linter { - a := nilerr.Analyzer - - return goanalysis.NewLinter( - a.Name, - "Finds the code that returns nil even if it checks that the error is not nil.", - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nilnil/nilnil.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/nilnil/nilnil.go deleted file mode 100644 index d8d677d99..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nilnil/nilnil.go +++ /dev/null @@ -1,31 +0,0 @@ -package nilnil - -import ( - "github.com/Antonboom/nilnil/pkg/analyzer" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(settings *config.NilNilSettings) *goanalysis.Linter { - a := analyzer.New() - - cfgMap := make(map[string]map[string]any) - if settings != nil { - cfgMap[a.Name] = map[string]any{ - "detect-opposite": settings.DetectOpposite, - } - if len(settings.CheckedTypes) != 0 { - cfgMap[a.Name]["checked-types"] = settings.CheckedTypes - } - } - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfgMap, - ). - WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nlreturn/nlreturn.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/nlreturn/nlreturn.go deleted file mode 100644 index 509218808..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nlreturn/nlreturn.go +++ /dev/null @@ -1,27 +0,0 @@ -package nlreturn - -import ( - "github.com/ssgreg/nlreturn/v2/pkg/nlreturn" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(settings *config.NlreturnSettings) *goanalysis.Linter { - a := nlreturn.NewAnalyzer() - - cfg := map[string]map[string]any{} - if settings != nil { - cfg[a.Name] = map[string]any{ - "block-size": settings.BlockSize, - } - } - - return goanalysis.NewLinter( - a.Name, - "nlreturn checks for a new line before return and branch statements to increase code clarity", - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeSyntax) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/noctx/noctx.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/noctx/noctx.go deleted file mode 100644 index 8a063c613..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/noctx/noctx.go +++ /dev/null @@ -1,19 +0,0 @@ -package noctx - -import ( - "github.com/sonatard/noctx" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New() *goanalysis.Linter { - a := noctx.Analyzer - - return goanalysis.NewLinter( - a.Name, - "Finds sending http request without context.Context", - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nolintlint/internal/nolintlint.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/nolintlint/internal/nolintlint.go deleted file mode 100644 index 08dd74378..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nolintlint/internal/nolintlint.go +++ /dev/null @@ -1,311 +0,0 @@ -// Package internal provides a linter to ensure that all //nolint directives are followed by explanations -package internal - -import ( - "fmt" - "go/ast" - "go/token" - "regexp" - "strings" - "unicode" - - "github.com/golangci/golangci-lint/pkg/result" -) - -type BaseIssue struct { - fullDirective string - directiveWithOptionalLeadingSpace string - position token.Position - replacement *result.Replacement -} - -//nolint:gocritic // TODO(ldez) must be change in the future. -func (b BaseIssue) Position() token.Position { - return b.position -} - -//nolint:gocritic // TODO(ldez) must be change in the future. -func (b BaseIssue) Replacement() *result.Replacement { - return b.replacement -} - -type ExtraLeadingSpace struct { - BaseIssue -} - -//nolint:gocritic // TODO(ldez) must be change in the future. -func (i ExtraLeadingSpace) Details() string { - return fmt.Sprintf("directive `%s` should not have more than one leading space", i.fullDirective) -} - -func (i ExtraLeadingSpace) String() string { return toString(i) } - -type NotMachine struct { - BaseIssue -} - -//nolint:gocritic // TODO(ldez) must be change in the future. -func (i NotMachine) Details() string { - expected := i.fullDirective[:2] + strings.TrimLeftFunc(i.fullDirective[2:], unicode.IsSpace) - return fmt.Sprintf("directive `%s` should be written without leading space as `%s`", - i.fullDirective, expected) -} - -func (i NotMachine) String() string { return toString(i) } - -type NotSpecific struct { - BaseIssue -} - -//nolint:gocritic // TODO(ldez) must be change in the future. -func (i NotSpecific) Details() string { - return fmt.Sprintf("directive `%s` should mention specific linter such as `%s:my-linter`", - i.fullDirective, i.directiveWithOptionalLeadingSpace) -} - -func (i NotSpecific) String() string { return toString(i) } - -type ParseError struct { - BaseIssue -} - -//nolint:gocritic // TODO(ldez) must be change in the future. -func (i ParseError) Details() string { - return fmt.Sprintf("directive `%s` should match `%s[:] [// ]`", - i.fullDirective, - i.directiveWithOptionalLeadingSpace) -} - -func (i ParseError) String() string { return toString(i) } - -type NoExplanation struct { - BaseIssue - fullDirectiveWithoutExplanation string -} - -//nolint:gocritic // TODO(ldez) must be change in the future. -func (i NoExplanation) Details() string { - return fmt.Sprintf("directive `%s` should provide explanation such as `%s // this is why`", - i.fullDirective, i.fullDirectiveWithoutExplanation) -} - -func (i NoExplanation) String() string { return toString(i) } - -type UnusedCandidate struct { - BaseIssue - ExpectedLinter string -} - -//nolint:gocritic // TODO(ldez) must be change in the future. -func (i UnusedCandidate) Details() string { - details := fmt.Sprintf("directive `%s` is unused", i.fullDirective) - if i.ExpectedLinter != "" { - details += fmt.Sprintf(" for linter %q", i.ExpectedLinter) - } - return details -} - -func (i UnusedCandidate) String() string { return toString(i) } - -func toString(issue Issue) string { - return fmt.Sprintf("%s at %s", issue.Details(), issue.Position()) -} - -type Issue interface { - Details() string - Position() token.Position - String() string - Replacement() *result.Replacement -} - -type Needs uint - -const ( - NeedsMachineOnly Needs = 1 << iota - NeedsSpecific - NeedsExplanation - NeedsUnused - NeedsAll = NeedsMachineOnly | NeedsSpecific | NeedsExplanation -) - -var commentPattern = regexp.MustCompile(`^//\s*(nolint)(:\s*[\w-]+\s*(?:,\s*[\w-]+\s*)*)?\b`) - -// matches a complete nolint directive -var fullDirectivePattern = regexp.MustCompile(`^//\s*nolint(?::(\s*[\w-]+\s*(?:,\s*[\w-]+\s*)*))?\s*(//.*)?\s*\n?$`) - -type Linter struct { - needs Needs // indicates which linter checks to perform - excludeByLinter map[string]bool -} - -// NewLinter creates a linter that enforces that the provided directives fulfill the provided requirements -func NewLinter(needs Needs, excludes []string) (*Linter, error) { - excludeByName := make(map[string]bool) - for _, e := range excludes { - excludeByName[e] = true - } - - return &Linter{ - needs: needs | NeedsMachineOnly, - excludeByLinter: excludeByName, - }, nil -} - -var ( - leadingSpacePattern = regexp.MustCompile(`^//(\s*)`) - trailingBlankExplanation = regexp.MustCompile(`\s*(//\s*)?$`) -) - -//nolint:funlen,gocyclo // the function is going to be refactored in the future -func (l Linter) Run(fset *token.FileSet, nodes ...ast.Node) ([]Issue, error) { - var issues []Issue - - for _, node := range nodes { - file, ok := node.(*ast.File) - if !ok { - continue - } - - for _, c := range file.Comments { - for _, comment := range c.List { - if !commentPattern.MatchString(comment.Text) { - continue - } - - // check for a space between the "//" and the directive - leadingSpaceMatches := leadingSpacePattern.FindStringSubmatch(comment.Text) - - var leadingSpace string - if len(leadingSpaceMatches) > 0 { - leadingSpace = leadingSpaceMatches[1] - } - - directiveWithOptionalLeadingSpace := "//" - if leadingSpace != "" { - directiveWithOptionalLeadingSpace += " " - } - - split := strings.Split(strings.SplitN(comment.Text, ":", 2)[0], "//") - directiveWithOptionalLeadingSpace += strings.TrimSpace(split[1]) - - pos := fset.Position(comment.Pos()) - end := fset.Position(comment.End()) - - base := BaseIssue{ - fullDirective: comment.Text, - directiveWithOptionalLeadingSpace: directiveWithOptionalLeadingSpace, - position: pos, - } - - // check for, report and eliminate leading spaces, so we can check for other issues - if leadingSpace != "" { - removeWhitespace := &result.Replacement{ - Inline: &result.InlineFix{ - StartCol: pos.Column + 1, - Length: len(leadingSpace), - NewString: "", - }, - } - if (l.needs & NeedsMachineOnly) != 0 { - issue := NotMachine{BaseIssue: base} - issue.BaseIssue.replacement = removeWhitespace - issues = append(issues, issue) - } else if len(leadingSpace) > 1 { - issue := ExtraLeadingSpace{BaseIssue: base} - issue.BaseIssue.replacement = removeWhitespace - issue.BaseIssue.replacement.Inline.NewString = " " // assume a single space was intended - issues = append(issues, issue) - } - } - - fullMatches := fullDirectivePattern.FindStringSubmatch(comment.Text) - if len(fullMatches) == 0 { - issues = append(issues, ParseError{BaseIssue: base}) - continue - } - - lintersText, explanation := fullMatches[1], fullMatches[2] - - var linters []string - if lintersText != "" && !strings.HasPrefix(lintersText, "all") { - lls := strings.Split(lintersText, ",") - linters = make([]string, 0, len(lls)) - rangeStart := (pos.Column - 1) + len("//") + len(leadingSpace) + len("nolint:") - for i, ll := range lls { - rangeEnd := rangeStart + len(ll) - if i < len(lls)-1 { - rangeEnd++ // include trailing comma - } - trimmedLinterName := strings.TrimSpace(ll) - if trimmedLinterName != "" { - linters = append(linters, trimmedLinterName) - } - rangeStart = rangeEnd - } - } - - if (l.needs & NeedsSpecific) != 0 { - if len(linters) == 0 { - issues = append(issues, NotSpecific{BaseIssue: base}) - } - } - - // when detecting unused directives, we send all the directives through and filter them out in the nolint processor - if (l.needs & NeedsUnused) != 0 { - removeNolintCompletely := &result.Replacement{} - - startCol := pos.Column - 1 - - if startCol == 0 { - // if the directive starts from a new line, remove the line - removeNolintCompletely.NeedOnlyDelete = true - } else { - removeNolintCompletely.Inline = &result.InlineFix{ - StartCol: startCol, - Length: end.Column - pos.Column, - NewString: "", - } - } - - if len(linters) == 0 { - issue := UnusedCandidate{BaseIssue: base} - issue.replacement = removeNolintCompletely - issues = append(issues, issue) - } else { - for _, linter := range linters { - issue := UnusedCandidate{BaseIssue: base, ExpectedLinter: linter} - // only offer replacement if there is a single linter - // because of issues around commas and the possibility of all - // linters being removed - if len(linters) == 1 { - issue.replacement = removeNolintCompletely - } - issues = append(issues, issue) - } - } - } - - if (l.needs&NeedsExplanation) != 0 && (explanation == "" || strings.TrimSpace(explanation) == "//") { - needsExplanation := len(linters) == 0 // if no linters are mentioned, we must have explanation - // otherwise, check if we are excluding all the mentioned linters - for _, ll := range linters { - if !l.excludeByLinter[ll] { // if a linter does require explanation - needsExplanation = true - break - } - } - - if needsExplanation { - fullDirectiveWithoutExplanation := trailingBlankExplanation.ReplaceAllString(comment.Text, "") - issues = append(issues, NoExplanation{ - BaseIssue: base, - fullDirectiveWithoutExplanation: fullDirectiveWithoutExplanation, - }) - } - } - } - } - } - - return issues, nil -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nolintlint/nolintlint.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/nolintlint/nolintlint.go deleted file mode 100644 index 9f04454a5..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nolintlint/nolintlint.go +++ /dev/null @@ -1,104 +0,0 @@ -package nolintlint - -import ( - "fmt" - "go/ast" - "sync" - - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/golinters/nolintlint/internal" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -const LinterName = "nolintlint" - -func New(settings *config.NoLintLintSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - analyzer := &analysis.Analyzer{ - Name: LinterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues, err := runNoLintLint(pass, settings) - if err != nil { - return nil, err - } - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - }, - } - - return goanalysis.NewLinter( - LinterName, - "Reports ill-formed or insufficient nolint directives", - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) -} - -func runNoLintLint(pass *analysis.Pass, settings *config.NoLintLintSettings) ([]goanalysis.Issue, error) { - var needs internal.Needs - if settings.RequireExplanation { - needs |= internal.NeedsExplanation - } - if settings.RequireSpecific { - needs |= internal.NeedsSpecific - } - if !settings.AllowUnused { - needs |= internal.NeedsUnused - } - - lnt, err := internal.NewLinter(needs, settings.AllowNoExplanation) - if err != nil { - return nil, err - } - - nodes := make([]ast.Node, 0, len(pass.Files)) - for _, n := range pass.Files { - nodes = append(nodes, n) - } - - lintIssues, err := lnt.Run(pass.Fset, nodes...) - if err != nil { - return nil, fmt.Errorf("linter failed to run: %w", err) - } - - var issues []goanalysis.Issue - - for _, i := range lintIssues { - expectNoLint := false - var expectedNolintLinter string - if ii, ok := i.(internal.UnusedCandidate); ok { - expectedNolintLinter = ii.ExpectedLinter - expectNoLint = true - } - - issue := &result.Issue{ - FromLinter: LinterName, - Text: i.Details(), - Pos: i.Position(), - ExpectNoLint: expectNoLint, - ExpectedNoLintLinter: expectedNolintLinter, - Replacement: i.Replacement(), - } - - issues = append(issues, goanalysis.NewIssue(issue, pass)) - } - - return issues, nil -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nonamedreturns/nonamedreturns.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/nonamedreturns/nonamedreturns.go deleted file mode 100644 index 42a618e64..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nonamedreturns/nonamedreturns.go +++ /dev/null @@ -1,29 +0,0 @@ -package nonamedreturns - -import ( - "github.com/firefart/nonamedreturns/analyzer" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(settings *config.NoNamedReturnsSettings) *goanalysis.Linter { - a := analyzer.Analyzer - - var cfg map[string]map[string]any - if settings != nil { - cfg = map[string]map[string]any{ - a.Name: { - analyzer.FlagReportErrorInDefer: settings.ReportErrorInDefer, - }, - } - } - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nosprintfhostport/nosprintfhostport.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/nosprintfhostport/nosprintfhostport.go deleted file mode 100644 index 8f06ae1f6..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nosprintfhostport/nosprintfhostport.go +++ /dev/null @@ -1,19 +0,0 @@ -package nosprintfhostport - -import ( - "github.com/stbenjam/no-sprintf-host-port/pkg/analyzer" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New() *goanalysis.Linter { - a := analyzer.Analyzer - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/paralleltest/paralleltest.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/paralleltest/paralleltest.go deleted file mode 100644 index 0c908fa38..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/paralleltest/paralleltest.go +++ /dev/null @@ -1,34 +0,0 @@ -package paralleltest - -import ( - "github.com/kunwardeep/paralleltest/pkg/paralleltest" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(settings *config.ParallelTestSettings) *goanalysis.Linter { - a := paralleltest.NewAnalyzer() - - var cfg map[string]map[string]any - if settings != nil { - d := map[string]any{ - "i": settings.IgnoreMissing, - "ignoremissingsubtests": settings.IgnoreMissingSubtests, - } - - if config.IsGoGreaterThanOrEqual(settings.Go, "1.22") { - d["ignoreloopVar"] = true - } - - cfg = map[string]map[string]any{a.Name: d} - } - - return goanalysis.NewLinter( - a.Name, - "Detects missing usage of t.Parallel() method in your Go test", - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/perfsprint/perfsprint.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/perfsprint/perfsprint.go deleted file mode 100644 index a4ead1914..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/perfsprint/perfsprint.go +++ /dev/null @@ -1,32 +0,0 @@ -package perfsprint - -import ( - "github.com/catenacyber/perfsprint/analyzer" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(settings *config.PerfSprintSettings) *goanalysis.Linter { - a := analyzer.New() - - cfg := map[string]map[string]any{ - a.Name: {"fiximports": false}, - } - - if settings != nil { - cfg[a.Name]["int-conversion"] = settings.IntConversion - cfg[a.Name]["err-error"] = settings.ErrError - cfg[a.Name]["errorf"] = settings.ErrorF - cfg[a.Name]["sprintf1"] = settings.SprintF1 - cfg[a.Name]["strconcat"] = settings.StrConcat - } - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/prealloc/prealloc.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/prealloc/prealloc.go deleted file mode 100644 index ce7ff9d59..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/prealloc/prealloc.go +++ /dev/null @@ -1,65 +0,0 @@ -package prealloc - -import ( - "fmt" - "sync" - - "github.com/alexkohler/prealloc/pkg" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/golinters/internal" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -const linterName = "prealloc" - -func New(settings *config.PreallocSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues := runPreAlloc(pass, settings) - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Finds slice declarations that could potentially be pre-allocated", - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) -} - -func runPreAlloc(pass *analysis.Pass, settings *config.PreallocSettings) []goanalysis.Issue { - var issues []goanalysis.Issue - - hints := pkg.Check(pass.Files, settings.Simple, settings.RangeLoops, settings.ForLoops) - - for _, hint := range hints { - issues = append(issues, goanalysis.NewIssue(&result.Issue{ - Pos: pass.Fset.Position(hint.Pos), - Text: fmt.Sprintf("Consider pre-allocating %s", internal.FormatCode(hint.DeclaredSliceName, nil)), - FromLinter: linterName, - }, pass)) - } - - return issues -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/predeclared/predeclared.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/predeclared/predeclared.go deleted file mode 100644 index b8d189fd5..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/predeclared/predeclared.go +++ /dev/null @@ -1,26 +0,0 @@ -package predeclared - -import ( - "github.com/nishanths/predeclared/passes/predeclared" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(settings *config.PredeclaredSettings) *goanalysis.Linter { - a := predeclared.Analyzer - - var cfg map[string]map[string]any - if settings != nil { - cfg = map[string]map[string]any{ - a.Name: { - predeclared.IgnoreFlag: settings.Ignore, - predeclared.QualifiedFlag: settings.Qualified, - }, - } - } - - return goanalysis.NewLinter(a.Name, a.Doc, []*analysis.Analyzer{a}, cfg). - WithLoadMode(goanalysis.LoadModeSyntax) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/promlinter/promlinter.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/promlinter/promlinter.go deleted file mode 100644 index 5decbbc7c..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/promlinter/promlinter.go +++ /dev/null @@ -1,77 +0,0 @@ -package promlinter - -import ( - "fmt" - "sync" - - "github.com/yeya24/promlinter" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -const linterName = "promlinter" - -func New(settings *config.PromlinterSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - var promSettings promlinter.Setting - if settings != nil { - promSettings = promlinter.Setting{ - Strict: settings.Strict, - DisabledLintFuncs: settings.DisabledLinters, - } - } - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues := runPromLinter(pass, promSettings) - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Check Prometheus metrics naming via promlint", - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) -} - -func runPromLinter(pass *analysis.Pass, promSettings promlinter.Setting) []goanalysis.Issue { - lintIssues := promlinter.RunLint(pass.Fset, pass.Files, promSettings) - - if len(lintIssues) == 0 { - return nil - } - - issues := make([]goanalysis.Issue, len(lintIssues)) - for k, i := range lintIssues { - issue := result.Issue{ - Pos: i.Pos, - Text: fmt.Sprintf("Metric: %s Error: %s", i.Metric, i.Text), - FromLinter: linterName, - } - - issues[k] = goanalysis.NewIssue(&issue, pass) - } - - return issues -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/protogetter/protogetter.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/protogetter/protogetter.go deleted file mode 100644 index 302ce67b8..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/protogetter/protogetter.go +++ /dev/null @@ -1,74 +0,0 @@ -package protogetter - -import ( - "sync" - - "github.com/ghostiam/protogetter" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -func New(settings *config.ProtoGetterSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - var cfg protogetter.Config - if settings != nil { - cfg = protogetter.Config{ - SkipGeneratedBy: settings.SkipGeneratedBy, - SkipFiles: settings.SkipFiles, - SkipAnyGenerated: settings.SkipAnyGenerated, - ReplaceFirstArgInAppend: settings.ReplaceFirstArgInAppend, - } - } - cfg.Mode = protogetter.GolangciLintMode - - a := protogetter.NewAnalyzer(&cfg) - a.Run = func(pass *analysis.Pass) (any, error) { - pgIssues, err := protogetter.Run(pass, &cfg) - if err != nil { - return nil, err - } - - issues := make([]goanalysis.Issue, len(pgIssues)) - for i, issue := range pgIssues { - report := &result.Issue{ - FromLinter: a.Name, - Pos: issue.Pos, - Text: issue.Message, - Replacement: &result.Replacement{ - Inline: &result.InlineFix{ - StartCol: issue.InlineFix.StartCol, - Length: issue.InlineFix.Length, - NewString: issue.InlineFix.NewString, - }, - }, - } - - issues[i] = goanalysis.NewIssue(report, pass) - } - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - } - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/reassign/reassign.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/reassign/reassign.go deleted file mode 100644 index cfc85635e..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/reassign/reassign.go +++ /dev/null @@ -1,32 +0,0 @@ -package reassign - -import ( - "fmt" - "strings" - - "github.com/curioswitch/go-reassign" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(settings *config.ReassignSettings) *goanalysis.Linter { - a := reassign.NewAnalyzer() - - var cfg map[string]map[string]any - if settings != nil && len(settings.Patterns) > 0 { - cfg = map[string]map[string]any{ - a.Name: { - reassign.FlagPattern: fmt.Sprintf("^(%s)$", strings.Join(settings.Patterns, "|")), - }, - } - } - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/recvcheck/recvcheck.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/recvcheck/recvcheck.go deleted file mode 100644 index 8b030f15d..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/recvcheck/recvcheck.go +++ /dev/null @@ -1,19 +0,0 @@ -package recvcheck - -import ( - "github.com/raeperd/recvcheck" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New() *goanalysis.Linter { - a := recvcheck.Analyzer - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/rowserrcheck/rowserrcheck.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/rowserrcheck/rowserrcheck.go deleted file mode 100644 index 3fe824467..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/rowserrcheck/rowserrcheck.go +++ /dev/null @@ -1,25 +0,0 @@ -package rowserrcheck - -import ( - "github.com/jingyugao/rowserrcheck/passes/rowserr" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(settings *config.RowsErrCheckSettings) *goanalysis.Linter { - var pkgs []string - if settings != nil { - pkgs = settings.Packages - } - - a := rowserr.NewAnalyzer(pkgs...) - - return goanalysis.NewLinter( - a.Name, - "checks whether Rows.Err of rows is checked successfully", - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/spancheck/spancheck.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/spancheck/spancheck.go deleted file mode 100644 index a800a1705..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/spancheck/spancheck.go +++ /dev/null @@ -1,33 +0,0 @@ -package spancheck - -import ( - "github.com/jjti/go-spancheck" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(settings *config.SpancheckSettings) *goanalysis.Linter { - cfg := spancheck.NewDefaultConfig() - - if settings != nil { - if settings.Checks != nil { - cfg.EnabledChecks = settings.Checks - } - - if settings.IgnoreCheckSignatures != nil { - cfg.IgnoreChecksSignaturesSlice = settings.IgnoreCheckSignatures - } - - if settings.ExtraStartSpanSignatures != nil { - cfg.StartSpanMatchersSlice = settings.ExtraStartSpanSignatures - } - } - - a := spancheck.NewAnalyzerWithConfig(cfg) - - return goanalysis. - NewLinter(a.Name, a.Doc, []*analysis.Analyzer{a}, nil). - WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/sqlclosecheck/sqlclosecheck.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/sqlclosecheck/sqlclosecheck.go deleted file mode 100644 index 5eb32ff9d..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/sqlclosecheck/sqlclosecheck.go +++ /dev/null @@ -1,19 +0,0 @@ -package sqlclosecheck - -import ( - "github.com/ryanrolds/sqlclosecheck/pkg/analyzer" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New() *goanalysis.Linter { - a := analyzer.NewAnalyzer() - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/staticcheck/staticcheck.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/staticcheck/staticcheck.go deleted file mode 100644 index 79394bdb7..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/staticcheck/staticcheck.go +++ /dev/null @@ -1,22 +0,0 @@ -package staticcheck - -import ( - "honnef.co/go/tools/staticcheck" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/golinters/internal" -) - -func New(settings *config.StaticCheckSettings) *goanalysis.Linter { - cfg := internal.StaticCheckConfig(settings) - analyzers := internal.SetupStaticCheckAnalyzers(staticcheck.Analyzers, cfg.Checks) - - return goanalysis.NewLinter( - "staticcheck", - "It's a set of rules from staticcheck. It's not the same thing as the staticcheck binary."+ - " The author of staticcheck doesn't support or approve the use of staticcheck as a library inside golangci-lint.", - analyzers, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/stylecheck/stylecheck.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/stylecheck/stylecheck.go deleted file mode 100644 index 60859f28a..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/stylecheck/stylecheck.go +++ /dev/null @@ -1,31 +0,0 @@ -package stylecheck - -import ( - "golang.org/x/tools/go/analysis" - scconfig "honnef.co/go/tools/config" - "honnef.co/go/tools/stylecheck" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/golinters/internal" -) - -func New(settings *config.StaticCheckSettings) *goanalysis.Linter { - cfg := internal.StaticCheckConfig(settings) - - // `scconfig.Analyzer` is a singleton, then it's not possible to have more than one instance for all staticcheck "sub-linters". - // When we will merge the 4 "sub-linters", the problem will disappear: https://github.com/golangci/golangci-lint/issues/357 - // Currently only stylecheck analyzer has a configuration in staticcheck. - scconfig.Analyzer.Run = func(_ *analysis.Pass) (any, error) { - return cfg, nil - } - - analyzers := internal.SetupStaticCheckAnalyzers(stylecheck.Analyzers, cfg.Checks) - - return goanalysis.NewLinter( - "stylecheck", - "Stylecheck is a replacement for golint", - analyzers, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/tagalign/tagalign.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/tagalign/tagalign.go deleted file mode 100644 index f438c51b5..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/tagalign/tagalign.go +++ /dev/null @@ -1,75 +0,0 @@ -package tagalign - -import ( - "sync" - - "github.com/4meepo/tagalign" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -func New(settings *config.TagAlignSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - options := []tagalign.Option{tagalign.WithMode(tagalign.GolangciLintMode)} - - if settings != nil { - options = append(options, tagalign.WithAlign(settings.Align)) - - if settings.Sort || len(settings.Order) > 0 { - options = append(options, tagalign.WithSort(settings.Order...)) - } - - // Strict style will be applied only if Align and Sort are enabled together. - if settings.Strict && settings.Align && settings.Sort { - options = append(options, tagalign.WithStrictStyle()) - } - } - - analyzer := tagalign.NewAnalyzer(options...) - analyzer.Run = func(pass *analysis.Pass) (any, error) { - taIssues := tagalign.Run(pass, options...) - - issues := make([]goanalysis.Issue, len(taIssues)) - for i, issue := range taIssues { - report := &result.Issue{ - FromLinter: analyzer.Name, - Pos: issue.Pos, - Text: issue.Message, - Replacement: &result.Replacement{ - Inline: &result.InlineFix{ - StartCol: issue.InlineFix.StartCol, - Length: issue.InlineFix.Length, - NewString: issue.InlineFix.NewString, - }, - }, - } - - issues[i] = goanalysis.NewIssue(report, pass) - } - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - } - - return goanalysis.NewLinter( - analyzer.Name, - analyzer.Doc, - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/tagliatelle/tagliatelle.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/tagliatelle/tagliatelle.go deleted file mode 100644 index d1674c3e9..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/tagliatelle/tagliatelle.go +++ /dev/null @@ -1,35 +0,0 @@ -package tagliatelle - -import ( - "github.com/ldez/tagliatelle" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(settings *config.TagliatelleSettings) *goanalysis.Linter { - cfg := tagliatelle.Config{ - Rules: map[string]string{ - "json": "camel", - "yaml": "camel", - "header": "header", - }, - } - - if settings != nil { - for k, v := range settings.Case.Rules { - cfg.Rules[k] = v - } - cfg.UseFieldName = settings.Case.UseFieldName - } - - a := tagliatelle.New(cfg) - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/tenv/tenv.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/tenv/tenv.go deleted file mode 100644 index 2fc247fab..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/tenv/tenv.go +++ /dev/null @@ -1,29 +0,0 @@ -package tenv - -import ( - "github.com/sivchari/tenv" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(settings *config.TenvSettings) *goanalysis.Linter { - a := tenv.Analyzer - - var cfg map[string]map[string]any - if settings != nil { - cfg = map[string]map[string]any{ - a.Name: { - tenv.A: settings.All, - }, - } - } - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/testableexamples/testableexamples.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/testableexamples/testableexamples.go deleted file mode 100644 index 6b76271db..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/testableexamples/testableexamples.go +++ /dev/null @@ -1,19 +0,0 @@ -package testableexamples - -import ( - "github.com/maratori/testableexamples/pkg/testableexamples" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New() *goanalysis.Linter { - a := testableexamples.NewAnalyzer() - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/testpackage/testpackage.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/testpackage/testpackage.go deleted file mode 100644 index 632152712..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/testpackage/testpackage.go +++ /dev/null @@ -1,28 +0,0 @@ -package testpackage - -import ( - "strings" - - "github.com/maratori/testpackage/pkg/testpackage" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(cfg *config.TestpackageSettings) *goanalysis.Linter { - a := testpackage.NewAnalyzer() - - var settings map[string]map[string]any - if cfg != nil { - settings = map[string]map[string]any{ - a.Name: { - testpackage.SkipRegexpFlagName: cfg.SkipRegexp, - testpackage.AllowPackagesFlagName: strings.Join(cfg.AllowPackages, ","), - }, - } - } - - return goanalysis.NewLinter(a.Name, a.Doc, []*analysis.Analyzer{a}, settings). - WithLoadMode(goanalysis.LoadModeSyntax) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/tparallel/tparallel.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/tparallel/tparallel.go deleted file mode 100644 index 4f7c43a99..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/tparallel/tparallel.go +++ /dev/null @@ -1,18 +0,0 @@ -package tparallel - -import ( - "github.com/moricho/tparallel" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New() *goanalysis.Linter { - a := tparallel.Analyzer - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/typecheck.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/typecheck.go deleted file mode 100644 index d0eaa00d0..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/typecheck.go +++ /dev/null @@ -1,24 +0,0 @@ -package golinters - -import ( - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func NewTypecheck() *goanalysis.Linter { - const linterName = "typecheck" - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: goanalysis.DummyRun, - } - - return goanalysis.NewLinter( - linterName, - "Like the front-end of a Go compiler, parses and type-checks Go code", - []*analysis.Analyzer{analyzer}, - nil, - ).WithLoadMode(goanalysis.LoadModeNone) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/unconvert/unconvert.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/unconvert/unconvert.go deleted file mode 100644 index 954cc9eb3..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/unconvert/unconvert.go +++ /dev/null @@ -1,62 +0,0 @@ -package unconvert - -import ( - "sync" - - "github.com/golangci/unconvert" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -const linterName = "unconvert" - -func New(settings *config.UnconvertSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues := runUnconvert(pass, settings) - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Remove unnecessary type conversions", - []*analysis.Analyzer{analyzer}, - nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeTypesInfo) -} - -func runUnconvert(pass *analysis.Pass, settings *config.UnconvertSettings) []goanalysis.Issue { - positions := unconvert.Run(pass, settings.FastMath, settings.Safe) - - var issues []goanalysis.Issue - for _, position := range positions { - issues = append(issues, goanalysis.NewIssue(&result.Issue{ - Pos: position, - Text: "unnecessary conversion", - FromLinter: linterName, - }, pass)) - } - - return issues -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/unparam/unparam.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/unparam/unparam.go deleted file mode 100644 index 0fe184736..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/unparam/unparam.go +++ /dev/null @@ -1,90 +0,0 @@ -package unparam - -import ( - "sync" - - "golang.org/x/tools/go/analysis" - "golang.org/x/tools/go/analysis/passes/buildssa" - "golang.org/x/tools/go/packages" - "mvdan.cc/unparam/check" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -const linterName = "unparam" - -func New(settings *config.UnparamSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Requires: []*analysis.Analyzer{buildssa.Analyzer}, - Run: func(pass *analysis.Pass) (any, error) { - issues, err := runUnparam(pass, settings) - if err != nil { - return nil, err - } - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - "Reports unused function parameters", - []*analysis.Analyzer{analyzer}, - nil, - ).WithContextSetter(func(lintCtx *linter.Context) { - if settings.Algo != "cha" { - lintCtx.Log.Warnf("`linters-settings.unparam.algo` isn't supported by the newest `unparam`") - } - }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeTypesInfo) -} - -func runUnparam(pass *analysis.Pass, settings *config.UnparamSettings) ([]goanalysis.Issue, error) { - ssa := pass.ResultOf[buildssa.Analyzer].(*buildssa.SSA) - ssaPkg := ssa.Pkg - - pkg := &packages.Package{ - Fset: pass.Fset, - Syntax: pass.Files, - Types: pass.Pkg, - TypesInfo: pass.TypesInfo, - } - - c := &check.Checker{} - c.CheckExportedFuncs(settings.CheckExported) - c.Packages([]*packages.Package{pkg}) - c.ProgramSSA(ssaPkg.Prog) - - unparamIssues, err := c.Check() - if err != nil { - return nil, err - } - - var issues []goanalysis.Issue - for _, i := range unparamIssues { - issues = append(issues, goanalysis.NewIssue(&result.Issue{ - Pos: pass.Fset.Position(i.Pos()), - Text: i.Message(), - FromLinter: linterName, - }, pass)) - } - - return issues, nil -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/usestdlibvars/usestdlibvars.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/usestdlibvars/usestdlibvars.go deleted file mode 100644 index 050e47f24..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/usestdlibvars/usestdlibvars.go +++ /dev/null @@ -1,38 +0,0 @@ -package usestdlibvars - -import ( - "github.com/sashamelentyev/usestdlibvars/pkg/analyzer" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(cfg *config.UseStdlibVarsSettings) *goanalysis.Linter { - a := analyzer.New() - - cfgMap := make(map[string]map[string]any) - if cfg != nil { - cfgMap[a.Name] = map[string]any{ - analyzer.ConstantKindFlag: cfg.ConstantKind, - analyzer.CryptoHashFlag: cfg.CryptoHash, - analyzer.HTTPMethodFlag: cfg.HTTPMethod, - analyzer.HTTPStatusCodeFlag: cfg.HTTPStatusCode, - analyzer.OSDevNullFlag: cfg.OSDevNull, - analyzer.RPCDefaultPathFlag: cfg.DefaultRPCPath, - analyzer.SQLIsolationLevelFlag: cfg.SQLIsolationLevel, - analyzer.SyslogPriorityFlag: cfg.SyslogPriority, - analyzer.TimeLayoutFlag: cfg.TimeLayout, - analyzer.TimeMonthFlag: cfg.TimeMonth, - analyzer.TimeWeekdayFlag: cfg.TimeWeekday, - analyzer.TLSSignatureSchemeFlag: cfg.TLSSignatureScheme, - } - } - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfgMap, - ).WithLoadMode(goanalysis.LoadModeSyntax) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/wastedassign/wastedassign.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/wastedassign/wastedassign.go deleted file mode 100644 index 094fa95c2..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/wastedassign/wastedassign.go +++ /dev/null @@ -1,19 +0,0 @@ -package wastedassign - -import ( - "github.com/sanposhiho/wastedassign/v2" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New() *goanalysis.Linter { - a := wastedassign.Analyzer - - return goanalysis.NewLinter( - a.Name, - "Finds wasted assignment statements", - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/whitespace/whitespace.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/whitespace/whitespace.go deleted file mode 100644 index 721bfada1..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/whitespace/whitespace.go +++ /dev/null @@ -1,102 +0,0 @@ -package whitespace - -import ( - "fmt" - "sync" - - "github.com/ultraware/whitespace" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -const linterName = "whitespace" - -func New(settings *config.WhitespaceSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - var wsSettings whitespace.Settings - if settings != nil { - wsSettings = whitespace.Settings{ - Mode: whitespace.RunningModeGolangCI, - MultiIf: settings.MultiIf, - MultiFunc: settings.MultiFunc, - } - } - - a := whitespace.NewAnalyzer(&wsSettings) - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithContextSetter(func(_ *linter.Context) { - a.Run = func(pass *analysis.Pass) (any, error) { - issues, err := runWhitespace(pass, wsSettings) - if err != nil { - return nil, err - } - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - } - }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) -} - -func runWhitespace(pass *analysis.Pass, wsSettings whitespace.Settings) ([]goanalysis.Issue, error) { - lintIssues := whitespace.Run(pass, &wsSettings) - - issues := make([]goanalysis.Issue, len(lintIssues)) - for i, issue := range lintIssues { - report := &result.Issue{ - FromLinter: linterName, - Pos: pass.Fset.PositionFor(issue.Diagnostic, false), - Text: issue.Message, - } - - switch issue.MessageType { - case whitespace.MessageTypeRemove: - if len(issue.LineNumbers) == 0 { - continue - } - - report.LineRange = &result.Range{ - From: issue.LineNumbers[0], - To: issue.LineNumbers[len(issue.LineNumbers)-1], - } - - report.Replacement = &result.Replacement{NeedOnlyDelete: true} - - case whitespace.MessageTypeAdd: - report.Pos = pass.Fset.PositionFor(issue.FixStart, false) - report.Replacement = &result.Replacement{ - Inline: &result.InlineFix{ - StartCol: 0, - Length: 1, - NewString: "\n\t", - }, - } - - default: - return nil, fmt.Errorf("unknown message type: %v", issue.MessageType) - } - - issues[i] = goanalysis.NewIssue(report, pass) - } - - return issues, nil -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/wsl/wsl.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/wsl/wsl.go deleted file mode 100644 index c728340ec..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/wsl/wsl.go +++ /dev/null @@ -1,40 +0,0 @@ -package wsl - -import ( - "github.com/bombsimon/wsl/v4" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New(settings *config.WSLSettings) *goanalysis.Linter { - var conf *wsl.Configuration - if settings != nil { - conf = &wsl.Configuration{ - StrictAppend: settings.StrictAppend, - AllowAssignAndCallCuddle: settings.AllowAssignAndCallCuddle, - AllowAssignAndAnythingCuddle: settings.AllowAssignAndAnythingCuddle, - AllowMultiLineAssignCuddle: settings.AllowMultiLineAssignCuddle, - ForceCaseTrailingWhitespaceLimit: settings.ForceCaseTrailingWhitespaceLimit, - AllowTrailingComment: settings.AllowTrailingComment, - AllowSeparatedLeadingComment: settings.AllowSeparatedLeadingComment, - AllowCuddleDeclaration: settings.AllowCuddleDeclaration, - AllowCuddleWithCalls: settings.AllowCuddleWithCalls, - AllowCuddleWithRHS: settings.AllowCuddleWithRHS, - ForceCuddleErrCheckAndAssign: settings.ForceCuddleErrCheckAndAssign, - ErrorVariableNames: settings.ErrorVariableNames, - ForceExclusiveShortDeclarations: settings.ForceExclusiveShortDeclarations, - IncludeGenerated: true, // force to true because golangci-lint already have a way to filter generated files. - } - } - - a := wsl.NewAnalyzer(conf) - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeSyntax) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/zerologlint/zerologlint.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/zerologlint/zerologlint.go deleted file mode 100644 index 6ca74020c..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/zerologlint/zerologlint.go +++ /dev/null @@ -1,19 +0,0 @@ -package zerologlint - -import ( - "github.com/ykadowak/zerologlint" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/goanalysis" -) - -func New() *goanalysis.Linter { - a := zerologlint.Analyzer - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/goutil/env.go b/vendor/github.com/golangci/golangci-lint/pkg/goutil/env.go deleted file mode 100644 index 7b748d8e9..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/goutil/env.go +++ /dev/null @@ -1,63 +0,0 @@ -package goutil - -import ( - "context" - "encoding/json" - "fmt" - "os" - "os/exec" - "strings" - "time" - - "github.com/golangci/golangci-lint/pkg/logutils" -) - -type EnvKey string - -const ( - EnvGoCache EnvKey = "GOCACHE" - EnvGoRoot EnvKey = "GOROOT" -) - -type Env struct { - vars map[string]string - log logutils.Log - debugf logutils.DebugFunc -} - -func NewEnv(log logutils.Log) *Env { - return &Env{ - vars: map[string]string{}, - log: log, - debugf: logutils.Debug(logutils.DebugKeyEnv), - } -} - -func (e Env) Discover(ctx context.Context) error { - startedAt := time.Now() - - //nolint:gosec // Everything is static here. - cmd := exec.CommandContext(ctx, "go", "env", "-json", string(EnvGoCache), string(EnvGoRoot)) - - out, err := cmd.Output() - if err != nil { - return fmt.Errorf("failed to run '%s': %w", strings.Join(cmd.Args, " "), err) - } - - if err = json.Unmarshal(out, &e.vars); err != nil { - return fmt.Errorf("failed to parse '%s' json: %w", strings.Join(cmd.Args, " "), err) - } - - e.debugf("Read go env for %s: %#v", time.Since(startedAt), e.vars) - - return nil -} - -func (e Env) Get(k EnvKey) string { - envValue := os.Getenv(string(k)) - if envValue != "" { - return envValue - } - - return e.vars[string(k)] -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/builder_linter.go b/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/builder_linter.go deleted file mode 100644 index d2a2dc3d0..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/builder_linter.go +++ /dev/null @@ -1,856 +0,0 @@ -package lintersdb - -import ( - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/golinters" - "github.com/golangci/golangci-lint/pkg/golinters/asasalint" - "github.com/golangci/golangci-lint/pkg/golinters/asciicheck" - "github.com/golangci/golangci-lint/pkg/golinters/bidichk" - "github.com/golangci/golangci-lint/pkg/golinters/bodyclose" - "github.com/golangci/golangci-lint/pkg/golinters/canonicalheader" - "github.com/golangci/golangci-lint/pkg/golinters/containedctx" - "github.com/golangci/golangci-lint/pkg/golinters/contextcheck" - "github.com/golangci/golangci-lint/pkg/golinters/copyloopvar" - "github.com/golangci/golangci-lint/pkg/golinters/cyclop" - "github.com/golangci/golangci-lint/pkg/golinters/decorder" - "github.com/golangci/golangci-lint/pkg/golinters/depguard" - "github.com/golangci/golangci-lint/pkg/golinters/dogsled" - "github.com/golangci/golangci-lint/pkg/golinters/dupl" - "github.com/golangci/golangci-lint/pkg/golinters/dupword" - "github.com/golangci/golangci-lint/pkg/golinters/durationcheck" - "github.com/golangci/golangci-lint/pkg/golinters/err113" - "github.com/golangci/golangci-lint/pkg/golinters/errcheck" - "github.com/golangci/golangci-lint/pkg/golinters/errchkjson" - "github.com/golangci/golangci-lint/pkg/golinters/errname" - "github.com/golangci/golangci-lint/pkg/golinters/errorlint" - "github.com/golangci/golangci-lint/pkg/golinters/exhaustive" - "github.com/golangci/golangci-lint/pkg/golinters/exhaustruct" - "github.com/golangci/golangci-lint/pkg/golinters/exportloopref" - "github.com/golangci/golangci-lint/pkg/golinters/fatcontext" - "github.com/golangci/golangci-lint/pkg/golinters/forbidigo" - "github.com/golangci/golangci-lint/pkg/golinters/forcetypeassert" - "github.com/golangci/golangci-lint/pkg/golinters/funlen" - "github.com/golangci/golangci-lint/pkg/golinters/gci" - "github.com/golangci/golangci-lint/pkg/golinters/ginkgolinter" - "github.com/golangci/golangci-lint/pkg/golinters/gocheckcompilerdirectives" - "github.com/golangci/golangci-lint/pkg/golinters/gochecknoglobals" - "github.com/golangci/golangci-lint/pkg/golinters/gochecknoinits" - "github.com/golangci/golangci-lint/pkg/golinters/gochecksumtype" - "github.com/golangci/golangci-lint/pkg/golinters/gocognit" - "github.com/golangci/golangci-lint/pkg/golinters/goconst" - "github.com/golangci/golangci-lint/pkg/golinters/gocritic" - "github.com/golangci/golangci-lint/pkg/golinters/gocyclo" - "github.com/golangci/golangci-lint/pkg/golinters/godot" - "github.com/golangci/golangci-lint/pkg/golinters/godox" - "github.com/golangci/golangci-lint/pkg/golinters/gofmt" - "github.com/golangci/golangci-lint/pkg/golinters/gofumpt" - "github.com/golangci/golangci-lint/pkg/golinters/goheader" - "github.com/golangci/golangci-lint/pkg/golinters/goimports" - "github.com/golangci/golangci-lint/pkg/golinters/gomoddirectives" - "github.com/golangci/golangci-lint/pkg/golinters/gomodguard" - "github.com/golangci/golangci-lint/pkg/golinters/goprintffuncname" - "github.com/golangci/golangci-lint/pkg/golinters/gosec" - "github.com/golangci/golangci-lint/pkg/golinters/gosimple" - "github.com/golangci/golangci-lint/pkg/golinters/gosmopolitan" - "github.com/golangci/golangci-lint/pkg/golinters/govet" - "github.com/golangci/golangci-lint/pkg/golinters/grouper" - "github.com/golangci/golangci-lint/pkg/golinters/iface" - "github.com/golangci/golangci-lint/pkg/golinters/importas" - "github.com/golangci/golangci-lint/pkg/golinters/inamedparam" - "github.com/golangci/golangci-lint/pkg/golinters/ineffassign" - "github.com/golangci/golangci-lint/pkg/golinters/interfacebloat" - "github.com/golangci/golangci-lint/pkg/golinters/intrange" - "github.com/golangci/golangci-lint/pkg/golinters/ireturn" - "github.com/golangci/golangci-lint/pkg/golinters/lll" - "github.com/golangci/golangci-lint/pkg/golinters/loggercheck" - "github.com/golangci/golangci-lint/pkg/golinters/maintidx" - "github.com/golangci/golangci-lint/pkg/golinters/makezero" - "github.com/golangci/golangci-lint/pkg/golinters/mirror" - "github.com/golangci/golangci-lint/pkg/golinters/misspell" - "github.com/golangci/golangci-lint/pkg/golinters/mnd" - "github.com/golangci/golangci-lint/pkg/golinters/musttag" - "github.com/golangci/golangci-lint/pkg/golinters/nakedret" - "github.com/golangci/golangci-lint/pkg/golinters/nestif" - "github.com/golangci/golangci-lint/pkg/golinters/nilerr" - "github.com/golangci/golangci-lint/pkg/golinters/nilnil" - "github.com/golangci/golangci-lint/pkg/golinters/nlreturn" - "github.com/golangci/golangci-lint/pkg/golinters/noctx" - "github.com/golangci/golangci-lint/pkg/golinters/nolintlint" - "github.com/golangci/golangci-lint/pkg/golinters/nonamedreturns" - "github.com/golangci/golangci-lint/pkg/golinters/nosprintfhostport" - "github.com/golangci/golangci-lint/pkg/golinters/paralleltest" - "github.com/golangci/golangci-lint/pkg/golinters/perfsprint" - "github.com/golangci/golangci-lint/pkg/golinters/prealloc" - "github.com/golangci/golangci-lint/pkg/golinters/predeclared" - "github.com/golangci/golangci-lint/pkg/golinters/promlinter" - "github.com/golangci/golangci-lint/pkg/golinters/protogetter" - "github.com/golangci/golangci-lint/pkg/golinters/reassign" - "github.com/golangci/golangci-lint/pkg/golinters/recvcheck" - "github.com/golangci/golangci-lint/pkg/golinters/revive" - "github.com/golangci/golangci-lint/pkg/golinters/rowserrcheck" - "github.com/golangci/golangci-lint/pkg/golinters/sloglint" - "github.com/golangci/golangci-lint/pkg/golinters/spancheck" - "github.com/golangci/golangci-lint/pkg/golinters/sqlclosecheck" - "github.com/golangci/golangci-lint/pkg/golinters/staticcheck" - "github.com/golangci/golangci-lint/pkg/golinters/stylecheck" - "github.com/golangci/golangci-lint/pkg/golinters/tagalign" - "github.com/golangci/golangci-lint/pkg/golinters/tagliatelle" - "github.com/golangci/golangci-lint/pkg/golinters/tenv" - "github.com/golangci/golangci-lint/pkg/golinters/testableexamples" - "github.com/golangci/golangci-lint/pkg/golinters/testifylint" - "github.com/golangci/golangci-lint/pkg/golinters/testpackage" - "github.com/golangci/golangci-lint/pkg/golinters/thelper" - "github.com/golangci/golangci-lint/pkg/golinters/tparallel" - "github.com/golangci/golangci-lint/pkg/golinters/unconvert" - "github.com/golangci/golangci-lint/pkg/golinters/unparam" - "github.com/golangci/golangci-lint/pkg/golinters/unused" - "github.com/golangci/golangci-lint/pkg/golinters/usestdlibvars" - "github.com/golangci/golangci-lint/pkg/golinters/varnamelen" - "github.com/golangci/golangci-lint/pkg/golinters/wastedassign" - "github.com/golangci/golangci-lint/pkg/golinters/whitespace" - "github.com/golangci/golangci-lint/pkg/golinters/wrapcheck" - "github.com/golangci/golangci-lint/pkg/golinters/wsl" - "github.com/golangci/golangci-lint/pkg/golinters/zerologlint" - "github.com/golangci/golangci-lint/pkg/lint/linter" -) - -// LinterBuilder builds the "internal" linters based on the configuration. -type LinterBuilder struct{} - -// NewLinterBuilder creates a new LinterBuilder. -func NewLinterBuilder() *LinterBuilder { - return &LinterBuilder{} -} - -// Build loads all the "internal" linters. -// The configuration is use for the linter settings. -func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) { - if cfg == nil { - return nil, nil - } - - const megacheckName = "megacheck" - - // The linters are sorted in the alphabetical order (case-insensitive). - // When a new linter is added the version in `WithSince(...)` must be the next minor version of golangci-lint. - return []*linter.Config{ - linter.NewConfig(asasalint.New(&cfg.LintersSettings.Asasalint)). - WithSince("v1.47.0"). - WithPresets(linter.PresetBugs). - WithLoadForGoAnalysis(). - WithURL("https://github.com/alingse/asasalint"), - - linter.NewConfig(asciicheck.New()). - WithSince("v1.26.0"). - WithPresets(linter.PresetBugs, linter.PresetStyle). - WithURL("https://github.com/tdakkota/asciicheck"), - - linter.NewConfig(bidichk.New(&cfg.LintersSettings.BiDiChk)). - WithSince("v1.43.0"). - WithPresets(linter.PresetBugs). - WithURL("https://github.com/breml/bidichk"), - - linter.NewConfig(bodyclose.New()). - WithSince("v1.18.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetPerformance, linter.PresetBugs). - WithURL("https://github.com/timakin/bodyclose"), - - linter.NewConfig(canonicalheader.New()). - WithSince("v1.58.0"). - WithPresets(linter.PresetStyle). - WithLoadForGoAnalysis(). - WithURL("https://github.com/lasiar/canonicalHeader"), - - linter.NewConfig(containedctx.New()). - WithSince("v1.44.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/sivchari/containedctx"), - - linter.NewConfig(contextcheck.New()). - WithSince("v1.43.0"). - WithPresets(linter.PresetBugs). - WithLoadForGoAnalysis(). - WithURL("https://github.com/kkHAIKE/contextcheck"), - - linter.NewConfig(copyloopvar.New(&cfg.LintersSettings.CopyLoopVar)). - WithSince("v1.57.0"). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/karamaru-alpha/copyloopvar"). - WithNoopFallback(cfg, linter.IsGoLowerThanGo122()), - - linter.NewConfig(cyclop.New(&cfg.LintersSettings.Cyclop)). - WithSince("v1.37.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetComplexity). - WithURL("https://github.com/bkielbasa/cyclop"), - - linter.NewConfig(decorder.New(&cfg.LintersSettings.Decorder)). - WithSince("v1.44.0"). - WithPresets(linter.PresetFormatting, linter.PresetStyle). - WithURL("https://gitlab.com/bosi/decorder"), - - linter.NewConfig(linter.NewNoopDeprecated("deadcode", cfg, linter.DeprecationError)). - WithSince("v1.0.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetUnused). - WithURL("https://github.com/remyoudompheng/go-misc/tree/master/deadcode"). - DeprecatedError("The owner seems to have abandoned the linter.", "v1.49.0", "unused"), - - linter.NewConfig(depguard.New(&cfg.LintersSettings.Depguard)). - WithSince("v1.4.0"). - WithPresets(linter.PresetStyle, linter.PresetImport, linter.PresetModule). - WithURL("https://github.com/OpenPeeDeeP/depguard"), - - linter.NewConfig(dogsled.New(&cfg.LintersSettings.Dogsled)). - WithSince("v1.19.0"). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/alexkohler/dogsled"), - - linter.NewConfig(dupl.New(&cfg.LintersSettings.Dupl)). - WithSince("v1.0.0"). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/mibk/dupl"), - - linter.NewConfig(dupword.New(&cfg.LintersSettings.DupWord)). - WithSince("v1.50.0"). - WithPresets(linter.PresetComment). - WithURL("https://github.com/Abirdcfly/dupword"), - - linter.NewConfig(durationcheck.New()). - WithSince("v1.37.0"). - WithPresets(linter.PresetBugs). - WithLoadForGoAnalysis(). - WithURL("https://github.com/charithe/durationcheck"), - - linter.NewConfig(errcheck.New(&cfg.LintersSettings.Errcheck)). - WithEnabledByDefault(). - WithSince("v1.0.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetBugs, linter.PresetError). - WithURL("https://github.com/kisielk/errcheck"), - - linter.NewConfig(errchkjson.New(&cfg.LintersSettings.ErrChkJSON)). - WithSince("v1.44.0"). - WithPresets(linter.PresetBugs). - WithLoadForGoAnalysis(). - WithURL("https://github.com/breml/errchkjson"), - - linter.NewConfig(errname.New()). - WithSince("v1.42.0"). - WithPresets(linter.PresetStyle). - WithLoadForGoAnalysis(). - WithURL("https://github.com/Antonboom/errname"), - - linter.NewConfig(errorlint.New(&cfg.LintersSettings.ErrorLint)). - WithSince("v1.32.0"). - WithPresets(linter.PresetBugs, linter.PresetError). - WithLoadForGoAnalysis(). - WithURL("https://github.com/polyfloyd/go-errorlint"), - - linter.NewConfig(linter.NewNoopDeprecated("execinquery", cfg, linter.DeprecationError)). - WithSince("v1.46.0"). - WithPresets(linter.PresetSQL). - WithLoadForGoAnalysis(). - WithURL("https://github.com/1uf3/execinquery"). - DeprecatedError("The repository of the linter has been archived by the owner.", "v1.58.0", ""), - - linter.NewConfig(exhaustive.New(&cfg.LintersSettings.Exhaustive)). - WithSince(" v1.28.0"). - WithPresets(linter.PresetBugs). - WithLoadForGoAnalysis(). - WithURL("https://github.com/nishanths/exhaustive"), - - linter.NewConfig(linter.NewNoopDeprecated("exhaustivestruct", cfg, linter.DeprecationError)). - WithSince("v1.32.0"). - WithPresets(linter.PresetStyle, linter.PresetTest). - WithLoadForGoAnalysis(). - WithURL("https://github.com/mbilski/exhaustivestruct"). - DeprecatedError("The repository of the linter has been deprecated by the owner.", "v1.46.0", "exhaustruct"), - - linter.NewConfig(exhaustruct.New(&cfg.LintersSettings.Exhaustruct)). - WithSince("v1.46.0"). - WithPresets(linter.PresetStyle, linter.PresetTest). - WithLoadForGoAnalysis(). - WithURL("https://github.com/GaijinEntertainment/go-exhaustruct"), - - linter.NewConfig(exportloopref.New()). - WithSince("v1.28.0"). - WithPresets(linter.PresetBugs). - WithLoadForGoAnalysis(). - WithURL("https://github.com/kyoh86/exportloopref"). - DeprecatedWarning("Since Go1.22 (loopvar) this linter is no longer relevant.", "v1.60.2", "copyloopvar"), - - linter.NewConfig(forbidigo.New(&cfg.LintersSettings.Forbidigo)). - WithSince("v1.34.0"). - WithPresets(linter.PresetStyle). - // Strictly speaking, - // the additional information is only needed when forbidigoCfg.AnalyzeTypes is chosen by the user. - // But we don't know that here in all cases (sometimes config is not loaded), - // so we have to assume that it is needed to be on the safe side. - WithLoadForGoAnalysis(). - WithURL("https://github.com/ashanbrown/forbidigo"), - - linter.NewConfig(forcetypeassert.New()). - WithSince("v1.38.0"). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/gostaticanalysis/forcetypeassert"), - - linter.NewConfig(fatcontext.New()). - WithSince("v1.58.0"). - WithPresets(linter.PresetPerformance). - WithLoadForGoAnalysis(). - WithURL("https://github.com/Crocmagnon/fatcontext"), - - linter.NewConfig(funlen.New(&cfg.LintersSettings.Funlen)). - WithSince("v1.18.0"). - WithPresets(linter.PresetComplexity). - WithURL("https://github.com/ultraware/funlen"), - - linter.NewConfig(gci.New(&cfg.LintersSettings.Gci)). - WithSince("v1.30.0"). - WithPresets(linter.PresetFormatting, linter.PresetImport). - WithAutoFix(). - WithURL("https://github.com/daixiang0/gci"), - - linter.NewConfig(ginkgolinter.New(&cfg.LintersSettings.GinkgoLinter)). - WithSince("v1.51.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/nunnatsa/ginkgolinter"), - - linter.NewConfig(gocheckcompilerdirectives.New()). - WithSince("v1.51.0"). - WithPresets(linter.PresetBugs). - WithURL("https://github.com/leighmcculloch/gocheckcompilerdirectives"), - - linter.NewConfig(gochecknoglobals.New()). - WithSince("v1.12.0"). - WithPresets(linter.PresetStyle). - WithLoadForGoAnalysis(). - WithURL("https://github.com/leighmcculloch/gochecknoglobals"), - - linter.NewConfig(gochecknoinits.New()). - WithSince("v1.12.0"). - WithPresets(linter.PresetStyle), - - linter.NewConfig(gochecksumtype.New(&cfg.LintersSettings.GoChecksumType)). - WithSince("v1.55.0"). - WithPresets(linter.PresetBugs). - WithLoadForGoAnalysis(). - WithURL("https://github.com/alecthomas/go-check-sumtype"), - - linter.NewConfig(gocognit.New(&cfg.LintersSettings.Gocognit)). - WithSince("v1.20.0"). - WithPresets(linter.PresetComplexity). - WithURL("https://github.com/uudashr/gocognit"), - - linter.NewConfig(goconst.New(&cfg.LintersSettings.Goconst)). - WithSince("v1.0.0"). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/jgautheron/goconst"), - - linter.NewConfig(gocritic.New(&cfg.LintersSettings.Gocritic)). - WithSince("v1.12.0"). - WithPresets(linter.PresetStyle, linter.PresetMetaLinter). - WithLoadForGoAnalysis(). - WithAutoFix(). - WithURL("https://github.com/go-critic/go-critic"), - - linter.NewConfig(gocyclo.New(&cfg.LintersSettings.Gocyclo)). - WithSince("v1.0.0"). - WithPresets(linter.PresetComplexity). - WithURL("https://github.com/fzipp/gocyclo"), - - linter.NewConfig(godot.New(&cfg.LintersSettings.Godot)). - WithSince("v1.25.0"). - WithPresets(linter.PresetStyle, linter.PresetComment). - WithAutoFix(). - WithURL("https://github.com/tetafro/godot"), - - linter.NewConfig(godox.New(&cfg.LintersSettings.Godox)). - WithSince("v1.19.0"). - WithPresets(linter.PresetStyle, linter.PresetComment). - WithURL("https://github.com/matoous/godox"), - - linter.NewConfig(err113.New()). - WithSince("v1.26.0"). - WithPresets(linter.PresetStyle, linter.PresetError). - WithLoadForGoAnalysis(). - WithAlternativeNames("goerr113"). - WithURL("https://github.com/Djarvur/go-err113"), - - linter.NewConfig(gofmt.New(&cfg.LintersSettings.Gofmt)). - WithSince("v1.0.0"). - WithPresets(linter.PresetFormatting). - WithAutoFix(). - WithURL("https://pkg.go.dev/cmd/gofmt"), - - linter.NewConfig(gofumpt.New(&cfg.LintersSettings.Gofumpt)). - WithSince("v1.28.0"). - WithPresets(linter.PresetFormatting). - WithAutoFix(). - WithURL("https://github.com/mvdan/gofumpt"), - - linter.NewConfig(goheader.New(&cfg.LintersSettings.Goheader)). - WithSince("v1.28.0"). - WithPresets(linter.PresetStyle). - WithAutoFix(). - WithURL("https://github.com/denis-tingaikin/go-header"), - - linter.NewConfig(goimports.New(&cfg.LintersSettings.Goimports)). - WithSince("v1.20.0"). - WithPresets(linter.PresetFormatting, linter.PresetImport). - WithAutoFix(). - WithURL("https://pkg.go.dev/golang.org/x/tools/cmd/goimports"), - - linter.NewConfig(linter.NewNoopDeprecated("golint", cfg, linter.DeprecationError)). - WithSince("v1.0.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/golang/lint"). - DeprecatedError("The repository of the linter has been archived by the owner.", "v1.41.0", "revive"), - - linter.NewConfig(mnd.New(&cfg.LintersSettings.Mnd)). - WithSince("v1.22.0"). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/tommy-muehle/go-mnd"), - - linter.NewConfig(linter.NewNoopDeprecated("gomnd", cfg, linter.DeprecationError)). - WithSince("v1.22.0"). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/tommy-muehle/go-mnd"). - DeprecatedError("The linter has been renamed.", "v1.58.0", "mnd"), - - linter.NewConfig(gomoddirectives.New(&cfg.LintersSettings.GoModDirectives)). - WithSince("v1.39.0"). - WithPresets(linter.PresetStyle, linter.PresetModule). - WithURL("https://github.com/ldez/gomoddirectives"), - - linter.NewConfig(gomodguard.New(&cfg.LintersSettings.Gomodguard)). - WithSince("v1.25.0"). - WithPresets(linter.PresetStyle, linter.PresetImport, linter.PresetModule). - WithURL("https://github.com/ryancurrah/gomodguard"), - - linter.NewConfig(goprintffuncname.New()). - WithSince("v1.23.0"). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/golangci/go-printf-func-name"), - - linter.NewConfig(gosec.New(&cfg.LintersSettings.Gosec)). - WithSince("v1.0.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetBugs). - WithURL("https://github.com/securego/gosec"). - WithAlternativeNames("gas"), - - linter.NewConfig(gosimple.New(&cfg.LintersSettings.Gosimple)). - WithEnabledByDefault(). - WithSince("v1.20.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetStyle). - WithAlternativeNames(megacheckName). - WithURL("https://github.com/dominikh/go-tools/tree/master/simple"), - - linter.NewConfig(gosmopolitan.New(&cfg.LintersSettings.Gosmopolitan)). - WithSince("v1.53.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetBugs). - WithURL("https://github.com/xen0n/gosmopolitan"), - - linter.NewConfig(govet.New(&cfg.LintersSettings.Govet)). - WithEnabledByDefault(). - WithSince("v1.0.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetBugs, linter.PresetMetaLinter). - WithAlternativeNames("vet", "vetshadow"). - WithURL("https://pkg.go.dev/cmd/vet"), - - linter.NewConfig(grouper.New(&cfg.LintersSettings.Grouper)). - WithSince("v1.44.0"). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/leonklingele/grouper"), - - linter.NewConfig(linter.NewNoopDeprecated("ifshort", cfg, linter.DeprecationError)). - WithSince("v1.36.0"). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/esimonov/ifshort"). - DeprecatedError("The repository of the linter has been deprecated by the owner.", "v1.48.0", ""), - - linter.NewConfig(iface.New(&cfg.LintersSettings.Iface)). - WithSince("v1.62.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/uudashr/iface"), - - linter.NewConfig(importas.New(&cfg.LintersSettings.ImportAs)). - WithSince("v1.38.0"). - WithPresets(linter.PresetStyle). - WithLoadForGoAnalysis(). - WithURL("https://github.com/julz/importas"), - - linter.NewConfig(inamedparam.New(&cfg.LintersSettings.Inamedparam)). - WithSince("v1.55.0"). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/macabu/inamedparam"), - - linter.NewConfig(ineffassign.New()). - WithEnabledByDefault(). - WithSince("v1.0.0"). - WithPresets(linter.PresetUnused). - WithURL("https://github.com/gordonklaus/ineffassign"), - - linter.NewConfig(interfacebloat.New(&cfg.LintersSettings.InterfaceBloat)). - WithSince("v1.49.0"). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/sashamelentyev/interfacebloat"), - - linter.NewConfig(linter.NewNoopDeprecated("interfacer", cfg, linter.DeprecationError)). - WithSince("v1.0.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/mvdan/interfacer"). - DeprecatedError("The repository of the linter has been archived by the owner.", "v1.38.0", ""), - - linter.NewConfig(intrange.New()). - WithSince("v1.57.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/ckaznocha/intrange"). - WithNoopFallback(cfg, linter.IsGoLowerThanGo122()), - - linter.NewConfig(ireturn.New(&cfg.LintersSettings.Ireturn)). - WithSince("v1.43.0"). - WithPresets(linter.PresetStyle). - WithLoadForGoAnalysis(). - WithURL("https://github.com/butuzov/ireturn"), - - linter.NewConfig(lll.New(&cfg.LintersSettings.Lll)). - WithSince("v1.8.0"). - WithPresets(linter.PresetStyle), - - linter.NewConfig(loggercheck.New(&cfg.LintersSettings.LoggerCheck)). - WithSince("v1.49.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetStyle, linter.PresetBugs). - WithAlternativeNames("logrlint"). - WithURL("https://github.com/timonwong/loggercheck"), - - linter.NewConfig(maintidx.New(&cfg.LintersSettings.MaintIdx)). - WithSince("v1.44.0"). - WithPresets(linter.PresetComplexity). - WithURL("https://github.com/yagipy/maintidx"), - - linter.NewConfig(makezero.New(&cfg.LintersSettings.Makezero)). - WithSince("v1.34.0"). - WithPresets(linter.PresetStyle, linter.PresetBugs). - WithLoadForGoAnalysis(). - WithURL("https://github.com/ashanbrown/makezero"), - - linter.NewConfig(linter.NewNoopDeprecated("maligned", cfg, linter.DeprecationError)). - WithSince("v1.0.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetPerformance). - WithURL("https://github.com/mdempsky/maligned"). - DeprecatedError("The repository of the linter has been archived by the owner.", "v1.38.0", "govet 'fieldalignment'"), - - linter.NewConfig(mirror.New()). - WithSince("v1.53.0"). - WithPresets(linter.PresetStyle). - WithLoadForGoAnalysis(). - WithAutoFix(). - WithURL("https://github.com/butuzov/mirror"), - - linter.NewConfig(misspell.New(&cfg.LintersSettings.Misspell)). - WithSince("v1.8.0"). - WithPresets(linter.PresetStyle, linter.PresetComment). - WithAutoFix(). - WithURL("https://github.com/client9/misspell"), - - linter.NewConfig(musttag.New(&cfg.LintersSettings.MustTag)). - WithSince("v1.51.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetStyle, linter.PresetBugs). - WithURL("https://github.com/go-simpler/musttag"), - - linter.NewConfig(nakedret.New(&cfg.LintersSettings.Nakedret)). - WithSince("v1.19.0"). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/alexkohler/nakedret"), - - linter.NewConfig(nestif.New(&cfg.LintersSettings.Nestif)). - WithSince("v1.25.0"). - WithPresets(linter.PresetComplexity). - WithURL("https://github.com/nakabonne/nestif"), - - linter.NewConfig(nilerr.New()). - WithSince("v1.38.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetBugs). - WithURL("https://github.com/gostaticanalysis/nilerr"), - - linter.NewConfig(nilnil.New(&cfg.LintersSettings.NilNil)). - WithSince("v1.43.0"). - WithPresets(linter.PresetStyle). - WithLoadForGoAnalysis(). - WithURL("https://github.com/Antonboom/nilnil"), - - linter.NewConfig(nlreturn.New(&cfg.LintersSettings.Nlreturn)). - WithSince("v1.30.0"). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/ssgreg/nlreturn"), - - linter.NewConfig(noctx.New()). - WithSince("v1.28.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetPerformance, linter.PresetBugs). - WithURL("https://github.com/sonatard/noctx"), - - linter.NewConfig(nonamedreturns.New(&cfg.LintersSettings.NoNamedReturns)). - WithSince("v1.46.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/firefart/nonamedreturns"), - - linter.NewConfig(linter.NewNoopDeprecated("nosnakecase", cfg, linter.DeprecationError)). - WithSince("v1.47.0"). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/sivchari/nosnakecase"). - DeprecatedError("The repository of the linter has been deprecated by the owner.", "v1.48.1", "revive 'var-naming'"), - - linter.NewConfig(nosprintfhostport.New()). - WithSince("v1.46.0"). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/stbenjam/no-sprintf-host-port"), - - linter.NewConfig(paralleltest.New(&cfg.LintersSettings.ParallelTest)). - WithSince("v1.33.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetStyle, linter.PresetTest). - WithURL("https://github.com/kunwardeep/paralleltest"), - - linter.NewConfig(perfsprint.New(&cfg.LintersSettings.PerfSprint)). - WithSince("v1.55.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetPerformance). - WithURL("https://github.com/catenacyber/perfsprint"), - - linter.NewConfig(prealloc.New(&cfg.LintersSettings.Prealloc)). - WithSince("v1.19.0"). - WithPresets(linter.PresetPerformance). - WithURL("https://github.com/alexkohler/prealloc"), - - linter.NewConfig(predeclared.New(&cfg.LintersSettings.Predeclared)). - WithSince("v1.35.0"). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/nishanths/predeclared"), - - linter.NewConfig(promlinter.New(&cfg.LintersSettings.Promlinter)). - WithSince("v1.40.0"). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/yeya24/promlinter"), - - linter.NewConfig(protogetter.New(&cfg.LintersSettings.ProtoGetter)). - WithSince("v1.55.0"). - WithPresets(linter.PresetBugs). - WithLoadForGoAnalysis(). - WithAutoFix(). - WithURL("https://github.com/ghostiam/protogetter"), - - linter.NewConfig(reassign.New(&cfg.LintersSettings.Reassign)). - WithSince("v1.49.0"). - WithPresets(linter.PresetBugs). - WithLoadForGoAnalysis(). - WithURL("https://github.com/curioswitch/go-reassign"), - - linter.NewConfig(recvcheck.New()). - WithSince("v1.62.0"). - WithPresets(linter.PresetBugs). - WithLoadForGoAnalysis(). - WithURL("https://github.com/raeperd/recvcheck"), - - linter.NewConfig(revive.New(&cfg.LintersSettings.Revive)). - WithSince("v1.37.0"). - WithPresets(linter.PresetStyle, linter.PresetMetaLinter). - ConsiderSlow(). - WithURL("https://github.com/mgechev/revive"), - - linter.NewConfig(rowserrcheck.New(&cfg.LintersSettings.RowsErrCheck)). - WithSince("v1.23.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetBugs, linter.PresetSQL). - WithURL("https://github.com/jingyugao/rowserrcheck"), - - linter.NewConfig(sloglint.New(&cfg.LintersSettings.SlogLint)). - WithSince("v1.55.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetStyle, linter.PresetFormatting). - WithURL("https://github.com/go-simpler/sloglint"), - - linter.NewConfig(linter.NewNoopDeprecated("scopelint", cfg, linter.DeprecationError)). - WithSince("v1.12.0"). - WithPresets(linter.PresetBugs). - WithURL("https://github.com/kyoh86/scopelint"). - DeprecatedError("The repository of the linter has been deprecated by the owner.", "v1.39.0", "exportloopref"), - - linter.NewConfig(sqlclosecheck.New()). - WithSince("v1.28.0"). - WithPresets(linter.PresetBugs, linter.PresetSQL). - WithLoadForGoAnalysis(). - WithURL("https://github.com/ryanrolds/sqlclosecheck"), - - linter.NewConfig(spancheck.New(&cfg.LintersSettings.Spancheck)). - WithSince("v1.56.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetBugs). - WithURL("https://github.com/jjti/go-spancheck"), - - linter.NewConfig(staticcheck.New(&cfg.LintersSettings.Staticcheck)). - WithEnabledByDefault(). - WithSince("v1.0.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetBugs, linter.PresetMetaLinter). - WithAlternativeNames(megacheckName). - WithURL("https://staticcheck.dev/"), - - linter.NewConfig(linter.NewNoopDeprecated("structcheck", cfg, linter.DeprecationError)). - WithSince("v1.0.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetUnused). - WithURL("https://github.com/opennota/check"). - DeprecatedError("The owner seems to have abandoned the linter.", "v1.49.0", "unused"), - - linter.NewConfig(stylecheck.New(&cfg.LintersSettings.Stylecheck)). - WithSince("v1.20.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/dominikh/go-tools/tree/master/stylecheck"), - - linter.NewConfig(tagalign.New(&cfg.LintersSettings.TagAlign)). - WithSince("v1.53.0"). - WithPresets(linter.PresetStyle, linter.PresetFormatting). - WithAutoFix(). - WithURL("https://github.com/4meepo/tagalign"), - - linter.NewConfig(tagliatelle.New(&cfg.LintersSettings.Tagliatelle)). - WithSince("v1.40.0"). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/ldez/tagliatelle"), - - linter.NewConfig(tenv.New(&cfg.LintersSettings.Tenv)). - WithSince("v1.43.0"). - WithPresets(linter.PresetTest). - WithLoadForGoAnalysis(). - WithURL("https://github.com/sivchari/tenv"), - - linter.NewConfig(testableexamples.New()). - WithSince("v1.50.0"). - WithPresets(linter.PresetTest). - WithURL("https://github.com/maratori/testableexamples"), - - linter.NewConfig(testifylint.New(&cfg.LintersSettings.Testifylint)). - WithSince("v1.55.0"). - WithPresets(linter.PresetTest, linter.PresetBugs). - WithLoadForGoAnalysis(). - WithURL("https://github.com/Antonboom/testifylint"), - - linter.NewConfig(testpackage.New(&cfg.LintersSettings.Testpackage)). - WithSince("v1.25.0"). - WithPresets(linter.PresetStyle, linter.PresetTest). - WithURL("https://github.com/maratori/testpackage"), - - linter.NewConfig(thelper.New(&cfg.LintersSettings.Thelper)). - WithSince("v1.34.0"). - WithPresets(linter.PresetTest). - WithLoadForGoAnalysis(). - WithURL("https://github.com/kulti/thelper"), - - linter.NewConfig(tparallel.New()). - WithSince("v1.32.0"). - WithPresets(linter.PresetStyle, linter.PresetTest). - WithLoadForGoAnalysis(). - WithURL("https://github.com/moricho/tparallel"), - - linter.NewConfig(golinters.NewTypecheck()). - WithInternal(). - WithEnabledByDefault(). - WithSince("v1.3.0"), - - linter.NewConfig(unconvert.New(&cfg.LintersSettings.Unconvert)). - WithSince("v1.0.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/mdempsky/unconvert"), - - linter.NewConfig(unparam.New(&cfg.LintersSettings.Unparam)). - WithSince("v1.9.0"). - WithPresets(linter.PresetUnused). - WithLoadForGoAnalysis(). - WithURL("https://github.com/mvdan/unparam"), - - linter.NewConfig(unused.New(&cfg.LintersSettings.Unused)). - WithEnabledByDefault(). - WithSince("v1.20.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetUnused). - WithAlternativeNames(megacheckName). - ConsiderSlow(). - WithChangeTypes(). - WithURL("https://github.com/dominikh/go-tools/tree/master/unused"), - - linter.NewConfig(usestdlibvars.New(&cfg.LintersSettings.UseStdlibVars)). - WithSince("v1.48.0"). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/sashamelentyev/usestdlibvars"), - - linter.NewConfig(linter.NewNoopDeprecated("varcheck", cfg, linter.DeprecationError)). - WithSince("v1.0.0"). - WithLoadForGoAnalysis(). - WithPresets(linter.PresetUnused). - WithURL("https://github.com/opennota/check"). - DeprecatedError("The owner seems to have abandoned the linter.", "v1.49.0", "unused"), - - linter.NewConfig(varnamelen.New(&cfg.LintersSettings.Varnamelen)). - WithSince("v1.43.0"). - WithPresets(linter.PresetStyle). - WithLoadForGoAnalysis(). - WithURL("https://github.com/blizzy78/varnamelen"), - - linter.NewConfig(wastedassign.New()). - WithSince("v1.38.0"). - WithPresets(linter.PresetStyle). - WithLoadForGoAnalysis(). - WithURL("https://github.com/sanposhiho/wastedassign"), - - linter.NewConfig(whitespace.New(&cfg.LintersSettings.Whitespace)). - WithSince("v1.19.0"). - WithPresets(linter.PresetStyle). - WithAutoFix(). - WithURL("https://github.com/ultraware/whitespace"), - - linter.NewConfig(wrapcheck.New(&cfg.LintersSettings.Wrapcheck)). - WithSince("v1.32.0"). - WithPresets(linter.PresetStyle, linter.PresetError). - WithLoadForGoAnalysis(). - WithURL("https://github.com/tomarrell/wrapcheck"), - - linter.NewConfig(wsl.New(&cfg.LintersSettings.WSL)). - WithSince("v1.20.0"). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/bombsimon/wsl"), - - linter.NewConfig(zerologlint.New()). - WithSince("v1.53.0"). - WithPresets(linter.PresetBugs). - WithLoadForGoAnalysis(). - WithURL("https://github.com/ykadowak/zerologlint"), - - // nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives - linter.NewConfig(nolintlint.New(&cfg.LintersSettings.NoLintLint)). - WithSince("v1.26.0"). - WithPresets(linter.PresetStyle). - WithAutoFix(). - WithURL("https://github.com/golangci/golangci-lint/tree/master/pkg/golinters/nolintlint/internal"), - }, nil -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/logutils/logutils.go b/vendor/github.com/golangci/golangci-lint/pkg/logutils/logutils.go deleted file mode 100644 index 3c27e2557..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/logutils/logutils.go +++ /dev/null @@ -1,117 +0,0 @@ -package logutils - -import ( - "os" - "strings" -) - -// EnvTestRun value: "1" -const EnvTestRun = "GL_TEST_RUN" - -// envDebug value: one or several debug keys. -// examples: -// - Remove output to `/dev/null`: `GL_DEBUG=linters_output ./golangci-lint run` -// - Show linters configuration: `GL_DEBUG=enabled_linters golangci-lint run` -// - Some analysis details: `GL_DEBUG=goanalysis/analyze,goanalysis/facts golangci-lint run` -const envDebug = "GL_DEBUG" - -const ( - DebugKeyAutogenExclude = "autogen_exclude" // Debugs a filter excluding autogenerated source code. - DebugKeyBinSalt = "bin_salt" - DebugKeyConfigReader = "config_reader" - DebugKeyEmpty = "" - DebugKeyEnabledLinters = "enabled_linters" - DebugKeyEnv = "env" // Debugs `go env` command. - DebugKeyExcludeRules = "exclude_rules" - DebugKeyExec = "exec" - DebugKeyFilenameUnadjuster = "filename_unadjuster" - DebugKeyInvalidIssue = "invalid_issue" - DebugKeyForbidigo = "forbidigo" - DebugKeyGoEnv = "goenv" - DebugKeyLinter = "linter" - DebugKeyLintersContext = "linters_context" - DebugKeyLintersDB = "lintersdb" - DebugKeyLintersOutput = "linters_output" - DebugKeyLoader = "loader" // Debugs packages loading (including `go/packages` internal debugging). - DebugKeyMaxFromLinter = "max_from_linter" - DebugKeyMaxSameIssues = "max_same_issues" - DebugKeyPkgCache = "pkgcache" - DebugKeyRunner = "runner" - DebugKeySeverityRules = "severity_rules" - DebugKeySkipDirs = "skip_dirs" - DebugKeySourceCode = "source_code" - DebugKeyStopwatch = "stopwatch" - DebugKeyTabPrinter = "tab_printer" - DebugKeyTest = "test" - DebugKeyTextPrinter = "text_printer" -) - -const ( - DebugKeyGoAnalysis = "goanalysis" - - DebugKeyGoAnalysisAnalyze = DebugKeyGoAnalysis + "/analyze" - DebugKeyGoAnalysisIssuesCache = DebugKeyGoAnalysis + "/issues/cache" - DebugKeyGoAnalysisMemory = DebugKeyGoAnalysis + "/memory" - - DebugKeyGoAnalysisFacts = DebugKeyGoAnalysis + "/facts" - DebugKeyGoAnalysisFactsCache = DebugKeyGoAnalysisFacts + "/cache" - DebugKeyGoAnalysisFactsExport = DebugKeyGoAnalysisFacts + "/export" - DebugKeyGoAnalysisFactsInherit = DebugKeyGoAnalysisFacts + "/inherit" -) - -const ( - DebugKeyGoCritic = "gocritic" // Debugs `go-critic` linter. - DebugKeyGovet = "govet" // Debugs `govet` linter. - DebugKeyNolint = "nolint" // Debugs a filter excluding issues by `//nolint` comments. - DebugKeyRevive = "revive" // Debugs `revive` linter. -) - -func getEnabledDebugs() map[string]bool { - ret := map[string]bool{} - debugVar := os.Getenv(envDebug) - if debugVar == "" { - return ret - } - - for _, tag := range strings.Split(debugVar, ",") { - ret[tag] = true - } - - return ret -} - -var enabledDebugs = getEnabledDebugs() - -type DebugFunc func(format string, args ...any) - -func nopDebugf(_ string, _ ...any) {} - -func Debug(tag string) DebugFunc { - if !enabledDebugs[tag] { - return nopDebugf - } - - logger := NewStderrLog(tag) - logger.SetLevel(LogLevelDebug) - - return func(format string, args ...any) { - logger.Debugf(format, args...) - } -} - -func HaveDebugTag(tag string) bool { - return enabledDebugs[tag] -} - -var verbose bool - -func SetupVerboseLog(log Log, isVerbose bool) { - if isVerbose { - verbose = isVerbose - log.SetLevel(LogLevelInfo) - } -} - -func IsVerbose() bool { - return verbose -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/printers/codeclimate.go b/vendor/github.com/golangci/golangci-lint/pkg/printers/codeclimate.go deleted file mode 100644 index b65339682..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/printers/codeclimate.go +++ /dev/null @@ -1,59 +0,0 @@ -package printers - -import ( - "encoding/json" - "io" - - "github.com/golangci/golangci-lint/pkg/result" -) - -const defaultCodeClimateSeverity = "critical" - -// CodeClimateIssue is a subset of the Code Climate spec. -// https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#data-types -// It is just enough to support GitLab CI Code Quality. -// https://docs.gitlab.com/ee/ci/testing/code_quality.html#implement-a-custom-tool -type CodeClimateIssue struct { - Description string `json:"description"` - CheckName string `json:"check_name"` - Severity string `json:"severity,omitempty"` - Fingerprint string `json:"fingerprint"` - Location struct { - Path string `json:"path"` - Lines struct { - Begin int `json:"begin"` - } `json:"lines"` - } `json:"location"` -} - -type CodeClimate struct { - w io.Writer -} - -func NewCodeClimate(w io.Writer) *CodeClimate { - return &CodeClimate{w: w} -} - -func (p CodeClimate) Print(issues []result.Issue) error { - codeClimateIssues := make([]CodeClimateIssue, 0, len(issues)) - - for i := range issues { - issue := &issues[i] - - codeClimateIssue := CodeClimateIssue{} - codeClimateIssue.Description = issue.Description() - codeClimateIssue.CheckName = issue.FromLinter - codeClimateIssue.Location.Path = issue.Pos.Filename - codeClimateIssue.Location.Lines.Begin = issue.Pos.Line - codeClimateIssue.Fingerprint = issue.Fingerprint() - codeClimateIssue.Severity = defaultCodeClimateSeverity - - if issue.Severity != "" { - codeClimateIssue.Severity = issue.Severity - } - - codeClimateIssues = append(codeClimateIssues, codeClimateIssue) - } - - return json.NewEncoder(p.w).Encode(codeClimateIssues) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/printers/githubaction.go b/vendor/github.com/golangci/golangci-lint/pkg/printers/githubaction.go deleted file mode 100644 index d9cdb1e6e..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/printers/githubaction.go +++ /dev/null @@ -1,52 +0,0 @@ -package printers - -import ( - "fmt" - "io" - "path/filepath" - - "github.com/golangci/golangci-lint/pkg/result" -) - -const defaultGithubSeverity = "error" - -type GitHubAction struct { - w io.Writer -} - -// NewGitHubAction output format outputs issues according to GitHub Action. -// Deprecated -func NewGitHubAction(w io.Writer) *GitHubAction { - return &GitHubAction{w: w} -} - -func (p *GitHubAction) Print(issues []result.Issue) error { - for ind := range issues { - _, err := fmt.Fprintln(p.w, formatIssueAsGitHub(&issues[ind])) - if err != nil { - return err - } - } - return nil -} - -// print each line as: ::error file=app.js,line=10,col=15::Something went wrong -func formatIssueAsGitHub(issue *result.Issue) string { - severity := defaultGithubSeverity - if issue.Severity != "" { - severity = issue.Severity - } - - // Convert backslashes to forward slashes. - // This is needed when running on windows. - // Otherwise, GitHub won't be able to show the annotations pointing to the file path with backslashes. - file := filepath.ToSlash(issue.FilePath()) - - ret := fmt.Sprintf("::%s file=%s,line=%d", severity, file, issue.Line()) - if issue.Pos.Column != 0 { - ret += fmt.Sprintf(",col=%d", issue.Pos.Column) - } - - ret += fmt.Sprintf("::%s (%s)", issue.Text, issue.FromLinter) - return ret -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/printers/json.go b/vendor/github.com/golangci/golangci-lint/pkg/printers/json.go deleted file mode 100644 index 28509cac4..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/printers/json.go +++ /dev/null @@ -1,38 +0,0 @@ -package printers - -import ( - "encoding/json" - "io" - - "github.com/golangci/golangci-lint/pkg/report" - "github.com/golangci/golangci-lint/pkg/result" -) - -type JSON struct { - rd *report.Data // TODO(ldez) should be drop in v2. Only use by JSON reporter. - w io.Writer -} - -func NewJSON(rd *report.Data, w io.Writer) *JSON { - return &JSON{ - rd: rd, - w: w, - } -} - -type JSONResult struct { - Issues []result.Issue - Report *report.Data -} - -func (p JSON) Print(issues []result.Issue) error { - res := JSONResult{ - Issues: issues, - Report: p.rd, - } - if res.Issues == nil { - res.Issues = []result.Issue{} - } - - return json.NewEncoder(p.w).Encode(res) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/printers/printer.go b/vendor/github.com/golangci/golangci-lint/pkg/printers/printer.go deleted file mode 100644 index 20be02e01..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/printers/printer.go +++ /dev/null @@ -1,145 +0,0 @@ -package printers - -import ( - "errors" - "fmt" - "io" - "os" - "path/filepath" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/logutils" - "github.com/golangci/golangci-lint/pkg/report" - "github.com/golangci/golangci-lint/pkg/result" -) - -const defaultFileMode = 0o644 - -type issuePrinter interface { - Print(issues []result.Issue) error -} - -// Printer prints issues -type Printer struct { - cfg *config.Output - reportData *report.Data - - log logutils.Log - - stdOut io.Writer - stdErr io.Writer -} - -// NewPrinter creates a new Printer. -func NewPrinter(log logutils.Log, cfg *config.Output, reportData *report.Data) (*Printer, error) { - if log == nil { - return nil, errors.New("missing log argument in constructor") - } - if cfg == nil { - return nil, errors.New("missing config argument in constructor") - } - if reportData == nil { - return nil, errors.New("missing reportData argument in constructor") - } - - return &Printer{ - cfg: cfg, - reportData: reportData, - log: log, - stdOut: logutils.StdOut, - stdErr: logutils.StdErr, - }, nil -} - -// Print prints issues based on the formats defined -func (c *Printer) Print(issues []result.Issue) error { - for _, format := range c.cfg.Formats { - err := c.printReports(issues, format) - if err != nil { - return err - } - } - - return nil -} - -func (c *Printer) printReports(issues []result.Issue, format config.OutputFormat) error { - w, shouldClose, err := c.createWriter(format.Path) - if err != nil { - return fmt.Errorf("can't create output for %s: %w", format.Path, err) - } - - defer func() { - if file, ok := w.(io.Closer); shouldClose && ok { - _ = file.Close() - } - }() - - p, err := c.createPrinter(format.Format, w) - if err != nil { - return err - } - - if err = p.Print(issues); err != nil { - return fmt.Errorf("can't print %d issues: %w", len(issues), err) - } - - return nil -} - -func (c *Printer) createWriter(path string) (io.Writer, bool, error) { - if path == "" || path == "stdout" { - return c.stdOut, false, nil - } - - if path == "stderr" { - return c.stdErr, false, nil - } - - err := os.MkdirAll(filepath.Dir(path), os.ModePerm) - if err != nil { - return nil, false, err - } - - f, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, defaultFileMode) - if err != nil { - return nil, false, err - } - - return f, true, nil -} - -func (c *Printer) createPrinter(format string, w io.Writer) (issuePrinter, error) { - var p issuePrinter - - switch format { - case config.OutFormatJSON: - p = NewJSON(c.reportData, w) - case config.OutFormatLineNumber, config.OutFormatColoredLineNumber: - p = NewText(c.cfg.PrintIssuedLine, - format == config.OutFormatColoredLineNumber, c.cfg.PrintLinterName, - c.log.Child(logutils.DebugKeyTextPrinter), w) - case config.OutFormatTab, config.OutFormatColoredTab: - p = NewTab(c.cfg.PrintLinterName, - format == config.OutFormatColoredTab, - c.log.Child(logutils.DebugKeyTabPrinter), w) - case config.OutFormatCheckstyle: - p = NewCheckstyle(w) - case config.OutFormatCodeClimate: - p = NewCodeClimate(w) - case config.OutFormatHTML: - p = NewHTML(w) - case config.OutFormatJunitXML, config.OutFormatJunitXMLExtended: - p = NewJunitXML(format == config.OutFormatJunitXMLExtended, w) - case config.OutFormatGithubActions: - p = NewGitHubAction(w) - case config.OutFormatTeamCity: - p = NewTeamCity(w) - case config.OutFormatSarif: - p = NewSarif(w) - default: - return nil, fmt.Errorf("unknown output format %q", format) - } - - return p, nil -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/autogenerated_exclude.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/autogenerated_exclude.go deleted file mode 100644 index 82316f6a0..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/autogenerated_exclude.go +++ /dev/null @@ -1,177 +0,0 @@ -package processors - -import ( - "fmt" - "go/parser" - "go/token" - "path/filepath" - "regexp" - "strings" - - "github.com/golangci/golangci-lint/pkg/logutils" - "github.com/golangci/golangci-lint/pkg/result" -) - -const ( - AutogeneratedModeLax = "lax" - AutogeneratedModeStrict = "strict" - AutogeneratedModeDisable = "disable" -) - -// The values must be in lowercase. -const ( - genCodeGenerated = "code generated" - genDoNotEdit = "do not edit" - - // Related to easyjson. - genAutoFile = "autogenerated file" - - //nolint:lll // Long URL - // Related to Swagger Codegen. - // https://github.com/swagger-api/swagger-codegen/blob/61cfeac3b9d855b4eb8bffa0d118bece117bcb7d/modules/swagger-codegen/src/main/resources/go/partial_header.mustache#L16 - // https://github.com/swagger-api/swagger-codegen/issues/12358 - genSwaggerCodegen = "* generated by: swagger codegen " -) - -var _ Processor = (*AutogeneratedExclude)(nil) - -type fileSummary struct { - generated bool -} - -type AutogeneratedExclude struct { - debugf logutils.DebugFunc - - mode string - strictPattern *regexp.Regexp - - fileSummaryCache map[string]*fileSummary -} - -func NewAutogeneratedExclude(mode string) *AutogeneratedExclude { - return &AutogeneratedExclude{ - debugf: logutils.Debug(logutils.DebugKeyAutogenExclude), - mode: mode, - strictPattern: regexp.MustCompile(`^// Code generated .* DO NOT EDIT\.$`), - fileSummaryCache: map[string]*fileSummary{}, - } -} - -func (*AutogeneratedExclude) Name() string { - return "autogenerated_exclude" -} - -func (p *AutogeneratedExclude) Process(issues []result.Issue) ([]result.Issue, error) { - if p.mode == AutogeneratedModeDisable { - return issues, nil - } - - return filterIssuesErr(issues, p.shouldPassIssue) -} - -func (*AutogeneratedExclude) Finish() {} - -func (p *AutogeneratedExclude) shouldPassIssue(issue *result.Issue) (bool, error) { - if filepath.Base(issue.FilePath()) == "go.mod" { - return true, nil - } - - // The file is already known. - fs := p.fileSummaryCache[issue.FilePath()] - if fs != nil { - return !fs.generated, nil - } - - fs = &fileSummary{} - p.fileSummaryCache[issue.FilePath()] = fs - - if p.mode == AutogeneratedModeStrict { - var err error - fs.generated, err = p.isGeneratedFileStrict(issue.FilePath()) - if err != nil { - return false, fmt.Errorf("failed to get doc (strict) of file %s: %w", issue.FilePath(), err) - } - } else { - doc, err := getComments(issue.FilePath()) - if err != nil { - return false, fmt.Errorf("failed to get doc (lax) of file %s: %w", issue.FilePath(), err) - } - - fs.generated = p.isGeneratedFileLax(doc) - } - - p.debugf("file %q is generated: %t", issue.FilePath(), fs.generated) - - // don't report issues for autogenerated files - return !fs.generated, nil -} - -// isGeneratedFileLax reports whether the source file is generated code. -// The function uses a bit laxer rules than isGeneratedFileStrict to match more generated code. -// See https://github.com/golangci/golangci-lint/issues/48 and https://github.com/golangci/golangci-lint/issues/72. -func (p *AutogeneratedExclude) isGeneratedFileLax(doc string) bool { - markers := []string{genCodeGenerated, genDoNotEdit, genAutoFile, genSwaggerCodegen} - - doc = strings.ToLower(doc) - - for _, marker := range markers { - if strings.Contains(doc, marker) { - p.debugf("doc contains marker %q: file is generated", marker) - - return true - } - } - - p.debugf("doc of len %d doesn't contain any of markers: %s", len(doc), markers) - - return false -} - -// isGeneratedFileStrict returns true if the source file has a line that matches the regular expression: -// -// ^// Code generated .* DO NOT EDIT\.$ -// -// This line must appear before the first non-comment, non-blank text in the file. -// Based on https://go.dev/s/generatedcode. -func (p *AutogeneratedExclude) isGeneratedFileStrict(filePath string) (bool, error) { - file, err := parser.ParseFile(token.NewFileSet(), filePath, nil, parser.PackageClauseOnly|parser.ParseComments) - if err != nil { - return false, fmt.Errorf("failed to parse file: %w", err) - } - - if file == nil || len(file.Comments) == 0 { - return false, nil - } - - for _, comment := range file.Comments { - if comment.Pos() > file.Package { - return false, nil - } - - for _, line := range comment.List { - generated := p.strictPattern.MatchString(line.Text) - if generated { - p.debugf("doc contains ignore expression: file is generated") - - return true, nil - } - } - } - - return false, nil -} - -func getComments(filePath string) (string, error) { - fset := token.NewFileSet() - syntax, err := parser.ParseFile(fset, filePath, nil, parser.PackageClauseOnly|parser.ParseComments) - if err != nil { - return "", fmt.Errorf("failed to parse file: %w", err) - } - - var docLines []string - for _, c := range syntax.Comments { - docLines = append(docLines, strings.TrimSpace(c.Text())) - } - - return strings.Join(docLines, "\n"), nil -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/base_rule.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/base_rule.go deleted file mode 100644 index d7a4f0ec4..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/base_rule.go +++ /dev/null @@ -1,68 +0,0 @@ -package processors - -import ( - "regexp" - - "github.com/golangci/golangci-lint/pkg/fsutils" - "github.com/golangci/golangci-lint/pkg/logutils" - "github.com/golangci/golangci-lint/pkg/result" -) - -const caseInsensitivePrefix = "(?i)" - -type baseRule struct { - text *regexp.Regexp - source *regexp.Regexp - path *regexp.Regexp - pathExcept *regexp.Regexp - linters []string -} - -func (r *baseRule) isEmpty() bool { - return r.text == nil && r.source == nil && r.path == nil && r.pathExcept == nil && len(r.linters) == 0 -} - -func (r *baseRule) match(issue *result.Issue, files *fsutils.Files, log logutils.Log) bool { - if r.isEmpty() { - return false - } - if r.text != nil && !r.text.MatchString(issue.Text) { - return false - } - if r.path != nil && !r.path.MatchString(files.WithPathPrefix(issue.FilePath())) { - return false - } - if r.pathExcept != nil && r.pathExcept.MatchString(issue.FilePath()) { - return false - } - if len(r.linters) != 0 && !r.matchLinter(issue) { - return false - } - - // the most heavyweight checking last - if r.source != nil && !r.matchSource(issue, files.LineCache, log) { - return false - } - - return true -} - -func (r *baseRule) matchLinter(issue *result.Issue) bool { - for _, linter := range r.linters { - if linter == issue.FromLinter { - return true - } - } - - return false -} - -func (r *baseRule) matchSource(issue *result.Issue, lineCache *fsutils.LineCache, log logutils.Log) bool { - sourceLine, errSourceLine := lineCache.GetLine(issue.FilePath(), issue.Line()) - if errSourceLine != nil { - log.Warnf("Failed to get line %s:%d from line cache: %s", issue.FilePath(), issue.Line(), errSourceLine) - return false // can't properly match - } - - return r.source.MatchString(sourceLine) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/cgo.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/cgo.go deleted file mode 100644 index 0e659f0f3..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/cgo.go +++ /dev/null @@ -1,59 +0,0 @@ -package processors - -import ( - "fmt" - "path/filepath" - "strings" - - "github.com/golangci/golangci-lint/pkg/goutil" - "github.com/golangci/golangci-lint/pkg/result" -) - -var _ Processor = (*Cgo)(nil) - -type Cgo struct { - goCacheDir string -} - -func NewCgo(goenv *goutil.Env) *Cgo { - return &Cgo{ - goCacheDir: goenv.Get(goutil.EnvGoCache), - } -} - -func (Cgo) Name() string { - return "cgo" -} - -func (p Cgo) Process(issues []result.Issue) ([]result.Issue, error) { - return filterIssuesErr(issues, p.shouldPassIssue) -} - -func (Cgo) Finish() {} - -func (p Cgo) shouldPassIssue(issue *result.Issue) (bool, error) { - // some linters (e.g. gosec, deadcode) return incorrect filepaths for cgo issues, - // also cgo files have strange issues looking like false positives. - - // cache dir contains all preprocessed files including cgo files - - issueFilePath := issue.FilePath() - if !filepath.IsAbs(issue.FilePath()) { - absPath, err := filepath.Abs(issue.FilePath()) - if err != nil { - return false, fmt.Errorf("failed to build abs path for %q: %w", issue.FilePath(), err) - } - issueFilePath = absPath - } - - if p.goCacheDir != "" && strings.HasPrefix(issueFilePath, p.goCacheDir) { - return false, nil - } - - if filepath.Base(issue.FilePath()) == "_cgo_gotypes.go" { - // skip cgo warning for go1.10 - return false, nil - } - - return true, nil -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/exclude.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/exclude.go deleted file mode 100644 index 543120450..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/exclude.go +++ /dev/null @@ -1,55 +0,0 @@ -package processors - -import ( - "fmt" - "regexp" - "strings" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/result" -) - -var _ Processor = (*Exclude)(nil) - -type Exclude struct { - name string - - pattern *regexp.Regexp -} - -func NewExclude(cfg *config.Issues) *Exclude { - p := &Exclude{name: "exclude"} - - var pattern string - if len(cfg.ExcludePatterns) != 0 { - pattern = fmt.Sprintf("(%s)", strings.Join(cfg.ExcludePatterns, "|")) - } - - prefix := caseInsensitivePrefix - if cfg.ExcludeCaseSensitive { - p.name = "exclude-case-sensitive" - prefix = "" - } - - if pattern != "" { - p.pattern = regexp.MustCompile(prefix + pattern) - } - - return p -} - -func (p Exclude) Name() string { - return p.name -} - -func (p Exclude) Process(issues []result.Issue) ([]result.Issue, error) { - if p.pattern == nil { - return issues, nil - } - - return filterIssues(issues, func(issue *result.Issue) bool { - return !p.pattern.MatchString(issue.Text) - }), nil -} - -func (Exclude) Finish() {} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/exclude_rules.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/exclude_rules.go deleted file mode 100644 index bf255ae82..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/exclude_rules.go +++ /dev/null @@ -1,105 +0,0 @@ -package processors - -import ( - "regexp" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/fsutils" - "github.com/golangci/golangci-lint/pkg/logutils" - "github.com/golangci/golangci-lint/pkg/result" -) - -var _ Processor = (*ExcludeRules)(nil) - -type excludeRule struct { - baseRule -} - -type ExcludeRules struct { - name string - - log logutils.Log - files *fsutils.Files - - rules []excludeRule -} - -func NewExcludeRules(log logutils.Log, files *fsutils.Files, cfg *config.Issues) *ExcludeRules { - p := &ExcludeRules{ - name: "exclude-rules", - files: files, - log: log, - } - - prefix := caseInsensitivePrefix - if cfg.ExcludeCaseSensitive { - prefix = "" - p.name = "exclude-rules-case-sensitive" - } - - excludeRules := cfg.ExcludeRules - - if cfg.UseDefaultExcludes { - for _, r := range config.GetExcludePatterns(cfg.IncludeDefaultExcludes) { - excludeRules = append(excludeRules, config.ExcludeRule{ - BaseRule: config.BaseRule{ - Text: r.Pattern, - Linters: []string{r.Linter}, - }, - }) - } - } - - p.rules = createRules(excludeRules, prefix) - - return p -} - -func (p ExcludeRules) Name() string { return p.name } - -func (p ExcludeRules) Process(issues []result.Issue) ([]result.Issue, error) { - if len(p.rules) == 0 { - return issues, nil - } - - return filterIssues(issues, func(issue *result.Issue) bool { - for _, rule := range p.rules { - if rule.match(issue, p.files, p.log) { - return false - } - } - - return true - }), nil -} - -func (ExcludeRules) Finish() {} - -func createRules(rules []config.ExcludeRule, prefix string) []excludeRule { - parsedRules := make([]excludeRule, 0, len(rules)) - - for _, rule := range rules { - parsedRule := excludeRule{} - parsedRule.linters = rule.Linters - - if rule.Text != "" { - parsedRule.text = regexp.MustCompile(prefix + rule.Text) - } - - if rule.Source != "" { - parsedRule.source = regexp.MustCompile(prefix + rule.Source) - } - - if rule.Path != "" { - parsedRule.path = regexp.MustCompile(fsutils.NormalizePathInRegex(rule.Path)) - } - - if rule.PathExcept != "" { - parsedRule.pathExcept = regexp.MustCompile(fsutils.NormalizePathInRegex(rule.PathExcept)) - } - - parsedRules = append(parsedRules, parsedRule) - } - - return parsedRules -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/fixer.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/fixer.go deleted file mode 100644 index 764af5a92..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/fixer.go +++ /dev/null @@ -1,260 +0,0 @@ -package processors - -import ( - "bytes" - "fmt" - "os" - "path/filepath" - "sort" - "strings" - - "github.com/golangci/golangci-lint/internal/go/robustio" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/fsutils" - "github.com/golangci/golangci-lint/pkg/logutils" - "github.com/golangci/golangci-lint/pkg/result" - "github.com/golangci/golangci-lint/pkg/timeutils" -) - -var _ Processor = (*Fixer)(nil) - -type Fixer struct { - cfg *config.Config - log logutils.Log - fileCache *fsutils.FileCache - sw *timeutils.Stopwatch -} - -func NewFixer(cfg *config.Config, log logutils.Log, fileCache *fsutils.FileCache) *Fixer { - return &Fixer{ - cfg: cfg, - log: log, - fileCache: fileCache, - sw: timeutils.NewStopwatch("fixer", log), - } -} - -func (Fixer) Name() string { - return "fixer" -} - -func (p Fixer) Process(issues []result.Issue) ([]result.Issue, error) { - if !p.cfg.Issues.NeedFix { - return issues, nil - } - - outIssues := make([]result.Issue, 0, len(issues)) - issuesToFixPerFile := map[string][]result.Issue{} - for i := range issues { - issue := &issues[i] - if issue.Replacement == nil { - outIssues = append(outIssues, *issue) - continue - } - - issuesToFixPerFile[issue.FilePath()] = append(issuesToFixPerFile[issue.FilePath()], *issue) - } - - for file, issuesToFix := range issuesToFixPerFile { - err := p.sw.TrackStageErr("all", func() error { - return p.fixIssuesInFile(file, issuesToFix) - }) - if err != nil { - p.log.Errorf("Failed to fix issues in file %s: %s", file, err) - - // show issues only if can't fix them - outIssues = append(outIssues, issuesToFix...) - } - } - - p.printStat() - - return outIssues, nil -} - -func (Fixer) Finish() {} - -func (p Fixer) fixIssuesInFile(filePath string, issues []result.Issue) error { - // TODO: don't read the whole file into memory: read line by line; - // can't just use bufio.scanner: it has a line length limit - origFileData, err := p.fileCache.GetFileBytes(filePath) - if err != nil { - return fmt.Errorf("failed to get file bytes for %s: %w", filePath, err) - } - - origFileLines := bytes.Split(origFileData, []byte("\n")) - - tmpFileName := filepath.Join(filepath.Dir(filePath), fmt.Sprintf(".%s.golangci_fix", filepath.Base(filePath))) - - tmpOutFile, err := os.Create(tmpFileName) - if err != nil { - return fmt.Errorf("failed to make file %s: %w", tmpFileName, err) - } - - // merge multiple issues per line into one issue - issuesPerLine := map[int][]result.Issue{} - for i := range issues { - issue := &issues[i] - issuesPerLine[issue.Line()] = append(issuesPerLine[issue.Line()], *issue) - } - - issues = issues[:0] // reuse the same memory - for line, lineIssues := range issuesPerLine { - if mergedIssue := p.mergeLineIssues(line, lineIssues, origFileLines); mergedIssue != nil { - issues = append(issues, *mergedIssue) - } - } - - issues = p.findNotIntersectingIssues(issues) - - if err = p.writeFixedFile(origFileLines, issues, tmpOutFile); err != nil { - tmpOutFile.Close() - _ = robustio.RemoveAll(tmpOutFile.Name()) - return err - } - - tmpOutFile.Close() - - if err = robustio.Rename(tmpOutFile.Name(), filePath); err != nil { - _ = robustio.RemoveAll(tmpOutFile.Name()) - return fmt.Errorf("failed to rename %s -> %s: %w", tmpOutFile.Name(), filePath, err) - } - - return nil -} - -func (p Fixer) mergeLineIssues(lineNum int, lineIssues []result.Issue, origFileLines [][]byte) *result.Issue { - origLine := origFileLines[lineNum-1] // lineNum is 1-based - - if len(lineIssues) == 1 && lineIssues[0].Replacement.Inline == nil { - return &lineIssues[0] - } - - // check issues first - for ind := range lineIssues { - li := &lineIssues[ind] - - if li.LineRange != nil { - p.log.Infof("Line %d has multiple issues but at least one of them is ranged: %#v", lineNum, lineIssues) - return &lineIssues[0] - } - - inline := li.Replacement.Inline - - if inline == nil || len(li.Replacement.NewLines) != 0 || li.Replacement.NeedOnlyDelete { - p.log.Infof("Line %d has multiple issues but at least one of them isn't inline: %#v", lineNum, lineIssues) - return li - } - - if inline.StartCol < 0 || inline.Length <= 0 || inline.StartCol+inline.Length > len(origLine) { - p.log.Warnf("Line %d (%q) has invalid inline fix: %#v, %#v", lineNum, origLine, li, inline) - return nil - } - } - - return p.applyInlineFixes(lineIssues, origLine, lineNum) -} - -func (p Fixer) applyInlineFixes(lineIssues []result.Issue, origLine []byte, lineNum int) *result.Issue { - sort.Slice(lineIssues, func(i, j int) bool { - return lineIssues[i].Replacement.Inline.StartCol < lineIssues[j].Replacement.Inline.StartCol - }) - - var newLineBuf bytes.Buffer - newLineBuf.Grow(len(origLine)) - - //nolint:misspell // misspelling is intentional - // example: origLine="it's becouse of them", StartCol=5, Length=7, NewString="because" - - curOrigLinePos := 0 - for i := range lineIssues { - fix := lineIssues[i].Replacement.Inline - if fix.StartCol < curOrigLinePos { - p.log.Warnf("Line %d has multiple intersecting issues: %#v", lineNum, lineIssues) - return nil - } - - if curOrigLinePos != fix.StartCol { - newLineBuf.Write(origLine[curOrigLinePos:fix.StartCol]) - } - newLineBuf.WriteString(fix.NewString) - curOrigLinePos = fix.StartCol + fix.Length - } - if curOrigLinePos != len(origLine) { - newLineBuf.Write(origLine[curOrigLinePos:]) - } - - mergedIssue := lineIssues[0] // use text from the first issue (it's not really used) - mergedIssue.Replacement = &result.Replacement{ - NewLines: []string{newLineBuf.String()}, - } - return &mergedIssue -} - -func (p Fixer) findNotIntersectingIssues(issues []result.Issue) []result.Issue { - sort.SliceStable(issues, func(i, j int) bool { - a, b := issues[i], issues[j] - return a.Line() < b.Line() - }) - - var ret []result.Issue - var currentEnd int - for i := range issues { - issue := &issues[i] - rng := issue.GetLineRange() - if rng.From <= currentEnd { - p.log.Infof("Skip issue %#v: intersects with end %d", issue, currentEnd) - continue // skip intersecting issue - } - p.log.Infof("Fix issue %#v with range %v", issue, issue.GetLineRange()) - ret = append(ret, *issue) - currentEnd = rng.To - } - - return ret -} - -func (p Fixer) writeFixedFile(origFileLines [][]byte, issues []result.Issue, tmpOutFile *os.File) error { - // issues aren't intersecting - - nextIssueIndex := 0 - for i := 0; i < len(origFileLines); i++ { - var outLine string - var nextIssue *result.Issue - if nextIssueIndex != len(issues) { - nextIssue = &issues[nextIssueIndex] - } - - origFileLineNumber := i + 1 - if nextIssue == nil || origFileLineNumber != nextIssue.GetLineRange().From { - outLine = string(origFileLines[i]) - } else { - nextIssueIndex++ - rng := nextIssue.GetLineRange() - if rng.From > rng.To { - // Maybe better decision is to skip such issues, re-evaluate if regressed. - p.log.Warnf("[fixer]: issue line range is probably invalid, fix can be incorrect (from=%d, to=%d, linter=%s)", - rng.From, rng.To, nextIssue.FromLinter, - ) - } - i += rng.To - rng.From - if nextIssue.Replacement.NeedOnlyDelete { - continue - } - outLine = strings.Join(nextIssue.Replacement.NewLines, "\n") - } - - if i < len(origFileLines)-1 { - outLine += "\n" - } - if _, err := tmpOutFile.WriteString(outLine); err != nil { - return fmt.Errorf("failed to write output line: %w", err) - } - } - - return nil -} - -func (p Fixer) printStat() { - p.sw.PrintStages() -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/identifier_marker.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/identifier_marker.go deleted file mode 100644 index 876fd3bd3..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/identifier_marker.go +++ /dev/null @@ -1,154 +0,0 @@ -package processors - -import ( - "regexp" - - "github.com/golangci/golangci-lint/pkg/result" -) - -var _ Processor = (*IdentifierMarker)(nil) - -type replacePattern struct { - re string - repl string -} - -type replaceRegexp struct { - re *regexp.Regexp - repl string -} - -var replacePatterns = []replacePattern{ - // unparam - {`^(\S+) - (\S+) is unused$`, "`${1}` - `${2}` is unused"}, - {`^(\S+) - (\S+) always receives (\S+) \((.*)\)$`, "`${1}` - `${2}` always receives `${3}` (`${4}`)"}, - {`^(\S+) - (\S+) always receives (.*)$`, "`${1}` - `${2}` always receives `${3}`"}, - {`^(\S+) - result (\S+) is always (\S+)`, "`${1}` - result `${2}` is always `${3}`"}, - - // interfacer - {`^(\S+) can be (\S+)$`, "`${1}` can be `${2}`"}, - - // govet - {`^printf: (\S+) arg list ends with redundant newline$`, "printf: `${1}` arg list ends with redundant newline"}, - {`^composites: (\S+) composite literal uses unkeyed fields$`, "composites: `${1}` composite literal uses unkeyed fields"}, - - // gosec - { - `^(\S+): Blacklisted import (\S+): weak cryptographic primitive$`, - "${1}: Blacklisted import `${2}`: weak cryptographic primitive", - }, - {`^TLS InsecureSkipVerify set true.$`, "TLS `InsecureSkipVerify` set true."}, - - // gosimple - {`should replace loop with (.*)$`, "should replace loop with `${1}`"}, - { - `should use a simple channel send/receive instead of select with a single case`, - "should use a simple channel send/receive instead of `select` with a single case", - }, - { - `should omit comparison to bool constant, can be simplified to (.+)$`, - "should omit comparison to bool constant, can be simplified to `${1}`", - }, - {`should write (.+) instead of (.+)$`, "should write `${1}` instead of `${2}`"}, - {`redundant return statement$`, "redundant `return` statement"}, - { - `should replace this if statement with an unconditional strings.TrimPrefix`, - "should replace this `if` statement with an unconditional `strings.TrimPrefix`", - }, - - // staticcheck - {`this value of (\S+) is never used$`, "this value of `${1}` is never used"}, - { - `should use time.Since instead of time.Now\(\).Sub$`, - "should use `time.Since` instead of `time.Now().Sub`", - }, - { - `should check returned error before deferring response.Close\(\)$`, - "should check returned error before deferring `response.Close()`", - }, - {`no value of type uint is less than 0$`, "no value of type `uint` is less than `0`"}, - - // unused - {`(func|const|field|type|var) (\S+) is unused$`, "${1} `${2}` is unused"}, - - // typecheck - {`^unknown field (\S+) in struct literal$`, "unknown field `${1}` in struct literal"}, - { - `^invalid operation: (\S+) \(variable of type (\S+)\) has no field or method (\S+)$`, - "invalid operation: `${1}` (variable of type `${2}`) has no field or method `${3}`", - }, - {`^undeclared name: (\S+)$`, "undeclared name: `${1}`"}, - { - `^cannot use addr \(variable of type (\S+)\) as (\S+) value in argument to (\S+)$`, - "cannot use addr (variable of type `${1}`) as `${2}` value in argument to `${3}`", - }, - {`^other declaration of (\S+)$`, "other declaration of `${1}`"}, - {`^(\S+) redeclared in this block$`, "`${1}` redeclared in this block"}, - - // golint - { - `^exported (type|method|function|var|const) (\S+) should have comment or be unexported$`, - "exported ${1} `${2}` should have comment or be unexported", - }, - { - `^comment on exported (type|method|function|var|const) (\S+) should be of the form "(\S+) ..."$`, - "comment on exported ${1} `${2}` should be of the form `${3} ...`", - }, - {`^should replace (.+) with (.+)$`, "should replace `${1}` with `${2}`"}, - { - `^if block ends with a return statement, so drop this else and outdent its block$`, - "`if` block ends with a `return` statement, so drop this `else` and outdent its block", - }, - { - `^(struct field|var|range var|const|type|(?:func|method|interface method) (?:parameter|result)) (\S+) should be (\S+)$`, - "${1} `${2}` should be `${3}`", - }, - { - `^don't use underscores in Go names; var (\S+) should be (\S+)$`, - "don't use underscores in Go names; var `${1}` should be `${2}`", - }, -} - -type IdentifierMarker struct { - replaceRegexps []replaceRegexp -} - -func NewIdentifierMarker() *IdentifierMarker { - var replaceRegexps []replaceRegexp - for _, p := range replacePatterns { - r := replaceRegexp{ - re: regexp.MustCompile(p.re), - repl: p.repl, - } - replaceRegexps = append(replaceRegexps, r) - } - - return &IdentifierMarker{ - replaceRegexps: replaceRegexps, - } -} - -func (IdentifierMarker) Name() string { - return "identifier_marker" -} - -func (p IdentifierMarker) Process(issues []result.Issue) ([]result.Issue, error) { - return transformIssues(issues, func(issue *result.Issue) *result.Issue { - newIssue := *issue - newIssue.Text = p.markIdentifiers(newIssue.Text) - return &newIssue - }), nil -} - -func (IdentifierMarker) Finish() {} - -func (p IdentifierMarker) markIdentifiers(s string) string { - for _, rr := range p.replaceRegexps { - rs := rr.re.ReplaceAllString(s, rr.repl) - if rs != s { - return rs - } - } - - return s -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/issues.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/issues.go deleted file mode 100644 index ab443b87d..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/issues.go +++ /dev/null @@ -1,69 +0,0 @@ -package processors - -import ( - "fmt" - - "github.com/golangci/golangci-lint/pkg/result" -) - -func filterIssues(issues []result.Issue, filter func(issue *result.Issue) bool) []result.Issue { - retIssues := make([]result.Issue, 0, len(issues)) - for i := range issues { - if issues[i].FromLinter == typeCheckName { - // don't hide typechecking errors in generated files: users expect to see why the project isn't compiling - retIssues = append(retIssues, issues[i]) - continue - } - - if filter(&issues[i]) { - retIssues = append(retIssues, issues[i]) - } - } - - return retIssues -} - -func filterIssuesUnsafe(issues []result.Issue, filter func(issue *result.Issue) bool) []result.Issue { - retIssues := make([]result.Issue, 0, len(issues)) - for i := range issues { - if filter(&issues[i]) { - retIssues = append(retIssues, issues[i]) - } - } - - return retIssues -} - -func filterIssuesErr(issues []result.Issue, filter func(issue *result.Issue) (bool, error)) ([]result.Issue, error) { - retIssues := make([]result.Issue, 0, len(issues)) - for i := range issues { - if issues[i].FromLinter == typeCheckName { - // don't hide typechecking errors in generated files: users expect to see why the project isn't compiling - retIssues = append(retIssues, issues[i]) - continue - } - - ok, err := filter(&issues[i]) - if err != nil { - return nil, fmt.Errorf("can't filter issue %#v: %w", issues[i], err) - } - - if ok { - retIssues = append(retIssues, issues[i]) - } - } - - return retIssues, nil -} - -func transformIssues(issues []result.Issue, transform func(issue *result.Issue) *result.Issue) []result.Issue { - retIssues := make([]result.Issue, 0, len(issues)) - for i := range issues { - newIssue := transform(&issues[i]) - if newIssue != nil { - retIssues = append(retIssues, *newIssue) - } - } - - return retIssues -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_prefixer.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_prefixer.go deleted file mode 100644 index 8036e3fd6..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_prefixer.go +++ /dev/null @@ -1,36 +0,0 @@ -package processors - -import ( - "github.com/golangci/golangci-lint/pkg/fsutils" - "github.com/golangci/golangci-lint/pkg/result" -) - -var _ Processor = (*PathPrefixer)(nil) - -// PathPrefixer adds a customizable prefix to every output path -type PathPrefixer struct { - prefix string -} - -// NewPathPrefixer returns a new path prefixer for the provided string -func NewPathPrefixer(prefix string) *PathPrefixer { - return &PathPrefixer{prefix: prefix} -} - -// Name returns the name of this processor -func (*PathPrefixer) Name() string { - return "path_prefixer" -} - -// Process adds the prefix to each path -func (p *PathPrefixer) Process(issues []result.Issue) ([]result.Issue, error) { - if p.prefix != "" { - for i := range issues { - issues[i].Pos.Filename = fsutils.WithPathPrefix(p.prefix, issues[i].Pos.Filename) - } - } - return issues, nil -} - -// Finish is implemented to satisfy the Processor interface -func (*PathPrefixer) Finish() {} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_prettifier.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_prettifier.go deleted file mode 100644 index c5c27357c..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_prettifier.go +++ /dev/null @@ -1,40 +0,0 @@ -package processors - -import ( - "path/filepath" - - "github.com/golangci/golangci-lint/pkg/fsutils" - "github.com/golangci/golangci-lint/pkg/result" -) - -var _ Processor = (*PathPrettifier)(nil) - -type PathPrettifier struct { -} - -func NewPathPrettifier() *PathPrettifier { - return &PathPrettifier{} -} - -func (PathPrettifier) Name() string { - return "path_prettifier" -} - -func (PathPrettifier) Process(issues []result.Issue) ([]result.Issue, error) { - return transformIssues(issues, func(issue *result.Issue) *result.Issue { - if !filepath.IsAbs(issue.FilePath()) { - return issue - } - - rel, err := fsutils.ShortestRelPath(issue.FilePath(), "") - if err != nil { - return issue - } - - newIssue := issue - newIssue.Pos.Filename = rel - return newIssue - }), nil -} - -func (PathPrettifier) Finish() {} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/severity.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/severity.go deleted file mode 100644 index 93a26586d..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/severity.go +++ /dev/null @@ -1,116 +0,0 @@ -package processors - -import ( - "regexp" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/fsutils" - "github.com/golangci/golangci-lint/pkg/logutils" - "github.com/golangci/golangci-lint/pkg/result" -) - -const severityFromLinter = "@linter" - -var _ Processor = (*Severity)(nil) - -type severityRule struct { - baseRule - severity string -} - -type Severity struct { - name string - - log logutils.Log - - files *fsutils.Files - - defaultSeverity string - rules []severityRule -} - -func NewSeverity(log logutils.Log, files *fsutils.Files, cfg *config.Severity) *Severity { - p := &Severity{ - name: "severity-rules", - files: files, - log: log, - defaultSeverity: cfg.Default, - } - - prefix := caseInsensitivePrefix - if cfg.CaseSensitive { - prefix = "" - p.name = "severity-rules-case-sensitive" - } - - p.rules = createSeverityRules(cfg.Rules, prefix) - - return p -} - -func (p *Severity) Name() string { return p.name } - -func (p *Severity) Process(issues []result.Issue) ([]result.Issue, error) { - if len(p.rules) == 0 && p.defaultSeverity == "" { - return issues, nil - } - - return transformIssues(issues, p.transform), nil -} - -func (*Severity) Finish() {} - -func (p *Severity) transform(issue *result.Issue) *result.Issue { - for _, rule := range p.rules { - if rule.match(issue, p.files, p.log) { - if rule.severity == severityFromLinter || (rule.severity == "" && p.defaultSeverity == severityFromLinter) { - return issue - } - - issue.Severity = rule.severity - if issue.Severity == "" { - issue.Severity = p.defaultSeverity - } - - return issue - } - } - - if p.defaultSeverity != severityFromLinter { - issue.Severity = p.defaultSeverity - } - - return issue -} - -func createSeverityRules(rules []config.SeverityRule, prefix string) []severityRule { - parsedRules := make([]severityRule, 0, len(rules)) - - for _, rule := range rules { - parsedRule := severityRule{} - parsedRule.linters = rule.Linters - parsedRule.severity = rule.Severity - - if rule.Text != "" { - parsedRule.text = regexp.MustCompile(prefix + rule.Text) - } - - if rule.Source != "" { - parsedRule.source = regexp.MustCompile(prefix + rule.Source) - } - - if rule.Path != "" { - path := fsutils.NormalizePathInRegex(rule.Path) - parsedRule.path = regexp.MustCompile(path) - } - - if rule.PathExcept != "" { - pathExcept := fsutils.NormalizePathInRegex(rule.PathExcept) - parsedRule.pathExcept = regexp.MustCompile(pathExcept) - } - - parsedRules = append(parsedRules, parsedRule) - } - - return parsedRules -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/skip_dirs.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/skip_dirs.go deleted file mode 100644 index 39dbfd1d3..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/skip_dirs.go +++ /dev/null @@ -1,172 +0,0 @@ -package processors - -import ( - "fmt" - "path/filepath" - "regexp" - - "github.com/golangci/golangci-lint/pkg/fsutils" - "github.com/golangci/golangci-lint/pkg/logutils" - "github.com/golangci/golangci-lint/pkg/result" -) - -var _ Processor = (*SkipDirs)(nil) - -var StdExcludeDirRegexps = []string{ - normalizePathRegex("vendor"), - normalizePathRegex("third_party"), - normalizePathRegex("testdata"), - normalizePathRegex("examples"), - normalizePathRegex("Godeps"), - normalizePathRegex("builtin"), -} - -type skipStat struct { - pattern string - count int -} - -type SkipDirs struct { - patterns []*regexp.Regexp - log logutils.Log - skippedDirs map[string]*skipStat - absArgsDirs []string - skippedDirsCache map[string]bool - pathPrefix string -} - -func NewSkipDirs(log logutils.Log, patterns, args []string, pathPrefix string) (*SkipDirs, error) { - var patternsRe []*regexp.Regexp - for _, p := range patterns { - p = fsutils.NormalizePathInRegex(p) - patternRe, err := regexp.Compile(p) - if err != nil { - return nil, fmt.Errorf("can't compile regexp %q: %w", p, err) - } - patternsRe = append(patternsRe, patternRe) - } - - absArgsDirs, err := absDirs(args) - if err != nil { - return nil, err - } - - return &SkipDirs{ - patterns: patternsRe, - log: log, - skippedDirs: map[string]*skipStat{}, - absArgsDirs: absArgsDirs, - skippedDirsCache: map[string]bool{}, - pathPrefix: pathPrefix, - }, nil -} - -func (*SkipDirs) Name() string { - return "skip_dirs" -} - -func (p *SkipDirs) Process(issues []result.Issue) ([]result.Issue, error) { - if len(p.patterns) == 0 { - return issues, nil - } - - return filterIssues(issues, p.shouldPassIssue), nil -} - -func (p *SkipDirs) Finish() { - for dir, stat := range p.skippedDirs { - p.log.Infof("Skipped %d issues from dir %s by pattern %s", stat.count, dir, stat.pattern) - } -} - -func (p *SkipDirs) shouldPassIssue(issue *result.Issue) bool { - if filepath.IsAbs(issue.FilePath()) { - if isGoFile(issue.FilePath()) { - p.log.Warnf("Got abs path %s in skip dirs processor, it should be relative", issue.FilePath()) - } - return true - } - - issueRelDir := filepath.Dir(issue.FilePath()) - - if toPass, ok := p.skippedDirsCache[issueRelDir]; ok { - if !toPass { - p.skippedDirs[issueRelDir].count++ - } - return toPass - } - - issueAbsDir, err := filepath.Abs(issueRelDir) - if err != nil { - p.log.Warnf("Can't abs-ify path %q: %s", issueRelDir, err) - return true - } - - toPass := p.shouldPassIssueDirs(issueRelDir, issueAbsDir) - p.skippedDirsCache[issueRelDir] = toPass - return toPass -} - -func (p *SkipDirs) shouldPassIssueDirs(issueRelDir, issueAbsDir string) bool { - for _, absArgDir := range p.absArgsDirs { - if absArgDir == issueAbsDir { - // we must not skip issues if they are from explicitly set dirs - // even if they match skip patterns - return true - } - } - - // We use issueRelDir for matching: it's the relative to the current - // work dir path of directory of source file with the issue. It can lead - // to unexpected behavior if we're analyzing files out of current work dir. - // The alternative solution is to find relative to args path, but it has - // disadvantages (https://github.com/golangci/golangci-lint/pull/313). - - path := fsutils.WithPathPrefix(p.pathPrefix, issueRelDir) - for _, pattern := range p.patterns { - if pattern.MatchString(path) { - ps := pattern.String() - if p.skippedDirs[issueRelDir] == nil { - p.skippedDirs[issueRelDir] = &skipStat{ - pattern: ps, - } - } - p.skippedDirs[issueRelDir].count++ - return false - } - } - - return true -} - -func absDirs(args []string) ([]string, error) { - if len(args) == 0 { - args = append(args, "./...") - } - - var absArgsDirs []string - for _, arg := range args { - base := filepath.Base(arg) - if base == "..." || isGoFile(base) { - arg = filepath.Dir(arg) - } - - absArg, err := filepath.Abs(arg) - if err != nil { - return nil, fmt.Errorf("failed to abs-ify arg %q: %w", arg, err) - } - - absArgsDirs = append(absArgsDirs, absArg) - } - - return absArgsDirs, nil -} - -func normalizePathRegex(e string) string { - return createPathRegex(e, filepath.Separator) -} - -func createPathRegex(e string, sep rune) string { - escapedSep := regexp.QuoteMeta(string(sep)) // needed for windows sep '\\' - return fmt.Sprintf(`(^|%[1]s)%[2]s($|%[1]s)`, escapedSep, e) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/skip_files.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/skip_files.go deleted file mode 100644 index 3b17a9f32..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/skip_files.go +++ /dev/null @@ -1,59 +0,0 @@ -package processors - -import ( - "fmt" - "regexp" - - "github.com/golangci/golangci-lint/pkg/fsutils" - "github.com/golangci/golangci-lint/pkg/result" -) - -var _ Processor = (*SkipFiles)(nil) - -type SkipFiles struct { - patterns []*regexp.Regexp - pathPrefix string -} - -func NewSkipFiles(patterns []string, pathPrefix string) (*SkipFiles, error) { - var patternsRe []*regexp.Regexp - for _, p := range patterns { - p = fsutils.NormalizePathInRegex(p) - - patternRe, err := regexp.Compile(p) - if err != nil { - return nil, fmt.Errorf("can't compile regexp %q: %w", p, err) - } - - patternsRe = append(patternsRe, patternRe) - } - - return &SkipFiles{ - patterns: patternsRe, - pathPrefix: pathPrefix, - }, nil -} - -func (SkipFiles) Name() string { - return "skip_files" -} - -func (p SkipFiles) Process(issues []result.Issue) ([]result.Issue, error) { - if len(p.patterns) == 0 { - return issues, nil - } - - return filterIssues(issues, func(issue *result.Issue) bool { - path := fsutils.WithPathPrefix(p.pathPrefix, issue.FilePath()) - - for _, pattern := range p.patterns { - if pattern.MatchString(path) { - return false - } - } - - return true - }), nil -} - -func (SkipFiles) Finish() {} diff --git a/vendor/github.com/golangci/golangci-lint/LICENSE b/vendor/github.com/golangci/golangci-lint/v2/LICENSE similarity index 100% rename from vendor/github.com/golangci/golangci-lint/LICENSE rename to vendor/github.com/golangci/golangci-lint/v2/LICENSE diff --git a/vendor/github.com/golangci/golangci-lint/cmd/golangci-lint/main.go b/vendor/github.com/golangci/golangci-lint/v2/cmd/golangci-lint/main.go similarity index 66% rename from vendor/github.com/golangci/golangci-lint/cmd/golangci-lint/main.go rename to vendor/github.com/golangci/golangci-lint/v2/cmd/golangci-lint/main.go index 413e071d6..acb09cd8c 100644 --- a/vendor/github.com/golangci/golangci-lint/cmd/golangci-lint/main.go +++ b/vendor/github.com/golangci/golangci-lint/v2/cmd/golangci-lint/main.go @@ -1,12 +1,15 @@ package main import ( + "cmp" "fmt" "os" + "regexp" "runtime/debug" + "strings" - "github.com/golangci/golangci-lint/pkg/commands" - "github.com/golangci/golangci-lint/pkg/exitcodes" + "github.com/golangci/golangci-lint/v2/pkg/commands" + "github.com/golangci/golangci-lint/v2/pkg/exitcodes" ) var ( @@ -22,7 +25,7 @@ func main() { info := createBuildInfo() if err := commands.Execute(info); err != nil { - _, _ = fmt.Fprintf(os.Stderr, "Failed executing command with error: %v\n", err) + _, _ = fmt.Fprintf(os.Stderr, "The command is terminated due to an error: %v\n", err) os.Exit(exitcodes.Failure) } } @@ -48,6 +51,11 @@ func createBuildInfo() commands.BuildInfo { info.Version = buildInfo.Main.Version + matched, _ := regexp.MatchString(`v\d+\.\d+\.\d+`, buildInfo.Main.Version) + if matched { + info.Version = strings.TrimPrefix(buildInfo.Main.Version, "v") + } + var revision string var modified string for _, setting := range buildInfo.Settings { @@ -63,19 +71,10 @@ func createBuildInfo() commands.BuildInfo { } } - if revision == "" { - revision = "unknown" - } - - if modified == "" { - modified = "?" - } - - if info.Date == "" { - info.Date = "(unknown)" - } + info.Date = cmp.Or(info.Date, "(unknown)") - info.Commit = fmt.Sprintf("(%s, modified: %s, mod sum: %q)", revision, modified, buildInfo.Main.Sum) + info.Commit = fmt.Sprintf("(%s, modified: %s, mod sum: %q)", + cmp.Or(revision, "unknown"), cmp.Or(modified, "?"), buildInfo.Main.Sum) return info } diff --git a/vendor/github.com/golangci/golangci-lint/cmd/golangci-lint/plugins.go b/vendor/github.com/golangci/golangci-lint/v2/cmd/golangci-lint/plugins.go similarity index 100% rename from vendor/github.com/golangci/golangci-lint/cmd/golangci-lint/plugins.go rename to vendor/github.com/golangci/golangci-lint/v2/cmd/golangci-lint/plugins.go diff --git a/vendor/github.com/golangci/golangci-lint/internal/cache/cache.go b/vendor/github.com/golangci/golangci-lint/v2/internal/cache/cache.go similarity index 95% rename from vendor/github.com/golangci/golangci-lint/internal/cache/cache.go rename to vendor/github.com/golangci/golangci-lint/v2/internal/cache/cache.go index c249084e1..138a36148 100644 --- a/vendor/github.com/golangci/golangci-lint/internal/cache/cache.go +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/cache/cache.go @@ -6,17 +6,17 @@ import ( "encoding/hex" "errors" "fmt" + "maps" "runtime" "slices" "strings" "sync" - "golang.org/x/exp/maps" "golang.org/x/tools/go/packages" - "github.com/golangci/golangci-lint/internal/go/cache" - "github.com/golangci/golangci-lint/pkg/logutils" - "github.com/golangci/golangci-lint/pkg/timeutils" + "github.com/golangci/golangci-lint/v2/internal/go/cache" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/timeutils" ) type HashMode int @@ -166,7 +166,7 @@ func (c *Cache) computePkgHash(pkg *packages.Package) (hashResults, error) { fmt.Fprintf(key, "pkgpath %s\n", pkg.PkgPath) - for _, f := range pkg.CompiledGoFiles { + for _, f := range slices.Concat(pkg.CompiledGoFiles, pkg.IgnoredFiles) { h, fErr := c.fileHash(f) if fErr != nil { return nil, fmt.Errorf("failed to calculate file %s hash: %w", f, fErr) @@ -178,9 +178,7 @@ func (c *Cache) computePkgHash(pkg *packages.Package) (hashResults, error) { curSum := key.Sum() hashRes[HashModeNeedOnlySelf] = hex.EncodeToString(curSum[:]) - imps := maps.Values(pkg.Imports) - - slices.SortFunc(imps, func(a, b *packages.Package) int { + imps := slices.SortedFunc(maps.Values(pkg.Imports), func(a, b *packages.Package) int { return strings.Compare(a.PkgPath, b.PkgPath) }) diff --git a/vendor/github.com/golangci/golangci-lint/internal/errorutil/errors.go b/vendor/github.com/golangci/golangci-lint/v2/internal/errorutil/errors.go similarity index 100% rename from vendor/github.com/golangci/golangci-lint/internal/errorutil/errors.go rename to vendor/github.com/golangci/golangci-lint/v2/internal/errorutil/errors.go diff --git a/vendor/github.com/golangci/gofmt/goimports/LICENSE b/vendor/github.com/golangci/golangci-lint/v2/internal/go/LICENSE similarity index 100% rename from vendor/github.com/golangci/gofmt/goimports/LICENSE rename to vendor/github.com/golangci/golangci-lint/v2/internal/go/LICENSE diff --git a/vendor/github.com/golangci/golangci-lint/v2/internal/go/base/error_notunix.go b/vendor/github.com/golangci/golangci-lint/v2/internal/go/base/error_notunix.go new file mode 100644 index 000000000..c7780fa30 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/go/base/error_notunix.go @@ -0,0 +1,12 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !unix + +package base + +func IsETXTBSY(err error) bool { + // syscall.ETXTBSY is only meaningful on Unix platforms. + return false +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/internal/go/base/error_unix.go b/vendor/github.com/golangci/golangci-lint/v2/internal/go/base/error_unix.go new file mode 100644 index 000000000..2dcd75e5f --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/go/base/error_unix.go @@ -0,0 +1,16 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build unix + +package base + +import ( + "errors" + "syscall" +) + +func IsETXTBSY(err error) bool { + return errors.Is(err, syscall.ETXTBSY) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/internal/go/base/readme.md b/vendor/github.com/golangci/golangci-lint/v2/internal/go/base/readme.md new file mode 100644 index 000000000..93afe9f28 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/go/base/readme.md @@ -0,0 +1,10 @@ +# quoted + +Extracted from `go/src/cmd/go/internal/base/` (related to `cache`). + +Only the function `IsETXTBSY` is extracted. + +## History + +- https://github.com/golangci/golangci-lint/pull/5576 + - sync go1.24.1 diff --git a/vendor/github.com/golangci/golangci-lint/internal/go/cache/cache.go b/vendor/github.com/golangci/golangci-lint/v2/internal/go/cache/cache.go similarity index 83% rename from vendor/github.com/golangci/golangci-lint/internal/go/cache/cache.go rename to vendor/github.com/golangci/golangci-lint/v2/internal/go/cache/cache.go index 85899ebc9..c514613dc 100644 --- a/vendor/github.com/golangci/golangci-lint/internal/go/cache/cache.go +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/go/cache/cache.go @@ -22,9 +22,11 @@ import ( "strings" "time" - "github.com/golangci/golangci-lint/internal/go/mmap" - "github.com/golangci/golangci-lint/internal/go/robustio" "github.com/rogpeppe/go-internal/lockedfile" + "github.com/rogpeppe/go-internal/robustio" + + "github.com/golangci/golangci-lint/v2/internal/go/base" + "github.com/golangci/golangci-lint/v2/internal/go/mmap" ) // An ActionID is a cache action key, the hash of a complete description of a @@ -40,8 +42,8 @@ type Cache interface { // Get returns the cache entry for the provided ActionID. // On miss, the error type should be of type *entryNotFoundError. // - // After a success call to Get, OutputFile(Entry.OutputID) must - // exist on disk for until Close is called (at the end of the process). + // After a successful call to Get, OutputFile(Entry.OutputID) must + // exist on disk until Close is called (at the end of the process). Get(ActionID) (Entry, error) // Put adds an item to the cache. @@ -52,14 +54,14 @@ type Cache interface { // As a special case, if the ReadSeeker is of type noVerifyReadSeeker, // the verification from GODEBUG=goverifycache=1 is skipped. // - // After a success call to Get, OutputFile(Entry.OutputID) must - // exist on disk for until Close is called (at the end of the process). + // After a successful call to Put, OutputFile(OutputID) must + // exist on disk until Close is called (at the end of the process). Put(ActionID, io.ReadSeeker) (_ OutputID, size int64, _ error) // Close is called at the end of the go process. Implementations can do // cache cleanup work at this phase, or wait for and report any errors from - // background cleanup work started earlier. Any cache trimming should in one - // process should not violate cause the invariants of this interface to be + // background cleanup work started earlier. Any cache trimming in one + // process should not cause the invariants of this interface to be // violated in another process. Namely, a cache trim from one process should // not delete an ObjectID from disk that was recently Get or Put from // another process. As a rule of thumb, don't trim things used in the last @@ -104,7 +106,7 @@ func Open(dir string) (*DiskCache, error) { } for i := 0; i < 256; i++ { name := filepath.Join(dir, fmt.Sprintf("%02x", i)) - if err := os.MkdirAll(name, 0744); err != nil { + if err := os.MkdirAll(name, 0o777); err != nil { return nil, err } } @@ -160,13 +162,13 @@ var errVerifyMode = errors.New("gocacheverify=1") var DebugTest = false // func init() { initEnv() } - +// // var ( // gocacheverify = godebug.New("gocacheverify") // gocachehash = godebug.New("gocachehash") // gocachetest = godebug.New("gocachetest") // ) - +// // func initEnv() { // if gocacheverify.Value() == "1" { // gocacheverify.IncNonDefault() @@ -257,10 +259,7 @@ func (c *DiskCache) get(id ActionID) (Entry, error) { return missing(errors.New("negative timestamp")) } - err = c.used(c.fileName(id, "a")) - if err != nil { - return Entry{}, fmt.Errorf("failed to mark %s as used: %w", c.fileName(id, "a"), err) - } + c.markUsed(c.fileName(id, "a")) return Entry{buf, size, time.Unix(0, tm)}, nil } @@ -304,25 +303,35 @@ func GetBytes(c Cache, id ActionID) ([]byte, Entry, error) { // GetMmap looks up the action ID in the cache and returns // the corresponding output bytes. // GetMmap should only be used for data that can be expected to fit in memory. -func GetMmap(c Cache, id ActionID) ([]byte, Entry, error) { +func GetMmap(c Cache, id ActionID) ([]byte, Entry, bool, error) { entry, err := c.Get(id) if err != nil { - return nil, entry, err + return nil, entry, false, err } - md, err := mmap.Mmap(c.OutputFile(entry.OutputID)) + md, opened, err := mmap.Mmap(c.OutputFile(entry.OutputID)) if err != nil { - return nil, Entry{}, err + return nil, Entry{}, opened, err } if int64(len(md.Data)) != entry.Size { - return nil, Entry{}, &entryNotFoundError{Err: errors.New("file incomplete")} + return nil, Entry{}, true, &entryNotFoundError{Err: errors.New("file incomplete")} } - return md.Data, entry, nil + return md.Data, entry, true, nil } // OutputFile returns the name of the cache file storing output with the given OutputID. func (c *DiskCache) OutputFile(out OutputID) string { file := c.fileName(out, "d") - c.used(file) + isDir := c.markUsed(file) + if isDir { // => cached executable + entries, err := os.ReadDir(file) + if err != nil { + return fmt.Sprintf("DO NOT USE - missing binary cache entry: %v", err) + } + if len(entries) != 1 { + return "DO NOT USE - invalid binary cache entry" + } + return filepath.Join(file, entries[0].Name()) + } return file } @@ -344,7 +353,7 @@ const ( trimLimit = 5 * 24 * time.Hour ) -// used makes a best-effort attempt to update mtime on file, +// markUsed makes a best-effort attempt to update mtime on file, // so that mtime reflects cache access time. // // Because the reflection only needs to be approximate, @@ -353,25 +362,17 @@ const ( // mtime is more than an hour old. This heuristic eliminates // nearly all of the mtime updates that would otherwise happen, // while still keeping the mtimes useful for cache trimming. -func (c *DiskCache) used(file string) error { +// +// markUsed reports whether the file is a directory (an executable cache entry). +func (c *DiskCache) markUsed(file string) (isDir bool) { info, err := os.Stat(file) - if err == nil && c.now().Sub(info.ModTime()) < mtimeInterval { - return nil - } - if err != nil { - if os.IsNotExist(err) { - return &entryNotFoundError{Err: err} - } - return &entryNotFoundError{Err: fmt.Errorf("failed to stat file %s: %w", file, err)} + return false } - - err = os.Chtimes(file, c.now(), c.now()) - if err != nil { - return fmt.Errorf("failed to change time of file %s: %w", file, err) + if now := c.now(); now.Sub(info.ModTime()) >= mtimeInterval { + os.Chtimes(file, now, now) } - - return nil + return info.IsDir() } func (c *DiskCache) Close() error { return c.Trim() } @@ -409,7 +410,7 @@ func (c *DiskCache) Trim() error { // cache will appear older than it is, and we'll trim it again next time. var b bytes.Buffer fmt.Fprintf(&b, "%d", now.Unix()) - if err := lockedfile.Write(filepath.Join(c.dir, "trim.txt"), &b, 0666); err != nil { + if err := lockedfile.Write(filepath.Join(c.dir, "trim.txt"), &b, 0o666); err != nil { return err } @@ -438,6 +439,10 @@ func (c *DiskCache) trimSubdir(subdir string, cutoff time.Time) { entry := filepath.Join(subdir, name) info, err := os.Stat(entry) if err == nil && info.ModTime().Before(cutoff) { + if info.IsDir() { // executable cache entry + os.RemoveAll(entry) + continue + } os.Remove(entry) } } @@ -470,7 +475,7 @@ func (c *DiskCache) putIndexEntry(id ActionID, out OutputID, size int64, allowVe // Copy file to cache directory. mode := os.O_WRONLY | os.O_CREATE - f, err := os.OpenFile(file, mode, 0666) + f, err := os.OpenFile(file, mode, 0o666) if err != nil { return err } @@ -516,7 +521,21 @@ func (c *DiskCache) Put(id ActionID, file io.ReadSeeker) (OutputID, int64, error if isNoVerify { file = wrapper.ReadSeeker } - return c.put(id, file, !isNoVerify) + return c.put(id, "", file, !isNoVerify) +} + +// PutExecutable is used to store the output as the output for the action ID into a +// file with the given base name, with the executable mode bit set. +// It may read file twice. The content of file must not change between the two passes. +func (c *DiskCache) PutExecutable(id ActionID, name string, file io.ReadSeeker) (OutputID, int64, error) { + if name == "" { + panic("PutExecutable called without a name") + } + wrapper, isNoVerify := file.(noVerifyReadSeeker) + if isNoVerify { + file = wrapper.ReadSeeker + } + return c.put(id, name, file, !isNoVerify) } // PutNoVerify is like Put but disables the verify check @@ -527,7 +546,7 @@ func PutNoVerify(c Cache, id ActionID, file io.ReadSeeker) (OutputID, int64, err return c.Put(id, noVerifyReadSeeker{file}) } -func (c *DiskCache) put(id ActionID, file io.ReadSeeker, allowVerify bool) (OutputID, int64, error) { +func (c *DiskCache) put(id ActionID, executableName string, file io.ReadSeeker, allowVerify bool) (OutputID, int64, error) { // Compute output ID. h := sha256.New() if _, err := file.Seek(0, 0); err != nil { @@ -541,7 +560,11 @@ func (c *DiskCache) put(id ActionID, file io.ReadSeeker, allowVerify bool) (Outp h.Sum(out[:0]) // Copy to cached output file (if not already present). - if err := c.copyFile(file, out, size); err != nil { + fileMode := fs.FileMode(0o666) + if executableName != "" { + fileMode = 0o777 + } + if err := c.copyFile(file, executableName, out, size, fileMode); err != nil { return out, size, err } @@ -557,9 +580,33 @@ func PutBytes(c Cache, id ActionID, data []byte) error { // copyFile copies file into the cache, expecting it to have the given // output ID and size, if that file is not present already. -func (c *DiskCache) copyFile(file io.ReadSeeker, out OutputID, size int64) error { - name := c.fileName(out, "d") +func (c *DiskCache) copyFile(file io.ReadSeeker, executableName string, out OutputID, size int64, perm os.FileMode) error { + name := c.fileName(out, "d") // TODO(matloob): use a different suffix for the executable cache? info, err := os.Stat(name) + if executableName != "" { + // This is an executable file. The file at name won't hold the output itself, but will + // be a directory that holds the output, named according to executableName. Check to see + // if the directory already exists, and if it does not, create it. Then reset name + // to the name we want the output written to. + if err != nil { + if !os.IsNotExist(err) { + return err + } + if err := os.Mkdir(name, 0o777); err != nil { + return err + } + if info, err = os.Stat(name); err != nil { + return err + } + } + if !info.IsDir() { + return errors.New("internal error: invalid binary cache entry: not a directory") + } + + // directory exists. now set name to the inner file + name = filepath.Join(name, executableName) + info, err = os.Stat(name) + } if err == nil && info.Size() == size { // Check hash. if f, err := os.Open(name); err == nil { @@ -584,8 +631,14 @@ func (c *DiskCache) copyFile(file io.ReadSeeker, out OutputID, size int64) error if err == nil && info.Size() > size { // shouldn't happen but fix in case mode |= os.O_TRUNC } - f, err := os.OpenFile(name, mode, 0666) + f, err := os.OpenFile(name, mode, perm) if err != nil { + if base.IsETXTBSY(err) { + // This file is being used by an executable. It must have + // already been written by another go process and then run. + // return without an error. + return nil + } return err } defer f.Close() diff --git a/vendor/github.com/golangci/golangci-lint/internal/go/cache/cache_gcil.go b/vendor/github.com/golangci/golangci-lint/v2/internal/go/cache/cache_gcil.go similarity index 100% rename from vendor/github.com/golangci/golangci-lint/internal/go/cache/cache_gcil.go rename to vendor/github.com/golangci/golangci-lint/v2/internal/go/cache/cache_gcil.go diff --git a/vendor/github.com/golangci/golangci-lint/internal/go/cache/default.go b/vendor/github.com/golangci/golangci-lint/v2/internal/go/cache/default.go similarity index 80% rename from vendor/github.com/golangci/golangci-lint/internal/go/cache/default.go rename to vendor/github.com/golangci/golangci-lint/v2/internal/go/cache/default.go index 7232f1ef3..cf38ab3d7 100644 --- a/vendor/github.com/golangci/golangci-lint/internal/go/cache/default.go +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/go/cache/default.go @@ -15,14 +15,10 @@ import ( // Default returns the default cache to use. // It never returns nil. func Default() Cache { - defaultOnce.Do(initDefaultCache) - return defaultCache + return initDefaultCacheOnce() } -var ( - defaultOnce sync.Once - defaultCache Cache -) +var initDefaultCacheOnce = sync.OnceValue(initDefaultCache) // cacheREADME is a message stored in a README in the cache directory. // Because the cache lives outside the normal Go trees, we leave the @@ -32,22 +28,20 @@ const cacheREADME = `This directory holds cached build artifacts from golangci-l // initDefaultCache does the work of finding the default cache // the first time Default is called. -func initDefaultCache() { +func initDefaultCache() Cache { dir, _ := DefaultDir() if dir == "off" { if defaultDirErr != nil { base.Fatalf("build cache is required, but could not be located: %v", defaultDirErr) } - base.Fatalf("build cache is disabled by %s=off, but required", envGolangciLintCache) + base.Fatalf("build cache is disabled by %s=off, but required as of Go 1.12", envGolangciLintCache) } - if err := os.MkdirAll(dir, 0744); err != nil { + if err := os.MkdirAll(dir, 0o777); err != nil { base.Fatalf("failed to initialize build cache at %s: %s\n", dir, err) } if _, err := os.Stat(filepath.Join(dir, "README")); err != nil { // Best effort. - if wErr := os.WriteFile(filepath.Join(dir, "README"), []byte(cacheREADME), 0666); wErr != nil { - base.Fatalf("Failed to write README file to cache dir %s: %s", dir, err) - } + os.WriteFile(filepath.Join(dir, "README"), []byte(cacheREADME), 0666) } diskCache, err := Open(dir) @@ -56,10 +50,10 @@ func initDefaultCache() { } if v := os.Getenv(envGolangciLintCacheProg); v != "" { - defaultCache = startCacheProg(v, diskCache) - } else { - defaultCache = diskCache + return startCacheProg(v, diskCache) } + + return diskCache } var ( @@ -74,7 +68,7 @@ var ( // and reports whether the effective value differs from GOLANGCI_LINT_CACHE. func DefaultDir() (string, bool) { // Save the result of the first call to DefaultDir for later use in - // initDefaultCache. cmd/go/main.go explicitly sets GOCACHE so that + // initDefaultCache. cmd/go/main.go explicitly sets GOLANGCI_LINT_CACHE so that // subprocesses will inherit it, but that means initDefaultCache can't // otherwise distinguish between an explicit "off" and a UserCacheDir error. diff --git a/vendor/github.com/golangci/golangci-lint/internal/go/cache/default_gcil.go b/vendor/github.com/golangci/golangci-lint/v2/internal/go/cache/default_gcil.go similarity index 100% rename from vendor/github.com/golangci/golangci-lint/internal/go/cache/default_gcil.go rename to vendor/github.com/golangci/golangci-lint/v2/internal/go/cache/default_gcil.go diff --git a/vendor/github.com/golangci/golangci-lint/internal/go/cache/hash.go b/vendor/github.com/golangci/golangci-lint/v2/internal/go/cache/hash.go similarity index 99% rename from vendor/github.com/golangci/golangci-lint/internal/go/cache/hash.go rename to vendor/github.com/golangci/golangci-lint/v2/internal/go/cache/hash.go index d5169dd4c..6a53dd886 100644 --- a/vendor/github.com/golangci/golangci-lint/internal/go/cache/hash.go +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/go/cache/hash.go @@ -50,7 +50,7 @@ func stripExperiment(version string) string { // action ID with a string description of the subkey. func Subkey(parent ActionID, desc string) (ActionID, error) { h := sha256.New() - h.Write([]byte(("subkey:"))) + h.Write([]byte("subkey:")) n, err := h.Write(parent[:]) if n != len(parent) { return ActionID{}, fmt.Errorf("wrote %d/%d bytes of parent with error %s", n, len(parent), err) diff --git a/vendor/github.com/golangci/golangci-lint/internal/go/cache/hash_gcil.go b/vendor/github.com/golangci/golangci-lint/v2/internal/go/cache/hash_gcil.go similarity index 100% rename from vendor/github.com/golangci/golangci-lint/internal/go/cache/hash_gcil.go rename to vendor/github.com/golangci/golangci-lint/v2/internal/go/cache/hash_gcil.go diff --git a/vendor/github.com/golangci/golangci-lint/internal/go/cache/prog.go b/vendor/github.com/golangci/golangci-lint/v2/internal/go/cache/prog.go similarity index 66% rename from vendor/github.com/golangci/golangci-lint/internal/go/cache/prog.go rename to vendor/github.com/golangci/golangci-lint/v2/internal/go/cache/prog.go index a93740a3c..dc44e1385 100644 --- a/vendor/github.com/golangci/golangci-lint/internal/go/cache/prog.go +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/go/cache/prog.go @@ -21,7 +21,8 @@ import ( "sync/atomic" "time" - "github.com/golangci/golangci-lint/internal/go/quoted" + "github.com/golangci/golangci-lint/v2/internal/go/cacheprog" + "github.com/golangci/golangci-lint/v2/internal/go/quoted" ) // ProgCache implements Cache via JSON messages over stdin/stdout to a child @@ -38,7 +39,7 @@ type ProgCache struct { // can are the commands that the child process declared that it supports. // This is effectively the versioning mechanism. - can map[ProgCmd]bool + can map[cacheprog.Cmd]bool // fuzzDirCache is another Cache implementation to use for the FuzzDir // method. In practice this is the default GOCACHE disk-based @@ -55,7 +56,7 @@ type ProgCache struct { mu sync.Mutex // guards following fields nextID int64 - inFlight map[int64]chan<- *ProgResponse + inFlight map[int64]chan<- *cacheprog.Response outputFile map[OutputID]string // object => abs path on disk // writeMu serializes writing to the child process. @@ -63,84 +64,6 @@ type ProgCache struct { writeMu sync.Mutex } -// ProgCmd is a command that can be issued to a child process. -// -// If the interface needs to grow, we can add new commands or new versioned -// commands like "get2". -type ProgCmd string - -const ( - cmdGet = ProgCmd("get") - cmdPut = ProgCmd("put") - cmdClose = ProgCmd("close") -) - -// ProgRequest is the JSON-encoded message that's sent from cmd/go to -// the GOLANGCI_LINT_CACHEPROG child process over stdin. Each JSON object is on its -// own line. A ProgRequest of Type "put" with BodySize > 0 will be followed -// by a line containing a base64-encoded JSON string literal of the body. -type ProgRequest struct { - // ID is a unique number per process across all requests. - // It must be echoed in the ProgResponse from the child. - ID int64 - - // Command is the type of request. - // The cmd/go tool will only send commands that were declared - // as supported by the child. - Command ProgCmd - - // ActionID is non-nil for get and puts. - ActionID []byte `json:",omitempty"` // or nil if not used - - // ObjectID is set for Type "put" and "output-file". - ObjectID []byte `json:",omitempty"` // or nil if not used - - // Body is the body for "put" requests. It's sent after the JSON object - // as a base64-encoded JSON string when BodySize is non-zero. - // It's sent as a separate JSON value instead of being a struct field - // send in this JSON object so large values can be streamed in both directions. - // The base64 string body of a ProgRequest will always be written - // immediately after the JSON object and a newline. - Body io.Reader `json:"-"` - - // BodySize is the number of bytes of Body. If zero, the body isn't written. - BodySize int64 `json:",omitempty"` -} - -// ProgResponse is the JSON response from the child process to cmd/go. -// -// With the exception of the first protocol message that the child writes to its -// stdout with ID==0 and KnownCommands populated, these are only sent in -// response to a ProgRequest from cmd/go. -// -// ProgResponses can be sent in any order. The ID must match the request they're -// replying to. -type ProgResponse struct { - ID int64 // that corresponds to ProgRequest; they can be answered out of order - Err string `json:",omitempty"` // if non-empty, the error - - // KnownCommands is included in the first message that cache helper program - // writes to stdout on startup (with ID==0). It includes the - // ProgRequest.Command types that are supported by the program. - // - // This lets us extend the protocol gracefully over time (adding "get2", - // etc), or fail gracefully when needed. It also lets us verify the program - // wants to be a cache helper. - KnownCommands []ProgCmd `json:",omitempty"` - - // For Get requests. - - Miss bool `json:",omitempty"` // cache miss - OutputID []byte `json:",omitempty"` - Size int64 `json:",omitempty"` // in bytes - Time *time.Time `json:",omitempty"` // an Entry.Time; when the object was added to the docs - - // DiskPath is the absolute path on disk of the ObjectID corresponding - // a "get" request's ActionID (on cache hit) or a "put" request's - // provided ObjectID. - DiskPath string `json:",omitempty"` -} - // startCacheProg starts the prog binary (with optional space-separated flags) // and returns a Cache implementation that talks to it. // @@ -165,13 +88,15 @@ func startCacheProg(progAndArgs string, fuzzDirCache Cache) Cache { cmd := exec.CommandContext(ctx, prog, args...) out, err := cmd.StdoutPipe() if err != nil { - base.Fatalf("StdoutPipe to %s: %v", envGolangciLintCacheProg, err) + base.Fatalf("StdoutPipe to %s: envGolangciLintCacheProg, %v", envGolangciLintCacheProg, err) } in, err := cmd.StdinPipe() if err != nil { - base.Fatalf("StdinPipe to %s: %v", envGolangciLintCacheProg, err) + base.Fatalf("StdinPipe to %s: envGolangciLintCacheProg, %v", envGolangciLintCacheProg, err) } cmd.Stderr = os.Stderr + // On close, we cancel the context. Rather than killing the helper, + // close its stdin. cmd.Cancel = in.Close if err := cmd.Start(); err != nil { @@ -186,14 +111,14 @@ func startCacheProg(progAndArgs string, fuzzDirCache Cache) Cache { stdout: out, stdin: in, bw: bufio.NewWriter(in), - inFlight: make(map[int64]chan<- *ProgResponse), + inFlight: make(map[int64]chan<- *cacheprog.Response), outputFile: make(map[OutputID]string), readLoopDone: make(chan struct{}), } // Register our interest in the initial protocol message from the child to // us, saying what it can do. - capResc := make(chan *ProgResponse, 1) + capResc := make(chan *cacheprog.Response, 1) pc.inFlight[0] = capResc pc.jenc = json.NewEncoder(pc.bw) @@ -208,7 +133,7 @@ func startCacheProg(progAndArgs string, fuzzDirCache Cache) Cache { case <-timer.C: log.Printf("# still waiting for %s %v ...", envGolangciLintCacheProg, prog) case capRes := <-capResc: - can := map[ProgCmd]bool{} + can := map[cacheprog.Cmd]bool{} for _, cmd := range capRes.KnownCommands { can[cmd] = true } @@ -225,9 +150,15 @@ func (c *ProgCache) readLoop(readLoopDone chan<- struct{}) { defer close(readLoopDone) jd := json.NewDecoder(c.stdout) for { - res := new(ProgResponse) + res := new(cacheprog.Response) if err := jd.Decode(res); err != nil { if c.closing.Load() { + c.mu.Lock() + for _, ch := range c.inFlight { + close(ch) + } + c.inFlight = nil + c.mu.Unlock() return // quietly } if err == io.EOF { @@ -250,13 +181,18 @@ func (c *ProgCache) readLoop(readLoopDone chan<- struct{}) { } } -func (c *ProgCache) send(ctx context.Context, req *ProgRequest) (*ProgResponse, error) { - resc := make(chan *ProgResponse, 1) +var errCacheprogClosed = fmt.Errorf("%s program closed unexpectedly", envGolangciLintCacheProg) + +func (c *ProgCache) send(ctx context.Context, req *cacheprog.Request) (*cacheprog.Response, error) { + resc := make(chan *cacheprog.Response, 1) if err := c.writeToChild(req, resc); err != nil { return nil, err } select { case res := <-resc: + if res == nil { + return nil, errCacheprogClosed + } if res.Err != "" { return nil, errors.New(res.Err) } @@ -266,8 +202,11 @@ func (c *ProgCache) send(ctx context.Context, req *ProgRequest) (*ProgResponse, } } -func (c *ProgCache) writeToChild(req *ProgRequest, resc chan<- *ProgResponse) (err error) { +func (c *ProgCache) writeToChild(req *cacheprog.Request, resc chan<- *cacheprog.Response) (err error) { c.mu.Lock() + if c.inFlight == nil { + return errCacheprogClosed + } c.nextID++ req.ID = c.nextID c.inFlight[req.ID] = resc @@ -276,7 +215,9 @@ func (c *ProgCache) writeToChild(req *ProgRequest, resc chan<- *ProgResponse) (e defer func() { if err != nil { c.mu.Lock() - delete(c.inFlight, req.ID) + if c.inFlight != nil { + delete(c.inFlight, req.ID) + } c.mu.Unlock() } }() @@ -303,8 +244,8 @@ func (c *ProgCache) writeToChild(req *ProgRequest, resc chan<- *ProgResponse) (e return nil } if wrote != req.BodySize { - return fmt.Errorf("short write writing body to %s for action %x, object %x: wrote %v; expected %v", - envGolangciLintCacheProg, req.ActionID, req.ObjectID, wrote, req.BodySize) + return fmt.Errorf("short write writing body to %s for action %x, output %x: wrote %v; expected %v", + envGolangciLintCacheProg, req.ActionID, req.OutputID, wrote, req.BodySize) } if _, err := c.bw.WriteString("\"\n"); err != nil { return err @@ -317,7 +258,7 @@ func (c *ProgCache) writeToChild(req *ProgRequest, resc chan<- *ProgResponse) (e } func (c *ProgCache) Get(a ActionID) (Entry, error) { - if !c.can[cmdGet] { + if !c.can[cacheprog.CmdGet] { // They can't do a "get". Maybe they're a write-only cache. // // TODO(bradfitz,bcmills): figure out the proper error type here. Maybe @@ -327,8 +268,8 @@ func (c *ProgCache) Get(a ActionID) (Entry, error) { // error types on the Cache interface. return Entry{}, &entryNotFoundError{} } - res, err := c.send(c.ctx, &ProgRequest{ - Command: cmdGet, + res, err := c.send(c.ctx, &cacheprog.Request{ + Command: cacheprog.CmdGet, ActionID: a[:], }) if err != nil { @@ -384,15 +325,15 @@ func (c *ProgCache) Put(a ActionID, file io.ReadSeeker) (_ OutputID, size int64, return OutputID{}, 0, err } - if !c.can[cmdPut] { + if !c.can[cacheprog.CmdPut] { // Child is a read-only cache. Do nothing. return out, size, nil } - res, err := c.send(c.ctx, &ProgRequest{ - Command: cmdPut, + res, err := c.send(c.ctx, &cacheprog.Request{ + Command: cacheprog.CmdPut, ActionID: a[:], - ObjectID: out[:], + OutputID: out[:], Body: file, BodySize: size, }) @@ -413,10 +354,16 @@ func (c *ProgCache) Close() error { // First write a "close" message to the child so it can exit nicely // and clean up if it wants. Only after that exchange do we cancel // the context that kills the process. - if c.can[cmdClose] { - _, err = c.send(c.ctx, &ProgRequest{Command: cmdClose}) + if c.can[cacheprog.CmdClose] { + _, err = c.send(c.ctx, &cacheprog.Request{Command: cacheprog.CmdClose}) + if errors.Is(err, errCacheprogClosed) { + // Allow the child to quit without responding to close. + err = nil + } } + // Cancel the context, which will close the helper's stdin. c.ctxCancel() + // Wait until the helper closes its stdout. <-c.readLoopDone return err } diff --git a/vendor/github.com/golangci/golangci-lint/internal/go/cache/readme.md b/vendor/github.com/golangci/golangci-lint/v2/internal/go/cache/readme.md similarity index 97% rename from vendor/github.com/golangci/golangci-lint/internal/go/cache/readme.md rename to vendor/github.com/golangci/golangci-lint/v2/internal/go/cache/readme.md index 5be600e42..66341fd4b 100644 --- a/vendor/github.com/golangci/golangci-lint/internal/go/cache/readme.md +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/go/cache/readme.md @@ -12,6 +12,8 @@ The main modifications are: ## History +- https://github.com/golangci/golangci-lint/pull/5576 + - sync go1.24.1 - https://github.com/golangci/golangci-lint/pull/5100 - Move package from `internal/cache` to `internal/go/cache` - https://github.com/golangci/golangci-lint/pull/5098 diff --git a/vendor/github.com/golangci/golangci-lint/v2/internal/go/cacheprog/cacheprog.go b/vendor/github.com/golangci/golangci-lint/v2/internal/go/cacheprog/cacheprog.go new file mode 100644 index 000000000..a2796592d --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/go/cacheprog/cacheprog.go @@ -0,0 +1,137 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package cacheprog defines the protocol for a GOCACHEPROG program. +// +// By default, the go command manages a build cache stored in the file system +// itself. GOCACHEPROG can be set to the name of a command (with optional +// space-separated flags) that implements the go command build cache externally. +// This permits defining a different cache policy. +// +// The go command will start the GOCACHEPROG as a subprocess and communicate +// with it via JSON messages over stdin/stdout. The subprocess's stderr will be +// connected to the go command's stderr. +// +// The subprocess should immediately send a [Response] with its capabilities. +// After that, the go command will send a stream of [Request] messages and the +// subprocess should reply to each [Request] with a [Response] message. +package cacheprog + +import ( + "io" + "time" +) + +// Cmd is a command that can be issued to a child process. +// +// If the interface needs to grow, the go command can add new commands or new +// versioned commands like "get2" in the future. The initial [Response] from +// the child process indicates which commands it supports. +type Cmd string + +const ( + // CmdPut tells the cache program to store an object in the cache. + // + // [Request.ActionID] is the cache key of this object. The cache should + // store [Request.OutputID] and [Request.Body] under this key for a + // later "get" request. It must also store the Body in a file in the local + // file system and return the path to that file in [Response.DiskPath], + // which must exist at least until a "close" request. + CmdPut = Cmd("put") + + // CmdGet tells the cache program to retrieve an object from the cache. + // + // [Request.ActionID] specifies the key of the object to get. If the + // cache does not contain this object, it should set [Response.Miss] to + // true. Otherwise, it should populate the fields of [Response], + // including setting [Response.OutputID] to the OutputID of the original + // "put" request and [Response.DiskPath] to the path of a local file + // containing the Body of the original "put" request. That file must + // continue to exist at least until a "close" request. + CmdGet = Cmd("get") + + // CmdClose requests that the cache program exit gracefully. + // + // The cache program should reply to this request and then exit + // (thus closing its stdout). + CmdClose = Cmd("close") +) + +// Request is the JSON-encoded message that's sent from the go command to +// the GOCACHEPROG child process over stdin. Each JSON object is on its own +// line. A ProgRequest of Type "put" with BodySize > 0 will be followed by a +// line containing a base64-encoded JSON string literal of the body. +type Request struct { + // ID is a unique number per process across all requests. + // It must be echoed in the Response from the child. + ID int64 + + // Command is the type of request. + // The go command will only send commands that were declared + // as supported by the child. + Command Cmd + + // ActionID is the cache key for "put" and "get" requests. + ActionID []byte `json:",omitempty"` // or nil if not used + + // OutputID is stored with the body for "put" requests. + // + // Prior to Go 1.24, when GOCACHEPROG was still an experiment, this was + // accidentally named ObjectID. It was renamed to OutputID in Go 1.24. + OutputID []byte `json:",omitempty"` // or nil if not used + + // Body is the body for "put" requests. It's sent after the JSON object + // as a base64-encoded JSON string when BodySize is non-zero. + // It's sent as a separate JSON value instead of being a struct field + // send in this JSON object so large values can be streamed in both directions. + // The base64 string body of a Request will always be written + // immediately after the JSON object and a newline. + Body io.Reader `json:"-"` + + // BodySize is the number of bytes of Body. If zero, the body isn't written. + BodySize int64 `json:",omitempty"` + + // ObjectID is the accidental spelling of OutputID that was used prior to Go + // 1.24. + // + // Deprecated: use OutputID. This field is only populated temporarily for + // backwards compatibility with Go 1.23 and earlier when + // GOEXPERIMENT=gocacheprog is set. It will be removed in Go 1.25. + ObjectID []byte `json:",omitempty"` +} + +// Response is the JSON response from the child process to the go command. +// +// With the exception of the first protocol message that the child writes to its +// stdout with ID==0 and KnownCommands populated, these are only sent in +// response to a Request from the go command. +// +// Responses can be sent in any order. The ID must match the request they're +// replying to. +type Response struct { + ID int64 // that corresponds to Request; they can be answered out of order + Err string `json:",omitempty"` // if non-empty, the error + + // KnownCommands is included in the first message that cache helper program + // writes to stdout on startup (with ID==0). It includes the + // Request.Command types that are supported by the program. + // + // This lets the go command extend the protocol gracefully over time (adding + // "get2", etc), or fail gracefully when needed. It also lets the go command + // verify the program wants to be a cache helper. + KnownCommands []Cmd `json:",omitempty"` + + // For "get" requests. + + Miss bool `json:",omitempty"` // cache miss + OutputID []byte `json:",omitempty"` // the ObjectID stored with the body + Size int64 `json:",omitempty"` // body size in bytes + Time *time.Time `json:",omitempty"` // when the object was put in the cache (optional; used for cache expiration) + + // For "get" and "put" requests. + + // DiskPath is the absolute path on disk of the body corresponding to a + // "get" (on cache hit) or "put" request's ActionID. + DiskPath string `json:",omitempty"` +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/internal/go/cacheprog/readme.md b/vendor/github.com/golangci/golangci-lint/v2/internal/go/cacheprog/readme.md new file mode 100644 index 000000000..1b08c8480 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/go/cacheprog/readme.md @@ -0,0 +1,9 @@ +# quoted + +Extracted from `go/src/cmd/go/internal/cacheprog/` (related to `cache`). +This is just a copy of the Go code without any changes. + +## History + +- https://github.com/golangci/golangci-lint/pull/5576 + - sync go1.24.1 diff --git a/vendor/github.com/golangci/golangci-lint/internal/go/mmap/mmap.go b/vendor/github.com/golangci/golangci-lint/v2/internal/go/mmap/mmap.go similarity index 84% rename from vendor/github.com/golangci/golangci-lint/internal/go/mmap/mmap.go rename to vendor/github.com/golangci/golangci-lint/v2/internal/go/mmap/mmap.go index fcbd3e08c..fd374df82 100644 --- a/vendor/github.com/golangci/golangci-lint/internal/go/mmap/mmap.go +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/go/mmap/mmap.go @@ -22,10 +22,11 @@ type Data struct { } // Mmap maps the given file into memory. -func Mmap(file string) (Data, error) { +func Mmap(file string) (Data, bool, error) { f, err := os.Open(file) if err != nil { - return Data{}, err + return Data{}, false, err } - return mmapFile(f) + data, err := mmapFile(f) + return data, true, err } diff --git a/vendor/github.com/golangci/golangci-lint/internal/go/mmap/mmap_other.go b/vendor/github.com/golangci/golangci-lint/v2/internal/go/mmap/mmap_other.go similarity index 100% rename from vendor/github.com/golangci/golangci-lint/internal/go/mmap/mmap_other.go rename to vendor/github.com/golangci/golangci-lint/v2/internal/go/mmap/mmap_other.go diff --git a/vendor/github.com/golangci/golangci-lint/internal/go/mmap/mmap_unix.go b/vendor/github.com/golangci/golangci-lint/v2/internal/go/mmap/mmap_unix.go similarity index 100% rename from vendor/github.com/golangci/golangci-lint/internal/go/mmap/mmap_unix.go rename to vendor/github.com/golangci/golangci-lint/v2/internal/go/mmap/mmap_unix.go diff --git a/vendor/github.com/golangci/golangci-lint/internal/go/mmap/mmap_windows.go b/vendor/github.com/golangci/golangci-lint/v2/internal/go/mmap/mmap_windows.go similarity index 74% rename from vendor/github.com/golangci/golangci-lint/internal/go/mmap/mmap_windows.go rename to vendor/github.com/golangci/golangci-lint/v2/internal/go/mmap/mmap_windows.go index 479ee3075..256fab4b4 100644 --- a/vendor/github.com/golangci/golangci-lint/internal/go/mmap/mmap_windows.go +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/go/mmap/mmap_windows.go @@ -37,5 +37,11 @@ func mmapFile(f *os.File) (Data, error) { return Data{}, fmt.Errorf("VirtualQuery %s: %w", f.Name(), err) } data := unsafe.Slice((*byte)(unsafe.Pointer(addr)), int(info.RegionSize)) - return Data{f, data}, nil + if len(data) < int(size) { + // In some cases, especially on 386, we may not receive a in incomplete mapping: + // one that is shorter than the file itself. Return an error in those cases because + // incomplete mappings are not useful. + return Data{}, fmt.Errorf("mmapFile: received incomplete mapping of file") + } + return Data{f, data[:int(size)]}, nil } diff --git a/vendor/github.com/golangci/golangci-lint/internal/go/mmap/readme.md b/vendor/github.com/golangci/golangci-lint/v2/internal/go/mmap/readme.md similarity index 85% rename from vendor/github.com/golangci/golangci-lint/internal/go/mmap/readme.md rename to vendor/github.com/golangci/golangci-lint/v2/internal/go/mmap/readme.md index f68aef097..5cbfdeefe 100644 --- a/vendor/github.com/golangci/golangci-lint/internal/go/mmap/readme.md +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/go/mmap/readme.md @@ -5,6 +5,8 @@ This is just a copy of the Go code without any changes. ## History +- https://github.com/golangci/golangci-lint/pull/5576 + - sync go1.24.1 - https://github.com/golangci/golangci-lint/pull/5100 - Move package from `internal/mmap` to `internal/go/mmap` - https://github.com/golangci/golangci-lint/pull/5098 diff --git a/vendor/github.com/golangci/golangci-lint/internal/go/quoted/quoted.go b/vendor/github.com/golangci/golangci-lint/v2/internal/go/quoted/quoted.go similarity index 100% rename from vendor/github.com/golangci/golangci-lint/internal/go/quoted/quoted.go rename to vendor/github.com/golangci/golangci-lint/v2/internal/go/quoted/quoted.go diff --git a/vendor/github.com/golangci/golangci-lint/internal/go/quoted/readme.md b/vendor/github.com/golangci/golangci-lint/v2/internal/go/quoted/readme.md similarity index 81% rename from vendor/github.com/golangci/golangci-lint/internal/go/quoted/readme.md rename to vendor/github.com/golangci/golangci-lint/v2/internal/go/quoted/readme.md index a5e4c4bb3..97868185c 100644 --- a/vendor/github.com/golangci/golangci-lint/internal/go/quoted/readme.md +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/go/quoted/readme.md @@ -5,6 +5,8 @@ This is just a copy of the Go code without any changes. ## History +- https://github.com/golangci/golangci-lint/pull/5576 + - sync go1.24.1 (no change) - https://github.com/golangci/golangci-lint/pull/5100 - Move package from `internal/quoted` to `internal/go/quoted` - https://github.com/golangci/golangci-lint/pull/5098 diff --git a/vendor/github.com/sagikazarmark/slog-shim/LICENSE b/vendor/github.com/golangci/golangci-lint/v2/internal/x/LICENSE similarity index 92% rename from vendor/github.com/sagikazarmark/slog-shim/LICENSE rename to vendor/github.com/golangci/golangci-lint/v2/internal/x/LICENSE index 6a66aea5e..2a7cf70da 100644 --- a/vendor/github.com/sagikazarmark/slog-shim/LICENSE +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/x/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. +Copyright 2009 The Go Authors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer. copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of Google Inc. nor the names of its + * Neither the name of Google LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/analysisflags/readme.md b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/analysisflags/readme.md new file mode 100644 index 000000000..6035c2226 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/analysisflags/readme.md @@ -0,0 +1,11 @@ +# analysisflags + +Extracted from `/go/analysis/internal/analysisflags` (related to `checker`). +This is just a copy of the code without any changes. + +## History + +- https://github.com/golangci/golangci-lint/pull/6076 + - sync with https://github.com/golang/tools/blob/v0.37.0/go/analysis/internal/analysisflags +- https://github.com/golangci/golangci-lint/pull/5576 + - sync with https://github.com/golang/tools/blob/v0.28.0/go/analysis/internal/analysisflags diff --git a/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/analysisflags/url.go b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/analysisflags/url.go new file mode 100644 index 000000000..26a917a99 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/analysisflags/url.go @@ -0,0 +1,33 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package analysisflags + +import ( + "fmt" + "net/url" + + "golang.org/x/tools/go/analysis" +) + +// ResolveURL resolves the URL field for a Diagnostic from an Analyzer +// and returns the URL. See Diagnostic.URL for details. +func ResolveURL(a *analysis.Analyzer, d analysis.Diagnostic) (string, error) { + if d.URL == "" && d.Category == "" && a.URL == "" { + return "", nil // do nothing + } + raw := d.URL + if d.URL == "" && d.Category != "" { + raw = "#" + d.Category + } + u, err := url.Parse(raw) + if err != nil { + return "", fmt.Errorf("invalid Diagnostic.URL %q: %s", raw, err) + } + base, err := url.Parse(a.URL) + if err != nil { + return "", fmt.Errorf("invalid Analyzer.URL %q: %s", a.URL, err) + } + return base.ResolveReference(u).String(), nil +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/analysisinternal/analysis.go b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/analysisinternal/analysis.go new file mode 100644 index 000000000..b613d1673 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/analysisinternal/analysis.go @@ -0,0 +1,43 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package analysisinternal provides gopls' internal analyses with a +// number of helper functions that operate on typed syntax trees. +package analysisinternal + +import ( + "fmt" + "slices" + + "golang.org/x/tools/go/analysis" +) + +// A ReadFileFunc is a function that returns the +// contents of a file, such as [os.ReadFile]. +type ReadFileFunc = func(filename string) ([]byte, error) + +// CheckedReadFile returns a wrapper around a Pass.ReadFile +// function that performs the appropriate checks. +func CheckedReadFile(pass *analysis.Pass, readFile ReadFileFunc) ReadFileFunc { + return func(filename string) ([]byte, error) { + if err := CheckReadable(pass, filename); err != nil { + return nil, err + } + return readFile(filename) + } +} + +// CheckReadable enforces the access policy defined by the ReadFile field of [analysis.Pass]. +func CheckReadable(pass *analysis.Pass, filename string) error { + if slices.Contains(pass.OtherFiles, filename) || + slices.Contains(pass.IgnoredFiles, filename) { + return nil + } + for _, f := range pass.Files { + if pass.Fset.File(f.FileStart).Name() == filename { + return nil + } + } + return fmt.Errorf("Pass.ReadFile: %s is not among OtherFiles, IgnoredFiles, or names of Files", filename) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/analysisinternal/readme.md b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/analysisinternal/readme.md new file mode 100644 index 000000000..6c54592d9 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/analysisinternal/readme.md @@ -0,0 +1,11 @@ +# analysisinternal + +Extracted from `/internal/analysisinternal/` (related to `checker`). +This is just a copy of the code without any changes. + +## History + +- https://github.com/golangci/golangci-lint/pull/6076 + - sync with https://github.com/golang/tools/blob/v0.37.0/internal/analysisinternal/ +- https://github.com/golangci/golangci-lint/pull/5576 + - sync with https://github.com/golang/tools/blob/v0.28.0/internal/analysisinternal/ diff --git a/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/diff.go b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/diff.go new file mode 100644 index 000000000..c12bdfd2a --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/diff.go @@ -0,0 +1,177 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package diff computes differences between text files or strings. +package diff + +import ( + "fmt" + "slices" + "sort" + "strings" +) + +// An Edit describes the replacement of a portion of a text file. +type Edit struct { + Start, End int // byte offsets of the region to replace + New string // the replacement +} + +func (e Edit) String() string { + return fmt.Sprintf("{Start:%d,End:%d,New:%q}", e.Start, e.End, e.New) +} + +// Apply applies a sequence of edits to the src buffer and returns the +// result. Edits are applied in order of start offset; edits with the +// same start offset are applied in they order they were provided. +// +// Apply returns an error if any edit is out of bounds, +// or if any pair of edits is overlapping. +func Apply(src string, edits []Edit) (string, error) { + edits, size, err := validate(src, edits) + if err != nil { + return "", err + } + + // Apply edits. + out := make([]byte, 0, size) + lastEnd := 0 + for _, edit := range edits { + if lastEnd < edit.Start { + out = append(out, src[lastEnd:edit.Start]...) + } + out = append(out, edit.New...) + lastEnd = edit.End + } + out = append(out, src[lastEnd:]...) + + if len(out) != size { + panic("wrong size") + } + + return string(out), nil +} + +// ApplyBytes is like Apply, but it accepts a byte slice. +// The result is always a new array. +func ApplyBytes(src []byte, edits []Edit) ([]byte, error) { + res, err := Apply(string(src), edits) + return []byte(res), err +} + +// validate checks that edits are consistent with src, +// and returns the size of the patched output. +// It may return a different slice. +func validate(src string, edits []Edit) ([]Edit, int, error) { + if !sort.IsSorted(editsSort(edits)) { + edits = slices.Clone(edits) + SortEdits(edits) + } + + // Check validity of edits and compute final size. + size := len(src) + lastEnd := 0 + for _, edit := range edits { + if !(0 <= edit.Start && edit.Start <= edit.End && edit.End <= len(src)) { + return nil, 0, fmt.Errorf("diff has out-of-bounds edits") + } + if edit.Start < lastEnd { + return nil, 0, fmt.Errorf("diff has overlapping edits") + } + size += len(edit.New) + edit.Start - edit.End + lastEnd = edit.End + } + + return edits, size, nil +} + +// SortEdits orders a slice of Edits by (start, end) offset. +// This ordering puts insertions (end = start) before deletions +// (end > start) at the same point, but uses a stable sort to preserve +// the order of multiple insertions at the same point. +// (Apply detects multiple deletions at the same point as an error.) +func SortEdits(edits []Edit) { + sort.Stable(editsSort(edits)) +} + +type editsSort []Edit + +func (a editsSort) Len() int { return len(a) } +func (a editsSort) Less(i, j int) bool { + if cmp := a[i].Start - a[j].Start; cmp != 0 { + return cmp < 0 + } + return a[i].End < a[j].End +} +func (a editsSort) Swap(i, j int) { a[i], a[j] = a[j], a[i] } + +// lineEdits expands and merges a sequence of edits so that each +// resulting edit replaces one or more complete lines. +// See ApplyEdits for preconditions. +func lineEdits(src string, edits []Edit) ([]Edit, error) { + edits, _, err := validate(src, edits) + if err != nil { + return nil, err + } + + // Do all deletions begin and end at the start of a line, + // and all insertions end with a newline? + // (This is merely a fast path.) + for _, edit := range edits { + if edit.Start >= len(src) || // insertion at EOF + edit.Start > 0 && src[edit.Start-1] != '\n' || // not at line start + edit.End > 0 && src[edit.End-1] != '\n' || // not at line start + edit.New != "" && edit.New[len(edit.New)-1] != '\n' { // partial insert + goto expand // slow path + } + } + return edits, nil // aligned + +expand: + if len(edits) == 0 { + return edits, nil // no edits (unreachable due to fast path) + } + expanded := make([]Edit, 0, len(edits)) // a guess + prev := edits[0] + // TODO(adonovan): opt: start from the first misaligned edit. + // TODO(adonovan): opt: avoid quadratic cost of string += string. + for _, edit := range edits[1:] { + between := src[prev.End:edit.Start] + if !strings.Contains(between, "\n") { + // overlapping lines: combine with previous edit. + prev.New += between + edit.New + prev.End = edit.End + } else { + // non-overlapping lines: flush previous edit. + expanded = append(expanded, expandEdit(prev, src)) + prev = edit + } + } + return append(expanded, expandEdit(prev, src)), nil // flush final edit +} + +// expandEdit returns edit expanded to complete whole lines. +func expandEdit(edit Edit, src string) Edit { + // Expand start left to start of line. + // (delta is the zero-based column number of start.) + start := edit.Start + if delta := start - 1 - strings.LastIndex(src[:start], "\n"); delta > 0 { + edit.Start -= delta + edit.New = src[start-delta:start] + edit.New + } + + // Expand end right to end of line. + end := edit.End + if end > 0 && src[end-1] != '\n' || + edit.New != "" && edit.New[len(edit.New)-1] != '\n' { + if nl := strings.IndexByte(src[end:], '\n'); nl < 0 { + edit.End = len(src) // extend to EOF + } else { + edit.End = end + nl + 1 // extend beyond \n + } + } + edit.New += src[end:edit.End] + + return edit +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/lcs/common.go b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/lcs/common.go new file mode 100644 index 000000000..27fa9ecbd --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/lcs/common.go @@ -0,0 +1,179 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package lcs + +import ( + "log" + "sort" +) + +// lcs is a longest common sequence +type lcs []diag + +// A diag is a piece of the edit graph where A[X+i] == B[Y+i], for 0<=i l[j].Len + }) + return l +} + +// validate that the elements of the lcs do not overlap +// (can only happen when the two-sided algorithm ends early) +// expects the lcs to be sorted +func (l lcs) valid() bool { + for i := 1; i < len(l); i++ { + if l[i-1].X+l[i-1].Len > l[i].X { + return false + } + if l[i-1].Y+l[i-1].Len > l[i].Y { + return false + } + } + return true +} + +// repair overlapping lcs +// only called if two-sided stops early +func (l lcs) fix() lcs { + // from the set of diagonals in l, find a maximal non-conflicting set + // this problem may be NP-complete, but we use a greedy heuristic, + // which is quadratic, but with a better data structure, could be D log D. + // independent is not enough: {0,3,1} and {3,0,2} can't both occur in an lcs + // which has to have monotone x and y + if len(l) == 0 { + return nil + } + sort.Slice(l, func(i, j int) bool { return l[i].Len > l[j].Len }) + tmp := make(lcs, 0, len(l)) + tmp = append(tmp, l[0]) + for i := 1; i < len(l); i++ { + var dir direction + nxt := l[i] + for _, in := range tmp { + if dir, nxt = overlap(in, nxt); dir == empty || dir == bad { + break + } + } + if nxt.Len > 0 && dir != bad { + tmp = append(tmp, nxt) + } + } + tmp.sort() + if false && !tmp.valid() { // debug checking + log.Fatalf("here %d", len(tmp)) + } + return tmp +} + +type direction int + +const ( + empty direction = iota // diag is empty (so not in lcs) + leftdown // proposed acceptably to the left and below + rightup // proposed diag is acceptably to the right and above + bad // proposed diag is inconsistent with the lcs so far +) + +// overlap trims the proposed diag prop so it doesn't overlap with +// the existing diag that has already been added to the lcs. +func overlap(exist, prop diag) (direction, diag) { + if prop.X <= exist.X && exist.X < prop.X+prop.Len { + // remove the end of prop where it overlaps with the X end of exist + delta := prop.X + prop.Len - exist.X + prop.Len -= delta + if prop.Len <= 0 { + return empty, prop + } + } + if exist.X <= prop.X && prop.X < exist.X+exist.Len { + // remove the beginning of prop where overlaps with exist + delta := exist.X + exist.Len - prop.X + prop.Len -= delta + if prop.Len <= 0 { + return empty, prop + } + prop.X += delta + prop.Y += delta + } + if prop.Y <= exist.Y && exist.Y < prop.Y+prop.Len { + // remove the end of prop that overlaps (in Y) with exist + delta := prop.Y + prop.Len - exist.Y + prop.Len -= delta + if prop.Len <= 0 { + return empty, prop + } + } + if exist.Y <= prop.Y && prop.Y < exist.Y+exist.Len { + // remove the beginning of peop that overlaps with exist + delta := exist.Y + exist.Len - prop.Y + prop.Len -= delta + if prop.Len <= 0 { + return empty, prop + } + prop.X += delta // no test reaches this code + prop.Y += delta + } + if prop.X+prop.Len <= exist.X && prop.Y+prop.Len <= exist.Y { + return leftdown, prop + } + if exist.X+exist.Len <= prop.X && exist.Y+exist.Len <= prop.Y { + return rightup, prop + } + // prop can't be in an lcs that contains exist + return bad, prop +} + +// manipulating Diag and lcs + +// prepend a diagonal (x,y)-(x+1,y+1) segment either to an empty lcs +// or to its first Diag. prepend is only called to extend diagonals +// the backward direction. +func (lcs lcs) prepend(x, y int) lcs { + if len(lcs) > 0 { + d := &lcs[0] + if int(d.X) == x+1 && int(d.Y) == y+1 { + // extend the diagonal down and to the left + d.X, d.Y = int(x), int(y) + d.Len++ + return lcs + } + } + + r := diag{X: int(x), Y: int(y), Len: 1} + lcs = append([]diag{r}, lcs...) + return lcs +} + +// append appends a diagonal, or extends the existing one. +// by adding the edge (x,y)-(x+1.y+1). append is only called +// to extend diagonals in the forward direction. +func (lcs lcs) append(x, y int) lcs { + if len(lcs) > 0 { + last := &lcs[len(lcs)-1] + // Expand last element if adjoining. + if last.X+last.Len == x && last.Y+last.Len == y { + last.Len++ + return lcs + } + } + + return append(lcs, diag{X: x, Y: y, Len: 1}) +} + +// enforce constraint on d, k +func ok(d, k int) bool { + return d >= 0 && -d <= k && k <= d +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/lcs/doc.go b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/lcs/doc.go new file mode 100644 index 000000000..aa4b0fb59 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/lcs/doc.go @@ -0,0 +1,156 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// package lcs contains code to find longest-common-subsequences +// (and diffs) +package lcs + +/* +Compute longest-common-subsequences of two slices A, B using +algorithms from Myers' paper. A longest-common-subsequence +(LCS from now on) of A and B is a maximal set of lexically increasing +pairs of subscripts (x,y) with A[x]==B[y]. There may be many LCS, but +they all have the same length. An LCS determines a sequence of edits +that changes A into B. + +The key concept is the edit graph of A and B. +If A has length N and B has length M, then the edit graph has +vertices v[i][j] for 0 <= i <= N, 0 <= j <= M. There is a +horizontal edge from v[i][j] to v[i+1][j] whenever both are in +the graph, and a vertical edge from v[i][j] to f[i][j+1] similarly. +When A[i] == B[j] there is a diagonal edge from v[i][j] to v[i+1][j+1]. + +A path between in the graph between (0,0) and (N,M) determines a sequence +of edits converting A into B: each horizontal edge corresponds to removing +an element of A, and each vertical edge corresponds to inserting an +element of B. + +A vertex (x,y) is on (forward) diagonal k if x-y=k. A path in the graph +is of length D if it has D non-diagonal edges. The algorithms generate +forward paths (in which at least one of x,y increases at each edge), +or backward paths (in which at least one of x,y decreases at each edge), +or a combination. (Note that the orientation is the traditional mathematical one, +with the origin in the lower-left corner.) + +Here is the edit graph for A:"aabbaa", B:"aacaba". (I know the diagonals look weird.) + ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ + a | ___/‾‾‾ | ___/‾‾‾ | | | ___/‾‾‾ | ___/‾‾‾ | + ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ + b | | | ___/‾‾‾ | ___/‾‾‾ | | | + ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ + a | ___/‾‾‾ | ___/‾‾‾ | | | ___/‾‾‾ | ___/‾‾‾ | + ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ + c | | | | | | | + ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ + a | ___/‾‾‾ | ___/‾‾‾ | | | ___/‾‾‾ | ___/‾‾‾ | + ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ + a | ___/‾‾‾ | ___/‾‾‾ | | | ___/‾‾‾ | ___/‾‾‾ | + ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ + a a b b a a + + +The algorithm labels a vertex (x,y) with D,k if it is on diagonal k and at +the end of a maximal path of length D. (Because x-y=k it suffices to remember +only the x coordinate of the vertex.) + +The forward algorithm: Find the longest diagonal starting at (0,0) and +label its end with D=0,k=0. From that vertex take a vertical step and +then follow the longest diagonal (up and to the right), and label that vertex +with D=1,k=-1. From the D=0,k=0 point take a horizontal step and the follow +the longest diagonal (up and to the right) and label that vertex +D=1,k=1. In the same way, having labelled all the D vertices, +from a vertex labelled D,k find two vertices +tentatively labelled D+1,k-1 and D+1,k+1. There may be two on the same +diagonal, in which case take the one with the larger x. + +Eventually the path gets to (N,M), and the diagonals on it are the LCS. + +Here is the edit graph with the ends of D-paths labelled. (So, for instance, +0/2,2 indicates that x=2,y=2 is labelled with 0, as it should be, since the first +step is to go up the longest diagonal from (0,0).) +A:"aabbaa", B:"aacaba" + ⊙ ------- ⊙ ------- ⊙ -------(3/3,6)------- ⊙ -------(3/5,6)-------(4/6,6) + a | ___/‾‾‾ | ___/‾‾‾ | | | ___/‾‾‾ | ___/‾‾‾ | + ⊙ ------- ⊙ ------- ⊙ -------(2/3,5)------- ⊙ ------- ⊙ ------- ⊙ + b | | | ___/‾‾‾ | ___/‾‾‾ | | | + ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ -------(3/5,4)------- ⊙ + a | ___/‾‾‾ | ___/‾‾‾ | | | ___/‾‾‾ | ___/‾‾‾ | + ⊙ ------- ⊙ -------(1/2,3)-------(2/3,3)------- ⊙ ------- ⊙ ------- ⊙ + c | | | | | | | + ⊙ ------- ⊙ -------(0/2,2)-------(1/3,2)-------(2/4,2)-------(3/5,2)-------(4/6,2) + a | ___/‾‾‾ | ___/‾‾‾ | | | ___/‾‾‾ | ___/‾‾‾ | + ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ + a | ___/‾‾‾ | ___/‾‾‾ | | | ___/‾‾‾ | ___/‾‾‾ | + ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ ------- ⊙ + a a b b a a + +The 4-path is reconstructed starting at (4/6,6), horizontal to (3/5,6), diagonal to (3,4), vertical +to (2/3,3), horizontal to (1/2,3), vertical to (0/2,2), and diagonal to (0,0). As expected, +there are 4 non-diagonal steps, and the diagonals form an LCS. + +There is a symmetric backward algorithm, which gives (backwards labels are prefixed with a colon): +A:"aabbaa", B:"aacaba" + ⊙ -------- ⊙ -------- ⊙ -------- ⊙ -------- ⊙ -------- ⊙ -------- ⊙ + a | ____/‾‾‾ | ____/‾‾‾ | | | ____/‾‾‾ | ____/‾‾‾ | + ⊙ -------- ⊙ -------- ⊙ -------- ⊙ -------- ⊙ --------(:0/5,5)-------- ⊙ + b | | | ____/‾‾‾ | ____/‾‾‾ | | | + ⊙ -------- ⊙ -------- ⊙ --------(:1/3,4)-------- ⊙ -------- ⊙ -------- ⊙ + a | ____/‾‾‾ | ____/‾‾‾ | | | ____/‾‾‾ | ____/‾‾‾ | + (:3/0,3)--------(:2/1,3)-------- ⊙ --------(:2/3,3)--------(:1/4,3)-------- ⊙ -------- ⊙ + c | | | | | | | + ⊙ -------- ⊙ -------- ⊙ --------(:3/3,2)--------(:2/4,2)-------- ⊙ -------- ⊙ + a | ____/‾‾‾ | ____/‾‾‾ | | | ____/‾‾‾ | ____/‾‾‾ | + (:3/0,1)-------- ⊙ -------- ⊙ -------- ⊙ --------(:3/4,1)-------- ⊙ -------- ⊙ + a | ____/‾‾‾ | ____/‾‾‾ | | | ____/‾‾‾ | ____/‾‾‾ | + (:4/0,0)-------- ⊙ -------- ⊙ -------- ⊙ --------(:4/4,0)-------- ⊙ -------- ⊙ + a a b b a a + +Neither of these is ideal for use in an editor, where it is undesirable to send very long diffs to the +front end. It's tricky to decide exactly what 'very long diffs' means, as "replace A by B" is very short. +We want to control how big D can be, by stopping when it gets too large. The forward algorithm then +privileges common prefixes, and the backward algorithm privileges common suffixes. Either is an undesirable +asymmetry. + +Fortunately there is a two-sided algorithm, implied by results in Myers' paper. Here's what the labels in +the edit graph look like. +A:"aabbaa", B:"aacaba" + ⊙ --------- ⊙ --------- ⊙ --------- ⊙ --------- ⊙ --------- ⊙ --------- ⊙ + a | ____/‾‾‾‾ | ____/‾‾‾‾ | | | ____/‾‾‾‾ | ____/‾‾‾‾ | + ⊙ --------- ⊙ --------- ⊙ --------- (2/3,5) --------- ⊙ --------- (:0/5,5)--------- ⊙ + b | | | ____/‾‾‾‾ | ____/‾‾‾‾ | | | + ⊙ --------- ⊙ --------- ⊙ --------- (:1/3,4)--------- ⊙ --------- ⊙ --------- ⊙ + a | ____/‾‾‾‾ | ____/‾‾‾‾ | | | ____/‾‾‾‾ | ____/‾‾‾‾ | + ⊙ --------- (:2/1,3)--------- (1/2,3) ---------(2:2/3,3)--------- (:1/4,3)--------- ⊙ --------- ⊙ + c | | | | | | | + ⊙ --------- ⊙ --------- (0/2,2) --------- (1/3,2) ---------(2:2/4,2)--------- ⊙ --------- ⊙ + a | ____/‾‾‾‾ | ____/‾‾‾‾ | | | ____/‾‾‾‾ | ____/‾‾‾‾ | + ⊙ --------- ⊙ --------- ⊙ --------- ⊙ --------- ⊙ --------- ⊙ --------- ⊙ + a | ____/‾‾‾‾ | ____/‾‾‾‾ | | | ____/‾‾‾‾ | ____/‾‾‾‾ | + ⊙ --------- ⊙ --------- ⊙ --------- ⊙ --------- ⊙ --------- ⊙ --------- ⊙ + a a b b a a + +The algorithm stopped when it saw the backwards 2-path ending at (1,3) and the forwards 2-path ending at (3,5). The criterion +is a backwards path ending at (u,v) and a forward path ending at (x,y), where u <= x and the two points are on the same +diagonal. (Here the edgegraph has a diagonal, but the criterion is x-y=u-v.) Myers proves there is a forward +2-path from (0,0) to (1,3), and that together with the backwards 2-path ending at (1,3) gives the expected 4-path. +Unfortunately the forward path has to be constructed by another run of the forward algorithm; it can't be found from the +computed labels. That is the worst case. Had the code noticed (x,y)=(u,v)=(3,3) the whole path could be reconstructed +from the edgegraph. The implementation looks for a number of special cases to try to avoid computing an extra forward path. + +If the two-sided algorithm has stop early (because D has become too large) it will have found a forward LCS and a +backwards LCS. Ideally these go with disjoint prefixes and suffixes of A and B, but disjointedness may fail and the two +computed LCS may conflict. (An easy example is where A is a suffix of B, and shares a short prefix. The backwards LCS +is all of A, and the forward LCS is a prefix of A.) The algorithm combines the two +to form a best-effort LCS. In the worst case the forward partial LCS may have to +be recomputed. +*/ + +/* Eugene Myers paper is titled +"An O(ND) Difference Algorithm and Its Variations" +and can be found at +http://www.xmailserver.org/diff2.pdf + +(There is a generic implementation of the algorithm the repository with git hash +b9ad7e4ade3a686d608e44475390ad428e60e7fc) +*/ diff --git a/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/lcs/git.sh b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/lcs/git.sh new file mode 100644 index 000000000..b25ba4aac --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/lcs/git.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# +# Copyright 2022 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. +# +# Creates a zip file containing all numbered versions +# of the commit history of a large source file, for use +# as input data for the tests of the diff algorithm. +# +# Run script from root of the x/tools repo. + +set -eu + +# WARNING: This script will install the latest version of $file +# The largest real source file in the x/tools repo. +# file=internal/golang/completion/completion.go +# file=internal/golang/diagnostics.go +file=internal/protocol/tsprotocol.go + +tmp=$(mktemp -d) +git log $file | + awk '/^commit / {print $2}' | + nl -ba -nrz | + while read n hash; do + git checkout --quiet $hash $file + cp -f $file $tmp/$n + done +(cd $tmp && zip -q - *) > testdata.zip +rm -fr $tmp +git restore --staged $file +git restore $file +echo "Created testdata.zip" diff --git a/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/lcs/labels.go b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/lcs/labels.go new file mode 100644 index 000000000..504913d1d --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/lcs/labels.go @@ -0,0 +1,55 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package lcs + +import ( + "fmt" +) + +// For each D, vec[D] has length D+1, +// and the label for (D, k) is stored in vec[D][(D+k)/2]. +type label struct { + vec [][]int +} + +// Temporary checking DO NOT COMMIT true TO PRODUCTION CODE +const debug = false + +// debugging. check that the (d,k) pair is valid +// (that is, -d<=k<=d and d+k even) +func checkDK(D, k int) { + if k >= -D && k <= D && (D+k)%2 == 0 { + return + } + panic(fmt.Sprintf("out of range, d=%d,k=%d", D, k)) +} + +func (t *label) set(D, k, x int) { + if debug { + checkDK(D, k) + } + for len(t.vec) <= D { + t.vec = append(t.vec, nil) + } + if t.vec[D] == nil { + t.vec[D] = make([]int, D+1) + } + t.vec[D][(D+k)/2] = x // known that D+k is even +} + +func (t *label) get(d, k int) int { + if debug { + checkDK(d, k) + } + return int(t.vec[d][(d+k)/2]) +} + +func newtriang(limit int) label { + if limit < 100 { + // Preallocate if limit is not large. + return label{vec: make([][]int, limit)} + } + return label{} +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/lcs/old.go b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/lcs/old.go new file mode 100644 index 000000000..4c346706a --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/lcs/old.go @@ -0,0 +1,478 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package lcs + +// TODO(adonovan): remove unclear references to "old" in this package. + +import ( + "fmt" +) + +// A Diff is a replacement of a portion of A by a portion of B. +type Diff struct { + Start, End int // offsets of portion to delete in A + ReplStart, ReplEnd int // offset of replacement text in B +} + +// DiffStrings returns the differences between two strings. +// It does not respect rune boundaries. +func DiffStrings(a, b string) []Diff { return diff(stringSeqs{a, b}) } + +// DiffBytes returns the differences between two byte sequences. +// It does not respect rune boundaries. +func DiffBytes(a, b []byte) []Diff { return diff(bytesSeqs{a, b}) } + +// DiffRunes returns the differences between two rune sequences. +func DiffRunes(a, b []rune) []Diff { return diff(runesSeqs{a, b}) } + +func diff(seqs sequences) []Diff { + // A limit on how deeply the LCS algorithm should search. The value is just a guess. + const maxDiffs = 100 + diff, _ := compute(seqs, twosided, maxDiffs/2) + return diff +} + +// compute computes the list of differences between two sequences, +// along with the LCS. It is exercised directly by tests. +// The algorithm is one of {forward, backward, twosided}. +func compute(seqs sequences, algo func(*editGraph) lcs, limit int) ([]Diff, lcs) { + if limit <= 0 { + limit = 1 << 25 // effectively infinity + } + alen, blen := seqs.lengths() + g := &editGraph{ + seqs: seqs, + vf: newtriang(limit), + vb: newtriang(limit), + limit: limit, + ux: alen, + uy: blen, + delta: alen - blen, + } + lcs := algo(g) + diffs := lcs.toDiffs(alen, blen) + return diffs, lcs +} + +// editGraph carries the information for computing the lcs of two sequences. +type editGraph struct { + seqs sequences + vf, vb label // forward and backward labels + + limit int // maximal value of D + // the bounding rectangle of the current edit graph + lx, ly, ux, uy int + delta int // common subexpression: (ux-lx)-(uy-ly) +} + +// toDiffs converts an LCS to a list of edits. +func (lcs lcs) toDiffs(alen, blen int) []Diff { + var diffs []Diff + var pa, pb int // offsets in a, b + for _, l := range lcs { + if pa < l.X || pb < l.Y { + diffs = append(diffs, Diff{pa, l.X, pb, l.Y}) + } + pa = l.X + l.Len + pb = l.Y + l.Len + } + if pa < alen || pb < blen { + diffs = append(diffs, Diff{pa, alen, pb, blen}) + } + return diffs +} + +// --- FORWARD --- + +// fdone decides if the forward path has reached the upper right +// corner of the rectangle. If so, it also returns the computed lcs. +func (e *editGraph) fdone(D, k int) (bool, lcs) { + // x, y, k are relative to the rectangle + x := e.vf.get(D, k) + y := x - k + if x == e.ux && y == e.uy { + return true, e.forwardlcs(D, k) + } + return false, nil +} + +// run the forward algorithm, until success or up to the limit on D. +func forward(e *editGraph) lcs { + e.setForward(0, 0, e.lx) + if ok, ans := e.fdone(0, 0); ok { + return ans + } + // from D to D+1 + for D := range e.limit { + e.setForward(D+1, -(D + 1), e.getForward(D, -D)) + if ok, ans := e.fdone(D+1, -(D + 1)); ok { + return ans + } + e.setForward(D+1, D+1, e.getForward(D, D)+1) + if ok, ans := e.fdone(D+1, D+1); ok { + return ans + } + for k := -D + 1; k <= D-1; k += 2 { + // these are tricky and easy to get backwards + lookv := e.lookForward(k, e.getForward(D, k-1)+1) + lookh := e.lookForward(k, e.getForward(D, k+1)) + if lookv > lookh { + e.setForward(D+1, k, lookv) + } else { + e.setForward(D+1, k, lookh) + } + if ok, ans := e.fdone(D+1, k); ok { + return ans + } + } + } + // D is too large + // find the D path with maximal x+y inside the rectangle and + // use that to compute the found part of the lcs + kmax := -e.limit - 1 + diagmax := -1 + for k := -e.limit; k <= e.limit; k += 2 { + x := e.getForward(e.limit, k) + y := x - k + if x+y > diagmax && x <= e.ux && y <= e.uy { + diagmax, kmax = x+y, k + } + } + return e.forwardlcs(e.limit, kmax) +} + +// recover the lcs by backtracking from the farthest point reached +func (e *editGraph) forwardlcs(D, k int) lcs { + var ans lcs + for x := e.getForward(D, k); x != 0 || x-k != 0; { + if ok(D-1, k-1) && x-1 == e.getForward(D-1, k-1) { + // if (x-1,y) is labelled D-1, x--,D--,k--,continue + D, k, x = D-1, k-1, x-1 + continue + } else if ok(D-1, k+1) && x == e.getForward(D-1, k+1) { + // if (x,y-1) is labelled D-1, x, D--,k++, continue + D, k = D-1, k+1 + continue + } + // if (x-1,y-1)--(x,y) is a diagonal, prepend,x--,y--, continue + y := x - k + ans = ans.prepend(x+e.lx-1, y+e.ly-1) + x-- + } + return ans +} + +// start at (x,y), go up the diagonal as far as possible, +// and label the result with d +func (e *editGraph) lookForward(k, relx int) int { + rely := relx - k + x, y := relx+e.lx, rely+e.ly + if x < e.ux && y < e.uy { + x += e.seqs.commonPrefixLen(x, e.ux, y, e.uy) + } + return x +} + +func (e *editGraph) setForward(d, k, relx int) { + x := e.lookForward(k, relx) + e.vf.set(d, k, x-e.lx) +} + +func (e *editGraph) getForward(d, k int) int { + x := e.vf.get(d, k) + return x +} + +// --- BACKWARD --- + +// bdone decides if the backward path has reached the lower left corner +func (e *editGraph) bdone(D, k int) (bool, lcs) { + // x, y, k are relative to the rectangle + x := e.vb.get(D, k) + y := x - (k + e.delta) + if x == 0 && y == 0 { + return true, e.backwardlcs(D, k) + } + return false, nil +} + +// run the backward algorithm, until success or up to the limit on D. +// (used only by tests) +func backward(e *editGraph) lcs { + e.setBackward(0, 0, e.ux) + if ok, ans := e.bdone(0, 0); ok { + return ans + } + // from D to D+1 + for D := range e.limit { + e.setBackward(D+1, -(D + 1), e.getBackward(D, -D)-1) + if ok, ans := e.bdone(D+1, -(D + 1)); ok { + return ans + } + e.setBackward(D+1, D+1, e.getBackward(D, D)) + if ok, ans := e.bdone(D+1, D+1); ok { + return ans + } + for k := -D + 1; k <= D-1; k += 2 { + // these are tricky and easy to get wrong + lookv := e.lookBackward(k, e.getBackward(D, k-1)) + lookh := e.lookBackward(k, e.getBackward(D, k+1)-1) + if lookv < lookh { + e.setBackward(D+1, k, lookv) + } else { + e.setBackward(D+1, k, lookh) + } + if ok, ans := e.bdone(D+1, k); ok { + return ans + } + } + } + + // D is too large + // find the D path with minimal x+y inside the rectangle and + // use that to compute the part of the lcs found + kmax := -e.limit - 1 + diagmin := 1 << 25 + for k := -e.limit; k <= e.limit; k += 2 { + x := e.getBackward(e.limit, k) + y := x - (k + e.delta) + if x+y < diagmin && x >= 0 && y >= 0 { + diagmin, kmax = x+y, k + } + } + if kmax < -e.limit { + panic(fmt.Sprintf("no paths when limit=%d?", e.limit)) + } + return e.backwardlcs(e.limit, kmax) +} + +// recover the lcs by backtracking +func (e *editGraph) backwardlcs(D, k int) lcs { + var ans lcs + for x := e.getBackward(D, k); x != e.ux || x-(k+e.delta) != e.uy; { + if ok(D-1, k-1) && x == e.getBackward(D-1, k-1) { + // D--, k--, x unchanged + D, k = D-1, k-1 + continue + } else if ok(D-1, k+1) && x+1 == e.getBackward(D-1, k+1) { + // D--, k++, x++ + D, k, x = D-1, k+1, x+1 + continue + } + y := x - (k + e.delta) + ans = ans.append(x+e.lx, y+e.ly) + x++ + } + return ans +} + +// start at (x,y), go down the diagonal as far as possible, +func (e *editGraph) lookBackward(k, relx int) int { + rely := relx - (k + e.delta) // forward k = k + e.delta + x, y := relx+e.lx, rely+e.ly + if x > 0 && y > 0 { + x -= e.seqs.commonSuffixLen(0, x, 0, y) + } + return x +} + +// convert to rectangle, and label the result with d +func (e *editGraph) setBackward(d, k, relx int) { + x := e.lookBackward(k, relx) + e.vb.set(d, k, x-e.lx) +} + +func (e *editGraph) getBackward(d, k int) int { + x := e.vb.get(d, k) + return x +} + +// -- TWOSIDED --- + +func twosided(e *editGraph) lcs { + // The termination condition could be improved, as either the forward + // or backward pass could succeed before Myers' Lemma applies. + // Aside from questions of efficiency (is the extra testing cost-effective) + // this is more likely to matter when e.limit is reached. + e.setForward(0, 0, e.lx) + e.setBackward(0, 0, e.ux) + + // from D to D+1 + for D := range e.limit { + // just finished a backwards pass, so check + if got, ok := e.twoDone(D, D); ok { + return e.twolcs(D, D, got) + } + // do a forwards pass (D to D+1) + e.setForward(D+1, -(D + 1), e.getForward(D, -D)) + e.setForward(D+1, D+1, e.getForward(D, D)+1) + for k := -D + 1; k <= D-1; k += 2 { + // these are tricky and easy to get backwards + lookv := e.lookForward(k, e.getForward(D, k-1)+1) + lookh := e.lookForward(k, e.getForward(D, k+1)) + if lookv > lookh { + e.setForward(D+1, k, lookv) + } else { + e.setForward(D+1, k, lookh) + } + } + // just did a forward pass, so check + if got, ok := e.twoDone(D+1, D); ok { + return e.twolcs(D+1, D, got) + } + // do a backward pass, D to D+1 + e.setBackward(D+1, -(D + 1), e.getBackward(D, -D)-1) + e.setBackward(D+1, D+1, e.getBackward(D, D)) + for k := -D + 1; k <= D-1; k += 2 { + // these are tricky and easy to get wrong + lookv := e.lookBackward(k, e.getBackward(D, k-1)) + lookh := e.lookBackward(k, e.getBackward(D, k+1)-1) + if lookv < lookh { + e.setBackward(D+1, k, lookv) + } else { + e.setBackward(D+1, k, lookh) + } + } + } + + // D too large. combine a forward and backward partial lcs + // first, a forward one + kmax := -e.limit - 1 + diagmax := -1 + for k := -e.limit; k <= e.limit; k += 2 { + x := e.getForward(e.limit, k) + y := x - k + if x+y > diagmax && x <= e.ux && y <= e.uy { + diagmax, kmax = x+y, k + } + } + if kmax < -e.limit { + panic(fmt.Sprintf("no forward paths when limit=%d?", e.limit)) + } + lcs := e.forwardlcs(e.limit, kmax) + // now a backward one + // find the D path with minimal x+y inside the rectangle and + // use that to compute the lcs + diagmin := 1 << 25 // infinity + for k := -e.limit; k <= e.limit; k += 2 { + x := e.getBackward(e.limit, k) + y := x - (k + e.delta) + if x+y < diagmin && x >= 0 && y >= 0 { + diagmin, kmax = x+y, k + } + } + if kmax < -e.limit { + panic(fmt.Sprintf("no backward paths when limit=%d?", e.limit)) + } + lcs = append(lcs, e.backwardlcs(e.limit, kmax)...) + // These may overlap (e.forwardlcs and e.backwardlcs return sorted lcs) + ans := lcs.fix() + return ans +} + +// Does Myers' Lemma apply? +func (e *editGraph) twoDone(df, db int) (int, bool) { + if (df+db+e.delta)%2 != 0 { + return 0, false // diagonals cannot overlap + } + kmin := max(-df, -db+e.delta) + kmax := db + e.delta + if df < kmax { + kmax = df + } + for k := kmin; k <= kmax; k += 2 { + x := e.vf.get(df, k) + u := e.vb.get(db, k-e.delta) + if u <= x { + // is it worth looking at all the other k? + for l := k; l <= kmax; l += 2 { + x := e.vf.get(df, l) + y := x - l + u := e.vb.get(db, l-e.delta) + v := u - l + if x == u || u == 0 || v == 0 || y == e.uy || x == e.ux { + return l, true + } + } + return k, true + } + } + return 0, false +} + +func (e *editGraph) twolcs(df, db, kf int) lcs { + // db==df || db+1==df + x := e.vf.get(df, kf) + y := x - kf + kb := kf - e.delta + u := e.vb.get(db, kb) + v := u - kf + + // Myers proved there is a df-path from (0,0) to (u,v) + // and a db-path from (x,y) to (N,M). + // In the first case the overall path is the forward path + // to (u,v) followed by the backward path to (N,M). + // In the second case the path is the backward path to (x,y) + // followed by the forward path to (x,y) from (0,0). + + // Look for some special cases to avoid computing either of these paths. + if x == u { + // "babaab" "cccaba" + // already patched together + lcs := e.forwardlcs(df, kf) + lcs = append(lcs, e.backwardlcs(db, kb)...) + return lcs.sort() + } + + // is (u-1,v) or (u,v-1) labelled df-1? + // if so, that forward df-1-path plus a horizontal or vertical edge + // is the df-path to (u,v), then plus the db-path to (N,M) + if u > 0 && ok(df-1, u-1-v) && e.vf.get(df-1, u-1-v) == u-1 { + // "aabbab" "cbcabc" + lcs := e.forwardlcs(df-1, u-1-v) + lcs = append(lcs, e.backwardlcs(db, kb)...) + return lcs.sort() + } + if v > 0 && ok(df-1, (u-(v-1))) && e.vf.get(df-1, u-(v-1)) == u { + // "abaabb" "bcacab" + lcs := e.forwardlcs(df-1, u-(v-1)) + lcs = append(lcs, e.backwardlcs(db, kb)...) + return lcs.sort() + } + + // The path can't possibly contribute to the lcs because it + // is all horizontal or vertical edges + if u == 0 || v == 0 || x == e.ux || y == e.uy { + // "abaabb" "abaaaa" + if u == 0 || v == 0 { + return e.backwardlcs(db, kb) + } + return e.forwardlcs(df, kf) + } + + // is (x+1,y) or (x,y+1) labelled db-1? + if x+1 <= e.ux && ok(db-1, x+1-y-e.delta) && e.vb.get(db-1, x+1-y-e.delta) == x+1 { + // "bababb" "baaabb" + lcs := e.backwardlcs(db-1, kb+1) + lcs = append(lcs, e.forwardlcs(df, kf)...) + return lcs.sort() + } + if y+1 <= e.uy && ok(db-1, x-(y+1)-e.delta) && e.vb.get(db-1, x-(y+1)-e.delta) == x { + // "abbbaa" "cabacc" + lcs := e.backwardlcs(db-1, kb-1) + lcs = append(lcs, e.forwardlcs(df, kf)...) + return lcs.sort() + } + + // need to compute another path + // "aabbaa" "aacaba" + lcs := e.backwardlcs(db, kb) + oldx, oldy := e.ux, e.uy + e.ux = u + e.uy = v + lcs = append(lcs, forward(e)...) + e.ux, e.uy = oldx, oldy + return lcs.sort() +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/lcs/sequence.go b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/lcs/sequence.go new file mode 100644 index 000000000..2d72d2630 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/lcs/sequence.go @@ -0,0 +1,113 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package lcs + +// This file defines the abstract sequence over which the LCS algorithm operates. + +// sequences abstracts a pair of sequences, A and B. +type sequences interface { + lengths() (int, int) // len(A), len(B) + commonPrefixLen(ai, aj, bi, bj int) int // len(commonPrefix(A[ai:aj], B[bi:bj])) + commonSuffixLen(ai, aj, bi, bj int) int // len(commonSuffix(A[ai:aj], B[bi:bj])) +} + +type stringSeqs struct{ a, b string } + +func (s stringSeqs) lengths() (int, int) { return len(s.a), len(s.b) } +func (s stringSeqs) commonPrefixLen(ai, aj, bi, bj int) int { + return commonPrefixLenString(s.a[ai:aj], s.b[bi:bj]) +} +func (s stringSeqs) commonSuffixLen(ai, aj, bi, bj int) int { + return commonSuffixLenString(s.a[ai:aj], s.b[bi:bj]) +} + +// The explicit capacity in s[i:j:j] leads to more efficient code. + +type bytesSeqs struct{ a, b []byte } + +func (s bytesSeqs) lengths() (int, int) { return len(s.a), len(s.b) } +func (s bytesSeqs) commonPrefixLen(ai, aj, bi, bj int) int { + return commonPrefixLenBytes(s.a[ai:aj:aj], s.b[bi:bj:bj]) +} +func (s bytesSeqs) commonSuffixLen(ai, aj, bi, bj int) int { + return commonSuffixLenBytes(s.a[ai:aj:aj], s.b[bi:bj:bj]) +} + +type runesSeqs struct{ a, b []rune } + +func (s runesSeqs) lengths() (int, int) { return len(s.a), len(s.b) } +func (s runesSeqs) commonPrefixLen(ai, aj, bi, bj int) int { + return commonPrefixLenRunes(s.a[ai:aj:aj], s.b[bi:bj:bj]) +} +func (s runesSeqs) commonSuffixLen(ai, aj, bi, bj int) int { + return commonSuffixLenRunes(s.a[ai:aj:aj], s.b[bi:bj:bj]) +} + +// TODO(adonovan): optimize these functions using ideas from: +// - https://go.dev/cl/408116 common.go +// - https://go.dev/cl/421435 xor_generic.go + +// TODO(adonovan): factor using generics when available, +// but measure performance impact. + +// commonPrefixLen* returns the length of the common prefix of a[ai:aj] and b[bi:bj]. +func commonPrefixLenBytes(a, b []byte) int { + n := min(len(a), len(b)) + i := 0 + for i < n && a[i] == b[i] { + i++ + } + return i +} +func commonPrefixLenRunes(a, b []rune) int { + n := min(len(a), len(b)) + i := 0 + for i < n && a[i] == b[i] { + i++ + } + return i +} +func commonPrefixLenString(a, b string) int { + n := min(len(a), len(b)) + i := 0 + for i < n && a[i] == b[i] { + i++ + } + return i +} + +// commonSuffixLen* returns the length of the common suffix of a[ai:aj] and b[bi:bj]. +func commonSuffixLenBytes(a, b []byte) int { + n := min(len(a), len(b)) + i := 0 + for i < n && a[len(a)-1-i] == b[len(b)-1-i] { + i++ + } + return i +} +func commonSuffixLenRunes(a, b []rune) int { + n := min(len(a), len(b)) + i := 0 + for i < n && a[len(a)-1-i] == b[len(b)-1-i] { + i++ + } + return i +} +func commonSuffixLenString(a, b string) int { + n := min(len(a), len(b)) + i := 0 + for i < n && a[len(a)-1-i] == b[len(b)-1-i] { + i++ + } + return i +} + +func min(x, y int) int { + if x < y { + return x + } else { + return y + } +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/ndiff.go b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/ndiff.go new file mode 100644 index 000000000..1c64d1ecd --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/ndiff.go @@ -0,0 +1,99 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package diff + +import ( + "bytes" + "unicode/utf8" + + "github.com/golangci/golangci-lint/v2/internal/x/tools/diff/lcs" +) + +// Strings computes the differences between two strings. +// The resulting edits respect rune boundaries. +func Strings(before, after string) []Edit { + if before == after { + return nil // common case + } + + if isASCII(before) && isASCII(after) { + // TODO(adonovan): opt: specialize diffASCII for strings. + return diffASCII([]byte(before), []byte(after)) + } + return diffRunes([]rune(before), []rune(after)) +} + +// Bytes computes the differences between two byte slices. +// The resulting edits respect rune boundaries. +func Bytes(before, after []byte) []Edit { + if bytes.Equal(before, after) { + return nil // common case + } + + if isASCII(before) && isASCII(after) { + return diffASCII(before, after) + } + return diffRunes(runes(before), runes(after)) +} + +func diffASCII(before, after []byte) []Edit { + diffs := lcs.DiffBytes(before, after) + + // Convert from LCS diffs. + res := make([]Edit, len(diffs)) + for i, d := range diffs { + res[i] = Edit{d.Start, d.End, string(after[d.ReplStart:d.ReplEnd])} + } + return res +} + +func diffRunes(before, after []rune) []Edit { + diffs := lcs.DiffRunes(before, after) + + // The diffs returned by the lcs package use indexes + // into whatever slice was passed in. + // Convert rune offsets to byte offsets. + res := make([]Edit, len(diffs)) + lastEnd := 0 + utf8Len := 0 + for i, d := range diffs { + utf8Len += runesLen(before[lastEnd:d.Start]) // text between edits + start := utf8Len + utf8Len += runesLen(before[d.Start:d.End]) // text deleted by this edit + res[i] = Edit{start, utf8Len, string(after[d.ReplStart:d.ReplEnd])} + lastEnd = d.End + } + return res +} + +// runes is like []rune(string(bytes)) without the duplicate allocation. +func runes(bytes []byte) []rune { + n := utf8.RuneCount(bytes) + runes := make([]rune, n) + for i := range n { + r, sz := utf8.DecodeRune(bytes) + bytes = bytes[sz:] + runes[i] = r + } + return runes +} + +// runesLen returns the length in bytes of the UTF-8 encoding of runes. +func runesLen(runes []rune) (len int) { + for _, r := range runes { + len += utf8.RuneLen(r) + } + return len +} + +// isASCII reports whether s contains only ASCII. +func isASCII[S string | []byte](s S) bool { + for i := 0; i < len(s); i++ { + if s[i] >= utf8.RuneSelf { + return false + } + } + return true +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/readme.md b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/readme.md new file mode 100644 index 000000000..b28e41d9c --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/readme.md @@ -0,0 +1,11 @@ +# diff + +Extracted from `/internal/diff/` (related to `fixer`). +This is just a copy of the code without any changes. + +## History + +- https://github.com/golangci/golangci-lint/pull/6076 + - sync with https://github.com/golang/tools/blob/v0.37.0/internal/diff/ +- https://github.com/golangci/golangci-lint/pull/5576 + - sync with https://github.com/golang/tools/blob/v0.28.0/internal/diff/ diff --git a/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/unified.go b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/unified.go new file mode 100644 index 000000000..9a786dbbe --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/internal/x/tools/diff/unified.go @@ -0,0 +1,251 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package diff + +import ( + "fmt" + "log" + "strings" +) + +// DefaultContextLines is the number of unchanged lines of surrounding +// context displayed by Unified. Use ToUnified to specify a different value. +const DefaultContextLines = 3 + +// Unified returns a unified diff of the old and new strings. +// The old and new labels are the names of the old and new files. +// If the strings are equal, it returns the empty string. +func Unified(oldLabel, newLabel, old, new string) string { + edits := Strings(old, new) + unified, err := ToUnified(oldLabel, newLabel, old, edits, DefaultContextLines) + if err != nil { + // Can't happen: edits are consistent. + log.Fatalf("internal error in diff.Unified: %v", err) + } + return unified +} + +// ToUnified applies the edits to content and returns a unified diff, +// with contextLines lines of (unchanged) context around each diff hunk. +// The old and new labels are the names of the content and result files. +// It returns an error if the edits are inconsistent; see ApplyEdits. +func ToUnified(oldLabel, newLabel, content string, edits []Edit, contextLines int) (string, error) { + u, err := toUnified(oldLabel, newLabel, content, edits, contextLines) + if err != nil { + return "", err + } + return u.String(), nil +} + +// unified represents a set of edits as a unified diff. +type unified struct { + // from is the name of the original file. + from string + // to is the name of the modified file. + to string + // hunks is the set of edit hunks needed to transform the file content. + hunks []*hunk +} + +// Hunk represents a contiguous set of line edits to apply. +type hunk struct { + // The line in the original source where the hunk starts. + fromLine int + // The line in the original source where the hunk finishes. + toLine int + // The set of line based edits to apply. + lines []line +} + +// Line represents a single line operation to apply as part of a Hunk. +type line struct { + // kind is the type of line this represents, deletion, insertion or copy. + kind opKind + // content is the content of this line. + // For deletion it is the line being removed, for all others it is the line + // to put in the output. + content string +} + +// opKind is used to denote the type of operation a line represents. +type opKind int + +const ( + // opDelete is the operation kind for a line that is present in the input + // but not in the output. + opDelete opKind = iota + // opInsert is the operation kind for a line that is new in the output. + opInsert + // opEqual is the operation kind for a line that is the same in the input and + // output, often used to provide context around edited lines. + opEqual +) + +// String returns a human readable representation of an OpKind. It is not +// intended for machine processing. +func (k opKind) String() string { + switch k { + case opDelete: + return "delete" + case opInsert: + return "insert" + case opEqual: + return "equal" + default: + panic("unknown operation kind") + } +} + +// toUnified takes a file contents and a sequence of edits, and calculates +// a unified diff that represents those edits. +func toUnified(fromName, toName string, content string, edits []Edit, contextLines int) (unified, error) { + gap := contextLines * 2 + u := unified{ + from: fromName, + to: toName, + } + if len(edits) == 0 { + return u, nil + } + var err error + edits, err = lineEdits(content, edits) // expand to whole lines + if err != nil { + return u, err + } + lines := splitLines(content) + var h *hunk + last := 0 + toLine := 0 + for _, edit := range edits { + // Compute the zero-based line numbers of the edit start and end. + // TODO(adonovan): opt: compute incrementally, avoid O(n^2). + start := strings.Count(content[:edit.Start], "\n") + end := strings.Count(content[:edit.End], "\n") + if edit.End == len(content) && len(content) > 0 && content[len(content)-1] != '\n' { + end++ // EOF counts as an implicit newline + } + + switch { + case h != nil && start == last: + // direct extension + case h != nil && start <= last+gap: + // within range of previous lines, add the joiners + addEqualLines(h, lines, last, start) + default: + // need to start a new hunk + if h != nil { + // add the edge to the previous hunk + addEqualLines(h, lines, last, last+contextLines) + u.hunks = append(u.hunks, h) + } + toLine += start - last + h = &hunk{ + fromLine: start + 1, + toLine: toLine + 1, + } + // add the edge to the new hunk + delta := addEqualLines(h, lines, start-contextLines, start) + h.fromLine -= delta + h.toLine -= delta + } + last = start + for i := start; i < end; i++ { + h.lines = append(h.lines, line{kind: opDelete, content: lines[i]}) + last++ + } + if edit.New != "" { + for _, content := range splitLines(edit.New) { + h.lines = append(h.lines, line{kind: opInsert, content: content}) + toLine++ + } + } + } + if h != nil { + // add the edge to the final hunk + addEqualLines(h, lines, last, last+contextLines) + u.hunks = append(u.hunks, h) + } + return u, nil +} + +func splitLines(text string) []string { + lines := strings.SplitAfter(text, "\n") + if lines[len(lines)-1] == "" { + lines = lines[:len(lines)-1] + } + return lines +} + +func addEqualLines(h *hunk, lines []string, start, end int) int { + delta := 0 + for i := start; i < end; i++ { + if i < 0 { + continue + } + if i >= len(lines) { + return delta + } + h.lines = append(h.lines, line{kind: opEqual, content: lines[i]}) + delta++ + } + return delta +} + +// String converts a unified diff to the standard textual form for that diff. +// The output of this function can be passed to tools like patch. +func (u unified) String() string { + if len(u.hunks) == 0 { + return "" + } + b := new(strings.Builder) + fmt.Fprintf(b, "--- %s\n", u.from) + fmt.Fprintf(b, "+++ %s\n", u.to) + for _, hunk := range u.hunks { + fromCount, toCount := 0, 0 + for _, l := range hunk.lines { + switch l.kind { + case opDelete: + fromCount++ + case opInsert: + toCount++ + default: + fromCount++ + toCount++ + } + } + fmt.Fprint(b, "@@") + if fromCount > 1 { + fmt.Fprintf(b, " -%d,%d", hunk.fromLine, fromCount) + } else if hunk.fromLine == 1 && fromCount == 0 { + // Match odd GNU diff -u behavior adding to empty file. + fmt.Fprintf(b, " -0,0") + } else { + fmt.Fprintf(b, " -%d", hunk.fromLine) + } + if toCount > 1 { + fmt.Fprintf(b, " +%d,%d", hunk.toLine, toCount) + } else if hunk.toLine == 1 && toCount == 0 { + // Match odd GNU diff -u behavior adding to empty file. + fmt.Fprintf(b, " +0,0") + } else { + fmt.Fprintf(b, " +%d", hunk.toLine) + } + fmt.Fprint(b, " @@\n") + for _, l := range hunk.lines { + switch l.kind { + case opDelete: + fmt.Fprintf(b, "-%s", l.content) + case opInsert: + fmt.Fprintf(b, "+%s", l.content) + default: + fmt.Fprintf(b, " %s", l.content) + } + if !strings.HasSuffix(l.content, "\n") { + fmt.Fprintf(b, "\n\\ No newline at end of file\n") + } + } + } + return b.String() +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/commands/cache.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/cache.go similarity index 89% rename from vendor/github.com/golangci/golangci-lint/pkg/commands/cache.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/commands/cache.go index 4f2c812dc..9772841c9 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/commands/cache.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/cache.go @@ -7,9 +7,9 @@ import ( "github.com/spf13/cobra" - "github.com/golangci/golangci-lint/internal/cache" - "github.com/golangci/golangci-lint/pkg/fsutils" - "github.com/golangci/golangci-lint/pkg/logutils" + "github.com/golangci/golangci-lint/v2/internal/cache" + "github.com/golangci/golangci-lint/v2/pkg/fsutils" + "github.com/golangci/golangci-lint/v2/pkg/logutils" ) type cacheCommand struct { @@ -21,7 +21,7 @@ func newCacheCommand() *cacheCommand { cacheCmd := &cobra.Command{ Use: "cache", - Short: "Cache control and information", + Short: "Cache control and information.", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { return cmd.Help() diff --git a/vendor/github.com/golangci/golangci-lint/pkg/commands/config.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/config.go similarity index 66% rename from vendor/github.com/golangci/golangci-lint/pkg/commands/config.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/commands/config.go index 935ec5e86..b1889fa42 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/commands/config.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/config.go @@ -1,25 +1,32 @@ package commands import ( + "encoding/json" "fmt" "os" + "path/filepath" "github.com/fatih/color" "github.com/spf13/cobra" "github.com/spf13/viper" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/exitcodes" - "github.com/golangci/golangci-lint/pkg/fsutils" - "github.com/golangci/golangci-lint/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/exitcodes" + "github.com/golangci/golangci-lint/v2/pkg/fsutils" + "github.com/golangci/golangci-lint/v2/pkg/logutils" ) +type pathOptions struct { + JSON bool +} + type configCommand struct { viper *viper.Viper cmd *cobra.Command opts config.LoaderOptions verifyOpts verifyOptions + pathOpts pathOptions buildInfo BuildInfo @@ -35,7 +42,7 @@ func newConfigCommand(log logutils.Log, info BuildInfo) *configCommand { configCmd := &cobra.Command{ Use: "config", - Short: "Config file information", + Short: "Configuration file information and verification.", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { return cmd.Help() @@ -45,7 +52,7 @@ func newConfigCommand(log logutils.Log, info BuildInfo) *configCommand { verifyCommand := &cobra.Command{ Use: "verify", - Short: "Verify configuration against JSON schema", + Short: "Verify configuration against JSON schema.", Args: cobra.NoArgs, ValidArgsFunction: cobra.NoFileCompletions, RunE: c.executeVerify, @@ -53,14 +60,16 @@ func newConfigCommand(log logutils.Log, info BuildInfo) *configCommand { SilenceErrors: true, } + pathCommand := &cobra.Command{ + Use: "path", + Short: "Print used configuration path.", + Args: cobra.NoArgs, + ValidArgsFunction: cobra.NoFileCompletions, + RunE: c.executePath, + } + configCmd.AddCommand( - &cobra.Command{ - Use: "path", - Short: "Print used config path", - Args: cobra.NoArgs, - ValidArgsFunction: cobra.NoFileCompletions, - Run: c.executePath, - }, + pathCommand, verifyCommand, ) @@ -74,6 +83,9 @@ func newConfigCommand(log logutils.Log, info BuildInfo) *configCommand { verifyFlagSet.StringVar(&c.verifyOpts.schemaURL, "schema", "", color.GreenString("JSON schema URL")) _ = verifyFlagSet.MarkHidden("schema") + pathFlagSet := pathCommand.Flags() + pathFlagSet.BoolVar(&c.pathOpts.JSON, "json", false, color.GreenString("Display as JSON")) + c.cmd = configCmd return c @@ -84,7 +96,7 @@ func (c *configCommand) preRunE(cmd *cobra.Command, args []string) error { // It only needs to know the path of the configuration file. cfg := config.NewDefault() - loader := config.NewLoader(c.log.Child(logutils.DebugKeyConfigReader), c.viper, cmd.Flags(), c.opts, cfg, args) + loader := config.NewLintersLoader(c.log.Child(logutils.DebugKeyConfigReader), c.viper, cmd.Flags(), c.opts, cfg, args) err := loader.Load(config.LoadOptions{}) if err != nil { @@ -94,14 +106,29 @@ func (c *configCommand) preRunE(cmd *cobra.Command, args []string) error { return nil } -func (c *configCommand) executePath(cmd *cobra.Command, _ []string) { +func (c *configCommand) executePath(cmd *cobra.Command, _ []string) error { usedConfigFile := c.getUsedConfig() + + if c.pathOpts.JSON { + abs, err := filepath.Abs(usedConfigFile) + if err != nil { + return err + } + + return json.NewEncoder(cmd.OutOrStdout()).Encode(map[string]string{ + "path": usedConfigFile, + "absolutePath": abs, + }) + } + if usedConfigFile == "" { c.log.Warnf("No config file detected") os.Exit(exitcodes.NoConfigFileDetected) } cmd.Println(usedConfigFile) + + return nil } // getUsedConfig returns the resolved path to the golangci config file, diff --git a/vendor/github.com/golangci/golangci-lint/pkg/commands/config_verify.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/config_verify.go similarity index 55% rename from vendor/github.com/golangci/golangci-lint/pkg/commands/config_verify.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/commands/config_verify.go index 89017e9bf..7281e0888 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/commands/config_verify.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/config_verify.go @@ -1,23 +1,25 @@ package commands import ( + "context" + "encoding/json" "errors" "fmt" "net/http" "os" "path/filepath" + "strconv" "strings" "time" hcversion "github.com/hashicorp/go-version" "github.com/pelletier/go-toml/v2" - "github.com/santhosh-tekuri/jsonschema/v5" - "github.com/santhosh-tekuri/jsonschema/v5/httploader" + "github.com/santhosh-tekuri/jsonschema/v6" "github.com/spf13/cobra" "github.com/spf13/pflag" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" - "github.com/golangci/golangci-lint/pkg/exitcodes" + "github.com/golangci/golangci-lint/v2/pkg/exitcodes" ) type verifyOptions struct { @@ -36,6 +38,8 @@ func (c *configCommand) executeVerify(cmd *cobra.Command, _ []string) error { return fmt.Errorf("get JSON schema: %w", err) } + c.log.Infof("Verifying the configuration file %q with the JSON Schema from %s", usedConfigFile, schemaURL) + err = validateConfiguration(schemaURL, usedConfigFile) if err != nil { var v *jsonschema.ValidationError @@ -43,9 +47,7 @@ func (c *configCommand) executeVerify(cmd *cobra.Command, _ []string) error { return fmt.Errorf("[%s] validate: %w", usedConfigFile, err) } - detail := v.DetailedOutput() - - printValidationDetail(cmd, &detail) + printValidationDetail(cmd, v.DetailedOutput()) return errors.New("the configuration contains invalid elements") } @@ -70,40 +72,67 @@ func createSchemaURL(flags *pflag.FlagSet, buildInfo BuildInfo) (string, error) return "", fmt.Errorf("parse version: %w", err) } - schemaURL = fmt.Sprintf("https://golangci-lint.run/jsonschema/golangci.v%d.%d.jsonschema.json", - version.Segments()[0], version.Segments()[1]) + if version.Core().Equal(hcversion.Must(hcversion.NewVersion("v0.0.0"))) { + commit, err := extractCommitHash(buildInfo) + if err != nil { + return "", err + } - case buildInfo.Commit != "" && buildInfo.Commit != "?": - if buildInfo.Commit == "unknown" { - return "", errors.New("unknown commit information") + return fmt.Sprintf("https://raw.githubusercontent.com/golangci/golangci-lint/%s/jsonschema/golangci.next.jsonschema.json", + commit), nil } - commit := buildInfo.Commit - - if strings.HasPrefix(commit, "(") { - c, _, ok := strings.Cut(strings.TrimPrefix(commit, "("), ",") - if !ok { - return "", errors.New("commit information not found") - } + return fmt.Sprintf("https://golangci-lint.run/jsonschema/golangci.v%d.%d.jsonschema.json", + version.Segments()[0], version.Segments()[1]), nil - commit = c + case buildInfo.Commit != "" && buildInfo.Commit != "?": + commit, err := extractCommitHash(buildInfo) + if err != nil { + return "", err } - schemaURL = fmt.Sprintf("https://raw.githubusercontent.com/golangci/golangci-lint/%s/jsonschema/golangci.next.jsonschema.json", - commit) + return fmt.Sprintf("https://raw.githubusercontent.com/golangci/golangci-lint/%s/jsonschema/golangci.next.jsonschema.json", + commit), nil default: return "", errors.New("version not found") } +} - return schemaURL, nil +func extractCommitHash(buildInfo BuildInfo) (string, error) { + if buildInfo.Commit == "" || buildInfo.Commit == "?" { + return "", errors.New("empty commit information") + } + + if buildInfo.Commit == "unknown" { + return "", errors.New("unknown commit information") + } + + commit := buildInfo.Commit + + if after, ok := strings.CutPrefix(commit, "("); ok { + c, _, ok := strings.Cut(after, ",") + if !ok { + return "", errors.New("commit information not found") + } + + commit = c + } + + if commit == "unknown" { + return "", errors.New("unknown commit information") + } + + return commit, nil } func validateConfiguration(schemaPath, targetFile string) error { - httploader.Client = &http.Client{Timeout: 2 * time.Second} - compiler := jsonschema.NewCompiler() - compiler.Draft = jsonschema.Draft7 + compiler.UseLoader(jsonschema.SchemeURLLoader{ + "file": jsonschema.FileLoader{}, + "https": newJSONSchemaHTTPLoader(), + }) + compiler.DefaultDraft(jsonschema.Draft7) schema, err := compiler.Compile(schemaPath) if err != nil { @@ -133,10 +162,13 @@ func validateConfiguration(schemaPath, targetFile string) error { return schema.Validate(m) } -func printValidationDetail(cmd *cobra.Command, detail *jsonschema.Detailed) { - if detail.Error != "" { +func printValidationDetail(cmd *cobra.Command, detail *jsonschema.OutputUnit) { + if detail.Error != nil { + data, _ := json.Marshal(detail.Error) + details, _ := strconv.Unquote(string(data)) + cmd.PrintErrf("jsonschema: %q does not validate with %q: %s\n", - strings.ReplaceAll(strings.TrimPrefix(detail.InstanceLocation, "/"), "/", "."), detail.KeywordLocation, detail.Error) + strings.ReplaceAll(strings.TrimPrefix(detail.InstanceLocation, "/"), "/", "."), detail.KeywordLocation, details) } for _, d := range detail.Errors { @@ -177,3 +209,33 @@ func decodeTomlFile(filename string) (any, error) { return m, nil } + +type jsonschemaHTTPLoader struct { + *http.Client +} + +func newJSONSchemaHTTPLoader() *jsonschemaHTTPLoader { + return &jsonschemaHTTPLoader{Client: &http.Client{ + Timeout: 2 * time.Second, + }} +} + +func (l jsonschemaHTTPLoader) Load(url string) (any, error) { + req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, url, http.NoBody) + if err != nil { + return nil, err + } + + resp, err := l.Do(req) + if err != nil { + return nil, err + } + + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%s returned status code %d", url, resp.StatusCode) + } + + return jsonschema.UnmarshalJSON(resp.Body) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/commands/custom.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/custom.go similarity index 60% rename from vendor/github.com/golangci/golangci-lint/pkg/commands/custom.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/commands/custom.go index 1bc9f9014..e6a7f5ed7 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/commands/custom.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/custom.go @@ -5,19 +5,28 @@ import ( "log" "os" + "github.com/fatih/color" "github.com/spf13/cobra" - "github.com/golangci/golangci-lint/pkg/commands/internal" - "github.com/golangci/golangci-lint/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/commands/internal" + "github.com/golangci/golangci-lint/v2/pkg/logutils" ) const envKeepTempFiles = "CUSTOM_GCL_KEEP_TEMP_FILES" +type customOptions struct { + version string + name string + destination string +} + type customCommand struct { cmd *cobra.Command cfg *internal.Configuration + opts customOptions + log logutils.Log } @@ -26,13 +35,20 @@ func newCustomCommand(logger logutils.Log) *customCommand { customCmd := &cobra.Command{ Use: "custom", - Short: "Build a version of golangci-lint with custom linters", + Short: "Build a version of golangci-lint with custom linters.", Args: cobra.NoArgs, PreRunE: c.preRunE, RunE: c.runE, SilenceUsage: true, } + flagSet := customCmd.PersistentFlags() + flagSet.SortFlags = false // sort them as they are defined here + + flagSet.StringVar(&c.opts.version, "version", "", color.GreenString("The golangci-lint version used to build the custom binary")) + flagSet.StringVar(&c.opts.name, "name", "", color.GreenString("The name of the custom binary")) + flagSet.StringVar(&c.opts.destination, "destination", "", color.GreenString("The directory path used to store the custom binary")) + c.cmd = customCmd return c @@ -44,6 +60,18 @@ func (c *customCommand) preRunE(_ *cobra.Command, _ []string) error { return err } + if c.opts.version != "" { + cfg.Version = c.opts.version + } + + if c.opts.name != "" { + cfg.Name = c.opts.name + } + + if c.opts.destination != "" { + cfg.Destination = c.opts.destination + } + err = cfg.Validate() if err != nil { return err diff --git a/vendor/github.com/golangci/golangci-lint/pkg/commands/flagsets.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/flagsets.go similarity index 50% rename from vendor/github.com/golangci/golangci-lint/pkg/commands/flagsets.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/commands/flagsets.go index 608f6b9de..2b61217c6 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/commands/flagsets.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/flagsets.go @@ -1,62 +1,54 @@ package commands import ( - "fmt" - "strings" - "github.com/fatih/color" "github.com/spf13/pflag" "github.com/spf13/viper" - "github.com/golangci/golangci-lint/pkg/commands/internal" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/exitcodes" - "github.com/golangci/golangci-lint/pkg/lint/lintersdb" - "github.com/golangci/golangci-lint/pkg/result/processors" + "github.com/golangci/golangci-lint/v2/pkg/commands/internal" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/exitcodes" ) const defaultMaxIssuesPerLinter = 50 func setupLintersFlagSet(v *viper.Viper, fs *pflag.FlagSet) { - internal.AddHackedStringSliceP(fs, "disable", "D", color.GreenString("Disable specific linter")) - internal.AddFlagAndBind(v, fs, fs.Bool, "disable-all", "linters.disable-all", false, color.GreenString("Disable all linters")) + internal.AddFlagAndBind(v, fs, fs.String, "default", "linters.default", config.GroupStandard, + color.GreenString("Default set of linters to enable")) + internal.AddHackedStringSliceP(fs, "disable", "D", color.GreenString("Disable specific linter")) internal.AddHackedStringSliceP(fs, "enable", "E", color.GreenString("Enable specific linter")) - internal.AddFlagAndBind(v, fs, fs.Bool, "enable-all", "linters.enable-all", false, color.GreenString("Enable all linters")) - - internal.AddFlagAndBind(v, fs, fs.Bool, "fast", "linters.fast", false, - color.GreenString("Enable only fast linters from enabled linters set (first run won't be fast)")) - - internal.AddHackedStringSliceP(fs, "presets", "p", - color.GreenString(fmt.Sprintf("Enable presets (%s) of linters.\n"+ - "Run 'golangci-lint help linters' to see them.\n"+ - "This option implies option --disable-all", - strings.Join(lintersdb.AllPresets(), "|"), - ))) fs.StringSlice("enable-only", nil, color.GreenString("Override linters configuration section to only run the specific linter(s)")) // Flags only. + + internal.AddFlagAndBind(v, fs, fs.Bool, "fast-only", "linters.fast-only", false, + color.GreenString("Filter enabled linters to run only fast linters")) +} + +func setupFormattersFlagSet(v *viper.Viper, fs *pflag.FlagSet) { + internal.AddFlagAndBindP(v, fs, fs.StringSliceP, "enable", "E", "formatters.enable", nil, + color.GreenString("Enable specific formatter")) } func setupRunFlagSet(v *viper.Viper, fs *pflag.FlagSet) { - internal.AddFlagAndBindP(v, fs, fs.IntP, "concurrency", "j", "run.concurrency", getDefaultConcurrency(), - color.GreenString("Number of CPUs to use (Default: number of logical CPUs)")) + internal.AddFlagAndBindP(v, fs, fs.IntP, "concurrency", "j", "run.concurrency", 0, + color.GreenString("Number of CPUs to use (Default: Automatically set to match Linux container CPU quota"+ + " and fall back to the number of logical CPUs in the machine)")) internal.AddFlagAndBind(v, fs, fs.String, "modules-download-mode", "run.modules-download-mode", "", color.GreenString("Modules download mode. If not empty, passed as -mod= to go tools")) internal.AddFlagAndBind(v, fs, fs.Int, "issues-exit-code", "run.issues-exit-code", exitcodes.IssuesFound, color.GreenString("Exit code when issues were found")) - internal.AddFlagAndBind(v, fs, fs.String, "go", "run.go", "", color.GreenString("Targeted Go version")) internal.AddHackedStringSlice(fs, "build-tags", color.GreenString("Build tags")) - internal.AddFlagAndBind(v, fs, fs.Duration, "timeout", "run.timeout", defaultTimeout, color.GreenString("Timeout for total work")) + internal.AddFlagAndBind(v, fs, fs.Duration, "timeout", "run.timeout", defaultTimeout, + color.GreenString("Timeout for total work. Disabled by default")) internal.AddFlagAndBind(v, fs, fs.Bool, "tests", "run.tests", true, color.GreenString("Analyze tests (*_test.go)")) internal.AddDeprecatedHackedStringSlice(fs, "skip-files", color.GreenString("Regexps of files to skip")) internal.AddDeprecatedHackedStringSlice(fs, "skip-dirs", color.GreenString("Regexps of directories to skip")) - internal.AddDeprecatedFlagAndBind(v, fs, fs.Bool, "skip-dirs-use-default", "run.skip-dirs-use-default", true, - getDefaultDirectoryExcludeHelp()) const allowParallelDesc = "Allow multiple parallel golangci-lint instances running.\n" + "If false (default) - golangci-lint acquires file lock on start." @@ -68,43 +60,67 @@ func setupRunFlagSet(v *viper.Viper, fs *pflag.FlagSet) { } func setupOutputFlagSet(v *viper.Viper, fs *pflag.FlagSet) { - internal.AddFlagAndBind(v, fs, fs.String, "out-format", "output.formats", config.OutFormatColoredLineNumber, - color.GreenString(fmt.Sprintf("Formats of output: %s", strings.Join(config.AllOutputFormats, "|")))) - internal.AddFlagAndBind(v, fs, fs.Bool, "print-issued-lines", "output.print-issued-lines", true, - color.GreenString("Print lines of code with issue")) - internal.AddFlagAndBind(v, fs, fs.Bool, "print-linter-name", "output.print-linter-name", true, - color.GreenString("Print linter name in issue line")) - internal.AddFlagAndBind(v, fs, fs.Bool, "uniq-by-line", "output.uniq-by-line", true, - color.GreenString("Make issues output unique by line")) - internal.AddFlagAndBind(v, fs, fs.Bool, "sort-results", "output.sort-results", false, - color.GreenString("Sort linter results")) - internal.AddFlagAndBind(v, fs, fs.StringSlice, "sort-order", "output.sort-order", nil, - color.GreenString("Sort order of linter results")) internal.AddFlagAndBind(v, fs, fs.String, "path-prefix", "output.path-prefix", "", color.GreenString("Path prefix to add to output")) - internal.AddFlagAndBind(v, fs, fs.Bool, "show-stats", "output.show-stats", false, color.GreenString("Show statistics per linter")) + internal.AddFlagAndBind(v, fs, fs.String, "path-mode", "output.path-mode", "", + color.GreenString("Path mode to use (empty, or 'abs')")) + internal.AddFlagAndBind(v, fs, fs.Bool, "show-stats", "output.show-stats", true, color.GreenString("Show statistics per linter")) + + setupOutputFormatsFlagSet(v, fs) } -//nolint:gomnd // magic numbers here is ok -func setupIssuesFlagSet(v *viper.Viper, fs *pflag.FlagSet) { - internal.AddHackedStringSliceP(fs, "exclude", "e", color.GreenString("Exclude issue by regexp")) - internal.AddFlagAndBind(v, fs, fs.Bool, "exclude-use-default", "issues.exclude-use-default", true, - getDefaultIssueExcludeHelp()) - internal.AddFlagAndBind(v, fs, fs.Bool, "exclude-case-sensitive", "issues.exclude-case-sensitive", false, - color.GreenString("If set to true exclude and exclude rules regular expressions are case-sensitive")) +func setupOutputFormatsFlagSet(v *viper.Viper, fs *pflag.FlagSet) { + outputPathDesc := "Output path can be either `stdout`, `stderr` or path to the file to write to." + printLinterNameDesc := "Print linter name in the end of issue text." + colorsDesc := "Use colors." + + internal.AddFlagAndBind(v, fs, fs.String, "output.text.path", "output.formats.text.path", "", + color.GreenString(outputPathDesc)) + internal.AddFlagAndBind(v, fs, fs.Bool, "output.text.print-linter-name", "output.formats.text.print-linter-name", true, + color.GreenString(printLinterNameDesc)) + internal.AddFlagAndBind(v, fs, fs.Bool, "output.text.print-issued-lines", "output.formats.text.print-issued-lines", true, + color.GreenString("Print lines of code with issue.")) + internal.AddFlagAndBind(v, fs, fs.Bool, "output.text.colors", "output.formats.text.colors", true, + color.GreenString(colorsDesc)) + + internal.AddFlagAndBind(v, fs, fs.String, "output.json.path", "output.formats.json.path", "", + color.GreenString(outputPathDesc)) + + internal.AddFlagAndBind(v, fs, fs.String, "output.tab.path", "output.formats.tab.path", "", + color.GreenString(outputPathDesc)) + internal.AddFlagAndBind(v, fs, fs.Bool, "output.tab.print-linter-name", "output.formats.tab.print-linter-name", + true, color.GreenString(printLinterNameDesc)) + internal.AddFlagAndBind(v, fs, fs.Bool, "output.tab.colors", "output.formats.tab.colors", true, + color.GreenString(colorsDesc)) + + internal.AddFlagAndBind(v, fs, fs.String, "output.html.path", "output.formats.html.path", "", + color.GreenString(outputPathDesc)) + + internal.AddFlagAndBind(v, fs, fs.String, "output.checkstyle.path", "output.formats.checkstyle.path", "", + color.GreenString(outputPathDesc)) + + internal.AddFlagAndBind(v, fs, fs.String, "output.code-climate.path", "output.formats.code-climate.path", "", + color.GreenString(outputPathDesc)) + + internal.AddFlagAndBind(v, fs, fs.String, "output.junit-xml.path", "output.formats.junit-xml.path", "", + color.GreenString(outputPathDesc)) + internal.AddFlagAndBind(v, fs, fs.Bool, "output.junit-xml.extended", "output.formats.junit-xml.extended", false, + color.GreenString("Support extra JUnit XML fields.")) + + internal.AddFlagAndBind(v, fs, fs.String, "output.teamcity.path", "output.formats.teamcity.path", "", + color.GreenString(outputPathDesc)) + + internal.AddFlagAndBind(v, fs, fs.String, "output.sarif.path", "output.formats.sarif.path", "", + color.GreenString(outputPathDesc)) +} +func setupIssuesFlagSet(v *viper.Viper, fs *pflag.FlagSet) { internal.AddFlagAndBind(v, fs, fs.Int, "max-issues-per-linter", "issues.max-issues-per-linter", defaultMaxIssuesPerLinter, color.GreenString("Maximum issues count per one linter. Set to 0 to disable")) internal.AddFlagAndBind(v, fs, fs.Int, "max-same-issues", "issues.max-same-issues", 3, color.GreenString("Maximum count of issues with the same text. Set to 0 to disable")) - - internal.AddHackedStringSlice(fs, "exclude-files", color.GreenString("Regexps of files to exclude")) - internal.AddHackedStringSlice(fs, "exclude-dirs", color.GreenString("Regexps of directories to exclude")) - internal.AddFlagAndBind(v, fs, fs.Bool, "exclude-dirs-use-default", "issues.exclude-dirs-use-default", true, - getDefaultDirectoryExcludeHelp()) - - internal.AddFlagAndBind(v, fs, fs.String, "exclude-generated", "issues.exclude-generated", processors.AutogeneratedModeLax, - color.GreenString("Mode of the generated files analysis")) + internal.AddFlagAndBind(v, fs, fs.Bool, "uniq-by-line", "issues.uniq-by-line", true, + color.GreenString("Make issues output unique by line")) const newDesc = "Show only new issues: if there are unstaged changes or untracked files, only those changes " + "are analyzed, else only changes in HEAD~ are analyzed.\nIt's a super-useful option for integration " + @@ -117,30 +133,10 @@ func setupIssuesFlagSet(v *viper.Viper, fs *pflag.FlagSet) { color.GreenString("Show only new issues created after git revision `REV`")) internal.AddFlagAndBind(v, fs, fs.String, "new-from-patch", "issues.new-from-patch", "", color.GreenString("Show only new issues created in git patch with file path `PATH`")) + internal.AddFlagAndBind(v, fs, fs.String, "new-from-merge-base", "issues.new-from-merge-base", "", + color.GreenString("Show only new issues created after the best common ancestor (merge-base against HEAD)")) internal.AddFlagAndBind(v, fs, fs.Bool, "whole-files", "issues.whole-files", false, color.GreenString("Show issues in any part of update files (requires new-from-rev or new-from-patch)")) internal.AddFlagAndBind(v, fs, fs.Bool, "fix", "issues.fix", false, - color.GreenString("Fix found issues (if it's supported by the linter)")) -} - -func getDefaultIssueExcludeHelp() string { - parts := []string{color.GreenString("Use or not use default excludes:")} - - for _, ep := range config.DefaultExcludePatterns { - parts = append(parts, - fmt.Sprintf(" - %s (%s): %s", color.BlueString(ep.ID), color.CyanString(ep.Linter), ep.Why), - fmt.Sprintf(` Pattern: %s`, color.YellowString(`'`+ep.Pattern+`'`)), - ) - } - - return strings.Join(parts, "\n") -} - -func getDefaultDirectoryExcludeHelp() string { - parts := []string{color.GreenString("Use or not use default excluded directories:")} - for _, dir := range processors.StdExcludeDirRegexps { - parts = append(parts, fmt.Sprintf(" - %s", color.YellowString(dir))) - } - parts = append(parts, "") - return strings.Join(parts, "\n") + color.GreenString("Apply the fixes detected by the linters and formatters (if it's supported by the linter)")) } diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/fmt.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/fmt.go new file mode 100644 index 000000000..ab1aef45b --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/fmt.go @@ -0,0 +1,145 @@ +package commands + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/fatih/color" + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goformat" + "github.com/golangci/golangci-lint/v2/pkg/goformatters" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result/processors" +) + +type fmtOptions struct { + config.LoaderOptions + + diff bool // Flag only. + diffColored bool // Flag only. + stdin bool // Flag only. +} + +type fmtCommand struct { + viper *viper.Viper + cmd *cobra.Command + + opts fmtOptions + + cfg *config.Config + + buildInfo BuildInfo + + runner *goformat.Runner + + log logutils.Log +} + +func newFmtCommand(logger logutils.Log, info BuildInfo) *fmtCommand { + c := &fmtCommand{ + viper: viper.New(), + log: logger, + cfg: config.NewDefault(), + buildInfo: info, + } + + fmtCmd := &cobra.Command{ + Use: "fmt", + Short: "Format Go source files.", + RunE: c.execute, + PreRunE: c.preRunE, + PersistentPreRunE: c.persistentPreRunE, + PersistentPostRun: c.persistentPostRun, + SilenceUsage: true, + } + + fmtCmd.SetOut(logutils.StdOut) // use custom output to properly color it in Windows terminals + fmtCmd.SetErr(logutils.StdErr) + + fs := fmtCmd.Flags() + fs.SortFlags = false // sort them as they are defined here + + setupConfigFileFlagSet(fs, &c.opts.LoaderOptions) + + setupFormattersFlagSet(c.viper, fs) + + fs.BoolVarP(&c.opts.diff, "diff", "d", false, color.GreenString("Display diffs instead of rewriting files")) + fs.BoolVar(&c.opts.diffColored, "diff-colored", false, color.GreenString("Display diffs instead of rewriting files (with colors)")) + fs.BoolVar(&c.opts.stdin, "stdin", false, color.GreenString("Use standard input for piping source files")) + + c.cmd = fmtCmd + + return c +} + +func (c *fmtCommand) persistentPreRunE(cmd *cobra.Command, args []string) error { + c.log.Infof("%s", c.buildInfo.String()) + + loader := config.NewFormattersLoader(c.log.Child(logutils.DebugKeyConfigReader), c.viper, cmd.Flags(), c.opts.LoaderOptions, c.cfg, args) + + err := loader.Load(config.LoadOptions{CheckDeprecation: true, Validation: true}) + if err != nil { + return fmt.Errorf("can't load config: %w", err) + } + + return nil +} + +func (c *fmtCommand) preRunE(_ *cobra.Command, _ []string) error { + if c.cfg.GetConfigDir() != "" && c.cfg.Version != "2" { + return fmt.Errorf("invalid version of the configuration: %q", c.cfg.Version) + } + + metaFormatter, err := goformatters.NewMetaFormatter(c.log, &c.cfg.Formatters, &c.cfg.Run) + if err != nil { + return fmt.Errorf("failed to create meta-formatter: %w", err) + } + + matcher := processors.NewGeneratedFileMatcher(c.cfg.Formatters.Exclusions.Generated) + + opts, err := goformat.NewRunnerOptions(c.cfg, c.opts.diff, c.opts.diffColored, c.opts.stdin) + if err != nil { + return fmt.Errorf("build walk options: %w", err) + } + + c.runner = goformat.NewRunner(c.log, metaFormatter, matcher, opts) + + return nil +} + +func (c *fmtCommand) execute(_ *cobra.Command, args []string) error { + paths := cleanArgs(args) + + c.log.Infof("Formatting Go files...") + + err := c.runner.Run(paths) + if err != nil { + return fmt.Errorf("failed to process files: %w", err) + } + + return nil +} + +func (c *fmtCommand) persistentPostRun(_ *cobra.Command, _ []string) { + if c.runner.ExitCode() != 0 { + os.Exit(c.runner.ExitCode()) + } +} + +func cleanArgs(args []string) []string { + if len(args) == 0 { + return []string{"."} + } + + var expanded []string + for _, arg := range args { + expanded = append(expanded, filepath.Clean(strings.ReplaceAll(arg, "...", ""))) + } + + return expanded +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/formatters.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/formatters.go new file mode 100644 index 000000000..bd6e0e80f --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/formatters.go @@ -0,0 +1,137 @@ +package commands + +import ( + "encoding/json" + "fmt" + + "github.com/fatih/color" + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goformatters" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/lint/lintersdb" + "github.com/golangci/golangci-lint/v2/pkg/logutils" +) + +type formattersHelp struct { + Enabled []formatterHelp + Disabled []formatterHelp +} + +type formattersOptions struct { + config.LoaderOptions + JSON bool +} + +type formattersCommand struct { + viper *viper.Viper + cmd *cobra.Command + + opts formattersOptions + + cfg *config.Config + + log logutils.Log + + dbManager *lintersdb.Manager +} + +func newFormattersCommand(logger logutils.Log) *formattersCommand { + c := &formattersCommand{ + viper: viper.New(), + cfg: config.NewDefault(), + log: logger, + } + + formattersCmd := &cobra.Command{ + Use: "formatters", + Short: "List current formatters configuration.", + Args: cobra.NoArgs, + ValidArgsFunction: cobra.NoFileCompletions, + RunE: c.execute, + PreRunE: c.preRunE, + SilenceUsage: true, + } + + fs := formattersCmd.Flags() + fs.SortFlags = false // sort them as they are defined here + + setupConfigFileFlagSet(fs, &c.opts.LoaderOptions) + + setupFormattersFlagSet(c.viper, fs) + + fs.BoolVar(&c.opts.JSON, "json", false, color.GreenString("Display as JSON")) + + c.cmd = formattersCmd + + return c +} + +func (c *formattersCommand) preRunE(cmd *cobra.Command, args []string) error { + loader := config.NewFormattersLoader(c.log.Child(logutils.DebugKeyConfigReader), c.viper, cmd.Flags(), c.opts.LoaderOptions, c.cfg, args) + + err := loader.Load(config.LoadOptions{Validation: true}) + if err != nil { + return fmt.Errorf("can't load config: %w", err) + } + + dbManager, err := lintersdb.NewManager(c.log.Child(logutils.DebugKeyLintersDB), c.cfg, + lintersdb.NewLinterBuilder(), lintersdb.NewPluginModuleBuilder(c.log), lintersdb.NewPluginGoBuilder(c.log)) + if err != nil { + return err + } + + c.dbManager = dbManager + + return nil +} + +func (c *formattersCommand) execute(_ *cobra.Command, _ []string) error { + enabledLintersMap, err := c.dbManager.GetEnabledLintersMap() + if err != nil { + return fmt.Errorf("can't get enabled formatters: %w", err) + } + + var enabledFormatters []*linter.Config + var disabledFormatters []*linter.Config + + for _, lc := range c.dbManager.GetAllSupportedLinterConfigs() { + if lc.Internal { + continue + } + + if !goformatters.IsFormatter(lc.Name()) { + continue + } + + if enabledLintersMap[lc.Name()] == nil { + disabledFormatters = append(disabledFormatters, lc) + } else { + enabledFormatters = append(enabledFormatters, lc) + } + } + + if c.opts.JSON { + formatters := formattersHelp{} + + for _, lc := range enabledFormatters { + formatters.Enabled = append(formatters.Enabled, newFormatterHelp(lc)) + } + + for _, lc := range disabledFormatters { + formatters.Disabled = append(formatters.Disabled, newFormatterHelp(lc)) + } + + return json.NewEncoder(c.cmd.OutOrStdout()).Encode(formatters) + } + + color.Green("Enabled by your configuration formatters:\n") + printFormatters(enabledFormatters) + + color.Red("\nDisabled by your configuration formatters:\n") + printFormatters(disabledFormatters) + + return nil +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/help.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/help.go new file mode 100644 index 000000000..6e9393ddd --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/help.go @@ -0,0 +1,101 @@ +package commands + +import ( + "strings" + "unicode" + "unicode/utf8" + + "github.com/fatih/color" + "github.com/spf13/cobra" + + "github.com/golangci/golangci-lint/v2/pkg/lint/lintersdb" + "github.com/golangci/golangci-lint/v2/pkg/logutils" +) + +type helpOptions struct { + JSON bool +} + +type helpCommand struct { + cmd *cobra.Command + + opts helpOptions + + dbManager *lintersdb.Manager + + log logutils.Log +} + +func newHelpCommand(logger logutils.Log) *helpCommand { + c := &helpCommand{log: logger} + + helpCmd := &cobra.Command{ + Use: "help", + Short: "Display extra help", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + return cmd.Help() + }, + } + + lintersCmd := &cobra.Command{ + Use: "linters", + Short: "Display help for linters.", + Args: cobra.NoArgs, + ValidArgsFunction: cobra.NoFileCompletions, + RunE: c.lintersExecute, + PreRunE: c.lintersPreRunE, + } + + fsLinter := lintersCmd.Flags() + fsLinter.SortFlags = false // sort them as they are defined here + + fsLinter.BoolVar(&c.opts.JSON, "json", false, color.GreenString("Display as JSON")) + + helpCmd.AddCommand(lintersCmd) + + formattersCmd := &cobra.Command{ + Use: "formatters", + Short: "Display help for formatters.", + Args: cobra.NoArgs, + ValidArgsFunction: cobra.NoFileCompletions, + RunE: c.formattersExecute, + PreRunE: c.formattersPreRunE, + } + + fsFormatter := formattersCmd.Flags() + fsFormatter.SortFlags = false // sort them as they are defined here + + fsFormatter.BoolVar(&c.opts.JSON, "json", false, color.GreenString("Display as JSON")) + + helpCmd.AddCommand(formattersCmd) + + c.cmd = helpCmd + + return c +} + +func formatDescription(desc string) string { + desc = strings.TrimSpace(desc) + + if desc == "" { + return desc + } + + // If the linter description spans multiple lines, truncate everything following the first newline + endFirstLine := strings.IndexRune(desc, '\n') + if endFirstLine > 0 { + desc = desc[:endFirstLine] + } + + rawDesc := []rune(desc) + + r, _ := utf8.DecodeRuneInString(desc) + rawDesc[0] = unicode.ToUpper(r) + + if rawDesc[len(rawDesc)-1] != '.' { + rawDesc = append(rawDesc, '.') + } + + return string(rawDesc) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/help_formatters.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/help_formatters.go new file mode 100644 index 000000000..e41cea368 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/help_formatters.go @@ -0,0 +1,123 @@ +package commands + +import ( + "encoding/json" + "fmt" + "slices" + "strings" + + "github.com/fatih/color" + "github.com/spf13/cobra" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goformatters" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/lint/lintersdb" + "github.com/golangci/golangci-lint/v2/pkg/logutils" +) + +type formatterHelp struct { + Name string `json:"name"` + Desc string `json:"description"` + Deprecated bool `json:"deprecated"` + Since string `json:"since"` + OriginalURL string `json:"originalURL,omitempty"` +} + +func newFormatterHelp(lc *linter.Config) formatterHelp { + return formatterHelp{ + Name: lc.Name(), + Desc: formatDescription(lc.Linter.Desc()), + Deprecated: lc.IsDeprecated(), + Since: lc.Since, + OriginalURL: lc.OriginalURL, + } +} + +func (c *helpCommand) formattersPreRunE(_ *cobra.Command, _ []string) error { + // The command doesn't depend on the real configuration. + dbManager, err := lintersdb.NewManager(c.log.Child(logutils.DebugKeyLintersDB), config.NewDefault(), lintersdb.NewLinterBuilder()) + if err != nil { + return err + } + + c.dbManager = dbManager + + return nil +} + +func (c *helpCommand) formattersExecute(_ *cobra.Command, _ []string) error { + if c.opts.JSON { + return c.formattersPrintJSON() + } + + c.formattersPrint() + + return nil +} + +func (c *helpCommand) formattersPrintJSON() error { + var formatters []formatterHelp + + for _, lc := range c.dbManager.GetAllSupportedLinterConfigs() { + if lc.Internal { + continue + } + + if !goformatters.IsFormatter(lc.Name()) { + continue + } + + formatters = append(formatters, newFormatterHelp(lc)) + } + + return json.NewEncoder(c.cmd.OutOrStdout()).Encode(formatters) +} + +func (c *helpCommand) formattersPrint() { + var lcs []*linter.Config + for _, lc := range c.dbManager.GetAllSupportedLinterConfigs() { + if lc.Internal { + continue + } + + if !goformatters.IsFormatter(lc.Name()) { + continue + } + + lcs = append(lcs, lc) + } + + color.Green("Disabled by default formatters:\n") + printFormatters(lcs) +} + +func printFormatters(lcs []*linter.Config) { + slices.SortFunc(lcs, func(a, b *linter.Config) int { + if a.IsDeprecated() && b.IsDeprecated() { + return strings.Compare(a.Name(), b.Name()) + } + + if a.IsDeprecated() { + return 1 + } + + if b.IsDeprecated() { + return -1 + } + + return strings.Compare(a.Name(), b.Name()) + }) + + for _, lc := range lcs { + desc := formatDescription(lc.Linter.Desc()) + + deprecatedMark := "" + if lc.IsDeprecated() { + deprecatedMark = " [" + color.RedString("deprecated") + "]" + } + + _, _ = fmt.Fprintf(logutils.StdOut, "%s%s: %s\n", + color.YellowString(lc.Name()), deprecatedMark, desc) + } +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/help_linters.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/help_linters.go new file mode 100644 index 000000000..b4e647700 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/help_linters.go @@ -0,0 +1,156 @@ +package commands + +import ( + "encoding/json" + "fmt" + "maps" + "slices" + "strings" + + "github.com/fatih/color" + "github.com/spf13/cobra" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goformatters" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/lint/lintersdb" + "github.com/golangci/golangci-lint/v2/pkg/logutils" +) + +type linterHelp struct { + Name string `json:"name"` + Desc string `json:"description"` + Groups []string `json:"groups"` + Fast bool `json:"fast"` + AutoFix bool `json:"autoFix"` + Deprecated bool `json:"deprecated"` + Since string `json:"since"` + OriginalURL string `json:"originalURL,omitempty"` +} + +func newLinterHelp(lc *linter.Config) linterHelp { + groups := []string{config.GroupAll} + + if !lc.IsSlowLinter() { + groups = append(groups, config.GroupFast) + } + + return linterHelp{ + Name: lc.Name(), + Desc: formatDescription(lc.Linter.Desc()), + Groups: slices.Concat(groups, slices.Collect(maps.Keys(lc.Groups))), + Fast: !lc.IsSlowLinter(), + AutoFix: lc.CanAutoFix, + Deprecated: lc.IsDeprecated(), + Since: lc.Since, + OriginalURL: lc.OriginalURL, + } +} + +func (c *helpCommand) lintersPreRunE(_ *cobra.Command, _ []string) error { + // The command doesn't depend on the real configuration. + dbManager, err := lintersdb.NewManager(c.log.Child(logutils.DebugKeyLintersDB), config.NewDefault(), lintersdb.NewLinterBuilder()) + if err != nil { + return err + } + + c.dbManager = dbManager + + return nil +} + +func (c *helpCommand) lintersExecute(_ *cobra.Command, _ []string) error { + if c.opts.JSON { + return c.lintersPrintJSON() + } + + c.lintersPrint() + + return nil +} + +func (c *helpCommand) lintersPrintJSON() error { + var linters []linterHelp + + for _, lc := range c.dbManager.GetAllSupportedLinterConfigs() { + if lc.Internal { + continue + } + + if goformatters.IsFormatter(lc.Name()) { + continue + } + + linters = append(linters, newLinterHelp(lc)) + } + + return json.NewEncoder(c.cmd.OutOrStdout()).Encode(linters) +} + +func (c *helpCommand) lintersPrint() { + var enabledLCs, disabledLCs []*linter.Config + for _, lc := range c.dbManager.GetAllSupportedLinterConfigs() { + if lc.Internal { + continue + } + + if goformatters.IsFormatter(lc.Name()) { + continue + } + + if lc.FromGroup(config.GroupStandard) { + enabledLCs = append(enabledLCs, lc) + } else { + disabledLCs = append(disabledLCs, lc) + } + } + + color.Green("Enabled by default linters:\n") + printLinters(enabledLCs) + + color.Red("\nDisabled by default linters:\n") + printLinters(disabledLCs) +} + +func printLinters(lcs []*linter.Config) { + slices.SortFunc(lcs, func(a, b *linter.Config) int { + if a.IsDeprecated() && b.IsDeprecated() { + return strings.Compare(a.Name(), b.Name()) + } + + if a.IsDeprecated() { + return 1 + } + + if b.IsDeprecated() { + return -1 + } + + return strings.Compare(a.Name(), b.Name()) + }) + + for _, lc := range lcs { + desc := formatDescription(lc.Linter.Desc()) + + deprecatedMark := "" + if lc.IsDeprecated() { + deprecatedMark = " [" + color.RedString("deprecated") + "]" + } + + var capabilities []string + if !lc.IsSlowLinter() { + capabilities = append(capabilities, color.BlueString("fast")) + } + if lc.CanAutoFix { + capabilities = append(capabilities, color.GreenString("auto-fix")) + } + + var capability string + if capabilities != nil { + capability = " [" + strings.Join(capabilities, ", ") + "]" + } + + _, _ = fmt.Fprintf(logutils.StdOut, "%s%s: %s%s\n", + color.YellowString(lc.Name()), deprecatedMark, desc, capability) + } +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/commands/internal/builder.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/builder.go similarity index 82% rename from vendor/github.com/golangci/golangci-lint/pkg/commands/internal/builder.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/builder.go index f0e259fb0..63f6f2f18 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/commands/internal/builder.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/builder.go @@ -2,6 +2,8 @@ package internal import ( "context" + "crypto/sha256" + "encoding/base64" "fmt" "io" "os" @@ -12,7 +14,9 @@ import ( "time" "unicode" - "github.com/golangci/golangci-lint/pkg/logutils" + "golang.org/x/mod/sumdb/dirhash" + + "github.com/golangci/golangci-lint/v2/pkg/logutils" ) // Builder runs all the required commands to build a binary. @@ -88,7 +92,7 @@ func (b Builder) clone(ctx context.Context) error { //nolint:gosec // the variable is sanitized. cmd := exec.CommandContext(ctx, "git", "clone", "--branch", sanitizeVersion(b.cfg.Version), - "--single-branch", "--depth", "1", "-c advice.detachedHead=false", "-q", + "--single-branch", "--depth", "1", "-c", "advice.detachedHead=false", "-q", "https://github.com/golangci/golangci-lint.git", ) cmd.Dir = b.root @@ -173,13 +177,17 @@ func (b Builder) goModTidy(ctx context.Context) error { } func (b Builder) goBuild(ctx context.Context, binaryName string) error { + version, err := b.createVersion(b.cfg.Version) + if err != nil { + return fmt.Errorf("custom version: %w", err) + } + + b.log.Infof("version: %s", version) + //nolint:gosec // the variable is sanitized. cmd := exec.CommandContext(ctx, "go", "build", "-ldflags", - fmt.Sprintf( - "-s -w -X 'main.version=%s-custom-gcl' -X 'main.date=%s'", - sanitizeVersion(b.cfg.Version), time.Now().UTC().String(), - ), + fmt.Sprintf("-s -w -X 'main.version=%s' -X 'main.date=%s'", version, time.Now().UTC().String()), "-o", binaryName, "./cmd/golangci-lint", ) @@ -241,9 +249,33 @@ func (b Builder) getBinaryName() string { return name } +func (b Builder) createVersion(orig string) (string, error) { + hash := sha256.New() + + for _, plugin := range b.cfg.Plugins { + if plugin.Path == "" { + continue + } + + dh, err := hashDir(plugin.Path, "", dirhash.DefaultHash) + if err != nil { + return "", fmt.Errorf("hash plugin directory: %w", err) + } + + b.log.Infof("%s: %s", plugin.Path, dh) + + hash.Write([]byte(dh)) + } + + return fmt.Sprintf("%s-custom-gcl-%s", + sanitizeVersion(orig), + sanitizeVersion(base64.URLEncoding.EncodeToString(hash.Sum(nil))), + ), nil +} + func sanitizeVersion(v string) string { fn := func(c rune) bool { - return !(unicode.IsLetter(c) || unicode.IsNumber(c) || c == '.' || c == '/') + return !unicode.IsLetter(c) && !unicode.IsNumber(c) && c != '.' && c != '/' } return strings.Join(strings.FieldsFunc(v, fn), "") diff --git a/vendor/github.com/golangci/golangci-lint/pkg/commands/internal/configuration.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/configuration.go similarity index 99% rename from vendor/github.com/golangci/golangci-lint/pkg/commands/internal/configuration.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/configuration.go index f9de4c47a..0982c3eca 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/commands/internal/configuration.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/configuration.go @@ -7,7 +7,7 @@ import ( "path/filepath" "strings" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" ) const base = ".custom-gcl" diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/dirhash.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/dirhash.go new file mode 100644 index 000000000..16ea6a856 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/dirhash.go @@ -0,0 +1,93 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package internal + +import ( + "fmt" + "io" + "os" + "path/filepath" + "strings" + + "golang.org/x/mod/sumdb/dirhash" +) + +// Slightly modified copy of [dirhash.HashDir]. +// https://github.com/golang/mod/blob/v0.28.0/sumdb/dirhash/hash.go#L67-L79 +func hashDir(dir, prefix string, hash dirhash.Hash) (string, error) { + files, err := dirFiles(dir, prefix) + if err != nil { + return "", err + } + + osOpen := func(name string) (io.ReadCloser, error) { + return os.Open(filepath.Join(dir, strings.TrimPrefix(name, prefix))) + } + + return hash(files, osOpen) +} + +// Modified copy of [dirhash.DirFiles]. +// https://github.com/golang/mod/blob/v0.28.0/sumdb/dirhash/hash.go#L81-L109 +// And adapted to globally follows the rules from https://github.com/golang/mod/blob/v0.28.0/zip/zip.go +func dirFiles(dir, prefix string) ([]string, error) { + var files []string + + dir = filepath.Clean(dir) + + err := filepath.Walk(dir, func(file string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if info.IsDir() { + if dir == file { + // Don't skip the top-level directory. + return nil + } + + switch info.Name() { + // Skip vendor and node directories. + case "vendor", "node_modules": + return filepath.SkipDir + + // Skip VCS directories. + case ".bzr", ".git", ".hg", ".svn": + return filepath.SkipDir + } + + // Skip submodules (directories containing go.mod files). + if goModInfo, err := os.Lstat(filepath.Join(dir, "go.mod")); err == nil && !goModInfo.IsDir() { + return filepath.SkipDir + } + + return nil + } + + if file == dir { + return fmt.Errorf("%s is not a directory", dir) + } + + if !info.Mode().IsRegular() { + return nil + } + + rel := file + + if dir != "." { + rel = file[len(dir)+1:] + } + + f := filepath.Join(prefix, rel) + + files = append(files, filepath.ToSlash(f)) + + return nil + }) + if err != nil { + return nil, err + } + return files, nil +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/commands/internal/imports.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/imports.go similarity index 100% rename from vendor/github.com/golangci/golangci-lint/pkg/commands/internal/imports.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/imports.go diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/fakeloader/config.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/fakeloader/config.go new file mode 100644 index 000000000..159f4cba0 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/fakeloader/config.go @@ -0,0 +1,22 @@ +package fakeloader + +// Config implements [config.BaseConfig]. +// This only the stub for the real file loader. +type Config struct { + Version string `mapstructure:"version"` + + cfgDir string // Path to the directory containing golangci-lint config file. +} + +func NewConfig() *Config { + return &Config{} +} + +// SetConfigDir sets the path to directory that contains golangci-lint config file. +func (c *Config) SetConfigDir(dir string) { + c.cfgDir = dir +} + +func (*Config) IsInternalTest() bool { + return false +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/fakeloader/fakeloader.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/fakeloader/fakeloader.go new file mode 100644 index 000000000..fd17449b5 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/fakeloader/fakeloader.go @@ -0,0 +1,48 @@ +package fakeloader + +import ( + "fmt" + "os" + + "github.com/go-viper/mapstructure/v2" + + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/parser" + "github.com/golangci/golangci-lint/v2/pkg/config" +) + +// Load is used to keep case of configuration. +// Viper serialize raw map keys in lowercase, this is a problem with the configuration of some linters. +func Load(srcPath string, old any) error { + file, err := os.Open(srcPath) + if err != nil { + return fmt.Errorf("open file: %w", err) + } + + defer func() { _ = file.Close() }() + + raw := map[string]any{} + + err = parser.Decode(file, raw) + if err != nil { + return err + } + + // NOTE: this is inspired by viper internals. + cc := &mapstructure.DecoderConfig{ + Result: old, + WeaklyTypedInput: true, + DecodeHook: config.DecodeHookFunc(), + } + + decoder, err := mapstructure.NewDecoder(cc) + if err != nil { + return fmt.Errorf("constructing mapstructure decoder: %w", err) + } + + err = decoder.Decode(raw) + if err != nil { + return fmt.Errorf("decoding configuration file: %w", err) + } + + return nil +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate.go new file mode 100644 index 000000000..69b6c7c42 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate.go @@ -0,0 +1,19 @@ +package migrate + +import ( + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/ptr" + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone" + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo" +) + +func ToConfig(old *versionone.Config) *versiontwo.Config { + return &versiontwo.Config{ + Version: ptr.Pointer("2"), + Linters: toLinters(old), + Formatters: toFormatters(old), + Issues: toIssues(old), + Output: toOutput(old), + Severity: toSeverity(old), + Run: toRun(old), + } +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_formatters.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_formatters.go new file mode 100644 index 000000000..8836e6db8 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_formatters.go @@ -0,0 +1,105 @@ +package migrate + +import ( + "slices" + "strings" + + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/ptr" + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone" + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo" +) + +func toFormatters(old *versionone.Config) versiontwo.Formatters { + enable := ProcessEffectiveFormatters(old.Linters) + + var paths []string + if len(enable) > 0 { + paths = slices.Concat(old.Issues.ExcludeFiles, old.Issues.ExcludeDirs) + } + + if old.Issues.UseDefaultExcludeDirs == nil || ptr.Deref(old.Issues.UseDefaultExcludeDirs) { + paths = append(paths, "third_party$", "builtin$", "examples$") + } + + paths = append(paths, toFormattersPathsFromRules(old.Issues)...) + + return versiontwo.Formatters{ + Enable: enable, + Settings: versiontwo.FormatterSettings{ + Gci: toGciSettings(old.LintersSettings.Gci), + GoFmt: toGoFmtSettings(old.LintersSettings.GoFmt), + GoFumpt: toGoFumptSettings(old.LintersSettings.GoFumpt), + GoImports: toGoImportsSettings(old.LintersSettings.GoImports), + }, + Exclusions: versiontwo.FormatterExclusions{ + Generated: toExclusionGenerated(old.Issues.ExcludeGenerated), + Paths: paths, + }, + } +} + +func toFormattersPathsFromRules(old versionone.Issues) []string { + var results []string + + for _, rule := range old.ExcludeRules { + allNames := convertStaticcheckLinterNames(convertAlternativeNames(rule.Linters)) + + names := onlyFormatterNames(allNames) + if len(names) == 0 { + continue + } + + if ptr.Deref(rule.Path) == "" { + continue + } + + results = append(results, ptr.Deref(rule.Path)) + } + + return results +} + +func toGciSettings(old versionone.GciSettings) versiontwo.GciSettings { + return versiontwo.GciSettings{ + Sections: old.Sections, + NoInlineComments: old.NoInlineComments, + NoPrefixComments: old.NoPrefixComments, + CustomOrder: old.CustomOrder, + NoLexOrder: old.NoLexOrder, + } +} + +func toGoFmtSettings(old versionone.GoFmtSettings) versiontwo.GoFmtSettings { + settings := versiontwo.GoFmtSettings{ + Simplify: old.Simplify, + } + + for _, rule := range old.RewriteRules { + settings.RewriteRules = append(settings.RewriteRules, versiontwo.GoFmtRewriteRule{ + Pattern: rule.Pattern, + Replacement: rule.Replacement, + }) + } + + return settings +} + +func toGoFumptSettings(old versionone.GoFumptSettings) versiontwo.GoFumptSettings { + return versiontwo.GoFumptSettings{ + ModulePath: old.ModulePath, + ExtraRules: old.ExtraRules, + } +} + +func toGoImportsSettings(old versionone.GoImportsSettings) versiontwo.GoImportsSettings { + var localPrefixes []string + + prefixes := ptr.Deref(old.LocalPrefixes) + if prefixes != "" { + localPrefixes = strings.Split(prefixes, ",") + } + + return versiontwo.GoImportsSettings{ + LocalPrefixes: localPrefixes, + } +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_issues.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_issues.go new file mode 100644 index 000000000..eab9d17c6 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_issues.go @@ -0,0 +1,20 @@ +package migrate + +import ( + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone" + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo" +) + +func toIssues(old *versionone.Config) versiontwo.Issues { + return versiontwo.Issues{ + MaxIssuesPerLinter: old.Issues.MaxIssuesPerLinter, + MaxSameIssues: old.Issues.MaxSameIssues, + UniqByLine: old.Issues.UniqByLine, + DiffFromRevision: old.Issues.DiffFromRevision, + DiffFromMergeBase: old.Issues.DiffFromMergeBase, + DiffPatchFilePath: old.Issues.DiffPatchFilePath, + WholeFiles: old.Issues.WholeFiles, + Diff: old.Issues.Diff, + NeedFix: old.Issues.NeedFix, + } +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_linter_names.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_linter_names.go new file mode 100644 index 000000000..bbb178ab3 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_linter_names.go @@ -0,0 +1,966 @@ +package migrate + +import ( + "cmp" + "slices" + + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/ptr" + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone" +) + +type LinterInfo struct { + Name string `json:"name"` + Presets []string `json:"inPresets"` + Slow bool `json:"isSlow,omitempty"` + Default bool `json:"enabledByDefault,omitempty"` + AlternativeNames []string `json:"alternativeNames,omitempty"` +} + +func (l *LinterInfo) isName(name string) bool { + if name == l.Name { + return true + } + + return slices.Contains(l.AlternativeNames, name) +} + +func (l *LinterInfo) hasPresets(names []string) bool { + for _, name := range names { + if slices.Contains(l.Presets, name) { + return true + } + } + + return false +} + +func ProcessEffectiveLinters(old versionone.Linters) (enable, disable []string) { + switch { + case ptr.Deref(old.DisableAll): + return disableAllFilter(old), nil + + case ptr.Deref(old.EnableAll): + return nil, enableAllFilter(old) + + default: + return defaultLintersFilter(old) + } +} + +func ProcessEffectiveFormatters(old versionone.Linters) []string { + enabled, disabled := ProcessEffectiveLinters(old) + + if ptr.Deref(old.EnableAll) { + var formatterNames []string + + for _, f := range getAllFormatterNames() { + if !slices.Contains(disabled, f) { + formatterNames = append(formatterNames, f) + } + } + + return formatterNames + } + + return onlyFormatterNames(enabled) +} + +// disableAllFilter generates the value of `enable` when `disable-all` is `true`. +func disableAllFilter(old versionone.Linters) []string { + // Note: + // - disable-all + enable-all + // => impossible (https://github.com/golangci/golangci-lint/blob/e1eb4cb2c7fba29b5831b63e454844d83c692874/pkg/config/linters.go#L38) + // - disable-all + disable + // => impossible (https://github.com/golangci/golangci-lint/blob/e1eb4cb2c7fba29b5831b63e454844d83c692874/pkg/config/linters.go#L47) + + // if disable-all -> presets fast enable + // - presets fast enable: (presets - [slow]) + enable => effective enable + none + // - presets fast: presets - slow => effective enable + none + // - presets fast enable: presets + enable => effective enable + none + // - enable => effective enable + none + // - fast => nothing + // - fast enable: enable => effective enable + none + + // (presets - [slow]) + enable => effective enable + none + names := toNames( + slices.Concat( + filter( + allLinters(), onlyPresets(old), keepFast(old), // presets - [slow] + ), + allEnabled(old, allLinters()), // + enable + ), + ) + + return slices.Concat(names, unknownLinterNames(old.Enable, allLinters())) +} + +// enableAllFilter generates the value of `disable` when `enable-all` is `true`. +func enableAllFilter(old versionone.Linters) []string { + // Note: + // - enable-all + disable-all + // => impossible (https://github.com/golangci/golangci-lint/blob/e1eb4cb2c7fba29b5831b63e454844d83c692874/pkg/config/linters.go#L38) + // - enable-all + enable + fast=false + // => impossible (https://github.com/golangci/golangci-lint/blob/e1eb4cb2c7fba29b5831b63e454844d83c692874/pkg/config/linters.go#L52) + // - enable-all + enable + fast=true + // => possible (https://github.com/golangci/golangci-lint/blob/e1eb4cb2c7fba29b5831b63e454844d83c692874/pkg/config/linters.go#L51) + + // if enable-all -> presets fast enable disable + // - presets fast enable disable: all - fast - enable + disable => effective disable + all + // - presets fast disable: all - fast + disable => effective disable + all + // - presets fast: all - fast => effective disable + all + // - presets disable: disable => effective disable + all + // - disable => effective disable + all + // - fast: all - fast => effective disable + all + // - fast disable: all - fast + disable => effective disable + all + + // all - [fast] - enable + disable => effective disable + all + names := toNames( + slices.Concat( + removeLinters( + filter( + allLinters(), keepSlow(old), // all - fast + ), + allEnabled(old, allLinters()), // - enable + ), + allDisabled(old, allLinters()), // + disable + ), + ) + + return slices.Concat(names, unknownLinterNames(old.Disable, allLinters())) +} + +// defaultLintersFilter generates the values of `enable` and `disable` when using default linters. +func defaultLintersFilter(old versionone.Linters) (enable, disable []string) { + // Note: + // - a linter cannot be inside `enable` and `disable` in the same configuration + // => https://github.com/golangci/golangci-lint/blob/e1eb4cb2c7fba29b5831b63e454844d83c692874/pkg/config/linters.go#L66 + + // if default -> presets fast disable + // - presets > fast > disable > enable => effective enable + disable + standard + // - (default - fast) - enable + disable => effective disable + // - presets - slow + enable - default - [effective disable] => effective enable + // - presets + fast + disable => effective enable + disable + standard + // - (default - fast) + disable => effective disable + // - presets - slow - default - [effective disable] => effective enable + // - presets + fast + enable + // - (default - fast) - enable => effective disable + // - presets - slow + enable - default - [effective disable] => effective enable + // - presets + fast + // - (default - fast) => effective disable + // - presets - slow - default - [effective disable] => effective enable + // - presets + disable + // - default + disable => effective disable + // - presets - default - [effective disable] => effective enable + // - presets + enable + // - default - enable => effective disable + // - presets + enable - default - [effective disable] => effective enable + // - disable + // - default + disable => effective disable + // - default - [effective disable] => effective enable + // - enable + // - default - enable => effective disable + // - enable - default - [effective disable] => effective enable + // - fast + // - default - fast => effective disable + // - default - [effective disable] => effective enable + // - fast + disable + // - (default - fast) + disable => effective disable + // - default - [effective disable] => effective enable + // - fast + enable + // - (default - fast) - enable => effective disable + // - enable - default - [effective disable] => effective enable + + disabledLinters := defaultLintersDisableFilter(old) + + enabledLinters := defaultLintersEnableFilter(old, disabledLinters) + + enabled := toNames(enabledLinters) + disabled := toNames(disabledLinters) + + return slices.Concat(enabled, unknownLinterNames(old.Enable, allLinters())), + slices.Concat(disabled, unknownLinterNames(old.Disable, allLinters())) +} + +// defaultLintersEnableFilter generates the value of `enable` when using default linters. +func defaultLintersEnableFilter(old versionone.Linters, effectiveDisabled []LinterInfo) []LinterInfo { + // presets - slow + enable - default - [effective disable] => effective enable + return removeLinters( + filter( + slices.Concat( + filter( + allLinters(), onlyPresets(old), keepFast(old), // presets - slow + ), + allEnabled(old, allLinters()), // + enable + ), + notDefault, // - default + ), + effectiveDisabled, // - [effective disable] + ) +} + +// defaultLintersDisableFilter generates the value of `disable` when using default linters. +func defaultLintersDisableFilter(old versionone.Linters) []LinterInfo { + // (default - fast) - enable + disable => effective disable + return slices.Concat( + removeLinters( + filter(allLinters(), onlyDefault, keepSlow(old)), // (default - fast) + allEnabled(old, allLinters()), // - enable + ), + allDisabled(old, allLinters()), // + disable + ) +} + +func allLinters() []LinterInfo { + return []LinterInfo{ + { + Name: "asasalint", + Presets: []string{"bugs"}, + Slow: true, + }, + { + Name: "asciicheck", + Presets: []string{"bugs", "style"}, + }, + { + Name: "bidichk", + Presets: []string{"bugs"}, + }, + { + Name: "bodyclose", + Presets: []string{"performance", "bugs"}, + Slow: true, + }, + { + Name: "canonicalheader", + Presets: []string{"style"}, + Slow: true, + }, + { + Name: "containedctx", + Presets: []string{"style"}, + Slow: true, + }, + { + Name: "contextcheck", + Presets: []string{"bugs"}, + Slow: true, + }, + { + Name: "copyloopvar", + Presets: []string{"style"}, + }, + { + Name: "cyclop", + Presets: []string{"complexity"}, + }, + { + Name: "decorder", + Presets: []string{"style"}, + }, + { + Name: "depguard", + Presets: []string{"style", "import", "module"}, + }, + { + Name: "dogsled", + Presets: []string{"style"}, + }, + { + Name: "dupl", + Presets: []string{"style"}, + }, + { + Name: "dupword", + Presets: []string{"comment"}, + }, + { + Name: "durationcheck", + Presets: []string{"bugs"}, + Slow: true, + }, + { + Name: "errcheck", + Presets: []string{"bugs", "error"}, + Slow: true, + Default: true, + }, + { + Name: "errchkjson", + Presets: []string{"bugs"}, + Slow: true, + }, + { + Name: "errname", + Presets: []string{"style"}, + Slow: true, + }, + { + Name: "errorlint", + Presets: []string{"bugs", "error"}, + Slow: true, + }, + { + Name: "exhaustive", + Presets: []string{"bugs"}, + Slow: true, + }, + { + Name: "exhaustruct", + Presets: []string{"style", "test"}, + Slow: true, + }, + { + Name: "exptostd", + Presets: []string{"style"}, + Slow: true, + }, + { + Name: "forbidigo", + Presets: []string{"style"}, + Slow: true, + }, + { + Name: "forcetypeassert", + Presets: []string{"style"}, + Slow: true, + }, + { + Name: "fatcontext", + Presets: []string{"performance"}, + Slow: true, + }, + { + Name: "funlen", + Presets: []string{"complexity"}, + }, + { + Name: "gci", + Presets: []string{"format", "import"}, + }, + { + Name: "ginkgolinter", + Presets: []string{"style"}, + Slow: true, + }, + { + Name: "gocheckcompilerdirectives", + Presets: []string{"bugs"}, + }, + { + Name: "gochecknoglobals", + Presets: []string{"style"}, + Slow: true, + }, + { + Name: "gochecknoinits", + Presets: []string{"style"}, + }, + { + Name: "gochecksumtype", + Presets: []string{"bugs"}, + Slow: true, + }, + { + Name: "gocognit", + Presets: []string{"complexity"}, + }, + { + Name: "goconst", + Presets: []string{"style"}, + }, + { + Name: "gocritic", + Presets: []string{"style", "metalinter"}, + Slow: true, + }, + { + Name: "gocyclo", + Presets: []string{"complexity"}, + }, + { + Name: "godot", + Presets: []string{"style", "comment"}, + }, + { + Name: "godox", + Presets: []string{"style", "comment"}, + }, + { + Name: "err113", + Presets: []string{"style", "error"}, + Slow: true, + AlternativeNames: []string{"goerr113"}, + }, + { + Name: "gofmt", + Presets: []string{"format"}, + }, + { + Name: "gofumpt", + Presets: []string{"format"}, + }, + { + Name: "goheader", + Presets: []string{"style"}, + }, + { + Name: "goimports", + Presets: []string{"format", "import"}, + }, + { + Name: "mnd", + Presets: []string{"style"}, + AlternativeNames: []string{"gomnd"}, + }, + { + Name: "gomoddirectives", + Presets: []string{"style", "module"}, + }, + { + Name: "gomodguard", + Presets: []string{"style", "import", "module"}, + }, + { + Name: "goprintffuncname", + Presets: []string{"style"}, + }, + { + Name: "gosec", + Presets: []string{"bugs"}, + Slow: true, + AlternativeNames: []string{"gas"}, + }, + { + Name: "gosimple", + Presets: []string{"style"}, + Slow: true, + Default: true, + AlternativeNames: []string{"megacheck"}, + }, + { + Name: "gosmopolitan", + Presets: []string{"bugs"}, + Slow: true, + }, + { + Name: "govet", + Presets: []string{"bugs", "metalinter"}, + Slow: true, + Default: true, + AlternativeNames: []string{"vet", "vetshadow"}, + }, + { + Name: "grouper", + Presets: []string{"style"}, + }, + { + Name: "iface", + Presets: []string{"style"}, + Slow: true, + }, + { + Name: "importas", + Presets: []string{"style"}, + Slow: true, + }, + { + Name: "inamedparam", + Presets: []string{"style"}, + }, + { + Name: "ineffassign", + Presets: []string{"unused"}, + Default: true, + }, + { + Name: "interfacebloat", + Presets: []string{"style"}, + }, + { + Name: "intrange", + Presets: []string{"style"}, + Slow: true, + }, + { + Name: "ireturn", + Presets: []string{"style"}, + Slow: true, + }, + { + Name: "lll", + Presets: []string{"style"}, + }, + { + Name: "loggercheck", + Presets: []string{"style", "bugs"}, + Slow: true, + AlternativeNames: []string{"logrlint"}, + }, + { + Name: "maintidx", + Presets: []string{"complexity"}, + }, + { + Name: "makezero", + Presets: []string{"style", "bugs"}, + Slow: true, + }, + { + Name: "mirror", + Presets: []string{"style"}, + Slow: true, + }, + { + Name: "misspell", + Presets: []string{"style", "comment"}, + }, + { + Name: "musttag", + Presets: []string{"style", "bugs"}, + Slow: true, + }, + { + Name: "nakedret", + Presets: []string{"style"}, + }, + { + Name: "nestif", + Presets: []string{"complexity"}, + }, + { + Name: "nilerr", + Presets: []string{"bugs"}, + Slow: true, + }, + { + Name: "nilnesserr", + Presets: []string{"bugs"}, + Slow: true, + }, + { + Name: "nilnil", + Presets: []string{"style"}, + Slow: true, + }, + { + Name: "nlreturn", + Presets: []string{"style"}, + }, + { + Name: "noctx", + Presets: []string{"performance", "bugs"}, + Slow: true, + }, + { + Name: "nonamedreturns", + Presets: []string{"style"}, + Slow: true, + }, + { + Name: "nosprintfhostport", + Presets: []string{"style"}, + }, + { + Name: "paralleltest", + Presets: []string{"style", "test"}, + Slow: true, + }, + { + Name: "perfsprint", + Presets: []string{"performance"}, + Slow: true, + }, + { + Name: "prealloc", + Presets: []string{"performance"}, + }, + { + Name: "predeclared", + Presets: []string{"style"}, + }, + { + Name: "promlinter", + Presets: []string{"style"}, + }, + { + Name: "protogetter", + Presets: []string{"bugs"}, + Slow: true, + }, + { + Name: "reassign", + Presets: []string{"bugs"}, + Slow: true, + }, + { + Name: "recvcheck", + Presets: []string{"bugs"}, + Slow: true, + }, + { + Name: "revive", + Presets: []string{"style", "metalinter"}, + Slow: true, + }, + { + Name: "rowserrcheck", + Presets: []string{"bugs", "sql"}, + Slow: true, + }, + { + Name: "sloglint", + Presets: []string{"style"}, + Slow: true, + }, + { + Name: "sqlclosecheck", + Presets: []string{"bugs", "sql"}, + Slow: true, + }, + { + Name: "spancheck", + Presets: []string{"bugs"}, + Slow: true, + }, + { + Name: "staticcheck", + Presets: []string{"bugs", "metalinter"}, + Slow: true, + Default: true, + AlternativeNames: []string{"megacheck"}, + }, + { + Name: "stylecheck", + Presets: []string{"style"}, + Slow: true, + }, + { + Name: "tagalign", + Presets: []string{"style"}, + }, + { + Name: "tagliatelle", + Presets: []string{"style"}, + Slow: true, + }, + { + Name: "testableexamples", + Presets: []string{"test"}, + }, + { + Name: "testifylint", + Presets: []string{"test", "bugs"}, + Slow: true, + }, + { + Name: "testpackage", + Presets: []string{"style", "test"}, + }, + { + Name: "thelper", + Presets: []string{"test"}, + Slow: true, + }, + { + Name: "tparallel", + Presets: []string{"style", "test"}, + Slow: true, + }, + { + Name: "unconvert", + Presets: []string{"style"}, + Slow: true, + }, + { + Name: "unparam", + Presets: []string{"unused"}, + Slow: true, + }, + { + Name: "unused", + Presets: []string{"unused"}, + Slow: true, + Default: true, + AlternativeNames: []string{"megacheck"}, + }, + { + Name: "usestdlibvars", + Presets: []string{"style"}, + }, + { + Name: "usetesting", + Presets: []string{"test"}, + Slow: true, + }, + { + Name: "varnamelen", + Presets: []string{"style"}, + Slow: true, + }, + { + Name: "wastedassign", + Presets: []string{"style"}, + Slow: true, + }, + { + Name: "whitespace", + Presets: []string{"style"}, + }, + { + Name: "wrapcheck", + Presets: []string{"style", "error"}, + Slow: true, + }, + { + Name: "wsl", + Presets: []string{"style"}, + }, + { + Name: "zerologlint", + Presets: []string{"bugs"}, + Slow: true, + }, + { + Name: "nolintlint", + Presets: []string{"style"}, + }, + } +} + +func toNames(linters []LinterInfo) []string { + var results []string + + for _, linter := range linters { + results = append(results, linter.Name) + } + + return Unique(results) +} + +func removeLinters(linters, toRemove []LinterInfo) []LinterInfo { + return slices.DeleteFunc(linters, func(info LinterInfo) bool { + return slices.ContainsFunc(toRemove, func(en LinterInfo) bool { + return info.Name == en.Name + }) + }) +} + +func allEnabled(old versionone.Linters, linters []LinterInfo) []LinterInfo { + var results []LinterInfo + + for _, linter := range linters { + if slices.ContainsFunc(old.Enable, linter.isName) { + results = append(results, linter) + } + } + + return results +} + +func allDisabled(old versionone.Linters, linters []LinterInfo) []LinterInfo { + var results []LinterInfo + + for _, linter := range linters { + if slices.ContainsFunc(old.Disable, linter.isName) { + results = append(results, linter) + } + } + + return results +} + +func filter(linters []LinterInfo, fns ...fnFilter) []LinterInfo { + var results []LinterInfo + + for _, linter := range linters { + if mergeFilters(linter, fns) { + results = append(results, linter) + } + } + + return results +} + +func mergeFilters(linter LinterInfo, fns []fnFilter) bool { + for _, fn := range fns { + if !fn(linter) { + return false + } + } + + return true +} + +type fnFilter func(linter LinterInfo) bool + +func onlyPresets(old versionone.Linters) fnFilter { + return func(linter LinterInfo) bool { + return linter.hasPresets(old.Presets) + } +} + +func onlyDefault(linter LinterInfo) bool { + return linter.Default +} + +func notDefault(linter LinterInfo) bool { + return !linter.Default +} + +func keepFast(old versionone.Linters) fnFilter { + return func(linter LinterInfo) bool { + if !ptr.Deref(old.Fast) { + return true + } + + return !linter.Slow + } +} + +func keepSlow(old versionone.Linters) fnFilter { + return func(linter LinterInfo) bool { + if !ptr.Deref(old.Fast) { + return false + } + + return linter.Slow + } +} + +func unknownLinterNames(names []string, linters []LinterInfo) []string { + deprecatedLinters := []string{ + "deadcode", + "execinquery", + "exhaustivestruct", + "exportloopref", + "golint", + "ifshort", + "interfacer", + "maligned", + "nosnakecase", + "scopelint", + "structcheck", + "tenv", + "typecheck", + "varcheck", + } + + var results []string + + for _, name := range names { + found := slices.ContainsFunc(linters, func(l LinterInfo) bool { + return l.isName(name) + }) + + if !found { + if slices.Contains(deprecatedLinters, name) { + continue + } + + results = append(results, name) + } + } + + return Unique(results) +} + +func convertStaticcheckLinterNames(names []string) []string { + var results []string + + for _, name := range names { + if slices.Contains([]string{"stylecheck", "gosimple"}, name) { + results = append(results, "staticcheck") + continue + } + + results = append(results, name) + } + + return Unique(results) +} + +func convertDisabledStaticcheckLinterNames(names []string) []string { + removeStaticcheck := slices.Contains(names, "staticcheck") && slices.Contains(names, "stylecheck") && slices.Contains(names, "gosimple") + + var results []string + + for _, name := range names { + if removeStaticcheck && slices.Contains([]string{"stylecheck", "gosimple", "staticcheck"}, name) { + results = append(results, "staticcheck") + continue + } + + if slices.Contains([]string{"stylecheck", "gosimple"}, name) { + continue + } + + results = append(results, name) + } + + return Unique(results) +} + +func onlyLinterNames(names []string) []string { + formatters := []string{"gci", "gofmt", "gofumpt", "goimports"} + + var results []string + + for _, name := range names { + if !slices.Contains(formatters, name) { + results = append(results, name) + } + } + + return results +} + +func onlyFormatterNames(names []string) []string { + formatters := getAllFormatterNames() + + var results []string + + for _, name := range names { + if slices.Contains(formatters, name) { + results = append(results, name) + } + } + + return results +} + +func convertAlternativeNames(names []string) []string { + altNames := map[string]string{ + "gas": "gosec", + "goerr113": "err113", + "gomnd": "mnd", + "logrlint": "loggercheck", + "megacheck": "staticcheck", + "vet": "govet", + "vetshadow": "govet", + } + + var results []string + + for _, name := range names { + if name == "typecheck" { + continue + } + + if n, ok := altNames[name]; ok { + results = append(results, n) + continue + } + + results = append(results, name) + } + + return Unique(results) +} + +func Unique[S ~[]E, E cmp.Ordered](s S) S { + return slices.Compact(slices.Sorted(slices.Values(s))) +} + +func getAllFormatterNames() []string { + return []string{"gci", "gofmt", "gofumpt", "goimports"} +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_linters.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_linters.go new file mode 100644 index 000000000..c070119b6 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_linters.go @@ -0,0 +1,31 @@ +package migrate + +import ( + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/ptr" + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone" + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo" +) + +func toLinters(old *versionone.Config) versiontwo.Linters { + enable, disable := ProcessEffectiveLinters(old.Linters) + + return versiontwo.Linters{ + Default: getDefaultName(old.Linters), + Enable: onlyLinterNames(convertStaticcheckLinterNames(enable)), + Disable: onlyLinterNames(convertDisabledStaticcheckLinterNames(disable)), + FastOnly: nil, + Settings: toLinterSettings(old.LintersSettings), + Exclusions: toExclusions(old), + } +} + +func getDefaultName(old versionone.Linters) *string { + switch { + case ptr.Deref(old.DisableAll): + return ptr.Pointer("none") + case ptr.Deref(old.EnableAll): + return ptr.Pointer("all") + default: + return nil // standard is the default + } +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_linters_exclusions.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_linters_exclusions.go new file mode 100644 index 000000000..aac4d381a --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_linters_exclusions.go @@ -0,0 +1,144 @@ +package migrate + +import ( + "slices" + + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/ptr" + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone" + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/result/processors" +) + +func toExclusions(old *versionone.Config) versiontwo.LinterExclusions { + return versiontwo.LinterExclusions{ + Generated: toExclusionGenerated(old.Issues.ExcludeGenerated), + Presets: toPresets(old.Issues), + Rules: toExclusionRules(old), + Paths: toExclusionPaths(old.Issues), + } +} + +func toExclusionGenerated(excludeGenerated *string) *string { + if excludeGenerated == nil || ptr.Deref(excludeGenerated) == "" { + return ptr.Pointer("lax") + } + + if ptr.Deref(excludeGenerated) == "strict" { + return nil + } + + return excludeGenerated +} + +func toPresets(old versionone.Issues) []string { + if old.UseDefaultExcludes != nil && !ptr.Deref(old.UseDefaultExcludes) { + return nil + } + + if len(old.IncludeDefaultExcludes) != 0 { + var pp []string + for p, rules := range processors.LinterExclusionPresets { + found := slices.ContainsFunc(rules, func(rule config.ExcludeRule) bool { + return slices.Contains(old.IncludeDefaultExcludes, rule.InternalReference) + }) + if !found { + pp = append(pp, p) + } + } + + slices.Sort(pp) + + return pp + } + + return []string{ + config.ExclusionPresetComments, + config.ExclusionPresetCommonFalsePositives, + config.ExclusionPresetLegacy, + config.ExclusionPresetStdErrorHandling, + } +} + +func toExclusionRules(old *versionone.Config) []versiontwo.ExcludeRule { + var results []versiontwo.ExcludeRule + + for _, rule := range old.Issues.ExcludeRules { + names := onlyLinterNames(convertStaticcheckLinterNames(convertAlternativeNames(rule.Linters))) + if len(rule.Linters) > 0 && len(names) == 0 { + continue + } + + results = append(results, versiontwo.ExcludeRule{ + BaseRule: versiontwo.BaseRule{ + Linters: names, + Path: rule.Path, + PathExcept: rule.PathExcept, + Text: addPrefix(old.Issues, rule.Text), + Source: addPrefix(old.Issues, rule.Source), + }, + }) + } + + for _, pattern := range old.Issues.ExcludePatterns { + results = append(results, versiontwo.ExcludeRule{ + BaseRule: versiontwo.BaseRule{ + Path: ptr.Pointer(`(.+)\.go$`), + Text: addPrefix(old.Issues, ptr.Pointer(pattern)), + }, + }) + } + + return slices.Concat(results, linterTestExclusions(old.LintersSettings)) +} + +func addPrefix(old versionone.Issues, s *string) *string { + if s == nil || ptr.Deref(s) == "" { + return s + } + + var prefix string + if ptr.Deref(old.ExcludeCaseSensitive) { + prefix = "(?i)" + } + + return ptr.Pointer(prefix + ptr.Deref(s)) +} + +func linterTestExclusions(old versionone.LintersSettings) []versiontwo.ExcludeRule { + var excludedTestLinters []string + + if ptr.Deref(old.Asasalint.IgnoreTest) { + excludedTestLinters = append(excludedTestLinters, "asasalint") + } + if ptr.Deref(old.Cyclop.SkipTests) { + excludedTestLinters = append(excludedTestLinters, "cyclop") + } + if ptr.Deref(old.Goconst.IgnoreTests) { + excludedTestLinters = append(excludedTestLinters, "goconst") + } + if ptr.Deref(old.Gosmopolitan.IgnoreTests) { + excludedTestLinters = append(excludedTestLinters, "gosmopolitan") + } + + if len(excludedTestLinters) == 0 { + return nil + } + + return []versiontwo.ExcludeRule{{ + BaseRule: versiontwo.BaseRule{ + Linters: excludedTestLinters, + Path: ptr.Pointer(`(.+)_test\.go`), + }, + }} +} + +func toExclusionPaths(old versionone.Issues) []string { + results := slices.Concat(old.ExcludeFiles, old.ExcludeDirs) + + if old.UseDefaultExcludeDirs == nil || ptr.Deref(old.UseDefaultExcludeDirs) { + results = append(results, "third_party$", "builtin$", "examples$") + } + + return results +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_linters_settings.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_linters_settings.go new file mode 100644 index 000000000..4656842d6 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_linters_settings.go @@ -0,0 +1,1037 @@ +package migrate + +import ( + "slices" + "strings" + + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/ptr" + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone" + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo" +) + +func toLinterSettings(old versionone.LintersSettings) versiontwo.LintersSettings { + return versiontwo.LintersSettings{ + Asasalint: toAsasalintSettings(old.Asasalint), + BiDiChk: toBiDiChkSettings(old.BiDiChk), + CopyLoopVar: toCopyLoopVarSettings(old.CopyLoopVar), + Cyclop: toCyclopSettings(old.Cyclop), + Decorder: toDecorderSettings(old.Decorder), + Depguard: toDepGuardSettings(old.Depguard), + Dogsled: toDogsledSettings(old.Dogsled), + Dupl: toDuplSettings(old.Dupl), + DupWord: toDupWordSettings(old.DupWord), + Errcheck: toErrcheckSettings(old.Errcheck), + ErrChkJSON: toErrChkJSONSettings(old.ErrChkJSON), + ErrorLint: toErrorLintSettings(old.ErrorLint), + Exhaustive: toExhaustiveSettings(old.Exhaustive), + Exhaustruct: toExhaustructSettings(old.Exhaustruct), + Fatcontext: toFatcontextSettings(old.Fatcontext), + Forbidigo: toForbidigoSettings(old.Forbidigo), + Funlen: toFunlenSettings(old.Funlen), + GinkgoLinter: toGinkgoLinterSettings(old.GinkgoLinter), + Gocognit: toGocognitSettings(old.Gocognit), + GoChecksumType: toGoChecksumTypeSettings(old.GoChecksumType), + Goconst: toGoConstSettings(old.Goconst), + Gocritic: toGoCriticSettings(old.Gocritic), + Gocyclo: toGoCycloSettings(old.Gocyclo), + Godot: toGodotSettings(old.Godot), + Godox: toGodoxSettings(old.Godox), + Goheader: toGoHeaderSettings(old.Goheader), + GoModDirectives: toGoModDirectivesSettings(old.GoModDirectives), + Gomodguard: toGoModGuardSettings(old.Gomodguard), + Gosec: toGoSecSettings(old.Gosec), + Gosmopolitan: toGosmopolitanSettings(old.Gosmopolitan), + Govet: toGovetSettings(old.Govet), + Grouper: toGrouperSettings(old.Grouper), + Iface: toIfaceSettings(old.Iface), + ImportAs: toImportAsSettings(old.ImportAs), + Inamedparam: toINamedParamSettings(old.Inamedparam), + InterfaceBloat: toInterfaceBloatSettings(old.InterfaceBloat), + Ireturn: toIreturnSettings(old.Ireturn), + Lll: toLllSettings(old.Lll), + LoggerCheck: toLoggerCheckSettings(old.LoggerCheck), + MaintIdx: toMaintIdxSettings(old.MaintIdx), + Makezero: toMakezeroSettings(old.Makezero), + Misspell: toMisspellSettings(old.Misspell), + Mnd: toMndSettings(old.Mnd), + MustTag: toMustTagSettings(old.MustTag), + Nakedret: toNakedretSettings(old.Nakedret), + Nestif: toNestifSettings(old.Nestif), + NilNil: toNilNilSettings(old.NilNil), + Nlreturn: toNlreturnSettings(old.Nlreturn), + NoLintLint: toNoLintLintSettings(old.NoLintLint), + NoNamedReturns: toNoNamedReturnsSettings(old.NoNamedReturns), + ParallelTest: toParallelTestSettings(old.ParallelTest), + PerfSprint: toPerfSprintSettings(old.PerfSprint), + Prealloc: toPreallocSettings(old.Prealloc), + Predeclared: toPredeclaredSettings(old.Predeclared), + Promlinter: toPromlinterSettings(old.Promlinter), + ProtoGetter: toProtoGetterSettings(old.ProtoGetter), + Reassign: toReassignSettings(old.Reassign), + Recvcheck: toRecvcheckSettings(old.Recvcheck), + Revive: toReviveSettings(old.Revive), + RowsErrCheck: toRowsErrCheckSettings(old.RowsErrCheck), + SlogLint: toSlogLintSettings(old.SlogLint), + Spancheck: toSpancheckSettings(old.Spancheck), + Staticcheck: toStaticCheckSettings(old), + TagAlign: toTagAlignSettings(old.TagAlign), + Tagliatelle: toTagliatelleSettings(old.Tagliatelle), + Testifylint: toTestifylintSettings(old.Testifylint), + Testpackage: toTestpackageSettings(old.Testpackage), + Thelper: toThelperSettings(old.Thelper), + Unconvert: toUnconvertSettings(old.Unconvert), + Unparam: toUnparamSettings(old.Unparam), + Unused: toUnusedSettings(old.Unused), + UseStdlibVars: toUseStdlibVarsSettings(old.UseStdlibVars), + UseTesting: toUseTestingSettings(old.UseTesting), + Varnamelen: toVarnamelenSettings(old.Varnamelen), + Whitespace: toWhitespaceSettings(old.Whitespace), + Wrapcheck: toWrapcheckSettings(old.Wrapcheck), + WSL: toWSLSettings(old.WSL), + Custom: toCustom(old.Custom), + } +} + +func toAsasalintSettings(old versionone.AsasalintSettings) versiontwo.AsasalintSettings { + return versiontwo.AsasalintSettings{ + Exclude: old.Exclude, + UseBuiltinExclusions: old.UseBuiltinExclusions, + } +} + +func toBiDiChkSettings(old versionone.BiDiChkSettings) versiontwo.BiDiChkSettings { + // The values are true be default, but the default are defined after the configuration loading. + // So the serialization doesn't have good results, but it's complex to do better. + return versiontwo.BiDiChkSettings{ + LeftToRightEmbedding: old.LeftToRightEmbedding, + RightToLeftEmbedding: old.RightToLeftEmbedding, + PopDirectionalFormatting: old.PopDirectionalFormatting, + LeftToRightOverride: old.LeftToRightOverride, + RightToLeftOverride: old.RightToLeftOverride, + LeftToRightIsolate: old.LeftToRightIsolate, + RightToLeftIsolate: old.RightToLeftIsolate, + FirstStrongIsolate: old.FirstStrongIsolate, + PopDirectionalIsolate: old.PopDirectionalIsolate, + } +} + +func toCopyLoopVarSettings(old versionone.CopyLoopVarSettings) versiontwo.CopyLoopVarSettings { + return versiontwo.CopyLoopVarSettings{ + CheckAlias: old.CheckAlias, + } +} + +func toCyclopSettings(old versionone.Cyclop) versiontwo.CyclopSettings { + return versiontwo.CyclopSettings{ + MaxComplexity: old.MaxComplexity, + PackageAverage: old.PackageAverage, + } +} + +func toDecorderSettings(old versionone.DecorderSettings) versiontwo.DecorderSettings { + return versiontwo.DecorderSettings{ + DecOrder: old.DecOrder, + IgnoreUnderscoreVars: old.IgnoreUnderscoreVars, + DisableDecNumCheck: old.DisableDecNumCheck, + DisableTypeDecNumCheck: old.DisableTypeDecNumCheck, + DisableConstDecNumCheck: old.DisableConstDecNumCheck, + DisableVarDecNumCheck: old.DisableVarDecNumCheck, + DisableDecOrderCheck: old.DisableDecOrderCheck, + DisableInitFuncFirstCheck: old.DisableInitFuncFirstCheck, + } +} + +func toDepGuardSettings(old versionone.DepGuardSettings) versiontwo.DepGuardSettings { + settings := versiontwo.DepGuardSettings{} + + for k, r := range old.Rules { + if settings.Rules == nil { + settings.Rules = make(map[string]*versiontwo.DepGuardList) + } + + list := &versiontwo.DepGuardList{ + ListMode: r.ListMode, + Files: r.Files, + Allow: r.Allow, + } + + for _, deny := range r.Deny { + list.Deny = append(list.Deny, versiontwo.DepGuardDeny{ + Pkg: deny.Pkg, + Desc: deny.Desc, + }) + } + + settings.Rules[k] = list + } + + return settings +} + +func toDogsledSettings(old versionone.DogsledSettings) versiontwo.DogsledSettings { + return versiontwo.DogsledSettings{ + MaxBlankIdentifiers: old.MaxBlankIdentifiers, + } +} + +func toDuplSettings(old versionone.DuplSettings) versiontwo.DuplSettings { + return versiontwo.DuplSettings{ + Threshold: old.Threshold, + } +} + +func toDupWordSettings(old versionone.DupWordSettings) versiontwo.DupWordSettings { + return versiontwo.DupWordSettings{ + Keywords: old.Keywords, + Ignore: old.Ignore, + } +} + +func toErrcheckSettings(old versionone.ErrcheckSettings) versiontwo.ErrcheckSettings { + return versiontwo.ErrcheckSettings{ + DisableDefaultExclusions: old.DisableDefaultExclusions, + CheckTypeAssertions: old.CheckTypeAssertions, + CheckAssignToBlank: old.CheckAssignToBlank, + ExcludeFunctions: old.ExcludeFunctions, + } +} + +func toErrChkJSONSettings(old versionone.ErrChkJSONSettings) versiontwo.ErrChkJSONSettings { + return versiontwo.ErrChkJSONSettings{ + CheckErrorFreeEncoding: old.CheckErrorFreeEncoding, + ReportNoExported: old.ReportNoExported, + } +} + +func toErrorLintSettings(old versionone.ErrorLintSettings) versiontwo.ErrorLintSettings { + settings := versiontwo.ErrorLintSettings{ + Errorf: old.Errorf, + ErrorfMulti: old.ErrorfMulti, + Asserts: old.Asserts, + Comparison: old.Comparison, + } + + for _, allowedError := range old.AllowedErrors { + settings.AllowedErrors = append(settings.AllowedErrors, versiontwo.ErrorLintAllowPair{ + Err: allowedError.Err, + Fun: allowedError.Fun, + }) + } + for _, allowedError := range old.AllowedErrorsWildcard { + settings.AllowedErrorsWildcard = append(settings.AllowedErrorsWildcard, versiontwo.ErrorLintAllowPair{ + Err: allowedError.Err, + Fun: allowedError.Fun, + }) + } + + return settings +} + +func toExhaustiveSettings(old versionone.ExhaustiveSettings) versiontwo.ExhaustiveSettings { + return versiontwo.ExhaustiveSettings{ + Check: old.Check, + DefaultSignifiesExhaustive: old.DefaultSignifiesExhaustive, + IgnoreEnumMembers: old.IgnoreEnumMembers, + IgnoreEnumTypes: old.IgnoreEnumTypes, + PackageScopeOnly: old.PackageScopeOnly, + ExplicitExhaustiveMap: old.ExplicitExhaustiveMap, + ExplicitExhaustiveSwitch: old.ExplicitExhaustiveSwitch, + DefaultCaseRequired: old.DefaultCaseRequired, + } +} + +func toExhaustructSettings(old versionone.ExhaustructSettings) versiontwo.ExhaustructSettings { + return versiontwo.ExhaustructSettings{ + Include: old.Include, + Exclude: old.Exclude, + } +} + +func toFatcontextSettings(old versionone.FatcontextSettings) versiontwo.FatcontextSettings { + return versiontwo.FatcontextSettings{ + CheckStructPointers: old.CheckStructPointers, + } +} + +func toForbidigoSettings(old versionone.ForbidigoSettings) versiontwo.ForbidigoSettings { + settings := versiontwo.ForbidigoSettings{ + ExcludeGodocExamples: old.ExcludeGodocExamples, + AnalyzeTypes: old.AnalyzeTypes, + } + + for _, pattern := range old.Forbid { + if pattern.Pattern == nil && pattern.Msg == nil && pattern.Package == nil { + buffer, err := pattern.MarshalString() + if err != nil { + // impossible case + panic(err) + } + + settings.Forbid = append(settings.Forbid, versiontwo.ForbidigoPattern{ + Pattern: ptr.Pointer(string(buffer)), + }) + + continue + } + + settings.Forbid = append(settings.Forbid, versiontwo.ForbidigoPattern{ + Pattern: pattern.Pattern, + Package: pattern.Package, + Msg: pattern.Msg, + }) + } + + return settings +} + +func toFunlenSettings(old versionone.FunlenSettings) versiontwo.FunlenSettings { + return versiontwo.FunlenSettings{ + Lines: old.Lines, + Statements: old.Statements, + IgnoreComments: old.IgnoreComments, + } +} + +func toGinkgoLinterSettings(old versionone.GinkgoLinterSettings) versiontwo.GinkgoLinterSettings { + return versiontwo.GinkgoLinterSettings{ + SuppressLenAssertion: old.SuppressLenAssertion, + SuppressNilAssertion: old.SuppressNilAssertion, + SuppressErrAssertion: old.SuppressErrAssertion, + SuppressCompareAssertion: old.SuppressCompareAssertion, + SuppressAsyncAssertion: old.SuppressAsyncAssertion, + SuppressTypeCompareWarning: old.SuppressTypeCompareWarning, + ForbidFocusContainer: old.ForbidFocusContainer, + AllowHaveLenZero: old.AllowHaveLenZero, + ForceExpectTo: old.ForceExpectTo, + ValidateAsyncIntervals: old.ValidateAsyncIntervals, + ForbidSpecPollution: old.ForbidSpecPollution, + ForceSucceedForFuncs: old.ForceSucceedForFuncs, + } +} + +func toGocognitSettings(old versionone.GocognitSettings) versiontwo.GocognitSettings { + return versiontwo.GocognitSettings{ + MinComplexity: old.MinComplexity, + } +} + +func toGoChecksumTypeSettings(old versionone.GoChecksumTypeSettings) versiontwo.GoChecksumTypeSettings { + return versiontwo.GoChecksumTypeSettings{ + DefaultSignifiesExhaustive: old.DefaultSignifiesExhaustive, + IncludeSharedInterfaces: old.IncludeSharedInterfaces, + } +} + +func toGoConstSettings(old versionone.GoConstSettings) versiontwo.GoConstSettings { + return versiontwo.GoConstSettings{ + IgnoreStrings: old.IgnoreStrings, + MatchWithConstants: old.MatchWithConstants, + MinStringLen: old.MinStringLen, + MinOccurrencesCount: old.MinOccurrencesCount, + ParseNumbers: old.ParseNumbers, + NumberMin: old.NumberMin, + NumberMax: old.NumberMax, + IgnoreCalls: old.IgnoreCalls, + } +} + +func toGoCriticSettings(old versionone.GoCriticSettings) versiontwo.GoCriticSettings { + settings := versiontwo.GoCriticSettings{ + Go: old.Go, + DisableAll: old.DisableAll, + EnabledChecks: old.EnabledChecks, + EnableAll: old.EnableAll, + DisabledChecks: old.DisabledChecks, + EnabledTags: old.EnabledTags, + DisabledTags: old.DisabledTags, + } + + for k, checkSettings := range old.SettingsPerCheck { + if settings.SettingsPerCheck == nil { + settings.SettingsPerCheck = make(map[string]versiontwo.GoCriticCheckSettings) + } + + if k != "ruleguard" { + settings.SettingsPerCheck[k] = versiontwo.GoCriticCheckSettings(checkSettings) + + continue + } + + gccs := versiontwo.GoCriticCheckSettings{} + + for sk, value := range checkSettings { + if sk != "rules" { + gccs[sk] = value + + continue + } + + if rules, ok := value.(string); ok { + gccs[sk] = strings.ReplaceAll(rules, "${configDir}", "${base-path}") + } + } + + settings.SettingsPerCheck[k] = gccs + } + + return settings +} + +func toGoCycloSettings(old versionone.GoCycloSettings) versiontwo.GoCycloSettings { + return versiontwo.GoCycloSettings{ + MinComplexity: old.MinComplexity, + } +} + +func toGodotSettings(old versionone.GodotSettings) versiontwo.GodotSettings { + return versiontwo.GodotSettings{ + Scope: old.Scope, + Exclude: old.Exclude, + Capital: old.Capital, + Period: old.Period, + } +} + +func toGodoxSettings(old versionone.GodoxSettings) versiontwo.GodoxSettings { + return versiontwo.GodoxSettings{ + Keywords: old.Keywords, + } +} + +func toGoHeaderSettings(old versionone.GoHeaderSettings) versiontwo.GoHeaderSettings { + return versiontwo.GoHeaderSettings{ + Values: old.Values, + Template: old.Template, + TemplatePath: old.TemplatePath, + } +} + +func toGoModDirectivesSettings(old versionone.GoModDirectivesSettings) versiontwo.GoModDirectivesSettings { + return versiontwo.GoModDirectivesSettings{ + ReplaceAllowList: old.ReplaceAllowList, + ReplaceLocal: old.ReplaceLocal, + ExcludeForbidden: old.ExcludeForbidden, + RetractAllowNoExplanation: old.RetractAllowNoExplanation, + ToolchainForbidden: old.ToolchainForbidden, + ToolchainPattern: old.ToolchainPattern, + ToolForbidden: old.ToolForbidden, + GoDebugForbidden: old.GoDebugForbidden, + GoVersionPattern: old.GoVersionPattern, + } +} + +func toGoModGuardSettings(old versionone.GoModGuardSettings) versiontwo.GoModGuardSettings { + blocked := versiontwo.GoModGuardBlocked{ + LocalReplaceDirectives: old.Blocked.LocalReplaceDirectives, + } + + for _, version := range old.Blocked.Modules { + data := map[string]versiontwo.GoModGuardModule{} + + for k, v := range version { + data[k] = versiontwo.GoModGuardModule{ + Recommendations: v.Recommendations, + Reason: v.Reason, + } + } + + blocked.Modules = append(blocked.Modules, data) + } + + for _, version := range old.Blocked.Versions { + data := map[string]versiontwo.GoModGuardVersion{} + + for k, v := range version { + data[k] = versiontwo.GoModGuardVersion{ + Version: v.Version, + Reason: v.Reason, + } + } + + blocked.Versions = append(blocked.Versions, data) + } + + return versiontwo.GoModGuardSettings{ + Allowed: versiontwo.GoModGuardAllowed{ + Modules: old.Allowed.Modules, + Domains: old.Allowed.Domains, + }, + Blocked: blocked, + } +} + +func toGoSecSettings(old versionone.GoSecSettings) versiontwo.GoSecSettings { + return versiontwo.GoSecSettings{ + Includes: old.Includes, + Excludes: old.Excludes, + Severity: old.Severity, + Confidence: old.Confidence, + Config: old.Config, + Concurrency: old.Concurrency, + } +} + +func toGosmopolitanSettings(old versionone.GosmopolitanSettings) versiontwo.GosmopolitanSettings { + return versiontwo.GosmopolitanSettings{ + AllowTimeLocal: old.AllowTimeLocal, + EscapeHatches: old.EscapeHatches, + WatchForScripts: old.WatchForScripts, + } +} + +func toGovetSettings(old versionone.GovetSettings) versiontwo.GovetSettings { + return versiontwo.GovetSettings{ + Go: old.Go, + Enable: old.Enable, + Disable: old.Disable, + EnableAll: old.EnableAll, + DisableAll: old.DisableAll, + Settings: old.Settings, + } +} + +func toGrouperSettings(old versionone.GrouperSettings) versiontwo.GrouperSettings { + return versiontwo.GrouperSettings{ + ConstRequireSingleConst: old.ConstRequireSingleConst, + ConstRequireGrouping: old.ConstRequireGrouping, + ImportRequireSingleImport: old.ImportRequireSingleImport, + ImportRequireGrouping: old.ImportRequireGrouping, + TypeRequireSingleType: old.TypeRequireSingleType, + TypeRequireGrouping: old.TypeRequireGrouping, + VarRequireSingleVar: old.VarRequireSingleVar, + VarRequireGrouping: old.VarRequireGrouping, + } +} + +func toIfaceSettings(old versionone.IfaceSettings) versiontwo.IfaceSettings { + return versiontwo.IfaceSettings{ + Enable: old.Enable, + Settings: old.Settings, + } +} + +func toImportAsSettings(old versionone.ImportAsSettings) versiontwo.ImportAsSettings { + settings := versiontwo.ImportAsSettings{ + NoUnaliased: old.NoUnaliased, + NoExtraAliases: old.NoExtraAliases, + } + + for _, alias := range old.Alias { + settings.Alias = append(settings.Alias, versiontwo.ImportAsAlias{ + Pkg: alias.Pkg, + Alias: alias.Alias, + }) + } + + return settings +} + +func toINamedParamSettings(old versionone.INamedParamSettings) versiontwo.INamedParamSettings { + return versiontwo.INamedParamSettings{ + SkipSingleParam: old.SkipSingleParam, + } +} + +func toInterfaceBloatSettings(old versionone.InterfaceBloatSettings) versiontwo.InterfaceBloatSettings { + return versiontwo.InterfaceBloatSettings{ + Max: old.Max, + } +} + +func toIreturnSettings(old versionone.IreturnSettings) versiontwo.IreturnSettings { + return versiontwo.IreturnSettings{ + Allow: old.Allow, + Reject: old.Reject, + } +} + +func toLllSettings(old versionone.LllSettings) versiontwo.LllSettings { + return versiontwo.LllSettings{ + LineLength: old.LineLength, + TabWidth: old.TabWidth, + } +} + +func toLoggerCheckSettings(old versionone.LoggerCheckSettings) versiontwo.LoggerCheckSettings { + return versiontwo.LoggerCheckSettings{ + Kitlog: old.Kitlog, + Klog: old.Klog, + Logr: old.Logr, + Slog: old.Slog, + Zap: old.Zap, + RequireStringKey: old.RequireStringKey, + NoPrintfLike: old.NoPrintfLike, + Rules: old.Rules, + } +} + +func toMaintIdxSettings(old versionone.MaintIdxSettings) versiontwo.MaintIdxSettings { + return versiontwo.MaintIdxSettings{ + Under: old.Under, + } +} + +func toMakezeroSettings(old versionone.MakezeroSettings) versiontwo.MakezeroSettings { + return versiontwo.MakezeroSettings{ + Always: old.Always, + } +} + +func toMisspellSettings(old versionone.MisspellSettings) versiontwo.MisspellSettings { + settings := versiontwo.MisspellSettings{ + Mode: old.Mode, + Locale: old.Locale, + IgnoreRules: old.IgnoreWords, + } + + for _, word := range old.ExtraWords { + settings.ExtraWords = append(settings.ExtraWords, versiontwo.MisspellExtraWords{ + Typo: word.Typo, + Correction: word.Correction, + }) + } + + return settings +} + +func toMndSettings(old versionone.MndSettings) versiontwo.MndSettings { + return versiontwo.MndSettings{ + Checks: old.Checks, + IgnoredNumbers: old.IgnoredNumbers, + IgnoredFiles: old.IgnoredFiles, + IgnoredFunctions: old.IgnoredFunctions, + } +} + +func toMustTagSettings(old versionone.MustTagSettings) versiontwo.MustTagSettings { + settings := versiontwo.MustTagSettings{} + + for _, function := range old.Functions { + settings.Functions = append(settings.Functions, versiontwo.MustTagFunction{ + Name: function.Name, + Tag: function.Tag, + ArgPos: function.ArgPos, + }) + } + + return settings +} + +func toNakedretSettings(old versionone.NakedretSettings) versiontwo.NakedretSettings { + return versiontwo.NakedretSettings{ + MaxFuncLines: old.MaxFuncLines, + } +} + +func toNestifSettings(old versionone.NestifSettings) versiontwo.NestifSettings { + return versiontwo.NestifSettings{ + MinComplexity: old.MinComplexity, + } +} + +func toNilNilSettings(old versionone.NilNilSettings) versiontwo.NilNilSettings { + return versiontwo.NilNilSettings{ + DetectOpposite: old.DetectOpposite, + CheckedTypes: old.CheckedTypes, + } +} + +func toNlreturnSettings(old versionone.NlreturnSettings) versiontwo.NlreturnSettings { + return versiontwo.NlreturnSettings{ + BlockSize: old.BlockSize, + } +} + +func toNoLintLintSettings(old versionone.NoLintLintSettings) versiontwo.NoLintLintSettings { + return versiontwo.NoLintLintSettings{ + RequireExplanation: old.RequireExplanation, + RequireSpecific: old.RequireSpecific, + AllowNoExplanation: old.AllowNoExplanation, + AllowUnused: old.AllowUnused, + } +} + +func toNoNamedReturnsSettings(old versionone.NoNamedReturnsSettings) versiontwo.NoNamedReturnsSettings { + return versiontwo.NoNamedReturnsSettings{ + ReportErrorInDefer: old.ReportErrorInDefer, + } +} + +func toParallelTestSettings(old versionone.ParallelTestSettings) versiontwo.ParallelTestSettings { + return versiontwo.ParallelTestSettings{ + Go: nil, + IgnoreMissing: old.IgnoreMissing, + IgnoreMissingSubtests: old.IgnoreMissingSubtests, + } +} + +func toPerfSprintSettings(old versionone.PerfSprintSettings) versiontwo.PerfSprintSettings { + return versiontwo.PerfSprintSettings{ + IntegerFormat: old.IntegerFormat, + IntConversion: old.IntConversion, + ErrorFormat: old.ErrorFormat, + ErrError: old.ErrError, + ErrorF: old.ErrorF, + StringFormat: old.StringFormat, + SprintF1: old.SprintF1, + StrConcat: old.StrConcat, + BoolFormat: old.BoolFormat, + HexFormat: old.HexFormat, + } +} + +func toPreallocSettings(old versionone.PreallocSettings) versiontwo.PreallocSettings { + return versiontwo.PreallocSettings{ + Simple: old.Simple, + RangeLoops: old.RangeLoops, + ForLoops: old.ForLoops, + } +} + +func toPredeclaredSettings(old versionone.PredeclaredSettings) versiontwo.PredeclaredSettings { + var ignore []string + if ptr.Deref(old.Ignore) != "" { + ignore = strings.Split(ptr.Deref(old.Ignore), ",") + } + + return versiontwo.PredeclaredSettings{ + Ignore: ignore, + Qualified: old.Qualified, + } +} + +func toPromlinterSettings(old versionone.PromlinterSettings) versiontwo.PromlinterSettings { + return versiontwo.PromlinterSettings{ + Strict: old.Strict, + DisabledLinters: old.DisabledLinters, + } +} + +func toProtoGetterSettings(old versionone.ProtoGetterSettings) versiontwo.ProtoGetterSettings { + return versiontwo.ProtoGetterSettings{ + SkipGeneratedBy: old.SkipGeneratedBy, + SkipFiles: old.SkipFiles, + SkipAnyGenerated: old.SkipAnyGenerated, + ReplaceFirstArgInAppend: old.ReplaceFirstArgInAppend, + } +} + +func toReassignSettings(old versionone.ReassignSettings) versiontwo.ReassignSettings { + return versiontwo.ReassignSettings{ + Patterns: old.Patterns, + } +} + +func toRecvcheckSettings(old versionone.RecvcheckSettings) versiontwo.RecvcheckSettings { + return versiontwo.RecvcheckSettings{ + DisableBuiltin: old.DisableBuiltin, + Exclusions: old.Exclusions, + } +} + +func toReviveSettings(old versionone.ReviveSettings) versiontwo.ReviveSettings { + settings := versiontwo.ReviveSettings{ + MaxOpenFiles: old.MaxOpenFiles, + Confidence: old.Confidence, + Severity: old.Severity, + EnableAllRules: old.EnableAllRules, + ErrorCode: old.ErrorCode, + WarningCode: old.WarningCode, + } + + for _, rule := range old.Rules { + settings.Rules = append(settings.Rules, versiontwo.ReviveRule{ + Name: rule.Name, + Arguments: rule.Arguments, + Severity: rule.Severity, + Disabled: rule.Disabled, + Exclude: rule.Exclude, + }) + } + + for _, directive := range old.Directives { + settings.Directives = append(settings.Directives, versiontwo.ReviveDirective{ + Name: directive.Name, + Severity: directive.Severity, + }) + } + + return settings +} + +func toRowsErrCheckSettings(old versionone.RowsErrCheckSettings) versiontwo.RowsErrCheckSettings { + return versiontwo.RowsErrCheckSettings{ + Packages: old.Packages, + } +} + +func toSlogLintSettings(old versionone.SlogLintSettings) versiontwo.SlogLintSettings { + return versiontwo.SlogLintSettings{ + NoMixedArgs: old.NoMixedArgs, + KVOnly: old.KVOnly, + AttrOnly: old.AttrOnly, + NoGlobal: old.NoGlobal, + Context: old.Context, + StaticMsg: old.StaticMsg, + NoRawKeys: old.NoRawKeys, + KeyNamingCase: old.KeyNamingCase, + ForbiddenKeys: old.ForbiddenKeys, + ArgsOnSepLines: old.ArgsOnSepLines, + } +} + +func toSpancheckSettings(old versionone.SpancheckSettings) versiontwo.SpancheckSettings { + return versiontwo.SpancheckSettings{ + Checks: old.Checks, + IgnoreCheckSignatures: old.IgnoreCheckSignatures, + ExtraStartSpanSignatures: old.ExtraStartSpanSignatures, + } +} + +func toStaticCheckSettings(old versionone.LintersSettings) versiontwo.StaticCheckSettings { + var checks []string + + for _, check := range slices.Concat(old.Staticcheck.Checks, old.Stylecheck.Checks, old.Gosimple.Checks) { + if check == "*" { + checks = append(checks, "all") + continue + } + checks = append(checks, check) + } + + checks = Unique(checks) + + slices.SortFunc(checks, func(a, b string) int { + if a == "all" { + return -1 + } + + if b == "all" { + return 1 + } + + return strings.Compare(a, b) + }) + + return versiontwo.StaticCheckSettings{ + Checks: checks, + Initialisms: old.Stylecheck.Initialisms, + DotImportWhitelist: old.Stylecheck.DotImportWhitelist, + HTTPStatusCodeWhitelist: old.Stylecheck.HTTPStatusCodeWhitelist, + } +} + +func toTagAlignSettings(old versionone.TagAlignSettings) versiontwo.TagAlignSettings { + return versiontwo.TagAlignSettings{ + Align: old.Align, + Sort: old.Sort, + Order: old.Order, + Strict: old.Strict, + } +} + +func toTagliatelleSettings(old versionone.TagliatelleSettings) versiontwo.TagliatelleSettings { + tcase := versiontwo.TagliatelleCase{ + TagliatelleBase: versiontwo.TagliatelleBase{ + Rules: old.Case.Rules, + UseFieldName: old.Case.UseFieldName, + IgnoredFields: old.Case.IgnoredFields, + }, + Overrides: []versiontwo.TagliatelleOverrides{}, + } + + for k, rule := range old.Case.ExtendedRules { + if tcase.ExtendedRules == nil { + tcase.ExtendedRules = make(map[string]versiontwo.TagliatelleExtendedRule) + } + + tcase.ExtendedRules[k] = versiontwo.TagliatelleExtendedRule{ + Case: rule.Case, + ExtraInitialisms: rule.ExtraInitialisms, + InitialismOverrides: rule.InitialismOverrides, + } + } + + return versiontwo.TagliatelleSettings{Case: tcase} +} + +func toTestifylintSettings(old versionone.TestifylintSettings) versiontwo.TestifylintSettings { + return versiontwo.TestifylintSettings{ + EnableAll: old.EnableAll, + DisableAll: old.DisableAll, + EnabledCheckers: old.EnabledCheckers, + DisabledCheckers: old.DisabledCheckers, + BoolCompare: versiontwo.TestifylintBoolCompare{ + IgnoreCustomTypes: old.BoolCompare.IgnoreCustomTypes, + }, + ExpectedActual: versiontwo.TestifylintExpectedActual{ + ExpVarPattern: old.ExpectedActual.ExpVarPattern, + }, + Formatter: versiontwo.TestifylintFormatter{ + CheckFormatString: old.Formatter.CheckFormatString, + RequireFFuncs: old.Formatter.RequireFFuncs, + }, + GoRequire: versiontwo.TestifylintGoRequire{ + IgnoreHTTPHandlers: old.GoRequire.IgnoreHTTPHandlers, + }, + RequireError: versiontwo.TestifylintRequireError{ + FnPattern: old.RequireError.FnPattern, + }, + SuiteExtraAssertCall: versiontwo.TestifylintSuiteExtraAssertCall{ + Mode: old.SuiteExtraAssertCall.Mode, + }, + } +} + +func toTestpackageSettings(old versionone.TestpackageSettings) versiontwo.TestpackageSettings { + return versiontwo.TestpackageSettings{ + SkipRegexp: old.SkipRegexp, + AllowPackages: old.AllowPackages, + } +} + +func toThelperSettings(old versionone.ThelperSettings) versiontwo.ThelperSettings { + return versiontwo.ThelperSettings{ + Test: versiontwo.ThelperOptions{ + First: old.Test.First, + Name: old.Test.Name, + Begin: old.Test.Begin, + }, + Fuzz: versiontwo.ThelperOptions{ + First: old.Fuzz.First, + Name: old.Fuzz.Name, + Begin: old.Fuzz.Begin, + }, + Benchmark: versiontwo.ThelperOptions{ + First: old.Benchmark.First, + Name: old.Benchmark.Name, + Begin: old.Benchmark.Begin, + }, + TB: versiontwo.ThelperOptions{ + First: old.TB.First, + Name: old.TB.Name, + Begin: old.TB.Begin, + }, + } +} + +func toUnconvertSettings(old versionone.UnconvertSettings) versiontwo.UnconvertSettings { + return versiontwo.UnconvertSettings{ + FastMath: old.FastMath, + Safe: old.Safe, + } +} + +func toUnparamSettings(old versionone.UnparamSettings) versiontwo.UnparamSettings { + return versiontwo.UnparamSettings{ + CheckExported: old.CheckExported, + } +} + +func toUnusedSettings(old versionone.UnusedSettings) versiontwo.UnusedSettings { + return versiontwo.UnusedSettings{ + FieldWritesAreUses: old.FieldWritesAreUses, + PostStatementsAreReads: old.PostStatementsAreReads, + ExportedFieldsAreUsed: old.ExportedFieldsAreUsed, + ParametersAreUsed: old.ParametersAreUsed, + LocalVariablesAreUsed: old.LocalVariablesAreUsed, + GeneratedIsUsed: old.GeneratedIsUsed, + } +} + +func toUseStdlibVarsSettings(old versionone.UseStdlibVarsSettings) versiontwo.UseStdlibVarsSettings { + return versiontwo.UseStdlibVarsSettings{ + HTTPMethod: old.HTTPMethod, + HTTPStatusCode: old.HTTPStatusCode, + TimeWeekday: old.TimeWeekday, + TimeMonth: old.TimeMonth, + TimeLayout: old.TimeLayout, + CryptoHash: old.CryptoHash, + DefaultRPCPath: old.DefaultRPCPath, + SQLIsolationLevel: old.SQLIsolationLevel, + TLSSignatureScheme: old.TLSSignatureScheme, + ConstantKind: old.ConstantKind, + } +} + +func toUseTestingSettings(old versionone.UseTestingSettings) versiontwo.UseTestingSettings { + return versiontwo.UseTestingSettings{ + ContextBackground: old.ContextBackground, + ContextTodo: old.ContextTodo, + OSChdir: old.OSChdir, + OSMkdirTemp: old.OSMkdirTemp, + OSSetenv: old.OSSetenv, + OSTempDir: old.OSTempDir, + OSCreateTemp: old.OSCreateTemp, + } +} + +func toVarnamelenSettings(old versionone.VarnamelenSettings) versiontwo.VarnamelenSettings { + return versiontwo.VarnamelenSettings{ + MaxDistance: old.MaxDistance, + MinNameLength: old.MinNameLength, + CheckReceiver: old.CheckReceiver, + CheckReturn: old.CheckReturn, + CheckTypeParam: old.CheckTypeParam, + IgnoreNames: old.IgnoreNames, + IgnoreTypeAssertOk: old.IgnoreTypeAssertOk, + IgnoreMapIndexOk: old.IgnoreMapIndexOk, + IgnoreChanRecvOk: old.IgnoreChanRecvOk, + IgnoreDecls: old.IgnoreDecls, + } +} + +func toWhitespaceSettings(old versionone.WhitespaceSettings) versiontwo.WhitespaceSettings { + return versiontwo.WhitespaceSettings{ + MultiIf: old.MultiIf, + MultiFunc: old.MultiFunc, + } +} + +func toWrapcheckSettings(old versionone.WrapcheckSettings) versiontwo.WrapcheckSettings { + return versiontwo.WrapcheckSettings{ + ExtraIgnoreSigs: old.ExtraIgnoreSigs, + IgnoreSigs: old.IgnoreSigs, + IgnoreSigRegexps: old.IgnoreSigRegexps, + IgnorePackageGlobs: old.IgnorePackageGlobs, + IgnoreInterfaceRegexps: old.IgnoreInterfaceRegexps, + } +} + +func toWSLSettings(old versionone.WSLSettings) versiontwo.WSLv4Settings { + return versiontwo.WSLv4Settings{ + StrictAppend: old.StrictAppend, + AllowAssignAndCallCuddle: old.AllowAssignAndCallCuddle, + AllowAssignAndAnythingCuddle: old.AllowAssignAndAnythingCuddle, + AllowMultiLineAssignCuddle: old.AllowMultiLineAssignCuddle, + ForceCaseTrailingWhitespaceLimit: old.ForceCaseTrailingWhitespaceLimit, + AllowTrailingComment: old.AllowTrailingComment, + AllowSeparatedLeadingComment: old.AllowSeparatedLeadingComment, + AllowCuddleDeclaration: old.AllowCuddleDeclaration, + AllowCuddleWithCalls: old.AllowCuddleWithCalls, + AllowCuddleWithRHS: old.AllowCuddleWithRHS, + ForceCuddleErrCheckAndAssign: old.ForceCuddleErrCheckAndAssign, + ErrorVariableNames: old.ErrorVariableNames, + ForceExclusiveShortDeclarations: old.ForceExclusiveShortDeclarations, + } +} + +func toCustom(old map[string]versionone.CustomLinterSettings) map[string]versiontwo.CustomLinterSettings { + if old == nil { + return nil + } + + settings := map[string]versiontwo.CustomLinterSettings{} + + for k, s := range old { + settings[k] = versiontwo.CustomLinterSettings{ + Type: s.Type, + Path: s.Path, + Description: s.Description, + OriginalURL: s.OriginalURL, + Settings: s.Settings, + } + } + + return settings +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_output.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_output.go new file mode 100644 index 000000000..e76f8e447 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_output.go @@ -0,0 +1,103 @@ +package migrate + +import ( + "slices" + + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/ptr" + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone" + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo" +) + +func toOutput(old *versionone.Config) versiontwo.Output { + formats := versiontwo.Formats{} + + oldFormats := cleanIncompatibleFormats(old.Output.Formats, "colored-line-number", "line-number") + oldFormats = cleanIncompatibleFormats(oldFormats, "colored-tab", "tab") + oldFormats = cleanIncompatibleFormats(oldFormats, "junit-xml-extended", "junit-xml") + + for _, format := range oldFormats { + switch ptr.Deref(format.Format) { + case "colored-line-number": + formats.Text.PrintLinterName = old.Output.PrintLinterName + formats.Text.PrintIssuedLine = old.Output.PrintIssuedLine + formats.Text.Colors = nil // color is true by default (flags). + formats.Text.Path = ptr.Pointer(defaultFormatPath(ptr.Deref(format.Path))) + + case "line-number": + formats.Text.PrintLinterName = old.Output.PrintLinterName + formats.Text.PrintIssuedLine = old.Output.PrintIssuedLine + formats.Text.Colors = ptr.Pointer(false) + formats.Text.Path = ptr.Pointer(defaultFormatPath(ptr.Deref(format.Path))) + + case "json": + formats.JSON.Path = ptr.Pointer(defaultFormatPath(ptr.Deref(format.Path))) + + case "colored-tab": + formats.Tab.PrintLinterName = old.Output.PrintLinterName + formats.Tab.Colors = nil // Colors is true by default (flags). + formats.Tab.Path = ptr.Pointer(defaultFormatPath(ptr.Deref(format.Path))) + + case "tab": + formats.Tab.PrintLinterName = old.Output.PrintLinterName + formats.Tab.Colors = ptr.Pointer(false) + formats.Tab.Path = ptr.Pointer(defaultFormatPath(ptr.Deref(format.Path))) + + case "html": + formats.HTML.Path = ptr.Pointer(defaultFormatPath(ptr.Deref(format.Path))) + + case "checkstyle": + formats.Checkstyle.Path = ptr.Pointer(defaultFormatPath(ptr.Deref(format.Path))) + + case "code-climate": + formats.CodeClimate.Path = ptr.Pointer(defaultFormatPath(ptr.Deref(format.Path))) + + case "junit-xml": + formats.JUnitXML.Extended = nil // Extended is false by default. + formats.JUnitXML.Path = ptr.Pointer(defaultFormatPath(ptr.Deref(format.Path))) + + case "junit-xml-extended": + formats.JUnitXML.Extended = ptr.Pointer(true) + formats.JUnitXML.Path = ptr.Pointer(defaultFormatPath(ptr.Deref(format.Path))) + + case "github-actions": + // Ignored + + case "teamcity": + formats.TeamCity.Path = ptr.Pointer(defaultFormatPath(ptr.Deref(format.Path))) + + case "sarif": + formats.Sarif.Path = ptr.Pointer(defaultFormatPath(ptr.Deref(format.Path))) + } + } + + return versiontwo.Output{ + Formats: formats, + SortOrder: old.Output.SortOrder, + PathPrefix: old.Output.PathPrefix, + ShowStats: nil, // Enforce the new default. (nil -> omitempty -> true) + } +} + +func defaultFormatPath(p string) string { + if p == "" { + return "stdout" + } + + return p +} + +func cleanIncompatibleFormats(old versionone.OutputFormats, f1, f2 string) versionone.OutputFormats { + index1 := slices.IndexFunc(old, func(format versionone.OutputFormat) bool { + return ptr.Deref(format.Format) == f1 + }) + + index2 := slices.IndexFunc(old, func(format versionone.OutputFormat) bool { + return ptr.Deref(format.Format) == f2 + }) + + if index1 >= 0 && index2 >= 0 { + return slices.Delete(old, index2, index2+1) + } + + return old +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_run.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_run.go new file mode 100644 index 000000000..88db44709 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_run.go @@ -0,0 +1,34 @@ +package migrate + +import ( + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/ptr" + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone" + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo" +) + +func toRun(old *versionone.Config) versiontwo.Run { + var relativePathMode *string + if ptr.Deref(old.Run.RelativePathMode) != "cfg" { + // cfg is the new default. + relativePathMode = old.Run.RelativePathMode + } + + var concurrency *int + if ptr.Deref(old.Run.Concurrency) != 0 { + // 0 is the new default + concurrency = old.Run.Concurrency + } + + return versiontwo.Run{ + Timeout: 0, // Enforce new default. + Concurrency: concurrency, + Go: old.Run.Go, + RelativePathMode: relativePathMode, + BuildTags: old.Run.BuildTags, + ModulesDownloadMode: old.Run.ModulesDownloadMode, + ExitCodeIfIssuesFound: old.Run.ExitCodeIfIssuesFound, + AnalyzeTests: old.Run.AnalyzeTests, + AllowParallelRunners: old.Run.AllowParallelRunners, + AllowSerialRunners: old.Run.AllowSerialRunners, + } +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_severity.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_severity.go new file mode 100644 index 000000000..6db40bca7 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/migrate_severity.go @@ -0,0 +1,33 @@ +package migrate + +import ( + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone" + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo" +) + +func toSeverity(old *versionone.Config) versiontwo.Severity { + var rules []versiontwo.SeverityRule + + for _, rule := range old.Severity.Rules { + names := convertStaticcheckLinterNames(convertAlternativeNames(rule.Linters)) + if len(rule.Linters) > 0 && len(names) == 0 { + continue + } + + rules = append(rules, versiontwo.SeverityRule{ + BaseRule: versiontwo.BaseRule{ + Linters: names, + Path: rule.Path, + PathExcept: rule.PathExcept, + Text: rule.Text, + Source: rule.Source, + }, + Severity: rule.Severity, + }) + } + + return versiontwo.Severity{ + Default: old.Severity.Default, + Rules: rules, + } +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/parser/parser.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/parser/parser.go new file mode 100644 index 000000000..293eaf18a --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/parser/parser.go @@ -0,0 +1,87 @@ +package parser + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io" + "path/filepath" + "strings" + + "github.com/pelletier/go-toml/v2" + "go.yaml.in/yaml/v3" +) + +type File interface { + io.ReadWriter + Name() string +} + +// Decode decodes a file into data. +// The choice of the decoder is based on the file extension. +func Decode(file File, data any) error { + ext := filepath.Ext(file.Name()) + + switch strings.ToLower(ext) { + case ".yaml", ".yml", ".json": + err := yaml.NewDecoder(file).Decode(data) + if err != nil && !errors.Is(err, io.EOF) { + return fmt.Errorf("YAML decode file %s: %w", file.Name(), err) + } + + case ".toml": + err := toml.NewDecoder(file).Decode(&data) + if err != nil { + return fmt.Errorf("TOML decode file %s: %w", file.Name(), err) + } + + default: + return fmt.Errorf("unsupported file type: %s", ext) + } + + return nil +} + +// Encode encodes data into a file. +// The choice of the encoder is based on the file extension. +func Encode(data any, dstFile File) error { + ext := filepath.Ext(dstFile.Name()) + + switch strings.ToLower(ext) { + case ".yml", ".yaml": + encoder := yaml.NewEncoder(dstFile) + encoder.SetIndent(2) + + return encoder.Encode(data) + + case ".toml": + encoder := toml.NewEncoder(dstFile) + + return encoder.Encode(data) + + case ".json": + // The JSON encoder converts empty struct to `{}` instead of nothing (even with omitempty JSON struct tags). + // So we need to use the YAML encoder as bridge to create JSON file. + + var buf bytes.Buffer + err := yaml.NewEncoder(&buf).Encode(data) + if err != nil { + return err + } + + raw := map[string]any{} + err = yaml.NewDecoder(&buf).Decode(raw) + if err != nil { + return err + } + + encoder := json.NewEncoder(dstFile) + encoder.SetIndent("", " ") + + return encoder.Encode(raw) + + default: + return fmt.Errorf("unsupported file type: %s", ext) + } +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/ptr/ptr.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/ptr/ptr.go new file mode 100644 index 000000000..b0c7974e0 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/ptr/ptr.go @@ -0,0 +1,12 @@ +package ptr + +func Deref[T any](v *T) T { + if v == nil { + var zero T + return zero + } + + return *v +} + +func Pointer[T any](v T) *T { return &v } diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/base_rule.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/base_rule.go new file mode 100644 index 000000000..244e25997 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/base_rule.go @@ -0,0 +1,9 @@ +package versionone + +type BaseRule struct { + Linters []string `mapstructure:"linters"` + Path *string `mapstructure:"path"` + PathExcept *string `mapstructure:"path-except"` + Text *string `mapstructure:"text"` + Source *string `mapstructure:"source"` +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/config.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/config.go new file mode 100644 index 000000000..1e9d0ee15 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/config.go @@ -0,0 +1,18 @@ +package versionone + +type Config struct { + Version string `mapstructure:"version"` // From v2, to be able to detect already migrated config file. + + Run Run `mapstructure:"run"` + + Output Output `mapstructure:"output"` + + LintersSettings LintersSettings `mapstructure:"linters-settings"` + Linters Linters `mapstructure:"linters"` + Issues Issues `mapstructure:"issues"` + Severity Severity `mapstructure:"severity"` +} + +func NewConfig() *Config { + return &Config{} +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/doc.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/doc.go new file mode 100644 index 000000000..fb945f3c5 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/doc.go @@ -0,0 +1,4 @@ +// Package versionone contains a modified copy of v1 configuration. +// The structures are altered to use pointer on builtin types. +// The field version is added to enforce the detection of already migrated file. +package versionone diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/issues.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/issues.go new file mode 100644 index 000000000..bac6ba9ca --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/issues.go @@ -0,0 +1,32 @@ +package versionone + +type Issues struct { + IncludeDefaultExcludes []string `mapstructure:"include"` + ExcludeCaseSensitive *bool `mapstructure:"exclude-case-sensitive"` + ExcludePatterns []string `mapstructure:"exclude"` + ExcludeRules []ExcludeRule `mapstructure:"exclude-rules"` + UseDefaultExcludes *bool `mapstructure:"exclude-use-default"` + + ExcludeGenerated *string `mapstructure:"exclude-generated"` + + ExcludeFiles []string `mapstructure:"exclude-files"` + ExcludeDirs []string `mapstructure:"exclude-dirs"` + + UseDefaultExcludeDirs *bool `mapstructure:"exclude-dirs-use-default"` + + MaxIssuesPerLinter *int `mapstructure:"max-issues-per-linter"` + MaxSameIssues *int `mapstructure:"max-same-issues"` + UniqByLine *bool `mapstructure:"uniq-by-line"` + + DiffFromRevision *string `mapstructure:"new-from-rev"` + DiffFromMergeBase *string `mapstructure:"new-from-merge-base"` + DiffPatchFilePath *string `mapstructure:"new-from-patch"` + WholeFiles *bool `mapstructure:"whole-files"` + Diff *bool `mapstructure:"new"` + + NeedFix *bool `mapstructure:"fix"` +} + +type ExcludeRule struct { + BaseRule `mapstructure:",squash"` +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/linters.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/linters.go new file mode 100644 index 000000000..d6a490fee --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/linters.go @@ -0,0 +1,11 @@ +package versionone + +type Linters struct { + Enable []string `mapstructure:"enable"` + Disable []string `mapstructure:"disable"` + EnableAll *bool `mapstructure:"enable-all"` + DisableAll *bool `mapstructure:"disable-all"` + Fast *bool `mapstructure:"fast"` + + Presets []string `mapstructure:"presets"` +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/linters_settings.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/linters_settings.go new file mode 100644 index 000000000..3c641541c --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/linters_settings.go @@ -0,0 +1,865 @@ +package versionone + +import ( + "encoding" + + "go.yaml.in/yaml/v3" + + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/ptr" +) + +type LintersSettings struct { + Asasalint AsasalintSettings `mapstructure:"asasalint"` + BiDiChk BiDiChkSettings `mapstructure:"bidichk"` + CopyLoopVar CopyLoopVarSettings `mapstructure:"copyloopvar"` + Cyclop Cyclop `mapstructure:"cyclop"` + Decorder DecorderSettings `mapstructure:"decorder"` + Depguard DepGuardSettings `mapstructure:"depguard"` + Dogsled DogsledSettings `mapstructure:"dogsled"` + Dupl DuplSettings `mapstructure:"dupl"` + DupWord DupWordSettings `mapstructure:"dupword"` + Errcheck ErrcheckSettings `mapstructure:"errcheck"` + ErrChkJSON ErrChkJSONSettings `mapstructure:"errchkjson"` + ErrorLint ErrorLintSettings `mapstructure:"errorlint"` + Exhaustive ExhaustiveSettings `mapstructure:"exhaustive"` + Exhaustruct ExhaustructSettings `mapstructure:"exhaustruct"` + Fatcontext FatcontextSettings `mapstructure:"fatcontext"` + Forbidigo ForbidigoSettings `mapstructure:"forbidigo"` + Funlen FunlenSettings `mapstructure:"funlen"` + GinkgoLinter GinkgoLinterSettings `mapstructure:"ginkgolinter"` + Gocognit GocognitSettings `mapstructure:"gocognit"` + GoChecksumType GoChecksumTypeSettings `mapstructure:"gochecksumtype"` + Goconst GoConstSettings `mapstructure:"goconst"` + Gocritic GoCriticSettings `mapstructure:"gocritic"` + Gocyclo GoCycloSettings `mapstructure:"gocyclo"` + Godot GodotSettings `mapstructure:"godot"` + Godox GodoxSettings `mapstructure:"godox"` + Goheader GoHeaderSettings `mapstructure:"goheader"` + GoModDirectives GoModDirectivesSettings `mapstructure:"gomoddirectives"` + Gomodguard GoModGuardSettings `mapstructure:"gomodguard"` + Gosec GoSecSettings `mapstructure:"gosec"` + Gosimple StaticCheckSettings `mapstructure:"gosimple"` + Gosmopolitan GosmopolitanSettings `mapstructure:"gosmopolitan"` + Govet GovetSettings `mapstructure:"govet"` + Grouper GrouperSettings `mapstructure:"grouper"` + Iface IfaceSettings `mapstructure:"iface"` + ImportAs ImportAsSettings `mapstructure:"importas"` + Inamedparam INamedParamSettings `mapstructure:"inamedparam"` + InterfaceBloat InterfaceBloatSettings `mapstructure:"interfacebloat"` + Ireturn IreturnSettings `mapstructure:"ireturn"` + Lll LllSettings `mapstructure:"lll"` + LoggerCheck LoggerCheckSettings `mapstructure:"loggercheck"` + MaintIdx MaintIdxSettings `mapstructure:"maintidx"` + Makezero MakezeroSettings `mapstructure:"makezero"` + Misspell MisspellSettings `mapstructure:"misspell"` + Mnd MndSettings `mapstructure:"mnd"` + MustTag MustTagSettings `mapstructure:"musttag"` + Nakedret NakedretSettings `mapstructure:"nakedret"` + Nestif NestifSettings `mapstructure:"nestif"` + NilNil NilNilSettings `mapstructure:"nilnil"` + Nlreturn NlreturnSettings `mapstructure:"nlreturn"` + NoLintLint NoLintLintSettings `mapstructure:"nolintlint"` + NoNamedReturns NoNamedReturnsSettings `mapstructure:"nonamedreturns"` + ParallelTest ParallelTestSettings `mapstructure:"paralleltest"` + PerfSprint PerfSprintSettings `mapstructure:"perfsprint"` + Prealloc PreallocSettings `mapstructure:"prealloc"` + Predeclared PredeclaredSettings `mapstructure:"predeclared"` + Promlinter PromlinterSettings `mapstructure:"promlinter"` + ProtoGetter ProtoGetterSettings `mapstructure:"protogetter"` + Reassign ReassignSettings `mapstructure:"reassign"` + Recvcheck RecvcheckSettings `mapstructure:"recvcheck"` + Revive ReviveSettings `mapstructure:"revive"` + RowsErrCheck RowsErrCheckSettings `mapstructure:"rowserrcheck"` + SlogLint SlogLintSettings `mapstructure:"sloglint"` + Spancheck SpancheckSettings `mapstructure:"spancheck"` + Staticcheck StaticCheckSettings `mapstructure:"staticcheck"` + Stylecheck StaticCheckSettings `mapstructure:"stylecheck"` + TagAlign TagAlignSettings `mapstructure:"tagalign"` + Tagliatelle TagliatelleSettings `mapstructure:"tagliatelle"` + Tenv TenvSettings `mapstructure:"tenv"` + Testifylint TestifylintSettings `mapstructure:"testifylint"` + Testpackage TestpackageSettings `mapstructure:"testpackage"` + Thelper ThelperSettings `mapstructure:"thelper"` + Unconvert UnconvertSettings `mapstructure:"unconvert"` + Unparam UnparamSettings `mapstructure:"unparam"` + Unused UnusedSettings `mapstructure:"unused"` + UseStdlibVars UseStdlibVarsSettings `mapstructure:"usestdlibvars"` + UseTesting UseTestingSettings `mapstructure:"usetesting"` + Varnamelen VarnamelenSettings `mapstructure:"varnamelen"` + Whitespace WhitespaceSettings `mapstructure:"whitespace"` + Wrapcheck WrapcheckSettings `mapstructure:"wrapcheck"` + WSL WSLSettings `mapstructure:"wsl"` + + Custom map[string]CustomLinterSettings `mapstructure:"custom"` + + Gci GciSettings `mapstructure:"gci"` + GoFmt GoFmtSettings `mapstructure:"gofmt"` + GoFumpt GoFumptSettings `mapstructure:"gofumpt"` + GoImports GoImportsSettings `mapstructure:"goimports"` +} + +type AsasalintSettings struct { + Exclude []string `mapstructure:"exclude"` + UseBuiltinExclusions *bool `mapstructure:"use-builtin-exclusions"` + IgnoreTest *bool `mapstructure:"ignore-test"` +} + +type BiDiChkSettings struct { + LeftToRightEmbedding *bool `mapstructure:"left-to-right-embedding"` + RightToLeftEmbedding *bool `mapstructure:"right-to-left-embedding"` + PopDirectionalFormatting *bool `mapstructure:"pop-directional-formatting"` + LeftToRightOverride *bool `mapstructure:"left-to-right-override"` + RightToLeftOverride *bool `mapstructure:"right-to-left-override"` + LeftToRightIsolate *bool `mapstructure:"left-to-right-isolate"` + RightToLeftIsolate *bool `mapstructure:"right-to-left-isolate"` + FirstStrongIsolate *bool `mapstructure:"first-strong-isolate"` + PopDirectionalIsolate *bool `mapstructure:"pop-directional-isolate"` +} + +type CopyLoopVarSettings struct { + CheckAlias *bool `mapstructure:"check-alias"` + + // Deprecated: use CheckAlias + IgnoreAlias *bool `mapstructure:"ignore-alias"` +} + +type Cyclop struct { + MaxComplexity *int `mapstructure:"max-complexity"` + PackageAverage *float64 `mapstructure:"package-average"` + SkipTests *bool `mapstructure:"skip-tests"` +} + +type DepGuardSettings struct { + Rules map[string]*DepGuardList `mapstructure:"rules"` +} + +type DepGuardList struct { + ListMode *string `mapstructure:"list-mode"` + Files []string `mapstructure:"files"` + Allow []string `mapstructure:"allow"` + Deny []DepGuardDeny `mapstructure:"deny"` +} + +type DepGuardDeny struct { + Pkg *string `mapstructure:"pkg"` + Desc *string `mapstructure:"desc"` +} + +type DecorderSettings struct { + DecOrder []string `mapstructure:"dec-order"` + IgnoreUnderscoreVars *bool `mapstructure:"ignore-underscore-vars"` + DisableDecNumCheck *bool `mapstructure:"disable-dec-num-check"` + DisableTypeDecNumCheck *bool `mapstructure:"disable-type-dec-num-check"` + DisableConstDecNumCheck *bool `mapstructure:"disable-const-dec-num-check"` + DisableVarDecNumCheck *bool `mapstructure:"disable-var-dec-num-check"` + DisableDecOrderCheck *bool `mapstructure:"disable-dec-order-check"` + DisableInitFuncFirstCheck *bool `mapstructure:"disable-init-func-first-check"` +} + +type DogsledSettings struct { + MaxBlankIdentifiers *int `mapstructure:"max-blank-identifiers"` +} + +type DuplSettings struct { + Threshold *int `mapstructure:"threshold"` +} + +type DupWordSettings struct { + Keywords []string `mapstructure:"keywords"` + Ignore []string `mapstructure:"ignore"` +} + +type ErrcheckSettings struct { + DisableDefaultExclusions *bool `mapstructure:"disable-default-exclusions"` + CheckTypeAssertions *bool `mapstructure:"check-type-assertions"` + CheckAssignToBlank *bool `mapstructure:"check-blank"` + ExcludeFunctions []string `mapstructure:"exclude-functions"` + + // Deprecated: use ExcludeFunctions instead + Exclude *string `mapstructure:"exclude"` + + // Deprecated: use ExcludeFunctions instead + Ignore *string `mapstructure:"ignore"` +} + +type ErrChkJSONSettings struct { + CheckErrorFreeEncoding *bool `mapstructure:"check-error-free-encoding"` + ReportNoExported *bool `mapstructure:"report-no-exported"` +} + +type ErrorLintSettings struct { + Errorf *bool `mapstructure:"errorf"` + ErrorfMulti *bool `mapstructure:"errorf-multi"` + Asserts *bool `mapstructure:"asserts"` + Comparison *bool `mapstructure:"comparison"` + AllowedErrors []ErrorLintAllowPair `mapstructure:"allowed-errors"` + AllowedErrorsWildcard []ErrorLintAllowPair `mapstructure:"allowed-errors-wildcard"` +} + +type ErrorLintAllowPair struct { + Err *string `mapstructure:"err"` + Fun *string `mapstructure:"fun"` +} + +type ExhaustiveSettings struct { + Check []string `mapstructure:"check"` + CheckGenerated *bool `mapstructure:"check-generated"` + DefaultSignifiesExhaustive *bool `mapstructure:"default-signifies-exhaustive"` + IgnoreEnumMembers *string `mapstructure:"ignore-enum-members"` + IgnoreEnumTypes *string `mapstructure:"ignore-enum-types"` + PackageScopeOnly *bool `mapstructure:"package-scope-only"` + ExplicitExhaustiveMap *bool `mapstructure:"explicit-exhaustive-map"` + ExplicitExhaustiveSwitch *bool `mapstructure:"explicit-exhaustive-switch"` + DefaultCaseRequired *bool `mapstructure:"default-case-required"` +} + +type ExhaustructSettings struct { + Include []string `mapstructure:"include"` + Exclude []string `mapstructure:"exclude"` +} + +type FatcontextSettings struct { + CheckStructPointers *bool `mapstructure:"check-struct-pointers"` +} + +type ForbidigoSettings struct { + Forbid []ForbidigoPattern `mapstructure:"forbid"` + ExcludeGodocExamples *bool `mapstructure:"exclude-godoc-examples"` + AnalyzeTypes *bool `mapstructure:"analyze-types"` +} + +var _ encoding.TextUnmarshaler = &ForbidigoPattern{} + +// ForbidigoPattern corresponds to forbidigo.pattern and adds mapstructure support. +// The YAML field names must match what forbidigo expects. +type ForbidigoPattern struct { + // patternString gets populated when the config contains a *string as entry in ForbidigoSettings.Forbid[] + // because ForbidigoPattern implements encoding.TextUnmarshaler + // and the reader uses the mapstructure.TextUnmarshallerHookFunc as decoder hook. + // + // If the entry is a map, then the other fields are set as usual by mapstructure. + patternString *string + Pattern *string `yaml:"p" mapstructure:"p"` + Package *string `yaml:"pkg,omitempty" mapstructure:"pkg,omitempty"` + Msg *string `yaml:"msg,omitempty" mapstructure:"msg,omitempty"` +} + +func (p *ForbidigoPattern) UnmarshalText(text []byte) error { + // Validation happens when instantiating forbidigo. + p.patternString = ptr.Pointer(string(text)) + return nil +} + +// MarshalString converts the pattern into a *string as needed by forbidigo.NewLinter. +// +// MarshalString is intentionally not called MarshalText, +// although it has the same signature +// because implementing encoding.TextMarshaler led to infinite recursion when yaml.Marshal called MarshalText. +func (p *ForbidigoPattern) MarshalString() ([]byte, error) { + if ptr.Deref(p.patternString) != "" { + return []byte(ptr.Deref(p.patternString)), nil + } + + return yaml.Marshal(p) +} + +type FunlenSettings struct { + Lines *int `mapstructure:"lines"` + Statements *int `mapstructure:"statements"` + IgnoreComments *bool `mapstructure:"ignore-comments"` +} + +type GinkgoLinterSettings struct { + SuppressLenAssertion *bool `mapstructure:"suppress-len-assertion"` + SuppressNilAssertion *bool `mapstructure:"suppress-nil-assertion"` + SuppressErrAssertion *bool `mapstructure:"suppress-err-assertion"` + SuppressCompareAssertion *bool `mapstructure:"suppress-compare-assertion"` + SuppressAsyncAssertion *bool `mapstructure:"suppress-async-assertion"` + SuppressTypeCompareWarning *bool `mapstructure:"suppress-type-compare-assertion"` + ForbidFocusContainer *bool `mapstructure:"forbid-focus-container"` + AllowHaveLenZero *bool `mapstructure:"allow-havelen-zero"` + ForceExpectTo *bool `mapstructure:"force-expect-to"` + ValidateAsyncIntervals *bool `mapstructure:"validate-async-intervals"` + ForbidSpecPollution *bool `mapstructure:"forbid-spec-pollution"` + ForceSucceedForFuncs *bool `mapstructure:"force-succeed"` +} + +type GoChecksumTypeSettings struct { + DefaultSignifiesExhaustive *bool `mapstructure:"default-signifies-exhaustive"` + IncludeSharedInterfaces *bool `mapstructure:"include-shared-interfaces"` +} + +type GocognitSettings struct { + MinComplexity *int `mapstructure:"min-complexity"` +} + +type GoConstSettings struct { + IgnoreStrings *string `mapstructure:"ignore-strings"` + IgnoreTests *bool `mapstructure:"ignore-tests"` + MatchWithConstants *bool `mapstructure:"match-constant"` + MinStringLen *int `mapstructure:"min-len"` + MinOccurrencesCount *int `mapstructure:"min-occurrences"` + ParseNumbers *bool `mapstructure:"numbers"` + NumberMin *int `mapstructure:"min"` + NumberMax *int `mapstructure:"max"` + IgnoreCalls *bool `mapstructure:"ignore-calls"` +} + +type GoCriticSettings struct { + Go *string `mapstructure:"-"` + DisableAll *bool `mapstructure:"disable-all"` + EnabledChecks []string `mapstructure:"enabled-checks"` + EnableAll *bool `mapstructure:"enable-all"` + DisabledChecks []string `mapstructure:"disabled-checks"` + EnabledTags []string `mapstructure:"enabled-tags"` + DisabledTags []string `mapstructure:"disabled-tags"` + SettingsPerCheck map[string]GoCriticCheckSettings `mapstructure:"settings"` +} + +type GoCriticCheckSettings map[string]any + +type GoCycloSettings struct { + MinComplexity *int `mapstructure:"min-complexity"` +} + +type GodotSettings struct { + Scope *string `mapstructure:"scope"` + Exclude []string `mapstructure:"exclude"` + Capital *bool `mapstructure:"capital"` + Period *bool `mapstructure:"period"` + + // Deprecated: use Scope instead + CheckAll *bool `mapstructure:"check-all"` +} + +type GodoxSettings struct { + Keywords []string `mapstructure:"keywords"` +} + +type GoHeaderSettings struct { + Values map[string]map[string]string `mapstructure:"values"` + Template *string `mapstructure:"template"` + TemplatePath *string `mapstructure:"template-path"` +} + +type GoModDirectivesSettings struct { + ReplaceAllowList []string `mapstructure:"replace-allow-list"` + ReplaceLocal *bool `mapstructure:"replace-local"` + ExcludeForbidden *bool `mapstructure:"exclude-forbidden"` + RetractAllowNoExplanation *bool `mapstructure:"retract-allow-no-explanation"` + ToolchainForbidden *bool `mapstructure:"toolchain-forbidden"` + ToolchainPattern *string `mapstructure:"toolchain-pattern"` + ToolForbidden *bool `mapstructure:"tool-forbidden"` + GoDebugForbidden *bool `mapstructure:"go-debug-forbidden"` + GoVersionPattern *string `mapstructure:"go-version-pattern"` +} + +type GoModGuardSettings struct { + Allowed struct { + Modules []string `mapstructure:"modules"` + Domains []string `mapstructure:"domains"` + } `mapstructure:"allowed"` + Blocked struct { + Modules []map[string]struct { + Recommendations []string `mapstructure:"recommendations"` + Reason *string `mapstructure:"reason"` + } `mapstructure:"modules"` + Versions []map[string]struct { + Version *string `mapstructure:"version"` + Reason *string `mapstructure:"reason"` + } `mapstructure:"versions"` + LocalReplaceDirectives *bool `mapstructure:"local_replace_directives"` + } `mapstructure:"blocked"` +} + +type GoSecSettings struct { + Includes []string `mapstructure:"includes"` + Excludes []string `mapstructure:"excludes"` + Severity *string `mapstructure:"severity"` + Confidence *string `mapstructure:"confidence"` + ExcludeGenerated *bool `mapstructure:"exclude-generated"` + Config map[string]any `mapstructure:"config"` + Concurrency *int `mapstructure:"concurrency"` +} + +type GosmopolitanSettings struct { + AllowTimeLocal *bool `mapstructure:"allow-time-local"` + EscapeHatches []string `mapstructure:"escape-hatches"` + IgnoreTests *bool `mapstructure:"ignore-tests"` + WatchForScripts []string `mapstructure:"watch-for-scripts"` +} + +type GovetSettings struct { + Go *string `mapstructure:"-"` + + Enable []string `mapstructure:"enable"` + Disable []string `mapstructure:"disable"` + EnableAll *bool `mapstructure:"enable-all"` + DisableAll *bool `mapstructure:"disable-all"` + + Settings map[string]map[string]any `mapstructure:"settings"` + + // Deprecated: the linter should be enabled inside Enable. + CheckShadowing *bool `mapstructure:"check-shadowing"` +} + +type GrouperSettings struct { + ConstRequireSingleConst *bool `mapstructure:"const-require-single-const"` + ConstRequireGrouping *bool `mapstructure:"const-require-grouping"` + ImportRequireSingleImport *bool `mapstructure:"import-require-single-import"` + ImportRequireGrouping *bool `mapstructure:"import-require-grouping"` + TypeRequireSingleType *bool `mapstructure:"type-require-single-type"` + TypeRequireGrouping *bool `mapstructure:"type-require-grouping"` + VarRequireSingleVar *bool `mapstructure:"var-require-single-var"` + VarRequireGrouping *bool `mapstructure:"var-require-grouping"` +} + +type IfaceSettings struct { + Enable []string `mapstructure:"enable"` + Settings map[string]map[string]any `mapstructure:"settings"` +} + +type ImportAsSettings struct { + Alias []ImportAsAlias `mapstructure:"alias"` + NoUnaliased *bool `mapstructure:"no-unaliased"` + NoExtraAliases *bool `mapstructure:"no-extra-aliases"` +} + +type ImportAsAlias struct { + Pkg *string `mapstructure:"pkg"` + Alias *string `mapstructure:"alias"` +} + +type INamedParamSettings struct { + SkipSingleParam *bool `mapstructure:"skip-single-param"` +} + +type InterfaceBloatSettings struct { + Max *int `mapstructure:"max"` +} + +type IreturnSettings struct { + Allow []string `mapstructure:"allow"` + Reject []string `mapstructure:"reject"` +} + +type LllSettings struct { + LineLength *int `mapstructure:"line-length"` + TabWidth *int `mapstructure:"tab-width"` +} + +type LoggerCheckSettings struct { + Kitlog *bool `mapstructure:"kitlog"` + Klog *bool `mapstructure:"klog"` + Logr *bool `mapstructure:"logr"` + Slog *bool `mapstructure:"slog"` + Zap *bool `mapstructure:"zap"` + RequireStringKey *bool `mapstructure:"require-string-key"` + NoPrintfLike *bool `mapstructure:"no-printf-like"` + Rules []string `mapstructure:"rules"` +} + +type MaintIdxSettings struct { + Under *int `mapstructure:"under"` +} + +type MakezeroSettings struct { + Always *bool `mapstructure:"always"` +} + +type MisspellSettings struct { + Mode *string `mapstructure:"mode"` + Locale *string `mapstructure:"locale"` + ExtraWords []MisspellExtraWords `mapstructure:"extra-words"` + // TODO(ldez): v2 the option must be renamed to `IgnoredRules`. + IgnoreWords []string `mapstructure:"ignore-words"` +} + +type MisspellExtraWords struct { + Typo *string `mapstructure:"typo"` + Correction *string `mapstructure:"correction"` +} + +type MustTagSettings struct { + Functions []struct { + Name *string `mapstructure:"name"` + Tag *string `mapstructure:"tag"` + ArgPos *int `mapstructure:"arg-pos"` + } `mapstructure:"functions"` +} + +type NakedretSettings struct { + MaxFuncLines *uint `mapstructure:"max-func-lines"` +} + +type NestifSettings struct { + MinComplexity *int `mapstructure:"min-complexity"` +} + +type NilNilSettings struct { + DetectOpposite *bool `mapstructure:"detect-opposite"` + CheckedTypes []string `mapstructure:"checked-types"` +} + +type NlreturnSettings struct { + BlockSize *int `mapstructure:"block-size"` +} + +type MndSettings struct { + Checks []string `mapstructure:"checks"` + IgnoredNumbers []string `mapstructure:"ignored-numbers"` + IgnoredFiles []string `mapstructure:"ignored-files"` + IgnoredFunctions []string `mapstructure:"ignored-functions"` +} + +type NoLintLintSettings struct { + RequireExplanation *bool `mapstructure:"require-explanation"` + RequireSpecific *bool `mapstructure:"require-specific"` + AllowNoExplanation []string `mapstructure:"allow-no-explanation"` + AllowUnused *bool `mapstructure:"allow-unused"` +} + +type NoNamedReturnsSettings struct { + ReportErrorInDefer *bool `mapstructure:"report-error-in-defer"` +} + +type ParallelTestSettings struct { + Go *string `mapstructure:"-"` + IgnoreMissing *bool `mapstructure:"ignore-missing"` + IgnoreMissingSubtests *bool `mapstructure:"ignore-missing-subtests"` +} + +type PerfSprintSettings struct { + IntegerFormat *bool `mapstructure:"integer-format"` + IntConversion *bool `mapstructure:"int-conversion"` + + ErrorFormat *bool `mapstructure:"error-format"` + ErrError *bool `mapstructure:"err-error"` + ErrorF *bool `mapstructure:"errorf"` + + StringFormat *bool `mapstructure:"string-format"` + SprintF1 *bool `mapstructure:"sprintf1"` + StrConcat *bool `mapstructure:"strconcat"` + + BoolFormat *bool `mapstructure:"bool-format"` + HexFormat *bool `mapstructure:"hex-format"` +} + +type PreallocSettings struct { + Simple *bool `mapstructure:"simple"` + RangeLoops *bool `mapstructure:"range-loops"` + ForLoops *bool `mapstructure:"for-loops"` +} + +type PredeclaredSettings struct { + Ignore *string `mapstructure:"ignore"` + Qualified *bool `mapstructure:"q"` +} + +type PromlinterSettings struct { + Strict *bool `mapstructure:"strict"` + DisabledLinters []string `mapstructure:"disabled-linters"` +} + +type ProtoGetterSettings struct { + SkipGeneratedBy []string `mapstructure:"skip-generated-by"` + SkipFiles []string `mapstructure:"skip-files"` + SkipAnyGenerated *bool `mapstructure:"skip-any-generated"` + ReplaceFirstArgInAppend *bool `mapstructure:"replace-first-arg-in-append"` +} + +type ReassignSettings struct { + Patterns []string `mapstructure:"patterns"` +} + +type RecvcheckSettings struct { + DisableBuiltin *bool `mapstructure:"disable-builtin"` + Exclusions []string `mapstructure:"exclusions"` +} + +type ReviveSettings struct { + Go *string `mapstructure:"-"` + MaxOpenFiles *int `mapstructure:"max-open-files"` + IgnoreGeneratedHeader *bool `mapstructure:"ignore-generated-header"` + Confidence *float64 `mapstructure:"confidence"` + Severity *string `mapstructure:"severity"` + EnableAllRules *bool `mapstructure:"enable-all-rules"` + Rules []struct { + Name *string `mapstructure:"name"` + Arguments []any `mapstructure:"arguments"` + Severity *string `mapstructure:"severity"` + Disabled *bool `mapstructure:"disabled"` + Exclude []string `mapstructure:"exclude"` + } `mapstructure:"rules"` + ErrorCode *int `mapstructure:"error-code"` + WarningCode *int `mapstructure:"warning-code"` + Directives []struct { + Name *string `mapstructure:"name"` + Severity *string `mapstructure:"severity"` + } `mapstructure:"directives"` +} + +type RowsErrCheckSettings struct { + Packages []string `mapstructure:"packages"` +} + +type SlogLintSettings struct { + NoMixedArgs *bool `mapstructure:"no-mixed-args"` + KVOnly *bool `mapstructure:"kv-only"` + AttrOnly *bool `mapstructure:"attr-only"` + NoGlobal *string `mapstructure:"no-global"` + Context *string `mapstructure:"context"` + StaticMsg *bool `mapstructure:"static-msg"` + NoRawKeys *bool `mapstructure:"no-raw-keys"` + KeyNamingCase *string `mapstructure:"key-naming-case"` + ForbiddenKeys []string `mapstructure:"forbidden-keys"` + ArgsOnSepLines *bool `mapstructure:"args-on-sep-lines"` +} + +type SpancheckSettings struct { + Checks []string `mapstructure:"checks"` + IgnoreCheckSignatures []string `mapstructure:"ignore-check-signatures"` + ExtraStartSpanSignatures []string `mapstructure:"extra-start-span-signatures"` +} + +type StaticCheckSettings struct { + Checks []string `mapstructure:"checks"` + Initialisms []string `mapstructure:"initialisms"` // only for stylecheck + DotImportWhitelist []string `mapstructure:"dot-import-whitelist"` // only for stylecheck + HTTPStatusCodeWhitelist []string `mapstructure:"http-status-code-whitelist"` // only for stylecheck +} + +type TagAlignSettings struct { + Align *bool `mapstructure:"align"` + Sort *bool `mapstructure:"sort"` + Order []string `mapstructure:"order"` + Strict *bool `mapstructure:"strict"` +} + +type TagliatelleSettings struct { + Case TagliatelleCase `mapstructure:"case"` +} + +type TagliatelleCase struct { + TagliatelleBase `mapstructure:",squash"` + Overrides []TagliatelleOverrides `mapstructure:"overrides"` +} + +type TagliatelleOverrides struct { + TagliatelleBase `mapstructure:",squash"` + Package *string `mapstructure:"pkg"` + Ignore *bool `mapstructure:"ignore"` +} + +type TagliatelleBase struct { + Rules map[string]string `mapstructure:"rules"` + ExtendedRules map[string]TagliatelleExtendedRule `mapstructure:"extended-rules"` + UseFieldName *bool `mapstructure:"use-field-name"` + IgnoredFields []string `mapstructure:"ignored-fields"` +} + +type TagliatelleExtendedRule struct { + Case *string `mapstructure:"case"` + ExtraInitialisms *bool `mapstructure:"extra-initialisms"` + InitialismOverrides map[string]bool `mapstructure:"initialism-overrides"` +} + +type TestifylintSettings struct { + EnableAll *bool `mapstructure:"enable-all"` + DisableAll *bool `mapstructure:"disable-all"` + EnabledCheckers []string `mapstructure:"enable"` + DisabledCheckers []string `mapstructure:"disable"` + + BoolCompare struct { + IgnoreCustomTypes *bool `mapstructure:"ignore-custom-types"` + } `mapstructure:"bool-compare"` + + ExpectedActual struct { + ExpVarPattern *string `mapstructure:"pattern"` + } `mapstructure:"expected-actual"` + + Formatter struct { + CheckFormatString *bool `mapstructure:"check-format-string"` + RequireFFuncs *bool `mapstructure:"require-f-funcs"` + } `mapstructure:"formatter"` + + GoRequire struct { + IgnoreHTTPHandlers *bool `mapstructure:"ignore-http-handlers"` + } `mapstructure:"go-require"` + + RequireError struct { + FnPattern *string `mapstructure:"fn-pattern"` + } `mapstructure:"require-error"` + + SuiteExtraAssertCall struct { + Mode *string `mapstructure:"mode"` + } `mapstructure:"suite-extra-assert-call"` +} + +type TestpackageSettings struct { + SkipRegexp *string `mapstructure:"skip-regexp"` + AllowPackages []string `mapstructure:"allow-packages"` +} + +type ThelperSettings struct { + Test ThelperOptions `mapstructure:"test"` + Fuzz ThelperOptions `mapstructure:"fuzz"` + Benchmark ThelperOptions `mapstructure:"benchmark"` + TB ThelperOptions `mapstructure:"tb"` +} + +type ThelperOptions struct { + First *bool `mapstructure:"first"` + Name *bool `mapstructure:"name"` + Begin *bool `mapstructure:"begin"` +} + +type TenvSettings struct { + All *bool `mapstructure:"all"` +} + +type UseStdlibVarsSettings struct { + HTTPMethod *bool `mapstructure:"http-method"` + HTTPStatusCode *bool `mapstructure:"http-status-code"` + TimeWeekday *bool `mapstructure:"time-weekday"` + TimeMonth *bool `mapstructure:"time-month"` + TimeLayout *bool `mapstructure:"time-layout"` + CryptoHash *bool `mapstructure:"crypto-hash"` + DefaultRPCPath *bool `mapstructure:"default-rpc-path"` + SQLIsolationLevel *bool `mapstructure:"sql-isolation-level"` + TLSSignatureScheme *bool `mapstructure:"tls-signature-scheme"` + ConstantKind *bool `mapstructure:"constant-kind"` + + // Deprecated + OSDevNull *bool `mapstructure:"os-dev-null"` + // Deprecated + SyslogPriority *bool `mapstructure:"syslog-priority"` +} + +type UseTestingSettings struct { + ContextBackground *bool `mapstructure:"context-background"` + ContextTodo *bool `mapstructure:"context-todo"` + OSChdir *bool `mapstructure:"os-chdir"` + OSMkdirTemp *bool `mapstructure:"os-mkdir-temp"` + OSSetenv *bool `mapstructure:"os-setenv"` + OSTempDir *bool `mapstructure:"os-temp-dir"` + OSCreateTemp *bool `mapstructure:"os-create-temp"` +} + +type UnconvertSettings struct { + FastMath *bool `mapstructure:"fast-math"` + Safe *bool `mapstructure:"safe"` +} + +type UnparamSettings struct { + CheckExported *bool `mapstructure:"check-exported"` + Algo *string `mapstructure:"algo"` +} + +type UnusedSettings struct { + FieldWritesAreUses *bool `mapstructure:"field-writes-are-uses"` + PostStatementsAreReads *bool `mapstructure:"post-statements-are-reads"` + ExportedFieldsAreUsed *bool `mapstructure:"exported-fields-are-used"` + ParametersAreUsed *bool `mapstructure:"parameters-are-used"` + LocalVariablesAreUsed *bool `mapstructure:"local-variables-are-used"` + GeneratedIsUsed *bool `mapstructure:"generated-is-used"` + + // Deprecated + ExportedIsUsed *bool `mapstructure:"exported-is-used"` +} + +type VarnamelenSettings struct { + MaxDistance *int `mapstructure:"max-distance"` + MinNameLength *int `mapstructure:"min-name-length"` + CheckReceiver *bool `mapstructure:"check-receiver"` + CheckReturn *bool `mapstructure:"check-return"` + CheckTypeParam *bool `mapstructure:"check-type-param"` + IgnoreNames []string `mapstructure:"ignore-names"` + IgnoreTypeAssertOk *bool `mapstructure:"ignore-type-assert-ok"` + IgnoreMapIndexOk *bool `mapstructure:"ignore-map-index-ok"` + IgnoreChanRecvOk *bool `mapstructure:"ignore-chan-recv-ok"` + IgnoreDecls []string `mapstructure:"ignore-decls"` +} + +type WhitespaceSettings struct { + MultiIf *bool `mapstructure:"multi-if"` + MultiFunc *bool `mapstructure:"multi-func"` +} + +type WrapcheckSettings struct { + ExtraIgnoreSigs []string `mapstructure:"extra-ignore-sigs"` + // TODO(ldez): v2 the options must be renamed to use hyphen. + IgnoreSigs []string `mapstructure:"ignoreSigs"` + IgnoreSigRegexps []string `mapstructure:"ignoreSigRegexps"` + IgnorePackageGlobs []string `mapstructure:"ignorePackageGlobs"` + IgnoreInterfaceRegexps []string `mapstructure:"ignoreInterfaceRegexps"` +} + +type WSLSettings struct { + StrictAppend *bool `mapstructure:"strict-append"` + AllowAssignAndCallCuddle *bool `mapstructure:"allow-assign-and-call"` + AllowAssignAndAnythingCuddle *bool `mapstructure:"allow-assign-and-anything"` + AllowMultiLineAssignCuddle *bool `mapstructure:"allow-multiline-assign"` + ForceCaseTrailingWhitespaceLimit *int `mapstructure:"force-case-trailing-whitespace"` + AllowTrailingComment *bool `mapstructure:"allow-trailing-comment"` + AllowSeparatedLeadingComment *bool `mapstructure:"allow-separated-leading-comment"` + AllowCuddleDeclaration *bool `mapstructure:"allow-cuddle-declarations"` + AllowCuddleWithCalls []string `mapstructure:"allow-cuddle-with-calls"` + AllowCuddleWithRHS []string `mapstructure:"allow-cuddle-with-rhs"` + ForceCuddleErrCheckAndAssign *bool `mapstructure:"force-err-cuddling"` + ErrorVariableNames []string `mapstructure:"error-variable-names"` + ForceExclusiveShortDeclarations *bool `mapstructure:"force-short-decl-cuddling"` +} + +// CustomLinterSettings encapsulates the meta-data of a private linter. +type CustomLinterSettings struct { + // Type plugin type. + // It can be `goplugin` or `module`. + Type *string `mapstructure:"type"` + + // Path to a plugin *.so file that implements the private linter. + // Only for Go plugin system. + Path *string `mapstructure:"path"` + + // Description describes the purpose of the private linter. + Description *string `mapstructure:"description"` + // OriginalURL The URL containing the source code for the private linter. + OriginalURL *string `mapstructure:"original-url"` + + // Settings plugin settings only work with linterdb.PluginConstructor symbol. + Settings any `mapstructure:"settings"` +} + +type GciSettings struct { + Sections []string `mapstructure:"sections"` + NoInlineComments *bool `mapstructure:"no-inline-comments"` + NoPrefixComments *bool `mapstructure:"no-prefix-comments"` + SkipGenerated *bool `mapstructure:"skip-generated"` + CustomOrder *bool `mapstructure:"custom-order"` + NoLexOrder *bool `mapstructure:"no-lex-order"` + + // Deprecated: use Sections instead. + LocalPrefixes *string `mapstructure:"local-prefixes"` +} + +type GoFmtSettings struct { + Simplify *bool `mapstructure:"simplify"` + RewriteRules []GoFmtRewriteRule `mapstructure:"rewrite-rules"` +} + +type GoFmtRewriteRule struct { + Pattern *string `mapstructure:"pattern"` + Replacement *string `mapstructure:"replacement"` +} + +type GoFumptSettings struct { + ModulePath *string `mapstructure:"module-path"` + ExtraRules *bool `mapstructure:"extra-rules"` + + // Deprecated: use the global `run.go` instead. + LangVersion *string `mapstructure:"lang-version"` +} + +type GoImportsSettings struct { + LocalPrefixes *string `mapstructure:"local-prefixes"` +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/output.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/output.go new file mode 100644 index 000000000..a3d86fc1d --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/output.go @@ -0,0 +1,37 @@ +package versionone + +import ( + "strings" + + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/ptr" +) + +type Output struct { + Formats OutputFormats `mapstructure:"formats"` + PrintIssuedLine *bool `mapstructure:"print-issued-lines"` + PrintLinterName *bool `mapstructure:"print-linter-name"` + SortResults *bool `mapstructure:"sort-results"` + SortOrder []string `mapstructure:"sort-order"` + PathPrefix *string `mapstructure:"path-prefix"` + ShowStats *bool `mapstructure:"show-stats"` +} + +type OutputFormat struct { + Format *string `mapstructure:"format"` + Path *string `mapstructure:"path"` +} + +type OutputFormats []OutputFormat + +func (p *OutputFormats) UnmarshalText(text []byte) error { + for item := range strings.SplitSeq(string(text), ",") { + format, path, _ := strings.Cut(item, ":") + + *p = append(*p, OutputFormat{ + Path: ptr.Pointer(path), + Format: ptr.Pointer(format), + }) + } + + return nil +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/run.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/run.go new file mode 100644 index 000000000..db3e0edc9 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/run.go @@ -0,0 +1,25 @@ +package versionone + +import ( + "time" +) + +// Run encapsulates the config options for running the linter analysis. +type Run struct { + Timeout time.Duration `mapstructure:"timeout"` + + Concurrency *int `mapstructure:"concurrency"` + + Go *string `mapstructure:"go"` + + RelativePathMode *string `mapstructure:"relative-path-mode"` + + BuildTags []string `mapstructure:"build-tags"` + ModulesDownloadMode *string `mapstructure:"modules-download-mode"` + + ExitCodeIfIssuesFound *int `mapstructure:"issues-exit-code"` + AnalyzeTests *bool `mapstructure:"tests"` + + AllowParallelRunners *bool `mapstructure:"allow-parallel-runners"` + AllowSerialRunners *bool `mapstructure:"allow-serial-runners"` +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/severity.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/severity.go new file mode 100644 index 000000000..b9d52e692 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone/severity.go @@ -0,0 +1,12 @@ +package versionone + +type Severity struct { + Default *string `mapstructure:"default-severity"` + CaseSensitive *bool `mapstructure:"case-sensitive"` + Rules []SeverityRule `mapstructure:"rules"` +} + +type SeverityRule struct { + BaseRule `mapstructure:",squash"` + Severity *string `mapstructure:"severity"` +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/base_rule.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/base_rule.go new file mode 100644 index 000000000..469592dcc --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/base_rule.go @@ -0,0 +1,13 @@ +// Code generated by pkg/commands/internal/migrate/cloner/cloner.go. DO NOT EDIT. + +package versiontwo + +type BaseRule struct { + Linters []string `yaml:"linters,omitempty" toml:"linters,multiline,omitempty"` + Path *string `yaml:"path,omitempty" toml:"path,multiline,omitempty"` + PathExcept *string `yaml:"path-except,omitempty" toml:"path-except,multiline,omitempty"` + Text *string `yaml:"text,omitempty" toml:"text,multiline,omitempty"` + Source *string `yaml:"source,omitempty" toml:"source,multiline,omitempty"` + + InternalReference *string `yaml:"-,omitempty" toml:"-,multiline,omitempty"` +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/config.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/config.go new file mode 100644 index 000000000..341b47b6c --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/config.go @@ -0,0 +1,18 @@ +// Code generated by pkg/commands/internal/migrate/cloner/cloner.go. DO NOT EDIT. + +package versiontwo + +type Config struct { + Version *string `yaml:"version,omitempty" toml:"version,multiline,omitempty"` + + Run Run `yaml:"run,omitempty" toml:"run,multiline,omitempty"` + + Output Output `yaml:"output,omitempty" toml:"output,multiline,omitempty"` + + Linters Linters `yaml:"linters,omitempty" toml:"linters,multiline,omitempty"` + + Issues Issues `yaml:"issues,omitempty" toml:"issues,multiline,omitempty"` + Severity Severity `yaml:"severity,omitempty" toml:"severity,multiline,omitempty"` + + Formatters Formatters `yaml:"formatters,omitempty" toml:"formatters,multiline,omitempty"` +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/formatters.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/formatters.go new file mode 100644 index 000000000..417714947 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/formatters.go @@ -0,0 +1,15 @@ +// Code generated by pkg/commands/internal/migrate/cloner/cloner.go. DO NOT EDIT. + +package versiontwo + +type Formatters struct { + Enable []string `yaml:"enable,omitempty" toml:"enable,multiline,omitempty"` + Settings FormatterSettings `yaml:"settings,omitempty" toml:"settings,multiline,omitempty"` + Exclusions FormatterExclusions `yaml:"exclusions,omitempty" toml:"exclusions,multiline,omitempty"` +} + +type FormatterExclusions struct { + Generated *string `yaml:"generated,omitempty" toml:"generated,multiline,omitempty"` + Paths []string `yaml:"paths,omitempty" toml:"paths,multiline,omitempty"` + WarnUnused *bool `yaml:"warn-unused,omitempty" toml:"warn-unused,multiline,omitempty"` +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/formatters_settings.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/formatters_settings.go new file mode 100644 index 000000000..878b2c417 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/formatters_settings.go @@ -0,0 +1,48 @@ +// Code generated by pkg/commands/internal/migrate/cloner/cloner.go. DO NOT EDIT. + +package versiontwo + +type FormatterSettings struct { + Gci GciSettings `yaml:"gci,omitempty" toml:"gci,multiline,omitempty"` + GoFmt GoFmtSettings `yaml:"gofmt,omitempty" toml:"gofmt,multiline,omitempty"` + GoFumpt GoFumptSettings `yaml:"gofumpt,omitempty" toml:"gofumpt,multiline,omitempty"` + GoImports GoImportsSettings `yaml:"goimports,omitempty" toml:"goimports,multiline,omitempty"` + GoLines GoLinesSettings `yaml:"golines,omitempty" toml:"golines,multiline,omitempty"` +} + +type GciSettings struct { + Sections []string `yaml:"sections,omitempty" toml:"sections,multiline,omitempty"` + NoInlineComments *bool `yaml:"no-inline-comments,omitempty" toml:"no-inline-comments,multiline,omitempty"` + NoPrefixComments *bool `yaml:"no-prefix-comments,omitempty" toml:"no-prefix-comments,multiline,omitempty"` + CustomOrder *bool `yaml:"custom-order,omitempty" toml:"custom-order,multiline,omitempty"` + NoLexOrder *bool `yaml:"no-lex-order,omitempty" toml:"no-lex-order,multiline,omitempty"` +} + +type GoFmtSettings struct { + Simplify *bool `yaml:"simplify,omitempty" toml:"simplify,multiline,omitempty"` + RewriteRules []GoFmtRewriteRule `yaml:"rewrite-rules,omitempty" toml:"rewrite-rules,multiline,omitempty"` +} + +type GoFmtRewriteRule struct { + Pattern *string `yaml:"pattern,omitempty" toml:"pattern,multiline,omitempty"` + Replacement *string `yaml:"replacement,omitempty" toml:"replacement,multiline,omitempty"` +} + +type GoFumptSettings struct { + ModulePath *string `yaml:"module-path,omitempty" toml:"module-path,multiline,omitempty"` + ExtraRules *bool `yaml:"extra-rules,omitempty" toml:"extra-rules,multiline,omitempty"` + + LangVersion *string `yaml:"-,omitempty" toml:"-,multiline,omitempty"` +} + +type GoImportsSettings struct { + LocalPrefixes []string `yaml:"local-prefixes,omitempty" toml:"local-prefixes,multiline,omitempty"` +} + +type GoLinesSettings struct { + MaxLen *int `yaml:"max-len,omitempty" toml:"max-len,multiline,omitempty"` + TabLen *int `yaml:"tab-len,omitempty" toml:"tab-len,multiline,omitempty"` + ShortenComments *bool `yaml:"shorten-comments,omitempty" toml:"shorten-comments,multiline,omitempty"` + ReformatTags *bool `yaml:"reformat-tags,omitempty" toml:"reformat-tags,multiline,omitempty"` + ChainSplitDots *bool `yaml:"chain-split-dots,omitempty" toml:"chain-split-dots,multiline,omitempty"` +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/issues.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/issues.go new file mode 100644 index 000000000..fa3b06ac5 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/issues.go @@ -0,0 +1,17 @@ +// Code generated by pkg/commands/internal/migrate/cloner/cloner.go. DO NOT EDIT. + +package versiontwo + +type Issues struct { + MaxIssuesPerLinter *int `yaml:"max-issues-per-linter,omitempty" toml:"max-issues-per-linter,multiline,omitempty"` + MaxSameIssues *int `yaml:"max-same-issues,omitempty" toml:"max-same-issues,multiline,omitempty"` + UniqByLine *bool `yaml:"uniq-by-line,omitempty" toml:"uniq-by-line,multiline,omitempty"` + + DiffFromRevision *string `yaml:"new-from-rev,omitempty" toml:"new-from-rev,multiline,omitempty"` + DiffFromMergeBase *string `yaml:"new-from-merge-base,omitempty" toml:"new-from-merge-base,multiline,omitempty"` + DiffPatchFilePath *string `yaml:"new-from-patch,omitempty" toml:"new-from-patch,multiline,omitempty"` + WholeFiles *bool `yaml:"whole-files,omitempty" toml:"whole-files,multiline,omitempty"` + Diff *bool `yaml:"new,omitempty" toml:"new,multiline,omitempty"` + + NeedFix *bool `yaml:"fix,omitempty" toml:"fix,multiline,omitempty"` +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/linters.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/linters.go new file mode 100644 index 000000000..797313111 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/linters.go @@ -0,0 +1,14 @@ +// Code generated by pkg/commands/internal/migrate/cloner/cloner.go. DO NOT EDIT. + +package versiontwo + +type Linters struct { + Default *string `yaml:"default,omitempty" toml:"default,multiline,omitempty"` + Enable []string `yaml:"enable,omitempty" toml:"enable,multiline,omitempty"` + Disable []string `yaml:"disable,omitempty" toml:"disable,multiline,omitempty"` + FastOnly *bool `yaml:"fast-only,omitempty" toml:"fast-only,multiline,omitempty"` + + Settings LintersSettings `yaml:"settings,omitempty" toml:"settings,multiline,omitempty"` + + Exclusions LinterExclusions `yaml:"exclusions,omitempty" toml:"exclusions,multiline,omitempty"` +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/linters_exclusions.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/linters_exclusions.go new file mode 100644 index 000000000..d4ecb9720 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/linters_exclusions.go @@ -0,0 +1,16 @@ +// Code generated by pkg/commands/internal/migrate/cloner/cloner.go. DO NOT EDIT. + +package versiontwo + +type LinterExclusions struct { + Generated *string `yaml:"generated,omitempty" toml:"generated,multiline,omitempty"` + WarnUnused *bool `yaml:"warn-unused,omitempty" toml:"warn-unused,multiline,omitempty"` + Presets []string `yaml:"presets,omitempty" toml:"presets,multiline,omitempty"` + Rules []ExcludeRule `yaml:"rules,omitempty" toml:"rules,multiline,omitempty"` + Paths []string `yaml:"paths,omitempty" toml:"paths,multiline,omitempty"` + PathsExcept []string `yaml:"paths-except,omitempty" toml:"paths-except,multiline,omitempty"` +} + +type ExcludeRule struct { + BaseRule `yaml:",inline"` +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/linters_settings.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/linters_settings.go new file mode 100644 index 000000000..be35d1390 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/linters_settings.go @@ -0,0 +1,801 @@ +// Code generated by pkg/commands/internal/migrate/cloner/cloner.go. DO NOT EDIT. + +package versiontwo + +type LintersSettings struct { + FormatterSettings `yaml:"-,omitempty" toml:"-,multiline,omitempty"` + + Asasalint AsasalintSettings `yaml:"asasalint,omitempty" toml:"asasalint,multiline,omitempty"` + BiDiChk BiDiChkSettings `yaml:"bidichk,omitempty" toml:"bidichk,multiline,omitempty"` + CopyLoopVar CopyLoopVarSettings `yaml:"copyloopvar,omitempty" toml:"copyloopvar,multiline,omitempty"` + Cyclop CyclopSettings `yaml:"cyclop,omitempty" toml:"cyclop,multiline,omitempty"` + Decorder DecorderSettings `yaml:"decorder,omitempty" toml:"decorder,multiline,omitempty"` + Depguard DepGuardSettings `yaml:"depguard,omitempty" toml:"depguard,multiline,omitempty"` + Dogsled DogsledSettings `yaml:"dogsled,omitempty" toml:"dogsled,multiline,omitempty"` + Dupl DuplSettings `yaml:"dupl,omitempty" toml:"dupl,multiline,omitempty"` + DupWord DupWordSettings `yaml:"dupword,omitempty" toml:"dupword,multiline,omitempty"` + EmbeddedStructFieldCheck EmbeddedStructFieldCheckSettings `yaml:"embeddedstructfieldcheck,omitempty" toml:"embeddedstructfieldcheck,multiline,omitempty"` + Errcheck ErrcheckSettings `yaml:"errcheck,omitempty" toml:"errcheck,multiline,omitempty"` + ErrChkJSON ErrChkJSONSettings `yaml:"errchkjson,omitempty" toml:"errchkjson,multiline,omitempty"` + ErrorLint ErrorLintSettings `yaml:"errorlint,omitempty" toml:"errorlint,multiline,omitempty"` + Exhaustive ExhaustiveSettings `yaml:"exhaustive,omitempty" toml:"exhaustive,multiline,omitempty"` + Exhaustruct ExhaustructSettings `yaml:"exhaustruct,omitempty" toml:"exhaustruct,multiline,omitempty"` + Fatcontext FatcontextSettings `yaml:"fatcontext,omitempty" toml:"fatcontext,multiline,omitempty"` + Forbidigo ForbidigoSettings `yaml:"forbidigo,omitempty" toml:"forbidigo,multiline,omitempty"` + FuncOrder FuncOrderSettings `yaml:"funcorder,omitempty" toml:"funcorder,multiline,omitempty"` + Funlen FunlenSettings `yaml:"funlen,omitempty" toml:"funlen,multiline,omitempty"` + GinkgoLinter GinkgoLinterSettings `yaml:"ginkgolinter,omitempty" toml:"ginkgolinter,multiline,omitempty"` + Gocognit GocognitSettings `yaml:"gocognit,omitempty" toml:"gocognit,multiline,omitempty"` + GoChecksumType GoChecksumTypeSettings `yaml:"gochecksumtype,omitempty" toml:"gochecksumtype,multiline,omitempty"` + Goconst GoConstSettings `yaml:"goconst,omitempty" toml:"goconst,multiline,omitempty"` + Gocritic GoCriticSettings `yaml:"gocritic,omitempty" toml:"gocritic,multiline,omitempty"` + Gocyclo GoCycloSettings `yaml:"gocyclo,omitempty" toml:"gocyclo,multiline,omitempty"` + Godot GodotSettings `yaml:"godot,omitempty" toml:"godot,multiline,omitempty"` + Godox GodoxSettings `yaml:"godox,omitempty" toml:"godox,multiline,omitempty"` + Goheader GoHeaderSettings `yaml:"goheader,omitempty" toml:"goheader,multiline,omitempty"` + GoModDirectives GoModDirectivesSettings `yaml:"gomoddirectives,omitempty" toml:"gomoddirectives,multiline,omitempty"` + Gomodguard GoModGuardSettings `yaml:"gomodguard,omitempty" toml:"gomodguard,multiline,omitempty"` + Gosec GoSecSettings `yaml:"gosec,omitempty" toml:"gosec,multiline,omitempty"` + Gosmopolitan GosmopolitanSettings `yaml:"gosmopolitan,omitempty" toml:"gosmopolitan,multiline,omitempty"` + Govet GovetSettings `yaml:"govet,omitempty" toml:"govet,multiline,omitempty"` + Grouper GrouperSettings `yaml:"grouper,omitempty" toml:"grouper,multiline,omitempty"` + Iface IfaceSettings `yaml:"iface,omitempty" toml:"iface,multiline,omitempty"` + ImportAs ImportAsSettings `yaml:"importas,omitempty" toml:"importas,multiline,omitempty"` + Inamedparam INamedParamSettings `yaml:"inamedparam,omitempty" toml:"inamedparam,multiline,omitempty"` + InterfaceBloat InterfaceBloatSettings `yaml:"interfacebloat,omitempty" toml:"interfacebloat,multiline,omitempty"` + Ireturn IreturnSettings `yaml:"ireturn,omitempty" toml:"ireturn,multiline,omitempty"` + Lll LllSettings `yaml:"lll,omitempty" toml:"lll,multiline,omitempty"` + LoggerCheck LoggerCheckSettings `yaml:"loggercheck,omitempty" toml:"loggercheck,multiline,omitempty"` + MaintIdx MaintIdxSettings `yaml:"maintidx,omitempty" toml:"maintidx,multiline,omitempty"` + Makezero MakezeroSettings `yaml:"makezero,omitempty" toml:"makezero,multiline,omitempty"` + Misspell MisspellSettings `yaml:"misspell,omitempty" toml:"misspell,multiline,omitempty"` + Mnd MndSettings `yaml:"mnd,omitempty" toml:"mnd,multiline,omitempty"` + MustTag MustTagSettings `yaml:"musttag,omitempty" toml:"musttag,multiline,omitempty"` + Nakedret NakedretSettings `yaml:"nakedret,omitempty" toml:"nakedret,multiline,omitempty"` + Nestif NestifSettings `yaml:"nestif,omitempty" toml:"nestif,multiline,omitempty"` + NilNil NilNilSettings `yaml:"nilnil,omitempty" toml:"nilnil,multiline,omitempty"` + Nlreturn NlreturnSettings `yaml:"nlreturn,omitempty" toml:"nlreturn,multiline,omitempty"` + NoLintLint NoLintLintSettings `yaml:"nolintlint,omitempty" toml:"nolintlint,multiline,omitempty"` + NoNamedReturns NoNamedReturnsSettings `yaml:"nonamedreturns,omitempty" toml:"nonamedreturns,multiline,omitempty"` + ParallelTest ParallelTestSettings `yaml:"paralleltest,omitempty" toml:"paralleltest,multiline,omitempty"` + PerfSprint PerfSprintSettings `yaml:"perfsprint,omitempty" toml:"perfsprint,multiline,omitempty"` + Prealloc PreallocSettings `yaml:"prealloc,omitempty" toml:"prealloc,multiline,omitempty"` + Predeclared PredeclaredSettings `yaml:"predeclared,omitempty" toml:"predeclared,multiline,omitempty"` + Promlinter PromlinterSettings `yaml:"promlinter,omitempty" toml:"promlinter,multiline,omitempty"` + ProtoGetter ProtoGetterSettings `yaml:"protogetter,omitempty" toml:"protogetter,multiline,omitempty"` + Reassign ReassignSettings `yaml:"reassign,omitempty" toml:"reassign,multiline,omitempty"` + Recvcheck RecvcheckSettings `yaml:"recvcheck,omitempty" toml:"recvcheck,multiline,omitempty"` + Revive ReviveSettings `yaml:"revive,omitempty" toml:"revive,multiline,omitempty"` + RowsErrCheck RowsErrCheckSettings `yaml:"rowserrcheck,omitempty" toml:"rowserrcheck,multiline,omitempty"` + SlogLint SlogLintSettings `yaml:"sloglint,omitempty" toml:"sloglint,multiline,omitempty"` + Spancheck SpancheckSettings `yaml:"spancheck,omitempty" toml:"spancheck,multiline,omitempty"` + Staticcheck StaticCheckSettings `yaml:"staticcheck,omitempty" toml:"staticcheck,multiline,omitempty"` + TagAlign TagAlignSettings `yaml:"tagalign,omitempty" toml:"tagalign,multiline,omitempty"` + Tagliatelle TagliatelleSettings `yaml:"tagliatelle,omitempty" toml:"tagliatelle,multiline,omitempty"` + Testifylint TestifylintSettings `yaml:"testifylint,omitempty" toml:"testifylint,multiline,omitempty"` + Testpackage TestpackageSettings `yaml:"testpackage,omitempty" toml:"testpackage,multiline,omitempty"` + Thelper ThelperSettings `yaml:"thelper,omitempty" toml:"thelper,multiline,omitempty"` + Unconvert UnconvertSettings `yaml:"unconvert,omitempty" toml:"unconvert,multiline,omitempty"` + Unparam UnparamSettings `yaml:"unparam,omitempty" toml:"unparam,multiline,omitempty"` + Unused UnusedSettings `yaml:"unused,omitempty" toml:"unused,multiline,omitempty"` + UseStdlibVars UseStdlibVarsSettings `yaml:"usestdlibvars,omitempty" toml:"usestdlibvars,multiline,omitempty"` + UseTesting UseTestingSettings `yaml:"usetesting,omitempty" toml:"usetesting,multiline,omitempty"` + Varnamelen VarnamelenSettings `yaml:"varnamelen,omitempty" toml:"varnamelen,multiline,omitempty"` + Whitespace WhitespaceSettings `yaml:"whitespace,omitempty" toml:"whitespace,multiline,omitempty"` + Wrapcheck WrapcheckSettings `yaml:"wrapcheck,omitempty" toml:"wrapcheck,multiline,omitempty"` + WSL WSLv4Settings `yaml:"wsl,omitempty" toml:"wsl,multiline,omitempty"` + WSLv5 WSLv5Settings `yaml:"wsl_v5,omitempty" toml:"wsl_v5,multiline,omitempty"` + + Custom map[string]CustomLinterSettings `yaml:"custom,omitempty" toml:"custom,multiline,omitempty"` +} + +type AsasalintSettings struct { + Exclude []string `yaml:"exclude,omitempty" toml:"exclude,multiline,omitempty"` + UseBuiltinExclusions *bool `yaml:"use-builtin-exclusions,omitempty" toml:"use-builtin-exclusions,multiline,omitempty"` +} + +type BiDiChkSettings struct { + LeftToRightEmbedding *bool `yaml:"left-to-right-embedding,omitempty" toml:"left-to-right-embedding,multiline,omitempty"` + RightToLeftEmbedding *bool `yaml:"right-to-left-embedding,omitempty" toml:"right-to-left-embedding,multiline,omitempty"` + PopDirectionalFormatting *bool `yaml:"pop-directional-formatting,omitempty" toml:"pop-directional-formatting,multiline,omitempty"` + LeftToRightOverride *bool `yaml:"left-to-right-override,omitempty" toml:"left-to-right-override,multiline,omitempty"` + RightToLeftOverride *bool `yaml:"right-to-left-override,omitempty" toml:"right-to-left-override,multiline,omitempty"` + LeftToRightIsolate *bool `yaml:"left-to-right-isolate,omitempty" toml:"left-to-right-isolate,multiline,omitempty"` + RightToLeftIsolate *bool `yaml:"right-to-left-isolate,omitempty" toml:"right-to-left-isolate,multiline,omitempty"` + FirstStrongIsolate *bool `yaml:"first-strong-isolate,omitempty" toml:"first-strong-isolate,multiline,omitempty"` + PopDirectionalIsolate *bool `yaml:"pop-directional-isolate,omitempty" toml:"pop-directional-isolate,multiline,omitempty"` +} + +type CopyLoopVarSettings struct { + CheckAlias *bool `yaml:"check-alias,omitempty" toml:"check-alias,multiline,omitempty"` +} + +type CyclopSettings struct { + MaxComplexity *int `yaml:"max-complexity,omitempty" toml:"max-complexity,multiline,omitempty"` + PackageAverage *float64 `yaml:"package-average,omitempty" toml:"package-average,multiline,omitempty"` +} + +type DepGuardSettings struct { + Rules map[string]*DepGuardList `yaml:"rules,omitempty" toml:"rules,multiline,omitempty"` +} + +type DepGuardList struct { + ListMode *string `yaml:"list-mode,omitempty" toml:"list-mode,multiline,omitempty"` + Files []string `yaml:"files,omitempty" toml:"files,multiline,omitempty"` + Allow []string `yaml:"allow,omitempty" toml:"allow,multiline,omitempty"` + Deny []DepGuardDeny `yaml:"deny,omitempty" toml:"deny,multiline,omitempty"` +} + +type DepGuardDeny struct { + Pkg *string `yaml:"pkg,omitempty" toml:"pkg,multiline,omitempty"` + Desc *string `yaml:"desc,omitempty" toml:"desc,multiline,omitempty"` +} + +type DecorderSettings struct { + DecOrder []string `yaml:"dec-order,omitempty" toml:"dec-order,multiline,omitempty"` + IgnoreUnderscoreVars *bool `yaml:"ignore-underscore-vars,omitempty" toml:"ignore-underscore-vars,multiline,omitempty"` + DisableDecNumCheck *bool `yaml:"disable-dec-num-check,omitempty" toml:"disable-dec-num-check,multiline,omitempty"` + DisableTypeDecNumCheck *bool `yaml:"disable-type-dec-num-check,omitempty" toml:"disable-type-dec-num-check,multiline,omitempty"` + DisableConstDecNumCheck *bool `yaml:"disable-const-dec-num-check,omitempty" toml:"disable-const-dec-num-check,multiline,omitempty"` + DisableVarDecNumCheck *bool `yaml:"disable-var-dec-num-check,omitempty" toml:"disable-var-dec-num-check,multiline,omitempty"` + DisableDecOrderCheck *bool `yaml:"disable-dec-order-check,omitempty" toml:"disable-dec-order-check,multiline,omitempty"` + DisableInitFuncFirstCheck *bool `yaml:"disable-init-func-first-check,omitempty" toml:"disable-init-func-first-check,multiline,omitempty"` +} + +type DogsledSettings struct { + MaxBlankIdentifiers *int `yaml:"max-blank-identifiers,omitempty" toml:"max-blank-identifiers,multiline,omitempty"` +} + +type DuplSettings struct { + Threshold *int `yaml:"threshold,omitempty" toml:"threshold,multiline,omitempty"` +} + +type DupWordSettings struct { + Keywords []string `yaml:"keywords,omitempty" toml:"keywords,multiline,omitempty"` + Ignore []string `yaml:"ignore,omitempty" toml:"ignore,multiline,omitempty"` +} + +type EmbeddedStructFieldCheckSettings struct { + ForbidMutex *bool `yaml:"forbid-mutex,omitempty" toml:"forbid-mutex,multiline,omitempty"` +} + +type ErrcheckSettings struct { + DisableDefaultExclusions *bool `yaml:"disable-default-exclusions,omitempty" toml:"disable-default-exclusions,multiline,omitempty"` + CheckTypeAssertions *bool `yaml:"check-type-assertions,omitempty" toml:"check-type-assertions,multiline,omitempty"` + CheckAssignToBlank *bool `yaml:"check-blank,omitempty" toml:"check-blank,multiline,omitempty"` + ExcludeFunctions []string `yaml:"exclude-functions,omitempty" toml:"exclude-functions,multiline,omitempty"` + Verbose *bool `yaml:"verbose,omitempty" toml:"verbose,multiline,omitempty"` +} + +type ErrChkJSONSettings struct { + CheckErrorFreeEncoding *bool `yaml:"check-error-free-encoding,omitempty" toml:"check-error-free-encoding,multiline,omitempty"` + ReportNoExported *bool `yaml:"report-no-exported,omitempty" toml:"report-no-exported,multiline,omitempty"` +} + +type ErrorLintSettings struct { + Errorf *bool `yaml:"errorf,omitempty" toml:"errorf,multiline,omitempty"` + ErrorfMulti *bool `yaml:"errorf-multi,omitempty" toml:"errorf-multi,multiline,omitempty"` + Asserts *bool `yaml:"asserts,omitempty" toml:"asserts,multiline,omitempty"` + Comparison *bool `yaml:"comparison,omitempty" toml:"comparison,multiline,omitempty"` + AllowedErrors []ErrorLintAllowPair `yaml:"allowed-errors,omitempty" toml:"allowed-errors,multiline,omitempty"` + AllowedErrorsWildcard []ErrorLintAllowPair `yaml:"allowed-errors-wildcard,omitempty" toml:"allowed-errors-wildcard,multiline,omitempty"` +} + +type ErrorLintAllowPair struct { + Err *string `yaml:"err,omitempty" toml:"err,multiline,omitempty"` + Fun *string `yaml:"fun,omitempty" toml:"fun,multiline,omitempty"` +} + +type ExhaustiveSettings struct { + Check []string `yaml:"check,omitempty" toml:"check,multiline,omitempty"` + DefaultSignifiesExhaustive *bool `yaml:"default-signifies-exhaustive,omitempty" toml:"default-signifies-exhaustive,multiline,omitempty"` + IgnoreEnumMembers *string `yaml:"ignore-enum-members,omitempty" toml:"ignore-enum-members,multiline,omitempty"` + IgnoreEnumTypes *string `yaml:"ignore-enum-types,omitempty" toml:"ignore-enum-types,multiline,omitempty"` + PackageScopeOnly *bool `yaml:"package-scope-only,omitempty" toml:"package-scope-only,multiline,omitempty"` + ExplicitExhaustiveMap *bool `yaml:"explicit-exhaustive-map,omitempty" toml:"explicit-exhaustive-map,multiline,omitempty"` + ExplicitExhaustiveSwitch *bool `yaml:"explicit-exhaustive-switch,omitempty" toml:"explicit-exhaustive-switch,multiline,omitempty"` + DefaultCaseRequired *bool `yaml:"default-case-required,omitempty" toml:"default-case-required,multiline,omitempty"` +} + +type ExhaustructSettings struct { + Include []string `yaml:"include,omitempty" toml:"include,multiline,omitempty"` + Exclude []string `yaml:"exclude,omitempty" toml:"exclude,multiline,omitempty"` +} + +type FatcontextSettings struct { + CheckStructPointers *bool `yaml:"check-struct-pointers,omitempty" toml:"check-struct-pointers,multiline,omitempty"` +} + +type ForbidigoSettings struct { + Forbid []ForbidigoPattern `yaml:"forbid,omitempty" toml:"forbid,multiline,omitempty"` + ExcludeGodocExamples *bool `yaml:"exclude-godoc-examples,omitempty" toml:"exclude-godoc-examples,multiline,omitempty"` + AnalyzeTypes *bool `yaml:"analyze-types,omitempty" toml:"analyze-types,multiline,omitempty"` +} + +type ForbidigoPattern struct { + Pattern *string `yaml:"pattern,omitempty" toml:"pattern,multiline,omitempty"` + Package *string `yaml:"pkg,omitempty,omitempty" toml:"pkg,omitempty,multiline,omitempty"` + Msg *string `yaml:"msg,omitempty,omitempty" toml:"msg,omitempty,multiline,omitempty"` +} + +type FuncOrderSettings struct { + Constructor *bool `yaml:"constructor,omitempty,omitempty" toml:"constructor,omitempty,multiline,omitempty"` + StructMethod *bool `yaml:"struct-method,omitempty,omitempty" toml:"struct-method,omitempty,multiline,omitempty"` + Alphabetical *bool `yaml:"alphabetical,omitempty,omitempty" toml:"alphabetical,omitempty,multiline,omitempty"` +} + +type FunlenSettings struct { + Lines *int `yaml:"lines,omitempty" toml:"lines,multiline,omitempty"` + Statements *int `yaml:"statements,omitempty" toml:"statements,multiline,omitempty"` + IgnoreComments *bool `yaml:"ignore-comments,omitempty" toml:"ignore-comments,multiline,omitempty"` +} + +type GinkgoLinterSettings struct { + SuppressLenAssertion *bool `yaml:"suppress-len-assertion,omitempty" toml:"suppress-len-assertion,multiline,omitempty"` + SuppressNilAssertion *bool `yaml:"suppress-nil-assertion,omitempty" toml:"suppress-nil-assertion,multiline,omitempty"` + SuppressErrAssertion *bool `yaml:"suppress-err-assertion,omitempty" toml:"suppress-err-assertion,multiline,omitempty"` + SuppressCompareAssertion *bool `yaml:"suppress-compare-assertion,omitempty" toml:"suppress-compare-assertion,multiline,omitempty"` + SuppressAsyncAssertion *bool `yaml:"suppress-async-assertion,omitempty" toml:"suppress-async-assertion,multiline,omitempty"` + SuppressTypeCompareWarning *bool `yaml:"suppress-type-compare-assertion,omitempty" toml:"suppress-type-compare-assertion,multiline,omitempty"` + ForbidFocusContainer *bool `yaml:"forbid-focus-container,omitempty" toml:"forbid-focus-container,multiline,omitempty"` + AllowHaveLenZero *bool `yaml:"allow-havelen-zero,omitempty" toml:"allow-havelen-zero,multiline,omitempty"` + ForceExpectTo *bool `yaml:"force-expect-to,omitempty" toml:"force-expect-to,multiline,omitempty"` + ValidateAsyncIntervals *bool `yaml:"validate-async-intervals,omitempty" toml:"validate-async-intervals,multiline,omitempty"` + ForbidSpecPollution *bool `yaml:"forbid-spec-pollution,omitempty" toml:"forbid-spec-pollution,multiline,omitempty"` + ForceSucceedForFuncs *bool `yaml:"force-succeed,omitempty" toml:"force-succeed,multiline,omitempty"` +} + +type GoChecksumTypeSettings struct { + DefaultSignifiesExhaustive *bool `yaml:"default-signifies-exhaustive,omitempty" toml:"default-signifies-exhaustive,multiline,omitempty"` + IncludeSharedInterfaces *bool `yaml:"include-shared-interfaces,omitempty" toml:"include-shared-interfaces,multiline,omitempty"` +} + +type GocognitSettings struct { + MinComplexity *int `yaml:"min-complexity,omitempty" toml:"min-complexity,multiline,omitempty"` +} + +type GoConstSettings struct { + IgnoreStringValues []string `yaml:"ignore-string-values,omitempty" toml:"ignore-string-values,multiline,omitempty"` + MatchWithConstants *bool `yaml:"match-constant,omitempty" toml:"match-constant,multiline,omitempty"` + MinStringLen *int `yaml:"min-len,omitempty" toml:"min-len,multiline,omitempty"` + MinOccurrencesCount *int `yaml:"min-occurrences,omitempty" toml:"min-occurrences,multiline,omitempty"` + ParseNumbers *bool `yaml:"numbers,omitempty" toml:"numbers,multiline,omitempty"` + NumberMin *int `yaml:"min,omitempty" toml:"min,multiline,omitempty"` + NumberMax *int `yaml:"max,omitempty" toml:"max,multiline,omitempty"` + IgnoreCalls *bool `yaml:"ignore-calls,omitempty" toml:"ignore-calls,multiline,omitempty"` + FindDuplicates *bool `yaml:"find-duplicates,omitempty" toml:"find-duplicates,multiline,omitempty"` + EvalConstExpressions *bool `yaml:"eval-const-expressions,omitempty" toml:"eval-const-expressions,multiline,omitempty"` + + IgnoreStrings *string `yaml:"ignore-strings,omitempty" toml:"ignore-strings,multiline,omitempty"` +} + +type GoCriticSettings struct { + Go *string `yaml:"-,omitempty" toml:"-,multiline,omitempty"` + DisableAll *bool `yaml:"disable-all,omitempty" toml:"disable-all,multiline,omitempty"` + EnabledChecks []string `yaml:"enabled-checks,omitempty" toml:"enabled-checks,multiline,omitempty"` + EnableAll *bool `yaml:"enable-all,omitempty" toml:"enable-all,multiline,omitempty"` + DisabledChecks []string `yaml:"disabled-checks,omitempty" toml:"disabled-checks,multiline,omitempty"` + EnabledTags []string `yaml:"enabled-tags,omitempty" toml:"enabled-tags,multiline,omitempty"` + DisabledTags []string `yaml:"disabled-tags,omitempty" toml:"disabled-tags,multiline,omitempty"` + SettingsPerCheck map[string]GoCriticCheckSettings `yaml:"settings,omitempty" toml:"settings,multiline,omitempty"` +} + +type GoCriticCheckSettings map[string]any + +type GoCycloSettings struct { + MinComplexity *int `yaml:"min-complexity,omitempty" toml:"min-complexity,multiline,omitempty"` +} + +type GodotSettings struct { + Scope *string `yaml:"scope,omitempty" toml:"scope,multiline,omitempty"` + Exclude []string `yaml:"exclude,omitempty" toml:"exclude,multiline,omitempty"` + Capital *bool `yaml:"capital,omitempty" toml:"capital,multiline,omitempty"` + Period *bool `yaml:"period,omitempty" toml:"period,multiline,omitempty"` +} + +type GodoxSettings struct { + Keywords []string `yaml:"keywords,omitempty" toml:"keywords,multiline,omitempty"` +} + +type GoHeaderSettings struct { + Values map[string]map[string]string `yaml:"values,omitempty" toml:"values,multiline,omitempty"` + Template *string `yaml:"template,omitempty" toml:"template,multiline,omitempty"` + TemplatePath *string `yaml:"template-path,omitempty" toml:"template-path,multiline,omitempty"` +} + +type GoModDirectivesSettings struct { + ReplaceAllowList []string `yaml:"replace-allow-list,omitempty" toml:"replace-allow-list,multiline,omitempty"` + ReplaceLocal *bool `yaml:"replace-local,omitempty" toml:"replace-local,multiline,omitempty"` + ExcludeForbidden *bool `yaml:"exclude-forbidden,omitempty" toml:"exclude-forbidden,multiline,omitempty"` + RetractAllowNoExplanation *bool `yaml:"retract-allow-no-explanation,omitempty" toml:"retract-allow-no-explanation,multiline,omitempty"` + ToolchainForbidden *bool `yaml:"toolchain-forbidden,omitempty" toml:"toolchain-forbidden,multiline,omitempty"` + ToolchainPattern *string `yaml:"toolchain-pattern,omitempty" toml:"toolchain-pattern,multiline,omitempty"` + ToolForbidden *bool `yaml:"tool-forbidden,omitempty" toml:"tool-forbidden,multiline,omitempty"` + GoDebugForbidden *bool `yaml:"go-debug-forbidden,omitempty" toml:"go-debug-forbidden,multiline,omitempty"` + GoVersionPattern *string `yaml:"go-version-pattern,omitempty" toml:"go-version-pattern,multiline,omitempty"` +} + +type GoModGuardSettings struct { + Allowed GoModGuardAllowed `yaml:"allowed,omitempty" toml:"allowed,multiline,omitempty"` + Blocked GoModGuardBlocked `yaml:"blocked,omitempty" toml:"blocked,multiline,omitempty"` +} + +type GoModGuardAllowed struct { + Modules []string `yaml:"modules,omitempty" toml:"modules,multiline,omitempty"` + Domains []string `yaml:"domains,omitempty" toml:"domains,multiline,omitempty"` +} + +type GoModGuardBlocked struct { + Modules []map[string]GoModGuardModule `yaml:"modules,omitempty" toml:"modules,multiline,omitempty"` + Versions []map[string]GoModGuardVersion `yaml:"versions,omitempty" toml:"versions,multiline,omitempty"` + LocalReplaceDirectives *bool `yaml:"local-replace-directives,omitempty" toml:"local-replace-directives,multiline,omitempty"` +} + +type GoModGuardModule struct { + Recommendations []string `yaml:"recommendations,omitempty" toml:"recommendations,multiline,omitempty"` + Reason *string `yaml:"reason,omitempty" toml:"reason,multiline,omitempty"` +} + +type GoModGuardVersion struct { + Version *string `yaml:"version,omitempty" toml:"version,multiline,omitempty"` + Reason *string `yaml:"reason,omitempty" toml:"reason,multiline,omitempty"` +} + +type GoSecSettings struct { + Includes []string `yaml:"includes,omitempty" toml:"includes,multiline,omitempty"` + Excludes []string `yaml:"excludes,omitempty" toml:"excludes,multiline,omitempty"` + Severity *string `yaml:"severity,omitempty" toml:"severity,multiline,omitempty"` + Confidence *string `yaml:"confidence,omitempty" toml:"confidence,multiline,omitempty"` + Config map[string]any `yaml:"config,omitempty" toml:"config,multiline,omitempty"` + Concurrency *int `yaml:"concurrency,omitempty" toml:"concurrency,multiline,omitempty"` +} + +type GosmopolitanSettings struct { + AllowTimeLocal *bool `yaml:"allow-time-local,omitempty" toml:"allow-time-local,multiline,omitempty"` + EscapeHatches []string `yaml:"escape-hatches,omitempty" toml:"escape-hatches,multiline,omitempty"` + WatchForScripts []string `yaml:"watch-for-scripts,omitempty" toml:"watch-for-scripts,multiline,omitempty"` +} + +type GovetSettings struct { + Go *string `yaml:"-,omitempty" toml:"-,multiline,omitempty"` + + Enable []string `yaml:"enable,omitempty" toml:"enable,multiline,omitempty"` + Disable []string `yaml:"disable,omitempty" toml:"disable,multiline,omitempty"` + EnableAll *bool `yaml:"enable-all,omitempty" toml:"enable-all,multiline,omitempty"` + DisableAll *bool `yaml:"disable-all,omitempty" toml:"disable-all,multiline,omitempty"` + + Settings map[string]map[string]any `yaml:"settings,omitempty" toml:"settings,multiline,omitempty"` +} + +type GrouperSettings struct { + ConstRequireSingleConst *bool `yaml:"const-require-single-const,omitempty" toml:"const-require-single-const,multiline,omitempty"` + ConstRequireGrouping *bool `yaml:"const-require-grouping,omitempty" toml:"const-require-grouping,multiline,omitempty"` + ImportRequireSingleImport *bool `yaml:"import-require-single-import,omitempty" toml:"import-require-single-import,multiline,omitempty"` + ImportRequireGrouping *bool `yaml:"import-require-grouping,omitempty" toml:"import-require-grouping,multiline,omitempty"` + TypeRequireSingleType *bool `yaml:"type-require-single-type,omitempty" toml:"type-require-single-type,multiline,omitempty"` + TypeRequireGrouping *bool `yaml:"type-require-grouping,omitempty" toml:"type-require-grouping,multiline,omitempty"` + VarRequireSingleVar *bool `yaml:"var-require-single-var,omitempty" toml:"var-require-single-var,multiline,omitempty"` + VarRequireGrouping *bool `yaml:"var-require-grouping,omitempty" toml:"var-require-grouping,multiline,omitempty"` +} + +type IfaceSettings struct { + Enable []string `yaml:"enable,omitempty" toml:"enable,multiline,omitempty"` + Settings map[string]map[string]any `yaml:"settings,omitempty" toml:"settings,multiline,omitempty"` +} + +type ImportAsSettings struct { + Alias []ImportAsAlias `yaml:"alias,omitempty" toml:"alias,multiline,omitempty"` + NoUnaliased *bool `yaml:"no-unaliased,omitempty" toml:"no-unaliased,multiline,omitempty"` + NoExtraAliases *bool `yaml:"no-extra-aliases,omitempty" toml:"no-extra-aliases,multiline,omitempty"` +} + +type ImportAsAlias struct { + Pkg *string `yaml:"pkg,omitempty" toml:"pkg,multiline,omitempty"` + Alias *string `yaml:"alias,omitempty" toml:"alias,multiline,omitempty"` +} + +type INamedParamSettings struct { + SkipSingleParam *bool `yaml:"skip-single-param,omitempty" toml:"skip-single-param,multiline,omitempty"` +} + +type InterfaceBloatSettings struct { + Max *int `yaml:"max,omitempty" toml:"max,multiline,omitempty"` +} + +type IreturnSettings struct { + Allow []string `yaml:"allow,omitempty" toml:"allow,multiline,omitempty"` + Reject []string `yaml:"reject,omitempty" toml:"reject,multiline,omitempty"` +} + +type LllSettings struct { + LineLength *int `yaml:"line-length,omitempty" toml:"line-length,multiline,omitempty"` + TabWidth *int `yaml:"tab-width,omitempty" toml:"tab-width,multiline,omitempty"` +} + +type LoggerCheckSettings struct { + Kitlog *bool `yaml:"kitlog,omitempty" toml:"kitlog,multiline,omitempty"` + Klog *bool `yaml:"klog,omitempty" toml:"klog,multiline,omitempty"` + Logr *bool `yaml:"logr,omitempty" toml:"logr,multiline,omitempty"` + Slog *bool `yaml:"slog,omitempty" toml:"slog,multiline,omitempty"` + Zap *bool `yaml:"zap,omitempty" toml:"zap,multiline,omitempty"` + RequireStringKey *bool `yaml:"require-string-key,omitempty" toml:"require-string-key,multiline,omitempty"` + NoPrintfLike *bool `yaml:"no-printf-like,omitempty" toml:"no-printf-like,multiline,omitempty"` + Rules []string `yaml:"rules,omitempty" toml:"rules,multiline,omitempty"` +} + +type MaintIdxSettings struct { + Under *int `yaml:"under,omitempty" toml:"under,multiline,omitempty"` +} + +type MakezeroSettings struct { + Always *bool `yaml:"always,omitempty" toml:"always,multiline,omitempty"` +} + +type MisspellSettings struct { + Mode *string `yaml:"mode,omitempty" toml:"mode,multiline,omitempty"` + Locale *string `yaml:"locale,omitempty" toml:"locale,multiline,omitempty"` + ExtraWords []MisspellExtraWords `yaml:"extra-words,omitempty" toml:"extra-words,multiline,omitempty"` + IgnoreRules []string `yaml:"ignore-rules,omitempty" toml:"ignore-rules,multiline,omitempty"` +} + +type MisspellExtraWords struct { + Typo *string `yaml:"typo,omitempty" toml:"typo,multiline,omitempty"` + Correction *string `yaml:"correction,omitempty" toml:"correction,multiline,omitempty"` +} + +type MustTagSettings struct { + Functions []MustTagFunction `yaml:"functions,omitempty" toml:"functions,multiline,omitempty"` +} + +type MustTagFunction struct { + Name *string `yaml:"name,omitempty" toml:"name,multiline,omitempty"` + Tag *string `yaml:"tag,omitempty" toml:"tag,multiline,omitempty"` + ArgPos *int `yaml:"arg-pos,omitempty" toml:"arg-pos,multiline,omitempty"` +} + +type NakedretSettings struct { + MaxFuncLines *uint `yaml:"max-func-lines,omitempty" toml:"max-func-lines,multiline,omitempty"` +} + +type NestifSettings struct { + MinComplexity *int `yaml:"min-complexity,omitempty" toml:"min-complexity,multiline,omitempty"` +} + +type NilNilSettings struct { + OnlyTwo *bool `yaml:"only-two,omitempty" toml:"only-two,multiline,omitempty"` + DetectOpposite *bool `yaml:"detect-opposite,omitempty" toml:"detect-opposite,multiline,omitempty"` + CheckedTypes []string `yaml:"checked-types,omitempty" toml:"checked-types,multiline,omitempty"` +} + +type NlreturnSettings struct { + BlockSize *int `yaml:"block-size,omitempty" toml:"block-size,multiline,omitempty"` +} + +type MndSettings struct { + Checks []string `yaml:"checks,omitempty" toml:"checks,multiline,omitempty"` + IgnoredNumbers []string `yaml:"ignored-numbers,omitempty" toml:"ignored-numbers,multiline,omitempty"` + IgnoredFiles []string `yaml:"ignored-files,omitempty" toml:"ignored-files,multiline,omitempty"` + IgnoredFunctions []string `yaml:"ignored-functions,omitempty" toml:"ignored-functions,multiline,omitempty"` +} + +type NoLintLintSettings struct { + RequireExplanation *bool `yaml:"require-explanation,omitempty" toml:"require-explanation,multiline,omitempty"` + RequireSpecific *bool `yaml:"require-specific,omitempty" toml:"require-specific,multiline,omitempty"` + AllowNoExplanation []string `yaml:"allow-no-explanation,omitempty" toml:"allow-no-explanation,multiline,omitempty"` + AllowUnused *bool `yaml:"allow-unused,omitempty" toml:"allow-unused,multiline,omitempty"` +} + +type NoNamedReturnsSettings struct { + ReportErrorInDefer *bool `yaml:"report-error-in-defer,omitempty" toml:"report-error-in-defer,multiline,omitempty"` +} + +type ParallelTestSettings struct { + Go *string `yaml:"-,omitempty" toml:"-,multiline,omitempty"` + IgnoreMissing *bool `yaml:"ignore-missing,omitempty" toml:"ignore-missing,multiline,omitempty"` + IgnoreMissingSubtests *bool `yaml:"ignore-missing-subtests,omitempty" toml:"ignore-missing-subtests,multiline,omitempty"` +} + +type PerfSprintSettings struct { + IntegerFormat *bool `yaml:"integer-format,omitempty" toml:"integer-format,multiline,omitempty"` + IntConversion *bool `yaml:"int-conversion,omitempty" toml:"int-conversion,multiline,omitempty"` + + ErrorFormat *bool `yaml:"error-format,omitempty" toml:"error-format,multiline,omitempty"` + ErrError *bool `yaml:"err-error,omitempty" toml:"err-error,multiline,omitempty"` + ErrorF *bool `yaml:"errorf,omitempty" toml:"errorf,multiline,omitempty"` + + StringFormat *bool `yaml:"string-format,omitempty" toml:"string-format,multiline,omitempty"` + SprintF1 *bool `yaml:"sprintf1,omitempty" toml:"sprintf1,multiline,omitempty"` + StrConcat *bool `yaml:"strconcat,omitempty" toml:"strconcat,multiline,omitempty"` + + BoolFormat *bool `yaml:"bool-format,omitempty" toml:"bool-format,multiline,omitempty"` + HexFormat *bool `yaml:"hex-format,omitempty" toml:"hex-format,multiline,omitempty"` +} + +type PreallocSettings struct { + Simple *bool `yaml:"simple,omitempty" toml:"simple,multiline,omitempty"` + RangeLoops *bool `yaml:"range-loops,omitempty" toml:"range-loops,multiline,omitempty"` + ForLoops *bool `yaml:"for-loops,omitempty" toml:"for-loops,multiline,omitempty"` +} + +type PredeclaredSettings struct { + Ignore []string `yaml:"ignore,omitempty" toml:"ignore,multiline,omitempty"` + Qualified *bool `yaml:"qualified-name,omitempty" toml:"qualified-name,multiline,omitempty"` +} + +type PromlinterSettings struct { + Strict *bool `yaml:"strict,omitempty" toml:"strict,multiline,omitempty"` + DisabledLinters []string `yaml:"disabled-linters,omitempty" toml:"disabled-linters,multiline,omitempty"` +} + +type ProtoGetterSettings struct { + SkipGeneratedBy []string `yaml:"skip-generated-by,omitempty" toml:"skip-generated-by,multiline,omitempty"` + SkipFiles []string `yaml:"skip-files,omitempty" toml:"skip-files,multiline,omitempty"` + SkipAnyGenerated *bool `yaml:"skip-any-generated,omitempty" toml:"skip-any-generated,multiline,omitempty"` + ReplaceFirstArgInAppend *bool `yaml:"replace-first-arg-in-append,omitempty" toml:"replace-first-arg-in-append,multiline,omitempty"` +} + +type ReassignSettings struct { + Patterns []string `yaml:"patterns,omitempty" toml:"patterns,multiline,omitempty"` +} + +type RecvcheckSettings struct { + DisableBuiltin *bool `yaml:"disable-builtin,omitempty" toml:"disable-builtin,multiline,omitempty"` + Exclusions []string `yaml:"exclusions,omitempty" toml:"exclusions,multiline,omitempty"` +} + +type ReviveSettings struct { + Go *string `yaml:"-,omitempty" toml:"-,multiline,omitempty"` + MaxOpenFiles *int `yaml:"max-open-files,omitempty" toml:"max-open-files,multiline,omitempty"` + Confidence *float64 `yaml:"confidence,omitempty" toml:"confidence,multiline,omitempty"` + Severity *string `yaml:"severity,omitempty" toml:"severity,multiline,omitempty"` + EnableAllRules *bool `yaml:"enable-all-rules,omitempty" toml:"enable-all-rules,multiline,omitempty"` + Rules []ReviveRule `yaml:"rules,omitempty" toml:"rules,multiline,omitempty"` + ErrorCode *int `yaml:"error-code,omitempty" toml:"error-code,multiline,omitempty"` + WarningCode *int `yaml:"warning-code,omitempty" toml:"warning-code,multiline,omitempty"` + Directives []ReviveDirective `yaml:"directives,omitempty" toml:"directives,multiline,omitempty"` +} + +type ReviveRule struct { + Name *string `yaml:"name,omitempty" toml:"name,multiline,omitempty"` + Arguments []any `yaml:"arguments,omitempty" toml:"arguments,multiline,omitempty"` + Severity *string `yaml:"severity,omitempty" toml:"severity,multiline,omitempty"` + Disabled *bool `yaml:"disabled,omitempty" toml:"disabled,multiline,omitempty"` + Exclude []string `yaml:"exclude,omitempty" toml:"exclude,multiline,omitempty"` +} + +type ReviveDirective struct { + Name *string `yaml:"name,omitempty" toml:"name,multiline,omitempty"` + Severity *string `yaml:"severity,omitempty" toml:"severity,multiline,omitempty"` +} + +type RowsErrCheckSettings struct { + Packages []string `yaml:"packages,omitempty" toml:"packages,multiline,omitempty"` +} + +type SlogLintSettings struct { + NoMixedArgs *bool `yaml:"no-mixed-args,omitempty" toml:"no-mixed-args,multiline,omitempty"` + KVOnly *bool `yaml:"kv-only,omitempty" toml:"kv-only,multiline,omitempty"` + AttrOnly *bool `yaml:"attr-only,omitempty" toml:"attr-only,multiline,omitempty"` + NoGlobal *string `yaml:"no-global,omitempty" toml:"no-global,multiline,omitempty"` + Context *string `yaml:"context,omitempty" toml:"context,multiline,omitempty"` + StaticMsg *bool `yaml:"static-msg,omitempty" toml:"static-msg,multiline,omitempty"` + MsgStyle *string `yaml:"msg-style,omitempty" toml:"msg-style,multiline,omitempty"` + NoRawKeys *bool `yaml:"no-raw-keys,omitempty" toml:"no-raw-keys,multiline,omitempty"` + KeyNamingCase *string `yaml:"key-naming-case,omitempty" toml:"key-naming-case,multiline,omitempty"` + ForbiddenKeys []string `yaml:"forbidden-keys,omitempty" toml:"forbidden-keys,multiline,omitempty"` + ArgsOnSepLines *bool `yaml:"args-on-sep-lines,omitempty" toml:"args-on-sep-lines,multiline,omitempty"` +} + +type SpancheckSettings struct { + Checks []string `yaml:"checks,omitempty" toml:"checks,multiline,omitempty"` + IgnoreCheckSignatures []string `yaml:"ignore-check-signatures,omitempty" toml:"ignore-check-signatures,multiline,omitempty"` + ExtraStartSpanSignatures []string `yaml:"extra-start-span-signatures,omitempty" toml:"extra-start-span-signatures,multiline,omitempty"` +} + +type StaticCheckSettings struct { + Checks []string `yaml:"checks,omitempty" toml:"checks,multiline,omitempty"` + Initialisms []string `yaml:"initialisms,omitempty" toml:"initialisms,multiline,omitempty"` + DotImportWhitelist []string `yaml:"dot-import-whitelist,omitempty" toml:"dot-import-whitelist,multiline,omitempty"` + HTTPStatusCodeWhitelist []string `yaml:"http-status-code-whitelist,omitempty" toml:"http-status-code-whitelist,multiline,omitempty"` +} + +type TagAlignSettings struct { + Align *bool `yaml:"align,omitempty" toml:"align,multiline,omitempty"` + Sort *bool `yaml:"sort,omitempty" toml:"sort,multiline,omitempty"` + Order []string `yaml:"order,omitempty" toml:"order,multiline,omitempty"` + Strict *bool `yaml:"strict,omitempty" toml:"strict,multiline,omitempty"` +} + +type TagliatelleSettings struct { + Case TagliatelleCase `yaml:"case,omitempty" toml:"case,multiline,omitempty"` +} + +type TagliatelleCase struct { + TagliatelleBase `yaml:",inline"` + Overrides []TagliatelleOverrides `yaml:"overrides,omitempty" toml:"overrides,multiline,omitempty"` +} + +type TagliatelleOverrides struct { + TagliatelleBase `yaml:",inline"` + Package *string `yaml:"pkg,omitempty" toml:"pkg,multiline,omitempty"` + Ignore *bool `yaml:"ignore,omitempty" toml:"ignore,multiline,omitempty"` +} + +type TagliatelleBase struct { + Rules map[string]string `yaml:"rules,omitempty" toml:"rules,multiline,omitempty"` + ExtendedRules map[string]TagliatelleExtendedRule `yaml:"extended-rules,omitempty" toml:"extended-rules,multiline,omitempty"` + UseFieldName *bool `yaml:"use-field-name,omitempty" toml:"use-field-name,multiline,omitempty"` + IgnoredFields []string `yaml:"ignored-fields,omitempty" toml:"ignored-fields,multiline,omitempty"` +} + +type TagliatelleExtendedRule struct { + Case *string `yaml:"case,omitempty" toml:"case,multiline,omitempty"` + ExtraInitialisms *bool `yaml:"extra-initialisms,omitempty" toml:"extra-initialisms,multiline,omitempty"` + InitialismOverrides map[string]bool `yaml:"initialism-overrides,omitempty" toml:"initialism-overrides,multiline,omitempty"` +} + +type TestifylintSettings struct { + EnableAll *bool `yaml:"enable-all,omitempty" toml:"enable-all,multiline,omitempty"` + DisableAll *bool `yaml:"disable-all,omitempty" toml:"disable-all,multiline,omitempty"` + EnabledCheckers []string `yaml:"enable,omitempty" toml:"enable,multiline,omitempty"` + DisabledCheckers []string `yaml:"disable,omitempty" toml:"disable,multiline,omitempty"` + + BoolCompare TestifylintBoolCompare `yaml:"bool-compare,omitempty" toml:"bool-compare,multiline,omitempty"` + ExpectedActual TestifylintExpectedActual `yaml:"expected-actual,omitempty" toml:"expected-actual,multiline,omitempty"` + Formatter TestifylintFormatter `yaml:"formatter,omitempty" toml:"formatter,multiline,omitempty"` + GoRequire TestifylintGoRequire `yaml:"go-require,omitempty" toml:"go-require,multiline,omitempty"` + RequireError TestifylintRequireError `yaml:"require-error,omitempty" toml:"require-error,multiline,omitempty"` + SuiteExtraAssertCall TestifylintSuiteExtraAssertCall `yaml:"suite-extra-assert-call,omitempty" toml:"suite-extra-assert-call,multiline,omitempty"` +} + +type TestifylintBoolCompare struct { + IgnoreCustomTypes *bool `yaml:"ignore-custom-types,omitempty" toml:"ignore-custom-types,multiline,omitempty"` +} + +type TestifylintExpectedActual struct { + ExpVarPattern *string `yaml:"pattern,omitempty" toml:"pattern,multiline,omitempty"` +} + +type TestifylintFormatter struct { + CheckFormatString *bool `yaml:"check-format-string,omitempty" toml:"check-format-string,multiline,omitempty"` + RequireFFuncs *bool `yaml:"require-f-funcs,omitempty" toml:"require-f-funcs,multiline,omitempty"` + RequireStringMsg *bool `yaml:"require-string-msg,omitempty" toml:"require-string-msg,multiline,omitempty"` +} + +type TestifylintGoRequire struct { + IgnoreHTTPHandlers *bool `yaml:"ignore-http-handlers,omitempty" toml:"ignore-http-handlers,multiline,omitempty"` +} + +type TestifylintRequireError struct { + FnPattern *string `yaml:"fn-pattern,omitempty" toml:"fn-pattern,multiline,omitempty"` +} + +type TestifylintSuiteExtraAssertCall struct { + Mode *string `yaml:"mode,omitempty" toml:"mode,multiline,omitempty"` +} + +type TestpackageSettings struct { + SkipRegexp *string `yaml:"skip-regexp,omitempty" toml:"skip-regexp,multiline,omitempty"` + AllowPackages []string `yaml:"allow-packages,omitempty" toml:"allow-packages,multiline,omitempty"` +} + +type ThelperSettings struct { + Test ThelperOptions `yaml:"test,omitempty" toml:"test,multiline,omitempty"` + Fuzz ThelperOptions `yaml:"fuzz,omitempty" toml:"fuzz,multiline,omitempty"` + Benchmark ThelperOptions `yaml:"benchmark,omitempty" toml:"benchmark,multiline,omitempty"` + TB ThelperOptions `yaml:"tb,omitempty" toml:"tb,multiline,omitempty"` +} + +type ThelperOptions struct { + First *bool `yaml:"first,omitempty" toml:"first,multiline,omitempty"` + Name *bool `yaml:"name,omitempty" toml:"name,multiline,omitempty"` + Begin *bool `yaml:"begin,omitempty" toml:"begin,multiline,omitempty"` +} + +type UseStdlibVarsSettings struct { + HTTPMethod *bool `yaml:"http-method,omitempty" toml:"http-method,multiline,omitempty"` + HTTPStatusCode *bool `yaml:"http-status-code,omitempty" toml:"http-status-code,multiline,omitempty"` + TimeWeekday *bool `yaml:"time-weekday,omitempty" toml:"time-weekday,multiline,omitempty"` + TimeMonth *bool `yaml:"time-month,omitempty" toml:"time-month,multiline,omitempty"` + TimeLayout *bool `yaml:"time-layout,omitempty" toml:"time-layout,multiline,omitempty"` + CryptoHash *bool `yaml:"crypto-hash,omitempty" toml:"crypto-hash,multiline,omitempty"` + DefaultRPCPath *bool `yaml:"default-rpc-path,omitempty" toml:"default-rpc-path,multiline,omitempty"` + SQLIsolationLevel *bool `yaml:"sql-isolation-level,omitempty" toml:"sql-isolation-level,multiline,omitempty"` + TLSSignatureScheme *bool `yaml:"tls-signature-scheme,omitempty" toml:"tls-signature-scheme,multiline,omitempty"` + ConstantKind *bool `yaml:"constant-kind,omitempty" toml:"constant-kind,multiline,omitempty"` + TimeDateMonth *bool `yaml:"time-date-month,omitempty" toml:"time-date-month,multiline,omitempty"` +} + +type UseTestingSettings struct { + ContextBackground *bool `yaml:"context-background,omitempty" toml:"context-background,multiline,omitempty"` + ContextTodo *bool `yaml:"context-todo,omitempty" toml:"context-todo,multiline,omitempty"` + OSChdir *bool `yaml:"os-chdir,omitempty" toml:"os-chdir,multiline,omitempty"` + OSMkdirTemp *bool `yaml:"os-mkdir-temp,omitempty" toml:"os-mkdir-temp,multiline,omitempty"` + OSSetenv *bool `yaml:"os-setenv,omitempty" toml:"os-setenv,multiline,omitempty"` + OSTempDir *bool `yaml:"os-temp-dir,omitempty" toml:"os-temp-dir,multiline,omitempty"` + OSCreateTemp *bool `yaml:"os-create-temp,omitempty" toml:"os-create-temp,multiline,omitempty"` +} + +type UnconvertSettings struct { + FastMath *bool `yaml:"fast-math,omitempty" toml:"fast-math,multiline,omitempty"` + Safe *bool `yaml:"safe,omitempty" toml:"safe,multiline,omitempty"` +} + +type UnparamSettings struct { + CheckExported *bool `yaml:"check-exported,omitempty" toml:"check-exported,multiline,omitempty"` +} + +type UnusedSettings struct { + FieldWritesAreUses *bool `yaml:"field-writes-are-uses,omitempty" toml:"field-writes-are-uses,multiline,omitempty"` + PostStatementsAreReads *bool `yaml:"post-statements-are-reads,omitempty" toml:"post-statements-are-reads,multiline,omitempty"` + ExportedFieldsAreUsed *bool `yaml:"exported-fields-are-used,omitempty" toml:"exported-fields-are-used,multiline,omitempty"` + ParametersAreUsed *bool `yaml:"parameters-are-used,omitempty" toml:"parameters-are-used,multiline,omitempty"` + LocalVariablesAreUsed *bool `yaml:"local-variables-are-used,omitempty" toml:"local-variables-are-used,multiline,omitempty"` + GeneratedIsUsed *bool `yaml:"generated-is-used,omitempty" toml:"generated-is-used,multiline,omitempty"` +} + +type VarnamelenSettings struct { + MaxDistance *int `yaml:"max-distance,omitempty" toml:"max-distance,multiline,omitempty"` + MinNameLength *int `yaml:"min-name-length,omitempty" toml:"min-name-length,multiline,omitempty"` + CheckReceiver *bool `yaml:"check-receiver,omitempty" toml:"check-receiver,multiline,omitempty"` + CheckReturn *bool `yaml:"check-return,omitempty" toml:"check-return,multiline,omitempty"` + CheckTypeParam *bool `yaml:"check-type-param,omitempty" toml:"check-type-param,multiline,omitempty"` + IgnoreNames []string `yaml:"ignore-names,omitempty" toml:"ignore-names,multiline,omitempty"` + IgnoreTypeAssertOk *bool `yaml:"ignore-type-assert-ok,omitempty" toml:"ignore-type-assert-ok,multiline,omitempty"` + IgnoreMapIndexOk *bool `yaml:"ignore-map-index-ok,omitempty" toml:"ignore-map-index-ok,multiline,omitempty"` + IgnoreChanRecvOk *bool `yaml:"ignore-chan-recv-ok,omitempty" toml:"ignore-chan-recv-ok,multiline,omitempty"` + IgnoreDecls []string `yaml:"ignore-decls,omitempty" toml:"ignore-decls,multiline,omitempty"` +} + +type WhitespaceSettings struct { + MultiIf *bool `yaml:"multi-if,omitempty" toml:"multi-if,multiline,omitempty"` + MultiFunc *bool `yaml:"multi-func,omitempty" toml:"multi-func,multiline,omitempty"` +} + +type WrapcheckSettings struct { + ExtraIgnoreSigs []string `yaml:"extra-ignore-sigs,omitempty" toml:"extra-ignore-sigs,multiline,omitempty"` + IgnoreSigs []string `yaml:"ignore-sigs,omitempty" toml:"ignore-sigs,multiline,omitempty"` + IgnoreSigRegexps []string `yaml:"ignore-sig-regexps,omitempty" toml:"ignore-sig-regexps,multiline,omitempty"` + IgnorePackageGlobs []string `yaml:"ignore-package-globs,omitempty" toml:"ignore-package-globs,multiline,omitempty"` + IgnoreInterfaceRegexps []string `yaml:"ignore-interface-regexps,omitempty" toml:"ignore-interface-regexps,multiline,omitempty"` + ReportInternalErrors *bool `yaml:"report-internal-errors,omitempty" toml:"report-internal-errors,multiline,omitempty"` +} + +type WSLv4Settings struct { + StrictAppend *bool `yaml:"strict-append,omitempty" toml:"strict-append,multiline,omitempty"` + AllowAssignAndCallCuddle *bool `yaml:"allow-assign-and-call,omitempty" toml:"allow-assign-and-call,multiline,omitempty"` + AllowAssignAndAnythingCuddle *bool `yaml:"allow-assign-and-anything,omitempty" toml:"allow-assign-and-anything,multiline,omitempty"` + AllowMultiLineAssignCuddle *bool `yaml:"allow-multiline-assign,omitempty" toml:"allow-multiline-assign,multiline,omitempty"` + ForceCaseTrailingWhitespaceLimit *int `yaml:"force-case-trailing-whitespace,omitempty" toml:"force-case-trailing-whitespace,multiline,omitempty"` + AllowTrailingComment *bool `yaml:"allow-trailing-comment,omitempty" toml:"allow-trailing-comment,multiline,omitempty"` + AllowSeparatedLeadingComment *bool `yaml:"allow-separated-leading-comment,omitempty" toml:"allow-separated-leading-comment,multiline,omitempty"` + AllowCuddleDeclaration *bool `yaml:"allow-cuddle-declarations,omitempty" toml:"allow-cuddle-declarations,multiline,omitempty"` + AllowCuddleWithCalls []string `yaml:"allow-cuddle-with-calls,omitempty" toml:"allow-cuddle-with-calls,multiline,omitempty"` + AllowCuddleWithRHS []string `yaml:"allow-cuddle-with-rhs,omitempty" toml:"allow-cuddle-with-rhs,multiline,omitempty"` + AllowCuddleUsedInBlock *bool `yaml:"allow-cuddle-used-in-block,omitempty" toml:"allow-cuddle-used-in-block,multiline,omitempty"` + ForceCuddleErrCheckAndAssign *bool `yaml:"force-err-cuddling,omitempty" toml:"force-err-cuddling,multiline,omitempty"` + ErrorVariableNames []string `yaml:"error-variable-names,omitempty" toml:"error-variable-names,multiline,omitempty"` + ForceExclusiveShortDeclarations *bool `yaml:"force-short-decl-cuddling,omitempty" toml:"force-short-decl-cuddling,multiline,omitempty"` +} + +type WSLv5Settings struct { + AllowFirstInBlock *bool `yaml:"allow-first-in-block,omitempty" toml:"allow-first-in-block,multiline,omitempty"` + AllowWholeBlock *bool `yaml:"allow-whole-block,omitempty" toml:"allow-whole-block,multiline,omitempty"` + BranchMaxLines *int `yaml:"branch-max-lines,omitempty" toml:"branch-max-lines,multiline,omitempty"` + CaseMaxLines *int `yaml:"case-max-lines,omitempty" toml:"case-max-lines,multiline,omitempty"` + Default *string `yaml:"default,omitempty" toml:"default,multiline,omitempty"` + Enable []string `yaml:"enable,omitempty" toml:"enable,multiline,omitempty"` + Disable []string `yaml:"disable,omitempty" toml:"disable,multiline,omitempty"` +} + +type CustomLinterSettings struct { + Type *string `yaml:"type,omitempty" toml:"type,multiline,omitempty"` + + Path *string `yaml:"path,omitempty" toml:"path,multiline,omitempty"` + + Description *string `yaml:"description,omitempty" toml:"description,multiline,omitempty"` + + OriginalURL *string `yaml:"original-url,omitempty" toml:"original-url,multiline,omitempty"` + + Settings any `yaml:"settings,omitempty" toml:"settings,multiline,omitempty"` +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/output.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/output.go new file mode 100644 index 000000000..16afb6701 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/output.go @@ -0,0 +1,11 @@ +// Code generated by pkg/commands/internal/migrate/cloner/cloner.go. DO NOT EDIT. + +package versiontwo + +type Output struct { + Formats Formats `yaml:"formats,omitempty" toml:"formats,multiline,omitempty"` + SortOrder []string `yaml:"sort-order,omitempty" toml:"sort-order,multiline,omitempty"` + ShowStats *bool `yaml:"show-stats,omitempty" toml:"show-stats,multiline,omitempty"` + PathPrefix *string `yaml:"path-prefix,omitempty" toml:"path-prefix,multiline,omitempty"` + PathMode *string `yaml:"path-mode,omitempty" toml:"path-mode,multiline,omitempty"` +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/output_formats.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/output_formats.go new file mode 100644 index 000000000..dbc5665f7 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/output_formats.go @@ -0,0 +1,37 @@ +// Code generated by pkg/commands/internal/migrate/cloner/cloner.go. DO NOT EDIT. + +package versiontwo + +type Formats struct { + Text Text `yaml:"text,omitempty" toml:"text,multiline,omitempty"` + JSON SimpleFormat `yaml:"json,omitempty" toml:"json,multiline,omitempty"` + Tab Tab `yaml:"tab,omitempty" toml:"tab,multiline,omitempty"` + HTML SimpleFormat `yaml:"html,omitempty" toml:"html,multiline,omitempty"` + Checkstyle SimpleFormat `yaml:"checkstyle,omitempty" toml:"checkstyle,multiline,omitempty"` + CodeClimate SimpleFormat `yaml:"code-climate,omitempty" toml:"code-climate,multiline,omitempty"` + JUnitXML JUnitXML `yaml:"junit-xml,omitempty" toml:"junit-xml,multiline,omitempty"` + TeamCity SimpleFormat `yaml:"teamcity,omitempty" toml:"teamcity,multiline,omitempty"` + Sarif SimpleFormat `yaml:"sarif,omitempty" toml:"sarif,multiline,omitempty"` +} + +type SimpleFormat struct { + Path *string `yaml:"path,omitempty" toml:"path,multiline,omitempty"` +} + +type Text struct { + SimpleFormat `yaml:",inline"` + PrintLinterName *bool `yaml:"print-linter-name,omitempty" toml:"print-linter-name,multiline,omitempty"` + PrintIssuedLine *bool `yaml:"print-issued-lines,omitempty" toml:"print-issued-lines,multiline,omitempty"` + Colors *bool `yaml:"colors,omitempty" toml:"colors,multiline,omitempty"` +} + +type Tab struct { + SimpleFormat `yaml:",inline"` + PrintLinterName *bool `yaml:"print-linter-name,omitempty" toml:"print-linter-name,multiline,omitempty"` + Colors *bool `yaml:"colors,omitempty" toml:"colors,multiline,omitempty"` +} + +type JUnitXML struct { + SimpleFormat `yaml:",inline"` + Extended *bool `yaml:"extended,omitempty" toml:"extended,multiline,omitempty"` +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/run.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/run.go new file mode 100644 index 000000000..501d3e9fc --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/run.go @@ -0,0 +1,26 @@ +// Code generated by pkg/commands/internal/migrate/cloner/cloner.go. DO NOT EDIT. + +package versiontwo + +import ( + "time" +) + +type Run struct { + Timeout time.Duration `yaml:"timeout,omitempty" toml:"timeout,multiline,omitempty"` + + Concurrency *int `yaml:"concurrency,omitempty" toml:"concurrency,multiline,omitempty"` + + Go *string `yaml:"go,omitempty" toml:"go,multiline,omitempty"` + + RelativePathMode *string `yaml:"relative-path-mode,omitempty" toml:"relative-path-mode,multiline,omitempty"` + + BuildTags []string `yaml:"build-tags,omitempty" toml:"build-tags,multiline,omitempty"` + ModulesDownloadMode *string `yaml:"modules-download-mode,omitempty" toml:"modules-download-mode,multiline,omitempty"` + + ExitCodeIfIssuesFound *int `yaml:"issues-exit-code,omitempty" toml:"issues-exit-code,multiline,omitempty"` + AnalyzeTests *bool `yaml:"tests,omitempty" toml:"tests,multiline,omitempty"` + + AllowParallelRunners *bool `yaml:"allow-parallel-runners,omitempty" toml:"allow-parallel-runners,multiline,omitempty"` + AllowSerialRunners *bool `yaml:"allow-serial-runners,omitempty" toml:"allow-serial-runners,multiline,omitempty"` +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/severity.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/severity.go new file mode 100644 index 000000000..248ddf1f1 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versiontwo/severity.go @@ -0,0 +1,13 @@ +// Code generated by pkg/commands/internal/migrate/cloner/cloner.go. DO NOT EDIT. + +package versiontwo + +type Severity struct { + Default *string `yaml:"default,omitempty" toml:"default,multiline,omitempty"` + Rules []SeverityRule `yaml:"rules,omitempty" toml:"rules,multiline,omitempty"` +} + +type SeverityRule struct { + BaseRule `yaml:",inline"` + Severity *string `yaml:"severity,omitempty" toml:"severity,multiline,omitempty"` +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/commands/internal/vibra.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/vibra.go similarity index 100% rename from vendor/github.com/golangci/golangci-lint/pkg/commands/internal/vibra.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/commands/internal/vibra.go diff --git a/vendor/github.com/golangci/golangci-lint/pkg/commands/linters.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/linters.go similarity index 63% rename from vendor/github.com/golangci/golangci-lint/pkg/commands/linters.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/commands/linters.go index a93814f0f..4be11ab56 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/commands/linters.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/linters.go @@ -1,20 +1,28 @@ package commands import ( + "encoding/json" "fmt" "github.com/fatih/color" "github.com/spf13/cobra" "github.com/spf13/viper" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/lint/lintersdb" - "github.com/golangci/golangci-lint/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goformatters" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/lint/lintersdb" + "github.com/golangci/golangci-lint/v2/pkg/logutils" ) +type lintersHelp struct { + Enabled []linterHelp + Disabled []linterHelp +} + type lintersOptions struct { config.LoaderOptions + JSON bool } type lintersCommand struct { @@ -39,7 +47,7 @@ func newLintersCommand(logger logutils.Log) *lintersCommand { lintersCmd := &cobra.Command{ Use: "linters", - Short: "List current linters configuration", + Short: "List current linters configuration.", Args: cobra.NoArgs, ValidArgsFunction: cobra.NoFileCompletions, RunE: c.execute, @@ -53,13 +61,15 @@ func newLintersCommand(logger logutils.Log) *lintersCommand { setupConfigFileFlagSet(fs, &c.opts.LoaderOptions) setupLintersFlagSet(c.viper, fs) + fs.BoolVar(&c.opts.JSON, "json", false, color.GreenString("Display as JSON")) + c.cmd = lintersCmd return c } func (c *lintersCommand) preRunE(cmd *cobra.Command, args []string) error { - loader := config.NewLoader(c.log.Child(logutils.DebugKeyConfigReader), c.viper, cmd.Flags(), c.opts.LoaderOptions, c.cfg, args) + loader := config.NewLintersLoader(c.log.Child(logutils.DebugKeyConfigReader), c.viper, cmd.Flags(), c.opts.LoaderOptions, c.cfg, args) err := loader.Load(config.LoadOptions{Validation: true}) if err != nil { @@ -84,24 +94,43 @@ func (c *lintersCommand) execute(_ *cobra.Command, _ []string) error { } var enabledLinters []*linter.Config - var disabledLCs []*linter.Config + var disabledLinters []*linter.Config for _, lc := range c.dbManager.GetAllSupportedLinterConfigs() { if lc.Internal { continue } + if goformatters.IsFormatter(lc.Name()) { + continue + } + if enabledLintersMap[lc.Name()] == nil { - disabledLCs = append(disabledLCs, lc) + disabledLinters = append(disabledLinters, lc) } else { enabledLinters = append(enabledLinters, lc) } } + if c.opts.JSON { + linters := lintersHelp{} + + for _, lc := range enabledLinters { + linters.Enabled = append(linters.Enabled, newLinterHelp(lc)) + } + + for _, lc := range disabledLinters { + linters.Disabled = append(linters.Disabled, newLinterHelp(lc)) + } + + return json.NewEncoder(c.cmd.OutOrStdout()).Encode(linters) + } + color.Green("Enabled by your configuration linters:\n") printLinters(enabledLinters) + color.Red("\nDisabled by your configuration linters:\n") - printLinters(disabledLCs) + printLinters(disabledLinters) return nil } diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/migrate.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/migrate.go new file mode 100644 index 000000000..7012e9226 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/migrate.go @@ -0,0 +1,243 @@ +package commands + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/charmbracelet/lipgloss" + "github.com/fatih/color" + "github.com/santhosh-tekuri/jsonschema/v6" + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate" + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/fakeloader" + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/parser" + "github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/versionone" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/exitcodes" + "github.com/golangci/golangci-lint/v2/pkg/logutils" +) + +type migrateOptions struct { + config.LoaderOptions + + format string // Flag only. + skipValidation bool // Flag only. +} +type migrateCommand struct { + viper *viper.Viper + cmd *cobra.Command + + opts migrateOptions + + cfg *versionone.Config + + buildInfo BuildInfo + + log logutils.Log +} + +func newMigrateCommand(log logutils.Log, info BuildInfo) *migrateCommand { + c := &migrateCommand{ + viper: viper.New(), + cfg: versionone.NewConfig(), + buildInfo: info, + log: log, + } + + migrateCmd := &cobra.Command{ + Use: "migrate", + Short: "Migrate configuration file from v1 to v2.", + SilenceUsage: true, + SilenceErrors: true, + Args: cobra.NoArgs, + RunE: c.execute, + PreRunE: c.preRunE, + PersistentPreRunE: c.persistentPreRunE, + } + + migrateCmd.SetOut(logutils.StdOut) // use custom output to properly color it in Windows terminals + migrateCmd.SetErr(logutils.StdErr) + + fs := migrateCmd.Flags() + fs.SortFlags = false // sort them as they are defined here + + setupConfigFileFlagSet(fs, &c.opts.LoaderOptions) + + fs.StringVar(&c.opts.format, "format", "", + color.GreenString("Output file format.\nBy default, the format of the input configuration file is used.\n"+ + "It can be 'yml', 'yaml', 'toml', or 'json'.")) + + fs.BoolVar(&c.opts.skipValidation, "skip-validation", false, + color.GreenString("Skip validation of the configuration file against the JSON Schema for v1.")) + + c.cmd = migrateCmd + + return c +} + +func (c *migrateCommand) execute(_ *cobra.Command, _ []string) error { + srcPath := c.viper.ConfigFileUsed() + if srcPath == "" { + c.log.Warnf("No config file detected") + os.Exit(exitcodes.NoConfigFileDetected) + } + + err := c.backupConfigurationFile(srcPath) + if err != nil { + return err + } + + c.log.Warnf("The configuration comments are not migrated.") + c.log.Warnf("Details about the migration: https://golangci-lint.run/docs/product/migration-guide/") + + c.log.Infof("Migrating v1 configuration file: %s", srcPath) + + ext := filepath.Ext(srcPath) + + if c.opts.format != "" { + ext = "." + c.opts.format + } + + if !strings.EqualFold(filepath.Ext(srcPath), ext) { + defer func() { + _ = os.RemoveAll(srcPath) + }() + } + + if c.cfg.Run.Timeout != 0 { + c.log.Warnf("The configuration `run.timeout` is ignored. By default, in v2, the timeout is disabled.") + } + + newCfg := migrate.ToConfig(c.cfg) + + dstPath := strings.TrimSuffix(srcPath, filepath.Ext(srcPath)) + ext + + err = saveNewConfiguration(newCfg, dstPath) + if err != nil { + return fmt.Errorf("saving configuration file: %w", err) + } + + c.log.Infof("Migration done: %s", dstPath) + + callForAction(c.cmd) + + return nil +} + +func (c *migrateCommand) preRunE(cmd *cobra.Command, _ []string) error { + switch strings.ToLower(c.opts.format) { + case "", "yml", "yaml", "toml", "json": + // Valid format. + default: + return fmt.Errorf("unsupported format: %s", c.opts.format) + } + + if c.cfg.Version != "" { + return fmt.Errorf("configuration version is already set: %s", c.cfg.Version) + } + + if c.opts.skipValidation { + return nil + } + + usedConfigFile := c.viper.ConfigFileUsed() + if usedConfigFile == "" { + c.log.Warnf("No config file detected") + os.Exit(exitcodes.NoConfigFileDetected) + } + + c.log.Infof("Validating v1 configuration file: %s", usedConfigFile) + + err := validateConfiguration("https://golangci-lint.run/jsonschema/golangci.v1.jsonschema.json", usedConfigFile) + if err != nil { + var v *jsonschema.ValidationError + if !errors.As(err, &v) { + return fmt.Errorf("[%s] validate: %w", usedConfigFile, err) + } + + printValidationDetail(cmd, v.DetailedOutput()) + + return errors.New("the configuration contains invalid elements") + } + + return nil +} + +func (c *migrateCommand) persistentPreRunE(_ *cobra.Command, args []string) error { + c.log.Infof("%s", c.buildInfo.String()) + + loader := config.NewBaseLoader(c.log.Child(logutils.DebugKeyConfigReader), c.viper, c.opts.LoaderOptions, fakeloader.NewConfig(), args) + + // Loads the configuration just to get the effective path of the configuration. + err := loader.Load() + if err != nil { + return fmt.Errorf("can't load config: %w", err) + } + + srcPath := c.viper.ConfigFileUsed() + if srcPath == "" { + c.log.Warnf("No config file detected") + os.Exit(exitcodes.NoConfigFileDetected) + } + + return fakeloader.Load(srcPath, c.cfg) +} + +func (c *migrateCommand) backupConfigurationFile(srcPath string) error { + filename := strings.TrimSuffix(filepath.Base(srcPath), filepath.Ext(srcPath)) + ".bck" + filepath.Ext(srcPath) + dstPath := filepath.Join(filepath.Dir(srcPath), filename) + + c.log.Infof("Saving the v1 configuration to: %s", dstPath) + + stat, err := os.Stat(srcPath) + if err != nil { + return err + } + + data, err := os.ReadFile(srcPath) + if err != nil { + return err + } + + err = os.WriteFile(dstPath, data, stat.Mode()) + if err != nil { + return err + } + + return nil +} + +func saveNewConfiguration(cfg any, dstPath string) error { + dstFile, err := os.Create(dstPath) + if err != nil { + return err + } + + defer func() { _ = dstFile.Close() }() + + return parser.Encode(cfg, dstFile) +} + +func callForAction(cmd *cobra.Command) { + pStyle := lipgloss.NewStyle(). + Padding(1). + BorderStyle(lipgloss.RoundedBorder()). + BorderForeground(lipgloss.Color("161")). + Align(lipgloss.Center) + + hStyle := lipgloss.NewStyle().Bold(true) + + s := fmt.Sprintln(hStyle.Render("We need you!")) + s += ` +Donations help fund the ongoing development and maintenance of this tool. +If golangci-lint has been useful to you, please consider contributing. + +Donate now: https://donate.golangci.org` + + cmd.Println(pStyle.Render(s)) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/commands/root.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/root.go similarity index 92% rename from vendor/github.com/golangci/golangci-lint/pkg/commands/root.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/commands/root.go index cbb838aac..9fa36f25f 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/commands/root.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/root.go @@ -10,7 +10,7 @@ import ( "github.com/spf13/cobra" "github.com/spf13/pflag" - "github.com/golangci/golangci-lint/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/logutils" ) func Execute(info BuildInfo) error { @@ -59,7 +59,10 @@ func newRootCommand(info BuildInfo) *rootCommand { // Each command uses a dedicated configuration structure to avoid side effects of bindings. rootCmd.AddCommand( newLintersCommand(log).cmd, + newFormattersCommand(log).cmd, newRunCommand(log, info).cmd, + newFmtCommand(log, info).cmd, + newMigrateCommand(log, info).cmd, newCacheCommand().cmd, newConfigCommand(log, info).cmd, newVersionCommand(info).cmd, @@ -112,6 +115,9 @@ func setupLogger(logger logutils.Log) error { logger.Fatalf("invalid value %q for --color; must be 'always', 'auto', or 'never'", opts.Color) } + // For log level colors (mainly for verbose output) + logutils.DisableColors(color.NoColor) + return nil } @@ -121,7 +127,7 @@ func forceRootParsePersistentFlags() (*rootOptions, error) { fs := pflag.NewFlagSet("config flag set", pflag.ContinueOnError) // Ignore unknown flags because we will parse the command flags later. - fs.ParseErrorsWhitelist = pflag.ParseErrorsWhitelist{UnknownFlags: true} + fs.ParseErrorsAllowlist = pflag.ParseErrorsAllowlist{UnknownFlags: true} opts := &rootOptions{} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/commands/run.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/run.go similarity index 80% rename from vendor/github.com/golangci/golangci-lint/pkg/commands/run.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/commands/run.go index ff7c5e467..a9a3495aa 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/commands/run.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/run.go @@ -8,42 +8,43 @@ import ( "fmt" "io" "log" + "maps" "os" "path/filepath" "runtime" "runtime/pprof" "runtime/trace" - "sort" + "slices" "strconv" "strings" "time" "github.com/fatih/color" "github.com/gofrs/flock" + "github.com/ldez/grignotin/goenv" "github.com/spf13/cobra" "github.com/spf13/pflag" "github.com/spf13/viper" - "go.uber.org/automaxprocs/maxprocs" - "golang.org/x/exp/maps" - "gopkg.in/yaml.v3" - - "github.com/golangci/golangci-lint/internal/cache" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/exitcodes" - "github.com/golangci/golangci-lint/pkg/fsutils" - "github.com/golangci/golangci-lint/pkg/goanalysis/load" - "github.com/golangci/golangci-lint/pkg/goutil" - "github.com/golangci/golangci-lint/pkg/lint" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/lint/lintersdb" - "github.com/golangci/golangci-lint/pkg/logutils" - "github.com/golangci/golangci-lint/pkg/printers" - "github.com/golangci/golangci-lint/pkg/report" - "github.com/golangci/golangci-lint/pkg/result" - "github.com/golangci/golangci-lint/pkg/timeutils" + "go.yaml.in/yaml/v3" + "golang.org/x/mod/sumdb/dirhash" + + "github.com/golangci/golangci-lint/v2/internal/cache" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/exitcodes" + "github.com/golangci/golangci-lint/v2/pkg/fsutils" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis/load" + "github.com/golangci/golangci-lint/v2/pkg/goutil" + "github.com/golangci/golangci-lint/v2/pkg/lint" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/lint/lintersdb" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/printers" + "github.com/golangci/golangci-lint/v2/pkg/report" + "github.com/golangci/golangci-lint/v2/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/timeutils" ) -const defaultTimeout = time.Minute +const defaultTimeout = 0 * time.Minute const ( // envFailOnWarnings value: "1" @@ -53,8 +54,6 @@ const ( ) const ( - // envHelpRun value: "1". - envHelpRun = "HELP_RUN" envMemProfileRate = "GL_MEM_PROFILE_RATE" ) @@ -111,7 +110,7 @@ func newRunCommand(logger logutils.Log, info BuildInfo) *runCommand { runCmd := &cobra.Command{ Use: "run", - Short: "Run the linters", + Short: "Lint the code.", Run: c.execute, PreRunE: c.preRunE, PostRun: c.postRun, @@ -153,22 +152,15 @@ func (c *runCommand) persistentPreRunE(cmd *cobra.Command, args []string) error c.log.Infof("%s", c.buildInfo.String()) - loader := config.NewLoader(c.log.Child(logutils.DebugKeyConfigReader), c.viper, cmd.Flags(), c.opts.LoaderOptions, c.cfg, args) + loader := config.NewLintersLoader(c.log.Child(logutils.DebugKeyConfigReader), c.viper, cmd.Flags(), c.opts.LoaderOptions, c.cfg, args) err := loader.Load(config.LoadOptions{CheckDeprecation: true, Validation: true}) if err != nil { return fmt.Errorf("can't load config: %w", err) } - if c.cfg.Run.Concurrency == 0 { - backup := runtime.GOMAXPROCS(0) - - // Automatically set GOMAXPROCS to match Linux container CPU quota. - _, err := maxprocs.Set(maxprocs.Logger(c.log.Infof)) - if err != nil { - runtime.GOMAXPROCS(backup) - } - } else { + // https://go.dev/doc/go1.25#container-aware-gomaxprocs + if c.cfg.Run.Concurrency != 0 { runtime.GOMAXPROCS(c.cfg.Run.Concurrency) } @@ -194,13 +186,11 @@ func (c *runCommand) preRunE(_ *cobra.Command, args []string) error { c.dbManager = dbManager - printer, err := printers.NewPrinter(c.log, &c.cfg.Output, c.reportData) + c.printer, err = printers.NewPrinter(c.log, &c.cfg.Output.Formats, c.reportData, c.cfg.GetBasePath()) if err != nil { return err } - c.printer = printer - c.goenv = goutil.NewEnv(c.log.Child(logutils.DebugKeyGoEnv)) c.fileCache = fsutils.NewFileCache() @@ -217,9 +207,9 @@ func (c *runCommand) preRunE(_ *cobra.Command, args []string) error { pkgLoader := lint.NewPackageLoader(c.log.Child(logutils.DebugKeyLoader), c.cfg, args, c.goenv, guard) - c.contextBuilder = lint.NewContextBuilder(c.cfg, pkgLoader, c.fileCache, pkgCache, guard) + c.contextBuilder = lint.NewContextBuilder(c.cfg, pkgLoader, pkgCache, guard) - if err = initHashSalt(c.buildInfo.Version, c.cfg); err != nil { + if err = initHashSalt(c.log.Child(logutils.DebugKeyGoModSalt), c.buildInfo.Version, c.cfg); err != nil { return fmt.Errorf("failed to init hash salt: %w", err) } @@ -234,24 +224,30 @@ func (c *runCommand) postRun(_ *cobra.Command, _ []string) { c.releaseFileLock() } -func (c *runCommand) execute(_ *cobra.Command, args []string) { +func (c *runCommand) execute(_ *cobra.Command, _ []string) { needTrackResources := logutils.IsVerbose() || c.opts.PrintResourcesUsage trackResourcesEndCh := make(chan struct{}) - defer func() { // XXX: this defer must be before ctx.cancel defer - if needTrackResources { // wait until resource tracking finished to print properly + + // Note: this defer must be before ctx.cancel defer + defer func() { + // wait until resource tracking finished to print properly + if needTrackResources { <-trackResourcesEndCh } }() - ctx, cancel := context.WithTimeout(context.Background(), c.cfg.Run.Timeout) + ctx, cancel := context.WithCancel(context.Background()) + if c.cfg.Run.Timeout > 0 { + ctx, cancel = context.WithTimeout(ctx, c.cfg.Run.Timeout) + } defer cancel() if needTrackResources { go watchResources(ctx, trackResourcesEndCh, c.log, c.debugf) } - if err := c.runAndPrint(ctx, args); err != nil { + if err := c.runAndPrint(ctx); err != nil { c.log.Errorf("Running error: %s", err) if c.exitCode == exitcodes.Success { var exitErr *exitcodes.ExitError @@ -324,7 +320,7 @@ func (c *runCommand) stopTracing() error { return nil } -func (c *runCommand) runAndPrint(ctx context.Context, args []string) error { +func (c *runCommand) runAndPrint(ctx context.Context) error { if err := c.goenv.Discover(ctx); err != nil { c.log.Warnf("Failed to discover go env: %s", err) } @@ -345,7 +341,7 @@ func (c *runCommand) runAndPrint(ctx context.Context, args []string) error { c.printDeprecatedLinterMessages(enabledLintersMap) - issues, err := c.runAnalysis(ctx, args) + issues, err := c.runAnalysis(ctx) if err != nil { return err // XXX: don't lose type } @@ -353,7 +349,7 @@ func (c *runCommand) runAndPrint(ctx context.Context, args []string) error { // Fills linters information for the JSON printer. for _, lc := range c.dbManager.GetAllSupportedLinterConfigs() { isEnabled := enabledLintersMap[lc.Name()] != nil - c.reportData.AddLinter(lc.Name(), isEnabled, lc.EnabledByDefault) + c.reportData.AddLinter(lc.Name(), isEnabled) } err = c.printer.Print(issues) @@ -371,7 +367,7 @@ func (c *runCommand) runAndPrint(ctx context.Context, args []string) error { } // runAnalysis executes the linters that have been enabled in the configuration. -func (c *runCommand) runAnalysis(ctx context.Context, args []string) ([]result.Issue, error) { +func (c *runCommand) runAnalysis(ctx context.Context) ([]*result.Issue, error) { lintersToRun, err := c.dbManager.GetOptimizedLinters() if err != nil { return nil, err @@ -382,7 +378,7 @@ func (c *runCommand) runAnalysis(ctx context.Context, args []string) ([]result.I return nil, fmt.Errorf("context loading failed: %w", err) } - runner, err := lint.NewRunner(c.log.Child(logutils.DebugKeyRunner), c.cfg, args, + runner, err := lint.NewRunner(c.log.Child(logutils.DebugKeyRunner), c.cfg, c.goenv, c.lineCache, c.fileCache, c.dbManager, lintCtx) if err != nil { return nil, err @@ -403,7 +399,7 @@ func (c *runCommand) setOutputToDevNull() (savedStdout, savedStderr *os.File) { return } -func (c *runCommand) setExitCodeIfIssuesFound(issues []result.Issue) { +func (c *runCommand) setExitCodeIfIssuesFound(issues []*result.Issue) { if len(issues) != 0 { c.exitCode = c.cfg.Run.ExitCodeIfIssuesFound } @@ -425,10 +421,21 @@ func (c *runCommand) printDeprecatedLinterMessages(enabledLinters map[string]*li } c.log.Warnf("The linter '%s' is deprecated (since %s) due to: %s %s", name, lc.Deprecation.Since, lc.Deprecation.Message, extra) + + if lc.Deprecation.ConfigSuggestion != nil { + suggestion, err := lc.Deprecation.ConfigSuggestion() + if err != nil { + c.log.Errorf("New configuration suggestion error: %v", err) + } + + if suggestion != "" { + c.log.Warnf("Suggested new configuration:\n%s", suggestion) + } + } } } -func (c *runCommand) printStats(issues []result.Issue) { +func (c *runCommand) printStats(issues []*result.Issue) { if !c.cfg.Output.ShowStats { return } @@ -445,8 +452,7 @@ func (c *runCommand) printStats(issues []result.Issue) { c.cmd.Printf("%d issues:\n", len(issues)) - keys := maps.Keys(stats) - sort.Strings(keys) + keys := slices.Sorted(maps.Keys(stats)) for _, key := range keys { c.cmd.Printf("* %s: %d\n", key, stats[key]) @@ -580,22 +586,13 @@ func setupConfigFileFlagSet(fs *pflag.FlagSet, cfg *config.LoaderOptions) { func setupRunPersistentFlags(fs *pflag.FlagSet, opts *runOptions) { fs.BoolVar(&opts.PrintResourcesUsage, "print-resources-usage", false, color.GreenString("Print avg and max memory usage of golangci-lint and total time")) + _ = fs.MarkDeprecated("print-resources-usage", "use --verbose instead") fs.StringVar(&opts.CPUProfilePath, "cpu-profile-path", "", color.GreenString("Path to CPU profile output file")) fs.StringVar(&opts.MemProfilePath, "mem-profile-path", "", color.GreenString("Path to memory profile output file")) fs.StringVar(&opts.TracePath, "trace-path", "", color.GreenString("Path to trace output file")) } -func getDefaultConcurrency() int { - if os.Getenv(envHelpRun) == "1" { - // Make stable concurrency for generating help documentation. - const prettyConcurrency = 8 - return prettyConcurrency - } - - return runtime.NumCPU() -} - func printMemStats(ms *runtime.MemStats, logger logutils.Log) { logger.Infof("Mem stats: alloc=%s total_alloc=%s sys=%s "+ "heap_alloc=%s heap_sys=%s heap_idle=%s heap_released=%s heap_in_use=%s "+ @@ -626,7 +623,7 @@ func formatMemory(memBytes uint64) string { // Related to cache. -func initHashSalt(version string, cfg *config.Config) error { +func initHashSalt(logger logutils.Log, version string, cfg *config.Config) error { binSalt, err := computeBinarySalt(version) if err != nil { return fmt.Errorf("failed to calculate binary salt: %w", err) @@ -637,9 +634,18 @@ func initHashSalt(version string, cfg *config.Config) error { return fmt.Errorf("failed to calculate config salt: %w", err) } + goModSalt, err := computeGoModSalt() + if err != nil { + // NOTE: missing go.mod must be ignored. + logger.Warnf("Failed to calculate go.mod salt: %v", err) + } + b := bytes.NewBuffer(binSalt) b.Write(configSalt) + b.WriteString(goModSalt) + cache.SetSalt(b) + return nil } @@ -656,15 +662,19 @@ func computeBinarySalt(version string) ([]byte, error) { if err != nil { return nil, err } + f, err := os.Open(p) if err != nil { return nil, err } + defer f.Close() + h := sha256.New() if _, err := io.Copy(h, f); err != nil { return nil, err } + return h.Sum(nil), nil } @@ -673,12 +683,12 @@ func computeBinarySalt(version string) ([]byte, error) { // At least, it has a huge impact on tests speed. // Fields: `LintersSettings` and `Run.BuildTags`. func computeConfigSalt(cfg *config.Config) ([]byte, error) { - lintersSettingsBytes, err := yaml.Marshal(cfg.LintersSettings) + lintersSettingsBytes, err := yaml.Marshal(cfg.Linters.Settings) if err != nil { return nil, fmt.Errorf("failed to JSON marshal config linter settings: %w", err) } - configData := bytes.NewBufferString("linters-settings=") + configData := bytes.NewBufferString("linters.settings=") configData.Write(lintersSettingsBytes) configData.WriteString("\nbuild-tags=%s" + strings.Join(cfg.Run.BuildTags, ",")) @@ -686,5 +696,29 @@ func computeConfigSalt(cfg *config.Config) ([]byte, error) { if _, err := h.Write(configData.Bytes()); err != nil { return nil, err } + return h.Sum(nil), nil } + +func computeGoModSalt() (string, error) { + values, err := goenv.Get(context.Background(), goenv.GOMOD) + if err != nil { + return "", fmt.Errorf("failed to get goenv: %w", err) + } + + goModPath := filepath.Clean(values[goenv.GOMOD]) + + data, err := os.ReadFile(goModPath) + if err != nil { + return "", fmt.Errorf("failed to read go.mod: %w", err) + } + + sum, err := dirhash.Hash1([]string{goModPath}, func(string) (io.ReadCloser, error) { + return io.NopCloser(bytes.NewReader(data)), nil + }) + if err != nil { + return "", fmt.Errorf("failed to compute go.sum: %w", err) + } + + return sum, nil +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/commands/version.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/version.go similarity index 63% rename from vendor/github.com/golangci/golangci-lint/pkg/commands/version.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/commands/version.go index ac665f4c5..c8057a86c 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/commands/version.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/commands/version.go @@ -6,17 +6,17 @@ import ( "io" "os" "runtime/debug" - "strings" "github.com/fatih/color" "github.com/spf13/cobra" ) type BuildInfo struct { - GoVersion string `json:"goVersion"` - Version string `json:"version"` - Commit string `json:"commit"` - Date string `json:"date"` + GoVersion string `json:"goVersion"` + Version string `json:"version"` + Commit string `json:"commit"` + Date string `json:"date"` + BuildInfo *debug.BuildInfo `json:"buildInfo,omitempty"` } func (b BuildInfo) String() string { @@ -24,14 +24,10 @@ func (b BuildInfo) String() string { b.Version, b.GoVersion, b.Commit, b.Date) } -type versionInfo struct { - Info BuildInfo - BuildInfo *debug.BuildInfo -} - type versionOptions struct { - Format string - Debug bool + Debug bool + JSON bool + Short bool } type versionCommand struct { @@ -46,7 +42,7 @@ func newVersionCommand(info BuildInfo) *versionCommand { versionCmd := &cobra.Command{ Use: "version", - Short: "Version", + Short: "Display the golangci-lint version.", Args: cobra.NoArgs, ValidArgsFunction: cobra.NoFileCompletions, RunE: c.execute, @@ -55,8 +51,9 @@ func newVersionCommand(info BuildInfo) *versionCommand { fs := versionCmd.Flags() fs.SortFlags = false // sort them as they are defined here - fs.StringVar(&c.opts.Format, "format", "", color.GreenString("The version's format can be: 'short', 'json'")) fs.BoolVar(&c.opts.Debug, "debug", false, color.GreenString("Add build information")) + fs.BoolVar(&c.opts.JSON, "json", false, color.GreenString("Display as JSON")) + fs.BoolVar(&c.opts.Short, "short", false, color.GreenString("Display only the version number")) c.cmd = versionCmd @@ -64,34 +61,26 @@ func newVersionCommand(info BuildInfo) *versionCommand { } func (c *versionCommand) execute(_ *cobra.Command, _ []string) error { + var info *debug.BuildInfo if c.opts.Debug { - info, ok := debug.ReadBuildInfo() - if !ok { - return nil - } - - switch strings.ToLower(c.opts.Format) { - case "json": - return json.NewEncoder(os.Stdout).Encode(versionInfo{ - Info: c.info, - BuildInfo: info, - }) - - default: - fmt.Println(info.String()) - return printVersion(os.Stdout, c.info) - } + info, _ = debug.ReadBuildInfo() } - switch strings.ToLower(c.opts.Format) { - case "short": - fmt.Println(c.info.Version) - return nil + switch { + case c.opts.JSON: + c.info.BuildInfo = info - case "json": return json.NewEncoder(os.Stdout).Encode(c.info) + case c.opts.Short: + fmt.Println(c.info.Version) + + return nil default: + if info != nil { + fmt.Println(info.String()) + } + return printVersion(os.Stdout, c.info) } } diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/config/base_loader.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/base_loader.go new file mode 100644 index 000000000..9ad332ac2 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/base_loader.go @@ -0,0 +1,232 @@ +package config + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "slices" + + "github.com/go-viper/mapstructure/v2" + "github.com/mitchellh/go-homedir" + "github.com/spf13/viper" + + "github.com/golangci/golangci-lint/v2/pkg/exitcodes" + "github.com/golangci/golangci-lint/v2/pkg/fsutils" + "github.com/golangci/golangci-lint/v2/pkg/logutils" +) + +type BaseConfig interface { + IsInternalTest() bool + SetConfigDir(dir string) +} + +type BaseLoader struct { + opts LoaderOptions + + viper *viper.Viper + + log logutils.Log + + cfg BaseConfig + args []string +} + +func NewBaseLoader(log logutils.Log, v *viper.Viper, opts LoaderOptions, cfg BaseConfig, args []string) *BaseLoader { + return &BaseLoader{ + opts: opts, + viper: v, + log: log, + cfg: cfg, + args: args, + } +} + +func (l *BaseLoader) Load() error { + err := l.setConfigFile() + if err != nil { + return err + } + + err = l.parseConfig() + if err != nil { + return err + } + + return nil +} + +func (l *BaseLoader) setConfigFile() error { + configFile, err := l.evaluateOptions() + if err != nil { + if errors.Is(err, errConfigDisabled) { + return nil + } + + return fmt.Errorf("can't parse --config option: %w", err) + } + + if configFile != "" { + l.viper.SetConfigFile(configFile) + + // Assume YAML if the file has no extension. + if filepath.Ext(configFile) == "" { + l.viper.SetConfigType("yaml") + } + } else { + l.setupConfigFileSearch() + } + + return nil +} + +func (l *BaseLoader) evaluateOptions() (string, error) { + if l.opts.NoConfig && l.opts.Config != "" { + return "", errors.New("can't combine option --config and --no-config") + } + + if l.opts.NoConfig { + return "", errConfigDisabled + } + + configFile, err := homedir.Expand(l.opts.Config) + if err != nil { + return "", errors.New("failed to expand configuration path") + } + + return configFile, nil +} + +func (l *BaseLoader) setupConfigFileSearch() { + l.viper.SetConfigName(".golangci") + + configSearchPaths := l.getConfigSearchPaths() + + l.log.Infof("Config search paths: %s", configSearchPaths) + + for _, p := range configSearchPaths { + l.viper.AddConfigPath(p) + } +} + +func (l *BaseLoader) getConfigSearchPaths() []string { + firstArg := "./..." + if len(l.args) > 0 { + firstArg = l.args[0] + } + + absPath, err := filepath.Abs(firstArg) + if err != nil { + l.log.Warnf("Can't make abs path for %q: %s", firstArg, err) + absPath = filepath.Clean(firstArg) + } + + // start from it + var currentDir string + if fsutils.IsDir(absPath) { + currentDir = absPath + } else { + currentDir = filepath.Dir(absPath) + } + + // find all dirs from it up to the root + searchPaths := []string{"./"} + + for { + searchPaths = append(searchPaths, currentDir) + + parent := filepath.Dir(currentDir) + if currentDir == parent || parent == "" { + break + } + + currentDir = parent + } + + // find home directory for global config + if home, err := homedir.Dir(); err != nil { + l.log.Warnf("Can't get user's home directory: %v", err) + } else if !slices.Contains(searchPaths, home) { + searchPaths = append(searchPaths, home) + } + + return searchPaths +} + +func (l *BaseLoader) parseConfig() error { + if err := l.viper.ReadInConfig(); err != nil { + var configFileNotFoundError viper.ConfigFileNotFoundError + if errors.As(err, &configFileNotFoundError) { + // Load configuration from flags only. + err = l.viper.Unmarshal(l.cfg, customDecoderHook()) + if err != nil { + return fmt.Errorf("can't unmarshal config by viper (flags): %w", err) + } + + return nil + } + + return fmt.Errorf("can't read viper config: %w", err) + } + + err := l.setConfigDir() + if err != nil { + return err + } + + // Load configuration from all sources (flags, file). + if err := l.viper.Unmarshal(l.cfg, customDecoderHook()); err != nil { + return fmt.Errorf("can't unmarshal config by viper (flags, file): %w", err) + } + + if l.cfg.IsInternalTest() { // just for testing purposes: to detect config file usage + _, _ = fmt.Fprintln(logutils.StdOut, "test") + os.Exit(exitcodes.Success) + } + + return nil +} + +func (l *BaseLoader) setConfigDir() error { + usedConfigFile := l.viper.ConfigFileUsed() + if usedConfigFile == "" { + return nil + } + + if usedConfigFile == os.Stdin.Name() { + usedConfigFile = "" + l.log.Infof("Reading config file stdin") + } else { + var err error + usedConfigFile, err = fsutils.ShortestRelPath(usedConfigFile, "") + if err != nil { + l.log.Warnf("Can't pretty print config file path: %v", err) + } + + l.log.Infof("Used config file %s", usedConfigFile) + } + + usedConfigDir, err := filepath.Abs(filepath.Dir(usedConfigFile)) + if err != nil { + return errors.New("can't get config directory") + } + + l.cfg.SetConfigDir(usedConfigDir) + + return nil +} + +func customDecoderHook() viper.DecoderConfigOption { + return viper.DecodeHook(DecodeHookFunc()) +} + +func DecodeHookFunc() mapstructure.DecodeHookFunc { + return mapstructure.ComposeDecodeHookFunc( + // Default hooks (https://github.com/spf13/viper/blob/518241257478c557633ab36e474dfcaeb9a3c623/viper.go#L135-L138). + mapstructure.StringToTimeDurationHookFunc(), + mapstructure.StringToSliceHookFunc(","), + + // Needed for forbidigo, and output.formats. + mapstructure.TextUnmarshallerHookFunc(), + ) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/config/base_rule.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/base_rule.go new file mode 100644 index 000000000..3a8286504 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/base_rule.go @@ -0,0 +1,75 @@ +package config + +import ( + "errors" + "fmt" + "regexp" +) + +type BaseRule struct { + Linters []string `mapstructure:"linters"` + Path string `mapstructure:"path"` + PathExcept string `mapstructure:"path-except"` + Text string `mapstructure:"text"` + Source string `mapstructure:"source"` + + // For compatibility with exclude-use-default/include. + InternalReference string `mapstructure:"-"` +} + +func (b *BaseRule) Validate(minConditionsCount int) error { + if err := validateOptionalRegex(b.Path); err != nil { + return fmt.Errorf("invalid path regex: %w", err) + } + + if err := validateOptionalRegex(b.PathExcept); err != nil { + return fmt.Errorf("invalid path-except regex: %w", err) + } + + if err := validateOptionalRegex(b.Text); err != nil { + return fmt.Errorf("invalid text regex: %w", err) + } + + if err := validateOptionalRegex(b.Source); err != nil { + return fmt.Errorf("invalid source regex: %w", err) + } + + if b.Path != "" && b.PathExcept != "" { + return errors.New("path and path-except should not be set at the same time") + } + + nonBlank := 0 + if len(b.Linters) > 0 { + nonBlank++ + } + + // Filtering by path counts as one condition, regardless how it is done (one or both). + // Otherwise, a rule with Path and PathExcept set would pass validation + // whereas before the introduction of path-except that wouldn't have been precise enough. + if b.Path != "" || b.PathExcept != "" { + nonBlank++ + } + + if b.Text != "" { + nonBlank++ + } + + if b.Source != "" { + nonBlank++ + } + + if nonBlank < minConditionsCount { + return fmt.Errorf("at least %d of (text, source, path[-except], linters) should be set", minConditionsCount) + } + + return nil +} + +func validateOptionalRegex(value string) error { + if value == "" { + return nil + } + + _, err := regexp.Compile(value) + return err +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/config/config.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/config.go new file mode 100644 index 000000000..6d7586621 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/config.go @@ -0,0 +1,201 @@ +package config + +import ( + "cmp" + "context" + "fmt" + "os" + "path/filepath" + "slices" + "strings" + + hcversion "github.com/hashicorp/go-version" + "github.com/ldez/grignotin/goenv" + "github.com/ldez/grignotin/gomod" + "golang.org/x/mod/modfile" + + "github.com/golangci/golangci-lint/v2/pkg/logutils" +) + +// defaultGoVersion the value should be "oldstable" - 1. +// If the current stable version is 1.24 then 1.23 - 1 = 1.22. +const defaultGoVersion = "1.22" + +// Config encapsulates the config data specified in the golangci-lint YAML config file. +type Config struct { + cfgDir string // Path to the directory containing golangci-lint config file. + basePath string // Path the root directory related to [Run.RelativePathMode]. + + Version string `mapstructure:"version"` + + Run Run `mapstructure:"run"` + + Output Output `mapstructure:"output"` + + Linters Linters `mapstructure:"linters"` + + Issues Issues `mapstructure:"issues"` + Severity Severity `mapstructure:"severity"` + + Formatters Formatters `mapstructure:"formatters"` + + InternalCmdTest bool // Option is used only for testing golangci-lint command, don't use it + InternalTest bool // Option is used only for testing golangci-lint code, don't use it +} + +// GetConfigDir returns the directory that contains golangci-lint config file. +func (c *Config) GetConfigDir() string { + return c.cfgDir +} + +// SetConfigDir sets the path to directory that contains golangci-lint config file. +func (c *Config) SetConfigDir(dir string) { + c.cfgDir = dir +} + +func (c *Config) GetBasePath() string { + return c.basePath +} + +func (c *Config) IsInternalTest() bool { + return c.InternalTest +} + +func (c *Config) Validate() error { + validators := []func() error{ + c.Run.Validate, + c.Output.Validate, + c.Linters.Validate, + c.Formatters.Validate, + c.Severity.Validate, + } + + for _, v := range validators { + if err := v(); err != nil { + return err + } + } + + return nil +} + +func NewDefault() *Config { + return &Config{ + Linters: Linters{ + Settings: defaultLintersSettings, + }, + Formatters: Formatters{ + Settings: defaultFormatterSettings, + }, + } +} + +func IsGoGreaterThanOrEqual(current, limit string) bool { + v1, err := hcversion.NewVersion(strings.TrimPrefix(current, "go")) + if err != nil { + return false + } + + l, err := hcversion.NewVersion(limit) + if err != nil { + return false + } + + return v1.GreaterThanOrEqual(l) +} + +func detectGoVersion(ctx context.Context, log logutils.Log) string { + return cmp.Or(detectGoVersionFromGoMod(ctx, log), defaultGoVersion) +} + +// detectGoVersionFromGoMod tries to get Go version from go.mod. +// It returns `toolchain` version if present, +// else it returns `go` version if present, +// else it returns `GOVERSION` version if present, +// else it returns empty. +func detectGoVersionFromGoMod(ctx context.Context, log logutils.Log) string { + values, err := goenv.Get(ctx, goenv.GOMOD, goenv.GOVERSION) + if err != nil { + values = map[string]string{ + goenv.GOMOD: detectGoModFallback(ctx), + } + } + + if values[goenv.GOMOD] == "" { + return parseGoVersion(values[goenv.GOVERSION]) + } + + file, err := parseGoMod(values[goenv.GOMOD]) + if err != nil { + return parseGoVersion(values[goenv.GOVERSION]) + } + + if file.Module != nil { + log.Infof("Module name %q", file.Module.Mod.Path) + } + + // The toolchain exists only if 'toolchain' version > 'go' version. + // If 'toolchain' version <= 'go' version, `go mod tidy` will remove 'toolchain' version from go.mod. + if file.Toolchain != nil && file.Toolchain.Name != "" { + return parseGoVersion(file.Toolchain.Name) + } + + if file.Go != nil && file.Go.Version != "" { + return file.Go.Version + } + + return parseGoVersion(values[goenv.GOVERSION]) +} + +func parseGoVersion(v string) string { + raw := strings.TrimPrefix(v, "go") + + // prerelease version (ex: go1.24rc1) + idx := strings.IndexFunc(raw, func(r rune) bool { + return (r < '0' || r > '9') && r != '.' + }) + + if idx != -1 { + raw = raw[:idx] + } + + return raw +} + +func parseGoMod(goMod string) (*modfile.File, error) { + raw, err := os.ReadFile(filepath.Clean(goMod)) + if err != nil { + return nil, fmt.Errorf("reading go.mod file: %w", err) + } + + return modfile.Parse("go.mod", raw, nil) +} + +func detectGoModFallback(ctx context.Context) string { + info, err := gomod.GetModuleInfo(ctx) + if err != nil { + return "" + } + + wd, err := os.Getwd() + if err != nil { + return "" + } + + slices.SortFunc(info, func(a, b gomod.ModInfo) int { + return cmp.Compare(len(b.Path), len(a.Path)) + }) + + goMod := info[0] + for _, m := range info { + if !strings.HasPrefix(wd, m.Dir) { + continue + } + + goMod = m + + break + } + + return goMod.GoMod +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/config/formatters.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/formatters.go new file mode 100644 index 000000000..e1723ac10 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/formatters.go @@ -0,0 +1,28 @@ +package config + +import ( + "fmt" + "slices" +) + +type Formatters struct { + Enable []string `mapstructure:"enable"` + Settings FormatterSettings `mapstructure:"settings"` + Exclusions FormatterExclusions `mapstructure:"exclusions"` +} + +func (f *Formatters) Validate() error { + for _, n := range f.Enable { + if !slices.Contains(getAllFormatterNames(), n) { + return fmt.Errorf("%s is not a formatter", n) + } + } + + return nil +} + +type FormatterExclusions struct { + Generated string `mapstructure:"generated"` + Paths []string `mapstructure:"paths"` + WarnUnused bool `mapstructure:"warn-unused"` +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/config/formatters_settings.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/formatters_settings.go new file mode 100644 index 000000000..d99354ba3 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/formatters_settings.go @@ -0,0 +1,61 @@ +package config + +var defaultFormatterSettings = FormatterSettings{ + GoFmt: GoFmtSettings{ + Simplify: true, + }, + Gci: GciSettings{ + Sections: []string{"standard", "default"}, + }, + GoLines: GoLinesSettings{ + MaxLen: 100, + TabLen: 4, + ReformatTags: true, + ChainSplitDots: true, + }, +} + +type FormatterSettings struct { + Gci GciSettings `mapstructure:"gci"` + GoFmt GoFmtSettings `mapstructure:"gofmt"` + GoFumpt GoFumptSettings `mapstructure:"gofumpt"` + GoImports GoImportsSettings `mapstructure:"goimports"` + GoLines GoLinesSettings `mapstructure:"golines"` +} + +type GciSettings struct { + Sections []string `mapstructure:"sections"` + NoInlineComments bool `mapstructure:"no-inline-comments"` + NoPrefixComments bool `mapstructure:"no-prefix-comments"` + CustomOrder bool `mapstructure:"custom-order"` + NoLexOrder bool `mapstructure:"no-lex-order"` +} + +type GoFmtSettings struct { + Simplify bool `mapstructure:"simplify"` + RewriteRules []GoFmtRewriteRule `mapstructure:"rewrite-rules"` +} + +type GoFmtRewriteRule struct { + Pattern string `mapstructure:"pattern"` + Replacement string `mapstructure:"replacement"` +} + +type GoFumptSettings struct { + ModulePath string `mapstructure:"module-path"` + ExtraRules bool `mapstructure:"extra-rules"` + + LangVersion string `mapstructure:"-"` +} + +type GoImportsSettings struct { + LocalPrefixes []string `mapstructure:"local-prefixes"` +} + +type GoLinesSettings struct { + MaxLen int `mapstructure:"max-len"` + TabLen int `mapstructure:"tab-len"` + ShortenComments bool `mapstructure:"shorten-comments"` + ReformatTags bool `mapstructure:"reformat-tags"` + ChainSplitDots bool `mapstructure:"chain-split-dots"` +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/config/issues.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/issues.go new file mode 100644 index 000000000..5dc630b00 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/issues.go @@ -0,0 +1,15 @@ +package config + +type Issues struct { + MaxIssuesPerLinter int `mapstructure:"max-issues-per-linter"` + MaxSameIssues int `mapstructure:"max-same-issues"` + UniqByLine bool `mapstructure:"uniq-by-line"` + + DiffFromRevision string `mapstructure:"new-from-rev"` + DiffFromMergeBase string `mapstructure:"new-from-merge-base"` + DiffPatchFilePath string `mapstructure:"new-from-patch"` + WholeFiles bool `mapstructure:"whole-files"` + Diff bool `mapstructure:"new"` + + NeedFix bool `mapstructure:"fix"` +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/config/linters.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/linters.go new file mode 100644 index 000000000..2669f2e64 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/linters.go @@ -0,0 +1,53 @@ +package config + +import ( + "fmt" + "slices" +) + +const ( + GroupStandard = "standard" + GroupAll = "all" + GroupNone = "none" + GroupFast = "fast" +) + +type Linters struct { + Default string `mapstructure:"default"` + Enable []string `mapstructure:"enable"` + Disable []string `mapstructure:"disable"` + FastOnly bool `mapstructure:"fast-only"` // Flag only option. + + Settings LintersSettings `mapstructure:"settings"` + + Exclusions LinterExclusions `mapstructure:"exclusions"` +} + +func (l *Linters) Validate() error { + validators := []func() error{ + l.Exclusions.Validate, + l.validateNoFormatters, + } + + for _, v := range validators { + if err := v(); err != nil { + return err + } + } + + return nil +} + +func (l *Linters) validateNoFormatters() error { + for _, n := range slices.Concat(l.Enable, l.Disable) { + if slices.Contains(getAllFormatterNames(), n) { + return fmt.Errorf("%s is a formatter", n) + } + } + + return nil +} + +func getAllFormatterNames() []string { + return []string{"gci", "gofmt", "gofumpt", "goimports", "golines", "swaggo"} +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/config/linters_exclusions.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/linters_exclusions.go new file mode 100644 index 000000000..57d08b483 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/linters_exclusions.go @@ -0,0 +1,61 @@ +package config + +import ( + "fmt" + "slices" +) + +const ( + GeneratedModeLax = "lax" + GeneratedModeStrict = "strict" + GeneratedModeDisable = "disable" +) + +const ( + ExclusionPresetComments = "comments" + ExclusionPresetStdErrorHandling = "std-error-handling" + ExclusionPresetCommonFalsePositives = "common-false-positives" + ExclusionPresetLegacy = "legacy" +) + +const excludeRuleMinConditionsCount = 2 + +type LinterExclusions struct { + Generated string `mapstructure:"generated"` + WarnUnused bool `mapstructure:"warn-unused"` + Presets []string `mapstructure:"presets"` + Rules []ExcludeRule `mapstructure:"rules"` + Paths []string `mapstructure:"paths"` + PathsExcept []string `mapstructure:"paths-except"` +} + +func (e *LinterExclusions) Validate() error { + for i, rule := range e.Rules { + if err := rule.Validate(); err != nil { + return fmt.Errorf("error in exclude rule #%d: %w", i, err) + } + } + + allPresets := []string{ + ExclusionPresetComments, + ExclusionPresetStdErrorHandling, + ExclusionPresetCommonFalsePositives, + ExclusionPresetLegacy, + } + + for _, preset := range e.Presets { + if !slices.Contains(allPresets, preset) { + return fmt.Errorf("invalid preset: %s", preset) + } + } + + return nil +} + +type ExcludeRule struct { + BaseRule `mapstructure:",squash"` +} + +func (e *ExcludeRule) Validate() error { + return e.BaseRule.Validate(excludeRuleMinConditionsCount) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/config/linters_settings.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/linters_settings.go similarity index 50% rename from vendor/github.com/golangci/golangci-lint/pkg/config/linters_settings.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/config/linters_settings.go index b182d1e0f..3f7193bd3 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/config/linters_settings.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/linters_settings.go @@ -1,15 +1,14 @@ package config import ( - "encoding" "errors" "fmt" "runtime" - - "gopkg.in/yaml.v3" ) var defaultLintersSettings = LintersSettings{ + FormatterSettings: defaultFormatterSettings, + Asasalint: AsasalintSettings{ UseBuiltinExclusions: true, }, @@ -25,6 +24,9 @@ var defaultLintersSettings = LintersSettings{ Dupl: DuplSettings{ Threshold: 150, }, + EmbeddedStructFieldCheck: EmbeddedStructFieldCheckSettings{ + EmptyLine: true, + }, ErrorLint: ErrorLintSettings{ Errorf: true, ErrorfMulti: true, @@ -33,7 +35,6 @@ var defaultLintersSettings = LintersSettings{ }, Exhaustive: ExhaustiveSettings{ Check: []string{"switch"}, - CheckGenerated: false, DefaultSignifiesExhaustive: false, IgnoreEnumMembers: "", PackageScopeOnly: false, @@ -43,9 +44,12 @@ var defaultLintersSettings = LintersSettings{ Forbidigo: ForbidigoSettings{ ExcludeGodocExamples: true, }, - Gci: GciSettings{ - Sections: []string{"standard", "default"}, - SkipGenerated: true, + FuncOrder: FuncOrderSettings{ + Constructor: true, + StructMethod: true, + }, + Funlen: FunlenSettings{ + IgnoreComments: true, }, GoChecksumType: GoChecksumTypeSettings{ DefaultSignifiesExhaustive: true, @@ -74,21 +78,12 @@ var defaultLintersSettings = LintersSettings{ Scope: "declarations", Period: true, }, - Gofmt: GoFmtSettings{ - Simplify: true, - }, - Gofumpt: GofumptSettings{ - LangVersion: "", - ModulePath: "", - ExtraRules: false, - }, Gosec: GoSecSettings{ Concurrency: runtime.NumCPU(), }, Gosmopolitan: GosmopolitanSettings{ AllowTimeLocal: false, EscapeHatches: []string{}, - IgnoreTests: true, WatchForScripts: []string{"Han"}, }, Inamedparam: INamedParamSettings{ @@ -105,6 +100,7 @@ var defaultLintersSettings = LintersSettings{ Kitlog: true, Klog: true, Logr: true, + Slog: true, Zap: true, RequireStringKey: false, NoPrintfLike: false, @@ -125,11 +121,17 @@ var defaultLintersSettings = LintersSettings{ AllowUnused: false, }, PerfSprint: PerfSprintSettings{ + IntegerFormat: true, IntConversion: true, + ErrorFormat: true, ErrError: false, ErrorF: true, + StringFormat: true, SprintF1: true, StrConcat: true, + BoolFormat: true, + HexFormat: true, + ConcatLoop: true, }, Prealloc: PreallocSettings{ Simple: true, @@ -137,7 +139,6 @@ var defaultLintersSettings = LintersSettings{ ForLoops: false, }, Predeclared: PredeclaredSettings{ - Ignore: "", Qualified: false, }, SlogLint: SlogLintSettings{ @@ -162,13 +163,30 @@ var defaultLintersSettings = LintersSettings{ SkipRegexp: `(export|internal)_test\.go`, AllowPackages: []string{"main"}, }, - Unparam: UnparamSettings{ - Algo: "cha", + Unqueryvet: UnqueryvetSettings{ + CheckSQLBuilders: true, + CheckAliasedWildcard: true, + CheckStringConcat: true, + CheckFormatStrings: true, + CheckStringBuilder: true, + CheckSubqueries: true, + SQLBuilders: UnqueryvetSQLBuildersSettings{ + Squirrel: true, + GORM: true, + SQLx: true, + Ent: true, + PGX: true, + Bun: true, + SQLBoiler: true, + Jet: true, + }, + CheckN1: false, + CheckSQLInjection: false, + CheckTxLeak: false, }, Unused: UnusedSettings{ FieldWritesAreUses: true, PostStatementsAreReads: false, - ExportedIsUsed: true, ExportedFieldsAreUsed: true, ParametersAreUsed: true, LocalVariablesAreUsed: true, @@ -178,11 +196,20 @@ var defaultLintersSettings = LintersSettings{ HTTPMethod: true, HTTPStatusCode: true, }, + UseTesting: UseTestingSettings{ + ContextBackground: false, + ContextTodo: false, + OSChdir: true, + OSMkdirTemp: true, + OSSetenv: true, + OSTempDir: false, + OSCreateTemp: true, + }, Varnamelen: VarnamelenSettings{ MaxDistance: 5, MinNameLength: 3, }, - WSL: WSLSettings{ + WSL: WSLv4Settings{ StrictAppend: true, AllowAssignAndCallCuddle: true, AllowAssignAndAnythingCuddle: false, @@ -193,96 +220,112 @@ var defaultLintersSettings = LintersSettings{ AllowCuddleDeclaration: false, AllowCuddleWithCalls: []string{"Lock", "RLock"}, AllowCuddleWithRHS: []string{"Unlock", "RUnlock"}, + AllowCuddleUsedInBlock: false, ForceCuddleErrCheckAndAssign: false, ErrorVariableNames: []string{"err"}, ForceExclusiveShortDeclarations: false, }, + WSLv5: WSLv5Settings{ + AllowFirstInBlock: true, + AllowWholeBlock: false, + BranchMaxLines: 2, + CaseMaxLines: 0, + Default: "default", + Enable: nil, + Disable: nil, + }, } type LintersSettings struct { - Asasalint AsasalintSettings - BiDiChk BiDiChkSettings - CopyLoopVar CopyLoopVarSettings - Cyclop Cyclop - Decorder DecorderSettings - Depguard DepGuardSettings - Dogsled DogsledSettings - Dupl DuplSettings - DupWord DupWordSettings - Errcheck ErrcheckSettings - ErrChkJSON ErrChkJSONSettings - ErrorLint ErrorLintSettings - Exhaustive ExhaustiveSettings - Exhaustruct ExhaustructSettings - Forbidigo ForbidigoSettings - Funlen FunlenSettings - Gci GciSettings - GinkgoLinter GinkgoLinterSettings - Gocognit GocognitSettings - GoChecksumType GoChecksumTypeSettings - Goconst GoConstSettings - Gocritic GoCriticSettings - Gocyclo GoCycloSettings - Godot GodotSettings - Godox GodoxSettings - Gofmt GoFmtSettings - Gofumpt GofumptSettings - Goheader GoHeaderSettings - Goimports GoImportsSettings - GoModDirectives GoModDirectivesSettings - Gomodguard GoModGuardSettings - Gosec GoSecSettings - Gosimple StaticCheckSettings - Gosmopolitan GosmopolitanSettings - Govet GovetSettings - Grouper GrouperSettings - Iface IfaceSettings - ImportAs ImportAsSettings - Inamedparam INamedParamSettings - InterfaceBloat InterfaceBloatSettings - Ireturn IreturnSettings - Lll LllSettings - LoggerCheck LoggerCheckSettings - MaintIdx MaintIdxSettings - Makezero MakezeroSettings - Misspell MisspellSettings - Mnd MndSettings - MustTag MustTagSettings - Nakedret NakedretSettings - Nestif NestifSettings - NilNil NilNilSettings - Nlreturn NlreturnSettings - NoLintLint NoLintLintSettings - NoNamedReturns NoNamedReturnsSettings - ParallelTest ParallelTestSettings - PerfSprint PerfSprintSettings - Prealloc PreallocSettings - Predeclared PredeclaredSettings - Promlinter PromlinterSettings - ProtoGetter ProtoGetterSettings - Reassign ReassignSettings - Revive ReviveSettings - RowsErrCheck RowsErrCheckSettings - SlogLint SlogLintSettings - Spancheck SpancheckSettings - Staticcheck StaticCheckSettings - Stylecheck StaticCheckSettings - TagAlign TagAlignSettings - Tagliatelle TagliatelleSettings - Tenv TenvSettings - Testifylint TestifylintSettings - Testpackage TestpackageSettings - Thelper ThelperSettings - Unconvert UnconvertSettings - Unparam UnparamSettings - Unused UnusedSettings - UseStdlibVars UseStdlibVarsSettings - Varnamelen VarnamelenSettings - Whitespace WhitespaceSettings - Wrapcheck WrapcheckSettings - WSL WSLSettings - - Custom map[string]CustomLinterSettings + FormatterSettings `mapstructure:"-"` + + Asasalint AsasalintSettings `mapstructure:"asasalint"` + BiDiChk BiDiChkSettings `mapstructure:"bidichk"` + CopyLoopVar CopyLoopVarSettings `mapstructure:"copyloopvar"` + Cyclop CyclopSettings `mapstructure:"cyclop"` + Decorder DecorderSettings `mapstructure:"decorder"` + Depguard DepGuardSettings `mapstructure:"depguard"` + Dogsled DogsledSettings `mapstructure:"dogsled"` + Dupl DuplSettings `mapstructure:"dupl"` + DupWord DupWordSettings `mapstructure:"dupword"` + EmbeddedStructFieldCheck EmbeddedStructFieldCheckSettings `mapstructure:"embeddedstructfieldcheck"` + Errcheck ErrcheckSettings `mapstructure:"errcheck"` + ErrChkJSON ErrChkJSONSettings `mapstructure:"errchkjson"` + ErrorLint ErrorLintSettings `mapstructure:"errorlint"` + Exhaustive ExhaustiveSettings `mapstructure:"exhaustive"` + Exhaustruct ExhaustructSettings `mapstructure:"exhaustruct"` + Fatcontext FatcontextSettings `mapstructure:"fatcontext"` + Forbidigo ForbidigoSettings `mapstructure:"forbidigo"` + FuncOrder FuncOrderSettings `mapstructure:"funcorder"` + Funlen FunlenSettings `mapstructure:"funlen"` + GinkgoLinter GinkgoLinterSettings `mapstructure:"ginkgolinter"` + Gocognit GocognitSettings `mapstructure:"gocognit"` + GoChecksumType GoChecksumTypeSettings `mapstructure:"gochecksumtype"` + Goconst GoConstSettings `mapstructure:"goconst"` + Gocritic GoCriticSettings `mapstructure:"gocritic"` + Gocyclo GoCycloSettings `mapstructure:"gocyclo"` + Godoclint GodoclintSettings `mapstructure:"godoclint"` + Godot GodotSettings `mapstructure:"godot"` + Godox GodoxSettings `mapstructure:"godox"` + Goheader GoHeaderSettings `mapstructure:"goheader"` + GoModDirectives GoModDirectivesSettings `mapstructure:"gomoddirectives"` + Gomodguard GoModGuardSettings `mapstructure:"gomodguard"` + Gosec GoSecSettings `mapstructure:"gosec"` + Gosmopolitan GosmopolitanSettings `mapstructure:"gosmopolitan"` + Unqueryvet UnqueryvetSettings `mapstructure:"unqueryvet"` + Govet GovetSettings `mapstructure:"govet"` + Grouper GrouperSettings `mapstructure:"grouper"` + Iface IfaceSettings `mapstructure:"iface"` + ImportAs ImportAsSettings `mapstructure:"importas"` + Inamedparam INamedParamSettings `mapstructure:"inamedparam"` + Ineffassign IneffassignSettings `mapstructure:"ineffassign"` + InterfaceBloat InterfaceBloatSettings `mapstructure:"interfacebloat"` + IotaMixing IotaMixingSettings `mapstructure:"iotamixing"` + Ireturn IreturnSettings `mapstructure:"ireturn"` + Lll LllSettings `mapstructure:"lll"` + LoggerCheck LoggerCheckSettings `mapstructure:"loggercheck"` + MaintIdx MaintIdxSettings `mapstructure:"maintidx"` + Makezero MakezeroSettings `mapstructure:"makezero"` + Misspell MisspellSettings `mapstructure:"misspell"` + Mnd MndSettings `mapstructure:"mnd"` + Modernize ModernizeSettings `mapstructure:"modernize"` + MustTag MustTagSettings `mapstructure:"musttag"` + Nakedret NakedretSettings `mapstructure:"nakedret"` + Nestif NestifSettings `mapstructure:"nestif"` + NilNil NilNilSettings `mapstructure:"nilnil"` + Nlreturn NlreturnSettings `mapstructure:"nlreturn"` + NoLintLint NoLintLintSettings `mapstructure:"nolintlint"` + NoNamedReturns NoNamedReturnsSettings `mapstructure:"nonamedreturns"` + ParallelTest ParallelTestSettings `mapstructure:"paralleltest"` + PerfSprint PerfSprintSettings `mapstructure:"perfsprint"` + Prealloc PreallocSettings `mapstructure:"prealloc"` + Predeclared PredeclaredSettings `mapstructure:"predeclared"` + Promlinter PromlinterSettings `mapstructure:"promlinter"` + ProtoGetter ProtoGetterSettings `mapstructure:"protogetter"` + Reassign ReassignSettings `mapstructure:"reassign"` + Recvcheck RecvcheckSettings `mapstructure:"recvcheck"` + Revive ReviveSettings `mapstructure:"revive"` + RowsErrCheck RowsErrCheckSettings `mapstructure:"rowserrcheck"` + SlogLint SlogLintSettings `mapstructure:"sloglint"` + Spancheck SpancheckSettings `mapstructure:"spancheck"` + Staticcheck StaticCheckSettings `mapstructure:"staticcheck"` + TagAlign TagAlignSettings `mapstructure:"tagalign"` + Tagliatelle TagliatelleSettings `mapstructure:"tagliatelle"` + Testifylint TestifylintSettings `mapstructure:"testifylint"` + Testpackage TestpackageSettings `mapstructure:"testpackage"` + Thelper ThelperSettings `mapstructure:"thelper"` + Unconvert UnconvertSettings `mapstructure:"unconvert"` + Unparam UnparamSettings `mapstructure:"unparam"` + Unused UnusedSettings `mapstructure:"unused"` + UseStdlibVars UseStdlibVarsSettings `mapstructure:"usestdlibvars"` + UseTesting UseTestingSettings `mapstructure:"usetesting"` + Varnamelen VarnamelenSettings `mapstructure:"varnamelen"` + Whitespace WhitespaceSettings `mapstructure:"whitespace"` + Wrapcheck WrapcheckSettings `mapstructure:"wrapcheck"` + WSL WSLv4Settings `mapstructure:"wsl"` // Deprecated: use WSLv5 instead. + WSLv5 WSLv5Settings `mapstructure:"wsl_v5"` + + Custom map[string]CustomLinterSettings `mapstructure:"custom"` } func (s *LintersSettings) Validate() error { @@ -302,7 +345,6 @@ func (s *LintersSettings) Validate() error { type AsasalintSettings struct { Exclude []string `mapstructure:"exclude"` UseBuiltinExclusions bool `mapstructure:"use-builtin-exclusions"` - IgnoreTest bool `mapstructure:"ignore-test"` } type BiDiChkSettings struct { @@ -318,14 +360,12 @@ type BiDiChkSettings struct { } type CopyLoopVarSettings struct { - IgnoreAlias bool `mapstructure:"ignore-alias"` // Deprecated: use CheckAlias - CheckAlias bool `mapstructure:"check-alias"` + CheckAlias bool `mapstructure:"check-alias"` } -type Cyclop struct { +type CyclopSettings struct { MaxComplexity int `mapstructure:"max-complexity"` PackageAverage float64 `mapstructure:"package-average"` - SkipTests bool `mapstructure:"skip-tests"` } type DepGuardSettings struct { @@ -360,12 +400,18 @@ type DogsledSettings struct { } type DuplSettings struct { - Threshold int + Threshold int `mapstructure:"threshold"` } type DupWordSettings struct { - Keywords []string `mapstructure:"keywords"` - Ignore []string `mapstructure:"ignore"` + Keywords []string `mapstructure:"keywords"` + Ignore []string `mapstructure:"ignore"` + CommentsOnly bool `mapstructure:"comments-only"` +} + +type EmbeddedStructFieldCheckSettings struct { + ForbidMutex bool `mapstructure:"forbid-mutex"` + EmptyLine bool `mapstructure:"empty-line"` } type ErrcheckSettings struct { @@ -373,12 +419,7 @@ type ErrcheckSettings struct { CheckTypeAssertions bool `mapstructure:"check-type-assertions"` CheckAssignToBlank bool `mapstructure:"check-blank"` ExcludeFunctions []string `mapstructure:"exclude-functions"` - - // Deprecated: use ExcludeFunctions instead - Exclude string `mapstructure:"exclude"` - - // Deprecated: use ExcludeFunctions instead - Ignore string `mapstructure:"ignore"` + Verbose bool `mapstructure:"verbose"` } type ErrChkJSONSettings struct { @@ -402,7 +443,6 @@ type ErrorLintAllowPair struct { type ExhaustiveSettings struct { Check []string `mapstructure:"check"` - CheckGenerated bool `mapstructure:"check-generated"` DefaultSignifiesExhaustive bool `mapstructure:"default-signifies-exhaustive"` IgnoreEnumMembers string `mapstructure:"ignore-enum-members"` IgnoreEnumTypes string `mapstructure:"ignore-enum-types"` @@ -413,8 +453,16 @@ type ExhaustiveSettings struct { } type ExhaustructSettings struct { - Include []string `mapstructure:"include"` - Exclude []string `mapstructure:"exclude"` + Include []string `mapstructure:"include"` + Exclude []string `mapstructure:"exclude"` + AllowEmpty bool `mapstructure:"allow-empty"` + AllowEmptyRx []string `mapstructure:"allow-empty-rx"` + AllowEmptyReturns bool `mapstructure:"allow-empty-returns"` + AllowEmptyDeclarations bool `mapstructure:"allow-empty-declarations"` +} + +type FatcontextSettings struct { + CheckStructPointers bool `mapstructure:"check-struct-pointers"` } type ForbidigoSettings struct { @@ -423,58 +471,24 @@ type ForbidigoSettings struct { AnalyzeTypes bool `mapstructure:"analyze-types"` } -var _ encoding.TextUnmarshaler = &ForbidigoPattern{} - -// ForbidigoPattern corresponds to forbidigo.pattern and adds mapstructure support. -// The YAML field names must match what forbidigo expects. type ForbidigoPattern struct { - // patternString gets populated when the config contains a string as entry in ForbidigoSettings.Forbid[] - // because ForbidigoPattern implements encoding.TextUnmarshaler - // and the reader uses the mapstructure.TextUnmarshallerHookFunc as decoder hook. - // - // If the entry is a map, then the other fields are set as usual by mapstructure. - patternString string - - Pattern string `yaml:"p" mapstructure:"p"` + Pattern string `yaml:"p" mapstructure:"pattern"` Package string `yaml:"pkg,omitempty" mapstructure:"pkg,omitempty"` Msg string `yaml:"msg,omitempty" mapstructure:"msg,omitempty"` } -func (p *ForbidigoPattern) UnmarshalText(text []byte) error { - // Validation happens when instantiating forbidigo. - p.patternString = string(text) - return nil -} - -// MarshalString converts the pattern into a string as needed by forbidigo.NewLinter. -// -// MarshalString is intentionally not called MarshalText, -// although it has the same signature -// because implementing encoding.TextMarshaler led to infinite recursion when yaml.Marshal called MarshalText. -func (p *ForbidigoPattern) MarshalString() ([]byte, error) { - if p.patternString != "" { - return []byte(p.patternString), nil - } - - return yaml.Marshal(p) +type FuncOrderSettings struct { + Constructor bool `mapstructure:"constructor,omitempty"` + StructMethod bool `mapstructure:"struct-method,omitempty"` + Alphabetical bool `mapstructure:"alphabetical,omitempty"` } type FunlenSettings struct { - Lines int - Statements int + Lines int `mapstructure:"lines"` + Statements int `mapstructure:"statements"` IgnoreComments bool `mapstructure:"ignore-comments"` } -type GciSettings struct { - Sections []string `mapstructure:"sections"` - SkipGenerated bool `mapstructure:"skip-generated"` - CustomOrder bool `mapstructure:"custom-order"` - NoLexOrder bool `mapstructure:"no-lex-order"` - - // Deprecated: use Sections instead. - LocalPrefixes string `mapstructure:"local-prefixes"` -} - type GinkgoLinterSettings struct { SuppressLenAssertion bool `mapstructure:"suppress-len-assertion"` SuppressNilAssertion bool `mapstructure:"suppress-nil-assertion"` @@ -488,10 +502,13 @@ type GinkgoLinterSettings struct { ValidateAsyncIntervals bool `mapstructure:"validate-async-intervals"` ForbidSpecPollution bool `mapstructure:"forbid-spec-pollution"` ForceSucceedForFuncs bool `mapstructure:"force-succeed"` + ForceAssertionDescription bool `mapstructure:"force-assertion-description"` + ForeToNot bool `mapstructure:"force-tonot"` } type GoChecksumTypeSettings struct { DefaultSignifiesExhaustive bool `mapstructure:"default-signifies-exhaustive"` + IncludeSharedInterfaces bool `mapstructure:"include-shared-interfaces"` } type GocognitSettings struct { @@ -499,15 +516,19 @@ type GocognitSettings struct { } type GoConstSettings struct { - IgnoreStrings string `mapstructure:"ignore-strings"` - IgnoreTests bool `mapstructure:"ignore-tests"` - MatchWithConstants bool `mapstructure:"match-constant"` - MinStringLen int `mapstructure:"min-len"` - MinOccurrencesCount int `mapstructure:"min-occurrences"` - ParseNumbers bool `mapstructure:"numbers"` - NumberMin int `mapstructure:"min"` - NumberMax int `mapstructure:"max"` - IgnoreCalls bool `mapstructure:"ignore-calls"` + IgnoreStringValues []string `mapstructure:"ignore-string-values"` + MatchWithConstants bool `mapstructure:"match-constant"` + MinStringLen int `mapstructure:"min-len"` + MinOccurrencesCount int `mapstructure:"min-occurrences"` + ParseNumbers bool `mapstructure:"numbers"` + NumberMin int `mapstructure:"min"` + NumberMax int `mapstructure:"max"` + IgnoreCalls bool `mapstructure:"ignore-calls"` + FindDuplicates bool `mapstructure:"find-duplicates"` + EvalConstExpressions bool `mapstructure:"eval-const-expressions"` + + // Deprecated: use IgnoreStringValues instead. + IgnoreStrings string `mapstructure:"ignore-strings"` } type GoCriticSettings struct { @@ -527,36 +548,33 @@ type GoCycloSettings struct { MinComplexity int `mapstructure:"min-complexity"` } +type GodoclintSettings struct { + Default *string `mapstructure:"default"` + Enable []string `mapstructure:"enable"` + Disable []string `mapstructure:"disable"` + Options struct { + MaxLen struct { + Length *uint `mapstructure:"length"` + } `mapstructure:"max-len"` + RequireDoc struct { + IgnoreExported *bool `mapstructure:"ignore-exported"` + IgnoreUnexported *bool `mapstructure:"ignore-unexported"` + } `mapstructure:"require-doc"` + StartWithName struct { + IncludeUnexported *bool `mapstructure:"include-unexported"` + } `mapstructure:"start-with-name"` + } `mapstructure:"options"` +} + type GodotSettings struct { Scope string `mapstructure:"scope"` Exclude []string `mapstructure:"exclude"` Capital bool `mapstructure:"capital"` Period bool `mapstructure:"period"` - - // Deprecated: use Scope instead - CheckAll bool `mapstructure:"check-all"` } type GodoxSettings struct { - Keywords []string -} - -type GoFmtSettings struct { - Simplify bool - RewriteRules []GoFmtRewriteRule `mapstructure:"rewrite-rules"` -} - -type GoFmtRewriteRule struct { - Pattern string - Replacement string -} - -type GofumptSettings struct { - ModulePath string `mapstructure:"module-path"` - ExtraRules bool `mapstructure:"extra-rules"` - - // Deprecated: use the global `run.go` instead. - LangVersion string `mapstructure:"lang-version"` + Keywords []string `mapstructure:"keywords"` } type GoHeaderSettings struct { @@ -565,64 +583,69 @@ type GoHeaderSettings struct { TemplatePath string `mapstructure:"template-path"` } -type GoImportsSettings struct { - LocalPrefixes string `mapstructure:"local-prefixes"` -} - type GoModDirectivesSettings struct { ReplaceAllowList []string `mapstructure:"replace-allow-list"` ReplaceLocal bool `mapstructure:"replace-local"` ExcludeForbidden bool `mapstructure:"exclude-forbidden"` RetractAllowNoExplanation bool `mapstructure:"retract-allow-no-explanation"` + ToolchainForbidden bool `mapstructure:"toolchain-forbidden"` + ToolchainPattern string `mapstructure:"toolchain-pattern"` + ToolForbidden bool `mapstructure:"tool-forbidden"` + GoDebugForbidden bool `mapstructure:"go-debug-forbidden"` + GoVersionPattern string `mapstructure:"go-version-pattern"` + CheckModulePath bool `mapstructure:"check-module-path"` } type GoModGuardSettings struct { - Allowed struct { - Modules []string `mapstructure:"modules"` - Domains []string `mapstructure:"domains"` - } `mapstructure:"allowed"` - Blocked struct { - Modules []map[string]struct { - Recommendations []string `mapstructure:"recommendations"` - Reason string `mapstructure:"reason"` - } `mapstructure:"modules"` - Versions []map[string]struct { - Version string `mapstructure:"version"` - Reason string `mapstructure:"reason"` - } `mapstructure:"versions"` - LocalReplaceDirectives bool `mapstructure:"local_replace_directives"` - } `mapstructure:"blocked"` + Allowed GoModGuardAllowed `mapstructure:"allowed"` + Blocked GoModGuardBlocked `mapstructure:"blocked"` +} + +type GoModGuardAllowed struct { + Modules []string `mapstructure:"modules"` + Domains []string `mapstructure:"domains"` +} + +type GoModGuardBlocked struct { + Modules []map[string]GoModGuardModule `mapstructure:"modules"` + Versions []map[string]GoModGuardVersion `mapstructure:"versions"` + LocalReplaceDirectives bool `mapstructure:"local-replace-directives"` +} + +type GoModGuardModule struct { + Recommendations []string `mapstructure:"recommendations"` + Reason string `mapstructure:"reason"` +} + +type GoModGuardVersion struct { + Version string `mapstructure:"version"` + Reason string `mapstructure:"reason"` } type GoSecSettings struct { - Includes []string `mapstructure:"includes"` - Excludes []string `mapstructure:"excludes"` - Severity string `mapstructure:"severity"` - Confidence string `mapstructure:"confidence"` - ExcludeGenerated bool `mapstructure:"exclude-generated"` - Config map[string]any `mapstructure:"config"` - Concurrency int `mapstructure:"concurrency"` + Includes []string `mapstructure:"includes"` + Excludes []string `mapstructure:"excludes"` + Severity string `mapstructure:"severity"` + Confidence string `mapstructure:"confidence"` + Config map[string]any `mapstructure:"config"` + Concurrency int `mapstructure:"concurrency"` } type GosmopolitanSettings struct { AllowTimeLocal bool `mapstructure:"allow-time-local"` EscapeHatches []string `mapstructure:"escape-hatches"` - IgnoreTests bool `mapstructure:"ignore-tests"` WatchForScripts []string `mapstructure:"watch-for-scripts"` } type GovetSettings struct { Go string `mapstructure:"-"` - Enable []string - Disable []string - EnableAll bool `mapstructure:"enable-all"` - DisableAll bool `mapstructure:"disable-all"` - - Settings map[string]map[string]any + Enable []string `mapstructure:"enable"` + Disable []string `mapstructure:"disable"` + EnableAll bool `mapstructure:"enable-all"` + DisableAll bool `mapstructure:"disable-all"` - // Deprecated: the linter should be enabled inside Enable. - CheckShadowing bool `mapstructure:"check-shadowing"` + Settings map[string]map[string]any `mapstructure:"settings"` } func (cfg *GovetSettings) Validate() error { @@ -655,24 +678,32 @@ type IfaceSettings struct { } type ImportAsSettings struct { - Alias []ImportAsAlias - NoUnaliased bool `mapstructure:"no-unaliased"` - NoExtraAliases bool `mapstructure:"no-extra-aliases"` + Alias []ImportAsAlias `mapstructure:"alias"` + NoUnaliased bool `mapstructure:"no-unaliased"` + NoExtraAliases bool `mapstructure:"no-extra-aliases"` } type ImportAsAlias struct { - Pkg string - Alias string + Pkg string `mapstructure:"pkg"` + Alias string `mapstructure:"alias"` } type INamedParamSettings struct { SkipSingleParam bool `mapstructure:"skip-single-param"` } +type IneffassignSettings struct { + CheckEscapingErrors bool `mapstructure:"check-escaping-errors"` +} + type InterfaceBloatSettings struct { Max int `mapstructure:"max"` } +type IotaMixingSettings struct { + ReportIndividual bool `mapstructure:"report-individual"` +} + type IreturnSettings struct { Allow []string `mapstructure:"allow"` Reject []string `mapstructure:"reject"` @@ -687,6 +718,7 @@ type LoggerCheckSettings struct { Kitlog bool `mapstructure:"kitlog"` Klog bool `mapstructure:"klog"` Logr bool `mapstructure:"logr"` + Slog bool `mapstructure:"slog"` Zap bool `mapstructure:"zap"` RequireStringKey bool `mapstructure:"require-string-key"` NoPrintfLike bool `mapstructure:"no-printf-like"` @@ -698,15 +730,14 @@ type MaintIdxSettings struct { } type MakezeroSettings struct { - Always bool + Always bool `mapstructure:"always"` } type MisspellSettings struct { - Mode string `mapstructure:"mode"` - Locale string `mapstructure:"locale"` - ExtraWords []MisspellExtraWords `mapstructure:"extra-words"` - // TODO(ldez): v2 the option must be renamed to `IgnoredRules`. - IgnoreWords []string `mapstructure:"ignore-words"` + Mode string `mapstructure:"mode"` + Locale string `mapstructure:"locale"` + ExtraWords []MisspellExtraWords `mapstructure:"extra-words"` + IgnoreRules []string `mapstructure:"ignore-rules"` } type MisspellExtraWords struct { @@ -715,11 +746,13 @@ type MisspellExtraWords struct { } type MustTagSettings struct { - Functions []struct { - Name string `mapstructure:"name"` - Tag string `mapstructure:"tag"` - ArgPos int `mapstructure:"arg-pos"` - } `mapstructure:"functions"` + Functions []MustTagFunction `mapstructure:"functions"` +} + +type MustTagFunction struct { + Name string `mapstructure:"name"` + Tag string `mapstructure:"tag"` + ArgPos int `mapstructure:"arg-pos"` } type NakedretSettings struct { @@ -731,6 +764,7 @@ type NestifSettings struct { } type NilNilSettings struct { + OnlyTwo *bool `mapstructure:"only-two"` DetectOpposite bool `mapstructure:"detect-opposite"` CheckedTypes []string `mapstructure:"checked-types"` } @@ -746,6 +780,10 @@ type MndSettings struct { IgnoredFunctions []string `mapstructure:"ignored-functions"` } +type ModernizeSettings struct { + Disable []string `mapstructure:"disable"` +} + type NoLintLintSettings struct { RequireExplanation bool `mapstructure:"require-explanation"` RequireSpecific bool `mapstructure:"require-specific"` @@ -764,22 +802,33 @@ type ParallelTestSettings struct { } type PerfSprintSettings struct { + IntegerFormat bool `mapstructure:"integer-format"` IntConversion bool `mapstructure:"int-conversion"` - ErrError bool `mapstructure:"err-error"` - ErrorF bool `mapstructure:"errorf"` - SprintF1 bool `mapstructure:"sprintf1"` - StrConcat bool `mapstructure:"strconcat"` + + ErrorFormat bool `mapstructure:"error-format"` + ErrError bool `mapstructure:"err-error"` + ErrorF bool `mapstructure:"errorf"` + + StringFormat bool `mapstructure:"string-format"` + SprintF1 bool `mapstructure:"sprintf1"` + StrConcat bool `mapstructure:"strconcat"` + + BoolFormat bool `mapstructure:"bool-format"` + HexFormat bool `mapstructure:"hex-format"` + + ConcatLoop bool `mapstructure:"concat-loop"` + LoopOtherOps bool `mapstructure:"loop-other-ops"` } type PreallocSettings struct { - Simple bool + Simple bool `mapstructure:"simple"` RangeLoops bool `mapstructure:"range-loops"` ForLoops bool `mapstructure:"for-loops"` } type PredeclaredSettings struct { - Ignore string `mapstructure:"ignore"` - Qualified bool `mapstructure:"q"` + Ignore []string `mapstructure:"ignore"` + Qualified bool `mapstructure:"qualified-name"` } type PromlinterSettings struct { @@ -798,30 +847,39 @@ type ReassignSettings struct { Patterns []string `mapstructure:"patterns"` } +type RecvcheckSettings struct { + DisableBuiltin bool `mapstructure:"disable-builtin"` + Exclusions []string `mapstructure:"exclusions"` +} + type ReviveSettings struct { - Go string `mapstructure:"-"` - MaxOpenFiles int `mapstructure:"max-open-files"` - IgnoreGeneratedHeader bool `mapstructure:"ignore-generated-header"` - Confidence float64 - Severity string - EnableAllRules bool `mapstructure:"enable-all-rules"` - Rules []struct { - Name string - Arguments []any - Severity string - Disabled bool - Exclude []string - } - ErrorCode int `mapstructure:"error-code"` - WarningCode int `mapstructure:"warning-code"` - Directives []struct { - Name string - Severity string - } + Go string `mapstructure:"-"` + MaxOpenFiles int `mapstructure:"max-open-files"` + Confidence float64 `mapstructure:"confidence"` + Severity string `mapstructure:"severity"` + EnableAllRules bool `mapstructure:"enable-all-rules"` + EnableDefaultRules bool `mapstructure:"enable-default-rules"` + Rules []ReviveRule `mapstructure:"rules"` + ErrorCode int `mapstructure:"error-code"` + WarningCode int `mapstructure:"warning-code"` + Directives []ReviveDirective `mapstructure:"directives"` +} + +type ReviveRule struct { + Name string `mapstructure:"name"` + Arguments []any `mapstructure:"arguments"` + Severity string `mapstructure:"severity"` + Disabled bool `mapstructure:"disabled"` + Exclude []string `mapstructure:"exclude"` +} + +type ReviveDirective struct { + Name string `mapstructure:"name"` + Severity string `mapstructure:"severity"` } type RowsErrCheckSettings struct { - Packages []string + Packages []string `mapstructure:"packages"` } type SlogLintSettings struct { @@ -831,13 +889,11 @@ type SlogLintSettings struct { NoGlobal string `mapstructure:"no-global"` Context string `mapstructure:"context"` StaticMsg bool `mapstructure:"static-msg"` + MsgStyle string `mapstructure:"msg-style"` NoRawKeys bool `mapstructure:"no-raw-keys"` KeyNamingCase string `mapstructure:"key-naming-case"` ForbiddenKeys []string `mapstructure:"forbidden-keys"` ArgsOnSepLines bool `mapstructure:"args-on-sep-lines"` - - // Deprecated: use Context instead. - ContextOnly bool `mapstructure:"context-only"` } type SpancheckSettings struct { @@ -851,13 +907,10 @@ type StaticCheckSettings struct { Initialisms []string `mapstructure:"initialisms"` // only for stylecheck DotImportWhitelist []string `mapstructure:"dot-import-whitelist"` // only for stylecheck HTTPStatusCodeWhitelist []string `mapstructure:"http-status-code-whitelist"` // only for stylecheck - - // Deprecated: use the global `run.go` instead. - GoVersion string `mapstructure:"go"` } func (s *StaticCheckSettings) HasConfiguration() bool { - return len(s.Initialisms) > 0 || len(s.HTTPStatusCodeWhitelist) > 0 || len(s.DotImportWhitelist) > 0 || len(s.Checks) > 0 + return s.Initialisms == nil || s.HTTPStatusCodeWhitelist == nil || s.DotImportWhitelist == nil || s.Checks == nil } type TagAlignSettings struct { @@ -868,10 +921,31 @@ type TagAlignSettings struct { } type TagliatelleSettings struct { - Case struct { - Rules map[string]string - UseFieldName bool `mapstructure:"use-field-name"` - } + Case TagliatelleCase `mapstructure:"case"` +} + +type TagliatelleCase struct { + TagliatelleBase `mapstructure:",squash"` + Overrides []TagliatelleOverrides `mapstructure:"overrides"` +} + +type TagliatelleOverrides struct { + TagliatelleBase `mapstructure:",squash"` + Package string `mapstructure:"pkg"` + Ignore bool `mapstructure:"ignore"` +} + +type TagliatelleBase struct { + Rules map[string]string `mapstructure:"rules"` + ExtendedRules map[string]TagliatelleExtendedRule `mapstructure:"extended-rules"` + UseFieldName bool `mapstructure:"use-field-name"` + IgnoredFields []string `mapstructure:"ignored-fields"` +} + +type TagliatelleExtendedRule struct { + Case string `mapstructure:"case"` + ExtraInitialisms bool `mapstructure:"extra-initialisms"` + InitialismOverrides map[string]bool `mapstructure:"initialism-overrides"` } type TestifylintSettings struct { @@ -880,30 +954,38 @@ type TestifylintSettings struct { EnabledCheckers []string `mapstructure:"enable"` DisabledCheckers []string `mapstructure:"disable"` - BoolCompare struct { - IgnoreCustomTypes bool `mapstructure:"ignore-custom-types"` - } `mapstructure:"bool-compare"` + BoolCompare TestifylintBoolCompare `mapstructure:"bool-compare"` + ExpectedActual TestifylintExpectedActual `mapstructure:"expected-actual"` + Formatter TestifylintFormatter `mapstructure:"formatter"` + GoRequire TestifylintGoRequire `mapstructure:"go-require"` + RequireError TestifylintRequireError `mapstructure:"require-error"` + SuiteExtraAssertCall TestifylintSuiteExtraAssertCall `mapstructure:"suite-extra-assert-call"` +} + +type TestifylintBoolCompare struct { + IgnoreCustomTypes bool `mapstructure:"ignore-custom-types"` +} - ExpectedActual struct { - ExpVarPattern string `mapstructure:"pattern"` - } `mapstructure:"expected-actual"` +type TestifylintExpectedActual struct { + ExpVarPattern string `mapstructure:"pattern"` +} - Formatter struct { - CheckFormatString *bool `mapstructure:"check-format-string"` - RequireFFuncs bool `mapstructure:"require-f-funcs"` - } `mapstructure:"formatter"` +type TestifylintFormatter struct { + CheckFormatString *bool `mapstructure:"check-format-string"` + RequireFFuncs bool `mapstructure:"require-f-funcs"` + RequireStringMsg bool `mapstructure:"require-string-msg"` +} - GoRequire struct { - IgnoreHTTPHandlers bool `mapstructure:"ignore-http-handlers"` - } `mapstructure:"go-require"` +type TestifylintGoRequire struct { + IgnoreHTTPHandlers bool `mapstructure:"ignore-http-handlers"` +} - RequireError struct { - FnPattern string `mapstructure:"fn-pattern"` - } `mapstructure:"require-error"` +type TestifylintRequireError struct { + FnPattern string `mapstructure:"fn-pattern"` +} - SuiteExtraAssertCall struct { - Mode string `mapstructure:"mode"` - } `mapstructure:"suite-extra-assert-call"` +type TestifylintSuiteExtraAssertCall struct { + Mode string `mapstructure:"mode"` } type TestpackageSettings struct { @@ -924,10 +1006,6 @@ type ThelperOptions struct { Begin *bool `mapstructure:"begin"` } -type TenvSettings struct { - All bool `mapstructure:"all"` -} - type UseStdlibVarsSettings struct { HTTPMethod bool `mapstructure:"http-method"` HTTPStatusCode bool `mapstructure:"http-status-code"` @@ -936,11 +1014,20 @@ type UseStdlibVarsSettings struct { TimeLayout bool `mapstructure:"time-layout"` CryptoHash bool `mapstructure:"crypto-hash"` DefaultRPCPath bool `mapstructure:"default-rpc-path"` - OSDevNull bool `mapstructure:"os-dev-null"` // Deprecated SQLIsolationLevel bool `mapstructure:"sql-isolation-level"` TLSSignatureScheme bool `mapstructure:"tls-signature-scheme"` ConstantKind bool `mapstructure:"constant-kind"` - SyslogPriority bool `mapstructure:"syslog-priority"` // Deprecated + TimeDateMonth bool `mapstructure:"time-date-month"` +} + +type UseTestingSettings struct { + ContextBackground bool `mapstructure:"context-background"` + ContextTodo bool `mapstructure:"context-todo"` + OSChdir bool `mapstructure:"os-chdir"` + OSMkdirTemp bool `mapstructure:"os-mkdir-temp"` + OSSetenv bool `mapstructure:"os-setenv"` + OSTempDir bool `mapstructure:"os-temp-dir"` + OSCreateTemp bool `mapstructure:"os-create-temp"` } type UnconvertSettings struct { @@ -950,13 +1037,48 @@ type UnconvertSettings struct { type UnparamSettings struct { CheckExported bool `mapstructure:"check-exported"` - Algo string +} + +type UnqueryvetSettings struct { + CheckSQLBuilders bool `mapstructure:"check-sql-builders"` + AllowedPatterns []string `mapstructure:"allowed-patterns"` + IgnoredFunctions []string `mapstructure:"ignored-functions"` + CheckAliasedWildcard bool `mapstructure:"check-aliased-wildcard"` + CheckStringConcat bool `mapstructure:"check-string-concat"` + CheckFormatStrings bool `mapstructure:"check-format-strings"` + CheckStringBuilder bool `mapstructure:"check-string-builder"` + CheckSubqueries bool `mapstructure:"check-subqueries"` + CheckN1 bool `mapstructure:"check-n1"` + CheckSQLInjection bool `mapstructure:"check-sql-injection"` + CheckTxLeak bool `mapstructure:"check-tx-leaks"` + SQLBuilders UnqueryvetSQLBuildersSettings `mapstructure:"sql-builders"` + Allow []string `mapstructure:"allow"` + CustomRules []UnqueryvetCustomRule `mapstructure:"custom-rules"` +} + +type UnqueryvetSQLBuildersSettings struct { + Squirrel bool `mapstructure:"squirrel"` + GORM bool `mapstructure:"gorm"` + SQLx bool `mapstructure:"sqlx"` + Ent bool `mapstructure:"ent"` + PGX bool `mapstructure:"pgx"` + Bun bool `mapstructure:"bun"` + SQLBoiler bool `mapstructure:"sqlboiler"` + Jet bool `mapstructure:"jet"` +} + +type UnqueryvetCustomRule struct { + ID string `mapstructure:"id"` + Pattern string `mapstructure:"pattern"` + Patterns []string `mapstructure:"patterns"` + When string `mapstructure:"when"` + Message string `mapstructure:"message"` + Action string `mapstructure:"action"` } type UnusedSettings struct { FieldWritesAreUses bool `mapstructure:"field-writes-are-uses"` PostStatementsAreReads bool `mapstructure:"post-statements-are-reads"` - ExportedIsUsed bool `mapstructure:"exported-is-used"` // Deprecated ExportedFieldsAreUsed bool `mapstructure:"exported-fields-are-used"` ParametersAreUsed bool `mapstructure:"parameters-are-used"` LocalVariablesAreUsed bool `mapstructure:"local-variables-are-used"` @@ -982,14 +1104,16 @@ type WhitespaceSettings struct { } type WrapcheckSettings struct { - // TODO(ldez): v2 the options must be renamed to use hyphen. - IgnoreSigs []string `mapstructure:"ignoreSigs"` - IgnoreSigRegexps []string `mapstructure:"ignoreSigRegexps"` - IgnorePackageGlobs []string `mapstructure:"ignorePackageGlobs"` - IgnoreInterfaceRegexps []string `mapstructure:"ignoreInterfaceRegexps"` + ExtraIgnoreSigs []string `mapstructure:"extra-ignore-sigs"` + IgnoreSigs []string `mapstructure:"ignore-sigs"` + IgnoreSigRegexps []string `mapstructure:"ignore-sig-regexps"` + IgnorePackageGlobs []string `mapstructure:"ignore-package-globs"` + IgnoreInterfaceRegexps []string `mapstructure:"ignore-interface-regexps"` + ReportInternalErrors bool `mapstructure:"report-internal-errors"` } -type WSLSettings struct { +// Deprecated: use WSLv5Settings instead. +type WSLv4Settings struct { StrictAppend bool `mapstructure:"strict-append"` AllowAssignAndCallCuddle bool `mapstructure:"allow-assign-and-call"` AllowAssignAndAnythingCuddle bool `mapstructure:"allow-assign-and-anything"` @@ -1000,11 +1124,22 @@ type WSLSettings struct { AllowCuddleDeclaration bool `mapstructure:"allow-cuddle-declarations"` AllowCuddleWithCalls []string `mapstructure:"allow-cuddle-with-calls"` AllowCuddleWithRHS []string `mapstructure:"allow-cuddle-with-rhs"` + AllowCuddleUsedInBlock bool `mapstructure:"allow-cuddle-used-in-block"` ForceCuddleErrCheckAndAssign bool `mapstructure:"force-err-cuddling"` ErrorVariableNames []string `mapstructure:"error-variable-names"` ForceExclusiveShortDeclarations bool `mapstructure:"force-short-decl-cuddling"` } +type WSLv5Settings struct { + AllowFirstInBlock bool `mapstructure:"allow-first-in-block"` + AllowWholeBlock bool `mapstructure:"allow-whole-block"` + BranchMaxLines int `mapstructure:"branch-max-lines"` + CaseMaxLines int `mapstructure:"case-max-lines"` + Default string `mapstructure:"default"` + Enable []string `mapstructure:"enable"` + Disable []string `mapstructure:"disable"` +} + // CustomLinterSettings encapsulates the meta-data of a private linter. type CustomLinterSettings struct { // Type plugin type. @@ -1013,15 +1148,15 @@ type CustomLinterSettings struct { // Path to a plugin *.so file that implements the private linter. // Only for Go plugin system. - Path string + Path string `mapstructure:"path"` // Description describes the purpose of the private linter. - Description string + Description string `mapstructure:"description"` // OriginalURL The URL containing the source code for the private linter. OriginalURL string `mapstructure:"original-url"` // Settings plugin settings only work with linterdb.PluginConstructor symbol. - Settings any + Settings any `mapstructure:"settings"` } func (s *CustomLinterSettings) Validate() error { diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/config/loader.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/loader.go new file mode 100644 index 000000000..511c3ab7d --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/loader.go @@ -0,0 +1,275 @@ +package config + +import ( + "context" + "errors" + "fmt" + "os" + "slices" + + "github.com/spf13/pflag" + "github.com/spf13/viper" + + "github.com/golangci/golangci-lint/v2/pkg/fsutils" + "github.com/golangci/golangci-lint/v2/pkg/goutil" + "github.com/golangci/golangci-lint/v2/pkg/logutils" +) + +var errConfigDisabled = errors.New("config is disabled by --no-config") + +const ( + modeLinters = "linters" + modeFormatters = "formatters" +) + +type LoaderOptions struct { + Config string // Flag only. The path to the golangci config file, as specified with the --config argument. + NoConfig bool // Flag only. +} + +type LoadOptions struct { + CheckDeprecation bool + Validation bool +} + +type Loader struct { + *BaseLoader + + fs *pflag.FlagSet + + cfg *Config + + mode string +} + +func NewLintersLoader(log logutils.Log, v *viper.Viper, fs *pflag.FlagSet, opts LoaderOptions, cfg *Config, args []string) *Loader { + loader := newLoader(log, v, fs, opts, cfg, args) + loader.mode = modeLinters + + return loader +} + +func NewFormattersLoader(log logutils.Log, v *viper.Viper, fs *pflag.FlagSet, opts LoaderOptions, cfg *Config, args []string) *Loader { + loader := newLoader(log, v, fs, opts, cfg, args) + loader.mode = modeFormatters + + return loader +} + +func newLoader(log logutils.Log, v *viper.Viper, fs *pflag.FlagSet, opts LoaderOptions, cfg *Config, args []string) *Loader { + return &Loader{ + BaseLoader: NewBaseLoader(log, v, opts, cfg, args), + fs: fs, + cfg: cfg, + } +} + +func (l *Loader) Load(opts LoadOptions) error { + err := l.BaseLoader.Load() + if err != nil { + return err + } + + if l.mode == modeLinters { + l.applyStringSliceHack() + } + + if l.cfg.Linters.Exclusions.Generated == "" { + l.cfg.Linters.Exclusions.Generated = GeneratedModeStrict + } + + err = l.checkConfigurationVersion() + if err != nil { + return err + } + + if !l.cfg.InternalCmdTest { + for _, n := range slices.Concat(l.cfg.Linters.Enable, l.cfg.Linters.Disable) { + if n == "typecheck" { + return fmt.Errorf("%s is not a linter, it cannot be enabled or disabled", n) + } + } + } + + l.handleFormatters() + + if opts.CheckDeprecation { + err = l.handleDeprecation() + if err != nil { + return err + } + + l.handleFormatterDeprecations() + } + + l.handleGoVersion() + + err = goutil.CheckGoVersion(l.cfg.Run.Go) + if err != nil { + return err + } + + l.cfg.basePath, err = fsutils.GetBasePath(context.Background(), l.cfg.Run.RelativePathMode, l.cfg.cfgDir) + if err != nil { + return fmt.Errorf("get base path: %w", err) + } + + err = l.handleEnableOnlyOption() + if err != nil { + return err + } + + if opts.Validation { + err = l.cfg.Validate() + if err != nil { + return err + } + } + + return nil +} + +// Hack to append values from StringSlice flags. +// Viper always overrides StringSlice values. +// https://github.com/spf13/viper/issues/1448 +// So StringSlice flags are not bind to Viper like that their values are obtain via Cobra Flags. +func (l *Loader) applyStringSliceHack() { + if l.fs == nil { + return + } + + l.appendStringSlice("enable", &l.cfg.Linters.Enable) + l.appendStringSlice("disable", &l.cfg.Linters.Disable) + l.appendStringSlice("build-tags", &l.cfg.Run.BuildTags) +} + +func (l *Loader) appendStringSlice(name string, current *[]string) { + if l.fs.Changed(name) { + val, _ := l.fs.GetStringSlice(name) + *current = append(*current, val...) + } +} + +func (l *Loader) checkConfigurationVersion() error { + if l.cfg.GetConfigDir() != "" && l.cfg.Version != "2" { + return fmt.Errorf("unsupported version of the configuration: %q "+ + "See https://golangci-lint.run/docs/product/migration-guide for migration instructions", l.cfg.Version) + } + + return nil +} + +func (l *Loader) handleGoVersion() { + if l.cfg.Run.Go == "" { + l.cfg.Run.Go = detectGoVersion(context.Background(), l.log) + } + + l.cfg.Linters.Settings.Govet.Go = l.cfg.Run.Go + + l.cfg.Linters.Settings.ParallelTest.Go = l.cfg.Run.Go + + l.cfg.Linters.Settings.GoFumpt.LangVersion = l.cfg.Run.Go + l.cfg.Formatters.Settings.GoFumpt.LangVersion = l.cfg.Run.Go + + trimmedGoVersion := goutil.TrimGoVersion(l.cfg.Run.Go) + + l.cfg.Linters.Settings.Revive.Go = trimmedGoVersion + + l.cfg.Linters.Settings.Gocritic.Go = trimmedGoVersion + + os.Setenv("GOSECGOVERSION", l.cfg.Run.Go) +} + +func (l *Loader) handleDeprecation() error { + if l.cfg.InternalTest || l.cfg.InternalCmdTest || os.Getenv(logutils.EnvTestRun) == "1" { + return nil + } + + l.handleLinterOptionDeprecations() + + return nil +} + +func (l *Loader) handleLinterOptionDeprecations() { + // Deprecated since v2.1.0. + if l.cfg.Linters.Settings.Goconst.IgnoreStrings != "" { + l.log.Warnf("The configuration option `linters.settings.goconst.ignore-strings` is deprecated, " + + "please use `linters.settings.goconst.ignore-string-values`.") + + l.cfg.Linters.Settings.Goconst.IgnoreStringValues = append(l.cfg.Linters.Settings.Goconst.IgnoreStringValues, + l.cfg.Linters.Settings.Goconst.IgnoreStrings) + } +} + +func (l *Loader) handleEnableOnlyOption() error { + lookup := l.fs.Lookup("enable-only") + if lookup == nil { + return nil + } + + only, err := l.fs.GetStringSlice("enable-only") + if err != nil { + return err + } + + if len(only) > 0 { + l.cfg.Linters = Linters{ + Default: GroupNone, + Enable: only, + Settings: l.cfg.Linters.Settings, + Exclusions: l.cfg.Linters.Exclusions, + } + + l.cfg.Formatters = Formatters{} + } + + return nil +} + +func (l *Loader) handleFormatters() { + l.handleFormatterOverrides() + l.handleFormatterExclusions() +} + +// Overrides linter settings with formatter settings if the formatter is enabled. +func (l *Loader) handleFormatterOverrides() { + if slices.Contains(l.cfg.Formatters.Enable, "gofmt") { + l.cfg.Linters.Settings.GoFmt = l.cfg.Formatters.Settings.GoFmt + } + + if slices.Contains(l.cfg.Formatters.Enable, "gofumpt") { + l.cfg.Linters.Settings.GoFumpt = l.cfg.Formatters.Settings.GoFumpt + } + + if slices.Contains(l.cfg.Formatters.Enable, "goimports") { + l.cfg.Linters.Settings.GoImports = l.cfg.Formatters.Settings.GoImports + } + + if slices.Contains(l.cfg.Formatters.Enable, "gci") { + l.cfg.Linters.Settings.Gci = l.cfg.Formatters.Settings.Gci + } + + if slices.Contains(l.cfg.Formatters.Enable, "golines") { + l.cfg.Linters.Settings.GoLines = l.cfg.Formatters.Settings.GoLines + } +} + +// Add formatter exclusions to linters exclusions. +func (l *Loader) handleFormatterExclusions() { + if len(l.cfg.Formatters.Enable) == 0 { + return + } + + for _, path := range l.cfg.Formatters.Exclusions.Paths { + l.cfg.Linters.Exclusions.Rules = append(l.cfg.Linters.Exclusions.Rules, ExcludeRule{ + BaseRule: BaseRule{ + Linters: l.cfg.Formatters.Enable, + Path: path, + }, + }) + } +} + +func (*Loader) handleFormatterDeprecations() { + // The function is empty but deprecations will happen in the future. +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/config/output.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/output.go new file mode 100644 index 000000000..803dc3ac2 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/output.go @@ -0,0 +1,62 @@ +package config + +import ( + "fmt" + "slices" + "strings" + + "github.com/golangci/golangci-lint/v2/pkg/fsutils" +) + +type Output struct { + Formats Formats `mapstructure:"formats"` + SortOrder []string `mapstructure:"sort-order"` + ShowStats bool `mapstructure:"show-stats"` + PathPrefix string `mapstructure:"path-prefix"` + PathMode string `mapstructure:"path-mode"` +} + +func (o *Output) Validate() error { + validators := []func() error{ + o.validateSortOrder, + o.validatePathMode, + } + + for _, v := range validators { + if err := v(); err != nil { + return err + } + } + + return nil +} + +func (o *Output) validateSortOrder() error { + validOrders := []string{"linter", "file", "severity"} + + all := strings.Join(o.SortOrder, " ") + + for _, order := range o.SortOrder { + if strings.Count(all, order) > 1 { + return fmt.Errorf("the sort-order name %q is repeated several times", order) + } + + if !slices.Contains(validOrders, order) { + return fmt.Errorf("unsupported sort-order name %q", order) + } + } + + return nil +} + +func (o *Output) validatePathMode() error { + switch o.PathMode { + case "", fsutils.OutputPathModeAbsolute: + // Valid + + default: + return fmt.Errorf("unsupported output path mode %q", o.PathMode) + } + + return nil +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/config/output_formats.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/output_formats.go new file mode 100644 index 000000000..1c655c1b0 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/output_formats.go @@ -0,0 +1,57 @@ +package config + +type Formats struct { + Text Text `mapstructure:"text"` + JSON SimpleFormat `mapstructure:"json"` + Tab Tab `mapstructure:"tab"` + HTML SimpleFormat `mapstructure:"html"` + Checkstyle SimpleFormat `mapstructure:"checkstyle"` + CodeClimate SimpleFormat `mapstructure:"code-climate"` + JUnitXML JUnitXML `mapstructure:"junit-xml"` + TeamCity SimpleFormat `mapstructure:"teamcity"` + Sarif SimpleFormat `mapstructure:"sarif"` +} + +func (f *Formats) IsEmpty() bool { + formats := []SimpleFormat{ + f.Text.SimpleFormat, + f.JSON, + f.Tab.SimpleFormat, + f.HTML, + f.Checkstyle, + f.CodeClimate, + f.JUnitXML.SimpleFormat, + f.TeamCity, + f.Sarif, + } + + for _, format := range formats { + if format.Path != "" { + return false + } + } + + return true +} + +type SimpleFormat struct { + Path string `mapstructure:"path"` +} + +type Text struct { + SimpleFormat `mapstructure:",squash"` + PrintLinterName bool `mapstructure:"print-linter-name"` + PrintIssuedLine bool `mapstructure:"print-issued-lines"` + Colors bool `mapstructure:"colors"` +} + +type Tab struct { + SimpleFormat `mapstructure:",squash"` + PrintLinterName bool `mapstructure:"print-linter-name"` + Colors bool `mapstructure:"colors"` +} + +type JUnitXML struct { + SimpleFormat `mapstructure:",squash"` + Extended bool `mapstructure:"extended"` +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/config/placeholders.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/placeholders.go new file mode 100644 index 000000000..b3f35f7b3 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/placeholders.go @@ -0,0 +1,18 @@ +package config + +import "strings" + +const ( + // placeholderBasePath used inside linters to evaluate relative paths. + placeholderBasePath = "${base-path}" + + // placeholderConfigPath used inside linters to paths relative to configuration. + placeholderConfigPath = "${config-path}" +) + +func NewPlaceholderReplacer(cfg *Config) *strings.Replacer { + return strings.NewReplacer( + placeholderBasePath, cfg.GetBasePath(), + placeholderConfigPath, cfg.GetConfigDir(), + ) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/config/run.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/run.go similarity index 54% rename from vendor/github.com/golangci/golangci-lint/pkg/config/run.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/config/run.go index 2f6523c0b..358557c06 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/config/run.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/run.go @@ -5,6 +5,8 @@ import ( "slices" "strings" "time" + + "github.com/golangci/golangci-lint/v2/pkg/fsutils" ) // Run encapsulates the config options for running the linter analysis. @@ -15,32 +17,31 @@ type Run struct { Go string `mapstructure:"go"` + RelativePathMode string `mapstructure:"relative-path-mode"` + BuildTags []string `mapstructure:"build-tags"` ModulesDownloadMode string `mapstructure:"modules-download-mode"` + EnableBuildVCS bool `mapstructure:"enable-build-vcs"` ExitCodeIfIssuesFound int `mapstructure:"issues-exit-code"` AnalyzeTests bool `mapstructure:"tests"` AllowParallelRunners bool `mapstructure:"allow-parallel-runners"` AllowSerialRunners bool `mapstructure:"allow-serial-runners"` - - // Deprecated: use Issues.ExcludeFiles instead. - SkipFiles []string `mapstructure:"skip-files"` - // Deprecated: use Issues.ExcludeDirs instead. - SkipDirs []string `mapstructure:"skip-dirs"` - // Deprecated: use Issues.UseDefaultExcludeDirs instead. - UseDefaultSkipDirs bool `mapstructure:"skip-dirs-use-default"` - - // Deprecated: use Output.ShowStats instead. - ShowStats bool `mapstructure:"show-stats"` } func (r *Run) Validate() error { // go help modules - allowedMods := []string{"mod", "readonly", "vendor"} + allowedModes := []string{"mod", "readonly", "vendor"} + + if r.ModulesDownloadMode != "" && !slices.Contains(allowedModes, r.ModulesDownloadMode) { + return fmt.Errorf("invalid modules download path %s, only (%s) allowed", r.ModulesDownloadMode, strings.Join(allowedModes, "|")) + } + + pathRelativeToModes := fsutils.AllRelativePathModes() - if r.ModulesDownloadMode != "" && !slices.Contains(allowedMods, r.ModulesDownloadMode) { - return fmt.Errorf("invalid modules download path %s, only (%s) allowed", r.ModulesDownloadMode, strings.Join(allowedMods, "|")) + if r.RelativePathMode != "" && !slices.Contains(pathRelativeToModes, r.RelativePathMode) { + return fmt.Errorf("invalid relative path mode %s, only (%s) allowed", r.RelativePathMode, strings.Join(pathRelativeToModes, "|")) } return nil diff --git a/vendor/github.com/golangci/golangci-lint/pkg/config/severity.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/severity.go similarity index 77% rename from vendor/github.com/golangci/golangci-lint/pkg/config/severity.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/config/severity.go index a6d2c9ec3..f41e17b11 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/config/severity.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/config/severity.go @@ -8,9 +8,8 @@ import ( const severityRuleMinConditionsCount = 1 type Severity struct { - Default string `mapstructure:"default-severity"` - CaseSensitive bool `mapstructure:"case-sensitive"` - Rules []SeverityRule `mapstructure:"rules"` + Default string `mapstructure:"default"` + Rules []SeverityRule `mapstructure:"rules"` } func (s *Severity) Validate() error { @@ -29,7 +28,7 @@ func (s *Severity) Validate() error { type SeverityRule struct { BaseRule `mapstructure:",squash"` - Severity string + Severity string `mapstructure:"severity"` } func (s *SeverityRule) Validate() error { diff --git a/vendor/github.com/golangci/golangci-lint/pkg/exitcodes/exitcodes.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/exitcodes/exitcodes.go similarity index 100% rename from vendor/github.com/golangci/golangci-lint/pkg/exitcodes/exitcodes.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/exitcodes/exitcodes.go diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/fsutils/basepath.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/fsutils/basepath.go new file mode 100644 index 000000000..3761fa0ea --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/fsutils/basepath.go @@ -0,0 +1,77 @@ +package fsutils + +import ( + "bytes" + "cmp" + "context" + "fmt" + "os/exec" + "path/filepath" + + "github.com/ldez/grignotin/goenv" +) + +// Relative path modes. +const ( + RelativePathModeGoMod = "gomod" + RelativePathModeGitRoot = "gitroot" + RelativePathModeCfg = "cfg" + RelativePathModeWd = "wd" +) + +// OutputPathModeAbsolute path mode used to show absolute paths in output reports (user-facing). +const OutputPathModeAbsolute = "abs" + +func AllRelativePathModes() []string { + return []string{RelativePathModeGoMod, RelativePathModeGitRoot, RelativePathModeCfg, RelativePathModeWd} +} + +func GetBasePath(ctx context.Context, mode, cfgDir string) (string, error) { + mode = cmp.Or(mode, RelativePathModeCfg) + + switch mode { + case RelativePathModeCfg: + if cfgDir == "" { + return GetBasePath(ctx, RelativePathModeWd, cfgDir) + } + + return cfgDir, nil + + case RelativePathModeGoMod: + goMod, err := goenv.GetOne(ctx, goenv.GOMOD) + if err != nil { + return "", fmt.Errorf("get go.mod path: %w", err) + } + + return filepath.Dir(goMod), nil + + case RelativePathModeGitRoot: + root, err := gitRoot(ctx) + if err != nil { + return "", fmt.Errorf("get git root: %w", err) + } + + return root, nil + + case RelativePathModeWd: + wd, err := Getwd() + if err != nil { + return "", fmt.Errorf("get wd: %w", err) + } + + return wd, nil + + default: + return "", fmt.Errorf("unknown relative path mode: %s", mode) + } +} + +func gitRoot(ctx context.Context) (string, error) { + cmd := exec.CommandContext(ctx, "git", "rev-parse", "--show-toplevel") + out, err := cmd.Output() + if err != nil { + return "", err + } + + return string(bytes.TrimSpace(out)), nil +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/fsutils/filecache.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/fsutils/filecache.go similarity index 95% rename from vendor/github.com/golangci/golangci-lint/pkg/fsutils/filecache.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/fsutils/filecache.go index e8e5ba19b..e91b58748 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/fsutils/filecache.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/fsutils/filecache.go @@ -5,7 +5,7 @@ import ( "os" "sync" - "github.com/golangci/golangci-lint/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/logutils" ) type FileCache struct { diff --git a/vendor/github.com/golangci/golangci-lint/pkg/fsutils/fsutils.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/fsutils/fsutils.go similarity index 83% rename from vendor/github.com/golangci/golangci-lint/pkg/fsutils/fsutils.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/fsutils/fsutils.go index 80bb9c5b4..ead18a537 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/fsutils/fsutils.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/fsutils/fsutils.go @@ -34,13 +34,13 @@ func Getwd() (string, error) { return } - evaledWd, err := EvalSymlinks(cachedWd) + evaluatedWd, err := EvalSymlinks(cachedWd) if err != nil { cachedWd, cachedWdError = "", fmt.Errorf("can't eval symlinks on wd %s: %w", cachedWd, err) return } - cachedWd = evaledWd + cachedWd = evaluatedWd }) return cachedWd, cachedWdError @@ -61,7 +61,7 @@ func EvalSymlinks(path string) (string, error) { } var er evalSymlinkRes - er.path, er.err = filepath.EvalSymlinks(path) + er.path, er.err = evalSymlinks(path) evalSymlinkCache.Store(path, er) return er.path, er.err @@ -76,15 +76,15 @@ func ShortestRelPath(path, wd string) (string, error) { } } - evaledPath, err := EvalSymlinks(path) + evaluatedPath, err := EvalSymlinks(path) if err != nil { return "", fmt.Errorf("can't eval symlinks for path %s: %w", path, err) } - path = evaledPath + path = evaluatedPath // make path absolute and then relative to be able to fix this case: - // we are in /test dir, we want to normalize ../test, and have file file.go in this dir; - // it must have normalized path file.go, not ../test/file.go, + // we are in `/test` dir, we want to normalize `../test`, and have file `file.go` in this dir; + // it must have normalized path `file.go`, not `../test/file.go`, var absPath string if filepath.IsAbs(path) { absPath = path diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/fsutils/fsutils_unix.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/fsutils/fsutils_unix.go new file mode 100644 index 000000000..68e762cf4 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/fsutils/fsutils_unix.go @@ -0,0 +1,9 @@ +//go:build !windows + +package fsutils + +import "path/filepath" + +func evalSymlinks(path string) (string, error) { + return filepath.EvalSymlinks(path) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/fsutils/fsutils_windows.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/fsutils/fsutils_windows.go new file mode 100644 index 000000000..19efb1cfc --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/fsutils/fsutils_windows.go @@ -0,0 +1,39 @@ +//go:build windows + +package fsutils + +import ( + "errors" + "os" + "path/filepath" + "syscall" +) + +// This is a workaround for the behavior of [filepath.EvalSymlinks], +// which fails with [syscall.ENOTDIR] if the specified path contains a junction on Windows. +// Junctions can occur, for example, when a volume is mounted as a subdirectory inside another drive. +// This can usually happen when using the Dev Drives feature and replacing existing directories. +// See: https://github.com/golang/go/issues/40180 +// +// Since [syscall.ENOTDIR] is only returned when calling [filepath.EvalSymlinks] on Windows +// if part of the presented path is a junction and nothing before was a symlink, +// we simply treat this as NOT symlink, +// because a symlink over the junction makes no sense at all. +func evalSymlinks(path string) (string, error) { + resolved, err := filepath.EvalSymlinks(path) + if err == nil { + return resolved, nil + } + + if !errors.Is(err, syscall.ENOTDIR) { + return "", err + } + + _, err = os.Stat(path) + if err != nil { + return "", err + } + + // If exists, we make the path absolute, to be sure... + return filepath.Abs(path) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/fsutils/linecache.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/fsutils/linecache.go similarity index 100% rename from vendor/github.com/golangci/golangci-lint/pkg/fsutils/linecache.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/fsutils/linecache.go diff --git a/vendor/github.com/golangci/golangci-lint/pkg/fsutils/path_unix.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/fsutils/path_unix.go similarity index 100% rename from vendor/github.com/golangci/golangci-lint/pkg/fsutils/path_unix.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/fsutils/path_unix.go diff --git a/vendor/github.com/golangci/golangci-lint/pkg/fsutils/path_windows.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/fsutils/path_windows.go similarity index 100% rename from vendor/github.com/golangci/golangci-lint/pkg/fsutils/path_windows.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/fsutils/path_windows.go diff --git a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/issue.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/issue.go similarity index 65% rename from vendor/github.com/golangci/golangci-lint/pkg/goanalysis/issue.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/issue.go index 15d8dd2b3..88a59e53d 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/issue.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/issue.go @@ -5,17 +5,17 @@ import ( "golang.org/x/tools/go/analysis" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/result" ) type Issue struct { - result.Issue + *result.Issue Pass *analysis.Pass } -func NewIssue(issue *result.Issue, pass *analysis.Pass) Issue { - return Issue{ - Issue: *issue, +func NewIssue(issue *result.Issue, pass *analysis.Pass) *Issue { + return &Issue{ + Issue: issue, Pass: pass, } } @@ -26,7 +26,7 @@ type EncodingIssue struct { Severity string Pos token.Position LineRange *result.Range - Replacement *result.Replacement + SuggestedFixes []analysis.SuggestedFix ExpectNoLint bool ExpectedNoLintLinter string } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/linter.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/linter.go similarity index 79% rename from vendor/github.com/golangci/golangci-lint/pkg/goanalysis/linter.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/linter.go index 13d3a09a5..153e538b5 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/linter.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/linter.go @@ -9,13 +9,8 @@ import ( "golang.org/x/tools/go/analysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" -) - -const ( - TheOnlyAnalyzerName = "the_only_name" - TheOnlyanalyzerDoc = "the_only_doc" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/result" ) type LoadMode int @@ -45,7 +40,7 @@ type Linter struct { name, desc string analyzers []*analysis.Analyzer cfg map[string]map[string]any - issuesReporter func(*linter.Context) []Issue + issuesReporter func(*linter.Context) []*Issue contextSetter func(*linter.Context) loadMode LoadMode needUseOriginalPackages bool @@ -55,7 +50,11 @@ func NewLinter(name, desc string, analyzers []*analysis.Analyzer, cfg map[string return &Linter{name: name, desc: desc, analyzers: analyzers, cfg: cfg} } -func (lnt *Linter) Run(_ context.Context, lintCtx *linter.Context) ([]result.Issue, error) { +func NewLinterFromAnalyzer(analyzer *analysis.Analyzer) *Linter { + return NewLinter(analyzer.Name, analyzer.Doc, []*analysis.Analyzer{analyzer}, nil) +} + +func (lnt *Linter) Run(_ context.Context, lintCtx *linter.Context) ([]*result.Issue, error) { if err := lnt.preRun(lintCtx); err != nil { return nil, err } @@ -71,12 +70,49 @@ func (lnt *Linter) LoadMode() LoadMode { return lnt.loadMode } +func (lnt *Linter) WithDesc(desc string) *Linter { + lnt.desc = desc + + return lnt +} + +func (lnt *Linter) WithVersion(v int) *Linter { + if v == 0 { + return lnt + } + + for _, analyzer := range lnt.analyzers { + if lnt.name != analyzer.Name { + continue + } + + // The analyzer name should be the same as the linter name to avoid displaying the name inside the reports. + analyzer.Name = fmt.Sprintf("%s_v%d", analyzer.Name, v) + } + + lnt.name = fmt.Sprintf("%s_v%d", lnt.name, v) + + return lnt +} + +func (lnt *Linter) WithConfig(cfg map[string]any) *Linter { + if len(cfg) == 0 { + return lnt + } + + lnt.cfg = map[string]map[string]any{ + lnt.name: cfg, + } + + return lnt +} + func (lnt *Linter) WithLoadMode(loadMode LoadMode) *Linter { lnt.loadMode = loadMode return lnt } -func (lnt *Linter) WithIssuesReporter(r func(*linter.Context) []Issue) *Linter { +func (lnt *Linter) WithIssuesReporter(r func(*linter.Context) []*Issue) *Linter { lnt.issuesReporter = r return lnt } @@ -176,7 +212,7 @@ func (lnt *Linter) useOriginalPackages() bool { return lnt.needUseOriginalPackages } -func (lnt *Linter) reportIssues(lintCtx *linter.Context) []Issue { +func (lnt *Linter) reportIssues(lintCtx *linter.Context) []*Issue { if lnt.issuesReporter != nil { return lnt.issuesReporter(lintCtx) } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/load/guard.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/load/guard.go similarity index 100% rename from vendor/github.com/golangci/golangci-lint/pkg/goanalysis/load/guard.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/load/guard.go diff --git a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/metalinter.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/metalinter.go similarity index 89% rename from vendor/github.com/golangci/golangci-lint/pkg/goanalysis/metalinter.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/metalinter.go index c2a794997..b9a210a66 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/metalinter.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/metalinter.go @@ -6,8 +6,8 @@ import ( "golang.org/x/tools/go/analysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/result" ) type MetaLinter struct { @@ -21,7 +21,7 @@ func NewMetaLinter(linters []*Linter) *MetaLinter { return ml } -func (ml MetaLinter) Run(_ context.Context, lintCtx *linter.Context) ([]result.Issue, error) { +func (ml MetaLinter) Run(_ context.Context, lintCtx *linter.Context) ([]*result.Issue, error) { for _, l := range ml.linters { if err := l.preRun(lintCtx); err != nil { return nil, fmt.Errorf("failed to pre-run %s: %w", l.Name(), err) @@ -65,8 +65,8 @@ func (MetaLinter) useOriginalPackages() bool { return false // `unused` can't be run by this metalinter } -func (ml MetaLinter) reportIssues(lintCtx *linter.Context) []Issue { - var ret []Issue +func (ml MetaLinter) reportIssues(lintCtx *linter.Context) []*Issue { + var ret []*Issue for _, lnt := range ml.linters { if lnt.issuesReporter != nil { ret = append(ret, lnt.issuesReporter(lintCtx)...) diff --git a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/pkgerrors/errors.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/pkgerrors/errors.go similarity index 65% rename from vendor/github.com/golangci/golangci-lint/pkg/goanalysis/pkgerrors/errors.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/pkgerrors/errors.go index 7da659e80..5d2b816ac 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/pkgerrors/errors.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/pkgerrors/errors.go @@ -6,8 +6,8 @@ import ( "golang.org/x/tools/go/packages" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/result" ) type IllTypedError struct { @@ -15,11 +15,12 @@ type IllTypedError struct { } func (e *IllTypedError) Error() string { - return fmt.Sprintf("errors in package: %v", e.Pkg.Errors) + return fmt.Sprintf("IllTypedError: errors in package: %v", e.Pkg.Errors) } -func BuildIssuesFromIllTypedError(errs []error, lintCtx *linter.Context) ([]result.Issue, error) { - var issues []result.Issue +func BuildIssuesFromIllTypedError(errs []error, lintCtx *linter.Context) ([]*result.Issue, error) { + var issues []*result.Issue + uniqReportedIssues := map[string]bool{} var other error @@ -39,11 +40,19 @@ func BuildIssuesFromIllTypedError(errs []error, lintCtx *linter.Context) ([]resu if uniqReportedIssues[err.Msg] { continue } + uniqReportedIssues[err.Msg] = true lintCtx.Log.Errorf("typechecking error: %s", err.Msg) } else { + key := fmt.Sprintf("%s.%d.%d.%s", issue.FilePath(), issue.Line(), issue.Column(), issue.Text) + if uniqReportedIssues[key] { + continue + } + + uniqReportedIssues[key] = true + issue.Pkg = ill.Pkg // to save to cache later - issues = append(issues, *issue) + issues = append(issues, issue) } } } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/pkgerrors/extract.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/pkgerrors/extract.go similarity index 78% rename from vendor/github.com/golangci/golangci-lint/pkg/goanalysis/pkgerrors/extract.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/pkgerrors/extract.go index d1257e663..76a4c9022 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/pkgerrors/extract.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/pkgerrors/extract.go @@ -2,6 +2,7 @@ package pkgerrors import ( "fmt" + "maps" "regexp" "strings" @@ -18,7 +19,9 @@ func extractErrors(pkg *packages.Package) []packages.Error { return errors } + skippedErrors := map[string]packages.Error{} seenErrors := map[string]bool{} + var uniqErrors []packages.Error for _, err := range errors { msg := stackCrusher(err.Error()) @@ -26,15 +29,35 @@ func extractErrors(pkg *packages.Package) []packages.Error { continue } + // This `if` is important to avoid duplicate errors. + // The goal is to keep the most relevant error. if msg != err.Error() { + prev, alreadySkip := skippedErrors[msg] + if !alreadySkip { + skippedErrors[msg] = err + continue + } + + if len(err.Error()) < len(prev.Error()) { + skippedErrors[msg] = err + } + continue } + delete(skippedErrors, msg) + seenErrors[msg] = true uniqErrors = append(uniqErrors, err) } + // In some cases, the error stack doesn't contain the tip error. + // We must keep at least one of the original errors that contain the specific message. + for skippedError := range maps.Values(skippedErrors) { + uniqErrors = append(uniqErrors, skippedError) + } + if len(pkg.GoFiles) != 0 { // errors were extracted from deps and have at least one file in package for i := range uniqErrors { diff --git a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/pkgerrors/parse.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/pkgerrors/parse.go similarity index 88% rename from vendor/github.com/golangci/golangci-lint/pkg/goanalysis/pkgerrors/parse.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/pkgerrors/parse.go index b25b50f71..2fe1fb529 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/pkgerrors/parse.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/pkgerrors/parse.go @@ -9,7 +9,7 @@ import ( "golang.org/x/tools/go/packages" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/result" ) func parseError(srcErr packages.Error) (*result.Issue, error) { @@ -26,7 +26,7 @@ func parseError(srcErr packages.Error) (*result.Issue, error) { } func parseErrorPosition(pos string) (*token.Position, error) { - // file:line(:colon) + // file:line(:column) parts := strings.Split(pos, ":") if len(parts) == 1 { return nil, errors.New("no colons") @@ -39,7 +39,7 @@ func parseErrorPosition(pos string) (*token.Position, error) { } var column int - if len(parts) == 3 { // no column + if len(parts) == 3 { // got column column, err = strconv.Atoi(parts[2]) if err != nil { return nil, fmt.Errorf("failed to parse column from %q: %w", parts[2], err) diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/position.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/position.go new file mode 100644 index 000000000..28441b341 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/position.go @@ -0,0 +1,50 @@ +package goanalysis + +import ( + "go/ast" + "go/token" + "path/filepath" + + "golang.org/x/tools/go/analysis" +) + +func GetGoFilePosition(pass *analysis.Pass, f *ast.File) (token.Position, bool) { + position := GetFilePositionFor(pass.Fset, f.Pos()) + + if filepath.Ext(position.Filename) == ".go" { + return position, true + } + + return position, false +} + +func GetFilePositionFor(fset *token.FileSet, p token.Pos) token.Position { + pos := fset.PositionFor(p, true) + + ext := filepath.Ext(pos.Filename) + if ext != ".go" { + // position has been adjusted to a non-go file, revert to original file + return fset.PositionFor(p, false) + } + + return pos +} + +func EndOfLinePos(f *token.File, line int) token.Pos { + var end token.Pos + + if line >= f.LineCount() { + // missing newline at the end of the file + end = f.Pos(f.Size()) + } else { + end = f.LineStart(line+1) - token.Pos(1) + } + + return end +} + +// AdjustPos is a hack to get the right line to display. +// It should not be used outside some specific cases. +func AdjustPos(line, nonAdjLine, adjLine int) int { + return line + nonAdjLine - adjLine +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/runner.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/runner.go similarity index 82% rename from vendor/github.com/golangci/golangci-lint/pkg/goanalysis/runner.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/runner.go index ac03c71ec..2e7d30c76 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/runner.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/runner.go @@ -5,22 +5,23 @@ package goanalysis import ( + "context" "encoding/gob" "fmt" "go/token" + "maps" "runtime" - "sort" + "slices" "sync" - "golang.org/x/exp/maps" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/packages" - "github.com/golangci/golangci-lint/internal/cache" - "github.com/golangci/golangci-lint/internal/errorutil" - "github.com/golangci/golangci-lint/pkg/goanalysis/load" - "github.com/golangci/golangci-lint/pkg/logutils" - "github.com/golangci/golangci-lint/pkg/timeutils" + "github.com/golangci/golangci-lint/v2/internal/cache" + "github.com/golangci/golangci-lint/v2/internal/errorutil" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis/load" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/timeutils" ) var ( @@ -42,6 +43,7 @@ type Diagnostic struct { Analyzer *analysis.Analyzer Position token.Position Pkg *packages.Package + File *token.File } type runner struct { @@ -75,7 +77,7 @@ func newRunner(prefix string, logger logutils.Log, pkgCache *cache.Cache, loadGu // It provides most of the logic for the main functions of both the // singlechecker and the multi-analysis commands. // It returns the appropriate exit code. -func (r *runner) run(analyzers []*analysis.Analyzer, initialPackages []*packages.Package) ([]Diagnostic, +func (r *runner) run(analyzers []*analysis.Analyzer, initialPackages []*packages.Package) ([]*Diagnostic, []error, map[*analysis.Pass]*packages.Package, ) { debugf("Analyzing %d packages on load mode %s", len(initialPackages), r.loadMode) @@ -121,9 +123,9 @@ func (r *runner) makeAction(a *analysis.Analyzer, pkg *packages.Package, } act = actAlloc.alloc() - act.a = a - act.pkg = pkg - act.r = r + act.Analyzer = a + act.Package = pkg + act.runner = r act.isInitialPkg = initialPkgs[pkg] act.needAnalyzeSource = initialPkgs[pkg] act.analysisDoneCh = make(chan struct{}) @@ -132,11 +134,11 @@ func (r *runner) makeAction(a *analysis.Analyzer, pkg *packages.Package, if len(a.FactTypes) > 0 { depsCount += len(pkg.Imports) } - act.deps = make([]*action, 0, depsCount) + act.Deps = make([]*action, 0, depsCount) // Add a dependency on each required analyzers. for _, req := range a.Requires { - act.deps = append(act.deps, r.makeAction(req, pkg, initialPkgs, actions, actAlloc)) + act.Deps = append(act.Deps, r.makeAction(req, pkg, initialPkgs, actions, actAlloc)) } r.buildActionFactDeps(act, a, pkg, initialPkgs, actions, actAlloc) @@ -158,11 +160,11 @@ func (r *runner) buildActionFactDeps(act *action, a *analysis.Analyzer, pkg *pac act.objectFacts = make(map[objectFactKey]analysis.Fact) act.packageFacts = make(map[packageFactKey]analysis.Fact) - paths := maps.Keys(pkg.Imports) - sort.Strings(paths) // for determinism + paths := slices.Sorted(maps.Keys(pkg.Imports)) // for determinism + for _, path := range paths { dep := r.makeAction(a, pkg.Imports[path], initialPkgs, actions, actAlloc) - act.deps = append(act.deps, dep) + act.Deps = append(act.Deps, dep) } // Need to register fact types for pkgcache proper gob encoding. @@ -203,12 +205,12 @@ func (r *runner) prepareAnalysis(pkgs []*packages.Package, for _, a := range analyzers { for _, pkg := range pkgs { root := r.makeAction(a, pkg, initialPkgs, actions, actAlloc) - root.isroot = true + root.IsRoot = true roots = append(roots, root) } } - allActions = maps.Values(actions) + allActions = slices.Collect(maps.Values(actions)) debugf("Built %d actions", len(actions)) @@ -220,7 +222,7 @@ func (r *runner) analyze(pkgs []*packages.Package, analyzers []*analysis.Analyze actionPerPkg := map[*packages.Package][]*action{} for _, act := range actions { - actionPerPkg[act.pkg] = append(actionPerPkg[act.pkg], act) + actionPerPkg[act.Package] = append(actionPerPkg[act.Package], act) } // Fill Imports field. @@ -250,31 +252,36 @@ func (r *runner) analyze(pkgs []*packages.Package, analyzers []*analysis.Analyze } } for _, act := range actions { - dfs(act.pkg) + dfs(act.Package) } // Limit memory and IO usage. gomaxprocs := runtime.GOMAXPROCS(-1) debugf("Analyzing at most %d packages in parallel", gomaxprocs) + loadSem := make(chan struct{}, gomaxprocs) - var wg sync.WaitGroup debugf("There are %d initial and %d total packages", len(initialPkgs), len(loadingPackages)) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + var wg sync.WaitGroup + for _, lp := range loadingPackages { if lp.isInitial { - wg.Add(1) - go func(lp *loadingPackage) { - lp.analyzeRecursive(r.loadMode, loadSem) - wg.Done() - }(lp) + wg.Go(func() { + lp.analyzeRecursive(ctx, cancel, r.loadMode, loadSem) + }) } } + wg.Wait() return rootActions } -func extractDiagnostics(roots []*action) (retDiags []Diagnostic, retErrors []error) { +func extractDiagnostics(roots []*action) (retDiags []*Diagnostic, retErrors []error) { extracted := make(map[*action]bool) var extract func(*action) var visitAll func(actions []*action) @@ -282,7 +289,7 @@ func extractDiagnostics(roots []*action) (retDiags []Diagnostic, retErrors []err for _, act := range actions { if !extracted[act] { extracted[act] = true - visitAll(act.deps) + visitAll(act.Deps) extract(act) } } @@ -299,31 +306,34 @@ func extractDiagnostics(roots []*action) (retDiags []Diagnostic, retErrors []err seen := make(map[key]bool) extract = func(act *action) { - if act.err != nil { - if pe, ok := act.err.(*errorutil.PanicError); ok { + if act.Err != nil { + if pe, ok := act.Err.(*errorutil.PanicError); ok { panic(pe) } - retErrors = append(retErrors, fmt.Errorf("%s: %w", act.a.Name, act.err)) + retErrors = append(retErrors, fmt.Errorf("%s: %w", act.Analyzer.Name, act.Err)) return } - if act.isroot { - for _, diag := range act.diagnostics { + if act.IsRoot { + for _, diag := range act.Diagnostics { // We don't display a.Name/f.Category // as most users don't care. - posn := act.pkg.Fset.Position(diag.Pos) - k := key{posn, act.a, diag.Message} + position := GetFilePositionFor(act.Package.Fset, diag.Pos) + file := act.Package.Fset.File(diag.Pos) + + k := key{Position: position, Analyzer: act.Analyzer, message: diag.Message} if seen[k] { continue // duplicate } seen[k] = true - retDiag := Diagnostic{ + retDiag := &Diagnostic{ + File: file, Diagnostic: diag, - Analyzer: act.a, - Position: posn, - Pkg: act.pkg, + Analyzer: act.Analyzer, + Position: position, + Pkg: act.Package, } retDiags = append(retDiags, retDiag) } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/runner_action.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/runner_action.go similarity index 64% rename from vendor/github.com/golangci/golangci-lint/pkg/goanalysis/runner_action.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/runner_action.go index 152cab181..1ee3c4435 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/runner_action.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/runner_action.go @@ -1,10 +1,11 @@ package goanalysis import ( + "context" "fmt" "runtime/debug" - "github.com/golangci/golangci-lint/internal/errorutil" + "github.com/golangci/golangci-lint/v2/internal/errorutil" ) type actionAllocator struct { @@ -28,10 +29,14 @@ func (actAlloc *actionAllocator) alloc() *action { return act } -func (act *action) waitUntilDependingAnalyzersWorked() { - for _, dep := range act.deps { - if dep.pkg == act.pkg { - <-dep.analysisDoneCh +func (act *action) waitUntilDependingAnalyzersWorked(ctx context.Context) { + for _, dep := range act.Deps { + if dep.Package == act.Package { + select { + case <-ctx.Done(): + return + case <-dep.analysisDoneCh: + } } } } @@ -39,28 +44,29 @@ func (act *action) waitUntilDependingAnalyzersWorked() { func (act *action) analyzeSafe() { defer func() { if p := recover(); p != nil { - if !act.isroot { + if !act.IsRoot { // This line allows to display "hidden" panic with analyzers like buildssa. // Some linters are dependent of sub-analyzers but when a sub-analyzer fails the linter is not aware of that, // this results to another panic (ex: "interface conversion: interface {} is nil, not *buildssa.SSA"). - act.r.log.Errorf("%s: panic during analysis: %v, %s", act.a.Name, p, string(debug.Stack())) + act.runner.log.Errorf("%s: panic during analysis: %v, %s", act.Analyzer.Name, p, string(debug.Stack())) } - act.err = errorutil.NewPanicError(fmt.Sprintf("%s: package %q (isInitialPkg: %t, needAnalyzeSource: %t): %s", - act.a.Name, act.pkg.Name, act.isInitialPkg, act.needAnalyzeSource, p), debug.Stack()) + act.Err = errorutil.NewPanicError(fmt.Sprintf("%s: package %q (isInitialPkg: %t, needAnalyzeSource: %t): %s", + act.Analyzer.Name, act.Package.Name, act.isInitialPkg, act.needAnalyzeSource, p), debug.Stack()) } }() - act.r.sw.TrackStage(act.a.Name, act.analyze) + act.runner.sw.TrackStage(act.Analyzer.Name, act.analyze) } func (act *action) markDepsForAnalyzingSource() { // Horizontal deps (analyzer.Requires) must be loaded from source and analyzed before analyzing // this action. - for _, dep := range act.deps { - if dep.pkg == act.pkg { + for _, dep := range act.Deps { + if dep.Package == act.Package && !dep.needAnalyzeSource { // Analyze source only for horizontal dependencies, e.g. from "buildssa". dep.needAnalyzeSource = true // can't be set in parallel + dep.markDepsForAnalyzingSource() } } } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/runner_action_cache.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/runner_action_cache.go similarity index 63% rename from vendor/github.com/golangci/golangci-lint/pkg/goanalysis/runner_action_cache.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/runner_action_cache.go index fbc2f82fa..1fafbca57 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/runner_action_cache.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/runner_action_cache.go @@ -8,7 +8,7 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/types/objectpath" - "github.com/golangci/golangci-lint/internal/cache" + "github.com/golangci/golangci-lint/v2/internal/cache" ) type Fact struct { @@ -26,7 +26,7 @@ func (act *action) loadCachedFacts() bool { return true // load cached facts only for non-initial packages } - if len(act.a.FactTypes) == 0 { + if len(act.Analyzer.FactTypes) == 0 { return true // no need to load facts } @@ -38,7 +38,7 @@ func (act *action) loadCachedFacts() bool { } func (act *action) persistFactsToCache() error { - analyzer := act.a + analyzer := act.Analyzer if len(analyzer.FactTypes) == 0 { return nil } @@ -46,7 +46,7 @@ func (act *action) persistFactsToCache() error { // Merge new facts into the package and persist them. var facts []Fact for key, fact := range act.packageFacts { - if key.pkg != act.pkg.Types { + if key.pkg != act.Package.Types { // The fact is from inherited facts from another package continue } @@ -57,7 +57,7 @@ func (act *action) persistFactsToCache() error { } for key, fact := range act.objectFacts { obj := key.obj - if obj.Pkg() != act.pkg.Types { + if obj.Pkg() != act.Package.Types { // The fact is from inherited facts from another package continue } @@ -74,45 +74,44 @@ func (act *action) persistFactsToCache() error { }) } - factsCacheDebugf("Caching %d facts for package %q and analyzer %s", len(facts), act.pkg.Name, act.a.Name) + factsCacheDebugf("Caching %d facts for package %q and analyzer %s", len(facts), act.Package.Name, act.Analyzer.Name) - return act.r.pkgCache.Put(act.pkg, cache.HashModeNeedAllDeps, factCacheKey(analyzer), facts) + return act.runner.pkgCache.Put(act.Package, cache.HashModeNeedAllDeps, factCacheKey(analyzer), facts) } func (act *action) loadPersistedFacts() bool { var facts []Fact - err := act.r.pkgCache.Get(act.pkg, cache.HashModeNeedAllDeps, factCacheKey(act.a), &facts) + err := act.runner.pkgCache.Get(act.Package, cache.HashModeNeedAllDeps, factCacheKey(act.Analyzer), &facts) if err != nil { if !errors.Is(err, cache.ErrMissing) && !errors.Is(err, io.EOF) { - act.r.log.Warnf("Failed to get persisted facts: %s", err) + act.runner.log.Warnf("Failed to get persisted facts: %s", err) } - factsCacheDebugf("No cached facts for package %q and analyzer %s", act.pkg.Name, act.a.Name) + factsCacheDebugf("No cached facts for package %q and analyzer %s", act.Package.Name, act.Analyzer.Name) return false } - factsCacheDebugf("Loaded %d cached facts for package %q and analyzer %s", len(facts), act.pkg.Name, act.a.Name) + factsCacheDebugf("Loaded %d cached facts for package %q and analyzer %s", len(facts), act.Package.Name, act.Analyzer.Name) for _, f := range facts { if f.Path == "" { // this is a package fact - key := packageFactKey{act.pkg.Types, act.factType(f.Fact)} + key := packageFactKey{pkg: act.Package.Types, typ: act.factType(f.Fact)} act.packageFacts[key] = f.Fact continue } - obj, err := objectpath.Object(act.pkg.Types, objectpath.Path(f.Path)) + obj, err := objectpath.Object(act.Package.Types, objectpath.Path(f.Path)) if err != nil { - // Be lenient about these errors. For example, when - // analyzing io/ioutil from source, we may get a fact - // for methods on the devNull type, and objectpath - // will happily create a path for them. However, when - // we later load io/ioutil from export data, the path - // no longer resolves. + // Be lenient about these errors. + // For example, when analyzing io/ioutil from source, + // we may get a fact for methods on the devNull type, + // and objectpath will happily create a path for them. + // However, + // when we later load io/ioutil from export data, + // the path no longer resolves. // // If an exported type embeds the unexported type, - // then (part of) the unexported type will become part - // of the type information and our path will resolve - // again. + // then (part of) the unexported type will become part of the type information and our path will resolve again. continue } factKey := objectFactKey{obj, act.factType(f.Fact)} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/runner_base.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/runner_checker.go similarity index 51% rename from vendor/github.com/golangci/golangci-lint/pkg/goanalysis/runner_base.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/runner_checker.go index d868f8f5d..0d3fcdb9e 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/runner_base.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/runner_checker.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // -// Partial copy of https://github.com/golang/tools/blob/dba5486c2a1d03519930812112b23ed2c45c04fc/go/analysis/internal/checker/checker.go +// Altered copy of https://github.com/golang/tools/blob/v0.28.0/go/analysis/internal/checker/checker.go package goanalysis @@ -12,13 +12,16 @@ import ( "errors" "fmt" "go/types" + "os" "reflect" "time" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/packages" - "github.com/golangci/golangci-lint/pkg/goanalysis/pkgerrors" + "github.com/golangci/golangci-lint/v2/internal/x/tools/analysisflags" + "github.com/golangci/golangci-lint/v2/internal/x/tools/analysisinternal" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis/pkgerrors" ) // NOTE(ldez) altered: custom fields; remove 'once' and 'duration'. @@ -27,19 +30,21 @@ import ( // package (as different analyzers are applied, either in sequence or // parallel), and across packages (as dependencies are analyzed). type action struct { - a *analysis.Analyzer - pkg *packages.Package + Analyzer *analysis.Analyzer + Package *packages.Package + IsRoot bool // whether this is a root node of the graph + Deps []*action + Result any // computed result of Analyzer.run, if any (and if IsRoot) + Err error // error result of Analyzer.run + Diagnostics []analysis.Diagnostic + Duration time.Duration // execution time of this step + pass *analysis.Pass - isroot bool - deps []*action objectFacts map[objectFactKey]analysis.Fact packageFacts map[packageFactKey]analysis.Fact - result any - diagnostics []analysis.Diagnostic - err error // NOTE(ldez) custom fields. - r *runner + runner *runner analysisDoneCh chan struct{} loadCachedFactsDone bool loadCachedFactsOk bool @@ -61,7 +66,7 @@ type packageFactKey struct { // NOTE(ldez) no alteration. func (act *action) String() string { - return fmt.Sprintf("%s@%s", act.a, act.pkg) + return fmt.Sprintf("%s@%s", act.Analyzer, act.Package) } // NOTE(ldez) altered version of `func (act *action) execOnce()`. @@ -72,20 +77,26 @@ func (act *action) analyze() { return } - defer func(now time.Time) { - analyzeDebugf("go/analysis: %s: %s: analyzed package %q in %s", act.r.prefix, act.a.Name, act.pkg.Name, time.Since(now)) - }(time.Now()) + // Record time spent in this node but not its dependencies. + // In parallel mode, due to GC/scheduler contention, the + // time is 5x higher than in sequential mode, even with a + // semaphore limiting the number of threads here. + // So use -debug=tp. + t0 := time.Now() + defer func() { + act.Duration = time.Since(t0) + analyzeDebugf("go/analysis: %s: %s: analyzed package %q in %s", act.runner.prefix, act.Analyzer.Name, act.Package.Name, time.Since(t0)) + }() // Report an error if any dependency failures. var depErrors error - for _, dep := range act.deps { - if dep.err != nil { - depErrors = errors.Join(depErrors, errors.Unwrap(dep.err)) + for _, dep := range act.Deps { + if dep.Err != nil { + depErrors = errors.Join(depErrors, errors.Unwrap(dep.Err)) } } - if depErrors != nil { - act.err = fmt.Errorf("failed prerequisites: %w", depErrors) + act.Err = fmt.Errorf("failed prerequisites: %w", depErrors) return } @@ -94,15 +105,14 @@ func (act *action) analyze() { inputs := make(map[*analysis.Analyzer]any) act.objectFacts = make(map[objectFactKey]analysis.Fact) act.packageFacts = make(map[packageFactKey]analysis.Fact) - startedAt := time.Now() - - for _, dep := range act.deps { - if dep.pkg == act.pkg { + for _, dep := range act.Deps { + if dep.Package == act.Package { // Same package, different analysis (horizontal edge): // in-memory outputs of prerequisite analyzers // become inputs to this analysis pass. - inputs[dep.a] = dep.result - } else if dep.a == act.a { // (always true) + inputs[dep.Analyzer] = dep.Result + + } else if dep.Analyzer == act.Analyzer { // (always true) // Same analysis, different package (vertical edge): // serialized facts produced by prerequisite analysis // become available to this analysis pass. @@ -110,10 +120,20 @@ func (act *action) analyze() { } } - factsDebugf("%s: Inherited facts in %s", act, time.Since(startedAt)) + // NOTE(ldez) this is not compatible with our implementation. + // Quick (nonexhaustive) check that the correct go/packages mode bits were used. + // (If there were errors, all bets are off.) + // if pkg := act.Package; pkg.Errors == nil { + // if pkg.Name == "" || pkg.PkgPath == "" || pkg.Types == nil || pkg.Fset == nil || pkg.TypesSizes == nil { + // panic(fmt.Sprintf("packages must be loaded with packages.LoadSyntax mode: Name: %v, PkgPath: %v, Types: %v, Fset: %v, TypesSizes: %v", + // pkg.Name == "", pkg.PkgPath == "", pkg.Types == nil, pkg.Fset == nil, pkg.TypesSizes == nil)) + // } + // } + + factsDebugf("%s: Inherited facts in %s", act, time.Since(t0)) module := &analysis.Module{} // possibly empty (non nil) in go/analysis drivers. - if mod := act.pkg.Module; mod != nil { + if mod := act.Package.Module; mod != nil { module.Path = mod.Path module.Version = mod.Version module.GoVersion = mod.GoVersion @@ -121,79 +141,104 @@ func (act *action) analyze() { // Run the analysis. pass := &analysis.Pass{ - Analyzer: act.a, - Fset: act.pkg.Fset, - Files: act.pkg.Syntax, - OtherFiles: act.pkg.OtherFiles, - IgnoredFiles: act.pkg.IgnoredFiles, - Pkg: act.pkg.Types, - TypesInfo: act.pkg.TypesInfo, - TypesSizes: act.pkg.TypesSizes, - TypeErrors: act.pkg.TypeErrors, + Analyzer: act.Analyzer, + Fset: act.Package.Fset, + Files: act.Package.Syntax, + OtherFiles: act.Package.OtherFiles, + IgnoredFiles: act.Package.IgnoredFiles, + Pkg: act.Package.Types, + TypesInfo: act.Package.TypesInfo, + TypesSizes: act.Package.TypesSizes, + TypeErrors: act.Package.TypeErrors, Module: module, ResultOf: inputs, - Report: func(d analysis.Diagnostic) { act.diagnostics = append(act.diagnostics, d) }, - ImportObjectFact: act.importObjectFact, + Report: func(d analysis.Diagnostic) { act.Diagnostics = append(act.Diagnostics, d) }, + ImportObjectFact: act.ObjectFact, ExportObjectFact: act.exportObjectFact, - ImportPackageFact: act.importPackageFact, + ImportPackageFact: act.PackageFact, ExportPackageFact: act.exportPackageFact, - AllObjectFacts: act.allObjectFacts, - AllPackageFacts: act.allPackageFacts, + AllObjectFacts: act.AllObjectFacts, + AllPackageFacts: act.AllPackageFacts, } - + pass.ReadFile = analysisinternal.CheckedReadFile(pass, os.ReadFile) act.pass = pass - act.r.passToPkgGuard.Lock() - act.r.passToPkg[pass] = act.pkg - act.r.passToPkgGuard.Unlock() - if act.pkg.IllTyped { + act.runner.passToPkgGuard.Lock() + act.runner.passToPkg[pass] = act.Package + act.runner.passToPkgGuard.Unlock() + + act.Result, act.Err = func() (any, error) { + // NOTE(golangci-lint): // It looks like there should be !pass.Analyzer.RunDespiteErrors - // but govet's cgocall crashes on it. Govet itself contains !pass.Analyzer.RunDespiteErrors condition here, + // but govet's cgocall crashes on it. + // Govet itself contains !pass.Analyzer.RunDespiteErrors condition here, // but it exits before it if packages.Load have failed. - act.err = fmt.Errorf("analysis skipped: %w", &pkgerrors.IllTypedError{Pkg: act.pkg}) - } else { - startedAt = time.Now() + if act.Package.IllTyped { + return nil, fmt.Errorf("analysis skipped: %w", &pkgerrors.IllTypedError{Pkg: act.Package}) + } + + t1 := time.Now() - act.result, act.err = pass.Analyzer.Run(pass) + result, err := pass.Analyzer.Run(pass) + if err != nil { + return nil, err + } - analyzedIn := time.Since(startedAt) - if analyzedIn > time.Millisecond*10 { + analyzedIn := time.Since(t1) + if analyzedIn > 10*time.Millisecond { debugf("%s: run analyzer in %s", act, analyzedIn) } - } - // disallow calls after Run + // correct result type? + if got, want := reflect.TypeOf(result), pass.Analyzer.ResultType; got != want { + return nil, fmt.Errorf( + "internal error: on package %s, analyzer %s returned a result of type %v, but declared ResultType %v", + pass.Pkg.Path(), pass.Analyzer, got, want) + } + + // resolve diagnostic URLs + for i := range act.Diagnostics { + url, err := analysisflags.ResolveURL(act.Analyzer, act.Diagnostics[i]) + if err != nil { + return nil, err + } + act.Diagnostics[i].URL = url + } + return result, nil + }() + + // Help detect (disallowed) calls after Run. pass.ExportObjectFact = nil pass.ExportPackageFact = nil err := act.persistFactsToCache() if err != nil { - act.r.log.Warnf("Failed to persist facts to cache: %s", err) + act.runner.log.Warnf("Failed to persist facts to cache: %s", err) } } -// NOTE(ldez) altered: logger; serialize. +// NOTE(ldez) altered: logger; sanityCheck. // inheritFacts populates act.facts with // those it obtains from its dependency, dep. func inheritFacts(act, dep *action) { - const serialize = false + const sanityCheck = false for key, fact := range dep.objectFacts { // Filter out facts related to objects // that are irrelevant downstream // (equivalently: not in the compiler export data). - if !exportedFrom(key.obj, dep.pkg.Types) { + if !exportedFrom(key.obj, dep.Package.Types) { factsInheritDebugf("%v: discarding %T fact from %s for %s: %s", act, fact, dep, key.obj, fact) continue } // Optionally serialize/deserialize fact // to verify that it works across address spaces. - if serialize { + if sanityCheck { encodedFact, err := codeFact(fact) if err != nil { - act.r.log.Panicf("internal error: encoding of %T fact failed in %v: %v", fact, act, err) + act.runner.log.Panicf("internal error: encoding of %T fact failed in %v: %v", fact, act, err) } fact = encodedFact } @@ -207,14 +252,26 @@ func inheritFacts(act, dep *action) { // TODO: filter out facts that belong to // packages not mentioned in the export data // to prevent side channels. + // + // The Pass.All{Object,Package}Facts accessors expose too much: + // all facts, of all types, for all dependencies in the action + // graph. Not only does the representation grow quadratically, + // but it violates the separate compilation paradigm, allowing + // analysis implementations to communicate with indirect + // dependencies that are not mentioned in the export data. + // + // It's not clear how to fix this short of a rather expensive + // filtering step after each action that enumerates all the + // objects that would appear in export data, and deletes + // facts associated with objects not in this set. // Optionally serialize/deserialize fact // to verify that it works across address spaces // and is deterministic. - if serialize { + if sanityCheck { encodedFact, err := codeFact(fact) if err != nil { - act.r.log.Panicf("internal error: encoding of %T fact failed in %v", fact, act) + act.runner.log.Panicf("internal error: encoding of %T fact failed in %v", fact, act) } fact = encodedFact } @@ -225,7 +282,7 @@ func inheritFacts(act, dep *action) { } } -// NOTE(ldez) no alteration. +// NOTE(ldez) altered: `new` is renamed to `newFact`. // codeFact encodes then decodes a fact, // just to exercise that logic. func codeFact(fact analysis.Fact) (analysis.Fact, error) { @@ -259,7 +316,7 @@ func codeFact(fact analysis.Fact) (analysis.Fact, error) { // This includes not just the exported members of pkg, but also unexported // constants, types, fields, and methods, perhaps belonging to other packages, // that find there way into the API. -// This is an over-approximation of the more accurate approach used by +// This is an overapproximation of the more accurate approach used by // gc export data, which walks the type graph, but it's much simpler. // // TODO(adonovan): do more accurate filtering by walking the type graph. @@ -282,11 +339,14 @@ func exportedFrom(obj types.Object, pkg *types.Package) bool { return false // Nil, Builtin, Label, or PkgName } -// NOTE(ldez) altered: logger; `act.factType` -// importObjectFact implements Pass.ImportObjectFact. -// Given a non-nil pointer ptr of type *T, where *T satisfies Fact, -// importObjectFact copies the fact value to *ptr. -func (act *action) importObjectFact(obj types.Object, ptr analysis.Fact) bool { +// NOTE(ldez) altered: logger; `act.factType`. +// ObjectFact retrieves a fact associated with obj, +// and returns true if one was found. +// Given a value ptr of type *T, where *T satisfies Fact, +// ObjectFact copies the value to *ptr. +// +// See documentation at ImportObjectFact field of [analysis.Pass]. +func (act *action) ObjectFact(obj types.Object, ptr analysis.Fact) bool { if obj == nil { panic("nil object") } @@ -298,12 +358,16 @@ func (act *action) importObjectFact(obj types.Object, ptr analysis.Fact) bool { return false } -// NOTE(ldez) altered: removes code related to `act.pass.ExportPackageFact`; logger; `act.factType`. +// NOTE(ldez) altered: logger; `act.factType`. // exportObjectFact implements Pass.ExportObjectFact. func (act *action) exportObjectFact(obj types.Object, fact analysis.Fact) { - if obj.Pkg() != act.pkg.Types { - act.r.log.Panicf("internal error: in analysis %s of package %s: Fact.Set(%s, %T): can't set facts on objects belonging another package", - act.a, act.pkg, obj, fact) + if act.pass.ExportObjectFact == nil { + act.runner.log.Panicf("%s: Pass.ExportObjectFact(%s, %T) called after Run", act, obj, fact) + } + + if obj.Pkg() != act.Package.Types { + act.runner.log.Panicf("internal error: in analysis %s of package %s: Fact.Set(%s, %T): can't set facts on objects belonging another package", + act.Analyzer, act.Package, obj, fact) } key := objectFactKey{obj, act.factType(fact)} @@ -312,12 +376,16 @@ func (act *action) exportObjectFact(obj types.Object, fact analysis.Fact) { objstr := types.ObjectString(obj, (*types.Package).Name) factsExportDebugf("%s: object %s has fact %s\n", - act.pkg.Fset.Position(obj.Pos()), objstr, fact) + act.Package.Fset.Position(obj.Pos()), objstr, fact) } } // NOTE(ldez) no alteration. -func (act *action) allObjectFacts() []analysis.ObjectFact { +// AllObjectFacts returns a new slice containing all object facts of +// the analysis's FactTypes in unspecified order. +// +// See documentation at AllObjectFacts field of [analysis.Pass]. +func (act *action) AllObjectFacts() []analysis.ObjectFact { facts := make([]analysis.ObjectFact, 0, len(act.objectFacts)) for k := range act.objectFacts { facts = append(facts, analysis.ObjectFact{Object: k.obj, Fact: act.objectFacts[k]}) @@ -325,11 +393,12 @@ func (act *action) allObjectFacts() []analysis.ObjectFact { return facts } -// NOTE(ldez) altered: `act.factType` -// importPackageFact implements Pass.ImportPackageFact. -// Given a non-nil pointer ptr of type *T, where *T satisfies Fact, -// fact copies the fact value to *ptr. -func (act *action) importPackageFact(pkg *types.Package, ptr analysis.Fact) bool { +// NOTE(ldez) altered: `act.factType`. +// PackageFact retrieves a fact associated with package pkg, +// which must be this package or one of its dependencies. +// +// See documentation at ImportObjectFact field of [analysis.Pass]. +func (act *action) PackageFact(pkg *types.Package, ptr analysis.Fact) bool { if pkg == nil { panic("nil package") } @@ -341,30 +410,38 @@ func (act *action) importPackageFact(pkg *types.Package, ptr analysis.Fact) bool return false } -// NOTE(ldez) altered: removes code related to `act.pass.ExportPackageFact`; logger; `act.factType`. +// NOTE(ldez) altered: logger; `act.factType`. // exportPackageFact implements Pass.ExportPackageFact. func (act *action) exportPackageFact(fact analysis.Fact) { + if act.pass.ExportPackageFact == nil { + act.runner.log.Panicf("%s: Pass.ExportPackageFact(%T) called after Run", act, fact) + } + key := packageFactKey{act.pass.Pkg, act.factType(fact)} act.packageFacts[key] = fact // clobber any existing entry factsDebugf("%s: package %s has fact %s\n", - act.pkg.Fset.Position(act.pass.Files[0].Pos()), act.pass.Pkg.Path(), fact) + act.Package.Fset.Position(act.pass.Files[0].Pos()), act.pass.Pkg.Path(), fact) } // NOTE(ldez) altered: add receiver to handle logs. func (act *action) factType(fact analysis.Fact) reflect.Type { t := reflect.TypeOf(fact) - if t.Kind() != reflect.Ptr { - act.r.log.Fatalf("invalid Fact type: got %T, want pointer", fact) + if t.Kind() != reflect.Pointer { + act.runner.log.Fatalf("invalid Fact type: got %T, want pointer", fact) } return t } // NOTE(ldez) no alteration. -func (act *action) allPackageFacts() []analysis.PackageFact { +// AllPackageFacts returns a new slice containing all package +// facts of the analysis's FactTypes in unspecified order. +// +// See documentation at AllPackageFacts field of [analysis.Pass]. +func (act *action) AllPackageFacts() []analysis.PackageFact { facts := make([]analysis.PackageFact, 0, len(act.packageFacts)) - for k := range act.packageFacts { - facts = append(facts, analysis.PackageFact{Package: k.pkg, Fact: act.packageFacts[k]}) + for k, fact := range act.packageFacts { + facts = append(facts, analysis.PackageFact{Package: k.pkg, Fact: fact}) } return facts } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/runner_loadingpackage.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/runner_loadingpackage.go similarity index 84% rename from vendor/github.com/golangci/golangci-lint/pkg/goanalysis/runner_loadingpackage.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/runner_loadingpackage.go index 44d676958..e01d3eaa2 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/runner_loadingpackage.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/runner_loadingpackage.go @@ -1,6 +1,7 @@ package goanalysis import ( + "context" "errors" "fmt" "go/ast" @@ -14,16 +15,20 @@ import ( "sync" "sync/atomic" + "golang.org/x/sync/errgroup" "golang.org/x/tools/go/gcexportdata" "golang.org/x/tools/go/packages" - "github.com/golangci/golangci-lint/pkg/goanalysis/load" - "github.com/golangci/golangci-lint/pkg/goutil" - "github.com/golangci/golangci-lint/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis/load" + "github.com/golangci/golangci-lint/v2/pkg/goutil" + "github.com/golangci/golangci-lint/v2/pkg/logutils" ) const unsafePkgName = "unsafe" +// https://github.com/golang/go/blob/go1.23.8/src/internal/types/errors/codes.go#L1484 +const tooNew = 151 + type loadingPackage struct { pkg *packages.Package imports map[string]*loadingPackage @@ -36,54 +41,79 @@ type loadingPackage struct { decUseMutex sync.Mutex } -func (lp *loadingPackage) analyzeRecursive(loadMode LoadMode, loadSem chan struct{}) { +func (lp *loadingPackage) analyzeRecursive(ctx context.Context, cancel context.CancelFunc, loadMode LoadMode, loadSem chan struct{}) { lp.analyzeOnce.Do(func() { // Load the direct dependencies, in parallel. var wg sync.WaitGroup - wg.Add(len(lp.imports)) + for _, imp := range lp.imports { - go func(imp *loadingPackage) { - imp.analyzeRecursive(loadMode, loadSem) - wg.Done() - }(imp) + wg.Go(func() { + imp.analyzeRecursive(ctx, cancel, loadMode, loadSem) + }) } + wg.Wait() - lp.analyze(loadMode, loadSem) + + lp.analyze(ctx, cancel, loadMode, loadSem) }) } -func (lp *loadingPackage) analyze(loadMode LoadMode, loadSem chan struct{}) { - loadSem <- struct{}{} - defer func() { - <-loadSem - }() +func (lp *loadingPackage) analyze(ctx context.Context, cancel context.CancelFunc, loadMode LoadMode, loadSem chan struct{}) { + select { + case <-ctx.Done(): + return + case loadSem <- struct{}{}: + defer func() { + <-loadSem + }() + } // Save memory on unused more fields. defer lp.decUse(loadMode < LoadModeWholeProgram) if err := lp.loadWithFacts(loadMode); err != nil { + // Note: this error is ignored when there is no facts loading (e.g. with 98% of linters). + // But this is not a problem because the errors are added to the package.Errors. + // You through an error, try to add it to actions, but there is no action annnddd it's gone! werr := fmt.Errorf("failed to load package %s: %w", lp.pkg.Name, err) + // Don't need to write error to errCh, it will be extracted and reported on another layer. // Unblock depending on actions and propagate error. for _, act := range lp.actions { close(act.analysisDoneCh) - act.err = werr + + act.Err = werr + } + + if len(lp.actions) == 0 { + lp.log.Warnf("no action but there is an error: %v", err) } + return } - var actsWg sync.WaitGroup - actsWg.Add(len(lp.actions)) + actsWg, ctxGroup := errgroup.WithContext(ctx) + for _, act := range lp.actions { - go func(act *action) { - defer actsWg.Done() + actsWg.Go(func() error { + act.waitUntilDependingAnalyzersWorked(ctxGroup) - act.waitUntilDependingAnalyzersWorked() + select { + case <-ctxGroup.Done(): + return nil + default: + } act.analyzeSafe() - }(act) + + return act.Err + }) + } + + err := actsWg.Wait() + if err != nil { + cancel() } - actsWg.Wait() } func (lp *loadingPackage) loadFromSource(loadMode LoadMode) error { @@ -125,13 +155,14 @@ func (lp *loadingPackage) loadFromSource(loadMode LoadMode) error { pkg.IllTyped = true pkg.TypesInfo = &types.Info{ - Types: make(map[ast.Expr]types.TypeAndValue), - Instances: make(map[*ast.Ident]types.Instance), - Defs: make(map[*ast.Ident]types.Object), - Uses: make(map[*ast.Ident]types.Object), - Implicits: make(map[ast.Node]types.Object), - Scopes: make(map[ast.Node]*types.Scope), - Selections: make(map[*ast.SelectorExpr]*types.Selection), + Types: make(map[ast.Expr]types.TypeAndValue), + Instances: make(map[*ast.Ident]types.Instance), + Defs: make(map[*ast.Ident]types.Object), + Uses: make(map[*ast.Ident]types.Object), + Implicits: make(map[ast.Node]types.Object), + Selections: make(map[*ast.SelectorExpr]*types.Selection), + Scopes: make(map[ast.Node]*types.Scope), + FileVersions: make(map[*ast.File]string), } importer := func(path string) (*types.Package, error) { @@ -209,9 +240,11 @@ func (lp *loadingPackage) loadFromExportData() error { return fmt.Errorf("dependency %q hasn't been loaded yet", path) } } + if pkg.ExportFile == "" { return fmt.Errorf("no export data for %q", pkg.ID) } + f, err := os.Open(pkg.ExportFile) if err != nil { return err @@ -302,13 +335,15 @@ func (lp *loadingPackage) loadImportedPackageWithFacts(loadMode LoadMode) error if srcErr := lp.loadFromSource(loadMode); srcErr != nil { return srcErr } + // Make sure this package can't be imported successfully pkg.Errors = append(pkg.Errors, packages.Error{ Pos: "-", Msg: fmt.Sprintf("could not load export data: %s", err), Kind: packages.ParseError, }) - return fmt.Errorf("could not load export data: %w", err) + + return nil } } @@ -363,12 +398,12 @@ func (lp *loadingPackage) decUse(canClearTypes bool) { pass.ImportPackageFact = nil pass.ExportPackageFact = nil act.pass = nil - act.deps = nil - if act.result != nil { + act.Deps = nil + if act.Result != nil { if isMemoryDebug { - debugf("%s: decUse: nilling act result of size %d bytes", act, sizeOfValueTreeBytes(act.result)) + debugf("%s: decUse: nilling act result of size %d bytes", act, sizeOfValueTreeBytes(act.Result)) } - act.result = nil + act.Result = nil } } @@ -399,7 +434,7 @@ func (lp *loadingPackage) decUse(canClearTypes bool) { for _, act := range lp.actions { if !lp.isInitial { - act.pkg = nil + act.Package = nil } act.packageFacts = nil act.objectFacts = nil @@ -435,6 +470,14 @@ func (lp *loadingPackage) convertError(err error) []packages.Error { case types.Error: // from type checker + + // https://github.com/golang/go/blob/go1.23.8/src/go/types/api.go#L52-L57 + if int(reflect.ValueOf(err).FieldByName("go116code").Int()) == tooNew { + // https://github.com/golang/go/blob/go1.23.8/src/go/types/check.go#L380 + // https://github.com/golang/go/blob/go1.23.8/src/go/types/check.go#L349 + panic(err.Msg) + } + errs = append(errs, packages.Error{ Pos: err.Fset.Position(err.Pos).String(), Msg: err.Msg, @@ -470,7 +513,7 @@ func sizeOfValueTreeBytes(v any) int { func sizeOfReflectValueTreeBytes(rv reflect.Value, visitedPtrs map[uintptr]struct{}) int { switch rv.Kind() { - case reflect.Ptr: + case reflect.Pointer: ptrSize := int(rv.Type().Size()) if rv.IsNil() { return ptrSize diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/runners.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/runners.go new file mode 100644 index 000000000..bcbc0033e --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/runners.go @@ -0,0 +1,156 @@ +package goanalysis + +import ( + "fmt" + "go/token" + "slices" + "strings" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/packages" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis/pkgerrors" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/timeutils" +) + +type runAnalyzersConfig interface { + getName() string + getLinterNameForDiagnostic(*Diagnostic) string + getAnalyzers() []*analysis.Analyzer + useOriginalPackages() bool + reportIssues(*linter.Context) []*Issue + getLoadMode() LoadMode +} + +func runAnalyzers(cfg runAnalyzersConfig, lintCtx *linter.Context) ([]*result.Issue, error) { + log := lintCtx.Log.Child(logutils.DebugKeyGoAnalysis) + sw := timeutils.NewStopwatch("analyzers", log) + + const stagesToPrint = 10 + defer sw.PrintTopStages(stagesToPrint) + + runner := newRunner(cfg.getName(), log, lintCtx.PkgCache, lintCtx.LoadGuard, cfg.getLoadMode(), sw) + + pkgs := lintCtx.Packages + if cfg.useOriginalPackages() { + pkgs = lintCtx.OriginalPackages + } + + issues, pkgsFromCache := loadIssuesFromCache(pkgs, lintCtx, cfg.getAnalyzers()) + var pkgsToAnalyze []*packages.Package + for _, pkg := range pkgs { + if !pkgsFromCache[pkg] { + pkgsToAnalyze = append(pkgsToAnalyze, pkg) + } + } + + diags, errs, passToPkg := runner.run(cfg.getAnalyzers(), pkgsToAnalyze) + + defer func() { + if len(errs) == 0 { + // If we try to save to cache even if we have compilation errors + // we won't see them on repeated runs. + saveIssuesToCache(pkgs, pkgsFromCache, issues, lintCtx, cfg.getAnalyzers()) + } + }() + + buildAllIssues := func() []*result.Issue { + var retIssues []*result.Issue + + reportedIssues := cfg.reportIssues(lintCtx) + for _, reportedIssue := range reportedIssues { + if reportedIssue.Pkg == nil { + reportedIssue.Pkg = passToPkg[reportedIssue.Pass] + } + + retIssues = append(retIssues, reportedIssue.Issue) + } + + return slices.Concat(retIssues, buildIssues(diags, cfg.getLinterNameForDiagnostic)) + } + + errIssues, err := pkgerrors.BuildIssuesFromIllTypedError(errs, lintCtx) + if err != nil { + return nil, err + } + + issues = append(issues, errIssues...) + issues = append(issues, buildAllIssues()...) + + return issues, nil +} + +func buildIssues(diags []*Diagnostic, linterNameBuilder func(diag *Diagnostic) string) []*result.Issue { + var issues []*result.Issue + + for _, diag := range diags { + linterName := linterNameBuilder(diag) + + var text string + if diag.Analyzer.Name == linterName { + text = diag.Message + } else { + text = fmt.Sprintf("%s: %s", diag.Analyzer.Name, diag.Message) + } + + var suggestedFixes []analysis.SuggestedFix + + for _, sf := range diag.SuggestedFixes { + // Skip suggested fixes on cgo files. + // The related error is: "diff has out-of-bounds edits" + // This is a temporary workaround. + if !strings.HasSuffix(diag.File.Name(), ".go") { + continue + } + + nsf := analysis.SuggestedFix{Message: sf.Message} + + for _, edit := range sf.TextEdits { + end := edit.End + + if !end.IsValid() { + end = edit.Pos + } + + // To be applied the positions need to be "adjusted" based on the file. + // This is the difference between the "displayed" positions and "effective" positions. + nsf.TextEdits = append(nsf.TextEdits, analysis.TextEdit{ + Pos: token.Pos(diag.File.Offset(edit.Pos)), + End: token.Pos(diag.File.Offset(end)), + NewText: edit.NewText, + }) + } + + suggestedFixes = append(suggestedFixes, nsf) + } + + issues = append(issues, &result.Issue{ + FromLinter: linterName, + Text: text, + Pos: diag.Position, + Pkg: diag.Pkg, + SuggestedFixes: suggestedFixes, + }) + + if len(diag.Related) > 0 { + for _, info := range diag.Related { + relatedPos := diag.Pkg.Fset.Position(info.Pos) + + if relatedPos.Filename != diag.Position.Filename { + relatedPos = diag.Position + } + + issues = append(issues, &result.Issue{ + FromLinter: linterName, + Text: fmt.Sprintf("%s(related information): %s", diag.Analyzer.Name, info.Message), + Pos: relatedPos, + Pkg: diag.Pkg, + }) + } + } + } + return issues +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/runners_cache.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/runners_cache.go similarity index 73% rename from vendor/github.com/golangci/golangci-lint/pkg/goanalysis/runners_cache.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/runners_cache.go index 8c244688b..b74d4f94f 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/goanalysis/runners_cache.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goanalysis/runners_cache.go @@ -11,46 +11,42 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/packages" - "github.com/golangci/golangci-lint/internal/cache" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/internal/cache" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/result" ) func saveIssuesToCache(allPkgs []*packages.Package, pkgsFromCache map[*packages.Package]bool, - issues []result.Issue, lintCtx *linter.Context, analyzers []*analysis.Analyzer, + issues []*result.Issue, lintCtx *linter.Context, analyzers []*analysis.Analyzer, ) { startedAt := time.Now() - perPkgIssues := map[*packages.Package][]result.Issue{} - for ind := range issues { - i := &issues[ind] - perPkgIssues[i.Pkg] = append(perPkgIssues[i.Pkg], *i) + perPkgIssues := map[*packages.Package][]*result.Issue{} + for _, issue := range issues { + perPkgIssues[issue.Pkg] = append(perPkgIssues[issue.Pkg], issue) } - var savedIssuesCount int64 = 0 + var savedIssuesCount int64 lintResKey := getIssuesCacheKey(analyzers) workerCount := runtime.GOMAXPROCS(-1) var wg sync.WaitGroup - wg.Add(workerCount) pkgCh := make(chan *packages.Package, len(allPkgs)) - for i := 0; i < workerCount; i++ { - go func() { - defer wg.Done() + for range workerCount { + wg.Go(func() { for pkg := range pkgCh { pkgIssues := perPkgIssues[pkg] encodedIssues := make([]EncodingIssue, 0, len(pkgIssues)) - for ind := range pkgIssues { - i := &pkgIssues[ind] + for _, issue := range pkgIssues { encodedIssues = append(encodedIssues, EncodingIssue{ - FromLinter: i.FromLinter, - Text: i.Text, - Severity: i.Severity, - Pos: i.Pos, - LineRange: i.LineRange, - Replacement: i.Replacement, - ExpectNoLint: i.ExpectNoLint, - ExpectedNoLintLinter: i.ExpectedNoLintLinter, + FromLinter: issue.FromLinter, + Text: issue.Text, + Severity: issue.Severity, + Pos: issue.Pos, + LineRange: issue.LineRange, + SuggestedFixes: issue.SuggestedFixes, + ExpectNoLint: issue.ExpectNoLint, + ExpectedNoLintLinter: issue.ExpectedNoLintLinter, }) } @@ -61,7 +57,7 @@ func saveIssuesToCache(allPkgs []*packages.Package, pkgsFromCache map[*packages. issuesCacheDebugf("Saved package %s issues (%d) to cache", pkg, len(pkgIssues)) } } - }() + }) } for _, pkg := range allPkgs { @@ -81,12 +77,12 @@ func saveIssuesToCache(allPkgs []*packages.Package, pkgsFromCache map[*packages. func loadIssuesFromCache(pkgs []*packages.Package, lintCtx *linter.Context, analyzers []*analysis.Analyzer, -) (issuesFromCache []result.Issue, pkgsFromCache map[*packages.Package]bool) { +) (issuesFromCache []*result.Issue, pkgsFromCache map[*packages.Package]bool) { startedAt := time.Now() lintResKey := getIssuesCacheKey(analyzers) type cacheRes struct { - issues []result.Issue + issues []*result.Issue loadErr error } pkgToCacheRes := make(map[*packages.Package]*cacheRes, len(pkgs)) @@ -96,14 +92,12 @@ func loadIssuesFromCache(pkgs []*packages.Package, lintCtx *linter.Context, workerCount := runtime.GOMAXPROCS(-1) var wg sync.WaitGroup - wg.Add(workerCount) pkgCh := make(chan *packages.Package, len(pkgs)) for range workerCount { - go func() { - defer wg.Done() + wg.Go(func() { for pkg := range pkgCh { - var pkgIssues []EncodingIssue + var pkgIssues []*EncodingIssue err := lintCtx.PkgCache.Get(pkg, cache.HashModeNeedAllDeps, lintResKey, &pkgIssues) cacheRes := pkgToCacheRes[pkg] cacheRes.loadErr = err @@ -114,16 +108,15 @@ func loadIssuesFromCache(pkgs []*packages.Package, lintCtx *linter.Context, continue } - issues := make([]result.Issue, 0, len(pkgIssues)) - for i := range pkgIssues { - issue := &pkgIssues[i] - issues = append(issues, result.Issue{ + issues := make([]*result.Issue, 0, len(pkgIssues)) + for _, issue := range pkgIssues { + issues = append(issues, &result.Issue{ FromLinter: issue.FromLinter, Text: issue.Text, Severity: issue.Severity, Pos: issue.Pos, LineRange: issue.LineRange, - Replacement: issue.Replacement, + SuggestedFixes: issue.SuggestedFixes, Pkg: pkg, ExpectNoLint: issue.ExpectNoLint, ExpectedNoLintLinter: issue.ExpectedNoLintLinter, @@ -131,7 +124,7 @@ func loadIssuesFromCache(pkgs []*packages.Package, lintCtx *linter.Context, } cacheRes.issues = issues } - }() + }) } for _, pkg := range pkgs { diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/goformat/runner.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformat/runner.go new file mode 100644 index 000000000..f15fd0a1a --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformat/runner.go @@ -0,0 +1,297 @@ +package goformat + +import ( + "bytes" + "context" + "fmt" + "io" + "io/fs" + "log" + "os" + "path/filepath" + "regexp" + "strings" + + "github.com/alecthomas/chroma/v2/quick" + rpdiff "github.com/rogpeppe/go-internal/diff" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/fsutils" + "github.com/golangci/golangci-lint/v2/pkg/goformatters" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result/processors" +) + +type Runner struct { + log logutils.Log + + metaFormatter *goformatters.MetaFormatter + matcher *processors.GeneratedFileMatcher + + opts RunnerOptions + + exitCode int +} + +func NewRunner(logger logutils.Log, + metaFormatter *goformatters.MetaFormatter, matcher *processors.GeneratedFileMatcher, + opts RunnerOptions) *Runner { + return &Runner{ + log: logger, + matcher: matcher, + metaFormatter: metaFormatter, + opts: opts, + } +} + +func (c *Runner) Run(paths []string) error { + savedStdout, savedStderr := os.Stdout, os.Stderr + + if !logutils.HaveDebugTag(logutils.DebugKeyFormattersOutput) { + // Don't allow linters and loader to print anything + log.SetOutput(io.Discard) + c.setOutputToDevNull() + defer func() { + os.Stdout, os.Stderr = savedStdout, savedStderr + }() + } + + if c.opts.stdin { + return c.formatStdIn("", savedStdout, os.Stdin) + } + + for _, path := range paths { + err := c.walk(path, savedStdout) + if err != nil { + return err + } + } + + for pattern, count := range c.opts.excludedPathCounter { + if c.opts.warnUnused && count == 0 { + c.log.Warnf("The pattern %q match no issues", pattern) + } else { + c.log.Infof("Skipped %d issues by pattern %q", count, pattern) + } + } + + return nil +} + +func (c *Runner) walk(root string, stdout *os.File) error { + r, err := os.OpenRoot(root) + if err != nil { + return err + } + + return filepath.Walk(root, func(path string, f fs.FileInfo, err error) error { + if err != nil { + return err + } + + if f.IsDir() && skipDir(f.Name()) { + return fs.SkipDir + } + + if !isGoFile(f) { + return nil + } + + match, err := c.opts.MatchAnyPattern(path) + if err != nil || match { + return err + } + + in, err := r.Open(path) + if err != nil { + return err + } + + defer func() { _ = in.Close() }() + + return c.process(path, stdout, in) + }) +} + +func (c *Runner) process(path string, stdout io.Writer, in io.Reader) error { + input, err := io.ReadAll(in) + if err != nil { + return err + } + + match, err := c.matcher.IsGeneratedFile(path, input) + if err != nil || match { + return err + } + + output := c.metaFormatter.Format(path, input) + + if bytes.Equal(input, output) { + return nil + } + + if c.opts.diff { + newName := filepath.ToSlash(path) + oldName := newName + ".orig" + + patch := rpdiff.Diff(oldName, input, newName, output) + + if c.opts.colors { + err = quick.Highlight(stdout, string(patch), "diff", "terminal", "native") + if err != nil { + return err + } + } else { + _, err = stdout.Write(patch) + if err != nil { + return err + } + } + + c.exitCode = 1 + + return nil + } + + c.log.Infof("format: %s", path) + + // On Windows, we need to re-set the permissions from the file. See golang/go#38225. + var perms os.FileMode + if fi, err := os.Stat(path); err == nil { + perms = fi.Mode() & os.ModePerm + } + + return os.WriteFile(path, output, perms) +} + +func (c *Runner) formatStdIn(path string, stdout io.Writer, in io.Reader) error { + input, err := io.ReadAll(in) + if err != nil { + return err + } + + match, err := c.matcher.IsGeneratedFile(path, input) + if err != nil { + return err + } + + if match { + // If the file is generated, + // the input should be written to the stdout to avoid emptied the file. + _, err = stdout.Write(input) + if err != nil { + return err + } + + return nil + } + + output := c.metaFormatter.Format(path, input) + + _, err = stdout.Write(output) + if err != nil { + return err + } + + return nil +} + +func (c *Runner) setOutputToDevNull() { + devNull, err := os.Open(os.DevNull) + if err != nil { + c.log.Warnf("Can't open null device %q: %s", os.DevNull, err) + return + } + + os.Stdout, os.Stderr = devNull, devNull +} + +func (c *Runner) ExitCode() int { + return c.exitCode +} + +type RunnerOptions struct { + basePath string + patterns []*regexp.Regexp + generated string + diff bool + colors bool + stdin bool + + warnUnused bool + excludedPathCounter map[*regexp.Regexp]int +} + +func NewRunnerOptions(cfg *config.Config, diff, diffColored, stdin bool) (RunnerOptions, error) { + basePath, err := fsutils.GetBasePath(context.Background(), cfg.Run.RelativePathMode, cfg.GetConfigDir()) + if err != nil { + return RunnerOptions{}, fmt.Errorf("get base path: %w", err) + } + + // Required to be consistent with `RunnerOptions.MatchAnyPattern`. + absBasePath, err := filepath.Abs(basePath) + if err != nil { + return RunnerOptions{}, err + } + + opts := RunnerOptions{ + basePath: absBasePath, + generated: cfg.Formatters.Exclusions.Generated, + diff: diff || diffColored, + colors: diffColored, + stdin: stdin, + excludedPathCounter: make(map[*regexp.Regexp]int), + warnUnused: cfg.Formatters.Exclusions.WarnUnused, + } + + for _, pattern := range cfg.Formatters.Exclusions.Paths { + exp, err := regexp.Compile(fsutils.NormalizePathInRegex(pattern)) + if err != nil { + return RunnerOptions{}, fmt.Errorf("compile path pattern %q: %w", pattern, err) + } + + opts.patterns = append(opts.patterns, exp) + opts.excludedPathCounter[exp] = 0 + } + + return opts, nil +} + +func (o RunnerOptions) MatchAnyPattern(path string) (bool, error) { + if len(o.patterns) == 0 { + return false, nil + } + + abs, err := filepath.Abs(path) + if err != nil { + return false, err + } + + rel, err := filepath.Rel(o.basePath, abs) + if err != nil { + return false, err + } + + for _, pattern := range o.patterns { + if pattern.MatchString(rel) { + o.excludedPathCounter[pattern]++ + return true, nil + } + } + + return false, nil +} + +func skipDir(name string) bool { + switch name { + case "vendor", "testdata", "node_modules": + return true + + default: + return strings.HasPrefix(name, ".") && name != "." + } +} + +func isGoFile(f fs.FileInfo) bool { + return !f.IsDir() && !strings.HasPrefix(f.Name(), ".") && strings.HasSuffix(f.Name(), ".go") +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/analyzer.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/analyzer.go new file mode 100644 index 000000000..d6d92d5b9 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/analyzer.go @@ -0,0 +1,55 @@ +package goformatters + +import ( + "bytes" + "fmt" + "os" + "path/filepath" + + "github.com/rogpeppe/go-internal/diff" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/goformatters/internal" + "github.com/golangci/golangci-lint/v2/pkg/logutils" +) + +// NewAnalyzer converts a [Formatter] to an [analysis.Analyzer]. +func NewAnalyzer(logger logutils.Log, doc string, formatter Formatter) *analysis.Analyzer { + return &analysis.Analyzer{ + Name: formatter.Name(), + Doc: doc, + Run: func(pass *analysis.Pass) (any, error) { + for _, file := range pass.Files { + position, isGoFile := goanalysis.GetGoFilePosition(pass, file) + if !isGoFile { + continue + } + + input, err := os.ReadFile(position.Filename) + if err != nil { + return nil, fmt.Errorf("unable to open file %s: %w", position.Filename, err) + } + + output, err := formatter.Format(position.Filename, input) + if err != nil { + return nil, fmt.Errorf("error while running %s: %w", formatter.Name(), err) + } + + if !bytes.Equal(input, output) { + newName := filepath.ToSlash(position.Filename) + oldName := newName + ".orig" + + patch := diff.Diff(oldName, input, newName, output) + + err = internal.ExtractDiagnosticFromPatch(pass, file, patch, logger) + if err != nil { + return nil, fmt.Errorf("can't extract issues from %s diff output %q: %w", formatter.Name(), patch, err) + } + } + } + + return nil, nil + }, + } +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/formatters.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/formatters.go new file mode 100644 index 000000000..c8953ad3b --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/formatters.go @@ -0,0 +1,6 @@ +package goformatters + +type Formatter interface { + Name() string + Format(filename string, src []byte) ([]byte, error) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/gci.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/gci.go new file mode 100644 index 000000000..cf1e86515 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/gci.go @@ -0,0 +1,74 @@ +package gci + +import ( + "context" + "go/format" + + gcicfg "github.com/daixiang0/gci/pkg/config" + "github.com/daixiang0/gci/pkg/gci" + "github.com/daixiang0/gci/pkg/log" + "github.com/ldez/grignotin/gomod" + + "github.com/golangci/golangci-lint/v2/pkg/config" + gcicfgi "github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/config" + "github.com/golangci/golangci-lint/v2/pkg/goformatters/internal" +) + +const Name = "gci" + +type Formatter struct { + config *gcicfg.Config +} + +func New(settings *config.GciSettings) (*Formatter, error) { + log.InitLogger() + _ = log.L().Sync() + + modPath, err := gomod.GetModulePath(context.Background()) + if err != nil { + internal.FormatterLogger.Errorf("gci: %v", err) + } + + cfg := gcicfgi.YamlConfig{ + Cfg: gcicfg.BoolConfig{ + NoInlineComments: settings.NoInlineComments, + NoPrefixComments: settings.NoPrefixComments, + CustomOrder: settings.CustomOrder, + NoLexOrder: settings.NoLexOrder, + + // Should be managed with `formatters.exclusions.generated`. + SkipGenerated: false, + }, + SectionStrings: settings.Sections, + ModPath: modPath, + } + + parsedCfg, err := cfg.Parse() + if err != nil { + return nil, err + } + + return &Formatter{config: &gcicfg.Config{ + BoolConfig: parsedCfg.BoolConfig, + Sections: parsedCfg.Sections, + SectionSeparators: parsedCfg.SectionSeparators, + }}, nil +} + +func (*Formatter) Name() string { + return Name +} + +func (f *Formatter) Format(filename string, src []byte) ([]byte, error) { + _, formatted, err := gci.LoadFormat(src, filename, *f.config) + if err != nil { + return nil, err + } + + // gci format the code only when the imports are modified, + // this produced inconsistencies. + // To be always consistent, the code should always be formatted. + // https://github.com/daixiang0/gci/blob/c4f689991095c0e54843dca76fb9c3bad58ec5c7/pkg/gci/gci.go#L148-L151 + // https://github.com/daixiang0/gci/blob/c4f689991095c0e54843dca76fb9c3bad58ec5c7/pkg/gci/gci.go#L215 + return format.Source(formatted) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/LICENSE b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/LICENSE new file mode 100644 index 000000000..e1292f738 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2020, Xiang Dai +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/config/config.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/config/config.go new file mode 100644 index 000000000..13ca6dd86 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/config/config.go @@ -0,0 +1,108 @@ +package config + +import ( + "sort" + "strings" + + "go.yaml.in/yaml/v3" + + "github.com/daixiang0/gci/pkg/config" + "github.com/daixiang0/gci/pkg/section" + + sectioni "github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/section" +) + +var defaultOrder = map[string]int{ + section.StandardType: 0, + section.DefaultType: 1, + section.CustomType: 2, + section.BlankType: 3, + section.DotType: 4, + section.AliasType: 5, + section.LocalModuleType: 6, +} + +type Config struct { + config.BoolConfig + Sections section.SectionList + SectionSeparators section.SectionList +} + +type YamlConfig struct { + Cfg config.BoolConfig `yaml:",inline"` + SectionStrings []string `yaml:"sections"` + SectionSeparatorStrings []string `yaml:"sectionseparators"` + + // Since history issue, Golangci-lint needs Analyzer to run and GCI add an Analyzer layer to integrate. + // The ModPath param is only from analyzer.go, no need to set it in all other places. + ModPath string `yaml:"-"` +} + +func (g YamlConfig) Parse() (*Config, error) { + var err error + + sections, err := sectioni.Parse(g.SectionStrings) + if err != nil { + return nil, err + } + if sections == nil { + sections = sectioni.DefaultSections() + } + if err := configureSections(sections, g.ModPath); err != nil { + return nil, err + } + + // if default order sorted sections + if !g.Cfg.CustomOrder { + sort.Slice(sections, func(i, j int) bool { + sectionI, sectionJ := sections[i].Type(), sections[j].Type() + + if g.Cfg.NoLexOrder || strings.Compare(sectionI, sectionJ) != 0 { + return defaultOrder[sectionI] < defaultOrder[sectionJ] + } + + return strings.Compare(sections[i].String(), sections[j].String()) < 0 + }) + } + + sectionSeparators, err := sectioni.Parse(g.SectionSeparatorStrings) + if err != nil { + return nil, err + } + if sectionSeparators == nil { + sectionSeparators = section.DefaultSectionSeparators() + } + + return &Config{g.Cfg, sections, sectionSeparators}, nil +} + +func ParseConfig(in string) (*Config, error) { + config := YamlConfig{} + + err := yaml.Unmarshal([]byte(in), &config) + if err != nil { + return nil, err + } + + gciCfg, err := config.Parse() + if err != nil { + return nil, err + } + + return gciCfg, nil +} + +// configureSections now only do golang module path finding. +// Since history issue, Golangci-lint needs Analyzer to run and GCI add an Analyzer layer to integrate. +// The path param is from analyzer.go, in all other places should pass empty string. +func configureSections(sections section.SectionList, path string) error { + for _, sec := range sections { + switch s := sec.(type) { + case *section.LocalModule: + if err := s.Configure(path); err != nil { + return err + } + } + } + return nil +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/section/parser.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/section/parser.go new file mode 100644 index 000000000..9662cbd1a --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/section/parser.go @@ -0,0 +1,51 @@ +package section + +import ( + "errors" + "fmt" + "strings" + + "github.com/daixiang0/gci/pkg/section" +) + +func Parse(data []string) (section.SectionList, error) { + if len(data) == 0 { + return nil, nil + } + + var list section.SectionList + var errString string + for _, d := range data { + s := strings.ToLower(d) + if len(s) == 0 { + return nil, nil + } + + if s == "default" { + list = append(list, section.Default{}) + } else if s == "standard" { + list = append(list, Standard{}) + } else if s == "newline" { + list = append(list, section.NewLine{}) + } else if strings.HasPrefix(s, "prefix(") && len(d) > 8 { + list = append(list, section.Custom{Prefix: d[7 : len(d)-1]}) + } else if strings.HasPrefix(s, "commentline(") && len(d) > 13 { + list = append(list, section.Custom{Prefix: d[12 : len(d)-1]}) + } else if s == "dot" { + list = append(list, section.Dot{}) + } else if s == "blank" { + list = append(list, section.Blank{}) + } else if s == "alias" { + list = append(list, section.Alias{}) + } else if s == "localmodule" { + // pointer because we need to mutate the section at configuration time + list = append(list, §ion.LocalModule{}) + } else { + errString += fmt.Sprintf(" %s", s) + } + } + if errString != "" { + return nil, errors.New(fmt.Sprintf("invalid params:%s", errString)) + } + return list, nil +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/section/section.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/section/section.go new file mode 100644 index 000000000..e9c663222 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/section/section.go @@ -0,0 +1,7 @@ +package section + +import "github.com/daixiang0/gci/pkg/section" + +func DefaultSections() section.SectionList { + return section.SectionList{Standard{}, section.Default{}} +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/section/standard.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/section/standard.go new file mode 100644 index 000000000..26c7e9dc7 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/section/standard.go @@ -0,0 +1,30 @@ +package section + +import ( + "github.com/daixiang0/gci/pkg/parse" + "github.com/daixiang0/gci/pkg/specificity" +) + +const StandardType = "standard" + +type Standard struct{} + +func (s Standard) MatchSpecificity(spec *parse.GciImports) specificity.MatchSpecificity { + if isStandard(spec.Path) { + return specificity.StandardMatch{} + } + return specificity.MisMatch{} +} + +func (s Standard) String() string { + return StandardType +} + +func (s Standard) Type() string { + return StandardType +} + +func isStandard(pkg string) bool { + _, ok := standardPackages[pkg] + return ok +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/section/standard_list.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/section/standard_list.go new file mode 100644 index 000000000..a7787409e --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gci/internal/section/standard_list.go @@ -0,0 +1,189 @@ +package section + +// Code generated based on go1.26.0 X:boringcrypto,arenas,jsonv2,runtimesecret. DO NOT EDIT. + +var standardPackages = map[string]struct{}{ + "archive/tar": {}, + "archive/zip": {}, + "arena": {}, + "bufio": {}, + "bytes": {}, + "cmp": {}, + "compress/bzip2": {}, + "compress/flate": {}, + "compress/gzip": {}, + "compress/lzw": {}, + "compress/zlib": {}, + "container/heap": {}, + "container/list": {}, + "container/ring": {}, + "context": {}, + "crypto": {}, + "crypto/aes": {}, + "crypto/boring": {}, + "crypto/cipher": {}, + "crypto/des": {}, + "crypto/dsa": {}, + "crypto/ecdh": {}, + "crypto/ecdsa": {}, + "crypto/ed25519": {}, + "crypto/elliptic": {}, + "crypto/fips140": {}, + "crypto/hkdf": {}, + "crypto/hmac": {}, + "crypto/hpke": {}, + "crypto/md5": {}, + "crypto/mlkem": {}, + "crypto/mlkem/mlkemtest": {}, + "crypto/pbkdf2": {}, + "crypto/rand": {}, + "crypto/rc4": {}, + "crypto/rsa": {}, + "crypto/sha1": {}, + "crypto/sha256": {}, + "crypto/sha3": {}, + "crypto/sha512": {}, + "crypto/subtle": {}, + "crypto/tls": {}, + "crypto/tls/fipsonly": {}, + "crypto/x509": {}, + "crypto/x509/pkix": {}, + "database/sql": {}, + "database/sql/driver": {}, + "debug/buildinfo": {}, + "debug/dwarf": {}, + "debug/elf": {}, + "debug/gosym": {}, + "debug/macho": {}, + "debug/pe": {}, + "debug/plan9obj": {}, + "embed": {}, + "encoding": {}, + "encoding/ascii85": {}, + "encoding/asn1": {}, + "encoding/base32": {}, + "encoding/base64": {}, + "encoding/binary": {}, + "encoding/csv": {}, + "encoding/gob": {}, + "encoding/hex": {}, + "encoding/json": {}, + "encoding/json/jsontext": {}, + "encoding/json/v2": {}, + "encoding/pem": {}, + "encoding/xml": {}, + "errors": {}, + "expvar": {}, + "flag": {}, + "fmt": {}, + "go/ast": {}, + "go/build": {}, + "go/build/constraint": {}, + "go/constant": {}, + "go/doc": {}, + "go/doc/comment": {}, + "go/format": {}, + "go/importer": {}, + "go/parser": {}, + "go/printer": {}, + "go/scanner": {}, + "go/token": {}, + "go/types": {}, + "go/version": {}, + "hash": {}, + "hash/adler32": {}, + "hash/crc32": {}, + "hash/crc64": {}, + "hash/fnv": {}, + "hash/maphash": {}, + "html": {}, + "html/template": {}, + "image": {}, + "image/color": {}, + "image/color/palette": {}, + "image/draw": {}, + "image/gif": {}, + "image/jpeg": {}, + "image/png": {}, + "index/suffixarray": {}, + "io": {}, + "io/fs": {}, + "io/ioutil": {}, + "iter": {}, + "log": {}, + "log/slog": {}, + "log/syslog": {}, + "maps": {}, + "math": {}, + "math/big": {}, + "math/bits": {}, + "math/cmplx": {}, + "math/rand": {}, + "math/rand/v2": {}, + "mime": {}, + "mime/multipart": {}, + "mime/quotedprintable": {}, + "net": {}, + "net/http": {}, + "net/http/cgi": {}, + "net/http/cookiejar": {}, + "net/http/fcgi": {}, + "net/http/httptest": {}, + "net/http/httptrace": {}, + "net/http/httputil": {}, + "net/http/pprof": {}, + "net/mail": {}, + "net/netip": {}, + "net/rpc": {}, + "net/rpc/jsonrpc": {}, + "net/smtp": {}, + "net/textproto": {}, + "net/url": {}, + "os": {}, + "os/exec": {}, + "os/signal": {}, + "os/user": {}, + "path": {}, + "path/filepath": {}, + "plugin": {}, + "reflect": {}, + "regexp": {}, + "regexp/syntax": {}, + "runtime": {}, + "runtime/cgo": {}, + "runtime/coverage": {}, + "runtime/debug": {}, + "runtime/metrics": {}, + "runtime/pprof": {}, + "runtime/race": {}, + "runtime/secret": {}, + "runtime/trace": {}, + "slices": {}, + "sort": {}, + "strconv": {}, + "strings": {}, + "structs": {}, + "sync": {}, + "sync/atomic": {}, + "syscall": {}, + "syscall/js": {}, + "testing": {}, + "testing/cryptotest": {}, + "testing/fstest": {}, + "testing/iotest": {}, + "testing/quick": {}, + "testing/slogtest": {}, + "testing/synctest": {}, + "text/scanner": {}, + "text/tabwriter": {}, + "text/template": {}, + "text/template/parse": {}, + "time": {}, + "time/tzdata": {}, + "unicode": {}, + "unicode/utf16": {}, + "unicode/utf8": {}, + "unique": {}, + "unsafe": {}, + "weak": {}, +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gofmt/gofmt.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gofmt/gofmt.go new file mode 100644 index 000000000..4d5ff8632 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gofmt/gofmt.go @@ -0,0 +1,35 @@ +package gofmt + +import ( + "github.com/golangci/gofmt/gofmt" + + "github.com/golangci/golangci-lint/v2/pkg/config" +) + +const Name = "gofmt" + +type Formatter struct { + options gofmt.Options +} + +func New(settings *config.GoFmtSettings) *Formatter { + options := gofmt.Options{} + + if settings != nil { + options.NeedSimplify = settings.Simplify + + for _, rule := range settings.RewriteRules { + options.RewriteRules = append(options.RewriteRules, gofmt.RewriteRule(rule)) + } + } + + return &Formatter{options: options} +} + +func (*Formatter) Name() string { + return Name +} + +func (f *Formatter) Format(filename string, src []byte) ([]byte, error) { + return gofmt.Source(filename, src, f.options) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gofumpt/gofumpt.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gofumpt/gofumpt.go new file mode 100644 index 000000000..d8f5f2f73 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/gofumpt/gofumpt.go @@ -0,0 +1,41 @@ +package gofumpt + +import ( + "strings" + + gofumpt "mvdan.cc/gofumpt/format" + + "github.com/golangci/golangci-lint/v2/pkg/config" +) + +const Name = "gofumpt" + +type Formatter struct { + options gofumpt.Options +} + +func New(settings *config.GoFumptSettings, goVersion string) *Formatter { + var options gofumpt.Options + + if settings != nil { + options = gofumpt.Options{ + LangVersion: getLangVersion(goVersion), + ModulePath: settings.ModulePath, + ExtraRules: settings.ExtraRules, + } + } + + return &Formatter{options: options} +} + +func (*Formatter) Name() string { + return Name +} + +func (f *Formatter) Format(_ string, src []byte) ([]byte, error) { + return gofumpt.Source(src, f.options) +} + +func getLangVersion(v string) string { + return "go" + strings.TrimPrefix(v, "go") +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/goimports/goimports.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/goimports/goimports.go new file mode 100644 index 000000000..5b7edf2e4 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/goimports/goimports.go @@ -0,0 +1,30 @@ +package goimports + +import ( + "strings" + + "golang.org/x/tools/imports" + + "github.com/golangci/golangci-lint/v2/pkg/config" +) + +const Name = "goimports" + +type Formatter struct{} + +func New(settings *config.GoImportsSettings) *Formatter { + if settings != nil { + imports.LocalPrefix = strings.Join(settings.LocalPrefixes, ",") + } + + return &Formatter{} +} + +func (*Formatter) Name() string { + return Name +} + +func (*Formatter) Format(filename string, src []byte) ([]byte, error) { + // The `imports.LocalPrefix` (`settings.LocalPrefixes`) is a global var. + return imports.Process(filename, src, nil) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/golines/golines.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/golines/golines.go new file mode 100644 index 000000000..7c054866d --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/golines/golines.go @@ -0,0 +1,39 @@ +package golines + +import ( + "github.com/golangci/golines/shorten" + + "github.com/golangci/golangci-lint/v2/pkg/config" +) + +const Name = "golines" + +type Formatter struct { + shortener *shorten.Shortener +} + +func New(settings *config.GoLinesSettings) *Formatter { + cfg := &shorten.Config{} + + if settings != nil { + cfg = &shorten.Config{ + MaxLen: settings.MaxLen, + TabLen: settings.TabLen, + KeepAnnotations: false, // golines debug (not usable inside golangci-lint) + ShortenComments: settings.ShortenComments, + ReformatTags: settings.ReformatTags, + DotFile: "", // golines debug (not usable inside golangci-lint) + ChainSplitDots: settings.ChainSplitDots, + } + } + + return &Formatter{shortener: shorten.NewShortener(cfg)} +} + +func (*Formatter) Name() string { + return Name +} + +func (f *Formatter) Format(_ string, src []byte) ([]byte, error) { + return f.shortener.Process(src) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/internal/commons.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/internal/commons.go new file mode 100644 index 000000000..f18819e2f --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/internal/commons.go @@ -0,0 +1,6 @@ +package internal + +import "github.com/golangci/golangci-lint/v2/pkg/logutils" + +// FormatterLogger must be used only when the context logger is not available. +var FormatterLogger = logutils.NewStderrLog(logutils.DebugKeyFormatter) diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/internal/diff.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/internal/diff.go new file mode 100644 index 000000000..fcec87bb8 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/internal/diff.go @@ -0,0 +1,271 @@ +package internal + +import ( + "bytes" + "fmt" + "go/ast" + "go/token" + "slices" + "strings" + + diffpkg "github.com/sourcegraph/go-diff/diff" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/logutils" +) + +type Change struct { + From, To int + NewLines []string +} + +type diffLineType string + +const ( + diffLineAdded diffLineType = "added" + diffLineOriginal diffLineType = "original" + diffLineDeleted diffLineType = "deleted" +) + +type diffLine struct { + originalNumber int // 1-based original line number + typ diffLineType + data string // "+" or "-" stripped line +} + +type hunkChangesParser struct { + // needed because we merge currently added lines with the last original line + lastOriginalLine *diffLine + + // if the first line of diff is an adding we save all additions to replacementLinesToPrepend + replacementLinesToPrepend []string + + log logutils.Log + + changes []Change +} + +func (p *hunkChangesParser) parse(h *diffpkg.Hunk) []Change { + lines := parseDiffLines(h) + + for i := 0; i < len(lines); { + line := lines[i] + + if line.typ == diffLineOriginal { + p.handleOriginalLine(lines, line, &i) + continue + } + + var deletedLines []diffLine + for ; i < len(lines) && lines[i].typ == diffLineDeleted; i++ { + deletedLines = append(deletedLines, lines[i]) + } + + var addedLines []string + for ; i < len(lines) && lines[i].typ == diffLineAdded; i++ { + addedLines = append(addedLines, lines[i].data) + } + + if len(deletedLines) != 0 { + p.handleDeletedLines(deletedLines, addedLines) + continue + } + + // no deletions, only additions + p.handleAddedOnlyLines(addedLines) + } + + if len(p.replacementLinesToPrepend) != 0 { + p.log.Infof("The diff contains only additions: no original or deleted lines: %#v", lines) + return nil + } + + return p.changes +} + +func (p *hunkChangesParser) handleOriginalLine(lines []diffLine, line diffLine, i *int) { + if len(p.replacementLinesToPrepend) == 0 { + p.lastOriginalLine = &line + *i++ + return + } + + // check following added lines for the case: + // + added line 1 + // original line + // + added line 2 + + *i++ + var followingAddedLines []string + for ; *i < len(lines) && lines[*i].typ == diffLineAdded; *i++ { + followingAddedLines = append(followingAddedLines, lines[*i].data) + } + + change := Change{ + From: line.originalNumber, + To: line.originalNumber, + NewLines: slices.Concat(p.replacementLinesToPrepend, []string{line.data}, followingAddedLines), + } + p.changes = append(p.changes, change) + + p.replacementLinesToPrepend = nil + p.lastOriginalLine = &line +} + +func (p *hunkChangesParser) handleDeletedLines(deletedLines []diffLine, addedLines []string) { + change := Change{ + From: deletedLines[0].originalNumber, + To: deletedLines[len(deletedLines)-1].originalNumber, + } + + switch { + case len(addedLines) != 0: + change.NewLines = slices.Concat(p.replacementLinesToPrepend, addedLines) + p.replacementLinesToPrepend = nil + + case len(p.replacementLinesToPrepend) != 0: + // delete-only change with possible prepending + change.NewLines = slices.Clone(p.replacementLinesToPrepend) + p.replacementLinesToPrepend = nil + } + + p.changes = append(p.changes, change) +} + +func (p *hunkChangesParser) handleAddedOnlyLines(addedLines []string) { + if p.lastOriginalLine == nil { + // the first line is added; the diff looks like: + // 1. + ... + // 2. - ... + // or + // 1. + ... + // 2. ... + + p.replacementLinesToPrepend = addedLines + + return + } + + // add-only change merged into the last original line with possible prepending + change := Change{ + From: p.lastOriginalLine.originalNumber, + To: p.lastOriginalLine.originalNumber, + NewLines: slices.Concat(p.replacementLinesToPrepend, []string{p.lastOriginalLine.data}, addedLines), + } + + p.changes = append(p.changes, change) + + p.replacementLinesToPrepend = nil +} + +func parseDiffLines(h *diffpkg.Hunk) []diffLine { + lines := bytes.Split(h.Body, []byte{'\n'}) + + currentOriginalLineNumber := int(h.OrigStartLine) + + var diffLines []diffLine + + for i, line := range lines { + dl := diffLine{ + originalNumber: currentOriginalLineNumber, + } + + if i == len(lines)-1 && len(line) == 0 { + // handle last \n: don't add an empty original line + break + } + + lineStr := string(line) + + switch { + case strings.HasPrefix(lineStr, "-"): + dl.typ = diffLineDeleted + dl.data = strings.TrimPrefix(lineStr, "-") + currentOriginalLineNumber++ + + case strings.HasPrefix(lineStr, "+"): + dl.typ = diffLineAdded + dl.data = strings.TrimPrefix(lineStr, "+") + + default: + dl.typ = diffLineOriginal + dl.data = strings.TrimPrefix(lineStr, " ") + currentOriginalLineNumber++ + } + + diffLines = append(diffLines, dl) + } + + // if > 0, then the original file had a 'No newline at end of file' mark + if h.OrigNoNewlineAt > 0 { + dl := diffLine{ + originalNumber: currentOriginalLineNumber + 1, + typ: diffLineAdded, + data: "", + } + diffLines = append(diffLines, dl) + } + + return diffLines +} + +func ExtractDiagnosticFromPatch( + pass *analysis.Pass, + file *ast.File, + patch []byte, + logger logutils.Log, +) error { + diffs, err := diffpkg.ParseMultiFileDiff(patch) + if err != nil { + return fmt.Errorf("can't parse patch: %w", err) + } + + if len(diffs) == 0 { + return fmt.Errorf("got no diffs from patch parser: %s", patch) + } + + ft := pass.Fset.File(file.Pos()) + + adjLine := pass.Fset.PositionFor(file.Pos(), false).Line - pass.Fset.PositionFor(file.Pos(), true).Line + + for _, d := range diffs { + if len(d.Hunks) == 0 { + logger.Warnf("Got no hunks in diff %+v", d) + continue + } + + for _, hunk := range d.Hunks { + p := hunkChangesParser{log: logger} + + changes := p.parse(hunk) + + for _, change := range changes { + pass.Report(toDiagnostic(ft, change, adjLine)) + } + } + } + + return nil +} + +func toDiagnostic(ft *token.File, change Change, adjLine int) analysis.Diagnostic { + from := min(change.From+adjLine, ft.LineCount()) + + start := ft.LineStart(from) + + end := goanalysis.EndOfLinePos(ft, change.To+adjLine) + + return analysis.Diagnostic{ + Pos: start, + End: end, + Message: "File is not properly formatted", + SuggestedFixes: []analysis.SuggestedFix{{ + TextEdits: []analysis.TextEdit{{ + Pos: start, + End: end, + NewText: []byte(strings.Join(change.NewLines, "\n")), + }}, + }}, + } +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/meta_formatter.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/meta_formatter.go new file mode 100644 index 000000000..dbedcd4cb --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/meta_formatter.go @@ -0,0 +1,95 @@ +package goformatters + +import ( + "bytes" + "fmt" + "go/format" + "slices" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goformatters/gci" + "github.com/golangci/golangci-lint/v2/pkg/goformatters/gofmt" + "github.com/golangci/golangci-lint/v2/pkg/goformatters/gofumpt" + "github.com/golangci/golangci-lint/v2/pkg/goformatters/goimports" + "github.com/golangci/golangci-lint/v2/pkg/goformatters/golines" + "github.com/golangci/golangci-lint/v2/pkg/goformatters/swaggo" + "github.com/golangci/golangci-lint/v2/pkg/logutils" +) + +type MetaFormatter struct { + log logutils.Log + formatters []Formatter +} + +func NewMetaFormatter(log logutils.Log, cfg *config.Formatters, runCfg *config.Run) (*MetaFormatter, error) { + for _, formatter := range cfg.Enable { + if !IsFormatter(formatter) { + return nil, fmt.Errorf("invalid formatter %q", formatter) + } + } + + m := &MetaFormatter{log: log} + + if slices.Contains(cfg.Enable, gofmt.Name) { + m.formatters = append(m.formatters, gofmt.New(&cfg.Settings.GoFmt)) + } + + if slices.Contains(cfg.Enable, gofumpt.Name) { + m.formatters = append(m.formatters, gofumpt.New(&cfg.Settings.GoFumpt, runCfg.Go)) + } + + if slices.Contains(cfg.Enable, goimports.Name) { + m.formatters = append(m.formatters, goimports.New(&cfg.Settings.GoImports)) + } + + if slices.Contains(cfg.Enable, swaggo.Name) { + m.formatters = append(m.formatters, swaggo.New()) + } + + // gci is a last because the only goal of gci is to handle imports. + if slices.Contains(cfg.Enable, gci.Name) { + formatter, err := gci.New(&cfg.Settings.Gci) + if err != nil { + return nil, fmt.Errorf("gci: creating formatter: %w", err) + } + + m.formatters = append(m.formatters, formatter) + } + + // golines calls `format.Source()` internally so no need to format after it. + if slices.Contains(cfg.Enable, golines.Name) { + m.formatters = append(m.formatters, golines.New(&cfg.Settings.GoLines)) + } + + return m, nil +} + +func (m *MetaFormatter) Format(filename string, src []byte) []byte { + if len(m.formatters) == 0 { + data, err := format.Source(src) + if err != nil { + m.log.Warnf("(fmt) formatting file %s: %v", filename, err) + return src + } + + return data + } + + data := bytes.Clone(src) + + for _, formatter := range m.formatters { + formatted, err := formatter.Format(filename, data) + if err != nil { + m.log.Warnf("(%s) formatting file %s: %v", formatter.Name(), filename, err) + continue + } + + data = formatted + } + + return data +} + +func IsFormatter(name string) bool { + return slices.Contains([]string{gofmt.Name, gofumpt.Name, goimports.Name, gci.Name, golines.Name, swaggo.Name}, name) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/swaggo/swaggo.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/swaggo/swaggo.go new file mode 100644 index 000000000..2479fb35b --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goformatters/swaggo/swaggo.go @@ -0,0 +1,23 @@ +package swaggo + +import "github.com/golangci/swaggoswag" + +const Name = "swaggo" + +type Formatter struct { + formatter *swaggoswag.Formatter +} + +func New() *Formatter { + return &Formatter{ + formatter: swaggoswag.NewFormatter(), + } +} + +func (*Formatter) Name() string { + return Name +} + +func (f *Formatter) Format(path string, src []byte) ([]byte, error) { + return f.formatter.Format(path, src) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/arangolint/arangolint.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/arangolint/arangolint.go new file mode 100644 index 000000000..1598d532a --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/arangolint/arangolint.go @@ -0,0 +1,13 @@ +package arangolint + +import ( + "go.augendre.info/arangolint/pkg/analyzer" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(analyzer.NewAnalyzer()). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/asasalint/asasalint.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/asasalint/asasalint.go new file mode 100644 index 000000000..0261e109d --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/asasalint/asasalint.go @@ -0,0 +1,29 @@ +package asasalint + +import ( + "github.com/alingse/asasalint" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" +) + +func New(settings *config.AsasalintSettings) *goanalysis.Linter { + cfg := asasalint.LinterSetting{} + if settings != nil { + cfg.Exclude = settings.Exclude + cfg.NoBuiltinExclusions = !settings.UseBuiltinExclusions + + // Should be managed with `linters.exclusions.rules`. + cfg.IgnoreTest = false + } + + analyzer, err := asasalint.NewAnalyzer(cfg) + if err != nil { + internal.LinterLogger.Fatalf("asasalint: create analyzer: %v", err) + } + + return goanalysis. + NewLinterFromAnalyzer(analyzer). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/asciicheck/asciicheck.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/asciicheck/asciicheck.go new file mode 100644 index 000000000..6a34b256a --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/asciicheck/asciicheck.go @@ -0,0 +1,13 @@ +package asciicheck + +import ( + "github.com/golangci/asciicheck" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(asciicheck.NewAnalyzer()). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/bidichk/bidichk.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/bidichk/bidichk.go new file mode 100644 index 000000000..c35daafbf --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/bidichk/bidichk.go @@ -0,0 +1,55 @@ +package bidichk + +import ( + "strings" + + "github.com/breml/bidichk/pkg/bidichk" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.BiDiChkSettings) *goanalysis.Linter { + var cfg map[string]any + + if settings != nil { + var opts []string + + if settings.LeftToRightEmbedding { + opts = append(opts, "LEFT-TO-RIGHT-EMBEDDING") + } + if settings.RightToLeftEmbedding { + opts = append(opts, "RIGHT-TO-LEFT-EMBEDDING") + } + if settings.PopDirectionalFormatting { + opts = append(opts, "POP-DIRECTIONAL-FORMATTING") + } + if settings.LeftToRightOverride { + opts = append(opts, "LEFT-TO-RIGHT-OVERRIDE") + } + if settings.RightToLeftOverride { + opts = append(opts, "RIGHT-TO-LEFT-OVERRIDE") + } + if settings.LeftToRightIsolate { + opts = append(opts, "LEFT-TO-RIGHT-ISOLATE") + } + if settings.RightToLeftIsolate { + opts = append(opts, "RIGHT-TO-LEFT-ISOLATE") + } + if settings.FirstStrongIsolate { + opts = append(opts, "FIRST-STRONG-ISOLATE") + } + if settings.PopDirectionalIsolate { + opts = append(opts, "POP-DIRECTIONAL-ISOLATE") + } + + cfg = map[string]any{ + "disallowed-runes": strings.Join(opts, ","), + } + } + + return goanalysis. + NewLinterFromAnalyzer(bidichk.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/bodyclose/bodyclose.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/bodyclose/bodyclose.go new file mode 100644 index 000000000..f68c4d0a9 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/bodyclose/bodyclose.go @@ -0,0 +1,13 @@ +package bodyclose + +import ( + "github.com/timakin/bodyclose/passes/bodyclose" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(bodyclose.Analyzer). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/canonicalheader/canonicalheader.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/canonicalheader/canonicalheader.go new file mode 100644 index 000000000..24e95f143 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/canonicalheader/canonicalheader.go @@ -0,0 +1,13 @@ +package canonicalheader + +import ( + "github.com/lasiar/canonicalheader" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(canonicalheader.Analyzer). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/containedctx/containedctx.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/containedctx/containedctx.go new file mode 100644 index 000000000..6d17b8e46 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/containedctx/containedctx.go @@ -0,0 +1,13 @@ +package containedctx + +import ( + "github.com/sivchari/containedctx" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(containedctx.Analyzer). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/contextcheck/contextcheck.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/contextcheck/contextcheck.go new file mode 100644 index 000000000..b01df7d98 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/contextcheck/contextcheck.go @@ -0,0 +1,26 @@ +package contextcheck + +import ( + "github.com/kkHAIKE/contextcheck" + "golang.org/x/tools/go/analysis/passes/ctrlflow" + "golang.org/x/tools/go/analysis/passes/inspect" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" +) + +func New() *goanalysis.Linter { + analyzer := contextcheck.NewAnalyzer(contextcheck.Configuration{}) + // TODO(ldez) there is a problem with this linter: + // I think the problem related to facts. + // The BuildSSA pass has been changed inside (0.39.0): + // https://github.com/golang/tools/commit/b74c09864920a69a4d2f6ef0ecb4f9cff226893a + analyzer.Requires = append(analyzer.Requires, ctrlflow.Analyzer, inspect.Analyzer) + + return goanalysis. + NewLinterFromAnalyzer(analyzer). + WithContextSetter(func(lintCtx *linter.Context) { + analyzer.Run = contextcheck.NewRun(lintCtx.Packages, false) + }). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/copyloopvar/copyloopvar.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/copyloopvar/copyloopvar.go new file mode 100644 index 000000000..9dc81de58 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/copyloopvar/copyloopvar.go @@ -0,0 +1,23 @@ +package copyloopvar + +import ( + "github.com/karamaru-alpha/copyloopvar" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.CopyLoopVarSettings) *goanalysis.Linter { + var cfg map[string]any + + if settings != nil { + cfg = map[string]any{ + "check-alias": settings.CheckAlias, + } + } + + return goanalysis. + NewLinterFromAnalyzer(copyloopvar.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/cyclop/cyclop.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/cyclop/cyclop.go new file mode 100644 index 000000000..0a0e2dbc6 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/cyclop/cyclop.go @@ -0,0 +1,30 @@ +package cyclop + +import ( + "github.com/bkielbasa/cyclop/pkg/analyzer" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.CyclopSettings) *goanalysis.Linter { + cfg := map[string]any{} + + if settings != nil { + // Should be managed with `linters.exclusions.rules`. + cfg["skipTests"] = false + + if settings.MaxComplexity != 0 { + cfg["maxComplexity"] = settings.MaxComplexity + } + + if settings.PackageAverage != 0 { + cfg["packageAverage"] = settings.PackageAverage + } + } + + return goanalysis. + NewLinterFromAnalyzer(analyzer.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/decorder/decorder.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/decorder/decorder.go similarity index 76% rename from vendor/github.com/golangci/golangci-lint/pkg/golinters/decorder/decorder.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/decorder/decorder.go index a05f6a325..a67bdfade 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/decorder/decorder.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/decorder/decorder.go @@ -4,15 +4,12 @@ import ( "strings" "gitlab.com/bosi/decorder" - "golang.org/x/tools/go/analysis" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.DecorderSettings) *goanalysis.Linter { - a := decorder.Analyzer - // disable all rules/checks by default cfg := map[string]any{ "ignore-underscore-vars": false, @@ -35,10 +32,8 @@ func New(settings *config.DecorderSettings) *goanalysis.Linter { cfg["disable-init-func-first-check"] = settings.DisableInitFuncFirstCheck } - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - map[string]map[string]any{a.Name: cfg}, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(decorder.Analyzer). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/depguard/depguard.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/depguard/depguard.go new file mode 100644 index 000000000..cc01f4f47 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/depguard/depguard.go @@ -0,0 +1,54 @@ +package depguard + +import ( + "strings" + + "github.com/OpenPeeDeeP/depguard/v2" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" +) + +func New(settings *config.DepGuardSettings, replacer *strings.Replacer) *goanalysis.Linter { + conf := depguard.LinterSettings{} + + if settings != nil { + for s, rule := range settings.Rules { + var extendedPatterns []string + for _, file := range rule.Files { + extendedPatterns = append(extendedPatterns, replacer.Replace(file)) + } + + list := &depguard.List{ + ListMode: rule.ListMode, + Files: extendedPatterns, + Allow: rule.Allow, + } + + // because of bug with Viper parsing (split on dot) we use a list of struct instead of a map. + // https://github.com/spf13/viper/issues/324 + // https://github.com/golangci/golangci-lint/issues/3749#issuecomment-1492536630 + + deny := map[string]string{} + for _, r := range rule.Deny { + deny[r.Pkg] = r.Desc + } + list.Deny = deny + + conf[s] = list + } + } + + analyzer := depguard.NewUncompiledAnalyzer(&conf) + + return goanalysis. + NewLinterFromAnalyzer(analyzer.Analyzer). + WithContextSetter(func(lintCtx *linter.Context) { + err := analyzer.Compile() + if err != nil { + lintCtx.Log.Errorf("create analyzer: %v", err) + } + }). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/dogsled/dogsled.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/dogsled/dogsled.go new file mode 100644 index 000000000..5516d2b39 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/dogsled/dogsled.go @@ -0,0 +1,67 @@ +package dogsled + +import ( + "go/ast" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/ast/inspector" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.DogsledSettings) *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: "dogsled", + Doc: "Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f())", + Run: func(pass *analysis.Pass) (any, error) { + return run(pass, settings.MaxBlankIdentifiers) + }, + Requires: []*analysis.Analyzer{inspect.Analyzer}, + }). + WithLoadMode(goanalysis.LoadModeSyntax) +} + +func run(pass *analysis.Pass, maxBlanks int) (any, error) { + insp, ok := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + if !ok { + return nil, nil + } + + for node := range insp.PreorderSeq((*ast.FuncDecl)(nil)) { + funcDecl, ok := node.(*ast.FuncDecl) + if !ok { + continue + } + + if funcDecl.Body == nil { + continue + } + + for _, expr := range funcDecl.Body.List { + assgnStmt, ok := expr.(*ast.AssignStmt) + if !ok { + continue + } + + numBlank := 0 + for _, left := range assgnStmt.Lhs { + ident, ok := left.(*ast.Ident) + if !ok { + continue + } + if ident.Name == "_" { + numBlank++ + } + } + + if numBlank > maxBlanks { + pass.Reportf(assgnStmt.Pos(), "declaration has %v blank identifiers", numBlank) + } + } + } + + return nil, nil +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/dupl/dupl.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/dupl/dupl.go new file mode 100644 index 000000000..0b6b3a162 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/dupl/dupl.go @@ -0,0 +1,90 @@ +package dupl + +import ( + "fmt" + "go/token" + "sync" + + duplAPI "github.com/golangci/dupl/lib" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/fsutils" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/result" +) + +const linterName = "dupl" + +func New(settings *config.DuplSettings) *goanalysis.Linter { + var mu sync.Mutex + var resIssues []*goanalysis.Issue + + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: linterName, + Doc: "Detects duplicate fragments of code.", + Run: func(pass *analysis.Pass) (any, error) { + issues, err := runDupl(pass, settings) + if err != nil { + return nil, err + } + + if len(issues) == 0 { + return nil, nil + } + + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() + + return nil, nil + }, + }). + WithIssuesReporter(func(*linter.Context) []*goanalysis.Issue { + return resIssues + }). + WithLoadMode(goanalysis.LoadModeSyntax) +} + +func runDupl(pass *analysis.Pass, settings *config.DuplSettings) ([]*goanalysis.Issue, error) { + issues, err := duplAPI.Run(internal.GetGoFileNames(pass), settings.Threshold) + if err != nil { + return nil, err + } + + if len(issues) == 0 { + return nil, nil + } + + res := make([]*goanalysis.Issue, 0, len(issues)) + + for _, i := range issues { + toFilename, err := fsutils.ShortestRelPath(i.To.Filename(), "") + if err != nil { + return nil, fmt.Errorf("failed to get shortest rel path for %q: %w", i.To.Filename(), err) + } + + dupl := fmt.Sprintf("%s:%d-%d", toFilename, i.To.LineStart(), i.To.LineEnd()) + text := fmt.Sprintf("%d-%d lines are duplicate of %s", + i.From.LineStart(), i.From.LineEnd(), + internal.FormatCode(dupl)) + + res = append(res, goanalysis.NewIssue(&result.Issue{ + Pos: token.Position{ + Filename: i.From.Filename(), + Line: i.From.LineStart(), + }, + LineRange: &result.Range{ + From: i.From.LineStart(), + To: i.From.LineEnd(), + }, + Text: text, + FromLinter: linterName, + }, pass)) + } + + return res, nil +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/dupword/dupword.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/dupword/dupword.go new file mode 100644 index 000000000..0308534e3 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/dupword/dupword.go @@ -0,0 +1,28 @@ +package dupword + +import ( + "strings" + + "github.com/Abirdcfly/dupword" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.DupWordSettings) *goanalysis.Linter { + var cfg map[string]any + + if settings != nil { + cfg = map[string]any{ + "keyword": strings.Join(settings.Keywords, ","), + "ignore": strings.Join(settings.Ignore, ","), + "comments-only": settings.CommentsOnly, + } + } + + return goanalysis. + NewLinterFromAnalyzer(dupword.NewAnalyzer()). + WithDesc("Checks for duplicate words in the source code"). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/durationcheck/durationcheck.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/durationcheck/durationcheck.go new file mode 100644 index 000000000..b6723fa12 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/durationcheck/durationcheck.go @@ -0,0 +1,13 @@ +package durationcheck + +import ( + "github.com/charithe/durationcheck" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(durationcheck.Analyzer). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/embeddedstructfieldcheck/embeddedstructfieldcheck.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/embeddedstructfieldcheck/embeddedstructfieldcheck.go new file mode 100644 index 000000000..ba4c06eb7 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/embeddedstructfieldcheck/embeddedstructfieldcheck.go @@ -0,0 +1,24 @@ +package embeddedstructfieldcheck + +import ( + "github.com/manuelarte/embeddedstructfieldcheck/analyzer" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.EmbeddedStructFieldCheckSettings) *goanalysis.Linter { + var cfg map[string]any + + if settings != nil { + cfg = map[string]any{ + analyzer.ForbidMutexCheck: settings.ForbidMutex, + analyzer.EmptyLineCheck: settings.EmptyLine, + } + } + + return goanalysis. + NewLinterFromAnalyzer(analyzer.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/err113/err113.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/err113/err113.go new file mode 100644 index 000000000..d3b3a4c1c --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/err113/err113.go @@ -0,0 +1,14 @@ +package err113 + +import ( + "github.com/Djarvur/go-err113" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(err113.NewAnalyzer()). + WithDesc("Check errors handling expressions"). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/errcheck/errcheck.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/errcheck/errcheck.go new file mode 100644 index 000000000..6bd473845 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/errcheck/errcheck.go @@ -0,0 +1,115 @@ +package errcheck + +import ( + "cmp" + "fmt" + "regexp" + "sync" + + "github.com/kisielk/errcheck/errcheck" + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/packages" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/result" +) + +const linterName = "errcheck" + +func New(settings *config.ErrcheckSettings) *goanalysis.Linter { + var mu sync.Mutex + var resIssues []*goanalysis.Issue + + analyzer := &analysis.Analyzer{ + Name: linterName, + Doc: "errcheck is a program for checking for unchecked errors in Go code. " + + "These unchecked errors can be critical bugs in some cases", + Run: goanalysis.DummyRun, + } + + return goanalysis. + NewLinterFromAnalyzer(analyzer). + WithContextSetter(func(lintCtx *linter.Context) { + checker := getChecker(settings) + checker.Tags = lintCtx.Cfg.Run.BuildTags + + analyzer.Run = func(pass *analysis.Pass) (any, error) { + issues := runErrCheck(pass, checker, settings.Verbose) + + if len(issues) == 0 { + return nil, nil + } + + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() + + return nil, nil + } + }). + WithIssuesReporter(func(*linter.Context) []*goanalysis.Issue { + return resIssues + }). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} + +func runErrCheck(pass *analysis.Pass, checker *errcheck.Checker, verbose bool) []*goanalysis.Issue { + pkg := &packages.Package{ + Fset: pass.Fset, + Syntax: pass.Files, + Types: pass.Pkg, + TypesInfo: pass.TypesInfo, + } + + lintIssues := checker.CheckPackage(pkg).Unique() + if len(lintIssues.UncheckedErrors) == 0 { + return nil + } + + issues := make([]*goanalysis.Issue, len(lintIssues.UncheckedErrors)) + + for i, err := range lintIssues.UncheckedErrors { + text := "Error return value is not checked" + + if err.FuncName != "" { + code := cmp.Or(err.SelectorName, err.FuncName) + if verbose { + code = err.FuncName + } + + text = fmt.Sprintf("Error return value of %s is not checked", internal.FormatCode(code)) + } + + issues[i] = goanalysis.NewIssue( + &result.Issue{ + FromLinter: linterName, + Text: text, + Pos: err.Pos, + }, + pass, + ) + } + + return issues +} + +func getChecker(errCfg *config.ErrcheckSettings) *errcheck.Checker { + checker := errcheck.Checker{ + Exclusions: errcheck.Exclusions{ + BlankAssignments: !errCfg.CheckAssignToBlank, + TypeAssertions: !errCfg.CheckTypeAssertions, + SymbolRegexpsByPackage: map[string]*regexp.Regexp{}, + }, + } + + if !errCfg.DisableDefaultExclusions { + checker.Exclusions.Symbols = append(checker.Exclusions.Symbols, errcheck.DefaultExcludedSymbols...) + } + + checker.Exclusions.Symbols = append(checker.Exclusions.Symbols, errCfg.ExcludeFunctions...) + + return &checker +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/errchkjson/errchkjson.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/errchkjson/errchkjson.go new file mode 100644 index 000000000..02510ab49 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/errchkjson/errchkjson.go @@ -0,0 +1,26 @@ +package errchkjson + +import ( + "github.com/breml/errchkjson" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.ErrChkJSONSettings) *goanalysis.Linter { + cfg := map[string]any{ + "omit-safe": true, + } + + if settings != nil { + cfg = map[string]any{ + "omit-safe": !settings.CheckErrorFreeEncoding, + "report-no-exported": settings.ReportNoExported, + } + } + + return goanalysis. + NewLinterFromAnalyzer(errchkjson.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/errname/errname.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/errname/errname.go new file mode 100644 index 000000000..a66f3211f --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/errname/errname.go @@ -0,0 +1,13 @@ +package errname + +import ( + "github.com/Antonboom/errname/pkg/analyzer" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(analyzer.New()). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/errorlint/errorlint.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/errorlint/errorlint.go new file mode 100644 index 000000000..a92cb4c18 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/errorlint/errorlint.go @@ -0,0 +1,49 @@ +package errorlint + +import ( + "codeberg.org/polyfloyd/go-errorlint/errorlint" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.ErrorLintSettings) *goanalysis.Linter { + var opts []errorlint.Option + + if settings != nil { + ae := toAllowPairs(settings.AllowedErrors) + if len(ae) > 0 { + opts = append(opts, errorlint.WithAllowedErrors(ae)) + } + + aew := toAllowPairs(settings.AllowedErrorsWildcard) + if len(aew) > 0 { + opts = append(opts, errorlint.WithAllowedWildcard(aew)) + } + } + + var cfg map[string]any + + if settings != nil { + cfg = map[string]any{ + "errorf": settings.Errorf, + "errorf-multi": settings.ErrorfMulti, + "asserts": settings.Asserts, + "comparison": settings.Comparison, + } + } + + return goanalysis. + NewLinterFromAnalyzer(errorlint.NewAnalyzer(opts...)). + WithDesc("Find code that can cause problems with the error wrapping scheme introduced in Go 1.13."). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} + +func toAllowPairs(data []config.ErrorLintAllowPair) []errorlint.AllowPair { + var pairs []errorlint.AllowPair + for _, allowedError := range data { + pairs = append(pairs, errorlint.AllowPair(allowedError)) + } + return pairs +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/exhaustive/exhaustive.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/exhaustive/exhaustive.go new file mode 100644 index 000000000..ec240739d --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/exhaustive/exhaustive.go @@ -0,0 +1,32 @@ +package exhaustive + +import ( + "github.com/nishanths/exhaustive" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.ExhaustiveSettings) *goanalysis.Linter { + var cfg map[string]any + + if settings != nil { + cfg = map[string]any{ + exhaustive.CheckFlag: settings.Check, + exhaustive.DefaultSignifiesExhaustiveFlag: settings.DefaultSignifiesExhaustive, + exhaustive.IgnoreEnumMembersFlag: settings.IgnoreEnumMembers, + exhaustive.IgnoreEnumTypesFlag: settings.IgnoreEnumTypes, + exhaustive.PackageScopeOnlyFlag: settings.PackageScopeOnly, + exhaustive.ExplicitExhaustiveMapFlag: settings.ExplicitExhaustiveMap, + exhaustive.ExplicitExhaustiveSwitchFlag: settings.ExplicitExhaustiveSwitch, + exhaustive.DefaultCaseRequiredFlag: settings.DefaultCaseRequired, + // Should be managed with `linters.exclusions.generated`. + exhaustive.CheckGeneratedFlag: true, + } + } + + return goanalysis. + NewLinterFromAnalyzer(exhaustive.Analyzer). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/exhaustruct/exhaustruct.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/exhaustruct/exhaustruct.go new file mode 100644 index 000000000..01136aadc --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/exhaustruct/exhaustruct.go @@ -0,0 +1,30 @@ +package exhaustruct + +import ( + exhaustruct "dev.gaijin.team/go/exhaustruct/v4/analyzer" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" +) + +func New(settings *config.ExhaustructSettings) *goanalysis.Linter { + cfg := exhaustruct.Config{} + if settings != nil { + cfg.IncludeRx = settings.Include + cfg.ExcludeRx = settings.Exclude + cfg.AllowEmpty = settings.AllowEmpty + cfg.AllowEmptyRx = settings.AllowEmptyRx + cfg.AllowEmptyReturns = settings.AllowEmptyReturns + cfg.AllowEmptyDeclarations = settings.AllowEmptyDeclarations + } + + analyzer, err := exhaustruct.NewAnalyzer(cfg) + if err != nil { + internal.LinterLogger.Fatalf("exhaustruct configuration: %v", err) + } + + return goanalysis. + NewLinterFromAnalyzer(analyzer). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/exptostd/exptostd.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/exptostd/exptostd.go new file mode 100644 index 000000000..dbd78dce9 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/exptostd/exptostd.go @@ -0,0 +1,13 @@ +package exptostd + +import ( + "github.com/ldez/exptostd" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(exptostd.NewAnalyzer()). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/fatcontext/fatcontext.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/fatcontext/fatcontext.go new file mode 100644 index 000000000..58933c660 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/fatcontext/fatcontext.go @@ -0,0 +1,23 @@ +package fatcontext + +import ( + "go.augendre.info/fatcontext/pkg/analyzer" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.FatcontextSettings) *goanalysis.Linter { + var cfg map[string]any + + if settings != nil { + cfg = map[string]any{ + analyzer.FlagCheckStructPointers: settings.CheckStructPointers, + } + } + + return goanalysis. + NewLinterFromAnalyzer(analyzer.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/forbidigo/forbidigo.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/forbidigo/forbidigo.go new file mode 100644 index 000000000..1473b4d6e --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/forbidigo/forbidigo.go @@ -0,0 +1,85 @@ +package forbidigo + +import ( + "fmt" + + "github.com/ashanbrown/forbidigo/v2/forbidigo" + "go.yaml.in/yaml/v3" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/logutils" +) + +const linterName = "forbidigo" + +func New(settings *config.ForbidigoSettings) *goanalysis.Linter { + // Without AnalyzeTypes, LoadModeSyntax is enough. + // But we cannot make this depend on the settings and have to mirror the mode chosen in GetAllSupportedLinterConfigs, + // therefore, we have to use LoadModeTypesInfo in all cases. + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: linterName, + Doc: "Forbids identifiers", + Run: func(pass *analysis.Pass) (any, error) { + err := runForbidigo(pass, settings) + if err != nil { + return nil, err + } + + return nil, nil + }, + }). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} + +func runForbidigo(pass *analysis.Pass, settings *config.ForbidigoSettings) error { + options := []forbidigo.Option{ + forbidigo.OptionExcludeGodocExamples(settings.ExcludeGodocExamples), + // disable "//permit" directives so only "//nolint" directives matters within golangci-lint + forbidigo.OptionIgnorePermitDirectives(true), + forbidigo.OptionAnalyzeTypes(settings.AnalyzeTypes), + } + + // Convert patterns back to strings because that is what NewLinter accepts. + var patterns []string + for _, pattern := range settings.Forbid { + buffer, err := yaml.Marshal(pattern) + if err != nil { + return err + } + + patterns = append(patterns, string(buffer)) + } + + forbid, err := forbidigo.NewLinter(patterns, options...) + if err != nil { + return fmt.Errorf("failed to create linter %q: %w", linterName, err) + } + + for _, file := range pass.Files { + runConfig := forbidigo.RunConfig{ + Fset: pass.Fset, + DebugLog: logutils.Debug(logutils.DebugKeyForbidigo), + } + + if settings.AnalyzeTypes { + runConfig.TypesInfo = pass.TypesInfo + } + + hints, err := forbid.RunWithConfig(runConfig, file) + if err != nil { + return fmt.Errorf("forbidigo linter failed on file %q: %w", file.Name.String(), err) + } + + for _, hint := range hints { + pass.Report(analysis.Diagnostic{ + Pos: hint.Pos(), + Message: hint.Details(), + }) + } + } + + return nil +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/forcetypeassert/forcetypeassert.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/forcetypeassert/forcetypeassert.go new file mode 100644 index 000000000..19a0e3450 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/forcetypeassert/forcetypeassert.go @@ -0,0 +1,14 @@ +package forcetypeassert + +import ( + "github.com/gostaticanalysis/forcetypeassert" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(forcetypeassert.Analyzer). + WithDesc("Find forced type assertions"). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/funcorder/funcorder.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/funcorder/funcorder.go new file mode 100644 index 000000000..06400753e --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/funcorder/funcorder.go @@ -0,0 +1,25 @@ +package funcorder + +import ( + "github.com/manuelarte/funcorder/analyzer" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.FuncOrderSettings) *goanalysis.Linter { + var cfg map[string]any + + if settings != nil { + cfg = map[string]any{ + analyzer.ConstructorCheckName: settings.Constructor, + analyzer.StructMethodCheckName: settings.StructMethod, + analyzer.AlphabeticalCheckName: settings.Alphabetical, + } + } + + return goanalysis. + NewLinterFromAnalyzer(analyzer.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/funlen/funlen.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/funlen/funlen.go new file mode 100644 index 000000000..6e0f93b51 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/funlen/funlen.go @@ -0,0 +1,27 @@ +package funlen + +import ( + "github.com/ultraware/funlen" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +type Config struct { + lineLimit int + stmtLimit int + ignoreComments bool +} + +func New(settings *config.FunlenSettings) *goanalysis.Linter { + cfg := Config{} + if settings != nil { + cfg.lineLimit = settings.Lines + cfg.stmtLimit = settings.Statements + cfg.ignoreComments = settings.IgnoreComments + } + + return goanalysis. + NewLinterFromAnalyzer(funlen.NewAnalyzer(cfg.lineLimit, cfg.stmtLimit, cfg.ignoreComments)). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gci/gci.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gci/gci.go new file mode 100644 index 000000000..4357a3b15 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gci/gci.go @@ -0,0 +1,28 @@ +package gci + +import ( + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/goformatters" + gcibase "github.com/golangci/golangci-lint/v2/pkg/goformatters/gci" + "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" +) + +const linterName = "gci" + +func New(settings *config.GciSettings) *goanalysis.Linter { + formatter, err := gcibase.New(settings) + if err != nil { + internal.LinterLogger.Fatalf("%s: create analyzer: %v", linterName, err) + } + + return goanalysis. + NewLinterFromAnalyzer( + goformatters.NewAnalyzer( + internal.LinterLogger.Child(linterName), + "Check if code and import statements are formatted, with additional rules.", + formatter, + ), + ). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/ginkgolinter/ginkgolinter.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/ginkgolinter/ginkgolinter.go new file mode 100644 index 000000000..99b9eb474 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/ginkgolinter/ginkgolinter.go @@ -0,0 +1,37 @@ +package ginkgolinter + +import ( + "github.com/nunnatsa/ginkgolinter" + glconfig "github.com/nunnatsa/ginkgolinter/config" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.GinkgoLinterSettings) *goanalysis.Linter { + cfg := &glconfig.Config{} + + if settings != nil { + cfg = &glconfig.Config{ + SuppressLen: settings.SuppressLenAssertion, + SuppressNil: settings.SuppressNilAssertion, + SuppressErr: settings.SuppressErrAssertion, + SuppressCompare: settings.SuppressCompareAssertion, + SuppressAsync: settings.SuppressAsyncAssertion, + ForbidFocus: settings.ForbidFocusContainer, + SuppressTypeCompare: settings.SuppressTypeCompareWarning, + AllowHaveLen0: settings.AllowHaveLenZero, + ForceExpectTo: settings.ForceExpectTo, + ValidateAsyncIntervals: settings.ValidateAsyncIntervals, + ForbidSpecPollution: settings.ForbidSpecPollution, + ForceSucceedForFuncs: settings.ForceSucceedForFuncs, + ForceAssertionDescription: settings.ForceAssertionDescription, + ForeToNot: settings.ForeToNot, + } + } + + return goanalysis. + NewLinterFromAnalyzer(ginkgolinter.NewAnalyzerWithConfig(cfg)). + WithDesc("enforces standards of using ginkgo and gomega"). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gocheckcompilerdirectives/gocheckcompilerdirectives.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gocheckcompilerdirectives/gocheckcompilerdirectives.go new file mode 100644 index 000000000..71f4be8c4 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gocheckcompilerdirectives/gocheckcompilerdirectives.go @@ -0,0 +1,13 @@ +package gocheckcompilerdirectives + +import ( + "4d63.com/gocheckcompilerdirectives/checkcompilerdirectives" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(checkcompilerdirectives.Analyzer()). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gochecknoglobals/gochecknoglobals.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gochecknoglobals/gochecknoglobals.go new file mode 100644 index 000000000..2fd3f3c3b --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gochecknoglobals/gochecknoglobals.go @@ -0,0 +1,14 @@ +package gochecknoglobals + +import ( + "4d63.com/gochecknoglobals/checknoglobals" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(checknoglobals.Analyzer()). + WithDesc("Check that no global variables exist."). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gochecknoinits/gochecknoinits.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gochecknoinits/gochecknoinits.go new file mode 100644 index 000000000..161db84ee --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gochecknoinits/gochecknoinits.go @@ -0,0 +1,44 @@ +package gochecknoinits + +import ( + "go/ast" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/ast/inspector" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: "gochecknoinits", + Doc: "Checks that no init functions are present in Go code", + Run: run, + Requires: []*analysis.Analyzer{inspect.Analyzer}, + }). + WithLoadMode(goanalysis.LoadModeSyntax) +} + +func run(pass *analysis.Pass) (any, error) { + insp, ok := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + if !ok { + return nil, nil + } + + for node := range insp.PreorderSeq((*ast.FuncDecl)(nil)) { + funcDecl, ok := node.(*ast.FuncDecl) + if !ok { + continue + } + + fnName := funcDecl.Name.Name + if fnName == "init" && funcDecl.Recv.NumFields() == 0 { + pass.Reportf(funcDecl.Pos(), "don't use %s function", internal.FormatCode(fnName)) + } + } + + return nil, nil +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gochecksumtype/gochecksumtype.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gochecksumtype/gochecksumtype.go new file mode 100644 index 000000000..825975f14 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gochecksumtype/gochecksumtype.go @@ -0,0 +1,82 @@ +package gochecksumtype + +import ( + "strings" + "sync" + + gochecksumtype "github.com/alecthomas/go-check-sumtype" + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/packages" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/result" +) + +const linterName = "gochecksumtype" + +func New(settings *config.GoChecksumTypeSettings) *goanalysis.Linter { + var mu sync.Mutex + var resIssues []*goanalysis.Issue + + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: linterName, + Doc: `Run exhaustiveness checks on Go "sum types"`, + Run: func(pass *analysis.Pass) (any, error) { + issues, err := runGoCheckSumType(pass, settings) + if err != nil { + return nil, err + } + + if len(issues) == 0 { + return nil, nil + } + + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() + + return nil, nil + }, + }). + WithIssuesReporter(func(_ *linter.Context) []*goanalysis.Issue { + return resIssues + }). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} + +func runGoCheckSumType(pass *analysis.Pass, settings *config.GoChecksumTypeSettings) ([]*goanalysis.Issue, error) { + var resIssues []*goanalysis.Issue + + pkg := &packages.Package{ + Fset: pass.Fset, + Syntax: pass.Files, + Types: pass.Pkg, + TypesInfo: pass.TypesInfo, + } + + cfg := gochecksumtype.Config{ + DefaultSignifiesExhaustive: settings.DefaultSignifiesExhaustive, + IncludeSharedInterfaces: settings.IncludeSharedInterfaces, + } + + var unknownError error + errors := gochecksumtype.Run([]*packages.Package{pkg}, cfg) + for _, err := range errors { + err, ok := err.(gochecksumtype.Error) + if !ok { + unknownError = err + continue + } + + resIssues = append(resIssues, goanalysis.NewIssue(&result.Issue{ + FromLinter: linterName, + Text: strings.TrimPrefix(err.Error(), err.Pos().String()+": "), + Pos: err.Pos(), + }, pass)) + } + + return resIssues, unknownError +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gocognit/gocognit.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gocognit/gocognit.go new file mode 100644 index 000000000..b17912c0a --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gocognit/gocognit.go @@ -0,0 +1,76 @@ +package gocognit + +import ( + "fmt" + "sort" + "sync" + + "github.com/uudashr/gocognit" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/result" +) + +const linterName = "gocognit" + +func New(settings *config.GocognitSettings) *goanalysis.Linter { + var mu sync.Mutex + var resIssues []*goanalysis.Issue + + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: linterName, + Doc: "Computes and checks the cognitive complexity of functions", + Run: func(pass *analysis.Pass) (any, error) { + issues := runGocognit(pass, settings) + + if len(issues) == 0 { + return nil, nil + } + + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() + + return nil, nil + }, + }). + WithIssuesReporter(func(*linter.Context) []*goanalysis.Issue { + return resIssues + }). + WithLoadMode(goanalysis.LoadModeSyntax) +} + +func runGocognit(pass *analysis.Pass, settings *config.GocognitSettings) []*goanalysis.Issue { + var stats []gocognit.Stat + for _, f := range pass.Files { + stats = gocognit.ComplexityStats(f, pass.Fset, stats) + } + if len(stats) == 0 { + return nil + } + + sort.SliceStable(stats, func(i, j int) bool { + return stats[i].Complexity > stats[j].Complexity + }) + + issues := make([]*goanalysis.Issue, 0, len(stats)) + for _, s := range stats { + if s.Complexity <= settings.MinComplexity { + break // Break as the stats is already sorted from greatest to least + } + + issues = append(issues, goanalysis.NewIssue(&result.Issue{ + Pos: s.Pos, + Text: fmt.Sprintf("cognitive complexity %d of func %s is high (> %d)", + s.Complexity, internal.FormatCode(s.FuncName), settings.MinComplexity), + FromLinter: linterName, + }, pass)) + } + + return issues +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/goconst/goconst.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/goconst/goconst.go new file mode 100644 index 000000000..b58d860c6 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/goconst/goconst.go @@ -0,0 +1,113 @@ +package goconst + +import ( + "fmt" + "sync" + + goconstAPI "github.com/jgautheron/goconst" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/result" +) + +const linterName = "goconst" + +func New(settings *config.GoConstSettings) *goanalysis.Linter { + var mu sync.Mutex + var resIssues []*goanalysis.Issue + + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: linterName, + Doc: "Finds repeated strings that could be replaced by a constant", + Run: func(pass *analysis.Pass) (any, error) { + issues, err := runGoconst(pass, settings) + if err != nil { + return nil, err + } + + if len(issues) == 0 { + return nil, nil + } + + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() + + return nil, nil + }, + }). + WithIssuesReporter(func(*linter.Context) []*goanalysis.Issue { + return resIssues + }). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} + +func runGoconst(pass *analysis.Pass, settings *config.GoConstSettings) ([]*goanalysis.Issue, error) { + cfg := goconstAPI.Config{ + IgnoreStrings: settings.IgnoreStringValues, + MatchWithConstants: settings.MatchWithConstants, + MinStringLength: settings.MinStringLen, + MinOccurrences: settings.MinOccurrencesCount, + ParseNumbers: settings.ParseNumbers, + NumberMin: settings.NumberMin, + NumberMax: settings.NumberMax, + ExcludeTypes: map[goconstAPI.Type]bool{}, + FindDuplicates: settings.FindDuplicates, + EvalConstExpressions: settings.EvalConstExpressions, + + // Should be managed with `linters.exclusions.rules`. + IgnoreTests: false, + } + + if settings.IgnoreCalls { + cfg.ExcludeTypes[goconstAPI.Call] = true + } + + lintIssues, err := goconstAPI.Run(pass.Files, pass.Fset, pass.TypesInfo, &cfg) + if err != nil { + return nil, err + } + + if len(lintIssues) == 0 { + return nil, nil + } + + res := make([]*goanalysis.Issue, 0, len(lintIssues)) + for i := range lintIssues { + issue := &lintIssues[i] + + var text string + + switch { + case issue.OccurrencesCount > 0: + text = fmt.Sprintf("string %s has %d occurrences", internal.FormatCode(issue.Str), issue.OccurrencesCount) + + if issue.MatchingConst == "" { + text += ", make it a constant" + } else { + text += fmt.Sprintf(", but such constant %s already exists", internal.FormatCode(issue.MatchingConst)) + } + + case issue.DuplicateConst != "": + text = fmt.Sprintf("This constant is a duplicate of %s at %s", + internal.FormatCode(issue.DuplicateConst), + issue.DuplicatePos.String()) + + default: + continue + } + + res = append(res, goanalysis.NewIssue(&result.Issue{ + Pos: issue.Pos, + Text: text, + FromLinter: linterName, + }, pass)) + } + + return res, nil +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gocritic/gocritic.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gocritic/gocritic.go new file mode 100644 index 000000000..cd7337590 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gocritic/gocritic.go @@ -0,0 +1,166 @@ +package gocritic + +import ( + "errors" + "fmt" + "go/ast" + "go/types" + "runtime" + "slices" + "strings" + "sync" + + "github.com/go-critic/go-critic/checkers" + gocriticlinter "github.com/go-critic/go-critic/linter" + _ "github.com/quasilyte/go-ruleguard/dsl" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/logutils" +) + +const linterName = "gocritic" + +var ( + debugf = logutils.Debug(logutils.DebugKeyGoCritic) + isDebug = logutils.HaveDebugTag(logutils.DebugKeyGoCritic) +) + +func New(settings *config.GoCriticSettings, replacer *strings.Replacer) *goanalysis.Linter { + wrapper := &goCriticWrapper{ + sizes: types.SizesFor("gc", runtime.GOARCH), + } + + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: linterName, + Doc: `Provides diagnostics that check for bugs, performance and style issues. +Extensible without recompilation through dynamic rules. +Dynamic rules are written declaratively with AST patterns, filters, report message and optional suggestion.`, + Run: func(pass *analysis.Pass) (any, error) { + err := wrapper.run(pass) + if err != nil { + return nil, err + } + + return nil, nil + }, + }). + WithContextSetter(func(context *linter.Context) { + wrapper.init(context.Log, settings, replacer) + }). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} + +type goCriticWrapper struct { + settingsWrapper *settingsWrapper + sizes types.Sizes + once sync.Once +} + +func (w *goCriticWrapper) init(logger logutils.Log, settings *config.GoCriticSettings, replacer *strings.Replacer) { + if settings == nil { + return + } + + w.once.Do(func() { + err := checkers.InitEmbeddedRules() + if err != nil { + logger.Fatalf("%s: %v: setting an explicit GOROOT can fix this problem", linterName, err) + } + }) + + settingsWrapper := newSettingsWrapper(logger, settings, replacer) + + if err := settingsWrapper.Load(); err != nil { + logger.Fatalf("%s: invalid settings: %s", linterName, err) + } + + w.settingsWrapper = settingsWrapper +} + +func (w *goCriticWrapper) run(pass *analysis.Pass) error { + if w.settingsWrapper == nil { + return errors.New("the settings wrapper is nil") + } + + linterCtx := gocriticlinter.NewContext(pass.Fset, w.sizes) + + linterCtx.SetGoVersion(w.settingsWrapper.Go) + + enabledCheckers, err := w.buildEnabledCheckers(linterCtx) + if err != nil { + return err + } + + linterCtx.SetPackageInfo(pass.TypesInfo, pass.Pkg) + + needFileInfo := slices.ContainsFunc(enabledCheckers, func(c *gocriticlinter.Checker) bool { + // Related to https://github.com/go-critic/go-critic/blob/440ff466685b41e67d231a1c4a8f5e093374ee93/checkers/importShadow_checker.go#L23 + return strings.EqualFold(c.Info.Name, "importShadow") + }) + + for _, f := range pass.Files { + if needFileInfo { + // Related to https://github.com/go-critic/go-critic/blob/440ff466685b41e67d231a1c4a8f5e093374ee93/checkers/importShadow_checker.go#L23 + linterCtx.SetFileInfo(f.Name.Name, f) + } + + runOnFile(pass, f, enabledCheckers) + } + + return nil +} + +func (w *goCriticWrapper) buildEnabledCheckers(linterCtx *gocriticlinter.Context) ([]*gocriticlinter.Checker, error) { + allLowerCasedParams := w.settingsWrapper.GetLowerCasedParams() + + var enabledCheckers []*gocriticlinter.Checker + for _, info := range gocriticlinter.GetCheckersInfo() { + if !w.settingsWrapper.IsCheckEnabled(info.Name) { + continue + } + + err := w.settingsWrapper.setCheckerParams(info, allLowerCasedParams) + if err != nil { + return nil, err + } + + c, err := gocriticlinter.NewChecker(linterCtx, info) + if err != nil { + return nil, err + } + + enabledCheckers = append(enabledCheckers, c) + } + + return enabledCheckers, nil +} + +func runOnFile(pass *analysis.Pass, f *ast.File, checks []*gocriticlinter.Checker) { + for _, c := range checks { + // All checkers are expected to use *lint.Context + // as read-only structure, so no copying is required. + for _, warn := range c.Check(f) { + diag := analysis.Diagnostic{ + Pos: warn.Pos, + Category: c.Info.Name, + Message: fmt.Sprintf("%s: %s", c.Info.Name, warn.Text), + } + + if warn.HasQuickFix() { + diag.SuggestedFixes = []analysis.SuggestedFix{{ + TextEdits: []analysis.TextEdit{{ + Pos: warn.Suggestion.From, + End: warn.Suggestion.To, + NewText: warn.Suggestion.Replacement, + }}, + }} + } + + pass.Report(diag) + } + } +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocritic/gocritic.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gocritic/gocritic_settings.go similarity index 57% rename from vendor/github.com/golangci/golangci-lint/pkg/golinters/gocritic/gocritic.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gocritic/gocritic_settings.go index 194ea3535..e3267eeec 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocritic/gocritic.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gocritic/gocritic_settings.go @@ -3,270 +3,22 @@ package gocritic import ( "errors" "fmt" - "go/ast" - "go/types" - "path/filepath" + "maps" "reflect" - "runtime" "slices" - "sort" "strings" - "sync" - "github.com/go-critic/go-critic/checkers" gocriticlinter "github.com/go-critic/go-critic/linter" - _ "github.com/quasilyte/go-ruleguard/dsl" - "golang.org/x/exp/maps" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/logutils" - "github.com/golangci/golangci-lint/pkg/result" -) - -const linterName = "gocritic" -var ( - debugf = logutils.Debug(logutils.DebugKeyGoCritic) - isDebug = logutils.HaveDebugTag(logutils.DebugKeyGoCritic) + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/logutils" ) -func New(settings *config.GoCriticSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - wrapper := &goCriticWrapper{ - sizes: types.SizesFor("gc", runtime.GOARCH), - } - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues, err := wrapper.run(pass) - if err != nil { - return nil, err - } - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - }, - } - - return goanalysis.NewLinter( - linterName, - `Provides diagnostics that check for bugs, performance and style issues. -Extensible without recompilation through dynamic rules. -Dynamic rules are written declaratively with AST patterns, filters, report message and optional suggestion.`, - []*analysis.Analyzer{analyzer}, - nil, - ). - WithContextSetter(func(context *linter.Context) { - wrapper.configDir = context.Cfg.GetConfigDir() - - wrapper.init(context.Log, settings) - }). - WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }). - WithLoadMode(goanalysis.LoadModeTypesInfo) -} - -type goCriticWrapper struct { - settingsWrapper *settingsWrapper - configDir string - sizes types.Sizes - once sync.Once -} - -func (w *goCriticWrapper) init(logger logutils.Log, settings *config.GoCriticSettings) { - if settings == nil { - return - } - - w.once.Do(func() { - err := checkers.InitEmbeddedRules() - if err != nil { - logger.Fatalf("%s: %v: setting an explicit GOROOT can fix this problem", linterName, err) - } - }) - - settingsWrapper := newSettingsWrapper(settings, logger) - settingsWrapper.InferEnabledChecks() - // Validate must be after InferEnabledChecks, not before. - // Because it uses gathered information about tags set and finally enabled checks. - if err := settingsWrapper.Validate(); err != nil { - logger.Fatalf("%s: invalid settings: %s", linterName, err) - } - - w.settingsWrapper = settingsWrapper -} - -func (w *goCriticWrapper) run(pass *analysis.Pass) ([]goanalysis.Issue, error) { - if w.settingsWrapper == nil { - return nil, errors.New("the settings wrapper is nil") - } - - linterCtx := gocriticlinter.NewContext(pass.Fset, w.sizes) - - linterCtx.SetGoVersion(w.settingsWrapper.Go) - - enabledCheckers, err := w.buildEnabledCheckers(linterCtx) - if err != nil { - return nil, err - } - - linterCtx.SetPackageInfo(pass.TypesInfo, pass.Pkg) - - pkgIssues := runOnPackage(linterCtx, enabledCheckers, pass.Files) - - issues := make([]goanalysis.Issue, 0, len(pkgIssues)) - for i := range pkgIssues { - issues = append(issues, goanalysis.NewIssue(&pkgIssues[i], pass)) - } - - return issues, nil -} - -func (w *goCriticWrapper) buildEnabledCheckers(linterCtx *gocriticlinter.Context) ([]*gocriticlinter.Checker, error) { - allLowerCasedParams := w.settingsWrapper.GetLowerCasedParams() - - var enabledCheckers []*gocriticlinter.Checker - for _, info := range gocriticlinter.GetCheckersInfo() { - if !w.settingsWrapper.IsCheckEnabled(info.Name) { - continue - } - - if err := w.configureCheckerInfo(info, allLowerCasedParams); err != nil { - return nil, err - } - - c, err := gocriticlinter.NewChecker(linterCtx, info) - if err != nil { - return nil, err - } - enabledCheckers = append(enabledCheckers, c) - } - - return enabledCheckers, nil -} - -func (w *goCriticWrapper) configureCheckerInfo( - info *gocriticlinter.CheckerInfo, - allLowerCasedParams map[string]config.GoCriticCheckSettings, -) error { - params := allLowerCasedParams[strings.ToLower(info.Name)] - if params == nil { // no config for this checker - return nil - } - - // To lowercase info param keys here because golangci-lint's config parser lowercases all strings. - infoParams := normalizeMap(info.Params) - for k, p := range params { - v, ok := infoParams[k] - if ok { - v.Value = w.normalizeCheckerParamsValue(p) - continue - } - - // param `k` isn't supported - if len(info.Params) == 0 { - return fmt.Errorf("checker %s config param %s doesn't exist: checker doesn't have params", - info.Name, k) - } - - supportedKeys := maps.Keys(info.Params) - sort.Strings(supportedKeys) - - return fmt.Errorf("checker %s config param %s doesn't exist, all existing: %s", - info.Name, k, supportedKeys) - } - - return nil -} - -// normalizeCheckerParamsValue normalizes value types. -// go-critic asserts that CheckerParam.Value has some specific types, -// but the file parsers (TOML, YAML, JSON) don't create the same representation for raw type. -// then we have to convert value types into the expected value types. -// Maybe in the future, this kind of conversion will be done in go-critic itself. -func (w *goCriticWrapper) normalizeCheckerParamsValue(p any) any { - rv := reflect.ValueOf(p) - switch rv.Type().Kind() { - case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int: - return int(rv.Int()) - case reflect.Bool: - return rv.Bool() - case reflect.String: - // Perform variable substitution. - return strings.ReplaceAll(rv.String(), "${configDir}", w.configDir) - default: - return p - } -} - -func runOnPackage(linterCtx *gocriticlinter.Context, checks []*gocriticlinter.Checker, files []*ast.File) []result.Issue { - var res []result.Issue - for _, f := range files { - filename := filepath.Base(linterCtx.FileSet.Position(f.Pos()).Filename) - linterCtx.SetFileInfo(filename, f) - - issues := runOnFile(linterCtx, f, checks) - res = append(res, issues...) - } - return res -} - -func runOnFile(linterCtx *gocriticlinter.Context, f *ast.File, checks []*gocriticlinter.Checker) []result.Issue { - var res []result.Issue - - for _, c := range checks { - // All checkers are expected to use *lint.Context - // as read-only structure, so no copying is required. - for _, warn := range c.Check(f) { - pos := linterCtx.FileSet.Position(warn.Pos) - issue := result.Issue{ - Pos: pos, - Text: fmt.Sprintf("%s: %s", c.Info.Name, warn.Text), - FromLinter: linterName, - } - - if warn.HasQuickFix() { - issue.Replacement = &result.Replacement{ - Inline: &result.InlineFix{ - StartCol: pos.Column - 1, - Length: int(warn.Suggestion.To - warn.Suggestion.From), - NewString: string(warn.Suggestion.Replacement), - }, - } - } - - res = append(res, issue) - } - } - - return res -} - -type goCriticChecks[T any] map[string]T - -func (m goCriticChecks[T]) has(name string) bool { - _, ok := m[name] - return ok -} - type settingsWrapper struct { *config.GoCriticSettings + replacer *strings.Replacer + logger logutils.Log allCheckers []*gocriticlinter.CheckerInfo @@ -282,12 +34,13 @@ type settingsWrapper struct { inferredEnabledChecksLowerCased goCriticChecks[struct{}] } -func newSettingsWrapper(settings *config.GoCriticSettings, logger logutils.Log) *settingsWrapper { +func newSettingsWrapper(logger logutils.Log, settings *config.GoCriticSettings, replacer *strings.Replacer) *settingsWrapper { allCheckers := gocriticlinter.GetCheckersInfo() allChecks := make(goCriticChecks[struct{}], len(allCheckers)) allChecksLowerCased := make(goCriticChecks[struct{}], len(allCheckers)) allChecksByTag := make(goCriticChecks[[]string]) + for _, checker := range allCheckers { allChecks[checker.Name] = struct{}{} allChecksLowerCased[strings.ToLower(checker.Name)] = struct{}{} @@ -297,18 +50,18 @@ func newSettingsWrapper(settings *config.GoCriticSettings, logger logutils.Log) } } - allTagsSorted := maps.Keys(allChecksByTag) - sort.Strings(allTagsSorted) - return &settingsWrapper{ - GoCriticSettings: settings, - logger: logger, - allCheckers: allCheckers, - allChecks: allChecks, + GoCriticSettings: settings, + replacer: replacer, + logger: logger, + + allCheckers: allCheckers, + allChecks: allChecks, + allChecksByTag: allChecksByTag, + allTagsSorted: slices.Sorted(maps.Keys(allChecksByTag)), + inferredEnabledChecks: make(goCriticChecks[struct{}]), + allChecksLowerCased: allChecksLowerCased, - allChecksByTag: allChecksByTag, - allTagsSorted: allTagsSorted, - inferredEnabledChecks: make(goCriticChecks[struct{}]), inferredEnabledChecksLowerCased: make(goCriticChecks[struct{}]), } } @@ -321,39 +74,56 @@ func (s *settingsWrapper) GetLowerCasedParams() map[string]config.GoCriticCheckS return normalizeMap(s.SettingsPerCheck) } -// InferEnabledChecks tries to be consistent with (lintersdb.Manager).build. -func (s *settingsWrapper) InferEnabledChecks() { +func (s *settingsWrapper) Load() error { + s.inferEnabledChecks() + + // validate must be after inferEnabledChecks, not before. + // Because it uses gathered information about tags set and finally enabled checks. + return s.validate() +} + +func (s *settingsWrapper) inferEnabledChecks() { s.debugChecksInitialState() enabledByDefaultChecks, disabledByDefaultChecks := s.buildEnabledAndDisabledByDefaultChecks() + debugChecksListf(enabledByDefaultChecks, "Enabled by default") debugChecksListf(disabledByDefaultChecks, "Disabled by default") - enabledChecks := make(goCriticChecks[struct{}]) + var enabledChecks goCriticChecks[struct{}] + + switch { + case s.DisableAll: + // disable-all revokes the default settings. + enabledChecks = make(goCriticChecks[struct{}]) - if s.EnableAll { + case s.EnableAll: + // enable-all revokes the default settings. enabledChecks = make(goCriticChecks[struct{}], len(s.allCheckers)) + for _, info := range s.allCheckers { enabledChecks[info.Name] = struct{}{} } - } else if !s.DisableAll { - // enable-all/disable-all revokes the default settings. + + default: enabledChecks = make(goCriticChecks[struct{}], len(enabledByDefaultChecks)) + for _, check := range enabledByDefaultChecks { enabledChecks[check] = struct{}{} } } - if len(s.EnabledTags) != 0 { + if len(s.EnabledTags) > 0 { enabledFromTags := s.expandTagsToChecks(s.EnabledTags) - debugChecksListf(enabledFromTags, "Enabled by config tags %s", sprintSortedStrings(s.EnabledTags)) + + debugChecksListf(enabledFromTags, "Enabled by config tags %s", s.EnabledTags) for _, check := range enabledFromTags { enabledChecks[check] = struct{}{} } } - if len(s.EnabledChecks) != 0 { + if len(s.EnabledChecks) > 0 { debugChecksListf(s.EnabledChecks, "Enabled by config") for _, check := range s.EnabledChecks { @@ -361,20 +131,22 @@ func (s *settingsWrapper) InferEnabledChecks() { s.logger.Warnf("%s: no need to enable check %q: it's already enabled", linterName, check) continue } + enabledChecks[check] = struct{}{} } } - if len(s.DisabledTags) != 0 { + if len(s.DisabledTags) > 0 { disabledFromTags := s.expandTagsToChecks(s.DisabledTags) - debugChecksListf(disabledFromTags, "Disabled by config tags %s", sprintSortedStrings(s.DisabledTags)) + + debugChecksListf(disabledFromTags, "Disabled by config tags %s", s.DisabledTags) for _, check := range disabledFromTags { delete(enabledChecks, check) } } - if len(s.DisabledChecks) != 0 { + if len(s.DisabledChecks) > 0 { debugChecksListf(s.DisabledChecks, "Disabled by config") for _, check := range s.DisabledChecks { @@ -382,40 +154,77 @@ func (s *settingsWrapper) InferEnabledChecks() { s.logger.Warnf("%s: no need to disable check %q: it's already disabled", linterName, check) continue } + delete(enabledChecks, check) } } s.inferredEnabledChecks = enabledChecks s.inferredEnabledChecksLowerCased = normalizeMap(s.inferredEnabledChecks) + s.debugChecksFinalState() } func (s *settingsWrapper) buildEnabledAndDisabledByDefaultChecks() (enabled, disabled []string) { for _, info := range s.allCheckers { - if enabledByDef := isEnabledByDefaultGoCriticChecker(info); enabledByDef { + if isEnabledByDefaultGoCriticChecker(info) { enabled = append(enabled, info.Name) } else { disabled = append(disabled, info.Name) } } + return enabled, disabled } func (s *settingsWrapper) expandTagsToChecks(tags []string) []string { var checks []string + for _, tag := range tags { checks = append(checks, s.allChecksByTag[tag]...) } + return checks } +func (s *settingsWrapper) setCheckerParams( + info *gocriticlinter.CheckerInfo, + allLowerCasedParams map[string]config.GoCriticCheckSettings, +) error { + params := allLowerCasedParams[strings.ToLower(info.Name)] + if params == nil { // no config for this checker + return nil + } + + // To lowercase info param keys here because golangci-lint's config parser lowercases all strings. + infoParams := normalizeMap(info.Params) + for k, p := range params { + v, ok := infoParams[k] + if ok { + v.Value = s.normalizeCheckerParamsValue(p) + continue + } + + // param `k` isn't supported + if len(info.Params) == 0 { + return fmt.Errorf("checker %s config param %s doesn't exist: checker doesn't have params", + info.Name, k) + } + + return fmt.Errorf("checker %s config param %s doesn't exist, all existing: %s", + info.Name, k, slices.Sorted(maps.Keys(info.Params))) + } + + return nil +} + func (s *settingsWrapper) debugChecksInitialState() { if !isDebug { return } debugf("All gocritic existing tags and checks:") + for _, tag := range s.allTagsSorted { debugChecksListf(s.allChecksByTag[tag], " tag %q", tag) } @@ -430,11 +239,10 @@ func (s *settingsWrapper) debugChecksFinalState() { var disabledChecks []string for _, checker := range s.allCheckers { - check := checker.Name - if s.inferredEnabledChecks.has(check) { - enabledChecks = append(enabledChecks, check) + if s.IsCheckEnabled(checker.Name) { + enabledChecks = append(enabledChecks, checker.Name) } else { - disabledChecks = append(disabledChecks, check) + disabledChecks = append(disabledChecks, checker.Name) } } @@ -447,8 +255,32 @@ func (s *settingsWrapper) debugChecksFinalState() { } } -// Validate tries to be consistent with (lintersdb.Validator).validateEnabledDisabledLintersConfig. -func (s *settingsWrapper) Validate() error { +// normalizeCheckerParamsValue normalizes value types. +// go-critic asserts that CheckerParam.Value has some specific types, +// but the file parsers (TOML, YAML, JSON) don't create the same representation for raw type. +// then we have to convert value types into the expected value types. +// Maybe in the future, this kind of conversion will be done in go-critic itself. +func (s *settingsWrapper) normalizeCheckerParamsValue(p any) any { + rv := reflect.ValueOf(p) + + switch rv.Type().Kind() { + case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int: + return int(rv.Int()) + + case reflect.Bool: + return rv.Bool() + + case reflect.String: + // Perform variable substitution. + return s.replacer.Replace(rv.String()) + + default: + return p + } +} + +// validate tries to be consistent with (lintersdb.Validator).validateEnabledDisabledLintersConfig. +func (s *settingsWrapper) validate() error { for _, v := range []func() error{ s.validateOptionsCombinations, s.validateCheckerTags, @@ -464,26 +296,26 @@ func (s *settingsWrapper) Validate() error { } func (s *settingsWrapper) validateOptionsCombinations() error { - if s.EnableAll { - if s.DisableAll { - return errors.New("enable-all and disable-all options must not be combined") - } + if s.EnableAll && s.DisableAll { + return errors.New("enable-all and disable-all options must not be combined") + } - if len(s.EnabledTags) != 0 { + switch { + case s.EnableAll: + if len(s.EnabledTags) > 0 { return errors.New("enable-all and enabled-tags options must not be combined") } - if len(s.EnabledChecks) != 0 { + if len(s.EnabledChecks) > 0 { return errors.New("enable-all and enabled-checks options must not be combined") } - } - if s.DisableAll { - if len(s.DisabledTags) != 0 { + case s.DisableAll: + if len(s.DisabledTags) > 0 { return errors.New("disable-all and disabled-tags options must not be combined") } - if len(s.DisabledChecks) != 0 { + if len(s.DisabledChecks) > 0 { return errors.New("disable-all and disabled-checks options must not be combined") } @@ -526,9 +358,11 @@ func (s *settingsWrapper) validateCheckerNames() error { for check := range s.SettingsPerCheck { lcName := strings.ToLower(check) + if !s.allChecksLowerCased.has(lcName) { return fmt.Errorf("invalid check settings: check %q doesn't exist, see %s documentation", check, linterName) } + if !s.inferredEnabledChecksLowerCased.has(lcName) { s.logger.Warnf("%s: settings were provided for disabled check %q", check, linterName) } @@ -557,14 +391,34 @@ func (s *settingsWrapper) validateAtLeastOneCheckerEnabled() error { if len(s.inferredEnabledChecks) == 0 { return errors.New("eventually all checks were disabled: at least one must be enabled") } + return nil } +type goCriticChecks[T any] map[string]T + +func (m goCriticChecks[T]) has(name string) bool { + _, ok := m[name] + return ok +} + +func debugChecksListf(checks []string, format string, args ...any) { + if !isDebug { + return + } + + v := slices.Sorted(slices.Values(checks)) + + debugf("%s checks (%d): %s", fmt.Sprintf(format, args...), len(checks), strings.Join(v, ", ")) +} + func normalizeMap[ValueT any](in map[string]ValueT) map[string]ValueT { ret := make(map[string]ValueT, len(in)) + for k, v := range in { ret[strings.ToLower(k)] = v } + return ret } @@ -575,16 +429,3 @@ func isEnabledByDefaultGoCriticChecker(info *gocriticlinter.CheckerInfo) bool { !info.HasTag(gocriticlinter.PerformanceTag) && !info.HasTag(gocriticlinter.SecurityTag) } - -func debugChecksListf(checks []string, format string, args ...any) { - if !isDebug { - return - } - - debugf("%s checks (%d): %s", fmt.Sprintf(format, args...), len(checks), sprintSortedStrings(checks)) -} - -func sprintSortedStrings(v []string) string { - sort.Strings(slices.Clone(v)) - return fmt.Sprint(v) -} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gocyclo/gocyclo.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gocyclo/gocyclo.go new file mode 100644 index 000000000..de0374607 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gocyclo/gocyclo.go @@ -0,0 +1,72 @@ +package gocyclo + +import ( + "fmt" + "sync" + + "github.com/fzipp/gocyclo" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/result" +) + +const linterName = "gocyclo" + +func New(settings *config.GoCycloSettings) *goanalysis.Linter { + var mu sync.Mutex + var resIssues []*goanalysis.Issue + + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: linterName, + Doc: "Computes and checks the cyclomatic complexity of functions", + Run: func(pass *analysis.Pass) (any, error) { + issues := runGoCyclo(pass, settings) + + if len(issues) == 0 { + return nil, nil + } + + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() + + return nil, nil + }, + }). + WithIssuesReporter(func(*linter.Context) []*goanalysis.Issue { + return resIssues + }). + WithLoadMode(goanalysis.LoadModeSyntax) +} + +func runGoCyclo(pass *analysis.Pass, settings *config.GoCycloSettings) []*goanalysis.Issue { + var stats gocyclo.Stats + for _, f := range pass.Files { + stats = gocyclo.AnalyzeASTFile(f, pass.Fset, stats) + } + if len(stats) == 0 { + return nil + } + + stats = stats.SortAndFilter(-1, settings.MinComplexity) + + issues := make([]*goanalysis.Issue, 0, len(stats)) + + for _, s := range stats { + text := fmt.Sprintf("cyclomatic complexity %d of func %s is high (> %d)", + s.Complexity, internal.FormatCode(s.FuncName), settings.MinComplexity) + + issues = append(issues, goanalysis.NewIssue(&result.Issue{ + Pos: s.Pos, + Text: text, + FromLinter: linterName, + }, pass)) + } + + return issues +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/godoclint/godoclint.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/godoclint/godoclint.go new file mode 100644 index 000000000..0d0171251 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/godoclint/godoclint.go @@ -0,0 +1,119 @@ +package godoclint + +import ( + "errors" + "fmt" + "slices" + + glcompose "github.com/godoc-lint/godoc-lint/pkg/compose" + glconfig "github.com/godoc-lint/godoc-lint/pkg/config" + "github.com/godoc-lint/godoc-lint/pkg/model" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" +) + +func New(settings *config.GodoclintSettings) *goanalysis.Linter { + var pcfg glconfig.PlainConfig + + if settings != nil { + err := checkSettings(settings) + if err != nil { + internal.LinterLogger.Fatalf("godoclint: %v", err) + } + + // The following options are explicitly ignored: they must be handled globally with exclusions or nolint directives. + // - Include + // - Exclude + + // The following options are explicitly ignored: these options cannot work as expected because the global configuration about tests. + // - Options.MaxLenIncludeTests + // - Options.PkgDocIncludeTests + // - Options.SinglePkgDocIncludeTests + // - Options.RequirePkgDocIncludeTests + // - Options.RequireDocIncludeTests + // - Options.StartWithNameIncludeTests + // - Options.NoUnusedLinkIncludeTests + // - Options.RequireStdlibDoclinkIncludeTests + + // Also, Options.MaxLenIgnorePatterns is ignored because the Golangci-lint's idiomatic way to ignore such issues + // is exclusion by source text patterns. + + pcfg = glconfig.PlainConfig{ + Default: settings.Default, + Enable: settings.Enable, + Disable: settings.Disable, + Options: &glconfig.PlainRuleOptions{ + MaxLenLength: settings.Options.MaxLen.Length, + MaxLenIncludeTests: pointer(true), + MaxLenIgnorePatterns: []string{`^\+kubebuilder:`}, + PkgDocIncludeTests: pointer(false), + SinglePkgDocIncludeTests: pointer(true), + RequirePkgDocIncludeTests: pointer(false), + RequireDocIncludeTests: pointer(true), + RequireDocIgnoreExported: settings.Options.RequireDoc.IgnoreExported, + RequireDocIgnoreUnexported: settings.Options.RequireDoc.IgnoreUnexported, + StartWithNameIncludeTests: pointer(false), + StartWithNameIncludeUnexported: settings.Options.StartWithName.IncludeUnexported, + RequireStdlibDoclinkIncludeTests: pointer(true), + NoUnusedLinkIncludeTests: pointer(true), + }, + } + + if err := pcfg.Validate(); err != nil { + internal.LinterLogger.Fatalf("godoclint: %v", err) + } + } + + composition := glcompose.Compose(glcompose.CompositionConfig{ + BaseDirPlainConfig: &pcfg, + ExitFunc: func(_ int, err error) { + internal.LinterLogger.Errorf("godoclint: %v", err) + }, + }) + + return goanalysis. + NewLinterFromAnalyzer(composition.Analyzer.GetAnalyzer()). + WithLoadMode(goanalysis.LoadModeSyntax) +} + +func checkSettings(settings *config.GodoclintSettings) error { + switch deref(settings.Default) { + case string(model.DefaultSetAll): + if len(settings.Enable) > 0 { + return errors.New("cannot use 'enable' with 'default=all'") + } + + case string(model.DefaultSetNone): + if len(settings.Disable) > 0 { + return errors.New("cannot use 'disable' with 'default=none'") + } + + default: + for _, rule := range settings.Enable { + if slices.Contains(settings.Disable, rule) { + return fmt.Errorf("a rule cannot be enabled and disabled at the same time: '%s'", rule) + } + } + + for _, rule := range settings.Disable { + if slices.Contains(settings.Enable, rule) { + return fmt.Errorf("a rule cannot be enabled and disabled at the same time: '%s'", rule) + } + } + } + + return nil +} + +func pointer[T any](v T) *T { return &v } + +func deref[T any](v *T) T { + if v == nil { + var zero T + return zero + } + + return *v +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/godot/godot.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/godot/godot.go new file mode 100644 index 000000000..e83495128 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/godot/godot.go @@ -0,0 +1,76 @@ +package godot + +import ( + "cmp" + + "github.com/tetafro/godot" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.GodotSettings) *goanalysis.Linter { + var dotSettings godot.Settings + + if settings != nil { + dotSettings = godot.Settings{ + Scope: godot.Scope(settings.Scope), + Exclude: settings.Exclude, + Period: settings.Period, + Capital: settings.Capital, + } + } + + dotSettings.Scope = cmp.Or(dotSettings.Scope, godot.DeclScope) + + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: "godot", + Doc: "Check if comments end in a period", + Run: func(pass *analysis.Pass) (any, error) { + err := runGodot(pass, dotSettings) + if err != nil { + return nil, err + } + + return nil, nil + }, + }). + WithLoadMode(goanalysis.LoadModeSyntax) +} + +func runGodot(pass *analysis.Pass, settings godot.Settings) error { + for _, file := range pass.Files { + iss, err := godot.Run(file, pass.Fset, settings) + if err != nil { + return err + } + + if len(iss) == 0 { + continue + } + + f := pass.Fset.File(file.Pos()) + + for _, i := range iss { + start := f.Pos(i.Pos.Offset) + end := goanalysis.EndOfLinePos(f, i.Pos.Line) + + pass.Report(analysis.Diagnostic{ + Pos: start, + End: end, + Message: i.Message, + SuggestedFixes: []analysis.SuggestedFix{{ + TextEdits: []analysis.TextEdit{{ + Pos: start, + End: end, + NewText: []byte(i.Replacement), + }}, + }}, + }) + } + } + + return nil +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/godox/godox.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/godox/godox.go new file mode 100644 index 000000000..e05fc123a --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/godox/godox.go @@ -0,0 +1,60 @@ +package godox + +import ( + "go/token" + "strings" + + "github.com/matoous/godox" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.GodoxSettings) *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: "godox", + Doc: "Detects usage of FIXME, TODO and other keywords inside comments", + Run: func(pass *analysis.Pass) (any, error) { + return run(pass, settings), nil + }, + }). + WithLoadMode(goanalysis.LoadModeSyntax) +} + +func run(pass *analysis.Pass, settings *config.GodoxSettings) error { + for _, file := range pass.Files { + position, isGoFile := goanalysis.GetGoFilePosition(pass, file) + if !isGoFile { + continue + } + + messages, err := godox.Run(file, pass.Fset, settings.Keywords...) + if err != nil { + return err + } + + if len(messages) == 0 { + continue + } + + nonAdjPosition := pass.Fset.PositionFor(file.Pos(), false) + + ft := pass.Fset.File(file.Pos()) + + for _, i := range messages { + msg := strings.TrimRight(i.Message, "\n") + + // https://github.com/matoous/godox/blob/1d6ac9d899726279072e1c4d2b10f1eb52f22878/godox.go#L56 + index := strings.Index(msg, "Line contains") + + pass.Report(analysis.Diagnostic{ + Pos: ft.LineStart(goanalysis.AdjustPos(i.Pos.Line, nonAdjPosition.Line, position.Line)) + token.Pos(i.Pos.Column), + Message: msg[index:], + }) + } + } + + return nil +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gofmt/gofmt.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gofmt/gofmt.go new file mode 100644 index 000000000..04de51efc --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gofmt/gofmt.go @@ -0,0 +1,21 @@ +package gofmt + +import ( + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/goformatters" + gofmtbase "github.com/golangci/golangci-lint/v2/pkg/goformatters/gofmt" + "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" +) + +func New(settings *config.GoFmtSettings) *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer( + goformatters.NewAnalyzer( + internal.LinterLogger.Child(gofmtbase.Name), + "Check if the code is formatted according to 'gofmt' command.", + gofmtbase.New(settings), + ), + ). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gofumpt/gofumpt.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gofumpt/gofumpt.go new file mode 100644 index 000000000..1ee7c833a --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gofumpt/gofumpt.go @@ -0,0 +1,21 @@ +package gofumpt + +import ( + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/goformatters" + gofumptbase "github.com/golangci/golangci-lint/v2/pkg/goformatters/gofumpt" + "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" +) + +func New(settings *config.GoFumptSettings) *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer( + goformatters.NewAnalyzer( + internal.LinterLogger.Child(gofumptbase.Name), + "Check if code and import statements are formatted, with additional rules.", + gofumptbase.New(settings, settings.LangVersion), + ), + ). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/goheader/goheader.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/goheader/goheader.go new file mode 100644 index 000000000..0634dbd42 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/goheader/goheader.go @@ -0,0 +1,126 @@ +package goheader + +import ( + "go/token" + "strings" + + goheader "github.com/denis-tingaikin/go-header" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +const linterName = "goheader" + +func New(settings *config.GoHeaderSettings, replacer *strings.Replacer) *goanalysis.Linter { + conf := &goheader.Configuration{} + if settings != nil { + conf = &goheader.Configuration{ + Values: settings.Values, + Template: settings.Template, + TemplatePath: replacer.Replace(settings.TemplatePath), + } + } + + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: linterName, + Doc: "Check if file header matches to pattern", + Run: func(pass *analysis.Pass) (any, error) { + err := runGoHeader(pass, conf) + if err != nil { + return nil, err + } + + return nil, nil + }, + }). + WithLoadMode(goanalysis.LoadModeSyntax) +} + +func runGoHeader(pass *analysis.Pass, conf *goheader.Configuration) error { + if conf.TemplatePath == "" && conf.Template == "" { + // User did not pass template, so then do not run go-header linter + return nil + } + + template, err := conf.GetTemplate() + if err != nil { + return err + } + + values, err := conf.GetValues() + if err != nil { + return err + } + + a := goheader.New(goheader.WithTemplate(template), goheader.WithValues(values)) + + for _, file := range pass.Files { + position, isGoFile := goanalysis.GetGoFilePosition(pass, file) + if !isGoFile { + continue + } + + issue := a.Analyze(&goheader.Target{File: file, Path: position.Filename}) + if issue == nil { + continue + } + + f := pass.Fset.File(file.Pos()) + + commentLine := 1 + var offset int + + // Inspired by https://github.com/denis-tingaikin/go-header/blob/4c75a6a2332f025705325d6c71fff4616aedf48f/analyzer.go#L85-L92 + if len(file.Comments) > 0 && file.Comments[0].Pos() < file.Package { + if !strings.HasPrefix(file.Comments[0].List[0].Text, "/*") { + // When the comment is "//" there is a one character offset. + offset = 1 + } + commentLine = goanalysis.GetFilePositionFor(pass.Fset, file.Comments[0].Pos()).Line + } + + // Skip issues related to build directives. + // https://github.com/denis-tingaikin/go-header/issues/18 + if issue.Location().Position-offset < 0 { + continue + } + + diag := analysis.Diagnostic{ + Pos: f.LineStart(issue.Location().Line+1) + token.Pos(issue.Location().Position-offset), // The position of the first divergence. + Message: issue.Message(), + } + + if fix := issue.Fix(); fix != nil { + current := len(fix.Actual) + for _, s := range fix.Actual { + current += len(s) + } + + start := f.LineStart(commentLine) + + end := start + token.Pos(current) + + header := strings.Join(fix.Expected, "\n") + "\n" + + // Adds an extra line between the package and the header. + if end == file.Package { + header += "\n" + } + + diag.SuggestedFixes = []analysis.SuggestedFix{{ + TextEdits: []analysis.TextEdit{{ + Pos: start, + End: end, + NewText: []byte(header), + }}, + }} + } + + pass.Report(diag) + } + + return nil +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/goimports/goimports.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/goimports/goimports.go new file mode 100644 index 000000000..b3b9b5800 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/goimports/goimports.go @@ -0,0 +1,21 @@ +package goimports + +import ( + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/goformatters" + goimportsbase "github.com/golangci/golangci-lint/v2/pkg/goformatters/goimports" + "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" +) + +func New(settings *config.GoImportsSettings) *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer( + goformatters.NewAnalyzer( + internal.LinterLogger.Child(goimportsbase.Name), + "Checks if the code and import statements are formatted according to the 'goimports' command.", + goimportsbase.New(settings), + ), + ). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/golines/golines.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/golines/golines.go new file mode 100644 index 000000000..0a32971de --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/golines/golines.go @@ -0,0 +1,21 @@ +package golines + +import ( + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/goformatters" + golinesbase "github.com/golangci/golangci-lint/v2/pkg/goformatters/golines" + "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" +) + +func New(settings *config.GoLinesSettings) *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer( + goformatters.NewAnalyzer( + internal.LinterLogger.Child(golinesbase.Name), + "Checks if code is formatted, and fixes long lines", + golinesbase.New(settings), + ), + ). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gomoddirectives/gomoddirectives.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gomoddirectives/gomoddirectives.go new file mode 100644 index 000000000..817b5498e --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gomoddirectives/gomoddirectives.go @@ -0,0 +1,87 @@ +package gomoddirectives + +import ( + "regexp" + "sync" + + "github.com/ldez/gomoddirectives" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/result" +) + +const linterName = "gomoddirectives" + +func New(settings *config.GoModDirectivesSettings) *goanalysis.Linter { + var issues []*goanalysis.Issue + var once sync.Once + + var opts gomoddirectives.Options + if settings != nil { + opts.ReplaceAllowLocal = settings.ReplaceLocal + opts.ReplaceAllowList = settings.ReplaceAllowList + opts.RetractAllowNoExplanation = settings.RetractAllowNoExplanation + opts.ExcludeForbidden = settings.ExcludeForbidden + opts.ToolchainForbidden = settings.ToolchainForbidden + opts.ToolForbidden = settings.ToolForbidden + opts.GoDebugForbidden = settings.GoDebugForbidden + opts.CheckModulePath = settings.CheckModulePath + + if settings.ToolchainPattern != "" { + exp, err := regexp.Compile(settings.ToolchainPattern) + if err != nil { + internal.LinterLogger.Fatalf("%s: invalid toolchain pattern: %v", linterName, err) + } else { + opts.ToolchainPattern = exp + } + } + + if settings.GoVersionPattern != "" { + exp, err := regexp.Compile(settings.GoVersionPattern) + if err != nil { + internal.LinterLogger.Fatalf("%s: invalid Go version pattern: %v", linterName, err) + } else { + opts.GoVersionPattern = exp + } + } + } + + analyzer := &analysis.Analyzer{ + Name: linterName, + Doc: "Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod.", + Run: goanalysis.DummyRun, + } + + return goanalysis. + NewLinterFromAnalyzer(analyzer). + WithContextSetter(func(lintCtx *linter.Context) { + analyzer.Run = func(pass *analysis.Pass) (any, error) { + once.Do(func() { + results, err := gomoddirectives.AnalyzePass(pass, opts) + if err != nil { + lintCtx.Log.Warnf("running %s failed: %s: "+ + "if you are not using go modules it is suggested to disable this linter", linterName, err) + return + } + + for _, p := range results { + issues = append(issues, goanalysis.NewIssue(&result.Issue{ + FromLinter: linterName, + Pos: p.Start, + Text: p.Reason, + }, pass)) + } + }) + + return nil, nil + } + }). + WithIssuesReporter(func(*linter.Context) []*goanalysis.Issue { + return issues + }). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gomodguard/gomodguard.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gomodguard/gomodguard.go new file mode 100644 index 000000000..7d16f57b3 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gomodguard/gomodguard.go @@ -0,0 +1,89 @@ +package gomodguard + +import ( + "sync" + + "github.com/ryancurrah/gomodguard" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/result" +) + +const linterName = "gomodguard" + +func New(settings *config.GoModGuardSettings) *goanalysis.Linter { + var issues []*goanalysis.Issue + var mu sync.Mutex + + processorCfg := &gomodguard.Configuration{} + if settings != nil { + processorCfg.Allowed.Modules = settings.Allowed.Modules + processorCfg.Allowed.Domains = settings.Allowed.Domains + processorCfg.Blocked.LocalReplaceDirectives = settings.Blocked.LocalReplaceDirectives + + for n := range settings.Blocked.Modules { + for k, v := range settings.Blocked.Modules[n] { + m := map[string]gomodguard.BlockedModule{k: { + Recommendations: v.Recommendations, + Reason: v.Reason, + }} + processorCfg.Blocked.Modules = append(processorCfg.Blocked.Modules, m) + break + } + } + + for n := range settings.Blocked.Versions { + for k, v := range settings.Blocked.Versions[n] { + m := map[string]gomodguard.BlockedVersion{k: { + Version: v.Version, + Reason: v.Reason, + }} + processorCfg.Blocked.Versions = append(processorCfg.Blocked.Versions, m) + break + } + } + } + + analyzer := &analysis.Analyzer{ + Name: linterName, + Doc: "Allow and blocklist linter for direct Go module dependencies. " + + "This is different from depguard where there are different block " + + "types for example version constraints and module recommendations.", + Run: goanalysis.DummyRun, + } + + return goanalysis.NewLinterFromAnalyzer(analyzer). + WithContextSetter(func(lintCtx *linter.Context) { + processor, err := gomodguard.NewProcessor(processorCfg) + if err != nil { + lintCtx.Log.Warnf("running gomodguard failed: %s: if you are not using go modules "+ + "it is suggested to disable this linter", err) + return + } + + analyzer.Run = func(pass *analysis.Pass) (any, error) { + gomodguardIssues := processor.ProcessFiles(internal.GetGoFileNames(pass)) + + mu.Lock() + defer mu.Unlock() + + for _, gomodguardIssue := range gomodguardIssues { + issues = append(issues, goanalysis.NewIssue(&result.Issue{ + FromLinter: linterName, + Pos: gomodguardIssue.Position, + Text: gomodguardIssue.Reason, + }, pass)) + } + + return nil, nil + } + }). + WithIssuesReporter(func(*linter.Context) []*goanalysis.Issue { + return issues + }). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/goprintffuncname/goprintffuncname.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/goprintffuncname/goprintffuncname.go new file mode 100644 index 000000000..a56dce8e0 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/goprintffuncname/goprintffuncname.go @@ -0,0 +1,13 @@ +package goprintffuncname + +import ( + "github.com/golangci/go-printf-func-name/pkg/analyzer" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(analyzer.Analyzer). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gosec/gosec.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gosec/gosec.go similarity index 78% rename from vendor/github.com/golangci/golangci-lint/pkg/golinters/gosec/gosec.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gosec/gosec.go index a5367399b..66d229295 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gosec/gosec.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gosec/gosec.go @@ -16,17 +16,17 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/packages" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/result" ) const linterName = "gosec" func New(settings *config.GoSecSettings) *goanalysis.Linter { var mu sync.Mutex - var resIssues []goanalysis.Issue + var resIssues []*goanalysis.Issue conf := gosec.NewConfig() @@ -50,37 +50,36 @@ func New(settings *config.GoSecSettings) *goanalysis.Linter { analyzer := &analysis.Analyzer{ Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, + Doc: "Inspects source code for security problems", Run: goanalysis.DummyRun, } - return goanalysis.NewLinter( - linterName, - "Inspects source code for security problems", - []*analysis.Analyzer{analyzer}, - nil, - ).WithContextSetter(func(lintCtx *linter.Context) { - analyzer.Run = func(pass *analysis.Pass) (any, error) { - // The `gosecAnalyzer` is here because of concurrency issue. - gosecAnalyzer := gosec.NewAnalyzer(conf, true, settings.ExcludeGenerated, false, settings.Concurrency, logger) + return goanalysis. + NewLinterFromAnalyzer(analyzer). + WithContextSetter(func(lintCtx *linter.Context) { + analyzer.Run = func(pass *analysis.Pass) (any, error) { + // The `gosecAnalyzer` is here because of concurrency issue. + gosecAnalyzer := gosec.NewAnalyzer(conf, true, false, false, settings.Concurrency, logger) - gosecAnalyzer.LoadRules(ruleDefinitions.RulesInfo()) - gosecAnalyzer.LoadAnalyzers(analyzerDefinitions.AnalyzersInfo()) + gosecAnalyzer.LoadRules(ruleDefinitions.RulesInfo()) + gosecAnalyzer.LoadAnalyzers(analyzerDefinitions.AnalyzersInfo()) - issues := runGoSec(lintCtx, pass, settings, gosecAnalyzer) + issues := runGoSec(lintCtx, pass, settings, gosecAnalyzer) - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() - return nil, nil - } - }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeTypesInfo) + return nil, nil + } + }). + WithIssuesReporter(func(*linter.Context) []*goanalysis.Issue { + return resIssues + }). + WithLoadMode(goanalysis.LoadModeTypesInfo) } -func runGoSec(lintCtx *linter.Context, pass *analysis.Pass, settings *config.GoSecSettings, analyzer *gosec.Analyzer) []goanalysis.Issue { +func runGoSec(lintCtx *linter.Context, pass *analysis.Pass, settings *config.GoSecSettings, analyzer *gosec.Analyzer) []*goanalysis.Issue { pkg := &packages.Package{ Fset: pass.Fset, Syntax: pass.Files, @@ -108,7 +107,7 @@ func runGoSec(lintCtx *linter.Context, pass *analysis.Pass, settings *config.GoS secIssues = filterIssues(secIssues, severity, confidence) - issues := make([]goanalysis.Issue, 0, len(secIssues)) + issues := make([]*goanalysis.Issue, 0, len(secIssues)) for _, i := range secIssues { text := fmt.Sprintf("%s: %s", i.RuleID, i.What) @@ -184,7 +183,15 @@ func convertGosecGlobals(globalOptionFromConfig any, conf gosec.Config) { } for k, v := range globalOptionMap { - conf.SetGlobal(gosec.GlobalOption(k), fmt.Sprintf("%v", v)) + option := gosec.GlobalOption(k) + + // Set nosec global option only if the value is true + // https://github.com/securego/gosec/blob/v2.21.4/analyzer.go#L572 + if option == gosec.Nosec && v == false { + continue + } + + conf.SetGlobal(option, fmt.Sprintf("%v", v)) } } diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gosmopolitan/gosmopolitan.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gosmopolitan/gosmopolitan.go new file mode 100644 index 000000000..76261abe1 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/gosmopolitan/gosmopolitan.go @@ -0,0 +1,30 @@ +package gosmopolitan + +import ( + "strings" + + "github.com/xen0n/gosmopolitan" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.GosmopolitanSettings) *goanalysis.Linter { + var cfg map[string]any + + if settings != nil { + cfg = map[string]any{ + "allowtimelocal": settings.AllowTimeLocal, + "escapehatches": strings.Join(settings.EscapeHatches, ","), + "watchforscripts": strings.Join(settings.WatchForScripts, ","), + + // Should be managed with `linters.exclusions.rules`. + "lookattests": true, + } + } + + return goanalysis. + NewLinterFromAnalyzer(gosmopolitan.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/govet/govet.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/govet/govet.go similarity index 86% rename from vendor/github.com/golangci/golangci-lint/pkg/golinters/govet/govet.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/govet/govet.go index eb63a5d33..7755e4ec2 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/govet/govet.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/govet/govet.go @@ -2,7 +2,7 @@ package govet import ( "slices" - "sort" + "strings" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/appends" @@ -24,6 +24,8 @@ import ( "golang.org/x/tools/go/analysis/passes/fieldalignment" "golang.org/x/tools/go/analysis/passes/findcall" "golang.org/x/tools/go/analysis/passes/framepointer" + "golang.org/x/tools/go/analysis/passes/hostport" + "golang.org/x/tools/go/analysis/passes/httpmux" "golang.org/x/tools/go/analysis/passes/httpresponse" "golang.org/x/tools/go/analysis/passes/ifaceassert" _ "golang.org/x/tools/go/analysis/passes/inspect" // unused internal analyzer @@ -40,6 +42,7 @@ import ( "golang.org/x/tools/go/analysis/passes/slog" "golang.org/x/tools/go/analysis/passes/sortslice" "golang.org/x/tools/go/analysis/passes/stdmethods" + "golang.org/x/tools/go/analysis/passes/stdversion" "golang.org/x/tools/go/analysis/passes/stringintconv" "golang.org/x/tools/go/analysis/passes/structtag" "golang.org/x/tools/go/analysis/passes/testinggoroutine" @@ -50,10 +53,11 @@ import ( "golang.org/x/tools/go/analysis/passes/unsafeptr" "golang.org/x/tools/go/analysis/passes/unusedresult" "golang.org/x/tools/go/analysis/passes/unusedwrite" + "golang.org/x/tools/go/analysis/passes/waitgroup" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/logutils" ) var ( @@ -75,6 +79,8 @@ var ( fieldalignment.Analyzer, findcall.Analyzer, framepointer.Analyzer, + hostport.Analyzer, + httpmux.Analyzer, httpresponse.Analyzer, ifaceassert.Analyzer, loopclosure.Analyzer, @@ -89,6 +95,7 @@ var ( slog.Analyzer, sortslice.Analyzer, stdmethods.Analyzer, + stdversion.Analyzer, stringintconv.Analyzer, structtag.Analyzer, testinggoroutine.Analyzer, @@ -99,9 +106,10 @@ var ( unsafeptr.Analyzer, unusedresult.Analyzer, unusedwrite.Analyzer, + waitgroup.Analyzer, } - // https://github.com/golang/go/blob/b56645a87b28840a180d64077877cb46570b4176/src/cmd/vet/main.go#L49-L81 + // https://github.com/golang/go/blob/go1.25.2/src/cmd/vet/main.go#L57-L91 defaultAnalyzers = []*analysis.Analyzer{ appends.Analyzer, asmdecl.Analyzer, @@ -116,6 +124,7 @@ var ( directive.Analyzer, errorsas.Analyzer, framepointer.Analyzer, + hostport.Analyzer, httpresponse.Analyzer, ifaceassert.Analyzer, loopclosure.Analyzer, @@ -126,6 +135,7 @@ var ( sigchanyzer.Analyzer, slog.Analyzer, stdmethods.Analyzer, + stdversion.Analyzer, stringintconv.Analyzer, structtag.Analyzer, testinggoroutine.Analyzer, @@ -135,6 +145,7 @@ var ( unreachable.Analyzer, unsafeptr.Analyzer, unusedresult.Analyzer, + waitgroup.Analyzer, } ) @@ -159,8 +170,8 @@ func New(settings *config.GovetSettings) *goanalysis.Linter { } func analyzersFromConfig(settings *config.GovetSettings) []*analysis.Analyzer { - debugAnalyzersListf(allAnalyzers, "All available analyzers") - debugAnalyzersListf(defaultAnalyzers, "Default analyzers") + logAnalyzers("All available analyzers", allAnalyzers) + logAnalyzers("Default analyzers", defaultAnalyzers) if settings == nil { return defaultAnalyzers @@ -173,7 +184,7 @@ func analyzersFromConfig(settings *config.GovetSettings) []*analysis.Analyzer { } } - debugAnalyzersListf(enabledAnalyzers, "Enabled by config analyzers") + logAnalyzers("Enabled by config analyzers", enabledAnalyzers) return enabledAnalyzers } @@ -184,11 +195,6 @@ func isAnalyzerEnabled(name string, cfg *config.GovetSettings, defaultAnalyzers return false } - // Keeping for backward compatibility. - if cfg.CheckShadowing && name == shadow.Analyzer.Name { - return true - } - switch { case cfg.EnableAll: return !slices.Contains(cfg.Disable, name) @@ -207,7 +213,7 @@ func isAnalyzerEnabled(name string, cfg *config.GovetSettings, defaultAnalyzers } } -func debugAnalyzersListf(analyzers []*analysis.Analyzer, message string) { +func logAnalyzers(message string, analyzers []*analysis.Analyzer) { if !isDebug { return } @@ -217,7 +223,7 @@ func debugAnalyzersListf(analyzers []*analysis.Analyzer, message string) { analyzerNames = append(analyzerNames, a.Name) } - sort.Strings(analyzerNames) + slices.Sort(analyzerNames) - debugf("%s (%d): %s", message, len(analyzerNames), analyzerNames) + debugf("%s (%d): %s", message, len(analyzerNames), strings.Join(analyzerNames, ", ")) } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/grouper/grouper.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/grouper/grouper.go similarity index 64% rename from vendor/github.com/golangci/golangci-lint/pkg/golinters/grouper/grouper.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/grouper/grouper.go index aa6ce1ceb..ed3601617 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/grouper/grouper.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/grouper/grouper.go @@ -2,18 +2,16 @@ package grouper import ( grouper "github.com/leonklingele/grouper/pkg/analyzer" - "golang.org/x/tools/go/analysis" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.GrouperSettings) *goanalysis.Linter { - a := grouper.New() + var cfg map[string]any - linterCfg := map[string]map[string]any{} if settings != nil { - linterCfg[a.Name] = map[string]any{ + cfg = map[string]any{ "const-require-single-const": settings.ConstRequireSingleConst, "const-require-grouping": settings.ConstRequireGrouping, "import-require-single-import": settings.ImportRequireSingleImport, @@ -24,11 +22,9 @@ func New(settings *config.GrouperSettings) *goanalysis.Linter { "var-require-grouping": settings.VarRequireGrouping, } } - - return goanalysis.NewLinter( - a.Name, - "Analyze expression groups.", - []*analysis.Analyzer{a}, - linterCfg, - ).WithLoadMode(goanalysis.LoadModeSyntax) + return goanalysis. + NewLinterFromAnalyzer(grouper.New()). + WithDesc("Analyze expression groups."). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/iface/iface.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/iface/iface.go similarity index 80% rename from vendor/github.com/golangci/golangci-lint/pkg/golinters/iface/iface.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/iface/iface.go index 31f88160e..0a4a38abc 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/iface/iface.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/iface/iface.go @@ -5,11 +5,12 @@ import ( "github.com/uudashr/iface/identical" "github.com/uudashr/iface/opaque" + "github.com/uudashr/iface/unexported" "github.com/uudashr/iface/unused" "golang.org/x/tools/go/analysis" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.IfaceSettings) *goanalysis.Linter { @@ -28,9 +29,10 @@ func New(settings *config.IfaceSettings) *goanalysis.Linter { func analyzersFromSettings(settings *config.IfaceSettings) []*analysis.Analyzer { allAnalyzers := map[string]*analysis.Analyzer{ - "identical": identical.Analyzer, - "unused": unused.Analyzer, - "opaque": opaque.Analyzer, + "identical": identical.Analyzer, + "unused": unused.Analyzer, + "opaque": opaque.Analyzer, + "unexported": unexported.Analyzer, } if settings == nil || len(settings.Enable) == 0 { diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/importas/importas.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/importas/importas.go new file mode 100644 index 000000000..fa7a54300 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/importas/importas.go @@ -0,0 +1,67 @@ +package importas + +import ( + "fmt" + "strconv" + "strings" + + "github.com/julz/importas" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" +) + +func New(settings *config.ImportAsSettings) *goanalysis.Linter { + analyzer := importas.Analyzer + + return goanalysis. + NewLinterFromAnalyzer(analyzer). + WithContextSetter(func(lintCtx *linter.Context) { + if settings == nil { + return + } + if len(settings.Alias) == 0 { + lintCtx.Log.Infof("importas settings found, but no aliases listed. List aliases under alias: key.") + } + + if err := analyzer.Flags.Set("no-unaliased", strconv.FormatBool(settings.NoUnaliased)); err != nil { + lintCtx.Log.Errorf("failed to parse configuration: %v", err) + } + + if err := analyzer.Flags.Set("no-extra-aliases", strconv.FormatBool(settings.NoExtraAliases)); err != nil { + lintCtx.Log.Errorf("failed to parse configuration: %v", err) + } + + uniqPackages := make(map[string]config.ImportAsAlias) + uniqAliases := make(map[string]config.ImportAsAlias) + for _, a := range settings.Alias { + if a.Pkg == "" { + lintCtx.Log.Errorf("invalid configuration, empty package: pkg=%s alias=%s", a.Pkg, a.Alias) + continue + } + + if v, ok := uniqPackages[a.Pkg]; ok { + lintCtx.Log.Errorf("invalid configuration, multiple aliases for the same package: pkg=%s aliases=[%s,%s]", a.Pkg, a.Alias, v.Alias) + } else { + uniqPackages[a.Pkg] = a + } + + // Skips the duplication check when: + // - the alias is empty. + // - the alias is a regular expression replacement pattern (ie. contains `$`). + v, ok := uniqAliases[a.Alias] + if ok && a.Alias != "" && !strings.Contains(a.Alias, "$") { + lintCtx.Log.Errorf("invalid configuration, multiple packages with the same alias: alias=%s packages=[%s,%s]", a.Alias, a.Pkg, v.Pkg) + } else { + uniqAliases[a.Alias] = a + } + + err := analyzer.Flags.Set("alias", fmt.Sprintf("%s:%s", a.Pkg, a.Alias)) + if err != nil { + lintCtx.Log.Errorf("failed to parse configuration: %v", err) + } + } + }). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/inamedparam/inamedparam.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/inamedparam/inamedparam.go new file mode 100644 index 000000000..ecb6f7e50 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/inamedparam/inamedparam.go @@ -0,0 +1,23 @@ +package inamedparam + +import ( + "github.com/macabu/inamedparam" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.INamedParamSettings) *goanalysis.Linter { + var cfg map[string]any + + if settings != nil { + cfg = map[string]any{ + "skip-single-param": settings.SkipSingleParam, + } + } + + return goanalysis. + NewLinterFromAnalyzer(inamedparam.Analyzer). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/ineffassign/ineffassign.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/ineffassign/ineffassign.go new file mode 100644 index 000000000..1df737cbf --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/ineffassign/ineffassign.go @@ -0,0 +1,23 @@ +package ineffassign + +import ( + "github.com/gordonklaus/ineffassign/pkg/ineffassign" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.IneffassignSettings) *goanalysis.Linter { + var cfg map[string]any + + if settings != nil { + cfg = map[string]any{ + "check-escaping-errors": settings.CheckEscapingErrors, + } + } + + return goanalysis. + NewLinterFromAnalyzer(ineffassign.Analyzer). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/interfacebloat/interfacebloat.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/interfacebloat/interfacebloat.go new file mode 100644 index 000000000..f2e187423 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/interfacebloat/interfacebloat.go @@ -0,0 +1,23 @@ +package interfacebloat + +import ( + "github.com/sashamelentyev/interfacebloat/pkg/analyzer" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.InterfaceBloatSettings) *goanalysis.Linter { + var cfg map[string]any + + if settings != nil { + cfg = map[string]any{ + analyzer.InterfaceMaxMethodsFlag: settings.Max, + } + } + + return goanalysis. + NewLinterFromAnalyzer(analyzer.New()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/internal/commons.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/internal/commons.go similarity index 73% rename from vendor/github.com/golangci/golangci-lint/pkg/golinters/internal/commons.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/internal/commons.go index c21dd0092..d19c1fd45 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/internal/commons.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/internal/commons.go @@ -1,6 +1,6 @@ package internal -import "github.com/golangci/golangci-lint/pkg/logutils" +import "github.com/golangci/golangci-lint/v2/pkg/logutils" // LinterLogger must be use only when the context logger is not available. var LinterLogger = logutils.NewStderrLog(logutils.DebugKeyLinter) diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/internal/util.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/internal/util.go new file mode 100644 index 000000000..86137cf66 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/internal/util.go @@ -0,0 +1,33 @@ +package internal + +import ( + "fmt" + "strings" + + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func FormatCode(code string) string { + if strings.Contains(code, "`") { + return code // TODO: properly escape or remove + } + + return fmt.Sprintf("`%s`", code) +} + +func GetGoFileNames(pass *analysis.Pass) []string { + var filenames []string + + for _, f := range pass.Files { + position, b := goanalysis.GetGoFilePosition(pass, f) + if !b { + continue + } + + filenames = append(filenames, position.Filename) + } + + return filenames +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/intrange/intrange.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/intrange/intrange.go new file mode 100644 index 000000000..1ff02964c --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/intrange/intrange.go @@ -0,0 +1,13 @@ +package intrange + +import ( + "github.com/ckaznocha/intrange" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(intrange.Analyzer). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/iotamixing/iotamixing.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/iotamixing/iotamixing.go new file mode 100644 index 000000000..dee0c3c77 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/iotamixing/iotamixing.go @@ -0,0 +1,26 @@ +package iotamixing + +import ( + im "github.com/AdminBenni/iota-mixing/pkg/analyzer" + "github.com/AdminBenni/iota-mixing/pkg/analyzer/flags" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.IotaMixingSettings) *goanalysis.Linter { + cfg := map[string]any{} + + if settings != nil { + cfg[flags.ReportIndividualFlagName] = settings.ReportIndividual + } + + analyzer := im.GetIotaMixingAnalyzer() + + flags.SetupFlags(&analyzer.Flags) + + return goanalysis. + NewLinterFromAnalyzer(analyzer). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/ireturn/ireturn.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/ireturn/ireturn.go new file mode 100644 index 000000000..b9cce0001 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/ireturn/ireturn.go @@ -0,0 +1,27 @@ +package ireturn + +import ( + "strings" + + "github.com/butuzov/ireturn/analyzer" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.IreturnSettings) *goanalysis.Linter { + var cfg map[string]any + + if settings != nil { + cfg = map[string]any{ + "allow": strings.Join(settings.Allow, ","), + "reject": strings.Join(settings.Reject, ","), + "nonolint": true, + } + } + + return goanalysis. + NewLinterFromAnalyzer(analyzer.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/lll/lll.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/lll/lll.go new file mode 100644 index 000000000..c8e6717de --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/lll/lll.go @@ -0,0 +1,126 @@ +package lll + +import ( + "bufio" + "errors" + "fmt" + "go/ast" + "os" + "strings" + "unicode/utf8" + + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +const goCommentDirectivePrefix = "//go:" + +func New(settings *config.LllSettings) *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: "lll", + Doc: "Reports long lines", + Run: func(pass *analysis.Pass) (any, error) { + err := runLll(pass, settings) + if err != nil { + return nil, err + } + + return nil, nil + }, + }). + WithLoadMode(goanalysis.LoadModeSyntax) +} + +func runLll(pass *analysis.Pass, settings *config.LllSettings) error { + spaces := strings.Repeat(" ", settings.TabWidth) + + for _, file := range pass.Files { + err := getLLLIssuesForFile(pass, file, settings.LineLength, spaces) + if err != nil { + return err + } + } + + return nil +} + +func getLLLIssuesForFile(pass *analysis.Pass, file *ast.File, maxLineLen int, tabSpaces string) error { + position, isGoFile := goanalysis.GetGoFilePosition(pass, file) + if !isGoFile { + return nil + } + + nonAdjPosition := pass.Fset.PositionFor(file.Pos(), false) + + f, err := os.Open(position.Filename) + if err != nil { + return fmt.Errorf("can't open file %s: %w", position.Filename, err) + } + + defer f.Close() + + ft := pass.Fset.File(file.Pos()) + + lineNumber := 0 + multiImportEnabled := false + + scanner := bufio.NewScanner(f) + for scanner.Scan() { + lineNumber++ + + line := scanner.Text() + line = strings.ReplaceAll(line, "\t", tabSpaces) + + if strings.HasPrefix(line, goCommentDirectivePrefix) { + continue + } + + if strings.HasPrefix(line, "import") { + multiImportEnabled = strings.HasSuffix(line, "(") + continue + } + + if multiImportEnabled { + if line == ")" { + multiImportEnabled = false + } + + continue + } + + lineLen := utf8.RuneCountInString(line) + if lineLen > maxLineLen { + pass.Report(analysis.Diagnostic{ + Pos: ft.LineStart(goanalysis.AdjustPos(lineNumber, nonAdjPosition.Line, position.Line)), + Message: fmt.Sprintf("The line is %d characters long, which exceeds the maximum of %d characters.", + lineLen, maxLineLen), + }) + } + } + + if err := scanner.Err(); err != nil { + // scanner.Scan() might fail if the line is longer than bufio.MaxScanTokenSize + // In the case where the specified maxLineLen is smaller than bufio.MaxScanTokenSize + // we can return this line as a long line instead of returning an error. + // The reason for this change is that this case might happen with autogenerated files + // The go-bindata tool for instance might generate a file with a very long line. + // In this case, as it's an auto generated file, the warning returned by lll will + // be ignored. + // But if we return a linter error here, and this error happens for an autogenerated + // file the error will be discarded (fine), but all the subsequent errors for lll will + // be discarded for other files, and we'll miss legit error. + if errors.Is(err, bufio.ErrTooLong) && maxLineLen < bufio.MaxScanTokenSize { + pass.Report(analysis.Diagnostic{ + Pos: ft.LineStart(goanalysis.AdjustPos(lineNumber, nonAdjPosition.Line, position.Line)), + Message: fmt.Sprintf("line is more than %d characters", bufio.MaxScanTokenSize), + }) + } else { + return fmt.Errorf("can't scan file %s: %w", position.Filename, err) + } + } + + return nil +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/loggercheck/loggercheck.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/loggercheck/loggercheck.go similarity index 68% rename from vendor/github.com/golangci/golangci-lint/pkg/golinters/loggercheck/loggercheck.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/loggercheck/loggercheck.go index 077e8a512..b9a6efa75 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/loggercheck/loggercheck.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/loggercheck/loggercheck.go @@ -2,10 +2,9 @@ package loggercheck import ( "github.com/timonwong/loggercheck" - "golang.org/x/tools/go/analysis" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.LoggerCheckSettings) *goanalysis.Linter { @@ -22,6 +21,9 @@ func New(settings *config.LoggerCheckSettings) *goanalysis.Linter { if !settings.Logr { disable = append(disable, "logr") } + if !settings.Slog { + disable = append(disable, "slog") + } if !settings.Zap { disable = append(disable, "zap") } @@ -34,11 +36,7 @@ func New(settings *config.LoggerCheckSettings) *goanalysis.Linter { } } - analyzer := loggercheck.NewAnalyzer(opts...) - return goanalysis.NewLinter( - analyzer.Name, - analyzer.Doc, - []*analysis.Analyzer{analyzer}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(loggercheck.NewAnalyzer(opts...)). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/maintidx/maintidx.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/maintidx/maintidx.go new file mode 100644 index 000000000..f2076c8ab --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/maintidx/maintidx.go @@ -0,0 +1,23 @@ +package maintidx + +import ( + "github.com/yagipy/maintidx" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.MaintIdxSettings) *goanalysis.Linter { + cfg := map[string]any{ + "under": 20, + } + + if settings != nil { + cfg["under"] = settings.Under + } + + return goanalysis. + NewLinterFromAnalyzer(maintidx.Analyzer). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/makezero/makezero.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/makezero/makezero.go new file mode 100644 index 000000000..5ee298d99 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/makezero/makezero.go @@ -0,0 +1,48 @@ +package makezero + +import ( + "fmt" + + "github.com/ashanbrown/makezero/v2/makezero" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.MakezeroSettings) *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: "makezero", + Doc: "Find slice declarations with non-zero initial length", + Run: func(pass *analysis.Pass) (any, error) { + err := runMakeZero(pass, settings) + if err != nil { + return nil, err + } + + return nil, nil + }, + }). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} + +func runMakeZero(pass *analysis.Pass, settings *config.MakezeroSettings) error { + zero := makezero.NewLinter(settings.Always) + + for _, file := range pass.Files { + hints, err := zero.Run(pass.Fset, pass.TypesInfo, file) + if err != nil { + return fmt.Errorf("makezero linter failed on file %q: %w", file.Name.String(), err) + } + + for _, hint := range hints { + pass.Report(analysis.Diagnostic{ + Pos: hint.Pos(), + Message: hint.Details(), + }) + } + } + + return nil +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/mirror/mirror.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/mirror/mirror.go new file mode 100644 index 000000000..07cfe25e4 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/mirror/mirror.go @@ -0,0 +1,23 @@ +package mirror + +import ( + "github.com/butuzov/mirror" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + // mirror only lints test files if the `--with-tests` flag is passed, + // so we pass the `with-tests` flag as true to the analyzer before running it. + // This can be turned off by using the regular golangci-lint flags such as `--tests` or `--skip-files` + // or can be disabled per linter via exclude rules. + // (see https://github.com/golangci/golangci-lint/issues/2527#issuecomment-1023707262) + cfg := map[string]any{ + "with-tests": true, + } + + return goanalysis. + NewLinterFromAnalyzer(mirror.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/misspell/misspell.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/misspell/misspell.go similarity index 50% rename from vendor/github.com/golangci/golangci-lint/pkg/golinters/misspell/misspell.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/misspell/misspell.go index 44409cec9..cbf378505 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/misspell/misspell.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/misspell/misspell.go @@ -2,82 +2,43 @@ package misspell import ( "fmt" + "go/ast" "go/token" "strings" - "sync" "unicode" "github.com/golangci/misspell" "golang.org/x/tools/go/analysis" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/golinters/internal" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" ) const linterName = "misspell" func New(settings *config.MisspellSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - analyzer := &analysis.Analyzer{ - Name: linterName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: goanalysis.DummyRun, + replacer, err := createMisspellReplacer(settings) + if err != nil { + internal.LinterLogger.Fatalf("%s: %v", linterName, err) } - return goanalysis.NewLinter( - linterName, - "Finds commonly misspelled English words", - []*analysis.Analyzer{analyzer}, - nil, - ).WithContextSetter(func(lintCtx *linter.Context) { - replacer, ruleErr := createMisspellReplacer(settings) - - analyzer.Run = func(pass *analysis.Pass) (any, error) { - if ruleErr != nil { - return nil, ruleErr - } - - issues, err := runMisspell(lintCtx, pass, replacer, settings.Mode) - if err != nil { - return nil, err - } - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - } - }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) -} - -func runMisspell(lintCtx *linter.Context, pass *analysis.Pass, replacer *misspell.Replacer, mode string) ([]goanalysis.Issue, error) { - fileNames := internal.GetFileNames(pass) - - var issues []goanalysis.Issue - for _, filename := range fileNames { - lintIssues, err := runMisspellOnFile(lintCtx, filename, replacer, mode) - if err != nil { - return nil, err - } - - for i := range lintIssues { - issues = append(issues, goanalysis.NewIssue(&lintIssues[i], pass)) - } - } + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: linterName, + Doc: "Finds commonly misspelled English words", + Run: func(pass *analysis.Pass) (any, error) { + for _, file := range pass.Files { + err := runMisspellOnFile(pass, file, replacer, settings.Mode) + if err != nil { + return nil, err + } + } - return issues, nil + return nil, nil + }, + }). + WithLoadMode(goanalysis.LoadModeSyntax) } func createMisspellReplacer(settings *config.MisspellSettings) (*misspell.Replacer, error) { @@ -102,8 +63,8 @@ func createMisspellReplacer(settings *config.MisspellSettings) (*misspell.Replac return nil, fmt.Errorf("process extra words: %w", err) } - if len(settings.IgnoreWords) != 0 { - replacer.RemoveRule(settings.IgnoreWords) + if len(settings.IgnoreRules) != 0 { + replacer.RemoveRule(settings.IgnoreRules) } // It can panic. @@ -112,10 +73,17 @@ func createMisspellReplacer(settings *config.MisspellSettings) (*misspell.Replac return replacer, nil } -func runMisspellOnFile(lintCtx *linter.Context, filename string, replacer *misspell.Replacer, mode string) ([]result.Issue, error) { - fileContent, err := lintCtx.FileCache.GetFileBytes(filename) +func runMisspellOnFile(pass *analysis.Pass, file *ast.File, replacer *misspell.Replacer, mode string) error { + position, isGoFile := goanalysis.GetGoFilePosition(pass, file) + if !isGoFile { + return nil + } + + // Uses the non-adjusted file to work with cgo: + // if we read the real file, the positions are wrong in some cases. + fileContent, err := pass.ReadFile(pass.Fset.PositionFor(file.Pos(), false).Filename) if err != nil { - return nil, fmt.Errorf("can't get file %s contents: %w", filename, err) + return fmt.Errorf("can't get file %s contents: %w", position.Filename, err) } // `r.ReplaceGo` doesn't find issues inside strings: it searches only inside comments. @@ -129,36 +97,31 @@ func runMisspellOnFile(lintCtx *linter.Context, filename string, replacer *missp replace = replacer.Replace } - _, diffs := replace(string(fileContent)) + f := pass.Fset.File(file.Pos()) - var res []result.Issue + _, diffs := replace(string(fileContent)) for _, diff := range diffs { text := fmt.Sprintf("`%s` is a misspelling of `%s`", diff.Original, diff.Corrected) - pos := token.Position{ - Filename: filename, - Line: diff.Line, - Column: diff.Column + 1, - } - - replacement := &result.Replacement{ - Inline: &result.InlineFix{ - StartCol: diff.Column, - Length: len(diff.Original), - NewString: diff.Corrected, - }, - } - - res = append(res, result.Issue{ - Pos: pos, - Text: text, - FromLinter: linterName, - Replacement: replacement, + start := f.LineStart(diff.Line) + token.Pos(diff.Column) + end := f.LineStart(diff.Line) + token.Pos(diff.Column+len(diff.Original)) + + pass.Report(analysis.Diagnostic{ + Pos: start, + End: end, + Message: text, + SuggestedFixes: []analysis.SuggestedFix{{ + TextEdits: []analysis.TextEdit{{ + Pos: start, + End: end, + NewText: []byte(diff.Corrected), + }}, + }}, }) } - return res, nil + return nil } func appendExtraWords(replacer *misspell.Replacer, extraWords []config.MisspellExtraWords) error { diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/mnd/mnd.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/mnd/mnd.go new file mode 100644 index 000000000..07174c899 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/mnd/mnd.go @@ -0,0 +1,33 @@ +package mnd + +import ( + mnd "github.com/tommy-muehle/go-mnd/v2" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.MndSettings) *goanalysis.Linter { + cfg := map[string]any{} + + if settings != nil { + if len(settings.Checks) > 0 { + cfg["checks"] = settings.Checks + } + if len(settings.IgnoredNumbers) > 0 { + cfg["ignored-numbers"] = settings.IgnoredNumbers + } + if len(settings.IgnoredFiles) > 0 { + cfg["ignored-files"] = settings.IgnoredFiles + } + if len(settings.IgnoredFunctions) > 0 { + cfg["ignored-functions"] = settings.IgnoredFunctions + } + } + + return goanalysis. + NewLinterFromAnalyzer(mnd.Analyzer). + WithDesc("An analyzer to detect magic numbers."). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/modernize/modernize.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/modernize/modernize.go new file mode 100644 index 000000000..97825c07e --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/modernize/modernize.go @@ -0,0 +1,34 @@ +package modernize + +import ( + "slices" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/modernize" +) + +func New(settings *config.ModernizeSettings) *goanalysis.Linter { + var analyzers []*analysis.Analyzer + + if settings == nil { + analyzers = modernize.Suite + } else { + for _, analyzer := range modernize.Suite { + if slices.Contains(settings.Disable, analyzer.Name) { + continue + } + + analyzers = append(analyzers, analyzer) + } + } + + return goanalysis.NewLinter( + "modernize", + "A suite of analyzers that suggest simplifications to Go code, using modern language and library features.", + analyzers, + nil). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/musttag/musttag.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/musttag/musttag.go new file mode 100644 index 000000000..d17df9c2b --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/musttag/musttag.go @@ -0,0 +1,26 @@ +package musttag + +import ( + "go-simpler.org/musttag" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.MustTagSettings) *goanalysis.Linter { + var funcs []musttag.Func + + if settings != nil { + for _, fn := range settings.Functions { + funcs = append(funcs, musttag.Func{ + Name: fn.Name, + Tag: fn.Tag, + ArgPos: fn.ArgPos, + }) + } + } + + return goanalysis. + NewLinterFromAnalyzer(musttag.New(funcs...)). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nakedret/nakedret.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nakedret/nakedret.go new file mode 100644 index 000000000..90053a1aa --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nakedret/nakedret.go @@ -0,0 +1,21 @@ +package nakedret + +import ( + "github.com/alexkohler/nakedret/v2" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.NakedretSettings) *goanalysis.Linter { + cfg := &nakedret.NakedReturnRunner{} + + if settings != nil { + // SkipTestFiles is intentionally ignored => should be managed with `linters.exclusions.rules`. + cfg.MaxLength = settings.MaxFuncLines + } + + return goanalysis. + NewLinterFromAnalyzer(nakedret.NakedReturnAnalyzer(cfg)). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nestif/nestif.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nestif/nestif.go new file mode 100644 index 000000000..e5823723c --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nestif/nestif.go @@ -0,0 +1,52 @@ +package nestif + +import ( + "github.com/nakabonne/nestif" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.NestifSettings) *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: "nestif", + Doc: "Reports deeply nested if statements", + Run: func(pass *analysis.Pass) (any, error) { + runNestIf(pass, settings) + + return nil, nil + }, + }). + WithLoadMode(goanalysis.LoadModeSyntax) +} + +func runNestIf(pass *analysis.Pass, settings *config.NestifSettings) { + checker := &nestif.Checker{ + MinComplexity: settings.MinComplexity, + } + + for _, file := range pass.Files { + position, isGoFile := goanalysis.GetGoFilePosition(pass, file) + if !isGoFile { + continue + } + + issues := checker.Check(file, pass.Fset) + if len(issues) == 0 { + continue + } + + nonAdjPosition := pass.Fset.PositionFor(file.Pos(), false) + + f := pass.Fset.File(file.Pos()) + + for _, issue := range issues { + pass.Report(analysis.Diagnostic{ + Pos: f.LineStart(goanalysis.AdjustPos(issue.Pos.Line, nonAdjPosition.Line, position.Line)), + Message: issue.Message, + }) + } + } +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nilerr/nilerr.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nilerr/nilerr.go new file mode 100644 index 000000000..fa5dcdc25 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nilerr/nilerr.go @@ -0,0 +1,14 @@ +package nilerr + +import ( + "github.com/gostaticanalysis/nilerr" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(nilerr.Analyzer). + WithDesc("Find the code that returns nil even if it checks that the error is not nil."). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nilnesserr/nilnesserr.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nilnesserr/nilnesserr.go new file mode 100644 index 000000000..95eaf94ab --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nilnesserr/nilnesserr.go @@ -0,0 +1,19 @@ +package nilnesserr + +import ( + "github.com/alingse/nilnesserr" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" +) + +func New() *goanalysis.Linter { + analyzer, err := nilnesserr.NewAnalyzer(nilnesserr.LinterSetting{}) + if err != nil { + internal.LinterLogger.Fatalf("nilnesserr: create analyzer: %v", err) + } + + return goanalysis. + NewLinterFromAnalyzer(analyzer). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nilnil/nilnil.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nilnil/nilnil.go new file mode 100644 index 000000000..4936a6b84 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nilnil/nilnil.go @@ -0,0 +1,29 @@ +package nilnil + +import ( + "github.com/Antonboom/nilnil/pkg/analyzer" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.NilNilSettings) *goanalysis.Linter { + var cfg map[string]any + + if settings != nil { + cfg = map[string]any{ + "detect-opposite": settings.DetectOpposite, + } + if b := settings.OnlyTwo; b != nil { + cfg["only-two"] = *b + } + if len(settings.CheckedTypes) != 0 { + cfg["checked-types"] = settings.CheckedTypes + } + } + + return goanalysis. + NewLinterFromAnalyzer(analyzer.New()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nlreturn/nlreturn.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nlreturn/nlreturn.go new file mode 100644 index 000000000..7b7ab745a --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nlreturn/nlreturn.go @@ -0,0 +1,23 @@ +package nlreturn + +import ( + "github.com/ssgreg/nlreturn/v2/pkg/nlreturn" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.NlreturnSettings) *goanalysis.Linter { + var cfg map[string]any + + if settings != nil { + cfg = map[string]any{ + "block-size": settings.BlockSize, + } + } + return goanalysis. + NewLinterFromAnalyzer(nlreturn.NewAnalyzer()). + WithDesc("Checks for a new line before return and branch statements to increase code clarity"). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/noctx/noctx.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/noctx/noctx.go new file mode 100644 index 000000000..c3e5be104 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/noctx/noctx.go @@ -0,0 +1,14 @@ +package noctx + +import ( + "github.com/sonatard/noctx" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(noctx.Analyzer). + WithDesc("Detects function and method with missing usage of context.Context"). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/noinlineerr/noinlineerr.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/noinlineerr/noinlineerr.go new file mode 100644 index 000000000..4f9f82eb4 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/noinlineerr/noinlineerr.go @@ -0,0 +1,13 @@ +package noinlineerr + +import ( + "github.com/AlwxSin/noinlineerr" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(noinlineerr.NewAnalyzer()). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nolintlint/internal/README.md b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nolintlint/internal/README.md similarity index 100% rename from vendor/github.com/golangci/golangci-lint/pkg/golinters/nolintlint/internal/README.md rename to vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nolintlint/internal/README.md diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nolintlint/internal/issues.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nolintlint/internal/issues.go new file mode 100644 index 000000000..5e9ba4117 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nolintlint/internal/issues.go @@ -0,0 +1,41 @@ +package internal + +import ( + "fmt" + "strings" + "unicode" +) + +func formatExtraLeadingSpace(fullDirective string) string { + return fmt.Sprintf("directive `%s` should not have more than one leading space", fullDirective) +} + +func formatNotMachine(fullDirective string) string { + expected := fullDirective[:2] + strings.TrimLeftFunc(fullDirective[2:], unicode.IsSpace) + return fmt.Sprintf("directive `%s` should be written without leading space as `%s`", + fullDirective, expected) +} + +func formatNotSpecific(fullDirective, directiveWithOptionalLeadingSpace string) string { + return fmt.Sprintf("directive `%s` should mention specific linter such as `%s:my-linter`", + fullDirective, directiveWithOptionalLeadingSpace) +} + +func formatParseError(fullDirective, directiveWithOptionalLeadingSpace string) string { + return fmt.Sprintf("directive `%s` should match `%s[:] [// ]`", + fullDirective, + directiveWithOptionalLeadingSpace) +} + +func formatNoExplanation(fullDirective, fullDirectiveWithoutExplanation string) string { + return fmt.Sprintf("directive `%s` should provide explanation such as `%s // this is why`", + fullDirective, fullDirectiveWithoutExplanation) +} + +func formatUnusedCandidate(fullDirective, expectedLinter string) string { + details := fmt.Sprintf("directive `%s` is unused", fullDirective) + if expectedLinter != "" { + details += fmt.Sprintf(" for linter %q", expectedLinter) + } + return details +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nolintlint/internal/nolintlint.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nolintlint/internal/nolintlint.go new file mode 100644 index 000000000..a20161405 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nolintlint/internal/nolintlint.go @@ -0,0 +1,232 @@ +// Package internal provides a linter to ensure that all //nolint directives are followed by explanations +package internal + +import ( + "go/token" + "regexp" + "strings" + + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/result" +) + +const LinterName = "nolintlint" + +const ( + NeedsMachineOnly Needs = 1 << iota + NeedsSpecific + NeedsExplanation + NeedsUnused + NeedsAll = NeedsMachineOnly | NeedsSpecific | NeedsExplanation +) + +type Needs uint + +const commentMark = "//" + +var commentPattern = regexp.MustCompile(`^//\s*(nolint)(:\s*[\w-]+\s*(?:,\s*[\w-]+\s*)*)?\b`) + +// matches a complete nolint directive +var fullDirectivePattern = regexp.MustCompile(`^//\s*nolint(?::(\s*[\w-]+\s*(?:,\s*[\w-]+\s*)*))?\s*(//.*)?\s*\n?$`) + +type Linter struct { + needs Needs // indicates which linter checks to perform + excludeByLinter map[string]bool +} + +// NewLinter creates a linter that enforces that the provided directives fulfill the provided requirements +func NewLinter(needs Needs, excludes []string) (*Linter, error) { + excludeByName := make(map[string]bool) + for _, e := range excludes { + excludeByName[e] = true + } + + return &Linter{ + needs: needs | NeedsMachineOnly, + excludeByLinter: excludeByName, + }, nil +} + +var ( + leadingSpacePattern = regexp.MustCompile(`^//(\s*)`) + trailingBlankExplanation = regexp.MustCompile(`\s*(//\s*)?$`) +) + +//nolint:funlen,gocyclo // the function is going to be refactored in the future +func (l Linter) Run(pass *analysis.Pass) ([]*goanalysis.Issue, error) { + var issues []*goanalysis.Issue + + for _, file := range pass.Files { + for _, c := range file.Comments { + for _, comment := range c.List { + if !commentPattern.MatchString(comment.Text) { + continue + } + + // check for a space between the "//" and the directive + leadingSpaceMatches := leadingSpacePattern.FindStringSubmatch(comment.Text) + + var leadingSpace string + if len(leadingSpaceMatches) > 0 { + leadingSpace = leadingSpaceMatches[1] + } + + directiveWithOptionalLeadingSpace := commentMark + if leadingSpace != "" { + directiveWithOptionalLeadingSpace += " " + } + + split := strings.Split(strings.SplitN(comment.Text, ":", 2)[0], commentMark) + directiveWithOptionalLeadingSpace += strings.TrimSpace(split[1]) + + pos := pass.Fset.Position(comment.Pos()) + end := pass.Fset.Position(comment.End()) + + // check for, report and eliminate leading spaces, so we can check for other issues + if leadingSpace != "" { + removeWhitespace := []analysis.SuggestedFix{{ + TextEdits: []analysis.TextEdit{{ + Pos: token.Pos(pos.Offset), + End: token.Pos(pos.Offset + len(commentMark) + len(leadingSpace)), + NewText: []byte(commentMark), + }}, + }} + + if (l.needs & NeedsMachineOnly) != 0 { + issue := &result.Issue{ + FromLinter: LinterName, + Text: formatNotMachine(comment.Text), + Pos: pos, + SuggestedFixes: removeWhitespace, + } + + issues = append(issues, goanalysis.NewIssue(issue, pass)) + } else if len(leadingSpace) > 1 { + issue := &result.Issue{ + FromLinter: LinterName, + Text: formatExtraLeadingSpace(comment.Text), + Pos: pos, + SuggestedFixes: removeWhitespace, + } + + issues = append(issues, goanalysis.NewIssue(issue, pass)) + } + } + + fullMatches := fullDirectivePattern.FindStringSubmatch(comment.Text) + if len(fullMatches) == 0 { + issue := &result.Issue{ + FromLinter: LinterName, + Text: formatParseError(comment.Text, directiveWithOptionalLeadingSpace), + Pos: pos, + } + + issues = append(issues, goanalysis.NewIssue(issue, pass)) + + continue + } + + lintersText, explanation := fullMatches[1], fullMatches[2] + + var linters []string + if lintersText != "" && !strings.HasPrefix(lintersText, "all") { + lls := strings.Split(lintersText, ",") + linters = make([]string, 0, len(lls)) + rangeStart := (pos.Column - 1) + len(commentMark) + len(leadingSpace) + len("nolint:") + for i, ll := range lls { + rangeEnd := rangeStart + len(ll) + if i < len(lls)-1 { + rangeEnd++ // include trailing comma + } + trimmedLinterName := strings.TrimSpace(ll) + if trimmedLinterName != "" { + linters = append(linters, trimmedLinterName) + } + rangeStart = rangeEnd + } + } + + if (l.needs & NeedsSpecific) != 0 { + if len(linters) == 0 { + issue := &result.Issue{ + FromLinter: LinterName, + Text: formatNotSpecific(comment.Text, directiveWithOptionalLeadingSpace), + Pos: pos, + } + + issues = append(issues, goanalysis.NewIssue(issue, pass)) + } + } + + // when detecting unused directives, we send all the directives through and filter them out in the nolint processor + if (l.needs & NeedsUnused) != 0 { + removeNolintCompletely := []analysis.SuggestedFix{{ + TextEdits: []analysis.TextEdit{{ + Pos: token.Pos(pos.Offset), + End: token.Pos(end.Offset), + NewText: nil, + }}, + }} + + if len(linters) == 0 { + issue := &result.Issue{ + FromLinter: LinterName, + Text: formatUnusedCandidate(comment.Text, ""), + Pos: pos, + ExpectNoLint: true, + SuggestedFixes: removeNolintCompletely, + } + + issues = append(issues, goanalysis.NewIssue(issue, pass)) + } else { + for _, linter := range linters { + issue := &result.Issue{ + FromLinter: LinterName, + Text: formatUnusedCandidate(comment.Text, linter), + Pos: pos, + ExpectNoLint: true, + ExpectedNoLintLinter: linter, + } + + // only offer SuggestedFix if there is a single linter + // because of issues around commas and the possibility of all + // linters being removed + if len(linters) == 1 { + issue.SuggestedFixes = removeNolintCompletely + } + + issues = append(issues, goanalysis.NewIssue(issue, pass)) + } + } + } + + if (l.needs&NeedsExplanation) != 0 && (explanation == "" || strings.TrimSpace(explanation) == commentMark) { + needsExplanation := len(linters) == 0 // if no linters are mentioned, we must have explanation + // otherwise, check if we are excluding all the mentioned linters + for _, ll := range linters { + if !l.excludeByLinter[ll] { // if a linter does require explanation + needsExplanation = true + break + } + } + + if needsExplanation { + fullDirectiveWithoutExplanation := trailingBlankExplanation.ReplaceAllString(comment.Text, "") + + issue := &result.Issue{ + FromLinter: LinterName, + Text: formatNoExplanation(comment.Text, fullDirectiveWithoutExplanation), + Pos: pos, + } + + issues = append(issues, goanalysis.NewIssue(issue, pass)) + } + } + } + } + } + + return issues, nil +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nolintlint/nolintlint.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nolintlint/nolintlint.go new file mode 100644 index 000000000..6f3d37306 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nolintlint/nolintlint.go @@ -0,0 +1,63 @@ +package nolintlint + +import ( + "fmt" + "sync" + + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" + nolintlint "github.com/golangci/golangci-lint/v2/pkg/golinters/nolintlint/internal" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" +) + +const LinterName = nolintlint.LinterName + +func New(settings *config.NoLintLintSettings) *goanalysis.Linter { + var mu sync.Mutex + var resIssues []*goanalysis.Issue + + var needs nolintlint.Needs + if settings.RequireExplanation { + needs |= nolintlint.NeedsExplanation + } + if settings.RequireSpecific { + needs |= nolintlint.NeedsSpecific + } + if !settings.AllowUnused { + needs |= nolintlint.NeedsUnused + } + + lnt, err := nolintlint.NewLinter(needs, settings.AllowNoExplanation) + if err != nil { + internal.LinterLogger.Fatalf("%s: create analyzer: %v", nolintlint.LinterName, err) + } + + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: nolintlint.LinterName, + Doc: "Reports ill-formed or insufficient nolint directives", + Run: func(pass *analysis.Pass) (any, error) { + issues, err := lnt.Run(pass) + if err != nil { + return nil, fmt.Errorf("linter failed to run: %w", err) + } + + if len(issues) == 0 { + return nil, nil + } + + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() + + return nil, nil + }, + }). + WithIssuesReporter(func(*linter.Context) []*goanalysis.Issue { + return resIssues + }). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nonamedreturns/nonamedreturns.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nonamedreturns/nonamedreturns.go new file mode 100644 index 000000000..4149ef818 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nonamedreturns/nonamedreturns.go @@ -0,0 +1,23 @@ +package nonamedreturns + +import ( + "github.com/firefart/nonamedreturns/analyzer" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.NoNamedReturnsSettings) *goanalysis.Linter { + var cfg map[string]any + + if settings != nil { + cfg = map[string]any{ + analyzer.FlagReportErrorInDefer: settings.ReportErrorInDefer, + } + } + + return goanalysis. + NewLinterFromAnalyzer(analyzer.Analyzer). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nosprintfhostport/nosprintfhostport.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nosprintfhostport/nosprintfhostport.go new file mode 100644 index 000000000..f8ca26b73 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/nosprintfhostport/nosprintfhostport.go @@ -0,0 +1,13 @@ +package nosprintfhostport + +import ( + "github.com/stbenjam/no-sprintf-host-port/pkg/analyzer" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(analyzer.Analyzer). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/paralleltest/paralleltest.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/paralleltest/paralleltest.go new file mode 100644 index 000000000..f3eac2e05 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/paralleltest/paralleltest.go @@ -0,0 +1,29 @@ +package paralleltest + +import ( + "github.com/kunwardeep/paralleltest/pkg/paralleltest" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.ParallelTestSettings) *goanalysis.Linter { + var cfg map[string]any + + if settings != nil { + cfg = map[string]any{ + "i": settings.IgnoreMissing, + "ignoremissingsubtests": settings.IgnoreMissingSubtests, + } + + if config.IsGoGreaterThanOrEqual(settings.Go, "1.22") { + cfg["ignoreloopVar"] = true + } + } + + return goanalysis. + NewLinterFromAnalyzer(paralleltest.NewAnalyzer()). + WithDesc("Detects missing usage of t.Parallel() method in your Go test"). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/perfsprint/perfsprint.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/perfsprint/perfsprint.go new file mode 100644 index 000000000..e06b5c2a9 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/perfsprint/perfsprint.go @@ -0,0 +1,40 @@ +package perfsprint + +import ( + "github.com/catenacyber/perfsprint/analyzer" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.PerfSprintSettings) *goanalysis.Linter { + cfg := map[string]any{ + "fiximports": false, + } + + if settings != nil { + // NOTE: The option `ignore-tests` is not handled because it should be managed with `linters.exclusions.rules` + + cfg["integer-format"] = settings.IntegerFormat + cfg["int-conversion"] = settings.IntConversion + + cfg["error-format"] = settings.ErrorFormat + cfg["err-error"] = settings.ErrError + cfg["errorf"] = settings.ErrorF + + cfg["string-format"] = settings.StringFormat + cfg["sprintf1"] = settings.SprintF1 + cfg["strconcat"] = settings.StrConcat + + cfg["bool-format"] = settings.BoolFormat + cfg["hex-format"] = settings.HexFormat + + cfg["concat-loop"] = settings.ConcatLoop + cfg["loop-other-ops"] = settings.LoopOtherOps + } + + return goanalysis. + NewLinterFromAnalyzer(analyzer.New()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/prealloc/prealloc.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/prealloc/prealloc.go new file mode 100644 index 000000000..cc209feff --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/prealloc/prealloc.go @@ -0,0 +1,23 @@ +package prealloc + +import ( + "github.com/alexkohler/prealloc/pkg" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.PreallocSettings) *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: "prealloc", + Doc: "Find slice declarations that could potentially be pre-allocated", + Run: func(pass *analysis.Pass) (any, error) { + pkg.Check(pass, settings.Simple, settings.RangeLoops, settings.ForLoops) + + return nil, nil + }, + }). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/predeclared/predeclared.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/predeclared/predeclared.go new file mode 100644 index 000000000..8f2be53c4 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/predeclared/predeclared.go @@ -0,0 +1,26 @@ +package predeclared + +import ( + "strings" + + "github.com/nishanths/predeclared/passes/predeclared" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.PredeclaredSettings) *goanalysis.Linter { + var cfg map[string]any + + if settings != nil { + cfg = map[string]any{ + predeclared.IgnoreFlag: strings.Join(settings.Ignore, ","), + predeclared.QualifiedFlag: settings.Qualified, + } + } + + return goanalysis. + NewLinterFromAnalyzer(predeclared.Analyzer). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/promlinter/promlinter.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/promlinter/promlinter.go new file mode 100644 index 000000000..491409f4e --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/promlinter/promlinter.go @@ -0,0 +1,73 @@ +package promlinter + +import ( + "fmt" + "sync" + + "github.com/yeya24/promlinter" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/result" +) + +const linterName = "promlinter" + +func New(settings *config.PromlinterSettings) *goanalysis.Linter { + var mu sync.Mutex + var resIssues []*goanalysis.Issue + + var promSettings promlinter.Setting + if settings != nil { + promSettings = promlinter.Setting{ + Strict: settings.Strict, + DisabledLintFuncs: settings.DisabledLinters, + } + } + + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: linterName, + Doc: "Check Prometheus metrics naming via promlint", + Run: func(pass *analysis.Pass) (any, error) { + issues := runPromLinter(pass, promSettings) + + if len(issues) == 0 { + return nil, nil + } + + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() + + return nil, nil + }, + }). + WithIssuesReporter(func(*linter.Context) []*goanalysis.Issue { + return resIssues + }). + WithLoadMode(goanalysis.LoadModeSyntax) +} + +func runPromLinter(pass *analysis.Pass, promSettings promlinter.Setting) []*goanalysis.Issue { + lintIssues := promlinter.RunLint(pass.Fset, pass.Files, promSettings) + + if len(lintIssues) == 0 { + return nil + } + + issues := make([]*goanalysis.Issue, len(lintIssues)) + for k, i := range lintIssues { + issue := result.Issue{ + Pos: i.Pos, + Text: fmt.Sprintf("Metric: %s Error: %s", i.Metric, i.Text), + FromLinter: linterName, + } + + issues[k] = goanalysis.NewIssue(&issue, pass) + } + + return issues +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/protogetter/protogetter.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/protogetter/protogetter.go new file mode 100644 index 000000000..bee5da263 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/protogetter/protogetter.go @@ -0,0 +1,25 @@ +package protogetter + +import ( + "github.com/ghostiam/protogetter" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.ProtoGetterSettings) *goanalysis.Linter { + var cfg protogetter.Config + + if settings != nil { + cfg = protogetter.Config{ + SkipGeneratedBy: settings.SkipGeneratedBy, + SkipFiles: settings.SkipFiles, + SkipAnyGenerated: settings.SkipAnyGenerated, + ReplaceFirstArgInAppend: settings.ReplaceFirstArgInAppend, + } + } + + return goanalysis. + NewLinterFromAnalyzer(protogetter.NewAnalyzer(&cfg)). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/reassign/reassign.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/reassign/reassign.go new file mode 100644 index 000000000..35e661cae --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/reassign/reassign.go @@ -0,0 +1,26 @@ +package reassign + +import ( + "fmt" + "strings" + + "github.com/curioswitch/go-reassign" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.ReassignSettings) *goanalysis.Linter { + var cfg map[string]any + + if settings != nil && len(settings.Patterns) > 0 { + cfg = map[string]any{ + reassign.FlagPattern: fmt.Sprintf("^(%s)$", strings.Join(settings.Patterns, "|")), + } + } + + return goanalysis. + NewLinterFromAnalyzer(reassign.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/recvcheck/recvcheck.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/recvcheck/recvcheck.go new file mode 100644 index 000000000..76db48f93 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/recvcheck/recvcheck.go @@ -0,0 +1,21 @@ +package recvcheck + +import ( + "github.com/raeperd/recvcheck" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.RecvcheckSettings) *goanalysis.Linter { + var cfg recvcheck.Settings + + if settings != nil { + cfg.DisableBuiltin = settings.DisableBuiltin + cfg.Exclusions = settings.Exclusions + } + + return goanalysis. + NewLinterFromAnalyzer(recvcheck.NewAnalyzer(cfg)). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/revive/revive.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/revive/revive.go similarity index 54% rename from vendor/github.com/golangci/golangci-lint/pkg/golinters/revive/revive.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/revive/revive.go index 056a258e0..9dc845371 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/revive/revive.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/revive/revive.go @@ -2,11 +2,13 @@ package revive import ( "bytes" - "encoding/json" + "cmp" "fmt" "go/token" "os" "reflect" + "slices" + "strings" "sync" "github.com/BurntSushi/toml" @@ -16,70 +18,65 @@ import ( "github.com/mgechev/revive/rule" "golang.org/x/tools/go/analysis" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/golinters/internal" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/logutils" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result" ) const linterName = "revive" -var debugf = logutils.Debug(logutils.DebugKeyRevive) - -// jsonObject defines a JSON object of a failure -type jsonObject struct { - Severity lint.Severity - lint.Failure `json:",inline"` -} +var ( + debugf = logutils.Debug(logutils.DebugKeyRevive) + isDebug = logutils.HaveDebugTag(logutils.DebugKeyRevive) +) func New(settings *config.ReviveSettings) *goanalysis.Linter { var mu sync.Mutex - var resIssues []goanalysis.Issue + var resIssues []*goanalysis.Issue analyzer := &analysis.Analyzer{ - Name: goanalysis.TheOnlyAnalyzerName, - Doc: goanalysis.TheOnlyanalyzerDoc, + Name: linterName, + Doc: "Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint.", Run: goanalysis.DummyRun, } - return goanalysis.NewLinter( - linterName, - "Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint.", - []*analysis.Analyzer{analyzer}, - nil, - ).WithContextSetter(func(lintCtx *linter.Context) { - w, err := newWrapper(settings) - if err != nil { - lintCtx.Log.Errorf("setup revive: %v", err) - return - } - - analyzer.Run = func(pass *analysis.Pass) (any, error) { - issues, err := w.run(lintCtx, pass) + return goanalysis. + NewLinterFromAnalyzer(analyzer). + WithContextSetter(func(lintCtx *linter.Context) { + w, err := newWrapper(settings) if err != nil { - return nil, err + lintCtx.Log.Errorf("setup revive: %v", err) + return } - if len(issues) == 0 { - return nil, nil - } + analyzer.Run = func(pass *analysis.Pass) (any, error) { + issues, err := w.run(pass) + if err != nil { + return nil, err + } - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() + if len(issues) == 0 { + return nil, nil + } - return nil, nil - } - }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() + + return nil, nil + } + }). + WithIssuesReporter(func(*linter.Context) []*goanalysis.Issue { + return resIssues + }). + WithLoadMode(goanalysis.LoadModeSyntax) } type wrapper struct { revive lint.Linter - formatter lint.Formatter lintingRules []lint.Rule conf *lint.Config } @@ -90,12 +87,9 @@ func newWrapper(settings *config.ReviveSettings) (*wrapper, error) { return nil, err } - conf.GoVersion, err = hcversion.NewVersion(settings.Go) - if err != nil { - return nil, err - } + displayRules(conf) - formatter, err := reviveConfig.GetFormatter("json") + conf.GoVersion, err = hcversion.NewVersion(settings.Go) if err != nil { return nil, err } @@ -107,85 +101,78 @@ func newWrapper(settings *config.ReviveSettings) (*wrapper, error) { return &wrapper{ revive: lint.New(os.ReadFile, settings.MaxOpenFiles), - formatter: formatter, lintingRules: lintingRules, conf: conf, }, nil } -func (w *wrapper) run(lintCtx *linter.Context, pass *analysis.Pass) ([]goanalysis.Issue, error) { - packages := [][]string{internal.GetFileNames(pass)} +func (w *wrapper) run(pass *analysis.Pass) ([]*goanalysis.Issue, error) { + packages := [][]string{internal.GetGoFileNames(pass)} failures, err := w.revive.Lint(packages, w.lintingRules, *w.conf) if err != nil { return nil, err } - formatChan := make(chan lint.Failure) - exitChan := make(chan bool) - - var output string - go func() { - output, err = w.formatter.Format(formatChan, *w.conf) - if err != nil { - lintCtx.Log.Errorf("Format error: %v", err) - } - exitChan <- true - }() - - for f := range failures { - if f.Confidence < w.conf.Confidence { + var issues []*goanalysis.Issue + for failure := range failures { + if failure.Confidence < w.conf.Confidence { continue } - formatChan <- f - } - - close(formatChan) - <-exitChan - - var results []jsonObject - err = json.Unmarshal([]byte(output), &results) - if err != nil { - return nil, err - } - - var issues []goanalysis.Issue - for i := range results { - issues = append(issues, toIssue(pass, &results[i])) + issues = append(issues, w.toIssue(pass, &failure)) } return issues, nil } -func toIssue(pass *analysis.Pass, object *jsonObject) goanalysis.Issue { - lineRangeTo := object.Position.End.Line - if object.RuleName == (&rule.ExportedRule{}).Name() { - lineRangeTo = object.Position.Start.Line +func (w *wrapper) toIssue(pass *analysis.Pass, failure *lint.Failure) *goanalysis.Issue { + lineRangeTo := failure.Position.End.Line + if failure.RuleName == (&rule.ExportedRule{}).Name() { + lineRangeTo = failure.Position.Start.Line } - return goanalysis.NewIssue(&result.Issue{ - Severity: string(object.Severity), - Text: fmt.Sprintf("%s: %s", object.RuleName, object.Failure.Failure), + issue := &result.Issue{ + Severity: string(severity(w.conf, failure)), + Text: fmt.Sprintf("%s: %s", failure.RuleName, failure.Failure), Pos: token.Position{ - Filename: object.Position.Start.Filename, - Line: object.Position.Start.Line, - Offset: object.Position.Start.Offset, - Column: object.Position.Start.Column, + Filename: failure.Position.Start.Filename, + Line: failure.Position.Start.Line, + Offset: failure.Position.Start.Offset, + Column: failure.Position.Start.Column, }, LineRange: &result.Range{ - From: object.Position.Start.Line, + From: failure.Position.Start.Line, To: lineRangeTo, }, FromLinter: linterName, - }, pass) + } + + if failure.ReplacementLine != "" { + f := pass.Fset.File(token.Pos(failure.Position.Start.Offset)) + + // Skip cgo files because the positions are wrong. + if failure.Filename() == f.Name() { + issue.SuggestedFixes = []analysis.SuggestedFix{{ + TextEdits: []analysis.TextEdit{{ + Pos: f.LineStart(failure.Position.Start.Line), + End: goanalysis.EndOfLinePos(f, failure.Position.End.Line), + // ReplacementLine doesn't contain the full line (missing newline), so we have to add a newline. + // Also `failure.Position.End.Offset` is at the end of the node but not the line. + NewText: []byte(failure.ReplacementLine + "\n"), + }}, + }} + } + } + + return goanalysis.NewIssue(issue, pass) } // This function mimics the GetConfig function of revive. // This allows to get default values and right types. // https://github.com/golangci/golangci-lint/issues/1745 -// https://github.com/mgechev/revive/blob/v1.5.0/config/config.go#L220 -// https://github.com/mgechev/revive/blob/v1.5.0/config/config.go#L172-L178 +// https://github.com/mgechev/revive/blob/v1.13.0/config/config.go#L249 +// https://github.com/mgechev/revive/blob/v1.13.0/config/config.go#L198-L204 func getConfig(cfg *config.ReviveSettings) (*lint.Config, error) { conf := defaultConfig() @@ -218,19 +205,20 @@ func getConfig(cfg *config.ReviveSettings) (*lint.Config, error) { conf.Rules[k] = r } - debugf("revive configuration: %#v", conf) - return conf, nil } func createConfigMap(cfg *config.ReviveSettings) map[string]any { rawRoot := map[string]any{ - "ignoreGeneratedHeader": cfg.IgnoreGeneratedHeader, - "confidence": cfg.Confidence, - "severity": cfg.Severity, - "errorCode": cfg.ErrorCode, - "warningCode": cfg.WarningCode, - "enableAllRules": cfg.EnableAllRules, + "confidence": cfg.Confidence, + "severity": cfg.Severity, + "errorCode": cfg.ErrorCode, + "warningCode": cfg.WarningCode, + "enableAllRules": cfg.EnableAllRules, + "enableDefaultRules": cfg.EnableDefaultRules, + + // Should be managed with `linters.exclusions.generated`. + "ignoreGeneratedHeader": false, } rawDirectives := map[string]map[string]any{} @@ -284,7 +272,7 @@ func safeTomlSlice(r []any) []any { } // This element is not exported by revive, so we need copy the code. -// Extracted from https://github.com/mgechev/revive/blob/v1.5.0/config/config.go#L16 +// Extracted from https://github.com/mgechev/revive/blob/v1.15.0/config/config.go#L16 var defaultRules = []lint.Rule{ &rule.VarDeclarationsRule{}, &rule.PackageCommentsRule{}, @@ -312,97 +300,117 @@ var defaultRules = []lint.Rule{ } var allRules = append([]lint.Rule{ + &rule.AddConstantRule{}, &rule.ArgumentsLimitRule{}, - &rule.CyclomaticRule{}, - &rule.FileHeaderRule{}, + &rule.AtomicRule{}, + &rule.BannedCharsRule{}, + &rule.BareReturnRule{}, + &rule.BoolLiteralRule{}, + &rule.CallToGCRule{}, + &rule.CognitiveComplexityRule{}, + &rule.CommentsDensityRule{}, + &rule.CommentSpacingsRule{}, &rule.ConfusingNamingRule{}, - &rule.GetReturnRule{}, - &rule.ModifiesParamRule{}, &rule.ConfusingResultsRule{}, + &rule.ConstantLogicalExprRule{}, + &rule.CyclomaticRule{}, + &rule.DataRaceRule{}, &rule.DeepExitRule{}, - &rule.AddConstantRule{}, + &rule.DeferRule{}, + &rule.DuplicatedImportsRule{}, + &rule.EarlyReturnRule{}, + &rule.EmptyLinesRule{}, + &rule.EnforceMapStyleRule{}, + &rule.EnforceRepeatedArgTypeStyleRule{}, + &rule.EnforceSliceStyleRule{}, + &rule.EnforceSwitchStyleRule{}, + &rule.EpochNamingRule{}, + &rule.FileHeaderRule{}, + &rule.FileLengthLimitRule{}, + &rule.FilenameFormatRule{}, &rule.FlagParamRule{}, - &rule.UnnecessaryStmtRule{}, - &rule.StructTagRule{}, - &rule.ModifiesValRecRule{}, - &rule.ConstantLogicalExprRule{}, - &rule.BoolLiteralRule{}, - &rule.ImportsBlocklistRule{}, + &rule.ForbiddenCallInWgGoRule{}, + &rule.FunctionLength{}, &rule.FunctionResultsLimitRule{}, + &rule.GetReturnRule{}, + &rule.IdenticalBranchesRule{}, + &rule.IdenticalIfElseIfBranchesRule{}, + &rule.IdenticalIfElseIfConditionsRule{}, + &rule.IdenticalSwitchBranchesRule{}, + &rule.IdenticalSwitchConditionsRule{}, + &rule.IfReturnRule{}, + &rule.ImportAliasNamingRule{}, + &rule.ImportsBlocklistRule{}, + &rule.ImportShadowingRule{}, + &rule.InefficientMapLookupRule{}, + &rule.LineLengthLimitRule{}, + &rule.MaxControlNestingRule{}, &rule.MaxPublicStructsRule{}, - &rule.RangeValInClosureRule{}, + &rule.ModifiesParamRule{}, + &rule.ModifiesValRecRule{}, + &rule.NestedStructs{}, + &rule.OptimizeOperandsOrderRule{}, + &rule.PackageDirectoryMismatchRule{}, + &rule.PackageNamingRule{}, &rule.RangeValAddress{}, - &rule.WaitGroupByValueRule{}, - &rule.AtomicRule{}, - &rule.EmptyLinesRule{}, - &rule.LineLengthLimitRule{}, - &rule.CallToGCRule{}, - &rule.DuplicatedImportsRule{}, - &rule.ImportShadowingRule{}, - &rule.BareReturnRule{}, - &rule.UnusedReceiverRule{}, - &rule.UnhandledErrorRule{}, - &rule.CognitiveComplexityRule{}, - &rule.StringOfIntRule{}, + &rule.RangeValInClosureRule{}, + &rule.RedundantBuildTagRule{}, + &rule.RedundantImportAlias{}, + &rule.RedundantTestMainExitRule{}, &rule.StringFormatRule{}, - &rule.EarlyReturnRule{}, + &rule.StringOfIntRule{}, + &rule.StructTagRule{}, + &rule.TimeDateRule{}, + &rule.TimeEqualRule{}, + &rule.UncheckedTypeAssertionRule{}, &rule.UnconditionalRecursionRule{}, - &rule.IdenticalBranchesRule{}, - &rule.DeferRule{}, &rule.UnexportedNamingRule{}, - &rule.FunctionLength{}, - &rule.NestedStructs{}, - &rule.UselessBreak{}, - &rule.UncheckedTypeAssertionRule{}, - &rule.TimeEqualRule{}, - &rule.BannedCharsRule{}, - &rule.OptimizeOperandsOrderRule{}, + &rule.UnhandledErrorRule{}, + &rule.UnnecessaryFormatRule{}, + &rule.UnnecessaryIfRule{}, + &rule.UnnecessaryStmtRule{}, + &rule.UnsecureURLSchemeRule{}, + &rule.UnusedReceiverRule{}, &rule.UseAnyRule{}, - &rule.DataRaceRule{}, - &rule.CommentSpacingsRule{}, - &rule.IfReturnRule{}, - &rule.RedundantImportAlias{}, - &rule.ImportAliasNamingRule{}, - &rule.EnforceMapStyleRule{}, - &rule.EnforceRepeatedArgTypeStyleRule{}, - &rule.EnforceSliceStyleRule{}, - &rule.MaxControlNestingRule{}, - &rule.CommentsDensityRule{}, - &rule.FileLengthLimitRule{}, - &rule.FilenameFormatRule{}, + &rule.UseErrorsNewRule{}, + &rule.UseFmtPrintRule{}, + &rule.UselessBreak{}, + &rule.UselessFallthroughRule{}, + &rule.UseSlicesSort{}, + &rule.UseWaitGroupGoRule{}, + &rule.WaitGroupByValueRule{}, }, defaultRules...) const defaultConfidence = 0.8 // This element is not exported by revive, so we need copy the code. -// Extracted from https://github.com/mgechev/revive/blob/v1.5.0/config/config.go#L183 +// Extracted from https://github.com/mgechev/revive/blob/v1.13.0/config/config.go#L209 func normalizeConfig(cfg *lint.Config) { // NOTE(ldez): this custom section for golangci-lint should be kept. // --- - if cfg.Confidence == 0 { - cfg.Confidence = defaultConfidence - } - if cfg.Severity == "" { - cfg.Severity = lint.SeverityWarning - } + cfg.Confidence = cmp.Or(cfg.Confidence, defaultConfidence) + cfg.Severity = cmp.Or(cfg.Severity, lint.SeverityWarning) // --- if len(cfg.Rules) == 0 { cfg.Rules = map[string]lint.RuleConfig{} } - if cfg.EnableAllRules { - // Add to the configuration all rules not yet present in it - for _, r := range allRules { + + addRules := func(config *lint.Config, rules []lint.Rule) { + for _, r := range rules { ruleName := r.Name() - _, alreadyInConf := cfg.Rules[ruleName] - if alreadyInConf { - continue + if _, ok := config.Rules[ruleName]; !ok { + config.Rules[ruleName] = lint.RuleConfig{} } - // Add the rule with an empty conf for - cfg.Rules[ruleName] = lint.RuleConfig{} } } + if cfg.EnableAllRules { + addRules(cfg, allRules) + } else if cfg.EnableDefaultRules { + addRules(cfg, defaultRules) + } + severity := cfg.Severity if severity != "" { for k, v := range cfg.Rules { @@ -421,7 +429,7 @@ func normalizeConfig(cfg *lint.Config) { } // This element is not exported by revive, so we need copy the code. -// Extracted from https://github.com/mgechev/revive/blob/v1.5.0/config/config.go#L252 +// Extracted from https://github.com/mgechev/revive/blob/v1.13.0/config/config.go#L280 func defaultConfig() *lint.Config { defaultConfig := lint.Config{ Confidence: defaultConfidence, @@ -433,3 +441,48 @@ func defaultConfig() *lint.Config { } return &defaultConfig } + +func displayRules(conf *lint.Config) { + if !isDebug { + return + } + + var enabledRules []string + for k, r := range conf.Rules { + if !r.Disabled { + enabledRules = append(enabledRules, k) + } + } + + slices.Sort(enabledRules) + + debugf("All available rules (%d): %s.", len(allRules), strings.Join(extractRulesName(allRules), ", ")) + debugf("Default rules (%d): %s.", len(defaultRules), strings.Join(extractRulesName(defaultRules), ", ")) + debugf("Enabled by config rules (%d): %s.", len(enabledRules), strings.Join(enabledRules, ", ")) + + debugf("revive configuration: %#v", conf) +} + +func extractRulesName(rules []lint.Rule) []string { + var names []string + + for _, r := range rules { + names = append(names, r.Name()) + } + + slices.Sort(names) + + return names +} + +// Extracted from https://github.com/mgechev/revive/blob/v1.13.0/formatter/severity.go +// Modified to use pointers (related to hugeParam rule). +func severity(cfg *lint.Config, failure *lint.Failure) lint.Severity { + if cfg, ok := cfg.Rules[failure.RuleName]; ok && cfg.Severity == lint.SeverityError { + return lint.SeverityError + } + if cfg, ok := cfg.Directives[failure.RuleName]; ok && cfg.Severity == lint.SeverityError { + return lint.SeverityError + } + return lint.SeverityWarning +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/rowserrcheck/rowserrcheck.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/rowserrcheck/rowserrcheck.go new file mode 100644 index 000000000..de0fe4da9 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/rowserrcheck/rowserrcheck.go @@ -0,0 +1,21 @@ +package rowserrcheck + +import ( + "github.com/jingyugao/rowserrcheck/passes/rowserr" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.RowsErrCheckSettings) *goanalysis.Linter { + var pkgs []string + + if settings != nil { + pkgs = settings.Packages + } + + return goanalysis. + NewLinterFromAnalyzer(rowserr.NewAnalyzer(pkgs...)). + WithDesc("checks whether Rows.Err of rows is checked successfully"). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/sloglint/sloglint.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/sloglint/sloglint.go similarity index 75% rename from vendor/github.com/golangci/golangci-lint/pkg/golinters/sloglint/sloglint.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/sloglint/sloglint.go index 486662577..891f1fcfd 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/sloglint/sloglint.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/sloglint/sloglint.go @@ -2,14 +2,14 @@ package sloglint import ( "go-simpler.org/sloglint" - "golang.org/x/tools/go/analysis" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.SlogLintSettings) *goanalysis.Linter { var opts *sloglint.Options + if settings != nil { opts = &sloglint.Options{ NoMixedArgs: settings.NoMixedArgs, @@ -18,6 +18,7 @@ func New(settings *config.SlogLintSettings) *goanalysis.Linter { NoGlobal: settings.NoGlobal, ContextOnly: settings.Context, StaticMsg: settings.StaticMsg, + MsgStyle: settings.MsgStyle, NoRawKeys: settings.NoRawKeys, KeyNamingCase: settings.KeyNamingCase, ForbiddenKeys: settings.ForbiddenKeys, @@ -25,9 +26,7 @@ func New(settings *config.SlogLintSettings) *goanalysis.Linter { } } - a := sloglint.New(opts) - return goanalysis. - NewLinter(a.Name, a.Doc, []*analysis.Analyzer{a}, nil). + NewLinterFromAnalyzer(sloglint.New(opts)). WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/spancheck/spancheck.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/spancheck/spancheck.go new file mode 100644 index 000000000..345c36277 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/spancheck/spancheck.go @@ -0,0 +1,30 @@ +package spancheck + +import ( + "github.com/jjti/go-spancheck" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.SpancheckSettings) *goanalysis.Linter { + cfg := spancheck.NewDefaultConfig() + + if settings != nil { + if len(settings.Checks) > 0 { + cfg.EnabledChecks = settings.Checks + } + + if len(settings.IgnoreCheckSignatures) > 0 { + cfg.IgnoreChecksSignaturesSlice = settings.IgnoreCheckSignatures + } + + if len(settings.ExtraStartSpanSignatures) > 0 { + cfg.StartSpanMatchersSlice = append(cfg.StartSpanMatchersSlice, settings.ExtraStartSpanSignatures...) + } + } + + return goanalysis. + NewLinterFromAnalyzer(spancheck.NewAnalyzerWithConfig(cfg)). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/sqlclosecheck/sqlclosecheck.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/sqlclosecheck/sqlclosecheck.go new file mode 100644 index 000000000..4c970cc52 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/sqlclosecheck/sqlclosecheck.go @@ -0,0 +1,13 @@ +package sqlclosecheck + +import ( + "github.com/ryanrolds/sqlclosecheck/pkg/analyzer" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(analyzer.NewAnalyzer()). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/internal/staticcheck_common.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/staticcheck/staticcheck.go similarity index 60% rename from vendor/github.com/golangci/golangci-lint/pkg/golinters/internal/staticcheck_common.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/staticcheck/staticcheck.go index e5a0e33b7..0f529a58e 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/internal/staticcheck_common.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/staticcheck/staticcheck.go @@ -1,40 +1,71 @@ -package internal +package staticcheck import ( + "slices" "strings" "unicode" "golang.org/x/tools/go/analysis" "honnef.co/go/tools/analysis/lint" scconfig "honnef.co/go/tools/config" + "honnef.co/go/tools/quickfix" + "honnef.co/go/tools/simple" + "honnef.co/go/tools/staticcheck" + "honnef.co/go/tools/stylecheck" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/logutils" +) - "github.com/golangci/golangci-lint/pkg/config" +var ( + debugf = logutils.Debug(logutils.DebugKeyStaticcheck) + isDebug = logutils.HaveDebugTag(logutils.DebugKeyStaticcheck) ) -func SetupStaticCheckAnalyzers(src []*lint.Analyzer, checks []string) []*analysis.Analyzer { - var names []string - for _, a := range src { - names = append(names, a.Analyzer.Name) +func New(settings *config.StaticCheckSettings) *goanalysis.Linter { + cfg := createConfig(settings) + + // `scconfig.Analyzer` is a singleton. + scconfig.Analyzer.Run = func(_ *analysis.Pass) (any, error) { + return cfg, nil } - filter := filterAnalyzerNames(names, checks) + allAnalyzers := slices.Concat(staticcheck.Analyzers, stylecheck.Analyzers, simple.Analyzers, quickfix.Analyzers) - var ret []*analysis.Analyzer - for _, a := range src { - if filter[a.Analyzer.Name] { - ret = append(ret, a.Analyzer) + analyzers := setupAnalyzers(allAnalyzers, cfg.Checks) + + if isDebug { + allAnalyzerNames := extractAnalyzerNames(allAnalyzers) + slices.Sort(allAnalyzerNames) + debugf("All available checks (%d): %s", len(allAnalyzers), strings.Join(allAnalyzerNames, ",")) + + var cfgAnalyzerNames []string + for _, a := range analyzers { + cfgAnalyzerNames = append(cfgAnalyzerNames, a.Name) } + slices.Sort(cfgAnalyzerNames) + debugf("Enabled by config checks (%d): %s", len(analyzers), strings.Join(cfgAnalyzerNames, ",")) + + debugf("staticcheck configuration: %#v", cfg) } - return ret + return goanalysis.NewLinter( + "staticcheck", + "It's the set of rules from staticcheck.", + analyzers, + nil, + ).WithLoadMode(goanalysis.LoadModeTypesInfo) } -func StaticCheckConfig(settings *config.StaticCheckSettings) *scconfig.Config { +func createConfig(settings *config.StaticCheckSettings) *scconfig.Config { + defaultChecks := []string{"all", "-ST1000", "-ST1003", "-ST1016", "-ST1020", "-ST1021", "-ST1022"} + var cfg *scconfig.Config if settings == nil || !settings.HasConfiguration() { return &scconfig.Config{ - Checks: []string{"*"}, // override for compatibility reason. Must drop in the next major version. + Checks: defaultChecks, Initialisms: scconfig.DefaultConfig.Initialisms, DotImportWhitelist: scconfig.DefaultConfig.DotImportWhitelist, HTTPStatusCodeWhitelist: scconfig.DefaultConfig.HTTPStatusCodeWhitelist, @@ -48,19 +79,19 @@ func StaticCheckConfig(settings *config.StaticCheckSettings) *scconfig.Config { HTTPStatusCodeWhitelist: settings.HTTPStatusCodeWhitelist, } - if len(cfg.Checks) == 0 { - cfg.Checks = append(cfg.Checks, "*") // override for compatibility reason. Must drop in the next major version. + if cfg.Checks == nil { + cfg.Checks = defaultChecks } - if len(cfg.Initialisms) == 0 { + if cfg.Initialisms == nil { cfg.Initialisms = append(cfg.Initialisms, scconfig.DefaultConfig.Initialisms...) } - if len(cfg.DotImportWhitelist) == 0 { + if cfg.DotImportWhitelist == nil { cfg.DotImportWhitelist = append(cfg.DotImportWhitelist, scconfig.DefaultConfig.DotImportWhitelist...) } - if len(cfg.HTTPStatusCodeWhitelist) == 0 { + if cfg.HTTPStatusCodeWhitelist == nil { cfg.HTTPStatusCodeWhitelist = append(cfg.HTTPStatusCodeWhitelist, scconfig.DefaultConfig.HTTPStatusCodeWhitelist...) } @@ -72,6 +103,51 @@ func StaticCheckConfig(settings *config.StaticCheckSettings) *scconfig.Config { return cfg } +// https://github.com/dominikh/go-tools/blob/9bf17c0388a65710524ba04c2d821469e639fdc2/config/config.go#L95-L116 +func normalizeList(list []string) []string { + if len(list) > 1 { + nlist := make([]string, 0, len(list)) + nlist = append(nlist, list[0]) + for i, el := range list[1:] { + if el != list[i] { + nlist = append(nlist, el) + } + } + list = nlist + } + + for _, el := range list { + if el == "inherit" { + // This should never happen, because the default config + // should not use "inherit" + panic(`unresolved "inherit"`) + } + } + + return list +} + +func setupAnalyzers(src []*lint.Analyzer, checks []string) []*analysis.Analyzer { + filter := filterAnalyzerNames(extractAnalyzerNames(src), checks) + + var ret []*analysis.Analyzer + for _, a := range src { + if filter[a.Analyzer.Name] { + ret = append(ret, a.Analyzer) + } + } + + return ret +} + +func extractAnalyzerNames(analyzers []*lint.Analyzer) []string { + var names []string + for _, a := range analyzers { + names = append(names, a.Analyzer.Name) + } + return names +} + // https://github.com/dominikh/go-tools/blob/9bf17c0388a65710524ba04c2d821469e639fdc2/lintcmd/lint.go#L437-L477 // //nolint:gocritic // Keep the original source code. @@ -117,27 +193,3 @@ func filterAnalyzerNames(analyzers []string, checks []string) map[string]bool { } return allowedChecks } - -// https://github.com/dominikh/go-tools/blob/9bf17c0388a65710524ba04c2d821469e639fdc2/config/config.go#L95-L116 -func normalizeList(list []string) []string { - if len(list) > 1 { - nlist := make([]string, 0, len(list)) - nlist = append(nlist, list[0]) - for i, el := range list[1:] { - if el != list[i] { - nlist = append(nlist, el) - } - } - list = nlist - } - - for _, el := range list { - if el == "inherit" { - // This should never happen, because the default config - // should not use "inherit" - panic(`unresolved "inherit"`) - } - } - - return list -} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/swaggo/swaggo.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/swaggo/swaggo.go new file mode 100644 index 000000000..98f7a6bef --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/swaggo/swaggo.go @@ -0,0 +1,20 @@ +package swaggo + +import ( + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/goformatters" + "github.com/golangci/golangci-lint/v2/pkg/goformatters/swaggo" + "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer( + goformatters.NewAnalyzer( + internal.LinterLogger.Child(swaggo.Name), + "Check if swaggo comments are formatted", + swaggo.New(), + ), + ). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/tagalign/tagalign.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/tagalign/tagalign.go new file mode 100644 index 000000000..eba51311c --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/tagalign/tagalign.go @@ -0,0 +1,29 @@ +package tagalign + +import ( + "github.com/4meepo/tagalign" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.TagAlignSettings) *goanalysis.Linter { + var options []tagalign.Option + + if settings != nil { + options = append(options, tagalign.WithAlign(settings.Align)) + + if settings.Sort || len(settings.Order) > 0 { + options = append(options, tagalign.WithSort(settings.Order...)) + } + + // Strict style will be applied only if Align and Sort are enabled together. + if settings.Strict && settings.Align && settings.Sort { + options = append(options, tagalign.WithStrictStyle()) + } + } + + return goanalysis. + NewLinterFromAnalyzer(tagalign.NewAnalyzer(options...)). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/tagliatelle/tagliatelle.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/tagliatelle/tagliatelle.go new file mode 100644 index 000000000..d0268d11f --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/tagliatelle/tagliatelle.go @@ -0,0 +1,67 @@ +package tagliatelle + +import ( + "maps" + "strings" + + "github.com/ldez/tagliatelle" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.TagliatelleSettings) *goanalysis.Linter { + cfg := tagliatelle.Config{ + Base: tagliatelle.Base{ + Rules: map[string]string{ + "json": "camel", + "yaml": "camel", + "header": "header", + }, + }, + } + + if settings != nil { + maps.Copy(cfg.Rules, settings.Case.Rules) + + cfg.ExtendedRules = toExtendedRules(settings.Case.ExtendedRules) + cfg.UseFieldName = settings.Case.UseFieldName + cfg.IgnoredFields = settings.Case.IgnoredFields + + for _, override := range settings.Case.Overrides { + cfg.Overrides = append(cfg.Overrides, tagliatelle.Overrides{ + Base: tagliatelle.Base{ + Rules: override.Rules, + ExtendedRules: toExtendedRules(override.ExtendedRules), + UseFieldName: override.UseFieldName, + IgnoredFields: override.IgnoredFields, + Ignore: override.Ignore, + }, + Package: override.Package, + }) + } + } + + return goanalysis. + NewLinterFromAnalyzer(tagliatelle.New(cfg)). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} + +func toExtendedRules(src map[string]config.TagliatelleExtendedRule) map[string]tagliatelle.ExtendedRule { + result := make(map[string]tagliatelle.ExtendedRule, len(src)) + + for k, v := range src { + initialismOverrides := make(map[string]bool, len(v.InitialismOverrides)) + for ki, vi := range v.InitialismOverrides { + initialismOverrides[strings.ToUpper(ki)] = vi + } + + result[k] = tagliatelle.ExtendedRule{ + Case: v.Case, + ExtraInitialisms: v.ExtraInitialisms, + InitialismOverrides: initialismOverrides, + } + } + + return result +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/testableexamples/testableexamples.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/testableexamples/testableexamples.go new file mode 100644 index 000000000..45fdc900e --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/testableexamples/testableexamples.go @@ -0,0 +1,13 @@ +package testableexamples + +import ( + "github.com/maratori/testableexamples/pkg/testableexamples" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(testableexamples.NewAnalyzer()). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/testifylint/testifylint.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/testifylint/testifylint.go similarity index 55% rename from vendor/github.com/golangci/golangci-lint/pkg/golinters/testifylint/testifylint.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/testifylint/testifylint.go index b3f2f0bd4..bb5eac0e4 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/testifylint/testifylint.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/testifylint/testifylint.go @@ -2,50 +2,47 @@ package testifylint import ( "github.com/Antonboom/testifylint/analyzer" - "golang.org/x/tools/go/analysis" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.TestifylintSettings) *goanalysis.Linter { - a := analyzer.New() + var cfg map[string]any - cfg := make(map[string]map[string]any) if settings != nil { - cfg[a.Name] = map[string]any{ + cfg = map[string]any{ "enable-all": settings.EnableAll, "disable-all": settings.DisableAll, "bool-compare.ignore-custom-types": settings.BoolCompare.IgnoreCustomTypes, "formatter.require-f-funcs": settings.Formatter.RequireFFuncs, + "formatter.require-string-msg": settings.Formatter.RequireStringMsg, "go-require.ignore-http-handlers": settings.GoRequire.IgnoreHTTPHandlers, } if len(settings.EnabledCheckers) > 0 { - cfg[a.Name]["enable"] = settings.EnabledCheckers + cfg["enable"] = settings.EnabledCheckers } if len(settings.DisabledCheckers) > 0 { - cfg[a.Name]["disable"] = settings.DisabledCheckers + cfg["disable"] = settings.DisabledCheckers } if b := settings.Formatter.CheckFormatString; b != nil { - cfg[a.Name]["formatter.check-format-string"] = *b + cfg["formatter.check-format-string"] = *b } if p := settings.ExpectedActual.ExpVarPattern; p != "" { - cfg[a.Name]["expected-actual.pattern"] = p + cfg["expected-actual.pattern"] = p } if p := settings.RequireError.FnPattern; p != "" { - cfg[a.Name]["require-error.fn-pattern"] = p + cfg["require-error.fn-pattern"] = p } if m := settings.SuiteExtraAssertCall.Mode; m != "" { - cfg[a.Name]["suite-extra-assert-call.mode"] = m + cfg["suite-extra-assert-call.mode"] = m } } - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfg, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(analyzer.New()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/testpackage/testpackage.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/testpackage/testpackage.go new file mode 100644 index 000000000..39c333f1b --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/testpackage/testpackage.go @@ -0,0 +1,26 @@ +package testpackage + +import ( + "strings" + + "github.com/maratori/testpackage/pkg/testpackage" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.TestpackageSettings) *goanalysis.Linter { + var cfg map[string]any + + if settings != nil { + cfg = map[string]any{ + testpackage.SkipRegexpFlagName: settings.SkipRegexp, + testpackage.AllowPackagesFlagName: strings.Join(settings.AllowPackages, ","), + } + } + + return goanalysis. + NewLinterFromAnalyzer(testpackage.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/thelper/thelper.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/thelper/thelper.go similarity index 50% rename from vendor/github.com/golangci/golangci-lint/pkg/golinters/thelper/thelper.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/thelper/thelper.go index cc6ea755c..77090c5f8 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/thelper/thelper.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/thelper/thelper.go @@ -1,20 +1,18 @@ package thelper import ( + "maps" + "slices" "strings" "github.com/kulti/thelper/pkg/analyzer" - "golang.org/x/exp/maps" - "golang.org/x/tools/go/analysis" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/golinters/internal" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" ) -func New(cfg *config.ThelperSettings) *goanalysis.Linter { - a := analyzer.NewAnalyzer() - +func New(settings *config.ThelperSettings) *goanalysis.Linter { opts := map[string]struct{}{ "t_name": {}, "t_begin": {}, @@ -33,31 +31,27 @@ func New(cfg *config.ThelperSettings) *goanalysis.Linter { "tb_first": {}, } - if cfg != nil { - applyTHelperOptions(cfg.Test, "t_", opts) - applyTHelperOptions(cfg.Fuzz, "f_", opts) - applyTHelperOptions(cfg.Benchmark, "b_", opts) - applyTHelperOptions(cfg.TB, "tb_", opts) + if settings != nil { + applyTHelperOptions(settings.Test, "t_", opts) + applyTHelperOptions(settings.Fuzz, "f_", opts) + applyTHelperOptions(settings.Benchmark, "b_", opts) + applyTHelperOptions(settings.TB, "tb_", opts) } if len(opts) == 0 { internal.LinterLogger.Fatalf("thelper: at least one option must be enabled") } - args := maps.Keys(opts) + args := slices.Collect(maps.Keys(opts)) - cfgMap := map[string]map[string]any{ - a.Name: { - "checks": strings.Join(args, ","), - }, + cfg := map[string]any{ + "checks": strings.Join(args, ","), } - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - cfgMap, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(analyzer.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) } func applyTHelperOptions(o config.ThelperOptions, prefix string, opts map[string]struct{}) { diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/tparallel/tparallel.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/tparallel/tparallel.go new file mode 100644 index 000000000..480ef3b1e --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/tparallel/tparallel.go @@ -0,0 +1,13 @@ +package tparallel + +import ( + "github.com/moricho/tparallel" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(tparallel.Analyzer). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/typecheck.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/typecheck.go new file mode 100644 index 000000000..db29f7c18 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/typecheck.go @@ -0,0 +1,17 @@ +package golinters + +import ( + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func NewTypecheck() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: "typecheck", + Doc: "Like the front-end of a Go compiler, parses and type-checks Go code", + Run: goanalysis.DummyRun, + }). + WithLoadMode(goanalysis.LoadModeNone) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/unconvert/unconvert.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/unconvert/unconvert.go new file mode 100644 index 000000000..593dfbe96 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/unconvert/unconvert.go @@ -0,0 +1,61 @@ +package unconvert + +import ( + "sync" + + "github.com/golangci/unconvert" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/result" +) + +const linterName = "unconvert" + +func New(settings *config.UnconvertSettings) *goanalysis.Linter { + var mu sync.Mutex + var resIssues []*goanalysis.Issue + + unconvert.SetFastMath(settings.FastMath) + unconvert.SetSafe(settings.Safe) + + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: linterName, + Doc: "Remove unnecessary type conversions", + Run: func(pass *analysis.Pass) (any, error) { + issues := runUnconvert(pass) + + if len(issues) == 0 { + return nil, nil + } + + mu.Lock() + resIssues = append(resIssues, issues...) + mu.Unlock() + + return nil, nil + }, + }). + WithIssuesReporter(func(*linter.Context) []*goanalysis.Issue { + return resIssues + }). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} + +func runUnconvert(pass *analysis.Pass) []*goanalysis.Issue { + positions := unconvert.Run(pass) + + var issues []*goanalysis.Issue + for _, position := range positions { + issues = append(issues, goanalysis.NewIssue(&result.Issue{ + Pos: position, + Text: "unnecessary conversion", + FromLinter: linterName, + }, pass)) + } + + return issues +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/unparam/unparam.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/unparam/unparam.go new file mode 100644 index 000000000..b6cb2668b --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/unparam/unparam.go @@ -0,0 +1,60 @@ +package unparam + +import ( + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/buildssa" + "golang.org/x/tools/go/packages" + "mvdan.cc/unparam/check" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.UnparamSettings) *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(&analysis.Analyzer{ + Name: "unparam", + Doc: "Reports unused function parameters", + Requires: []*analysis.Analyzer{buildssa.Analyzer}, + Run: func(pass *analysis.Pass) (any, error) { + err := runUnparam(pass, settings) + if err != nil { + return nil, err + } + + return nil, nil + }, + }). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} + +func runUnparam(pass *analysis.Pass, settings *config.UnparamSettings) error { + ssa := pass.ResultOf[buildssa.Analyzer].(*buildssa.SSA) + ssaPkg := ssa.Pkg + + pkg := &packages.Package{ + Fset: pass.Fset, + Syntax: pass.Files, + Types: pass.Pkg, + TypesInfo: pass.TypesInfo, + } + + c := &check.Checker{} + c.CheckExportedFuncs(settings.CheckExported) + c.Packages([]*packages.Package{pkg}) + c.ProgramSSA(ssaPkg.Prog) + + unparamIssues, err := c.Check() + if err != nil { + return err + } + + for _, i := range unparamIssues { + pass.Report(analysis.Diagnostic{ + Pos: i.Pos(), + Message: i.Message(), + }) + } + + return nil +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/unqueryvet/unqueryvet.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/unqueryvet/unqueryvet.go new file mode 100644 index 000000000..e2c185869 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/unqueryvet/unqueryvet.go @@ -0,0 +1,63 @@ +package unqueryvet + +import ( + "github.com/MirrexOne/unqueryvet" + pkgconfig "github.com/MirrexOne/unqueryvet/pkg/config" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.UnqueryvetSettings) *goanalysis.Linter { + cfg := pkgconfig.DefaultSettings() + + if settings != nil { + // IgnoredFiles, Ignore, Severity, and Rules are explicitly ignored. + cfg.CheckSQLBuilders = settings.CheckSQLBuilders + cfg.CheckAliasedWildcard = settings.CheckAliasedWildcard + cfg.CheckStringConcat = settings.CheckStringConcat + cfg.CheckFormatStrings = settings.CheckFormatStrings + cfg.CheckStringBuilder = settings.CheckStringBuilder + cfg.CheckSubqueries = settings.CheckSubqueries + cfg.N1DetectionEnabled = settings.CheckN1 + cfg.SQLInjectionDetectionEnabled = settings.CheckSQLInjection + cfg.TxLeakDetectionEnabled = settings.CheckTxLeak + cfg.IgnoredFunctions = settings.IgnoredFunctions + + for _, rule := range settings.CustomRules { + // The field Fix is explicitly ignored. + cfg.CustomRules = append(cfg.CustomRules, pkgconfig.CustomRule{ + ID: rule.ID, + Pattern: rule.Pattern, + Patterns: rule.Patterns, + When: rule.When, + Message: rule.Message, + Severity: "error", + Action: rule.Action, + }) + } + + if len(settings.Allow) > 0 { + cfg.Allow = settings.Allow + } + + if len(settings.AllowedPatterns) > 0 { + cfg.AllowedPatterns = settings.AllowedPatterns + } + + cfg.SQLBuilders = pkgconfig.SQLBuildersConfig{ + Squirrel: settings.SQLBuilders.Squirrel, + GORM: settings.SQLBuilders.GORM, + SQLx: settings.SQLBuilders.SQLx, + Ent: settings.SQLBuilders.Ent, + PGX: settings.SQLBuilders.PGX, + Bun: settings.SQLBuilders.Bun, + SQLBoiler: settings.SQLBuilders.SQLBoiler, + Jet: settings.SQLBuilders.Jet, + } + } + + return goanalysis. + NewLinterFromAnalyzer(unqueryvet.NewWithConfig(&cfg)). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/unused/unused.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/unused/unused.go similarity index 88% rename from vendor/github.com/golangci/golangci-lint/pkg/golinters/unused/unused.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/unused/unused.go index 7b2b478fc..c0f4657dc 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/unused/unused.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/unused/unused.go @@ -10,17 +10,17 @@ import ( "honnef.co/go/tools/analysis/lint" "honnef.co/go/tools/unused" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/result" ) const linterName = "unused" func New(settings *config.UnusedSettings) *goanalysis.Linter { var mu sync.Mutex - var resIssues []goanalysis.Issue + var resIssues []*goanalysis.Issue analyzer := &analysis.Analyzer{ Name: linterName, @@ -45,12 +45,12 @@ func New(settings *config.UnusedSettings) *goanalysis.Linter { "Checks Go code for unused constants, variables, functions and types", []*analysis.Analyzer{analyzer}, nil, - ).WithIssuesReporter(func(_ *linter.Context) []goanalysis.Issue { + ).WithIssuesReporter(func(_ *linter.Context) []*goanalysis.Issue { return resIssues }).WithLoadMode(goanalysis.LoadModeTypesInfo) } -func runUnused(pass *analysis.Pass, cfg *config.UnusedSettings) []goanalysis.Issue { +func runUnused(pass *analysis.Pass, cfg *config.UnusedSettings) []*goanalysis.Issue { res := getUnusedResults(pass, cfg) used := make(map[string]bool) @@ -58,7 +58,7 @@ func runUnused(pass *analysis.Pass, cfg *config.UnusedSettings) []goanalysis.Iss used[fmt.Sprintf("%s %d %s", obj.Position.Filename, obj.Position.Line, obj.Name)] = true } - var issues []goanalysis.Issue + var issues []*goanalysis.Issue // Inspired by https://github.com/dominikh/go-tools/blob/d694aadcb1f50c2d8ac0a1dd06217ebb9f654764/lintcmd/lint.go#L177-L197 for _, object := range res.Unused { diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/usestdlibvars/usestdlibvars.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/usestdlibvars/usestdlibvars.go new file mode 100644 index 000000000..e4a900ff6 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/usestdlibvars/usestdlibvars.go @@ -0,0 +1,35 @@ +package usestdlibvars + +import ( + "github.com/sashamelentyev/usestdlibvars/pkg/analyzer" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.UseStdlibVarsSettings) *goanalysis.Linter { + var cfg map[string]any + + if settings != nil { + cfg = map[string]any{ + analyzer.ConstantKindFlag: settings.ConstantKind, + analyzer.CryptoHashFlag: settings.CryptoHash, + analyzer.HTTPMethodFlag: settings.HTTPMethod, + analyzer.HTTPStatusCodeFlag: settings.HTTPStatusCode, + analyzer.OSDevNullFlag: false, // Noop because the linter ignore it. + analyzer.RPCDefaultPathFlag: settings.DefaultRPCPath, + analyzer.SQLIsolationLevelFlag: settings.SQLIsolationLevel, + analyzer.SyslogPriorityFlag: false, // Noop because the linter ignore it. + analyzer.TimeLayoutFlag: settings.TimeLayout, + analyzer.TimeMonthFlag: settings.TimeMonth, + analyzer.TimeWeekdayFlag: settings.TimeWeekday, + analyzer.TLSSignatureSchemeFlag: settings.TLSSignatureScheme, + analyzer.TimeDateMonthFlag: settings.TimeDateMonth, + } + } + + return goanalysis. + NewLinterFromAnalyzer(analyzer.New()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/usetesting/usetesting.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/usetesting/usetesting.go new file mode 100644 index 000000000..7371cc28e --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/usetesting/usetesting.go @@ -0,0 +1,29 @@ +package usetesting + +import ( + "github.com/ldez/usetesting" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.UseTestingSettings) *goanalysis.Linter { + var cfg map[string]any + + if settings != nil { + cfg = map[string]any{ + "contextbackground": settings.ContextBackground, + "contexttodo": settings.ContextTodo, + "oschdir": settings.OSChdir, + "osmkdirtemp": settings.OSMkdirTemp, + "ossetenv": settings.OSSetenv, + "ostempdir": settings.OSTempDir, + "oscreatetemp": settings.OSCreateTemp, + } + } + + return goanalysis. + NewLinterFromAnalyzer(usetesting.NewAnalyzer()). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/varnamelen/varnamelen.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/varnamelen/varnamelen.go similarity index 58% rename from vendor/github.com/golangci/golangci-lint/pkg/golinters/varnamelen/varnamelen.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/varnamelen/varnamelen.go index 6cb57ffa5..349feefa0 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/varnamelen/varnamelen.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/varnamelen/varnamelen.go @@ -5,18 +5,16 @@ import ( "strings" "github.com/blizzy78/varnamelen" - "golang.org/x/tools/go/analysis" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.VarnamelenSettings) *goanalysis.Linter { - analyzer := varnamelen.NewAnalyzer() - cfg := map[string]map[string]any{} + var cfg map[string]any if settings != nil { - vnlCfg := map[string]any{ + cfg = map[string]any{ "checkReceiver": strconv.FormatBool(settings.CheckReceiver), "checkReturn": strconv.FormatBool(settings.CheckReturn), "checkTypeParam": strconv.FormatBool(settings.CheckTypeParam), @@ -28,19 +26,17 @@ func New(settings *config.VarnamelenSettings) *goanalysis.Linter { } if settings.MaxDistance > 0 { - vnlCfg["maxDistance"] = strconv.Itoa(settings.MaxDistance) + cfg["maxDistance"] = strconv.Itoa(settings.MaxDistance) } + if settings.MinNameLength > 0 { - vnlCfg["minNameLength"] = strconv.Itoa(settings.MinNameLength) + cfg["minNameLength"] = strconv.Itoa(settings.MinNameLength) } - - cfg[analyzer.Name] = vnlCfg } - return goanalysis.NewLinter( - analyzer.Name, - "checks that the length of a variable's name matches its scope", - []*analysis.Analyzer{analyzer}, - cfg, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(varnamelen.NewAnalyzer()). + WithDesc("checks that the length of a variable's name matches its scope"). + WithConfig(cfg). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/wastedassign/wastedassign.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/wastedassign/wastedassign.go new file mode 100644 index 000000000..d103a8d5a --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/wastedassign/wastedassign.go @@ -0,0 +1,14 @@ +package wastedassign + +import ( + "github.com/sanposhiho/wastedassign/v2" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(wastedassign.Analyzer). + WithDesc("Finds wasted assignment statements"). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/whitespace/whitespace.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/whitespace/whitespace.go new file mode 100644 index 000000000..bf03e1d80 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/whitespace/whitespace.go @@ -0,0 +1,22 @@ +package whitespace + +import ( + "github.com/ultraware/whitespace" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New(settings *config.WhitespaceSettings) *goanalysis.Linter { + var wsSettings whitespace.Settings + if settings != nil { + wsSettings = whitespace.Settings{ + MultiIf: settings.MultiIf, + MultiFunc: settings.MultiFunc, + } + } + + return goanalysis. + NewLinterFromAnalyzer(whitespace.NewAnalyzer(&wsSettings)). + WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/wrapcheck/wrapcheck.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/wrapcheck/wrapcheck.go similarity index 64% rename from vendor/github.com/golangci/golangci-lint/pkg/golinters/wrapcheck/wrapcheck.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/wrapcheck/wrapcheck.go index 96ec2eeae..c29c509a8 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/wrapcheck/wrapcheck.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/wrapcheck/wrapcheck.go @@ -2,15 +2,18 @@ package wrapcheck import ( "github.com/tomarrell/wrapcheck/v2/wrapcheck" - "golang.org/x/tools/go/analysis" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" ) func New(settings *config.WrapcheckSettings) *goanalysis.Linter { cfg := wrapcheck.NewDefaultConfig() + if settings != nil { + cfg.ExtraIgnoreSigs = settings.ExtraIgnoreSigs + cfg.ReportInternalErrors = settings.ReportInternalErrors + if len(settings.IgnoreSigs) != 0 { cfg.IgnoreSigs = settings.IgnoreSigs } @@ -25,12 +28,7 @@ func New(settings *config.WrapcheckSettings) *goanalysis.Linter { } } - a := wrapcheck.NewAnalyzer(cfg) - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + return goanalysis. + NewLinterFromAnalyzer(wrapcheck.NewAnalyzer(cfg)). + WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/wsl/wsl.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/wsl/wsl.go new file mode 100644 index 000000000..4a5c6e19b --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/wsl/wsl.go @@ -0,0 +1,105 @@ +package wsl + +import ( + "slices" + + wslv4 "github.com/bombsimon/wsl/v4" + wslv5 "github.com/bombsimon/wsl/v5" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" +) + +// Deprecated: use NewV5 instead. +func NewV4(settings *config.WSLv4Settings) *goanalysis.Linter { + var conf *wslv4.Configuration + + if settings != nil { + conf = &wslv4.Configuration{ + StrictAppend: settings.StrictAppend, + AllowAssignAndCallCuddle: settings.AllowAssignAndCallCuddle, + AllowAssignAndAnythingCuddle: settings.AllowAssignAndAnythingCuddle, + AllowMultiLineAssignCuddle: settings.AllowMultiLineAssignCuddle, + ForceCaseTrailingWhitespaceLimit: settings.ForceCaseTrailingWhitespaceLimit, + AllowTrailingComment: settings.AllowTrailingComment, + AllowSeparatedLeadingComment: settings.AllowSeparatedLeadingComment, + AllowCuddleDeclaration: settings.AllowCuddleDeclaration, + AllowCuddleWithCalls: settings.AllowCuddleWithCalls, + AllowCuddleWithRHS: settings.AllowCuddleWithRHS, + ForceCuddleErrCheckAndAssign: settings.ForceCuddleErrCheckAndAssign, + AllowCuddleUsedInBlock: settings.AllowCuddleUsedInBlock, + ErrorVariableNames: settings.ErrorVariableNames, + ForceExclusiveShortDeclarations: settings.ForceExclusiveShortDeclarations, + IncludeGenerated: true, // force to true because golangci-lint already have a way to filter generated files. + } + } + + return goanalysis. + NewLinterFromAnalyzer(wslv4.NewAnalyzer(conf)). + WithLoadMode(goanalysis.LoadModeSyntax) +} + +// Only used the set YAML struct tags. +type v5YAML struct { + AllowFirstInBlock bool `yaml:"allow-first-in-block"` + AllowWholeBlock bool `yaml:"allow-whole-block"` + BranchMaxLines int `yaml:"branch-max-lines,omitempty"` + CaseMaxLines int `yaml:"case-max-lines,omitempty"` + Enable []string `yaml:"enable,omitempty"` + Disable []string `yaml:"disable,omitempty"` +} + +func Migration(old *config.WSLv4Settings) any { + if old == nil { + return nil + } + + cfg := v5YAML{ + AllowFirstInBlock: true, + AllowWholeBlock: false, + BranchMaxLines: 2, + CaseMaxLines: old.ForceCaseTrailingWhitespaceLimit, + } + + if !old.StrictAppend { + cfg.Disable = append(cfg.Disable, wslv5.CheckAppend.String()) + } + + if old.AllowAssignAndAnythingCuddle { + cfg.Disable = append(cfg.Disable, wslv5.CheckAssign.String()) + } + + if old.AllowMultiLineAssignCuddle { + internal.LinterLogger.Warnf("`allow-multiline-assign` is deprecated and always allowed in wsl >= v5") + } + + if old.AllowTrailingComment { + internal.LinterLogger.Warnf("`allow-trailing-comment` is deprecated and always allowed in wsl >= v5") + } + + if old.AllowSeparatedLeadingComment { + internal.LinterLogger.Warnf("`allow-separated-leading-comment` is deprecated and always allowed in wsl >= v5") + } + + if old.AllowCuddleDeclaration { + cfg.Disable = append(cfg.Disable, wslv5.CheckDecl.String()) + } + + if old.ForceCuddleErrCheckAndAssign { + cfg.Enable = append(cfg.Enable, wslv5.CheckErr.String()) + } + + if old.ForceExclusiveShortDeclarations { + cfg.Enable = append(cfg.Enable, wslv5.CheckAssignExclusive.String()) + } + + if !old.AllowAssignAndCallCuddle { + cfg.Enable = append(cfg.Enable, wslv5.CheckAssignExpr.String()) + } + + slices.Sort(cfg.Enable) + slices.Sort(cfg.Disable) + + return cfg +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/wsl/wsl_v5.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/wsl/wsl_v5.go new file mode 100644 index 000000000..cb7b25628 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/wsl/wsl_v5.go @@ -0,0 +1,34 @@ +package wsl + +import ( + "github.com/bombsimon/wsl/v5" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/golinters/internal" +) + +func NewV5(settings *config.WSLv5Settings) *goanalysis.Linter { + var conf *wsl.Configuration + + if settings != nil { + checkSet, err := wsl.NewCheckSet(settings.Default, settings.Enable, settings.Disable) + if err != nil { + internal.LinterLogger.Fatalf("wsl: invalid check: %v", err) + } + + conf = &wsl.Configuration{ + IncludeGenerated: true, // force to true because golangci-lint already has a way to filter generated files. + AllowFirstInBlock: settings.AllowFirstInBlock, + AllowWholeBlock: settings.AllowWholeBlock, + BranchMaxLines: settings.BranchMaxLines, + CaseMaxLines: settings.CaseMaxLines, + Checks: checkSet, + } + } + + return goanalysis. + NewLinterFromAnalyzer(wsl.NewAnalyzer(conf)). + WithVersion(5). //nolint:mnd // It's the linter version. + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/zerologlint/zerologlint.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/zerologlint/zerologlint.go new file mode 100644 index 000000000..46832da96 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/zerologlint/zerologlint.go @@ -0,0 +1,13 @@ +package zerologlint + +import ( + "github.com/ykadowak/zerologlint" + + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" +) + +func New() *goanalysis.Linter { + return goanalysis. + NewLinterFromAnalyzer(zerologlint.Analyzer). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/goutil/env.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goutil/env.go new file mode 100644 index 000000000..89e1634ca --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goutil/env.go @@ -0,0 +1,49 @@ +package goutil + +import ( + "context" + "fmt" + "os" + "time" + + "github.com/ldez/grignotin/goenv" + + "github.com/golangci/golangci-lint/v2/pkg/logutils" +) + +type EnvKey string + +type Env struct { + vars map[string]string + log logutils.Log +} + +func NewEnv(log logutils.Log) *Env { + return &Env{ + vars: map[string]string{}, + log: log, + } +} + +func (e Env) Discover(ctx context.Context) error { + startedAt := time.Now() + + var err error + e.vars, err = goenv.Get(ctx, goenv.GOCACHE, goenv.GOROOT) + if err != nil { + return fmt.Errorf("%w", err) + } + + e.log.Infof("Read go env for %s: %#v", time.Since(startedAt), e.vars) + + return nil +} + +func (e Env) Get(k EnvKey) string { + envValue := os.Getenv(string(k)) + if envValue != "" { + return envValue + } + + return e.vars[string(k)] +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/goutil/version.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/goutil/version.go similarity index 96% rename from vendor/github.com/golangci/golangci-lint/pkg/goutil/version.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/goutil/version.go index 4f42ebd1b..77e5b0f35 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/goutil/version.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/goutil/version.go @@ -60,9 +60,7 @@ func CleanRuntimeVersion() (string, error) { } func cleanRuntimeVersion(rv string) (string, error) { - parts := strings.Fields(rv) - - for _, part := range parts { + for part := range strings.FieldsSeq(rv) { // Allow to handle: // - GOEXPERIMENT -> "go1.23.0 X:boringcrypto" // - devel -> "devel go1.24-e705a2d Wed Aug 7 01:16:42 2024 +0000 linux/amd64" diff --git a/vendor/github.com/golangci/golangci-lint/pkg/lint/context.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/lint/context.go similarity index 67% rename from vendor/github.com/golangci/golangci-lint/pkg/lint/context.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/lint/context.go index d04a11b81..e8e8cc366 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/lint/context.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/lint/context.go @@ -4,13 +4,12 @@ import ( "context" "fmt" - "github.com/golangci/golangci-lint/internal/cache" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/exitcodes" - "github.com/golangci/golangci-lint/pkg/fsutils" - "github.com/golangci/golangci-lint/pkg/goanalysis/load" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/logutils" + "github.com/golangci/golangci-lint/v2/internal/cache" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/exitcodes" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis/load" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/logutils" ) type ContextBuilder struct { @@ -18,19 +17,17 @@ type ContextBuilder struct { pkgLoader *PackageLoader - fileCache *fsutils.FileCache - pkgCache *cache.Cache + pkgCache *cache.Cache loadGuard *load.Guard } func NewContextBuilder(cfg *config.Config, pkgLoader *PackageLoader, - fileCache *fsutils.FileCache, pkgCache *cache.Cache, loadGuard *load.Guard, + pkgCache *cache.Cache, loadGuard *load.Guard, ) *ContextBuilder { return &ContextBuilder{ cfg: cfg, pkgLoader: pkgLoader, - fileCache: fileCache, pkgCache: pkgCache, loadGuard: loadGuard, } @@ -55,7 +52,6 @@ func (cl *ContextBuilder) Build(ctx context.Context, log logutils.Log, linters [ Cfg: cl.cfg, Log: log, - FileCache: cl.fileCache, PkgCache: cl.pkgCache, LoadGuard: cl.loadGuard, } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/lint/linter/config.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/lint/linter/config.go similarity index 55% rename from vendor/github.com/golangci/golangci-lint/pkg/lint/linter/config.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/lint/linter/config.go index 6d6d4b17e..a5b98413d 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/lint/linter/config.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/lint/linter/config.go @@ -1,27 +1,13 @@ package linter import ( + "bytes" "fmt" + "go.yaml.in/yaml/v3" "golang.org/x/tools/go/packages" - "github.com/golangci/golangci-lint/pkg/config" -) - -const ( - PresetBugs = "bugs" // Related to bugs detection. - PresetComment = "comment" // Related to comments analysis. - PresetComplexity = "complexity" // Related to code complexity analysis. - PresetError = "error" // Related to error handling analysis. - PresetFormatting = "format" // Related to code formatting. - PresetImport = "import" // Related to imports analysis. - PresetMetaLinter = "metalinter" // Related to linter that contains multiple rules or multiple linters. - PresetModule = "module" // Related to Go modules analysis. - PresetPerformance = "performance" // Related to performance. - PresetSQL = "sql" // Related to SQL. - PresetStyle = "style" // Related to coding style. - PresetTest = "test" // Related to the analysis of the code of the tests. - PresetUnused = "unused" // Related to the detection of unused code. + "github.com/golangci/golangci-lint/v2/pkg/config" ) // LastLinter nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives. @@ -36,19 +22,19 @@ const ( ) type Deprecation struct { - Since string - Message string - Replacement string - Level DeprecationLevel + Since string + Message string + Replacement string + Level DeprecationLevel + ConfigSuggestion func() (string, error) } type Config struct { - Linter Linter - EnabledByDefault bool + Linter Linter + Groups map[string]struct{} LoadMode packages.LoadMode - InPresets []string AlternativeNames []string OriginalURL string // URL of original (not forked) repo, needed for autogenerated README @@ -61,9 +47,11 @@ type Config struct { Deprecation *Deprecation } -func (lc *Config) WithEnabledByDefault() *Config { - lc.EnabledByDefault = true - return lc +func NewConfig(linter Linter) *Config { + lc := &Config{ + Linter: linter, + } + return lc.WithLoadFiles() } func (lc *Config) WithInternal() *Config { @@ -92,11 +80,23 @@ func (lc *Config) WithLoadForGoAnalysis() *Config { return lc } -func (lc *Config) WithPresets(presets ...string) *Config { - lc.InPresets = presets +func (lc *Config) WithGroups(names ...string) *Config { + if lc.Groups == nil { + lc.Groups = make(map[string]struct{}) + } + + for _, name := range names { + lc.Groups[name] = struct{}{} + } + return lc } +func (lc *Config) FromGroup(name string) bool { + _, ok := lc.Groups[name] + return ok +} + func (lc *Config) WithURL(url string) *Config { lc.OriginalURL = url return lc @@ -122,22 +122,26 @@ func (lc *Config) WithSince(version string) *Config { return lc } -func (lc *Config) Deprecated(message, version, replacement string, level DeprecationLevel) *Config { +func (lc *Config) Deprecated(message, version string, level DeprecationLevel, opts ...func(*Deprecation)) *Config { lc.Deprecation = &Deprecation{ - Since: version, - Message: message, - Replacement: replacement, - Level: level, + Since: version, + Message: message, + Level: level, + } + + for _, opt := range opts { + opt(lc.Deprecation) } + return lc } -func (lc *Config) DeprecatedWarning(message, version, replacement string) *Config { - return lc.Deprecated(message, version, replacement, DeprecationWarning) +func (lc *Config) DeprecatedWarning(message, version string, opts ...func(*Deprecation)) *Config { + return lc.Deprecated(message, version, DeprecationWarning, opts...) } -func (lc *Config) DeprecatedError(message, version, replacement string) *Config { - return lc.Deprecated(message, version, replacement, DeprecationError) +func (lc *Config) DeprecatedError(message, version string, opts ...func(*Deprecation)) *Config { + return lc.Deprecated(message, version, DeprecationError, opts...) } func (lc *Config) IsDeprecated() bool { @@ -163,19 +167,55 @@ func (lc *Config) WithNoopFallback(cfg *config.Config, cond func(cfg *config.Con return lc } -func IsGoLowerThanGo122() func(cfg *config.Config) error { - return func(cfg *config.Config) error { - if cfg == nil || config.IsGoGreaterThanOrEqual(cfg.Run.Go, "1.22") { - return nil +func Replacement[T any](replacement string, mgr func(T) any, data T) func(*Deprecation) { + return func(d *Deprecation) { + if replacement == "" { + return } - return fmt.Errorf("this linter is disabled because the Go version (%s) of your project is lower than Go 1.22", cfg.Run.Go) + d.Replacement = replacement + + if mgr == nil { + return + } + + d.ConfigSuggestion = func() (string, error) { + buf := bytes.NewBuffer([]byte{}) + + encoder := yaml.NewEncoder(buf) + encoder.SetIndent(2) + + suggestion := map[string]any{ + "linters": map[string]any{ + "enable": []string{ + d.Replacement, + }, + "settings": map[string]any{ + d.Replacement: mgr(data), + }, + }, + } + + err := encoder.Encode(suggestion) + if err != nil { + return "", fmt.Errorf("%s: invalid configuration: %w", d.Replacement, err) + } + + return buf.String(), nil + } } } -func NewConfig(linter Linter) *Config { - lc := &Config{ - Linter: linter, +func IsGoLowerThanGo122() func(cfg *config.Config) error { + return isGoLowerThanGo("1.22") +} + +func isGoLowerThanGo(v string) func(cfg *config.Config) error { + return func(cfg *config.Config) error { + if cfg == nil || config.IsGoGreaterThanOrEqual(cfg.Run.Go, v) { + return nil + } + + return fmt.Errorf("this linter is disabled because the Go version (%s) of your project is lower than Go %s", cfg.Run.Go, v) } - return lc.WithLoadFiles() } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/lint/linter/context.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/lint/linter/context.go similarity index 65% rename from vendor/github.com/golangci/golangci-lint/pkg/lint/linter/context.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/lint/linter/context.go index 9f29b5c4c..cf463ea92 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/lint/linter/context.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/lint/linter/context.go @@ -5,11 +5,10 @@ import ( "golang.org/x/tools/go/packages" - "github.com/golangci/golangci-lint/internal/cache" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/fsutils" - "github.com/golangci/golangci-lint/pkg/goanalysis/load" - "github.com/golangci/golangci-lint/pkg/logutils" + "github.com/golangci/golangci-lint/v2/internal/cache" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis/load" + "github.com/golangci/golangci-lint/v2/pkg/logutils" ) type Context struct { @@ -20,16 +19,15 @@ type Context struct { // version for each of packages OriginalPackages []*packages.Package - Cfg *config.Config - FileCache *fsutils.FileCache - Log logutils.Log + Cfg *config.Config + Log logutils.Log PkgCache *cache.Cache LoadGuard *load.Guard } func (c *Context) Settings() *config.LintersSettings { - return &c.Cfg.LintersSettings + return &c.Cfg.Linters.Settings } func (c *Context) ClearTypesInPackages() { diff --git a/vendor/github.com/golangci/golangci-lint/pkg/lint/linter/linter.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/lint/linter/linter.go similarity index 78% rename from vendor/github.com/golangci/golangci-lint/pkg/lint/linter/linter.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/lint/linter/linter.go index 088aa3d78..e6b484efb 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/lint/linter/linter.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/lint/linter/linter.go @@ -3,12 +3,12 @@ package linter import ( "context" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/result" ) type Linter interface { - Run(ctx context.Context, lintCtx *Context) ([]result.Issue, error) + Run(ctx context.Context, lintCtx *Context) ([]*result.Issue, error) Name() string Desc() string } @@ -43,7 +43,7 @@ func NewNoopDeprecated(name string, cfg *config.Config, level DeprecationLevel) return noop } -func (n Noop) Run(_ context.Context, lintCtx *Context) ([]result.Issue, error) { +func (n Noop) Run(_ context.Context, lintCtx *Context) ([]*result.Issue, error) { if n.reason == "" { return nil, nil } diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/lint/lintersdb/builder_linter.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/lint/lintersdb/builder_linter.go new file mode 100644 index 000000000..2581bb74e --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/lint/lintersdb/builder_linter.go @@ -0,0 +1,741 @@ +package lintersdb + +import ( + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/golinters" + "github.com/golangci/golangci-lint/v2/pkg/golinters/arangolint" + "github.com/golangci/golangci-lint/v2/pkg/golinters/asasalint" + "github.com/golangci/golangci-lint/v2/pkg/golinters/asciicheck" + "github.com/golangci/golangci-lint/v2/pkg/golinters/bidichk" + "github.com/golangci/golangci-lint/v2/pkg/golinters/bodyclose" + "github.com/golangci/golangci-lint/v2/pkg/golinters/canonicalheader" + "github.com/golangci/golangci-lint/v2/pkg/golinters/containedctx" + "github.com/golangci/golangci-lint/v2/pkg/golinters/contextcheck" + "github.com/golangci/golangci-lint/v2/pkg/golinters/copyloopvar" + "github.com/golangci/golangci-lint/v2/pkg/golinters/cyclop" + "github.com/golangci/golangci-lint/v2/pkg/golinters/decorder" + "github.com/golangci/golangci-lint/v2/pkg/golinters/depguard" + "github.com/golangci/golangci-lint/v2/pkg/golinters/dogsled" + "github.com/golangci/golangci-lint/v2/pkg/golinters/dupl" + "github.com/golangci/golangci-lint/v2/pkg/golinters/dupword" + "github.com/golangci/golangci-lint/v2/pkg/golinters/durationcheck" + "github.com/golangci/golangci-lint/v2/pkg/golinters/embeddedstructfieldcheck" + "github.com/golangci/golangci-lint/v2/pkg/golinters/err113" + "github.com/golangci/golangci-lint/v2/pkg/golinters/errcheck" + "github.com/golangci/golangci-lint/v2/pkg/golinters/errchkjson" + "github.com/golangci/golangci-lint/v2/pkg/golinters/errname" + "github.com/golangci/golangci-lint/v2/pkg/golinters/errorlint" + "github.com/golangci/golangci-lint/v2/pkg/golinters/exhaustive" + "github.com/golangci/golangci-lint/v2/pkg/golinters/exhaustruct" + "github.com/golangci/golangci-lint/v2/pkg/golinters/exptostd" + "github.com/golangci/golangci-lint/v2/pkg/golinters/fatcontext" + "github.com/golangci/golangci-lint/v2/pkg/golinters/forbidigo" + "github.com/golangci/golangci-lint/v2/pkg/golinters/forcetypeassert" + "github.com/golangci/golangci-lint/v2/pkg/golinters/funcorder" + "github.com/golangci/golangci-lint/v2/pkg/golinters/funlen" + "github.com/golangci/golangci-lint/v2/pkg/golinters/gci" + "github.com/golangci/golangci-lint/v2/pkg/golinters/ginkgolinter" + "github.com/golangci/golangci-lint/v2/pkg/golinters/gocheckcompilerdirectives" + "github.com/golangci/golangci-lint/v2/pkg/golinters/gochecknoglobals" + "github.com/golangci/golangci-lint/v2/pkg/golinters/gochecknoinits" + "github.com/golangci/golangci-lint/v2/pkg/golinters/gochecksumtype" + "github.com/golangci/golangci-lint/v2/pkg/golinters/gocognit" + "github.com/golangci/golangci-lint/v2/pkg/golinters/goconst" + "github.com/golangci/golangci-lint/v2/pkg/golinters/gocritic" + "github.com/golangci/golangci-lint/v2/pkg/golinters/gocyclo" + "github.com/golangci/golangci-lint/v2/pkg/golinters/godoclint" + "github.com/golangci/golangci-lint/v2/pkg/golinters/godot" + "github.com/golangci/golangci-lint/v2/pkg/golinters/godox" + "github.com/golangci/golangci-lint/v2/pkg/golinters/gofmt" + "github.com/golangci/golangci-lint/v2/pkg/golinters/gofumpt" + "github.com/golangci/golangci-lint/v2/pkg/golinters/goheader" + "github.com/golangci/golangci-lint/v2/pkg/golinters/goimports" + "github.com/golangci/golangci-lint/v2/pkg/golinters/golines" + "github.com/golangci/golangci-lint/v2/pkg/golinters/gomoddirectives" + "github.com/golangci/golangci-lint/v2/pkg/golinters/gomodguard" + "github.com/golangci/golangci-lint/v2/pkg/golinters/goprintffuncname" + "github.com/golangci/golangci-lint/v2/pkg/golinters/gosec" + "github.com/golangci/golangci-lint/v2/pkg/golinters/gosmopolitan" + "github.com/golangci/golangci-lint/v2/pkg/golinters/govet" + "github.com/golangci/golangci-lint/v2/pkg/golinters/grouper" + "github.com/golangci/golangci-lint/v2/pkg/golinters/iface" + "github.com/golangci/golangci-lint/v2/pkg/golinters/importas" + "github.com/golangci/golangci-lint/v2/pkg/golinters/inamedparam" + "github.com/golangci/golangci-lint/v2/pkg/golinters/ineffassign" + "github.com/golangci/golangci-lint/v2/pkg/golinters/interfacebloat" + "github.com/golangci/golangci-lint/v2/pkg/golinters/intrange" + "github.com/golangci/golangci-lint/v2/pkg/golinters/iotamixing" + "github.com/golangci/golangci-lint/v2/pkg/golinters/ireturn" + "github.com/golangci/golangci-lint/v2/pkg/golinters/lll" + "github.com/golangci/golangci-lint/v2/pkg/golinters/loggercheck" + "github.com/golangci/golangci-lint/v2/pkg/golinters/maintidx" + "github.com/golangci/golangci-lint/v2/pkg/golinters/makezero" + "github.com/golangci/golangci-lint/v2/pkg/golinters/mirror" + "github.com/golangci/golangci-lint/v2/pkg/golinters/misspell" + "github.com/golangci/golangci-lint/v2/pkg/golinters/mnd" + "github.com/golangci/golangci-lint/v2/pkg/golinters/modernize" + "github.com/golangci/golangci-lint/v2/pkg/golinters/musttag" + "github.com/golangci/golangci-lint/v2/pkg/golinters/nakedret" + "github.com/golangci/golangci-lint/v2/pkg/golinters/nestif" + "github.com/golangci/golangci-lint/v2/pkg/golinters/nilerr" + "github.com/golangci/golangci-lint/v2/pkg/golinters/nilnesserr" + "github.com/golangci/golangci-lint/v2/pkg/golinters/nilnil" + "github.com/golangci/golangci-lint/v2/pkg/golinters/nlreturn" + "github.com/golangci/golangci-lint/v2/pkg/golinters/noctx" + "github.com/golangci/golangci-lint/v2/pkg/golinters/noinlineerr" + "github.com/golangci/golangci-lint/v2/pkg/golinters/nolintlint" + "github.com/golangci/golangci-lint/v2/pkg/golinters/nonamedreturns" + "github.com/golangci/golangci-lint/v2/pkg/golinters/nosprintfhostport" + "github.com/golangci/golangci-lint/v2/pkg/golinters/paralleltest" + "github.com/golangci/golangci-lint/v2/pkg/golinters/perfsprint" + "github.com/golangci/golangci-lint/v2/pkg/golinters/prealloc" + "github.com/golangci/golangci-lint/v2/pkg/golinters/predeclared" + "github.com/golangci/golangci-lint/v2/pkg/golinters/promlinter" + "github.com/golangci/golangci-lint/v2/pkg/golinters/protogetter" + "github.com/golangci/golangci-lint/v2/pkg/golinters/reassign" + "github.com/golangci/golangci-lint/v2/pkg/golinters/recvcheck" + "github.com/golangci/golangci-lint/v2/pkg/golinters/revive" + "github.com/golangci/golangci-lint/v2/pkg/golinters/rowserrcheck" + "github.com/golangci/golangci-lint/v2/pkg/golinters/sloglint" + "github.com/golangci/golangci-lint/v2/pkg/golinters/spancheck" + "github.com/golangci/golangci-lint/v2/pkg/golinters/sqlclosecheck" + "github.com/golangci/golangci-lint/v2/pkg/golinters/staticcheck" + "github.com/golangci/golangci-lint/v2/pkg/golinters/swaggo" + "github.com/golangci/golangci-lint/v2/pkg/golinters/tagalign" + "github.com/golangci/golangci-lint/v2/pkg/golinters/tagliatelle" + "github.com/golangci/golangci-lint/v2/pkg/golinters/testableexamples" + "github.com/golangci/golangci-lint/v2/pkg/golinters/testifylint" + "github.com/golangci/golangci-lint/v2/pkg/golinters/testpackage" + "github.com/golangci/golangci-lint/v2/pkg/golinters/thelper" + "github.com/golangci/golangci-lint/v2/pkg/golinters/tparallel" + "github.com/golangci/golangci-lint/v2/pkg/golinters/unconvert" + "github.com/golangci/golangci-lint/v2/pkg/golinters/unparam" + "github.com/golangci/golangci-lint/v2/pkg/golinters/unqueryvet" + "github.com/golangci/golangci-lint/v2/pkg/golinters/unused" + "github.com/golangci/golangci-lint/v2/pkg/golinters/usestdlibvars" + "github.com/golangci/golangci-lint/v2/pkg/golinters/usetesting" + "github.com/golangci/golangci-lint/v2/pkg/golinters/varnamelen" + "github.com/golangci/golangci-lint/v2/pkg/golinters/wastedassign" + "github.com/golangci/golangci-lint/v2/pkg/golinters/whitespace" + "github.com/golangci/golangci-lint/v2/pkg/golinters/wrapcheck" + "github.com/golangci/golangci-lint/v2/pkg/golinters/wsl" + "github.com/golangci/golangci-lint/v2/pkg/golinters/zerologlint" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" +) + +// LinterBuilder builds the "internal" linters based on the configuration. +type LinterBuilder struct{} + +// NewLinterBuilder creates a new LinterBuilder. +func NewLinterBuilder() *LinterBuilder { + return &LinterBuilder{} +} + +// Build loads all the "internal" linters. +// The configuration is use for the linter settings. +func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) { + if cfg == nil { + return nil, nil + } + + placeholderReplacer := config.NewPlaceholderReplacer(cfg) + + // The linters are sorted in the alphabetical order (case-insensitive). + // When a new linter is added the version in `WithSince(...)` must be the next minor version of golangci-lint. + return []*linter.Config{ + linter.NewConfig(arangolint.New()). + WithSince("v2.2.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/Crocmagnon/arangolint"), + + linter.NewConfig(asasalint.New(&cfg.Linters.Settings.Asasalint)). + WithSince("v1.47.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/alingse/asasalint"), + + linter.NewConfig(asciicheck.New()). + WithSince("v1.26.0"). + WithURL("https://github.com/golangci/asciicheck"), + + linter.NewConfig(bidichk.New(&cfg.Linters.Settings.BiDiChk)). + WithSince("v1.43.0"). + WithURL("https://github.com/breml/bidichk"), + + linter.NewConfig(bodyclose.New()). + WithSince("v1.18.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/timakin/bodyclose"), + + linter.NewConfig(canonicalheader.New()). + WithSince("v1.58.0"). + WithLoadForGoAnalysis(). + WithAutoFix(). + WithURL("https://github.com/lasiar/canonicalheader"), + + linter.NewConfig(containedctx.New()). + WithSince("v1.44.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/sivchari/containedctx"), + + linter.NewConfig(contextcheck.New()). + WithSince("v1.43.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/kkHAIKE/contextcheck"), + + linter.NewConfig(copyloopvar.New(&cfg.Linters.Settings.CopyLoopVar)). + WithSince("v1.57.0"). + WithAutoFix(). + WithURL("https://github.com/karamaru-alpha/copyloopvar"). + WithNoopFallback(cfg, linter.IsGoLowerThanGo122()), + + linter.NewConfig(cyclop.New(&cfg.Linters.Settings.Cyclop)). + WithSince("v1.37.0"). + WithURL("https://github.com/bkielbasa/cyclop"), + + linter.NewConfig(decorder.New(&cfg.Linters.Settings.Decorder)). + WithSince("v1.44.0"). + WithURL("https://gitlab.com/bosi/decorder"), + + linter.NewConfig(depguard.New(&cfg.Linters.Settings.Depguard, placeholderReplacer)). + WithSince("v1.4.0"). + WithURL("https://github.com/OpenPeeDeeP/depguard"), + + linter.NewConfig(dogsled.New(&cfg.Linters.Settings.Dogsled)). + WithSince("v1.19.0"). + WithURL("https://github.com/alexkohler/dogsled"), + + linter.NewConfig(dupl.New(&cfg.Linters.Settings.Dupl)). + WithSince("v1.0.0"). + WithURL("https://github.com/mibk/dupl"), + + linter.NewConfig(dupword.New(&cfg.Linters.Settings.DupWord)). + WithSince("v1.50.0"). + WithAutoFix(). + WithURL("https://github.com/Abirdcfly/dupword"), + + linter.NewConfig(durationcheck.New()). + WithSince("v1.37.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/charithe/durationcheck"), + + linter.NewConfig(embeddedstructfieldcheck.New(&cfg.Linters.Settings.EmbeddedStructFieldCheck)). + WithSince("v2.2.0"). + WithURL("https://github.com/manuelarte/embeddedstructfieldcheck"), + + linter.NewConfig(errcheck.New(&cfg.Linters.Settings.Errcheck)). + WithGroups(config.GroupStandard). + WithSince("v1.0.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/kisielk/errcheck"), + + linter.NewConfig(errchkjson.New(&cfg.Linters.Settings.ErrChkJSON)). + WithSince("v1.44.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/breml/errchkjson"), + + linter.NewConfig(errname.New()). + WithSince("v1.42.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/Antonboom/errname"), + + linter.NewConfig(errorlint.New(&cfg.Linters.Settings.ErrorLint)). + WithSince("v1.32.0"). + WithLoadForGoAnalysis(). + WithAutoFix(). + WithURL("https://codeberg.org/polyfloyd/go-errorlint"), + + linter.NewConfig(exhaustive.New(&cfg.Linters.Settings.Exhaustive)). + WithSince("v1.28.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/nishanths/exhaustive"), + + linter.NewConfig(exhaustruct.New(&cfg.Linters.Settings.Exhaustruct)). + WithSince("v1.46.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/GaijinEntertainment/go-exhaustruct"), + + linter.NewConfig(exptostd.New()). + WithSince("v1.63.0"). + WithLoadForGoAnalysis(). + WithAutoFix(). + WithURL("https://github.com/ldez/exptostd"), + + linter.NewConfig(forbidigo.New(&cfg.Linters.Settings.Forbidigo)). + WithSince("v1.34.0"). + // Strictly speaking, + // the additional information is only needed when forbidigoCfg.AnalyzeTypes is chosen by the user. + // But we don't know that here in all cases (sometimes config is not loaded), + // so we have to assume that it is needed to be on the safe side. + WithLoadForGoAnalysis(). + WithURL("https://github.com/ashanbrown/forbidigo"), + + linter.NewConfig(forcetypeassert.New()). + WithSince("v1.38.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/gostaticanalysis/forcetypeassert"), + + linter.NewConfig(funcorder.New(&cfg.Linters.Settings.FuncOrder)). + WithSince("v2.1.0"). + WithURL("https://github.com/manuelarte/funcorder"), + + linter.NewConfig(fatcontext.New(&cfg.Linters.Settings.Fatcontext)). + WithSince("v1.58.0"). + WithLoadForGoAnalysis(). + WithAutoFix(). + WithURL("https://github.com/Crocmagnon/fatcontext"), + + linter.NewConfig(funlen.New(&cfg.Linters.Settings.Funlen)). + WithSince("v1.18.0"). + WithURL("https://github.com/ultraware/funlen"), + + linter.NewConfig(gci.New(&cfg.Linters.Settings.Gci)). + WithSince("v1.30.0"). + WithAutoFix(). + WithURL("https://github.com/daixiang0/gci"), + + linter.NewConfig(ginkgolinter.New(&cfg.Linters.Settings.GinkgoLinter)). + WithSince("v1.51.0"). + WithLoadForGoAnalysis(). + WithAutoFix(). + WithURL("https://github.com/nunnatsa/ginkgolinter"), + + linter.NewConfig(gocheckcompilerdirectives.New()). + WithSince("v1.51.0"). + WithURL("https://github.com/leighmcculloch/gocheckcompilerdirectives"), + + linter.NewConfig(gochecknoglobals.New()). + WithSince("v1.12.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/leighmcculloch/gochecknoglobals"), + + linter.NewConfig(gochecknoinits.New()). + WithSince("v1.12.0"), + + linter.NewConfig(gochecksumtype.New(&cfg.Linters.Settings.GoChecksumType)). + WithSince("v1.55.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/alecthomas/go-check-sumtype"), + + linter.NewConfig(gocognit.New(&cfg.Linters.Settings.Gocognit)). + WithSince("v1.20.0"). + WithURL("https://github.com/uudashr/gocognit"), + + linter.NewConfig(goconst.New(&cfg.Linters.Settings.Goconst)). + WithSince("v1.0.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/jgautheron/goconst"), + + linter.NewConfig(gocritic.New(&cfg.Linters.Settings.Gocritic, placeholderReplacer)). + WithSince("v1.12.0"). + WithLoadForGoAnalysis(). + WithAutoFix(). + WithURL("https://github.com/go-critic/go-critic"), + + linter.NewConfig(gocyclo.New(&cfg.Linters.Settings.Gocyclo)). + WithSince("v1.0.0"). + WithURL("https://github.com/fzipp/gocyclo"), + + linter.NewConfig(godoclint.New(&cfg.Linters.Settings.Godoclint)). + WithSince("v2.5.0"). + WithURL("https://github.com/godoc-lint/godoc-lint"), + + linter.NewConfig(godot.New(&cfg.Linters.Settings.Godot)). + WithSince("v1.25.0"). + WithAutoFix(). + WithURL("https://github.com/tetafro/godot"), + + linter.NewConfig(godox.New(&cfg.Linters.Settings.Godox)). + WithSince("v1.19.0"). + WithURL("https://github.com/matoous/godox"), + + linter.NewConfig(err113.New()). + WithSince("v1.26.0"). + WithLoadForGoAnalysis(). + WithAutoFix(). + WithURL("https://github.com/Djarvur/go-err113"), + + linter.NewConfig(gofmt.New(&cfg.Linters.Settings.GoFmt)). + WithSince("v1.0.0"). + WithAutoFix(). + WithURL("https://pkg.go.dev/cmd/gofmt"), + + linter.NewConfig(gofumpt.New(&cfg.Linters.Settings.GoFumpt)). + WithSince("v1.28.0"). + WithAutoFix(). + WithURL("https://github.com/mvdan/gofumpt"), + + linter.NewConfig(golines.New(&cfg.Linters.Settings.GoLines)). + WithSince("v2.0.0"). + WithAutoFix(). + WithURL("https://github.com/segmentio/golines"), + + linter.NewConfig(goheader.New(&cfg.Linters.Settings.Goheader, placeholderReplacer)). + WithSince("v1.28.0"). + WithAutoFix(). + WithURL("https://github.com/denis-tingaikin/go-header"), + + linter.NewConfig(goimports.New(&cfg.Linters.Settings.GoImports)). + WithSince("v1.20.0"). + WithAutoFix(). + WithURL("https://pkg.go.dev/golang.org/x/tools/cmd/goimports"), + + linter.NewConfig(mnd.New(&cfg.Linters.Settings.Mnd)). + WithSince("v1.22.0"). + WithURL("https://github.com/tommy-muehle/go-mnd"), + + linter.NewConfig(modernize.New(&cfg.Linters.Settings.Modernize)). + WithSince("v2.6.0"). + WithLoadForGoAnalysis(). + WithURL("https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize"), + + linter.NewConfig(gomoddirectives.New(&cfg.Linters.Settings.GoModDirectives)). + WithSince("v1.39.0"). + WithURL("https://github.com/ldez/gomoddirectives"), + + linter.NewConfig(gomodguard.New(&cfg.Linters.Settings.Gomodguard)). + WithSince("v1.25.0"). + WithURL("https://github.com/ryancurrah/gomodguard"), + + linter.NewConfig(goprintffuncname.New()). + WithSince("v1.23.0"). + WithURL("https://github.com/golangci/go-printf-func-name"), + + linter.NewConfig(gosec.New(&cfg.Linters.Settings.Gosec)). + WithSince("v1.0.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/securego/gosec"), + + linter.NewConfig(gosmopolitan.New(&cfg.Linters.Settings.Gosmopolitan)). + WithSince("v1.53.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/xen0n/gosmopolitan"), + + linter.NewConfig(govet.New(&cfg.Linters.Settings.Govet)). + WithGroups(config.GroupStandard). + WithSince("v1.0.0"). + WithLoadForGoAnalysis(). + WithAutoFix(). + WithURL("https://pkg.go.dev/cmd/vet"), + + linter.NewConfig(grouper.New(&cfg.Linters.Settings.Grouper)). + WithSince("v1.44.0"). + WithURL("https://github.com/leonklingele/grouper"), + + linter.NewConfig(iface.New(&cfg.Linters.Settings.Iface)). + WithSince("v1.62.0"). + WithLoadForGoAnalysis(). + WithAutoFix(). + WithURL("https://github.com/uudashr/iface"), + + linter.NewConfig(importas.New(&cfg.Linters.Settings.ImportAs)). + WithSince("v1.38.0"). + WithLoadForGoAnalysis(). + WithAutoFix(). + WithURL("https://github.com/julz/importas"), + + linter.NewConfig(inamedparam.New(&cfg.Linters.Settings.Inamedparam)). + WithSince("v1.55.0"). + WithURL("https://github.com/macabu/inamedparam"), + + linter.NewConfig(ineffassign.New(&cfg.Linters.Settings.Ineffassign)). + WithGroups(config.GroupStandard). + WithSince("v1.0.0"). + WithURL("https://github.com/gordonklaus/ineffassign"), + + linter.NewConfig(interfacebloat.New(&cfg.Linters.Settings.InterfaceBloat)). + WithSince("v1.49.0"). + WithURL("https://github.com/sashamelentyev/interfacebloat"), + + linter.NewConfig(intrange.New()). + WithSince("v1.57.0"). + WithLoadForGoAnalysis(). + WithAutoFix(). + WithURL("https://github.com/ckaznocha/intrange"). + WithNoopFallback(cfg, linter.IsGoLowerThanGo122()), + + linter.NewConfig(iotamixing.New(&cfg.Linters.Settings.IotaMixing)). + WithSince("v2.5.0"). + WithURL("https://github.com/AdminBenni/iota-mixing"), + + linter.NewConfig(ireturn.New(&cfg.Linters.Settings.Ireturn)). + WithSince("v1.43.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/butuzov/ireturn"), + + linter.NewConfig(lll.New(&cfg.Linters.Settings.Lll)). + WithSince("v1.8.0"), + + linter.NewConfig(loggercheck.New(&cfg.Linters.Settings.LoggerCheck)). + WithSince("v1.49.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/timonwong/loggercheck"), + + linter.NewConfig(maintidx.New(&cfg.Linters.Settings.MaintIdx)). + WithSince("v1.44.0"). + WithURL("https://github.com/yagipy/maintidx"), + + linter.NewConfig(makezero.New(&cfg.Linters.Settings.Makezero)). + WithSince("v1.34.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/ashanbrown/makezero"), + + linter.NewConfig(mirror.New()). + WithSince("v1.53.0"). + WithLoadForGoAnalysis(). + WithAutoFix(). + WithURL("https://github.com/butuzov/mirror"), + + linter.NewConfig(misspell.New(&cfg.Linters.Settings.Misspell)). + WithSince("v1.8.0"). + WithAutoFix(). + WithURL("https://github.com/golangci/misspell"), + + linter.NewConfig(musttag.New(&cfg.Linters.Settings.MustTag)). + WithSince("v1.51.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/go-simpler/musttag"), + + linter.NewConfig(nakedret.New(&cfg.Linters.Settings.Nakedret)). + WithSince("v1.19.0"). + WithAutoFix(). + WithURL("https://github.com/alexkohler/nakedret"), + + linter.NewConfig(nestif.New(&cfg.Linters.Settings.Nestif)). + WithSince("v1.25.0"). + WithURL("https://github.com/nakabonne/nestif"), + + linter.NewConfig(nilerr.New()). + WithSince("v1.38.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/gostaticanalysis/nilerr"), + + linter.NewConfig(nilnesserr.New()). + WithSince("v1.63.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/alingse/nilnesserr"), + + linter.NewConfig(nilnil.New(&cfg.Linters.Settings.NilNil)). + WithSince("v1.43.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/Antonboom/nilnil"), + + linter.NewConfig(nlreturn.New(&cfg.Linters.Settings.Nlreturn)). + WithSince("v1.30.0"). + WithAutoFix(). + WithURL("https://github.com/ssgreg/nlreturn"), + + linter.NewConfig(noctx.New()). + WithSince("v1.28.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/sonatard/noctx"), + + linter.NewConfig(noinlineerr.New()). + WithSince("v2.2.0"). + WithLoadForGoAnalysis(). + WithAutoFix(). + WithURL("https://github.com/AlwxSin/noinlineerr"), + + linter.NewConfig(nonamedreturns.New(&cfg.Linters.Settings.NoNamedReturns)). + WithSince("v1.46.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/firefart/nonamedreturns"), + + linter.NewConfig(nosprintfhostport.New()). + WithSince("v1.46.0"). + WithURL("https://github.com/stbenjam/no-sprintf-host-port"), + + linter.NewConfig(paralleltest.New(&cfg.Linters.Settings.ParallelTest)). + WithSince("v1.33.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/kunwardeep/paralleltest"), + + linter.NewConfig(perfsprint.New(&cfg.Linters.Settings.PerfSprint)). + WithSince("v1.55.0"). + WithLoadForGoAnalysis(). + WithAutoFix(). + WithURL("https://github.com/catenacyber/perfsprint"), + + linter.NewConfig(prealloc.New(&cfg.Linters.Settings.Prealloc)). + WithSince("v1.19.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/alexkohler/prealloc"), + + linter.NewConfig(predeclared.New(&cfg.Linters.Settings.Predeclared)). + WithSince("v1.35.0"). + WithURL("https://github.com/nishanths/predeclared"), + + linter.NewConfig(promlinter.New(&cfg.Linters.Settings.Promlinter)). + WithSince("v1.40.0"). + WithURL("https://github.com/yeya24/promlinter"), + + linter.NewConfig(protogetter.New(&cfg.Linters.Settings.ProtoGetter)). + WithSince("v1.55.0"). + WithLoadForGoAnalysis(). + WithAutoFix(). + WithURL("https://github.com/ghostiam/protogetter"), + + linter.NewConfig(reassign.New(&cfg.Linters.Settings.Reassign)). + WithSince("v1.49.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/curioswitch/go-reassign"), + + linter.NewConfig(recvcheck.New(&cfg.Linters.Settings.Recvcheck)). + WithSince("v1.62.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/raeperd/recvcheck"), + + linter.NewConfig(revive.New(&cfg.Linters.Settings.Revive)). + WithSince("v1.37.0"). + ConsiderSlow(). + WithAutoFix(). + WithURL("https://github.com/mgechev/revive"), + + linter.NewConfig(rowserrcheck.New(&cfg.Linters.Settings.RowsErrCheck)). + WithSince("v1.23.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/jingyugao/rowserrcheck"), + + linter.NewConfig(sloglint.New(&cfg.Linters.Settings.SlogLint)). + WithSince("v1.55.0"). + WithLoadForGoAnalysis(). + WithAutoFix(). + WithURL("https://github.com/go-simpler/sloglint"), + + linter.NewConfig(sqlclosecheck.New()). + WithSince("v1.28.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/ryanrolds/sqlclosecheck"), + + linter.NewConfig(spancheck.New(&cfg.Linters.Settings.Spancheck)). + WithSince("v1.56.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/jjti/go-spancheck"), + + linter.NewConfig(staticcheck.New(&cfg.Linters.Settings.Staticcheck)). + WithGroups(config.GroupStandard). + WithSince("v1.0.0"). + WithLoadForGoAnalysis(). + WithAutoFix(). + WithURL("https://github.com/dominikh/go-tools"), + + linter.NewConfig(swaggo.New()). + WithSince("v2.2.0"). + WithAutoFix(). + WithURL("https://github.com/swaggo/swag"), + + linter.NewConfig(tagalign.New(&cfg.Linters.Settings.TagAlign)). + WithSince("v1.53.0"). + WithAutoFix(). + WithURL("https://github.com/4meepo/tagalign"), + + linter.NewConfig(tagliatelle.New(&cfg.Linters.Settings.Tagliatelle)). + WithSince("v1.40.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/ldez/tagliatelle"), + + linter.NewConfig(testableexamples.New()). + WithSince("v1.50.0"). + WithURL("https://github.com/maratori/testableexamples"), + + linter.NewConfig(testifylint.New(&cfg.Linters.Settings.Testifylint)). + WithSince("v1.55.0"). + WithLoadForGoAnalysis(). + WithAutoFix(). + WithURL("https://github.com/Antonboom/testifylint"), + + linter.NewConfig(testpackage.New(&cfg.Linters.Settings.Testpackage)). + WithSince("v1.25.0"). + WithURL("https://github.com/maratori/testpackage"), + + linter.NewConfig(thelper.New(&cfg.Linters.Settings.Thelper)). + WithSince("v1.34.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/kulti/thelper"), + + linter.NewConfig(tparallel.New()). + WithSince("v1.32.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/moricho/tparallel"), + + linter.NewConfig(golinters.NewTypecheck()). + WithInternal(). + WithSince("v1.3.0"), + + linter.NewConfig(unconvert.New(&cfg.Linters.Settings.Unconvert)). + WithSince("v1.0.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/mdempsky/unconvert"), + + linter.NewConfig(unparam.New(&cfg.Linters.Settings.Unparam)). + WithSince("v1.9.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/mvdan/unparam"), + + linter.NewConfig(unqueryvet.New(&cfg.Linters.Settings.Unqueryvet)). + WithSince("v2.5.0"). + WithURL("https://github.com/MirrexOne/unqueryvet"), + + linter.NewConfig(unused.New(&cfg.Linters.Settings.Unused)). + WithGroups(config.GroupStandard). + WithSince("v1.20.0"). + WithLoadForGoAnalysis(). + ConsiderSlow(). + WithChangeTypes(). + WithURL("https://github.com/dominikh/go-tools/tree/HEAD/unused"), + + linter.NewConfig(usestdlibvars.New(&cfg.Linters.Settings.UseStdlibVars)). + WithSince("v1.48.0"). + WithAutoFix(). + WithURL("https://github.com/sashamelentyev/usestdlibvars"), + + linter.NewConfig(usetesting.New(&cfg.Linters.Settings.UseTesting)). + WithSince("v1.63.0"). + WithLoadForGoAnalysis(). + WithAutoFix(). + WithURL("https://github.com/ldez/usetesting"), + + linter.NewConfig(varnamelen.New(&cfg.Linters.Settings.Varnamelen)). + WithSince("v1.43.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/blizzy78/varnamelen"), + + linter.NewConfig(wastedassign.New()). + WithSince("v1.38.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/sanposhiho/wastedassign"), + + linter.NewConfig(whitespace.New(&cfg.Linters.Settings.Whitespace)). + WithSince("v1.19.0"). + WithAutoFix(). + WithURL("https://github.com/ultraware/whitespace"), + + linter.NewConfig(wrapcheck.New(&cfg.Linters.Settings.Wrapcheck)). + WithSince("v1.32.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/tomarrell/wrapcheck"), + + linter.NewConfig(wsl.NewV4(&cfg.Linters.Settings.WSL)). + DeprecatedWarning("new major version.", "v2.2.0", + linter.Replacement("wsl_v5", wsl.Migration, &cfg.Linters.Settings.WSL)). + WithSince("v1.20.0"). + WithAutoFix(). + WithURL("https://github.com/bombsimon/wsl"), + + linter.NewConfig(wsl.NewV5(&cfg.Linters.Settings.WSLv5)). + WithSince("v2.2.0"). + WithLoadForGoAnalysis(). + WithAutoFix(). + WithURL("https://github.com/bombsimon/wsl"), + + linter.NewConfig(zerologlint.New()). + WithSince("v1.53.0"). + WithLoadForGoAnalysis(). + WithURL("https://github.com/ykadowak/zerologlint"), + + // nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives + linter.NewConfig(nolintlint.New(&cfg.Linters.Settings.NoLintLint)). + WithSince("v1.26.0"). + WithAutoFix(). + WithURL("https://github.com/golangci/golangci-lint/tree/HEAD/pkg/golinters/nolintlint/internal"), + }, nil +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/builder_plugin_go.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/lint/lintersdb/builder_plugin_go.go similarity index 84% rename from vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/builder_plugin_go.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/lint/lintersdb/builder_plugin_go.go index 88f3e2ae3..005ca6169 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/builder_plugin_go.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/lint/lintersdb/builder_plugin_go.go @@ -1,6 +1,7 @@ package lintersdb import ( + "context" "errors" "fmt" "path/filepath" @@ -8,10 +9,11 @@ import ( "golang.org/x/tools/go/analysis" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/fsutils" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/logutils" ) const goPluginType = "goplugin" @@ -38,7 +40,7 @@ func (b *PluginGoBuilder) Build(cfg *config.Config) ([]*linter.Config, error) { var linters []*linter.Config - for name, settings := range cfg.LintersSettings.Custom { + for name, settings := range cfg.Linters.Settings.Custom { if settings.Type != goPluginType && settings.Type != "" { continue } @@ -67,7 +69,7 @@ func (b *PluginGoBuilder) loadConfig(cfg *config.Config, name string, settings * WithLoadMode(goanalysis.LoadModeTypesInfo) linterConfig := linter.NewConfig(customLinter). - WithEnabledByDefault(). + WithGroups(config.GroupStandard). WithLoadForGoAnalysis(). WithURL(settings.OriginalURL) @@ -81,8 +83,13 @@ func (b *PluginGoBuilder) loadConfig(cfg *config.Config, name string, settings * // or the linter does not implement the AnalyzerPlugin interface. func (b *PluginGoBuilder) getAnalyzerPlugin(cfg *config.Config, path string, settings any) ([]*analysis.Analyzer, error) { if !filepath.IsAbs(path) { + basePath, err := fsutils.GetBasePath(context.Background(), cfg.Run.RelativePathMode, cfg.GetConfigDir()) + if err != nil { + return nil, fmt.Errorf("get base path: %w", err) + } + // resolve non-absolute paths relative to config file's directory - path = filepath.Join(cfg.GetConfigDir(), path) + path = filepath.Join(basePath, path) } plug, err := plugin.Open(path) @@ -125,7 +132,7 @@ func (b *PluginGoBuilder) lookupAnalyzerPlugin(plug *plugin.Plugin) ([]*analysis } b.log.Warnf("plugin: 'AnalyzerPlugin' plugins are deprecated, please use the new plugin signature: " + - "https://golangci-lint.run/plugins/go-plugins#create-a-plugin") + "https://golangci-lint.run/docs/plugins/go-plugins#create-a-plugin") analyzerPlugin, ok := symbol.(AnalyzerPlugin) if !ok { diff --git a/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/builder_plugin_module.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/lint/lintersdb/builder_plugin_module.go similarity index 86% rename from vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/builder_plugin_module.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/lint/lintersdb/builder_plugin_module.go index 60fb58d8c..71a01302d 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/builder_plugin_module.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/lint/lintersdb/builder_plugin_module.go @@ -6,10 +6,10 @@ import ( "github.com/golangci/plugin-module-register/register" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/logutils" ) const modulePluginType = "module" @@ -32,7 +32,7 @@ func (b *PluginModuleBuilder) Build(cfg *config.Config) ([]*linter.Config, error var linters []*linter.Config - for name, settings := range cfg.LintersSettings.Custom { + for name, settings := range cfg.Linters.Settings.Custom { if settings.Type != modulePluginType { continue } @@ -66,7 +66,7 @@ func (b *PluginModuleBuilder) Build(cfg *config.Config) ([]*linter.Config, error } lc := linter.NewConfig(customLinter). - WithEnabledByDefault(). + WithGroups(config.GroupStandard). WithURL(settings.OriginalURL) switch strings.ToLower(p.GetLoadMode()) { diff --git a/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/manager.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/lint/lintersdb/manager.go similarity index 66% rename from vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/manager.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/lint/lintersdb/manager.go index 75ab53d7c..9750301bf 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/manager.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/lint/lintersdb/manager.go @@ -1,17 +1,19 @@ package lintersdb import ( + "cmp" "fmt" + "maps" "os" "slices" "sort" + "strings" - "golang.org/x/exp/maps" - - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis" + "github.com/golangci/golangci-lint/v2/pkg/goformatters" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/logutils" ) type Builder interface { @@ -76,23 +78,11 @@ func (m *Manager) GetAllSupportedLinterConfigs() []*linter.Config { return m.linters } -func (m *Manager) GetAllLinterConfigsForPreset(p string) []*linter.Config { - var ret []*linter.Config - for _, lc := range m.linters { - if lc.IsDeprecated() { - continue - } - - if slices.Contains(lc.InPresets, p) { - ret = append(ret, lc) - } - } - - return ret -} - func (m *Manager) GetEnabledLintersMap() (map[string]*linter.Config, error) { - enabledLinters := m.build(m.GetAllEnabledByDefaultLinters()) + enabledLinters, err := m.build() + if err != nil { + return nil, err + } if os.Getenv(logutils.EnvTestRun) == "1" { m.verbosePrintLintersStatus(enabledLinters) @@ -104,80 +94,83 @@ func (m *Manager) GetEnabledLintersMap() (map[string]*linter.Config, error) { // GetOptimizedLinters returns enabled linters after optimization (merging) of multiple linters into a fewer number of linters. // E.g. some go/analysis linters can be optimized into one metalinter for data reuse and speed up. func (m *Manager) GetOptimizedLinters() ([]*linter.Config, error) { - resultLintersSet := m.build(m.GetAllEnabledByDefaultLinters()) + resultLintersSet, err := m.build() + if err != nil { + return nil, err + } + m.verbosePrintLintersStatus(resultLintersSet) m.combineGoAnalysisLinters(resultLintersSet) - resultLinters := maps.Values(resultLintersSet) - // Make order of execution of linters (go/analysis metalinter and unused) stable. - sort.Slice(resultLinters, func(i, j int) bool { - a, b := resultLinters[i], resultLinters[j] - + resultLinters := slices.SortedFunc(maps.Values(resultLintersSet), func(a *linter.Config, b *linter.Config) int { if b.Name() == linter.LastLinter { - return true + return -1 } if a.Name() == linter.LastLinter { - return false + return 1 } if a.DoesChangeTypes != b.DoesChangeTypes { - return b.DoesChangeTypes // move type-changing linters to the end to optimize speed + // move type-changing linters to the end to optimize speed + if b.DoesChangeTypes { + return -1 + } + return 1 } - return a.Name() < b.Name() + + return strings.Compare(a.Name(), b.Name()) }) return resultLinters, nil } -func (m *Manager) GetAllEnabledByDefaultLinters() []*linter.Config { - var ret []*linter.Config - for _, lc := range m.linters { - if lc.EnabledByDefault { - ret = append(ret, lc) - } - } - - return ret -} - //nolint:gocyclo // the complexity cannot be reduced. -func (m *Manager) build(enabledByDefaultLinters []*linter.Config) map[string]*linter.Config { +func (m *Manager) build() (map[string]*linter.Config, error) { m.debugf("Linters config: %#v", m.cfg.Linters) resultLintersSet := map[string]*linter.Config{} - switch { - case m.cfg.Linters.DisableAll: + + groupName := cmp.Or(m.cfg.Linters.Default, config.GroupStandard) + + switch groupName { + case config.GroupNone: // no default linters - case len(m.cfg.Linters.Presets) != 0: - // imply --disable-all - case m.cfg.Linters.EnableAll: + + case config.GroupAll: resultLintersSet = linterConfigsToMap(m.linters) - default: - resultLintersSet = linterConfigsToMap(enabledByDefaultLinters) - } - // --presets can only add linters to default set - for _, p := range m.cfg.Linters.Presets { - for _, lc := range m.GetAllLinterConfigsForPreset(p) { - resultLintersSet[lc.Name()] = lc + case config.GroupFast: + var selected []*linter.Config + for _, lc := range m.linters { + if lc.IsSlowLinter() { + continue + } + + selected = append(selected, lc) } - } - // --fast removes slow linters from current set. - // It should be after --presets to be able to run only fast linters in preset. - // It should be before --enable and --disable to be able to enable or disable specific linter. - if m.cfg.Linters.Fast { - for name, lc := range resultLintersSet { - if lc.IsSlowLinter() { - delete(resultLintersSet, name) + resultLintersSet = linterConfigsToMap(selected) + + case config.GroupStandard: + var selected []*linter.Config + for _, lc := range m.linters { + if !lc.FromGroup(config.GroupStandard) { + continue } + + selected = append(selected, lc) } + + resultLintersSet = linterConfigsToMap(selected) + + default: + return nil, fmt.Errorf("unknown group: %s", groupName) } - for _, name := range m.cfg.Linters.Enable { + for _, name := range slices.Concat(m.cfg.Linters.Enable, m.cfg.Formatters.Enable) { for _, lc := range m.GetLinterConfigs(name) { // it's important to use lc.Name() nor name because name can be alias resultLintersSet[lc.Name()] = lc @@ -191,6 +184,15 @@ func (m *Manager) build(enabledByDefaultLinters []*linter.Config) map[string]*li } } + if m.cfg.Linters.FastOnly { + for lc := range maps.Values(resultLintersSet) { + if lc.IsSlowLinter() { + // it's important to use lc.Name() nor name because name can be alias + delete(resultLintersSet, lc.Name()) + } + } + } + // typecheck is not a real linter and cannot be disabled. if _, ok := resultLintersSet["typecheck"]; !ok && (m.cfg == nil || !m.cfg.InternalCmdTest) { for _, lc := range m.GetLinterConfigs("typecheck") { @@ -199,7 +201,7 @@ func (m *Manager) build(enabledByDefaultLinters []*linter.Config) map[string]*li } } - return resultLintersSet + return resultLintersSet, nil } func (m *Manager) combineGoAnalysisLinters(linters map[string]*linter.Config) { @@ -224,8 +226,6 @@ func (m *Manager) combineGoAnalysisLinters(linters map[string]*linter.Config) { mlConfig.ConsiderSlow() } - mlConfig.InPresets = append(mlConfig.InPresets, lc.InPresets...) - goanalysisLinters = append(goanalysisLinters, lnt) } @@ -255,9 +255,6 @@ func (m *Manager) combineGoAnalysisLinters(linters map[string]*linter.Config) { mlConfig.Linter = goanalysis.NewMetaLinter(goanalysisLinters) - sort.Strings(mlConfig.InPresets) - mlConfig.InPresets = slices.Compact(mlConfig.InPresets) - linters[mlConfig.Linter.Name()] = mlConfig m.debugf("Combined %d go/analysis linters into one metalinter", len(goanalysisLinters)) @@ -274,29 +271,6 @@ func (m *Manager) verbosePrintLintersStatus(lcs map[string]*linter.Config) { } sort.Strings(linterNames) m.log.Infof("Active %d linters: %s", len(linterNames), linterNames) - - if len(m.cfg.Linters.Presets) != 0 { - sort.Strings(m.cfg.Linters.Presets) - m.log.Infof("Active presets: %s", m.cfg.Linters.Presets) - } -} - -func AllPresets() []string { - return []string{ - linter.PresetBugs, - linter.PresetComment, - linter.PresetComplexity, - linter.PresetError, - linter.PresetFormatting, - linter.PresetImport, - linter.PresetMetaLinter, - linter.PresetModule, - linter.PresetPerformance, - linter.PresetSQL, - linter.PresetStyle, - linter.PresetTest, - linter.PresetUnused, - } } func linterConfigsToMap(lcs []*linter.Config) map[string]*linter.Config { @@ -306,6 +280,10 @@ func linterConfigsToMap(lcs []*linter.Config) map[string]*linter.Config { continue } + if goformatters.IsFormatter(lc.Name()) { + continue + } + ret[lc.Name()] = lc } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/validator.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/lint/lintersdb/validator.go similarity index 76% rename from vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/validator.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/lint/lintersdb/validator.go index 264d063aa..34a6c63f9 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/validator.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/lint/lintersdb/validator.go @@ -1,15 +1,13 @@ package lintersdb import ( - "errors" "fmt" "os" - "slices" "strings" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/logutils" ) type Validator struct { @@ -25,7 +23,6 @@ func NewValidator(m *Manager) *Validator { func (v Validator) Validate(cfg *config.Config) error { validators := []func(cfg *config.Linters) error{ v.validateLintersNames, - v.validatePresets, v.alternativeNamesDeprecation, } @@ -58,7 +55,7 @@ func (v Validator) validateLintersNames(cfg *config.Linters) error { if lc.IsDeprecated() && lc.Deprecation.Level > linter.DeprecationWarning { v.m.log.Warnf("The linter %q is deprecated (step 2) and deactivated. "+ "It should be removed from the list of disabled linters. "+ - "https://golangci-lint.run/product/roadmap/#linter-deprecation-cycle", lc.Name()) + "https://golangci-lint.run/docs/product/roadmap/#linter-deprecation-cycle", lc.Name()) } } } @@ -71,23 +68,6 @@ func (v Validator) validateLintersNames(cfg *config.Linters) error { return nil } -func (Validator) validatePresets(cfg *config.Linters) error { - presets := AllPresets() - - for _, p := range cfg.Presets { - if !slices.Contains(presets, p) { - return fmt.Errorf("no such preset %q: only next presets exist: (%s)", - p, strings.Join(presets, "|")) - } - } - - if len(cfg.Presets) != 0 && cfg.EnableAll { - return errors.New("--presets is incompatible with --enable-all") - } - - return nil -} - func (v Validator) alternativeNamesDeprecation(cfg *config.Linters) error { if v.m.cfg.InternalTest || v.m.cfg.InternalCmdTest || os.Getenv(logutils.EnvTestRun) == "1" { return nil diff --git a/vendor/github.com/golangci/golangci-lint/pkg/lint/package.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/lint/package.go similarity index 91% rename from vendor/github.com/golangci/golangci-lint/pkg/lint/package.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/lint/package.go index c314166ca..1d68efb68 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/lint/package.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/lint/package.go @@ -11,14 +11,15 @@ import ( "strings" "time" + "github.com/ldez/grignotin/goenv" "golang.org/x/tools/go/packages" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/exitcodes" - "github.com/golangci/golangci-lint/pkg/goanalysis/load" - "github.com/golangci/golangci-lint/pkg/goutil" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/exitcodes" + "github.com/golangci/golangci-lint/v2/pkg/goanalysis/load" + "github.com/golangci/golangci-lint/v2/pkg/goutil" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/logutils" ) // PackageLoader loads packages based on [golang.org/x/tools/go/packages.Load]. @@ -38,13 +39,13 @@ type PackageLoader struct { } // NewPackageLoader creates a new PackageLoader. -func NewPackageLoader(log logutils.Log, cfg *config.Config, args []string, goenv *goutil.Env, loadGuard *load.Guard) *PackageLoader { +func NewPackageLoader(log logutils.Log, cfg *config.Config, args []string, env *goutil.Env, loadGuard *load.Guard) *PackageLoader { return &PackageLoader{ cfg: cfg, args: args, log: log, debugf: logutils.Debug(logutils.DebugKeyLoader), - goenv: goenv, + goenv: env, pkgTestIDRe: regexp.MustCompile(`^(.*) \[(.*)\.test\]`), loadGuard: loadGuard, } @@ -204,12 +205,13 @@ func (l *PackageLoader) debugPrintLoadedPackages(pkgs []*packages.Package) { func (l *PackageLoader) prepareBuildContext() { // Set GOROOT to have working cross-compilation: cross-compiled binaries // have invalid GOROOT. XXX: can't use runtime.GOROOT(). - goroot := l.goenv.Get(goutil.EnvGoRoot) + goroot := l.goenv.Get(goenv.GOROOT) if goroot == "" { return } - os.Setenv(string(goutil.EnvGoRoot), goroot) + _ = os.Setenv(goenv.GOROOT, goroot) + build.Default.GOROOT = goroot build.Default.BuildTags = l.cfg.Run.BuildTags } @@ -228,6 +230,11 @@ func (l *PackageLoader) makeBuildFlags() []string { buildFlags = append(buildFlags, fmt.Sprintf("-mod=%s", l.cfg.Run.ModulesDownloadMode)) } + if !l.cfg.Run.EnableBuildVCS { + // disable collecting VCS information + buildFlags = append(buildFlags, "-buildvcs=false") + } + return buildFlags } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/lint/runner.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/lint/runner.go similarity index 61% rename from vendor/github.com/golangci/golangci-lint/pkg/lint/runner.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/lint/runner.go index 2c47c7166..99182ffe3 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/lint/runner.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/lint/runner.go @@ -4,19 +4,21 @@ import ( "context" "errors" "fmt" + "maps" "runtime/debug" "strings" - "github.com/golangci/golangci-lint/internal/errorutil" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/fsutils" - "github.com/golangci/golangci-lint/pkg/goutil" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/lint/lintersdb" - "github.com/golangci/golangci-lint/pkg/logutils" - "github.com/golangci/golangci-lint/pkg/result" - "github.com/golangci/golangci-lint/pkg/result/processors" - "github.com/golangci/golangci-lint/pkg/timeutils" + "github.com/golangci/golangci-lint/v2/internal/errorutil" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/fsutils" + "github.com/golangci/golangci-lint/v2/pkg/goformatters" + "github.com/golangci/golangci-lint/v2/pkg/goutil" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/lint/lintersdb" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/result/processors" + "github.com/golangci/golangci-lint/v2/pkg/timeutils" ) type processorStat struct { @@ -31,26 +33,16 @@ type Runner struct { Processors []processors.Processor } -func NewRunner(log logutils.Log, cfg *config.Config, args []string, goenv *goutil.Env, +func NewRunner(log logutils.Log, cfg *config.Config, goenv *goutil.Env, lineCache *fsutils.LineCache, fileCache *fsutils.FileCache, dbManager *lintersdb.Manager, lintCtx *linter.Context, ) (*Runner, error) { - // Beware that some processors need to add the path prefix when working with paths - // because they get invoked before the path prefixer (exclude and severity rules) - // or process other paths (skip files). - files := fsutils.NewFiles(lineCache, cfg.Output.PathPrefix) - - skipFilesProcessor, err := processors.NewSkipFiles(cfg.Issues.ExcludeFiles, cfg.Output.PathPrefix) + pathRelativity, err := processors.NewPathRelativity(log, cfg.GetBasePath()) if err != nil { - return nil, err - } - - skipDirs := cfg.Issues.ExcludeDirs - if cfg.Issues.UseDefaultExcludeDirs { - skipDirs = append(skipDirs, processors.StdExcludeDirRegexps...) + return nil, fmt.Errorf("error creating path relativity processor: %w", err) } - skipDirsProcessor, err := processors.NewSkipDirs(log.Child(logutils.DebugKeySkipDirs), skipDirs, args, cfg.Output.PathPrefix) + exclusionPaths, err := processors.NewExclusionPaths(log, &cfg.Linters.Exclusions) if err != nil { return nil, err } @@ -60,62 +52,92 @@ func NewRunner(log logutils.Log, cfg *config.Config, args []string, goenv *gouti return nil, fmt.Errorf("failed to get enabled linters: %w", err) } + var enabledFormatters []string + for name := range maps.Keys(enabledLinters) { + if goformatters.IsFormatter(name) { + enabledFormatters = append(enabledFormatters, name) + } + } + + switch len(enabledLinters) { + case 0: + return nil, errors.New("no linters enabled") + case 1: + if _, ok := enabledLinters["typecheck"]; ok { + return nil, errors.New("no linters enabled") + } + } + + formattersCfg := &config.Formatters{ + Enable: enabledFormatters, + Settings: cfg.Linters.Settings.FormatterSettings, + } + + metaFormatter, err := goformatters.NewMetaFormatter(log, formattersCfg, &cfg.Run) + if err != nil { + return nil, fmt.Errorf("failed to create meta-formatter: %w", err) + } + return &Runner{ Processors: []processors.Processor{ + // Must be the first processor. + processors.NewPathAbsoluter(log), + processors.NewCgo(goenv), - // Must go after Cgo. + // Must be after Cgo. processors.NewFilenameUnadjuster(lintCtx.Packages, log.Child(logutils.DebugKeyFilenameUnadjuster)), - // Must go after FilenameUnadjuster. + // Must be after FilenameUnadjuster. processors.NewInvalidIssue(log.Child(logutils.DebugKeyInvalidIssue)), - // Must be before diff, nolint and exclude autogenerated processor at least. - processors.NewPathPrettifier(), - skipFilesProcessor, - skipDirsProcessor, // must be after path prettifier + // Must be after PathAbsoluter, Cgo, FilenameUnadjuster InvalidIssue. + pathRelativity, + + // Must be after PathRelativity. + exclusionPaths, - processors.NewAutogeneratedExclude(cfg.Issues.ExcludeGenerated), + processors.NewGeneratedFileFilter(cfg.Linters.Exclusions.Generated), - // Must be before exclude because users see already marked output and configure excluding by it. - processors.NewIdentifierMarker(), + processors.NewExclusionRules(log.Child(logutils.DebugKeyExclusionRules), lineCache, + &cfg.Linters.Exclusions), - processors.NewExclude(&cfg.Issues), - processors.NewExcludeRules(log.Child(logutils.DebugKeyExcludeRules), files, &cfg.Issues), - processors.NewNolint(log.Child(logutils.DebugKeyNolint), dbManager, enabledLinters), + processors.NewNolintFilter(log.Child(logutils.DebugKeyNolintFilter), dbManager, enabledLinters), - processors.NewUniqByLine(cfg), processors.NewDiff(&cfg.Issues), + + // The fixer still needs to see paths for the issues that are relative to the current directory. + processors.NewFixer(cfg, log, fileCache, metaFormatter), + + // Must be after the Fixer. + processors.NewUniqByLine(cfg.Issues.UniqByLine), processors.NewMaxPerFileFromLinter(cfg), processors.NewMaxSameIssues(cfg.Issues.MaxSameIssues, log.Child(logutils.DebugKeyMaxSameIssues), cfg), processors.NewMaxFromLinter(cfg.Issues.MaxIssuesPerLinter, log.Child(logutils.DebugKeyMaxFromLinter), cfg), - processors.NewSourceCode(lineCache, log.Child(logutils.DebugKeySourceCode)), - processors.NewPathShortener(), - processors.NewSeverity(log.Child(logutils.DebugKeySeverityRules), files, &cfg.Severity), - - // The fixer still needs to see paths for the issues that are relative to the current directory. - processors.NewFixer(cfg, log, fileCache), // Now we can modify the issues for output. - processors.NewPathPrefixer(cfg.Output.PathPrefix), - processors.NewSortResults(cfg), + processors.NewSourceCode(lineCache, log.Child(logutils.DebugKeySourceCode)), + processors.NewPathShortener(), + processors.NewSeverity(log.Child(logutils.DebugKeySeverityRules), lineCache, &cfg.Severity), + processors.NewPathPrettifier(log, &cfg.Output), + processors.NewSortResults(&cfg.Output), }, lintCtx: lintCtx, Log: log, }, nil } -func (r *Runner) Run(ctx context.Context, linters []*linter.Config) ([]result.Issue, error) { +func (r *Runner) Run(ctx context.Context, linters []*linter.Config) ([]*result.Issue, error) { sw := timeutils.NewStopwatch("linters", r.Log) defer sw.Print() var ( lintErrors error - issues []result.Issue + issues []*result.Issue ) for _, lc := range linters { - linterIssues, err := timeutils.TrackStage(sw, lc.Name(), func() ([]result.Issue, error) { + linterIssues, err := timeutils.TrackStage(sw, lc.Name(), func() ([]*result.Issue, error) { return r.runLinterSafe(ctx, r.lintCtx, lc) }) if err != nil { @@ -133,7 +155,7 @@ func (r *Runner) Run(ctx context.Context, linters []*linter.Config) ([]result.Is func (r *Runner) runLinterSafe(ctx context.Context, lintCtx *linter.Context, lc *linter.Config, -) (ret []result.Issue, err error) { +) (ret []*result.Issue, err error) { defer func() { if panicData := recover(); panicData != nil { if pe, ok := panicData.(*errorutil.PanicError); ok { @@ -172,13 +194,13 @@ func (r *Runner) runLinterSafe(ctx context.Context, lintCtx *linter.Context, return issues, nil } -func (r *Runner) processLintResults(inIssues []result.Issue) []result.Issue { +func (r *Runner) processLintResults(inIssues []*result.Issue) []*result.Issue { sw := timeutils.NewStopwatch("processing", r.Log) var issuesBefore, issuesAfter int statPerProcessor := map[string]processorStat{} - var outIssues []result.Issue + var outIssues []*result.Issue if len(inIssues) != 0 { issuesBefore += len(inIssues) outIssues = r.processIssues(inIssues, sw, statPerProcessor) @@ -212,14 +234,14 @@ func (r *Runner) printPerProcessorStat(stat map[string]processorStat) { } } -func (r *Runner) processIssues(issues []result.Issue, sw *timeutils.Stopwatch, statPerProcessor map[string]processorStat) []result.Issue { +func (r *Runner) processIssues(issues []*result.Issue, sw *timeutils.Stopwatch, statPerProcessor map[string]processorStat) []*result.Issue { for _, p := range r.Processors { - newIssues, err := timeutils.TrackStage(sw, p.Name(), func() ([]result.Issue, error) { + newIssues, err := timeutils.TrackStage(sw, p.Name(), func() ([]*result.Issue, error) { return p.Process(issues) }) if err != nil { - r.Log.Warnf("Can't process result by %s processor: %s", p.Name(), err) + r.Log.Warnf("Can't process results by %s processor: %s", p.Name(), err) } else { stat := statPerProcessor[p.Name()] stat.inCount += len(issues) @@ -230,7 +252,7 @@ func (r *Runner) processIssues(issues []result.Issue, sw *timeutils.Stopwatch, s // This is required by JSON serialization if issues == nil { - issues = []result.Issue{} + issues = []*result.Issue{} } } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/logutils/log.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/logutils/log.go similarity index 100% rename from vendor/github.com/golangci/golangci-lint/pkg/logutils/log.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/logutils/log.go diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/logutils/logutils.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/logutils/logutils.go new file mode 100644 index 000000000..50b8fa3f3 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/logutils/logutils.go @@ -0,0 +1,138 @@ +package logutils + +import ( + "os" + "strings" +) + +// EnvTestRun value: "1" +const EnvTestRun = "GL_TEST_RUN" + +// envDebug value: one or several debug keys. +// examples: +// - Remove output to `/dev/null`: `GL_DEBUG=linters_output ./golangci-lint run` +// - Show linters configuration: `GL_DEBUG=enabled_linters golangci-lint run` +// - Some analysis details: `GL_DEBUG=goanalysis/analyze,goanalysis/facts golangci-lint run` +const envDebug = "GL_DEBUG" + +const ( + DebugKeyBinSalt = "bin_salt" // Forces the usage of constant as salt (only for maintainers). + DebugKeyGoModSalt = "gomod_salt" // Display logs related to the salt computation from the go.mod file. + DebugKeyConfigReader = "config_reader" // Display logs related to configuration loading. + DebugKeyEmpty = "" + DebugKeyEnabledLinters = "enabled_linters" // Display logs related to the enabled linters inside the [lintersdb.Manager]. + DebugKeyExec = "exec" // Display logs related to the lock file. + DebugKeyGoEnv = "goenv" // Display logs related to [goenv.Env]. + DebugKeyLintersContext = "linters_context" // Display logs related to the package analysis context (not related to [context.Context]). + DebugKeyLintersDB = "lintersdb" // Display logs related to the linters/formatters loading. + DebugKeyLoader = "loader" // Display logs related to package loading (including `go/packages` internal debugging). + DebugKeyPkgCache = "pkgcache" // Display logs related to cache. + DebugKeyRunner = "runner" // Display logs related to the linter runner. + DebugKeyStopwatch = "stopwatch" // Display logs related to the stopwatch of the cache. + DebugKeyTest = "test" // Display debug logs during integration tests. +) + +// Printers. +const ( + DebugKeyCheckstylePrinter = "checkstyle_printer" + DebugKeyCodeClimatePrinter = "codeclimate_printer" + DebugKeySarifPrinter = "sarif_printer" + DebugKeyTabPrinter = "tab_printer" + DebugKeyTeamCityPrinter = "teamcity_printer" + DebugKeyTextPrinter = "text_printer" +) + +// Processors. +const ( + DebugKeyExclusionPaths = "exclusion_paths" + DebugKeyExclusionRules = "exclusion_rules" + DebugKeyFilenameUnadjuster = "filename_unadjuster" + DebugKeyGeneratedFileFilter = "generated_file_filter" // Debugs a filter excluding autogenerated source code. + DebugKeyInvalidIssue = "invalid_issue" + DebugKeyMaxFromLinter = "max_from_linter" + DebugKeyMaxSameIssues = "max_same_issues" + DebugKeyNolintFilter = "nolint_filter" // Debugs a filter excluding issues by `//nolint` comments. + DebugKeyPathAbsoluter = "path_absoluter" + DebugKeyPathPrettifier = "path_prettifier" + DebugKeyPathRelativity = "path_relativity" + DebugKeySeverityRules = "severity_rules" + DebugKeySourceCode = "source_code" +) + +// Analysis. +const ( + DebugKeyGoAnalysis = "goanalysis" + + DebugKeyGoAnalysisAnalyze = DebugKeyGoAnalysis + "/analyze" + DebugKeyGoAnalysisIssuesCache = DebugKeyGoAnalysis + "/issues/cache" + DebugKeyGoAnalysisMemory = DebugKeyGoAnalysis + "/memory" + + DebugKeyGoAnalysisFacts = DebugKeyGoAnalysis + "/facts" + DebugKeyGoAnalysisFactsCache = DebugKeyGoAnalysisFacts + "/cache" + DebugKeyGoAnalysisFactsExport = DebugKeyGoAnalysisFacts + "/export" + DebugKeyGoAnalysisFactsInherit = DebugKeyGoAnalysisFacts + "/inherit" +) + +// Linters and Formatters. +const ( + DebugKeyFormatter = "formatter" // Display logs from the shared logger for formatters. + DebugKeyFormattersOutput = "formatters_output" // Display logs from formatters themselves. + DebugKeyLinter = "linter" // Display logs from the shared logger for linters. + DebugKeyLintersOutput = "linters_output" // Display logs from linters themselves. + + DebugKeyForbidigo = "forbidigo" // Debugs `forbidigo` linter. + DebugKeyGoCritic = "gocritic" // Debugs `gocritic` linter. + DebugKeyGovet = "govet" // Debugs `govet` linter. + DebugKeyRevive = "revive" // Debugs `revive` linter. + DebugKeyStaticcheck = "staticcheck" // Debugs `staticcheck` linter. +) + +func getEnabledDebugs() map[string]bool { + ret := map[string]bool{} + debugVar := os.Getenv(envDebug) + if debugVar == "" { + return ret + } + + for tag := range strings.SplitSeq(debugVar, ",") { + ret[tag] = true + } + + return ret +} + +var enabledDebugs = getEnabledDebugs() + +type DebugFunc func(format string, args ...any) + +func nopDebugf(_ string, _ ...any) {} + +func Debug(tag string) DebugFunc { + if !enabledDebugs[tag] { + return nopDebugf + } + + logger := NewStderrLog(tag) + logger.SetLevel(LogLevelDebug) + + return func(format string, args ...any) { + logger.Debugf(format, args...) + } +} + +func HaveDebugTag(tag string) bool { + return enabledDebugs[tag] +} + +var verbose bool + +func SetupVerboseLog(log Log, isVerbose bool) { + if isVerbose { + verbose = isVerbose + log.SetLevel(LogLevelInfo) + } +} + +func IsVerbose() bool { + return verbose +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/logutils/mock.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/logutils/mock.go similarity index 100% rename from vendor/github.com/golangci/golangci-lint/pkg/logutils/mock.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/logutils/mock.go diff --git a/vendor/github.com/golangci/golangci-lint/pkg/logutils/out.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/logutils/out.go similarity index 100% rename from vendor/github.com/golangci/golangci-lint/pkg/logutils/out.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/logutils/out.go diff --git a/vendor/github.com/golangci/golangci-lint/pkg/logutils/stderr_log.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/logutils/stderr_log.go similarity index 90% rename from vendor/github.com/golangci/golangci-lint/pkg/logutils/stderr_log.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/logutils/stderr_log.go index 569a177a7..af4296429 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/logutils/stderr_log.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/logutils/stderr_log.go @@ -7,7 +7,7 @@ import ( "github.com/sirupsen/logrus" - "github.com/golangci/golangci-lint/pkg/exitcodes" + "github.com/golangci/golangci-lint/v2/pkg/exitcodes" ) const ( @@ -17,14 +17,14 @@ const ( envLogTimestamp = "LOG_TIMESTAMP" ) +var _ Log = NewStderrLog(DebugKeyEmpty) + type StderrLog struct { name string logger *logrus.Logger level LogLevel } -var _ Log = NewStderrLog(DebugKeyEmpty) - func NewStderrLog(name string) *StderrLog { sl := &StderrLog{ name: name, @@ -44,16 +44,7 @@ func NewStderrLog(name string) *StderrLog { } sl.logger.Out = StdErr - formatter := &logrus.TextFormatter{ - DisableTimestamp: true, // `INFO[0007] msg` -> `INFO msg` - EnvironmentOverrideColors: true, - } - if os.Getenv(envLogTimestamp) == "1" { - formatter.DisableTimestamp = false - formatter.FullTimestamp = true - formatter.TimestampFormat = time.StampMilli - } - sl.logger.Formatter = formatter + sl.logger.Formatter = logFormatter return sl } @@ -127,3 +118,24 @@ func (sl StderrLog) Child(name string) Log { func (sl *StderrLog) SetLevel(level LogLevel) { sl.level = level } + +var logFormatter = newLogFormatter() + +func DisableColors(disable bool) { + logFormatter.DisableColors = disable +} + +func newLogFormatter() *logrus.TextFormatter { + formatter := &logrus.TextFormatter{ + DisableTimestamp: true, // `INFO[0007] msg` -> `INFO msg` + EnvironmentOverrideColors: true, + } + + if os.Getenv(envLogTimestamp) == "1" { + formatter.DisableTimestamp = false + formatter.FullTimestamp = true + formatter.TimestampFormat = time.StampMilli + } + + return formatter +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/printers/checkstyle.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/printers/checkstyle.go similarity index 54% rename from vendor/github.com/golangci/golangci-lint/pkg/printers/checkstyle.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/printers/checkstyle.go index e32eef7f5..c3869bd39 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/printers/checkstyle.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/printers/checkstyle.go @@ -4,52 +4,47 @@ import ( "encoding/xml" "fmt" "io" - "sort" + "maps" + "slices" + "strings" "github.com/go-xmlfmt/xmlfmt" - "golang.org/x/exp/maps" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result" ) const defaultCheckstyleSeverity = "error" -type checkstyleOutput struct { - XMLName xml.Name `xml:"checkstyle"` - Version string `xml:"version,attr"` - Files []*checkstyleFile `xml:"file"` -} - -type checkstyleFile struct { - Name string `xml:"name,attr"` - Errors []*checkstyleError `xml:"error"` -} - -type checkstyleError struct { - Column int `xml:"column,attr"` - Line int `xml:"line,attr"` - Message string `xml:"message,attr"` - Severity string `xml:"severity,attr"` - Source string `xml:"source,attr"` -} - +// Checkstyle prints issues in the Checkstyle format. +// https://checkstyle.org/config.html type Checkstyle struct { - w io.Writer + log logutils.Log + w io.Writer + sanitizer severitySanitizer } -func NewCheckstyle(w io.Writer) *Checkstyle { - return &Checkstyle{w: w} +func NewCheckstyle(log logutils.Log, w io.Writer) *Checkstyle { + return &Checkstyle{ + log: log.Child(logutils.DebugKeyCheckstylePrinter), + w: w, + sanitizer: severitySanitizer{ + // https://checkstyle.org/config.html#Severity + // https://checkstyle.org/property_types.html#SeverityLevel + allowedSeverities: []string{"ignore", "info", "warning", defaultCheckstyleSeverity}, + defaultSeverity: defaultCheckstyleSeverity, + }, + } } -func (p Checkstyle) Print(issues []result.Issue) error { +func (p *Checkstyle) Print(issues []*result.Issue) error { out := checkstyleOutput{ Version: "5.0", } files := map[string]*checkstyleFile{} - for i := range issues { - issue := &issues[i] + for _, issue := range issues { file, ok := files[issue.FilePath()] if !ok { file = &checkstyleFile{ @@ -59,26 +54,24 @@ func (p Checkstyle) Print(issues []result.Issue) error { files[issue.FilePath()] = file } - severity := defaultCheckstyleSeverity - if issue.Severity != "" { - severity = issue.Severity - } - newError := &checkstyleError{ Column: issue.Column(), Line: issue.Line(), Message: issue.Text, Source: issue.FromLinter, - Severity: severity, + Severity: p.sanitizer.Sanitize(issue.Severity), } file.Errors = append(file.Errors, newError) } - out.Files = maps.Values(files) + err := p.sanitizer.Err() + if err != nil { + p.log.Infof("%v", err) + } - sort.Slice(out.Files, func(i, j int) bool { - return out.Files[i].Name < out.Files[j].Name + out.Files = slices.SortedFunc(maps.Values(files), func(a *checkstyleFile, b *checkstyleFile) int { + return strings.Compare(a.Name, b.Name) }) data, err := xml.Marshal(&out) @@ -93,3 +86,22 @@ func (p Checkstyle) Print(issues []result.Issue) error { return nil } + +type checkstyleOutput struct { + XMLName xml.Name `xml:"checkstyle"` + Version string `xml:"version,attr"` + Files []*checkstyleFile `xml:"file"` +} + +type checkstyleFile struct { + Name string `xml:"name,attr"` + Errors []*checkstyleError `xml:"error"` +} + +type checkstyleError struct { + Column int `xml:"column,attr"` + Line int `xml:"line,attr"` + Message string `xml:"message,attr"` + Severity string `xml:"severity,attr"` + Source string `xml:"source,attr"` +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/printers/codeclimate.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/printers/codeclimate.go new file mode 100644 index 000000000..e2eded608 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/printers/codeclimate.go @@ -0,0 +1,73 @@ +package printers + +import ( + "encoding/json" + "io" + + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result" +) + +const defaultCodeClimateSeverity = "critical" + +// CodeClimate prints issues in the Code Climate format. +// https://github.com/codeclimate/platform/blob/HEAD/spec/analyzers/SPEC.md +type CodeClimate struct { + log logutils.Log + w io.Writer + sanitizer severitySanitizer +} + +func NewCodeClimate(log logutils.Log, w io.Writer) *CodeClimate { + return &CodeClimate{ + log: log.Child(logutils.DebugKeyCodeClimatePrinter), + w: w, + sanitizer: severitySanitizer{ + // https://github.com/codeclimate/platform/blob/HEAD/spec/analyzers/SPEC.md#data-types + allowedSeverities: []string{"info", "minor", "major", defaultCodeClimateSeverity, "blocker"}, + defaultSeverity: defaultCodeClimateSeverity, + }, + } +} + +func (p *CodeClimate) Print(issues []*result.Issue) error { + ccIssues := make([]codeClimateIssue, 0, len(issues)) + + for _, issue := range issues { + ccIssue := codeClimateIssue{ + Description: issue.Description(), + CheckName: issue.FromLinter, + Severity: p.sanitizer.Sanitize(issue.Severity), + Fingerprint: issue.Fingerprint(), + } + + ccIssue.Location.Path = issue.Pos.Filename + ccIssue.Location.Lines.Begin = issue.Pos.Line + + ccIssues = append(ccIssues, ccIssue) + } + + err := p.sanitizer.Err() + if err != nil { + p.log.Infof("%v", err) + } + + return json.NewEncoder(p.w).Encode(ccIssues) +} + +// codeClimateIssue is a subset of the Code Climate spec. +// https://github.com/codeclimate/platform/blob/HEAD/spec/analyzers/SPEC.md#data-types +// It is just enough to support GitLab CI Code Quality. +// https://docs.gitlab.com/ee/ci/testing/code_quality.html#code-quality-report-format +type codeClimateIssue struct { + Description string `json:"description"` + CheckName string `json:"check_name"` + Severity string `json:"severity,omitempty"` + Fingerprint string `json:"fingerprint"` + Location struct { + Path string `json:"path"` + Lines struct { + Begin int `json:"begin"` + } `json:"lines"` + } `json:"location"` +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/printers/html.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/printers/html.go similarity index 90% rename from vendor/github.com/golangci/golangci-lint/pkg/printers/html.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/printers/html.go index 7dd1e5c62..1f6ed1834 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/printers/html.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/printers/html.go @@ -6,7 +6,7 @@ import ( "io" "strings" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/result" ) const templateContent = ` @@ -122,6 +122,8 @@ type htmlIssue struct { Code string } +// HTML prints issues in an HTML page. +// It uses the Cloudflare CDN (cdnjs) and React. type HTML struct { w io.Writer } @@ -130,20 +132,20 @@ func NewHTML(w io.Writer) *HTML { return &HTML{w: w} } -func (p HTML) Print(issues []result.Issue) error { +func (p HTML) Print(issues []*result.Issue) error { var htmlIssues []htmlIssue - for i := range issues { - pos := fmt.Sprintf("%s:%d", issues[i].FilePath(), issues[i].Line()) - if issues[i].Pos.Column != 0 { - pos += fmt.Sprintf(":%d", issues[i].Pos.Column) + for _, issue := range issues { + pos := fmt.Sprintf("%s:%d", issue.FilePath(), issue.Line()) + if issue.Pos.Column != 0 { + pos += fmt.Sprintf(":%d", issue.Pos.Column) } htmlIssues = append(htmlIssues, htmlIssue{ - Title: strings.TrimSpace(issues[i].Text), + Title: strings.TrimSpace(issue.Text), Pos: pos, - Linter: issues[i].FromLinter, - Code: strings.Join(issues[i].SourceLines, "\n"), + Linter: issue.FromLinter, + Code: strings.Join(issue.SourceLines, "\n"), }) } diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/printers/json.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/printers/json.go new file mode 100644 index 000000000..97354081c --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/printers/json.go @@ -0,0 +1,39 @@ +package printers + +import ( + "encoding/json" + "io" + + "github.com/golangci/golangci-lint/v2/pkg/report" + "github.com/golangci/golangci-lint/v2/pkg/result" +) + +// JSON prints issues in a JSON representation. +type JSON struct { + rd *report.Data + w io.Writer +} + +func NewJSON(w io.Writer, rd *report.Data) *JSON { + return &JSON{ + rd: rd, + w: w, + } +} + +type JSONResult struct { + Issues []*result.Issue + Report *report.Data +} + +func (p JSON) Print(issues []*result.Issue) error { + res := JSONResult{ + Issues: issues, + Report: p.rd, + } + if res.Issues == nil { + res.Issues = []*result.Issue{} + } + + return json.NewEncoder(p.w).Encode(res) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/printers/junitxml.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/printers/junitxml.go similarity index 58% rename from vendor/github.com/golangci/golangci-lint/pkg/printers/junitxml.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/printers/junitxml.go index 7d0a703b0..b040e7467 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/printers/junitxml.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/printers/junitxml.go @@ -4,79 +4,53 @@ import ( "encoding/xml" "fmt" "io" - "sort" + "maps" + "slices" "strings" - "golang.org/x/exp/maps" - - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/result" ) -type testSuitesXML struct { - XMLName xml.Name `xml:"testsuites"` - TestSuites []testSuiteXML -} - -type testSuiteXML struct { - XMLName xml.Name `xml:"testsuite"` - Suite string `xml:"name,attr"` - Tests int `xml:"tests,attr"` - Errors int `xml:"errors,attr"` - Failures int `xml:"failures,attr"` - TestCases []testCaseXML `xml:"testcase"` -} - -type testCaseXML struct { - Name string `xml:"name,attr"` - ClassName string `xml:"classname,attr"` - Failure failureXML `xml:"failure"` - File string `xml:"file,attr,omitempty"` - Line int `xml:"line,attr,omitempty"` -} - -type failureXML struct { - Message string `xml:"message,attr"` - Type string `xml:"type,attr"` - Content string `xml:",cdata"` -} - -type JunitXML struct { +// JUnitXML prints issues in the JUnit XML format. +// There is no official specification for the JUnit XML file format, +// and various tools generate and support different flavors of this format. +// https://github.com/testmoapp/junitxml +type JUnitXML struct { extended bool w io.Writer } -func NewJunitXML(extended bool, w io.Writer) *JunitXML { - return &JunitXML{ +func NewJUnitXML(w io.Writer, extended bool) *JUnitXML { + return &JUnitXML{ extended: extended, w: w, } } -func (p JunitXML) Print(issues []result.Issue) error { +func (p JUnitXML) Print(issues []*result.Issue) error { suites := make(map[string]testSuiteXML) // use a map to group by file - for ind := range issues { - i := &issues[ind] - suiteName := i.FilePath() + for _, issue := range issues { + suiteName := issue.FilePath() testSuite := suites[suiteName] - testSuite.Suite = i.FilePath() + testSuite.Suite = issue.FilePath() testSuite.Tests++ testSuite.Failures++ tc := testCaseXML{ - Name: i.FromLinter, - ClassName: i.Pos.String(), + Name: issue.FromLinter, + ClassName: issue.Pos.String(), Failure: failureXML{ - Type: i.Severity, - Message: i.Pos.String() + ": " + i.Text, + Type: issue.Severity, + Message: issue.Pos.String() + ": " + issue.Text, Content: fmt.Sprintf("%s: %s\nCategory: %s\nFile: %s\nLine: %d\nDetails: %s", - i.Severity, i.Text, i.FromLinter, i.Pos.Filename, i.Pos.Line, strings.Join(i.SourceLines, "\n")), + issue.Severity, issue.Text, issue.FromLinter, issue.Pos.Filename, issue.Pos.Line, strings.Join(issue.SourceLines, "\n")), }, } if p.extended { - tc.File = i.Pos.Filename - tc.Line = i.Pos.Line + tc.File = issue.Pos.Filename + tc.Line = issue.Pos.Line } testSuite.TestCases = append(testSuite.TestCases, tc) @@ -84,10 +58,9 @@ func (p JunitXML) Print(issues []result.Issue) error { } var res testSuitesXML - res.TestSuites = maps.Values(suites) - sort.Slice(res.TestSuites, func(i, j int) bool { - return res.TestSuites[i].Suite < res.TestSuites[j].Suite + res.TestSuites = slices.SortedFunc(maps.Values(suites), func(a testSuiteXML, b testSuiteXML) int { + return strings.Compare(a.Suite, b.Suite) }) enc := xml.NewEncoder(p.w) @@ -97,3 +70,31 @@ func (p JunitXML) Print(issues []result.Issue) error { } return nil } + +type testSuitesXML struct { + XMLName xml.Name `xml:"testsuites"` + TestSuites []testSuiteXML +} + +type testSuiteXML struct { + XMLName xml.Name `xml:"testsuite"` + Suite string `xml:"name,attr"` + Tests int `xml:"tests,attr"` + Errors int `xml:"errors,attr"` + Failures int `xml:"failures,attr"` + TestCases []testCaseXML `xml:"testcase"` +} + +type testCaseXML struct { + Name string `xml:"name,attr"` + ClassName string `xml:"classname,attr"` + Failure failureXML `xml:"failure"` + File string `xml:"file,attr,omitempty"` + Line int `xml:"line,attr,omitempty"` +} + +type failureXML struct { + Message string `xml:"message,attr"` + Type string `xml:"type,attr"` + Content string `xml:",cdata"` +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/printers/printer.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/printers/printer.go new file mode 100644 index 000000000..bb3eab620 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/printers/printer.go @@ -0,0 +1,241 @@ +package printers + +import ( + "errors" + "fmt" + "io" + "os" + "path/filepath" + "slices" + "strings" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/report" + "github.com/golangci/golangci-lint/v2/pkg/result" +) + +const ( + outputStdOut = "stdout" + outputStdErr = "stderr" +) + +const defaultFileMode = 0o644 + +type issuePrinter interface { + Print(issues []*result.Issue) error +} + +// Printer prints issues. +type Printer struct { + cfg *config.Formats + reportData *report.Data + basePath string + + log logutils.Log + + stdOut io.Writer + stdErr io.Writer +} + +// NewPrinter creates a new Printer. +func NewPrinter(log logutils.Log, cfg *config.Formats, reportData *report.Data, basePath string) (*Printer, error) { + if log == nil { + return nil, errors.New("missing log argument in constructor") + } + if cfg == nil { + return nil, errors.New("missing config argument in constructor") + } + if reportData == nil { + return nil, errors.New("missing reportData argument in constructor") + } + + return &Printer{ + cfg: cfg, + reportData: reportData, + basePath: basePath, + log: log, + stdOut: logutils.StdOut, + stdErr: logutils.StdErr, + }, nil +} + +// Print prints issues based on the formats defined. +// +//nolint:gocyclo,funlen // the complexity is related to the number of formats. +func (c *Printer) Print(issues []*result.Issue) error { + if c.cfg.IsEmpty() { + c.cfg.Text.Path = outputStdOut + } + + var printers []issuePrinter + + if c.cfg.Text.Path != "" { + w, closer, err := c.createWriter(&c.cfg.Text.SimpleFormat) + if err != nil { + return fmt.Errorf("can't create output for %s: %w", c.cfg.Text.Path, err) + } + + defer closer() + + printers = append(printers, NewText(c.log, w, &c.cfg.Text)) + } + + if c.cfg.JSON.Path != "" { + w, closer, err := c.createWriter(&c.cfg.JSON) + if err != nil { + return fmt.Errorf("can't create output for %s: %w", c.cfg.JSON.Path, err) + } + + defer closer() + + printers = append(printers, NewJSON(w, c.reportData)) + } + + if c.cfg.Tab.Path != "" { + w, closer, err := c.createWriter(&c.cfg.Tab.SimpleFormat) + if err != nil { + return fmt.Errorf("can't create output for %s: %w", c.cfg.Tab.Path, err) + } + + defer closer() + + printers = append(printers, NewTab(c.log, w, &c.cfg.Tab)) + } + + if c.cfg.HTML.Path != "" { + w, closer, err := c.createWriter(&c.cfg.HTML) + if err != nil { + return fmt.Errorf("can't create output for %s: %w", c.cfg.HTML.Path, err) + } + + defer closer() + + printers = append(printers, NewHTML(w)) + } + + if c.cfg.Checkstyle.Path != "" { + w, closer, err := c.createWriter(&c.cfg.Checkstyle) + if err != nil { + return fmt.Errorf("can't create output for %s: %w", c.cfg.Checkstyle.Path, err) + } + + defer closer() + + printers = append(printers, NewCheckstyle(c.log, w)) + } + + if c.cfg.CodeClimate.Path != "" { + w, closer, err := c.createWriter(&c.cfg.CodeClimate) + if err != nil { + return fmt.Errorf("can't create output for %s: %w", c.cfg.CodeClimate.Path, err) + } + + defer closer() + + printers = append(printers, NewCodeClimate(c.log, w)) + } + + if c.cfg.JUnitXML.Path != "" { + w, closer, err := c.createWriter(&c.cfg.JUnitXML.SimpleFormat) + if err != nil { + return fmt.Errorf("can't create output for %s: %w", c.cfg.JUnitXML.Path, err) + } + + defer closer() + + printers = append(printers, NewJUnitXML(w, c.cfg.JUnitXML.Extended)) + } + + if c.cfg.TeamCity.Path != "" { + w, closer, err := c.createWriter(&c.cfg.TeamCity) + if err != nil { + return fmt.Errorf("can't create output for %s: %w", c.cfg.TeamCity.Path, err) + } + + defer closer() + + printers = append(printers, NewTeamCity(c.log, w)) + } + + if c.cfg.Sarif.Path != "" { + w, closer, err := c.createWriter(&c.cfg.Sarif) + if err != nil { + return fmt.Errorf("can't create output for %s: %w", c.cfg.Sarif.Path, err) + } + + defer closer() + + printers = append(printers, NewSarif(c.log, w)) + } + + for _, printer := range printers { + err := printer.Print(issues) + if err != nil { + return err + } + } + + return nil +} + +func (c *Printer) createWriter(cfg *config.SimpleFormat) (io.Writer, func(), error) { + if cfg.Path == "" || cfg.Path == outputStdOut { + return c.stdOut, func() {}, nil + } + + if cfg.Path == outputStdErr { + return c.stdErr, func() {}, nil + } + + if !filepath.IsAbs(cfg.Path) { + cfg.Path = filepath.Join(c.basePath, cfg.Path) + } + + err := os.MkdirAll(filepath.Dir(cfg.Path), os.ModePerm) + if err != nil { + return nil, func() {}, err + } + + f, err := os.OpenFile(cfg.Path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, defaultFileMode) + if err != nil { + return nil, func() {}, err + } + + return f, func() { _ = f.Close() }, nil +} + +type severitySanitizer struct { + allowedSeverities []string + defaultSeverity string + + unsupportedSeverities map[string]struct{} +} + +func (s *severitySanitizer) Sanitize(severity string) string { + if slices.Contains(s.allowedSeverities, severity) { + return severity + } + + if s.unsupportedSeverities == nil { + s.unsupportedSeverities = make(map[string]struct{}) + } + + s.unsupportedSeverities[severity] = struct{}{} + + return s.defaultSeverity +} + +func (s *severitySanitizer) Err() error { + if len(s.unsupportedSeverities) == 0 { + return nil + } + + var names []string + for k := range s.unsupportedSeverities { + names = append(names, "'"+k+"'") + } + + return fmt.Errorf("severities (%v) are not inside supported values (%v), fallback to '%s'", + strings.Join(names, ", "), strings.Join(s.allowedSeverities, ", "), s.defaultSeverity) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/printers/sarif.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/printers/sarif.go similarity index 68% rename from vendor/github.com/golangci/golangci-lint/pkg/printers/sarif.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/printers/sarif.go index 8b1dd2ee2..e1caf179a 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/printers/sarif.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/printers/sarif.go @@ -4,7 +4,8 @@ import ( "encoding/json" "io" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result" ) const ( @@ -12,6 +13,71 @@ const ( sarifSchemaURI = "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.6.json" ) +const defaultSarifSeverity = "error" + +// Sarif prints issues in the SARIF format. +// https://sarifweb.azurewebsites.net/ +// https://docs.oasis-open.org/sarif/sarif/v2.1.0/ +type Sarif struct { + log logutils.Log + w io.Writer + sanitizer severitySanitizer +} + +func NewSarif(log logutils.Log, w io.Writer) *Sarif { + return &Sarif{ + log: log.Child(logutils.DebugKeySarifPrinter), + w: w, + sanitizer: severitySanitizer{ + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/sarif-v2.1.0-errata01-os-complete.html#_Toc141790898 + allowedSeverities: []string{"none", "note", "warning", defaultSarifSeverity}, + defaultSeverity: defaultSarifSeverity, + }, + } +} + +func (p *Sarif) Print(issues []*result.Issue) error { + run := sarifRun{} + run.Tool.Driver.Name = "golangci-lint" + run.Results = make([]sarifResult, 0) + + for _, issue := range issues { + sr := sarifResult{ + RuleID: issue.FromLinter, + Level: p.sanitizer.Sanitize(issue.Severity), + Message: sarifMessage{Text: issue.Text}, + Locations: []sarifLocation{ + { + PhysicalLocation: sarifPhysicalLocation{ + ArtifactLocation: sarifArtifactLocation{URI: issue.FilePath()}, + Region: sarifRegion{ + StartLine: issue.Line(), + // If startColumn is absent, it SHALL default to 1. + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/sarif-v2.1.0-errata01-os-complete.html#_Toc141790941 + StartColumn: max(1, issue.Column()), + }, + }, + }, + }, + } + + run.Results = append(run.Results, sr) + } + + err := p.sanitizer.Err() + if err != nil { + p.log.Infof("%v", err) + } + + output := SarifOutput{ + Version: sarifVersion, + Schema: sarifSchemaURI, + Runs: []sarifRun{run}, + } + + return json.NewEncoder(p.w).Encode(output) +} + type SarifOutput struct { Version string `json:"version"` Schema string `json:"$schema"` @@ -58,60 +124,3 @@ type sarifRegion struct { StartLine int `json:"startLine"` StartColumn int `json:"startColumn"` } - -type Sarif struct { - w io.Writer -} - -func NewSarif(w io.Writer) *Sarif { - return &Sarif{w: w} -} - -func (p Sarif) Print(issues []result.Issue) error { - run := sarifRun{} - run.Tool.Driver.Name = "golangci-lint" - run.Results = make([]sarifResult, 0) - - for i := range issues { - issue := issues[i] - - severity := issue.Severity - - switch severity { - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/sarif-v2.1.0-errata01-os-complete.html#_Toc141790898 - case "none", "note", "warning", "error": - // Valid levels. - default: - severity = "error" - } - - sr := sarifResult{ - RuleID: issue.FromLinter, - Level: severity, - Message: sarifMessage{Text: issue.Text}, - Locations: []sarifLocation{ - { - PhysicalLocation: sarifPhysicalLocation{ - ArtifactLocation: sarifArtifactLocation{URI: issue.FilePath()}, - Region: sarifRegion{ - StartLine: issue.Line(), - // If startColumn is absent, it SHALL default to 1. - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/sarif-v2.1.0-errata01-os-complete.html#_Toc141790941 - StartColumn: max(1, issue.Column()), - }, - }, - }, - }, - } - - run.Results = append(run.Results, sr) - } - - output := SarifOutput{ - Version: sarifVersion, - Schema: sarifSchemaURI, - Runs: []sarifRun{run}, - } - - return json.NewEncoder(p.w).Encode(output) -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/printers/tab.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/printers/tab.go similarity index 62% rename from vendor/github.com/golangci/golangci-lint/pkg/printers/tab.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/printers/tab.go index c6d390d18..8edbb05e1 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/printers/tab.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/printers/tab.go @@ -7,23 +7,25 @@ import ( "github.com/fatih/color" - "github.com/golangci/golangci-lint/pkg/logutils" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result" ) +// Tab prints issues using tabulation as a field separator. type Tab struct { printLinterName bool - useColors bool + colors bool log logutils.Log w io.Writer } -func NewTab(printLinterName, useColors bool, log logutils.Log, w io.Writer) *Tab { +func NewTab(log logutils.Log, w io.Writer, cfg *config.Tab) *Tab { return &Tab{ - printLinterName: printLinterName, - useColors: useColors, - log: log, + printLinterName: cfg.PrintLinterName, + colors: cfg.Colors, + log: log.Child(logutils.DebugKeyTabPrinter), w: w, } } @@ -31,18 +33,18 @@ func NewTab(printLinterName, useColors bool, log logutils.Log, w io.Writer) *Tab func (p *Tab) SprintfColored(ca color.Attribute, format string, args ...any) string { c := color.New(ca) - if !p.useColors { + if !p.colors { c.DisableColor() } return c.Sprintf(format, args...) } -func (p *Tab) Print(issues []result.Issue) error { +func (p *Tab) Print(issues []*result.Issue) error { w := tabwriter.NewWriter(p.w, 0, 0, 2, ' ', 0) - for i := range issues { - p.printIssue(&issues[i], w) + for _, issue := range issues { + p.printIssue(issue, w) } if err := w.Flush(); err != nil { diff --git a/vendor/github.com/golangci/golangci-lint/pkg/printers/teamcity.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/printers/teamcity.go similarity index 72% rename from vendor/github.com/golangci/golangci-lint/pkg/printers/teamcity.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/printers/teamcity.go index 1d1c9f7d3..36114fedf 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/printers/teamcity.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/printers/teamcity.go @@ -4,9 +4,9 @@ import ( "fmt" "io" "strings" - "unicode/utf8" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result" ) // Field limits. @@ -15,16 +15,22 @@ const ( largeLimit = 4000 ) -// TeamCity printer for TeamCity format. +const defaultTeamCitySeverity = "ERROR" + +// TeamCity prints issues in the TeamCity format. +// https://www.jetbrains.com/help/teamcity/service-messages.html type TeamCity struct { - w io.Writer - escaper *strings.Replacer + log logutils.Log + w io.Writer + escaper *strings.Replacer + sanitizer severitySanitizer } // NewTeamCity output format outputs issues according to TeamCity service message format. -func NewTeamCity(w io.Writer) *TeamCity { +func NewTeamCity(log logutils.Log, w io.Writer) *TeamCity { return &TeamCity{ - w: w, + log: log.Child(logutils.DebugKeyTeamCityPrinter), + w: w, // https://www.jetbrains.com/help/teamcity/service-messages.html#Escaped+Values escaper: strings.NewReplacer( "'", "|'", @@ -34,15 +40,18 @@ func NewTeamCity(w io.Writer) *TeamCity { "[", "|[", "]", "|]", ), + sanitizer: severitySanitizer{ + // https://www.jetbrains.com/help/teamcity/service-messages.html#Inspection+Instance + allowedSeverities: []string{"INFO", defaultTeamCitySeverity, "WARNING", "WEAK WARNING"}, + defaultSeverity: defaultTeamCitySeverity, + }, } } -func (p *TeamCity) Print(issues []result.Issue) error { +func (p *TeamCity) Print(issues []*result.Issue) error { uniqLinters := map[string]struct{}{} - for i := range issues { - issue := issues[i] - + for _, issue := range issues { _, ok := uniqLinters[issue.FromLinter] if !ok { inspectionType := InspectionType{ @@ -65,7 +74,7 @@ func (p *TeamCity) Print(issues []result.Issue) error { message: issue.Text, file: issue.FilePath(), line: issue.Line(), - severity: issue.Severity, + severity: p.sanitizer.Sanitize(strings.ToUpper(issue.Severity)), } _, err := instance.Print(p.w, p.escaper) @@ -74,6 +83,11 @@ func (p *TeamCity) Print(issues []result.Issue) error { } } + err := p.sanitizer.Err() + if err != nil { + p.log.Infof("%v", err) + } + return nil } @@ -108,15 +122,13 @@ func (i InspectionInstance) Print(w io.Writer, replacer *strings.Replacer) (int, cutVal(i.typeID, smallLimit), cutVal(replacer.Replace(i.message), largeLimit), cutVal(i.file, largeLimit), - i.line, strings.ToUpper(i.severity)) + i.line, i.severity) } func cutVal(s string, limit int) string { - var size, count int - for i := 0; i < limit && count < len(s); i++ { - _, size = utf8.DecodeRuneInString(s[count:]) - count += size + runes := []rune(s) + if len(runes) > limit { + return string(runes[:limit]) } - - return s[:count] + return s } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/printers/text.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/printers/text.go similarity index 70% rename from vendor/github.com/golangci/golangci-lint/pkg/printers/text.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/printers/text.go index 56cced769..eb9297615 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/printers/text.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/printers/text.go @@ -7,25 +7,27 @@ import ( "github.com/fatih/color" - "github.com/golangci/golangci-lint/pkg/logutils" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result" ) +// Text prints issues with a human friendly representation. type Text struct { - printIssuedLine bool printLinterName bool - useColors bool + printIssuedLine bool + colors bool log logutils.Log w io.Writer } -func NewText(printIssuedLine, useColors, printLinterName bool, log logutils.Log, w io.Writer) *Text { +func NewText(log logutils.Log, w io.Writer, cfg *config.Text) *Text { return &Text{ - printIssuedLine: printIssuedLine, - printLinterName: printLinterName, - useColors: useColors, - log: log, + printLinterName: cfg.PrintLinterName, + printIssuedLine: cfg.PrintIssuedLine, + colors: cfg.Colors, + log: log.Child(logutils.DebugKeyTextPrinter), w: w, } } @@ -33,23 +35,23 @@ func NewText(printIssuedLine, useColors, printLinterName bool, log logutils.Log, func (p *Text) SprintfColored(ca color.Attribute, format string, args ...any) string { c := color.New(ca) - if !p.useColors { + if !p.colors { c.DisableColor() } return c.Sprintf(format, args...) } -func (p *Text) Print(issues []result.Issue) error { - for i := range issues { - p.printIssue(&issues[i]) +func (p *Text) Print(issues []*result.Issue) error { + for _, issue := range issues { + p.printIssue(issue) if !p.printIssuedLine { continue } - p.printSourceCode(&issues[i]) - p.printUnderLinePointer(&issues[i]) + p.printSourceCode(issue) + p.printUnderLinePointer(issue) } return nil diff --git a/vendor/github.com/golangci/golangci-lint/pkg/report/data.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/report/data.go similarity index 53% rename from vendor/github.com/golangci/golangci-lint/pkg/report/data.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/report/data.go index f083fa9f5..7aedc5522 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/report/data.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/report/data.go @@ -6,9 +6,8 @@ type Warning struct { } type LinterData struct { - Name string - Enabled bool `json:",omitempty"` - EnabledByDefault bool `json:",omitempty"` + Name string + Enabled bool `json:",omitempty"` } type Data struct { @@ -17,10 +16,9 @@ type Data struct { Error string `json:",omitempty"` } -func (d *Data) AddLinter(name string, enabled, enabledByDefault bool) { +func (d *Data) AddLinter(name string, enabled bool) { d.Linters = append(d.Linters, LinterData{ - Name: name, - Enabled: enabled, - EnabledByDefault: enabledByDefault, + Name: name, + Enabled: enabled, }) } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/report/log.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/report/log.go similarity index 93% rename from vendor/github.com/golangci/golangci-lint/pkg/report/log.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/report/log.go index 61665f28b..c964af559 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/report/log.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/report/log.go @@ -2,9 +2,10 @@ package report import ( "fmt" + "slices" "strings" - "github.com/golangci/golangci-lint/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/logutils" ) type LogWrapper struct { @@ -50,7 +51,7 @@ func (lw LogWrapper) Infof(format string, args ...any) { func (lw LogWrapper) Child(name string) logutils.Log { c := lw c.origLog = lw.origLog.Child(name) - c.tags = append([]string{}, lw.tags...) + c.tags = slices.Clone(lw.tags) c.tags = append(c.tags, name) return c } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/issue.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/issue.go similarity index 77% rename from vendor/github.com/golangci/golangci-lint/pkg/result/issue.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/result/issue.go index 32246a6df..2587ffff2 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/issue.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/issue.go @@ -5,6 +5,7 @@ import ( "fmt" "go/token" + "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/packages" ) @@ -12,18 +13,6 @@ type Range struct { From, To int } -type Replacement struct { - NeedOnlyDelete bool // need to delete all lines of the issue without replacement with new lines - NewLines []string // if NeedDelete is false it's the replacement lines - Inline *InlineFix -} - -type InlineFix struct { - StartCol int // zero-based - Length int // length of chunk to be replaced - NewString string -} - type Issue struct { FromLinter string Text string @@ -33,22 +22,28 @@ type Issue struct { // Source lines of a code with the issue to show SourceLines []string - // If we know how to fix the issue we can provide replacement lines - Replacement *Replacement - // Pkg is needed for proper caching of linting results Pkg *packages.Package `json:"-"` - LineRange *Range `json:",omitempty"` - Pos token.Position + LineRange *Range `json:",omitempty"` + // HunkPos is used only when golangci-lint is run over a diff HunkPos int `json:",omitempty"` + // If we know how to fix the issue, we can provide replacement lines + SuggestedFixes []analysis.SuggestedFix `json:",omitempty"` + // If we are expecting a nolint (because this is from nolintlint), record the expected linter ExpectNoLint bool ExpectedNoLintLinter string + + // Only for Diff processor needs. + WorkingDirectoryRelativePath string `json:"-"` + + // Only for processors that need relative paths evaluation. + RelativePath string `json:"-"` } func (i *Issue) FilePath() string { diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/base_rule.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/base_rule.go new file mode 100644 index 000000000..468866248 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/base_rule.go @@ -0,0 +1,102 @@ +package processors + +import ( + "regexp" + "slices" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/fsutils" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result" +) + +type baseRule struct { + text *regexp.Regexp + source *regexp.Regexp + path *regexp.Regexp + pathExcept *regexp.Regexp + linters []string +} + +// The usage of `regexp.MustCompile()` is safe here, +// because the regular expressions are checked before inside [config.BaseRule.Validate]. +func newBaseRule(rule *config.BaseRule, prefix string) baseRule { + base := baseRule{ + linters: rule.Linters, + } + + if rule.Text != "" { + base.text = regexp.MustCompile(prefix + rule.Text) + } + + if rule.Source != "" { + base.source = regexp.MustCompile(prefix + rule.Source) + } + + if rule.Path != "" { + base.path = regexp.MustCompile(fsutils.NormalizePathInRegex(rule.Path)) + } + + if rule.PathExcept != "" { + base.pathExcept = regexp.MustCompile(fsutils.NormalizePathInRegex(rule.PathExcept)) + } + + return base +} + +func (r *baseRule) isEmpty() bool { + return r.text == nil && r.source == nil && r.path == nil && r.pathExcept == nil && len(r.linters) == 0 +} + +func (r *baseRule) match(issue *result.Issue, lines *fsutils.LineCache, log logutils.Log) bool { + if r.isEmpty() { + return false + } + if r.text != nil && !r.text.MatchString(issue.Text) { + return false + } + if r.path != nil && !r.path.MatchString(issue.RelativePath) { + return false + } + if r.pathExcept != nil && r.pathExcept.MatchString(issue.RelativePath) { + return false + } + if len(r.linters) != 0 && !r.matchLinter(issue) { + return false + } + + // the most heavyweight checking last + if r.source != nil && !r.matchSource(issue, lines, log) { + return false + } + + return true +} + +func (r *baseRule) matchLinter(issue *result.Issue) bool { + return slices.Contains(r.linters, issue.FromLinter) +} + +func (r *baseRule) matchSource(issue *result.Issue, lineCache *fsutils.LineCache, log logutils.Log) bool { + sourceLine, errSourceLine := lineCache.GetLine(issue.FilePath(), issue.Line()) + if errSourceLine != nil { + log.Warnf("Failed to get line %s:%d from line cache: %s", issue.FilePath(), issue.Line(), errSourceLine) + return false // can't properly match + } + + return r.source.MatchString(sourceLine) +} + +func parseRules[T, V any](rules []T, prefix string, newFn func(*T, string) V) []V { + if len(rules) == 0 { + return nil + } + + parsedRules := make([]V, 0, len(rules)) + + for _, r := range rules { + parsedRules = append(parsedRules, newFn(&r, prefix)) + } + + return parsedRules +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/cgo.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/cgo.go new file mode 100644 index 000000000..4cc7b57db --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/cgo.go @@ -0,0 +1,52 @@ +package processors + +import ( + "path/filepath" + "strings" + + "github.com/ldez/grignotin/goenv" + + "github.com/golangci/golangci-lint/v2/pkg/goutil" + "github.com/golangci/golangci-lint/v2/pkg/result" +) + +var _ Processor = (*Cgo)(nil) + +// Cgo filters cgo artifacts. +// +// Some linters (e.g. gosec, etc.) return incorrect file paths for cgo files. +// +// Require absolute file path. +type Cgo struct { + goCacheDir string +} + +func NewCgo(env *goutil.Env) *Cgo { + return &Cgo{ + goCacheDir: env.Get(goenv.GOCACHE), + } +} + +func (*Cgo) Name() string { + return "cgo" +} + +func (p *Cgo) Process(issues []*result.Issue) ([]*result.Issue, error) { + return filterIssuesErr(issues, p.shouldPassIssue) +} + +func (*Cgo) Finish() {} + +func (p *Cgo) shouldPassIssue(issue *result.Issue) (bool, error) { + // [p.goCacheDir] contains all preprocessed files including cgo files. + if p.goCacheDir != "" && strings.HasPrefix(issue.FilePath(), p.goCacheDir) { + return false, nil + } + + if filepath.Base(issue.FilePath()) == "_cgo_gotypes.go" { + // skip cgo warning for go1.10 + return false, nil + } + + return true, nil +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/diff.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/diff.go similarity index 59% rename from vendor/github.com/golangci/golangci-lint/pkg/result/processors/diff.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/diff.go index c602cdc65..15574ff0d 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/diff.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/diff.go @@ -2,6 +2,7 @@ package processors import ( "bytes" + "context" "fmt" "io" "os" @@ -9,17 +10,24 @@ import ( "github.com/golangci/revgrep" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/result" ) const envGolangciDiffProcessorPatch = "GOLANGCI_DIFF_PROCESSOR_PATCH" var _ Processor = (*Diff)(nil) +// Diff filters issues based on options `new`, `new-from-rev`, etc. +// +// Uses `git`. +// The paths inside the patch are relative to the path where git is run (the same location where golangci-lint is run). +// +// Warning: it doesn't use `path-prefix` option. type Diff struct { onlyNew bool fromRev string + fromMergeBase string patchFilePath string wholeFiles bool patch string @@ -29,38 +37,45 @@ func NewDiff(cfg *config.Issues) *Diff { return &Diff{ onlyNew: cfg.Diff, fromRev: cfg.DiffFromRevision, + fromMergeBase: cfg.DiffFromMergeBase, patchFilePath: cfg.DiffPatchFilePath, wholeFiles: cfg.WholeFiles, patch: os.Getenv(envGolangciDiffProcessorPatch), } } -func (Diff) Name() string { +func (*Diff) Name() string { return "diff" } -func (p Diff) Process(issues []result.Issue) ([]result.Issue, error) { - if !p.onlyNew && p.fromRev == "" && p.patchFilePath == "" && p.patch == "" { // no need to work +func (p *Diff) Process(issues []*result.Issue) ([]*result.Issue, error) { + if !p.onlyNew && p.fromRev == "" && p.fromMergeBase == "" && p.patchFilePath == "" && p.patch == "" { return issues, nil } var patchReader io.Reader - if p.patchFilePath != "" { + switch { + case p.patchFilePath != "": patch, err := os.ReadFile(p.patchFilePath) if err != nil { return nil, fmt.Errorf("can't read from patch file %s: %w", p.patchFilePath, err) } + patchReader = bytes.NewReader(patch) - } else if p.patch != "" { + + case p.patch != "": patchReader = strings.NewReader(p.patch) } - c := revgrep.Checker{ + checker := revgrep.Checker{ Patch: patchReader, RevisionFrom: p.fromRev, + MergeBase: p.fromMergeBase, WholeFiles: p.wholeFiles, } - if err := c.Prepare(); err != nil { + + err := checker.Prepare(context.Background()) + if err != nil { return nil, fmt.Errorf("can't prepare diff by revgrep: %w", err) } @@ -70,15 +85,16 @@ func (p Diff) Process(issues []result.Issue) ([]result.Issue, error) { return issue } - hunkPos, isNew := c.IsNewIssue(issue) + hunkPos, isNew := checker.IsNew(issue.WorkingDirectoryRelativePath, issue.Line()) if !isNew { return nil } newIssue := *issue newIssue.HunkPos = hunkPos + return &newIssue }), nil } -func (Diff) Finish() {} +func (*Diff) Finish() {} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/exclusion_generated_file_filter.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/exclusion_generated_file_filter.go new file mode 100644 index 000000000..d76ec3184 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/exclusion_generated_file_filter.go @@ -0,0 +1,77 @@ +package processors + +import ( + "fmt" + "path/filepath" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result" +) + +var _ Processor = (*GeneratedFileFilter)(nil) + +type fileSummary struct { + generated bool +} + +// GeneratedFileFilter filters generated files. +type GeneratedFileFilter struct { + debugf logutils.DebugFunc + + mode string + matcher *GeneratedFileMatcher + + fileSummaryCache map[string]*fileSummary +} + +func NewGeneratedFileFilter(mode string) *GeneratedFileFilter { + return &GeneratedFileFilter{ + debugf: logutils.Debug(logutils.DebugKeyGeneratedFileFilter), + + mode: mode, + matcher: NewGeneratedFileMatcher(mode), + + fileSummaryCache: map[string]*fileSummary{}, + } +} + +func (*GeneratedFileFilter) Name() string { + return "generated_file_filter" +} + +func (p *GeneratedFileFilter) Process(issues []*result.Issue) ([]*result.Issue, error) { + if p.mode == config.GeneratedModeDisable { + return issues, nil + } + + return filterIssuesErr(issues, p.shouldPassIssue) +} + +func (*GeneratedFileFilter) Finish() {} + +func (p *GeneratedFileFilter) shouldPassIssue(issue *result.Issue) (bool, error) { + if filepath.Base(issue.FilePath()) == "go.mod" { + return true, nil + } + + // The file is already known. + fs := p.fileSummaryCache[issue.FilePath()] + if fs != nil { + return !fs.generated, nil + } + + fs = &fileSummary{} + p.fileSummaryCache[issue.FilePath()] = fs + + var err error + fs.generated, err = p.matcher.IsGeneratedFile(issue.FilePath(), nil) + if err != nil { + return false, fmt.Errorf("failed to get doc (%s) of file %s: %w", p.mode, issue.FilePath(), err) + } + + p.debugf("file %q is generated: %t", issue.FilePath(), fs.generated) + + // don't report issues for autogenerated files + return !fs.generated, nil +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/exclusion_generated_file_matcher.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/exclusion_generated_file_matcher.go new file mode 100644 index 000000000..763ca9e38 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/exclusion_generated_file_matcher.go @@ -0,0 +1,107 @@ +package processors + +import ( + "fmt" + "go/ast" + "go/parser" + "go/token" + "strings" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/logutils" +) + +// The values must be in lowercase. +const ( + genCodeGenerated = "code generated" + genDoNotEdit = "do not edit" + + // Related to easyjson. + genAutoFile = "autogenerated file" + + //nolint:lll // Long URL + // Related to Swagger Codegen. + // https://github.com/swagger-api/swagger-codegen/blob/61cfeac3b9d855b4eb8bffa0d118bece117bcb7d/modules/swagger-codegen/src/main/resources/go/partial_header.mustache#L16 + // https://github.com/swagger-api/swagger-codegen/issues/12358 + genSwaggerCodegen = "* generated by: swagger codegen " +) + +// GeneratedFileMatcher detects generated files. +// - mode "lax": see `isGeneratedFileLax` documentation. +// - mode "strict": see `isGeneratedFileStrict` documentation. +// - mode "disable": skips this processor. +type GeneratedFileMatcher struct { + debugf logutils.DebugFunc + + mode string +} + +func NewGeneratedFileMatcher(mode string) *GeneratedFileMatcher { + return &GeneratedFileMatcher{ + debugf: logutils.Debug(logutils.DebugKeyGeneratedFileFilter), + mode: mode, + } +} + +func (p *GeneratedFileMatcher) IsGeneratedFile(filepath string, src any) (bool, error) { + if p.mode == config.GeneratedModeDisable { + return false, nil + } + + file, err := parser.ParseFile(token.NewFileSet(), filepath, src, parser.PackageClauseOnly|parser.ParseComments) + if err != nil { + return false, fmt.Errorf("failed to parse file: %w", err) + } + + if p.mode == config.GeneratedModeStrict { + return isGeneratedFileStrict(file), nil + } + + doc := getComments(file) + + return p.isGeneratedFileLax(doc), nil +} + +// isGeneratedFileLax reports whether the source file is generated code. +// The function uses a bit laxer rules than isGeneratedFileStrict to match more generated code. +// See https://github.com/golangci/golangci-lint/issues/48 and https://github.com/golangci/golangci-lint/issues/72. +func (p *GeneratedFileMatcher) isGeneratedFileLax(doc string) bool { + markers := []string{genCodeGenerated, genDoNotEdit, genAutoFile, genSwaggerCodegen} + + doc = strings.ToLower(doc) + + for _, marker := range markers { + if strings.Contains(doc, marker) { + p.debugf("doc contains marker %q: file is generated", marker) + + return true + } + } + + p.debugf("doc of len %d doesn't contain any of markers: %s", len(doc), markers) + + return false +} + +// isGeneratedFileStrict returns true if the source file has a line that matches the regular expression: +// +// ^// Code generated .* DO NOT EDIT\.$ +// +// This line must appear before the first non-comment, non-blank text in the file. +// Based on https://go.dev/s/generatedcode. +func isGeneratedFileStrict(file *ast.File) bool { + if file == nil || len(file.Comments) == 0 { + return false + } + + return ast.IsGenerated(file) +} + +func getComments(file *ast.File) string { + var docLines []string + for _, c := range file.Comments { + docLines = append(docLines, strings.TrimSpace(c.Text())) + } + + return strings.Join(docLines, "\n") +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/exclusion_paths.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/exclusion_paths.go new file mode 100644 index 000000000..acf13edd0 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/exclusion_paths.go @@ -0,0 +1,118 @@ +package processors + +import ( + "fmt" + "regexp" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/fsutils" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result" +) + +var _ Processor = (*ExclusionPaths)(nil) + +type ExclusionPaths struct { + pathPatterns []*regexp.Regexp + pathExceptPatterns []*regexp.Regexp + + warnUnused bool + excludedPathCounter map[*regexp.Regexp]int + excludedPathExceptCounter map[*regexp.Regexp]int + + log logutils.Log +} + +func NewExclusionPaths(log logutils.Log, cfg *config.LinterExclusions) (*ExclusionPaths, error) { + excludedPathCounter := make(map[*regexp.Regexp]int) + + var pathPatterns []*regexp.Regexp + for _, p := range cfg.Paths { + p = fsutils.NormalizePathInRegex(p) + + patternRe, err := regexp.Compile(p) + if err != nil { + return nil, fmt.Errorf("can't compile regexp %q: %w", p, err) + } + + pathPatterns = append(pathPatterns, patternRe) + excludedPathCounter[patternRe] = 0 + } + + excludedPathExceptCounter := make(map[*regexp.Regexp]int) + + var pathExceptPatterns []*regexp.Regexp + for _, p := range cfg.PathsExcept { + p = fsutils.NormalizePathInRegex(p) + + patternRe, err := regexp.Compile(p) + if err != nil { + return nil, fmt.Errorf("can't compile regexp %q: %w", p, err) + } + + pathExceptPatterns = append(pathExceptPatterns, patternRe) + excludedPathExceptCounter[patternRe] = 0 + } + + return &ExclusionPaths{ + pathPatterns: pathPatterns, + pathExceptPatterns: pathExceptPatterns, + warnUnused: cfg.WarnUnused, + excludedPathCounter: excludedPathCounter, + excludedPathExceptCounter: excludedPathExceptCounter, + log: log.Child(logutils.DebugKeyExclusionPaths), + }, nil +} + +func (*ExclusionPaths) Name() string { + return "exclusion_paths" +} + +func (p *ExclusionPaths) Process(issues []*result.Issue) ([]*result.Issue, error) { + if len(p.pathPatterns) == 0 && len(p.pathExceptPatterns) == 0 { + return issues, nil + } + + return filterIssues(issues, p.shouldPassIssue), nil +} + +func (p *ExclusionPaths) Finish() { + for pattern, count := range p.excludedPathCounter { + if p.warnUnused && count == 0 { + p.log.Warnf("The pattern %q match no issues", pattern) + } else { + p.log.Infof("Skipped %d issues by pattern %q", count, pattern) + } + } + + for pattern, count := range p.excludedPathExceptCounter { + if p.warnUnused && count == 0 { + p.log.Warnf("The pattern %q match no issues", pattern) + } + } +} + +func (p *ExclusionPaths) shouldPassIssue(issue *result.Issue) bool { + for _, pattern := range p.pathPatterns { + if pattern.MatchString(issue.RelativePath) { + p.excludedPathCounter[pattern]++ + return false + } + } + + if len(p.pathExceptPatterns) == 0 { + return true + } + + matched := false + for _, pattern := range p.pathExceptPatterns { + if !pattern.MatchString(issue.RelativePath) { + continue + } + + p.excludedPathExceptCounter[pattern]++ + matched = true + } + + return matched +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/exclusion_presets.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/exclusion_presets.go new file mode 100644 index 000000000..4c2fa4c47 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/exclusion_presets.go @@ -0,0 +1,138 @@ +package processors + +import "github.com/golangci/golangci-lint/v2/pkg/config" + +var LinterExclusionPresets = map[string][]config.ExcludeRule{ + config.ExclusionPresetComments: { + { + // Annoying issue about not having a comment. The rare codebase has such comments. + // CheckPackageComment, CheckExportedFunctionDocs, CheckExportedTypeDocs, CheckExportedVarDocs + BaseRule: config.BaseRule{ + Text: "(ST1000|ST1020|ST1021|ST1022)", + Linters: []string{"staticcheck"}, + InternalReference: "EXC0011", + }, + }, + { + // Annoying issue about not having a comment. The rare codebase has such comments. + // rule: exported + BaseRule: config.BaseRule{ + Text: `exported (.+) should have comment( \(or a comment on this block\))? or be unexported`, + Linters: []string{"revive"}, + InternalReference: "EXC0012", + }, + }, + { + // Annoying issue about not having a comment. The rare codebase has such comments. + // rule: package-comments + BaseRule: config.BaseRule{ + Text: `package comment should be of the form "(.+)..."`, + Linters: []string{"revive"}, + InternalReference: "EXC0013", + }, + }, + { + // Annoying issue about not having a comment. The rare codebase has such comments. + // rule: exported + BaseRule: config.BaseRule{ + Text: `comment on exported (.+) should be of the form "(.+)..."`, + Linters: []string{"revive"}, + InternalReference: "EXC0014", + }, + }, + { + // Annoying issue about not having a comment. The rare codebase has such comments. + // rule: package-comments + BaseRule: config.BaseRule{ + Text: `should have a package comment`, + Linters: []string{"revive"}, + InternalReference: "EXC0015", + }, + }, + }, + config.ExclusionPresetStdErrorHandling: { + { + // Almost all programs ignore errors on these functions and in most cases it's ok. + BaseRule: config.BaseRule{ + Text: "(?i)Error return value of .((os\\.)?std(out|err)\\..*|.*Close" + + "|.*Flush|os\\.Remove(All)?|.*print(f|ln)?|os\\.(Un)?Setenv). is not checked", + Linters: []string{"errcheck"}, + InternalReference: "EXC0001", + }, + }, + }, + config.ExclusionPresetCommonFalsePositives: { + { + // Too many false-positives on 'unsafe' usage. + BaseRule: config.BaseRule{ + Text: "G103: Use of unsafe calls should be audited", + Linters: []string{"gosec"}, + InternalReference: "EXC0006", + }, + }, + { + // Too many false-positives for parametrized shell calls. + BaseRule: config.BaseRule{ + Text: "G204: Subprocess launched with variable", + Linters: []string{"gosec"}, + InternalReference: "EXC0007", + }, + }, + { + // False positive is triggered by 'src, err := ioutil.ReadFile(filename)'. + BaseRule: config.BaseRule{ + Text: "G304: Potential file inclusion via variable", + Linters: []string{"gosec"}, + InternalReference: "EXC0010", + }, + }, + }, + config.ExclusionPresetLegacy: { + { + // Common false positives. + BaseRule: config.BaseRule{ + Text: "(possible misuse of unsafe.Pointer|should have signature)", + Linters: []string{"govet"}, + InternalReference: "EXC0004", + }, + }, + { + // Developers tend to write in C-style with an explicit 'break' in a 'switch', so it's ok to ignore. + // CheckScopedBreak + BaseRule: config.BaseRule{ + Text: "SA4011", + Linters: []string{"staticcheck"}, + InternalReference: "EXC0005", + }, + }, + { + // Duplicated errcheck checks. + // Errors unhandled. + BaseRule: config.BaseRule{ + Text: "G104", + Linters: []string{"gosec"}, + InternalReference: "EXC0008", + }, + }, + { + // Too many issues in popular repos. + BaseRule: config.BaseRule{ + Text: "(G301|G302|G307): Expect (directory permissions to be 0750|file permissions to be 0600) or less", + Linters: []string{"gosec"}, + InternalReference: "EXC0009", + }, + }, + }, +} + +func getLinterExclusionPresets(names []string) []config.ExcludeRule { + var rules []config.ExcludeRule + + for _, name := range names { + if p, ok := LinterExclusionPresets[name]; ok { + rules = append(rules, p...) + } + } + + return rules +} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/exclusion_rules.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/exclusion_rules.go new file mode 100644 index 000000000..2e29600f5 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/exclusion_rules.go @@ -0,0 +1,123 @@ +package processors + +import ( + "fmt" + "slices" + "strings" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/fsutils" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result" +) + +var _ Processor = (*ExclusionRules)(nil) + +type ExclusionRules struct { + log logutils.Log + + lines *fsutils.LineCache + + warnUnused bool + skippedCounter map[string]int + + rules []excludeRule +} + +func NewExclusionRules(log logutils.Log, lines *fsutils.LineCache, cfg *config.LinterExclusions) *ExclusionRules { + p := &ExclusionRules{ + log: log, + lines: lines, + warnUnused: cfg.WarnUnused, + skippedCounter: map[string]int{}, + } + + excludeRules := slices.Concat(cfg.Rules, getLinterExclusionPresets(cfg.Presets)) + + p.rules = parseRules(excludeRules, "", newExcludeRule) + + for _, rule := range p.rules { + if rule.internalReference == "" { + p.skippedCounter[rule.String()] = 0 + } + } + + return p +} + +func (*ExclusionRules) Name() string { + return "exclusion_rules" +} + +func (p *ExclusionRules) Process(issues []*result.Issue) ([]*result.Issue, error) { + if len(p.rules) == 0 { + return issues, nil + } + + return filterIssues(issues, func(issue *result.Issue) bool { + for _, rule := range p.rules { + if !rule.match(issue, p.lines, p.log) { + continue + } + + // Ignore default rules. + if rule.internalReference == "" { + p.skippedCounter[rule.String()]++ + } + + return false + } + + return true + }), nil +} + +func (p *ExclusionRules) Finish() { + for rule, count := range p.skippedCounter { + if p.warnUnused && count == 0 { + p.log.Warnf("Skipped %d issues by rules: [%s]", count, rule) + } else { + p.log.Infof("Skipped %d issues by rules: [%s]", count, rule) + } + } +} + +type excludeRule struct { + baseRule + + // For compatibility with exclude-use-default/include. + internalReference string `mapstructure:"-"` +} + +func newExcludeRule(rule *config.ExcludeRule, prefix string) excludeRule { + return excludeRule{ + baseRule: newBaseRule(&rule.BaseRule, prefix), + internalReference: rule.InternalReference, + } +} + +func (e excludeRule) String() string { + var msg []string + + if e.text != nil && e.text.String() != "" { + msg = append(msg, fmt.Sprintf("Text: %q", e.text)) + } + + if e.source != nil && e.source.String() != "" { + msg = append(msg, fmt.Sprintf("Source: %q", e.source)) + } + + if e.path != nil && e.path.String() != "" { + msg = append(msg, fmt.Sprintf("Path: %q", e.path)) + } + + if e.pathExcept != nil && e.pathExcept.String() != "" { + msg = append(msg, fmt.Sprintf("Path Except: %q", e.pathExcept)) + } + + if len(e.linters) > 0 { + msg = append(msg, fmt.Sprintf("Linters: %q", strings.Join(e.linters, ", "))) + } + + return strings.Join(msg, ", ") +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/filename_unadjuster.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/filename_unadjuster.go similarity index 74% rename from vendor/github.com/golangci/golangci-lint/pkg/result/processors/filename_unadjuster.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/filename_unadjuster.go index 6a1387c87..9a8f35ab0 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/filename_unadjuster.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/filename_unadjuster.go @@ -3,15 +3,15 @@ package processors import ( "go/parser" "go/token" - "path/filepath" + "slices" "strings" "sync" "time" "golang.org/x/tools/go/packages" - "github.com/golangci/golangci-lint/pkg/logutils" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result" ) var _ Processor = (*FilenameUnadjuster)(nil) @@ -23,9 +23,13 @@ type adjustMap struct { m map[string]posMapper } -// FilenameUnadjuster is needed because a lot of linters use fset.Position(f.Pos()) -// to get filename. And they return adjusted filename (e.g. *.qtpl) for an issue. We need -// restore real .go filename to properly output it, parse it, etc. +// FilenameUnadjuster fixes filename based on adjusted and unadjusted position (related to line directives and cgo). +// +// A lot of linters use `fset.Position(f.Pos())` to get filename, +// and they return adjusted filename (e.g.` *.qtpl`) for an issue. +// We need restore real `.go` filename to properly output it, parse it, etc. +// +// Require absolute file path. type FilenameUnadjuster struct { m map[string]posMapper // map from adjusted filename to position mapper: adjusted -> unadjusted position log logutils.Log @@ -36,16 +40,20 @@ func NewFilenameUnadjuster(pkgs []*packages.Package, log logutils.Log) *Filename m := adjustMap{m: map[string]posMapper{}} startedAt := time.Now() + var wg sync.WaitGroup - wg.Add(len(pkgs)) - for _, pkg := range pkgs { - go func(pkg *packages.Package) { - // It's important to call func here to run GC - processUnadjusterPkg(&m, pkg, log) - wg.Done() - }(pkg) + + for chunk := range slices.Chunk(pkgs, len(pkgs)/2000+1) { + wg.Go(func() { + for _, pkg := range chunk { + // It's important to call func here to run GC + processUnadjusterPkg(&m, pkg, log) + } + }) } + wg.Wait() + log.Infof("Pre-built %d adjustments in %s", len(m.m), time.Since(startedAt)) return &FilenameUnadjuster{ @@ -59,19 +67,9 @@ func (*FilenameUnadjuster) Name() string { return "filename_unadjuster" } -func (p *FilenameUnadjuster) Process(issues []result.Issue) ([]result.Issue, error) { +func (p *FilenameUnadjuster) Process(issues []*result.Issue) ([]*result.Issue, error) { return transformIssues(issues, func(issue *result.Issue) *result.Issue { - issueFilePath := issue.FilePath() - if !filepath.IsAbs(issue.FilePath()) { - absPath, err := filepath.Abs(issue.FilePath()) - if err != nil { - p.log.Warnf("failed to build abs path for %q: %s", issue.FilePath(), err) - return issue - } - issueFilePath = absPath - } - - mapper := p.m[issueFilePath] + mapper := p.m[issue.FilePath()] if mapper == nil { return issue } diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/fixer.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/fixer.go new file mode 100644 index 000000000..ce33b27fb --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/fixer.go @@ -0,0 +1,306 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// +// This file is inspired by go/analysis/internal/checker/checker.go + +package processors + +import ( + "errors" + "fmt" + "maps" + "os" + "slices" + + "github.com/golangci/golangci-lint/v2/internal/x/tools/diff" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/fsutils" + "github.com/golangci/golangci-lint/v2/pkg/goformatters" + "github.com/golangci/golangci-lint/v2/pkg/goformatters/gci" + "github.com/golangci/golangci-lint/v2/pkg/goformatters/gofmt" + "github.com/golangci/golangci-lint/v2/pkg/goformatters/gofumpt" + "github.com/golangci/golangci-lint/v2/pkg/goformatters/goimports" + "github.com/golangci/golangci-lint/v2/pkg/goformatters/golines" + "github.com/golangci/golangci-lint/v2/pkg/goformatters/swaggo" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/timeutils" +) + +var _ Processor = (*Fixer)(nil) + +const filePerm = 0644 + +// Fixer fixes reports if possible. +// The reports that are not fixed are passed to the next processor. +type Fixer struct { + cfg *config.Config + log logutils.Log + fileCache *fsutils.FileCache + sw *timeutils.Stopwatch + formatter *goformatters.MetaFormatter +} + +func NewFixer(cfg *config.Config, log logutils.Log, fileCache *fsutils.FileCache, formatter *goformatters.MetaFormatter) *Fixer { + return &Fixer{ + cfg: cfg, + log: log, + fileCache: fileCache, + sw: timeutils.NewStopwatch("fixer", log), + formatter: formatter, + } +} + +func (Fixer) Name() string { + return "fixer" +} + +func (p Fixer) Process(issues []*result.Issue) ([]*result.Issue, error) { + if !p.cfg.Issues.NeedFix { + return issues, nil + } + + p.log.Infof("Applying suggested fixes") + + notFixableIssues, err := timeutils.TrackStage(p.sw, "all", func() ([]*result.Issue, error) { + return p.process(issues) + }) + if err != nil { + p.log.Warnf("Failed to fix issues: %v", err) + } + + p.printStat() + + return notFixableIssues, nil +} + +//nolint:funlen,gocyclo // This function should not be split. +func (p Fixer) process(issues []*result.Issue) ([]*result.Issue, error) { + // filenames / linters / edits + editsByLinter := make(map[string]map[string][]diff.Edit) + + formatters := []string{gofumpt.Name, goimports.Name, gofmt.Name, gci.Name, golines.Name, swaggo.Name} + + var notFixableIssues []*result.Issue + + toBeFormattedFiles := make(map[string]struct{}) + + for i := range issues { + issue := issues[i] + + if slices.Contains(formatters, issue.FromLinter) { + toBeFormattedFiles[issue.FilePath()] = struct{}{} + continue + } + + if issue.SuggestedFixes == nil || skipNoTextEdit(issue) { + notFixableIssues = append(notFixableIssues, issue) + continue + } + + for _, sf := range issue.SuggestedFixes { + for _, edit := range sf.TextEdits { + start, end := edit.Pos, edit.End + if start > end { + return nil, fmt.Errorf("%q suggests invalid fix: pos (%v) > end (%v)", + issue.FromLinter, edit.Pos, edit.End) + } + + edit := diff.Edit{ + Start: int(start), + End: int(end), + New: string(edit.NewText), + } + + if _, ok := editsByLinter[issue.FilePath()]; !ok { + editsByLinter[issue.FilePath()] = make(map[string][]diff.Edit) + } + + editsByLinter[issue.FilePath()][issue.FromLinter] = append(editsByLinter[issue.FilePath()][issue.FromLinter], edit) + } + } + } + + // Validate and group the edits to each actual file. + editsByPath := make(map[string][]diff.Edit) + for path, linterToEdits := range editsByLinter { + excludedLinters := make(map[string]struct{}) + + linters := slices.Collect(maps.Keys(linterToEdits)) + + // Does any linter create conflicting edits? + for _, linter := range linters { + edits := linterToEdits[linter] + if _, invalid := validateEdits(edits); invalid > 0 { + name, x, y := linter, edits[invalid-1], edits[invalid] + excludedLinters[name] = struct{}{} + + err := diff3Conflict(path, name, name, []diff.Edit{x}, []diff.Edit{y}) + // TODO(ldez) TUI? + p.log.Warnf("Changes related to %q are skipped for the file %q: %v", + name, path, err) + } + } + + // Does any pair of different linters create edits that conflict? + for j := range linters { + for k := range linters[:j] { + x, y := linters[j], linters[k] + if x > y { + x, y = y, x + } + + _, foundX := excludedLinters[x] + _, foundY := excludedLinters[y] + if foundX || foundY { + continue + } + + xedits, yedits := linterToEdits[x], linterToEdits[y] + + combined := slices.Concat(xedits, yedits) + + if _, invalid := validateEdits(combined); invalid > 0 { + excludedLinters[x] = struct{}{} + p.log.Warnf("Changes related to %q are skipped for the file %q due to conflicts with %q.", x, path, y) + } + } + } + + var edits []diff.Edit + for linter := range linterToEdits { + if _, found := excludedLinters[linter]; !found { + edits = append(edits, linterToEdits[linter]...) + } + } + + editsByPath[path], _ = validateEdits(edits) // remove duplicates. already validated. + } + + var editError error + + var formattedFiles []string + + // Now we've got a set of valid edits for each file. Apply them. + for path, edits := range editsByPath { + contents, err := p.fileCache.GetFileBytes(path) + if err != nil { + editError = errors.Join(editError, fmt.Errorf("%s: %w", path, err)) + continue + } + + out, err := diff.ApplyBytes(contents, edits) + if err != nil { + editError = errors.Join(editError, fmt.Errorf("%s: %w", path, err)) + continue + } + + // Try to format the file. + out = p.formatter.Format(path, out) + + if err := os.WriteFile(path, out, filePerm); err != nil { + editError = errors.Join(editError, fmt.Errorf("%s: %w", path, err)) + continue + } + + formattedFiles = append(formattedFiles, path) + } + + for path := range toBeFormattedFiles { + // Skips files already formatted by the previous fix step. + if !slices.Contains(formattedFiles, path) { + content, err := p.fileCache.GetFileBytes(path) + if err != nil { + p.log.Warnf("Error reading file %s: %v", path, err) + continue + } + + out := p.formatter.Format(path, content) + + if err := os.WriteFile(path, out, filePerm); err != nil { + editError = errors.Join(editError, fmt.Errorf("%s: %w", path, err)) + continue + } + } + } + + return notFixableIssues, editError +} + +func (Fixer) Finish() {} + +func (p Fixer) printStat() { + p.sw.PrintStages() +} + +func skipNoTextEdit(issue *result.Issue) bool { + var onlyMessage int + for _, sf := range issue.SuggestedFixes { + if len(sf.TextEdits) == 0 { + onlyMessage++ + } + } + + return len(issue.SuggestedFixes) == onlyMessage +} + +// validateEdits returns a list of edits that is sorted and +// contains no duplicate edits. Returns the index of some +// overlapping adjacent edits if there is one and <0 if the +// edits are valid. +// +//nolint:gocritic // Copy of go/analysis/internal/checker/checker.go +func validateEdits(edits []diff.Edit) ([]diff.Edit, int) { + if len(edits) == 0 { + return nil, -1 + } + + equivalent := func(x, y diff.Edit) bool { + return x.Start == y.Start && x.End == y.End && x.New == y.New + } + + diff.SortEdits(edits) + + unique := []diff.Edit{edits[0]} + + invalid := -1 + + for i := 1; i < len(edits); i++ { + prev, cur := edits[i-1], edits[i] + // We skip over equivalent edits without considering them + // an error. This handles identical edits coming from the + // multiple ways of loading a package into a + // *go/packages.Packages for testing, e.g. packages "p" and "p [p.test]". + if !equivalent(prev, cur) { + unique = append(unique, cur) + if prev.End > cur.Start { + invalid = i + } + } + } + return unique, invalid +} + +// diff3Conflict returns an error describing two conflicting sets of +// edits on a file at path. +// Copy of go/analysis/internal/checker/checker.go +func diff3Conflict(path, xlabel, ylabel string, xedits, yedits []diff.Edit) error { + contents, err := os.ReadFile(path) + if err != nil { + return err + } + oldlabel, old := "base", string(contents) + + xdiff, err := diff.ToUnified(oldlabel, xlabel, old, xedits, diff.DefaultContextLines) + if err != nil { + return err + } + ydiff, err := diff.ToUnified(oldlabel, ylabel, old, yedits, diff.DefaultContextLines) + if err != nil { + return err + } + + return fmt.Errorf("conflicting edits from %s and %s on %s\nfirst edits:\n%s\nsecond edits:\n%s", + xlabel, ylabel, path, xdiff, ydiff) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/invalid_issue.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/invalid_issue.go similarity index 78% rename from vendor/github.com/golangci/golangci-lint/pkg/result/processors/invalid_issue.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/invalid_issue.go index 3f6cfc540..fa1b19e82 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/invalid_issue.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/invalid_issue.go @@ -3,12 +3,15 @@ package processors import ( "path/filepath" - "github.com/golangci/golangci-lint/pkg/logutils" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result" ) var _ Processor = (*InvalidIssue)(nil) +// InvalidIssue filters invalid reports. +// - non-go files (except `go.mod`) +// - reports without file path type InvalidIssue struct { log logutils.Log } @@ -21,7 +24,7 @@ func (InvalidIssue) Name() string { return "invalid_issue" } -func (p InvalidIssue) Process(issues []result.Issue) ([]result.Issue, error) { +func (p InvalidIssue) Process(issues []*result.Issue) ([]*result.Issue, error) { tcIssues := filterIssuesUnsafe(issues, func(issue *result.Issue) bool { return issue.FromLinter == typeCheckName }) diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/issues.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/issues.go new file mode 100644 index 000000000..cc4deeb52 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/issues.go @@ -0,0 +1,69 @@ +package processors + +import ( + "fmt" + + "github.com/golangci/golangci-lint/v2/pkg/result" +) + +func filterIssues(issues []*result.Issue, filter func(issue *result.Issue) bool) []*result.Issue { + retIssues := make([]*result.Issue, 0, len(issues)) + for _, issue := range issues { + if issue.FromLinter == typeCheckName { + // don't hide typechecking errors in generated files: users expect to see why the project isn't compiling + retIssues = append(retIssues, issue) + continue + } + + if filter(issue) { + retIssues = append(retIssues, issue) + } + } + + return retIssues +} + +func filterIssuesUnsafe(issues []*result.Issue, filter func(issue *result.Issue) bool) []*result.Issue { + retIssues := make([]*result.Issue, 0, len(issues)) + for _, issue := range issues { + if filter(issue) { + retIssues = append(retIssues, issue) + } + } + + return retIssues +} + +func filterIssuesErr(issues []*result.Issue, filter func(issue *result.Issue) (bool, error)) ([]*result.Issue, error) { + retIssues := make([]*result.Issue, 0, len(issues)) + for _, issue := range issues { + if issue.FromLinter == typeCheckName { + // don't hide typechecking errors in generated files: users expect to see why the project isn't compiling + retIssues = append(retIssues, issue) + continue + } + + ok, err := filter(issue) + if err != nil { + return nil, fmt.Errorf("can't filter issue %#v: %w", issue, err) + } + + if ok { + retIssues = append(retIssues, issue) + } + } + + return retIssues, nil +} + +func transformIssues(issues []*result.Issue, transform func(issue *result.Issue) *result.Issue) []*result.Issue { + retIssues := make([]*result.Issue, 0, len(issues)) + for _, issue := range issues { + newIssue := transform(issue) + if newIssue != nil { + retIssues = append(retIssues, newIssue) + } + } + + return retIssues +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/max_from_linter.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/max_from_linter.go similarity index 73% rename from vendor/github.com/golangci/golangci-lint/pkg/result/processors/max_from_linter.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/max_from_linter.go index 0680c3f29..bc7572f2c 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/max_from_linter.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/max_from_linter.go @@ -1,13 +1,14 @@ package processors import ( - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/logutils" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result" ) var _ Processor = (*MaxFromLinter)(nil) +// MaxFromLinter limits the number of reports from the same linter. type MaxFromLinter struct { linterCounter map[string]int limit int @@ -28,17 +29,12 @@ func (*MaxFromLinter) Name() string { return "max_from_linter" } -func (p *MaxFromLinter) Process(issues []result.Issue) ([]result.Issue, error) { +func (p *MaxFromLinter) Process(issues []*result.Issue) ([]*result.Issue, error) { if p.limit <= 0 { // no limit return issues, nil } return filterIssuesUnsafe(issues, func(issue *result.Issue) bool { - if issue.Replacement != nil && p.cfg.Issues.NeedFix { - // we need to fix all issues at once => we need to return all of them - return true - } - p.linterCounter[issue.FromLinter]++ // always inc for stat return p.linterCounter[issue.FromLinter] <= p.limit diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/max_per_file_from_linter.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/max_per_file_from_linter.go similarity index 65% rename from vendor/github.com/golangci/golangci-lint/pkg/result/processors/max_per_file_from_linter.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/max_per_file_from_linter.go index a39c98473..b04b92ea7 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/max_per_file_from_linter.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/max_per_file_from_linter.go @@ -1,12 +1,19 @@ package processors import ( - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/goformatters/gci" + "github.com/golangci/golangci-lint/v2/pkg/goformatters/gofmt" + "github.com/golangci/golangci-lint/v2/pkg/goformatters/gofumpt" + "github.com/golangci/golangci-lint/v2/pkg/goformatters/goimports" + "github.com/golangci/golangci-lint/v2/pkg/goformatters/golines" + "github.com/golangci/golangci-lint/v2/pkg/goformatters/swaggo" + "github.com/golangci/golangci-lint/v2/pkg/result" ) var _ Processor = (*MaxPerFileFromLinter)(nil) +// MaxPerFileFromLinter limits the number of reports by file and by linter. type MaxPerFileFromLinter struct { fileLinterCounter fileLinterCounter maxPerFileFromLinterConfig map[string]int @@ -18,8 +25,9 @@ func NewMaxPerFileFromLinter(cfg *config.Config) *MaxPerFileFromLinter { if !cfg.Issues.NeedFix { // if we don't fix we do this limiting to not annoy user; // otherwise we need to fix all issues in the file at once - maxPerFileFromLinterConfig["gofmt"] = 1 - maxPerFileFromLinterConfig["goimports"] = 1 + for _, f := range []string{gofmt.Name, gofumpt.Name, goimports.Name, gci.Name, golines.Name, swaggo.Name} { + maxPerFileFromLinterConfig[f] = 1 + } } return &MaxPerFileFromLinter{ @@ -32,7 +40,7 @@ func (*MaxPerFileFromLinter) Name() string { return "max_per_file_from_linter" } -func (p *MaxPerFileFromLinter) Process(issues []result.Issue) ([]result.Issue, error) { +func (p *MaxPerFileFromLinter) Process(issues []*result.Issue) ([]*result.Issue, error) { return filterIssuesUnsafe(issues, func(issue *result.Issue) bool { limit := p.maxPerFileFromLinterConfig[issue.FromLinter] if limit == 0 { diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/max_same_issues.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/max_same_issues.go similarity index 78% rename from vendor/github.com/golangci/golangci-lint/pkg/result/processors/max_same_issues.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/max_same_issues.go index 1647cace0..ba22cf31f 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/max_same_issues.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/max_same_issues.go @@ -3,13 +3,14 @@ package processors import ( "sort" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/logutils" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result" ) var _ Processor = (*MaxSameIssues)(nil) +// MaxSameIssues limits the number of reports with the same text. type MaxSameIssues struct { textCounter map[string]int limit int @@ -30,18 +31,14 @@ func (*MaxSameIssues) Name() string { return "max_same_issues" } -func (p *MaxSameIssues) Process(issues []result.Issue) ([]result.Issue, error) { +func (p *MaxSameIssues) Process(issues []*result.Issue) ([]*result.Issue, error) { if p.limit <= 0 { // no limit return issues, nil } return filterIssuesUnsafe(issues, func(issue *result.Issue) bool { - if issue.Replacement != nil && p.cfg.Issues.NeedFix { - // we need to fix all issues at once => we need to return all of them - return true - } - p.textCounter[issue.Text]++ // always inc for stat + return p.textCounter[issue.Text] <= p.limit }), nil } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/nolint.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/nolint_filter.go similarity index 79% rename from vendor/github.com/golangci/golangci-lint/pkg/result/processors/nolint.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/nolint_filter.go index 7794bd3ec..1f45f044e 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/nolint.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/nolint_filter.go @@ -4,22 +4,22 @@ import ( "go/ast" "go/parser" "go/token" + "maps" "regexp" + "slices" "sort" "strings" - "golang.org/x/exp/maps" - - "github.com/golangci/golangci-lint/pkg/golinters/nolintlint" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/lint/lintersdb" - "github.com/golangci/golangci-lint/pkg/logutils" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/golinters/nolintlint" + "github.com/golangci/golangci-lint/v2/pkg/lint/linter" + "github.com/golangci/golangci-lint/v2/pkg/lint/lintersdb" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result" ) -var _ Processor = (*Nolint)(nil) +var _ Processor = (*NolintFilter)(nil) -var nolintDebugf = logutils.Debug(logutils.DebugKeyNolint) +var nolintDebugf = logutils.Debug(logutils.DebugKeyNolintFilter) type ignoredRange struct { linters []string @@ -37,11 +37,8 @@ func (i *ignoredRange) doesMatch(issue *result.Issue) bool { // only allow selective nolinting of nolintlint nolintFoundForLinter := len(i.linters) == 0 && issue.FromLinter != nolintlint.LinterName - for _, linterName := range i.linters { - if linterName == issue.FromLinter { - nolintFoundForLinter = true - break - } + if slices.Contains(i.linters, issue.FromLinter) { + nolintFoundForLinter = true } if nolintFoundForLinter { @@ -64,7 +61,8 @@ type fileData struct { ignoredRanges []ignoredRange } -type Nolint struct { +// NolintFilter filters and sorts reports related to `nolint` directives. +type NolintFilter struct { fileCache map[string]*fileData dbManager *lintersdb.Manager enabledLinters map[string]*linter.Config @@ -75,8 +73,8 @@ type Nolint struct { pattern *regexp.Regexp } -func NewNolint(log logutils.Log, dbManager *lintersdb.Manager, enabledLinters map[string]*linter.Config) *Nolint { - return &Nolint{ +func NewNolintFilter(log logutils.Log, dbManager *lintersdb.Manager, enabledLinters map[string]*linter.Config) *NolintFilter { + return &NolintFilter{ fileCache: map[string]*fileData{}, dbManager: dbManager, enabledLinters: enabledLinters, @@ -86,28 +84,27 @@ func NewNolint(log logutils.Log, dbManager *lintersdb.Manager, enabledLinters ma } } -func (*Nolint) Name() string { - return "nolint" +func (*NolintFilter) Name() string { + return "nolint_filter" } -func (p *Nolint) Process(issues []result.Issue) ([]result.Issue, error) { +func (p *NolintFilter) Process(issues []*result.Issue) ([]*result.Issue, error) { // put nolintlint issues last because we process other issues first to determine which nolint directives are unused sort.Stable(sortWithNolintlintLast(issues)) return filterIssuesErr(issues, p.shouldPassIssue) } -func (p *Nolint) Finish() { +func (p *NolintFilter) Finish() { if len(p.unknownLintersSet) == 0 { return } - unknownLinters := maps.Keys(p.unknownLintersSet) - sort.Strings(unknownLinters) + unknownLinters := slices.Sorted(maps.Keys(p.unknownLintersSet)) p.log.Warnf("Found unknown linters in //nolint directives: %s", strings.Join(unknownLinters, ", ")) } -func (p *Nolint) shouldPassIssue(issue *result.Issue) (bool, error) { +func (p *NolintFilter) shouldPassIssue(issue *result.Issue) (bool, error) { nolintDebugf("got issue: %v", *issue) // don't expect disabled linters to cover their nolint statements @@ -142,7 +139,7 @@ func (p *Nolint) shouldPassIssue(issue *result.Issue) (bool, error) { return true, nil } -func (p *Nolint) getOrCreateFileData(issue *result.Issue) *fileData { +func (p *NolintFilter) getOrCreateFileData(issue *result.Issue) *fileData { fd := p.fileCache[issue.FilePath()] if fd != nil { return fd @@ -169,7 +166,7 @@ func (p *Nolint) getOrCreateFileData(issue *result.Issue) *fileData { return fd } -func (p *Nolint) buildIgnoredRangesForFile(f *ast.File, fset *token.FileSet, filePath string) []ignoredRange { +func (p *NolintFilter) buildIgnoredRangesForFile(f *ast.File, fset *token.FileSet, filePath string) []ignoredRange { inlineRanges := p.extractFileCommentsInlineRanges(fset, f.Comments...) nolintDebugf("file %s: inline nolint ranges are %+v", filePath, inlineRanges) @@ -185,13 +182,12 @@ func (p *Nolint) buildIgnoredRangesForFile(f *ast.File, fset *token.FileSet, fil ast.Walk(&e, f) // TODO: merge all ranges: there are repeated ranges - allRanges := append([]ignoredRange{}, inlineRanges...) - allRanges = append(allRanges, e.expandedRanges...) + allRanges := slices.Concat(inlineRanges, e.expandedRanges) return allRanges } -func (p *Nolint) extractFileCommentsInlineRanges(fset *token.FileSet, comments ...*ast.CommentGroup) []ignoredRange { +func (p *NolintFilter) extractFileCommentsInlineRanges(fset *token.FileSet, comments ...*ast.CommentGroup) []ignoredRange { var ret []ignoredRange for _, g := range comments { for _, c := range g.List { @@ -205,7 +201,7 @@ func (p *Nolint) extractFileCommentsInlineRanges(fset *token.FileSet, comments . return ret } -func (p *Nolint) extractInlineRangeFromComment(text string, g ast.Node, fset *token.FileSet) *ignoredRange { +func (p *NolintFilter) extractInlineRangeFromComment(text string, g ast.Node, fset *token.FileSet) *ignoredRange { text = strings.TrimLeft(text, "/ ") if !p.pattern.MatchString(text) { return nil @@ -228,11 +224,12 @@ func (p *Nolint) extractInlineRangeFromComment(text string, g ast.Node, fset *to return buildRange(nil) // ignore all linters } + text, _, _ = strings.Cut(text, "//") // allow another comment after this comment + // ignore specific linters var linters []string - text = strings.Split(text, "//")[0] // allow another comment after this comment - linterItems := strings.Split(strings.TrimPrefix(text, "nolint:"), ",") - for _, item := range linterItems { + + for item := range strings.SplitSeq(strings.TrimPrefix(text, "nolint:"), ",") { linterName := strings.ToLower(strings.TrimSpace(item)) if linterName == "all" { p.unknownLintersSet = map[string]bool{} @@ -300,7 +297,7 @@ func (e *rangeExpander) Visit(node ast.Node) ast.Visitor { } // put nolintlint last -type sortWithNolintlintLast []result.Issue +type sortWithNolintlintLast []*result.Issue func (issues sortWithNolintlintLast) Len() int { return len(issues) diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/path_absoluter.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/path_absoluter.go new file mode 100644 index 000000000..240cedf8e --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/path_absoluter.go @@ -0,0 +1,44 @@ +package processors + +import ( + "path/filepath" + + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result" +) + +var _ Processor = (*PathAbsoluter)(nil) + +// PathAbsoluter ensures that representation of path are absolute. +type PathAbsoluter struct { + log logutils.Log +} + +func NewPathAbsoluter(log logutils.Log) *PathAbsoluter { + return &PathAbsoluter{log: log.Child(logutils.DebugKeyPathAbsoluter)} +} + +func (*PathAbsoluter) Name() string { + return "path_absoluter" +} + +func (p *PathAbsoluter) Process(issues []*result.Issue) ([]*result.Issue, error) { + return transformIssues(issues, func(issue *result.Issue) *result.Issue { + if filepath.IsAbs(issue.FilePath()) { + return issue + } + + absPath, err := filepath.Abs(issue.FilePath()) + if err != nil { + p.log.Warnf("failed to get absolute path for %q: %v", issue.FilePath(), err) + return nil + } + + newIssue := issue + newIssue.Pos.Filename = absPath + + return newIssue + }), nil +} + +func (*PathAbsoluter) Finish() {} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/path_prettifier.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/path_prettifier.go new file mode 100644 index 000000000..94dfbab37 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/path_prettifier.go @@ -0,0 +1,51 @@ +package processors + +import ( + "path/filepath" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/fsutils" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result" +) + +var _ Processor = (*PathPrettifier)(nil) + +// PathPrettifier modifies report file path to be relative to the base path. +// Also handles the `output.path-prefix` option. +type PathPrettifier struct { + cfg *config.Output + + log logutils.Log +} + +func NewPathPrettifier(log logutils.Log, cfg *config.Output) *PathPrettifier { + return &PathPrettifier{ + cfg: cfg, + log: log.Child(logutils.DebugKeyPathPrettifier), + } +} + +func (*PathPrettifier) Name() string { + return "path_prettifier" +} + +func (p *PathPrettifier) Process(issues []*result.Issue) ([]*result.Issue, error) { + if p.cfg.PathMode == fsutils.OutputPathModeAbsolute { + return issues, nil + } + + return transformIssues(issues, func(issue *result.Issue) *result.Issue { + newIssue := issue + + if p.cfg.PathPrefix == "" { + newIssue.Pos.Filename = issue.RelativePath + } else { + newIssue.Pos.Filename = filepath.Join(p.cfg.PathPrefix, issue.RelativePath) + } + + return newIssue + }), nil +} + +func (*PathPrettifier) Finish() {} diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/path_relativity.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/path_relativity.go new file mode 100644 index 000000000..c68662c7b --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/path_relativity.go @@ -0,0 +1,60 @@ +package processors + +import ( + "fmt" + "path/filepath" + + "github.com/golangci/golangci-lint/v2/pkg/fsutils" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result" +) + +var _ Processor = (*PathRelativity)(nil) + +// PathRelativity computes [result.Issue.RelativePath] and [result.Issue.WorkingDirectoryRelativePath], +// based on the base path. +type PathRelativity struct { + log logutils.Log + basePath string + workingDirectory string +} + +func NewPathRelativity(log logutils.Log, basePath string) (*PathRelativity, error) { + wd, err := fsutils.Getwd() + if err != nil { + return nil, fmt.Errorf("error getting working directory: %w", err) + } + + return &PathRelativity{ + log: log.Child(logutils.DebugKeyPathRelativity), + basePath: basePath, + workingDirectory: wd, + }, nil +} + +func (*PathRelativity) Name() string { + return "path_relativity" +} + +func (p *PathRelativity) Process(issues []*result.Issue) ([]*result.Issue, error) { + return transformIssues(issues, func(issue *result.Issue) *result.Issue { + newIssue := *issue + + var err error + newIssue.RelativePath, err = filepath.Rel(p.basePath, issue.FilePath()) + if err != nil { + p.log.Warnf("Getting relative path (basepath): %v", err) + return nil + } + + newIssue.WorkingDirectoryRelativePath, err = filepath.Rel(p.workingDirectory, issue.FilePath()) + if err != nil { + p.log.Warnf("Getting relative path (wd): %v", err) + return nil + } + + return &newIssue + }), nil +} + +func (*PathRelativity) Finish() {} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_shortener.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/path_shortener.go similarity index 65% rename from vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_shortener.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/path_shortener.go index b161e86c2..23df4f02c 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_shortener.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/path_shortener.go @@ -4,12 +4,14 @@ import ( "fmt" "strings" - "github.com/golangci/golangci-lint/pkg/fsutils" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/fsutils" + "github.com/golangci/golangci-lint/v2/pkg/result" ) var _ Processor = (*PathShortener)(nil) +// PathShortener modifies text of the reports to reduce file path inside the text. +// It uses the rooted path name corresponding to the current directory (`wd`). type PathShortener struct { wd string } @@ -27,7 +29,7 @@ func (PathShortener) Name() string { return "path_shortener" } -func (p PathShortener) Process(issues []result.Issue) ([]result.Issue, error) { +func (p PathShortener) Process(issues []*result.Issue) ([]*result.Issue, error) { return transformIssues(issues, func(issue *result.Issue) *result.Issue { newIssue := issue newIssue.Text = strings.ReplaceAll(newIssue.Text, p.wd+"/", "") diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/processor.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/processor.go similarity index 52% rename from vendor/github.com/golangci/golangci-lint/pkg/result/processors/processor.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/processor.go index 13e63d604..f5603c94d 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/processor.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/processor.go @@ -1,13 +1,13 @@ package processors import ( - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/result" ) const typeCheckName = "typecheck" type Processor interface { - Process(issues []result.Issue) ([]result.Issue, error) + Process(issues []*result.Issue) ([]*result.Issue, error) Name() string Finish() } diff --git a/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/severity.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/severity.go new file mode 100644 index 000000000..33c3997f8 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/severity.go @@ -0,0 +1,86 @@ +package processors + +import ( + "cmp" + + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/fsutils" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result" +) + +const severityFromLinter = "@linter" + +var _ Processor = (*Severity)(nil) + +// Severity modifies report severity. +// It uses the same `baseRule` structure as [ExcludeRules] processor. +// +// Warning: it doesn't use `path-prefix` option. +type Severity struct { + name string + + log logutils.Log + + lines *fsutils.LineCache + + defaultSeverity string + rules []severityRule +} + +func NewSeverity(log logutils.Log, lines *fsutils.LineCache, cfg *config.Severity) *Severity { + p := &Severity{ + name: "severity-rules", + lines: lines, + log: log, + defaultSeverity: cfg.Default, + } + + p.rules = parseRules(cfg.Rules, "", newSeverityRule) + + return p +} + +func (p *Severity) Name() string { return p.name } + +func (p *Severity) Process(issues []*result.Issue) ([]*result.Issue, error) { + if len(p.rules) == 0 && p.defaultSeverity == "" { + return issues, nil + } + + return transformIssues(issues, p.transform), nil +} + +func (*Severity) Finish() {} + +func (p *Severity) transform(issue *result.Issue) *result.Issue { + for _, rule := range p.rules { + if rule.match(issue, p.lines, p.log) { + if rule.severity == severityFromLinter || (rule.severity == "" && p.defaultSeverity == severityFromLinter) { + return issue + } + + issue.Severity = cmp.Or(rule.severity, p.defaultSeverity) + + return issue + } + } + + if p.defaultSeverity != severityFromLinter { + issue.Severity = p.defaultSeverity + } + + return issue +} + +type severityRule struct { + baseRule + severity string +} + +func newSeverityRule(rule *config.SeverityRule, prefix string) severityRule { + return severityRule{ + baseRule: newBaseRule(&rule.BaseRule, prefix), + severity: rule.Severity, + } +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/sort_results.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/sort_results.go similarity index 79% rename from vendor/github.com/golangci/golangci-lint/pkg/result/processors/sort_results.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/sort_results.go index 7eebea631..8ba06bccf 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/sort_results.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/sort_results.go @@ -6,15 +6,10 @@ import ( "slices" "strings" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/config" + "github.com/golangci/golangci-lint/v2/pkg/result" ) -// Base propose of this functionality to sort results (issues) -// produced by various linters by analyzing code. We're achieving this -// by sorting results.Issues using processor step, and chain based -// rules that can compare different properties of the Issues struct. - const ( orderNameFile = "file" orderNameLinter = "linter" @@ -31,13 +26,17 @@ var _ Processor = (*SortResults)(nil) type issueComparator func(a, b *result.Issue) int +// SortResults sorts reports based on criteria: +// - file names, line numbers, positions +// - linter names +// - severity names type SortResults struct { cmps map[string][]issueComparator cfg *config.Output } -func NewSortResults(cfg *config.Config) *SortResults { +func NewSortResults(cfg *config.Output) *SortResults { return &SortResults{ cmps: map[string][]issueComparator{ // For sorting we are comparing (in next order): @@ -48,20 +47,16 @@ func NewSortResults(cfg *config.Config) *SortResults { // For sorting we are comparing: severity orderNameSeverity: {bySeverity}, }, - cfg: &cfg.Output, + cfg: cfg, } } func (SortResults) Name() string { return "sort_results" } // Process is performing sorting of the result issues. -func (p SortResults) Process(issues []result.Issue) ([]result.Issue, error) { - if !p.cfg.SortResults { - return issues, nil - } - +func (p SortResults) Process(issues []*result.Issue) ([]*result.Issue, error) { if len(p.cfg.SortOrder) == 0 { - p.cfg.SortOrder = []string{orderNameFile} + p.cfg.SortOrder = []string{orderNameLinter, orderNameFile} } var cmps []issueComparator @@ -77,8 +72,8 @@ func (p SortResults) Process(issues []result.Issue) ([]result.Issue, error) { comp := mergeComparators(cmps...) - slices.SortFunc(issues, func(a, b result.Issue) int { - return comp(&a, &b) + slices.SortFunc(issues, func(a, b *result.Issue) int { + return comp(a, b) }) return issues, nil diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/source_code.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/source_code.go similarity index 61% rename from vendor/github.com/golangci/golangci-lint/pkg/result/processors/source_code.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/source_code.go index 4a89fc73e..d4e82643c 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/source_code.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/source_code.go @@ -1,13 +1,20 @@ package processors import ( - "github.com/golangci/golangci-lint/pkg/fsutils" - "github.com/golangci/golangci-lint/pkg/logutils" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/fsutils" + "github.com/golangci/golangci-lint/v2/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/result" ) var _ Processor = (*SourceCode)(nil) +// SourceCode modifies displayed information based on [result.Issue.GetLineRange()]. +// +// This is used: +// - to display the "UnderLinePointer". +// - in some rare cases to display multiple lines instead of one (ex: `dupl`) +// +// It requires to use [fsutils.LineCache] ([fsutils.FileCache]) to get the file information before the fixes. type SourceCode struct { lineCache *fsutils.LineCache log logutils.Log @@ -24,7 +31,7 @@ func (SourceCode) Name() string { return "source_code" } -func (p SourceCode) Process(issues []result.Issue) ([]result.Issue, error) { +func (p SourceCode) Process(issues []*result.Issue) ([]*result.Issue, error) { return transformIssues(issues, p.transform), nil } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/uniq_by_line.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/uniq_by_line.go similarity index 64% rename from vendor/github.com/golangci/golangci-lint/pkg/result/processors/uniq_by_line.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/uniq_by_line.go index 115196d9a..953496355 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/uniq_by_line.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/result/processors/uniq_by_line.go @@ -1,23 +1,23 @@ package processors import ( - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-lint/v2/pkg/result" ) const uniqByLineLimit = 1 var _ Processor = (*UniqByLine)(nil) +// UniqByLine filters reports to keep only one report by line of code. type UniqByLine struct { fileLineCounter fileLineCounter - cfg *config.Config + enabled bool } -func NewUniqByLine(cfg *config.Config) *UniqByLine { +func NewUniqByLine(enable bool) *UniqByLine { return &UniqByLine{ fileLineCounter: fileLineCounter{}, - cfg: cfg, + enabled: enable, } } @@ -25,8 +25,8 @@ func (*UniqByLine) Name() string { return "uniq_by_line" } -func (p *UniqByLine) Process(issues []result.Issue) ([]result.Issue, error) { - if !p.cfg.Output.UniqByLine { +func (p *UniqByLine) Process(issues []*result.Issue) ([]*result.Issue, error) { + if !p.enabled { return issues, nil } @@ -36,12 +36,6 @@ func (p *UniqByLine) Process(issues []result.Issue) ([]result.Issue, error) { func (*UniqByLine) Finish() {} func (p *UniqByLine) shouldPassIssue(issue *result.Issue) bool { - if issue.Replacement != nil && p.cfg.Issues.NeedFix { - // if issue will be auto-fixed we shouldn't collapse issues: - // e.g. one line can contain 2 misspellings, they will be in 2 issues and misspell should fix both of them. - return true - } - if p.fileLineCounter.GetCount(issue) == uniqByLineLimit { return false } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/timeutils/stopwatch.go b/vendor/github.com/golangci/golangci-lint/v2/pkg/timeutils/stopwatch.go similarity index 98% rename from vendor/github.com/golangci/golangci-lint/pkg/timeutils/stopwatch.go rename to vendor/github.com/golangci/golangci-lint/v2/pkg/timeutils/stopwatch.go index 95b16de9f..332c24c88 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/timeutils/stopwatch.go +++ b/vendor/github.com/golangci/golangci-lint/v2/pkg/timeutils/stopwatch.go @@ -7,7 +7,7 @@ import ( "sync" "time" - "github.com/golangci/golangci-lint/pkg/logutils" + "github.com/golangci/golangci-lint/v2/pkg/logutils" ) const noStagesText = "no stages" diff --git a/vendor/github.com/golangci/golines/LICENSE b/vendor/github.com/golangci/golines/LICENSE new file mode 100644 index 000000000..b417faf7e --- /dev/null +++ b/vendor/github.com/golangci/golines/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2025 Golangci Team +Copyright (c) 2019 Segment.io, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/golangci/golines/shorten/.gitattributes b/vendor/github.com/golangci/golines/shorten/.gitattributes new file mode 100644 index 000000000..90fe9352e --- /dev/null +++ b/vendor/github.com/golangci/golines/shorten/.gitattributes @@ -0,0 +1,3 @@ +/testdata/** text eol=lf +/internal/graph/testdata/** text eol=lf +/internal/comments/testdata/** text eol=lf diff --git a/vendor/github.com/golangci/golines/shorten/annotations.go b/vendor/github.com/golangci/golines/shorten/annotations.go new file mode 100644 index 000000000..0cba53fd6 --- /dev/null +++ b/vendor/github.com/golangci/golines/shorten/annotations.go @@ -0,0 +1,65 @@ +package shorten + +import ( + "strings" + + "github.com/golangci/golines/shorten/internal" + "github.com/golangci/golines/shorten/internal/annotation" + "github.com/golangci/golines/shorten/internal/comments" +) + +// annotateLongLines adds specially formatted comments to all eligible lines that +// are longer than the configured target length. +// If a line already has one of these comments from a previous shortening round, +// then the comment contents are updated. +func (s *Shortener) annotateLongLines(lines []string) ([]string, int) { + var ( + annotatedLines []string + nbLinesToShorten int + ) + + prevLen := -1 + + for _, line := range lines { + length := internal.LineLength(line, s.config.TabLen) + + if prevLen > -1 { + if length <= s.config.MaxLen { + // Shortening successful, remove previous annotation + annotatedLines = annotatedLines[:len(annotatedLines)-1] + } else if length < prevLen { + // Replace annotation with a new length + annotatedLines[len(annotatedLines)-1] = annotation.Create(length) + + nbLinesToShorten++ + } + } else if !comments.Is(line) && length > s.config.MaxLen { + annotatedLines = append( + annotatedLines, + annotation.Create(length), + ) + + nbLinesToShorten++ + } + + annotatedLines = append(annotatedLines, line) + prevLen = annotation.Parse(line) + } + + return annotatedLines, nbLinesToShorten +} + +// removeAnnotations removes all comments added by the annotateLongLines function above. +func removeAnnotations(content []byte) []byte { + var cleanedLines []string + + lines := strings.SplitSeq(string(content), "\n") + + for line := range lines { + if !annotation.Is(line) { + cleanedLines = append(cleanedLines, line) + } + } + + return []byte(strings.Join(cleanedLines, "\n")) +} diff --git a/vendor/github.com/golangci/golines/shorten/format.go b/vendor/github.com/golangci/golines/shorten/format.go new file mode 100644 index 000000000..c177ee573 --- /dev/null +++ b/vendor/github.com/golangci/golines/shorten/format.go @@ -0,0 +1,347 @@ +package shorten + +import ( + "go/token" + "log/slog" + "reflect" + + "github.com/dave/dst" + "github.com/golangci/golines/shorten/internal/annotation" + "github.com/golangci/golines/shorten/internal/tags" +) + +// formatFile formats the provided AST file starting at the top-level declarations. +func (s *Shortener) formatFile(file *dst.File) { + for _, decl := range file.Decls { + s.formatNode(decl) + } +} + +// formatNode formats the provided AST node. +// The appropriate helper function is called based on +// whether the node is a declaration, expression, statement, or spec. +func (s *Shortener) formatNode(node dst.Node) { + switch n := node.(type) { + case dst.Decl: + s.logger.Debug("processing declaration", slog.Any("node", n)) + s.formatDecl(n) + + case dst.Expr: + s.logger.Debug("processing expression", slog.Any("node", n)) + s.formatExpr(n, false, false) + + case dst.Stmt: + s.logger.Debug("processing statement", slog.Any("node", n)) + s.formatStmt(n, false) + + case dst.Spec: + s.logger.Debug("processing spec", slog.Any("node", n)) + s.formatSpec(n, false) + + default: + s.logger.Debug( + "got a node type that can't be shortened", + slog.Any("node_type", reflect.TypeOf(n)), + ) + } +} + +// formatDecl formats an AST declaration node. +// These include function declarations, imports, and constants. +func (s *Shortener) formatDecl(decl dst.Decl) { + switch d := decl.(type) { + case *dst.FuncDecl: + if d.Type != nil && d.Type.Params != nil && annotation.HasRecursive(d) { + s.formatFieldList(d.Type.Params) + } + + s.formatStmt(d.Body, false) + + case *dst.GenDecl: + shouldShorten := annotation.Has(d) + + for _, spec := range d.Specs { + s.formatSpec(spec, shouldShorten) + } + + default: + s.logger.Debug( + "got a declaration type that can't be shortened", + slog.Any("decl_type", reflect.TypeOf(d)), + ) + } +} + +// formatStmt formats an AST statement node. +// Among other examples, these include assignments, case clauses, +// for statements, if statements, and select statements. +// +//nolint:funlen // the number of statements is expected. +func (s *Shortener) formatStmt(stmt dst.Stmt, force bool) { + stmtType := reflect.TypeOf(stmt) + + // Explicitly check for nil statements + if reflect.ValueOf(stmt) == reflect.Zero(stmtType) { + return + } + + shouldShorten := force || annotation.Has(stmt) + + switch st := stmt.(type) { + case *dst.AssignStmt: + s.formatExprs(st.Rhs, shouldShorten, false) + + case *dst.BlockStmt: + s.formatStmts(st.List, false) + + case *dst.CaseClause: + if shouldShorten { + for _, arg := range st.List { + arg.Decorations().After = dst.NewLine + + s.formatExpr(arg, false, false) + } + } + + s.formatStmts(st.Body, false) + + case *dst.CommClause: + s.formatStmts(st.Body, false) + + case *dst.DeclStmt: + s.formatDecl(st.Decl) + + case *dst.DeferStmt: + s.formatExpr(st.Call, shouldShorten, false) + + case *dst.ExprStmt: + s.formatExpr(st.X, shouldShorten, false) + + case *dst.ForStmt: + s.formatStmt(st.Body, false) + + case *dst.GoStmt: + s.formatExpr(st.Call, shouldShorten, false) + + case *dst.IfStmt: + s.formatExpr(st.Cond, shouldShorten, false) + s.formatStmt(st.Body, false) + + if st.Init != nil { + s.formatStmt(st.Init, shouldShorten) + } + + if st.Else != nil { + s.formatStmt(st.Else, shouldShorten) + } + + case *dst.RangeStmt: + s.formatStmt(st.Body, false) + + case *dst.ReturnStmt: + s.formatExprs(st.Results, shouldShorten, false) + + case *dst.SelectStmt: + s.formatStmt(st.Body, false) + + case *dst.SwitchStmt: + s.formatStmt(st.Body, false) + + // Ignored: st.Init + + if st.Tag != nil { + s.formatExpr(st.Tag, shouldShorten, false) + } + + case *dst.TypeSwitchStmt: + s.formatStmt(st.Body, false) + + case *dst.BadStmt, *dst.EmptyStmt, *dst.LabeledStmt, + *dst.SendStmt, *dst.IncDecStmt, *dst.BranchStmt: + // These statements are explicitly defined to improve switch cases exhaustiveness. + // They may be handled in the future. + if shouldShorten { + s.logger.Debug( + "got a statement type that is not shortened", + slog.Any("stmt_type", stmtType), + ) + } + + default: + if shouldShorten { + s.logger.Debug( + "got an unknown statement type", + slog.Any("stmt_type", stmtType), + ) + } + } +} + +// formatExpr formats an AST expression node. +// These include uniary and binary expressions, function literals, +// and key/value pair statements, among others. +func (s *Shortener) formatExpr(expr dst.Expr, force, isChain bool) { + shouldShorten := force || annotation.Has(expr) + + switch e := expr.(type) { + case *dst.BinaryExpr: + if (e.Op == token.LAND || e.Op == token.LOR) && shouldShorten { + if e.Y.Decorations().Before == dst.NewLine { + s.formatExpr(e.X, force, isChain) + } else { + e.Y.Decorations().Before = dst.NewLine + } + } else { + s.formatExpr(e.X, shouldShorten, isChain) + s.formatExpr(e.Y, shouldShorten, isChain) + } + + case *dst.CallExpr: + shortenChildArgs := shouldShorten || annotation.HasRecursive(e) + + _, ok := e.Fun.(*dst.SelectorExpr) + + if ok && shortenChildArgs && + s.config.ChainSplitDots && (isChain || chainLength(e) > 1) { + e.Decorations().After = dst.NewLine + + s.formatExprs(e.Args, false, true) + s.formatExpr(e.Fun, shouldShorten, true) + } else { + for i, arg := range e.Args { + if shortenChildArgs { + formatList(arg, i) + } + + s.formatExpr(arg, false, isChain) + } + + s.formatExpr(e.Fun, shouldShorten, isChain) + } + + case *dst.CompositeLit: + if shouldShorten || annotation.HasRecursive(e) { + for i, element := range e.Elts { + if i == 0 { + element.Decorations().Before = dst.NewLine + } + + element.Decorations().After = dst.NewLine + } + } + + s.formatExprs(e.Elts, false, isChain) + + case *dst.FuncLit: + s.formatStmt(e.Body, false) + + case *dst.FuncType: + if shouldShorten { + s.formatFieldList(e.Params) + } + + case *dst.InterfaceType: + for _, method := range e.Methods.List { + if annotation.Has(method) { + s.formatExpr(method.Type, true, isChain) + } + } + + case *dst.KeyValueExpr: + s.formatExpr(e.Value, shouldShorten, isChain) + + case *dst.SelectorExpr: + s.formatExpr(e.X, shouldShorten, isChain) + + case *dst.StructType: + if s.config.ReformatTags { + tags.FormatStructTags(e.Fields) + } + + case *dst.UnaryExpr: + s.formatExpr(e.X, shouldShorten, isChain) + + default: + if shouldShorten { + s.logger.Debug( + "got an expression type that can't be shortened", + slog.Any("expr_type", reflect.TypeOf(e)), + ) + } + } +} + +// formatSpec formats an AST spec node. +// These include type specifications, among other things. +func (s *Shortener) formatSpec(spec dst.Spec, force bool) { + shouldShorten := annotation.Has(spec) || force + + switch sp := spec.(type) { + case *dst.ValueSpec: + s.formatExprs(sp.Values, shouldShorten, false) + + case *dst.TypeSpec: + s.formatExpr(sp.Type, false, false) + + default: + if shouldShorten { + s.logger.Debug( + "got a spec type that can't be shortened", + slog.Any("spec_type", reflect.TypeOf(sp)), + ) + } + } +} + +func (s *Shortener) formatStmts(stmts []dst.Stmt, force bool) { + for _, stmt := range stmts { + s.formatStmt(stmt, force) + } +} + +func (s *Shortener) formatExprs(exprs []dst.Expr, force, isChain bool) { + for _, expr := range exprs { + s.formatExpr(expr, force, isChain) + } +} + +// formatFieldList formats a field list in a function declaration. +func (s *Shortener) formatFieldList(fieldList *dst.FieldList) { + for i, field := range fieldList.List { + formatList(field, i) + } +} + +func formatList(node dst.Node, index int) { + decorations := node.Decorations() + + if index == 0 { + decorations.Before = dst.NewLine + } else { + decorations.Before = dst.None + } + + decorations.After = dst.NewLine +} + +// chainLength determines the length of the function call chain in an expression. +func chainLength(callExpr *dst.CallExpr) int { + numCalls := 1 + currCall := callExpr + + for { + selectorExpr, ok := currCall.Fun.(*dst.SelectorExpr) + if !ok { + break + } + + currCall, ok = selectorExpr.X.(*dst.CallExpr) + if !ok { + break + } + + numCalls++ + } + + return numCalls +} diff --git a/vendor/github.com/golangci/golines/shorten/internal/annotation/annotation.go b/vendor/github.com/golangci/golines/shorten/internal/annotation/annotation.go new file mode 100644 index 000000000..0a9c1f0c8 --- /dev/null +++ b/vendor/github.com/golangci/golines/shorten/internal/annotation/annotation.go @@ -0,0 +1,94 @@ +package annotation + +import ( + "fmt" + "slices" + "strconv" + "strings" + + "github.com/dave/dst" +) + +const prefix = "//golines:shorten:" + +// Create generates the text of a comment that will annotate long lines. +func Create(length int) string { + return fmt.Sprintf("%s%d", prefix, length) +} + +// Is determines whether the given line is an annotation created with Create. +func Is(line string) bool { + return strings.HasPrefix( + strings.Trim(line, " \t"), + prefix, + ) +} + +// Has determines whether the given AST node has a line length annotation on it. +func Has[T dst.Node](node T) bool { + return has(node.Decorations().Start) +} + +// HasTail determines whether the given AST node has a line length annotation at its end. +// This is needed to catch long function declarations with inline interface definitions. +func HasTail(node dst.Node) bool { + return has(node.Decorations().End) +} + +// HasRecursive determines whether the given node or one of its children has a +// golines annotation on it. It's currently implemented for function declarations, fields, +// call expressions, and selector expressions only. +func HasRecursive[T dst.Node](node T) bool { + if Has(node) { + return true + } + + switch n := any(node).(type) { + case *dst.FuncDecl: + return n.Type != nil && n.Type.Params != nil && + HasRecursive(n.Type.Params) + + case *dst.Field: + return HasTail(n) || HasRecursive(n.Type) + + case *dst.SelectorExpr: + return Has(n.Sel) || Has(n.X) + + case *dst.CallExpr: + return HasRecursive(n.Fun) || slices.ContainsFunc(n.Args, Has) + + case *dst.InterfaceType: + return HasRecursive(n.Methods) + + case *dst.FieldList: + return slices.ContainsFunc(n.List, HasRecursive) + + case *dst.CompositeLit: + return slices.ContainsFunc(n.Elts, HasRecursive) + } + + return false +} + +// Parse returns the line length encoded in a golines annotation. +// If none is found, it returns -1. +func Parse(line string) int { + if !Is(line) { + return -1 + } + + components := strings.SplitN(line, ":", 3) + + val, err := strconv.Atoi(components[2]) + if err != nil { + return -1 + } + + return val +} + +func has(decorations dst.Decorations) bool { + deco := decorations.All() + + return len(deco) > 0 && Is(deco[len(deco)-1]) +} diff --git a/vendor/github.com/golangci/golines/shorten/internal/comments/comments.go b/vendor/github.com/golangci/golines/shorten/internal/comments/comments.go new file mode 100644 index 000000000..5fd0e202a --- /dev/null +++ b/vendor/github.com/golangci/golines/shorten/internal/comments/comments.go @@ -0,0 +1,104 @@ +package comments + +import ( + "fmt" + "regexp" + "strings" + + "github.com/golangci/golines/shorten/internal" + "github.com/golangci/golines/shorten/internal/annotation" +) + +// Shortener is a struct that can be used to shorten long comments. +// +// As noted in the repo README, +// this functionality has some quirks and is disabled by default. +type Shortener struct { + MaxLen int + TabLen int +} + +// Go directive (should be ignored). +// https://go.dev/doc/comment#syntax +var directivePattern = regexp.MustCompile(`\s*//(line |extern |export |[a-z0-9]+:[a-z0-9])`) + +// Process attempts to shorten long comments in the provided source. +// +// As noted in the repo README, +// this functionality has some quirks and is disabled by default. +func (s *Shortener) Process(content []byte) []byte { + if len(content) == 0 { + return content + } + + var cleanedLines []string + + // all words in a contiguous sequence of long comments + var words []string + + prefix := "" + + lines := strings.SplitSeq(string(content), "\n") + for line := range lines { + if Is(line) && !annotation.Is(line) && + !isDirective(line) && + internal.LineLength(line, s.TabLen) > s.MaxLen { + start := strings.Index(line, "//") + prefix = line[0:(start + 2)] + trimmedLine := strings.Trim(line[(start+2):], " ") + currLineWords := strings.Split(trimmedLine, " ") + words = append(words, currLineWords...) + } else { + // Reflow the accumulated `words` before appending the unprocessed `line`. + currLineLen := 0 + + var currLineWords []string + + maxCommentLen := s.MaxLen - internal.LineLength(prefix, s.TabLen) + for _, word := range words { + if currLineLen > 0 && currLineLen+1+len(word) > maxCommentLen { + cleanedLines = append( + cleanedLines, + fmt.Sprintf( + "%s %s", + prefix, + strings.Join(currLineWords, " "), + ), + ) + currLineWords = []string{} + currLineLen = 0 + } + + currLineWords = append(currLineWords, word) + currLineLen += 1 + len(word) + } + + if currLineLen > 0 { + cleanedLines = append( + cleanedLines, + fmt.Sprintf( + "%s %s", + prefix, + strings.Join(currLineWords, " "), + ), + ) + } + + words = []string{} + + cleanedLines = append(cleanedLines, line) + } + } + + return []byte(strings.Join(cleanedLines, "\n")) +} + +// Is determines whether the provided line is a non-block comment. +func Is(line string) bool { + return strings.HasPrefix(strings.Trim(line, " \t"), "//") +} + +// isDirective determines whether the provided line is a directive, e.g., for `go:generate`. +func isDirective(line string) bool { + return directivePattern.MatchString(line) +} diff --git a/vendor/github.com/golangci/golines/shorten/internal/graph/graph.go b/vendor/github.com/golangci/golines/shorten/internal/graph/graph.go new file mode 100644 index 000000000..e11eab9dd --- /dev/null +++ b/vendor/github.com/golangci/golines/shorten/internal/graph/graph.go @@ -0,0 +1,132 @@ +package graph + +import ( + "fmt" + "html" + "io" + "strings" + + "github.com/dave/dst" + "github.com/golangci/golines/shorten/internal/annotation" +) + +// Node is a representation of a node in the AST graph. +type Node struct { + Type string + Value string + Node dst.Node + Edges []*Edge + + // Used for keeping track of node position during rendering + level int + seq int +} + +func (n *Node) id() string { + return fmt.Sprintf("%s_%d_%d", n.Type, n.level, n.seq) +} + +// Edge is a representation of an edge in the AST graph. +type Edge struct { + Dest *Node + Relationship string +} + +// CreateDot creates a dot representation of the graph associated with a dst node. +func CreateDot(node dst.Node, out io.Writer) error { + root := NodeToGraphNode(node) + + dotGraph, err := Walk(root) + if err != nil { + return err + } + + _, err = out.Write([]byte(dotGraph)) + + return err +} + +// Walk walks the graph starting at the argument root and returns +// a graphviz (dot) representation. +func Walk(root *Node) (string, error) { + toProcess := []*Node{root} + + var processed []*Node + + outLines := []string{"digraph {"} + + var ( + currLevel int + currSeq int + ) + + // First, loop through the graph nodes to assign proper ids + + for len(toProcess) != 0 { + currNode := toProcess[0] + + if currNode.level > currLevel { + currLevel = currNode.level + currSeq = 0 + } + + currNode.seq = currSeq + currSeq++ + + processed = append(processed, currNode) + toProcess = toProcess[1:] + + for _, edge := range currNode.Edges { + edge.Dest.level = currLevel + 1 + toProcess = append(toProcess, edge.Dest) + } + } + + // Then, fill out the graph in dot format + for _, node := range processed { + var ( + nodeLabel string + nodeFormat string + ) + + if annotation.Has(node.Node) { + nodeFormat = ",penwidth=3.0" + } + + if node.Value != "" { + nodeLabel = fmt.Sprintf( + `%s
%s`, + node.Type, + html.EscapeString(node.Value), + ) + } else { + nodeLabel = node.Type + } + + outLines = append( + outLines, + fmt.Sprintf( + "\t"+`%s[label=<%s>,shape="box"%s]`, + node.id(), + nodeLabel, + nodeFormat, + ), + ) + + for _, edge := range node.Edges { + outLines = append( + outLines, + fmt.Sprintf( + "\t"+`%s->%s[label="%s",fontsize=12.0]`, + node.id(), + edge.Dest.id(), + edge.Relationship, + ), + ) + } + } + + outLines = append(outLines, "}") + + return strings.Join(outLines, "\n"), nil +} diff --git a/vendor/github.com/golangci/golines/shorten/internal/graph/graph_generated.go b/vendor/github.com/golangci/golines/shorten/internal/graph/graph_generated.go new file mode 100644 index 000000000..40fa188bb --- /dev/null +++ b/vendor/github.com/golangci/golines/shorten/internal/graph/graph_generated.go @@ -0,0 +1,596 @@ +// Code generated by 'generate/main.go.'; DO NOT EDIT. + +package graph + +import ( + dst "github.com/dave/dst" + "log" +) + +func NodeToGraphNode(node dst.Node) *Node { + gNode := &Node{Node: node, Edges: []*Edge{}} + var child *Node + switch n := node.(type) { + case *dst.ArrayType: + gNode.Type = "ArrayType" + if n.Len != nil { + child = NodeToGraphNode(n.Len) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Len"}) + } + if n.Elt != nil { + child = NodeToGraphNode(n.Elt) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Elt"}) + } + + case *dst.AssignStmt: + gNode.Type = "AssignStmt" + if n.Lhs != nil { + for _, obj := range n.Lhs { + child = NodeToGraphNode(obj) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Lhs"}) + } + } + if n.Rhs != nil { + for _, obj := range n.Rhs { + child = NodeToGraphNode(obj) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Rhs"}) + } + } + + case *dst.BadDecl: + gNode.Type = "BadDecl" + + case *dst.BadExpr: + gNode.Type = "BadExpr" + + case *dst.BadStmt: + gNode.Type = "BadStmt" + + case *dst.BasicLit: + gNode.Type = "BasicLit" + gNode.Value = n.Value + + case *dst.BinaryExpr: + gNode.Type = "BinaryExpr" + if n.X != nil { + child = NodeToGraphNode(n.X) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "X"}) + } + if n.Y != nil { + child = NodeToGraphNode(n.Y) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Y"}) + } + + case *dst.BlockStmt: + gNode.Type = "BlockStmt" + if n.List != nil { + for _, obj := range n.List { + child = NodeToGraphNode(obj) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "List"}) + } + } + + case *dst.BranchStmt: + gNode.Type = "BranchStmt" + if n.Label != nil { + child = NodeToGraphNode(n.Label) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Label"}) + } + + case *dst.CallExpr: + gNode.Type = "CallExpr" + if n.Fun != nil { + child = NodeToGraphNode(n.Fun) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Fun"}) + } + if n.Args != nil { + for _, obj := range n.Args { + child = NodeToGraphNode(obj) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Args"}) + } + } + + case *dst.CaseClause: + gNode.Type = "CaseClause" + if n.List != nil { + for _, obj := range n.List { + child = NodeToGraphNode(obj) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "List"}) + } + } + if n.Body != nil { + for _, obj := range n.Body { + child = NodeToGraphNode(obj) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Body"}) + } + } + + case *dst.ChanType: + gNode.Type = "ChanType" + if n.Value != nil { + child = NodeToGraphNode(n.Value) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Value"}) + } + + case *dst.CommClause: + gNode.Type = "CommClause" + if n.Comm != nil { + child = NodeToGraphNode(n.Comm) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Comm"}) + } + if n.Body != nil { + for _, obj := range n.Body { + child = NodeToGraphNode(obj) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Body"}) + } + } + + case *dst.CompositeLit: + gNode.Type = "CompositeLit" + if n.Type != nil { + child = NodeToGraphNode(n.Type) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Type"}) + } + if n.Elts != nil { + for _, obj := range n.Elts { + child = NodeToGraphNode(obj) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Elts"}) + } + } + + case *dst.DeclStmt: + gNode.Type = "DeclStmt" + if n.Decl != nil { + child = NodeToGraphNode(n.Decl) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Decl"}) + } + + case *dst.DeferStmt: + gNode.Type = "DeferStmt" + if n.Call != nil { + child = NodeToGraphNode(n.Call) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Call"}) + } + + case *dst.Ellipsis: + gNode.Type = "Ellipsis" + if n.Elt != nil { + child = NodeToGraphNode(n.Elt) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Elt"}) + } + + case *dst.EmptyStmt: + gNode.Type = "EmptyStmt" + + case *dst.ExprStmt: + gNode.Type = "ExprStmt" + if n.X != nil { + child = NodeToGraphNode(n.X) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "X"}) + } + + case *dst.Field: + gNode.Type = "Field" + if n.Names != nil { + for _, obj := range n.Names { + child = NodeToGraphNode(obj) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Names"}) + } + } + if n.Type != nil { + child = NodeToGraphNode(n.Type) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Type"}) + } + if n.Tag != nil { + child = NodeToGraphNode(n.Tag) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Tag"}) + } + + case *dst.FieldList: + gNode.Type = "FieldList" + if n.List != nil { + for _, obj := range n.List { + child = NodeToGraphNode(obj) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "List"}) + } + } + + case *dst.File: + gNode.Type = "File" + if n.Name != nil { + child = NodeToGraphNode(n.Name) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Name"}) + } + if n.Decls != nil { + for _, obj := range n.Decls { + child = NodeToGraphNode(obj) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Decls"}) + } + } + if n.Imports != nil { + for _, obj := range n.Imports { + child = NodeToGraphNode(obj) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Imports"}) + } + } + + case *dst.ForStmt: + gNode.Type = "ForStmt" + if n.Init != nil { + child = NodeToGraphNode(n.Init) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Init"}) + } + if n.Cond != nil { + child = NodeToGraphNode(n.Cond) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Cond"}) + } + if n.Post != nil { + child = NodeToGraphNode(n.Post) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Post"}) + } + if n.Body != nil { + child = NodeToGraphNode(n.Body) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Body"}) + } + + case *dst.FuncDecl: + gNode.Type = "FuncDecl" + if n.Recv != nil { + child = NodeToGraphNode(n.Recv) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Recv"}) + } + if n.Name != nil { + child = NodeToGraphNode(n.Name) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Name"}) + } + if n.Type.TypeParams != nil { + child = NodeToGraphNode(n.Type.TypeParams) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "TypeParams"}) + } + if n.Type.Params != nil { + child = NodeToGraphNode(n.Type.Params) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Params"}) + } + if n.Type.Results != nil { + child = NodeToGraphNode(n.Type.Results) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Results"}) + } + if n.Body != nil { + child = NodeToGraphNode(n.Body) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Body"}) + } + + case *dst.FuncLit: + gNode.Type = "FuncLit" + if n.Type != nil { + child = NodeToGraphNode(n.Type) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Type"}) + } + if n.Body != nil { + child = NodeToGraphNode(n.Body) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Body"}) + } + + case *dst.FuncType: + gNode.Type = "FuncType" + if n.TypeParams != nil { + child = NodeToGraphNode(n.TypeParams) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "TypeParams"}) + } + if n.Params != nil { + child = NodeToGraphNode(n.Params) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Params"}) + } + if n.Results != nil { + child = NodeToGraphNode(n.Results) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Results"}) + } + + case *dst.GenDecl: + gNode.Type = "GenDecl" + if n.Specs != nil { + for _, obj := range n.Specs { + child = NodeToGraphNode(obj) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Specs"}) + } + } + + case *dst.GoStmt: + gNode.Type = "GoStmt" + if n.Call != nil { + child = NodeToGraphNode(n.Call) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Call"}) + } + + case *dst.Ident: + gNode.Type = "Ident" + gNode.Value = n.Name + + case *dst.IfStmt: + gNode.Type = "IfStmt" + if n.Init != nil { + child = NodeToGraphNode(n.Init) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Init"}) + } + if n.Cond != nil { + child = NodeToGraphNode(n.Cond) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Cond"}) + } + if n.Body != nil { + child = NodeToGraphNode(n.Body) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Body"}) + } + if n.Else != nil { + child = NodeToGraphNode(n.Else) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Else"}) + } + + case *dst.ImportSpec: + gNode.Type = "ImportSpec" + if n.Name != nil { + child = NodeToGraphNode(n.Name) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Name"}) + } + if n.Path != nil { + child = NodeToGraphNode(n.Path) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Path"}) + } + + case *dst.IncDecStmt: + gNode.Type = "IncDecStmt" + if n.X != nil { + child = NodeToGraphNode(n.X) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "X"}) + } + + case *dst.IndexExpr: + gNode.Type = "IndexExpr" + if n.X != nil { + child = NodeToGraphNode(n.X) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "X"}) + } + if n.Index != nil { + child = NodeToGraphNode(n.Index) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Index"}) + } + + case *dst.IndexListExpr: + gNode.Type = "IndexListExpr" + if n.X != nil { + child = NodeToGraphNode(n.X) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "X"}) + } + if n.Indices != nil { + for _, obj := range n.Indices { + child = NodeToGraphNode(obj) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Indices"}) + } + } + + case *dst.InterfaceType: + gNode.Type = "InterfaceType" + if n.Methods != nil { + child = NodeToGraphNode(n.Methods) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Methods"}) + } + + case *dst.KeyValueExpr: + gNode.Type = "KeyValueExpr" + if n.Key != nil { + child = NodeToGraphNode(n.Key) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Key"}) + } + if n.Value != nil { + child = NodeToGraphNode(n.Value) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Value"}) + } + + case *dst.LabeledStmt: + gNode.Type = "LabeledStmt" + if n.Label != nil { + child = NodeToGraphNode(n.Label) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Label"}) + } + if n.Stmt != nil { + child = NodeToGraphNode(n.Stmt) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Stmt"}) + } + + case *dst.MapType: + gNode.Type = "MapType" + if n.Key != nil { + child = NodeToGraphNode(n.Key) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Key"}) + } + if n.Value != nil { + child = NodeToGraphNode(n.Value) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Value"}) + } + + case *dst.Package: + gNode.Type = "Package" + + case *dst.ParenExpr: + gNode.Type = "ParenExpr" + if n.X != nil { + child = NodeToGraphNode(n.X) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "X"}) + } + + case *dst.RangeStmt: + gNode.Type = "RangeStmt" + if n.Key != nil { + child = NodeToGraphNode(n.Key) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Key"}) + } + if n.Value != nil { + child = NodeToGraphNode(n.Value) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Value"}) + } + if n.X != nil { + child = NodeToGraphNode(n.X) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "X"}) + } + if n.Body != nil { + child = NodeToGraphNode(n.Body) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Body"}) + } + + case *dst.ReturnStmt: + gNode.Type = "ReturnStmt" + if n.Results != nil { + for _, obj := range n.Results { + child = NodeToGraphNode(obj) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Results"}) + } + } + + case *dst.SelectStmt: + gNode.Type = "SelectStmt" + if n.Body != nil { + child = NodeToGraphNode(n.Body) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Body"}) + } + + case *dst.SelectorExpr: + gNode.Type = "SelectorExpr" + if n.X != nil { + child = NodeToGraphNode(n.X) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "X"}) + } + if n.Sel != nil { + child = NodeToGraphNode(n.Sel) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Sel"}) + } + + case *dst.SendStmt: + gNode.Type = "SendStmt" + if n.Chan != nil { + child = NodeToGraphNode(n.Chan) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Chan"}) + } + if n.Value != nil { + child = NodeToGraphNode(n.Value) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Value"}) + } + + case *dst.SliceExpr: + gNode.Type = "SliceExpr" + if n.X != nil { + child = NodeToGraphNode(n.X) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "X"}) + } + if n.Low != nil { + child = NodeToGraphNode(n.Low) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Low"}) + } + if n.High != nil { + child = NodeToGraphNode(n.High) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "High"}) + } + if n.Max != nil { + child = NodeToGraphNode(n.Max) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Max"}) + } + + case *dst.StarExpr: + gNode.Type = "StarExpr" + if n.X != nil { + child = NodeToGraphNode(n.X) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "X"}) + } + + case *dst.StructType: + gNode.Type = "StructType" + if n.Fields != nil { + child = NodeToGraphNode(n.Fields) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Fields"}) + } + + case *dst.SwitchStmt: + gNode.Type = "SwitchStmt" + if n.Init != nil { + child = NodeToGraphNode(n.Init) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Init"}) + } + if n.Tag != nil { + child = NodeToGraphNode(n.Tag) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Tag"}) + } + if n.Body != nil { + child = NodeToGraphNode(n.Body) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Body"}) + } + + case *dst.TypeAssertExpr: + gNode.Type = "TypeAssertExpr" + if n.X != nil { + child = NodeToGraphNode(n.X) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "X"}) + } + if n.Type != nil { + child = NodeToGraphNode(n.Type) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Type"}) + } + + case *dst.TypeSpec: + gNode.Type = "TypeSpec" + if n.Name != nil { + child = NodeToGraphNode(n.Name) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Name"}) + } + if n.TypeParams != nil { + child = NodeToGraphNode(n.TypeParams) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "TypeParams"}) + } + if n.Type != nil { + child = NodeToGraphNode(n.Type) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Type"}) + } + + case *dst.TypeSwitchStmt: + gNode.Type = "TypeSwitchStmt" + if n.Init != nil { + child = NodeToGraphNode(n.Init) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Init"}) + } + if n.Assign != nil { + child = NodeToGraphNode(n.Assign) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Assign"}) + } + if n.Body != nil { + child = NodeToGraphNode(n.Body) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Body"}) + } + + case *dst.UnaryExpr: + gNode.Type = "UnaryExpr" + if n.X != nil { + child = NodeToGraphNode(n.X) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "X"}) + } + + case *dst.ValueSpec: + gNode.Type = "ValueSpec" + if n.Names != nil { + for _, obj := range n.Names { + child = NodeToGraphNode(obj) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Names"}) + } + } + if n.Type != nil { + child = NodeToGraphNode(n.Type) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Type"}) + } + if n.Values != nil { + for _, obj := range n.Values { + child = NodeToGraphNode(obj) + gNode.Edges = append(gNode.Edges, &Edge{Dest: child, Relationship: "Values"}) + } + } + + default: + log.Println("Unrecognized type") + } + return gNode +} diff --git a/vendor/github.com/golangci/golines/shorten/internal/line.go b/vendor/github.com/golangci/golines/shorten/internal/line.go new file mode 100644 index 000000000..a195469d6 --- /dev/null +++ b/vendor/github.com/golangci/golines/shorten/internal/line.go @@ -0,0 +1,16 @@ +package internal + +// LineLength gets the width of the provided line after tab expansion. +func LineLength(line string, tabLen int) int { + length := 0 + + for _, char := range line { + if char == '\t' { + length += tabLen + } else { + length++ + } + } + + return length +} diff --git a/vendor/github.com/golangci/golines/shorten/internal/tags/filler.go b/vendor/github.com/golangci/golines/shorten/internal/tags/filler.go new file mode 100644 index 000000000..d5efe8737 --- /dev/null +++ b/vendor/github.com/golangci/golines/shorten/internal/tags/filler.go @@ -0,0 +1,42 @@ +package tags + +import "fmt" + +type tagEntry struct { + Key string + Content string +} + +// filler is used to collect tags. +// It uses a slice to keep track of the tags in order of appearance. +type filler struct { + data []*tagEntry + + uniq map[string]*tagEntry +} + +func newFiller() *filler { + return &filler{ + uniq: map[string]*tagEntry{}, + } +} + +func (f *filler) Data() []*tagEntry { + return f.data +} + +func (f *filler) Fill(key, value string) error { + if e, ok := f.uniq[key]; ok { + e.Content += " " + fmt.Sprintf("%s:%q", key, value) + } else { + entry := &tagEntry{ + Key: key, + Content: fmt.Sprintf("%s:%q", key, value), + } + + f.uniq[key] = entry + f.data = append(f.data, entry) + } + + return nil +} diff --git a/vendor/github.com/golangci/golines/shorten/internal/tags/tags.go b/vendor/github.com/golangci/golines/shorten/internal/tags/tags.go new file mode 100644 index 000000000..ef9305b88 --- /dev/null +++ b/vendor/github.com/golangci/golines/shorten/internal/tags/tags.go @@ -0,0 +1,222 @@ +package tags + +import ( + "fmt" + "regexp" + "slices" + "strings" + "unicode/utf8" + + "github.com/dave/dst" + "github.com/golangci/golines/shorten/internal/annotation" + "github.com/ldez/structtags/parser" +) + +var structTagRegexp = regexp.MustCompile("`([ ]*[a-zA-Z0-9_-]+:\".*\"[ ]*){2,}`") + +// HasMultipleEntries returns whether the given lines have a multi-entries struct line. +// It's used as an optimization step to avoid unnecessary shortening rounds. +func HasMultipleEntries(lines []string) bool { + return slices.ContainsFunc(lines, structTagRegexp.MatchString) +} + +// FormatStructTags formats struct tags so that the keys within each block of fields are aligned. +// It's not technically a shortening (and it usually makes these tags longer), so it's being +// kept separate from the core shortening logic for now. +// +// See the struct_tags fixture for examples. +func FormatStructTags(fieldList *dst.FieldList) { + if fieldList == nil || len(fieldList.List) == 0 { + return + } + + var blockFields []*dst.Field + + // Divide fields into "blocks" so that we don't do alignments across blank lines and comments. + for _, field := range fieldList.List { + if isEndFieldsBlock(field) { + align(blockFields) + + blockFields = blockFields[:0] + } + + blockFields = append(blockFields, field) + } + + align(blockFields) +} + +func isEndFieldsBlock(field *dst.Field) bool { + return field.Decorations().Before == dst.EmptyLine || + slices.ContainsFunc(field.Decorations().Start.All(), func(s string) bool { + return !annotation.Is(s) + }) +} + +// align formats the struct tags within a single field block. +// NOTE(ldez): all the code of `align` is not related to shorten, +// instead of shortening a line, it increases the line length. +// It must be either: +// - disabled by default +// - or the additional spaces should be an option +// - or maybe removed. +func align(fields []*dst.Field) { + if len(fields) == 0 { + return + } + + maxTagWidths := map[string]int{} + + var tagKeys []string + + tagKVs := make([]map[string]string, len(fields)) + + var ( + maxTypeWidth int + invalidWidths bool + ) + + // First, scan over all field tags so that we can understand their values and widths + + for f, field := range fields { + if len(field.Names) > 0 { + typeWidth, err := getWidth(field.Type) + if err != nil { + // We couldn't figure out the proper width of this field + invalidWidths = true + } else if typeWidth > maxTypeWidth { + maxTypeWidth = typeWidth + } + } + + if field.Tag == nil { + continue + } + + tagValue := field.Tag.Value + + // The dst library doesn't strip off the backticks, so we need to do this manually + if tagValue[0] != '`' || tagValue[len(tagValue)-1] != '`' { + continue + } + + tagValue = tagValue[1 : len(tagValue)-1] + + entries, err := parser.Tag(tagValue, newFiller()) + if err != nil { + return + } + + for _, entry := range entries { + // Tag is key, value, and some extra chars (two quotes + one colon) + width := utf8.RuneCountInString(entry.Content) + + if _, ok := maxTagWidths[entry.Key]; !ok { + maxTagWidths[entry.Key] = width + tagKeys = append(tagKeys, entry.Key) + } else if width > maxTagWidths[entry.Key] { + maxTagWidths[entry.Key] = width + } + + if tagKVs[f] == nil { + tagKVs[f] = map[string]string{} + } + + tagKVs[f][entry.Key] = entry.Content + } + } + + // Go over all the fields again, replacing each tag with a reformatted one + for f, field := range fields { + if tagKVs[f] == nil { + continue + } + + var tagComponents []string + + if len(field.Names) == 0 && maxTypeWidth > 0 && !invalidWidths { + // Add extra spacing at beginning so that tag aligns with named field tags + tagComponents = append(tagComponents, "") + + tagComponents[len(tagComponents)-1] += strings.Repeat(" ", maxTypeWidth) + } + + for _, key := range tagKeys { + content, ok := tagKVs[f][key] + lenUsed := 0 + + if ok { + tagComponents = append(tagComponents, content) + lenUsed += utf8.RuneCountInString(content) + } else { + tagComponents = append(tagComponents, "") + } + + if len(field.Names) > 0 || !invalidWidths { + lenRemaining := maxTagWidths[key] - lenUsed + + tagComponents[len(tagComponents)-1] += strings.Repeat(" ", lenRemaining) + } + } + + field.Tag.Value = fmt.Sprintf("`%s`", + strings.TrimRight(strings.Join(tagComponents, " "), " ")) + } +} + +// getWidth tries to guess the formatted width of a dst node expression. +// If this isn't (yet) possible, it returns an error. +func getWidth(node dst.Node) (int, error) { + switch n := node.(type) { + case *dst.ArrayType: + eltWidth, err := getWidth(n.Elt) + if err != nil { + return 0, err + } + + return 2 + eltWidth, nil + + case *dst.ChanType: + valWidth, err := getWidth(n.Value) + if err != nil { + return 0, err + } + + isSend := n.Dir&dst.SEND > 0 + isRecv := n.Dir&dst.RECV > 0 + + if isSend && isRecv { + // Channel does not include an arrow + return 5 + valWidth, nil + } + + // Channel includes an arrow + return 7 + valWidth, nil + + case *dst.Ident: + return len(n.Name), nil + + case *dst.MapType: + keyWidth, err := getWidth(n.Key) + if err != nil { + return 0, err + } + + valWidth, err := getWidth(n.Value) + if err != nil { + return 0, err + } + + return 5 + keyWidth + valWidth, nil + + case *dst.StarExpr: + xWidth, err := getWidth(n.X) + if err != nil { + return 0, err + } + + return 1 + xWidth, nil + } + + return 0, fmt.Errorf("could not get the width of node %+v", node) +} diff --git a/vendor/github.com/golangci/golines/shorten/log.go b/vendor/github.com/golangci/golines/shorten/log.go new file mode 100644 index 000000000..fe1827424 --- /dev/null +++ b/vendor/github.com/golangci/golines/shorten/log.go @@ -0,0 +1,9 @@ +package shorten + +type Logger interface { + Debug(msg string, args ...any) +} + +type noopLogger struct{} + +func (n *noopLogger) Debug(_ string, _ ...any) {} diff --git a/vendor/github.com/golangci/golines/shorten/shortener.go b/vendor/github.com/golangci/golines/shorten/shortener.go new file mode 100644 index 000000000..413ce4c9d --- /dev/null +++ b/vendor/github.com/golangci/golines/shorten/shortener.go @@ -0,0 +1,206 @@ +package shorten + +import ( + "bytes" + "fmt" + "go/format" + "log/slog" + "os" + "strings" + + "github.com/dave/dst" + "github.com/dave/dst/decorator" + "github.com/golangci/golines/shorten/internal/comments" + "github.com/golangci/golines/shorten/internal/graph" + "github.com/golangci/golines/shorten/internal/tags" +) + +// The maximum number of shortening "rounds" that we'll allow. +// The shortening process should converge quickly, +// but we have this here as a safety mechanism to prevent loops that prevent termination. +const maxRounds = 20 + +// Config stores the configuration options exposed by a Shortener instance. +type Config struct { + // MaxLen Max target width for each line + MaxLen int + + // TabLen Width of a tab character + TabLen int + + // KeepAnnotations Whether to keep annotations in the final result (for debugging only) + KeepAnnotations bool + + // ShortenComments Whether to shorten comments + ShortenComments bool + + // ReformatTags Whether to reformat struct tags in addition to shortening long lines + ReformatTags bool + + // DotFile Path to write dot-formatted output to (for debugging only) + DotFile string + + // ChainSplitDots Whether to split chain methods by putting dots at the ends of lines + ChainSplitDots bool +} + +// NewDefaultConfig returns a [Config] with default values. +func NewDefaultConfig() *Config { + return &Config{ + MaxLen: 100, + TabLen: 4, + KeepAnnotations: false, + ShortenComments: false, + ReformatTags: true, + DotFile: "", + ChainSplitDots: true, + } +} + +// Options is the type for configuring options of a [Shortener] instance. +type Options func(*Shortener) + +// WithLogger sets the logger to use it for a [Shortener] instance. +func WithLogger(logger Logger) Options { + return func(s *Shortener) { + if logger != nil { + s.logger = logger + } + } +} + +// Shortener shortens a single go file according to a small set of user style preferences. +type Shortener struct { + config *Config + + commentsShortener *comments.Shortener + + logger Logger +} + +// NewShortener creates a new shortener instance from the provided config. +func NewShortener(config *Config, opts ...Options) *Shortener { + if config == nil { + config = NewDefaultConfig() + } + + s := &Shortener{ + config: config, + logger: &noopLogger{}, + } + + if config.ShortenComments { + s.commentsShortener = &comments.Shortener{ + MaxLen: config.MaxLen, + TabLen: config.TabLen, + } + } + + for _, opt := range opts { + opt(s) + } + + return s +} + +// Process shortens the provided golang file content bytes. +func (s *Shortener) Process(content []byte) ([]byte, error) { + var round int + + var err error + + // Do initial, non-line-length-aware formatting + content, err = format.Source(content) + if err != nil { + return nil, fmt.Errorf("error formatting source: %w", err) + } + + for { + s.logger.Debug("starting round", slog.Int("round", round)) + + // Annotate all long lines + lines := strings.Split(string(content), "\n") + annotatedLines, nbLinesToShorten := s.annotateLongLines(lines) + + if !s.shouldContinue(nbLinesToShorten, round, lines) { + s.logger.Debug("nothing more to shorten or reformat, stopping") + + break + } + + content = []byte(strings.Join(annotatedLines, "\n")) + + // Generate AST + result, err := decorator.Parse(content) + if err != nil { + return nil, err + } + + if s.config.DotFile != "" { + err = s.createDot(result) + if err != nil { + return nil, err + } + } + + // Process the file. + s.formatFile(result) + + // Materialize output + output := bytes.NewBuffer([]byte{}) + + err = decorator.Fprint(output, result) + if err != nil { + return nil, fmt.Errorf("error parsing source: %w", err) + } + + content = output.Bytes() + + round++ + + if round > maxRounds { + s.logger.Debug("hit max rounds, stopping") + + break + } + } + + if !s.config.KeepAnnotations { + content = removeAnnotations(content) + } + + if s.commentsShortener != nil { + content = s.commentsShortener.Process(content) + } + + // Do the final round of non-line-length-aware formatting after we've fixed up the comments + content, err = format.Source(content) + if err != nil { + return nil, fmt.Errorf("error formatting source: %w", err) + } + + return content, nil +} + +// shouldContinue returns true: +// if there are lines to shorten, +// or if this is the first round (0), +// and the option to reformat struct tags is enabled, +// and there are struct tags with multiple entries. +func (s *Shortener) shouldContinue(nbLinesToShorten, round int, lines []string) bool { + return nbLinesToShorten > 0 || + round == 0 && s.config.ReformatTags && tags.HasMultipleEntries(lines) +} + +func (s *Shortener) createDot(result dst.Node) error { + dotFile, err := os.Create(s.config.DotFile) + if err != nil { + return err + } + + defer dotFile.Close() + + s.logger.Debug("writing dot file output", slog.String("file", s.config.DotFile)) + + return graph.CreateDot(result, dotFile) +} diff --git a/vendor/github.com/golangci/misspell/.golangci.yml b/vendor/github.com/golangci/misspell/.golangci.yml index 2cfed442f..9e4446f99 100644 --- a/vendor/github.com/golangci/misspell/.golangci.yml +++ b/vendor/github.com/golangci/misspell/.golangci.yml @@ -1,107 +1,102 @@ -run: - timeout: 2m +version: "2" -linters-settings: - govet: - enable-all: true - disable: - - fieldalignment - gocyclo: - min-complexity: 16 - goconst: - min-len: 3 - min-occurrences: 3 - misspell: - locale: US - funlen: - lines: -1 - statements: 40 - gofumpt: - extra-rules: true - depguard: - rules: - main: - deny: - - pkg: "github.com/instana/testify" - desc: not allowed - - pkg: "github.com/pkg/errors" - desc: Should be replaced by standard lib errors package - godox: - keywords: - - FIXME - gocritic: - enabled-tags: - - diagnostic - - style - - performance - disabled-checks: - - sloppyReassign - - rangeValCopy - - octalLiteral - - paramTypeCombine # already handle by gofumpt.extra-rules - - exitAfterDefer # FIXME(ldez) must be fixed - - ifElseChain # FIXME(ldez) must be fixed - settings: - hugeParam: - sizeThreshold: 100 - forbidigo: - forbid: - - '^print(ln)?$' - - '^panic$' - - '^spew\.Print(f|ln)?$' - - '^spew\.Dump$' +formatters: + enable: + - gci + - gofumpt + settings: + gofumpt: + extra-rules: true linters: - enable-all: true + default: all disable: - - deadcode # deprecated - - exhaustivestruct # deprecated - - golint # deprecated - - ifshort # deprecated - - interfacer # deprecated - - maligned # deprecated - - nosnakecase # deprecated - - scopelint # deprecated - - scopelint # deprecated - - structcheck # deprecated - - varcheck # deprecated - - execinquery # not relevant (SQL) - - rowserrcheck # not relevant (SQL) - - sqlclosecheck # not relevant (SQL) - cyclop # duplicate of gocyclo - dupl + - err113 + - errcheck # FIXME(ldez) must be fixed - exhaustive - exhaustruct - forbidigo - gochecknoglobals - gochecknoinits - - goerr113 - - gomnd + - gosmopolitan + - gosec # FIXME(ldez) must be fixed - lll + - misspell + - mnd + - nakedret # FIXME(ldez) must be fixed - nilnil - nlreturn + - nonamedreturns # FIXME(ldez) must be fixed - paralleltest - prealloc + - rowserrcheck # not relevant (SQL) + - sqlclosecheck # not relevant (SQL) - testpackage - tparallel - varnamelen - wrapcheck - - wsl - - misspell - - gosec # FIXME(ldez) must be fixed - - errcheck # FIXME(ldez) must be fixed - - nonamedreturns # FIXME(ldez) must be fixed - - nakedret # FIXME(ldez) must be fixed + - wsl # deprecated + + settings: + depguard: + rules: + main: + deny: + - pkg: github.com/instana/testify + desc: not allowed + - pkg: github.com/pkg/errors + desc: Should be replaced by standard lib errors package + forbidigo: + forbid: + - pattern: ^print(ln)?$ + - pattern: ^panic$ + - pattern: ^spew\.Print(f|ln)?$ + - pattern: ^spew\.Dump$ + funlen: + lines: -1 + statements: 40 + goconst: + min-len: 3 + min-occurrences: 3 + gocritic: + disabled-checks: + - sloppyReassign + - rangeValCopy + - octalLiteral + - paramTypeCombine # already handle by gofumpt.extra-rules + - exitAfterDefer # FIXME(ldez) must be fixed + - ifElseChain # FIXME(ldez) must be fixed + enabled-tags: + - diagnostic + - style + - performance + settings: + hugeParam: + sizeThreshold: 100 + gocyclo: + min-complexity: 16 + godox: + keywords: + - FIXME + govet: + disable: + - fieldalignment + enable-all: true + misspell: + locale: US + + exclusions: + warn-unused: true + presets: + - comments + rules: + - linters: + - funlen + - goconst + path: .*_test.go issues: - exclude-use-default: false max-issues-per-linter: 0 max-same-issues: 0 - exclude: - - 'ST1000: at least one file in a package should have a package comment' - - 'package-comments: should have a package comment' - exclude-rules: - - path: .*_test.go - linters: - - funlen - - goconst diff --git a/vendor/github.com/golangci/misspell/CONTRIBUTING.md b/vendor/github.com/golangci/misspell/CONTRIBUTING.md new file mode 100644 index 000000000..1efa9fde6 --- /dev/null +++ b/vendor/github.com/golangci/misspell/CONTRIBUTING.md @@ -0,0 +1,29 @@ +# Contributing + +The files `words.go`, `works_uk.go`, and `works_us.go` must never be edited by hand. + +## Adding a word + +Misspell is neither a complete spell-checking program nor a grammar checker. +It is a tool to correct commonly misspelled English words. + +The list of words must contain only common mistakes. + +Before adding a word, you should have information about the misspelling frequency. + +- [ ] more than 15k inside GitHub (this limit is arbitrary and can involve) +- [ ] don't exist inside the [Wiktionary](https://en.wiktionary.org/wiki/) (as a modern form) +- [ ] don't exist inside the [Cambridge Dictionary](https://dictionary.cambridge.org) (as a modern form) +- [ ] don't exist inside the [Oxford Dictionary](https://www.oed.com/search/dictionary/) (as a modern form) + +If all criteria are met, a word can be added to the list of misspellings. + +The word should be added to one of the following files. + +- `internal/gen/sources/main.json`: common words. +- `internal/gen/sources/uk.json`: UK only words. +- `internal/gen/sources/us.json`: US only words. + +The target `make generate` will generate the Go files. + +The PR description must provide all the information (links) about the misspelling frequency. diff --git a/vendor/github.com/golangci/misspell/Makefile b/vendor/github.com/golangci/misspell/Makefile index fcda870ce..a5275d9fd 100644 --- a/vendor/github.com/golangci/misspell/Makefile +++ b/vendor/github.com/golangci/misspell/Makefile @@ -1,6 +1,6 @@ CONTAINER=golangci/misspell -default: lint test build +default: generate lint test build install: ## install misspell into GOPATH/bin go install ./cmd/misspell @@ -14,6 +14,9 @@ test: ## run all tests lint: ## run linter golangci-lint run +generate: + go run ./internal/gen/ + # the grep in line 2 is to remove misspellings in the spelling dictionary # that trigger false positives!! falsepositives: /scowl-wl diff --git a/vendor/github.com/golangci/misspell/README.md b/vendor/github.com/golangci/misspell/README.md index d2c3e7527..7a6abbe5f 100644 --- a/vendor/github.com/golangci/misspell/README.md +++ b/vendor/github.com/golangci/misspell/README.md @@ -1,7 +1,7 @@ [![Main](https://github.com/golangci/misspell/actions/workflows/ci.yml/badge.svg)](https://github.com/golangci/misspell/actions/workflows/ci.yml) [![Go Report Card](https://goreportcard.com/badge/github.com/golangci/misspell)](https://goreportcard.com/report/github.com/golangci/misspell) [![Go Reference](https://pkg.go.dev/badge/github.com/golangci/misspell.svg)](https://pkg.go.dev/github.com/golangci/misspell) -[![license](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://raw.golangci.com/golangci/misspell/master/LICENSE) +[![license](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://raw.golangci.com/golangci/misspell/head/LICENSE) Correct commonly misspelled English words... quickly. @@ -10,7 +10,7 @@ Correct commonly misspelled English words... quickly. If you just want a binary and to start using `misspell`: ```bash -curl -sfL https://raw.githubusercontent.com/golangci/misspell/master/install-misspell.sh | sh -s -- -b ./bin ${MISSPELL_VERSION} +curl -sfL https://raw.githubusercontent.com/golangci/misspell/head/install-misspell.sh | sh -s -- -b ./bin ${MISSPELL_VERSION} ``` Both will install as `./bin/misspell`. @@ -27,7 +27,7 @@ go install github.com/golangci/misspell/cmd/misspell@latest Also, if you like to live dangerously, one could do ```bash -curl -sfL https://raw.githubusercontent.com/golangci/misspell/master/install-misspell.sh | sh -s -- -b $(go env GOPATH)/bin ${MISSPELL_VERSION} +curl -sfL https://raw.githubusercontent.com/golangci/misspell/head/install-misspell.sh | sh -s -- -b $(go env GOPATH)/bin ${MISSPELL_VERSION} ``` ### Usage @@ -49,7 +49,7 @@ Usage of misspell: -error Exit with 2 if misspelling found -f string - 'csv', 'sqlite3' or custom Golang template for output + 'csv', 'sqlite3' or custom Go template for output -i string ignore the following corrections, comma-separated -j int @@ -89,7 +89,7 @@ To use misspell with [pre-commit](https://pre-commit.com/), add the following to * [Automatic Corrections](#correct) * [Converting UK spellings to US](#locale) * [Using pipes and stdin](#stdin) -* [Golang special support](#golang) +* [Go special support](#golang) * [CSV Output](#csv) * [Using SQLite3](#sqlite) * [Changing output format](#output) @@ -192,10 +192,10 @@ zebra ```
-### Are there special rules for golang source files? +### Are there special rules for Go source files? -yes, if you want to force a file to be checked as a golang source, use `-source=go` on the command line. -Conversely, you can check a golang source as if it were pure text by using `-source=text`. +Yes, if you want to force a file to be checked as a Go source, use `-source=go` on the command line. +Conversely, you can check a Go source as if it was pure text by using `-source=text`. You might want to do this since many variable names have misspellings in them! ### Can I check only-comments in other programming languages? @@ -207,7 +207,7 @@ It doesn't work well for Python and Bash. ### How Can I Get CSV Output? -Using `-f csv`, the output is standard comma-seprated values with headers in the first row. +Using `-f csv`, the output is standard comma-separated values with headers in the first row. ```console $ misspell -f csv * @@ -244,7 +244,7 @@ $ sqlite3 -init /tmp/misspell.sql :memory: 'select count(*) from misspell' 1 ``` -With some tricks you can directly pipe output to sqlite3 by using `-init /dev/stdin`: +With some tricks you can directly pipe output to `sqlite3` by using `-init /dev/stdin`: ``` misspell -f sqlite * | sqlite3 -init /dev/stdin -column -cmd '.width 60 15' ':memory' \ @@ -252,7 +252,7 @@ misspell -f sqlite * | sqlite3 -init /dev/stdin -column -cmd '.width 60 15' ':me ``` -### How can I ignore rules? +### How can I ignore the rules? Using the `-i "comma,separated,rules"` flag you can specify corrections to ignore. @@ -266,7 +266,7 @@ With debug mode on, you can see it print the corrections, but it will no longer ### How can I change the output format? -Using the `-f template` flag you can pass in a [golang text template](https://golang.org/pkg/text/template/) to format the output. +Using the `-f template` flag you can pass in a [Go text template](https://golang.org/pkg/text/template/) to format the output. One can use `printf "%q" VALUE` to safely quote a value. @@ -290,7 +290,7 @@ This corrects commonly misspelled English words in computer source code, and oth It is designed to run quickly, so it can be used as a [pre-commit hook](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) with minimal burden on the developer. -It does not work with binary formats (e.g. Word, etc.). +It does not work with binary formats (e.g., Word, etc.). It is not a complete spell-checking program nor a grammar checker. @@ -303,11 +303,11 @@ Some other misspelling correctors: * https://github.com/lyda/misspell-check * https://github.com/lucasdemarchi/codespell -They all work but had problems that prevented me from using them at scale: +They all work but have problems that prevented me from using them at scale: -* slow, all of the above check one misspelling at a time (i.e. linear) using regexps +* slow, all of the above check one misspelling at a time (i.e., linear) using regexps * not MIT/Apache2 licensed (or equivalent) -* have dependencies that don't work for me (python3, bash, linux sed, etc.) +* have dependencies that don't work for me (Python3, Bash, GNU sed, etc.) * don't understand American vs. British English and sometimes makes unwelcome "corrections" That said, they might be perfect for you and many have more features than this project! @@ -318,7 +318,7 @@ That said, they might be perfect for you and many have more features than this p Misspell is easily 100x to 1000x faster than other spelling correctors. You should be able to check and correct 1000 files in under 250ms. -This uses the mighty power of golang's [strings.Replacer](https://golang.org/pkg/strings/#Replacer) +This uses the mighty power of Go's [strings.Replacer](https://golang.org/pkg/strings/#Replacer) which is an implementation or variation of the [Aho–Corasick algorithm](https://en.wikipedia.org/wiki/Aho–Corasick_algorithm). This makes multiple substring matches *simultaneously*. @@ -337,7 +337,7 @@ Since it operates in parallel to make corrections, it can be non-obvious to determine exactly what word was corrected. -### It's making mistakes. How can I debug? +### It's making mistakes. How can I debug? Run using `-debug` flag on the file you want. It should then print what word it is trying to correct. @@ -345,7 +345,7 @@ Then [file a bug](https://github.com/golangci/misspell/issues) describing the pr Thanks! -### Why is it making mistakes or missing items in golang files? +### Why is it making mistakes or missing items in Go files? The matching function is *case-sensitive*, so variable names that are multiple worlds either in all-uppercase or all-lowercase case sometimes can cause false positives. @@ -358,11 +358,11 @@ You can check your code using [golint](https://github.com/golang/lint) ### What license is this? -The main code is [MIT](https://github.com/golangci/misspell/blob/master/LICENSE). +The main code is [MIT](https://github.com/golangci/misspell/blob/head/LICENSE). -Misspell also makes uses of the Golang standard library and contains a modified version of Golang's [strings.Replacer](https://golang.org/pkg/strings/#Replacer) -which is covered under a [BSD License](https://github.com/golang/go/blob/master/LICENSE). -Type `misspell -legal` for more details or see [legal.go](https://github.com/golangci/misspell/blob/master/legal.go) +Misspell also makes use of the Go standard library and contains a modified version of Go's [strings.Replacer](https://golang.org/pkg/strings/#Replacer) +which is covered under a [BSD License](https://github.com/golang/go/blob/head/LICENSE). +Type `misspell -legal` for more details or see [legal.go](https://github.com/golangci/misspell/blob/head/legal.go) ### Where do the word lists come from? @@ -371,13 +371,13 @@ It started with a word list from [Wikipedia](https://en.wikipedia.org/wiki/Wikipedia:Lists_of_common_misspellings/For_machines). Unfortunately, this list had to be highly edited as many of the words are obsolete or based on mistakes on mechanical typewriters (I'm guessing). -Additional words were added based on actually mistakes seen in the wild (meaning self-generated). +Additional words were added based on actual mistakes seen in the wild (meaning self-generated). -Variations of UK and US spellings are based on many sources including: +Variations of UK and US spellings are based on many sources, including: -* http://www.tysto.com/uk-us-spelling-list.html (with heavy editing, many are incorrect) -* http://www.oxforddictionaries.com/us/words/american-and-british-spelling-american (excellent site but incomplete) -* Diffing US and UK [scowl dictionaries](http://wordlist.aspell.net) +* [Comprehensive* list of American and British spelling differences (archive)](https://web.archive.org/web/20230326222449/http://tysto.com/uk-us-spelling-list.html) (with heavy editing, many are incorrect) +* [American and British spelling (archive)](https://web.archive.org/web/20160820231624/http://www.oxforddictionaries.com/us/words/american-and-british-spelling-american) (excellent site but incomplete) +* Diffing US and UK [SCOWL dictionaries](http://wordlist.aspell.net) American English is more accepting of spelling variations than is British English, so "what is American or not" is subject to opinion. @@ -388,14 +388,10 @@ Corrections and help welcome. Here are some ideas for enhancements: -*Capitalization of proper nouns* could be done (e.g. weekday and month names, country names, language names) - -*Opinionated US spellings* US English has a number of words with alternate spellings. +- Capitalization of proper nouns: could be done (e.g., weekday and month names, country names, language names) +- Opinionated US spellings: US English has a number of words with alternate spellings. Think [adviser vs. advisor](http://grammarist.com/spelling/adviser-advisor/). -While "advisor" is not wrong, the opinionated US locale would correct "advisor" to "adviser". - -*Versioning* Some type of versioning is needed so reporting mistakes and errors is easier. - -*Feedback* Mistakes would be sent to some server for aggregation and feedback review. - -*Contractions and Apostrophes* This would optionally correct "isnt" to "isn't", etc. +While "advisor" is not wrong, the opinionated US locale would correct "advisor" to "adviser". +- Versioning: Some type of versioning is needed, so reporting mistakes and errors is easier. +- Feedback: Mistakes would be sent to some server for aggregation and feedback review. +- Contractions and Apostrophes: This would optionally correct "isnt" to "isn't", etc. diff --git a/vendor/github.com/golangci/misspell/ascii.go b/vendor/github.com/golangci/misspell/ascii.go index d60af5a8d..acf5f5334 100644 --- a/vendor/github.com/golangci/misspell/ascii.go +++ b/vendor/github.com/golangci/misspell/ascii.go @@ -7,6 +7,7 @@ func ByteToUpper(x byte) byte { c := b - byte(0x61) d := ^(b - byte(0x7b)) e := (c & d) & (^x & 0x7f) + return x - (e >> 2) } @@ -16,6 +17,7 @@ func ByteToLower(eax byte) byte { ebx := eax&byte(0x7f) + byte(0x25) ebx = ebx&byte(0x7f) + byte(0x1a) ebx = ((ebx & ^eax) >> 2) & byte(0x20) + return eax + ebx } @@ -32,18 +34,21 @@ func StringEqualFold(s1, s2 string) bool { if len(s1) != len(s2) { return false } - for i := 0; i < len(s1); i++ { + + for i := range len(s1) { c1 := s1[i] c2 := s2[i] // c1 & c2 if c1 != c2 { c1 |= 'a' - 'A' + c2 |= 'a' - 'A' if c1 != c2 || c1 < 'a' || c1 > 'z' { return false } } } + return true } @@ -53,8 +58,10 @@ func StringHasPrefixFold(s1, s2 string) bool { if len(s1) < len(s2) { return false } + if len(s1) == len(s2) { return StringEqualFold(s1, s2) } + return StringEqualFold(s1[:len(s2)], s2) } diff --git a/vendor/github.com/golangci/misspell/case.go b/vendor/github.com/golangci/misspell/case.go index 0b580bedb..20e33a212 100644 --- a/vendor/github.com/golangci/misspell/case.go +++ b/vendor/github.com/golangci/misspell/case.go @@ -21,7 +21,7 @@ func CaseStyle(word string) WordCase { lowerCount := 0 // this iterates over RUNES not BYTES - for i := 0; i < len(word); i++ { + for i := range len(word) { ch := word[i] switch { case ch >= 'a' && ch <= 'z': @@ -39,6 +39,7 @@ func CaseStyle(word string) WordCase { case upperCount == 1 && lowerCount > 0 && word[0] >= 'A' && word[0] <= 'Z': return CaseTitle } + return CaseUnknown } diff --git a/vendor/github.com/golangci/misspell/install-misspell.sh b/vendor/github.com/golangci/misspell/install-misspell.sh index d6023e117..7d0655b2f 100644 --- a/vendor/github.com/golangci/misspell/install-misspell.sh +++ b/vendor/github.com/golangci/misspell/install-misspell.sh @@ -105,7 +105,7 @@ cat /dev/null < 50000 { var fin *os.File + fin, err = os.Open(filename) if err != nil { return "", fmt.Errorf("unable to open large file %q: %w", filename, err) } defer fin.Close() + buf := make([]byte, 512) + _, err = io.ReadFull(fin, buf) if err != nil { return "", fmt.Errorf("unable to read 512 bytes from %q: %w", filename, err) } + if !isTextFile(buf) { return "", nil } @@ -202,5 +208,6 @@ func ReadTextFile(filename string) (string, error) { if !isText && !isTextFile(raw) { return "", nil } + return string(raw), nil } diff --git a/vendor/github.com/golangci/misspell/notwords.go b/vendor/github.com/golangci/misspell/notwords.go index f694f46dc..4697dcf72 100644 --- a/vendor/github.com/golangci/misspell/notwords.go +++ b/vendor/github.com/golangci/misspell/notwords.go @@ -24,6 +24,7 @@ var ( // TODO: windows style. func RemovePath(s string) string { out := bytes.Buffer{} + var idx int for s != "" { if idx = strings.IndexByte(s, '/'); idx == -1 { @@ -36,6 +37,7 @@ func RemovePath(s string) string { } var chclass string + switch s[idx] { case '/', ' ', '\n', '\t', '\r': chclass = " \n\r\t" @@ -46,6 +48,7 @@ func RemovePath(s string) string { default: out.WriteString(s[:idx+2]) s = s[idx+2:] + continue } @@ -59,6 +62,7 @@ func RemovePath(s string) string { break } } + return out.String() } diff --git a/vendor/github.com/golangci/misspell/replace.go b/vendor/github.com/golangci/misspell/replace.go index b51dfa83b..6d88c5336 100644 --- a/vendor/github.com/golangci/misspell/replace.go +++ b/vendor/github.com/golangci/misspell/replace.go @@ -10,13 +10,6 @@ import ( "text/scanner" ) -func max(x, y int) int { - if x > y { - return x - } - return y -} - func inArray(haystack []string, needle string) bool { return slices.ContainsFunc(haystack, func(word string) bool { return strings.EqualFold(needle, word) @@ -49,6 +42,7 @@ func New() *Replacer { Replacements: DictMain, } r.Compile() + return &r } @@ -61,8 +55,10 @@ func (r *Replacer) RemoveRule(ignore []string) { if inArray(ignore, r.Replacements[i]) { continue } + newWords = append(newWords, r.Replacements[i:i+2]...) } + r.engine = nil r.Replacements = newWords } @@ -82,60 +78,8 @@ func (r *Replacer) Compile() { for i := 0; i < len(r.Replacements); i += 2 { r.corrected[r.Replacements[i]] = r.Replacements[i+1] } - r.engine = NewStringReplacer(r.Replacements...) -} - -/* -line1 and line2 are different -extract words from each line1 - -replace word -> newword -if word == new-word - - continue -if new-word in list of replacements - - continue - -new word not original, and not in list of replacements some substring got mixed up. UNdo. -*/ -func (r *Replacer) recheckLine(s string, lineNum int, buf io.Writer, next func(Diff)) { - first := 0 - redacted := RemoveNotWords(s) - - idx := wordRegexp.FindAllStringIndex(redacted, -1) - for _, ab := range idx { - word := s[ab[0]:ab[1]] - newword := r.engine.Replace(word) - if newword == word { - // no replacement done - continue - } - - // ignore camelCase words - // https://github.com/client9/misspell/issues/113 - if CaseStyle(word) == CaseUnknown { - continue - } - - if StringEqualFold(r.corrected[strings.ToLower(word)], newword) { - // word got corrected into something we know - io.WriteString(buf, s[first:ab[0]]) - io.WriteString(buf, newword) - first = ab[1] - next(Diff{ - FullLine: s, - Line: lineNum, - Original: word, - Corrected: newword, - Column: ab[0], - }) - continue - } - // Word got corrected into something unknown. Ignore it - } - io.WriteString(buf, s[first:]) + r.engine = NewStringReplacer(r.Replacements...) } // ReplaceGo is a specialized routine for correcting Golang source files. @@ -146,7 +90,9 @@ func (r *Replacer) ReplaceGo(input string) (string, []Diff) { s.Mode = scanner.ScanIdents | scanner.ScanFloats | scanner.ScanChars | scanner.ScanStrings | scanner.ScanRawStrings | scanner.ScanComments lastPos := 0 output := "" + Loop: + for { switch s.Scan() { case scanner.Comment: @@ -169,19 +115,23 @@ Loop: // no changes, no copies return input, nil } + if lastPos < len(input) { output += input[lastPos:] } + diffs := make([]Diff, 0, 8) buf := bytes.NewBuffer(make([]byte, 0, max(len(input), len(output))+100)) // faster that making a bytes.Buffer and bufio.ReadString outlines := strings.SplitAfter(output, "\n") + inlines := strings.SplitAfter(input, "\n") - for i := 0; i < len(inlines); i++ { + for i := range inlines { if inlines[i] == outlines[i] { buf.WriteString(outlines[i]) continue } + r.recheckLine(inlines[i], i+1, buf, func(d Diff) { diffs = append(diffs, d) }) @@ -196,16 +146,19 @@ func (r *Replacer) Replace(input string) (string, []Diff) { if input == output { return input, nil } + diffs := make([]Diff, 0, 8) buf := bytes.NewBuffer(make([]byte, 0, max(len(input), len(output))+100)) // faster that making a bytes.Buffer and bufio.ReadString outlines := strings.SplitAfter(output, "\n") + inlines := strings.SplitAfter(input, "\n") - for i := 0; i < len(inlines); i++ { + for i := range inlines { if inlines[i] == outlines[i] { buf.WriteString(outlines[i]) continue } + r.recheckLine(inlines[i], i+1, buf, func(d Diff) { diffs = append(diffs, d) }) @@ -222,7 +175,9 @@ func (r *Replacer) ReplaceReader(raw io.Reader, w io.Writer, next func(Diff)) er line string lineNum int ) + reader := bufio.NewReader(raw) + for err == nil { lineNum++ line, err = reader.ReadString('\n') @@ -241,5 +196,63 @@ func (r *Replacer) ReplaceReader(raw io.Reader, w io.Writer, next func(Diff)) er // but it can be inaccurate, so we need to double-check r.recheckLine(line, lineNum, w, next) } + return nil } + +/* +line1 and line2 are different +extract words from each line1 + +replace word -> newword +if word == new-word + + continue + +if new-word in list of replacements + + continue + +new word not original, and not in list of replacements some substring got mixed up. UNdo. +*/ +func (r *Replacer) recheckLine(s string, lineNum int, buf io.Writer, next func(Diff)) { + first := 0 + redacted := RemoveNotWords(s) + + idx := wordRegexp.FindAllStringIndex(redacted, -1) + for _, ab := range idx { + word := s[ab[0]:ab[1]] + + newword := r.engine.Replace(word) + if newword == word { + // no replacement done + continue + } + + // ignore camelCase words + // https://github.com/client9/misspell/issues/113 + if CaseStyle(word) == CaseUnknown { + continue + } + + if StringEqualFold(r.corrected[strings.ToLower(word)], newword) { + // word got corrected into something we know + io.WriteString(buf, s[first:ab[0]]) + io.WriteString(buf, newword) + + first = ab[1] + next(Diff{ + FullLine: s, + Line: lineNum, + Original: word, + Corrected: newword, + Column: ab[0], + }) + + continue + } + // Word got corrected into something unknown. Ignore it + } + + io.WriteString(buf, s[first:]) +} diff --git a/vendor/github.com/golangci/misspell/stringreplacer.go b/vendor/github.com/golangci/misspell/stringreplacer.go index 46cb6c4b6..b36fe6576 100644 --- a/vendor/github.com/golangci/misspell/stringreplacer.go +++ b/vendor/github.com/golangci/misspell/stringreplacer.go @@ -99,6 +99,7 @@ func (t *trieNode) add(key, val string, priority int, r *genericReplacer) { t.value = val t.priority = priority } + return } @@ -110,6 +111,7 @@ func (t *trieNode) add(key, val string, priority int, r *genericReplacer) { break } } + switch n { case len(t.prefix): t.next.add(key[n:], val, priority, r) @@ -126,12 +128,14 @@ func (t *trieNode) add(key, val string, priority int, r *genericReplacer) { next: t.next, } } + keyNode := new(trieNode) t.table = make([]*trieNode, r.tableSize) t.table[r.mapping[t.prefix[0]]] = prefixNode t.table[r.mapping[key[0]]] = keyNode t.prefix = "" t.next = nil + keyNode.add(key[1:], val, priority, r) default: // Insert new node after the common section of the prefix. @@ -143,6 +147,7 @@ func (t *trieNode) add(key, val string, priority int, r *genericReplacer) { t.next = next next.add(key[n:], val, priority, r) } + return } @@ -152,7 +157,9 @@ func (t *trieNode) add(key, val string, priority int, r *genericReplacer) { if t.table[m] == nil { t.table[m] = new(trieNode) } + t.table[m].add(key[1:], val, priority, r) + return } @@ -177,7 +184,7 @@ func makeGenericReplacer(oldnew []string) *genericReplacer { // Find each byte used, then assign them each an index. for i := 0; i < len(oldnew); i += 2 { key := strings.ToLower(oldnew[i]) - for j := 0; j < len(key); j++ { + for j := range len(key) { r.mapping[key[j]] = 1 } } @@ -187,6 +194,7 @@ func makeGenericReplacer(oldnew []string) *genericReplacer { } var index byte + for i, b := range r.mapping { if b == 0 { r.mapping[i] = byte(r.tableSize) @@ -201,55 +209,25 @@ func makeGenericReplacer(oldnew []string) *genericReplacer { for i := 0; i < len(oldnew); i += 2 { r.root.add(strings.ToLower(oldnew[i]), oldnew[i+1], len(oldnew)-i, r) } - return r -} - -func (r *genericReplacer) lookup(s string, ignoreRoot bool) (val string, keylen int, found bool) { - // Iterate down the trie to the end, and grab the value and keylen with - // the highest priority. - bestPriority := 0 - node := &r.root - n := 0 - for node != nil { - if node.priority > bestPriority && !(ignoreRoot && node == &r.root) { - bestPriority = node.priority - val = node.value - keylen = n - found = true - } - if s == "" { - break - } - if node.table != nil { - index := r.mapping[ByteToLower(s[0])] - if int(index) == r.tableSize { - break - } - node = node.table[index] - s = s[1:] - n++ - } else if node.prefix != "" && StringHasPrefixFold(s, node.prefix) { - n += len(node.prefix) - s = s[len(node.prefix):] - node = node.next - } else { - break - } - } - return + return r } func (r *genericReplacer) Replace(s string) string { buf := make(appendSliceWriter, 0, len(s)) r.WriteString(&buf, s) + return string(buf) } func (r *genericReplacer) WriteString(w io.Writer, s string) (n int, err error) { sw := getStringWriter(w) - var last, wn int - var prevMatchEmpty bool + + var ( + last, wn int + prevMatchEmpty bool + ) + for i := 0; i <= len(s); { // Fast path: s[i] is not a prefix of any pattern. if i != len(s) && r.root.priority == 0 { @@ -262,6 +240,7 @@ func (r *genericReplacer) WriteString(w io.Writer, s string) (n int, err error) // Ignore the empty match iff the previous loop found the empty match. val, keylen, match := r.lookup(s[i:], prevMatchEmpty) + prevMatchEmpty = match && keylen == 0 if match { orig := s[i : i+keylen] @@ -281,28 +260,77 @@ func (r *genericReplacer) WriteString(w io.Writer, s string) (n int, err error) val = strings.ToUpper(val[:1]) + strings.ToLower(val[1:]) } } + wn, err = sw.WriteString(s[last:i]) n += wn + if err != nil { - return + return n, err } + // debug helper: log.Printf("%d: Going to correct %q with %q", i, s[i:i+keylen], val) wn, err = sw.WriteString(val) n += wn + if err != nil { - return + return n, err } + i += keylen last = i + continue } + i++ } + if last != len(s) { wn, err = sw.WriteString(s[last:]) n += wn } - return + + return n, err +} + +func (r *genericReplacer) lookup(s string, ignoreRoot bool) (val string, keylen int, found bool) { + // Iterate down the trie to the end, and grab the value and keylen with + // the highest priority. + bestPriority := 0 + node := &r.root + n := 0 + + for node != nil { + if node.priority > bestPriority && (!ignoreRoot || node != &r.root) { + bestPriority = node.priority + val = node.value + keylen = n + found = true + } + + if s == "" { + break + } + + if node.table != nil { + index := r.mapping[ByteToLower(s[0])] + if int(index) == r.tableSize { + break + } + + node = node.table[index] + s = s[1:] + n++ + } else if node.prefix != "" && StringHasPrefixFold(s, node.prefix) { + n += len(node.prefix) + s = s[len(node.prefix):] + node = node.next + } else { + break + } + } + + return val, keylen, found } type appendSliceWriter []byte @@ -332,5 +360,6 @@ func getStringWriter(w io.Writer) io.StringWriter { if !ok { sw = stringWriter{w} } + return sw } diff --git a/vendor/github.com/golangci/misspell/words.go b/vendor/github.com/golangci/misspell/words.go index 1603d87e6..788682957 100644 --- a/vendor/github.com/golangci/misspell/words.go +++ b/vendor/github.com/golangci/misspell/words.go @@ -1,6 +1,6 @@ -package misspell +// Code generated by 'internal/gen'. DO NOT EDIT. -// Code generated automatically. DO NOT EDIT. +package misspell // DictMain is the main rule set, not including locale-specific spellings var DictMain = []string{ @@ -2554,7 +2554,7 @@ var DictMain = []string{ "acceleraptor", "accelerator", "accelorating", "accelerating", "accessibilty", "accessibility", - "accidentlaly", "accidently", + "accidentlaly", "accidentally", "accomadating", "accommodating", "accomadation", "accommodation", "accomodating", "accommodating", @@ -2580,12 +2580,12 @@ var DictMain = []string{ "acquaintaces", "acquaintances", "acquaintence", "acquaintance", "acquantaince", "acquaintance", - "acquantiance", "acquaintances", - "acquiantance", "acquaintances", + "acquantiance", "acquaintance", + "acquiantance", "acquaintance", "acquiantence", "acquaintance", "adknowledged", "acknowledged", "adknowledges", "acknowledges", - "administored", "administer", + "administored", "administered", "adminsitered", "administered", "adminstrator", "administrator", "advantagious", "advantageous", @@ -3042,6 +3042,7 @@ var DictMain = []string{ "confidentaly", "confidently", "confidentely", "confidently", "confidentiel", "confidential", + "configration", "configuration", "configuratin", "configurations", "configuraton", "configuration", "confirmacion", "confirmation", @@ -3555,7 +3556,7 @@ var DictMain = []string{ "elektrolytes", "electrolytes", "eloctrolytes", "electrolytes", "embarassment", "embarrassment", - "embarasssing", "embarassing", + "embarasssing", "embarrassing", "embarrasment", "embarrassment", "embarressing", "embarrassing", "embarrissing", "embarrassing", @@ -4031,7 +4032,7 @@ var DictMain = []string{ "intelligient", "intelligent", "intenational", "international", "intentionnal", "intentional", - "intepretator", "interpretor", + "intepretator", "interpreter", "interatellar", "interstellar", "interational", "international", "intercection", "interception", @@ -5582,14 +5583,14 @@ var DictMain = []string{ "accessibile", "accessible", "accessibily", "accessibility", "accessoires", "accessories", - "accidantely", "accidently", + "accidantely", "accidentally", "accidentaly", "accidentally", - "accidentely", "accidently", + "accidentely", "accidentally", "accidential", "accidental", - "accidentily", "accidently", - "accidentlay", "accidently", - "accidentley", "accidently", - "accidentlly", "accidently", + "accidentily", "accidentally", + "accidentlay", "accidentally", + "accidentley", "accidentally", + "accidentlly", "accidentally", "accomadated", "accommodated", "accomadates", "accommodates", "accommadate", "accommodate", @@ -5691,8 +5692,8 @@ var DictMain = []string{ "agnsoticism", "agnosticism", "agonsticism", "agnosticism", "agressively", "aggressively", - "agressivley", "agressive", - "agressivnes", "agressive", + "agressivley", "aggressive", + "agressivnes", "aggressive", "agricolture", "agriculture", "agriculteur", "agriculture", "agricultral", "agricultural", @@ -5751,7 +5752,7 @@ var DictMain = []string{ "anniversery", "anniversary", "annonymouse", "anonymous", "announceing", "announcing", - "announcemet", "announcements", + "announcemet", "announcement", "announcemnt", "announcement", "announcents", "announces", "annoymously", "anonymously", @@ -5840,9 +5841,10 @@ var DictMain = []string{ "archaoelogy", "archeology", "archeaology", "archaeology", "archimedian", "archimedean", - "architechts", "architect", + "architechts", "architects", "architectes", "architects", "architecure", "architecture", + "archtecture", "architecture", "argiculture", "agriculture", "argumentate", "argumentative", "aribtrarily", "arbitrarily", @@ -6750,17 +6752,17 @@ var DictMain = []string{ "deficiencey", "deficiency", "deficienies", "deficiencies", "deficientcy", "deficiency", - "definantley", "definately", - "definatedly", "definately", - "definateley", "definately", - "definatelly", "definately", - "definatelty", "definately", - "definatetly", "definately", + "definantley", "definitely", + "definatedly", "definitely", + "definateley", "definitely", + "definatelly", "definitely", + "definatelty", "definitely", + "definatetly", "definitely", "definations", "definitions", - "definatlely", "definately", - "definetally", "definately", - "definetlely", "definetly", - "definitaley", "definately", + "definatlely", "definitely", + "definetally", "definitely", + "definetlely", "definitely", + "definitaley", "definitely", "definitelly", "definitely", "definitevly", "definitively", "definitiely", "definitively", @@ -6769,8 +6771,8 @@ var DictMain = []string{ "definitivly", "definitively", "definitivno", "definition", "definitivos", "definitions", - "definitlely", "definitly", - "definitlety", "definitly", + "definitlely", "definitely", + "definitlety", "definitely", "deflecticon", "deflection", "degenererat", "degenerate", "degradacion", "degradation", @@ -7127,16 +7129,16 @@ var DictMain = []string{ "elimintates", "eliminates", "ellipitcals", "elliptical", "eloquentely", "eloquently", - "emabrassing", "embarassing", - "embaraasing", "embarassing", - "embarasaing", "embarassing", - "embarassign", "embarassing", - "embarassimg", "embarassing", + "emabrassing", "embarrassing", + "embaraasing", "embarrassing", + "embarasaing", "embarrassing", + "embarassign", "embarrassing", + "embarassimg", "embarrassing", "embarassing", "embarrassing", - "embarissing", "embarassing", + "embarissing", "embarrassing", "embarrasing", "embarrassing", "embarressed", "embarrassed", - "embarrssing", "embarassing", + "embarrssing", "embarrassing", "emergancies", "emergencies", "emergencias", "emergencies", "emergenices", "emergencies", @@ -10314,7 +10316,7 @@ var DictMain = []string{ "academicas", "academics", "academicos", "academics", "academicus", "academics", - "accdiently", "accidently", + "accdiently", "accidentally", "accelarate", "accelerate", "accelerade", "accelerated", "accelerare", "accelerate", @@ -10333,14 +10335,14 @@ var DictMain = []string{ "accessbile", "accessible", "accessoire", "accessories", "accessoirs", "accessories", - "accicently", "accidently", - "accidantly", "accidently", - "accidebtly", "accidently", - "accidenlty", "accidently", + "accicently", "accidentally", + "accidantly", "accidentally", + "accidebtly", "accidentally", + "accidenlty", "accidentally", "accidentes", "accidents", - "accidentky", "accidently", + "accidentky", "accidentally", "accidently", "accidentally", - "accidnetly", "accidently", + "accidnetly", "accidentally", "accomadate", "accommodate", "accomodate", "accommodate", "accompined", "accompanied", @@ -10368,8 +10370,8 @@ var DictMain = []string{ "achiavable", "achievable", "achieveble", "achievable", "achievemnt", "achievement", - "achievemts", "achieves", - "achievents", "achieves", + "achievemts", "achievements", + "achievents", "achievements", "achievment", "achievement", "achilleous", "achilles", "achiveable", "achievable", @@ -10510,6 +10512,7 @@ var DictMain = []string{ "allergisch", "allergic", "alliegance", "allegiance", "alligeance", "allegiance", + "allignment", "alignment", "alocholics", "alcoholics", "alocholism", "alcoholism", "alogrithms", "algorithms", @@ -10529,7 +10532,7 @@ var DictMain = []string{ "altruisitc", "altruistic", "altrusitic", "altruistic", "alturistic", "altruistic", - "aluminimum", "aluminum", + "aluminimum", "aluminium", "amargeddon", "armageddon", "amateurest", "amateurs", "ambassabor", "ambassador", @@ -10706,7 +10709,7 @@ var DictMain = []string{ "archictect", "architect", "architechs", "architects", "architecht", "architect", - "architecte", "architecture", + "architecte", "architect", "architexts", "architects", "architypes", "archetypes", "archtiects", "architects", @@ -11355,7 +11358,7 @@ var DictMain = []string{ "comminists", "communists", "commisison", "commissions", "commissons", "commissions", - "commiteted", "commited", + "commiteted", "committed", "commodites", "commodities", "commtiment", "commitments", "communicae", "communicated", @@ -11930,7 +11933,7 @@ var DictMain = []string{ "deducitble", "deductible", "defacation", "defamation", "defamating", "defamation", - "defanitely", "definately", + "defanitely", "definitely", "defelction", "deflection", "defendeers", "defender", "defendents", "defendants", @@ -11938,56 +11941,56 @@ var DictMain = []string{ "defenesman", "defenseman", "defenselss", "defenseless", "defensivly", "defensively", - "defianetly", "definately", - "defiantely", "definately", - "defiantley", "definately", - "defibately", "definately", - "deficately", "definately", + "defianetly", "definitely", + "defiantely", "definitely", + "defiantley", "definitely", + "defibately", "definitely", + "deficately", "definitely", "deficiancy", "deficiency", "deficience", "deficiencies", "deficienct", "deficient", "deficienty", "deficiency", - "defiintely", "definately", - "definaetly", "definately", - "definaitly", "definately", - "definaltey", "definately", - "definataly", "definately", - "definateky", "definately", + "defiintely", "definitely", + "definaetly", "definitely", + "definaitly", "definitely", + "definaltey", "definitely", + "definataly", "definitely", + "definateky", "definitely", "definately", "definitely", - "definatily", "definately", + "definatily", "definitely", "defination", "definition", "definative", "definitive", - "definatlly", "definately", - "definatrly", "definately", - "definayely", "definately", - "defineatly", "definately", - "definetaly", "definately", + "definatlly", "definitely", + "definatrly", "definitely", + "definayely", "definitely", + "defineatly", "definitely", + "definetaly", "definitely", "definetely", "definitely", - "definetily", "definately", - "definetlly", "definetly", - "definettly", "definately", + "definetily", "definitely", + "definetlly", "definitely", + "definettly", "definitely", "definicion", "definition", "definietly", "definitely", "definining", "defining", - "definitaly", "definately", - "definiteyl", "definitly", + "definitaly", "definitely", + "definiteyl", "definitely", "definitivo", "definition", "definitley", "definitely", - "definitlly", "definitly", - "definitlry", "definitly", - "definitlty", "definitly", - "definjtely", "definately", - "definltely", "definately", - "definotely", "definately", - "definstely", "definately", - "defintaley", "definately", + "definitlly", "definitely", + "definitlry", "definitely", + "definitlty", "definitely", + "definjtely", "definitely", + "definltely", "definitely", + "definotely", "definitely", + "definstely", "definitely", + "defintaley", "definitely", "defintiely", "definitely", "defintiion", "definitions", - "definutely", "definately", + "definutely", "definitely", "deflaction", "deflection", "defleciton", "deflection", "deflektion", "deflection", - "defniately", "definately", + "defniately", "definitely", "degenarate", "degenerate", "degenerare", "degenerate", "degenerite", "degenerate", @@ -11995,7 +11998,7 @@ var DictMain = []string{ "degraderad", "degraded", "dehydraded", "dehydrated", "dehyrdated", "dehydrated", - "deifnately", "definately", + "deifnately", "definitely", "deisgnated", "designated", "delaership", "dealership", "delearship", "dealership", @@ -12451,7 +12454,7 @@ var DictMain = []string{ "eloquintly", "eloquently", "emapthetic", "empathetic", "embarassed", "embarrassed", - "embarassig", "embarassing", + "embarassig", "embarrassing", "embarrased", "embarrassed", "embarrases", "embarrassed", "embezelled", "embezzled", @@ -12967,7 +12970,7 @@ var DictMain = []string{ "goosepumps", "goosebumps", "gothenberg", "gothenburg", "govenrment", "government", - "govermenet", "goverment", + "govermenet", "government", "govermnent", "governments", "governemnt", "government", "governened", "governed", @@ -13274,6 +13277,7 @@ var DictMain = []string{ "impliciete", "implicit", "implicilty", "implicitly", "impliments", "implements", + "implmented", "implemented", "imporbable", "improbable", "importanly", "importantly", "importanty", "importantly", @@ -13314,7 +13318,7 @@ var DictMain = []string{ "inadiquate", "inadequate", "inagurated", "inaugurated", "inbalanced", "imbalanced", - "inbetweeen", "inbetween", + "inbetweeen", "between", "incarnaton", "incarnation", "incentivos", "incentives", "inchoerent", "incoherent", @@ -15644,7 +15648,7 @@ var DictMain = []string{ "seperation", "separation", "seperatism", "separatism", "seperatist", "separatist", - "seperatley", "seperate", + "seperatley", "separate", "sepulchure", "sepulchre", "serenitary", "serenity", "serviceble", "serviceable", @@ -16691,7 +16695,7 @@ var DictMain = []string{ "accelerar", "accelerator", "accending", "ascending", "accension", "accession", - "accidenty", "accidently", + "accidenty", "accidentally", "acclamied", "acclaimed", "accliamed", "acclaimed", "accomdate", "accommodate", @@ -16771,10 +16775,10 @@ var DictMain = []string{ "agrentina", "argentina", "agression", "aggression", "agressive", "aggressive", - "agressvie", "agressive", - "agruement", "arguement", + "agressvie", "aggressive", + "agruement", "argument", "agruments", "arguments", - "agurement", "arguement", + "agurement", "argument", "ailenated", "alienated", "airbourne", "airborne", "aircrafts", "aircraft", @@ -16902,7 +16906,7 @@ var DictMain = []string{ "appetitie", "appetite", "applaudes", "applause", "applicato", "application", - "appreciae", "appreciates", + "appreciae", "appreciate", "apprentie", "apprentice", "approachs", "approaches", "apratheid", "apartheid", @@ -16917,16 +16921,16 @@ var DictMain = []string{ "archetyps", "archetypes", "architecs", "architects", "archtypes", "archetypes", - "aregument", "arguement", + "aregument", "argument", "areospace", "aerospace", - "argessive", "agressive", - "argeument", "arguement", + "argessive", "aggressive", + "argeument", "argument", "arguabley", "arguably", "arguablly", "arguably", "arguement", "argument", - "arguemnet", "arguement", + "arguemnet", "argument", "arguemnts", "arguments", - "argumeent", "arguement", + "argumeent", "argument", "arhtritis", "arthritis", "aribtrary", "arbitrary", "ariplanes", "airplanes", @@ -16942,7 +16946,7 @@ var DictMain = []string{ "artifcats", "artifacts", "artifical", "artificial", "artillary", "artillery", - "arugement", "arguement", + "arugement", "argument", "arugments", "arguments", "asapragus", "asparagus", "asbestoes", "asbestos", @@ -17367,7 +17371,7 @@ var DictMain = []string{ "commentes", "commenters", "commercie", "commerce", "commision", "commission", - "commiteed", "commited", + "commiteed", "committed", "commiting", "committing", "commitmet", "commitments", "commments", "comments", @@ -17610,7 +17614,7 @@ var DictMain = []string{ "defaintly", "defiantly", "defaltion", "deflation", "defanitly", "defiantly", - "defeintly", "definetly", + "defeintly", "definitely", "defendent", "defendant", "defensese", "defenseless", "defianlty", "defiantly", @@ -17618,35 +17622,35 @@ var DictMain = []string{ "deficieny", "deficiency", "deficites", "deficits", "definance", "defiance", - "definatey", "definately", + "definatey", "definitely", "definatly", "definitely", "definetly", "definitely", - "definetyl", "definetly", - "definilty", "definitly", + "definetyl", "definitely", + "definilty", "definitely", "definitie", "definitive", "definitin", "definitions", "definitly", "definitely", "definiton", "definition", "definitve", "definite", - "definityl", "definitly", - "definltey", "definetly", + "definityl", "definitely", + "definltey", "definitely", "defintaly", "defiantly", - "defintily", "definitly", + "defintily", "definitely", "defintion", "definition", - "defintley", "definetly", - "defitenly", "definetly", - "defitinly", "definitly", + "defintley", "definitely", + "defitenly", "definitely", + "defitinly", "definitely", "defitnaly", "defiantly", - "defitnely", "definetly", + "defitnely", "definitely", "deflectin", "deflection", - "defnietly", "definetly", + "defnietly", "definitely", "degeneret", "degenerate", "degradato", "degradation", "degradead", "degraded", "degrassie", "degrasse", "degrassse", "degrasse", - "deifnetly", "definetly", - "deifnitly", "definitly", + "deifnetly", "definitely", + "deifnitly", "definitely", "deisgners", "designers", "delagates", "delegates", "delcaring", "declaring", @@ -17734,7 +17738,7 @@ var DictMain = []string{ "dicovered", "discovered", "dictaters", "dictates", "dictionay", "dictionary", - "difenitly", "definitly", + "difenitly", "definitely", "diferrent", "different", "differene", "differences", "differens", "differences", @@ -18034,7 +18038,7 @@ var DictMain = []string{ "existance", "existence", "existenta", "existential", "existince", "existence", - "existnace", "existance", + "existnace", "existence", "exlcuding", "excluding", "exlcusion", "exclusion", "exlcusive", "exclusive", @@ -18066,7 +18070,7 @@ var DictMain = []string{ "expolsive", "explosive", "expressie", "expressive", "expressin", "expression", - "exsitance", "existance", + "exsitance", "existence", "extention", "extension", "exteriour", "exterior", "extermely", "extremely", @@ -18226,17 +18230,17 @@ var DictMain = []string{ "goegraphy", "geography", "goldfisch", "goldfish", "goosebums", "goosebumps", - "gorvement", "goverment", - "govemrent", "goverment", + "gorvement", "government", + "govemrent", "government", "govenment", "government", "goverance", "governance", - "goveremnt", "goverment", + "goveremnt", "government", "goverment", "government", - "govermetn", "goverment", - "govermnet", "goverment", + "govermetn", "government", + "govermnet", "government", "governmet", "governments", "govorment", "government", - "govrement", "goverment", + "govrement", "government", "gracefull", "graceful", "gracefuly", "gracefully", "graduaste", "graduates", @@ -18422,9 +18426,9 @@ var DictMain = []string{ "inadquate", "inadequate", "inaugures", "inaugurates", "inbalance", "imbalance", - "inbeetwen", "inbetween", + "inbeetwen", "between", "inbetween", "between", - "inbewteen", "inbetween", + "inbewteen", "between", "incarnato", "incarnation", "incgonito", "incognito", "inclinato", "inclination", @@ -18958,14 +18962,14 @@ var DictMain = []string{ "nostlagic", "nostalgic", "nostriles", "nostrils", "nostrills", "nostrils", - "notacible", "noticable", - "notciable", "noticable", + "notacible", "noticeable", + "notciable", "noticeable", "noteboook", "notebook", "noteriety", "notoriety", "noteworty", "noteworthy", "noticable", "noticeable", "noticably", "noticeably", - "noticalbe", "noticable", + "noticalbe", "noticeable", "noticeing", "noticing", "noticible", "noticeable", "notoroius", "notorious", @@ -19559,6 +19563,7 @@ var DictMain = []string{ "redundany", "redundancy", "redundent", "redundant", "reedeming", "redeeming", + "refection", "reflection", "refelcted", "reflected", "refereces", "references", "refereees", "referees", @@ -19567,7 +19572,7 @@ var DictMain = []string{ "referencs", "references", "referense", "references", "referiang", "referring", - "referinng", "refering", + "referinng", "referring", "refernces", "references", "refernece", "reference", "refershed", "refreshed", @@ -19637,6 +19642,7 @@ var DictMain = []string{ "repulican", "republican", "repulisve", "repulsive", "repuslive", "repulsive", + "requiered", "required", "resaurant", "restaurant", "researchs", "researchers", "resembels", "resembles", @@ -19813,7 +19819,7 @@ var DictMain = []string{ "signapore", "singapore", "signitory", "signatory", "silhouete", "silhouette", - "similiair", "similiar", + "similiair", "similar", "simliarly", "similarly", "simluated", "simulated", "simluator", "simulator", @@ -20448,7 +20454,7 @@ var DictMain = []string{ "acccused", "accused", "acceptes", "accepts", "accidens", "accidents", - "accideny", "accidently", + "accideny", "accidentally", "accoring", "according", "accountt", "accountant", "accpeted", "accepted", @@ -20480,13 +20486,13 @@ var DictMain = []string{ "activits", "activities", "activley", "actively", "actresss", "actresses", - "actualey", "actualy", + "actualey", "actually", "actualiy", "actuality", - "actualky", "actualy", - "actualmy", "actualy", - "actualoy", "actualy", - "actualpy", "actualy", - "actualty", "actualy", + "actualky", "actually", + "actualmy", "actually", + "actualoy", "actually", + "actualpy", "actually", + "actualty", "actually", "acutally", "actually", "acutions", "auctions", "adaptare", "adapter", @@ -20542,7 +20548,7 @@ var DictMain = []string{ "agravate", "aggravate", "agreemnt", "agreement", "agregate", "aggregate", - "agressie", "agressive", + "agressie", "aggressive", "agressor", "aggressor", "agrieved", "aggrieved", "agruable", "arguable", @@ -20591,11 +20597,11 @@ var DictMain = []string{ "altrusim", "altruism", "alturism", "altruism", "aluminim", "aluminium", - "alumnium", "aluminum", - "alunimum", "aluminum", + "alumnium", "aluminium", + "alunimum", "aluminium", "amatersu", "amateurs", "amaterus", "amateurs", - "amendmet", "amendments", + "amendmet", "amendment", "amercian", "american", "amercias", "americas", "amernian", "armenian", @@ -20666,7 +20672,7 @@ var DictMain = []string{ "anythign", "anything", "anytying", "anything", "aparment", "apartment", - "apartmet", "apartments", + "apartmet", "apartment", "apenines", "apennines", "aperutre", "aperture", "aplhabet", "alphabet", @@ -20700,8 +20706,8 @@ var DictMain = []string{ "aremnian", "armenian", "argentia", "argentina", "argubaly", "arguably", - "arguemet", "arguement", - "arguemtn", "arguement", + "arguemet", "argument", + "arguemtn", "argument", "ariborne", "airborne", "aricraft", "aircraft", "ariplane", "airplane", @@ -20770,7 +20776,7 @@ var DictMain = []string{ "athenean", "athenian", "athesits", "atheists", "athetlic", "athletic", - "athients", "athiest", + "athients", "atheist", "atittude", "attitude", "atlantia", "atlanta", "atmoizer", "atomizer", @@ -20854,9 +20860,9 @@ var DictMain = []string{ "barrakcs", "barracks", "barrells", "barrels", "basicaly", "basically", - "basiclay", "basicly", - "basicley", "basicly", - "basicliy", "basicly", + "basiclay", "basically", + "basicley", "basically", + "basicliy", "basically", "batistia", "batista", "battalin", "battalion", "bayonent", "bayonet", @@ -20866,7 +20872,7 @@ var DictMain = []string{ "beastley", "beastly", "beatiful", "beautiful", "beccause", "because", - "becuasse", "becuase", + "becuasse", "because", "befirend", "befriend", "befreind", "befriend", "begginer", "beginner", @@ -21349,6 +21355,7 @@ var DictMain = []string{ "containg", "containing", "contaire", "containers", "contanti", "contacting", + "contants", "constants", "contense", "contenders", "contenst", "contents", "contexta", "contextual", @@ -21510,8 +21517,8 @@ var DictMain = []string{ "deffined", "defined", "deficiet", "deficient", "definate", "definite", - "definaty", "definately", - "definety", "definetly", + "definaty", "definitely", + "definety", "definitely", "definito", "definition", "definitv", "definitive", "deflatin", "deflation", @@ -21828,7 +21835,7 @@ var DictMain = []string{ "esctatic", "ecstatic", "esential", "essential", "esitmate", "estimate", - "esperate", "seperate", + "esperate", "separate", "esportes", "esports", "estiamte", "estimate", "estoeric", "esoteric", @@ -21881,7 +21888,7 @@ var DictMain = []string{ "exhausto", "exhaustion", "exicting", "exciting", "exisitng", "existing", - "existane", "existance", + "existane", "existence", "existant", "existent", "existend", "existed", "exlcuded", "excluded", @@ -22071,6 +22078,7 @@ var DictMain = []string{ "franlkin", "franklin", "freckels", "freckles", "freindly", "friendly", + "freqency", "frequency", "frequeny", "frequency", "friendle", "friendlies", "friendsi", "friendlies", @@ -22081,6 +22089,7 @@ var DictMain = []string{ "froniter", "frontier", "fronteir", "frontier", "frosaken", "forsaken", + "frquency", "frequency", "frutcose", "fructose", "fucntion", "function", "fufilled", "fulfilled", @@ -22183,7 +22192,7 @@ var DictMain = []string{ "gouvener", "governor", "govement", "government", "goverend", "governed", - "govermet", "goverment", + "govermet", "government", "governer", "governor", "gradualy", "gradually", "grafield", "garfield", @@ -22395,7 +22404,7 @@ var DictMain = []string{ "impusles", "impulses", "imrpoved", "improved", "imrpoves", "improves", - "inbetwen", "inbetween", + "inbetwen", "between", "inclince", "incline", "inclinde", "incline", "includng", "including", @@ -22499,6 +22508,7 @@ var DictMain = []string{ "internus", "interns", "interpet", "interpret", "interrim", "interim", + "interrut", "interrupt", "interste", "interstate", "interupt", "interrupt", "intevene", "intervene", @@ -23033,7 +23043,7 @@ var DictMain = []string{ "notablly", "notably", "noteable", "notable", "noteably", "notably", - "noticabe", "noticable", + "noticabe", "noticeable", "notorios", "notorious", "novmeber", "november", "nromandy", "normandy", @@ -23596,7 +23606,7 @@ var DictMain = []string{ "referene", "referee", "referens", "references", "referere", "referee", - "referign", "refering", + "referign", "referring", "refering", "referring", "refernce", "references", "reffered", "referred", @@ -23605,7 +23615,7 @@ var DictMain = []string{ "reflecte", "reflective", "reflecto", "reflection", "reformes", "reforms", - "refreing", "refering", + "refreing", "referring", "refrence", "reference", "refreshd", "refreshed", "refreshr", "refresher", @@ -23632,7 +23642,7 @@ var DictMain = []string{ "regulats", "regulators", "rehersal", "rehearsal", "rehtoric", "rhetoric", - "reiceved", "recieved", + "reiceved", "received", "reigment", "regiment", "reigonal", "regional", "rekenton", "renekton", @@ -23884,11 +23894,11 @@ var DictMain = []string{ "sentires", "sentries", "sentreis", "sentries", "separato", "separation", - "separete", "seperate", - "sepearte", "seperate", + "separete", "separate", + "sepearte", "separate", "seperate", "separate", "seplling", "spelling", - "sepreate", "seperate", + "sepreate", "separate", "sepulcre", "sepulchre", "serached", "searched", "seraches", "searches", @@ -23951,15 +23961,15 @@ var DictMain = []string{ "silbings", "siblings", "silicoln", "silicon", "silicoon", "silicon", - "silimiar", "similiar", - "simialir", "similiar", - "simiilar", "similiar", + "silimiar", "similar", + "simialir", "similar", + "simiilar", "similar", "similair", "similar", - "similari", "similiar", + "similari", "similar", "similart", "similarity", "similary", "similarly", "similiar", "similar", - "simliiar", "similiar", + "simliiar", "similar", "simluate", "simulate", "simmilar", "similar", "simpelst", "simplest", @@ -24227,13 +24237,13 @@ var DictMain = []string{ "superham", "superhuman", "superheo", "superhero", "superios", "superiors", - "supirsed", "suprised", + "supirsed", "surprised", "suposing", "supposing", "supporre", "supporters", "suppoted", "supported", "suprised", "surprised", "suprized", "surprised", - "suprsied", "suprised", + "suprsied", "surprised", "supsects", "suspects", "supsense", "suspense", "surbuban", "suburban", @@ -24730,15 +24740,15 @@ var DictMain = []string{ "acident", "accident", "ackward", "awkward", "acrlyic", "acrylic", - "actauly", "actualy", + "actauly", "actually", "activit", "activist", "activly", "actively", "actualy", "actually", - "actulay", "actualy", + "actulay", "actually", "acuracy", "accuracy", "acusing", "causing", "acustom", "accustom", - "acutaly", "actualy", + "acutaly", "actually", "acyrlic", "acrylic", "adaptes", "adapters", "adatper", "adapter", @@ -24772,7 +24782,7 @@ var DictMain = []string{ "agianst", "against", "agreing", "agreeing", "agruing", "arguing", - "ahtiest", "athiest", + "ahtiest", "atheist", "aicraft", "aircraft", "ailmony", "alimony", "airbore", "airborne", @@ -24909,12 +24919,12 @@ var DictMain = []string{ "assualt", "assault", "asterik", "asterisk", "asutria", "austria", - "atcualy", "actualy", + "atcualy", "actually", "atelast", "atleast", "athesim", "atheism", "athiesm", "atheism", "athiest", "atheist", - "athiets", "athiest", + "athiets", "atheist", "athlets", "athletes", "atlantc", "atlantic", "atleats", "atleast", @@ -24938,7 +24948,7 @@ var DictMain = []string{ "backsta", "backseat", "baclony", "balcony", "badnits", "bandits", - "baiscly", "basicly", + "baiscly", "basically", "bakcers", "backers", "balanse", "balances", "balcked", "blacked", @@ -24956,9 +24966,9 @@ var DictMain = []string{ "barrles", "barrels", "barsita", "barista", "barvery", "bravery", - "bascily", "basicly", + "bascily", "basically", "basicly", "basically", - "basilcy", "basicly", + "basilcy", "basically", "basiton", "bastion", "basnhee", "banshee", "bastane", "bastante", @@ -24970,7 +24980,7 @@ var DictMain = []string{ "bayblon", "babylon", "baynoet", "bayonet", "bayoent", "bayonet", - "bceuase", "becuase", + "bceuase", "because", "beacuse", "because", "bealtes", "beatles", "beaslty", "beastly", @@ -24980,9 +24990,9 @@ var DictMain = []string{ "becames", "becomes", "becasue", "because", "becouse", "because", - "becuaes", "becuase", + "becuaes", "because", "becuase", "because", - "becusae", "becuase", + "becusae", "because", "befried", "befriend", "beggins", "begins", "beglian", "belgian", @@ -25012,7 +25022,7 @@ var DictMain = []string{ "betales", "beatles", "bethesa", "bethesda", "betrayd", "betrayed", - "beucase", "becuase", + "beucase", "because", "bewteen", "between", "bicthes", "bitches", "bidrman", "birdman", @@ -25277,7 +25287,7 @@ var DictMain = []string{ "commans", "commands", "commere", "commerce", "comming", "coming", - "commitd", "commited", + "commitd", "committed", "compase", "compares", "compede", "competed", "compilr", "compiler", @@ -25550,7 +25560,7 @@ var DictMain = []string{ "earliet", "earliest", "earplus", "earplugs", "eastwod", "eastwood", - "ebcuase", "becuase", + "ebcuase", "because", "ecilpse", "eclipse", "eclipes", "eclipse", "eclispe", "eclipse", @@ -26659,7 +26669,7 @@ var DictMain = []string{ "receips", "receipts", "recided", "resided", "reciept", "receipt", - "recievd", "recieved", + "recievd", "received", "recieve", "receive", "recitfy", "rectify", "recived", "received", @@ -26673,7 +26683,7 @@ var DictMain = []string{ "refelct", "reflect", "referal", "referral", "refered", "referred", - "referig", "refering", + "referig", "referring", "referrs", "refers", "reflexs", "reflexes", "refrers", "refers", @@ -26741,6 +26751,7 @@ var DictMain = []string{ "requeim", "requiem", "requime", "requiem", "requred", "required", + "requrie", "require", "resapwn", "respawn", "rescuse", "rescues", "resembe", "resemble", @@ -26913,7 +26924,7 @@ var DictMain = []string{ "signles", "singles", "silders", "sliders", "silenty", "silently", - "similir", "similiar", + "similir", "similar", "simliar", "similar", "simplet", "simplest", "simpley", "simply", @@ -27069,7 +27080,7 @@ var DictMain = []string{ "succesd", "succeeds", "suceeds", "succeeds", "suddeny", "suddenly", - "suefull", "usefull", + "suefull", "useful", "sufferd", "suffered", "summonr", "summoner", "summore", "summoner", @@ -27082,7 +27093,7 @@ var DictMain = []string{ "suppost", "supports", "suprass", "surpass", "supress", "suppress", - "suprisd", "suprised", + "suprisd", "surprised", "suprise", "surprise", "suprize", "surprise", "supsend", "suspend", @@ -27246,7 +27257,7 @@ var DictMain = []string{ "tyrhard", "tryhard", "tyrrany", "tyranny", "udpated", "updated", - "uesfull", "usefull", + "uesfull", "useful", "ugprade", "upgrade", "ukarine", "ukraine", "ukranie", "ukraine", @@ -27458,6 +27469,7 @@ var DictMain = []string{ "aplied", "applied", "appart", "apart", "aquire", "acquire", + "arcive", "archive", "aready", "already", "arised", "arose", "arival", "arrival", @@ -28017,6 +28029,7 @@ var DictMain = []string{ "noth", "north", "nowe", "now", "omre", "more", + "onlu", "only", "onot", "note", "onyl", "only", "owrk", "work", @@ -28088,3107 +28101,3 @@ var DictMain = []string{ "wih", "with", "yuo", "you", } - -// DictAmerican converts UK spellings to US spellings -var DictAmerican = []string{ - "institutionalisation", "institutionalization", - "internationalisation", "internationalization", - "professionalisation", "professionalization", - "compartmentalising", "compartmentalizing", - "institutionalising", "institutionalizing", - "internationalising", "internationalizing", - "compartmentalised", "compartmentalized", - "compartmentalises", "compartmentalizes", - "decriminalisation", "decriminalization", - "denationalisation", "denationalization", - "fictionalisations", "fictionalizations", - "institutionalised", "institutionalized", - "institutionalises", "institutionalizes", - "intellectualising", "intellectualizing", - "internationalised", "internationalized", - "internationalises", "internationalizes", - "pedestrianisation", "pedestrianization", - "professionalising", "professionalizing", - "archaeologically", "archeologically", - "compartmentalise", "compartmentalize", - "decentralisation", "decentralization", - "demilitarisation", "demilitarization", - "externalisations", "externalizations", - "fictionalisation", "fictionalization", - "institutionalise", "institutionalize", - "intellectualised", "intellectualized", - "intellectualises", "intellectualizes", - "internationalise", "internationalize", - "nationalisations", "nationalizations", - "palaeontologists", "paleontologists", - "professionalised", "professionalized", - "professionalises", "professionalizes", - "rationalisations", "rationalizations", - "sensationalising", "sensationalizing", - "sentimentalising", "sentimentalizing", - "acclimatisation", "acclimatization", - "bougainvillaeas", "bougainvilleas", - "commercialising", "commercializing", - "conceptualising", "conceptualizing", - "contextualising", "contextualizing", - "crystallisation", "crystallization", - "decriminalising", "decriminalizing", - "democratisation", "democratization", - "denationalising", "denationalizing", - "depersonalising", "depersonalizing", - "desensitisation", "desensitization", - "destabilisation", "destabilization", - "disorganisation", "disorganization", - "extemporisation", "extemporization", - "externalisation", "externalization", - "familiarisation", "familiarization", - "generalisations", "generalizations", - "hospitalisation", "hospitalization", - "individualising", "individualizing", - "industrialising", "industrializing", - "intellectualise", "intellectualize", - "internalisation", "internalization", - "manoeuvrability", "maneuverability", - "marginalisation", "marginalization", - "materialisation", "materialization", - "miniaturisation", "miniaturization", - "nationalisation", "nationalization", - "neighbourliness", "neighborliness", - "overemphasising", "overemphasizing", - "palaeontologist", "paleontologist", - "particularising", "particularizing", - "pedestrianising", "pedestrianizing", - "professionalise", "professionalize", - "psychoanalysing", "psychoanalyzing", - "rationalisation", "rationalization", - "reorganisations", "reorganizations", - "revolutionising", "revolutionizing", - "sensationalised", "sensationalized", - "sensationalises", "sensationalizes", - "sentimentalised", "sentimentalized", - "sentimentalises", "sentimentalizes", - "specialisations", "specializations", - "standardisation", "standardization", - "synchronisation", "synchronization", - "systematisation", "systematization", - "aggrandisement", "aggrandizement", - "anaesthetising", "anesthetizing", - "archaeological", "archeological", - "archaeologists", "archeologists", - "bougainvillaea", "bougainvillea", - "characterising", "characterizing", - "collectivising", "collectivizing", - "commercialised", "commercialized", - "commercialises", "commercializes", - "conceptualised", "conceptualized", - "conceptualises", "conceptualizes", - "contextualised", "contextualized", - "contextualises", "contextualizes", - "decentralising", "decentralizing", - "decriminalised", "decriminalized", - "decriminalises", "decriminalizes", - "dehumanisation", "dehumanization", - "demilitarising", "demilitarizing", - "demobilisation", "demobilization", - "demoralisation", "demoralization", - "denationalised", "denationalized", - "denationalises", "denationalizes", - "depersonalised", "depersonalized", - "depersonalises", "depersonalizes", - "disembowelling", "disemboweling", - "dramatisations", "dramatizations", - "editorialising", "editorializing", - "encyclopaedias", "encyclopedias", - "fictionalising", "fictionalizing", - "fraternisation", "fraternization", - "generalisation", "generalization", - "gynaecological", "gynecological", - "gynaecologists", "gynecologists", - "haematological", "hematological", - "haematologists", "hematologists", - "immobilisation", "immobilization", - "individualised", "individualized", - "individualises", "individualizes", - "industrialised", "industrialized", - "industrialises", "industrializes", - "liberalisation", "liberalization", - "monopolisation", "monopolization", - "naturalisation", "naturalization", - "neighbourhoods", "neighborhoods", - "neutralisation", "neutralization", - "organisational", "organizational", - "outmanoeuvring", "outmaneuvering", - "overemphasised", "overemphasized", - "overemphasises", "overemphasizes", - "paediatricians", "pediatricians", - "particularised", "particularized", - "particularises", "particularizes", - "pasteurisation", "pasteurization", - "pedestrianised", "pedestrianized", - "pedestrianises", "pedestrianizes", - "philosophising", "philosophizing", - "politicisation", "politicization", - "popularisation", "popularization", - "pressurisation", "pressurization", - "prioritisation", "prioritization", - "privatisations", "privatizations", - "propagandising", "propagandizing", - "psychoanalysed", "psychoanalyzed", - "psychoanalyses", "psychoanalyzes", - "regularisation", "regularization", - "reorganisation", "reorganization", - "revolutionised", "revolutionized", - "revolutionises", "revolutionizes", - "secularisation", "secularization", - "sensationalise", "sensationalize", - "sentimentalise", "sentimentalize", - "serialisations", "serializations", - "specialisation", "specialization", - "sterilisations", "sterilizations", - "stigmatisation", "stigmatization", - "transistorised", "transistorized", - "unrecognisable", "unrecognizable", - "visualisations", "visualizations", - "westernisation", "westernization", - "accessorising", "accessorizing", - "acclimatising", "acclimatizing", - "amortisations", "amortizations", - "amphitheatres", "amphitheaters", - "anaesthetised", "anesthetized", - "anaesthetises", "anesthetizes", - "anaesthetists", "anesthetists", - "archaeologist", "archeologist", - "backpedalling", "backpedaling", - "behaviourists", "behaviorists", - "breathalysers", "breathalyzers", - "breathalysing", "breathalyzing", - "callisthenics", "calisthenics", - "cannibalising", "cannibalizing", - "characterised", "characterized", - "characterises", "characterizes", - "circularising", "circularizing", - "clarinettists", "clarinetists", - "collectivised", "collectivized", - "collectivises", "collectivizes", - "commercialise", "commercialize", - "computerising", "computerizing", - "conceptualise", "conceptualize", - "contextualise", "contextualize", - "criminalising", "criminalizing", - "crystallising", "crystallizing", - "decentralised", "decentralized", - "decentralises", "decentralizes", - "decriminalise", "decriminalize", - "demilitarised", "demilitarized", - "demilitarises", "demilitarizes", - "democratising", "democratizing", - "denationalise", "denationalize", - "depersonalise", "depersonalize", - "desensitising", "desensitizing", - "destabilising", "destabilizing", - "disembowelled", "disemboweled", - "dishonourable", "dishonorable", - "dishonourably", "dishonorably", - "dramatisation", "dramatization", - "editorialised", "editorialized", - "editorialises", "editorializes", - "encyclopaedia", "encyclopedia", - "encyclopaedic", "encyclopedic", - "extemporising", "extemporizing", - "externalising", "externalizing", - "familiarising", "familiarizing", - "fertilisation", "fertilization", - "fictionalised", "fictionalized", - "fictionalises", "fictionalizes", - "formalisation", "formalization", - "fossilisation", "fossilization", - "globalisation", "globalization", - "gynaecologist", "gynecologist", - "haematologist", "hematologist", - "haemophiliacs", "hemophiliacs", - "haemorrhaging", "hemorrhaging", - "harmonisation", "harmonization", - "hospitalising", "hospitalizing", - "hypothesising", "hypothesizing", - "immortalising", "immortalizing", - "individualise", "individualize", - "industrialise", "industrialize", - "internalising", "internalizing", - "marginalising", "marginalizing", - "materialising", "materializing", - "mechanisation", "mechanization", - "memorialising", "memorializing", - "miniaturising", "miniaturizing", - "miscatalogued", "miscataloged", - "misdemeanours", "misdemeanors", - "multicoloured", "multicolored", - "nationalising", "nationalizing", - "neighbourhood", "neighborhood", - "normalisation", "normalization", - "organisations", "organizations", - "outmanoeuvred", "outmaneuvered", - "outmanoeuvres", "outmaneuvers", - "overemphasise", "overemphasize", - "paediatrician", "pediatrician", - "palaeontology", "paleontology", - "particularise", "particularize", - "passivisation", "passivization", - "patronisingly", "patronizingly", - "pedestrianise", "pedestrianize", - "personalising", "personalizing", - "philosophised", "philosophized", - "philosophises", "philosophizes", - "privatisation", "privatization", - "propagandised", "propagandized", - "propagandises", "propagandizes", - "proselytisers", "proselytizers", - "proselytising", "proselytizing", - "psychoanalyse", "psychoanalyze", - "pulverisation", "pulverization", - "rationalising", "rationalizing", - "reconnoitring", "reconnoitering", - "revolutionise", "revolutionize", - "romanticising", "romanticizing", - "serialisation", "serialization", - "socialisation", "socialization", - "stabilisation", "stabilization", - "standardising", "standardizing", - "sterilisation", "sterilization", - "subsidisation", "subsidization", - "synchronising", "synchronizing", - "systematising", "systematizing", - "tantalisingly", "tantalizingly", - "underutilised", "underutilized", - "victimisation", "victimization", - "visualisation", "visualization", - "vocalisations", "vocalizations", - "vulgarisation", "vulgarization", - "accessorised", "accessorized", - "accessorises", "accessorizes", - "acclimatised", "acclimatized", - "acclimatises", "acclimatizes", - "amortisation", "amortization", - "amphitheatre", "amphitheater", - "anaesthetics", "anesthetics", - "anaesthetise", "anesthetize", - "anaesthetist", "anesthetist", - "antagonising", "antagonizing", - "appetisingly", "appetizingly", - "backpedalled", "backpedaled", - "bastardising", "bastardizing", - "behaviourism", "behaviorism", - "behaviourist", "behaviorist", - "bowdlerising", "bowdlerizing", - "breathalysed", "breathalyzed", - "breathalyser", "breathalyzer", - "breathalyses", "breathalyzes", - "cannibalised", "cannibalized", - "cannibalises", "cannibalizes", - "capitalising", "capitalizing", - "caramelising", "caramelizing", - "categorising", "categorizing", - "centigrammes", "centigrams", - "centralising", "centralizing", - "centrepieces", "centerpieces", - "characterise", "characterize", - "circularised", "circularized", - "circularises", "circularizes", - "clarinettist", "clarinetist", - "collectivise", "collectivize", - "colonisation", "colonization", - "computerised", "computerized", - "computerises", "computerizes", - "criminalised", "criminalized", - "criminalises", "criminalizes", - "crystallised", "crystallized", - "crystallises", "crystallizes", - "decentralise", "decentralize", - "dehumanising", "dehumanizing", - "demilitarise", "demilitarize", - "demobilising", "demobilizing", - "democratised", "democratized", - "democratises", "democratizes", - "demoralising", "demoralizing", - "desensitised", "desensitized", - "desensitises", "desensitizes", - "destabilised", "destabilized", - "destabilises", "destabilizes", - "discolouring", "discoloring", - "dishonouring", "dishonoring", - "disorganised", "disorganized", - "editorialise", "editorialize", - "endeavouring", "endeavoring", - "equalisation", "equalization", - "evangelising", "evangelizing", - "extemporised", "extemporized", - "extemporises", "extemporizes", - "externalised", "externalized", - "externalises", "externalizes", - "familiarised", "familiarized", - "familiarises", "familiarizes", - "fictionalise", "fictionalize", - "finalisation", "finalization", - "fraternising", "fraternizing", - "generalising", "generalizing", - "haemophiliac", "hemophiliac", - "haemorrhaged", "hemorrhaged", - "haemorrhages", "hemorrhages", - "haemorrhoids", "hemorrhoids", - "homoeopathic", "homeopathic", - "homogenising", "homogenizing", - "hospitalised", "hospitalized", - "hospitalises", "hospitalizes", - "hypothesised", "hypothesized", - "hypothesises", "hypothesizes", - "idealisation", "idealization", - "immobilisers", "immobilizers", - "immobilising", "immobilizing", - "immortalised", "immortalized", - "immortalises", "immortalizes", - "immunisation", "immunization", - "initialising", "initializing", - "internalised", "internalized", - "internalises", "internalizes", - "jeopardising", "jeopardizing", - "legalisation", "legalization", - "legitimising", "legitimizing", - "liberalising", "liberalizing", - "manoeuvrable", "maneuverable", - "manoeuvrings", "maneuverings", - "marginalised", "marginalized", - "marginalises", "marginalizes", - "marvellously", "marvelously", - "materialised", "materialized", - "materialises", "materializes", - "maximisation", "maximization", - "memorialised", "memorialized", - "memorialises", "memorializes", - "metabolising", "metabolizing", - "militarising", "militarizing", - "milligrammes", "milligrams", - "miniaturised", "miniaturized", - "miniaturises", "miniaturizes", - "misbehaviour", "misbehavior", - "misdemeanour", "misdemeanor", - "mobilisation", "mobilization", - "moisturisers", "moisturizers", - "moisturising", "moisturizing", - "monopolising", "monopolizing", - "moustachioed", "mustachioed", - "nationalised", "nationalized", - "nationalises", "nationalizes", - "naturalising", "naturalizing", - "neighbouring", "neighboring", - "neutralising", "neutralizing", - "oesophaguses", "esophaguses", - "organisation", "organization", - "orthopaedics", "orthopedics", - "outmanoeuvre", "outmaneuver", - "palaeolithic", "paleolithic", - "pasteurising", "pasteurizing", - "personalised", "personalized", - "personalises", "personalizes", - "philosophise", "philosophize", - "plagiarising", "plagiarizing", - "ploughshares", "plowshares", - "polarisation", "polarization", - "politicising", "politicizing", - "popularising", "popularizing", - "pressurising", "pressurizing", - "prioritising", "prioritizing", - "propagandise", "propagandize", - "proselytised", "proselytized", - "proselytiser", "proselytizer", - "proselytises", "proselytizes", - "radicalising", "radicalizing", - "rationalised", "rationalized", - "rationalises", "rationalizes", - "realisations", "realizations", - "recognisable", "recognizable", - "recognisably", "recognizably", - "recognisance", "recognizance", - "reconnoitred", "reconnoitered", - "reconnoitres", "reconnoiters", - "regularising", "regularizing", - "reorganising", "reorganizing", - "revitalising", "revitalizing", - "rhapsodising", "rhapsodizing", - "romanticised", "romanticized", - "romanticises", "romanticizes", - "scandalising", "scandalizing", - "scrutinising", "scrutinizing", - "secularising", "secularizing", - "specialising", "specializing", - "squirrelling", "squirreling", - "standardised", "standardized", - "standardises", "standardizes", - "stigmatising", "stigmatizing", - "sympathisers", "sympathizers", - "sympathising", "sympathizing", - "synchronised", "synchronized", - "synchronises", "synchronizes", - "synthesisers", "synthesizers", - "synthesising", "synthesizing", - "systematised", "systematized", - "systematises", "systematizes", - "technicolour", "technicolor", - "theatregoers", "theatergoers", - "traumatising", "traumatizing", - "trivialising", "trivializing", - "unauthorised", "unauthorized", - "uncatalogued", "uncataloged", - "unfavourable", "unfavorable", - "unfavourably", "unfavorably", - "unionisation", "unionization", - "unrecognised", "unrecognized", - "untrammelled", "untrammeled", - "urbanisation", "urbanization", - "vaporisation", "vaporization", - "vocalisation", "vocalization", - "watercolours", "watercolors", - "westernising", "westernizing", - "accessorise", "accessorize", - "acclimatise", "acclimatize", - "agonisingly", "agonizingly", - "amortisable", "amortizable", - "anaesthesia", "anesthesia", - "anaesthetic", "anesthetic", - "anglicising", "anglicizing", - "antagonised", "antagonized", - "antagonises", "antagonizes", - "apologising", "apologizing", - "archaeology", "archeology", - "authorising", "authorizing", - "bastardised", "bastardized", - "bastardises", "bastardizes", - "bedevilling", "bedeviling", - "behavioural", "behavioral", - "belabouring", "belaboring", - "bowdlerised", "bowdlerized", - "bowdlerises", "bowdlerizes", - "breathalyse", "breathalyze", - "brutalising", "brutalizing", - "cannibalise", "cannibalize", - "capitalised", "capitalized", - "capitalises", "capitalizes", - "caramelised", "caramelized", - "caramelises", "caramelizes", - "carbonising", "carbonizing", - "cataloguing", "cataloging", - "categorised", "categorized", - "categorises", "categorizes", - "cauterising", "cauterizing", - "centigramme", "centigram", - "centilitres", "centiliters", - "centimetres", "centimeters", - "centralised", "centralized", - "centralises", "centralizes", - "centrefolds", "centerfolds", - "centrepiece", "centerpiece", - "channelling", "channeling", - "chequebooks", "checkbooks", - "circularise", "circularize", - "colourfully", "colorfully", - "colourizing", "colorizing", - "computerise", "computerize", - "councillors", "councilors", - "counselling", "counseling", - "counsellors", "counselors", - "criminalise", "criminalize", - "criticising", "criticizing", - "crystallise", "crystallize", - "customising", "customizing", - "defenceless", "defenseless", - "dehumanised", "dehumanized", - "dehumanises", "dehumanizes", - "demobilised", "demobilized", - "demobilises", "demobilizes", - "democratise", "democratize", - "demoralised", "demoralized", - "demoralises", "demoralizes", - "deodorising", "deodorizing", - "desensitise", "desensitize", - "destabilise", "destabilize", - "discoloured", "discolored", - "dishevelled", "disheveled", - "dishonoured", "dishonored", - "dramatising", "dramatizing", - "economising", "economizing", - "empathising", "empathizing", - "emphasising", "emphasizing", - "endeavoured", "endeavored", - "epitomising", "epitomizing", - "evangelised", "evangelized", - "evangelises", "evangelizes", - "extemporise", "extemporize", - "externalise", "externalize", - "factorising", "factorizing", - "familiarise", "familiarize", - "fantasising", "fantasizing", - "favouritism", "favoritism", - "fertilisers", "fertilizers", - "fertilising", "fertilizing", - "flavourings", "flavorings", - "flavourless", "flavorless", - "flavoursome", "flavorsome", - "formalising", "formalizing", - "fossilising", "fossilizing", - "fraternised", "fraternized", - "fraternises", "fraternizes", - "galvanising", "galvanizing", - "generalised", "generalized", - "generalises", "generalizes", - "ghettoising", "ghettoizing", - "globalising", "globalizing", - "gruellingly", "gruelingly", - "gynaecology", "gynecology", - "haematology", "hematology", - "haemoglobin", "hemoglobin", - "haemophilia", "hemophilia", - "haemorrhage", "hemorrhage", - "harmonising", "harmonizing", - "homoeopaths", "homeopaths", - "homoeopathy", "homeopathy", - "homogenised", "homogenized", - "homogenises", "homogenizes", - "hospitalise", "hospitalize", - "hybridising", "hybridizing", - "hypnotising", "hypnotizing", - "hypothesise", "hypothesize", - "immobilised", "immobilized", - "immobiliser", "immobilizer", - "immobilises", "immobilizes", - "immortalise", "immortalize", - "impanelling", "impaneling", - "imperilling", "imperiling", - "initialised", "initialized", - "initialises", "initializes", - "initialling", "initialing", - "instalments", "installments", - "internalise", "internalize", - "italicising", "italicizing", - "jeopardised", "jeopardized", - "jeopardises", "jeopardizes", - "kilogrammes", "kilograms", - "legitimised", "legitimized", - "legitimises", "legitimizes", - "liberalised", "liberalized", - "liberalises", "liberalizes", - "lionisation", "lionization", - "liquidisers", "liquidizers", - "liquidising", "liquidizing", - "magnetising", "magnetizing", - "manoeuvring", "maneuvering", - "marginalise", "marginalize", - "marshalling", "marshaling", - "materialise", "materialize", - "mechanising", "mechanizing", - "memorialise", "memorialize", - "mesmerising", "mesmerizing", - "metabolised", "metabolized", - "metabolises", "metabolizes", - "micrometres", "micrometers", - "militarised", "militarized", - "militarises", "militarizes", - "milligramme", "milligram", - "millilitres", "milliliters", - "millimetres", "millimeters", - "miniaturise", "miniaturize", - "modernising", "modernizing", - "moisturised", "moisturized", - "moisturiser", "moisturizer", - "moisturises", "moisturizes", - "monopolised", "monopolized", - "monopolises", "monopolizes", - "nationalise", "nationalize", - "naturalised", "naturalized", - "naturalises", "naturalizes", - "neighbourly", "neighborly", - "neutralised", "neutralized", - "neutralises", "neutralizes", - "normalising", "normalizing", - "orthopaedic", "orthopedic", - "ostracising", "ostracizing", - "oxidisation", "oxidization", - "paediatrics", "pediatrics", - "paedophiles", "pedophiles", - "paedophilia", "pedophilia", - "passivising", "passivizing", - "pasteurised", "pasteurized", - "pasteurises", "pasteurizes", - "patronising", "patronizing", - "personalise", "personalize", - "plagiarised", "plagiarized", - "plagiarises", "plagiarizes", - "ploughshare", "plowshare", - "politicised", "politicized", - "politicises", "politicizes", - "popularised", "popularized", - "popularises", "popularizes", - "praesidiums", "presidiums", - "pressurised", "pressurized", - "pressurises", "pressurizes", - "prioritised", "prioritized", - "prioritises", "prioritizes", - "privatising", "privatizing", - "proselytise", "proselytize", - "publicising", "publicizing", - "pulverising", "pulverizing", - "quarrelling", "quarreling", - "radicalised", "radicalized", - "radicalises", "radicalizes", - "randomising", "randomizing", - "rationalise", "rationalize", - "realisation", "realization", - "recognising", "recognizing", - "reconnoitre", "reconnoiter", - "regularised", "regularized", - "regularises", "regularizes", - "remodelling", "remodeling", - "reorganised", "reorganized", - "reorganises", "reorganizes", - "revitalised", "revitalized", - "revitalises", "revitalizes", - "rhapsodised", "rhapsodized", - "rhapsodises", "rhapsodizes", - "romanticise", "romanticize", - "scandalised", "scandalized", - "scandalises", "scandalizes", - "sceptically", "skeptically", - "scrutinised", "scrutinized", - "scrutinises", "scrutinizes", - "secularised", "secularized", - "secularises", "secularizes", - "sensitising", "sensitizing", - "serialising", "serializing", - "sermonising", "sermonizing", - "shrivelling", "shriveling", - "signalising", "signalizing", - "snorkelling", "snorkeling", - "snowploughs", "snowplow", - "socialising", "socializing", - "solemnising", "solemnizing", - "specialised", "specialized", - "specialises", "specializes", - "squirrelled", "squirreled", - "stabilisers", "stabilizers", - "stabilising", "stabilizing", - "standardise", "standardize", - "stencilling", "stenciling", - "sterilisers", "sterilizers", - "sterilising", "sterilizing", - "stigmatised", "stigmatized", - "stigmatises", "stigmatizes", - "subsidisers", "subsidizers", - "subsidising", "subsidizing", - "summarising", "summarizing", - "symbolising", "symbolizing", - "sympathised", "sympathized", - "sympathiser", "sympathizer", - "sympathises", "sympathizes", - "synchronise", "synchronize", - "synthesised", "synthesized", - "synthesiser", "synthesizer", - "synthesises", "synthesizes", - "systematise", "systematize", - "tantalising", "tantalizing", - "temporising", "temporizing", - "tenderising", "tenderizing", - "terrorising", "terrorizing", - "theatregoer", "theatergoer", - "traumatised", "traumatized", - "traumatises", "traumatizes", - "trivialised", "trivialized", - "trivialises", "trivializes", - "tyrannising", "tyrannizing", - "uncivilised", "uncivilized", - "unorganised", "unorganized", - "unravelling", "unraveling", - "utilisation", "utilization", - "vandalising", "vandalizing", - "verbalising", "verbalizing", - "victimising", "victimizing", - "visualising", "visualizing", - "vulgarising", "vulgarizing", - "watercolour", "watercolor", - "westernised", "westernized", - "westernises", "westernizes", - "worshipping", "worshiping", - "aeroplanes", "airplanes", - "amortising", "amortizing", - "anglicised", "anglicized", - "anglicises", "anglicizes", - "annualised", "annualized", - "antagonise", "antagonize", - "apologised", "apologized", - "apologises", "apologizes", - "appetisers", "appetizers", - "appetising", "appetizing", - "authorised", "authorized", - "authorises", "authorizes", - "bannisters", "banisters", - "bastardise", "bastardize", - "bedevilled", "bedeviled", - "behaviours", "behaviors", - "bejewelled", "bejeweled", - "belaboured", "belabored", - "bowdlerise", "bowdlerize", - "brutalised", "brutalized", - "brutalises", "brutalizes", - "canalising", "canalizing", - "cancelling", "canceling", - "canonising", "canonizing", - "capitalise", "capitalize", - "caramelise", "caramelize", - "carbonised", "carbonized", - "carbonises", "carbonizes", - "catalogued", "cataloged", - "catalogues", "catalogs", - "catalysing", "catalyzing", - "categorise", "categorize", - "cauterised", "cauterized", - "cauterises", "cauterizes", - "centilitre", "centiliter", - "centimetre", "centimeter", - "centralise", "centralize", - "centrefold", "centerfold", - "channelled", "channeled", - "chequebook", "checkbook", - "chiselling", "chiseling", - "civilising", "civilizing", - "clamouring", "clamoring", - "colonisers", "colonizers", - "colonising", "colonizing", - "colourants", "colorants", - "colourized", "colorized", - "colourizes", "colorizes", - "colourless", "colorless", - "connexions", "connections", - "councillor", "councilor", - "counselled", "counseled", - "counsellor", "counselor", - "criticised", "criticized", - "criticises", "criticizes", - "cudgelling", "cudgeling", - "customised", "customized", - "customises", "customizes", - "dehumanise", "dehumanize", - "demobilise", "demobilize", - "demonising", "demonizing", - "demoralise", "demoralize", - "deodorised", "deodorized", - "deodorises", "deodorizes", - "deputising", "deputizing", - "digitising", "digitizing", - "discolours", "discolors", - "dishonours", "dishonors", - "dramatised", "dramatized", - "dramatises", "dramatizes", - "drivelling", "driveling", - "economised", "economized", - "economises", "economizes", - "empathised", "empathized", - "empathises", "empathizes", - "emphasised", "emphasized", - "emphasises", "emphasizes", - "enamelling", "enameling", - "endeavours", "endeavors", - "energising", "energizing", - "epaulettes", "epaulets", - "epicentres", "epicenters", - "epitomised", "epitomized", - "epitomises", "epitomizes", - "equalisers", "equalizers", - "equalising", "equalizing", - "eulogising", "eulogizing", - "evangelise", "evangelize", - "factorised", "factorized", - "factorises", "factorizes", - "fantasised", "fantasized", - "fantasises", "fantasizes", - "favourable", "favorable", - "favourably", "favorably", - "favourites", "favorites", - "feminising", "feminizing", - "fertilised", "fertilized", - "fertiliser", "fertilizer", - "fertilises", "fertilizes", - "fibreglass", "fiberglass", - "finalising", "finalizing", - "flavouring", "flavoring", - "formalised", "formalized", - "formalises", "formalizes", - "fossilised", "fossilized", - "fossilises", "fossilizes", - "fraternise", "fraternize", - "fulfilment", "fulfillment", - "funnelling", "funneling", - "galvanised", "galvanized", - "galvanises", "galvanizes", - "gambolling", "gamboling", - "gaolbreaks", "jailbreaks", - "generalise", "generalize", - "ghettoised", "ghettoized", - "ghettoises", "ghettoizes", - "globalised", "globalized", - "globalises", "globalizes", - "gonorrhoea", "gonorrhea", - "grovelling", "groveling", - "harbouring", "harboring", - "harmonised", "harmonized", - "harmonises", "harmonizes", - "homoeopath", "homeopath", - "homogenise", "homogenize", - "honourable", "honorable", - "honourably", "honorably", - "humanising", "humanizing", - "humourless", "humorless", - "hybridised", "hybridized", - "hybridises", "hybridizes", - "hypnotised", "hypnotized", - "hypnotises", "hypnotizes", - "idealising", "idealizing", - "immobilise", "immobilize", - "immunising", "immunizing", - "impanelled", "impaneled", - "imperilled", "imperiled", - "inflexions", "inflections", - "initialise", "initialize", - "initialled", "initialed", - "instalment", "installment", - "ionisation", "ionization", - "italicised", "italicized", - "italicises", "italicizes", - "jeopardise", "jeopardize", - "kilogramme", "kilogram", - "kilometres", "kilometers", - "lacklustre", "lackluster", - "legalising", "legalizing", - "legitimise", "legitimize", - "liberalise", "liberalize", - "liquidised", "liquidized", - "liquidiser", "liquidizer", - "liquidises", "liquidizes", - "localising", "localizing", - "magnetised", "magnetized", - "magnetises", "magnetizes", - "manoeuvred", "maneuvered", - "manoeuvres", "maneuvers", - "marshalled", "marshaled", - "marvelling", "marveling", - "marvellous", "marvelous", - "maximising", "maximizing", - "mechanised", "mechanized", - "mechanises", "mechanizes", - "memorising", "memorizing", - "mesmerised", "mesmerized", - "mesmerises", "mesmerizes", - "metabolise", "metabolize", - "micrometre", "micrometer", - "militarise", "militarize", - "millilitre", "milliliter", - "millimetre", "millimeter", - "minimising", "minimizing", - "mobilising", "mobilizing", - "modernised", "modernized", - "modernises", "modernizes", - "moisturise", "moisturize", - "monopolise", "monopolize", - "moralising", "moralizing", - "mouldering", "moldering", - "moustached", "mustached", - "moustaches", "mustaches", - "naturalise", "naturalize", - "neighbours", "neighbors", - "neutralise", "neutralize", - "normalised", "normalized", - "normalises", "normalizes", - "oesophagus", "esophagus", - "optimising", "optimizing", - "organisers", "organizers", - "organising", "organizing", - "ostracised", "ostracized", - "ostracises", "ostracizes", - "paederasts", "pederasts", - "paediatric", "pediatric", - "paedophile", "pedophile", - "panellists", "panelists", - "paralysing", "paralyzing", - "parcelling", "parceling", - "passivised", "passivized", - "passivises", "passivizes", - "pasteurise", "pasteurize", - "patronised", "patronized", - "patronises", "patronizes", - "penalising", "penalizing", - "pencilling", "penciling", - "plagiarise", "plagiarize", - "polarising", "polarizing", - "politicise", "politicize", - "popularise", "popularize", - "practising", "practicing", - "praesidium", "presidium", - "pressurise", "pressurize", - "prioritise", "prioritize", - "privatised", "privatized", - "privatises", "privatizes", - "programmes", "programs", - "publicised", "publicized", - "publicises", "publicizes", - "pulverised", "pulverized", - "pulverises", "pulverizes", - "pummelling", "pummeled", - "quarrelled", "quarreled", - "radicalise", "radicalize", - "randomised", "randomized", - "randomises", "randomizes", - "realisable", "realizable", - "recognised", "recognized", - "recognises", "recognizes", - "refuelling", "refueling", - "regularise", "regularize", - "remodelled", "remodeled", - "remoulding", "remolding", - "reorganise", "reorganize", - "revitalise", "revitalize", - "rhapsodise", "rhapsodize", - "ritualised", "ritualized", - "sanitising", "sanitizing", - "satirising", "satirizing", - "scandalise", "scandalize", - "scepticism", "skepticism", - "scrutinise", "scrutinize", - "secularise", "secularize", - "sensitised", "sensitized", - "sensitises", "sensitizes", - "sepulchres", "sepulchers", - "serialised", "serialized", - "serialises", "serializes", - "sermonised", "sermonized", - "sermonises", "sermonizes", - "shovelling", "shoveling", - "shrivelled", "shriveled", - "signalised", "signalized", - "signalises", "signalizes", - "signalling", "signaling", - "snivelling", "sniveling", - "snorkelled", "snorkeled", - "snowplough", "snowplow", - "socialised", "socialized", - "socialises", "socializes", - "sodomising", "sodomizing", - "solemnised", "solemnized", - "solemnises", "solemnizes", - "specialise", "specialize", - "spiralling", "spiraling", - "splendours", "splendors", - "stabilised", "stabilized", - "stabiliser", "stabilizer", - "stabilises", "stabilizes", - "stencilled", "stenciled", - "sterilised", "sterilized", - "steriliser", "sterilizer", - "sterilises", "sterilizes", - "stigmatise", "stigmatize", - "subsidised", "subsidized", - "subsidiser", "subsidizer", - "subsidises", "subsidizes", - "succouring", "succoring", - "sulphurous", "sulfurous", - "summarised", "summarized", - "summarises", "summarizes", - "swivelling", "swiveling", - "symbolised", "symbolized", - "symbolises", "symbolizes", - "sympathise", "sympathize", - "synthesise", "synthesize", - "tantalised", "tantalized", - "tantalises", "tantalizes", - "temporised", "temporized", - "temporises", "temporizes", - "tenderised", "tenderized", - "tenderises", "tenderizes", - "terrorised", "terrorized", - "terrorises", "terrorizes", - "theorising", "theorizing", - "traumatise", "traumatize", - "travellers", "travelers", - "travelling", "traveling", - "tricolours", "tricolors", - "trivialise", "trivialize", - "tunnelling", "tunneling", - "tyrannised", "tyrannized", - "tyrannises", "tyrannizes", - "unequalled", "unequaled", - "unionising", "unionizing", - "unravelled", "unraveled", - "unrivalled", "unrivaled", - "urbanising", "urbanizing", - "utilisable", "utilizable", - "vandalised", "vandalized", - "vandalises", "vandalizes", - "vaporising", "vaporizing", - "verbalised", "verbalized", - "verbalises", "verbalizes", - "victimised", "victimized", - "victimises", "victimizes", - "visualised", "visualized", - "visualises", "visualizes", - "vocalising", "vocalizing", - "vulcanised", "vulcanized", - "vulgarised", "vulgarized", - "vulgarises", "vulgarizes", - "weaselling", "weaseling", - "westernise", "westernize", - "womanisers", "womanizers", - "womanising", "womanizing", - "worshipped", "worshiped", - "worshipper", "worshiper", - "aeroplane", "airplane", - "aetiology", "etiology", - "agonising", "agonizing", - "almanacks", "almanacs", - "aluminium", "aluminum", - "amortised", "amortized", - "amortises", "amortizes", - "analogues", "analogs", - "analysing", "analyzing", - "anglicise", "anglicize", - "apologise", "apologize", - "appetiser", "appetizer", - "armourers", "armorers", - "armouries", "armories", - "artefacts", "artifacts", - "authorise", "authorize", - "baptising", "baptizing", - "behaviour", "behavior", - "belabours", "belabors", - "brutalise", "brutalize", - "callipers", "calipers", - "canalised", "canalized", - "canalises", "canalizes", - "cancelled", "canceled", - "canonised", "canonized", - "canonises", "canonizes", - "carbonise", "carbonize", - "carolling", "caroling", - "catalogue", "catalog", - "catalysed", "catalyzed", - "catalyses", "catalyzes", - "cauterise", "cauterize", - "cavilling", "caviling", - "chequered", "checkered", - "chiselled", "chiseled", - "civilised", "civilized", - "civilises", "civilizes", - "clamoured", "clamored", - "colonised", "colonized", - "coloniser", "colonizer", - "colonises", "colonizes", - "colourant", "colorant", - "coloureds", "coloreds", - "colourful", "colorful", - "colouring", "coloring", - "colourize", "colorize", - "connexion", "connection", - "criticise", "criticize", - "cruellest", "cruelest", - "cudgelled", "cudgeled", - "customise", "customize", - "demeanour", "demeanor", - "demonised", "demonized", - "demonises", "demonizes", - "deodorise", "deodorize", - "deputised", "deputized", - "deputises", "deputizes", - "dialogues", "dialogs", - "diarrhoea", "diarrhea", - "digitised", "digitized", - "digitises", "digitizes", - "discolour", "discolor", - "disfavour", "disfavor", - "dishonour", "dishonor", - "dramatise", "dramatize", - "drivelled", "driveled", - "economise", "economize", - "empathise", "empathize", - "emphasise", "emphasize", - "enamelled", "enameled", - "enamoured", "enamored", - "endeavour", "endeavor", - "energised", "energized", - "energises", "energizes", - "epaulette", "epaulet", - "epicentre", "epicenter", - "epitomise", "epitomize", - "equalised", "equalized", - "equaliser", "equalizer", - "equalises", "equalizes", - "eulogised", "eulogized", - "eulogises", "eulogizes", - "factorise", "factorize", - "fantasise", "fantasize", - "favouring", "favoring", - "favourite", "favorite", - "feminised", "feminized", - "feminises", "feminizes", - "fertilise", "fertilize", - "finalised", "finalized", - "finalises", "finalizes", - "flautists", "flutists", - "flavoured", "flavored", - "formalise", "formalize", - "fossilise", "fossilize", - "funnelled", "funneled", - "galvanise", "galvanize", - "gambolled", "gamboled", - "gaolbirds", "jailbirds", - "gaolbreak", "jailbreak", - "ghettoise", "ghettoize", - "globalise", "globalize", - "gravelled", "graveled", - "grovelled", "groveled", - "gruelling", "grueling", - "harboured", "harbored", - "harmonise", "harmonize", - "honouring", "honoring", - "humanised", "humanized", - "humanises", "humanizes", - "humouring", "humoring", - "hybridise", "hybridize", - "hypnotise", "hypnotize", - "idealised", "idealized", - "idealises", "idealizes", - "idolising", "idolizing", - "immunised", "immunized", - "immunises", "immunizes", - "inflexion", "inflection", - "italicise", "italicize", - "itemising", "itemizing", - "jewellers", "jewelers", - "jewellery", "jewelry", - "kilometre", "kilometer", - "labelling", "labeling", - "labourers", "laborers", - "labouring", "laboring", - "legalised", "legalized", - "legalises", "legalizes", - "leukaemia", "leukemia", - "levellers", "levelers", - "levelling", "leveling", - "libelling", "libeling", - "libellous", "libelous", - "licencing", "licensing", - "lionising", "lionizing", - "liquidise", "liquidize", - "localised", "localized", - "localises", "localizes", - "magnetise", "magnetize", - "manoeuvre", "maneuver", - "marvelled", "marveled", - "maximised", "maximized", - "maximises", "maximizes", - "mechanise", "mechanize", - "mediaeval", "medieval", - "memorised", "memorized", - "memorises", "memorizes", - "mesmerise", "mesmerize", - "minimised", "minimized", - "minimises", "minimizes", - "mobilised", "mobilized", - "mobilises", "mobilizes", - "modellers", "modelers", - "modelling", "modeling", - "modernise", "modernize", - "moralised", "moralized", - "moralises", "moralizes", - "motorised", "motorized", - "mouldered", "moldered", - "mouldiest", "moldiest", - "mouldings", "moldings", - "moustache", "mustache", - "neighbour", "neighbor", - "normalise", "normalize", - "odourless", "odorless", - "oestrogen", "estrogen", - "optimised", "optimized", - "optimises", "optimizes", - "organised", "organized", - "organiser", "organizer", - "organises", "organizes", - "ostracise", "ostracize", - "oxidising", "oxidizing", - "paederast", "pederast", - "panelling", "paneling", - "panellist", "panelist", - "paralysed", "paralyzed", - "paralyses", "paralyzes", - "parcelled", "parceled", - "passivise", "passivize", - "patronise", "patronize", - "pedalling", "pedaling", - "penalised", "penalized", - "penalises", "penalizes", - "pencilled", "penciled", - "ploughing", "plowing", - "ploughman", "plowman", - "ploughmen", "plowmen", - "polarised", "polarized", - "polarises", "polarizes", - "practised", "practiced", - "practises", "practices", - "pretences", "pretenses", - "primaeval", "primeval", - "privatise", "privatize", - "programme", "program", - "publicise", "publicize", - "pulverise", "pulverize", - "pummelled", "pummel", - "randomise", "randomize", - "ravelling", "raveling", - "realising", "realizing", - "recognise", "recognize", - "refuelled", "refueled", - "remoulded", "remolded", - "revellers", "revelers", - "revelling", "reveling", - "rivalling", "rivaling", - "saltpetre", "saltpeter", - "sanitised", "sanitized", - "sanitises", "sanitizes", - "satirised", "satirized", - "satirises", "satirizes", - "savouries", "savories", - "savouring", "savoring", - "sceptical", "skeptical", - "sensitise", "sensitize", - "sepulchre", "sepulcher", - "serialise", "serialize", - "sermonise", "sermonize", - "shovelled", "shoveled", - "signalise", "signalize", - "signalled", "signaled", - "snivelled", "sniveled", - "socialise", "socialize", - "sodomised", "sodomized", - "sodomises", "sodomizes", - "solemnise", "solemnize", - "spiralled", "spiraled", - "splendour", "splendor", - "stabilise", "stabilize", - "sterilise", "sterilize", - "subsidise", "subsidize", - "succoured", "succored", - "sulphates", "sulfates", - "sulphides", "sulfides", - "summarise", "summarize", - "swivelled", "swiveled", - "symbolise", "symbolize", - "syphoning", "siphoning", - "tantalise", "tantalize", - "tasselled", "tasseled", - "temporise", "temporize", - "tenderise", "tenderize", - "terrorise", "terrorize", - "theorised", "theorized", - "theorises", "theorizes", - "towelling", "toweling", - "travelled", "traveled", - "traveller", "traveler", - "trialling", "trialing", - "tricolour", "tricolor", - "tunnelled", "tunneled", - "tyrannise", "tyrannize", - "unionised", "unionized", - "unionises", "unionizes", - "unsavoury", "unsavory", - "urbanised", "urbanized", - "urbanises", "urbanizes", - "utilising", "utilizing", - "vandalise", "vandalize", - "vaporised", "vaporized", - "vaporises", "vaporizes", - "verbalise", "verbalize", - "victimise", "victimize", - "visualise", "visualize", - "vocalised", "vocalized", - "vocalises", "vocalizes", - "vulgarise", "vulgarize", - "weaselled", "weaseled", - "womanised", "womanized", - "womaniser", "womanizer", - "womanises", "womanizes", - "yodelling", "yodeling", - "yoghourts", "yogurts", - "agonised", "agonized", - "agonises", "agonizes", - "almanack", "almanac", - "amortise", "amortize", - "analogue", "analog", - "analysed", "analyzed", - "analyses", "analyzes", - "armoured", "armored", - "armourer", "armorer", - "artefact", "artifact", - "baptised", "baptized", - "baptises", "baptizes", - "baulking", "balking", - "belabour", "belabor", - "bevelled", "beveled", - "calibres", "calibers", - "calliper", "caliper", - "canalise", "canalize", - "canonise", "canonize", - "carolled", "caroled", - "catalyse", "catalyze", - "cavilled", "caviled", - "civilise", "civilize", - "clamours", "clamors", - "clangour", "clangor", - "colonise", "colonize", - "coloured", "colored", - "cosiness", "coziness", - "crueller", "crueler", - "defences", "defenses", - "demonise", "demonize", - "deputise", "deputize", - "dialling", "dialing", - "dialogue", "dialog", - "digitise", "digitize", - "draughty", "drafty", - "duelling", "dueling", - "energise", "energize", - "enthrals", "enthralls", - "equalise", "equalize", - "eulogise", "eulogize", - "favoured", "favored", - "feminise", "feminize", - "finalise", "finalize", - "flautist", "flutist", - "flavours", "flavors", - "foetuses", "fetuses", - "fuelling", "fueling", - "gaolbird", "jailbird", - "gryphons", "griffins", - "harbours", "harbors", - "honoured", "honored", - "humanise", "humanize", - "humoured", "humored", - "idealise", "idealize", - "idolised", "idolized", - "idolises", "idolizes", - "immunise", "immunize", - "ionisers", "ionizers", - "ionising", "ionizing", - "itemised", "itemized", - "itemises", "itemizes", - "jewelled", "jeweled", - "jeweller", "jeweler", - "labelled", "labeled", - "laboured", "labored", - "labourer", "laborer", - "legalise", "legalize", - "levelled", "leveled", - "leveller", "leveler", - "libelled", "libeled", - "licenced", "licensed", - "licences", "licenses", - "lionised", "lionized", - "lionises", "lionizes", - "localise", "localize", - "maximise", "maximize", - "memorise", "memorize", - "minimise", "minimize", - "misspelt", "misspelled", - "mobilise", "mobilize", - "modelled", "modeled", - "modeller", "modeler", - "moralise", "moralize", - "moulders", "molders", - "mouldier", "moldier", - "moulding", "molding", - "moulting", "molting", - "offences", "offenses", - "optimise", "optimize", - "organise", "organize", - "oxidised", "oxidized", - "oxidises", "oxidizes", - "panelled", "paneled", - "paralyse", "paralyze", - "parlours", "parlors", - "pedalled", "pedaled", - "penalise", "penalize", - "philtres", "filters", - "ploughed", "plowed", - "polarise", "polarize", - "practise", "practice", - "pretence", "pretense", - "ravelled", "raveled", - "realised", "realized", - "realises", "realizes", - "remoulds", "remolds", - "revelled", "reveled", - "reveller", "reveler", - "rivalled", "rivaled", - "rumoured", "rumored", - "sanitise", "sanitize", - "satirise", "satirize", - "saviours", "saviors", - "savoured", "savored", - "sceptics", "skeptics", - "sceptres", "scepters", - "sodomise", "sodomize", - "spectres", "specters", - "succours", "succors", - "sulphate", "sulfate", - "sulphide", "sulfide", - "syphoned", "siphoned", - "theatres", "theaters", - "theorise", "theorize", - "towelled", "toweled", - "toxaemia", "toxemia", - "trialled", "trialed", - "unionise", "unionize", - "urbanise", "urbanize", - "utilised", "utilized", - "utilises", "utilizes", - "vaporise", "vaporize", - "vocalise", "vocalize", - "womanise", "womanize", - "yodelled", "yodeled", - "yoghourt", "yogurt", - "yoghurts", "yogurts", - "agonise", "agonize", - "anaemia", "anemia", - "anaemic", "anemic", - "analyse", "analyze", - "arbours", "arbors", - "armoury", "armory", - "baptise", "baptize", - "baulked", "balked", - "behoved", "behooved", - "behoves", "behooves", - "calibre", "caliber", - "candour", "candor", - "centred", "centered", - "centres", "centers", - "cheques", "checks", - "clamour", "clamor", - "colours", "colors", - "cosiest", "coziest", - "defence", "defense", - "dialled", "dialed", - "distils", "distills", - "duelled", "dueled", - "enthral", "enthrall", - "favours", "favors", - "fervour", "fervor", - "flavour", "flavor", - "fuelled", "fueled", - "fulfils", "fulfills", - "gaolers", "jailers", - "gaoling", "jailing", - "gipsies", "gypsies", - "glueing", "gluing", - "goitres", "goiters", - "grammes", "grams", - "groynes", "groins", - "gryphon", "griffin", - "harbour", "harbor", - "honours", "honors", - "humours", "humors", - "idolise", "idolize", - "instals", "installs", - "instils", "instills", - "ionised", "ionized", - "ioniser", "ionizer", - "ionises", "ionizes", - "itemise", "itemize", - "labours", "labors", - "licence", "license", - "lionise", "lionize", - "louvred", "louvered", - "louvres", "louvers", - "moulded", "molded", - "moulder", "molder", - "moulted", "molted", - "offence", "offense", - "oxidise", "oxidize", - "parlour", "parlor", - "philtre", "filter", - "ploughs", "plows", - "pyjamas", "pajamas", - "rancour", "rancor", - "realise", "realize", - "remould", "remold", - "rigours", "rigors", - "rumours", "rumors", - "saviour", "savior", - "savours", "savors", - "savoury", "savory", - "sceptic", "skeptic", - "sceptre", "scepter", - "spectre", "specter", - "storeys", "stories", - "succour", "succor", - "sulphur", "sulfur", - "syphons", "siphons", - "theatre", "theater", - "tumours", "tumors", - "utilise", "utilize", - "vapours", "vapors", - "waggons", "wagons", - "yoghurt", "yogurt", - "ageing", "aging", - "appals", "appalls", - "arbour", "arbor", - "ardour", "ardor", - "baulks", "balks", - "behove", "behoove", - "centre", "center", - "cheque", "check", - "chilli", "chili", - "colour", "color", - "cosier", "cozier", - "cosies", "cozies", - "cosily", "cozily", - "distil", "distill", - "edoema", "edema", - "enrols", "enrolls", - "faecal", "fecal", - "faeces", "feces", - "favour", "favor", - "fibres", "fibers", - "foetal", "fetal", - "foetid", "fetid", - "foetus", "fetus", - "fulfil", "fulfill", - "gaoled", "jailed", - "gaoler", "jailer", - "goitre", "goiter", - "gramme", "gram", - "groyne", "groin", - "honour", "honor", - "humour", "humor", - "instal", "install", - "instil", "instill", - "ionise", "ionize", - "labour", "labor", - "litres", "liters", - "lustre", "luster", - "meagre", "meager", - "metres", "meters", - "mitres", "miters", - "moulds", "molds", - "mouldy", "moldy", - "moults", "molts", - "odours", "odors", - "plough", "plow", - "pyjama", "pajama", - "rigour", "rigor", - "rumour", "rumor", - "savour", "savor", - "storey", "story", - "syphon", "siphon", - "tumour", "tumor", - "valour", "valor", - "vapour", "vapor", - "vigour", "vigor", - "waggon", "wagon", - "appal", "appall", - "baulk", "balk", - "enrol", "enroll", - "fibre", "fiber", - "gaols", "jails", - "litre", "liter", - "metre", "meter", - "mitre", "miter", - "mould", "mold", - "moult", "molt", - "odour", "odor", - "tyres", "tires", - "cosy", "cozy", - "gaol", "jail", - "tyre", "tire", -} - -// DictBritish converts US spellings to UK spellings -var DictBritish = []string{ - "institutionalization", "institutionalisation", - "internationalization", "internationalisation", - "professionalization", "professionalisation", - "compartmentalizing", "compartmentalising", - "institutionalizing", "institutionalising", - "internationalizing", "internationalising", - "compartmentalized", "compartmentalised", - "compartmentalizes", "compartmentalises", - "decriminalization", "decriminalisation", - "denationalization", "denationalisation", - "fictionalizations", "fictionalisations", - "institutionalized", "institutionalised", - "institutionalizes", "institutionalises", - "intellectualizing", "intellectualising", - "internationalized", "internationalised", - "internationalizes", "internationalises", - "pedestrianization", "pedestrianisation", - "professionalizing", "professionalising", - "compartmentalize", "compartmentalise", - "decentralization", "decentralisation", - "demilitarization", "demilitarisation", - "externalizations", "externalisations", - "fictionalization", "fictionalisation", - "institutionalize", "institutionalise", - "intellectualized", "intellectualised", - "intellectualizes", "intellectualises", - "internationalize", "internationalise", - "nationalizations", "nationalisations", - "professionalized", "professionalised", - "professionalizes", "professionalises", - "rationalizations", "rationalisations", - "sensationalizing", "sensationalising", - "sentimentalizing", "sentimentalising", - "acclimatization", "acclimatisation", - "commercializing", "commercialising", - "conceptualizing", "conceptualising", - "contextualizing", "contextualising", - "crystallization", "crystallisation", - "decriminalizing", "decriminalising", - "democratization", "democratisation", - "denationalizing", "denationalising", - "depersonalizing", "depersonalising", - "desensitization", "desensitisation", - "disorganization", "disorganisation", - "extemporization", "extemporisation", - "externalization", "externalisation", - "familiarization", "familiarisation", - "generalizations", "generalisations", - "hospitalization", "hospitalisation", - "individualizing", "individualising", - "industrializing", "industrialising", - "intellectualize", "intellectualise", - "internalization", "internalisation", - "maneuverability", "manoeuvrability", - "materialization", "materialisation", - "miniaturization", "miniaturisation", - "nationalization", "nationalisation", - "overemphasizing", "overemphasising", - "paleontologists", "palaeontologists", - "particularizing", "particularising", - "pedestrianizing", "pedestrianising", - "professionalize", "professionalise", - "psychoanalyzing", "psychoanalysing", - "rationalization", "rationalisation", - "reorganizations", "reorganisations", - "revolutionizing", "revolutionising", - "sensationalized", "sensationalised", - "sensationalizes", "sensationalises", - "sentimentalized", "sentimentalised", - "sentimentalizes", "sentimentalises", - "specializations", "specialisations", - "standardization", "standardisation", - "synchronization", "synchronisation", - "systematization", "systematisation", - "aggrandizement", "aggrandisement", - "characterizing", "characterising", - "collectivizing", "collectivising", - "commercialized", "commercialised", - "commercializes", "commercialises", - "conceptualized", "conceptualised", - "conceptualizes", "conceptualises", - "contextualized", "contextualised", - "contextualizes", "contextualises", - "decentralizing", "decentralising", - "decriminalized", "decriminalised", - "decriminalizes", "decriminalises", - "dehumanization", "dehumanisation", - "demilitarizing", "demilitarising", - "demobilization", "demobilisation", - "demoralization", "demoralisation", - "denationalized", "denationalised", - "denationalizes", "denationalises", - "depersonalized", "depersonalised", - "depersonalizes", "depersonalises", - "dramatizations", "dramatisations", - "editorializing", "editorialising", - "fictionalizing", "fictionalising", - "fraternization", "fraternisation", - "generalization", "generalisation", - "immobilization", "immobilisation", - "individualized", "individualised", - "individualizes", "individualises", - "industrialized", "industrialised", - "industrializes", "industrialises", - "liberalization", "liberalisation", - "monopolization", "monopolisation", - "naturalization", "naturalisation", - "neighborliness", "neighbourliness", - "neutralization", "neutralisation", - "organizational", "organisational", - "outmaneuvering", "outmanoeuvring", - "overemphasized", "overemphasised", - "overemphasizes", "overemphasises", - "paleontologist", "palaeontologist", - "particularized", "particularised", - "particularizes", "particularises", - "pasteurization", "pasteurisation", - "pedestrianized", "pedestrianised", - "pedestrianizes", "pedestrianises", - "philosophizing", "philosophising", - "politicization", "politicisation", - "popularization", "popularisation", - "pressurization", "pressurisation", - "prioritization", "prioritisation", - "privatizations", "privatisations", - "propagandizing", "propagandising", - "psychoanalyzed", "psychoanalysed", - "psychoanalyzes", "psychoanalyses", - "reconnoitering", "reconnoitring", - "regularization", "regularisation", - "reorganization", "reorganisation", - "revolutionized", "revolutionised", - "revolutionizes", "revolutionises", - "secularization", "secularisation", - "sensationalize", "sensationalise", - "sentimentalize", "sentimentalise", - "serializations", "serialisations", - "specialization", "specialisation", - "sterilizations", "sterilisations", - "stigmatization", "stigmatisation", - "transistorized", "transistorised", - "unrecognizable", "unrecognisable", - "visualizations", "visualisations", - "westernization", "westernisation", - "accessorizing", "accessorising", - "acclimatizing", "acclimatising", - "amortizations", "amortisations", - "amphitheaters", "amphitheatres", - "anesthetizing", "anaesthetising", - "archeologists", "archaeologists", - "breathalyzers", "breathalysers", - "breathalyzing", "breathalysing", - "cannibalizing", "cannibalising", - "characterized", "characterised", - "characterizes", "characterises", - "circularizing", "circularising", - "collectivized", "collectivised", - "collectivizes", "collectivises", - "commercialize", "commercialise", - "computerizing", "computerising", - "conceptualize", "conceptualise", - "contextualize", "contextualise", - "criminalizing", "criminalising", - "crystallizing", "crystallising", - "decentralized", "decentralised", - "decentralizes", "decentralises", - "decriminalize", "decriminalise", - "demilitarized", "demilitarised", - "demilitarizes", "demilitarises", - "democratizing", "democratising", - "denationalize", "denationalise", - "depersonalize", "depersonalise", - "desensitizing", "desensitising", - "destabilizing", "destabilising", - "disemboweling", "disembowelling", - "dramatization", "dramatisation", - "editorialized", "editorialised", - "editorializes", "editorialises", - "extemporizing", "extemporising", - "externalizing", "externalising", - "familiarizing", "familiarising", - "fertilization", "fertilisation", - "fictionalized", "fictionalised", - "fictionalizes", "fictionalises", - "formalization", "formalisation", - "fossilization", "fossilisation", - "globalization", "globalisation", - "gynecological", "gynaecological", - "gynecologists", "gynaecologists", - "harmonization", "harmonisation", - "hematological", "haematological", - "hematologists", "haematologists", - "hospitalizing", "hospitalising", - "hypothesizing", "hypothesising", - "immortalizing", "immortalising", - "individualize", "individualise", - "industrialize", "industrialise", - "internalizing", "internalising", - "marginalizing", "marginalising", - "materializing", "materialising", - "mechanization", "mechanisation", - "memorializing", "memorialising", - "miniaturizing", "miniaturising", - "nationalizing", "nationalising", - "neighborhoods", "neighbourhoods", - "normalization", "normalisation", - "organizations", "organisations", - "outmaneuvered", "outmanoeuvred", - "overemphasize", "overemphasise", - "particularize", "particularise", - "passivization", "passivisation", - "patronizingly", "patronisingly", - "pedestrianize", "pedestrianise", - "pediatricians", "paediatricians", - "personalizing", "personalising", - "philosophized", "philosophised", - "philosophizes", "philosophises", - "privatization", "privatisation", - "propagandized", "propagandised", - "propagandizes", "propagandises", - "proselytizers", "proselytisers", - "proselytizing", "proselytising", - "psychoanalyze", "psychoanalyse", - "pulverization", "pulverisation", - "rationalizing", "rationalising", - "reconnoitered", "reconnoitred", - "revolutionize", "revolutionise", - "romanticizing", "romanticising", - "serialization", "serialisation", - "socialization", "socialisation", - "standardizing", "standardising", - "sterilization", "sterilisation", - "subsidization", "subsidisation", - "synchronizing", "synchronising", - "systematizing", "systematising", - "tantalizingly", "tantalisingly", - "underutilized", "underutilised", - "victimization", "victimisation", - "visualization", "visualisation", - "vocalizations", "vocalisations", - "vulgarization", "vulgarisation", - "accessorized", "accessorised", - "accessorizes", "accessorises", - "acclimatized", "acclimatised", - "acclimatizes", "acclimatises", - "amortization", "amortisation", - "amphitheater", "amphitheatre", - "anesthetists", "anaesthetists", - "anesthetized", "anaesthetised", - "anesthetizes", "anaesthetises", - "antagonizing", "antagonising", - "appetizingly", "appetisingly", - "archeologist", "archaeologist", - "backpedaling", "backpedalling", - "bastardizing", "bastardising", - "behaviorists", "behaviourists", - "bowdlerizing", "bowdlerising", - "breathalyzed", "breathalysed", - "breathalyzes", "breathalyses", - "cannibalized", "cannibalised", - "cannibalizes", "cannibalises", - "capitalizing", "capitalising", - "caramelizing", "caramelising", - "categorizing", "categorising", - "centerpieces", "centrepieces", - "centralizing", "centralising", - "characterize", "characterise", - "circularized", "circularised", - "circularizes", "circularises", - "clarinetists", "clarinettists", - "collectivize", "collectivise", - "colonization", "colonisation", - "computerized", "computerised", - "computerizes", "computerises", - "criminalized", "criminalised", - "criminalizes", "criminalises", - "crystallized", "crystallised", - "crystallizes", "crystallises", - "decentralize", "decentralise", - "dehumanizing", "dehumanising", - "demilitarize", "demilitarise", - "demobilizing", "demobilising", - "democratized", "democratised", - "democratizes", "democratises", - "demoralizing", "demoralising", - "desensitized", "desensitised", - "desensitizes", "desensitises", - "destabilized", "destabilised", - "destabilizes", "destabilises", - "disemboweled", "disembowelled", - "dishonorable", "dishonourable", - "dishonorably", "dishonourably", - "disorganized", "disorganised", - "editorialize", "editorialise", - "equalization", "equalisation", - "evangelizing", "evangelising", - "extemporized", "extemporised", - "extemporizes", "extemporises", - "externalized", "externalised", - "externalizes", "externalises", - "familiarized", "familiarised", - "familiarizes", "familiarises", - "fictionalize", "fictionalise", - "finalization", "finalisation", - "fraternizing", "fraternising", - "generalizing", "generalising", - "gynecologist", "gynaecologist", - "hematologist", "haematologist", - "hemophiliacs", "haemophiliacs", - "hemorrhaging", "haemorrhaging", - "homogenizing", "homogenising", - "hospitalized", "hospitalised", - "hospitalizes", "hospitalises", - "hypothesized", "hypothesised", - "hypothesizes", "hypothesises", - "idealization", "idealisation", - "immobilizers", "immobilisers", - "immobilizing", "immobilising", - "immortalized", "immortalised", - "immortalizes", "immortalises", - "immunization", "immunisation", - "initializing", "initialising", - "installments", "instalments", - "internalized", "internalised", - "internalizes", "internalises", - "jeopardizing", "jeopardising", - "legalization", "legalisation", - "legitimizing", "legitimising", - "liberalizing", "liberalising", - "maneuverable", "manoeuvrable", - "maneuverings", "manoeuvrings", - "marginalized", "marginalised", - "marginalizes", "marginalises", - "materialized", "materialised", - "materializes", "materialises", - "maximization", "maximisation", - "memorialized", "memorialised", - "memorializes", "memorialises", - "metabolizing", "metabolising", - "militarizing", "militarising", - "miniaturized", "miniaturised", - "miniaturizes", "miniaturises", - "miscataloged", "miscatalogued", - "misdemeanors", "misdemeanours", - "mobilization", "mobilisation", - "moisturizers", "moisturisers", - "moisturizing", "moisturising", - "monopolizing", "monopolising", - "multicolored", "multicoloured", - "nationalized", "nationalised", - "nationalizes", "nationalises", - "naturalizing", "naturalising", - "neighborhood", "neighbourhood", - "neutralizing", "neutralising", - "organization", "organisation", - "outmaneuvers", "outmanoeuvres", - "paleontology", "palaeontology", - "pasteurizing", "pasteurising", - "pediatrician", "paediatrician", - "personalized", "personalised", - "personalizes", "personalises", - "philosophize", "philosophise", - "plagiarizing", "plagiarising", - "polarization", "polarisation", - "politicizing", "politicising", - "popularizing", "popularising", - "pressurizing", "pressurising", - "prioritizing", "prioritising", - "propagandize", "propagandise", - "proselytized", "proselytised", - "proselytizer", "proselytiser", - "proselytizes", "proselytises", - "radicalizing", "radicalising", - "rationalized", "rationalised", - "rationalizes", "rationalises", - "realizations", "realisations", - "recognizable", "recognisable", - "recognizably", "recognisably", - "recognizance", "recognisance", - "reconnoiters", "reconnoitres", - "regularizing", "regularising", - "reorganizing", "reorganising", - "revitalizing", "revitalising", - "rhapsodizing", "rhapsodising", - "romanticized", "romanticised", - "romanticizes", "romanticises", - "scandalizing", "scandalising", - "scrutinizing", "scrutinising", - "secularizing", "secularising", - "standardized", "standardised", - "standardizes", "standardises", - "stigmatizing", "stigmatising", - "sympathizers", "sympathisers", - "sympathizing", "sympathising", - "synchronized", "synchronised", - "synchronizes", "synchronises", - "synthesizing", "synthesising", - "systematized", "systematised", - "systematizes", "systematises", - "theatergoers", "theatregoers", - "traumatizing", "traumatising", - "trivializing", "trivialising", - "unauthorized", "unauthorised", - "unionization", "unionisation", - "unrecognized", "unrecognised", - "urbanization", "urbanisation", - "vaporization", "vaporisation", - "vocalization", "vocalisation", - "westernizing", "westernising", - "accessorize", "accessorise", - "acclimatize", "acclimatise", - "agonizingly", "agonisingly", - "amortizable", "amortisable", - "anesthetics", "anaesthetics", - "anesthetist", "anaesthetist", - "anesthetize", "anaesthetise", - "anglicizing", "anglicising", - "antagonized", "antagonised", - "antagonizes", "antagonises", - "apologizing", "apologising", - "backpedaled", "backpedalled", - "bastardized", "bastardised", - "bastardizes", "bastardises", - "behaviorism", "behaviourism", - "behaviorist", "behaviourist", - "bowdlerized", "bowdlerised", - "bowdlerizes", "bowdlerises", - "brutalizing", "brutalising", - "cannibalize", "cannibalise", - "capitalized", "capitalised", - "capitalizes", "capitalises", - "caramelized", "caramelised", - "caramelizes", "caramelises", - "carbonizing", "carbonising", - "categorized", "categorised", - "categorizes", "categorises", - "cauterizing", "cauterising", - "centerfolds", "centrefolds", - "centerpiece", "centrepiece", - "centiliters", "centilitres", - "centimeters", "centimetres", - "centralized", "centralised", - "centralizes", "centralises", - "circularize", "circularise", - "clarinetist", "clarinettist", - "computerize", "computerise", - "criminalize", "criminalise", - "criticizing", "criticising", - "crystallize", "crystallise", - "customizing", "customising", - "defenseless", "defenceless", - "dehumanized", "dehumanised", - "dehumanizes", "dehumanises", - "demobilized", "demobilised", - "demobilizes", "demobilises", - "democratize", "democratise", - "demoralized", "demoralised", - "demoralizes", "demoralises", - "deodorizing", "deodorising", - "desensitize", "desensitise", - "destabilize", "destabilise", - "discoloring", "discolouring", - "dishonoring", "dishonouring", - "dramatizing", "dramatising", - "economizing", "economising", - "empathizing", "empathising", - "emphasizing", "emphasising", - "endeavoring", "endeavouring", - "epitomizing", "epitomising", - "esophaguses", "oesophaguses", - "evangelized", "evangelised", - "evangelizes", "evangelises", - "extemporize", "extemporise", - "externalize", "externalise", - "factorizing", "factorising", - "familiarize", "familiarise", - "fantasizing", "fantasising", - "fertilizers", "fertilisers", - "fertilizing", "fertilising", - "formalizing", "formalising", - "fossilizing", "fossilising", - "fraternized", "fraternised", - "fraternizes", "fraternises", - "fulfillment", "fulfilment", - "galvanizing", "galvanising", - "generalized", "generalised", - "generalizes", "generalises", - "ghettoizing", "ghettoising", - "globalizing", "globalising", - "harmonizing", "harmonising", - "hemophiliac", "haemophiliac", - "hemorrhaged", "haemorrhaged", - "hemorrhages", "haemorrhages", - "hemorrhoids", "haemorrhoids", - "homogenized", "homogenised", - "homogenizes", "homogenises", - "hospitalize", "hospitalise", - "hybridizing", "hybridising", - "hypnotizing", "hypnotising", - "hypothesize", "hypothesise", - "immobilized", "immobilised", - "immobilizer", "immobiliser", - "immobilizes", "immobilises", - "immortalize", "immortalise", - "initialized", "initialised", - "initializes", "initialises", - "installment", "instalment", - "internalize", "internalise", - "italicizing", "italicising", - "jeopardized", "jeopardised", - "jeopardizes", "jeopardises", - "legitimized", "legitimised", - "legitimizes", "legitimises", - "liberalized", "liberalised", - "liberalizes", "liberalises", - "lionization", "lionisation", - "liquidizers", "liquidisers", - "liquidizing", "liquidising", - "magnetizing", "magnetising", - "maneuvering", "manoeuvring", - "marginalize", "marginalise", - "marvelously", "marvellously", - "materialize", "materialise", - "mechanizing", "mechanising", - "memorialize", "memorialise", - "mesmerizing", "mesmerising", - "metabolized", "metabolised", - "metabolizes", "metabolises", - "militarized", "militarised", - "militarizes", "militarises", - "milliliters", "millilitres", - "millimeters", "millimetres", - "miniaturize", "miniaturise", - "misbehavior", "misbehaviour", - "misdemeanor", "misdemeanour", - "modernizing", "modernising", - "moisturized", "moisturised", - "moisturizer", "moisturiser", - "moisturizes", "moisturises", - "monopolized", "monopolised", - "monopolizes", "monopolises", - "nationalize", "nationalise", - "naturalized", "naturalised", - "naturalizes", "naturalises", - "neighboring", "neighbouring", - "neutralized", "neutralised", - "neutralizes", "neutralises", - "normalizing", "normalising", - "orthopedics", "orthopaedics", - "ostracizing", "ostracising", - "outmaneuver", "outmanoeuvre", - "oxidization", "oxidisation", - "pasteurized", "pasteurised", - "pasteurizes", "pasteurises", - "patronizing", "patronising", - "personalize", "personalise", - "plagiarized", "plagiarised", - "plagiarizes", "plagiarises", - "politicized", "politicised", - "politicizes", "politicises", - "popularized", "popularised", - "popularizes", "popularises", - "pressurized", "pressurised", - "pressurizes", "pressurises", - "prioritized", "prioritised", - "prioritizes", "prioritises", - "privatizing", "privatising", - "proselytize", "proselytise", - "publicizing", "publicising", - "pulverizing", "pulverising", - "radicalized", "radicalised", - "radicalizes", "radicalises", - "randomizing", "randomising", - "rationalize", "rationalise", - "realization", "realisation", - "recognizing", "recognising", - "reconnoiter", "reconnoitre", - "regularized", "regularised", - "regularizes", "regularises", - "reorganized", "reorganised", - "reorganizes", "reorganises", - "revitalized", "revitalised", - "revitalizes", "revitalises", - "rhapsodized", "rhapsodised", - "rhapsodizes", "rhapsodises", - "romanticize", "romanticise", - "scandalized", "scandalised", - "scandalizes", "scandalises", - "scrutinized", "scrutinised", - "scrutinizes", "scrutinises", - "secularized", "secularised", - "secularizes", "secularises", - "sensitizing", "sensitising", - "serializing", "serialising", - "sermonizing", "sermonising", - "signalizing", "signalising", - "skeptically", "sceptically", - "socializing", "socialising", - "solemnizing", "solemnising", - "specialized", "specialised", - "specializes", "specialises", - "squirreling", "squirrelling", - "stabilizers", "stabilisers", - "stabilizing", "stabilising", - "standardize", "standardise", - "sterilizers", "sterilisers", - "sterilizing", "sterilising", - "stigmatized", "stigmatised", - "stigmatizes", "stigmatises", - "subsidizers", "subsidisers", - "subsidizing", "subsidising", - "summarizing", "summarising", - "symbolizing", "symbolising", - "sympathized", "sympathised", - "sympathizer", "sympathiser", - "sympathizes", "sympathises", - "synchronize", "synchronise", - "synthesized", "synthesised", - "synthesizes", "synthesises", - "systematize", "systematise", - "tantalizing", "tantalising", - "temporizing", "temporising", - "tenderizing", "tenderising", - "terrorizing", "terrorising", - "theatergoer", "theatregoer", - "traumatized", "traumatised", - "traumatizes", "traumatises", - "trivialized", "trivialised", - "trivializes", "trivialises", - "tyrannizing", "tyrannising", - "uncataloged", "uncatalogued", - "uncivilized", "uncivilised", - "unfavorable", "unfavourable", - "unfavorably", "unfavourably", - "unorganized", "unorganised", - "untrammeled", "untrammelled", - "utilization", "utilisation", - "vandalizing", "vandalising", - "verbalizing", "verbalising", - "victimizing", "victimising", - "visualizing", "visualising", - "vulgarizing", "vulgarising", - "watercolors", "watercolours", - "westernized", "westernised", - "westernizes", "westernises", - "amortizing", "amortising", - "anesthesia", "anaesthesia", - "anesthetic", "anaesthetic", - "anglicized", "anglicised", - "anglicizes", "anglicises", - "annualized", "annualised", - "antagonize", "antagonise", - "apologized", "apologised", - "apologizes", "apologises", - "appetizers", "appetisers", - "appetizing", "appetising", - "archeology", "archaeology", - "authorizes", "authorises", - "bastardize", "bastardise", - "bedeviling", "bedevilling", - "behavioral", "behavioural", - "belaboring", "belabouring", - "bowdlerize", "bowdlerise", - "brutalized", "brutalised", - "brutalizes", "brutalises", - "canalizing", "canalising", - "canonizing", "canonising", - "capitalize", "capitalise", - "caramelize", "caramelise", - "carbonized", "carbonised", - "carbonizes", "carbonises", - "cataloging", "cataloguing", - "catalyzing", "catalysing", - "categorize", "categorise", - "cauterized", "cauterised", - "cauterizes", "cauterises", - "centerfold", "centrefold", - "centiliter", "centilitre", - "centimeter", "centimetre", - "centralize", "centralise", - "channeling", "channelling", - "checkbooks", "chequebooks", - "civilizing", "civilising", - "colonizers", "colonisers", - "colonizing", "colonising", - "colorfully", "colourfully", - "colorizing", "colourizing", - "councilors", "councillors", - "counselors", "counsellors", - "criticized", "criticised", - "criticizes", "criticises", - "customized", "customised", - "customizes", "customises", - "dehumanize", "dehumanise", - "demobilize", "demobilise", - "demonizing", "demonising", - "demoralize", "demoralise", - "deodorized", "deodorised", - "deodorizes", "deodorises", - "deputizing", "deputising", - "digitizing", "digitising", - "discolored", "discoloured", - "disheveled", "dishevelled", - "dishonored", "dishonoured", - "dramatized", "dramatised", - "dramatizes", "dramatises", - "economized", "economised", - "economizes", "economises", - "empathized", "empathised", - "empathizes", "empathises", - "emphasized", "emphasised", - "emphasizes", "emphasises", - "endeavored", "endeavoured", - "energizing", "energising", - "epicenters", "epicentres", - "epitomized", "epitomised", - "epitomizes", "epitomises", - "equalizers", "equalisers", - "equalizing", "equalising", - "eulogizing", "eulogising", - "evangelize", "evangelise", - "factorized", "factorised", - "factorizes", "factorises", - "fantasized", "fantasised", - "fantasizes", "fantasises", - "favoritism", "favouritism", - "feminizing", "feminising", - "fertilized", "fertilised", - "fertilizer", "fertiliser", - "fertilizes", "fertilises", - "fiberglass", "fibreglass", - "finalizing", "finalising", - "flavorings", "flavourings", - "flavorless", "flavourless", - "flavorsome", "flavoursome", - "formalized", "formalised", - "formalizes", "formalises", - "fossilized", "fossilised", - "fossilizes", "fossilises", - "fraternize", "fraternise", - "galvanized", "galvanised", - "galvanizes", "galvanises", - "generalize", "generalise", - "ghettoized", "ghettoised", - "ghettoizes", "ghettoises", - "globalized", "globalised", - "globalizes", "globalises", - "gruelingly", "gruellingly", - "gynecology", "gynaecology", - "harmonized", "harmonised", - "harmonizes", "harmonises", - "hematology", "haematology", - "hemoglobin", "haemoglobin", - "hemophilia", "haemophilia", - "hemorrhage", "haemorrhage", - "homogenize", "homogenise", - "humanizing", "humanising", - "hybridized", "hybridised", - "hybridizes", "hybridises", - "hypnotized", "hypnotised", - "hypnotizes", "hypnotises", - "idealizing", "idealising", - "immobilize", "immobilise", - "immunizing", "immunising", - "impaneling", "impanelling", - "imperiling", "imperilling", - "initialing", "initialling", - "initialize", "initialise", - "ionization", "ionisation", - "italicized", "italicised", - "italicizes", "italicises", - "jeopardize", "jeopardise", - "kilometers", "kilometres", - "lackluster", "lacklustre", - "legalizing", "legalising", - "legitimize", "legitimise", - "liberalize", "liberalise", - "liquidized", "liquidised", - "liquidizer", "liquidiser", - "liquidizes", "liquidises", - "localizing", "localising", - "magnetized", "magnetised", - "magnetizes", "magnetises", - "maneuvered", "manoeuvred", - "marshaling", "marshalling", - "maximizing", "maximising", - "mechanized", "mechanised", - "mechanizes", "mechanises", - "memorizing", "memorising", - "mesmerized", "mesmerised", - "mesmerizes", "mesmerises", - "metabolize", "metabolise", - "militarize", "militarise", - "milliliter", "millilitre", - "millimeter", "millimetre", - "minimizing", "minimising", - "mobilizing", "mobilising", - "modernized", "modernised", - "modernizes", "modernises", - "moisturize", "moisturise", - "monopolize", "monopolise", - "moralizing", "moralising", - "naturalize", "naturalise", - "neighborly", "neighbourly", - "neutralize", "neutralise", - "normalized", "normalised", - "normalizes", "normalises", - "optimizing", "optimising", - "organizers", "organisers", - "organizing", "organising", - "orthopedic", "orthopaedic", - "ostracized", "ostracised", - "ostracizes", "ostracises", - "paralyzing", "paralysing", - "pasteurize", "pasteurise", - "patronized", "patronised", - "patronizes", "patronises", - "pedophiles", "paedophiles", - "pedophilia", "paedophilia", - "penalizing", "penalising", - "plagiarize", "plagiarise", - "plowshares", "ploughshares", - "polarizing", "polarising", - "politicize", "politicise", - "popularize", "popularise", - "prioritize", "prioritise", - "privatized", "privatised", - "privatizes", "privatises", - "publicized", "publicised", - "publicizes", "publicises", - "pulverized", "pulverised", - "pulverizes", "pulverises", - "quarreling", "quarrelling", - "radicalize", "radicalise", - "randomized", "randomised", - "randomizes", "randomises", - "realizable", "realisable", - "recognized", "recognised", - "recognizes", "recognises", - "regularize", "regularise", - "remodeling", "remodelling", - "reorganize", "reorganise", - "revitalize", "revitalise", - "rhapsodize", "rhapsodise", - "ritualized", "ritualised", - "sanitizing", "sanitising", - "satirizing", "satirising", - "scandalize", "scandalise", - "scrutinize", "scrutinise", - "secularize", "secularise", - "sensitized", "sensitised", - "sensitizes", "sensitises", - "sepulchers", "sepulchres", - "serialized", "serialised", - "serializes", "serialises", - "sermonized", "sermonised", - "sermonizes", "sermonises", - "shriveling", "shrivelling", - "signalized", "signalised", - "signalizes", "signalises", - "skepticism", "scepticism", - "socialized", "socialised", - "socializes", "socialises", - "sodomizing", "sodomising", - "solemnized", "solemnised", - "solemnizes", "solemnises", - "specialize", "specialise", - "squirreled", "squirrelled", - "stabilized", "stabilised", - "stabilizer", "stabiliser", - "stabilizes", "stabilises", - "stenciling", "stencilling", - "sterilized", "sterilised", - "sterilizer", "steriliser", - "sterilizes", "sterilises", - "stigmatize", "stigmatise", - "subsidized", "subsidised", - "subsidizer", "subsidiser", - "subsidizes", "subsidises", - "summarized", "summarised", - "summarizes", "summarises", - "symbolized", "symbolised", - "symbolizes", "symbolises", - "sympathize", "sympathise", - "tantalized", "tantalised", - "tantalizes", "tantalises", - "temporized", "temporised", - "temporizes", "temporises", - "tenderized", "tenderised", - "tenderizes", "tenderises", - "terrorized", "terrorised", - "terrorizes", "terrorises", - "theorizing", "theorising", - "traumatize", "traumatise", - "trivialize", "trivialise", - "tyrannized", "tyrannised", - "tyrannizes", "tyrannises", - "unionizing", "unionising", - "unraveling", "unravelling", - "urbanizing", "urbanising", - "utilizable", "utilisable", - "vandalized", "vandalised", - "vandalizes", "vandalises", - "vaporizing", "vaporising", - "verbalized", "verbalised", - "verbalizes", "verbalises", - "victimized", "victimised", - "victimizes", "victimises", - "visualized", "visualised", - "visualizes", "visualises", - "vocalizing", "vocalising", - "vulcanized", "vulcanised", - "vulgarized", "vulgarised", - "vulgarizes", "vulgarises", - "watercolor", "watercolour", - "westernize", "westernise", - "womanizers", "womanisers", - "womanizing", "womanising", - "worshiping", "worshipping", - "agonizing", "agonising", - "airplanes", "aeroplanes", - "amortized", "amortised", - "amortizes", "amortises", - "analyzing", "analysing", - "apologize", "apologise", - "appetizer", "appetiser", - "artifacts", "artefacts", - "baptizing", "baptising", - "bedeviled", "bedevilled", - "behaviors", "behaviours", - "bejeweled", "bejewelled", - "belabored", "belaboured", - "brutalize", "brutalise", - "canalized", "canalised", - "canalizes", "canalises", - "canonized", "canonised", - "canonizes", "canonises", - "carbonize", "carbonise", - "cataloged", "catalogued", - "catalyzed", "catalysed", - "catalyzes", "catalyses", - "cauterize", "cauterise", - "channeled", "channelled", - "checkbook", "chequebook", - "checkered", "chequered", - "chiseling", "chiselling", - "civilized", "civilised", - "civilizes", "civilises", - "clamoring", "clamouring", - "colonized", "colonised", - "colonizer", "coloniser", - "colonizes", "colonises", - "colorants", "colourants", - "colorized", "colourized", - "colorizes", "colourizes", - "colorless", "colourless", - "councilor", "councillor", - "counseled", "counselled", - "counselor", "counsellor", - "criticize", "criticise", - "cudgeling", "cudgelling", - "customize", "customise", - "demonized", "demonised", - "demonizes", "demonises", - "deodorize", "deodorise", - "deputized", "deputised", - "deputizes", "deputises", - "digitized", "digitised", - "digitizes", "digitises", - "discolors", "discolours", - "dishonors", "dishonours", - "dramatize", "dramatise", - "driveling", "drivelling", - "economize", "economise", - "empathize", "empathise", - "emphasize", "emphasise", - "enameling", "enamelling", - "endeavors", "endeavours", - "energized", "energised", - "energizes", "energises", - "enthralls", "enthrals", - "epicenter", "epicentre", - "epitomize", "epitomise", - "equalized", "equalised", - "equalizer", "equaliser", - "equalizes", "equalises", - "eulogized", "eulogised", - "eulogizes", "eulogises", - "factorize", "factorise", - "fantasize", "fantasise", - "favorable", "favourable", - "favorably", "favourably", - "favorites", "favourites", - "feminized", "feminised", - "feminizes", "feminises", - "fertilize", "fertilise", - "finalized", "finalised", - "finalizes", "finalises", - "flavoring", "flavouring", - "formalize", "formalise", - "fossilize", "fossilise", - "funneling", "funnelling", - "galvanize", "galvanise", - "gamboling", "gambolling", - "ghettoize", "ghettoise", - "globalize", "globalise", - "gonorrhea", "gonorrhoea", - "groveling", "grovelling", - "harboring", "harbouring", - "harmonize", "harmonise", - "honorably", "honourably", - "humanized", "humanised", - "humanizes", "humanises", - "hybridize", "hybridise", - "hypnotize", "hypnotise", - "idealized", "idealised", - "idealizes", "idealises", - "idolizing", "idolising", - "immunized", "immunised", - "immunizes", "immunises", - "impaneled", "impanelled", - "imperiled", "imperilled", - "initialed", "initialled", - "italicize", "italicise", - "itemizing", "itemising", - "kilometer", "kilometre", - "legalized", "legalised", - "legalizes", "legalises", - "lionizing", "lionising", - "liquidize", "liquidise", - "localized", "localised", - "localizes", "localises", - "magnetize", "magnetise", - "maneuvers", "manoeuvres", - "marshaled", "marshalled", - "marveling", "marvelling", - "marvelous", "marvellous", - "maximized", "maximised", - "maximizes", "maximises", - "mechanize", "mechanise", - "memorized", "memorised", - "memorizes", "memorises", - "mesmerize", "mesmerise", - "minimized", "minimised", - "minimizes", "minimises", - "mobilized", "mobilised", - "mobilizes", "mobilises", - "modernize", "modernise", - "moldering", "mouldering", - "moralized", "moralised", - "moralizes", "moralises", - "motorized", "motorised", - "mustached", "moustached", - "mustaches", "moustaches", - "neighbors", "neighbours", - "normalize", "normalise", - "optimized", "optimised", - "optimizes", "optimises", - "organized", "organised", - "organizer", "organiser", - "organizes", "organises", - "ostracize", "ostracise", - "oxidizing", "oxidising", - "panelists", "panellists", - "paralyzed", "paralysed", - "paralyzes", "paralyses", - "parceling", "parcelling", - "patronize", "patronise", - "pedophile", "paedophile", - "penalized", "penalised", - "penalizes", "penalises", - "penciling", "pencilling", - "plowshare", "ploughshare", - "polarized", "polarised", - "polarizes", "polarises", - "practiced", "practised", - "pretenses", "pretences", - "privatize", "privatise", - "publicize", "publicise", - "pulverize", "pulverise", - "quarreled", "quarrelled", - "randomize", "randomise", - "realizing", "realising", - "recognize", "recognise", - "refueling", "refuelling", - "remodeled", "remodelled", - "remolding", "remoulding", - "saltpeter", "saltpetre", - "sanitized", "sanitised", - "sanitizes", "sanitises", - "satirized", "satirised", - "satirizes", "satirises", - "sensitize", "sensitise", - "sepulcher", "sepulchre", - "serialize", "serialise", - "sermonize", "sermonise", - "shoveling", "shovelling", - "shriveled", "shrivelled", - "signaling", "signalling", - "signalize", "signalise", - "skeptical", "sceptical", - "sniveling", "snivelling", - "snorkeled", "snorkelled", - "socialize", "socialise", - "sodomized", "sodomised", - "sodomizes", "sodomises", - "solemnize", "solemnise", - "spiraling", "spiralling", - "splendors", "splendours", - "stabilize", "stabilise", - "stenciled", "stencilled", - "sterilize", "sterilise", - "subsidize", "subsidise", - "succoring", "succouring", - "sulfurous", "sulphurous", - "summarize", "summarise", - "swiveling", "swivelling", - "symbolize", "symbolise", - "tantalize", "tantalise", - "temporize", "temporise", - "tenderize", "tenderise", - "terrorize", "terrorise", - "theorized", "theorised", - "theorizes", "theorises", - "travelers", "travellers", - "traveling", "travelling", - "tricolors", "tricolours", - "tunneling", "tunnelling", - "tyrannize", "tyrannise", - "unequaled", "unequalled", - "unionized", "unionised", - "unionizes", "unionises", - "unraveled", "unravelled", - "unrivaled", "unrivalled", - "urbanized", "urbanised", - "urbanizes", "urbanises", - "utilizing", "utilising", - "vandalize", "vandalise", - "vaporized", "vaporised", - "vaporizes", "vaporises", - "verbalize", "verbalise", - "victimize", "victimise", - "visualize", "visualise", - "vocalized", "vocalised", - "vocalizes", "vocalises", - "vulgarize", "vulgarise", - "weaseling", "weaselling", - "womanized", "womanised", - "womanizer", "womaniser", - "womanizes", "womanises", - "worshiped", "worshipped", - "worshiper", "worshipper", - "agonized", "agonised", - "agonizes", "agonises", - "airplane", "aeroplane", - "aluminum", "aluminium", - "amortize", "amortise", - "analyzed", "analysed", - "analyzes", "analyses", - "armorers", "armourers", - "armories", "armouries", - "artifact", "artefact", - "baptized", "baptised", - "baptizes", "baptises", - "behavior", "behaviour", - "behooved", "behoved", - "behooves", "behoves", - "belabors", "belabours", - "calibers", "calibres", - "canalize", "canalise", - "canonize", "canonise", - "catalogs", "catalogues", - "catalyze", "catalyse", - "caviling", "cavilling", - "centered", "centred", - "chiseled", "chiselled", - "civilize", "civilise", - "clamored", "clamoured", - "colonize", "colonise", - "colorant", "colourant", - "coloreds", "coloureds", - "colorful", "colourful", - "coloring", "colouring", - "colorize", "colourize", - "coziness", "cosiness", - "cruelest", "cruellest", - "cudgeled", "cudgelled", - "defenses", "defences", - "demeanor", "demeanour", - "demonize", "demonise", - "deputize", "deputise", - "diarrhea", "diarrhoea", - "digitize", "digitise", - "disfavor", "disfavour", - "dishonor", "dishonour", - "distills", "distils", - "driveled", "drivelled", - "enameled", "enamelled", - "enamored", "enamoured", - "endeavor", "endeavour", - "energize", "energise", - "epaulets", "epaulettes", - "equalize", "equalise", - "estrogen", "oestrogen", - "etiology", "aetiology", - "eulogize", "eulogise", - "favoring", "favouring", - "favorite", "favourite", - "feminize", "feminise", - "finalize", "finalise", - "flavored", "flavoured", - "flutists", "flautists", - "fulfills", "fulfils", - "funneled", "funnelled", - "gamboled", "gambolled", - "graveled", "gravelled", - "groveled", "grovelled", - "grueling", "gruelling", - "harbored", "harboured", - "honoring", "honouring", - "humanize", "humanise", - "humoring", "humouring", - "idealize", "idealise", - "idolized", "idolised", - "idolizes", "idolises", - "immunize", "immunise", - "ionizing", "ionising", - "itemized", "itemised", - "itemizes", "itemises", - "jewelers", "jewellers", - "labeling", "labelling", - "laborers", "labourers", - "laboring", "labouring", - "legalize", "legalise", - "leukemia", "leukaemia", - "levelers", "levellers", - "leveling", "levelling", - "libeling", "libelling", - "libelous", "libellous", - "lionized", "lionised", - "lionizes", "lionises", - "localize", "localise", - "louvered", "louvred", - "maneuver", "manoeuvre", - "marveled", "marvelled", - "maximize", "maximise", - "memorize", "memorise", - "minimize", "minimise", - "mobilize", "mobilise", - "modelers", "modellers", - "modeling", "modelling", - "moldered", "mouldered", - "moldiest", "mouldiest", - "moldings", "mouldings", - "moralize", "moralise", - "mustache", "moustache", - "neighbor", "neighbour", - "odorless", "odourless", - "offenses", "offences", - "optimize", "optimise", - "organize", "organise", - "oxidized", "oxidised", - "oxidizes", "oxidises", - "paneling", "panelling", - "panelist", "panellist", - "paralyze", "paralyse", - "parceled", "parcelled", - "pedaling", "pedalling", - "penalize", "penalise", - "penciled", "pencilled", - "polarize", "polarise", - "pretense", "pretence", - "pummeled", "pummelling", - "raveling", "ravelling", - "realized", "realised", - "realizes", "realises", - "refueled", "refuelled", - "remolded", "remoulded", - "revelers", "revellers", - "reveling", "revelling", - "rivaling", "rivalling", - "sanitize", "sanitise", - "satirize", "satirise", - "savories", "savouries", - "savoring", "savouring", - "scepters", "sceptres", - "shoveled", "shovelled", - "signaled", "signalled", - "skeptics", "sceptics", - "sniveled", "snivelled", - "sodomize", "sodomise", - "specters", "spectres", - "spiraled", "spiralled", - "splendor", "splendour", - "succored", "succoured", - "sulfates", "sulphates", - "sulfides", "sulphides", - "swiveled", "swivelled", - "tasseled", "tasselled", - "theaters", "theatres", - "theorize", "theorise", - "toweling", "towelling", - "traveler", "traveller", - "trialing", "trialling", - "tricolor", "tricolour", - "tunneled", "tunnelled", - "unionize", "unionise", - "unsavory", "unsavoury", - "urbanize", "urbanise", - "utilized", "utilised", - "utilizes", "utilises", - "vaporize", "vaporise", - "vocalize", "vocalise", - "weaseled", "weaselled", - "womanize", "womanise", - "yodeling", "yodelling", - "agonize", "agonise", - "analyze", "analyse", - "appalls", "appals", - "armored", "armoured", - "armorer", "armourer", - "baptize", "baptise", - "behoove", "behove", - "belabor", "belabour", - "beveled", "bevelled", - "caliber", "calibre", - "caroled", "carolled", - "caviled", "cavilled", - "centers", "centres", - "clamors", "clamours", - "clangor", "clangour", - "colored", "coloured", - "coziest", "cosiest", - "crueler", "crueller", - "defense", "defence", - "dialing", "dialling", - "dialogs", "dialogues", - "distill", "distil", - "dueling", "duelling", - "enrolls", "enrols", - "epaulet", "epaulette", - "favored", "favoured", - "flavors", "flavours", - "flutist", "flautist", - "fueling", "fuelling", - "fulfill", "fulfil", - "goiters", "goitres", - "harbors", "harbours", - "honored", "honoured", - "humored", "humoured", - "idolize", "idolise", - "ionized", "ionised", - "ionizes", "ionises", - "itemize", "itemise", - "jeweled", "jewelled", - "jeweler", "jeweller", - "jewelry", "jewellery", - "labeled", "labelled", - "labored", "laboured", - "laborer", "labourer", - "leveled", "levelled", - "leveler", "leveller", - "libeled", "libelled", - "lionize", "lionise", - "louvers", "louvres", - "modeled", "modelled", - "modeler", "modeller", - "molders", "moulders", - "moldier", "mouldier", - "molding", "moulding", - "molting", "moulting", - "offense", "offence", - "oxidize", "oxidise", - "pajamas", "pyjamas", - "paneled", "panelled", - "parlors", "parlours", - "pedaled", "pedalled", - "plowing", "ploughing", - "plowman", "ploughman", - "plowmen", "ploughmen", - "realize", "realise", - "remolds", "remoulds", - "reveled", "revelled", - "reveler", "reveller", - "rivaled", "rivalled", - "rumored", "rumoured", - "saviors", "saviours", - "savored", "savoured", - "scepter", "sceptre", - "skeptic", "sceptic", - "specter", "spectre", - "succors", "succours", - "sulfate", "sulphate", - "sulfide", "sulphide", - "theater", "theatre", - "toweled", "towelled", - "toxemia", "toxaemia", - "trialed", "trialled", - "utilize", "utilise", - "yodeled", "yodelled", - "anemia", "anaemia", - "anemic", "anaemic", - "appall", "appal", - "arbors", "arbours", - "armory", "armoury", - "candor", "candour", - "center", "centre", - "clamor", "clamour", - "colors", "colours", - "cozier", "cosier", - "cozies", "cosies", - "cozily", "cosily", - "dialed", "dialled", - "drafty", "draughty", - "dueled", "duelled", - "favors", "favours", - "fervor", "fervour", - "fibers", "fibres", - "flavor", "flavour", - "fueled", "fuelled", - "goiter", "goitre", - "harbor", "harbour", - "honors", "honours", - "humors", "humours", - "labors", "labours", - "liters", "litres", - "louver", "louvre", - "luster", "lustre", - "meager", "meagre", - "miters", "mitres", - "molded", "moulded", - "molder", "moulder", - "molted", "moulted", - "pajama", "pyjama", - "parlor", "parlour", - "plowed", "ploughed", - "rancor", "rancour", - "remold", "remould", - "rigors", "rigours", - "rumors", "rumours", - "savors", "savours", - "savory", "savoury", - "succor", "succour", - "tumors", "tumours", - "vapors", "vapours", - "aging", "ageing", - "arbor", "arbour", - "ardor", "ardour", - "armor", "armour", - "chili", "chilli", - "color", "colour", - "edema", "edoema", - "favor", "favour", - "fecal", "faecal", - "feces", "faeces", - "fiber", "fibre", - "honor", "honour", - "humor", "humour", - "labor", "labour", - "liter", "litre", - "miter", "mitre", - "molds", "moulds", - "moldy", "mouldy", - "molts", "moults", - "odors", "odours", - "plows", "ploughs", - "rigor", "rigour", - "rumor", "rumour", - "savor", "savour", - "valor", "valour", - "vapor", "vapour", - "vigor", "vigour", - "cozy", "cosy", - "mold", "mould", - "molt", "moult", - "odor", "odour", - "plow", "plough", -} diff --git a/vendor/github.com/golangci/misspell/words_uk.go b/vendor/github.com/golangci/misspell/words_uk.go new file mode 100644 index 000000000..01ae08702 --- /dev/null +++ b/vendor/github.com/golangci/misspell/words_uk.go @@ -0,0 +1,1484 @@ +// Code generated by 'internal/gen'. DO NOT EDIT. + +package misspell + +// DictBritish converts US spellings to UK spellings +var DictBritish = []string{ + "institutionalization", "institutionalisation", + "internationalization", "internationalisation", + "professionalization", "professionalisation", + "compartmentalizing", "compartmentalising", + "institutionalizing", "institutionalising", + "internationalizing", "internationalising", + "compartmentalized", "compartmentalised", + "compartmentalizes", "compartmentalises", + "decriminalization", "decriminalisation", + "denationalization", "denationalisation", + "fictionalizations", "fictionalisations", + "institutionalized", "institutionalised", + "institutionalizes", "institutionalises", + "intellectualizing", "intellectualising", + "internationalized", "internationalised", + "internationalizes", "internationalises", + "pedestrianization", "pedestrianisation", + "professionalizing", "professionalising", + "compartmentalize", "compartmentalise", + "decentralization", "decentralisation", + "demilitarization", "demilitarisation", + "externalizations", "externalisations", + "fictionalization", "fictionalisation", + "institutionalize", "institutionalise", + "intellectualized", "intellectualised", + "intellectualizes", "intellectualises", + "internationalize", "internationalise", + "nationalizations", "nationalisations", + "professionalized", "professionalised", + "professionalizes", "professionalises", + "rationalizations", "rationalisations", + "sensationalizing", "sensationalising", + "sentimentalizing", "sentimentalising", + "acclimatization", "acclimatisation", + "commercializing", "commercialising", + "conceptualizing", "conceptualising", + "contextualizing", "contextualising", + "crystallization", "crystallisation", + "decriminalizing", "decriminalising", + "democratization", "democratisation", + "denationalizing", "denationalising", + "depersonalizing", "depersonalising", + "desensitization", "desensitisation", + "disorganization", "disorganisation", + "extemporization", "extemporisation", + "externalization", "externalisation", + "familiarization", "familiarisation", + "generalizations", "generalisations", + "hospitalization", "hospitalisation", + "individualizing", "individualising", + "industrializing", "industrialising", + "intellectualize", "intellectualise", + "internalization", "internalisation", + "maneuverability", "manoeuvrability", + "materialization", "materialisation", + "miniaturization", "miniaturisation", + "nationalization", "nationalisation", + "overemphasizing", "overemphasising", + "paleontologists", "palaeontologists", + "particularizing", "particularising", + "pedestrianizing", "pedestrianising", + "professionalize", "professionalise", + "psychoanalyzing", "psychoanalysing", + "rationalization", "rationalisation", + "reorganizations", "reorganisations", + "revolutionizing", "revolutionising", + "sensationalized", "sensationalised", + "sensationalizes", "sensationalises", + "sentimentalized", "sentimentalised", + "sentimentalizes", "sentimentalises", + "specializations", "specialisations", + "standardization", "standardisation", + "synchronization", "synchronisation", + "systematization", "systematisation", + "aggrandizement", "aggrandisement", + "characterizing", "characterising", + "collectivizing", "collectivising", + "commercialized", "commercialised", + "commercializes", "commercialises", + "conceptualized", "conceptualised", + "conceptualizes", "conceptualises", + "contextualized", "contextualised", + "contextualizes", "contextualises", + "decentralizing", "decentralising", + "decriminalized", "decriminalised", + "decriminalizes", "decriminalises", + "dehumanization", "dehumanisation", + "demilitarizing", "demilitarising", + "demobilization", "demobilisation", + "demoralization", "demoralisation", + "denationalized", "denationalised", + "denationalizes", "denationalises", + "depersonalized", "depersonalised", + "depersonalizes", "depersonalises", + "dramatizations", "dramatisations", + "editorializing", "editorialising", + "fictionalizing", "fictionalising", + "fraternization", "fraternisation", + "generalization", "generalisation", + "immobilization", "immobilisation", + "individualized", "individualised", + "individualizes", "individualises", + "industrialized", "industrialised", + "industrializes", "industrialises", + "liberalization", "liberalisation", + "monopolization", "monopolisation", + "naturalization", "naturalisation", + "neighborliness", "neighbourliness", + "neutralization", "neutralisation", + "organizational", "organisational", + "outmaneuvering", "outmanoeuvring", + "overemphasized", "overemphasised", + "overemphasizes", "overemphasises", + "paleontologist", "palaeontologist", + "particularized", "particularised", + "particularizes", "particularises", + "pasteurization", "pasteurisation", + "pedestrianized", "pedestrianised", + "pedestrianizes", "pedestrianises", + "philosophizing", "philosophising", + "politicization", "politicisation", + "popularization", "popularisation", + "pressurization", "pressurisation", + "prioritization", "prioritisation", + "privatizations", "privatisations", + "propagandizing", "propagandising", + "psychoanalyzed", "psychoanalysed", + "psychoanalyzes", "psychoanalyses", + "reconnoitering", "reconnoitring", + "regularization", "regularisation", + "reorganization", "reorganisation", + "revolutionized", "revolutionised", + "revolutionizes", "revolutionises", + "secularization", "secularisation", + "sensationalize", "sensationalise", + "sentimentalize", "sentimentalise", + "serializations", "serialisations", + "specialization", "specialisation", + "sterilizations", "sterilisations", + "stigmatization", "stigmatisation", + "transistorized", "transistorised", + "unrecognizable", "unrecognisable", + "visualizations", "visualisations", + "westernization", "westernisation", + "accessorizing", "accessorising", + "acclimatizing", "acclimatising", + "amortizations", "amortisations", + "amphitheaters", "amphitheatres", + "anesthetizing", "anaesthetising", + "archeologists", "archaeologists", + "breathalyzers", "breathalysers", + "breathalyzing", "breathalysing", + "cannibalizing", "cannibalising", + "characterized", "characterised", + "characterizes", "characterises", + "circularizing", "circularising", + "collectivized", "collectivised", + "collectivizes", "collectivises", + "commercialize", "commercialise", + "computerizing", "computerising", + "conceptualize", "conceptualise", + "contextualize", "contextualise", + "criminalizing", "criminalising", + "crystallizing", "crystallising", + "decentralized", "decentralised", + "decentralizes", "decentralises", + "decriminalize", "decriminalise", + "demilitarized", "demilitarised", + "demilitarizes", "demilitarises", + "democratizing", "democratising", + "denationalize", "denationalise", + "depersonalize", "depersonalise", + "desensitizing", "desensitising", + "destabilizing", "destabilising", + "disemboweling", "disembowelling", + "dramatization", "dramatisation", + "editorialized", "editorialised", + "editorializes", "editorialises", + "extemporizing", "extemporising", + "externalizing", "externalising", + "familiarizing", "familiarising", + "fertilization", "fertilisation", + "fictionalized", "fictionalised", + "fictionalizes", "fictionalises", + "formalization", "formalisation", + "fossilization", "fossilisation", + "globalization", "globalisation", + "gynecological", "gynaecological", + "gynecologists", "gynaecologists", + "harmonization", "harmonisation", + "hematological", "haematological", + "hematologists", "haematologists", + "hospitalizing", "hospitalising", + "hypothesizing", "hypothesising", + "immortalizing", "immortalising", + "individualize", "individualise", + "industrialize", "industrialise", + "internalizing", "internalising", + "marginalizing", "marginalising", + "materializing", "materialising", + "mechanization", "mechanisation", + "memorializing", "memorialising", + "miniaturizing", "miniaturising", + "nationalizing", "nationalising", + "neighborhoods", "neighbourhoods", + "normalization", "normalisation", + "organizations", "organisations", + "outmaneuvered", "outmanoeuvred", + "overemphasize", "overemphasise", + "particularize", "particularise", + "passivization", "passivisation", + "patronizingly", "patronisingly", + "pedestrianize", "pedestrianise", + "pediatricians", "paediatricians", + "personalizing", "personalising", + "philosophized", "philosophised", + "philosophizes", "philosophises", + "privatization", "privatisation", + "propagandized", "propagandised", + "propagandizes", "propagandises", + "proselytizers", "proselytisers", + "proselytizing", "proselytising", + "psychoanalyze", "psychoanalyse", + "pulverization", "pulverisation", + "rationalizing", "rationalising", + "reconnoitered", "reconnoitred", + "revolutionize", "revolutionise", + "romanticizing", "romanticising", + "serialization", "serialisation", + "socialization", "socialisation", + "standardizing", "standardising", + "sterilization", "sterilisation", + "subsidization", "subsidisation", + "synchronizing", "synchronising", + "systematizing", "systematising", + "tantalizingly", "tantalisingly", + "underutilized", "underutilised", + "victimization", "victimisation", + "visualization", "visualisation", + "vocalizations", "vocalisations", + "vulgarization", "vulgarisation", + "accessorized", "accessorised", + "accessorizes", "accessorises", + "acclimatized", "acclimatised", + "acclimatizes", "acclimatises", + "amortization", "amortisation", + "amphitheater", "amphitheatre", + "anesthetists", "anaesthetists", + "anesthetized", "anaesthetised", + "anesthetizes", "anaesthetises", + "antagonizing", "antagonising", + "appetizingly", "appetisingly", + "archeologist", "archaeologist", + "backpedaling", "backpedalling", + "bastardizing", "bastardising", + "behaviorists", "behaviourists", + "bowdlerizing", "bowdlerising", + "breathalyzed", "breathalysed", + "breathalyzes", "breathalyses", + "cannibalized", "cannibalised", + "cannibalizes", "cannibalises", + "capitalizing", "capitalising", + "caramelizing", "caramelising", + "categorizing", "categorising", + "centerpieces", "centrepieces", + "centralizing", "centralising", + "characterize", "characterise", + "circularized", "circularised", + "circularizes", "circularises", + "clarinetists", "clarinettists", + "collectivize", "collectivise", + "colonization", "colonisation", + "computerized", "computerised", + "computerizes", "computerises", + "criminalized", "criminalised", + "criminalizes", "criminalises", + "crystallized", "crystallised", + "crystallizes", "crystallises", + "decentralize", "decentralise", + "dehumanizing", "dehumanising", + "demilitarize", "demilitarise", + "demobilizing", "demobilising", + "democratized", "democratised", + "democratizes", "democratises", + "demoralizing", "demoralising", + "desensitized", "desensitised", + "desensitizes", "desensitises", + "destabilized", "destabilised", + "destabilizes", "destabilises", + "disemboweled", "disembowelled", + "dishonorable", "dishonourable", + "dishonorably", "dishonourably", + "disorganized", "disorganised", + "editorialize", "editorialise", + "equalization", "equalisation", + "evangelizing", "evangelising", + "extemporized", "extemporised", + "extemporizes", "extemporises", + "externalized", "externalised", + "externalizes", "externalises", + "familiarized", "familiarised", + "familiarizes", "familiarises", + "fictionalize", "fictionalise", + "finalization", "finalisation", + "fraternizing", "fraternising", + "generalizing", "generalising", + "gynecologist", "gynaecologist", + "hematologist", "haematologist", + "hemophiliacs", "haemophiliacs", + "hemorrhaging", "haemorrhaging", + "homogenizing", "homogenising", + "hospitalized", "hospitalised", + "hospitalizes", "hospitalises", + "hypothesized", "hypothesised", + "hypothesizes", "hypothesises", + "idealization", "idealisation", + "immobilizers", "immobilisers", + "immobilizing", "immobilising", + "immortalized", "immortalised", + "immortalizes", "immortalises", + "immunization", "immunisation", + "initializing", "initialising", + "installments", "instalments", + "internalized", "internalised", + "internalizes", "internalises", + "jeopardizing", "jeopardising", + "legalization", "legalisation", + "legitimizing", "legitimising", + "liberalizing", "liberalising", + "maneuverable", "manoeuvrable", + "maneuverings", "manoeuvrings", + "marginalized", "marginalised", + "marginalizes", "marginalises", + "materialized", "materialised", + "materializes", "materialises", + "maximization", "maximisation", + "memorialized", "memorialised", + "memorializes", "memorialises", + "metabolizing", "metabolising", + "militarizing", "militarising", + "miniaturized", "miniaturised", + "miniaturizes", "miniaturises", + "miscataloged", "miscatalogued", + "misdemeanors", "misdemeanours", + "mobilization", "mobilisation", + "moisturizers", "moisturisers", + "moisturizing", "moisturising", + "monopolizing", "monopolising", + "multicolored", "multicoloured", + "nationalized", "nationalised", + "nationalizes", "nationalises", + "naturalizing", "naturalising", + "neighborhood", "neighbourhood", + "neutralizing", "neutralising", + "organization", "organisation", + "outmaneuvers", "outmanoeuvres", + "paleontology", "palaeontology", + "pasteurizing", "pasteurising", + "pediatrician", "paediatrician", + "personalized", "personalised", + "personalizes", "personalises", + "philosophize", "philosophise", + "plagiarizing", "plagiarising", + "polarization", "polarisation", + "politicizing", "politicising", + "popularizing", "popularising", + "pressurizing", "pressurising", + "prioritizing", "prioritising", + "propagandize", "propagandise", + "proselytized", "proselytised", + "proselytizer", "proselytiser", + "proselytizes", "proselytises", + "radicalizing", "radicalising", + "rationalized", "rationalised", + "rationalizes", "rationalises", + "realizations", "realisations", + "recognizable", "recognisable", + "recognizably", "recognisably", + "recognizance", "recognisance", + "reconnoiters", "reconnoitres", + "regularizing", "regularising", + "reorganizing", "reorganising", + "revitalizing", "revitalising", + "rhapsodizing", "rhapsodising", + "romanticized", "romanticised", + "romanticizes", "romanticises", + "scandalizing", "scandalising", + "scrutinizing", "scrutinising", + "secularizing", "secularising", + "standardized", "standardised", + "standardizes", "standardises", + "stigmatizing", "stigmatising", + "sympathizers", "sympathisers", + "sympathizing", "sympathising", + "synchronized", "synchronised", + "synchronizes", "synchronises", + "synthesizing", "synthesising", + "systematized", "systematised", + "systematizes", "systematises", + "theatergoers", "theatregoers", + "traumatizing", "traumatising", + "trivializing", "trivialising", + "unauthorized", "unauthorised", + "unionization", "unionisation", + "unrecognized", "unrecognised", + "urbanization", "urbanisation", + "vaporization", "vaporisation", + "vocalization", "vocalisation", + "westernizing", "westernising", + "accessorize", "accessorise", + "acclimatize", "acclimatise", + "agonizingly", "agonisingly", + "amortizable", "amortisable", + "anesthetics", "anaesthetics", + "anesthetist", "anaesthetist", + "anesthetize", "anaesthetise", + "anglicizing", "anglicising", + "antagonized", "antagonised", + "antagonizes", "antagonises", + "apologizing", "apologising", + "backpedaled", "backpedalled", + "bastardized", "bastardised", + "bastardizes", "bastardises", + "behaviorism", "behaviourism", + "behaviorist", "behaviourist", + "bowdlerized", "bowdlerised", + "bowdlerizes", "bowdlerises", + "brutalizing", "brutalising", + "cannibalize", "cannibalise", + "capitalized", "capitalised", + "capitalizes", "capitalises", + "caramelized", "caramelised", + "caramelizes", "caramelises", + "carbonizing", "carbonising", + "categorized", "categorised", + "categorizes", "categorises", + "cauterizing", "cauterising", + "centerfolds", "centrefolds", + "centerpiece", "centrepiece", + "centiliters", "centilitres", + "centimeters", "centimetres", + "centralized", "centralised", + "centralizes", "centralises", + "circularize", "circularise", + "clarinetist", "clarinettist", + "computerize", "computerise", + "criminalize", "criminalise", + "criticizing", "criticising", + "crystallize", "crystallise", + "customizing", "customising", + "defenseless", "defenceless", + "dehumanized", "dehumanised", + "dehumanizes", "dehumanises", + "demobilized", "demobilised", + "demobilizes", "demobilises", + "democratize", "democratise", + "demoralized", "demoralised", + "demoralizes", "demoralises", + "deodorizing", "deodorising", + "desensitize", "desensitise", + "destabilize", "destabilise", + "discoloring", "discolouring", + "dishonoring", "dishonouring", + "dramatizing", "dramatising", + "economizing", "economising", + "empathizing", "empathising", + "emphasizing", "emphasising", + "endeavoring", "endeavouring", + "epitomizing", "epitomising", + "esophaguses", "oesophaguses", + "evangelized", "evangelised", + "evangelizes", "evangelises", + "extemporize", "extemporise", + "externalize", "externalise", + "factorizing", "factorising", + "familiarize", "familiarise", + "fantasizing", "fantasising", + "fertilizers", "fertilisers", + "fertilizing", "fertilising", + "formalizing", "formalising", + "fossilizing", "fossilising", + "fraternized", "fraternised", + "fraternizes", "fraternises", + "fulfillment", "fulfilment", + "galvanizing", "galvanising", + "generalized", "generalised", + "generalizes", "generalises", + "ghettoizing", "ghettoising", + "globalizing", "globalising", + "harmonizing", "harmonising", + "hemophiliac", "haemophiliac", + "hemorrhaged", "haemorrhaged", + "hemorrhages", "haemorrhages", + "hemorrhoids", "haemorrhoids", + "homogenized", "homogenised", + "homogenizes", "homogenises", + "hospitalize", "hospitalise", + "hybridizing", "hybridising", + "hypnotizing", "hypnotising", + "hypothesize", "hypothesise", + "immobilized", "immobilised", + "immobilizer", "immobiliser", + "immobilizes", "immobilises", + "immortalize", "immortalise", + "initialized", "initialised", + "initializes", "initialises", + "installment", "instalment", + "internalize", "internalise", + "italicizing", "italicising", + "jeopardized", "jeopardised", + "jeopardizes", "jeopardises", + "legitimized", "legitimised", + "legitimizes", "legitimises", + "liberalized", "liberalised", + "liberalizes", "liberalises", + "lionization", "lionisation", + "liquidizers", "liquidisers", + "liquidizing", "liquidising", + "magnetizing", "magnetising", + "maneuvering", "manoeuvring", + "marginalize", "marginalise", + "marvelously", "marvellously", + "materialize", "materialise", + "mechanizing", "mechanising", + "memorialize", "memorialise", + "mesmerizing", "mesmerising", + "metabolized", "metabolised", + "metabolizes", "metabolises", + "militarized", "militarised", + "militarizes", "militarises", + "milliliters", "millilitres", + "millimeters", "millimetres", + "miniaturize", "miniaturise", + "misbehavior", "misbehaviour", + "misdemeanor", "misdemeanour", + "modernizing", "modernising", + "moisturized", "moisturised", + "moisturizer", "moisturiser", + "moisturizes", "moisturises", + "monopolized", "monopolised", + "monopolizes", "monopolises", + "nationalize", "nationalise", + "naturalized", "naturalised", + "naturalizes", "naturalises", + "neighboring", "neighbouring", + "neutralized", "neutralised", + "neutralizes", "neutralises", + "normalizing", "normalising", + "orthopedics", "orthopaedics", + "ostracizing", "ostracising", + "outmaneuver", "outmanoeuvre", + "oxidization", "oxidisation", + "pasteurized", "pasteurised", + "pasteurizes", "pasteurises", + "patronizing", "patronising", + "personalize", "personalise", + "plagiarized", "plagiarised", + "plagiarizes", "plagiarises", + "politicized", "politicised", + "politicizes", "politicises", + "popularized", "popularised", + "popularizes", "popularises", + "pressurized", "pressurised", + "pressurizes", "pressurises", + "prioritized", "prioritised", + "prioritizes", "prioritises", + "privatizing", "privatising", + "proselytize", "proselytise", + "publicizing", "publicising", + "pulverizing", "pulverising", + "radicalized", "radicalised", + "radicalizes", "radicalises", + "randomizing", "randomising", + "rationalize", "rationalise", + "realization", "realisation", + "recognizing", "recognising", + "reconnoiter", "reconnoitre", + "regularized", "regularised", + "regularizes", "regularises", + "reorganized", "reorganised", + "reorganizes", "reorganises", + "revitalized", "revitalised", + "revitalizes", "revitalises", + "rhapsodized", "rhapsodised", + "rhapsodizes", "rhapsodises", + "romanticize", "romanticise", + "scandalized", "scandalised", + "scandalizes", "scandalises", + "scrutinized", "scrutinised", + "scrutinizes", "scrutinises", + "secularized", "secularised", + "secularizes", "secularises", + "sensitizing", "sensitising", + "serializing", "serialising", + "sermonizing", "sermonising", + "signalizing", "signalising", + "skeptically", "sceptically", + "socializing", "socialising", + "solemnizing", "solemnising", + "specialized", "specialised", + "specializes", "specialises", + "squirreling", "squirrelling", + "stabilizers", "stabilisers", + "stabilizing", "stabilising", + "standardize", "standardise", + "sterilizers", "sterilisers", + "sterilizing", "sterilising", + "stigmatized", "stigmatised", + "stigmatizes", "stigmatises", + "subsidizers", "subsidisers", + "subsidizing", "subsidising", + "summarizing", "summarising", + "symbolizing", "symbolising", + "sympathized", "sympathised", + "sympathizer", "sympathiser", + "sympathizes", "sympathises", + "synchronize", "synchronise", + "synthesized", "synthesised", + "synthesizes", "synthesises", + "systematize", "systematise", + "tantalizing", "tantalising", + "temporizing", "temporising", + "tenderizing", "tenderising", + "terrorizing", "terrorising", + "theatergoer", "theatregoer", + "traumatized", "traumatised", + "traumatizes", "traumatises", + "trivialized", "trivialised", + "trivializes", "trivialises", + "tyrannizing", "tyrannising", + "uncataloged", "uncatalogued", + "uncivilized", "uncivilised", + "unfavorable", "unfavourable", + "unfavorably", "unfavourably", + "unorganized", "unorganised", + "untrammeled", "untrammelled", + "utilization", "utilisation", + "vandalizing", "vandalising", + "verbalizing", "verbalising", + "victimizing", "victimising", + "visualizing", "visualising", + "vulgarizing", "vulgarising", + "watercolors", "watercolours", + "westernized", "westernised", + "westernizes", "westernises", + "amortizing", "amortising", + "anesthesia", "anaesthesia", + "anesthetic", "anaesthetic", + "anglicized", "anglicised", + "anglicizes", "anglicises", + "annualized", "annualised", + "antagonize", "antagonise", + "apologized", "apologised", + "apologizes", "apologises", + "appetizers", "appetisers", + "appetizing", "appetising", + "archeology", "archaeology", + "authorizes", "authorises", + "bastardize", "bastardise", + "bedeviling", "bedevilling", + "behavioral", "behavioural", + "belaboring", "belabouring", + "bowdlerize", "bowdlerise", + "brutalized", "brutalised", + "brutalizes", "brutalises", + "canalizing", "canalising", + "canonizing", "canonising", + "capitalize", "capitalise", + "caramelize", "caramelise", + "carbonized", "carbonised", + "carbonizes", "carbonises", + "cataloging", "cataloguing", + "catalyzing", "catalysing", + "categorize", "categorise", + "cauterized", "cauterised", + "cauterizes", "cauterises", + "centerfold", "centrefold", + "centiliter", "centilitre", + "centimeter", "centimetre", + "centralize", "centralise", + "channeling", "channelling", + "checkbooks", "chequebooks", + "civilizing", "civilising", + "colonizers", "colonisers", + "colonizing", "colonising", + "colorfully", "colourfully", + "colorizing", "colourizing", + "councilors", "councillors", + "counselors", "counsellors", + "criticized", "criticised", + "criticizes", "criticises", + "customized", "customised", + "customizes", "customises", + "dehumanize", "dehumanise", + "demobilize", "demobilise", + "demonizing", "demonising", + "demoralize", "demoralise", + "deodorized", "deodorised", + "deodorizes", "deodorises", + "deputizing", "deputising", + "digitizing", "digitising", + "discolored", "discoloured", + "disheveled", "dishevelled", + "dishonored", "dishonoured", + "dramatized", "dramatised", + "dramatizes", "dramatises", + "economized", "economised", + "economizes", "economises", + "empathized", "empathised", + "empathizes", "empathises", + "emphasized", "emphasised", + "emphasizes", "emphasises", + "endeavored", "endeavoured", + "energizing", "energising", + "epicenters", "epicentres", + "epitomized", "epitomised", + "epitomizes", "epitomises", + "equalizers", "equalisers", + "equalizing", "equalising", + "eulogizing", "eulogising", + "evangelize", "evangelise", + "factorized", "factorised", + "factorizes", "factorises", + "fantasized", "fantasised", + "fantasizes", "fantasises", + "favoritism", "favouritism", + "feminizing", "feminising", + "fertilized", "fertilised", + "fertilizer", "fertiliser", + "fertilizes", "fertilises", + "fiberglass", "fibreglass", + "finalizing", "finalising", + "flavorings", "flavourings", + "flavorless", "flavourless", + "flavorsome", "flavoursome", + "formalized", "formalised", + "formalizes", "formalises", + "fossilized", "fossilised", + "fossilizes", "fossilises", + "fraternize", "fraternise", + "galvanized", "galvanised", + "galvanizes", "galvanises", + "generalize", "generalise", + "ghettoized", "ghettoised", + "ghettoizes", "ghettoises", + "globalized", "globalised", + "globalizes", "globalises", + "gruelingly", "gruellingly", + "gynecology", "gynaecology", + "harmonized", "harmonised", + "harmonizes", "harmonises", + "hematology", "haematology", + "hemoglobin", "haemoglobin", + "hemophilia", "haemophilia", + "hemorrhage", "haemorrhage", + "homogenize", "homogenise", + "humanizing", "humanising", + "hybridized", "hybridised", + "hybridizes", "hybridises", + "hypnotized", "hypnotised", + "hypnotizes", "hypnotises", + "idealizing", "idealising", + "immobilize", "immobilise", + "immunizing", "immunising", + "impaneling", "impanelling", + "imperiling", "imperilling", + "initialing", "initialling", + "initialize", "initialise", + "ionization", "ionisation", + "italicized", "italicised", + "italicizes", "italicises", + "jeopardize", "jeopardise", + "kilometers", "kilometres", + "lackluster", "lacklustre", + "legalizing", "legalising", + "legitimize", "legitimise", + "liberalize", "liberalise", + "liquidized", "liquidised", + "liquidizer", "liquidiser", + "liquidizes", "liquidises", + "localizing", "localising", + "magnetized", "magnetised", + "magnetizes", "magnetises", + "maneuvered", "manoeuvred", + "marshaling", "marshalling", + "maximizing", "maximising", + "mechanized", "mechanised", + "mechanizes", "mechanises", + "memorizing", "memorising", + "mesmerized", "mesmerised", + "mesmerizes", "mesmerises", + "metabolize", "metabolise", + "militarize", "militarise", + "milliliter", "millilitre", + "millimeter", "millimetre", + "minimizing", "minimising", + "mobilizing", "mobilising", + "modernized", "modernised", + "modernizes", "modernises", + "moisturize", "moisturise", + "monopolize", "monopolise", + "moralizing", "moralising", + "naturalize", "naturalise", + "neighborly", "neighbourly", + "neutralize", "neutralise", + "normalized", "normalised", + "normalizes", "normalises", + "optimizing", "optimising", + "organizers", "organisers", + "organizing", "organising", + "orthopedic", "orthopaedic", + "ostracized", "ostracised", + "ostracizes", "ostracises", + "paralyzing", "paralysing", + "pasteurize", "pasteurise", + "patronized", "patronised", + "patronizes", "patronises", + "pedophiles", "paedophiles", + "pedophilia", "paedophilia", + "penalizing", "penalising", + "plagiarize", "plagiarise", + "plowshares", "ploughshares", + "polarizing", "polarising", + "politicize", "politicise", + "popularize", "popularise", + "prioritize", "prioritise", + "privatized", "privatised", + "privatizes", "privatises", + "publicized", "publicised", + "publicizes", "publicises", + "pulverized", "pulverised", + "pulverizes", "pulverises", + "quarreling", "quarrelling", + "radicalize", "radicalise", + "randomized", "randomised", + "randomizes", "randomises", + "realizable", "realisable", + "recognized", "recognised", + "recognizes", "recognises", + "regularize", "regularise", + "remodeling", "remodelling", + "reorganize", "reorganise", + "revitalize", "revitalise", + "rhapsodize", "rhapsodise", + "ritualized", "ritualised", + "sanitizing", "sanitising", + "satirizing", "satirising", + "scandalize", "scandalise", + "scrutinize", "scrutinise", + "secularize", "secularise", + "sensitized", "sensitised", + "sensitizes", "sensitises", + "sepulchers", "sepulchres", + "serialized", "serialised", + "serializes", "serialises", + "sermonized", "sermonised", + "sermonizes", "sermonises", + "shriveling", "shrivelling", + "signalized", "signalised", + "signalizes", "signalises", + "skepticism", "scepticism", + "socialized", "socialised", + "socializes", "socialises", + "sodomizing", "sodomising", + "solemnized", "solemnised", + "solemnizes", "solemnises", + "specialize", "specialise", + "squirreled", "squirrelled", + "stabilized", "stabilised", + "stabilizer", "stabiliser", + "stabilizes", "stabilises", + "stenciling", "stencilling", + "sterilized", "sterilised", + "sterilizer", "steriliser", + "sterilizes", "sterilises", + "stigmatize", "stigmatise", + "subsidized", "subsidised", + "subsidizer", "subsidiser", + "subsidizes", "subsidises", + "summarized", "summarised", + "summarizes", "summarises", + "symbolized", "symbolised", + "symbolizes", "symbolises", + "sympathize", "sympathise", + "tantalized", "tantalised", + "tantalizes", "tantalises", + "temporized", "temporised", + "temporizes", "temporises", + "tenderized", "tenderised", + "tenderizes", "tenderises", + "terrorized", "terrorised", + "terrorizes", "terrorises", + "theorizing", "theorising", + "traumatize", "traumatise", + "trivialize", "trivialise", + "tyrannized", "tyrannised", + "tyrannizes", "tyrannises", + "unionizing", "unionising", + "unraveling", "unravelling", + "urbanizing", "urbanising", + "utilizable", "utilisable", + "vandalized", "vandalised", + "vandalizes", "vandalises", + "vaporizing", "vaporising", + "verbalized", "verbalised", + "verbalizes", "verbalises", + "victimized", "victimised", + "victimizes", "victimises", + "visualized", "visualised", + "visualizes", "visualises", + "vocalizing", "vocalising", + "vulcanized", "vulcanised", + "vulgarized", "vulgarised", + "vulgarizes", "vulgarises", + "watercolor", "watercolour", + "westernize", "westernise", + "womanizers", "womanisers", + "womanizing", "womanising", + "worshiping", "worshipping", + "agonizing", "agonising", + "airplanes", "aeroplanes", + "amortized", "amortised", + "amortizes", "amortises", + "analyzing", "analysing", + "apologize", "apologise", + "appetizer", "appetiser", + "artifacts", "artefacts", + "baptizing", "baptising", + "bedeviled", "bedevilled", + "behaviors", "behaviours", + "bejeweled", "bejewelled", + "belabored", "belaboured", + "brutalize", "brutalise", + "canalized", "canalised", + "canalizes", "canalises", + "canonized", "canonised", + "canonizes", "canonises", + "carbonize", "carbonise", + "cataloged", "catalogued", + "catalyzed", "catalysed", + "catalyzes", "catalyses", + "cauterize", "cauterise", + "channeled", "channelled", + "checkbook", "chequebook", + "checkered", "chequered", + "chiseling", "chiselling", + "civilized", "civilised", + "civilizes", "civilises", + "clamoring", "clamouring", + "colonized", "colonised", + "colonizer", "coloniser", + "colonizes", "colonises", + "colorants", "colourants", + "colorized", "colourized", + "colorizes", "colourizes", + "colorless", "colourless", + "councilor", "councillor", + "counseled", "counselled", + "counselor", "counsellor", + "criticize", "criticise", + "cudgeling", "cudgelling", + "customize", "customise", + "demonized", "demonised", + "demonizes", "demonises", + "deodorize", "deodorise", + "deputized", "deputised", + "deputizes", "deputises", + "digitized", "digitised", + "digitizes", "digitises", + "discolors", "discolours", + "dishonors", "dishonours", + "dramatize", "dramatise", + "driveling", "drivelling", + "economize", "economise", + "empathize", "empathise", + "emphasize", "emphasise", + "enameling", "enamelling", + "endeavors", "endeavours", + "energized", "energised", + "energizes", "energises", + "enthralls", "enthrals", + "epicenter", "epicentre", + "epitomize", "epitomise", + "equalized", "equalised", + "equalizer", "equaliser", + "equalizes", "equalises", + "eulogized", "eulogised", + "eulogizes", "eulogises", + "factorize", "factorise", + "fantasize", "fantasise", + "favorable", "favourable", + "favorably", "favourably", + "favorites", "favourites", + "feminized", "feminised", + "feminizes", "feminises", + "fertilize", "fertilise", + "finalized", "finalised", + "finalizes", "finalises", + "flavoring", "flavouring", + "formalize", "formalise", + "fossilize", "fossilise", + "funneling", "funnelling", + "galvanize", "galvanise", + "gamboling", "gambolling", + "ghettoize", "ghettoise", + "globalize", "globalise", + "gonorrhea", "gonorrhoea", + "groveling", "grovelling", + "harboring", "harbouring", + "harmonize", "harmonise", + "honorably", "honourably", + "humanized", "humanised", + "humanizes", "humanises", + "hybridize", "hybridise", + "hypnotize", "hypnotise", + "idealized", "idealised", + "idealizes", "idealises", + "idolizing", "idolising", + "immunized", "immunised", + "immunizes", "immunises", + "impaneled", "impanelled", + "imperiled", "imperilled", + "initialed", "initialled", + "italicize", "italicise", + "itemizing", "itemising", + "kilometer", "kilometre", + "legalized", "legalised", + "legalizes", "legalises", + "lionizing", "lionising", + "liquidize", "liquidise", + "localized", "localised", + "localizes", "localises", + "magnetize", "magnetise", + "maneuvers", "manoeuvres", + "marshaled", "marshalled", + "marveling", "marvelling", + "marvelous", "marvellous", + "maximized", "maximised", + "maximizes", "maximises", + "mechanize", "mechanise", + "memorized", "memorised", + "memorizes", "memorises", + "mesmerize", "mesmerise", + "minimized", "minimised", + "minimizes", "minimises", + "mobilized", "mobilised", + "mobilizes", "mobilises", + "modernize", "modernise", + "moldering", "mouldering", + "moralized", "moralised", + "moralizes", "moralises", + "motorized", "motorised", + "mustached", "moustached", + "mustaches", "moustaches", + "neighbors", "neighbours", + "normalize", "normalise", + "optimized", "optimised", + "optimizes", "optimises", + "organized", "organised", + "organizer", "organiser", + "organizes", "organises", + "ostracize", "ostracise", + "oxidizing", "oxidising", + "panelists", "panellists", + "paralyzed", "paralysed", + "paralyzes", "paralyses", + "parceling", "parcelling", + "patronize", "patronise", + "pedophile", "paedophile", + "penalized", "penalised", + "penalizes", "penalises", + "penciling", "pencilling", + "plowshare", "ploughshare", + "polarized", "polarised", + "polarizes", "polarises", + "practiced", "practised", + "pretenses", "pretences", + "privatize", "privatise", + "publicize", "publicise", + "pulverize", "pulverise", + "quarreled", "quarrelled", + "randomize", "randomise", + "realizing", "realising", + "recognize", "recognise", + "refueling", "refuelling", + "remodeled", "remodelled", + "remolding", "remoulding", + "saltpeter", "saltpetre", + "sanitized", "sanitised", + "sanitizes", "sanitises", + "satirized", "satirised", + "satirizes", "satirises", + "sensitize", "sensitise", + "sepulcher", "sepulchre", + "serialize", "serialise", + "sermonize", "sermonise", + "shoveling", "shovelling", + "shriveled", "shrivelled", + "signaling", "signalling", + "signalize", "signalise", + "skeptical", "sceptical", + "sniveling", "snivelling", + "snorkeled", "snorkelled", + "socialize", "socialise", + "sodomized", "sodomised", + "sodomizes", "sodomises", + "solemnize", "solemnise", + "spiraling", "spiralling", + "splendors", "splendours", + "stabilize", "stabilise", + "stenciled", "stencilled", + "sterilize", "sterilise", + "subsidize", "subsidise", + "succoring", "succouring", + "sulfurous", "sulphurous", + "summarize", "summarise", + "swiveling", "swivelling", + "symbolize", "symbolise", + "tantalize", "tantalise", + "temporize", "temporise", + "tenderize", "tenderise", + "terrorize", "terrorise", + "theorized", "theorised", + "theorizes", "theorises", + "travelers", "travellers", + "traveling", "travelling", + "tricolors", "tricolours", + "tunneling", "tunnelling", + "tyrannize", "tyrannise", + "unequaled", "unequalled", + "unionized", "unionised", + "unionizes", "unionises", + "unraveled", "unravelled", + "unrivaled", "unrivalled", + "urbanized", "urbanised", + "urbanizes", "urbanises", + "utilizing", "utilising", + "vandalize", "vandalise", + "vaporized", "vaporised", + "vaporizes", "vaporises", + "verbalize", "verbalise", + "victimize", "victimise", + "visualize", "visualise", + "vocalized", "vocalised", + "vocalizes", "vocalises", + "vulgarize", "vulgarise", + "weaseling", "weaselling", + "womanized", "womanised", + "womanizer", "womaniser", + "womanizes", "womanises", + "worshiped", "worshipped", + "worshiper", "worshipper", + "agonized", "agonised", + "agonizes", "agonises", + "airplane", "aeroplane", + "aluminum", "aluminium", + "amortize", "amortise", + "analyzed", "analysed", + "analyzes", "analyses", + "armorers", "armourers", + "armories", "armouries", + "artifact", "artefact", + "baptized", "baptised", + "baptizes", "baptises", + "behavior", "behaviour", + "behooved", "behoved", + "behooves", "behoves", + "belabors", "belabours", + "calibers", "calibres", + "canalize", "canalise", + "canonize", "canonise", + "catalogs", "catalogues", + "catalyze", "catalyse", + "caviling", "cavilling", + "centered", "centred", + "chiseled", "chiselled", + "civilize", "civilise", + "clamored", "clamoured", + "colonize", "colonise", + "colorant", "colourant", + "coloreds", "coloureds", + "colorful", "colourful", + "coloring", "colouring", + "colorize", "colourize", + "coziness", "cosiness", + "cruelest", "cruellest", + "cudgeled", "cudgelled", + "defenses", "defences", + "demeanor", "demeanour", + "demonize", "demonise", + "deputize", "deputise", + "diarrhea", "diarrhoea", + "digitize", "digitise", + "disfavor", "disfavour", + "dishonor", "dishonour", + "distills", "distils", + "driveled", "drivelled", + "enameled", "enamelled", + "enamored", "enamoured", + "endeavor", "endeavour", + "energize", "energise", + "epaulets", "epaulettes", + "equalize", "equalise", + "estrogen", "oestrogen", + "etiology", "aetiology", + "eulogize", "eulogise", + "favoring", "favouring", + "favorite", "favourite", + "feminize", "feminise", + "finalize", "finalise", + "flavored", "flavoured", + "flutists", "flautists", + "fulfills", "fulfils", + "funneled", "funnelled", + "gamboled", "gambolled", + "graveled", "gravelled", + "groveled", "grovelled", + "grueling", "gruelling", + "harbored", "harboured", + "honoring", "honouring", + "humanize", "humanise", + "humoring", "humouring", + "idealize", "idealise", + "idolized", "idolised", + "idolizes", "idolises", + "immunize", "immunise", + "ionizing", "ionising", + "itemized", "itemised", + "itemizes", "itemises", + "jewelers", "jewellers", + "labeling", "labelling", + "laborers", "labourers", + "laboring", "labouring", + "legalize", "legalise", + "leukemia", "leukaemia", + "levelers", "levellers", + "leveling", "levelling", + "libeling", "libelling", + "libelous", "libellous", + "lionized", "lionised", + "lionizes", "lionises", + "localize", "localise", + "louvered", "louvred", + "maneuver", "manoeuvre", + "marveled", "marvelled", + "maximize", "maximise", + "memorize", "memorise", + "minimize", "minimise", + "mobilize", "mobilise", + "modelers", "modellers", + "modeling", "modelling", + "moldered", "mouldered", + "moldiest", "mouldiest", + "moldings", "mouldings", + "moralize", "moralise", + "mustache", "moustache", + "neighbor", "neighbour", + "odorless", "odourless", + "offenses", "offences", + "optimize", "optimise", + "organize", "organise", + "oxidized", "oxidised", + "oxidizes", "oxidises", + "paneling", "panelling", + "panelist", "panellist", + "paralyze", "paralyse", + "parceled", "parcelled", + "pedaling", "pedalling", + "penalize", "penalise", + "penciled", "pencilled", + "polarize", "polarise", + "pretense", "pretence", + "pummeled", "pummelling", + "raveling", "ravelling", + "realized", "realised", + "realizes", "realises", + "refueled", "refuelled", + "remolded", "remoulded", + "revelers", "revellers", + "reveling", "revelling", + "rivaling", "rivalling", + "sanitize", "sanitise", + "satirize", "satirise", + "savories", "savouries", + "savoring", "savouring", + "scepters", "sceptres", + "shoveled", "shovelled", + "signaled", "signalled", + "skeptics", "sceptics", + "sniveled", "snivelled", + "sodomize", "sodomise", + "specters", "spectres", + "spiraled", "spiralled", + "splendor", "splendour", + "succored", "succoured", + "sulfates", "sulphates", + "sulfides", "sulphides", + "swiveled", "swivelled", + "tasseled", "tasselled", + "theaters", "theatres", + "theorize", "theorise", + "toweling", "towelling", + "traveler", "traveller", + "trialing", "trialling", + "tricolor", "tricolour", + "tunneled", "tunnelled", + "unionize", "unionise", + "unsavory", "unsavoury", + "urbanize", "urbanise", + "utilized", "utilised", + "utilizes", "utilises", + "vaporize", "vaporise", + "vocalize", "vocalise", + "weaseled", "weaselled", + "womanize", "womanise", + "yodeling", "yodelling", + "agonize", "agonise", + "analyze", "analyse", + "appalls", "appals", + "armored", "armoured", + "armorer", "armourer", + "baptize", "baptise", + "behoove", "behove", + "belabor", "belabour", + "beveled", "bevelled", + "caliber", "calibre", + "caroled", "carolled", + "caviled", "cavilled", + "centers", "centres", + "clamors", "clamours", + "clangor", "clangour", + "colored", "coloured", + "coziest", "cosiest", + "crueler", "crueller", + "defense", "defence", + "dialing", "dialling", + "dialogs", "dialogues", + "distill", "distil", + "dueling", "duelling", + "enrolls", "enrols", + "epaulet", "epaulette", + "favored", "favoured", + "flavors", "flavours", + "flutist", "flautist", + "fueling", "fuelling", + "fulfill", "fulfil", + "goiters", "goitres", + "harbors", "harbours", + "honored", "honoured", + "humored", "humoured", + "idolize", "idolise", + "ionized", "ionised", + "ionizes", "ionises", + "itemize", "itemise", + "jeweled", "jewelled", + "jeweler", "jeweller", + "jewelry", "jewellery", + "labeled", "labelled", + "labored", "laboured", + "laborer", "labourer", + "leveled", "levelled", + "leveler", "leveller", + "libeled", "libelled", + "lionize", "lionise", + "louvers", "louvres", + "modeled", "modelled", + "modeler", "modeller", + "molders", "moulders", + "moldier", "mouldier", + "molding", "moulding", + "molting", "moulting", + "offense", "offence", + "oxidize", "oxidise", + "pajamas", "pyjamas", + "paneled", "panelled", + "parlors", "parlours", + "pedaled", "pedalled", + "plowing", "ploughing", + "plowman", "ploughman", + "plowmen", "ploughmen", + "realize", "realise", + "remolds", "remoulds", + "reveled", "revelled", + "reveler", "reveller", + "rivaled", "rivalled", + "rumored", "rumoured", + "saviors", "saviours", + "savored", "savoured", + "scepter", "sceptre", + "skeptic", "sceptic", + "specter", "spectre", + "succors", "succours", + "sulfate", "sulphate", + "sulfide", "sulphide", + "theater", "theatre", + "toweled", "towelled", + "toxemia", "toxaemia", + "trialed", "trialled", + "utilize", "utilise", + "yodeled", "yodelled", + "anemia", "anaemia", + "anemic", "anaemic", + "appall", "appal", + "arbors", "arbours", + "armory", "armoury", + "candor", "candour", + "center", "centre", + "clamor", "clamour", + "colors", "colours", + "cozier", "cosier", + "cozies", "cosies", + "cozily", "cosily", + "dialed", "dialled", + "drafty", "draughty", + "dueled", "duelled", + "favors", "favours", + "fervor", "fervour", + "fibers", "fibres", + "flavor", "flavour", + "fueled", "fuelled", + "goiter", "goitre", + "harbor", "harbour", + "honors", "honours", + "humors", "humours", + "labors", "labours", + "liters", "litres", + "louver", "louvre", + "luster", "lustre", + "meager", "meagre", + "miters", "mitres", + "molded", "moulded", + "molder", "moulder", + "molted", "moulted", + "pajama", "pyjama", + "parlor", "parlour", + "plowed", "ploughed", + "rancor", "rancour", + "remold", "remould", + "rigors", "rigours", + "rumors", "rumours", + "savors", "savours", + "savory", "savoury", + "succor", "succour", + "tumors", "tumours", + "vapors", "vapours", + "aging", "ageing", + "arbor", "arbour", + "ardor", "ardour", + "armor", "armour", + "chili", "chilli", + "color", "colour", + "edema", "edoema", + "favor", "favour", + "fecal", "faecal", + "feces", "faeces", + "fiber", "fibre", + "honor", "honour", + "humor", "humour", + "labor", "labour", + "liter", "litre", + "miter", "mitre", + "molds", "moulds", + "moldy", "mouldy", + "molts", "moults", + "odors", "odours", + "plows", "ploughs", + "rigor", "rigour", + "rumor", "rumour", + "savor", "savour", + "valor", "valour", + "vapor", "vapour", + "vigor", "vigour", + "cozy", "cosy", + "mold", "mould", + "molt", "moult", + "odor", "odour", + "plow", "plough", +} diff --git a/vendor/github.com/golangci/misspell/words_us.go b/vendor/github.com/golangci/misspell/words_us.go new file mode 100644 index 000000000..4dee20bc7 --- /dev/null +++ b/vendor/github.com/golangci/misspell/words_us.go @@ -0,0 +1,1625 @@ +// Code generated by 'internal/gen'. DO NOT EDIT. + +package misspell + +// DictAmerican converts UK spellings to US spellings +var DictAmerican = []string{ + "institutionalisation", "institutionalization", + "internationalisation", "internationalization", + "professionalisation", "professionalization", + "compartmentalising", "compartmentalizing", + "institutionalising", "institutionalizing", + "internationalising", "internationalizing", + "compartmentalised", "compartmentalized", + "compartmentalises", "compartmentalizes", + "decriminalisation", "decriminalization", + "denationalisation", "denationalization", + "fictionalisations", "fictionalizations", + "institutionalised", "institutionalized", + "institutionalises", "institutionalizes", + "intellectualising", "intellectualizing", + "internationalised", "internationalized", + "internationalises", "internationalizes", + "pedestrianisation", "pedestrianization", + "professionalising", "professionalizing", + "archaeologically", "archeologically", + "compartmentalise", "compartmentalize", + "decentralisation", "decentralization", + "demilitarisation", "demilitarization", + "externalisations", "externalizations", + "fictionalisation", "fictionalization", + "institutionalise", "institutionalize", + "intellectualised", "intellectualized", + "intellectualises", "intellectualizes", + "internationalise", "internationalize", + "nationalisations", "nationalizations", + "palaeontologists", "paleontologists", + "professionalised", "professionalized", + "professionalises", "professionalizes", + "rationalisations", "rationalizations", + "sensationalising", "sensationalizing", + "sentimentalising", "sentimentalizing", + "acclimatisation", "acclimatization", + "bougainvillaeas", "bougainvilleas", + "commercialising", "commercializing", + "conceptualising", "conceptualizing", + "contextualising", "contextualizing", + "crystallisation", "crystallization", + "decriminalising", "decriminalizing", + "democratisation", "democratization", + "denationalising", "denationalizing", + "depersonalising", "depersonalizing", + "desensitisation", "desensitization", + "destabilisation", "destabilization", + "disorganisation", "disorganization", + "extemporisation", "extemporization", + "externalisation", "externalization", + "familiarisation", "familiarization", + "generalisations", "generalizations", + "hospitalisation", "hospitalization", + "individualising", "individualizing", + "industrialising", "industrializing", + "intellectualise", "intellectualize", + "internalisation", "internalization", + "manoeuvrability", "maneuverability", + "marginalisation", "marginalization", + "materialisation", "materialization", + "miniaturisation", "miniaturization", + "nationalisation", "nationalization", + "neighbourliness", "neighborliness", + "overemphasising", "overemphasizing", + "palaeontologist", "paleontologist", + "particularising", "particularizing", + "pedestrianising", "pedestrianizing", + "professionalise", "professionalize", + "psychoanalysing", "psychoanalyzing", + "rationalisation", "rationalization", + "reorganisations", "reorganizations", + "revolutionising", "revolutionizing", + "sensationalised", "sensationalized", + "sensationalises", "sensationalizes", + "sentimentalised", "sentimentalized", + "sentimentalises", "sentimentalizes", + "specialisations", "specializations", + "standardisation", "standardization", + "synchronisation", "synchronization", + "systematisation", "systematization", + "aggrandisement", "aggrandizement", + "anaesthetising", "anesthetizing", + "archaeological", "archeological", + "archaeologists", "archeologists", + "bougainvillaea", "bougainvillea", + "characterising", "characterizing", + "collectivising", "collectivizing", + "commercialised", "commercialized", + "commercialises", "commercializes", + "conceptualised", "conceptualized", + "conceptualises", "conceptualizes", + "contextualised", "contextualized", + "contextualises", "contextualizes", + "decentralising", "decentralizing", + "decriminalised", "decriminalized", + "decriminalises", "decriminalizes", + "dehumanisation", "dehumanization", + "demilitarising", "demilitarizing", + "demobilisation", "demobilization", + "demoralisation", "demoralization", + "denationalised", "denationalized", + "denationalises", "denationalizes", + "depersonalised", "depersonalized", + "depersonalises", "depersonalizes", + "disembowelling", "disemboweling", + "dramatisations", "dramatizations", + "editorialising", "editorializing", + "encyclopaedias", "encyclopedias", + "fictionalising", "fictionalizing", + "fraternisation", "fraternization", + "generalisation", "generalization", + "gynaecological", "gynecological", + "gynaecologists", "gynecologists", + "haematological", "hematological", + "haematologists", "hematologists", + "immobilisation", "immobilization", + "individualised", "individualized", + "individualises", "individualizes", + "industrialised", "industrialized", + "industrialises", "industrializes", + "liberalisation", "liberalization", + "monopolisation", "monopolization", + "naturalisation", "naturalization", + "neighbourhoods", "neighborhoods", + "neutralisation", "neutralization", + "organisational", "organizational", + "outmanoeuvring", "outmaneuvering", + "overemphasised", "overemphasized", + "overemphasises", "overemphasizes", + "paediatricians", "pediatricians", + "particularised", "particularized", + "particularises", "particularizes", + "pasteurisation", "pasteurization", + "pedestrianised", "pedestrianized", + "pedestrianises", "pedestrianizes", + "philosophising", "philosophizing", + "politicisation", "politicization", + "popularisation", "popularization", + "pressurisation", "pressurization", + "prioritisation", "prioritization", + "privatisations", "privatizations", + "propagandising", "propagandizing", + "psychoanalysed", "psychoanalyzed", + "psychoanalyses", "psychoanalyzes", + "regularisation", "regularization", + "reorganisation", "reorganization", + "revolutionised", "revolutionized", + "revolutionises", "revolutionizes", + "secularisation", "secularization", + "sensationalise", "sensationalize", + "sentimentalise", "sentimentalize", + "serialisations", "serializations", + "specialisation", "specialization", + "sterilisations", "sterilizations", + "stigmatisation", "stigmatization", + "transistorised", "transistorized", + "unrecognisable", "unrecognizable", + "visualisations", "visualizations", + "westernisation", "westernization", + "accessorising", "accessorizing", + "acclimatising", "acclimatizing", + "amortisations", "amortizations", + "amphitheatres", "amphitheaters", + "anaesthetised", "anesthetized", + "anaesthetises", "anesthetizes", + "anaesthetists", "anesthetists", + "archaeologist", "archeologist", + "backpedalling", "backpedaling", + "behaviourists", "behaviorists", + "breathalysers", "breathalyzers", + "breathalysing", "breathalyzing", + "callisthenics", "calisthenics", + "cannibalising", "cannibalizing", + "characterised", "characterized", + "characterises", "characterizes", + "circularising", "circularizing", + "clarinettists", "clarinetists", + "collectivised", "collectivized", + "collectivises", "collectivizes", + "commercialise", "commercialize", + "computerising", "computerizing", + "conceptualise", "conceptualize", + "contextualise", "contextualize", + "criminalising", "criminalizing", + "crystallising", "crystallizing", + "decentralised", "decentralized", + "decentralises", "decentralizes", + "decriminalise", "decriminalize", + "demilitarised", "demilitarized", + "demilitarises", "demilitarizes", + "democratising", "democratizing", + "denationalise", "denationalize", + "depersonalise", "depersonalize", + "desensitising", "desensitizing", + "destabilising", "destabilizing", + "disembowelled", "disemboweled", + "dishonourable", "dishonorable", + "dishonourably", "dishonorably", + "dramatisation", "dramatization", + "editorialised", "editorialized", + "editorialises", "editorializes", + "encyclopaedia", "encyclopedia", + "encyclopaedic", "encyclopedic", + "extemporising", "extemporizing", + "externalising", "externalizing", + "familiarising", "familiarizing", + "fertilisation", "fertilization", + "fictionalised", "fictionalized", + "fictionalises", "fictionalizes", + "formalisation", "formalization", + "fossilisation", "fossilization", + "globalisation", "globalization", + "gynaecologist", "gynecologist", + "haematologist", "hematologist", + "haemophiliacs", "hemophiliacs", + "haemorrhaging", "hemorrhaging", + "harmonisation", "harmonization", + "hospitalising", "hospitalizing", + "hypothesising", "hypothesizing", + "immortalising", "immortalizing", + "individualise", "individualize", + "industrialise", "industrialize", + "internalising", "internalizing", + "marginalising", "marginalizing", + "materialising", "materializing", + "mechanisation", "mechanization", + "memorialising", "memorializing", + "miniaturising", "miniaturizing", + "miscatalogued", "miscataloged", + "misdemeanours", "misdemeanors", + "multicoloured", "multicolored", + "nationalising", "nationalizing", + "neighbourhood", "neighborhood", + "normalisation", "normalization", + "organisations", "organizations", + "outmanoeuvred", "outmaneuvered", + "outmanoeuvres", "outmaneuvers", + "overemphasise", "overemphasize", + "paediatrician", "pediatrician", + "palaeontology", "paleontology", + "particularise", "particularize", + "passivisation", "passivization", + "patronisingly", "patronizingly", + "pedestrianise", "pedestrianize", + "personalising", "personalizing", + "philosophised", "philosophized", + "philosophises", "philosophizes", + "privatisation", "privatization", + "propagandised", "propagandized", + "propagandises", "propagandizes", + "proselytisers", "proselytizers", + "proselytising", "proselytizing", + "psychoanalyse", "psychoanalyze", + "pulverisation", "pulverization", + "rationalising", "rationalizing", + "reconnoitring", "reconnoitering", + "revolutionise", "revolutionize", + "romanticising", "romanticizing", + "serialisation", "serialization", + "socialisation", "socialization", + "stabilisation", "stabilization", + "standardising", "standardizing", + "sterilisation", "sterilization", + "subsidisation", "subsidization", + "synchronising", "synchronizing", + "systematising", "systematizing", + "tantalisingly", "tantalizingly", + "underutilised", "underutilized", + "victimisation", "victimization", + "visualisation", "visualization", + "vocalisations", "vocalizations", + "vulgarisation", "vulgarization", + "accessorised", "accessorized", + "accessorises", "accessorizes", + "acclimatised", "acclimatized", + "acclimatises", "acclimatizes", + "amortisation", "amortization", + "amphitheatre", "amphitheater", + "anaesthetics", "anesthetics", + "anaesthetise", "anesthetize", + "anaesthetist", "anesthetist", + "antagonising", "antagonizing", + "appetisingly", "appetizingly", + "backpedalled", "backpedaled", + "bastardising", "bastardizing", + "behaviourism", "behaviorism", + "behaviourist", "behaviorist", + "bowdlerising", "bowdlerizing", + "breathalysed", "breathalyzed", + "breathalyser", "breathalyzer", + "breathalyses", "breathalyzes", + "cannibalised", "cannibalized", + "cannibalises", "cannibalizes", + "capitalising", "capitalizing", + "caramelising", "caramelizing", + "categorising", "categorizing", + "centigrammes", "centigrams", + "centralising", "centralizing", + "centrepieces", "centerpieces", + "characterise", "characterize", + "circularised", "circularized", + "circularises", "circularizes", + "clarinettist", "clarinetist", + "collectivise", "collectivize", + "colonisation", "colonization", + "computerised", "computerized", + "computerises", "computerizes", + "criminalised", "criminalized", + "criminalises", "criminalizes", + "crystallised", "crystallized", + "crystallises", "crystallizes", + "decentralise", "decentralize", + "dehumanising", "dehumanizing", + "demilitarise", "demilitarize", + "demobilising", "demobilizing", + "democratised", "democratized", + "democratises", "democratizes", + "demoralising", "demoralizing", + "desensitised", "desensitized", + "desensitises", "desensitizes", + "destabilised", "destabilized", + "destabilises", "destabilizes", + "discolouring", "discoloring", + "dishonouring", "dishonoring", + "disorganised", "disorganized", + "editorialise", "editorialize", + "endeavouring", "endeavoring", + "equalisation", "equalization", + "evangelising", "evangelizing", + "extemporised", "extemporized", + "extemporises", "extemporizes", + "externalised", "externalized", + "externalises", "externalizes", + "familiarised", "familiarized", + "familiarises", "familiarizes", + "fictionalise", "fictionalize", + "finalisation", "finalization", + "fraternising", "fraternizing", + "generalising", "generalizing", + "haemophiliac", "hemophiliac", + "haemorrhaged", "hemorrhaged", + "haemorrhages", "hemorrhages", + "haemorrhoids", "hemorrhoids", + "homoeopathic", "homeopathic", + "homogenising", "homogenizing", + "hospitalised", "hospitalized", + "hospitalises", "hospitalizes", + "hypothesised", "hypothesized", + "hypothesises", "hypothesizes", + "idealisation", "idealization", + "immobilisers", "immobilizers", + "immobilising", "immobilizing", + "immortalised", "immortalized", + "immortalises", "immortalizes", + "immunisation", "immunization", + "initialising", "initializing", + "internalised", "internalized", + "internalises", "internalizes", + "jeopardising", "jeopardizing", + "legalisation", "legalization", + "legitimising", "legitimizing", + "liberalising", "liberalizing", + "manoeuvrable", "maneuverable", + "manoeuvrings", "maneuverings", + "marginalised", "marginalized", + "marginalises", "marginalizes", + "marvellously", "marvelously", + "materialised", "materialized", + "materialises", "materializes", + "maximisation", "maximization", + "memorialised", "memorialized", + "memorialises", "memorializes", + "metabolising", "metabolizing", + "militarising", "militarizing", + "milligrammes", "milligrams", + "miniaturised", "miniaturized", + "miniaturises", "miniaturizes", + "misbehaviour", "misbehavior", + "misdemeanour", "misdemeanor", + "mobilisation", "mobilization", + "moisturisers", "moisturizers", + "moisturising", "moisturizing", + "monopolising", "monopolizing", + "moustachioed", "mustachioed", + "nationalised", "nationalized", + "nationalises", "nationalizes", + "naturalising", "naturalizing", + "neighbouring", "neighboring", + "neutralising", "neutralizing", + "oesophaguses", "esophaguses", + "organisation", "organization", + "orthopaedics", "orthopedics", + "outmanoeuvre", "outmaneuver", + "palaeolithic", "paleolithic", + "pasteurising", "pasteurizing", + "personalised", "personalized", + "personalises", "personalizes", + "philosophise", "philosophize", + "plagiarising", "plagiarizing", + "ploughshares", "plowshares", + "polarisation", "polarization", + "politicising", "politicizing", + "popularising", "popularizing", + "pressurising", "pressurizing", + "prioritising", "prioritizing", + "propagandise", "propagandize", + "proselytised", "proselytized", + "proselytiser", "proselytizer", + "proselytises", "proselytizes", + "radicalising", "radicalizing", + "rationalised", "rationalized", + "rationalises", "rationalizes", + "realisations", "realizations", + "recognisable", "recognizable", + "recognisably", "recognizably", + "recognisance", "recognizance", + "reconnoitred", "reconnoitered", + "reconnoitres", "reconnoiters", + "regularising", "regularizing", + "reorganising", "reorganizing", + "revitalising", "revitalizing", + "rhapsodising", "rhapsodizing", + "romanticised", "romanticized", + "romanticises", "romanticizes", + "scandalising", "scandalizing", + "scrutinising", "scrutinizing", + "secularising", "secularizing", + "specialising", "specializing", + "squirrelling", "squirreling", + "standardised", "standardized", + "standardises", "standardizes", + "stigmatising", "stigmatizing", + "sympathisers", "sympathizers", + "sympathising", "sympathizing", + "synchronised", "synchronized", + "synchronises", "synchronizes", + "synthesisers", "synthesizers", + "synthesising", "synthesizing", + "systematised", "systematized", + "systematises", "systematizes", + "technicolour", "technicolor", + "theatregoers", "theatergoers", + "traumatising", "traumatizing", + "trivialising", "trivializing", + "unauthorised", "unauthorized", + "uncatalogued", "uncataloged", + "unfavourable", "unfavorable", + "unfavourably", "unfavorably", + "unionisation", "unionization", + "unrecognised", "unrecognized", + "untrammelled", "untrammeled", + "urbanisation", "urbanization", + "vaporisation", "vaporization", + "vocalisation", "vocalization", + "watercolours", "watercolors", + "westernising", "westernizing", + "accessorise", "accessorize", + "acclimatise", "acclimatize", + "agonisingly", "agonizingly", + "amortisable", "amortizable", + "anaesthesia", "anesthesia", + "anaesthetic", "anesthetic", + "anglicising", "anglicizing", + "antagonised", "antagonized", + "antagonises", "antagonizes", + "apologising", "apologizing", + "archaeology", "archeology", + "authorising", "authorizing", + "bastardised", "bastardized", + "bastardises", "bastardizes", + "bedevilling", "bedeviling", + "behavioural", "behavioral", + "belabouring", "belaboring", + "bowdlerised", "bowdlerized", + "bowdlerises", "bowdlerizes", + "breathalyse", "breathalyze", + "brutalising", "brutalizing", + "cannibalise", "cannibalize", + "capitalised", "capitalized", + "capitalises", "capitalizes", + "caramelised", "caramelized", + "caramelises", "caramelizes", + "carbonising", "carbonizing", + "cataloguing", "cataloging", + "categorised", "categorized", + "categorises", "categorizes", + "cauterising", "cauterizing", + "centigramme", "centigram", + "centilitres", "centiliters", + "centimetres", "centimeters", + "centralised", "centralized", + "centralises", "centralizes", + "centrefolds", "centerfolds", + "centrepiece", "centerpiece", + "channelling", "channeling", + "chequebooks", "checkbooks", + "circularise", "circularize", + "colourfully", "colorfully", + "colourizing", "colorizing", + "computerise", "computerize", + "councillors", "councilors", + "counselling", "counseling", + "counsellors", "counselors", + "criminalise", "criminalize", + "criticising", "criticizing", + "crystallise", "crystallize", + "customising", "customizing", + "defenceless", "defenseless", + "dehumanised", "dehumanized", + "dehumanises", "dehumanizes", + "demobilised", "demobilized", + "demobilises", "demobilizes", + "democratise", "democratize", + "demoralised", "demoralized", + "demoralises", "demoralizes", + "deodorising", "deodorizing", + "desensitise", "desensitize", + "destabilise", "destabilize", + "discoloured", "discolored", + "dishevelled", "disheveled", + "dishonoured", "dishonored", + "dramatising", "dramatizing", + "economising", "economizing", + "empathising", "empathizing", + "emphasising", "emphasizing", + "endeavoured", "endeavored", + "epitomising", "epitomizing", + "evangelised", "evangelized", + "evangelises", "evangelizes", + "extemporise", "extemporize", + "externalise", "externalize", + "factorising", "factorizing", + "familiarise", "familiarize", + "fantasising", "fantasizing", + "favouritism", "favoritism", + "fertilisers", "fertilizers", + "fertilising", "fertilizing", + "flavourings", "flavorings", + "flavourless", "flavorless", + "flavoursome", "flavorsome", + "formalising", "formalizing", + "fossilising", "fossilizing", + "fraternised", "fraternized", + "fraternises", "fraternizes", + "galvanising", "galvanizing", + "generalised", "generalized", + "generalises", "generalizes", + "ghettoising", "ghettoizing", + "globalising", "globalizing", + "gruellingly", "gruelingly", + "gynaecology", "gynecology", + "haematology", "hematology", + "haemoglobin", "hemoglobin", + "haemophilia", "hemophilia", + "haemorrhage", "hemorrhage", + "harmonising", "harmonizing", + "homoeopaths", "homeopaths", + "homoeopathy", "homeopathy", + "homogenised", "homogenized", + "homogenises", "homogenizes", + "hospitalise", "hospitalize", + "hybridising", "hybridizing", + "hypnotising", "hypnotizing", + "hypothesise", "hypothesize", + "immobilised", "immobilized", + "immobiliser", "immobilizer", + "immobilises", "immobilizes", + "immortalise", "immortalize", + "impanelling", "impaneling", + "imperilling", "imperiling", + "initialised", "initialized", + "initialises", "initializes", + "initialling", "initialing", + "instalments", "installments", + "internalise", "internalize", + "italicising", "italicizing", + "jeopardised", "jeopardized", + "jeopardises", "jeopardizes", + "kilogrammes", "kilograms", + "legitimised", "legitimized", + "legitimises", "legitimizes", + "liberalised", "liberalized", + "liberalises", "liberalizes", + "lionisation", "lionization", + "liquidisers", "liquidizers", + "liquidising", "liquidizing", + "magnetising", "magnetizing", + "manoeuvring", "maneuvering", + "marginalise", "marginalize", + "marshalling", "marshaling", + "materialise", "materialize", + "mechanising", "mechanizing", + "memorialise", "memorialize", + "mesmerising", "mesmerizing", + "metabolised", "metabolized", + "metabolises", "metabolizes", + "micrometres", "micrometers", + "militarised", "militarized", + "militarises", "militarizes", + "milligramme", "milligram", + "millilitres", "milliliters", + "millimetres", "millimeters", + "miniaturise", "miniaturize", + "modernising", "modernizing", + "moisturised", "moisturized", + "moisturiser", "moisturizer", + "moisturises", "moisturizes", + "monopolised", "monopolized", + "monopolises", "monopolizes", + "nationalise", "nationalize", + "naturalised", "naturalized", + "naturalises", "naturalizes", + "neighbourly", "neighborly", + "neutralised", "neutralized", + "neutralises", "neutralizes", + "normalising", "normalizing", + "orthopaedic", "orthopedic", + "ostracising", "ostracizing", + "oxidisation", "oxidization", + "paediatrics", "pediatrics", + "paedophiles", "pedophiles", + "paedophilia", "pedophilia", + "passivising", "passivizing", + "pasteurised", "pasteurized", + "pasteurises", "pasteurizes", + "patronising", "patronizing", + "personalise", "personalize", + "plagiarised", "plagiarized", + "plagiarises", "plagiarizes", + "ploughshare", "plowshare", + "politicised", "politicized", + "politicises", "politicizes", + "popularised", "popularized", + "popularises", "popularizes", + "praesidiums", "presidiums", + "pressurised", "pressurized", + "pressurises", "pressurizes", + "prioritised", "prioritized", + "prioritises", "prioritizes", + "privatising", "privatizing", + "proselytise", "proselytize", + "publicising", "publicizing", + "pulverising", "pulverizing", + "quarrelling", "quarreling", + "radicalised", "radicalized", + "radicalises", "radicalizes", + "randomising", "randomizing", + "rationalise", "rationalize", + "realisation", "realization", + "recognising", "recognizing", + "reconnoitre", "reconnoiter", + "regularised", "regularized", + "regularises", "regularizes", + "remodelling", "remodeling", + "reorganised", "reorganized", + "reorganises", "reorganizes", + "revitalised", "revitalized", + "revitalises", "revitalizes", + "rhapsodised", "rhapsodized", + "rhapsodises", "rhapsodizes", + "romanticise", "romanticize", + "scandalised", "scandalized", + "scandalises", "scandalizes", + "sceptically", "skeptically", + "scrutinised", "scrutinized", + "scrutinises", "scrutinizes", + "secularised", "secularized", + "secularises", "secularizes", + "sensitising", "sensitizing", + "serialising", "serializing", + "sermonising", "sermonizing", + "shrivelling", "shriveling", + "signalising", "signalizing", + "snorkelling", "snorkeling", + "snowploughs", "snowplow", + "socialising", "socializing", + "solemnising", "solemnizing", + "specialised", "specialized", + "specialises", "specializes", + "squirrelled", "squirreled", + "stabilisers", "stabilizers", + "stabilising", "stabilizing", + "standardise", "standardize", + "stencilling", "stenciling", + "sterilisers", "sterilizers", + "sterilising", "sterilizing", + "stigmatised", "stigmatized", + "stigmatises", "stigmatizes", + "subsidisers", "subsidizers", + "subsidising", "subsidizing", + "summarising", "summarizing", + "symbolising", "symbolizing", + "sympathised", "sympathized", + "sympathiser", "sympathizer", + "sympathises", "sympathizes", + "synchronise", "synchronize", + "synthesised", "synthesized", + "synthesiser", "synthesizer", + "synthesises", "synthesizes", + "systematise", "systematize", + "tantalising", "tantalizing", + "temporising", "temporizing", + "tenderising", "tenderizing", + "terrorising", "terrorizing", + "theatregoer", "theatergoer", + "traumatised", "traumatized", + "traumatises", "traumatizes", + "trivialised", "trivialized", + "trivialises", "trivializes", + "tyrannising", "tyrannizing", + "uncivilised", "uncivilized", + "unorganised", "unorganized", + "unravelling", "unraveling", + "utilisation", "utilization", + "vandalising", "vandalizing", + "verbalising", "verbalizing", + "victimising", "victimizing", + "visualising", "visualizing", + "vulgarising", "vulgarizing", + "watercolour", "watercolor", + "westernised", "westernized", + "westernises", "westernizes", + "worshipping", "worshiping", + "aeroplanes", "airplanes", + "amortising", "amortizing", + "anglicised", "anglicized", + "anglicises", "anglicizes", + "annualised", "annualized", + "antagonise", "antagonize", + "apologised", "apologized", + "apologises", "apologizes", + "appetisers", "appetizers", + "appetising", "appetizing", + "authorised", "authorized", + "authorises", "authorizes", + "bannisters", "banisters", + "bastardise", "bastardize", + "bedevilled", "bedeviled", + "behaviours", "behaviors", + "bejewelled", "bejeweled", + "belaboured", "belabored", + "bowdlerise", "bowdlerize", + "brutalised", "brutalized", + "brutalises", "brutalizes", + "canalising", "canalizing", + "cancelling", "canceling", + "canonising", "canonizing", + "capitalise", "capitalize", + "caramelise", "caramelize", + "carbonised", "carbonized", + "carbonises", "carbonizes", + "catalogued", "cataloged", + "catalogues", "catalogs", + "catalysing", "catalyzing", + "categorise", "categorize", + "cauterised", "cauterized", + "cauterises", "cauterizes", + "centilitre", "centiliter", + "centimetre", "centimeter", + "centralise", "centralize", + "centrefold", "centerfold", + "channelled", "channeled", + "chequebook", "checkbook", + "chiselling", "chiseling", + "civilising", "civilizing", + "clamouring", "clamoring", + "colonisers", "colonizers", + "colonising", "colonizing", + "colourants", "colorants", + "colourized", "colorized", + "colourizes", "colorizes", + "colourless", "colorless", + "connexions", "connections", + "councillor", "councilor", + "counselled", "counseled", + "counsellor", "counselor", + "criticised", "criticized", + "criticises", "criticizes", + "cudgelling", "cudgeling", + "customised", "customized", + "customises", "customizes", + "dehumanise", "dehumanize", + "demobilise", "demobilize", + "demonising", "demonizing", + "demoralise", "demoralize", + "deodorised", "deodorized", + "deodorises", "deodorizes", + "deputising", "deputizing", + "digitising", "digitizing", + "discolours", "discolors", + "dishonours", "dishonors", + "dramatised", "dramatized", + "dramatises", "dramatizes", + "drivelling", "driveling", + "economised", "economized", + "economises", "economizes", + "empathised", "empathized", + "empathises", "empathizes", + "emphasised", "emphasized", + "emphasises", "emphasizes", + "enamelling", "enameling", + "endeavours", "endeavors", + "energising", "energizing", + "epaulettes", "epaulets", + "epicentres", "epicenters", + "epitomised", "epitomized", + "epitomises", "epitomizes", + "equalisers", "equalizers", + "equalising", "equalizing", + "eulogising", "eulogizing", + "evangelise", "evangelize", + "factorised", "factorized", + "factorises", "factorizes", + "fantasised", "fantasized", + "fantasises", "fantasizes", + "favourable", "favorable", + "favourably", "favorably", + "favourites", "favorites", + "feminising", "feminizing", + "fertilised", "fertilized", + "fertiliser", "fertilizer", + "fertilises", "fertilizes", + "fibreglass", "fiberglass", + "finalising", "finalizing", + "flavouring", "flavoring", + "formalised", "formalized", + "formalises", "formalizes", + "fossilised", "fossilized", + "fossilises", "fossilizes", + "fraternise", "fraternize", + "fulfilment", "fulfillment", + "funnelling", "funneling", + "galvanised", "galvanized", + "galvanises", "galvanizes", + "gambolling", "gamboling", + "gaolbreaks", "jailbreaks", + "generalise", "generalize", + "ghettoised", "ghettoized", + "ghettoises", "ghettoizes", + "globalised", "globalized", + "globalises", "globalizes", + "gonorrhoea", "gonorrhea", + "grovelling", "groveling", + "harbouring", "harboring", + "harmonised", "harmonized", + "harmonises", "harmonizes", + "homoeopath", "homeopath", + "homogenise", "homogenize", + "honourable", "honorable", + "honourably", "honorably", + "humanising", "humanizing", + "humourless", "humorless", + "hybridised", "hybridized", + "hybridises", "hybridizes", + "hypnotised", "hypnotized", + "hypnotises", "hypnotizes", + "idealising", "idealizing", + "immobilise", "immobilize", + "immunising", "immunizing", + "impanelled", "impaneled", + "imperilled", "imperiled", + "inflexions", "inflections", + "initialise", "initialize", + "initialled", "initialed", + "instalment", "installment", + "ionisation", "ionization", + "italicised", "italicized", + "italicises", "italicizes", + "jeopardise", "jeopardize", + "kilogramme", "kilogram", + "kilometres", "kilometers", + "lacklustre", "lackluster", + "legalising", "legalizing", + "legitimise", "legitimize", + "liberalise", "liberalize", + "liquidised", "liquidized", + "liquidiser", "liquidizer", + "liquidises", "liquidizes", + "localising", "localizing", + "magnetised", "magnetized", + "magnetises", "magnetizes", + "manoeuvred", "maneuvered", + "manoeuvres", "maneuvers", + "marshalled", "marshaled", + "marvelling", "marveling", + "marvellous", "marvelous", + "maximising", "maximizing", + "mechanised", "mechanized", + "mechanises", "mechanizes", + "memorising", "memorizing", + "mesmerised", "mesmerized", + "mesmerises", "mesmerizes", + "metabolise", "metabolize", + "micrometre", "micrometer", + "militarise", "militarize", + "millilitre", "milliliter", + "millimetre", "millimeter", + "minimising", "minimizing", + "mobilising", "mobilizing", + "modernised", "modernized", + "modernises", "modernizes", + "moisturise", "moisturize", + "monopolise", "monopolize", + "moralising", "moralizing", + "mouldering", "moldering", + "moustached", "mustached", + "moustaches", "mustaches", + "naturalise", "naturalize", + "neighbours", "neighbors", + "neutralise", "neutralize", + "normalised", "normalized", + "normalises", "normalizes", + "oesophagus", "esophagus", + "optimising", "optimizing", + "organisers", "organizers", + "organising", "organizing", + "ostracised", "ostracized", + "ostracises", "ostracizes", + "paederasts", "pederasts", + "paediatric", "pediatric", + "paedophile", "pedophile", + "panellists", "panelists", + "paralysing", "paralyzing", + "parcelling", "parceling", + "passivised", "passivized", + "passivises", "passivizes", + "pasteurise", "pasteurize", + "patronised", "patronized", + "patronises", "patronizes", + "penalising", "penalizing", + "pencilling", "penciling", + "plagiarise", "plagiarize", + "polarising", "polarizing", + "politicise", "politicize", + "popularise", "popularize", + "practising", "practicing", + "praesidium", "presidium", + "pressurise", "pressurize", + "prioritise", "prioritize", + "privatised", "privatized", + "privatises", "privatizes", + "programmes", "programs", + "publicised", "publicized", + "publicises", "publicizes", + "pulverised", "pulverized", + "pulverises", "pulverizes", + "pummelling", "pummeled", + "quarrelled", "quarreled", + "radicalise", "radicalize", + "randomised", "randomized", + "randomises", "randomizes", + "realisable", "realizable", + "recognised", "recognized", + "recognises", "recognizes", + "refuelling", "refueling", + "regularise", "regularize", + "remodelled", "remodeled", + "remoulding", "remolding", + "reorganise", "reorganize", + "revitalise", "revitalize", + "rhapsodise", "rhapsodize", + "ritualised", "ritualized", + "sanitising", "sanitizing", + "satirising", "satirizing", + "scandalise", "scandalize", + "scepticism", "skepticism", + "scrutinise", "scrutinize", + "secularise", "secularize", + "sensitised", "sensitized", + "sensitises", "sensitizes", + "sepulchres", "sepulchers", + "serialised", "serialized", + "serialises", "serializes", + "sermonised", "sermonized", + "sermonises", "sermonizes", + "shovelling", "shoveling", + "shrivelled", "shriveled", + "signalised", "signalized", + "signalises", "signalizes", + "signalling", "signaling", + "snivelling", "sniveling", + "snorkelled", "snorkeled", + "snowplough", "snowplow", + "socialised", "socialized", + "socialises", "socializes", + "sodomising", "sodomizing", + "solemnised", "solemnized", + "solemnises", "solemnizes", + "specialise", "specialize", + "spiralling", "spiraling", + "splendours", "splendors", + "stabilised", "stabilized", + "stabiliser", "stabilizer", + "stabilises", "stabilizes", + "stencilled", "stenciled", + "sterilised", "sterilized", + "steriliser", "sterilizer", + "sterilises", "sterilizes", + "stigmatise", "stigmatize", + "subsidised", "subsidized", + "subsidiser", "subsidizer", + "subsidises", "subsidizes", + "succouring", "succoring", + "sulphurous", "sulfurous", + "summarised", "summarized", + "summarises", "summarizes", + "swivelling", "swiveling", + "symbolised", "symbolized", + "symbolises", "symbolizes", + "sympathise", "sympathize", + "synthesise", "synthesize", + "tantalised", "tantalized", + "tantalises", "tantalizes", + "temporised", "temporized", + "temporises", "temporizes", + "tenderised", "tenderized", + "tenderises", "tenderizes", + "terrorised", "terrorized", + "terrorises", "terrorizes", + "theorising", "theorizing", + "traumatise", "traumatize", + "travellers", "travelers", + "travelling", "traveling", + "tricolours", "tricolors", + "trivialise", "trivialize", + "tunnelling", "tunneling", + "tyrannised", "tyrannized", + "tyrannises", "tyrannizes", + "unequalled", "unequaled", + "unionising", "unionizing", + "unravelled", "unraveled", + "unrivalled", "unrivaled", + "urbanising", "urbanizing", + "utilisable", "utilizable", + "vandalised", "vandalized", + "vandalises", "vandalizes", + "vaporising", "vaporizing", + "verbalised", "verbalized", + "verbalises", "verbalizes", + "victimised", "victimized", + "victimises", "victimizes", + "visualised", "visualized", + "visualises", "visualizes", + "vocalising", "vocalizing", + "vulcanised", "vulcanized", + "vulgarised", "vulgarized", + "vulgarises", "vulgarizes", + "weaselling", "weaseling", + "westernise", "westernize", + "womanisers", "womanizers", + "womanising", "womanizing", + "worshipped", "worshiped", + "worshipper", "worshiper", + "aeroplane", "airplane", + "aetiology", "etiology", + "agonising", "agonizing", + "almanacks", "almanacs", + "aluminium", "aluminum", + "amortised", "amortized", + "amortises", "amortizes", + "analogues", "analogs", + "analysing", "analyzing", + "anglicise", "anglicize", + "apologise", "apologize", + "appetiser", "appetizer", + "armourers", "armorers", + "armouries", "armories", + "artefacts", "artifacts", + "authorise", "authorize", + "baptising", "baptizing", + "behaviour", "behavior", + "belabours", "belabors", + "brutalise", "brutalize", + "callipers", "calipers", + "canalised", "canalized", + "canalises", "canalizes", + "cancelled", "canceled", + "canonised", "canonized", + "canonises", "canonizes", + "carbonise", "carbonize", + "carolling", "caroling", + "catalogue", "catalog", + "catalysed", "catalyzed", + "catalyses", "catalyzes", + "cauterise", "cauterize", + "cavilling", "caviling", + "chequered", "checkered", + "chiselled", "chiseled", + "civilised", "civilized", + "civilises", "civilizes", + "clamoured", "clamored", + "colonised", "colonized", + "coloniser", "colonizer", + "colonises", "colonizes", + "colourant", "colorant", + "coloureds", "coloreds", + "colourful", "colorful", + "colouring", "coloring", + "colourize", "colorize", + "connexion", "connection", + "criticise", "criticize", + "cruellest", "cruelest", + "cudgelled", "cudgeled", + "customise", "customize", + "demeanour", "demeanor", + "demonised", "demonized", + "demonises", "demonizes", + "deodorise", "deodorize", + "deputised", "deputized", + "deputises", "deputizes", + "dialogues", "dialogs", + "diarrhoea", "diarrhea", + "digitised", "digitized", + "digitises", "digitizes", + "discolour", "discolor", + "disfavour", "disfavor", + "dishonour", "dishonor", + "dramatise", "dramatize", + "drivelled", "driveled", + "economise", "economize", + "empathise", "empathize", + "emphasise", "emphasize", + "enamelled", "enameled", + "enamoured", "enamored", + "endeavour", "endeavor", + "energised", "energized", + "energises", "energizes", + "epaulette", "epaulet", + "epicentre", "epicenter", + "epitomise", "epitomize", + "equalised", "equalized", + "equaliser", "equalizer", + "equalises", "equalizes", + "eulogised", "eulogized", + "eulogises", "eulogizes", + "factorise", "factorize", + "fantasise", "fantasize", + "favouring", "favoring", + "favourite", "favorite", + "feminised", "feminized", + "feminises", "feminizes", + "fertilise", "fertilize", + "finalised", "finalized", + "finalises", "finalizes", + "flautists", "flutists", + "flavoured", "flavored", + "formalise", "formalize", + "fossilise", "fossilize", + "funnelled", "funneled", + "galvanise", "galvanize", + "gambolled", "gamboled", + "gaolbirds", "jailbirds", + "gaolbreak", "jailbreak", + "ghettoise", "ghettoize", + "globalise", "globalize", + "gravelled", "graveled", + "grovelled", "groveled", + "gruelling", "grueling", + "harboured", "harbored", + "harmonise", "harmonize", + "honouring", "honoring", + "humanised", "humanized", + "humanises", "humanizes", + "humouring", "humoring", + "hybridise", "hybridize", + "hypnotise", "hypnotize", + "idealised", "idealized", + "idealises", "idealizes", + "idolising", "idolizing", + "immunised", "immunized", + "immunises", "immunizes", + "inflexion", "inflection", + "italicise", "italicize", + "itemising", "itemizing", + "jewellers", "jewelers", + "jewellery", "jewelry", + "kilometre", "kilometer", + "labelling", "labeling", + "labourers", "laborers", + "labouring", "laboring", + "legalised", "legalized", + "legalises", "legalizes", + "leukaemia", "leukemia", + "levellers", "levelers", + "levelling", "leveling", + "libelling", "libeling", + "libellous", "libelous", + "licencing", "licensing", + "lionising", "lionizing", + "liquidise", "liquidize", + "localised", "localized", + "localises", "localizes", + "magnetise", "magnetize", + "manoeuvre", "maneuver", + "marvelled", "marveled", + "maximised", "maximized", + "maximises", "maximizes", + "mechanise", "mechanize", + "mediaeval", "medieval", + "memorised", "memorized", + "memorises", "memorizes", + "mesmerise", "mesmerize", + "minimised", "minimized", + "minimises", "minimizes", + "mobilised", "mobilized", + "mobilises", "mobilizes", + "modellers", "modelers", + "modelling", "modeling", + "modernise", "modernize", + "moralised", "moralized", + "moralises", "moralizes", + "motorised", "motorized", + "mouldered", "moldered", + "mouldiest", "moldiest", + "mouldings", "moldings", + "moustache", "mustache", + "neighbour", "neighbor", + "normalise", "normalize", + "odourless", "odorless", + "oestrogen", "estrogen", + "optimised", "optimized", + "optimises", "optimizes", + "organised", "organized", + "organiser", "organizer", + "organises", "organizes", + "ostracise", "ostracize", + "oxidising", "oxidizing", + "paederast", "pederast", + "panelling", "paneling", + "panellist", "panelist", + "paralysed", "paralyzed", + "paralyses", "paralyzes", + "parcelled", "parceled", + "passivise", "passivize", + "patronise", "patronize", + "pedalling", "pedaling", + "penalised", "penalized", + "penalises", "penalizes", + "pencilled", "penciled", + "ploughing", "plowing", + "ploughman", "plowman", + "ploughmen", "plowmen", + "polarised", "polarized", + "polarises", "polarizes", + "practised", "practiced", + "practises", "practices", + "pretences", "pretenses", + "primaeval", "primeval", + "privatise", "privatize", + "programme", "program", + "publicise", "publicize", + "pulverise", "pulverize", + "pummelled", "pummel", + "randomise", "randomize", + "ravelling", "raveling", + "realising", "realizing", + "recognise", "recognize", + "refuelled", "refueled", + "remoulded", "remolded", + "revellers", "revelers", + "revelling", "reveling", + "rivalling", "rivaling", + "saltpetre", "saltpeter", + "sanitised", "sanitized", + "sanitises", "sanitizes", + "satirised", "satirized", + "satirises", "satirizes", + "savouries", "savories", + "savouring", "savoring", + "sceptical", "skeptical", + "sensitise", "sensitize", + "sepulchre", "sepulcher", + "serialise", "serialize", + "sermonise", "sermonize", + "shovelled", "shoveled", + "signalise", "signalize", + "signalled", "signaled", + "snivelled", "sniveled", + "socialise", "socialize", + "sodomised", "sodomized", + "sodomises", "sodomizes", + "solemnise", "solemnize", + "spiralled", "spiraled", + "splendour", "splendor", + "stabilise", "stabilize", + "sterilise", "sterilize", + "subsidise", "subsidize", + "succoured", "succored", + "sulphates", "sulfates", + "sulphides", "sulfides", + "summarise", "summarize", + "swivelled", "swiveled", + "symbolise", "symbolize", + "syphoning", "siphoning", + "tantalise", "tantalize", + "tasselled", "tasseled", + "temporise", "temporize", + "tenderise", "tenderize", + "terrorise", "terrorize", + "theorised", "theorized", + "theorises", "theorizes", + "towelling", "toweling", + "travelled", "traveled", + "traveller", "traveler", + "trialling", "trialing", + "tricolour", "tricolor", + "tunnelled", "tunneled", + "tyrannise", "tyrannize", + "unionised", "unionized", + "unionises", "unionizes", + "unsavoury", "unsavory", + "urbanised", "urbanized", + "urbanises", "urbanizes", + "utilising", "utilizing", + "vandalise", "vandalize", + "vaporised", "vaporized", + "vaporises", "vaporizes", + "verbalise", "verbalize", + "victimise", "victimize", + "visualise", "visualize", + "vocalised", "vocalized", + "vocalises", "vocalizes", + "vulgarise", "vulgarize", + "weaselled", "weaseled", + "womanised", "womanized", + "womaniser", "womanizer", + "womanises", "womanizes", + "yodelling", "yodeling", + "yoghourts", "yogurts", + "agonised", "agonized", + "agonises", "agonizes", + "almanack", "almanac", + "amortise", "amortize", + "analogue", "analog", + "analysed", "analyzed", + "armoured", "armored", + "armourer", "armorer", + "artefact", "artifact", + "baptised", "baptized", + "baptises", "baptizes", + "baulking", "balking", + "belabour", "belabor", + "bevelled", "beveled", + "calibres", "calibers", + "calliper", "caliper", + "canalise", "canalize", + "canonise", "canonize", + "carolled", "caroled", + "catalyse", "catalyze", + "cavilled", "caviled", + "civilise", "civilize", + "clamours", "clamors", + "clangour", "clangor", + "colonise", "colonize", + "coloured", "colored", + "cosiness", "coziness", + "crueller", "crueler", + "defences", "defenses", + "demonise", "demonize", + "deputise", "deputize", + "dialling", "dialing", + "dialogue", "dialog", + "digitise", "digitize", + "draughty", "drafty", + "duelling", "dueling", + "energise", "energize", + "enthrals", "enthralls", + "equalise", "equalize", + "eulogise", "eulogize", + "favoured", "favored", + "feminise", "feminize", + "finalise", "finalize", + "flautist", "flutist", + "flavours", "flavors", + "foetuses", "fetuses", + "fuelling", "fueling", + "gaolbird", "jailbird", + "gryphons", "griffins", + "harbours", "harbors", + "honoured", "honored", + "humanise", "humanize", + "humoured", "humored", + "idealise", "idealize", + "idolised", "idolized", + "idolises", "idolizes", + "immunise", "immunize", + "ionisers", "ionizers", + "ionising", "ionizing", + "itemised", "itemized", + "itemises", "itemizes", + "jewelled", "jeweled", + "jeweller", "jeweler", + "labelled", "labeled", + "laboured", "labored", + "labourer", "laborer", + "legalise", "legalize", + "levelled", "leveled", + "leveller", "leveler", + "libelled", "libeled", + "licenced", "licensed", + "licences", "licenses", + "lionised", "lionized", + "lionises", "lionizes", + "localise", "localize", + "maximise", "maximize", + "memorise", "memorize", + "minimise", "minimize", + "misspelt", "misspelled", + "mobilise", "mobilize", + "modelled", "modeled", + "modeller", "modeler", + "moralise", "moralize", + "moulders", "molders", + "mouldier", "moldier", + "moulding", "molding", + "moulting", "molting", + "offences", "offenses", + "optimise", "optimize", + "organise", "organize", + "oxidised", "oxidized", + "oxidises", "oxidizes", + "panelled", "paneled", + "paralyse", "paralyze", + "parlours", "parlors", + "pedalled", "pedaled", + "penalise", "penalize", + "philtres", "filters", + "ploughed", "plowed", + "polarise", "polarize", + "practise", "practice", + "pretence", "pretense", + "ravelled", "raveled", + "realised", "realized", + "realises", "realizes", + "remoulds", "remolds", + "revelled", "reveled", + "reveller", "reveler", + "rivalled", "rivaled", + "rumoured", "rumored", + "sanitise", "sanitize", + "satirise", "satirize", + "saviours", "saviors", + "savoured", "savored", + "sceptics", "skeptics", + "sceptres", "scepters", + "sodomise", "sodomize", + "spectres", "specters", + "succours", "succors", + "sulphate", "sulfate", + "sulphide", "sulfide", + "syphoned", "siphoned", + "theatres", "theaters", + "theorise", "theorize", + "towelled", "toweled", + "toxaemia", "toxemia", + "trialled", "trialed", + "unionise", "unionize", + "urbanise", "urbanize", + "utilised", "utilized", + "utilises", "utilizes", + "vaporise", "vaporize", + "vocalise", "vocalize", + "womanise", "womanize", + "yodelled", "yodeled", + "yoghourt", "yogurt", + "yoghurts", "yogurts", + "agonise", "agonize", + "anaemia", "anemia", + "anaemic", "anemic", + "analyse", "analyze", + "arbours", "arbors", + "armoury", "armory", + "baptise", "baptize", + "baulked", "balked", + "behoved", "behooved", + "behoves", "behooves", + "calibre", "caliber", + "candour", "candor", + "centred", "centered", + "centres", "centers", + "cheques", "checks", + "clamour", "clamor", + "colours", "colors", + "cosiest", "coziest", + "defence", "defense", + "dialled", "dialed", + "distils", "distills", + "duelled", "dueled", + "enthral", "enthrall", + "favours", "favors", + "fervour", "fervor", + "flavour", "flavor", + "fuelled", "fueled", + "fulfils", "fulfills", + "gaolers", "jailers", + "gaoling", "jailing", + "gipsies", "gypsies", + "glueing", "gluing", + "goitres", "goiters", + "grammes", "grams", + "groynes", "groins", + "gryphon", "griffin", + "harbour", "harbor", + "honours", "honors", + "humours", "humors", + "idolise", "idolize", + "instals", "installs", + "instils", "instills", + "ionised", "ionized", + "ioniser", "ionizer", + "ionises", "ionizes", + "itemise", "itemize", + "labours", "labors", + "licence", "license", + "lionise", "lionize", + "louvred", "louvered", + "louvres", "louvers", + "moulded", "molded", + "moulder", "molder", + "moulted", "molted", + "offence", "offense", + "oxidise", "oxidize", + "parlour", "parlor", + "philtre", "filter", + "ploughs", "plows", + "pyjamas", "pajamas", + "rancour", "rancor", + "realise", "realize", + "remould", "remold", + "rigours", "rigors", + "rumours", "rumors", + "saviour", "savior", + "savours", "savors", + "savoury", "savory", + "sceptic", "skeptic", + "sceptre", "scepter", + "spectre", "specter", + "storeys", "stories", + "succour", "succor", + "sulphur", "sulfur", + "syphons", "siphons", + "theatre", "theater", + "tumours", "tumors", + "utilise", "utilize", + "vapours", "vapors", + "waggons", "wagons", + "yoghurt", "yogurt", + "ageing", "aging", + "appals", "appalls", + "arbour", "arbor", + "ardour", "ardor", + "baulks", "balks", + "behove", "behoove", + "centre", "center", + "cheque", "check", + "chilli", "chili", + "colour", "color", + "cosier", "cozier", + "cosies", "cozies", + "cosily", "cozily", + "distil", "distill", + "edoema", "edema", + "enrols", "enrolls", + "faecal", "fecal", + "faeces", "feces", + "favour", "favor", + "fibres", "fibers", + "foetal", "fetal", + "foetid", "fetid", + "foetus", "fetus", + "fulfil", "fulfill", + "gaoled", "jailed", + "gaoler", "jailer", + "goitre", "goiter", + "gramme", "gram", + "groyne", "groin", + "honour", "honor", + "humour", "humor", + "instal", "install", + "instil", "instill", + "ionise", "ionize", + "labour", "labor", + "litres", "liters", + "lustre", "luster", + "meagre", "meager", + "metres", "meters", + "mitres", "miters", + "moulds", "molds", + "mouldy", "moldy", + "moults", "molts", + "odours", "odors", + "plough", "plow", + "pyjama", "pajama", + "rigour", "rigor", + "rumour", "rumor", + "savour", "savor", + "storey", "story", + "syphon", "siphon", + "tumour", "tumor", + "valour", "valor", + "vapour", "vapor", + "vigour", "vigor", + "waggon", "wagon", + "appal", "appall", + "baulk", "balk", + "enrol", "enroll", + "fibre", "fiber", + "gaols", "jails", + "litre", "liter", + "metre", "meter", + "mitre", "miter", + "mould", "mold", + "moult", "molt", + "odour", "odor", + "tyres", "tires", + "cosy", "cozy", + "gaol", "jail", + "tyre", "tire", +} diff --git a/vendor/github.com/golangci/modinfo/.gitignore b/vendor/github.com/golangci/modinfo/.gitignore deleted file mode 100644 index 9f11b755a..000000000 --- a/vendor/github.com/golangci/modinfo/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.idea/ diff --git a/vendor/github.com/golangci/modinfo/.golangci.yml b/vendor/github.com/golangci/modinfo/.golangci.yml deleted file mode 100644 index 9698182f2..000000000 --- a/vendor/github.com/golangci/modinfo/.golangci.yml +++ /dev/null @@ -1,157 +0,0 @@ -run: - timeout: 7m - -linters-settings: - govet: - enable: - - shadow - gocyclo: - min-complexity: 12 - goconst: - min-len: 3 - min-occurrences: 3 - funlen: - lines: -1 - statements: 50 - misspell: - locale: US - depguard: - rules: - main: - deny: - - pkg: "github.com/instana/testify" - desc: not allowed - - pkg: "github.com/pkg/errors" - desc: Should be replaced by standard lib errors package - tagalign: - align: false - order: - - xml - - json - - yaml - - yml - - toml - - mapstructure - - url - godox: - keywords: - - FIXME - gocritic: - enabled-tags: - - diagnostic - - style - - performance - disabled-checks: - - paramTypeCombine # already handle by gofumpt.extra-rules - - whyNoLint # already handle by nonolint - - unnamedResult - - hugeParam - - sloppyReassign - - rangeValCopy - - octalLiteral - - ptrToRefParam - - appendAssign - - ruleguard - - httpNoBody - - exposedSyncMutex - revive: - rules: - - name: struct-tag - - name: blank-imports - - name: context-as-argument - - name: context-keys-type - - name: dot-imports - - name: error-return - - name: error-strings - - name: error-naming - - name: exported - disabled: true - - name: if-return - - name: increment-decrement - - name: var-naming - - name: var-declaration - - name: package-comments - disabled: true - - name: range - - name: receiver-naming - - name: time-naming - - name: unexported-return - - name: indent-error-flow - - name: errorf - - name: empty-block - - name: superfluous-else - - name: unused-parameter - disabled: true - - name: unreachable-code - - name: redefines-builtin-id - - tagliatelle: - case: - rules: - json: pascal - yaml: camel - xml: camel - header: header - mapstructure: camel - env: upperSnake - envconfig: upperSnake - -linters: - enable-all: true - disable: - - deadcode # deprecated - - exhaustivestruct # deprecated - - golint # deprecated - - ifshort # deprecated - - interfacer # deprecated - - maligned # deprecated - - nosnakecase # deprecated - - scopelint # deprecated - - structcheck # deprecated - - varcheck # deprecated - - cyclop # duplicate of gocyclo - - sqlclosecheck # not relevant (SQL) - - rowserrcheck # not relevant (SQL) - - execinquery # not relevant (SQL) - - lll - - gosec - - dupl # not relevant - - prealloc # too many false-positive - - bodyclose # too many false-positive - - gomnd - - testpackage # not relevant - - tparallel # not relevant - - paralleltest # not relevant - - nestif # too many false-positive - - wrapcheck - - goerr113 # not relevant - - nlreturn # not relevant - - wsl # not relevant - - exhaustive # not relevant - - exhaustruct # not relevant - - makezero # not relevant - - forbidigo - - varnamelen # not relevant - - nilnil # not relevant - - ireturn # not relevant - - contextcheck # too many false-positive - - tenv # we already have a test "framework" to handle env vars - - noctx - - errchkjson - - nonamedreturns - - gosmopolitan # not relevant - - gochecknoglobals - -issues: - exclude-use-default: false - max-issues-per-linter: 0 - max-same-issues: 0 - exclude: - - 'Error return value of .((os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*printf?|os\.(Un)?Setenv). is not checked' - - 'ST1000: at least one file in a package should have a package comment' - exclude-rules: - - path: (.+)_test.go - linters: - - funlen - - goconst - - maintidx diff --git a/vendor/github.com/golangci/modinfo/Makefile b/vendor/github.com/golangci/modinfo/Makefile deleted file mode 100644 index df91018f1..000000000 --- a/vendor/github.com/golangci/modinfo/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -.PHONY: clean check test - -default: clean check test - -clean: - rm -rf dist/ cover.out - -test: clean - go test -v -cover ./... - -check: - golangci-lint run diff --git a/vendor/github.com/golangci/modinfo/module.go b/vendor/github.com/golangci/modinfo/module.go deleted file mode 100644 index ff0b21b9b..000000000 --- a/vendor/github.com/golangci/modinfo/module.go +++ /dev/null @@ -1,157 +0,0 @@ -package modinfo - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "os" - "os/exec" - "path/filepath" - "reflect" - "sort" - "strings" - "sync" - - "golang.org/x/mod/modfile" - "golang.org/x/tools/go/analysis" -) - -type ModInfo struct { - Path string `json:"Path"` - Dir string `json:"Dir"` - GoMod string `json:"GoMod"` - GoVersion string `json:"GoVersion"` - Main bool `json:"Main"` -} - -var ( - once sync.Once - information []ModInfo - errInfo error -) - -var Analyzer = &analysis.Analyzer{ - Name: "modinfo", - Doc: "Module information", - URL: "https://github.com/golangci/modinfo", - Run: runOnce, - ResultType: reflect.TypeOf([]ModInfo(nil)), -} - -func runOnce(pass *analysis.Pass) (any, error) { - _, ok := os.LookupEnv("MODINFO_DEBUG_DISABLE_ONCE") - if ok { - return GetModuleInfo(pass) - } - - once.Do(func() { - information, errInfo = GetModuleInfo(pass) - }) - - return information, errInfo -} - -// GetModuleInfo gets modules information. -// Always returns 1 element except for workspace (returns all the modules of the workspace). -// Based on `go list -m -json` behavior. -func GetModuleInfo(pass *analysis.Pass) ([]ModInfo, error) { - // https://github.com/golang/go/issues/44753#issuecomment-790089020 - cmd := exec.Command("go", "list", "-m", "-json") - for _, file := range pass.Files { - name := pass.Fset.File(file.Pos()).Name() - if filepath.Ext(name) != ".go" { - continue - } - - cmd.Dir = filepath.Dir(name) - break - } - - out, err := cmd.Output() - if err != nil { - return nil, fmt.Errorf("command go list: %w: %s", err, string(out)) - } - - var infos []ModInfo - - for dec := json.NewDecoder(bytes.NewBuffer(out)); dec.More(); { - var v ModInfo - if err := dec.Decode(&v); err != nil { - return nil, fmt.Errorf("unmarshaling error: %w: %s", err, string(out)) - } - - if v.GoMod == "" { - return nil, errors.New("working directory is not part of a module") - } - - if !v.Main || v.Dir == "" { - continue - } - - infos = append(infos, v) - } - - if len(infos) == 0 { - return nil, errors.New("go.mod file not found") - } - - sort.Slice(infos, func(i, j int) bool { - return len(infos[i].Path) > len(infos[j].Path) - }) - - return infos, nil -} - -// FindModuleFromPass finds the module related to the files of the pass. -func FindModuleFromPass(pass *analysis.Pass) (ModInfo, error) { - infos, ok := pass.ResultOf[Analyzer].([]ModInfo) - if !ok { - return ModInfo{}, errors.New("no modinfo analyzer result") - } - - var name string - for _, file := range pass.Files { - f := pass.Fset.File(file.Pos()).Name() - if filepath.Ext(f) != ".go" { - continue - } - - name = f - break - } - - // no Go file found in analysis pass - if name == "" { - name, _ = os.Getwd() - } - - for _, info := range infos { - if !strings.HasPrefix(name, info.Dir) { - continue - } - return info, nil - } - - return ModInfo{}, errors.New("module information not found") -} - -// ReadModuleFileFromPass read the `go.mod` file from the pass result. -func ReadModuleFileFromPass(pass *analysis.Pass) (*modfile.File, error) { - info, err := FindModuleFromPass(pass) - if err != nil { - return nil, err - } - - return ReadModuleFile(info) -} - -// ReadModuleFile read the `go.mod` file. -func ReadModuleFile(info ModInfo) (*modfile.File, error) { - raw, err := os.ReadFile(info.GoMod) - if err != nil { - return nil, fmt.Errorf("reading go.mod file: %w", err) - } - - return modfile.Parse("go.mod", raw, nil) -} diff --git a/vendor/github.com/golangci/modinfo/readme.md b/vendor/github.com/golangci/modinfo/readme.md deleted file mode 100644 index 2175de8eb..000000000 --- a/vendor/github.com/golangci/modinfo/readme.md +++ /dev/null @@ -1,73 +0,0 @@ -# modinfo - -This module contains: -- an analyzer that returns module information. -- methods to find and read `go.mod` file - -## Examples - -```go -package main - -import ( - "fmt" - - "github.com/golangci/modinfo" - "golang.org/x/tools/go/analysis" - "golang.org/x/tools/go/analysis/passes/inspect" -) - -var Analyzer = &analysis.Analyzer{ - Name: "example", - Doc: "Example", - Run: func(pass *analysis.Pass) (interface{}, error) { - file, err := modinfo.ReadModuleFileFromPass(pass) - if err != nil { - return nil, err - } - - fmt.Println("go.mod", file) - - // TODO - - return nil, nil - }, - Requires: []*analysis.Analyzer{ - inspect.Analyzer, - modinfo.Analyzer, - }, -} -``` - -```go -package main - -import ( - "fmt" - - "github.com/golangci/modinfo" - "golang.org/x/tools/go/analysis" - "golang.org/x/tools/go/analysis/passes/inspect" -) - -var Analyzer = &analysis.Analyzer{ - Name: "example", - Doc: "Example", - Run: func(pass *analysis.Pass) (interface{}, error) { - info, err := modinfo.FindModuleFromPass(pass) - if err != nil { - return nil, err - } - - fmt.Println("Module", info.Dir) - - // TODO - - return nil, nil - }, - Requires: []*analysis.Analyzer{ - inspect.Analyzer, - modinfo.Analyzer, - }, -} -``` diff --git a/vendor/github.com/golangci/plugin-module-register/LICENSE b/vendor/github.com/golangci/plugin-module-register/LICENSE index e72bfddab..cbdf3d374 100644 --- a/vendor/github.com/golangci/plugin-module-register/LICENSE +++ b/vendor/github.com/golangci/plugin-module-register/LICENSE @@ -1,674 +1,201 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. \ No newline at end of file + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2024 GolangCI Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/golangci/revgrep/.golangci.yml b/vendor/github.com/golangci/revgrep/.golangci.yml index 5239720ac..f08807b12 100644 --- a/vendor/github.com/golangci/revgrep/.golangci.yml +++ b/vendor/github.com/golangci/revgrep/.golangci.yml @@ -1,5 +1,28 @@ -run: - timeout: 2m +linters: + enable-all: true + disable: + - exportloopref # deprecated + - cyclop # duplicate of gocyclo + - sqlclosecheck # not relevant (SQL) + - rowserrcheck # not relevant (SQL) + - dupl + - lll + - nestif + - mnd + - err113 + - nlreturn + - wsl + - exhaustive + - exhaustruct + - tparallel + - testpackage + - paralleltest + - forcetypeassert + - varnamelen + - prealloc # false-positives + - nonamedreturns + - nilerr + - depguard linters-settings: govet: @@ -23,44 +46,9 @@ linters-settings: godox: keywords: - FIXME - -linters: - enable-all: true - disable: - - deadcode # deprecated - - exhaustivestruct # deprecated - - golint # deprecated - - ifshort # deprecated - - interfacer # deprecated - - maligned # deprecated - - nosnakecase # deprecated - - scopelint # deprecated - - structcheck # deprecated - - varcheck # deprecated - - cyclop # duplicate of gocyclo - - sqlclosecheck # not relevant (SQL) - - rowserrcheck # not relevant (SQL) - - execinquery # not relevant (SQL) - - dupl - - lll - - nestif - - gomnd - - goerr113 - - nlreturn - - wsl - - exhaustive - - exhaustruct - - tparallel - - testpackage - - paralleltest - - ifshort - - forcetypeassert - - varnamelen - - prealloc # false-positives - - nosnakecase - - nonamedreturns - - nilerr - - depguard + gosec: + excludes: + - G115 # integer overflow conversion issues: exclude-use-default: false @@ -78,3 +66,6 @@ issues: - path: cmd/revgrep/main.go linters: - forbidigo + +run: + timeout: 2m diff --git a/vendor/github.com/golangci/revgrep/README.md b/vendor/github.com/golangci/revgrep/README.md index 97f25ffb3..c776cb451 100644 --- a/vendor/github.com/golangci/revgrep/README.md +++ b/vendor/github.com/golangci/revgrep/README.md @@ -1,14 +1,14 @@ -# Overview +## Overview `revgrep` is a CLI tool used to filter static analysis tools to only lines changed based on a commit reference. -# Install +## Install ```bash -go get -u github.com/golangci/revgrep/... +go install github.com/golangci/revgrep/cmd/revgrep@latest ``` -# Usage +## Usage In the scenario below, a change was made causing a warning in `go vet` on line 5, but `go vet` will show all warnings. Using `revgrep`, you can show only warnings for lines of code that have been changed (in this case, hiding line 6). @@ -42,7 +42,7 @@ from-rev filters issues to lines changed since (and including) this revision Regexp to match path, line number, optional column number, and message ``` -# Other Examples +## Other Examples Issues between branches: ```bash diff --git a/vendor/github.com/golangci/revgrep/issue.go b/vendor/github.com/golangci/revgrep/issue.go new file mode 100644 index 000000000..694d41639 --- /dev/null +++ b/vendor/github.com/golangci/revgrep/issue.go @@ -0,0 +1,37 @@ +package revgrep + +// Issue contains metadata about an issue found. +type Issue struct { + // File is the name of the file as it appeared from the patch. + File string + // LineNo is the line number of the file. + LineNo int + // ColNo is the column number or 0 if none could be parsed. + ColNo int + // HunkPos is position from file's first @@, for new files this will be the line number. + // See also: https://developer.github.com/v3/pulls/comments/#create-a-comment + HunkPos int + // Issue text as it appeared from the tool. + Issue string + // Message is the issue without file name, line number and column number. + Message string +} + +// InputIssue represents issue found by some linter. +type InputIssue interface { + FilePath() string + Line() int +} + +type simpleInputIssue struct { + filePath string + lineNumber int +} + +func (i simpleInputIssue) FilePath() string { + return i.filePath +} + +func (i simpleInputIssue) Line() int { + return i.lineNumber +} diff --git a/vendor/github.com/golangci/revgrep/patch.go b/vendor/github.com/golangci/revgrep/patch.go new file mode 100644 index 000000000..81a2acd7e --- /dev/null +++ b/vendor/github.com/golangci/revgrep/patch.go @@ -0,0 +1,195 @@ +package revgrep + +import ( + "bytes" + "context" + "errors" + "fmt" + "io" + "os/exec" + "regexp" + "strconv" + "strings" +) + +type patchOption struct { + revisionFrom string + revisionTo string + mergeBase string +} + +// GitPatch returns a patch from a git repository. +// If no git repository was found and no errors occurred, nil is returned, +// else an error is returned revisionFrom and revisionTo defines the git diff parameters, +// if left blank and there are unstaged changes or untracked files, +// only those will be returned else only check changes since HEAD~. +// If revisionFrom is set but revisionTo is not, +// untracked files will be included, to exclude untracked files set revisionTo to HEAD~. +// It's incorrect to specify revisionTo without a revisionFrom. +func GitPatch(ctx context.Context, option patchOption) (io.Reader, []string, error) { + // check if git repo exists + if err := exec.CommandContext(ctx, "git", "status", "--porcelain").Run(); err != nil { + // don't return an error, we assume the error is not repo exists + return nil, nil, nil + } + + // make a patch for untracked files + ls, err := exec.CommandContext(ctx, "git", "ls-files", "--others", "--exclude-standard").CombinedOutput() + if err != nil { + return nil, nil, fmt.Errorf("error executing git ls-files: %w", err) + } + + var newFiles []string + for _, file := range bytes.Split(ls, []byte{'\n'}) { + if len(file) == 0 || bytes.HasSuffix(file, []byte{'/'}) { + // ls-files was sometimes showing directories when they were ignored + // I couldn't create a test case for this as I couldn't reproduce correctly for the moment, + // just exclude files with trailing / + continue + } + + newFiles = append(newFiles, string(file)) + } + + if option.mergeBase != "" { + var base string + base, err = getMergeBase(ctx, option.mergeBase) + if err != nil { + return nil, nil, err + } + + if base != "" { + option.revisionFrom = base + } + } + + if option.revisionFrom != "" { + args := []string{option.revisionFrom} + + if option.revisionTo != "" { + args = append(args, option.revisionTo) + } + + args = append(args, "--") + + patch, errDiff := gitDiff(ctx, args...) + if errDiff != nil { + return nil, nil, errDiff + } + + if option.revisionTo == "" { + return patch, newFiles, nil + } + + return patch, nil, nil + } + + // make a patch for unstaged changes + patch, err := gitDiff(ctx, "--") + if err != nil { + return nil, nil, err + } + + unstaged := patch.Len() > 0 + + // If there's unstaged changes OR untracked changes (or both), + // then this is a suitable patch + if unstaged || newFiles != nil { + return patch, newFiles, nil + } + + // check for changes in recent commit + patch, err = gitDiff(ctx, "HEAD~", "--") + if err != nil { + return nil, nil, err + } + + return patch, nil, nil +} + +func gitDiff(ctx context.Context, extraArgs ...string) (*bytes.Buffer, error) { + cmd := exec.CommandContext(ctx, "git", "diff", "--color=never", "--no-ext-diff") + + if isSupportedByGit(ctx, 2, 41, 0) { + cmd.Args = append(cmd.Args, "--default-prefix") + } + + cmd.Args = append(cmd.Args, "--relative") + cmd.Args = append(cmd.Args, extraArgs...) + + patch := new(bytes.Buffer) + errBuff := new(bytes.Buffer) + + cmd.Stdout = patch + cmd.Stderr = errBuff + + if err := cmd.Run(); err != nil { + return nil, fmt.Errorf("error executing %q: %w: %w", strings.Join(cmd.Args, " "), err, readAsError(errBuff)) + } + + return patch, nil +} + +func readAsError(buff io.Reader) error { + output, err := io.ReadAll(buff) + if err != nil { + return fmt.Errorf("read stderr: %w", err) + } + + return errors.New(string(output)) +} + +func isSupportedByGit(ctx context.Context, major, minor, patch int) bool { + output, err := exec.CommandContext(ctx, "git", "version").CombinedOutput() + if err != nil { + return false + } + + parts := bytes.Split(bytes.TrimSpace(output), []byte(" ")) + if len(parts) < 3 { + return false + } + + v := string(parts[2]) + if v == "" { + return false + } + + vp := regexp.MustCompile(`^(\d+)\.(\d+)(?:\.(\d+))?.*$`).FindStringSubmatch(v) + if len(vp) < 4 { + return false + } + + currentMajor, err := strconv.Atoi(vp[1]) + if err != nil { + return false + } + + currentMinor, err := strconv.Atoi(vp[2]) + if err != nil { + return false + } + + currentPatch, err := strconv.Atoi(vp[3]) + if err != nil { + return false + } + + return currentMajor*1_000_000_000+currentMinor*1_000_000+currentPatch*1_000 >= major*1_000_000_000+minor*1_000_000+patch*1_000 +} + +func getMergeBase(ctx context.Context, base string) (string, error) { + cmd := exec.CommandContext(ctx, "git", "merge-base", base, "HEAD") + + patch := new(bytes.Buffer) + errBuff := new(bytes.Buffer) + + cmd.Stdout = patch + cmd.Stderr = errBuff + + if err := cmd.Run(); err != nil { + return "", fmt.Errorf("error executing %q: %w: %w", strings.Join(cmd.Args, " "), err, readAsError(errBuff)) + } + + return strings.TrimSpace(patch.String()), nil +} diff --git a/vendor/github.com/golangci/revgrep/revgrep.go b/vendor/github.com/golangci/revgrep/revgrep.go index 1ef81b203..ca4ac791c 100644 --- a/vendor/github.com/golangci/revgrep/revgrep.go +++ b/vendor/github.com/golangci/revgrep/revgrep.go @@ -3,12 +3,11 @@ package revgrep import ( "bufio" - "bytes" + "context" "errors" "fmt" "io" "os" - "os/exec" "path/filepath" "regexp" "strconv" @@ -30,96 +29,71 @@ type Checker struct { Debug io.Writer // RevisionFrom check revision starting at, leave blank for auto-detection ignored if patch is set. RevisionFrom string - // WholeFiles indicates that the user wishes to see all issues that comes up anywhere in any file that has been changed in this revision or patch. - WholeFiles bool // RevisionTo checks revision finishing at, leave blank for auto-detection ignored if patch is set. RevisionTo string + // MergeBase checks revision starting at the best common ancestor, leave blank for auto-detection ignored if patch is set. + MergeBase string + // WholeFiles indicates that the user wishes to see all issues that comes up anywhere in any file that has been changed in this revision or patch. + WholeFiles bool // Regexp to match path, line number, optional column number, and message. Regexp string // AbsPath is used to make an absolute path of an issue's filename to be relative in order to match patch file. // If not set, current working directory is used. AbsPath string - // Calculated changes for next calls to IsNewIssue + // Calculated changes for next calls to [Checker.IsNewIssue]/[Checker.IsNew]. changes map[string][]pos } -// Issue contains metadata about an issue found. -type Issue struct { - // File is the name of the file as it appeared from the patch. - File string - // LineNo is the line number of the file. - LineNo int - // ColNo is the column number or 0 if none could be parsed. - ColNo int - // HunkPos is position from file's first @@, for new files this will be the line number. - // See also: https://developer.github.com/v3/pulls/comments/#create-a-comment - HunkPos int - // Issue text as it appeared from the tool. - Issue string - // Message is the issue without file name, line number and column number. - Message string -} - -// InputIssue represents issue found by some linter. -type InputIssue interface { - FilePath() string - Line() int -} - -type simpleInputIssue struct { - filePath string - lineNumber int -} - -type pos struct { - lineNo int // line number - hunkPos int // position relative to first @@ in file -} - -func (i simpleInputIssue) FilePath() string { - return i.filePath -} - -func (i simpleInputIssue) Line() int { - return i.lineNumber -} - // Prepare extracts a patch and changed lines. -func (c *Checker) Prepare() error { - returnErr := c.preparePatch() +// +// WARNING: it should only be used before an explicit call to [Checker.IsNewIssue]/[Checker.IsNew]. +// +// WARNING: only [Checker.Patch], [Checker.RevisionFrom], [Checker.RevisionTo], [Checker.WholeFiles] options are used, +// the other options ([Checker.Regexp], [Checker.AbsPath]) are only used by [Checker.Check]. +func (c *Checker) Prepare(ctx context.Context) error { + err := c.loadPatch(ctx) + c.changes = c.linesChanged() - return returnErr + + return err } -// IsNewIssue checks whether issue found by linter is new: it was found in changed lines. -func (c *Checker) IsNewIssue(i InputIssue) (hunkPos int, isNew bool) { - fchanges, ok := c.changes[filepath.ToSlash(i.FilePath())] - if !ok { // file wasn't changed +// IsNew checks whether issue found by linter is new: it was found in changed lines. +// +// WARNING: it requires to call [Checker.Prepare] before call this method to load the changes from patch. +func (c *Checker) IsNew(filePath string, line int) (hunkPos int, isNew bool) { + changes, ok := c.changes[filepath.ToSlash(filePath)] + if !ok { + // file wasn't changed return 0, false } if c.WholeFiles { - return i.Line(), true + return line, true } var ( fpos pos changed bool ) + // found file, see if lines matched - for _, pos := range fchanges { - if pos.lineNo == i.Line() { + for _, pos := range changes { + if pos.lineNo == line { fpos = pos changed = true + break } } - if changed || fchanges == nil { + if changed || changes == nil { // either file changed or it's a new file hunkPos := fpos.lineNo - if changed { // existing file changed + + // existing file changed + if changed { hunkPos = fpos.hunkPos } @@ -129,7 +103,14 @@ func (c *Checker) IsNewIssue(i InputIssue) (hunkPos int, isNew bool) { return 0, false } -// Check scans reader and writes any lines to writer that have been added in Checker.Patch. +// IsNewIssue checks whether issue found by linter is new: it was found in changed lines. +// +// WARNING: it requires to call [Checker.Prepare] before call this method to load the changes from patch. +func (c *Checker) IsNewIssue(i InputIssue) (hunkPos int, isNew bool) { + return c.IsNew(i.FilePath(), i.Line()) +} + +// Check scans reader and writes any lines to writer that have been added in [Checker.Patch]. // // Returns the issues written to writer when no error occurs. // @@ -137,9 +118,10 @@ func (c *Checker) IsNewIssue(i InputIssue) (hunkPos int, isNew bool) { // all issues are written to writer and an error is returned. // // File paths in reader must be relative to current working directory or absolute. -func (c *Checker) Check(reader io.Reader, writer io.Writer) (issues []Issue, err error) { - returnErr := c.Prepare() - writeAll := returnErr != nil +func (c *Checker) Check(ctx context.Context, reader io.Reader, writer io.Writer) (issues []Issue, err error) { + errPrepare := c.Prepare(ctx) + + writeAll := errPrepare != nil // file.go:lineNo:colNo:message // colNo is optional, strip spaces before message @@ -159,7 +141,7 @@ func (c *Checker) Check(reader io.Reader, writer io.Writer) (issues []Issue, err if absPath == "" { absPath, err = os.Getwd() if err != nil { - returnErr = fmt.Errorf("could not get current working directory: %w", err) + errPrepare = fmt.Errorf("could not get current working directory: %w", err) } } @@ -227,30 +209,41 @@ func (c *Checker) Check(reader io.Reader, writer io.Writer) (issues []Issue, err } if err := scanner.Err(); err != nil { - returnErr = fmt.Errorf("error reading standard input: %w", err) + errPrepare = fmt.Errorf("error reading standard input: %w", err) } - return issues, returnErr + return issues, errPrepare } -func (c *Checker) debugf(format string, s ...interface{}) { - if c.Debug != nil { - _, _ = fmt.Fprint(c.Debug, "DEBUG: ") - _, _ = fmt.Fprintf(c.Debug, format+"\n", s...) +func (c *Checker) debugf(format string, s ...any) { + if c.Debug == nil { + return } + + _, _ = fmt.Fprint(c.Debug, "DEBUG: ") + _, _ = fmt.Fprintf(c.Debug, format+"\n", s...) } -func (c *Checker) preparePatch() error { - // Check if patch is supplied, if not, retrieve from VCS +// loadPatch checks if patch is supplied, if not, retrieve from VCS. +func (c *Checker) loadPatch(ctx context.Context) error { + if c.Patch != nil { + return nil + } + + option := patchOption{ + revisionFrom: c.RevisionFrom, + revisionTo: c.RevisionTo, + mergeBase: c.MergeBase, + } + + var err error + c.Patch, c.NewFiles, err = GitPatch(ctx, option) + if err != nil { + return fmt.Errorf("could not read git repo: %w", err) + } + if c.Patch == nil { - var err error - c.Patch, c.NewFiles, err = GitPatch(c.RevisionFrom, c.RevisionTo) - if err != nil { - return fmt.Errorf("could not read git repo: %w", err) - } - if c.Patch == nil { - return errors.New("no version control repository found") - } + return errors.New("no version control repository found") } return nil @@ -287,15 +280,19 @@ func (c *Checker) linesChanged() map[string][]pos { // it's likey part of a file and not relevant to the patch. continue } + if err != nil { scanErr = err break } + line := strings.TrimRight(string(lineB), "\n") c.debugf(line) + s.lineNo++ s.hunkPos++ + switch { case strings.HasPrefix(line, "+++ ") && len(line) > 4: if s.changes != nil { @@ -304,6 +301,7 @@ func (c *Checker) linesChanged() map[string][]pos { } // 6 removes "+++ b/" s = state{file: line[6:], hunkPos: -1, changes: []pos{}} + case strings.HasPrefix(line, "@@ "): // @@ -1 +2,4 @@ // chdr ^^^^^^^^^^^^^ @@ -311,14 +309,18 @@ func (c *Checker) linesChanged() map[string][]pos { // cstart ^ chdr := strings.Split(line, " ") ahdr := strings.Split(chdr[2], ",") + // [1:] to remove leading plus cstart, err := strconv.ParseUint(ahdr[0][1:], 10, 64) if err != nil { panic(err) } + s.lineNo = int(cstart) - 1 // -1 as cstart is the next line number + case strings.HasPrefix(line, "-"): s.lineNo-- + case strings.HasPrefix(line, "+"): s.changes = append(s.changes, pos{lineNo: s.lineNo, hunkPos: s.hunkPos}) } @@ -334,150 +336,9 @@ func (c *Checker) linesChanged() map[string][]pos { return changes } -// GitPatch returns a patch from a git repository. -// If no git repository was found and no errors occurred, nil is returned, -// else an error is returned revisionFrom and revisionTo defines the git diff parameters, -// if left blank and there are unstaged changes or untracked files, -// only those will be returned else only check changes since HEAD~. -// If revisionFrom is set but revisionTo is not, -// untracked files will be included, to exclude untracked files set revisionTo to HEAD~. -// It's incorrect to specify revisionTo without a revisionFrom. -func GitPatch(revisionFrom, revisionTo string) (io.Reader, []string, error) { - // check if git repo exists - if err := exec.Command("git", "status", "--porcelain").Run(); err != nil { - // don't return an error, we assume the error is not repo exists - return nil, nil, nil - } - - // make a patch for untracked files - ls, err := exec.Command("git", "ls-files", "--others", "--exclude-standard").CombinedOutput() - if err != nil { - return nil, nil, fmt.Errorf("error executing git ls-files: %w", err) - } - - var newFiles []string - for _, file := range bytes.Split(ls, []byte{'\n'}) { - if len(file) == 0 || bytes.HasSuffix(file, []byte{'/'}) { - // ls-files was sometimes showing directories when they were ignored - // I couldn't create a test case for this as I couldn't reproduce correctly for the moment, - // just exclude files with trailing / - continue - } - - newFiles = append(newFiles, string(file)) - } - - if revisionFrom != "" { - args := []string{revisionFrom} - - if revisionTo != "" { - args = append(args, revisionTo) - } - - args = append(args, "--") - - patch, errDiff := gitDiff(args...) - if errDiff != nil { - return nil, nil, errDiff - } - - if revisionTo == "" { - return patch, newFiles, nil - } - - return patch, nil, nil - } - - // make a patch for unstaged changes - patch, err := gitDiff("--") - if err != nil { - return nil, nil, err - } - - unstaged := patch.Len() > 0 - - // If there's unstaged changes OR untracked changes (or both), - // then this is a suitable patch - if unstaged || newFiles != nil { - return patch, newFiles, nil - } - - // check for changes in recent commit - patch, err = gitDiff("HEAD~", "--") - if err != nil { - return nil, nil, err - } - - return patch, nil, nil -} - -func gitDiff(extraArgs ...string) (*bytes.Buffer, error) { - cmd := exec.Command("git", "diff", "--color=never", "--no-ext-diff") - - if isSupportedByGit(2, 41, 0) { - cmd.Args = append(cmd.Args, "--default-prefix") - } - - cmd.Args = append(cmd.Args, "--relative") - cmd.Args = append(cmd.Args, extraArgs...) - - patch := new(bytes.Buffer) - errBuff := new(bytes.Buffer) - - cmd.Stdout = patch - cmd.Stderr = errBuff - - if err := cmd.Run(); err != nil { - return nil, fmt.Errorf("error executing %q: %w: %w", strings.Join(cmd.Args, " "), err, readAsError(errBuff)) - } - - return patch, nil -} - -func readAsError(buff io.Reader) error { - output, err := io.ReadAll(buff) - if err != nil { - return fmt.Errorf("read stderr: %w", err) - } - - return errors.New(string(output)) -} - -func isSupportedByGit(major, minor, patch int) bool { - output, err := exec.Command("git", "version").CombinedOutput() - if err != nil { - return false - } - - parts := bytes.Split(bytes.TrimSpace(output), []byte(" ")) - if len(parts) < 3 { - return false - } - - v := string(parts[2]) - if v == "" { - return false - } - - vp := regexp.MustCompile(`^(\d+)\.(\d+)(?:\.(\d+))?.*$`).FindStringSubmatch(v) - if len(vp) < 4 { - return false - } - - currentMajor, err := strconv.Atoi(vp[1]) - if err != nil { - return false - } - - currentMinor, err := strconv.Atoi(vp[2]) - if err != nil { - return false - } - - currentPatch, err := strconv.Atoi(vp[3]) - if err != nil { - return false - } - - return currentMajor*1_000_000_000+currentMinor*1_000_000+currentPatch*1_000 >= major*1_000_000_000+minor*1_000_000+patch*1_000 +type pos struct { + // Line number. + lineNo int + // Position relative to first @@ in file. + hunkPos int } diff --git a/vendor/github.com/golangci/swaggoswag/.gitignore b/vendor/github.com/golangci/swaggoswag/.gitignore new file mode 100644 index 000000000..865a6f357 --- /dev/null +++ b/vendor/github.com/golangci/swaggoswag/.gitignore @@ -0,0 +1,24 @@ +dist +testdata/simple*/docs +testdata/quotes/docs +testdata/quotes/quotes.so +testdata/delims/docs +testdata/delims/delims.so +example/basic/docs/* +example/celler/docs/* +cover.out + + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out +.idea +.vscode + +# Etc +.DS_Store + +/swag +/swag.exe diff --git a/vendor/github.com/golangci/swaggoswag/formatter.go b/vendor/github.com/golangci/swaggoswag/formatter.go new file mode 100644 index 000000000..6bf92861d --- /dev/null +++ b/vendor/github.com/golangci/swaggoswag/formatter.go @@ -0,0 +1,180 @@ +package swaggoswag + +import ( + "bytes" + "fmt" + "go/ast" + goparser "go/parser" + "go/token" + "regexp" + "sort" + "strings" + "text/tabwriter" + + "golang.org/x/tools/imports" +) + +// Check of @Param @Success @Failure @Response @Header +var specialTagForSplit = map[string]bool{ + paramAttr: true, + successAttr: true, + failureAttr: true, + responseAttr: true, + headerAttr: true, +} + +var skipChar = map[byte]byte{ + '"': '"', + '(': ')', + '{': '}', + '[': ']', +} + +// Formatter implements a formatter for Go source files. +type Formatter struct{} + +// NewFormatter create a new formatter instance. +func NewFormatter() *Formatter { + formatter := &Formatter{} + return formatter +} + +// Format formats swag comments in contents. It uses fileName to report errors +// that happen during parsing of contents. +func (f *Formatter) Format(fileName string, contents []byte) ([]byte, error) { + fileSet := token.NewFileSet() + ast, err := goparser.ParseFile(fileSet, fileName, contents, goparser.ParseComments) + if err != nil { + return nil, err + } + + // Formatting changes are described as an edit list of byte range + // replacements. We make these content-level edits directly rather than + // changing the AST nodes and writing those out (via [go/printer] or + // [go/format]) so that we only change the formatting of Swag attribute + // comments. This won't touch the formatting of any other comments, or of + // functions, etc. + maxEdits := 0 + for _, comment := range ast.Comments { + maxEdits += len(comment.List) + } + edits := make(edits, 0, maxEdits) + + for _, comment := range ast.Comments { + formatFuncDoc(fileSet, comment.List, &edits) + } + formatted, err := imports.Process(fileName, edits.apply(contents), nil) + if err != nil { + return nil, err + } + return formatted, nil +} + +type edit struct { + begin int + end int + replacement []byte +} + +type edits []edit + +func (edits edits) apply(contents []byte) []byte { + // Apply the edits with the highest offset first, so that earlier edits + // don't affect the offsets of later edits. + sort.Slice(edits, func(i, j int) bool { + return edits[i].begin > edits[j].begin + }) + + for _, edit := range edits { + prefix := contents[:edit.begin] + suffix := contents[edit.end:] + contents = append(prefix, append(edit.replacement, suffix...)...) + } + + return contents +} + +// formatFuncDoc reformats the comment lines in commentList, and appends any +// changes to the edit list. +func formatFuncDoc(fileSet *token.FileSet, commentList []*ast.Comment, edits *edits) { + // Building the edit list to format a comment block is a two-step process. + // First, we iterate over each comment line looking for Swag attributes. In + // each one we find, we replace alignment whitespace with a tab character, + // then write the result into a tab writer. + + linesToComments := make(map[int]int, len(commentList)) + + buffer := &bytes.Buffer{} + w := tabwriter.NewWriter(buffer, 1, 4, 1, '\t', 0) + + for commentIndex, comment := range commentList { + text := comment.Text + if attr, body, found := swagComment(text); found { + formatted := "//\t" + attr + if body != "" { + formatted += "\t" + splitComment2(attr, body) + } + _, _ = fmt.Fprintln(w, formatted) + linesToComments[len(linesToComments)] = commentIndex + } + } + + // Once we've loaded all of the comment lines to be aligned into the tab + // writer, flushing it causes the aligned text to be written out to the + // backing buffer. + _ = w.Flush() + + // Now the second step: we iterate over the aligned comment lines that were + // written into the backing buffer, pair each one up to its original + // comment line, and use the combination to describe the edit that needs to + // be made to the original input. + formattedComments := bytes.Split(buffer.Bytes(), []byte("\n")) + for lineIndex, commentIndex := range linesToComments { + comment := commentList[commentIndex] + *edits = append(*edits, edit{ + begin: fileSet.Position(comment.Pos()).Offset, + end: fileSet.Position(comment.End()).Offset, + replacement: formattedComments[lineIndex], + }) + } +} + +func splitComment2(attr, body string) string { + if specialTagForSplit[strings.ToLower(attr)] { + for i := 0; i < len(body); i++ { + if skipEnd, ok := skipChar[body[i]]; ok { + skipStart, n := body[i], 1 + for i++; i < len(body); i++ { + if skipStart != skipEnd && body[i] == skipStart { + n++ + } else if body[i] == skipEnd { + n-- + if n == 0 { + break + } + } + } + } else if body[i] == ' ' || body[i] == '\t' { + j := i + for ; j < len(body) && (body[j] == ' ' || body[j] == '\t'); j++ { + } + body = replaceRange(body, i, j, "\t") + } + } + } + return body +} + +func replaceRange(s string, start, end int, new string) string { + return s[:start] + new + s[end:] +} + +var swagCommentLineExpression = regexp.MustCompile(`^\/\/\s+(@[\S.]+)\s*(.*)`) + +func swagComment(comment string) (string, string, bool) { + matches := swagCommentLineExpression.FindStringSubmatch(comment) + if matches == nil { + return "", "", false + } + return matches[1], matches[2], true +} diff --git a/vendor/github.com/golangci/swaggoswag/license b/vendor/github.com/golangci/swaggoswag/license new file mode 100644 index 000000000..a97865bf4 --- /dev/null +++ b/vendor/github.com/golangci/swaggoswag/license @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Eason Lin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/golangci/swaggoswag/parser.go b/vendor/github.com/golangci/swaggoswag/parser.go new file mode 100644 index 000000000..368517b61 --- /dev/null +++ b/vendor/github.com/golangci/swaggoswag/parser.go @@ -0,0 +1,48 @@ +package swaggoswag + +const ( + // CamelCase indicates using CamelCase strategy for struct field. + CamelCase = "camelcase" + + // PascalCase indicates using PascalCase strategy for struct field. + PascalCase = "pascalcase" + + // SnakeCase indicates using SnakeCase strategy for struct field. + SnakeCase = "snakecase" + + idAttr = "@id" + acceptAttr = "@accept" + produceAttr = "@produce" + paramAttr = "@param" + successAttr = "@success" + failureAttr = "@failure" + responseAttr = "@response" + headerAttr = "@header" + tagsAttr = "@tags" + routerAttr = "@router" + deprecatedRouterAttr = "@deprecatedrouter" + summaryAttr = "@summary" + deprecatedAttr = "@deprecated" + securityAttr = "@security" + titleAttr = "@title" + conNameAttr = "@contact.name" + conURLAttr = "@contact.url" + conEmailAttr = "@contact.email" + licNameAttr = "@license.name" + licURLAttr = "@license.url" + versionAttr = "@version" + descriptionAttr = "@description" + descriptionMarkdownAttr = "@description.markdown" + secBasicAttr = "@securitydefinitions.basic" + secAPIKeyAttr = "@securitydefinitions.apikey" + secApplicationAttr = "@securitydefinitions.oauth2.application" + secImplicitAttr = "@securitydefinitions.oauth2.implicit" + secPasswordAttr = "@securitydefinitions.oauth2.password" + secAccessCodeAttr = "@securitydefinitions.oauth2.accesscode" + tosAttr = "@termsofservice" + extDocsDescAttr = "@externaldocs.description" + extDocsURLAttr = "@externaldocs.url" + xCodeSamplesAttr = "@x-codesamples" + scopeAttrPrefix = "@scope." + stateAttr = "@state" +) diff --git a/vendor/github.com/golangci/swaggoswag/readme.md b/vendor/github.com/golangci/swaggoswag/readme.md new file mode 100644 index 000000000..4d1c26005 --- /dev/null +++ b/vendor/github.com/golangci/swaggoswag/readme.md @@ -0,0 +1,26 @@ +# Fork of swaggo/swag + +This is a hard fork of [swaggo/swag](https://github.com/swaggo/swag) to be usable as a library. + +I considered other options before deciding to fork, but there are no straightforward or non-invasive changes. + +Issues should be open either on the original [swaggo/swag repository](https://github.com/swaggo/swag) or on [golangci-lint repository](https://github.com/golangci/golangci-lint). + +**No modifications will be accepted other than the synchronization of the fork.** + +The synchronization of the fork will be done by the golangci-lint maintainers only. + +## Modifications + +- All the files have been removed except: + - `formatter.go` (the unused field `debug Debugger` is removed) + - `formatter_test.go` + - `parser.go` (only the constants are kept.) + - `license` + - `.gitignore` +- The module name has been changed to `github.com/golangci/swaggoswag` to avoid replacement directives inside golangci-lint. + - The package name has been changed from `swag` to `swaggoswag`. + +## History + +- sync with 93e86851e9f22f1f2db57812cf71fc004c02159c (after v1.16.4) diff --git a/vendor/github.com/golangci/unconvert/golangci.go b/vendor/github.com/golangci/unconvert/golangci.go index 306c44e5e..04e385a0b 100644 --- a/vendor/github.com/golangci/unconvert/golangci.go +++ b/vendor/github.com/golangci/unconvert/golangci.go @@ -25,15 +25,22 @@ var ( func pointer[T string | int | int32 | int64 | bool](v T) *T { return &v } -func Run(pass *analysis.Pass, fastMath, safe bool) []token.Position { +func SetFastMath(fastMath bool) { + // To avoid race condition, the settings should not be defined during the Run. + flagFastMath = pointer(fastMath) +} + +func SetSafe(safe bool) { + // To avoid race condition, the settings should not be defined during the Run. + flagSafe = pointer(safe) +} + +func Run(pass *analysis.Pass) []token.Position { type res struct { file string edits editSet } - flagFastMath = pointer(fastMath) - flagSafe = pointer(safe) - ch := make(chan res) var wg sync.WaitGroup for _, file := range pass.Files { diff --git a/vendor/github.com/golangci/unconvert/unconvert.go b/vendor/github.com/golangci/unconvert/unconvert.go index 222aeadf8..36c34fa46 100644 --- a/vendor/github.com/golangci/unconvert/unconvert.go +++ b/vendor/github.com/golangci/unconvert/unconvert.go @@ -15,7 +15,6 @@ import ( "go/parser" "go/token" "go/types" - "io/ioutil" "log" "os" "os/exec" @@ -87,7 +86,7 @@ func apply(file string, edits editSet) { log.Fatal(err) } - err = ioutil.WriteFile(file, buf.Bytes(), 0) + err = os.WriteFile(file, buf.Bytes(), 0) if err != nil { log.Fatal(err) } @@ -143,7 +142,7 @@ func print(conversions []token.Position) { fmt.Printf("%s:%d:%d: unnecessary conversion\n", pos.Filename, pos.Line, pos.Column) if *flagV { if pos.Filename != file { - buf, err := ioutil.ReadFile(pos.Filename) + buf, err := os.ReadFile(pos.Filename) if err != nil { log.Fatal(err) } diff --git a/vendor/github.com/gordonklaus/ineffassign/pkg/ineffassign/ineffassign.go b/vendor/github.com/gordonklaus/ineffassign/pkg/ineffassign/ineffassign.go index f9dece8f2..19da47b5c 100644 --- a/vendor/github.com/gordonklaus/ineffassign/pkg/ineffassign/ineffassign.go +++ b/vendor/github.com/gordonklaus/ineffassign/pkg/ineffassign/ineffassign.go @@ -5,21 +5,26 @@ import ( "go/ast" "go/token" "sort" - "strings" "golang.org/x/tools/go/analysis" ) +var checkEscapingErrors bool + // Analyzer is the ineffassign analysis.Analyzer instance. var Analyzer = &analysis.Analyzer{ Name: "ineffassign", - Doc: "detect ineffectual assignments in Go code", + Doc: "detects when assignments to existing variables are not used", Run: checkPath, } +func init() { + Analyzer.Flags.BoolVar(&checkEscapingErrors, "check-escaping-errors", false, "check escaping variables of type error, may cause false positives") +} + func checkPath(pass *analysis.Pass) (interface{}, error) { for _, file := range pass.Files { - if isGenerated(file) { + if ast.IsGenerated(file) { continue } @@ -35,6 +40,7 @@ func checkPath(pass *analysis.Pass) (interface{}, error) { for _, id := range chk.ineff { pass.Report(analysis.Diagnostic{ Pos: id.Pos(), + End: id.End(), Message: fmt.Sprintf("ineffectual assignment to %s", id.Name), }) } @@ -43,18 +49,6 @@ func checkPath(pass *analysis.Pass) (interface{}, error) { return nil, nil } -func isGenerated(file *ast.File) bool { - for _, cg := range file.Comments { - for _, c := range cg.List { - if strings.HasPrefix(c.Text, "// Code generated ") && strings.HasSuffix(c.Text, " DO NOT EDIT.") { - return true - } - } - } - - return false -} - type builder struct { roots []*block block *block @@ -96,10 +90,10 @@ func (bld *builder) Visit(n ast.Node) ast.Visitor { switch n := n.(type) { case *ast.FuncDecl: if n.Body != nil { - bld.fun(n.Type, n.Body) + bld.fun(n.Recv, n.Type, n.Body) } case *ast.FuncLit: - bld.fun(n.Type, n.Body) + bld.fun(nil, n.Type, n.Body) case *ast.IfStmt: bld.walk(n.Init) bld.walk(n.Cond) @@ -290,9 +284,7 @@ func (bld *builder) Visit(n ast.Node) ast.Visitor { id, ok = ident(ix.X) } if ok && n.Op == token.AND { - if v, ok := bld.vars[id.Obj]; ok { - v.escapes = true - } + bld.escape(id) } return bld case *ast.SelectorExpr: @@ -301,18 +293,14 @@ func (bld *builder) Visit(n ast.Node) ast.Visitor { // the address of its receiver, causing it to escape. // We can't do any better here without knowing the variable's type. if id, ok := ident(n.X); ok { - if v, ok := bld.vars[id.Obj]; ok { - v.escapes = true - } + bld.escape(id) } return bld case *ast.SliceExpr: bld.maybePanic() // We don't care about slicing into slices, but without type information we can do no better. if id, ok := ident(n.X); ok { - if v, ok := bld.vars[id.Obj]; ok { - v.escapes = true - } + bld.escape(id) } return bld case *ast.StarExpr: @@ -328,6 +316,21 @@ func (bld *builder) Visit(n ast.Node) ast.Visitor { return nil } +func (bld *builder) escape(id *ast.Ident) { + if checkEscapingErrors && id.Obj != nil { + if d, ok := id.Obj.Decl.(*ast.ValueSpec); ok { + if t, ok := d.Type.(*ast.Ident); ok { + if t.Name == "error" { + return + } + } + } + } + if v, ok := bld.vars[id.Obj]; ok { + v.escapes = true + } +} + func isZeroInitializer(x ast.Expr) bool { // Assume that a call expression of a single argument is a conversion expression. We can't do better without type information. if c, ok := x.(*ast.CallExpr); ok { @@ -362,7 +365,7 @@ func isZeroInitializer(x ast.Expr) bool { return false } -func (bld *builder) fun(typ *ast.FuncType, body *ast.BlockStmt) { +func (bld *builder) fun(recv *ast.FieldList, typ *ast.FuncType, body *ast.BlockStmt) { for _, v := range bld.vars { v.fundept++ } @@ -372,6 +375,9 @@ func (bld *builder) fun(typ *ast.FuncType, body *ast.BlockStmt) { b := bld.block bld.newBlock() bld.roots = append(bld.roots, bld.block) + if recv != nil { + bld.walk(recv) + } bld.walk(typ) bld.walk(body) bld.block = b diff --git a/vendor/github.com/gostaticanalysis/comment/.tagpr b/vendor/github.com/gostaticanalysis/comment/.tagpr new file mode 100644 index 000000000..59bf98541 --- /dev/null +++ b/vendor/github.com/gostaticanalysis/comment/.tagpr @@ -0,0 +1,35 @@ +# config file for the tagpr in git config format +# The tagpr generates the initial configuration, which you can rewrite to suit your environment. +# CONFIGURATIONS: +# tagpr.releaseBranch +# Generally, it is "main." It is the branch for releases. The pcpr tracks this branch, +# creates or updates a pull request as a release candidate, or tags when they are merged. +# +# tagpr.versionFile +# Versioning file containing the semantic version needed to be updated at release. +# It will be synchronized with the "git tag". +# Often this is a meta-information file such as gemspec, setup.cfg, package.json, etc. +# Sometimes the source code file, such as version.go or Bar.pm, is used. +# If you do not want to use versioning files but only git tags, specify the "-" string here. +# You can specify multiple version files by comma separated strings. +# +# tagpr.vPrefix +# Flag whether or not v-prefix is added to semver when git tagging. (e.g. v1.2.3 if true) +# This is only a tagging convention, not how it is described in the version file. +# +# tagpr.changelog (Optional) +# Flag whether or not changelog is added or changed during the release. +# +# tagpr.command (Optional) +# Command to change files just before release. +# +# tagpr.tmplate (Optional) +# Pull request template in go template format +# +# tagpr.release (Optional) +# GitHub Release creation behavior after tagging [true, draft, false] +# If this value is not set, the release is to be created. +[tagpr] + vPrefix = true + releaseBranch = main + versionFile = version.txt diff --git a/vendor/github.com/gostaticanalysis/comment/CHANGELOG.md b/vendor/github.com/gostaticanalysis/comment/CHANGELOG.md new file mode 100644 index 000000000..941cc15ff --- /dev/null +++ b/vendor/github.com/gostaticanalysis/comment/CHANGELOG.md @@ -0,0 +1,34 @@ +# Changelog + +## [v1.5.0](https://github.com/gostaticanalysis/comment/compare/v1.4.2...v1.5.0) - 2024-11-15 +- Add tagpr and testvet by @tenntenn in https://github.com/gostaticanalysis/comment/pull/18 +- Add IgnorePosLine and deprecate IgnoreLine by @neglect-yp in https://github.com/gostaticanalysis/comment/pull/17 +- Fix errors for testvet by @tenntenn in https://github.com/gostaticanalysis/comment/pull/20 +- Add version.txt by @tenntenn in https://github.com/gostaticanalysis/comment/pull/21 +- Update go version and dependencies by @tenntenn in https://github.com/gostaticanalysis/comment/pull/19 + +## [v1.4.2](https://github.com/gostaticanalysis/comment/compare/v1.4.1...v1.4.2) - 2021-03-03 +- passes/commentmap: use txtar for testdata by @zchee in https://github.com/gostaticanalysis/comment/pull/14 +- github/workflows: add test GHA by @zchee in https://github.com/gostaticanalysis/comment/pull/15 +- omment: fix hasIgnoreCheck to more pares lines by @zchee in https://github.com/gostaticanalysis/comment/pull/16 + +## [v1.4.1](https://github.com/gostaticanalysis/comment/compare/v1.4.0...v1.4.1) - 2020-09-10 +- Fix comment directive parsing in Go 1.15+ by @nmiyake in https://github.com/gostaticanalysis/comment/pull/13 +- gofmt files by @nmiyake in https://github.com/gostaticanalysis/comment/pull/12 +- Fix logic error in hasIgnoreCheck by @nmiyake in https://github.com/gostaticanalysis/comment/pull/11 + +## [v1.4.0](https://github.com/gostaticanalysis/comment/compare/v1.3.0...v1.4.0) - 2020-08-20 +- Add CommentsByPosLine by @tenntenn in https://github.com/gostaticanalysis/comment/pull/9 + +## [v1.3.0](https://github.com/gostaticanalysis/comment/compare/v1.2.0...v1.3.0) - 2020-01-30 +- Fix link to ast package by @po3rin in https://github.com/gostaticanalysis/comment/pull/4 +- Add IgnoreLine by @tenntenn in https://github.com/gostaticanalysis/comment/pull/5 + +## [v1.2.0](https://github.com/gostaticanalysis/comment/compare/v1.1.0...v1.2.0) - 2019-03-18 +- Add IgnorePos by @tenntenn in https://github.com/gostaticanalysis/comment/pull/3 + +## [v1.1.0](https://github.com/gostaticanalysis/comment/compare/v1.0.0...v1.1.0) - 2019-03-08 +- Add ignore by @tenntenn in https://github.com/gostaticanalysis/comment/pull/1 +- Fix Ignore and add tests by @tenntenn in https://github.com/gostaticanalysis/comment/pull/2 + +## [v1.0.0](https://github.com/gostaticanalysis/comment/commits/v1.0.0) - 2019-03-08 diff --git a/vendor/github.com/gostaticanalysis/comment/comment.go b/vendor/github.com/gostaticanalysis/comment/comment.go index 79cb09382..2e418a466 100644 --- a/vendor/github.com/gostaticanalysis/comment/comment.go +++ b/vendor/github.com/gostaticanalysis/comment/comment.go @@ -52,7 +52,8 @@ func (maps Maps) Annotated(n ast.Node, annotation string) bool { // Ignore checks either specified AST node is ignored by the check. // It follows staticcheck style as the below. -// //lint:ignore Check1[,Check2,...,CheckN] reason +// +// //lint:ignore Check1[,Check2,...,CheckN] reason func (maps Maps) Ignore(n ast.Node, check string) bool { for _, cg := range maps.Comments(n) { if hasIgnoreCheck(cg, check) { @@ -64,7 +65,8 @@ func (maps Maps) Ignore(n ast.Node, check string) bool { // IgnorePos checks either specified postion of AST node is ignored by the check. // It follows staticcheck style as the below. -// //lint:ignore Check1[,Check2,...,CheckN] reason +// +// //lint:ignore Check1[,Check2,...,CheckN] reason func (maps Maps) IgnorePos(pos token.Pos, check string) bool { for _, cg := range maps.CommentsByPos(pos) { if hasIgnoreCheck(cg, check) { @@ -109,9 +111,11 @@ func (maps Maps) CommentsByPosLine(fset *token.FileSet, pos token.Pos) []*ast.Co return nil } +// Deprecated: This function does not work with multiple files. // IgnoreLine checks either specified lineof AST node is ignored by the check. // It follows staticcheck style as the below. -// //lint:ignore Check1[,Check2,...,CheckN] reason +// +// //lint:ignore Check1[,Check2,...,CheckN] reason func (maps Maps) IgnoreLine(fset *token.FileSet, line int, check string) bool { for _, cg := range maps.CommentsByLine(fset, line) { if hasIgnoreCheck(cg, check) { @@ -121,6 +125,19 @@ func (maps Maps) IgnoreLine(fset *token.FileSet, line int, check string) bool { return false } +// IgnorePosLine checks either specified lineof AST node is ignored by the check. +// It follows staticcheck style as the below. +// +// //lint:ignore Check1[,Check2,...,CheckN] reason +func (maps Maps) IgnorePosLine(fset *token.FileSet, pos token.Pos, check string) bool { + for _, cg := range maps.CommentsByPosLine(fset, pos) { + if hasIgnoreCheck(cg, check) { + return true + } + } + return false +} + // hasIgnoreCheck returns true if the provided CommentGroup starts with a comment // of the form "//lint:ignore Check1[,Check2,...,CheckN] reason" and one of the // checks matches the provided check. diff --git a/vendor/github.com/gostaticanalysis/comment/version.txt b/vendor/github.com/gostaticanalysis/comment/version.txt new file mode 100644 index 000000000..2e7bd9108 --- /dev/null +++ b/vendor/github.com/gostaticanalysis/comment/version.txt @@ -0,0 +1 @@ +v1.5.0 diff --git a/vendor/github.com/gostaticanalysis/forcetypeassert/.tagpr b/vendor/github.com/gostaticanalysis/forcetypeassert/.tagpr new file mode 100644 index 000000000..59bf98541 --- /dev/null +++ b/vendor/github.com/gostaticanalysis/forcetypeassert/.tagpr @@ -0,0 +1,35 @@ +# config file for the tagpr in git config format +# The tagpr generates the initial configuration, which you can rewrite to suit your environment. +# CONFIGURATIONS: +# tagpr.releaseBranch +# Generally, it is "main." It is the branch for releases. The pcpr tracks this branch, +# creates or updates a pull request as a release candidate, or tags when they are merged. +# +# tagpr.versionFile +# Versioning file containing the semantic version needed to be updated at release. +# It will be synchronized with the "git tag". +# Often this is a meta-information file such as gemspec, setup.cfg, package.json, etc. +# Sometimes the source code file, such as version.go or Bar.pm, is used. +# If you do not want to use versioning files but only git tags, specify the "-" string here. +# You can specify multiple version files by comma separated strings. +# +# tagpr.vPrefix +# Flag whether or not v-prefix is added to semver when git tagging. (e.g. v1.2.3 if true) +# This is only a tagging convention, not how it is described in the version file. +# +# tagpr.changelog (Optional) +# Flag whether or not changelog is added or changed during the release. +# +# tagpr.command (Optional) +# Command to change files just before release. +# +# tagpr.tmplate (Optional) +# Pull request template in go template format +# +# tagpr.release (Optional) +# GitHub Release creation behavior after tagging [true, draft, false] +# If this value is not set, the release is to be created. +[tagpr] + vPrefix = true + releaseBranch = main + versionFile = version.txt diff --git a/vendor/github.com/gostaticanalysis/forcetypeassert/CHANGELOG.md b/vendor/github.com/gostaticanalysis/forcetypeassert/CHANGELOG.md new file mode 100644 index 000000000..7575fec62 --- /dev/null +++ b/vendor/github.com/gostaticanalysis/forcetypeassert/CHANGELOG.md @@ -0,0 +1,19 @@ +# Changelog + +## [v0.2.0](https://github.com/gostaticanalysis/forcetypeassert/compare/v0.1.0...v0.2.0) - 2025-02-13 +- Update x/tools to fix panic in tests by @alexandear in https://github.com/gostaticanalysis/forcetypeassert/pull/19 +- go.mod: bump golang.org/x/tools dependency by @egonelbre in https://github.com/gostaticanalysis/forcetypeassert/pull/20 +- Add tagpr and version up Go and dependencies by @tenntenn in https://github.com/gostaticanalysis/forcetypeassert/pull/21 +- Support any by @tenntenn in https://github.com/gostaticanalysis/forcetypeassert/pull/23 +- Fix for #18 by @tenntenn in https://github.com/gostaticanalysis/forcetypeassert/pull/24 + +## [v0.1.0](https://github.com/gostaticanalysis/forcetypeassert/commits/v0.1.0) - 2021-09-08 +- update check pattern by @knsh14 in https://github.com/gostaticanalysis/forcetypeassert/pull/1 +- Fix typo by @tenntenn in https://github.com/gostaticanalysis/forcetypeassert/pull/3 +- Add reviewdog setting by @tenntenn in https://github.com/gostaticanalysis/forcetypeassert/pull/4 +- Add an explanation on how to fix the linter errors by @ozon2 in https://github.com/gostaticanalysis/forcetypeassert/pull/9 +- Delete reviewdog.yml by @tenntenn in https://github.com/gostaticanalysis/forcetypeassert/pull/11 +- Create testandvet.yml by @tenntenn in https://github.com/gostaticanalysis/forcetypeassert/pull/10 +- Fix bug for valuespec by @tenntenn in https://github.com/gostaticanalysis/forcetypeassert/pull/12 +- Fix bugs for expressions by @tenntenn in https://github.com/gostaticanalysis/forcetypeassert/pull/13 +- Add result by @tenntenn in https://github.com/gostaticanalysis/forcetypeassert/pull/14 diff --git a/vendor/github.com/gostaticanalysis/forcetypeassert/forcetypeassert.go b/vendor/github.com/gostaticanalysis/forcetypeassert/forcetypeassert.go index bb48485d9..e1b21825b 100644 --- a/vendor/github.com/gostaticanalysis/forcetypeassert/forcetypeassert.go +++ b/vendor/github.com/gostaticanalysis/forcetypeassert/forcetypeassert.go @@ -2,6 +2,7 @@ package forcetypeassert import ( "go/ast" + "go/types" "reflect" "golang.org/x/tools/go/analysis" @@ -42,7 +43,9 @@ func (p *Panicable) At(i int) ast.Node { const Doc = "forcetypeassert is finds type assertions which did forcely" -func run(pass *analysis.Pass) (interface{}, error) { +var anyTyp = types.Universe.Lookup("any").Type() + +func run(pass *analysis.Pass) (any, error) { inspect, _ := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) result := &Panicable{m: make(map[ast.Node]bool)} @@ -62,7 +65,7 @@ func run(pass *analysis.Pass) (interface{}, error) { case *ast.ValueSpec: return checkValueSpec(pass, result, n) case *ast.TypeAssertExpr: - if n.Type != nil { + if n.Type != nil && !isAny(pass, n.Type) { result.m[n] = true result.nodes = append(result.nodes, n) pass.Reportf(n.Pos(), "type assertion must be checked") @@ -76,6 +79,10 @@ func run(pass *analysis.Pass) (interface{}, error) { return result, nil } +func isAny(pass *analysis.Pass, expr ast.Expr) bool { + return types.Identical(pass.TypesInfo.TypeOf(expr), anyTyp) +} + func checkAssignStmt(pass *analysis.Pass, result *Panicable, n *ast.AssignStmt) bool { tae := findTypeAssertion(n.Rhs) if tae == nil { @@ -83,11 +90,16 @@ func checkAssignStmt(pass *analysis.Pass, result *Panicable, n *ast.AssignStmt) } switch { + + // if right hand is a call expression, assign statement can't assert boolean value which describes type assertion is succeeded + case len(n.Rhs) == 1 && isCallExpr(n.Rhs[0]): + pass.Reportf(n.Pos(), "right hand must be only type assertion") + return false // if right hand has 2 or more values, assign statement can't assert boolean value which describes type assertion is succeeded case len(n.Rhs) > 1: pass.Reportf(n.Pos(), "right hand must be only type assertion") return false - case len(n.Lhs) != 2 && tae.Type != nil: + case len(n.Lhs) != 2 && tae.Type != nil && !isAny(pass, tae.Type): result.m[n] = true result.nodes = append(result.nodes, n) pass.Reportf(n.Pos(), "type assertion must be checked") @@ -106,11 +118,15 @@ func checkValueSpec(pass *analysis.Pass, result *Panicable, n *ast.ValueSpec) bo } switch { + // if right hand is a call expression, assign statement can't assert boolean value which describes type assertion is succeeded + case len(n.Values) == 1 && isCallExpr(n.Values[0]): + pass.Reportf(n.Pos(), "right hand must be only type assertion") + return false // if right hand has 2 or more values, assign statement can't assert boolean value which describes type assertion is succeeded case len(n.Values) > 1: pass.Reportf(n.Pos(), "right hand must be only type assertion") return false - case len(n.Names) != 2 && tae.Type != nil: + case len(n.Names) != 2 && tae.Type != nil && !isAny(pass, tae.Type): result.m[n] = true result.nodes = append(result.nodes, n) pass.Reportf(n.Pos(), "type assertion must be checked") @@ -141,3 +157,8 @@ func findTypeAssertion(exprs []ast.Expr) *ast.TypeAssertExpr { } return nil } + +func isCallExpr(expr ast.Expr) bool { + _, isCallExpr := expr.(*ast.CallExpr) + return isCallExpr +} diff --git a/vendor/github.com/gostaticanalysis/forcetypeassert/version.txt b/vendor/github.com/gostaticanalysis/forcetypeassert/version.txt new file mode 100644 index 000000000..1474d00f0 --- /dev/null +++ b/vendor/github.com/gostaticanalysis/forcetypeassert/version.txt @@ -0,0 +1 @@ +v0.2.0 diff --git a/vendor/github.com/gostaticanalysis/nilerr/README.md b/vendor/github.com/gostaticanalysis/nilerr/README.md index d6b4acf8b..d2d8069bb 100644 --- a/vendor/github.com/gostaticanalysis/nilerr/README.md +++ b/vendor/github.com/gostaticanalysis/nilerr/README.md @@ -36,6 +36,12 @@ func f() error { } ``` +## How to use +``` +$ go install github.com/gostaticanalysis/nilerr/cmd/nilerr@latest +$ nilerr ./... +``` + [gopkg]: https://pkg.go.dev/github.com/gostaticanalysis/nilerr [gopkg-badge]: https://pkg.go.dev/badge/github.com/gostaticanalysis/nilerr?status.svg diff --git a/vendor/github.com/gostaticanalysis/nilerr/nilerr.go b/vendor/github.com/gostaticanalysis/nilerr/nilerr.go index 787a9e1e9..4615e6d14 100644 --- a/vendor/github.com/gostaticanalysis/nilerr/nilerr.go +++ b/vendor/github.com/gostaticanalysis/nilerr/nilerr.go @@ -4,6 +4,7 @@ import ( "fmt" "go/token" "go/types" + "slices" "github.com/gostaticanalysis/comment" "github.com/gostaticanalysis/comment/passes/commentmap" @@ -30,9 +31,10 @@ func run(pass *analysis.Pass) (interface{}, error) { reportFail := func(v ssa.Value, ret *ssa.Return, format string) { pos := ret.Pos() - line := getNodeLineNumber(pass, ret) - errLines := getValueLineNumbers(pass, v) - if !cmaps.IgnoreLine(pass.Fset, line, "nilerr") { + if !cmaps.IgnorePos(pos, "nilerr") { + seen := map[string]struct{}{} + errLines := getValueLineNumbers(pass, v, seen) + var errLineText string if len(errLines) == 1 { errLineText = fmt.Sprintf("line %d", errLines[0]) @@ -65,12 +67,30 @@ func run(pass *analysis.Pass) (interface{}, error) { return nil, nil } -func getValueLineNumbers(pass *analysis.Pass, v ssa.Value) []int { +// getValueLineNumbers returns the line numbers. +// `seen` is used to avoid infinite loop. +func getValueLineNumbers(pass *analysis.Pass, v ssa.Value, seen map[string]struct{}) []int { if phi, ok := v.(*ssa.Phi); ok { result := make([]int, 0, len(phi.Edges)) + for _, edge := range phi.Edges { - result = append(result, getValueLineNumbers(pass, edge)...) + if _, ok := seen[edge.Name()]; ok { + if edge.Pos() == token.NoPos { + // Skip elements without a position. + continue + } + + result = append(result, pass.Fset.File(edge.Pos()).Line(edge.Pos())) + continue + } + + seen[edge.Name()] = struct{}{} + + result = append(result, getValueLineNumbers(pass, edge, seen)...) } + + slices.Sort(result) + return result } @@ -80,12 +100,12 @@ func getValueLineNumbers(pass *analysis.Pass, v ssa.Value) []int { } pos := value.Pos() - return []int{pass.Fset.File(pos).Line(pos)} -} -func getNodeLineNumber(pass *analysis.Pass, node ssa.Node) int { - pos := node.Pos() - return pass.Fset.File(pos).Line(pos) + if pos == token.NoPos { + return nil + } + + return []int{pass.Fset.File(pos).Line(pos)} } var errType = types.Universe.Lookup("error").Type().Underlying().(*types.Interface) diff --git a/vendor/github.com/hashicorp/go-immutable-radix/v2/.gitignore b/vendor/github.com/hashicorp/go-immutable-radix/v2/.gitignore new file mode 100644 index 000000000..daf913b1b --- /dev/null +++ b/vendor/github.com/hashicorp/go-immutable-radix/v2/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/vendor/github.com/hashicorp/go-immutable-radix/v2/CHANGELOG.md b/vendor/github.com/hashicorp/go-immutable-radix/v2/CHANGELOG.md new file mode 100644 index 000000000..556f1a67b --- /dev/null +++ b/vendor/github.com/hashicorp/go-immutable-radix/v2/CHANGELOG.md @@ -0,0 +1,27 @@ +# UNRELEASED + +# 2.0.0 (December 15th, 2022) + +* Update API to use generics [[GH-43](https://github.com/hashicorp/go-immutable-radix/pull/43)) + +# 1.3.0 (September 17th, 2020) + +FEATURES + +* Add reverse tree traversal [[GH-30](https://github.com/hashicorp/go-immutable-radix/pull/30)] + +# 1.2.0 (March 18th, 2020) + +FEATURES + +* Adds a `Clone` method to `Txn` allowing transactions to be split either into two independently mutable trees. [[GH-26](https://github.com/hashicorp/go-immutable-radix/pull/26)] + +# 1.1.0 (May 22nd, 2019) + +FEATURES + +* Add `SeekLowerBound` to allow for range scans. [[GH-24](https://github.com/hashicorp/go-immutable-radix/pull/24)] + +# 1.0.0 (August 30th, 2018) + +* go mod adopted diff --git a/vendor/github.com/hashicorp/hcl/LICENSE b/vendor/github.com/hashicorp/go-immutable-radix/v2/LICENSE similarity index 50% rename from vendor/github.com/hashicorp/hcl/LICENSE rename to vendor/github.com/hashicorp/go-immutable-radix/v2/LICENSE index c33dcc7c9..f4f97ee58 100644 --- a/vendor/github.com/hashicorp/hcl/LICENSE +++ b/vendor/github.com/hashicorp/go-immutable-radix/v2/LICENSE @@ -1,90 +1,92 @@ +Copyright (c) 2015 HashiCorp, Inc. + Mozilla Public License, version 2.0 1. Definitions -1.1. “Contributor” +1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. -1.2. “Contributor Version” +1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a - Contributor and that particular Contributor’s Contribution. + Contributor and that particular Contributor's Contribution. -1.3. “Contribution” +1.3. "Contribution" means Covered Software of a particular Contributor. -1.4. “Covered Software” +1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. -1.5. “Incompatible With Secondary Licenses” +1.5. "Incompatible With Secondary Licenses" means a. that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or - b. that the Covered Software was made available under the terms of version - 1.1 or earlier of the License, but not also under the terms of a - Secondary License. + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. -1.6. “Executable Form” +1.6. "Executable Form" means any form of the work other than Source Code Form. -1.7. “Larger Work” +1.7. "Larger Work" - means a work that combines Covered Software with other material, in a separate - file or files, that is not Covered Software. + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. -1.8. “License” +1.8. "License" means this document. -1.9. “Licensable” +1.9. "Licensable" - means having the right to grant, to the maximum extent possible, whether at the - time of the initial grant or subsequently, any and all of the rights conveyed by - this License. + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. -1.10. “Modifications” +1.10. "Modifications" means any of the following: - a. any file in Source Code Form that results from an addition to, deletion - from, or modification of the contents of Covered Software; or + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or b. any new file in Source Code Form that contains any Covered Software. -1.11. “Patent Claims” of a Contributor +1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, process, - and apparatus claims, in any patent Licensable by such Contributor that - would be infringed, but for the grant of the License, by the making, - using, selling, offering for sale, having made, import, or transfer of - either its Contributions or its Contributor Version. + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. -1.12. “Secondary License” +1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. -1.13. “Source Code Form” +1.13. "Source Code Form" means the form of the work preferred for making modifications. -1.14. “You” (or “Your”) +1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this - License. For legal entities, “You” includes any entity that controls, is + License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this - definition, “control” means (a) the power, direct or indirect, to cause + definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. @@ -100,57 +102,59 @@ Mozilla Public License, version 2.0 a. under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or as - part of a Larger Work; and + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and b. under Patent Claims of such Contributor to make, use, sell, offer for - sale, have made, import, and otherwise transfer either its Contributions - or its Contributor Version. + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. 2.2. Effective Date - The licenses granted in Section 2.1 with respect to any Contribution become - effective for each Contribution on the date the Contributor first distributes - such Contribution. + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. 2.3. Limitations on Grant Scope - The licenses granted in this Section 2 are the only rights granted under this - License. No additional rights or licenses will be implied from the distribution - or licensing of Covered Software under this License. Notwithstanding Section - 2.1(b) above, no patent license is granted by a Contributor: + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: a. for any code that a Contributor has removed from Covered Software; or - b. for infringements caused by: (i) Your and any other third party’s + b. for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or - c. under Patent Claims infringed by Covered Software in the absence of its - Contributions. + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. - This License does not grant any rights in the trademarks, service marks, or - logos of any Contributor (except as may be necessary to comply with the - notice requirements in Section 3.4). + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to - distribute the Covered Software under a subsequent version of this License - (see Section 10.2) or under the terms of a Secondary License (if permitted - under the terms of Section 3.3). + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). 2.5. Representation - Each Contributor represents that the Contributor believes its Contributions - are its original creation(s) or it has sufficient rights to grant the - rights to its Contributions conveyed by this License. + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. 2.6. Fair Use - This License is not intended to limit any rights You have under applicable - copyright doctrines of fair use, fair dealing, or other equivalents. + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. 2.7. Conditions @@ -163,11 +167,12 @@ Mozilla Public License, version 2.0 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any - Modifications that You create or to which You contribute, must be under the - terms of this License. You must inform recipients that the Source Code Form - of the Covered Software is governed by the terms of this License, and how - they can obtain a copy of this License. You may not attempt to alter or - restrict the recipients’ rights in the Source Code Form. + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. 3.2. Distribution of Executable Form @@ -179,39 +184,40 @@ Mozilla Public License, version 2.0 reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and - b. You may distribute such Executable Form under the terms of this License, - or sublicense it under different terms, provided that the license for - the Executable Form does not attempt to limit or alter the recipients’ - rights in the Source Code Form under this License. + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, - provided that You also comply with the requirements of this License for the - Covered Software. If the Larger Work is a combination of Covered Software - with a work governed by one or more Secondary Licenses, and the Covered - Software is not Incompatible With Secondary Licenses, this License permits - You to additionally distribute such Covered Software under the terms of - such Secondary License(s), so that the recipient of the Larger Work may, at - their option, further distribute the Covered Software under the terms of - either this License or such Secondary License(s). + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). 3.4. Notices - You may not remove or alter the substance of any license notices (including - copyright notices, patent notices, disclaimers of warranty, or limitations - of liability) contained within the Source Code Form of the Covered - Software, except that You may alter any license notices to the extent - required to remedy known factual inaccuracies. + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered - Software. However, You may do so only on Your own behalf, and not on behalf - of any Contributor. You must make it absolutely clear that any such - warranty, support, indemnity, or liability obligation is offered by You - alone, and You hereby agree to indemnify every Contributor for any + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any @@ -220,14 +226,14 @@ Mozilla Public License, version 2.0 4. Inability to Comply Due to Statute or Regulation If it is impossible for You to comply with any of the terms of this License - with respect to some or all of the Covered Software due to statute, judicial - order, or regulation then You must: (a) comply with the terms of this License - to the maximum extent possible; and (b) describe the limitations and the code - they affect. Such description must be placed in a text file included with all - distributions of the Covered Software under this License. Except to the - extent prohibited by statute or regulation, such description must be - sufficiently detailed for a recipient of ordinary skill to be able to - understand it. + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. 5. Termination @@ -235,21 +241,22 @@ Mozilla Public License, version 2.0 fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor - explicitly and finally terminates Your grants, and (b) on an ongoing basis, - if such Contributor fails to notify You of the non-compliance by some - reasonable means prior to 60 days after You have come back into compliance. - Moreover, Your grants from a particular Contributor are reinstated on an - ongoing basis if such Contributor notifies You of the non-compliance by - some reasonable means, this is the first time You have received notice of - non-compliance with this License from such Contributor, and You become - compliant prior to 30 days after Your receipt of the notice. + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. 5.2. If You initiate litigation against any entity by asserting a patent - infringement claim (excluding declaratory judgment actions, counter-claims, - and cross-claims) alleging that a Contributor Version directly or - indirectly infringes any patent, then the rights granted to You by any and - all Contributors for the Covered Software under Section 2.1 of this License - shall terminate. + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been @@ -258,16 +265,16 @@ Mozilla Public License, version 2.0 6. Disclaimer of Warranty - Covered Software is provided under this License on an “as is” basis, without - warranty of any kind, either expressed, implied, or statutory, including, - without limitation, warranties that the Covered Software is free of defects, - merchantable, fit for a particular purpose or non-infringing. The entire - risk as to the quality and performance of the Covered Software is with You. - Should any Covered Software prove defective in any respect, You (not any - Contributor) assume the cost of any necessary servicing, repair, or - correction. This disclaimer of warranty constitutes an essential part of this - License. No use of any Covered Software is authorized under this License - except under this disclaimer. + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. 7. Limitation of Liability @@ -279,27 +286,29 @@ Mozilla Public License, version 2.0 goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability - shall not apply to liability for death or personal injury resulting from such - party’s negligence to the extent applicable law prohibits such limitation. - Some jurisdictions do not allow the exclusion or limitation of incidental or - consequential damages, so this exclusion and limitation may not apply to You. + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. 8. Litigation - Any litigation relating to this License may be brought only in the courts of - a jurisdiction where the defendant maintains its principal place of business - and such litigation shall be governed by laws of that jurisdiction, without - reference to its conflict-of-law provisions. Nothing in this Section shall - prevent a party’s ability to bring cross-claims or counter-claims. + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. 9. Miscellaneous - This License represents the complete agreement concerning the subject matter - hereof. If any provision of this License is held to be unenforceable, such - provision shall be reformed only to the extent necessary to make it - enforceable. Any law or regulation which provides that the language of a - contract shall be construed against the drafter shall not be used to construe - this License against a Contributor. + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. 10. Versions of the License @@ -313,23 +322,24 @@ Mozilla Public License, version 2.0 10.2. Effect of New Versions - You may distribute the Covered Software under the terms of the version of - the License under which You originally received the Covered Software, or - under the terms of any subsequent version published by the license + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to - create a new license for such software, you may create and use a modified - version of this License if you rename the license and remove any - references to the name of the license steward (except to note that such - modified license differs from this License). + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). -10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses - If You choose to distribute Source Code Form that is Incompatible With - Secondary Licenses under the terms of this version of the License, the - notice described in Exhibit B of this License must be attached. +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. Exhibit A - Source Code Form License Notice @@ -340,15 +350,16 @@ Exhibit A - Source Code Form License Notice obtain one at http://mozilla.org/MPL/2.0/. -If it is not possible or desirable to put the notice in a particular file, then -You may include the notice in a location (such as a LICENSE file in a relevant -directory) where a recipient would be likely to look for such a notice. +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. You may add additional accurate notices of copyright ownership. -Exhibit B - “Incompatible With Secondary Licenses” Notice +Exhibit B - "Incompatible With Secondary Licenses" Notice - This Source Code Form is “Incompatible - With Secondary Licenses”, as defined by + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. diff --git a/vendor/github.com/hashicorp/go-immutable-radix/v2/README.md b/vendor/github.com/hashicorp/go-immutable-radix/v2/README.md new file mode 100644 index 000000000..e17ccf4d1 --- /dev/null +++ b/vendor/github.com/hashicorp/go-immutable-radix/v2/README.md @@ -0,0 +1,73 @@ +go-immutable-radix [![Run CI Tests](https://github.com/hashicorp/go-immutable-radix/actions/workflows/ci.yaml/badge.svg)](https://github.com/hashicorp/go-immutable-radix/actions/workflows/ci.yaml) +========= + +Provides the `iradix` package that implements an immutable [radix tree](http://en.wikipedia.org/wiki/Radix_tree). +The package only provides a single `Tree` implementation, optimized for sparse nodes. + +As a radix tree, it provides the following: + * O(k) operations. In many cases, this can be faster than a hash table since + the hash function is an O(k) operation, and hash tables have very poor cache locality. + * Minimum / Maximum value lookups + * Ordered iteration + +A tree supports using a transaction to batch multiple updates (insert, delete) +in a more efficient manner than performing each operation one at a time. + +For a mutable variant, see [go-radix](https://github.com/armon/go-radix). + +V2 +== + +The v2 of go-immutable-radix introduces generics to improve compile-time type +safety for users of the package. The module name for v2 is +`github.com/hashicorp/go-immutable-radix/v2`. + +Documentation +============= + +The full documentation is available on [Godoc](http://godoc.org/github.com/hashicorp/go-immutable-radix). + +Example +======= + +Below is a simple example of usage + +```go +// Create a tree +r := iradix.New[int]() +r, _, _ = r.Insert([]byte("foo"), 1) +r, _, _ = r.Insert([]byte("bar"), 2) +r, _, _ = r.Insert([]byte("foobar"), 2) + +// Find the longest prefix match +m, _, _ := r.Root().LongestPrefix([]byte("foozip")) +if string(m) != "foo" { + panic("should be foo") +} +``` + +Here is an example of performing a range scan of the keys. + +```go +// Create a tree +r := iradix.New[int]() +r, _, _ = r.Insert([]byte("001"), 1) +r, _, _ = r.Insert([]byte("002"), 2) +r, _, _ = r.Insert([]byte("005"), 5) +r, _, _ = r.Insert([]byte("010"), 10) +r, _, _ = r.Insert([]byte("100"), 10) + +// Range scan over the keys that sort lexicographically between [003, 050) +it := r.Root().Iterator() +it.SeekLowerBound([]byte("003")) +for key, _, ok := it.Next(); ok; key, _, ok = it.Next() { + if string(key) >= "050" { + break + } + fmt.Println(string(key)) +} +// Output: +// 005 +// 010 +``` + diff --git a/vendor/github.com/hashicorp/go-immutable-radix/v2/edges.go b/vendor/github.com/hashicorp/go-immutable-radix/v2/edges.go new file mode 100644 index 000000000..2e452f3e6 --- /dev/null +++ b/vendor/github.com/hashicorp/go-immutable-radix/v2/edges.go @@ -0,0 +1,21 @@ +package iradix + +import "sort" + +type edges[T any] []edge[T] + +func (e edges[T]) Len() int { + return len(e) +} + +func (e edges[T]) Less(i, j int) bool { + return e[i].label < e[j].label +} + +func (e edges[T]) Swap(i, j int) { + e[i], e[j] = e[j], e[i] +} + +func (e edges[T]) Sort() { + sort.Sort(e) +} diff --git a/vendor/github.com/hashicorp/go-immutable-radix/v2/iradix.go b/vendor/github.com/hashicorp/go-immutable-radix/v2/iradix.go new file mode 100644 index 000000000..8774020bc --- /dev/null +++ b/vendor/github.com/hashicorp/go-immutable-radix/v2/iradix.go @@ -0,0 +1,679 @@ +package iradix + +import ( + "bytes" + "strings" + + "github.com/hashicorp/golang-lru/v2/simplelru" +) + +const ( + // defaultModifiedCache is the default size of the modified node + // cache used per transaction. This is used to cache the updates + // to the nodes near the root, while the leaves do not need to be + // cached. This is important for very large transactions to prevent + // the modified cache from growing to be enormous. This is also used + // to set the max size of the mutation notify maps since those should + // also be bounded in a similar way. + defaultModifiedCache = 8192 +) + +// Tree implements an immutable radix tree. This can be treated as a +// Dictionary abstract data type. The main advantage over a standard +// hash map is prefix-based lookups and ordered iteration. The immutability +// means that it is safe to concurrently read from a Tree without any +// coordination. +type Tree[T any] struct { + root *Node[T] + size int +} + +// New returns an empty Tree +func New[T any]() *Tree[T] { + t := &Tree[T]{ + root: &Node[T]{ + mutateCh: make(chan struct{}), + }, + } + return t +} + +// Len is used to return the number of elements in the tree +func (t *Tree[T]) Len() int { + return t.size +} + +// Txn is a transaction on the tree. This transaction is applied +// atomically and returns a new tree when committed. A transaction +// is not thread safe, and should only be used by a single goroutine. +type Txn[T any] struct { + // root is the modified root for the transaction. + root *Node[T] + + // snap is a snapshot of the root node for use if we have to run the + // slow notify algorithm. + snap *Node[T] + + // size tracks the size of the tree as it is modified during the + // transaction. + size int + + // writable is a cache of writable nodes that have been created during + // the course of the transaction. This allows us to re-use the same + // nodes for further writes and avoid unnecessary copies of nodes that + // have never been exposed outside the transaction. This will only hold + // up to defaultModifiedCache number of entries. + writable *simplelru.LRU[*Node[T], any] + + // trackChannels is used to hold channels that need to be notified to + // signal mutation of the tree. This will only hold up to + // defaultModifiedCache number of entries, after which we will set the + // trackOverflow flag, which will cause us to use a more expensive + // algorithm to perform the notifications. Mutation tracking is only + // performed if trackMutate is true. + trackChannels map[chan struct{}]struct{} + trackOverflow bool + trackMutate bool +} + +// Txn starts a new transaction that can be used to mutate the tree +func (t *Tree[T]) Txn() *Txn[T] { + txn := &Txn[T]{ + root: t.root, + snap: t.root, + size: t.size, + } + return txn +} + +// Clone makes an independent copy of the transaction. The new transaction +// does not track any nodes and has TrackMutate turned off. The cloned transaction will contain any uncommitted writes in the original transaction but further mutations to either will be independent and result in different radix trees on Commit. A cloned transaction may be passed to another goroutine and mutated there independently however each transaction may only be mutated in a single thread. +func (t *Txn[T]) Clone() *Txn[T] { + // reset the writable node cache to avoid leaking future writes into the clone + t.writable = nil + + txn := &Txn[T]{ + root: t.root, + snap: t.snap, + size: t.size, + } + return txn +} + +// TrackMutate can be used to toggle if mutations are tracked. If this is enabled +// then notifications will be issued for affected internal nodes and leaves when +// the transaction is committed. +func (t *Txn[T]) TrackMutate(track bool) { + t.trackMutate = track +} + +// trackChannel safely attempts to track the given mutation channel, setting the +// overflow flag if we can no longer track any more. This limits the amount of +// state that will accumulate during a transaction and we have a slower algorithm +// to switch to if we overflow. +func (t *Txn[T]) trackChannel(ch chan struct{}) { + // In overflow, make sure we don't store any more objects. + if t.trackOverflow { + return + } + + // If this would overflow the state we reject it and set the flag (since + // we aren't tracking everything that's required any longer). + if len(t.trackChannels) >= defaultModifiedCache { + // Mark that we are in the overflow state + t.trackOverflow = true + + // Clear the map so that the channels can be garbage collected. It is + // safe to do this since we have already overflowed and will be using + // the slow notify algorithm. + t.trackChannels = nil + return + } + + // Create the map on the fly when we need it. + if t.trackChannels == nil { + t.trackChannels = make(map[chan struct{}]struct{}) + } + + // Otherwise we are good to track it. + t.trackChannels[ch] = struct{}{} +} + +// writeNode returns a node to be modified, if the current node has already been +// modified during the course of the transaction, it is used in-place. Set +// forLeafUpdate to true if you are getting a write node to update the leaf, +// which will set leaf mutation tracking appropriately as well. +func (t *Txn[T]) writeNode(n *Node[T], forLeafUpdate bool) *Node[T] { + // Ensure the writable set exists. + if t.writable == nil { + lru, err := simplelru.NewLRU[*Node[T], any](defaultModifiedCache, nil) + if err != nil { + panic(err) + } + t.writable = lru + } + + // If this node has already been modified, we can continue to use it + // during this transaction. We know that we don't need to track it for + // a node update since the node is writable, but if this is for a leaf + // update we track it, in case the initial write to this node didn't + // update the leaf. + if _, ok := t.writable.Get(n); ok { + if t.trackMutate && forLeafUpdate && n.leaf != nil { + t.trackChannel(n.leaf.mutateCh) + } + return n + } + + // Mark this node as being mutated. + if t.trackMutate { + t.trackChannel(n.mutateCh) + } + + // Mark its leaf as being mutated, if appropriate. + if t.trackMutate && forLeafUpdate && n.leaf != nil { + t.trackChannel(n.leaf.mutateCh) + } + + // Copy the existing node. If you have set forLeafUpdate it will be + // safe to replace this leaf with another after you get your node for + // writing. You MUST replace it, because the channel associated with + // this leaf will be closed when this transaction is committed. + nc := &Node[T]{ + mutateCh: make(chan struct{}), + leaf: n.leaf, + } + if n.prefix != nil { + nc.prefix = make([]byte, len(n.prefix)) + copy(nc.prefix, n.prefix) + } + if len(n.edges) != 0 { + nc.edges = make([]edge[T], len(n.edges)) + copy(nc.edges, n.edges) + } + + // Mark this node as writable. + t.writable.Add(nc, nil) + return nc +} + +// Visit all the nodes in the tree under n, and add their mutateChannels to the transaction +// Returns the size of the subtree visited +func (t *Txn[T]) trackChannelsAndCount(n *Node[T]) int { + // Count only leaf nodes + leaves := 0 + if n.leaf != nil { + leaves = 1 + } + // Mark this node as being mutated. + if t.trackMutate { + t.trackChannel(n.mutateCh) + } + + // Mark its leaf as being mutated, if appropriate. + if t.trackMutate && n.leaf != nil { + t.trackChannel(n.leaf.mutateCh) + } + + // Recurse on the children + for _, e := range n.edges { + leaves += t.trackChannelsAndCount(e.node) + } + return leaves +} + +// mergeChild is called to collapse the given node with its child. This is only +// called when the given node is not a leaf and has a single edge. +func (t *Txn[T]) mergeChild(n *Node[T]) { + // Mark the child node as being mutated since we are about to abandon + // it. We don't need to mark the leaf since we are retaining it if it + // is there. + e := n.edges[0] + child := e.node + if t.trackMutate { + t.trackChannel(child.mutateCh) + } + + // Merge the nodes. + n.prefix = concat(n.prefix, child.prefix) + n.leaf = child.leaf + if len(child.edges) != 0 { + n.edges = make([]edge[T], len(child.edges)) + copy(n.edges, child.edges) + } else { + n.edges = nil + } +} + +// insert does a recursive insertion +func (t *Txn[T]) insert(n *Node[T], k, search []byte, v T) (*Node[T], T, bool) { + var zero T + + // Handle key exhaustion + if len(search) == 0 { + var oldVal T + didUpdate := false + if n.isLeaf() { + oldVal = n.leaf.val + didUpdate = true + } + + nc := t.writeNode(n, true) + nc.leaf = &leafNode[T]{ + mutateCh: make(chan struct{}), + key: k, + val: v, + } + return nc, oldVal, didUpdate + } + + // Look for the edge + idx, child := n.getEdge(search[0]) + + // No edge, create one + if child == nil { + e := edge[T]{ + label: search[0], + node: &Node[T]{ + mutateCh: make(chan struct{}), + leaf: &leafNode[T]{ + mutateCh: make(chan struct{}), + key: k, + val: v, + }, + prefix: search, + }, + } + nc := t.writeNode(n, false) + nc.addEdge(e) + return nc, zero, false + } + + // Determine longest prefix of the search key on match + commonPrefix := longestPrefix(search, child.prefix) + if commonPrefix == len(child.prefix) { + search = search[commonPrefix:] + newChild, oldVal, didUpdate := t.insert(child, k, search, v) + if newChild != nil { + nc := t.writeNode(n, false) + nc.edges[idx].node = newChild + return nc, oldVal, didUpdate + } + return nil, oldVal, didUpdate + } + + // Split the node + nc := t.writeNode(n, false) + splitNode := &Node[T]{ + mutateCh: make(chan struct{}), + prefix: search[:commonPrefix], + } + nc.replaceEdge(edge[T]{ + label: search[0], + node: splitNode, + }) + + // Restore the existing child node + modChild := t.writeNode(child, false) + splitNode.addEdge(edge[T]{ + label: modChild.prefix[commonPrefix], + node: modChild, + }) + modChild.prefix = modChild.prefix[commonPrefix:] + + // Create a new leaf node + leaf := &leafNode[T]{ + mutateCh: make(chan struct{}), + key: k, + val: v, + } + + // If the new key is a subset, add to to this node + search = search[commonPrefix:] + if len(search) == 0 { + splitNode.leaf = leaf + return nc, zero, false + } + + // Create a new edge for the node + splitNode.addEdge(edge[T]{ + label: search[0], + node: &Node[T]{ + mutateCh: make(chan struct{}), + leaf: leaf, + prefix: search, + }, + }) + return nc, zero, false +} + +// delete does a recursive deletion +func (t *Txn[T]) delete(n *Node[T], search []byte) (*Node[T], *leafNode[T]) { + // Check for key exhaustion + if len(search) == 0 { + if !n.isLeaf() { + return nil, nil + } + // Copy the pointer in case we are in a transaction that already + // modified this node since the node will be reused. Any changes + // made to the node will not affect returning the original leaf + // value. + oldLeaf := n.leaf + + // Remove the leaf node + nc := t.writeNode(n, true) + nc.leaf = nil + + // Check if this node should be merged + if n != t.root && len(nc.edges) == 1 { + t.mergeChild(nc) + } + return nc, oldLeaf + } + + // Look for an edge + label := search[0] + idx, child := n.getEdge(label) + if child == nil || !bytes.HasPrefix(search, child.prefix) { + return nil, nil + } + + // Consume the search prefix + search = search[len(child.prefix):] + newChild, leaf := t.delete(child, search) + if newChild == nil { + return nil, nil + } + + // Copy this node. WATCH OUT - it's safe to pass "false" here because we + // will only ADD a leaf via nc.mergeChild() if there isn't one due to + // the !nc.isLeaf() check in the logic just below. This is pretty subtle, + // so be careful if you change any of the logic here. + nc := t.writeNode(n, false) + + // Delete the edge if the node has no edges + if newChild.leaf == nil && len(newChild.edges) == 0 { + nc.delEdge(label) + if n != t.root && len(nc.edges) == 1 && !nc.isLeaf() { + t.mergeChild(nc) + } + } else { + nc.edges[idx].node = newChild + } + return nc, leaf +} + +// delete does a recursive deletion +func (t *Txn[T]) deletePrefix(n *Node[T], search []byte) (*Node[T], int) { + // Check for key exhaustion + if len(search) == 0 { + nc := t.writeNode(n, true) + if n.isLeaf() { + nc.leaf = nil + } + nc.edges = nil + return nc, t.trackChannelsAndCount(n) + } + + // Look for an edge + label := search[0] + idx, child := n.getEdge(label) + // We make sure that either the child node's prefix starts with the search term, or the search term starts with the child node's prefix + // Need to do both so that we can delete prefixes that don't correspond to any node in the tree + if child == nil || (!bytes.HasPrefix(child.prefix, search) && !bytes.HasPrefix(search, child.prefix)) { + return nil, 0 + } + + // Consume the search prefix + if len(child.prefix) > len(search) { + search = []byte("") + } else { + search = search[len(child.prefix):] + } + newChild, numDeletions := t.deletePrefix(child, search) + if newChild == nil { + return nil, 0 + } + // Copy this node. WATCH OUT - it's safe to pass "false" here because we + // will only ADD a leaf via nc.mergeChild() if there isn't one due to + // the !nc.isLeaf() check in the logic just below. This is pretty subtle, + // so be careful if you change any of the logic here. + + nc := t.writeNode(n, false) + + // Delete the edge if the node has no edges + if newChild.leaf == nil && len(newChild.edges) == 0 { + nc.delEdge(label) + if n != t.root && len(nc.edges) == 1 && !nc.isLeaf() { + t.mergeChild(nc) + } + } else { + nc.edges[idx].node = newChild + } + return nc, numDeletions +} + +// Insert is used to add or update a given key. The return provides +// the previous value and a bool indicating if any was set. +func (t *Txn[T]) Insert(k []byte, v T) (T, bool) { + newRoot, oldVal, didUpdate := t.insert(t.root, k, k, v) + if newRoot != nil { + t.root = newRoot + } + if !didUpdate { + t.size++ + } + return oldVal, didUpdate +} + +// Delete is used to delete a given key. Returns the old value if any, +// and a bool indicating if the key was set. +func (t *Txn[T]) Delete(k []byte) (T, bool) { + var zero T + newRoot, leaf := t.delete(t.root, k) + if newRoot != nil { + t.root = newRoot + } + if leaf != nil { + t.size-- + return leaf.val, true + } + return zero, false +} + +// DeletePrefix is used to delete an entire subtree that matches the prefix +// This will delete all nodes under that prefix +func (t *Txn[T]) DeletePrefix(prefix []byte) bool { + newRoot, numDeletions := t.deletePrefix(t.root, prefix) + if newRoot != nil { + t.root = newRoot + t.size = t.size - numDeletions + return true + } + return false + +} + +// Root returns the current root of the radix tree within this +// transaction. The root is not safe across insert and delete operations, +// but can be used to read the current state during a transaction. +func (t *Txn[T]) Root() *Node[T] { + return t.root +} + +// Get is used to lookup a specific key, returning +// the value and if it was found +func (t *Txn[T]) Get(k []byte) (T, bool) { + return t.root.Get(k) +} + +// GetWatch is used to lookup a specific key, returning +// the watch channel, value and if it was found +func (t *Txn[T]) GetWatch(k []byte) (<-chan struct{}, T, bool) { + return t.root.GetWatch(k) +} + +// Commit is used to finalize the transaction and return a new tree. If mutation +// tracking is turned on then notifications will also be issued. +func (t *Txn[T]) Commit() *Tree[T] { + nt := t.CommitOnly() + if t.trackMutate { + t.Notify() + } + return nt +} + +// CommitOnly is used to finalize the transaction and return a new tree, but +// does not issue any notifications until Notify is called. +func (t *Txn[T]) CommitOnly() *Tree[T] { + nt := &Tree[T]{t.root, t.size} + t.writable = nil + return nt +} + +// slowNotify does a complete comparison of the before and after trees in order +// to trigger notifications. This doesn't require any additional state but it +// is very expensive to compute. +func (t *Txn[T]) slowNotify() { + snapIter := t.snap.rawIterator() + rootIter := t.root.rawIterator() + for snapIter.Front() != nil || rootIter.Front() != nil { + // If we've exhausted the nodes in the old snapshot, we know + // there's nothing remaining to notify. + if snapIter.Front() == nil { + return + } + snapElem := snapIter.Front() + + // If we've exhausted the nodes in the new root, we know we need + // to invalidate everything that remains in the old snapshot. We + // know from the loop condition there's something in the old + // snapshot. + if rootIter.Front() == nil { + close(snapElem.mutateCh) + if snapElem.isLeaf() { + close(snapElem.leaf.mutateCh) + } + snapIter.Next() + continue + } + + // Do one string compare so we can check the various conditions + // below without repeating the compare. + cmp := strings.Compare(snapIter.Path(), rootIter.Path()) + + // If the snapshot is behind the root, then we must have deleted + // this node during the transaction. + if cmp < 0 { + close(snapElem.mutateCh) + if snapElem.isLeaf() { + close(snapElem.leaf.mutateCh) + } + snapIter.Next() + continue + } + + // If the snapshot is ahead of the root, then we must have added + // this node during the transaction. + if cmp > 0 { + rootIter.Next() + continue + } + + // If we have the same path, then we need to see if we mutated a + // node and possibly the leaf. + rootElem := rootIter.Front() + if snapElem != rootElem { + close(snapElem.mutateCh) + if snapElem.leaf != nil && (snapElem.leaf != rootElem.leaf) { + close(snapElem.leaf.mutateCh) + } + } + snapIter.Next() + rootIter.Next() + } +} + +// Notify is used along with TrackMutate to trigger notifications. This must +// only be done once a transaction is committed via CommitOnly, and it is called +// automatically by Commit. +func (t *Txn[T]) Notify() { + if !t.trackMutate { + return + } + + // If we've overflowed the tracking state we can't use it in any way and + // need to do a full tree compare. + if t.trackOverflow { + t.slowNotify() + } else { + for ch := range t.trackChannels { + close(ch) + } + } + + // Clean up the tracking state so that a re-notify is safe (will trigger + // the else clause above which will be a no-op). + t.trackChannels = nil + t.trackOverflow = false +} + +// Insert is used to add or update a given key. The return provides +// the new tree, previous value and a bool indicating if any was set. +func (t *Tree[T]) Insert(k []byte, v T) (*Tree[T], T, bool) { + txn := t.Txn() + old, ok := txn.Insert(k, v) + return txn.Commit(), old, ok +} + +// Delete is used to delete a given key. Returns the new tree, +// old value if any, and a bool indicating if the key was set. +func (t *Tree[T]) Delete(k []byte) (*Tree[T], T, bool) { + txn := t.Txn() + old, ok := txn.Delete(k) + return txn.Commit(), old, ok +} + +// DeletePrefix is used to delete all nodes starting with a given prefix. Returns the new tree, +// and a bool indicating if the prefix matched any nodes +func (t *Tree[T]) DeletePrefix(k []byte) (*Tree[T], bool) { + txn := t.Txn() + ok := txn.DeletePrefix(k) + return txn.Commit(), ok +} + +// Root returns the root node of the tree which can be used for richer +// query operations. +func (t *Tree[T]) Root() *Node[T] { + return t.root +} + +// Get is used to lookup a specific key, returning +// the value and if it was found +func (t *Tree[T]) Get(k []byte) (T, bool) { + return t.root.Get(k) +} + +// longestPrefix finds the length of the shared prefix +// of two strings +func longestPrefix(k1, k2 []byte) int { + max := len(k1) + if l := len(k2); l < max { + max = l + } + var i int + for i = 0; i < max; i++ { + if k1[i] != k2[i] { + break + } + } + return i +} + +// concat two byte slices, returning a third new copy +func concat(a, b []byte) []byte { + c := make([]byte, len(a)+len(b)) + copy(c, a) + copy(c[len(a):], b) + return c +} diff --git a/vendor/github.com/hashicorp/go-immutable-radix/v2/iter.go b/vendor/github.com/hashicorp/go-immutable-radix/v2/iter.go new file mode 100644 index 000000000..ffd2721c1 --- /dev/null +++ b/vendor/github.com/hashicorp/go-immutable-radix/v2/iter.go @@ -0,0 +1,205 @@ +package iradix + +import ( + "bytes" +) + +// Iterator is used to iterate over a set of nodes +// in pre-order +type Iterator[T any] struct { + node *Node[T] + stack []edges[T] +} + +// SeekPrefixWatch is used to seek the iterator to a given prefix +// and returns the watch channel of the finest granularity +func (i *Iterator[T]) SeekPrefixWatch(prefix []byte) (watch <-chan struct{}) { + // Wipe the stack + i.stack = nil + n := i.node + watch = n.mutateCh + search := prefix + for { + // Check for key exhaustion + if len(search) == 0 { + i.node = n + return + } + + // Look for an edge + _, n = n.getEdge(search[0]) + if n == nil { + i.node = nil + return + } + + // Update to the finest granularity as the search makes progress + watch = n.mutateCh + + // Consume the search prefix + if bytes.HasPrefix(search, n.prefix) { + search = search[len(n.prefix):] + + } else if bytes.HasPrefix(n.prefix, search) { + i.node = n + return + } else { + i.node = nil + return + } + } +} + +// SeekPrefix is used to seek the iterator to a given prefix +func (i *Iterator[T]) SeekPrefix(prefix []byte) { + i.SeekPrefixWatch(prefix) +} + +func (i *Iterator[T]) recurseMin(n *Node[T]) *Node[T] { + // Traverse to the minimum child + if n.leaf != nil { + return n + } + nEdges := len(n.edges) + if nEdges > 1 { + // Add all the other edges to the stack (the min node will be added as + // we recurse) + i.stack = append(i.stack, n.edges[1:]) + } + if nEdges > 0 { + return i.recurseMin(n.edges[0].node) + } + // Shouldn't be possible + return nil +} + +// SeekLowerBound is used to seek the iterator to the smallest key that is +// greater or equal to the given key. There is no watch variant as it's hard to +// predict based on the radix structure which node(s) changes might affect the +// result. +func (i *Iterator[T]) SeekLowerBound(key []byte) { + // Wipe the stack. Unlike Prefix iteration, we need to build the stack as we + // go because we need only a subset of edges of many nodes in the path to the + // leaf with the lower bound. Note that the iterator will still recurse into + // children that we don't traverse on the way to the reverse lower bound as it + // walks the stack. + i.stack = []edges[T]{} + // i.node starts off in the common case as pointing to the root node of the + // tree. By the time we return we have either found a lower bound and setup + // the stack to traverse all larger keys, or we have not and the stack and + // node should both be nil to prevent the iterator from assuming it is just + // iterating the whole tree from the root node. Either way this needs to end + // up as nil so just set it here. + n := i.node + i.node = nil + search := key + + found := func(n *Node[T]) { + i.stack = append( + i.stack, + edges[T]{edge[T]{node: n}}, + ) + } + + findMin := func(n *Node[T]) { + n = i.recurseMin(n) + if n != nil { + found(n) + return + } + } + + for { + // Compare current prefix with the search key's same-length prefix. + var prefixCmp int + if len(n.prefix) < len(search) { + prefixCmp = bytes.Compare(n.prefix, search[0:len(n.prefix)]) + } else { + prefixCmp = bytes.Compare(n.prefix, search) + } + + if prefixCmp > 0 { + // Prefix is larger, that means the lower bound is greater than the search + // and from now on we need to follow the minimum path to the smallest + // leaf under this subtree. + findMin(n) + return + } + + if prefixCmp < 0 { + // Prefix is smaller than search prefix, that means there is no lower + // bound + i.node = nil + return + } + + // Prefix is equal, we are still heading for an exact match. If this is a + // leaf and an exact match we're done. + if n.leaf != nil && bytes.Equal(n.leaf.key, key) { + found(n) + return + } + + // Consume the search prefix if the current node has one. Note that this is + // safe because if n.prefix is longer than the search slice prefixCmp would + // have been > 0 above and the method would have already returned. + search = search[len(n.prefix):] + + if len(search) == 0 { + // We've exhausted the search key, but the current node is not an exact + // match or not a leaf. That means that the leaf value if it exists, and + // all child nodes must be strictly greater, the smallest key in this + // subtree must be the lower bound. + findMin(n) + return + } + + // Otherwise, take the lower bound next edge. + idx, lbNode := n.getLowerBoundEdge(search[0]) + if lbNode == nil { + return + } + + // Create stack edges for the all strictly higher edges in this node. + if idx+1 < len(n.edges) { + i.stack = append(i.stack, n.edges[idx+1:]) + } + + // Recurse + n = lbNode + } +} + +// Next returns the next node in order +func (i *Iterator[T]) Next() ([]byte, T, bool) { + var zero T + // Initialize our stack if needed + if i.stack == nil && i.node != nil { + i.stack = []edges[T]{{edge[T]{node: i.node}}} + } + + for len(i.stack) > 0 { + // Inspect the last element of the stack + n := len(i.stack) + last := i.stack[n-1] + elem := last[0].node + + // Update the stack + if len(last) > 1 { + i.stack[n-1] = last[1:] + } else { + i.stack = i.stack[:n-1] + } + + // Push the edges onto the frontier + if len(elem.edges) > 0 { + i.stack = append(i.stack, elem.edges) + } + + // Return the leaf values if any + if elem.leaf != nil { + return elem.leaf.key, elem.leaf.val, true + } + } + return nil, zero, false +} diff --git a/vendor/github.com/hashicorp/go-immutable-radix/v2/node.go b/vendor/github.com/hashicorp/go-immutable-radix/v2/node.go new file mode 100644 index 000000000..1be963922 --- /dev/null +++ b/vendor/github.com/hashicorp/go-immutable-radix/v2/node.go @@ -0,0 +1,326 @@ +package iradix + +import ( + "bytes" + "sort" +) + +// WalkFn is used when walking the tree. Takes a +// key and value, returning if iteration should +// be terminated. +type WalkFn[T any] func(k []byte, v T) bool + +// leafNode is used to represent a value +type leafNode[T any] struct { + mutateCh chan struct{} + key []byte + val T +} + +// edge is used to represent an edge node +type edge[T any] struct { + label byte + node *Node[T] +} + +// Node is an immutable node in the radix tree +type Node[T any] struct { + // mutateCh is closed if this node is modified + mutateCh chan struct{} + + // leaf is used to store possible leaf + leaf *leafNode[T] + + // prefix is the common prefix we ignore + prefix []byte + + // Edges should be stored in-order for iteration. + // We avoid a fully materialized slice to save memory, + // since in most cases we expect to be sparse + edges edges[T] +} + +func (n *Node[T]) isLeaf() bool { + return n.leaf != nil +} + +func (n *Node[T]) addEdge(e edge[T]) { + num := len(n.edges) + idx := sort.Search(num, func(i int) bool { + return n.edges[i].label >= e.label + }) + n.edges = append(n.edges, e) + if idx != num { + copy(n.edges[idx+1:], n.edges[idx:num]) + n.edges[idx] = e + } +} + +func (n *Node[T]) replaceEdge(e edge[T]) { + num := len(n.edges) + idx := sort.Search(num, func(i int) bool { + return n.edges[i].label >= e.label + }) + if idx < num && n.edges[idx].label == e.label { + n.edges[idx].node = e.node + return + } + panic("replacing missing edge") +} + +func (n *Node[T]) getEdge(label byte) (int, *Node[T]) { + num := len(n.edges) + idx := sort.Search(num, func(i int) bool { + return n.edges[i].label >= label + }) + if idx < num && n.edges[idx].label == label { + return idx, n.edges[idx].node + } + return -1, nil +} + +func (n *Node[T]) getLowerBoundEdge(label byte) (int, *Node[T]) { + num := len(n.edges) + idx := sort.Search(num, func(i int) bool { + return n.edges[i].label >= label + }) + // we want lower bound behavior so return even if it's not an exact match + if idx < num { + return idx, n.edges[idx].node + } + return -1, nil +} + +func (n *Node[T]) delEdge(label byte) { + num := len(n.edges) + idx := sort.Search(num, func(i int) bool { + return n.edges[i].label >= label + }) + if idx < num && n.edges[idx].label == label { + copy(n.edges[idx:], n.edges[idx+1:]) + n.edges[len(n.edges)-1] = edge[T]{} + n.edges = n.edges[:len(n.edges)-1] + } +} + +func (n *Node[T]) GetWatch(k []byte) (<-chan struct{}, T, bool) { + search := k + watch := n.mutateCh + for { + // Check for key exhaustion + if len(search) == 0 { + if n.isLeaf() { + return n.leaf.mutateCh, n.leaf.val, true + } + break + } + + // Look for an edge + _, n = n.getEdge(search[0]) + if n == nil { + break + } + + // Update to the finest granularity as the search makes progress + watch = n.mutateCh + + // Consume the search prefix + if bytes.HasPrefix(search, n.prefix) { + search = search[len(n.prefix):] + } else { + break + } + } + var zero T + return watch, zero, false +} + +func (n *Node[T]) Get(k []byte) (T, bool) { + _, val, ok := n.GetWatch(k) + return val, ok +} + +// LongestPrefix is like Get, but instead of an +// exact match, it will return the longest prefix match. +func (n *Node[T]) LongestPrefix(k []byte) ([]byte, T, bool) { + var last *leafNode[T] + search := k + for { + // Look for a leaf node + if n.isLeaf() { + last = n.leaf + } + + // Check for key exhaustion + if len(search) == 0 { + break + } + + // Look for an edge + _, n = n.getEdge(search[0]) + if n == nil { + break + } + + // Consume the search prefix + if bytes.HasPrefix(search, n.prefix) { + search = search[len(n.prefix):] + } else { + break + } + } + if last != nil { + return last.key, last.val, true + } + var zero T + return nil, zero, false +} + +// Minimum is used to return the minimum value in the tree +func (n *Node[T]) Minimum() ([]byte, T, bool) { + for { + if n.isLeaf() { + return n.leaf.key, n.leaf.val, true + } + if len(n.edges) > 0 { + n = n.edges[0].node + } else { + break + } + } + var zero T + return nil, zero, false +} + +// Maximum is used to return the maximum value in the tree +func (n *Node[T]) Maximum() ([]byte, T, bool) { + for { + if num := len(n.edges); num > 0 { + n = n.edges[num-1].node // bug? + continue + } + if n.isLeaf() { + return n.leaf.key, n.leaf.val, true + } else { + break + } + } + var zero T + return nil, zero, false +} + +// Iterator is used to return an iterator at +// the given node to walk the tree +func (n *Node[T]) Iterator() *Iterator[T] { + return &Iterator[T]{node: n} +} + +// ReverseIterator is used to return an iterator at +// the given node to walk the tree backwards +func (n *Node[T]) ReverseIterator() *ReverseIterator[T] { + return NewReverseIterator(n) +} + +// Iterator is used to return an iterator at +// the given node to walk the tree +func (n *Node[T]) PathIterator(path []byte) *PathIterator[T] { + return &PathIterator[T]{node: n, path: path} +} + +// rawIterator is used to return a raw iterator at the given node to walk the +// tree. +func (n *Node[T]) rawIterator() *rawIterator[T] { + iter := &rawIterator[T]{node: n} + iter.Next() + return iter +} + +// Walk is used to walk the tree +func (n *Node[T]) Walk(fn WalkFn[T]) { + recursiveWalk(n, fn) +} + +// WalkBackwards is used to walk the tree in reverse order +func (n *Node[T]) WalkBackwards(fn WalkFn[T]) { + reverseRecursiveWalk(n, fn) +} + +// WalkPrefix is used to walk the tree under a prefix +func (n *Node[T]) WalkPrefix(prefix []byte, fn WalkFn[T]) { + search := prefix + for { + // Check for key exhaustion + if len(search) == 0 { + recursiveWalk(n, fn) + return + } + + // Look for an edge + _, n = n.getEdge(search[0]) + if n == nil { + break + } + + // Consume the search prefix + if bytes.HasPrefix(search, n.prefix) { + search = search[len(n.prefix):] + + } else if bytes.HasPrefix(n.prefix, search) { + // Child may be under our search prefix + recursiveWalk(n, fn) + return + } else { + break + } + } +} + +// WalkPath is used to walk the tree, but only visiting nodes +// from the root down to a given leaf. Where WalkPrefix walks +// all the entries *under* the given prefix, this walks the +// entries *above* the given prefix. +func (n *Node[T]) WalkPath(path []byte, fn WalkFn[T]) { + i := n.PathIterator(path) + + for path, val, ok := i.Next(); ok; path, val, ok = i.Next() { + if fn(path, val) { + return + } + } +} + +// recursiveWalk is used to do a pre-order walk of a node +// recursively. Returns true if the walk should be aborted +func recursiveWalk[T any](n *Node[T], fn WalkFn[T]) bool { + // Visit the leaf values if any + if n.leaf != nil && fn(n.leaf.key, n.leaf.val) { + return true + } + + // Recurse on the children + for _, e := range n.edges { + if recursiveWalk(e.node, fn) { + return true + } + } + return false +} + +// reverseRecursiveWalk is used to do a reverse pre-order +// walk of a node recursively. Returns true if the walk +// should be aborted +func reverseRecursiveWalk[T any](n *Node[T], fn WalkFn[T]) bool { + // Visit the leaf values if any + if n.leaf != nil && fn(n.leaf.key, n.leaf.val) { + return true + } + + // Recurse on the children in reverse order + for i := len(n.edges) - 1; i >= 0; i-- { + e := n.edges[i] + if reverseRecursiveWalk(e.node, fn) { + return true + } + } + return false +} diff --git a/vendor/github.com/hashicorp/go-immutable-radix/v2/path_iter.go b/vendor/github.com/hashicorp/go-immutable-radix/v2/path_iter.go new file mode 100644 index 000000000..21942afc8 --- /dev/null +++ b/vendor/github.com/hashicorp/go-immutable-radix/v2/path_iter.go @@ -0,0 +1,59 @@ +package iradix + +import "bytes" + +// PathIterator is used to iterate over a set of nodes from the root +// down to a specified path. This will iterate over the same values that +// the Node.WalkPath method will. +type PathIterator[T any] struct { + node *Node[T] + path []byte + done bool +} + +// Next returns the next node in order +func (i *PathIterator[T]) Next() ([]byte, T, bool) { + // This is mostly just an asynchronous implementation of the WalkPath + // method on the node. + var zero T + var leaf *leafNode[T] + + for leaf == nil && i.node != nil { + // visit the leaf values if any + if i.node.leaf != nil { + leaf = i.node.leaf + } + + i.iterate() + } + + if leaf != nil { + return leaf.key, leaf.val, true + } + + return nil, zero, false +} + +func (i *PathIterator[T]) iterate() { + // Check for key exhaustion + if len(i.path) == 0 { + i.node = nil + return + } + + // Look for an edge + _, i.node = i.node.getEdge(i.path[0]) + if i.node == nil { + return + } + + // Consume the search prefix + if bytes.HasPrefix(i.path, i.node.prefix) { + i.path = i.path[len(i.node.prefix):] + } else { + // there are no more nodes to iterate through so + // nil out the node to prevent returning results + // for subsequent calls to Next() + i.node = nil + } +} diff --git a/vendor/github.com/hashicorp/go-immutable-radix/v2/raw_iter.go b/vendor/github.com/hashicorp/go-immutable-radix/v2/raw_iter.go new file mode 100644 index 000000000..dd84f089d --- /dev/null +++ b/vendor/github.com/hashicorp/go-immutable-radix/v2/raw_iter.go @@ -0,0 +1,78 @@ +package iradix + +// rawIterator visits each of the nodes in the tree, even the ones that are not +// leaves. It keeps track of the effective path (what a leaf at a given node +// would be called), which is useful for comparing trees. +type rawIterator[T any] struct { + // node is the starting node in the tree for the iterator. + node *Node[T] + + // stack keeps track of edges in the frontier. + stack []rawStackEntry[T] + + // pos is the current position of the iterator. + pos *Node[T] + + // path is the effective path of the current iterator position, + // regardless of whether the current node is a leaf. + path string +} + +// rawStackEntry is used to keep track of the cumulative common path as well as +// its associated edges in the frontier. +type rawStackEntry[T any] struct { + path string + edges edges[T] +} + +// Front returns the current node that has been iterated to. +func (i *rawIterator[T]) Front() *Node[T] { + return i.pos +} + +// Path returns the effective path of the current node, even if it's not actually +// a leaf. +func (i *rawIterator[T]) Path() string { + return i.path +} + +// Next advances the iterator to the next node. +func (i *rawIterator[T]) Next() { + // Initialize our stack if needed. + if i.stack == nil && i.node != nil { + i.stack = []rawStackEntry[T]{ + { + edges: edges[T]{ + edge[T]{node: i.node}, + }, + }, + } + } + + for len(i.stack) > 0 { + // Inspect the last element of the stack. + n := len(i.stack) + last := i.stack[n-1] + elem := last.edges[0].node + + // Update the stack. + if len(last.edges) > 1 { + i.stack[n-1].edges = last.edges[1:] + } else { + i.stack = i.stack[:n-1] + } + + // Push the edges onto the frontier. + if len(elem.edges) > 0 { + path := last.path + string(elem.prefix) + i.stack = append(i.stack, rawStackEntry[T]{path, elem.edges}) + } + + i.pos = elem + i.path = last.path + string(elem.prefix) + return + } + + i.pos = nil + i.path = "" +} diff --git a/vendor/github.com/hashicorp/go-immutable-radix/v2/reverse_iter.go b/vendor/github.com/hashicorp/go-immutable-radix/v2/reverse_iter.go new file mode 100644 index 000000000..2a06cde7c --- /dev/null +++ b/vendor/github.com/hashicorp/go-immutable-radix/v2/reverse_iter.go @@ -0,0 +1,240 @@ +package iradix + +import ( + "bytes" +) + +// ReverseIterator is used to iterate over a set of nodes +// in reverse in-order +type ReverseIterator[T any] struct { + i *Iterator[T] + + // expandedParents stores the set of parent nodes whose relevant children have + // already been pushed into the stack. This can happen during seek or during + // iteration. + // + // Unlike forward iteration we need to recurse into children before we can + // output the value stored in an internal leaf since all children are greater. + // We use this to track whether we have already ensured all the children are + // in the stack. + expandedParents map[*Node[T]]struct{} +} + +// NewReverseIterator returns a new ReverseIterator at a node +func NewReverseIterator[T any](n *Node[T]) *ReverseIterator[T] { + return &ReverseIterator[T]{ + i: &Iterator[T]{node: n}, + } +} + +// SeekPrefixWatch is used to seek the iterator to a given prefix +// and returns the watch channel of the finest granularity +func (ri *ReverseIterator[T]) SeekPrefixWatch(prefix []byte) (watch <-chan struct{}) { + return ri.i.SeekPrefixWatch(prefix) +} + +// SeekPrefix is used to seek the iterator to a given prefix +func (ri *ReverseIterator[T]) SeekPrefix(prefix []byte) { + ri.i.SeekPrefixWatch(prefix) +} + +// SeekReverseLowerBound is used to seek the iterator to the largest key that is +// lower or equal to the given key. There is no watch variant as it's hard to +// predict based on the radix structure which node(s) changes might affect the +// result. +func (ri *ReverseIterator[T]) SeekReverseLowerBound(key []byte) { + // Wipe the stack. Unlike Prefix iteration, we need to build the stack as we + // go because we need only a subset of edges of many nodes in the path to the + // leaf with the lower bound. Note that the iterator will still recurse into + // children that we don't traverse on the way to the reverse lower bound as it + // walks the stack. + ri.i.stack = []edges[T]{} + // ri.i.node starts off in the common case as pointing to the root node of the + // tree. By the time we return we have either found a lower bound and setup + // the stack to traverse all larger keys, or we have not and the stack and + // node should both be nil to prevent the iterator from assuming it is just + // iterating the whole tree from the root node. Either way this needs to end + // up as nil so just set it here. + n := ri.i.node + ri.i.node = nil + search := key + + if ri.expandedParents == nil { + ri.expandedParents = make(map[*Node[T]]struct{}) + } + + found := func(n *Node[T]) { + ri.i.stack = append(ri.i.stack, edges[T]{edge[T]{node: n}}) + // We need to mark this node as expanded in advance too otherwise the + // iterator will attempt to walk all of its children even though they are + // greater than the lower bound we have found. We've expanded it in the + // sense that all of its children that we want to walk are already in the + // stack (i.e. none of them). + ri.expandedParents[n] = struct{}{} + } + + for { + // Compare current prefix with the search key's same-length prefix. + var prefixCmp int + if len(n.prefix) < len(search) { + prefixCmp = bytes.Compare(n.prefix, search[0:len(n.prefix)]) + } else { + prefixCmp = bytes.Compare(n.prefix, search) + } + + if prefixCmp < 0 { + // Prefix is smaller than search prefix, that means there is no exact + // match for the search key. But we are looking in reverse, so the reverse + // lower bound will be the largest leaf under this subtree, since it is + // the value that would come right before the current search key if it + // were in the tree. So we need to follow the maximum path in this subtree + // to find it. Note that this is exactly what the iterator will already do + // if it finds a node in the stack that has _not_ been marked as expanded + // so in this one case we don't call `found` and instead let the iterator + // do the expansion and recursion through all the children. + ri.i.stack = append(ri.i.stack, edges[T]{edge[T]{node: n}}) + return + } + + if prefixCmp > 0 { + // Prefix is larger than search prefix, or there is no prefix but we've + // also exhausted the search key. Either way, that means there is no + // reverse lower bound since nothing comes before our current search + // prefix. + return + } + + // If this is a leaf, something needs to happen! Note that if it's a leaf + // and prefixCmp was zero (which it must be to get here) then the leaf value + // is either an exact match for the search, or it's lower. It can't be + // greater. + if n.isLeaf() { + + // Firstly, if it's an exact match, we're done! + if bytes.Equal(n.leaf.key, key) { + found(n) + return + } + + // It's not so this node's leaf value must be lower and could still be a + // valid contender for reverse lower bound. + + // If it has no children then we are also done. + if len(n.edges) == 0 { + // This leaf is the lower bound. + found(n) + return + } + + // Finally, this leaf is internal (has children) so we'll keep searching, + // but we need to add it to the iterator's stack since it has a leaf value + // that needs to be iterated over. It needs to be added to the stack + // before its children below as it comes first. + ri.i.stack = append(ri.i.stack, edges[T]{edge[T]{node: n}}) + // We also need to mark it as expanded since we'll be adding any of its + // relevant children below and so don't want the iterator to re-add them + // on its way back up the stack. + ri.expandedParents[n] = struct{}{} + } + + // Consume the search prefix. Note that this is safe because if n.prefix is + // longer than the search slice prefixCmp would have been > 0 above and the + // method would have already returned. + search = search[len(n.prefix):] + + if len(search) == 0 { + // We've exhausted the search key but we are not at a leaf. That means all + // children are greater than the search key so a reverse lower bound + // doesn't exist in this subtree. Note that there might still be one in + // the whole radix tree by following a different path somewhere further + // up. If that's the case then the iterator's stack will contain all the + // smaller nodes already and Previous will walk through them correctly. + return + } + + // Otherwise, take the lower bound next edge. + idx, lbNode := n.getLowerBoundEdge(search[0]) + + // From here, we need to update the stack with all values lower than + // the lower bound edge. Since getLowerBoundEdge() returns -1 when the + // search prefix is larger than all edges, we need to place idx at the + // last edge index so they can all be place in the stack, since they + // come before our search prefix. + if idx == -1 { + idx = len(n.edges) + } + + // Create stack edges for the all strictly lower edges in this node. + if len(n.edges[:idx]) > 0 { + ri.i.stack = append(ri.i.stack, n.edges[:idx]) + } + + // Exit if there's no lower bound edge. The stack will have the previous + // nodes already. + if lbNode == nil { + return + } + + // Recurse + n = lbNode + } +} + +// Previous returns the previous node in reverse order +func (ri *ReverseIterator[T]) Previous() ([]byte, T, bool) { + // Initialize our stack if needed + if ri.i.stack == nil && ri.i.node != nil { + ri.i.stack = []edges[T]{ + { + edge[T]{node: ri.i.node}, + }, + } + } + + if ri.expandedParents == nil { + ri.expandedParents = make(map[*Node[T]]struct{}) + } + + for len(ri.i.stack) > 0 { + // Inspect the last element of the stack + n := len(ri.i.stack) + last := ri.i.stack[n-1] + m := len(last) + elem := last[m-1].node + + _, alreadyExpanded := ri.expandedParents[elem] + + // If this is an internal node and we've not seen it already, we need to + // leave it in the stack so we can return its possible leaf value _after_ + // we've recursed through all its children. + if len(elem.edges) > 0 && !alreadyExpanded { + // record that we've seen this node! + ri.expandedParents[elem] = struct{}{} + // push child edges onto stack and skip the rest of the loop to recurse + // into the largest one. + ri.i.stack = append(ri.i.stack, elem.edges) + continue + } + + // Remove the node from the stack + if m > 1 { + ri.i.stack[n-1] = last[:m-1] + } else { + ri.i.stack = ri.i.stack[:n-1] + } + // We don't need this state any more as it's no longer in the stack so we + // won't visit it again + if alreadyExpanded { + delete(ri.expandedParents, elem) + } + + // If this is a leaf, return it + if elem.leaf != nil { + return elem.leaf.key, elem.leaf.val, true + } + + // it's not a leaf so keep walking the stack to find the previous leaf + } + var zero T + return nil, zero, false +} diff --git a/vendor/github.com/hashicorp/go-version/LICENSE b/vendor/github.com/hashicorp/go-version/LICENSE index 1409d6ab9..bb1e9a486 100644 --- a/vendor/github.com/hashicorp/go-version/LICENSE +++ b/vendor/github.com/hashicorp/go-version/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2014 HashiCorp, Inc. +Copyright IBM Corp. 2014, 2025 Mozilla Public License, version 2.0 diff --git a/vendor/github.com/hashicorp/go-version/README.md b/vendor/github.com/hashicorp/go-version/README.md index 4b7806cd9..83a8249f7 100644 --- a/vendor/github.com/hashicorp/go-version/README.md +++ b/vendor/github.com/hashicorp/go-version/README.md @@ -1,6 +1,7 @@ # Versioning Library for Go + ![Build Status](https://github.com/hashicorp/go-version/actions/workflows/go-tests.yml/badge.svg) -[![GoDoc](https://godoc.org/github.com/hashicorp/go-version?status.svg)](https://godoc.org/github.com/hashicorp/go-version) +[![Go Reference](https://pkg.go.dev/badge/github.com/hashicorp/go-version.svg)](https://pkg.go.dev/github.com/hashicorp/go-version) go-version is a library for parsing versions and version constraints, and verifying versions against a set of constraints. go-version @@ -12,7 +13,7 @@ Versions used with go-version must follow [SemVer](http://semver.org/). ## Installation and Usage Package documentation can be found on -[GoDoc](http://godoc.org/github.com/hashicorp/go-version). +[Go Reference](https://pkg.go.dev/github.com/hashicorp/go-version). Installation can be done with a normal `go get`: diff --git a/vendor/github.com/hashicorp/go-version/constraint.go b/vendor/github.com/hashicorp/go-version/constraint.go index 29bdc4d2b..3964da070 100644 --- a/vendor/github.com/hashicorp/go-version/constraint.go +++ b/vendor/github.com/hashicorp/go-version/constraint.go @@ -1,4 +1,4 @@ -// Copyright (c) HashiCorp, Inc. +// Copyright IBM Corp. 2014, 2025 // SPDX-License-Identifier: MPL-2.0 package version @@ -8,8 +8,26 @@ import ( "regexp" "sort" "strings" + "sync" ) +var ( + constraintRegexp *regexp.Regexp + constraintRegexpOnce sync.Once +) + +func getConstraintRegexp() *regexp.Regexp { + constraintRegexpOnce.Do(func() { + // This heavy lifting only happens the first time this function is called + constraintRegexp = regexp.MustCompile(fmt.Sprintf( + `^\s*(%s)\s*(%s)\s*$`, + `<=|>=|!=|~>|<|>|=|`, + VersionRegexpRaw, + )) + }) + return constraintRegexp +} + // Constraint represents a single constraint for a version, such as // ">= 1.0". type Constraint struct { @@ -29,38 +47,11 @@ type Constraints []*Constraint type constraintFunc func(v, c *Version) bool -var constraintOperators map[string]constraintOperation - type constraintOperation struct { op operator f constraintFunc } -var constraintRegexp *regexp.Regexp - -func init() { - constraintOperators = map[string]constraintOperation{ - "": {op: equal, f: constraintEqual}, - "=": {op: equal, f: constraintEqual}, - "!=": {op: notEqual, f: constraintNotEqual}, - ">": {op: greaterThan, f: constraintGreaterThan}, - "<": {op: lessThan, f: constraintLessThan}, - ">=": {op: greaterThanEqual, f: constraintGreaterThanEqual}, - "<=": {op: lessThanEqual, f: constraintLessThanEqual}, - "~>": {op: pessimistic, f: constraintPessimistic}, - } - - ops := make([]string, 0, len(constraintOperators)) - for k := range constraintOperators { - ops = append(ops, regexp.QuoteMeta(k)) - } - - constraintRegexp = regexp.MustCompile(fmt.Sprintf( - `^\s*(%s)\s*(%s)\s*$`, - strings.Join(ops, "|"), - VersionRegexpRaw)) -} - // NewConstraint will parse one or more constraints from the given // constraint string. The string must be a comma-separated list of // constraints. @@ -107,7 +98,7 @@ func (cs Constraints) Check(v *Version) bool { // to '>0.2' it is *NOT* treated as equal. // // Missing operator is treated as equal to '=', whitespaces -// are ignored and constraints are sorted before comaparison. +// are ignored and constraints are sorted before comparison. func (cs Constraints) Equals(c Constraints) bool { if len(cs) != len(c) { return false @@ -176,9 +167,9 @@ func (c *Constraint) String() string { } func parseSingle(v string) (*Constraint, error) { - matches := constraintRegexp.FindStringSubmatch(v) + matches := getConstraintRegexp().FindStringSubmatch(v) if matches == nil { - return nil, fmt.Errorf("Malformed constraint: %s", v) + return nil, fmt.Errorf("malformed constraint: %s", v) } check, err := NewVersion(matches[2]) @@ -186,7 +177,25 @@ func parseSingle(v string) (*Constraint, error) { return nil, err } - cop := constraintOperators[matches[1]] + var cop constraintOperation + switch matches[1] { + case "=": + cop = constraintOperation{op: equal, f: constraintEqual} + case "!=": + cop = constraintOperation{op: notEqual, f: constraintNotEqual} + case ">": + cop = constraintOperation{op: greaterThan, f: constraintGreaterThan} + case "<": + cop = constraintOperation{op: lessThan, f: constraintLessThan} + case ">=": + cop = constraintOperation{op: greaterThanEqual, f: constraintGreaterThanEqual} + case "<=": + cop = constraintOperation{op: lessThanEqual, f: constraintLessThanEqual} + case "~>": + cop = constraintOperation{op: pessimistic, f: constraintPessimistic} + default: + cop = constraintOperation{op: equal, f: constraintEqual} + } return &Constraint{ f: cop.f, diff --git a/vendor/github.com/hashicorp/go-version/version.go b/vendor/github.com/hashicorp/go-version/version.go index 7c683c281..17b29732e 100644 --- a/vendor/github.com/hashicorp/go-version/version.go +++ b/vendor/github.com/hashicorp/go-version/version.go @@ -1,23 +1,39 @@ -// Copyright (c) HashiCorp, Inc. +// Copyright IBM Corp. 2014, 2025 // SPDX-License-Identifier: MPL-2.0 package version import ( - "bytes" "database/sql/driver" "fmt" "regexp" "strconv" "strings" + "sync" ) // The compiled regular expression used to test the validity of a version. var ( - versionRegexp *regexp.Regexp - semverRegexp *regexp.Regexp + versionRegexp *regexp.Regexp + versionRegexpOnce sync.Once + semverRegexp *regexp.Regexp + semverRegexpOnce sync.Once ) +func getVersionRegexp() *regexp.Regexp { + versionRegexpOnce.Do(func() { + versionRegexp = regexp.MustCompile("^" + VersionRegexpRaw + "$") + }) + return versionRegexp +} + +func getSemverRegexp() *regexp.Regexp { + semverRegexpOnce.Do(func() { + semverRegexp = regexp.MustCompile("^" + SemverRegexpRaw + "$") + }) + return semverRegexp +} + // The raw regular expression string used for testing the validity // of a version. const ( @@ -42,28 +58,23 @@ type Version struct { original string } -func init() { - versionRegexp = regexp.MustCompile("^" + VersionRegexpRaw + "$") - semverRegexp = regexp.MustCompile("^" + SemverRegexpRaw + "$") -} - // NewVersion parses the given version and returns a new // Version. func NewVersion(v string) (*Version, error) { - return newVersion(v, versionRegexp) + return newVersion(v, getVersionRegexp()) } // NewSemver parses the given version and returns a new // Version that adheres strictly to SemVer specs // https://semver.org/ func NewSemver(v string) (*Version, error) { - return newVersion(v, semverRegexp) + return newVersion(v, getSemverRegexp()) } func newVersion(v string, pattern *regexp.Regexp) (*Version, error) { matches := pattern.FindStringSubmatch(v) if matches == nil { - return nil, fmt.Errorf("Malformed version: %s", v) + return nil, fmt.Errorf("malformed version: %s", v) } segmentsStr := strings.Split(matches[1], ".") segments := make([]int64, len(segmentsStr)) @@ -71,7 +82,7 @@ func newVersion(v string, pattern *regexp.Regexp) (*Version, error) { val, err := strconv.ParseInt(str, 10, 64) if err != nil { return nil, fmt.Errorf( - "Error parsing version: %s", err) + "error parsing version: %s", err) } segments[i] = val @@ -174,7 +185,7 @@ func (v *Version) Compare(other *Version) int { } else if lhs < rhs { return -1 } - // Otherwis, rhs was > lhs, they're not equal + // Otherwise, rhs was > lhs, they're not equal return 1 } @@ -382,22 +393,29 @@ func (v *Version) Segments64() []int64 { // missing parts (1.0 => 1.0.0) will be made into a canonicalized form // as shown in the parenthesized examples. func (v *Version) String() string { - var buf bytes.Buffer - fmtParts := make([]string, len(v.segments)) + return string(v.bytes()) +} + +func (v *Version) bytes() []byte { + var buf []byte for i, s := range v.segments { - // We can ignore err here since we've pre-parsed the values in segments - str := strconv.FormatInt(s, 10) - fmtParts[i] = str + if i > 0 { + buf = append(buf, '.') + } + buf = strconv.AppendInt(buf, s, 10) } - fmt.Fprintf(&buf, strings.Join(fmtParts, ".")) + if v.pre != "" { - fmt.Fprintf(&buf, "-%s", v.pre) + buf = append(buf, '-') + buf = append(buf, v.pre...) } + if v.metadata != "" { - fmt.Fprintf(&buf, "+%s", v.metadata) + buf = append(buf, '+') + buf = append(buf, v.metadata...) } - return buf.String() + return buf } // Original returns the original parsed version as-is, including any diff --git a/vendor/github.com/hashicorp/go-version/version_collection.go b/vendor/github.com/hashicorp/go-version/version_collection.go index 83547fe13..11bc8b1c5 100644 --- a/vendor/github.com/hashicorp/go-version/version_collection.go +++ b/vendor/github.com/hashicorp/go-version/version_collection.go @@ -1,4 +1,4 @@ -// Copyright (c) HashiCorp, Inc. +// Copyright IBM Corp. 2014, 2025 // SPDX-License-Identifier: MPL-2.0 package version diff --git a/vendor/github.com/hashicorp/golang-lru/v2/LICENSE b/vendor/github.com/hashicorp/golang-lru/v2/LICENSE new file mode 100644 index 000000000..0e5d580e0 --- /dev/null +++ b/vendor/github.com/hashicorp/golang-lru/v2/LICENSE @@ -0,0 +1,364 @@ +Copyright (c) 2014 HashiCorp, Inc. + +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. diff --git a/vendor/github.com/hashicorp/golang-lru/v2/internal/list.go b/vendor/github.com/hashicorp/golang-lru/v2/internal/list.go new file mode 100644 index 000000000..5cd74a034 --- /dev/null +++ b/vendor/github.com/hashicorp/golang-lru/v2/internal/list.go @@ -0,0 +1,142 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE_list file. + +package internal + +import "time" + +// Entry is an LRU Entry +type Entry[K comparable, V any] struct { + // Next and previous pointers in the doubly-linked list of elements. + // To simplify the implementation, internally a list l is implemented + // as a ring, such that &l.root is both the next element of the last + // list element (l.Back()) and the previous element of the first list + // element (l.Front()). + next, prev *Entry[K, V] + + // The list to which this element belongs. + list *LruList[K, V] + + // The LRU Key of this element. + Key K + + // The Value stored with this element. + Value V + + // The time this element would be cleaned up, optional + ExpiresAt time.Time + + // The expiry bucket item was put in, optional + ExpireBucket uint8 +} + +// PrevEntry returns the previous list element or nil. +func (e *Entry[K, V]) PrevEntry() *Entry[K, V] { + if p := e.prev; e.list != nil && p != &e.list.root { + return p + } + return nil +} + +// LruList represents a doubly linked list. +// The zero Value for LruList is an empty list ready to use. +type LruList[K comparable, V any] struct { + root Entry[K, V] // sentinel list element, only &root, root.prev, and root.next are used + len int // current list Length excluding (this) sentinel element +} + +// Init initializes or clears list l. +func (l *LruList[K, V]) Init() *LruList[K, V] { + l.root.next = &l.root + l.root.prev = &l.root + l.len = 0 + return l +} + +// NewList returns an initialized list. +func NewList[K comparable, V any]() *LruList[K, V] { return new(LruList[K, V]).Init() } + +// Length returns the number of elements of list l. +// The complexity is O(1). +func (l *LruList[K, V]) Length() int { return l.len } + +// Back returns the last element of list l or nil if the list is empty. +func (l *LruList[K, V]) Back() *Entry[K, V] { + if l.len == 0 { + return nil + } + return l.root.prev +} + +// lazyInit lazily initializes a zero List Value. +func (l *LruList[K, V]) lazyInit() { + if l.root.next == nil { + l.Init() + } +} + +// insert inserts e after at, increments l.len, and returns e. +func (l *LruList[K, V]) insert(e, at *Entry[K, V]) *Entry[K, V] { + e.prev = at + e.next = at.next + e.prev.next = e + e.next.prev = e + e.list = l + l.len++ + return e +} + +// insertValue is a convenience wrapper for insert(&Entry{Value: v, ExpiresAt: ExpiresAt}, at). +func (l *LruList[K, V]) insertValue(k K, v V, expiresAt time.Time, at *Entry[K, V]) *Entry[K, V] { + return l.insert(&Entry[K, V]{Value: v, Key: k, ExpiresAt: expiresAt}, at) +} + +// Remove removes e from its list, decrements l.len +func (l *LruList[K, V]) Remove(e *Entry[K, V]) V { + e.prev.next = e.next + e.next.prev = e.prev + e.next = nil // avoid memory leaks + e.prev = nil // avoid memory leaks + e.list = nil + l.len-- + + return e.Value +} + +// move moves e to next to at. +func (l *LruList[K, V]) move(e, at *Entry[K, V]) { + if e == at { + return + } + e.prev.next = e.next + e.next.prev = e.prev + + e.prev = at + e.next = at.next + e.prev.next = e + e.next.prev = e +} + +// PushFront inserts a new element e with value v at the front of list l and returns e. +func (l *LruList[K, V]) PushFront(k K, v V) *Entry[K, V] { + l.lazyInit() + return l.insertValue(k, v, time.Time{}, &l.root) +} + +// PushFrontExpirable inserts a new expirable element e with Value v at the front of list l and returns e. +func (l *LruList[K, V]) PushFrontExpirable(k K, v V, expiresAt time.Time) *Entry[K, V] { + l.lazyInit() + return l.insertValue(k, v, expiresAt, &l.root) +} + +// MoveToFront moves element e to the front of list l. +// If e is not an element of l, the list is not modified. +// The element must not be nil. +func (l *LruList[K, V]) MoveToFront(e *Entry[K, V]) { + if e.list != l || l.root.next == e { + return + } + // see comment in List.Remove about initialization of l + l.move(e, &l.root) +} diff --git a/vendor/github.com/golangci/golangci-lint/internal/go/LICENSE b/vendor/github.com/hashicorp/golang-lru/v2/simplelru/LICENSE_list similarity index 97% rename from vendor/github.com/golangci/golangci-lint/internal/go/LICENSE rename to vendor/github.com/hashicorp/golang-lru/v2/simplelru/LICENSE_list index 6a66aea5e..c4764e6b2 100644 --- a/vendor/github.com/golangci/golangci-lint/internal/go/LICENSE +++ b/vendor/github.com/hashicorp/golang-lru/v2/simplelru/LICENSE_list @@ -1,3 +1,5 @@ +This license applies to simplelru/list.go + Copyright (c) 2009 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/vendor/github.com/hashicorp/golang-lru/v2/simplelru/lru.go b/vendor/github.com/hashicorp/golang-lru/v2/simplelru/lru.go new file mode 100644 index 000000000..f69792388 --- /dev/null +++ b/vendor/github.com/hashicorp/golang-lru/v2/simplelru/lru.go @@ -0,0 +1,177 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package simplelru + +import ( + "errors" + + "github.com/hashicorp/golang-lru/v2/internal" +) + +// EvictCallback is used to get a callback when a cache entry is evicted +type EvictCallback[K comparable, V any] func(key K, value V) + +// LRU implements a non-thread safe fixed size LRU cache +type LRU[K comparable, V any] struct { + size int + evictList *internal.LruList[K, V] + items map[K]*internal.Entry[K, V] + onEvict EvictCallback[K, V] +} + +// NewLRU constructs an LRU of the given size +func NewLRU[K comparable, V any](size int, onEvict EvictCallback[K, V]) (*LRU[K, V], error) { + if size <= 0 { + return nil, errors.New("must provide a positive size") + } + + c := &LRU[K, V]{ + size: size, + evictList: internal.NewList[K, V](), + items: make(map[K]*internal.Entry[K, V]), + onEvict: onEvict, + } + return c, nil +} + +// Purge is used to completely clear the cache. +func (c *LRU[K, V]) Purge() { + for k, v := range c.items { + if c.onEvict != nil { + c.onEvict(k, v.Value) + } + delete(c.items, k) + } + c.evictList.Init() +} + +// Add adds a value to the cache. Returns true if an eviction occurred. +func (c *LRU[K, V]) Add(key K, value V) (evicted bool) { + // Check for existing item + if ent, ok := c.items[key]; ok { + c.evictList.MoveToFront(ent) + ent.Value = value + return false + } + + // Add new item + ent := c.evictList.PushFront(key, value) + c.items[key] = ent + + evict := c.evictList.Length() > c.size + // Verify size not exceeded + if evict { + c.removeOldest() + } + return evict +} + +// Get looks up a key's value from the cache. +func (c *LRU[K, V]) Get(key K) (value V, ok bool) { + if ent, ok := c.items[key]; ok { + c.evictList.MoveToFront(ent) + return ent.Value, true + } + return +} + +// Contains checks if a key is in the cache, without updating the recent-ness +// or deleting it for being stale. +func (c *LRU[K, V]) Contains(key K) (ok bool) { + _, ok = c.items[key] + return ok +} + +// Peek returns the key value (or undefined if not found) without updating +// the "recently used"-ness of the key. +func (c *LRU[K, V]) Peek(key K) (value V, ok bool) { + var ent *internal.Entry[K, V] + if ent, ok = c.items[key]; ok { + return ent.Value, true + } + return +} + +// Remove removes the provided key from the cache, returning if the +// key was contained. +func (c *LRU[K, V]) Remove(key K) (present bool) { + if ent, ok := c.items[key]; ok { + c.removeElement(ent) + return true + } + return false +} + +// RemoveOldest removes the oldest item from the cache. +func (c *LRU[K, V]) RemoveOldest() (key K, value V, ok bool) { + if ent := c.evictList.Back(); ent != nil { + c.removeElement(ent) + return ent.Key, ent.Value, true + } + return +} + +// GetOldest returns the oldest entry +func (c *LRU[K, V]) GetOldest() (key K, value V, ok bool) { + if ent := c.evictList.Back(); ent != nil { + return ent.Key, ent.Value, true + } + return +} + +// Keys returns a slice of the keys in the cache, from oldest to newest. +func (c *LRU[K, V]) Keys() []K { + keys := make([]K, c.evictList.Length()) + i := 0 + for ent := c.evictList.Back(); ent != nil; ent = ent.PrevEntry() { + keys[i] = ent.Key + i++ + } + return keys +} + +// Values returns a slice of the values in the cache, from oldest to newest. +func (c *LRU[K, V]) Values() []V { + values := make([]V, len(c.items)) + i := 0 + for ent := c.evictList.Back(); ent != nil; ent = ent.PrevEntry() { + values[i] = ent.Value + i++ + } + return values +} + +// Len returns the number of items in the cache. +func (c *LRU[K, V]) Len() int { + return c.evictList.Length() +} + +// Resize changes the cache size. +func (c *LRU[K, V]) Resize(size int) (evicted int) { + diff := c.Len() - size + if diff < 0 { + diff = 0 + } + for i := 0; i < diff; i++ { + c.removeOldest() + } + c.size = size + return diff +} + +// removeOldest removes the oldest item from the cache. +func (c *LRU[K, V]) removeOldest() { + if ent := c.evictList.Back(); ent != nil { + c.removeElement(ent) + } +} + +// removeElement is used to remove a given list element from the cache +func (c *LRU[K, V]) removeElement(e *internal.Entry[K, V]) { + c.evictList.Remove(e) + delete(c.items, e.Key) + if c.onEvict != nil { + c.onEvict(e.Key, e.Value) + } +} diff --git a/vendor/github.com/hashicorp/golang-lru/v2/simplelru/lru_interface.go b/vendor/github.com/hashicorp/golang-lru/v2/simplelru/lru_interface.go new file mode 100644 index 000000000..043b8bcc3 --- /dev/null +++ b/vendor/github.com/hashicorp/golang-lru/v2/simplelru/lru_interface.go @@ -0,0 +1,46 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// Package simplelru provides simple LRU implementation based on build-in container/list. +package simplelru + +// LRUCache is the interface for simple LRU cache. +type LRUCache[K comparable, V any] interface { + // Adds a value to the cache, returns true if an eviction occurred and + // updates the "recently used"-ness of the key. + Add(key K, value V) bool + + // Returns key's value from the cache and + // updates the "recently used"-ness of the key. #value, isFound + Get(key K) (value V, ok bool) + + // Checks if a key exists in cache without updating the recent-ness. + Contains(key K) (ok bool) + + // Returns key's value without updating the "recently used"-ness of the key. + Peek(key K) (value V, ok bool) + + // Removes a key from the cache. + Remove(key K) bool + + // Removes the oldest entry from cache. + RemoveOldest() (K, V, bool) + + // Returns the oldest entry from the cache. #key, value, isFound + GetOldest() (K, V, bool) + + // Returns a slice of the keys in the cache, from oldest to newest. + Keys() []K + + // Values returns a slice of the values in the cache, from oldest to newest. + Values() []V + + // Returns the number of items in the cache. + Len() int + + // Clears all cache entries. + Purge() + + // Resizes cache, returning number evicted + Resize(int) int +} diff --git a/vendor/github.com/hashicorp/hcl/.gitignore b/vendor/github.com/hashicorp/hcl/.gitignore deleted file mode 100644 index 15586a2b5..000000000 --- a/vendor/github.com/hashicorp/hcl/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -y.output - -# ignore intellij files -.idea -*.iml -*.ipr -*.iws - -*.test diff --git a/vendor/github.com/hashicorp/hcl/.travis.yml b/vendor/github.com/hashicorp/hcl/.travis.yml deleted file mode 100644 index cb63a3216..000000000 --- a/vendor/github.com/hashicorp/hcl/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -sudo: false - -language: go - -go: - - 1.x - - tip - -branches: - only: - - master - -script: make test diff --git a/vendor/github.com/hashicorp/hcl/Makefile b/vendor/github.com/hashicorp/hcl/Makefile deleted file mode 100644 index 84fd743f5..000000000 --- a/vendor/github.com/hashicorp/hcl/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -TEST?=./... - -default: test - -fmt: generate - go fmt ./... - -test: generate - go get -t ./... - go test $(TEST) $(TESTARGS) - -generate: - go generate ./... - -updatedeps: - go get -u golang.org/x/tools/cmd/stringer - -.PHONY: default generate test updatedeps diff --git a/vendor/github.com/hashicorp/hcl/README.md b/vendor/github.com/hashicorp/hcl/README.md deleted file mode 100644 index c8223326d..000000000 --- a/vendor/github.com/hashicorp/hcl/README.md +++ /dev/null @@ -1,125 +0,0 @@ -# HCL - -[![GoDoc](https://godoc.org/github.com/hashicorp/hcl?status.png)](https://godoc.org/github.com/hashicorp/hcl) [![Build Status](https://travis-ci.org/hashicorp/hcl.svg?branch=master)](https://travis-ci.org/hashicorp/hcl) - -HCL (HashiCorp Configuration Language) is a configuration language built -by HashiCorp. The goal of HCL is to build a structured configuration language -that is both human and machine friendly for use with command-line tools, but -specifically targeted towards DevOps tools, servers, etc. - -HCL is also fully JSON compatible. That is, JSON can be used as completely -valid input to a system expecting HCL. This helps makes systems -interoperable with other systems. - -HCL is heavily inspired by -[libucl](https://github.com/vstakhov/libucl), -nginx configuration, and others similar. - -## Why? - -A common question when viewing HCL is to ask the question: why not -JSON, YAML, etc.? - -Prior to HCL, the tools we built at [HashiCorp](http://www.hashicorp.com) -used a variety of configuration languages from full programming languages -such as Ruby to complete data structure languages such as JSON. What we -learned is that some people wanted human-friendly configuration languages -and some people wanted machine-friendly languages. - -JSON fits a nice balance in this, but is fairly verbose and most -importantly doesn't support comments. With YAML, we found that beginners -had a really hard time determining what the actual structure was, and -ended up guessing more often than not whether to use a hyphen, colon, etc. -in order to represent some configuration key. - -Full programming languages such as Ruby enable complex behavior -a configuration language shouldn't usually allow, and also forces -people to learn some set of Ruby. - -Because of this, we decided to create our own configuration language -that is JSON-compatible. Our configuration language (HCL) is designed -to be written and modified by humans. The API for HCL allows JSON -as an input so that it is also machine-friendly (machines can generate -JSON instead of trying to generate HCL). - -Our goal with HCL is not to alienate other configuration languages. -It is instead to provide HCL as a specialized language for our tools, -and JSON as the interoperability layer. - -## Syntax - -For a complete grammar, please see the parser itself. A high-level overview -of the syntax and grammar is listed here. - - * Single line comments start with `#` or `//` - - * Multi-line comments are wrapped in `/*` and `*/`. Nested block comments - are not allowed. A multi-line comment (also known as a block comment) - terminates at the first `*/` found. - - * Values are assigned with the syntax `key = value` (whitespace doesn't - matter). The value can be any primitive: a string, number, boolean, - object, or list. - - * Strings are double-quoted and can contain any UTF-8 characters. - Example: `"Hello, World"` - - * Multi-line strings start with `<- - echo %Path% - - go version - - go env - - go get -t ./... - -build_script: -- cmd: go test -v ./... diff --git a/vendor/github.com/hashicorp/hcl/decoder.go b/vendor/github.com/hashicorp/hcl/decoder.go deleted file mode 100644 index bed9ebbe1..000000000 --- a/vendor/github.com/hashicorp/hcl/decoder.go +++ /dev/null @@ -1,729 +0,0 @@ -package hcl - -import ( - "errors" - "fmt" - "reflect" - "sort" - "strconv" - "strings" - - "github.com/hashicorp/hcl/hcl/ast" - "github.com/hashicorp/hcl/hcl/parser" - "github.com/hashicorp/hcl/hcl/token" -) - -// This is the tag to use with structures to have settings for HCL -const tagName = "hcl" - -var ( - // nodeType holds a reference to the type of ast.Node - nodeType reflect.Type = findNodeType() -) - -// Unmarshal accepts a byte slice as input and writes the -// data to the value pointed to by v. -func Unmarshal(bs []byte, v interface{}) error { - root, err := parse(bs) - if err != nil { - return err - } - - return DecodeObject(v, root) -} - -// Decode reads the given input and decodes it into the structure -// given by `out`. -func Decode(out interface{}, in string) error { - obj, err := Parse(in) - if err != nil { - return err - } - - return DecodeObject(out, obj) -} - -// DecodeObject is a lower-level version of Decode. It decodes a -// raw Object into the given output. -func DecodeObject(out interface{}, n ast.Node) error { - val := reflect.ValueOf(out) - if val.Kind() != reflect.Ptr { - return errors.New("result must be a pointer") - } - - // If we have the file, we really decode the root node - if f, ok := n.(*ast.File); ok { - n = f.Node - } - - var d decoder - return d.decode("root", n, val.Elem()) -} - -type decoder struct { - stack []reflect.Kind -} - -func (d *decoder) decode(name string, node ast.Node, result reflect.Value) error { - k := result - - // If we have an interface with a valid value, we use that - // for the check. - if result.Kind() == reflect.Interface { - elem := result.Elem() - if elem.IsValid() { - k = elem - } - } - - // Push current onto stack unless it is an interface. - if k.Kind() != reflect.Interface { - d.stack = append(d.stack, k.Kind()) - - // Schedule a pop - defer func() { - d.stack = d.stack[:len(d.stack)-1] - }() - } - - switch k.Kind() { - case reflect.Bool: - return d.decodeBool(name, node, result) - case reflect.Float32, reflect.Float64: - return d.decodeFloat(name, node, result) - case reflect.Int, reflect.Int32, reflect.Int64: - return d.decodeInt(name, node, result) - case reflect.Interface: - // When we see an interface, we make our own thing - return d.decodeInterface(name, node, result) - case reflect.Map: - return d.decodeMap(name, node, result) - case reflect.Ptr: - return d.decodePtr(name, node, result) - case reflect.Slice: - return d.decodeSlice(name, node, result) - case reflect.String: - return d.decodeString(name, node, result) - case reflect.Struct: - return d.decodeStruct(name, node, result) - default: - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("%s: unknown kind to decode into: %s", name, k.Kind()), - } - } -} - -func (d *decoder) decodeBool(name string, node ast.Node, result reflect.Value) error { - switch n := node.(type) { - case *ast.LiteralType: - if n.Token.Type == token.BOOL { - v, err := strconv.ParseBool(n.Token.Text) - if err != nil { - return err - } - - result.Set(reflect.ValueOf(v)) - return nil - } - } - - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("%s: unknown type %T", name, node), - } -} - -func (d *decoder) decodeFloat(name string, node ast.Node, result reflect.Value) error { - switch n := node.(type) { - case *ast.LiteralType: - if n.Token.Type == token.FLOAT || n.Token.Type == token.NUMBER { - v, err := strconv.ParseFloat(n.Token.Text, 64) - if err != nil { - return err - } - - result.Set(reflect.ValueOf(v).Convert(result.Type())) - return nil - } - } - - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("%s: unknown type %T", name, node), - } -} - -func (d *decoder) decodeInt(name string, node ast.Node, result reflect.Value) error { - switch n := node.(type) { - case *ast.LiteralType: - switch n.Token.Type { - case token.NUMBER: - v, err := strconv.ParseInt(n.Token.Text, 0, 0) - if err != nil { - return err - } - - if result.Kind() == reflect.Interface { - result.Set(reflect.ValueOf(int(v))) - } else { - result.SetInt(v) - } - return nil - case token.STRING: - v, err := strconv.ParseInt(n.Token.Value().(string), 0, 0) - if err != nil { - return err - } - - if result.Kind() == reflect.Interface { - result.Set(reflect.ValueOf(int(v))) - } else { - result.SetInt(v) - } - return nil - } - } - - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("%s: unknown type %T", name, node), - } -} - -func (d *decoder) decodeInterface(name string, node ast.Node, result reflect.Value) error { - // When we see an ast.Node, we retain the value to enable deferred decoding. - // Very useful in situations where we want to preserve ast.Node information - // like Pos - if result.Type() == nodeType && result.CanSet() { - result.Set(reflect.ValueOf(node)) - return nil - } - - var set reflect.Value - redecode := true - - // For testing types, ObjectType should just be treated as a list. We - // set this to a temporary var because we want to pass in the real node. - testNode := node - if ot, ok := node.(*ast.ObjectType); ok { - testNode = ot.List - } - - switch n := testNode.(type) { - case *ast.ObjectList: - // If we're at the root or we're directly within a slice, then we - // decode objects into map[string]interface{}, otherwise we decode - // them into lists. - if len(d.stack) == 0 || d.stack[len(d.stack)-1] == reflect.Slice { - var temp map[string]interface{} - tempVal := reflect.ValueOf(temp) - result := reflect.MakeMap( - reflect.MapOf( - reflect.TypeOf(""), - tempVal.Type().Elem())) - - set = result - } else { - var temp []map[string]interface{} - tempVal := reflect.ValueOf(temp) - result := reflect.MakeSlice( - reflect.SliceOf(tempVal.Type().Elem()), 0, len(n.Items)) - set = result - } - case *ast.ObjectType: - // If we're at the root or we're directly within a slice, then we - // decode objects into map[string]interface{}, otherwise we decode - // them into lists. - if len(d.stack) == 0 || d.stack[len(d.stack)-1] == reflect.Slice { - var temp map[string]interface{} - tempVal := reflect.ValueOf(temp) - result := reflect.MakeMap( - reflect.MapOf( - reflect.TypeOf(""), - tempVal.Type().Elem())) - - set = result - } else { - var temp []map[string]interface{} - tempVal := reflect.ValueOf(temp) - result := reflect.MakeSlice( - reflect.SliceOf(tempVal.Type().Elem()), 0, 1) - set = result - } - case *ast.ListType: - var temp []interface{} - tempVal := reflect.ValueOf(temp) - result := reflect.MakeSlice( - reflect.SliceOf(tempVal.Type().Elem()), 0, 0) - set = result - case *ast.LiteralType: - switch n.Token.Type { - case token.BOOL: - var result bool - set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) - case token.FLOAT: - var result float64 - set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) - case token.NUMBER: - var result int - set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) - case token.STRING, token.HEREDOC: - set = reflect.Indirect(reflect.New(reflect.TypeOf(""))) - default: - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("%s: cannot decode into interface: %T", name, node), - } - } - default: - return fmt.Errorf( - "%s: cannot decode into interface: %T", - name, node) - } - - // Set the result to what its supposed to be, then reset - // result so we don't reflect into this method anymore. - result.Set(set) - - if redecode { - // Revisit the node so that we can use the newly instantiated - // thing and populate it. - if err := d.decode(name, node, result); err != nil { - return err - } - } - - return nil -} - -func (d *decoder) decodeMap(name string, node ast.Node, result reflect.Value) error { - if item, ok := node.(*ast.ObjectItem); ok { - node = &ast.ObjectList{Items: []*ast.ObjectItem{item}} - } - - if ot, ok := node.(*ast.ObjectType); ok { - node = ot.List - } - - n, ok := node.(*ast.ObjectList) - if !ok { - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("%s: not an object type for map (%T)", name, node), - } - } - - // If we have an interface, then we can address the interface, - // but not the slice itself, so get the element but set the interface - set := result - if result.Kind() == reflect.Interface { - result = result.Elem() - } - - resultType := result.Type() - resultElemType := resultType.Elem() - resultKeyType := resultType.Key() - if resultKeyType.Kind() != reflect.String { - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("%s: map must have string keys", name), - } - } - - // Make a map if it is nil - resultMap := result - if result.IsNil() { - resultMap = reflect.MakeMap( - reflect.MapOf(resultKeyType, resultElemType)) - } - - // Go through each element and decode it. - done := make(map[string]struct{}) - for _, item := range n.Items { - if item.Val == nil { - continue - } - - // github.com/hashicorp/terraform/issue/5740 - if len(item.Keys) == 0 { - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("%s: map must have string keys", name), - } - } - - // Get the key we're dealing with, which is the first item - keyStr := item.Keys[0].Token.Value().(string) - - // If we've already processed this key, then ignore it - if _, ok := done[keyStr]; ok { - continue - } - - // Determine the value. If we have more than one key, then we - // get the objectlist of only these keys. - itemVal := item.Val - if len(item.Keys) > 1 { - itemVal = n.Filter(keyStr) - done[keyStr] = struct{}{} - } - - // Make the field name - fieldName := fmt.Sprintf("%s.%s", name, keyStr) - - // Get the key/value as reflection values - key := reflect.ValueOf(keyStr) - val := reflect.Indirect(reflect.New(resultElemType)) - - // If we have a pre-existing value in the map, use that - oldVal := resultMap.MapIndex(key) - if oldVal.IsValid() { - val.Set(oldVal) - } - - // Decode! - if err := d.decode(fieldName, itemVal, val); err != nil { - return err - } - - // Set the value on the map - resultMap.SetMapIndex(key, val) - } - - // Set the final map if we can - set.Set(resultMap) - return nil -} - -func (d *decoder) decodePtr(name string, node ast.Node, result reflect.Value) error { - // Create an element of the concrete (non pointer) type and decode - // into that. Then set the value of the pointer to this type. - resultType := result.Type() - resultElemType := resultType.Elem() - val := reflect.New(resultElemType) - if err := d.decode(name, node, reflect.Indirect(val)); err != nil { - return err - } - - result.Set(val) - return nil -} - -func (d *decoder) decodeSlice(name string, node ast.Node, result reflect.Value) error { - // If we have an interface, then we can address the interface, - // but not the slice itself, so get the element but set the interface - set := result - if result.Kind() == reflect.Interface { - result = result.Elem() - } - // Create the slice if it isn't nil - resultType := result.Type() - resultElemType := resultType.Elem() - if result.IsNil() { - resultSliceType := reflect.SliceOf(resultElemType) - result = reflect.MakeSlice( - resultSliceType, 0, 0) - } - - // Figure out the items we'll be copying into the slice - var items []ast.Node - switch n := node.(type) { - case *ast.ObjectList: - items = make([]ast.Node, len(n.Items)) - for i, item := range n.Items { - items[i] = item - } - case *ast.ObjectType: - items = []ast.Node{n} - case *ast.ListType: - items = n.List - default: - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("unknown slice type: %T", node), - } - } - - for i, item := range items { - fieldName := fmt.Sprintf("%s[%d]", name, i) - - // Decode - val := reflect.Indirect(reflect.New(resultElemType)) - - // if item is an object that was decoded from ambiguous JSON and - // flattened, make sure it's expanded if it needs to decode into a - // defined structure. - item := expandObject(item, val) - - if err := d.decode(fieldName, item, val); err != nil { - return err - } - - // Append it onto the slice - result = reflect.Append(result, val) - } - - set.Set(result) - return nil -} - -// expandObject detects if an ambiguous JSON object was flattened to a List which -// should be decoded into a struct, and expands the ast to properly deocode. -func expandObject(node ast.Node, result reflect.Value) ast.Node { - item, ok := node.(*ast.ObjectItem) - if !ok { - return node - } - - elemType := result.Type() - - // our target type must be a struct - switch elemType.Kind() { - case reflect.Ptr: - switch elemType.Elem().Kind() { - case reflect.Struct: - //OK - default: - return node - } - case reflect.Struct: - //OK - default: - return node - } - - // A list value will have a key and field name. If it had more fields, - // it wouldn't have been flattened. - if len(item.Keys) != 2 { - return node - } - - keyToken := item.Keys[0].Token - item.Keys = item.Keys[1:] - - // we need to un-flatten the ast enough to decode - newNode := &ast.ObjectItem{ - Keys: []*ast.ObjectKey{ - &ast.ObjectKey{ - Token: keyToken, - }, - }, - Val: &ast.ObjectType{ - List: &ast.ObjectList{ - Items: []*ast.ObjectItem{item}, - }, - }, - } - - return newNode -} - -func (d *decoder) decodeString(name string, node ast.Node, result reflect.Value) error { - switch n := node.(type) { - case *ast.LiteralType: - switch n.Token.Type { - case token.NUMBER: - result.Set(reflect.ValueOf(n.Token.Text).Convert(result.Type())) - return nil - case token.STRING, token.HEREDOC: - result.Set(reflect.ValueOf(n.Token.Value()).Convert(result.Type())) - return nil - } - } - - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("%s: unknown type for string %T", name, node), - } -} - -func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value) error { - var item *ast.ObjectItem - if it, ok := node.(*ast.ObjectItem); ok { - item = it - node = it.Val - } - - if ot, ok := node.(*ast.ObjectType); ok { - node = ot.List - } - - // Handle the special case where the object itself is a literal. Previously - // the yacc parser would always ensure top-level elements were arrays. The new - // parser does not make the same guarantees, thus we need to convert any - // top-level literal elements into a list. - if _, ok := node.(*ast.LiteralType); ok && item != nil { - node = &ast.ObjectList{Items: []*ast.ObjectItem{item}} - } - - list, ok := node.(*ast.ObjectList) - if !ok { - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("%s: not an object type for struct (%T)", name, node), - } - } - - // This slice will keep track of all the structs we'll be decoding. - // There can be more than one struct if there are embedded structs - // that are squashed. - structs := make([]reflect.Value, 1, 5) - structs[0] = result - - // Compile the list of all the fields that we're going to be decoding - // from all the structs. - type field struct { - field reflect.StructField - val reflect.Value - } - fields := []field{} - for len(structs) > 0 { - structVal := structs[0] - structs = structs[1:] - - structType := structVal.Type() - for i := 0; i < structType.NumField(); i++ { - fieldType := structType.Field(i) - tagParts := strings.Split(fieldType.Tag.Get(tagName), ",") - - // Ignore fields with tag name "-" - if tagParts[0] == "-" { - continue - } - - if fieldType.Anonymous { - fieldKind := fieldType.Type.Kind() - if fieldKind != reflect.Struct { - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("%s: unsupported type to struct: %s", - fieldType.Name, fieldKind), - } - } - - // We have an embedded field. We "squash" the fields down - // if specified in the tag. - squash := false - for _, tag := range tagParts[1:] { - if tag == "squash" { - squash = true - break - } - } - - if squash { - structs = append( - structs, result.FieldByName(fieldType.Name)) - continue - } - } - - // Normal struct field, store it away - fields = append(fields, field{fieldType, structVal.Field(i)}) - } - } - - usedKeys := make(map[string]struct{}) - decodedFields := make([]string, 0, len(fields)) - decodedFieldsVal := make([]reflect.Value, 0) - unusedKeysVal := make([]reflect.Value, 0) - for _, f := range fields { - field, fieldValue := f.field, f.val - if !fieldValue.IsValid() { - // This should never happen - panic("field is not valid") - } - - // If we can't set the field, then it is unexported or something, - // and we just continue onwards. - if !fieldValue.CanSet() { - continue - } - - fieldName := field.Name - - tagValue := field.Tag.Get(tagName) - tagParts := strings.SplitN(tagValue, ",", 2) - if len(tagParts) >= 2 { - switch tagParts[1] { - case "decodedFields": - decodedFieldsVal = append(decodedFieldsVal, fieldValue) - continue - case "key": - if item == nil { - return &parser.PosError{ - Pos: node.Pos(), - Err: fmt.Errorf("%s: %s asked for 'key', impossible", - name, fieldName), - } - } - - fieldValue.SetString(item.Keys[0].Token.Value().(string)) - continue - case "unusedKeys": - unusedKeysVal = append(unusedKeysVal, fieldValue) - continue - } - } - - if tagParts[0] != "" { - fieldName = tagParts[0] - } - - // Determine the element we'll use to decode. If it is a single - // match (only object with the field), then we decode it exactly. - // If it is a prefix match, then we decode the matches. - filter := list.Filter(fieldName) - - prefixMatches := filter.Children() - matches := filter.Elem() - if len(matches.Items) == 0 && len(prefixMatches.Items) == 0 { - continue - } - - // Track the used key - usedKeys[fieldName] = struct{}{} - - // Create the field name and decode. We range over the elements - // because we actually want the value. - fieldName = fmt.Sprintf("%s.%s", name, fieldName) - if len(prefixMatches.Items) > 0 { - if err := d.decode(fieldName, prefixMatches, fieldValue); err != nil { - return err - } - } - for _, match := range matches.Items { - var decodeNode ast.Node = match.Val - if ot, ok := decodeNode.(*ast.ObjectType); ok { - decodeNode = &ast.ObjectList{Items: ot.List.Items} - } - - if err := d.decode(fieldName, decodeNode, fieldValue); err != nil { - return err - } - } - - decodedFields = append(decodedFields, field.Name) - } - - if len(decodedFieldsVal) > 0 { - // Sort it so that it is deterministic - sort.Strings(decodedFields) - - for _, v := range decodedFieldsVal { - v.Set(reflect.ValueOf(decodedFields)) - } - } - - return nil -} - -// findNodeType returns the type of ast.Node -func findNodeType() reflect.Type { - var nodeContainer struct { - Node ast.Node - } - value := reflect.ValueOf(nodeContainer).FieldByName("Node") - return value.Type() -} diff --git a/vendor/github.com/hashicorp/hcl/hcl.go b/vendor/github.com/hashicorp/hcl/hcl.go deleted file mode 100644 index 575a20b50..000000000 --- a/vendor/github.com/hashicorp/hcl/hcl.go +++ /dev/null @@ -1,11 +0,0 @@ -// Package hcl decodes HCL into usable Go structures. -// -// hcl input can come in either pure HCL format or JSON format. -// It can be parsed into an AST, and then decoded into a structure, -// or it can be decoded directly from a string into a structure. -// -// If you choose to parse HCL into a raw AST, the benefit is that you -// can write custom visitor implementations to implement custom -// semantic checks. By default, HCL does not perform any semantic -// checks. -package hcl diff --git a/vendor/github.com/hashicorp/hcl/hcl/ast/ast.go b/vendor/github.com/hashicorp/hcl/hcl/ast/ast.go deleted file mode 100644 index 6e5ef654b..000000000 --- a/vendor/github.com/hashicorp/hcl/hcl/ast/ast.go +++ /dev/null @@ -1,219 +0,0 @@ -// Package ast declares the types used to represent syntax trees for HCL -// (HashiCorp Configuration Language) -package ast - -import ( - "fmt" - "strings" - - "github.com/hashicorp/hcl/hcl/token" -) - -// Node is an element in the abstract syntax tree. -type Node interface { - node() - Pos() token.Pos -} - -func (File) node() {} -func (ObjectList) node() {} -func (ObjectKey) node() {} -func (ObjectItem) node() {} -func (Comment) node() {} -func (CommentGroup) node() {} -func (ObjectType) node() {} -func (LiteralType) node() {} -func (ListType) node() {} - -// File represents a single HCL file -type File struct { - Node Node // usually a *ObjectList - Comments []*CommentGroup // list of all comments in the source -} - -func (f *File) Pos() token.Pos { - return f.Node.Pos() -} - -// ObjectList represents a list of ObjectItems. An HCL file itself is an -// ObjectList. -type ObjectList struct { - Items []*ObjectItem -} - -func (o *ObjectList) Add(item *ObjectItem) { - o.Items = append(o.Items, item) -} - -// Filter filters out the objects with the given key list as a prefix. -// -// The returned list of objects contain ObjectItems where the keys have -// this prefix already stripped off. This might result in objects with -// zero-length key lists if they have no children. -// -// If no matches are found, an empty ObjectList (non-nil) is returned. -func (o *ObjectList) Filter(keys ...string) *ObjectList { - var result ObjectList - for _, item := range o.Items { - // If there aren't enough keys, then ignore this - if len(item.Keys) < len(keys) { - continue - } - - match := true - for i, key := range item.Keys[:len(keys)] { - key := key.Token.Value().(string) - if key != keys[i] && !strings.EqualFold(key, keys[i]) { - match = false - break - } - } - if !match { - continue - } - - // Strip off the prefix from the children - newItem := *item - newItem.Keys = newItem.Keys[len(keys):] - result.Add(&newItem) - } - - return &result -} - -// Children returns further nested objects (key length > 0) within this -// ObjectList. This should be used with Filter to get at child items. -func (o *ObjectList) Children() *ObjectList { - var result ObjectList - for _, item := range o.Items { - if len(item.Keys) > 0 { - result.Add(item) - } - } - - return &result -} - -// Elem returns items in the list that are direct element assignments -// (key length == 0). This should be used with Filter to get at elements. -func (o *ObjectList) Elem() *ObjectList { - var result ObjectList - for _, item := range o.Items { - if len(item.Keys) == 0 { - result.Add(item) - } - } - - return &result -} - -func (o *ObjectList) Pos() token.Pos { - // always returns the uninitiliazed position - return o.Items[0].Pos() -} - -// ObjectItem represents a HCL Object Item. An item is represented with a key -// (or keys). It can be an assignment or an object (both normal and nested) -type ObjectItem struct { - // keys is only one length long if it's of type assignment. If it's a - // nested object it can be larger than one. In that case "assign" is - // invalid as there is no assignments for a nested object. - Keys []*ObjectKey - - // assign contains the position of "=", if any - Assign token.Pos - - // val is the item itself. It can be an object,list, number, bool or a - // string. If key length is larger than one, val can be only of type - // Object. - Val Node - - LeadComment *CommentGroup // associated lead comment - LineComment *CommentGroup // associated line comment -} - -func (o *ObjectItem) Pos() token.Pos { - // I'm not entirely sure what causes this, but removing this causes - // a test failure. We should investigate at some point. - if len(o.Keys) == 0 { - return token.Pos{} - } - - return o.Keys[0].Pos() -} - -// ObjectKeys are either an identifier or of type string. -type ObjectKey struct { - Token token.Token -} - -func (o *ObjectKey) Pos() token.Pos { - return o.Token.Pos -} - -// LiteralType represents a literal of basic type. Valid types are: -// token.NUMBER, token.FLOAT, token.BOOL and token.STRING -type LiteralType struct { - Token token.Token - - // comment types, only used when in a list - LeadComment *CommentGroup - LineComment *CommentGroup -} - -func (l *LiteralType) Pos() token.Pos { - return l.Token.Pos -} - -// ListStatement represents a HCL List type -type ListType struct { - Lbrack token.Pos // position of "[" - Rbrack token.Pos // position of "]" - List []Node // the elements in lexical order -} - -func (l *ListType) Pos() token.Pos { - return l.Lbrack -} - -func (l *ListType) Add(node Node) { - l.List = append(l.List, node) -} - -// ObjectType represents a HCL Object Type -type ObjectType struct { - Lbrace token.Pos // position of "{" - Rbrace token.Pos // position of "}" - List *ObjectList // the nodes in lexical order -} - -func (o *ObjectType) Pos() token.Pos { - return o.Lbrace -} - -// Comment node represents a single //, # style or /*- style commment -type Comment struct { - Start token.Pos // position of / or # - Text string -} - -func (c *Comment) Pos() token.Pos { - return c.Start -} - -// CommentGroup node represents a sequence of comments with no other tokens and -// no empty lines between. -type CommentGroup struct { - List []*Comment // len(List) > 0 -} - -func (c *CommentGroup) Pos() token.Pos { - return c.List[0].Pos() -} - -//------------------------------------------------------------------- -// GoStringer -//------------------------------------------------------------------- - -func (o *ObjectKey) GoString() string { return fmt.Sprintf("*%#v", *o) } -func (o *ObjectList) GoString() string { return fmt.Sprintf("*%#v", *o) } diff --git a/vendor/github.com/hashicorp/hcl/hcl/ast/walk.go b/vendor/github.com/hashicorp/hcl/hcl/ast/walk.go deleted file mode 100644 index ba07ad42b..000000000 --- a/vendor/github.com/hashicorp/hcl/hcl/ast/walk.go +++ /dev/null @@ -1,52 +0,0 @@ -package ast - -import "fmt" - -// WalkFunc describes a function to be called for each node during a Walk. The -// returned node can be used to rewrite the AST. Walking stops the returned -// bool is false. -type WalkFunc func(Node) (Node, bool) - -// Walk traverses an AST in depth-first order: It starts by calling fn(node); -// node must not be nil. If fn returns true, Walk invokes fn recursively for -// each of the non-nil children of node, followed by a call of fn(nil). The -// returned node of fn can be used to rewrite the passed node to fn. -func Walk(node Node, fn WalkFunc) Node { - rewritten, ok := fn(node) - if !ok { - return rewritten - } - - switch n := node.(type) { - case *File: - n.Node = Walk(n.Node, fn) - case *ObjectList: - for i, item := range n.Items { - n.Items[i] = Walk(item, fn).(*ObjectItem) - } - case *ObjectKey: - // nothing to do - case *ObjectItem: - for i, k := range n.Keys { - n.Keys[i] = Walk(k, fn).(*ObjectKey) - } - - if n.Val != nil { - n.Val = Walk(n.Val, fn) - } - case *LiteralType: - // nothing to do - case *ListType: - for i, l := range n.List { - n.List[i] = Walk(l, fn) - } - case *ObjectType: - n.List = Walk(n.List, fn).(*ObjectList) - default: - // should we panic here? - fmt.Printf("unknown type: %T\n", n) - } - - fn(nil) - return rewritten -} diff --git a/vendor/github.com/hashicorp/hcl/hcl/parser/error.go b/vendor/github.com/hashicorp/hcl/hcl/parser/error.go deleted file mode 100644 index 5c99381df..000000000 --- a/vendor/github.com/hashicorp/hcl/hcl/parser/error.go +++ /dev/null @@ -1,17 +0,0 @@ -package parser - -import ( - "fmt" - - "github.com/hashicorp/hcl/hcl/token" -) - -// PosError is a parse error that contains a position. -type PosError struct { - Pos token.Pos - Err error -} - -func (e *PosError) Error() string { - return fmt.Sprintf("At %s: %s", e.Pos, e.Err) -} diff --git a/vendor/github.com/hashicorp/hcl/hcl/parser/parser.go b/vendor/github.com/hashicorp/hcl/hcl/parser/parser.go deleted file mode 100644 index 64c83bcfb..000000000 --- a/vendor/github.com/hashicorp/hcl/hcl/parser/parser.go +++ /dev/null @@ -1,532 +0,0 @@ -// Package parser implements a parser for HCL (HashiCorp Configuration -// Language) -package parser - -import ( - "bytes" - "errors" - "fmt" - "strings" - - "github.com/hashicorp/hcl/hcl/ast" - "github.com/hashicorp/hcl/hcl/scanner" - "github.com/hashicorp/hcl/hcl/token" -) - -type Parser struct { - sc *scanner.Scanner - - // Last read token - tok token.Token - commaPrev token.Token - - comments []*ast.CommentGroup - leadComment *ast.CommentGroup // last lead comment - lineComment *ast.CommentGroup // last line comment - - enableTrace bool - indent int - n int // buffer size (max = 1) -} - -func newParser(src []byte) *Parser { - return &Parser{ - sc: scanner.New(src), - } -} - -// Parse returns the fully parsed source and returns the abstract syntax tree. -func Parse(src []byte) (*ast.File, error) { - // normalize all line endings - // since the scanner and output only work with "\n" line endings, we may - // end up with dangling "\r" characters in the parsed data. - src = bytes.Replace(src, []byte("\r\n"), []byte("\n"), -1) - - p := newParser(src) - return p.Parse() -} - -var errEofToken = errors.New("EOF token found") - -// Parse returns the fully parsed source and returns the abstract syntax tree. -func (p *Parser) Parse() (*ast.File, error) { - f := &ast.File{} - var err, scerr error - p.sc.Error = func(pos token.Pos, msg string) { - scerr = &PosError{Pos: pos, Err: errors.New(msg)} - } - - f.Node, err = p.objectList(false) - if scerr != nil { - return nil, scerr - } - if err != nil { - return nil, err - } - - f.Comments = p.comments - return f, nil -} - -// objectList parses a list of items within an object (generally k/v pairs). -// The parameter" obj" tells this whether to we are within an object (braces: -// '{', '}') or just at the top level. If we're within an object, we end -// at an RBRACE. -func (p *Parser) objectList(obj bool) (*ast.ObjectList, error) { - defer un(trace(p, "ParseObjectList")) - node := &ast.ObjectList{} - - for { - if obj { - tok := p.scan() - p.unscan() - if tok.Type == token.RBRACE { - break - } - } - - n, err := p.objectItem() - if err == errEofToken { - break // we are finished - } - - // we don't return a nil node, because might want to use already - // collected items. - if err != nil { - return node, err - } - - node.Add(n) - - // object lists can be optionally comma-delimited e.g. when a list of maps - // is being expressed, so a comma is allowed here - it's simply consumed - tok := p.scan() - if tok.Type != token.COMMA { - p.unscan() - } - } - return node, nil -} - -func (p *Parser) consumeComment() (comment *ast.Comment, endline int) { - endline = p.tok.Pos.Line - - // count the endline if it's multiline comment, ie starting with /* - if len(p.tok.Text) > 1 && p.tok.Text[1] == '*' { - // don't use range here - no need to decode Unicode code points - for i := 0; i < len(p.tok.Text); i++ { - if p.tok.Text[i] == '\n' { - endline++ - } - } - } - - comment = &ast.Comment{Start: p.tok.Pos, Text: p.tok.Text} - p.tok = p.sc.Scan() - return -} - -func (p *Parser) consumeCommentGroup(n int) (comments *ast.CommentGroup, endline int) { - var list []*ast.Comment - endline = p.tok.Pos.Line - - for p.tok.Type == token.COMMENT && p.tok.Pos.Line <= endline+n { - var comment *ast.Comment - comment, endline = p.consumeComment() - list = append(list, comment) - } - - // add comment group to the comments list - comments = &ast.CommentGroup{List: list} - p.comments = append(p.comments, comments) - - return -} - -// objectItem parses a single object item -func (p *Parser) objectItem() (*ast.ObjectItem, error) { - defer un(trace(p, "ParseObjectItem")) - - keys, err := p.objectKey() - if len(keys) > 0 && err == errEofToken { - // We ignore eof token here since it is an error if we didn't - // receive a value (but we did receive a key) for the item. - err = nil - } - if len(keys) > 0 && err != nil && p.tok.Type == token.RBRACE { - // This is a strange boolean statement, but what it means is: - // We have keys with no value, and we're likely in an object - // (since RBrace ends an object). For this, we set err to nil so - // we continue and get the error below of having the wrong value - // type. - err = nil - - // Reset the token type so we don't think it completed fine. See - // objectType which uses p.tok.Type to check if we're done with - // the object. - p.tok.Type = token.EOF - } - if err != nil { - return nil, err - } - - o := &ast.ObjectItem{ - Keys: keys, - } - - if p.leadComment != nil { - o.LeadComment = p.leadComment - p.leadComment = nil - } - - switch p.tok.Type { - case token.ASSIGN: - o.Assign = p.tok.Pos - o.Val, err = p.object() - if err != nil { - return nil, err - } - case token.LBRACE: - o.Val, err = p.objectType() - if err != nil { - return nil, err - } - default: - keyStr := make([]string, 0, len(keys)) - for _, k := range keys { - keyStr = append(keyStr, k.Token.Text) - } - - return nil, &PosError{ - Pos: p.tok.Pos, - Err: fmt.Errorf( - "key '%s' expected start of object ('{') or assignment ('=')", - strings.Join(keyStr, " ")), - } - } - - // key=#comment - // val - if p.lineComment != nil { - o.LineComment, p.lineComment = p.lineComment, nil - } - - // do a look-ahead for line comment - p.scan() - if len(keys) > 0 && o.Val.Pos().Line == keys[0].Pos().Line && p.lineComment != nil { - o.LineComment = p.lineComment - p.lineComment = nil - } - p.unscan() - return o, nil -} - -// objectKey parses an object key and returns a ObjectKey AST -func (p *Parser) objectKey() ([]*ast.ObjectKey, error) { - keyCount := 0 - keys := make([]*ast.ObjectKey, 0) - - for { - tok := p.scan() - switch tok.Type { - case token.EOF: - // It is very important to also return the keys here as well as - // the error. This is because we need to be able to tell if we - // did parse keys prior to finding the EOF, or if we just found - // a bare EOF. - return keys, errEofToken - case token.ASSIGN: - // assignment or object only, but not nested objects. this is not - // allowed: `foo bar = {}` - if keyCount > 1 { - return nil, &PosError{ - Pos: p.tok.Pos, - Err: fmt.Errorf("nested object expected: LBRACE got: %s", p.tok.Type), - } - } - - if keyCount == 0 { - return nil, &PosError{ - Pos: p.tok.Pos, - Err: errors.New("no object keys found!"), - } - } - - return keys, nil - case token.LBRACE: - var err error - - // If we have no keys, then it is a syntax error. i.e. {{}} is not - // allowed. - if len(keys) == 0 { - err = &PosError{ - Pos: p.tok.Pos, - Err: fmt.Errorf("expected: IDENT | STRING got: %s", p.tok.Type), - } - } - - // object - return keys, err - case token.IDENT, token.STRING: - keyCount++ - keys = append(keys, &ast.ObjectKey{Token: p.tok}) - case token.ILLEGAL: - return keys, &PosError{ - Pos: p.tok.Pos, - Err: fmt.Errorf("illegal character"), - } - default: - return keys, &PosError{ - Pos: p.tok.Pos, - Err: fmt.Errorf("expected: IDENT | STRING | ASSIGN | LBRACE got: %s", p.tok.Type), - } - } - } -} - -// object parses any type of object, such as number, bool, string, object or -// list. -func (p *Parser) object() (ast.Node, error) { - defer un(trace(p, "ParseType")) - tok := p.scan() - - switch tok.Type { - case token.NUMBER, token.FLOAT, token.BOOL, token.STRING, token.HEREDOC: - return p.literalType() - case token.LBRACE: - return p.objectType() - case token.LBRACK: - return p.listType() - case token.COMMENT: - // implement comment - case token.EOF: - return nil, errEofToken - } - - return nil, &PosError{ - Pos: tok.Pos, - Err: fmt.Errorf("Unknown token: %+v", tok), - } -} - -// objectType parses an object type and returns a ObjectType AST -func (p *Parser) objectType() (*ast.ObjectType, error) { - defer un(trace(p, "ParseObjectType")) - - // we assume that the currently scanned token is a LBRACE - o := &ast.ObjectType{ - Lbrace: p.tok.Pos, - } - - l, err := p.objectList(true) - - // if we hit RBRACE, we are good to go (means we parsed all Items), if it's - // not a RBRACE, it's an syntax error and we just return it. - if err != nil && p.tok.Type != token.RBRACE { - return nil, err - } - - // No error, scan and expect the ending to be a brace - if tok := p.scan(); tok.Type != token.RBRACE { - return nil, &PosError{ - Pos: tok.Pos, - Err: fmt.Errorf("object expected closing RBRACE got: %s", tok.Type), - } - } - - o.List = l - o.Rbrace = p.tok.Pos // advanced via parseObjectList - return o, nil -} - -// listType parses a list type and returns a ListType AST -func (p *Parser) listType() (*ast.ListType, error) { - defer un(trace(p, "ParseListType")) - - // we assume that the currently scanned token is a LBRACK - l := &ast.ListType{ - Lbrack: p.tok.Pos, - } - - needComma := false - for { - tok := p.scan() - if needComma { - switch tok.Type { - case token.COMMA, token.RBRACK: - default: - return nil, &PosError{ - Pos: tok.Pos, - Err: fmt.Errorf( - "error parsing list, expected comma or list end, got: %s", - tok.Type), - } - } - } - switch tok.Type { - case token.BOOL, token.NUMBER, token.FLOAT, token.STRING, token.HEREDOC: - node, err := p.literalType() - if err != nil { - return nil, err - } - - // If there is a lead comment, apply it - if p.leadComment != nil { - node.LeadComment = p.leadComment - p.leadComment = nil - } - - l.Add(node) - needComma = true - case token.COMMA: - // get next list item or we are at the end - // do a look-ahead for line comment - p.scan() - if p.lineComment != nil && len(l.List) > 0 { - lit, ok := l.List[len(l.List)-1].(*ast.LiteralType) - if ok { - lit.LineComment = p.lineComment - l.List[len(l.List)-1] = lit - p.lineComment = nil - } - } - p.unscan() - - needComma = false - continue - case token.LBRACE: - // Looks like a nested object, so parse it out - node, err := p.objectType() - if err != nil { - return nil, &PosError{ - Pos: tok.Pos, - Err: fmt.Errorf( - "error while trying to parse object within list: %s", err), - } - } - l.Add(node) - needComma = true - case token.LBRACK: - node, err := p.listType() - if err != nil { - return nil, &PosError{ - Pos: tok.Pos, - Err: fmt.Errorf( - "error while trying to parse list within list: %s", err), - } - } - l.Add(node) - case token.RBRACK: - // finished - l.Rbrack = p.tok.Pos - return l, nil - default: - return nil, &PosError{ - Pos: tok.Pos, - Err: fmt.Errorf("unexpected token while parsing list: %s", tok.Type), - } - } - } -} - -// literalType parses a literal type and returns a LiteralType AST -func (p *Parser) literalType() (*ast.LiteralType, error) { - defer un(trace(p, "ParseLiteral")) - - return &ast.LiteralType{ - Token: p.tok, - }, nil -} - -// scan returns the next token from the underlying scanner. If a token has -// been unscanned then read that instead. In the process, it collects any -// comment groups encountered, and remembers the last lead and line comments. -func (p *Parser) scan() token.Token { - // If we have a token on the buffer, then return it. - if p.n != 0 { - p.n = 0 - return p.tok - } - - // Otherwise read the next token from the scanner and Save it to the buffer - // in case we unscan later. - prev := p.tok - p.tok = p.sc.Scan() - - if p.tok.Type == token.COMMENT { - var comment *ast.CommentGroup - var endline int - - // fmt.Printf("p.tok.Pos.Line = %+v prev: %d endline %d \n", - // p.tok.Pos.Line, prev.Pos.Line, endline) - if p.tok.Pos.Line == prev.Pos.Line { - // The comment is on same line as the previous token; it - // cannot be a lead comment but may be a line comment. - comment, endline = p.consumeCommentGroup(0) - if p.tok.Pos.Line != endline { - // The next token is on a different line, thus - // the last comment group is a line comment. - p.lineComment = comment - } - } - - // consume successor comments, if any - endline = -1 - for p.tok.Type == token.COMMENT { - comment, endline = p.consumeCommentGroup(1) - } - - if endline+1 == p.tok.Pos.Line && p.tok.Type != token.RBRACE { - switch p.tok.Type { - case token.RBRACE, token.RBRACK: - // Do not count for these cases - default: - // The next token is following on the line immediately after the - // comment group, thus the last comment group is a lead comment. - p.leadComment = comment - } - } - - } - - return p.tok -} - -// unscan pushes the previously read token back onto the buffer. -func (p *Parser) unscan() { - p.n = 1 -} - -// ---------------------------------------------------------------------------- -// Parsing support - -func (p *Parser) printTrace(a ...interface{}) { - if !p.enableTrace { - return - } - - const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " - const n = len(dots) - fmt.Printf("%5d:%3d: ", p.tok.Pos.Line, p.tok.Pos.Column) - - i := 2 * p.indent - for i > n { - fmt.Print(dots) - i -= n - } - // i <= n - fmt.Print(dots[0:i]) - fmt.Println(a...) -} - -func trace(p *Parser, msg string) *Parser { - p.printTrace(msg, "(") - p.indent++ - return p -} - -// Usage pattern: defer un(trace(p, "...")) -func un(p *Parser) { - p.indent-- - p.printTrace(")") -} diff --git a/vendor/github.com/hashicorp/hcl/hcl/printer/nodes.go b/vendor/github.com/hashicorp/hcl/hcl/printer/nodes.go deleted file mode 100644 index 7c038d12a..000000000 --- a/vendor/github.com/hashicorp/hcl/hcl/printer/nodes.go +++ /dev/null @@ -1,789 +0,0 @@ -package printer - -import ( - "bytes" - "fmt" - "sort" - - "github.com/hashicorp/hcl/hcl/ast" - "github.com/hashicorp/hcl/hcl/token" -) - -const ( - blank = byte(' ') - newline = byte('\n') - tab = byte('\t') - infinity = 1 << 30 // offset or line -) - -var ( - unindent = []byte("\uE123") // in the private use space -) - -type printer struct { - cfg Config - prev token.Pos - - comments []*ast.CommentGroup // may be nil, contains all comments - standaloneComments []*ast.CommentGroup // contains all standalone comments (not assigned to any node) - - enableTrace bool - indentTrace int -} - -type ByPosition []*ast.CommentGroup - -func (b ByPosition) Len() int { return len(b) } -func (b ByPosition) Swap(i, j int) { b[i], b[j] = b[j], b[i] } -func (b ByPosition) Less(i, j int) bool { return b[i].Pos().Before(b[j].Pos()) } - -// collectComments comments all standalone comments which are not lead or line -// comment -func (p *printer) collectComments(node ast.Node) { - // first collect all comments. This is already stored in - // ast.File.(comments) - ast.Walk(node, func(nn ast.Node) (ast.Node, bool) { - switch t := nn.(type) { - case *ast.File: - p.comments = t.Comments - return nn, false - } - return nn, true - }) - - standaloneComments := make(map[token.Pos]*ast.CommentGroup, 0) - for _, c := range p.comments { - standaloneComments[c.Pos()] = c - } - - // next remove all lead and line comments from the overall comment map. - // This will give us comments which are standalone, comments which are not - // assigned to any kind of node. - ast.Walk(node, func(nn ast.Node) (ast.Node, bool) { - switch t := nn.(type) { - case *ast.LiteralType: - if t.LeadComment != nil { - for _, comment := range t.LeadComment.List { - if _, ok := standaloneComments[comment.Pos()]; ok { - delete(standaloneComments, comment.Pos()) - } - } - } - - if t.LineComment != nil { - for _, comment := range t.LineComment.List { - if _, ok := standaloneComments[comment.Pos()]; ok { - delete(standaloneComments, comment.Pos()) - } - } - } - case *ast.ObjectItem: - if t.LeadComment != nil { - for _, comment := range t.LeadComment.List { - if _, ok := standaloneComments[comment.Pos()]; ok { - delete(standaloneComments, comment.Pos()) - } - } - } - - if t.LineComment != nil { - for _, comment := range t.LineComment.List { - if _, ok := standaloneComments[comment.Pos()]; ok { - delete(standaloneComments, comment.Pos()) - } - } - } - } - - return nn, true - }) - - for _, c := range standaloneComments { - p.standaloneComments = append(p.standaloneComments, c) - } - - sort.Sort(ByPosition(p.standaloneComments)) -} - -// output prints creates b printable HCL output and returns it. -func (p *printer) output(n interface{}) []byte { - var buf bytes.Buffer - - switch t := n.(type) { - case *ast.File: - // File doesn't trace so we add the tracing here - defer un(trace(p, "File")) - return p.output(t.Node) - case *ast.ObjectList: - defer un(trace(p, "ObjectList")) - - var index int - for { - // Determine the location of the next actual non-comment - // item. If we're at the end, the next item is at "infinity" - var nextItem token.Pos - if index != len(t.Items) { - nextItem = t.Items[index].Pos() - } else { - nextItem = token.Pos{Offset: infinity, Line: infinity} - } - - // Go through the standalone comments in the file and print out - // the comments that we should be for this object item. - for _, c := range p.standaloneComments { - // Go through all the comments in the group. The group - // should be printed together, not separated by double newlines. - printed := false - newlinePrinted := false - for _, comment := range c.List { - // We only care about comments after the previous item - // we've printed so that comments are printed in the - // correct locations (between two objects for example). - // And before the next item. - if comment.Pos().After(p.prev) && comment.Pos().Before(nextItem) { - // if we hit the end add newlines so we can print the comment - // we don't do this if prev is invalid which means the - // beginning of the file since the first comment should - // be at the first line. - if !newlinePrinted && p.prev.IsValid() && index == len(t.Items) { - buf.Write([]byte{newline, newline}) - newlinePrinted = true - } - - // Write the actual comment. - buf.WriteString(comment.Text) - buf.WriteByte(newline) - - // Set printed to true to note that we printed something - printed = true - } - } - - // If we're not at the last item, write a new line so - // that there is a newline separating this comment from - // the next object. - if printed && index != len(t.Items) { - buf.WriteByte(newline) - } - } - - if index == len(t.Items) { - break - } - - buf.Write(p.output(t.Items[index])) - if index != len(t.Items)-1 { - // Always write a newline to separate us from the next item - buf.WriteByte(newline) - - // Need to determine if we're going to separate the next item - // with a blank line. The logic here is simple, though there - // are a few conditions: - // - // 1. The next object is more than one line away anyways, - // so we need an empty line. - // - // 2. The next object is not a "single line" object, so - // we need an empty line. - // - // 3. This current object is not a single line object, - // so we need an empty line. - current := t.Items[index] - next := t.Items[index+1] - if next.Pos().Line != t.Items[index].Pos().Line+1 || - !p.isSingleLineObject(next) || - !p.isSingleLineObject(current) { - buf.WriteByte(newline) - } - } - index++ - } - case *ast.ObjectKey: - buf.WriteString(t.Token.Text) - case *ast.ObjectItem: - p.prev = t.Pos() - buf.Write(p.objectItem(t)) - case *ast.LiteralType: - buf.Write(p.literalType(t)) - case *ast.ListType: - buf.Write(p.list(t)) - case *ast.ObjectType: - buf.Write(p.objectType(t)) - default: - fmt.Printf(" unknown type: %T\n", n) - } - - return buf.Bytes() -} - -func (p *printer) literalType(lit *ast.LiteralType) []byte { - result := []byte(lit.Token.Text) - switch lit.Token.Type { - case token.HEREDOC: - // Clear the trailing newline from heredocs - if result[len(result)-1] == '\n' { - result = result[:len(result)-1] - } - - // Poison lines 2+ so that we don't indent them - result = p.heredocIndent(result) - case token.STRING: - // If this is a multiline string, poison lines 2+ so we don't - // indent them. - if bytes.IndexRune(result, '\n') >= 0 { - result = p.heredocIndent(result) - } - } - - return result -} - -// objectItem returns the printable HCL form of an object item. An object type -// starts with one/multiple keys and has a value. The value might be of any -// type. -func (p *printer) objectItem(o *ast.ObjectItem) []byte { - defer un(trace(p, fmt.Sprintf("ObjectItem: %s", o.Keys[0].Token.Text))) - var buf bytes.Buffer - - if o.LeadComment != nil { - for _, comment := range o.LeadComment.List { - buf.WriteString(comment.Text) - buf.WriteByte(newline) - } - } - - // If key and val are on different lines, treat line comments like lead comments. - if o.LineComment != nil && o.Val.Pos().Line != o.Keys[0].Pos().Line { - for _, comment := range o.LineComment.List { - buf.WriteString(comment.Text) - buf.WriteByte(newline) - } - } - - for i, k := range o.Keys { - buf.WriteString(k.Token.Text) - buf.WriteByte(blank) - - // reach end of key - if o.Assign.IsValid() && i == len(o.Keys)-1 && len(o.Keys) == 1 { - buf.WriteString("=") - buf.WriteByte(blank) - } - } - - buf.Write(p.output(o.Val)) - - if o.LineComment != nil && o.Val.Pos().Line == o.Keys[0].Pos().Line { - buf.WriteByte(blank) - for _, comment := range o.LineComment.List { - buf.WriteString(comment.Text) - } - } - - return buf.Bytes() -} - -// objectType returns the printable HCL form of an object type. An object type -// begins with a brace and ends with a brace. -func (p *printer) objectType(o *ast.ObjectType) []byte { - defer un(trace(p, "ObjectType")) - var buf bytes.Buffer - buf.WriteString("{") - - var index int - var nextItem token.Pos - var commented, newlinePrinted bool - for { - // Determine the location of the next actual non-comment - // item. If we're at the end, the next item is the closing brace - if index != len(o.List.Items) { - nextItem = o.List.Items[index].Pos() - } else { - nextItem = o.Rbrace - } - - // Go through the standalone comments in the file and print out - // the comments that we should be for this object item. - for _, c := range p.standaloneComments { - printed := false - var lastCommentPos token.Pos - for _, comment := range c.List { - // We only care about comments after the previous item - // we've printed so that comments are printed in the - // correct locations (between two objects for example). - // And before the next item. - if comment.Pos().After(p.prev) && comment.Pos().Before(nextItem) { - // If there are standalone comments and the initial newline has not - // been printed yet, do it now. - if !newlinePrinted { - newlinePrinted = true - buf.WriteByte(newline) - } - - // add newline if it's between other printed nodes - if index > 0 { - commented = true - buf.WriteByte(newline) - } - - // Store this position - lastCommentPos = comment.Pos() - - // output the comment itself - buf.Write(p.indent(p.heredocIndent([]byte(comment.Text)))) - - // Set printed to true to note that we printed something - printed = true - - /* - if index != len(o.List.Items) { - buf.WriteByte(newline) // do not print on the end - } - */ - } - } - - // Stuff to do if we had comments - if printed { - // Always write a newline - buf.WriteByte(newline) - - // If there is another item in the object and our comment - // didn't hug it directly, then make sure there is a blank - // line separating them. - if nextItem != o.Rbrace && nextItem.Line != lastCommentPos.Line+1 { - buf.WriteByte(newline) - } - } - } - - if index == len(o.List.Items) { - p.prev = o.Rbrace - break - } - - // At this point we are sure that it's not a totally empty block: print - // the initial newline if it hasn't been printed yet by the previous - // block about standalone comments. - if !newlinePrinted { - buf.WriteByte(newline) - newlinePrinted = true - } - - // check if we have adjacent one liner items. If yes we'll going to align - // the comments. - var aligned []*ast.ObjectItem - for _, item := range o.List.Items[index:] { - // we don't group one line lists - if len(o.List.Items) == 1 { - break - } - - // one means a oneliner with out any lead comment - // two means a oneliner with lead comment - // anything else might be something else - cur := lines(string(p.objectItem(item))) - if cur > 2 { - break - } - - curPos := item.Pos() - - nextPos := token.Pos{} - if index != len(o.List.Items)-1 { - nextPos = o.List.Items[index+1].Pos() - } - - prevPos := token.Pos{} - if index != 0 { - prevPos = o.List.Items[index-1].Pos() - } - - // fmt.Println("DEBUG ----------------") - // fmt.Printf("prev = %+v prevPos: %s\n", prev, prevPos) - // fmt.Printf("cur = %+v curPos: %s\n", cur, curPos) - // fmt.Printf("next = %+v nextPos: %s\n", next, nextPos) - - if curPos.Line+1 == nextPos.Line { - aligned = append(aligned, item) - index++ - continue - } - - if curPos.Line-1 == prevPos.Line { - aligned = append(aligned, item) - index++ - - // finish if we have a new line or comment next. This happens - // if the next item is not adjacent - if curPos.Line+1 != nextPos.Line { - break - } - continue - } - - break - } - - // put newlines if the items are between other non aligned items. - // newlines are also added if there is a standalone comment already, so - // check it too - if !commented && index != len(aligned) { - buf.WriteByte(newline) - } - - if len(aligned) >= 1 { - p.prev = aligned[len(aligned)-1].Pos() - - items := p.alignedItems(aligned) - buf.Write(p.indent(items)) - } else { - p.prev = o.List.Items[index].Pos() - - buf.Write(p.indent(p.objectItem(o.List.Items[index]))) - index++ - } - - buf.WriteByte(newline) - } - - buf.WriteString("}") - return buf.Bytes() -} - -func (p *printer) alignedItems(items []*ast.ObjectItem) []byte { - var buf bytes.Buffer - - // find the longest key and value length, needed for alignment - var longestKeyLen int // longest key length - var longestValLen int // longest value length - for _, item := range items { - key := len(item.Keys[0].Token.Text) - val := len(p.output(item.Val)) - - if key > longestKeyLen { - longestKeyLen = key - } - - if val > longestValLen { - longestValLen = val - } - } - - for i, item := range items { - if item.LeadComment != nil { - for _, comment := range item.LeadComment.List { - buf.WriteString(comment.Text) - buf.WriteByte(newline) - } - } - - for i, k := range item.Keys { - keyLen := len(k.Token.Text) - buf.WriteString(k.Token.Text) - for i := 0; i < longestKeyLen-keyLen+1; i++ { - buf.WriteByte(blank) - } - - // reach end of key - if i == len(item.Keys)-1 && len(item.Keys) == 1 { - buf.WriteString("=") - buf.WriteByte(blank) - } - } - - val := p.output(item.Val) - valLen := len(val) - buf.Write(val) - - if item.Val.Pos().Line == item.Keys[0].Pos().Line && item.LineComment != nil { - for i := 0; i < longestValLen-valLen+1; i++ { - buf.WriteByte(blank) - } - - for _, comment := range item.LineComment.List { - buf.WriteString(comment.Text) - } - } - - // do not print for the last item - if i != len(items)-1 { - buf.WriteByte(newline) - } - } - - return buf.Bytes() -} - -// list returns the printable HCL form of an list type. -func (p *printer) list(l *ast.ListType) []byte { - if p.isSingleLineList(l) { - return p.singleLineList(l) - } - - var buf bytes.Buffer - buf.WriteString("[") - buf.WriteByte(newline) - - var longestLine int - for _, item := range l.List { - // for now we assume that the list only contains literal types - if lit, ok := item.(*ast.LiteralType); ok { - lineLen := len(lit.Token.Text) - if lineLen > longestLine { - longestLine = lineLen - } - } - } - - haveEmptyLine := false - for i, item := range l.List { - // If we have a lead comment, then we want to write that first - leadComment := false - if lit, ok := item.(*ast.LiteralType); ok && lit.LeadComment != nil { - leadComment = true - - // Ensure an empty line before every element with a - // lead comment (except the first item in a list). - if !haveEmptyLine && i != 0 { - buf.WriteByte(newline) - } - - for _, comment := range lit.LeadComment.List { - buf.Write(p.indent([]byte(comment.Text))) - buf.WriteByte(newline) - } - } - - // also indent each line - val := p.output(item) - curLen := len(val) - buf.Write(p.indent(val)) - - // if this item is a heredoc, then we output the comma on - // the next line. This is the only case this happens. - comma := []byte{','} - if lit, ok := item.(*ast.LiteralType); ok && lit.Token.Type == token.HEREDOC { - buf.WriteByte(newline) - comma = p.indent(comma) - } - - buf.Write(comma) - - if lit, ok := item.(*ast.LiteralType); ok && lit.LineComment != nil { - // if the next item doesn't have any comments, do not align - buf.WriteByte(blank) // align one space - for i := 0; i < longestLine-curLen; i++ { - buf.WriteByte(blank) - } - - for _, comment := range lit.LineComment.List { - buf.WriteString(comment.Text) - } - } - - buf.WriteByte(newline) - - // Ensure an empty line after every element with a - // lead comment (except the first item in a list). - haveEmptyLine = leadComment && i != len(l.List)-1 - if haveEmptyLine { - buf.WriteByte(newline) - } - } - - buf.WriteString("]") - return buf.Bytes() -} - -// isSingleLineList returns true if: -// * they were previously formatted entirely on one line -// * they consist entirely of literals -// * there are either no heredoc strings or the list has exactly one element -// * there are no line comments -func (printer) isSingleLineList(l *ast.ListType) bool { - for _, item := range l.List { - if item.Pos().Line != l.Lbrack.Line { - return false - } - - lit, ok := item.(*ast.LiteralType) - if !ok { - return false - } - - if lit.Token.Type == token.HEREDOC && len(l.List) != 1 { - return false - } - - if lit.LineComment != nil { - return false - } - } - - return true -} - -// singleLineList prints a simple single line list. -// For a definition of "simple", see isSingleLineList above. -func (p *printer) singleLineList(l *ast.ListType) []byte { - buf := &bytes.Buffer{} - - buf.WriteString("[") - for i, item := range l.List { - if i != 0 { - buf.WriteString(", ") - } - - // Output the item itself - buf.Write(p.output(item)) - - // The heredoc marker needs to be at the end of line. - if lit, ok := item.(*ast.LiteralType); ok && lit.Token.Type == token.HEREDOC { - buf.WriteByte(newline) - } - } - - buf.WriteString("]") - return buf.Bytes() -} - -// indent indents the lines of the given buffer for each non-empty line -func (p *printer) indent(buf []byte) []byte { - var prefix []byte - if p.cfg.SpacesWidth != 0 { - for i := 0; i < p.cfg.SpacesWidth; i++ { - prefix = append(prefix, blank) - } - } else { - prefix = []byte{tab} - } - - var res []byte - bol := true - for _, c := range buf { - if bol && c != '\n' { - res = append(res, prefix...) - } - - res = append(res, c) - bol = c == '\n' - } - return res -} - -// unindent removes all the indentation from the tombstoned lines -func (p *printer) unindent(buf []byte) []byte { - var res []byte - for i := 0; i < len(buf); i++ { - skip := len(buf)-i <= len(unindent) - if !skip { - skip = !bytes.Equal(unindent, buf[i:i+len(unindent)]) - } - if skip { - res = append(res, buf[i]) - continue - } - - // We have a marker. we have to backtrace here and clean out - // any whitespace ahead of our tombstone up to a \n - for j := len(res) - 1; j >= 0; j-- { - if res[j] == '\n' { - break - } - - res = res[:j] - } - - // Skip the entire unindent marker - i += len(unindent) - 1 - } - - return res -} - -// heredocIndent marks all the 2nd and further lines as unindentable -func (p *printer) heredocIndent(buf []byte) []byte { - var res []byte - bol := false - for _, c := range buf { - if bol && c != '\n' { - res = append(res, unindent...) - } - res = append(res, c) - bol = c == '\n' - } - return res -} - -// isSingleLineObject tells whether the given object item is a single -// line object such as "obj {}". -// -// A single line object: -// -// * has no lead comments (hence multi-line) -// * has no assignment -// * has no values in the stanza (within {}) -// -func (p *printer) isSingleLineObject(val *ast.ObjectItem) bool { - // If there is a lead comment, can't be one line - if val.LeadComment != nil { - return false - } - - // If there is assignment, we always break by line - if val.Assign.IsValid() { - return false - } - - // If it isn't an object type, then its not a single line object - ot, ok := val.Val.(*ast.ObjectType) - if !ok { - return false - } - - // If the object has no items, it is single line! - return len(ot.List.Items) == 0 -} - -func lines(txt string) int { - endline := 1 - for i := 0; i < len(txt); i++ { - if txt[i] == '\n' { - endline++ - } - } - return endline -} - -// ---------------------------------------------------------------------------- -// Tracing support - -func (p *printer) printTrace(a ...interface{}) { - if !p.enableTrace { - return - } - - const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " - const n = len(dots) - i := 2 * p.indentTrace - for i > n { - fmt.Print(dots) - i -= n - } - // i <= n - fmt.Print(dots[0:i]) - fmt.Println(a...) -} - -func trace(p *printer, msg string) *printer { - p.printTrace(msg, "(") - p.indentTrace++ - return p -} - -// Usage pattern: defer un(trace(p, "...")) -func un(p *printer) { - p.indentTrace-- - p.printTrace(")") -} diff --git a/vendor/github.com/hashicorp/hcl/hcl/printer/printer.go b/vendor/github.com/hashicorp/hcl/hcl/printer/printer.go deleted file mode 100644 index 6617ab8e7..000000000 --- a/vendor/github.com/hashicorp/hcl/hcl/printer/printer.go +++ /dev/null @@ -1,66 +0,0 @@ -// Package printer implements printing of AST nodes to HCL format. -package printer - -import ( - "bytes" - "io" - "text/tabwriter" - - "github.com/hashicorp/hcl/hcl/ast" - "github.com/hashicorp/hcl/hcl/parser" -) - -var DefaultConfig = Config{ - SpacesWidth: 2, -} - -// A Config node controls the output of Fprint. -type Config struct { - SpacesWidth int // if set, it will use spaces instead of tabs for alignment -} - -func (c *Config) Fprint(output io.Writer, node ast.Node) error { - p := &printer{ - cfg: *c, - comments: make([]*ast.CommentGroup, 0), - standaloneComments: make([]*ast.CommentGroup, 0), - // enableTrace: true, - } - - p.collectComments(node) - - if _, err := output.Write(p.unindent(p.output(node))); err != nil { - return err - } - - // flush tabwriter, if any - var err error - if tw, _ := output.(*tabwriter.Writer); tw != nil { - err = tw.Flush() - } - - return err -} - -// Fprint "pretty-prints" an HCL node to output -// It calls Config.Fprint with default settings. -func Fprint(output io.Writer, node ast.Node) error { - return DefaultConfig.Fprint(output, node) -} - -// Format formats src HCL and returns the result. -func Format(src []byte) ([]byte, error) { - node, err := parser.Parse(src) - if err != nil { - return nil, err - } - - var buf bytes.Buffer - if err := DefaultConfig.Fprint(&buf, node); err != nil { - return nil, err - } - - // Add trailing newline to result - buf.WriteString("\n") - return buf.Bytes(), nil -} diff --git a/vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go b/vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go deleted file mode 100644 index 624a18fe3..000000000 --- a/vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go +++ /dev/null @@ -1,652 +0,0 @@ -// Package scanner implements a scanner for HCL (HashiCorp Configuration -// Language) source text. -package scanner - -import ( - "bytes" - "fmt" - "os" - "regexp" - "unicode" - "unicode/utf8" - - "github.com/hashicorp/hcl/hcl/token" -) - -// eof represents a marker rune for the end of the reader. -const eof = rune(0) - -// Scanner defines a lexical scanner -type Scanner struct { - buf *bytes.Buffer // Source buffer for advancing and scanning - src []byte // Source buffer for immutable access - - // Source Position - srcPos token.Pos // current position - prevPos token.Pos // previous position, used for peek() method - - lastCharLen int // length of last character in bytes - lastLineLen int // length of last line in characters (for correct column reporting) - - tokStart int // token text start position - tokEnd int // token text end position - - // Error is called for each error encountered. If no Error - // function is set, the error is reported to os.Stderr. - Error func(pos token.Pos, msg string) - - // ErrorCount is incremented by one for each error encountered. - ErrorCount int - - // tokPos is the start position of most recently scanned token; set by - // Scan. The Filename field is always left untouched by the Scanner. If - // an error is reported (via Error) and Position is invalid, the scanner is - // not inside a token. - tokPos token.Pos -} - -// New creates and initializes a new instance of Scanner using src as -// its source content. -func New(src []byte) *Scanner { - // even though we accept a src, we read from a io.Reader compatible type - // (*bytes.Buffer). So in the future we might easily change it to streaming - // read. - b := bytes.NewBuffer(src) - s := &Scanner{ - buf: b, - src: src, - } - - // srcPosition always starts with 1 - s.srcPos.Line = 1 - return s -} - -// next reads the next rune from the bufferred reader. Returns the rune(0) if -// an error occurs (or io.EOF is returned). -func (s *Scanner) next() rune { - ch, size, err := s.buf.ReadRune() - if err != nil { - // advance for error reporting - s.srcPos.Column++ - s.srcPos.Offset += size - s.lastCharLen = size - return eof - } - - // remember last position - s.prevPos = s.srcPos - - s.srcPos.Column++ - s.lastCharLen = size - s.srcPos.Offset += size - - if ch == utf8.RuneError && size == 1 { - s.err("illegal UTF-8 encoding") - return ch - } - - if ch == '\n' { - s.srcPos.Line++ - s.lastLineLen = s.srcPos.Column - s.srcPos.Column = 0 - } - - if ch == '\x00' { - s.err("unexpected null character (0x00)") - return eof - } - - if ch == '\uE123' { - s.err("unicode code point U+E123 reserved for internal use") - return utf8.RuneError - } - - // debug - // fmt.Printf("ch: %q, offset:column: %d:%d\n", ch, s.srcPos.Offset, s.srcPos.Column) - return ch -} - -// unread unreads the previous read Rune and updates the source position -func (s *Scanner) unread() { - if err := s.buf.UnreadRune(); err != nil { - panic(err) // this is user fault, we should catch it - } - s.srcPos = s.prevPos // put back last position -} - -// peek returns the next rune without advancing the reader. -func (s *Scanner) peek() rune { - peek, _, err := s.buf.ReadRune() - if err != nil { - return eof - } - - s.buf.UnreadRune() - return peek -} - -// Scan scans the next token and returns the token. -func (s *Scanner) Scan() token.Token { - ch := s.next() - - // skip white space - for isWhitespace(ch) { - ch = s.next() - } - - var tok token.Type - - // token text markings - s.tokStart = s.srcPos.Offset - s.lastCharLen - - // token position, initial next() is moving the offset by one(size of rune - // actually), though we are interested with the starting point - s.tokPos.Offset = s.srcPos.Offset - s.lastCharLen - if s.srcPos.Column > 0 { - // common case: last character was not a '\n' - s.tokPos.Line = s.srcPos.Line - s.tokPos.Column = s.srcPos.Column - } else { - // last character was a '\n' - // (we cannot be at the beginning of the source - // since we have called next() at least once) - s.tokPos.Line = s.srcPos.Line - 1 - s.tokPos.Column = s.lastLineLen - } - - switch { - case isLetter(ch): - tok = token.IDENT - lit := s.scanIdentifier() - if lit == "true" || lit == "false" { - tok = token.BOOL - } - case isDecimal(ch): - tok = s.scanNumber(ch) - default: - switch ch { - case eof: - tok = token.EOF - case '"': - tok = token.STRING - s.scanString() - case '#', '/': - tok = token.COMMENT - s.scanComment(ch) - case '.': - tok = token.PERIOD - ch = s.peek() - if isDecimal(ch) { - tok = token.FLOAT - ch = s.scanMantissa(ch) - ch = s.scanExponent(ch) - } - case '<': - tok = token.HEREDOC - s.scanHeredoc() - case '[': - tok = token.LBRACK - case ']': - tok = token.RBRACK - case '{': - tok = token.LBRACE - case '}': - tok = token.RBRACE - case ',': - tok = token.COMMA - case '=': - tok = token.ASSIGN - case '+': - tok = token.ADD - case '-': - if isDecimal(s.peek()) { - ch := s.next() - tok = s.scanNumber(ch) - } else { - tok = token.SUB - } - default: - s.err("illegal char") - } - } - - // finish token ending - s.tokEnd = s.srcPos.Offset - - // create token literal - var tokenText string - if s.tokStart >= 0 { - tokenText = string(s.src[s.tokStart:s.tokEnd]) - } - s.tokStart = s.tokEnd // ensure idempotency of tokenText() call - - return token.Token{ - Type: tok, - Pos: s.tokPos, - Text: tokenText, - } -} - -func (s *Scanner) scanComment(ch rune) { - // single line comments - if ch == '#' || (ch == '/' && s.peek() != '*') { - if ch == '/' && s.peek() != '/' { - s.err("expected '/' for comment") - return - } - - ch = s.next() - for ch != '\n' && ch >= 0 && ch != eof { - ch = s.next() - } - if ch != eof && ch >= 0 { - s.unread() - } - return - } - - // be sure we get the character after /* This allows us to find comment's - // that are not erminated - if ch == '/' { - s.next() - ch = s.next() // read character after "/*" - } - - // look for /* - style comments - for { - if ch < 0 || ch == eof { - s.err("comment not terminated") - break - } - - ch0 := ch - ch = s.next() - if ch0 == '*' && ch == '/' { - break - } - } -} - -// scanNumber scans a HCL number definition starting with the given rune -func (s *Scanner) scanNumber(ch rune) token.Type { - if ch == '0' { - // check for hexadecimal, octal or float - ch = s.next() - if ch == 'x' || ch == 'X' { - // hexadecimal - ch = s.next() - found := false - for isHexadecimal(ch) { - ch = s.next() - found = true - } - - if !found { - s.err("illegal hexadecimal number") - } - - if ch != eof { - s.unread() - } - - return token.NUMBER - } - - // now it's either something like: 0421(octal) or 0.1231(float) - illegalOctal := false - for isDecimal(ch) { - ch = s.next() - if ch == '8' || ch == '9' { - // this is just a possibility. For example 0159 is illegal, but - // 0159.23 is valid. So we mark a possible illegal octal. If - // the next character is not a period, we'll print the error. - illegalOctal = true - } - } - - if ch == 'e' || ch == 'E' { - ch = s.scanExponent(ch) - return token.FLOAT - } - - if ch == '.' { - ch = s.scanFraction(ch) - - if ch == 'e' || ch == 'E' { - ch = s.next() - ch = s.scanExponent(ch) - } - return token.FLOAT - } - - if illegalOctal { - s.err("illegal octal number") - } - - if ch != eof { - s.unread() - } - return token.NUMBER - } - - s.scanMantissa(ch) - ch = s.next() // seek forward - if ch == 'e' || ch == 'E' { - ch = s.scanExponent(ch) - return token.FLOAT - } - - if ch == '.' { - ch = s.scanFraction(ch) - if ch == 'e' || ch == 'E' { - ch = s.next() - ch = s.scanExponent(ch) - } - return token.FLOAT - } - - if ch != eof { - s.unread() - } - return token.NUMBER -} - -// scanMantissa scans the mantissa beginning from the rune. It returns the next -// non decimal rune. It's used to determine wheter it's a fraction or exponent. -func (s *Scanner) scanMantissa(ch rune) rune { - scanned := false - for isDecimal(ch) { - ch = s.next() - scanned = true - } - - if scanned && ch != eof { - s.unread() - } - return ch -} - -// scanFraction scans the fraction after the '.' rune -func (s *Scanner) scanFraction(ch rune) rune { - if ch == '.' { - ch = s.peek() // we peek just to see if we can move forward - ch = s.scanMantissa(ch) - } - return ch -} - -// scanExponent scans the remaining parts of an exponent after the 'e' or 'E' -// rune. -func (s *Scanner) scanExponent(ch rune) rune { - if ch == 'e' || ch == 'E' { - ch = s.next() - if ch == '-' || ch == '+' { - ch = s.next() - } - ch = s.scanMantissa(ch) - } - return ch -} - -// scanHeredoc scans a heredoc string -func (s *Scanner) scanHeredoc() { - // Scan the second '<' in example: '<= len(identBytes) && identRegexp.Match(s.src[lineStart:s.srcPos.Offset-s.lastCharLen]) { - break - } - - // Not an anchor match, record the start of a new line - lineStart = s.srcPos.Offset - } - - if ch == eof { - s.err("heredoc not terminated") - return - } - } - - return -} - -// scanString scans a quoted string -func (s *Scanner) scanString() { - braces := 0 - for { - // '"' opening already consumed - // read character after quote - ch := s.next() - - if (ch == '\n' && braces == 0) || ch < 0 || ch == eof { - s.err("literal not terminated") - return - } - - if ch == '"' && braces == 0 { - break - } - - // If we're going into a ${} then we can ignore quotes for awhile - if braces == 0 && ch == '$' && s.peek() == '{' { - braces++ - s.next() - } else if braces > 0 && ch == '{' { - braces++ - } - if braces > 0 && ch == '}' { - braces-- - } - - if ch == '\\' { - s.scanEscape() - } - } - - return -} - -// scanEscape scans an escape sequence -func (s *Scanner) scanEscape() rune { - // http://en.cppreference.com/w/cpp/language/escape - ch := s.next() // read character after '/' - switch ch { - case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '"': - // nothing to do - case '0', '1', '2', '3', '4', '5', '6', '7': - // octal notation - ch = s.scanDigits(ch, 8, 3) - case 'x': - // hexademical notation - ch = s.scanDigits(s.next(), 16, 2) - case 'u': - // universal character name - ch = s.scanDigits(s.next(), 16, 4) - case 'U': - // universal character name - ch = s.scanDigits(s.next(), 16, 8) - default: - s.err("illegal char escape") - } - return ch -} - -// scanDigits scans a rune with the given base for n times. For example an -// octal notation \184 would yield in scanDigits(ch, 8, 3) -func (s *Scanner) scanDigits(ch rune, base, n int) rune { - start := n - for n > 0 && digitVal(ch) < base { - ch = s.next() - if ch == eof { - // If we see an EOF, we halt any more scanning of digits - // immediately. - break - } - - n-- - } - if n > 0 { - s.err("illegal char escape") - } - - if n != start && ch != eof { - // we scanned all digits, put the last non digit char back, - // only if we read anything at all - s.unread() - } - - return ch -} - -// scanIdentifier scans an identifier and returns the literal string -func (s *Scanner) scanIdentifier() string { - offs := s.srcPos.Offset - s.lastCharLen - ch := s.next() - for isLetter(ch) || isDigit(ch) || ch == '-' || ch == '.' { - ch = s.next() - } - - if ch != eof { - s.unread() // we got identifier, put back latest char - } - - return string(s.src[offs:s.srcPos.Offset]) -} - -// recentPosition returns the position of the character immediately after the -// character or token returned by the last call to Scan. -func (s *Scanner) recentPosition() (pos token.Pos) { - pos.Offset = s.srcPos.Offset - s.lastCharLen - switch { - case s.srcPos.Column > 0: - // common case: last character was not a '\n' - pos.Line = s.srcPos.Line - pos.Column = s.srcPos.Column - case s.lastLineLen > 0: - // last character was a '\n' - // (we cannot be at the beginning of the source - // since we have called next() at least once) - pos.Line = s.srcPos.Line - 1 - pos.Column = s.lastLineLen - default: - // at the beginning of the source - pos.Line = 1 - pos.Column = 1 - } - return -} - -// err prints the error of any scanning to s.Error function. If the function is -// not defined, by default it prints them to os.Stderr -func (s *Scanner) err(msg string) { - s.ErrorCount++ - pos := s.recentPosition() - - if s.Error != nil { - s.Error(pos, msg) - return - } - - fmt.Fprintf(os.Stderr, "%s: %s\n", pos, msg) -} - -// isHexadecimal returns true if the given rune is a letter -func isLetter(ch rune) bool { - return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch) -} - -// isDigit returns true if the given rune is a decimal digit -func isDigit(ch rune) bool { - return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch) -} - -// isDecimal returns true if the given rune is a decimal number -func isDecimal(ch rune) bool { - return '0' <= ch && ch <= '9' -} - -// isHexadecimal returns true if the given rune is an hexadecimal number -func isHexadecimal(ch rune) bool { - return '0' <= ch && ch <= '9' || 'a' <= ch && ch <= 'f' || 'A' <= ch && ch <= 'F' -} - -// isWhitespace returns true if the rune is a space, tab, newline or carriage return -func isWhitespace(ch rune) bool { - return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' -} - -// digitVal returns the integer value of a given octal,decimal or hexadecimal rune -func digitVal(ch rune) int { - switch { - case '0' <= ch && ch <= '9': - return int(ch - '0') - case 'a' <= ch && ch <= 'f': - return int(ch - 'a' + 10) - case 'A' <= ch && ch <= 'F': - return int(ch - 'A' + 10) - } - return 16 // larger than any legal digit val -} diff --git a/vendor/github.com/hashicorp/hcl/hcl/strconv/quote.go b/vendor/github.com/hashicorp/hcl/hcl/strconv/quote.go deleted file mode 100644 index 5f981eaa2..000000000 --- a/vendor/github.com/hashicorp/hcl/hcl/strconv/quote.go +++ /dev/null @@ -1,241 +0,0 @@ -package strconv - -import ( - "errors" - "unicode/utf8" -) - -// ErrSyntax indicates that a value does not have the right syntax for the target type. -var ErrSyntax = errors.New("invalid syntax") - -// Unquote interprets s as a single-quoted, double-quoted, -// or backquoted Go string literal, returning the string value -// that s quotes. (If s is single-quoted, it would be a Go -// character literal; Unquote returns the corresponding -// one-character string.) -func Unquote(s string) (t string, err error) { - n := len(s) - if n < 2 { - return "", ErrSyntax - } - quote := s[0] - if quote != s[n-1] { - return "", ErrSyntax - } - s = s[1 : n-1] - - if quote != '"' { - return "", ErrSyntax - } - if !contains(s, '$') && !contains(s, '{') && contains(s, '\n') { - return "", ErrSyntax - } - - // Is it trivial? Avoid allocation. - if !contains(s, '\\') && !contains(s, quote) && !contains(s, '$') { - switch quote { - case '"': - return s, nil - case '\'': - r, size := utf8.DecodeRuneInString(s) - if size == len(s) && (r != utf8.RuneError || size != 1) { - return s, nil - } - } - } - - var runeTmp [utf8.UTFMax]byte - buf := make([]byte, 0, 3*len(s)/2) // Try to avoid more allocations. - for len(s) > 0 { - // If we're starting a '${}' then let it through un-unquoted. - // Specifically: we don't unquote any characters within the `${}` - // section. - if s[0] == '$' && len(s) > 1 && s[1] == '{' { - buf = append(buf, '$', '{') - s = s[2:] - - // Continue reading until we find the closing brace, copying as-is - braces := 1 - for len(s) > 0 && braces > 0 { - r, size := utf8.DecodeRuneInString(s) - if r == utf8.RuneError { - return "", ErrSyntax - } - - s = s[size:] - - n := utf8.EncodeRune(runeTmp[:], r) - buf = append(buf, runeTmp[:n]...) - - switch r { - case '{': - braces++ - case '}': - braces-- - } - } - if braces != 0 { - return "", ErrSyntax - } - if len(s) == 0 { - // If there's no string left, we're done! - break - } else { - // If there's more left, we need to pop back up to the top of the loop - // in case there's another interpolation in this string. - continue - } - } - - if s[0] == '\n' { - return "", ErrSyntax - } - - c, multibyte, ss, err := unquoteChar(s, quote) - if err != nil { - return "", err - } - s = ss - if c < utf8.RuneSelf || !multibyte { - buf = append(buf, byte(c)) - } else { - n := utf8.EncodeRune(runeTmp[:], c) - buf = append(buf, runeTmp[:n]...) - } - if quote == '\'' && len(s) != 0 { - // single-quoted must be single character - return "", ErrSyntax - } - } - return string(buf), nil -} - -// contains reports whether the string contains the byte c. -func contains(s string, c byte) bool { - for i := 0; i < len(s); i++ { - if s[i] == c { - return true - } - } - return false -} - -func unhex(b byte) (v rune, ok bool) { - c := rune(b) - switch { - case '0' <= c && c <= '9': - return c - '0', true - case 'a' <= c && c <= 'f': - return c - 'a' + 10, true - case 'A' <= c && c <= 'F': - return c - 'A' + 10, true - } - return -} - -func unquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, err error) { - // easy cases - switch c := s[0]; { - case c == quote && (quote == '\'' || quote == '"'): - err = ErrSyntax - return - case c >= utf8.RuneSelf: - r, size := utf8.DecodeRuneInString(s) - return r, true, s[size:], nil - case c != '\\': - return rune(s[0]), false, s[1:], nil - } - - // hard case: c is backslash - if len(s) <= 1 { - err = ErrSyntax - return - } - c := s[1] - s = s[2:] - - switch c { - case 'a': - value = '\a' - case 'b': - value = '\b' - case 'f': - value = '\f' - case 'n': - value = '\n' - case 'r': - value = '\r' - case 't': - value = '\t' - case 'v': - value = '\v' - case 'x', 'u', 'U': - n := 0 - switch c { - case 'x': - n = 2 - case 'u': - n = 4 - case 'U': - n = 8 - } - var v rune - if len(s) < n { - err = ErrSyntax - return - } - for j := 0; j < n; j++ { - x, ok := unhex(s[j]) - if !ok { - err = ErrSyntax - return - } - v = v<<4 | x - } - s = s[n:] - if c == 'x' { - // single-byte string, possibly not UTF-8 - value = v - break - } - if v > utf8.MaxRune { - err = ErrSyntax - return - } - value = v - multibyte = true - case '0', '1', '2', '3', '4', '5', '6', '7': - v := rune(c) - '0' - if len(s) < 2 { - err = ErrSyntax - return - } - for j := 0; j < 2; j++ { // one digit already; two more - x := rune(s[j]) - '0' - if x < 0 || x > 7 { - err = ErrSyntax - return - } - v = (v << 3) | x - } - s = s[2:] - if v > 255 { - err = ErrSyntax - return - } - value = v - case '\\': - value = '\\' - case '\'', '"': - if c != quote { - err = ErrSyntax - return - } - value = rune(c) - default: - err = ErrSyntax - return - } - tail = s - return -} diff --git a/vendor/github.com/hashicorp/hcl/hcl/token/position.go b/vendor/github.com/hashicorp/hcl/hcl/token/position.go deleted file mode 100644 index 59c1bb72d..000000000 --- a/vendor/github.com/hashicorp/hcl/hcl/token/position.go +++ /dev/null @@ -1,46 +0,0 @@ -package token - -import "fmt" - -// Pos describes an arbitrary source position -// including the file, line, and column location. -// A Position is valid if the line number is > 0. -type Pos struct { - Filename string // filename, if any - Offset int // offset, starting at 0 - Line int // line number, starting at 1 - Column int // column number, starting at 1 (character count) -} - -// IsValid returns true if the position is valid. -func (p *Pos) IsValid() bool { return p.Line > 0 } - -// String returns a string in one of several forms: -// -// file:line:column valid position with file name -// line:column valid position without file name -// file invalid position with file name -// - invalid position without file name -func (p Pos) String() string { - s := p.Filename - if p.IsValid() { - if s != "" { - s += ":" - } - s += fmt.Sprintf("%d:%d", p.Line, p.Column) - } - if s == "" { - s = "-" - } - return s -} - -// Before reports whether the position p is before u. -func (p Pos) Before(u Pos) bool { - return u.Offset > p.Offset || u.Line > p.Line -} - -// After reports whether the position p is after u. -func (p Pos) After(u Pos) bool { - return u.Offset < p.Offset || u.Line < p.Line -} diff --git a/vendor/github.com/hashicorp/hcl/hcl/token/token.go b/vendor/github.com/hashicorp/hcl/hcl/token/token.go deleted file mode 100644 index e37c0664e..000000000 --- a/vendor/github.com/hashicorp/hcl/hcl/token/token.go +++ /dev/null @@ -1,219 +0,0 @@ -// Package token defines constants representing the lexical tokens for HCL -// (HashiCorp Configuration Language) -package token - -import ( - "fmt" - "strconv" - "strings" - - hclstrconv "github.com/hashicorp/hcl/hcl/strconv" -) - -// Token defines a single HCL token which can be obtained via the Scanner -type Token struct { - Type Type - Pos Pos - Text string - JSON bool -} - -// Type is the set of lexical tokens of the HCL (HashiCorp Configuration Language) -type Type int - -const ( - // Special tokens - ILLEGAL Type = iota - EOF - COMMENT - - identifier_beg - IDENT // literals - literal_beg - NUMBER // 12345 - FLOAT // 123.45 - BOOL // true,false - STRING // "abc" - HEREDOC // < 0 { - // Pop the current item - n := len(frontier) - item := frontier[n-1] - frontier = frontier[:n-1] - - switch v := item.Val.(type) { - case *ast.ObjectType: - items, frontier = flattenObjectType(v, item, items, frontier) - case *ast.ListType: - items, frontier = flattenListType(v, item, items, frontier) - default: - items = append(items, item) - } - } - - // Reverse the list since the frontier model runs things backwards - for i := len(items)/2 - 1; i >= 0; i-- { - opp := len(items) - 1 - i - items[i], items[opp] = items[opp], items[i] - } - - // Done! Set the original items - list.Items = items - return n, true - }) -} - -func flattenListType( - ot *ast.ListType, - item *ast.ObjectItem, - items []*ast.ObjectItem, - frontier []*ast.ObjectItem) ([]*ast.ObjectItem, []*ast.ObjectItem) { - // If the list is empty, keep the original list - if len(ot.List) == 0 { - items = append(items, item) - return items, frontier - } - - // All the elements of this object must also be objects! - for _, subitem := range ot.List { - if _, ok := subitem.(*ast.ObjectType); !ok { - items = append(items, item) - return items, frontier - } - } - - // Great! We have a match go through all the items and flatten - for _, elem := range ot.List { - // Add it to the frontier so that we can recurse - frontier = append(frontier, &ast.ObjectItem{ - Keys: item.Keys, - Assign: item.Assign, - Val: elem, - LeadComment: item.LeadComment, - LineComment: item.LineComment, - }) - } - - return items, frontier -} - -func flattenObjectType( - ot *ast.ObjectType, - item *ast.ObjectItem, - items []*ast.ObjectItem, - frontier []*ast.ObjectItem) ([]*ast.ObjectItem, []*ast.ObjectItem) { - // If the list has no items we do not have to flatten anything - if ot.List.Items == nil { - items = append(items, item) - return items, frontier - } - - // All the elements of this object must also be objects! - for _, subitem := range ot.List.Items { - if _, ok := subitem.Val.(*ast.ObjectType); !ok { - items = append(items, item) - return items, frontier - } - } - - // Great! We have a match go through all the items and flatten - for _, subitem := range ot.List.Items { - // Copy the new key - keys := make([]*ast.ObjectKey, len(item.Keys)+len(subitem.Keys)) - copy(keys, item.Keys) - copy(keys[len(item.Keys):], subitem.Keys) - - // Add it to the frontier so that we can recurse - frontier = append(frontier, &ast.ObjectItem{ - Keys: keys, - Assign: item.Assign, - Val: subitem.Val, - LeadComment: item.LeadComment, - LineComment: item.LineComment, - }) - } - - return items, frontier -} diff --git a/vendor/github.com/hashicorp/hcl/json/parser/parser.go b/vendor/github.com/hashicorp/hcl/json/parser/parser.go deleted file mode 100644 index 125a5f072..000000000 --- a/vendor/github.com/hashicorp/hcl/json/parser/parser.go +++ /dev/null @@ -1,313 +0,0 @@ -package parser - -import ( - "errors" - "fmt" - - "github.com/hashicorp/hcl/hcl/ast" - hcltoken "github.com/hashicorp/hcl/hcl/token" - "github.com/hashicorp/hcl/json/scanner" - "github.com/hashicorp/hcl/json/token" -) - -type Parser struct { - sc *scanner.Scanner - - // Last read token - tok token.Token - commaPrev token.Token - - enableTrace bool - indent int - n int // buffer size (max = 1) -} - -func newParser(src []byte) *Parser { - return &Parser{ - sc: scanner.New(src), - } -} - -// Parse returns the fully parsed source and returns the abstract syntax tree. -func Parse(src []byte) (*ast.File, error) { - p := newParser(src) - return p.Parse() -} - -var errEofToken = errors.New("EOF token found") - -// Parse returns the fully parsed source and returns the abstract syntax tree. -func (p *Parser) Parse() (*ast.File, error) { - f := &ast.File{} - var err, scerr error - p.sc.Error = func(pos token.Pos, msg string) { - scerr = fmt.Errorf("%s: %s", pos, msg) - } - - // The root must be an object in JSON - object, err := p.object() - if scerr != nil { - return nil, scerr - } - if err != nil { - return nil, err - } - - // We make our final node an object list so it is more HCL compatible - f.Node = object.List - - // Flatten it, which finds patterns and turns them into more HCL-like - // AST trees. - flattenObjects(f.Node) - - return f, nil -} - -func (p *Parser) objectList() (*ast.ObjectList, error) { - defer un(trace(p, "ParseObjectList")) - node := &ast.ObjectList{} - - for { - n, err := p.objectItem() - if err == errEofToken { - break // we are finished - } - - // we don't return a nil node, because might want to use already - // collected items. - if err != nil { - return node, err - } - - node.Add(n) - - // Check for a followup comma. If it isn't a comma, then we're done - if tok := p.scan(); tok.Type != token.COMMA { - break - } - } - - return node, nil -} - -// objectItem parses a single object item -func (p *Parser) objectItem() (*ast.ObjectItem, error) { - defer un(trace(p, "ParseObjectItem")) - - keys, err := p.objectKey() - if err != nil { - return nil, err - } - - o := &ast.ObjectItem{ - Keys: keys, - } - - switch p.tok.Type { - case token.COLON: - pos := p.tok.Pos - o.Assign = hcltoken.Pos{ - Filename: pos.Filename, - Offset: pos.Offset, - Line: pos.Line, - Column: pos.Column, - } - - o.Val, err = p.objectValue() - if err != nil { - return nil, err - } - } - - return o, nil -} - -// objectKey parses an object key and returns a ObjectKey AST -func (p *Parser) objectKey() ([]*ast.ObjectKey, error) { - keyCount := 0 - keys := make([]*ast.ObjectKey, 0) - - for { - tok := p.scan() - switch tok.Type { - case token.EOF: - return nil, errEofToken - case token.STRING: - keyCount++ - keys = append(keys, &ast.ObjectKey{ - Token: p.tok.HCLToken(), - }) - case token.COLON: - // If we have a zero keycount it means that we never got - // an object key, i.e. `{ :`. This is a syntax error. - if keyCount == 0 { - return nil, fmt.Errorf("expected: STRING got: %s", p.tok.Type) - } - - // Done - return keys, nil - case token.ILLEGAL: - return nil, errors.New("illegal") - default: - return nil, fmt.Errorf("expected: STRING got: %s", p.tok.Type) - } - } -} - -// object parses any type of object, such as number, bool, string, object or -// list. -func (p *Parser) objectValue() (ast.Node, error) { - defer un(trace(p, "ParseObjectValue")) - tok := p.scan() - - switch tok.Type { - case token.NUMBER, token.FLOAT, token.BOOL, token.NULL, token.STRING: - return p.literalType() - case token.LBRACE: - return p.objectType() - case token.LBRACK: - return p.listType() - case token.EOF: - return nil, errEofToken - } - - return nil, fmt.Errorf("Expected object value, got unknown token: %+v", tok) -} - -// object parses any type of object, such as number, bool, string, object or -// list. -func (p *Parser) object() (*ast.ObjectType, error) { - defer un(trace(p, "ParseType")) - tok := p.scan() - - switch tok.Type { - case token.LBRACE: - return p.objectType() - case token.EOF: - return nil, errEofToken - } - - return nil, fmt.Errorf("Expected object, got unknown token: %+v", tok) -} - -// objectType parses an object type and returns a ObjectType AST -func (p *Parser) objectType() (*ast.ObjectType, error) { - defer un(trace(p, "ParseObjectType")) - - // we assume that the currently scanned token is a LBRACE - o := &ast.ObjectType{} - - l, err := p.objectList() - - // if we hit RBRACE, we are good to go (means we parsed all Items), if it's - // not a RBRACE, it's an syntax error and we just return it. - if err != nil && p.tok.Type != token.RBRACE { - return nil, err - } - - o.List = l - return o, nil -} - -// listType parses a list type and returns a ListType AST -func (p *Parser) listType() (*ast.ListType, error) { - defer un(trace(p, "ParseListType")) - - // we assume that the currently scanned token is a LBRACK - l := &ast.ListType{} - - for { - tok := p.scan() - switch tok.Type { - case token.NUMBER, token.FLOAT, token.STRING: - node, err := p.literalType() - if err != nil { - return nil, err - } - - l.Add(node) - case token.COMMA: - continue - case token.LBRACE: - node, err := p.objectType() - if err != nil { - return nil, err - } - - l.Add(node) - case token.BOOL: - // TODO(arslan) should we support? not supported by HCL yet - case token.LBRACK: - // TODO(arslan) should we support nested lists? Even though it's - // written in README of HCL, it's not a part of the grammar - // (not defined in parse.y) - case token.RBRACK: - // finished - return l, nil - default: - return nil, fmt.Errorf("unexpected token while parsing list: %s", tok.Type) - } - - } -} - -// literalType parses a literal type and returns a LiteralType AST -func (p *Parser) literalType() (*ast.LiteralType, error) { - defer un(trace(p, "ParseLiteral")) - - return &ast.LiteralType{ - Token: p.tok.HCLToken(), - }, nil -} - -// scan returns the next token from the underlying scanner. If a token has -// been unscanned then read that instead. -func (p *Parser) scan() token.Token { - // If we have a token on the buffer, then return it. - if p.n != 0 { - p.n = 0 - return p.tok - } - - p.tok = p.sc.Scan() - return p.tok -} - -// unscan pushes the previously read token back onto the buffer. -func (p *Parser) unscan() { - p.n = 1 -} - -// ---------------------------------------------------------------------------- -// Parsing support - -func (p *Parser) printTrace(a ...interface{}) { - if !p.enableTrace { - return - } - - const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " - const n = len(dots) - fmt.Printf("%5d:%3d: ", p.tok.Pos.Line, p.tok.Pos.Column) - - i := 2 * p.indent - for i > n { - fmt.Print(dots) - i -= n - } - // i <= n - fmt.Print(dots[0:i]) - fmt.Println(a...) -} - -func trace(p *Parser, msg string) *Parser { - p.printTrace(msg, "(") - p.indent++ - return p -} - -// Usage pattern: defer un(trace(p, "...")) -func un(p *Parser) { - p.indent-- - p.printTrace(")") -} diff --git a/vendor/github.com/hashicorp/hcl/json/scanner/scanner.go b/vendor/github.com/hashicorp/hcl/json/scanner/scanner.go deleted file mode 100644 index fe3f0f095..000000000 --- a/vendor/github.com/hashicorp/hcl/json/scanner/scanner.go +++ /dev/null @@ -1,451 +0,0 @@ -package scanner - -import ( - "bytes" - "fmt" - "os" - "unicode" - "unicode/utf8" - - "github.com/hashicorp/hcl/json/token" -) - -// eof represents a marker rune for the end of the reader. -const eof = rune(0) - -// Scanner defines a lexical scanner -type Scanner struct { - buf *bytes.Buffer // Source buffer for advancing and scanning - src []byte // Source buffer for immutable access - - // Source Position - srcPos token.Pos // current position - prevPos token.Pos // previous position, used for peek() method - - lastCharLen int // length of last character in bytes - lastLineLen int // length of last line in characters (for correct column reporting) - - tokStart int // token text start position - tokEnd int // token text end position - - // Error is called for each error encountered. If no Error - // function is set, the error is reported to os.Stderr. - Error func(pos token.Pos, msg string) - - // ErrorCount is incremented by one for each error encountered. - ErrorCount int - - // tokPos is the start position of most recently scanned token; set by - // Scan. The Filename field is always left untouched by the Scanner. If - // an error is reported (via Error) and Position is invalid, the scanner is - // not inside a token. - tokPos token.Pos -} - -// New creates and initializes a new instance of Scanner using src as -// its source content. -func New(src []byte) *Scanner { - // even though we accept a src, we read from a io.Reader compatible type - // (*bytes.Buffer). So in the future we might easily change it to streaming - // read. - b := bytes.NewBuffer(src) - s := &Scanner{ - buf: b, - src: src, - } - - // srcPosition always starts with 1 - s.srcPos.Line = 1 - return s -} - -// next reads the next rune from the bufferred reader. Returns the rune(0) if -// an error occurs (or io.EOF is returned). -func (s *Scanner) next() rune { - ch, size, err := s.buf.ReadRune() - if err != nil { - // advance for error reporting - s.srcPos.Column++ - s.srcPos.Offset += size - s.lastCharLen = size - return eof - } - - if ch == utf8.RuneError && size == 1 { - s.srcPos.Column++ - s.srcPos.Offset += size - s.lastCharLen = size - s.err("illegal UTF-8 encoding") - return ch - } - - // remember last position - s.prevPos = s.srcPos - - s.srcPos.Column++ - s.lastCharLen = size - s.srcPos.Offset += size - - if ch == '\n' { - s.srcPos.Line++ - s.lastLineLen = s.srcPos.Column - s.srcPos.Column = 0 - } - - // debug - // fmt.Printf("ch: %q, offset:column: %d:%d\n", ch, s.srcPos.Offset, s.srcPos.Column) - return ch -} - -// unread unreads the previous read Rune and updates the source position -func (s *Scanner) unread() { - if err := s.buf.UnreadRune(); err != nil { - panic(err) // this is user fault, we should catch it - } - s.srcPos = s.prevPos // put back last position -} - -// peek returns the next rune without advancing the reader. -func (s *Scanner) peek() rune { - peek, _, err := s.buf.ReadRune() - if err != nil { - return eof - } - - s.buf.UnreadRune() - return peek -} - -// Scan scans the next token and returns the token. -func (s *Scanner) Scan() token.Token { - ch := s.next() - - // skip white space - for isWhitespace(ch) { - ch = s.next() - } - - var tok token.Type - - // token text markings - s.tokStart = s.srcPos.Offset - s.lastCharLen - - // token position, initial next() is moving the offset by one(size of rune - // actually), though we are interested with the starting point - s.tokPos.Offset = s.srcPos.Offset - s.lastCharLen - if s.srcPos.Column > 0 { - // common case: last character was not a '\n' - s.tokPos.Line = s.srcPos.Line - s.tokPos.Column = s.srcPos.Column - } else { - // last character was a '\n' - // (we cannot be at the beginning of the source - // since we have called next() at least once) - s.tokPos.Line = s.srcPos.Line - 1 - s.tokPos.Column = s.lastLineLen - } - - switch { - case isLetter(ch): - lit := s.scanIdentifier() - if lit == "true" || lit == "false" { - tok = token.BOOL - } else if lit == "null" { - tok = token.NULL - } else { - s.err("illegal char") - } - case isDecimal(ch): - tok = s.scanNumber(ch) - default: - switch ch { - case eof: - tok = token.EOF - case '"': - tok = token.STRING - s.scanString() - case '.': - tok = token.PERIOD - ch = s.peek() - if isDecimal(ch) { - tok = token.FLOAT - ch = s.scanMantissa(ch) - ch = s.scanExponent(ch) - } - case '[': - tok = token.LBRACK - case ']': - tok = token.RBRACK - case '{': - tok = token.LBRACE - case '}': - tok = token.RBRACE - case ',': - tok = token.COMMA - case ':': - tok = token.COLON - case '-': - if isDecimal(s.peek()) { - ch := s.next() - tok = s.scanNumber(ch) - } else { - s.err("illegal char") - } - default: - s.err("illegal char: " + string(ch)) - } - } - - // finish token ending - s.tokEnd = s.srcPos.Offset - - // create token literal - var tokenText string - if s.tokStart >= 0 { - tokenText = string(s.src[s.tokStart:s.tokEnd]) - } - s.tokStart = s.tokEnd // ensure idempotency of tokenText() call - - return token.Token{ - Type: tok, - Pos: s.tokPos, - Text: tokenText, - } -} - -// scanNumber scans a HCL number definition starting with the given rune -func (s *Scanner) scanNumber(ch rune) token.Type { - zero := ch == '0' - pos := s.srcPos - - s.scanMantissa(ch) - ch = s.next() // seek forward - if ch == 'e' || ch == 'E' { - ch = s.scanExponent(ch) - return token.FLOAT - } - - if ch == '.' { - ch = s.scanFraction(ch) - if ch == 'e' || ch == 'E' { - ch = s.next() - ch = s.scanExponent(ch) - } - return token.FLOAT - } - - if ch != eof { - s.unread() - } - - // If we have a larger number and this is zero, error - if zero && pos != s.srcPos { - s.err("numbers cannot start with 0") - } - - return token.NUMBER -} - -// scanMantissa scans the mantissa beginning from the rune. It returns the next -// non decimal rune. It's used to determine wheter it's a fraction or exponent. -func (s *Scanner) scanMantissa(ch rune) rune { - scanned := false - for isDecimal(ch) { - ch = s.next() - scanned = true - } - - if scanned && ch != eof { - s.unread() - } - return ch -} - -// scanFraction scans the fraction after the '.' rune -func (s *Scanner) scanFraction(ch rune) rune { - if ch == '.' { - ch = s.peek() // we peek just to see if we can move forward - ch = s.scanMantissa(ch) - } - return ch -} - -// scanExponent scans the remaining parts of an exponent after the 'e' or 'E' -// rune. -func (s *Scanner) scanExponent(ch rune) rune { - if ch == 'e' || ch == 'E' { - ch = s.next() - if ch == '-' || ch == '+' { - ch = s.next() - } - ch = s.scanMantissa(ch) - } - return ch -} - -// scanString scans a quoted string -func (s *Scanner) scanString() { - braces := 0 - for { - // '"' opening already consumed - // read character after quote - ch := s.next() - - if ch == '\n' || ch < 0 || ch == eof { - s.err("literal not terminated") - return - } - - if ch == '"' { - break - } - - // If we're going into a ${} then we can ignore quotes for awhile - if braces == 0 && ch == '$' && s.peek() == '{' { - braces++ - s.next() - } else if braces > 0 && ch == '{' { - braces++ - } - if braces > 0 && ch == '}' { - braces-- - } - - if ch == '\\' { - s.scanEscape() - } - } - - return -} - -// scanEscape scans an escape sequence -func (s *Scanner) scanEscape() rune { - // http://en.cppreference.com/w/cpp/language/escape - ch := s.next() // read character after '/' - switch ch { - case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '"': - // nothing to do - case '0', '1', '2', '3', '4', '5', '6', '7': - // octal notation - ch = s.scanDigits(ch, 8, 3) - case 'x': - // hexademical notation - ch = s.scanDigits(s.next(), 16, 2) - case 'u': - // universal character name - ch = s.scanDigits(s.next(), 16, 4) - case 'U': - // universal character name - ch = s.scanDigits(s.next(), 16, 8) - default: - s.err("illegal char escape") - } - return ch -} - -// scanDigits scans a rune with the given base for n times. For example an -// octal notation \184 would yield in scanDigits(ch, 8, 3) -func (s *Scanner) scanDigits(ch rune, base, n int) rune { - for n > 0 && digitVal(ch) < base { - ch = s.next() - n-- - } - if n > 0 { - s.err("illegal char escape") - } - - // we scanned all digits, put the last non digit char back - s.unread() - return ch -} - -// scanIdentifier scans an identifier and returns the literal string -func (s *Scanner) scanIdentifier() string { - offs := s.srcPos.Offset - s.lastCharLen - ch := s.next() - for isLetter(ch) || isDigit(ch) || ch == '-' { - ch = s.next() - } - - if ch != eof { - s.unread() // we got identifier, put back latest char - } - - return string(s.src[offs:s.srcPos.Offset]) -} - -// recentPosition returns the position of the character immediately after the -// character or token returned by the last call to Scan. -func (s *Scanner) recentPosition() (pos token.Pos) { - pos.Offset = s.srcPos.Offset - s.lastCharLen - switch { - case s.srcPos.Column > 0: - // common case: last character was not a '\n' - pos.Line = s.srcPos.Line - pos.Column = s.srcPos.Column - case s.lastLineLen > 0: - // last character was a '\n' - // (we cannot be at the beginning of the source - // since we have called next() at least once) - pos.Line = s.srcPos.Line - 1 - pos.Column = s.lastLineLen - default: - // at the beginning of the source - pos.Line = 1 - pos.Column = 1 - } - return -} - -// err prints the error of any scanning to s.Error function. If the function is -// not defined, by default it prints them to os.Stderr -func (s *Scanner) err(msg string) { - s.ErrorCount++ - pos := s.recentPosition() - - if s.Error != nil { - s.Error(pos, msg) - return - } - - fmt.Fprintf(os.Stderr, "%s: %s\n", pos, msg) -} - -// isHexadecimal returns true if the given rune is a letter -func isLetter(ch rune) bool { - return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch) -} - -// isHexadecimal returns true if the given rune is a decimal digit -func isDigit(ch rune) bool { - return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch) -} - -// isHexadecimal returns true if the given rune is a decimal number -func isDecimal(ch rune) bool { - return '0' <= ch && ch <= '9' -} - -// isHexadecimal returns true if the given rune is an hexadecimal number -func isHexadecimal(ch rune) bool { - return '0' <= ch && ch <= '9' || 'a' <= ch && ch <= 'f' || 'A' <= ch && ch <= 'F' -} - -// isWhitespace returns true if the rune is a space, tab, newline or carriage return -func isWhitespace(ch rune) bool { - return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' -} - -// digitVal returns the integer value of a given octal,decimal or hexadecimal rune -func digitVal(ch rune) int { - switch { - case '0' <= ch && ch <= '9': - return int(ch - '0') - case 'a' <= ch && ch <= 'f': - return int(ch - 'a' + 10) - case 'A' <= ch && ch <= 'F': - return int(ch - 'A' + 10) - } - return 16 // larger than any legal digit val -} diff --git a/vendor/github.com/hashicorp/hcl/json/token/position.go b/vendor/github.com/hashicorp/hcl/json/token/position.go deleted file mode 100644 index 59c1bb72d..000000000 --- a/vendor/github.com/hashicorp/hcl/json/token/position.go +++ /dev/null @@ -1,46 +0,0 @@ -package token - -import "fmt" - -// Pos describes an arbitrary source position -// including the file, line, and column location. -// A Position is valid if the line number is > 0. -type Pos struct { - Filename string // filename, if any - Offset int // offset, starting at 0 - Line int // line number, starting at 1 - Column int // column number, starting at 1 (character count) -} - -// IsValid returns true if the position is valid. -func (p *Pos) IsValid() bool { return p.Line > 0 } - -// String returns a string in one of several forms: -// -// file:line:column valid position with file name -// line:column valid position without file name -// file invalid position with file name -// - invalid position without file name -func (p Pos) String() string { - s := p.Filename - if p.IsValid() { - if s != "" { - s += ":" - } - s += fmt.Sprintf("%d:%d", p.Line, p.Column) - } - if s == "" { - s = "-" - } - return s -} - -// Before reports whether the position p is before u. -func (p Pos) Before(u Pos) bool { - return u.Offset > p.Offset || u.Line > p.Line -} - -// After reports whether the position p is after u. -func (p Pos) After(u Pos) bool { - return u.Offset < p.Offset || u.Line < p.Line -} diff --git a/vendor/github.com/hashicorp/hcl/json/token/token.go b/vendor/github.com/hashicorp/hcl/json/token/token.go deleted file mode 100644 index 95a0c3eee..000000000 --- a/vendor/github.com/hashicorp/hcl/json/token/token.go +++ /dev/null @@ -1,118 +0,0 @@ -package token - -import ( - "fmt" - "strconv" - - hcltoken "github.com/hashicorp/hcl/hcl/token" -) - -// Token defines a single HCL token which can be obtained via the Scanner -type Token struct { - Type Type - Pos Pos - Text string -} - -// Type is the set of lexical tokens of the HCL (HashiCorp Configuration Language) -type Type int - -const ( - // Special tokens - ILLEGAL Type = iota - EOF - - identifier_beg - literal_beg - NUMBER // 12345 - FLOAT // 123.45 - BOOL // true,false - STRING // "abc" - NULL // null - literal_end - identifier_end - - operator_beg - LBRACK // [ - LBRACE // { - COMMA // , - PERIOD // . - COLON // : - - RBRACK // ] - RBRACE // } - - operator_end -) - -var tokens = [...]string{ - ILLEGAL: "ILLEGAL", - - EOF: "EOF", - - NUMBER: "NUMBER", - FLOAT: "FLOAT", - BOOL: "BOOL", - STRING: "STRING", - NULL: "NULL", - - LBRACK: "LBRACK", - LBRACE: "LBRACE", - COMMA: "COMMA", - PERIOD: "PERIOD", - COLON: "COLON", - - RBRACK: "RBRACK", - RBRACE: "RBRACE", -} - -// String returns the string corresponding to the token tok. -func (t Type) String() string { - s := "" - if 0 <= t && t < Type(len(tokens)) { - s = tokens[t] - } - if s == "" { - s = "token(" + strconv.Itoa(int(t)) + ")" - } - return s -} - -// IsIdentifier returns true for tokens corresponding to identifiers and basic -// type literals; it returns false otherwise. -func (t Type) IsIdentifier() bool { return identifier_beg < t && t < identifier_end } - -// IsLiteral returns true for tokens corresponding to basic type literals; it -// returns false otherwise. -func (t Type) IsLiteral() bool { return literal_beg < t && t < literal_end } - -// IsOperator returns true for tokens corresponding to operators and -// delimiters; it returns false otherwise. -func (t Type) IsOperator() bool { return operator_beg < t && t < operator_end } - -// String returns the token's literal text. Note that this is only -// applicable for certain token types, such as token.IDENT, -// token.STRING, etc.. -func (t Token) String() string { - return fmt.Sprintf("%s %s %s", t.Pos.String(), t.Type.String(), t.Text) -} - -// HCLToken converts this token to an HCL token. -// -// The token type must be a literal type or this will panic. -func (t Token) HCLToken() hcltoken.Token { - switch t.Type { - case BOOL: - return hcltoken.Token{Type: hcltoken.BOOL, Text: t.Text} - case FLOAT: - return hcltoken.Token{Type: hcltoken.FLOAT, Text: t.Text} - case NULL: - return hcltoken.Token{Type: hcltoken.STRING, Text: ""} - case NUMBER: - return hcltoken.Token{Type: hcltoken.NUMBER, Text: t.Text} - case STRING: - return hcltoken.Token{Type: hcltoken.STRING, Text: t.Text, JSON: true} - default: - panic(fmt.Sprintf("unimplemented HCLToken for type: %s", t.Type)) - } -} diff --git a/vendor/github.com/hashicorp/hcl/lex.go b/vendor/github.com/hashicorp/hcl/lex.go deleted file mode 100644 index d9993c292..000000000 --- a/vendor/github.com/hashicorp/hcl/lex.go +++ /dev/null @@ -1,38 +0,0 @@ -package hcl - -import ( - "unicode" - "unicode/utf8" -) - -type lexModeValue byte - -const ( - lexModeUnknown lexModeValue = iota - lexModeHcl - lexModeJson -) - -// lexMode returns whether we're going to be parsing in JSON -// mode or HCL mode. -func lexMode(v []byte) lexModeValue { - var ( - r rune - w int - offset int - ) - - for { - r, w = utf8.DecodeRune(v[offset:]) - offset += w - if unicode.IsSpace(r) { - continue - } - if r == '{' { - return lexModeJson - } - break - } - - return lexModeHcl -} diff --git a/vendor/github.com/hashicorp/hcl/parse.go b/vendor/github.com/hashicorp/hcl/parse.go deleted file mode 100644 index 1fca53c4c..000000000 --- a/vendor/github.com/hashicorp/hcl/parse.go +++ /dev/null @@ -1,39 +0,0 @@ -package hcl - -import ( - "fmt" - - "github.com/hashicorp/hcl/hcl/ast" - hclParser "github.com/hashicorp/hcl/hcl/parser" - jsonParser "github.com/hashicorp/hcl/json/parser" -) - -// ParseBytes accepts as input byte slice and returns ast tree. -// -// Input can be either JSON or HCL -func ParseBytes(in []byte) (*ast.File, error) { - return parse(in) -} - -// ParseString accepts input as a string and returns ast tree. -func ParseString(input string) (*ast.File, error) { - return parse([]byte(input)) -} - -func parse(in []byte) (*ast.File, error) { - switch lexMode(in) { - case lexModeHcl: - return hclParser.Parse(in) - case lexModeJson: - return jsonParser.Parse(in) - } - - return nil, fmt.Errorf("unknown config format") -} - -// Parse parses the given input and returns the root object. -// -// The input format can be either HCL or JSON. -func Parse(input string) (*ast.File, error) { - return parse([]byte(input)) -} diff --git a/vendor/github.com/jgautheron/goconst/.gitignore b/vendor/github.com/jgautheron/goconst/.gitignore new file mode 100644 index 000000000..38dc761f1 --- /dev/null +++ b/vendor/github.com/jgautheron/goconst/.gitignore @@ -0,0 +1 @@ +/goconst diff --git a/vendor/github.com/jgautheron/goconst/README.md b/vendor/github.com/jgautheron/goconst/README.md index c671eb541..727974d00 100644 --- a/vendor/github.com/jgautheron/goconst/README.md +++ b/vendor/github.com/jgautheron/goconst/README.md @@ -10,7 +10,7 @@ While this could be considered a beginner mistake, across time, multiple package ### Get Started - $ go get github.com/jgautheron/goconst/cmd/goconst + $ go install github.com/jgautheron/goconst/cmd/goconst@latest $ goconst ./... ### Usage @@ -18,21 +18,24 @@ While this could be considered a beginner mistake, across time, multiple package ``` Usage: - goconst ARGS + goconst ARGS [...] Flags: -ignore exclude files matching the given regular expression - -ignore-strings exclude strings matching the given regular expression + -ignore-strings exclude strings matching the given regular expression -ignore-tests exclude tests from the search (default: true) -min-occurrences report from how many occurrences (default: 2) -min-length only report strings with the minimum given length (default: 3) - -match-constant look for existing constants matching the values + -match-constant look for existing constants matching the strings + -find-duplicates look for constants with identical values + -eval-const-expr enable evaluation of constant expressions (e.g., Prefix + "suffix") -numbers search also for duplicated numbers - -min minimum value, only works with -numbers - -max maximum value, only works with -numbers + -min minimum value, only works with -numbers + -max maximum value, only works with -numbers -output output formatting (text or json) -set-exit-status Set exit status to 2 if any issues are found + -grouped print single line per match, only works with -output text Examples: @@ -40,12 +43,47 @@ Examples: goconst -ignore "yacc|\.pb\." $GOPATH/src/github.com/cockroachdb/cockroach/... goconst -min-occurrences 3 -output json $GOPATH/src/github.com/cockroachdb/cockroach goconst -numbers -min 60 -max 512 . + goconst -min-occurrences 5 $(go list -m -f '{{.Dir}}') + goconst -eval-const-expr -match-constant . # Matches constant expressions like Prefix + "suffix" ``` +### Development + +#### Running Tests + +The project includes a comprehensive test suite. To run the tests: + +```bash +# Run all tests +go test ./... + +# Run tests with verbose output +go test -v ./... + +# Run tests with race detector +go test -race ./... + +# Run benchmarks +go test -bench=. ./... + +# Check test coverage +go test -cover ./... +``` + +#### Contributing + +Contributions are welcome! Before submitting a PR: + +1. Make sure all tests pass +2. Add tests for new functionality +3. Ensure your code passes linting checks +4. Update documentation as needed + ### Other static analysis tools - [gogetimports](https://github.com/jgautheron/gogetimports): Get a JSON-formatted list of imports. - [usedexports](https://github.com/jgautheron/usedexports): Find exported variables that could be unexported. ### License + MIT diff --git a/vendor/github.com/jgautheron/goconst/api.go b/vendor/github.com/jgautheron/goconst/api.go index b838e035f..10cece151 100644 --- a/vendor/github.com/jgautheron/goconst/api.go +++ b/vendor/github.com/jgautheron/goconst/api.go @@ -3,74 +3,253 @@ package goconst import ( "go/ast" "go/token" + "go/types" + "sort" "strings" + "sync" ) +// Issue represents a finding of duplicated strings, numbers, or constants. +// Each Issue includes the position where it was found, how many times it occurs, +// the string itself, and any matching constant name. type Issue struct { Pos token.Position OccurrencesCount int Str string MatchingConst string + DuplicateConst string + DuplicatePos token.Position } +// Config contains all configuration options for the goconst analyzer. type Config struct { - IgnoreStrings string - IgnoreTests bool + // IgnoreStrings is a list of regular expressions to filter strings + IgnoreStrings []string + // IgnoreTests indicates whether test files should be excluded + IgnoreTests bool + // MatchWithConstants enables matching strings with existing constants MatchWithConstants bool - MinStringLength int - MinOccurrences int - ParseNumbers bool - NumberMin int - NumberMax int - ExcludeTypes map[Type]bool + // MinStringLength is the minimum length a string must have to be reported + MinStringLength int + // MinOccurrences is the minimum number of occurrences required to report a string + MinOccurrences int + // ParseNumbers enables detection of duplicated numbers + ParseNumbers bool + // NumberMin sets the minimum value for reported number matches + NumberMin int + // NumberMax sets the maximum value for reported number matches + NumberMax int + // ExcludeTypes allows excluding specific types of contexts + ExcludeTypes map[Type]bool + // FindDuplicates enables finding constants whose values match existing constants in other packages. + FindDuplicates bool + // EvalConstExpressions enables evaluation of constant expressions like Prefix + "suffix" + EvalConstExpressions bool } -func Run(files []*ast.File, fset *token.FileSet, cfg *Config) ([]Issue, error) { - p := New( +// NewWithIgnorePatterns creates a new instance of the parser with support for multiple ignore patterns. +// This is an alternative constructor that takes a slice of ignore string patterns. +func NewWithIgnorePatterns( + path, ignore string, + ignoreStrings []string, + ignoreTests, matchConstant, numbers, findDuplicates, evalConstExpressions bool, + numberMin, numberMax, minLength, minOccurrences int, + excludeTypes map[Type]bool) *Parser { + + // Join multiple patterns with OR for regex + var ignoreStringsPattern string + if len(ignoreStrings) > 0 { + if len(ignoreStrings) > 1 { + // Wrap each pattern in parentheses and join with OR + patterns := make([]string, len(ignoreStrings)) + for i, pattern := range ignoreStrings { + patterns[i] = "(" + pattern + ")" + } + ignoreStringsPattern = strings.Join(patterns, "|") + } else { + // Single pattern case + ignoreStringsPattern = ignoreStrings[0] + } + } + + return New( + path, + ignore, + ignoreStringsPattern, + ignoreTests, + matchConstant, + numbers, + findDuplicates, + evalConstExpressions, + numberMin, + numberMax, + minLength, + minOccurrences, + excludeTypes, + ) +} + +// RunWithConfig is a convenience function that runs the analysis with a Config object +// directly supporting multiple ignore patterns. +func RunWithConfig(files []*ast.File, fset *token.FileSet, typeInfo *types.Info, cfg *Config) ([]Issue, error) { + p := NewWithIgnorePatterns( "", "", cfg.IgnoreStrings, cfg.IgnoreTests, cfg.MatchWithConstants, cfg.ParseNumbers, + cfg.FindDuplicates, + cfg.EvalConstExpressions, cfg.NumberMin, cfg.NumberMax, cfg.MinStringLength, cfg.MinOccurrences, cfg.ExcludeTypes, ) - var issues []Issue + + // Pre-allocate slice based on estimated result size + expectedIssues := len(files) * 5 // Assuming average of 5 issues per file + if expectedIssues > 1000 { + expectedIssues = 1000 // Cap at reasonable maximum + } + + // Allocate a new buffer + issueBuffer := make([]Issue, 0, expectedIssues) + + // Process files concurrently + var wg sync.WaitGroup + sem := make(chan struct{}, p.maxConcurrency) + + // Create a filtered files slice with capacity hint + filteredFiles := make([]*ast.File, 0, len(files)) + + // Filter test files first if needed for _, f := range files { if p.ignoreTests { - if filename := fset.Position(f.Pos()).Filename; strings.HasSuffix(filename, testSuffix) { + if filename := fset.Position(f.Pos()).Filename; strings.HasSuffix(filename, "_test.go") { continue } } - ast.Walk(&treeVisitor{ - fileSet: fset, - packageName: "", - fileName: "", - p: p, - }, f) + filteredFiles = append(filteredFiles, f) } + + // Process each file in parallel + for _, f := range filteredFiles { + wg.Add(1) + sem <- struct{}{} // acquire semaphore + + go func(f *ast.File) { + defer func() { + <-sem // release semaphore + wg.Done() + }() + + // Use empty interned strings for package/file names + // The visitor logic will set these appropriately + emptyStr := InternString("") + + ast.Walk(&treeVisitor{ + fileSet: fset, + packageName: emptyStr, + p: p, + ignoreRegex: p.ignoreStringsRegex, + typeInfo: typeInfo, + }, f) + }(f) + } + + wg.Wait() + p.ProcessResults() - for str, item := range p.strs { - fi := item[0] - i := Issue{ + // Process each string that passed the filters + p.stringMutex.RLock() + p.stringCountMutex.RLock() + + // Create a slice to hold the string keys + stringKeys := make([]string, 0, len(p.strs)) + + // Create an array of strings to sort for stable output + for str := range p.strs { + if count := p.stringCount[str]; count >= p.minOccurrences { + stringKeys = append(stringKeys, str) + } + } + + sort.Strings(stringKeys) + + // Process strings in a predictable order for stable output + for _, str := range stringKeys { + positions := p.strs[str] + if len(positions) == 0 { + continue + } + + // Use the first position as representative + fi := positions[0] + + // Create issue using the counted value to avoid recounting + issue := Issue{ Pos: fi.Position, - OccurrencesCount: len(item), + OccurrencesCount: p.stringCount[str], Str: str, } - if len(p.consts) != 0 { - if cst, ok := p.consts[str]; ok { + // Check for matching constants + if len(p.consts) > 0 { + p.constMutex.RLock() + if csts, ok := p.consts[str]; ok && len(csts) > 0 { // const should be in the same package and exported - i.MatchingConst = cst.Name + issue.MatchingConst = csts[0].Name } + p.constMutex.RUnlock() + } + + issueBuffer = append(issueBuffer, issue) + } + + p.stringCountMutex.RUnlock() + p.stringMutex.RUnlock() + + // process duplicate constants + p.constMutex.RLock() + + // Create a new slice for const keys + stringKeys = make([]string, 0, len(p.consts)) + + // Create an array of strings and sort for stable output + for str := range p.consts { + if len(p.consts[str]) > 1 { + stringKeys = append(stringKeys, str) } - issues = append(issues, i) } - return issues, nil + sort.Strings(stringKeys) + + // report an issue for every duplicated const + for _, str := range stringKeys { + positions := p.consts[str] + + for i := 1; i < len(positions); i++ { + issueBuffer = append(issueBuffer, Issue{ + Pos: positions[i].Position, + Str: str, + DuplicateConst: positions[0].Name, + DuplicatePos: positions[0].Position, + }) + } + } + + p.constMutex.RUnlock() + + // Don't return the buffer to pool as the caller now owns it + return issueBuffer, nil +} + +// Run analyzes the provided AST files for duplicated strings or numbers +// according to the provided configuration. +// It returns a slice of Issue objects containing the findings. +func Run(files []*ast.File, fset *token.FileSet, typeInfo *types.Info, cfg *Config) ([]Issue, error) { + return RunWithConfig(files, fset, typeInfo, cfg) } diff --git a/vendor/github.com/jgautheron/goconst/parser.go b/vendor/github.com/jgautheron/goconst/parser.go index 2f32740b9..9505d463e 100644 --- a/vendor/github.com/jgautheron/goconst/parser.go +++ b/vendor/github.com/jgautheron/goconst/parser.go @@ -8,180 +8,877 @@ package goconst import ( "go/ast" + "go/constant" "go/parser" "go/token" + "go/types" + "io" "log" "os" "path/filepath" "regexp" + "runtime" "strconv" "strings" + "sync" ) +// StringBuilderPool is a pool of string builders to reduce memory allocations +var StringBuilderPool = sync.Pool{ + New: func() interface{} { + return new(strings.Builder) + }, +} + +// FileReaderPool is a pool of byte buffers used for reading files +var FileReaderPool = sync.Pool{ + New: func() interface{} { + // Start with a 32KB buffer, which is sufficient for most Go files + return make([]byte, 32*1024) + }, +} + +// ByteBufferPool is a pool for temporary byte slices +var ByteBufferPool = sync.Pool{ + New: func() interface{} { + slice := make([]byte, 0, 8*1024) + return &slice + }, +} + +// ExtendedPosPool is a pool for slices of ExtendedPos +var ExtendedPosPool = sync.Pool{ + New: func() interface{} { + slice := make([]ExtendedPos, 0, 8) + return &slice + }, +} + +// StringInternPool is a pool for deduplicating strings to reduce memory usage +var StringInternPool = sync.Map{} + +// InternString returns a deduplicated reference to the given string +// to reduce memory usage when the same string appears multiple times +func InternString(s string) string { + if s == "" { + return "" + } + + if interned, ok := StringInternPool.Load(s); ok { + return interned.(string) + } + // Store a copy to prevent external modifications + interned := string([]byte(s)) + StringInternPool.Store(interned, interned) + return interned +} + +// GetStringBuilder retrieves a string builder from the pool +func GetStringBuilder() *strings.Builder { + return StringBuilderPool.Get().(*strings.Builder) +} + +// PutStringBuilder returns a string builder to the pool after resetting it +func PutStringBuilder(sb *strings.Builder) { + sb.Reset() + StringBuilderPool.Put(sb) +} + +// GetByteBuffer retrieves a byte buffer from the pool +func GetByteBuffer() []byte { + return (*ByteBufferPool.Get().(*[]byte))[:0] // Reset length but keep capacity +} + +// PutByteBuffer returns a byte buffer to the pool +func PutByteBuffer(buf []byte) { + bufCopy := make([]byte, 0, cap(buf)) + ByteBufferPool.Put(&bufCopy) +} + +// GetExtendedPosBuffer retrieves an ExtendedPos slice from the pool +func GetExtendedPosBuffer() []ExtendedPos { + return (*ExtendedPosPool.Get().(*[]ExtendedPos))[:0] // Reset length but keep capacity +} + +// PutExtendedPosBuffer returns an ExtendedPos slice to the pool +func PutExtendedPosBuffer(slice []ExtendedPos) { + sliceCopy := make([]ExtendedPos, 0, cap(slice)) + ExtendedPosPool.Put(&sliceCopy) +} + const ( testSuffix = "_test.go" ) +// Parser represents the core analysis engine for finding repeated strings and constants. +// It holds both configuration options and the internal state during analysis. type Parser struct { // Meant to be passed via New() path, ignore, ignoreStrings string ignoreTests, matchConstant bool + findDuplicates bool minLength, minOccurrences int numberMin, numberMax int excludeTypes map[Type]bool + maxConcurrency int + evalConstExpressions bool // Whether to evaluate constant expressions supportedTokens []token.Token + supportedKinds []constant.Kind // Internals - strs Strings - consts Constants + strs Strings + consts Constants + stringMutex sync.RWMutex + constMutex sync.RWMutex + + // Pre-compiled regexes for efficiency + ignoreRegex *regexp.Regexp + ignoreStringsRegex *regexp.Regexp + + // String occurrence counter + // Using a separate counter map improves performance for + // tracking frequency without having to compute len(items) repeatedly + stringCount map[string]int + stringCountMutex sync.RWMutex + + // Batch processing options + batchSize int + enableBatching bool + + // FileSet cache to avoid creating multiple fileSets + fileSetCache *token.FileSet + fileSetMutex sync.Mutex } // New creates a new instance of the parser. // This is your entry point if you'd like to use goconst as an API. -func New(path, ignore, ignoreStrings string, ignoreTests, matchConstant, numbers bool, numberMin, numberMax, minLength, minOccurrences int, excludeTypes map[Type]bool) *Parser { +// +// Parameters: +// - path: the file or directory path to analyze +// - ignore: regex pattern to ignore files +// - ignoreStrings: regex pattern to ignore strings +// - ignoreTests: whether to ignore test files +// - matchConstant: whether to match strings with existing constants +// - numbers: whether to analyze number literals +// - findDuplicates: whether to find consts with duplicate values +// - evalConstExpressions: whether to evaluate constant expressions +// - numberMin/numberMax: range limits for number analysis +// - minLength: minimum string length to consider +// - minOccurrences: minimum occurrences to report +// - excludeTypes: map of context types to exclude +func New(path, ignore, ignoreStrings string, ignoreTests, matchConstant, numbers, findDuplicates, evalConstExpressions bool, numberMin, numberMax, minLength, minOccurrences int, excludeTypes map[Type]bool) *Parser { supportedTokens := []token.Token{token.STRING} + supportedKinds := []constant.Kind{constant.String} if numbers { supportedTokens = append(supportedTokens, token.INT, token.FLOAT) + supportedKinds = append(supportedKinds, constant.Complex, constant.Float, constant.Int) + } + + // Set default concurrency to number of CPUs + maxConcurrency := runtime.NumCPU() + + // Pre-compile regular expressions for efficiency + var ignoreRegex, ignoreStringsRegex *regexp.Regexp + var err error + + if ignore != "" { + ignoreRegex, err = regexp.Compile(ignore) + if err != nil { + log.Printf("Warning: Invalid ignore regex pattern '%s': %v", ignore, err) + } + } + + if ignoreStrings != "" { + ignoreStringsRegex, err = regexp.Compile(ignoreStrings) + if err != nil { + log.Printf("Warning: Invalid ignore-strings regex pattern '%s': %v", ignoreStrings, err) + } + } + + // Estimate capacity based on typical usage patterns + stringMapCapacity := 500 + constMapCapacity := 100 + + // For large codebases, increase capacity estimates + if numbers { + stringMapCapacity *= 2 // Numbers typically increase the result set } + // Intern common strings to reduce memory usage + path = InternString(path) + ignore = InternString(ignore) + ignoreStrings = InternString(ignoreStrings) + + // Create a single FileSet to be reused + fileSet := token.NewFileSet() + return &Parser{ - path: path, - ignore: ignore, - ignoreStrings: ignoreStrings, - ignoreTests: ignoreTests, - matchConstant: matchConstant, - minLength: minLength, - minOccurrences: minOccurrences, - numberMin: numberMin, - numberMax: numberMax, - supportedTokens: supportedTokens, - excludeTypes: excludeTypes, + path: path, + ignore: ignore, + ignoreStrings: ignoreStrings, + ignoreTests: ignoreTests, + matchConstant: matchConstant, + findDuplicates: findDuplicates, + evalConstExpressions: evalConstExpressions, + minLength: minLength, + minOccurrences: minOccurrences, + numberMin: numberMin, + numberMax: numberMax, + supportedTokens: supportedTokens, + supportedKinds: supportedKinds, + excludeTypes: excludeTypes, + maxConcurrency: maxConcurrency, + ignoreRegex: ignoreRegex, + ignoreStringsRegex: ignoreStringsRegex, + + // Initialize the maps with capacity hints + strs: make(Strings, stringMapCapacity), + consts: make(Constants, constMapCapacity), + stringCount: make(map[string]int, stringMapCapacity), + + // Default batch processing settings + batchSize: 50, + enableBatching: true, + + // Cache a single FileSet for reuse + fileSetCache: fileSet, + } +} + +// SetConcurrency allows setting the maximum number of goroutines to use +// for parallel file processing. Default is the number of CPUs. +func (p *Parser) SetConcurrency(max int) { + if max > 0 { + p.maxConcurrency = max + } +} - // Initialize the maps - strs: Strings{}, - consts: Constants{}, +// EnableBatchProcessing activates batch processing mode for very large codebases. +// This mode collects files in batches before processing them to reduce memory usage. +// The batchSize parameter controls how many files to process in each batch. +func (p *Parser) EnableBatchProcessing(batchSize int) { + p.enableBatching = true + if batchSize > 0 { + p.batchSize = batchSize } } // ParseTree will search the given path for occurrences that could be moved into constants. // If "..." is appended, the search will be recursive. +// +// It returns maps of strings and constants found during the analysis, and any error encountered. +// Use ProcessResults to filter the results based on configuration before retrieving them. func (p *Parser) ParseTree() (Strings, Constants, error) { pathLen := len(p.path) // Parse recursively the given path if the recursive notation is found if pathLen >= 5 && p.path[pathLen-3:] == "..." { - filepath.Walk(p.path[:pathLen-3], func(path string, f os.FileInfo, err error) error { + return p.parseTreeConcurrent(p.path[:pathLen-3], true) + } else { + return p.parseTreeConcurrent(p.path, false) + } +} + +const ( + chanSize = 1000 +) + +// parseTreeConcurrent implements an optimized concurrent file traversal +// that efficiently processes directories and files using worker pools. +func (p *Parser) parseTreeConcurrent(rootPath string, recursive bool) (Strings, Constants, error) { + + // If batch processing is enabled, use that implementation instead + if p.enableBatching { + return p.parseTreeBatched(rootPath, recursive) + } + + // Process files directly if the input is a single file + fi, err := os.Stat(rootPath) + if err == nil && !fi.IsDir() { + fset := p.getFileSet() + src, err := p.readFileEfficiently(rootPath) + if err != nil { + return nil, nil, err + } + + f, err := parser.ParseFile(fset, rootPath, src, 0) + if err != nil { + return nil, nil, err + } + // run type checker + info := &types.Info{ + Types: make(map[ast.Expr]types.TypeAndValue), + } + + chkConfig := &types.Config{ + Error: func(err error) {}, // type checking is only used to evaluate constant expressions, so we ignore most errors + } + pkg := types.NewPackage("", f.Name.Name) + _ = types.NewChecker(chkConfig, fset, pkg, info).Files([]*ast.File{f}) + + // Process the file + ast.Walk(&treeVisitor{ + fileSet: fset, + packageName: f.Name.Name, + p: p, + ignoreRegex: p.ignoreStringsRegex, + typeInfo: info, + }, f) + + // Post-process and filter results + p.ProcessResults() + return p.strs, p.consts, nil + } + + // Create a channel to collect all files to be processed + filesChan := make(chan string, chanSize) + + // Start a goroutine to collect all Go files + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + defer close(filesChan) + + // If not recursive, just handle a single directory + if !recursive { + entries, err := os.ReadDir(rootPath) + if err != nil { + log.Printf("Error reading directory %s: %v", rootPath, err) + return + } + + // Process entries + for _, entry := range entries { + if entry.IsDir() { + continue + } + + path := filepath.Join(rootPath, entry.Name()) + if strings.HasSuffix(path, ".go") { + // Skip test files if configured + if p.ignoreTests && strings.HasSuffix(path, testSuffix) { + continue + } + + // Skip files matching ignore pattern + if p.shouldSkipPath(path) { + continue + } + + filesChan <- path + } + } + return + } + + // Walk the directory tree recursively + err := filepath.Walk(rootPath, func(path string, info os.FileInfo, err error) error { if err != nil { - log.Println(err) - // resume walking + log.Printf("Error accessing path %s: %v", path, err) + return nil // Continue walking + } + + // Skip directories based on ignore patterns + if info.IsDir() { + if p.shouldSkipPath(path) { + return filepath.SkipDir + } return nil } - if f.IsDir() { - p.parseDir(path) + // Only process Go files + if strings.HasSuffix(path, ".go") { + // Skip test files if configured + if p.ignoreTests && strings.HasSuffix(path, testSuffix) { + return nil + } + + // Skip files matching ignore pattern + if p.shouldSkipPath(path) { + return nil + } + + // Send the file path to the channel + filesChan <- path } + return nil }) - } else { - p.parseDir(p.path) + + if err != nil { + log.Printf("Error walking directory tree: %v", err) + } + }() + + // Read and parse files concurrently + fset, filesByPackage := p.parseConcurrently(filesChan) + + wg.Wait() + + // Type checking must be performed serially to avoid data races. + info := &types.Info{ + Types: make(map[ast.Expr]types.TypeAndValue), + } + + chkConfig := &types.Config{ + Error: func(err error) {}, // type checking is only used to evaluate constant expressions, so we ignore most errors } + for pkgName, files := range filesByPackage { + chk := types.NewChecker(chkConfig, fset, types.NewPackage("", pkgName), info) + _ = chk.Files(files) + } + + // Visit all files + p.visitConcurrently(fset, info, filesByPackage) + + // Post-process and filter results p.ProcessResults() return p.strs, p.consts, nil } -// ProcessResults post-processes the raw results. -func (p *Parser) ProcessResults() { - for str, item := range p.strs { - // Filter out items whose occurrences don't match the min value - if len(item) < p.minOccurrences { - delete(p.strs, str) - } +func (p *Parser) parseConcurrently(filesChan <-chan string) (*token.FileSet, map[string][]*ast.File) { + // Start file parser workers + var parserWg sync.WaitGroup - if p.ignoreStrings != "" { - match, err := regexp.MatchString(p.ignoreStrings, str) - if err != nil { - log.Println(err) - } - if match { - delete(p.strs, str) + fset := p.getFileSet() + + parsedFilesChan := make(chan parsedFile, chanSize) + + // Add all workers to the WaitGroup before starting any goroutines + // This prevents a race condition with the goroutine that waits + parserWg.Add(p.maxConcurrency) + + // Start a separate goroutine to close the channel after all parsers are done + go func() { + parserWg.Wait() + close(parsedFilesChan) + }() + + for i := 0; i < p.maxConcurrency; i++ { + go func() { + defer parserWg.Done() + + for filePath := range filesChan { + // Parse a single file + src, err := p.readFileEfficiently(filePath) + if err != nil { + log.Printf("Error reading file %s: %v", filePath, err) + continue + } + + f, err := parser.ParseFile(fset, filePath, src, 0) + if err != nil { + log.Printf("Error parsing file %s: %v", filePath, err) + continue + } + + // Process the file + pkgName := f.Name.Name + parsedFilesChan <- parsedFile{pkgName, f} } + }() + } + + // Read all parsed files into packgageFiles map. All packages must be parsed prior to type-checking. + fileCount := 0 + packageFiles := map[string][]*ast.File{} + + var readerWg sync.WaitGroup + readerWg.Add(1) + go func() { + defer readerWg.Done() + for parsed := range parsedFilesChan { + packageFiles[parsed.pkgName] = append(packageFiles[parsed.pkgName], parsed.f) + fileCount++ // safe since this is single-threaded. } + }() - // If the value is a number - if i, err := strconv.ParseInt(str, 0, 0); err == nil { - if p.numberMin != 0 && i < int64(p.numberMin) { - delete(p.strs, str) - } - if p.numberMax != 0 && i > int64(p.numberMax) { - delete(p.strs, str) + // Wait for all file parsing to complete + parserWg.Wait() + // Wait for collection to complete + readerWg.Wait() + + return fset, packageFiles +} + +// visitConcurrently visits all files in filesByPackage on a worker pool goroutines. +func (p *Parser) visitConcurrently(fset *token.FileSet, info *types.Info, filesByPackage map[string][]*ast.File) { + var visitorWg sync.WaitGroup + + parsedFilesChan := make(chan parsedFile, chanSize) + + // Add all workers to the WaitGroup before starting any goroutines + visitorWg.Add(p.maxConcurrency) + + for i := 0; i < p.maxConcurrency; i++ { + go func() { + defer visitorWg.Done() + for pf := range parsedFilesChan { + ast.Walk(&treeVisitor{ + fileSet: fset, + typeInfo: info, + packageName: pf.pkgName, + p: p, + ignoreRegex: p.ignoreStringsRegex, + }, pf.f) } + }() + } + + for pkgName, files := range filesByPackage { + for _, f := range files { + parsedFilesChan <- parsedFile{pkgName, f} } } + close(parsedFilesChan) + + visitorWg.Wait() } -func (p *Parser) parseDir(dir string) error { - fset := token.NewFileSet() - pkgs, err := parser.ParseDir(fset, dir, func(info os.FileInfo) bool { - valid, name := true, info.Name() +// parseTreeBatched implements batch processing for very large codebases. +// Instead of processing files immediately as they are found, it collects them +// in batches and processes each batch completely before moving to the next. +// This helps manage memory usage for extremely large codebases. +func (p *Parser) parseTreeBatched(rootPath string, recursive bool) (Strings, Constants, error) { + var ( + allFiles []string + allFilesByDir = make(map[string][]string) + ) + + // First, collect all file paths that need to be processed + if recursive { + // If recursive, walk the entire directory tree + err := filepath.Walk(rootPath, func(path string, info os.FileInfo, err error) error { + if err != nil { + log.Printf("Error accessing path %s: %v", path, err) + return nil // Continue walking + } + + // Only process Go files + if !info.IsDir() && strings.HasSuffix(path, ".go") { + // Skip test files if configured to do so + if p.ignoreTests && strings.HasSuffix(path, testSuffix) { + return nil + } + + // Skip files matching ignore pattern + if p.shouldSkipPath(path) { + return nil + } - if p.ignoreTests { - if strings.HasSuffix(name, testSuffix) { - valid = false + allFiles = append(allFiles, path) + dir := filepath.Dir(path) + allFilesByDir[dir] = append(allFilesByDir[dir], path) } + + return nil + }) + + if err != nil { + return nil, nil, err + } + } else { + // If not recursive, just read the files in the specified directory + entries, err := os.ReadDir(rootPath) + if err != nil { + return nil, nil, err } - if len(p.ignore) != 0 { - match, err := regexp.MatchString(p.ignore, dir+name) - if err != nil { - log.Fatal(err) - return true + for _, entry := range entries { + if entry.IsDir() { + continue } - if match { - valid = false + + path := filepath.Join(rootPath, entry.Name()) + + // Only process Go files + if strings.HasSuffix(path, ".go") { + // Skip test files if configured to do so + if p.ignoreTests && strings.HasSuffix(path, testSuffix) { + continue + } + + // Skip files matching ignore pattern + if p.shouldSkipPath(path) { + continue + } + + allFiles = append(allFiles, path) + allFilesByDir[rootPath] = append(allFilesByDir[rootPath], path) } } + } + + // Split into batches, ensuring each package's files are all in the same batch, since the typechecker requires + // entire packages. Some batches may exceed the requested batchSize. + totalFiles := 0 + largeBatches := 0 + maxBatchSize := 0 + + var batches [][]string + var currBatch []string + for _, pkgFiles := range allFilesByDir { + size := len(currBatch) + if size >= p.batchSize { + batches = append(batches, currBatch) + currBatch = nil + } + currBatch = append(currBatch, pkgFiles...) + + // compute some stats + if size >= p.batchSize { + largeBatches++ + } + if size >= maxBatchSize { + maxBatchSize = size + } + totalFiles += len(pkgFiles) + } + if len(currBatch) > 0 { + batches = append(batches, currBatch) + } + + // Process batches + log.Printf("Found %d Go files to process in batches of %d", totalFiles, p.batchSize) + if largeBatches > 0 { + log.Printf("Warning: %d batches exceed the configured batch size. Largest batch contains %d files", largeBatches, maxBatchSize) + } + + for i, batch := range batches { + log.Printf("Processing batch %d/%d (%d files)", i+1, len(batches), len(batch)) + + // Process this batch concurrently - return valid - }, 0) + // Queue all files in this batch + fileChan := make(chan string, len(batch)) + for _, filePath := range batch { + fileChan <- filePath + } + close(fileChan) // safe to close since len(fileChan) == len(batch) + + // Parse files concurrently + fset, filesByPackage := p.parseConcurrently(fileChan) + + // Type check -- must be processed serially to avoid data races + info := &types.Info{ + Types: make(map[ast.Expr]types.TypeAndValue), + } + + chkConfig := &types.Config{ + Error: func(err error) {}, // type checking is only used to evaluate constant expressions, so we ignore most errors + } + for pkgName, files := range filesByPackage { + chk := types.NewChecker(chkConfig, fset, types.NewPackage("", pkgName), info) + _ = chk.Files(files) + } + + // Visit all files concurrently + p.visitConcurrently(fset, info, filesByPackage) + + // Optional: Run garbage collection between batches for very large codebases + if totalFiles > 10000 && len(batch) >= 1000 { + runtime.GC() + } + } + + // Post-process and filter results + p.ProcessResults() + + return p.strs, p.consts, nil +} + +// readFileEfficiently reads a file in the most efficient way. +// Benchmarks showed that for our specific use case, the standard +// library's ReadFile is already well-optimized. +func (p *Parser) readFileEfficiently(path string) ([]byte, error) { + // Optimized file reading to reduce allocations + f, err := os.Open(path) + if err != nil { + return nil, err + } + defer func() { + if closeErr := f.Close(); closeErr != nil { + log.Printf("Error closing file: %v", closeErr) + } + }() + + // Get file size to allocate buffer exactly once + info, err := f.Stat() if err != nil { - return err + return nil, err } - for _, pkg := range pkgs { - for fn, f := range pkg.Files { - ast.Walk(&treeVisitor{ - fileSet: fset, - packageName: pkg.Name, - fileName: fn, - p: p, - }, f) + // For very small files, use ReadAll + if info.Size() < 8192 { + return io.ReadAll(f) + } + + // For larger files, allocate exact buffer size to avoid resize allocations + size := info.Size() + buf := make([]byte, size) + + // Read in a single operation + n, err := io.ReadFull(f, buf) + if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF { + return nil, err + } + + return buf[:n], nil +} + +// getFileSet returns a cached FileSet for reuse +func (p *Parser) getFileSet() *token.FileSet { + p.fileSetMutex.Lock() + defer p.fileSetMutex.Unlock() + + // Return existing cache if available + if p.fileSetCache != nil { + return p.fileSetCache + } + + // Create a new one if needed + p.fileSetCache = token.NewFileSet() + return p.fileSetCache +} + +// shouldSkipPath determines if a path should be skipped based on ignore patterns +func (p *Parser) shouldSkipPath(path string) bool { + if p.ignoreRegex != nil { + if p.ignoreRegex.MatchString(path) { + return true + } + } else if len(p.ignore) != 0 { + // Fallback to non-compiled regex if compilation failed + match, err := regexp.MatchString(p.ignore, path) + if err != nil { + log.Printf("Error matching ignore pattern on %s: %v", path, err) + return false + } + if match { + return true } } + return false +} + +// IncrementStringCount safely increments the count for a string and returns the new count +func (p *Parser) IncrementStringCount(str string) int { + p.stringCountMutex.Lock() + defer p.stringCountMutex.Unlock() - return nil + p.stringCount[str]++ + return p.stringCount[str] } +// GetStringCount safely gets the count for a string +func (p *Parser) GetStringCount(str string) int { + p.stringCountMutex.RLock() + defer p.stringCountMutex.RUnlock() + + return p.stringCount[str] +} + +// ProcessResults post-processes the raw results. +// It filters the discovered strings based on the parser's configuration: +// - Removes strings that don't meet the minimum occurrences threshold +// - Filters out strings matching the ignore pattern +// - Applies number range filtering if min/max values are set +func (p *Parser) ProcessResults() { + p.stringMutex.Lock() + defer p.stringMutex.Unlock() + + // Also acquire stringCount lock to ensure consistency during processing + p.stringCountMutex.Lock() + defer p.stringCountMutex.Unlock() + + for str := range p.strs { + // Check count first as it's faster than looking at slice length + count := p.stringCount[str] + if count < p.minOccurrences { + delete(p.strs, str) + delete(p.stringCount, str) + continue + } + + // Apply ignoreStrings filter + if p.ignoreStrings != "" { + if p.ignoreStringsRegex != nil { + // Use pre-compiled regex if available + if p.ignoreStringsRegex.MatchString(str) { + delete(p.strs, str) + delete(p.stringCount, str) + continue + } + } else { + // Fallback to the non-compiled version + match, err := regexp.MatchString(p.ignoreStrings, str) + if err != nil { + log.Println(err) + } + if match { + delete(p.strs, str) + delete(p.stringCount, str) + continue + } + } + } + + // Apply number range filtering if applicable + if i, err := strconv.ParseInt(str, 0, 0); err == nil { + if (p.numberMin != 0 && i < int64(p.numberMin)) || + (p.numberMax != 0 && i > int64(p.numberMax)) { + delete(p.strs, str) + delete(p.stringCount, str) + } + } + } +} + +type parsedFile struct { + pkgName string + f *ast.File +} + +// Strings maps string literals to their positions in the code. type Strings map[string][]ExtendedPos -type Constants map[string]ConstType +// Constants maps string values to their constant definitions. +type Constants map[string][]ConstType + +// ConstType holds information about a constant declaration. type ConstType struct { + // Using embedded Position to save memory vs. a separate field token.Position - Name, packageName string + // Interned strings to reduce memory usage + Name string + packageName string } +// ExtendedPos extends token.Position with package information. +// This structure is optimized for memory usage in large codebases. type ExtendedPos struct { + // Using embedded Position to save memory vs. a separate field token.Position + // Interned package name to reduce memory usage when many positions + // reference the same package packageName string } +// Type represents the context in which a string literal appears. type Type int const ( + // Assignment represents a string in an assignment context (e.g., x := "foo") Assignment Type = iota + // Binary represents a string in a binary expression (e.g., x == "foo") Binary + // Case represents a string in a case clause (e.g., case "foo":) Case + // Return represents a string in a return statement (e.g., return "foo") Return + // Call represents a string passed as an argument to a function call (e.g., f("foo")) Call ) diff --git a/vendor/github.com/jgautheron/goconst/visitor.go b/vendor/github.com/jgautheron/goconst/visitor.go index c0974da8f..350e3ae62 100644 --- a/vendor/github.com/jgautheron/goconst/visitor.go +++ b/vendor/github.com/jgautheron/goconst/visitor.go @@ -2,18 +2,21 @@ package goconst import ( "go/ast" + "go/constant" "go/token" + "go/types" + "regexp" "strconv" "strings" ) -// treeVisitor carries the package name and file name -// for passing it to the imports map, and the fileSet for -// retrieving the token.Position. +// treeVisitor is used to walk the AST and find strings that could be constants. type treeVisitor struct { - p *Parser - fileSet *token.FileSet - packageName, fileName string + fileSet *token.FileSet + typeInfo *types.Info + packageName string + p *Parser + ignoreRegex *regexp.Regexp } // Visit browses the AST tree for strings that could be potentially @@ -30,7 +33,7 @@ func (v *treeVisitor) Visit(node ast.Node) ast.Visitor { switch t := node.(type) { // Scan for constants in an attempt to match strings with existing constants case *ast.GenDecl: - if !v.p.matchConstant { + if !v.p.matchConstant && !v.p.findDuplicates { return v } if t.Tok != token.CONST { @@ -40,12 +43,20 @@ func (v *treeVisitor) Visit(node ast.Node) ast.Visitor { for _, spec := range t.Specs { val := spec.(*ast.ValueSpec) for i, str := range val.Values { - lit, ok := str.(*ast.BasicLit) - if !ok || !v.isSupported(lit.Kind) { - continue - } + if v.typeInfo != nil && v.p.evalConstExpressions { + typedVal, ok := v.typeInfo.Types[str] + if !ok || !v.isSupportedKind(typedVal.Value.Kind()) { + continue + } - v.addConst(val.Names[i].Name, lit.Value, val.Names[i].Pos()) + v.addConst(val.Names[i].Name, typedVal.Value.String(), str.Pos()) + } else { + lit, ok := str.(*ast.BasicLit) + if !ok || !v.isSupported(lit.Kind) { + continue + } + v.addConst(val.Names[i].Name, lit.Value, val.Names[i].Pos()) + } } } @@ -112,41 +123,131 @@ func (v *treeVisitor) Visit(node ast.Node) ast.Visitor { // addString adds a string in the map along with its position in the tree. func (v *treeVisitor) addString(str string, pos token.Pos, typ Type) { + // Early type exclusion check ok, excluded := v.p.excludeTypes[typ] if ok && excluded { return } + // Drop quotes if any + var unquotedStr string if strings.HasPrefix(str, `"`) || strings.HasPrefix(str, "`") { - str, _ = strconv.Unquote(str) + var err error + unquotedStr, err = strconv.Unquote(str) + if err != nil { + // Reuse strings from pool if possible to avoid allocations + sb := GetStringBuilder() + defer PutStringBuilder(sb) + + // If unquoting fails, manually strip quotes + // This avoids additional temporary strings + if len(str) >= 2 { + sb.WriteString(str[1 : len(str)-1]) + unquotedStr = sb.String() + } else { + unquotedStr = str + } + } + } else { + unquotedStr = str } - // Ignore empty strings - if len(str) == 0 { + // Early length check + if len(unquotedStr) == 0 || len(unquotedStr) < v.p.minLength { return } - if len(str) < v.p.minLength { + // Early regex filtering - pre-compiled for efficiency + if v.ignoreRegex != nil && v.ignoreRegex.MatchString(unquotedStr) { return } - _, ok = v.p.strs[str] - if !ok { - v.p.strs[str] = make([]ExtendedPos, 0) + // Early number range filtering + if v.p.numberMin != 0 || v.p.numberMax != 0 { + if i, err := strconv.ParseInt(unquotedStr, 0, 0); err == nil { + if (v.p.numberMin != 0 && i < int64(v.p.numberMin)) || + (v.p.numberMax != 0 && i > int64(v.p.numberMax)) { + return + } + } + } + + // Use interned string to reduce memory usage - identical strings share the same memory + internedStr := InternString(unquotedStr) + + // Update the count first, this is faster than appending to slices + count := v.p.IncrementStringCount(internedStr) + + // Only continue if we're still adding the position to the map + // or if count has reached threshold + if count == 1 || count == v.p.minOccurrences { + // Lock to safely update the shared map + v.p.stringMutex.Lock() + defer v.p.stringMutex.Unlock() + + _, exists := v.p.strs[internedStr] + if !exists { + v.p.strs[internedStr] = make([]ExtendedPos, 0, v.p.minOccurrences) // Preallocate with expected size + } + + // Create an optimized position record + newPos := ExtendedPos{ + packageName: InternString(v.packageName), // Intern the package name to reduce memory + Position: v.fileSet.Position(pos), + } + + v.p.strs[internedStr] = append(v.p.strs[internedStr], newPos) } - v.p.strs[str] = append(v.p.strs[str], ExtendedPos{ - packageName: v.packageName, - Position: v.fileSet.Position(pos), - }) } // addConst adds a const in the map along with its position in the tree. func (v *treeVisitor) addConst(name string, val string, pos token.Pos) { - val = strings.Replace(val, `"`, "", 2) - v.p.consts[val] = ConstType{ - Name: name, - packageName: v.packageName, - Position: v.fileSet.Position(pos), + // Early filtering using the same criteria as for strings + var unquotedVal string + if strings.HasPrefix(val, `"`) || strings.HasPrefix(val, "`") { + var err error + // Use string builder from pool to reduce allocations + sb := GetStringBuilder() + defer PutStringBuilder(sb) + + if unquotedVal, err = strconv.Unquote(val); err != nil { + // If unquoting fails, manually strip quotes without allocations + if len(val) >= 2 { + sb.WriteString(val[1 : len(val)-1]) + unquotedVal = sb.String() + } else { + unquotedVal = val + } + } + } else { + unquotedVal = val + } + + // Skip constants with values that would be filtered anyway + if len(unquotedVal) < v.p.minLength { + return + } + + if v.ignoreRegex != nil && v.ignoreRegex.MatchString(unquotedVal) { + return + } + + // Use interned string to reduce memory usage + internedVal := InternString(unquotedVal) + internedName := InternString(name) + internedPkg := InternString(v.packageName) + + // Lock to safely update the shared map + v.p.constMutex.Lock() + defer v.p.constMutex.Unlock() + + // track this const if this is a new const, or if we are searching for duplicate consts + if _, ok := v.p.consts[internedVal]; !ok || v.p.findDuplicates { + v.p.consts[internedVal] = append(v.p.consts[internedVal], ConstType{ + Name: internedName, + packageName: internedPkg, + Position: v.fileSet.Position(pos), + }) } } @@ -158,3 +259,12 @@ func (v *treeVisitor) isSupported(tk token.Token) bool { } return false } + +func (v *treeVisitor) isSupportedKind(kind constant.Kind) bool { + for _, s := range v.p.supportedKinds { + if kind == s { + return true + } + } + return false +} diff --git a/vendor/github.com/jjti/go-spancheck/.gitignore b/vendor/github.com/jjti/go-spancheck/.gitignore index 1f83be414..fc9b2a109 100644 --- a/vendor/github.com/jjti/go-spancheck/.gitignore +++ b/vendor/github.com/jjti/go-spancheck/.gitignore @@ -17,3 +17,6 @@ # Dependency directories (remove the comment below to include it) # vendor/ src/ + +.vscode +.DS_Store \ No newline at end of file diff --git a/vendor/github.com/jjti/go-spancheck/.golangci.yml b/vendor/github.com/jjti/go-spancheck/.golangci.yml index 15d8513d6..74a4377ab 100644 --- a/vendor/github.com/jjti/go-spancheck/.golangci.yml +++ b/vendor/github.com/jjti/go-spancheck/.golangci.yml @@ -17,12 +17,9 @@ linters: - errcheck - errname - errorlint - - exhaustive # checks exhaustiveness of enum switch statements - - exportloopref # checks for pointers to enclosing loop variables - gci - gochecknoinits # checks that no init functions are present in Go code - gocritic - - gomnd - gosimple - govet - importas # enforces consistent import aliases @@ -43,7 +40,6 @@ linters: - revive # fast, configurable, extensible, flexible, and beautiful linter for Go, drop-in replacement of golint - staticcheck - stylecheck - - tenv - thelper # detects golang test helpers without t.Helper() call and checks the consistency of test helpers - unconvert # removes unnecessary type conversions - unparam # reports unused function parameters @@ -59,12 +55,6 @@ linters-settings: - standard # Standard section: captures all standard packages. - default # Default section: contains all imports that could not be matched to another section type. - prefix(github.com/jjti) - exhaustive: - # Program elements to check for exhaustiveness. - # Default: [ switch ] - check: - - switch - - map gocritic: settings: captLocal: @@ -87,7 +77,7 @@ linters-settings: nestif: # Minimal complexity of if statements to report. # Default: 5 - min-complexity: 4 + min-complexity: 5 nolintlint: # Enable to require an explanation of nonzero length after each nolint directive. # Default: false diff --git a/vendor/github.com/jjti/go-spancheck/README.md b/vendor/github.com/jjti/go-spancheck/README.md index 393663ba7..87c32fc66 100644 --- a/vendor/github.com/jjti/go-spancheck/README.md +++ b/vendor/github.com/jjti/go-spancheck/README.md @@ -97,6 +97,8 @@ Flags: ### Ignore Check Signatures +This setting avoids false positives from utility functions that return spans (which are handled gracefully by callers of the function). + The `span.SetStatus()` and `span.RecordError()` checks warn when there is: 1. a path to return statement @@ -134,6 +136,8 @@ spancheck -checks 'end,set-status,record-error' -ignore-check-signatures 'record ### Extra Start Span Signatures +This setting informs spancheck of additional Span creation functions that should be linted (besides the library defaults). + By default, Span creation will be tracked from calls to [(go.opentelemetry.io/otel/trace.Tracer).Start](https://github.com/open-telemetry/opentelemetry-go/blob/98b32a6c3a87fbee5d34c063b9096f416b250897/trace/trace.go#L523), [go.opencensus.io/trace.StartSpan](https://pkg.go.dev/go.opencensus.io/trace#StartSpan), or [go.opencensus.io/trace.StartSpanWithRemoteParent](https://github.com/census-instrumentation/opencensus-go/blob/v0.24.0/trace/trace_api.go#L66). You can use the `-extra-start-span-signatures` flag to list additional Span creation functions. For all such functions: @@ -265,4 +269,6 @@ This linter is the product of liberal copying of: - [github.com/ghostiam/protogetter](https://github.com/ghostiam/protogetter/blob/main/testdata/Makefile) (test setup) And the contributions of: + - [@trixnz](https://github.com/trixnz) who [added support for custom span start functions](https://github.com/jjti/go-spancheck/pull/16) +- [@parsaaes](https://github.com/parsaaes) who [fixed a false negative bug in deferred methods that reference spans](https://github.com/jjti/go-spancheck/pull/31) diff --git a/vendor/github.com/jjti/go-spancheck/go.work b/vendor/github.com/jjti/go-spancheck/go.work index 7d0a87b9e..ff04ca17e 100644 --- a/vendor/github.com/jjti/go-spancheck/go.work +++ b/vendor/github.com/jjti/go-spancheck/go.work @@ -1,4 +1,4 @@ -go 1.20 +go 1.22.1 use ( . diff --git a/vendor/github.com/jjti/go-spancheck/go.work.sum b/vendor/github.com/jjti/go-spancheck/go.work.sum index 04eadf2c5..c96d590d6 100644 --- a/vendor/github.com/jjti/go-spancheck/go.work.sum +++ b/vendor/github.com/jjti/go-spancheck/go.work.sum @@ -1,4 +1,11 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= diff --git a/vendor/github.com/jjti/go-spancheck/spancheck.go b/vendor/github.com/jjti/go-spancheck/spancheck.go index 8fc7945c6..1618682aa 100644 --- a/vendor/github.com/jjti/go-spancheck/spancheck.go +++ b/vendor/github.com/jjti/go-spancheck/spancheck.go @@ -23,6 +23,12 @@ const ( spanOpenCensus // from go.opencensus.io/trace ) +const ( + selNameEnd = "End" + selNameSetStatus = "SetStatus" + selNameRecordError = "RecordError" +) + // SpanTypes is a list of all span types by name. var SpanTypes = map[string]spanType{ "opentelemetry": spanOpenTelemetry, @@ -183,7 +189,7 @@ func runFunc(pass *analysis.Pass, node ast.Node, config *Config) { for _, sv := range spanVars { if config.endCheckEnabled { // Check if there's no End to the span. - if ret := getMissingSpanCalls(pass, g, sv, "End", func(_ *analysis.Pass, ret *ast.ReturnStmt) *ast.ReturnStmt { return ret }, nil, config.startSpanMatchers); ret != nil { + if ret := getMissingSpanCalls(pass, g, sv, selNameEnd, func(_ *analysis.Pass, ret *ast.ReturnStmt) *ast.ReturnStmt { return ret }, nil, config.startSpanMatchers); ret != nil { pass.ReportRangef(sv.stmt, "%s.End is not called on all paths, possible memory leak", sv.vr.Name()) pass.ReportRangef(ret, "return can be reached without calling %s.End", sv.vr.Name()) } @@ -191,7 +197,7 @@ func runFunc(pass *analysis.Pass, node ast.Node, config *Config) { if config.setStatusEnabled { // Check if there's no SetStatus to the span setting an error. - if ret := getMissingSpanCalls(pass, g, sv, "SetStatus", getErrorReturn, config.ignoreChecksSignatures, config.startSpanMatchers); ret != nil { + if ret := getMissingSpanCalls(pass, g, sv, selNameSetStatus, getErrorReturn, config.ignoreChecksSignatures, config.startSpanMatchers); ret != nil { pass.ReportRangef(sv.stmt, "%s.SetStatus is not called on all paths", sv.vr.Name()) pass.ReportRangef(ret, "return can be reached without calling %s.SetStatus", sv.vr.Name()) } @@ -199,7 +205,7 @@ func runFunc(pass *analysis.Pass, node ast.Node, config *Config) { if config.recordErrorEnabled && sv.spanType == spanOpenTelemetry { // RecordError only exists in OpenTelemetry // Check if there's no RecordError to the span setting an error. - if ret := getMissingSpanCalls(pass, g, sv, "RecordError", getErrorReturn, config.ignoreChecksSignatures, config.startSpanMatchers); ret != nil { + if ret := getMissingSpanCalls(pass, g, sv, selNameRecordError, getErrorReturn, config.ignoreChecksSignatures, config.startSpanMatchers); ret != nil { pass.ReportRangef(sv.stmt, "%s.RecordError is not called on all paths", sv.vr.Name()) pass.ReportRangef(ret, "return can be reached without calling %s.RecordError", sv.vr.Name()) } @@ -216,7 +222,7 @@ func isSpanStart(info *types.Info, n ast.Node, startSpanMatchers []spanStartMatc fnSig := info.ObjectOf(sel.Sel).String() - // Check if the function is a span start function + // Check if the function is a span start function. for _, matcher := range startSpanMatchers { if matcher.signature.MatchString(fnSig) { return matcher.spanType, true @@ -309,6 +315,11 @@ outer: } seen[b] = true + // Skip successors that are not nested within this current block. + if _, ok := nestedBlockTypes[b.Kind]; !ok { + continue + } + // Prune the search if the block uses v. if blockUses(pass, b) { continue @@ -330,6 +341,21 @@ outer: return search(defBlock.Succs) } +var nestedBlockTypes = map[cfg.BlockKind]struct{}{ + cfg.KindBody: {}, + cfg.KindForBody: {}, + cfg.KindForLoop: {}, + cfg.KindIfElse: {}, + cfg.KindIfThen: {}, + cfg.KindLabel: {}, + cfg.KindRangeBody: {}, + cfg.KindRangeLoop: {}, + cfg.KindSelectCaseBody: {}, + cfg.KindSelectAfterCase: {}, + cfg.KindSwitchCaseBody: {}, + cfg.KindSwitchNextCase: {}, +} + // usesCall reports whether stmts contain a use of the selName call on variable v. func usesCall( pass *analysis.Pass, @@ -340,10 +366,12 @@ func usesCall( startSpanMatchers []spanStartMatcher, depth int, ) bool { - if depth > 1 { // for perf reasons, do not dive too deep thru func literals, just one level deep check. + if depth > 1 { // for perf reasons, do not dive too deep thru func literals, just two levels deep. return false } + cfgs := pass.ResultOf[ctrlflow.Analyzer].(*ctrlflow.CFGs) + found, reAssigned := false, false for _, subStmt := range stmts { stack := []ast.Node{} @@ -351,7 +379,6 @@ func usesCall( switch n := n.(type) { case *ast.FuncLit: if len(stack) > 0 { - cfgs := pass.ResultOf[ctrlflow.Analyzer].(*ctrlflow.CFGs) g := cfgs.FuncLit(n) if g != nil && len(g.Blocks) > 0 { return usesCall(pass, g.Blocks[0].Nodes, sv, selName, ignoreCheckSig, startSpanMatchers, depth+1) @@ -367,6 +394,52 @@ func usesCall( return false } } + case *ast.DeferStmt: + if n.Call == nil { + break + } + + f, ok := n.Call.Fun.(*ast.FuncLit) + if !ok { + break + } + + if g := cfgs.FuncLit(f); g != nil && len(g.Blocks) > 0 { + if selName == selNameEnd { + // Check if all returning blocks call end. + for _, b := range g.Blocks { + if b.Return() != nil && !usesCall( + pass, + b.Nodes, + sv, + selName, + ignoreCheckSig, + startSpanMatchers, + depth+1, + ) { + return false + } + } + + found = true + return false + } + + for _, b := range g.Blocks { + if usesCall( + pass, + b.Nodes, + sv, + selName, + ignoreCheckSig, + startSpanMatchers, + depth+1, + ) { + found = true + return false + } + } + } case nil: if len(stack) > 0 { stack = stack[:len(stack)-1] // pop diff --git a/vendor/github.com/julz/importas/Makefile b/vendor/github.com/julz/importas/Makefile new file mode 100644 index 000000000..e9838b43b --- /dev/null +++ b/vendor/github.com/julz/importas/Makefile @@ -0,0 +1,17 @@ +# default task since it's first +.PHONY: all +all: build test + +BINARY = importas +$(BINARY): *.go go.mod go.sum + go build -o $(BINARY) + +.PHONY: build +build: $(BINARY) ## Build binary + +.PHONY: test +test: build ## Unit test + go test -v ./... + +install: ## Install binary + go install diff --git a/vendor/github.com/julz/importas/analyzer.go b/vendor/github.com/julz/importas/analyzer.go index f19653478..25bc09b82 100644 --- a/vendor/github.com/julz/importas/analyzer.go +++ b/vendor/github.com/julz/importas/analyzer.go @@ -13,7 +13,7 @@ import ( ) var config = &Config{ - RequiredAlias: make(map[string]string), + RequiredAlias: make([][]string, 0), } var Analyzer = &analysis.Analyzer{ @@ -129,11 +129,19 @@ func findEdits(node ast.Node, uses map[*ast.Ident]types.Object, importPath, orig // skip identifiers pointing to a different import statement. continue } + pos := use.Pos() + end := use.End() + replacement := packageReplacement + + if packageReplacement == "." { + replacement = "" + end = end + 1 + } result = append(result, analysis.TextEdit{ - Pos: use.Pos(), - End: use.End(), - NewText: []byte(packageReplacement), + Pos: pos, + End: end, + NewText: []byte(replacement), }) } diff --git a/vendor/github.com/julz/importas/config.go b/vendor/github.com/julz/importas/config.go index 8c9c76d91..58be86c75 100644 --- a/vendor/github.com/julz/importas/config.go +++ b/vendor/github.com/julz/importas/config.go @@ -4,18 +4,26 @@ import ( "errors" "fmt" "regexp" + "sync" ) type Config struct { - RequiredAlias map[string]string + RequiredAlias aliasList Rules []*Rule DisallowUnaliased bool DisallowExtraAliases bool + muRules sync.Mutex } func (c *Config) CompileRegexp() error { + c.muRules.Lock() + defer c.muRules.Unlock() + if c.Rules != nil { + return nil + } rules := make([]*Rule, 0, len(c.RequiredAlias)) - for path, alias := range c.RequiredAlias { + for _, aliases := range c.RequiredAlias { + path, alias := aliases[0], aliases[1] reg, err := regexp.Compile(fmt.Sprintf("^%s$", path)) if err != nil { return err @@ -26,13 +34,15 @@ func (c *Config) CompileRegexp() error { Alias: alias, }) } - c.Rules = rules return nil } func (c *Config) findRule(path string) *Rule { - for _, rule := range c.Rules { + c.muRules.Lock() + rules := c.Rules + c.muRules.Unlock() + for _, rule := range rules { if rule.Regexp.MatchString(path) { return rule } diff --git a/vendor/github.com/julz/importas/flags.go b/vendor/github.com/julz/importas/flags.go index f8107104a..cc3f1f3aa 100644 --- a/vendor/github.com/julz/importas/flags.go +++ b/vendor/github.com/julz/importas/flags.go @@ -7,26 +7,27 @@ import ( "strings" ) +var errWrongAlias = errors.New("import flag must be of form path:alias") + func flags(config *Config) flag.FlagSet { fs := flag.FlagSet{} - fs.Var(stringMap(config.RequiredAlias), "alias", "required import alias in form path:alias") + fs.Var(&config.RequiredAlias, "alias", "required import alias in form path:alias") fs.BoolVar(&config.DisallowUnaliased, "no-unaliased", false, "do not allow unaliased imports of aliased packages") fs.BoolVar(&config.DisallowExtraAliases, "no-extra-aliases", false, "do not allow non-required aliases") return fs } -type stringMap map[string]string +type aliasList [][]string -func (v stringMap) Set(val string) error { - spl := strings.SplitN(val, ":", 2) - if len(spl) != 2 { - return errors.New("import flag must be of form path:alias") +func (v *aliasList) Set(val string) error { + lastColon := strings.LastIndex(val, ":") + if lastColon <= 1 { + return errWrongAlias } - - v[spl[0]] = spl[1] + *v = append(*v, []string{val[:lastColon], val[lastColon+1:]}) return nil } -func (v stringMap) String() string { - return fmt.Sprintf("%v", (map[string]string)(v)) +func (v *aliasList) String() string { + return fmt.Sprintf("%v", ([][]string)(*v)) } diff --git a/vendor/github.com/karamaru-alpha/copyloopvar/copyloopvar.go b/vendor/github.com/karamaru-alpha/copyloopvar/copyloopvar.go index 79dc6afcc..00c8e0e3d 100644 --- a/vendor/github.com/karamaru-alpha/copyloopvar/copyloopvar.go +++ b/vendor/github.com/karamaru-alpha/copyloopvar/copyloopvar.go @@ -15,7 +15,7 @@ var checkAlias bool func NewAnalyzer() *analysis.Analyzer { analyzer := &analysis.Analyzer{ Name: "copyloopvar", - Doc: "copyloopvar is a linter detects places where loop variables are copied", + Doc: "a linter detects places where loop variables are copied", Run: run, Requires: []*analysis.Analyzer{ inspect.Analyzer, @@ -77,10 +77,8 @@ func checkRangeStmt(pass *analysis.Pass, rangeStmt *ast.RangeStmt) { continue } } - pass.Report(analysis.Diagnostic{ - Pos: assignStmt.Pos(), - Message: fmt.Sprintf(`The copy of the 'for' variable "%s" can be deleted (Go 1.22+)`, right.Name), - }) + + report(pass, assignStmt, right, i) } } } @@ -124,10 +122,40 @@ func checkForStmt(pass *analysis.Pass, forStmt *ast.ForStmt) { continue } } - pass.Report(analysis.Diagnostic{ - Pos: assignStmt.Pos(), - Message: fmt.Sprintf(`The copy of the 'for' variable "%s" can be deleted (Go 1.22+)`, right.Name), - }) + + report(pass, assignStmt, right, i) } } } + +func report(pass *analysis.Pass, assignStmt *ast.AssignStmt, right *ast.Ident, i int) { + diagnostic := analysis.Diagnostic{ + Pos: assignStmt.Pos(), + Message: fmt.Sprintf(`The copy of the 'for' variable "%s" can be deleted (Go 1.22+)`, right.Name), + } + + if i == 0 && isSimpleAssignStmt(assignStmt, right) { + diagnostic.SuggestedFixes = append(diagnostic.SuggestedFixes, analysis.SuggestedFix{ + TextEdits: []analysis.TextEdit{{ + Pos: assignStmt.Pos(), + End: assignStmt.End(), + NewText: nil, + }}, + }) + } + + pass.Report(diagnostic) +} + +func isSimpleAssignStmt(assignStmt *ast.AssignStmt, rhs *ast.Ident) bool { + if len(assignStmt.Lhs) != 1 { + return false + } + + lhs, ok := assignStmt.Lhs[0].(*ast.Ident) + if !ok { + return false + } + + return rhs.Name == lhs.Name +} diff --git a/vendor/github.com/kisielk/errcheck/errcheck/errcheck.go b/vendor/github.com/kisielk/errcheck/errcheck/errcheck.go index a7a2a30bf..325aeec98 100644 --- a/vendor/github.com/kisielk/errcheck/errcheck/errcheck.go +++ b/vendor/github.com/kisielk/errcheck/errcheck/errcheck.go @@ -23,7 +23,9 @@ func init() { } var ( - // ErrNoGoFiles is returned when CheckPackage is run on a package with no Go source files + // ErrNoGoFiles is returned when CheckPackage is run on a package with no Go source files. + // + // Deprecated: this error is no longer returned by errcheck.LoadPackages. ErrNoGoFiles = errors.New("package contains no go source files") ) @@ -162,7 +164,7 @@ var loadPackages = func(cfg *packages.Config, paths ...string) ([]*packages.Pack // LoadPackages loads all the packages in all the paths provided. It uses the // exclusions and build tags provided to by the user when loading the packages. func (c *Checker) LoadPackages(paths ...string) ([]*packages.Package, error) { - buildFlags := []string{fmtTags(c.Tags)} + buildFlags := []string{fmt.Sprintf("-tags=%s", strings.Join(c.Tags, ","))} if c.Mod != "" { buildFlags = append(buildFlags, fmt.Sprintf("-mod=%s", c.Mod)) } diff --git a/vendor/github.com/kisielk/errcheck/errcheck/excludes.go b/vendor/github.com/kisielk/errcheck/errcheck/excludes.go index 450b798e4..3e28a2fdb 100644 --- a/vendor/github.com/kisielk/errcheck/errcheck/excludes.go +++ b/vendor/github.com/kisielk/errcheck/errcheck/excludes.go @@ -17,6 +17,9 @@ var DefaultExcludedSymbols = []string{ "(*bytes.Buffer).WriteRune", "(*bytes.Buffer).WriteString", + // crypto + "crypto/rand.Read", // https://github.com/golang/go/issues/66821 + // fmt "fmt.Print", "fmt.Printf", diff --git a/vendor/github.com/kisielk/errcheck/errcheck/tags.go b/vendor/github.com/kisielk/errcheck/errcheck/tags.go deleted file mode 100644 index 7b423ca69..000000000 --- a/vendor/github.com/kisielk/errcheck/errcheck/tags.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build go1.13 - -package errcheck - -import ( - "fmt" - "strings" -) - -func fmtTags(tags []string) string { - return fmt.Sprintf("-tags=%s", strings.Join(tags, ",")) -} diff --git a/vendor/github.com/kisielk/errcheck/errcheck/tags_compat.go b/vendor/github.com/kisielk/errcheck/errcheck/tags_compat.go deleted file mode 100644 index 2f534f40a..000000000 --- a/vendor/github.com/kisielk/errcheck/errcheck/tags_compat.go +++ /dev/null @@ -1,13 +0,0 @@ -// +build go1.11 -// +build !go1.13 - -package errcheck - -import ( - "fmt" - "strings" -) - -func fmtTags(tags []string) string { - return fmt.Sprintf("-tags=%s", strings.Join(tags, " ")) -} diff --git a/vendor/github.com/kkHAIKE/contextcheck/contextcheck.go b/vendor/github.com/kkHAIKE/contextcheck/contextcheck.go index 62696351a..c62909a87 100644 --- a/vendor/github.com/kkHAIKE/contextcheck/contextcheck.go +++ b/vendor/github.com/kkHAIKE/contextcheck/contextcheck.go @@ -727,6 +727,14 @@ func (r *runner) getFunction(instr ssa.Instruction) (f *ssa.Function) { } func (r *runner) isCtxType(tp types.Type) bool { + if p, ok := tp.(*types.Pointer); ok { + // opaqueType is not exposed and lead to unreachable error. + // Related to https://github.com/golang/tools/blob/63229bc79404d8cf2fe4e88ad569168fe251d993/go/ssa/builder.go#L107 + if p.Elem().String() == "deferStack" { + return false + } + } + return types.Identical(tp, r.ctxTyp) || types.Identical(tp, r.ctxPTyp) } diff --git a/vendor/github.com/kulti/thelper/pkg/analyzer/analyzer.go b/vendor/github.com/kulti/thelper/pkg/analyzer/analyzer.go index a22fd6aca..5a2d0f89d 100644 --- a/vendor/github.com/kulti/thelper/pkg/analyzer/analyzer.go +++ b/vendor/github.com/kulti/thelper/pkg/analyzer/analyzer.go @@ -1,3 +1,4 @@ +// Package analyzer implements the thelper linter logic. package analyzer import ( @@ -9,14 +10,14 @@ import ( "sort" "strings" - "github.com/gostaticanalysis/analysisutil" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/ast/inspector" ) const ( - doc = "thelper detects tests helpers which is not start with t.Helper() method." + doc = "thelper detects tests helpers which do not start with the t.Helper() method." + checksDoc = `coma separated list of enabled checks Available checks @@ -45,7 +46,9 @@ func (m enabledChecksValue) String() string { for s := range m { ss = append(ss, s) } + sort.Strings(ss) + return strings.Join(ss, ",") } @@ -58,6 +61,7 @@ func (m enabledChecksValue) Set(s string) error { for k := range m { delete(m, k) } + for _, v := range ss { switch v { case checkTBegin, checkTFirst, checkTName, @@ -69,6 +73,7 @@ func (m enabledChecksValue) Set(s string) error { return fmt.Errorf("unknown check name %q (see help for full list)", v) } } + return nil } @@ -125,6 +130,7 @@ func NewAnalyzer() *analysis.Analyzer { return a } +//nolint:funlen // The function is easier to grok this way. func (t thelper) run(pass *analysis.Pass) (interface{}, error) { tCheckOpts, fCheckOpts, bCheckOpts, tbCheckOpts, ok := t.buildCheckFuncOpts(pass) if !ok { @@ -137,6 +143,7 @@ func (t thelper) run(pass *analysis.Pass) (interface{}, error) { } var reports reports + nodeFilter := []ast.Node{ (*ast.FuncDecl)(nil), (*ast.FuncLit)(nil), @@ -144,6 +151,7 @@ func (t thelper) run(pass *analysis.Pass) (interface{}, error) { } inspect.Preorder(nodeFilter, func(node ast.Node) { var fd funcDecl + switch n := node.(type) { case *ast.FuncLit: fd.Pos = n.Pos() @@ -157,13 +165,19 @@ func (t thelper) run(pass *analysis.Pass) (interface{}, error) { fd.Name = n.Name case *ast.CallExpr: runSubtestExprs := extractSubtestExp(pass, n, tCheckOpts.subRun, tCheckOpts.subTestFuncType) + if len(runSubtestExprs) == 0 { runSubtestExprs = extractSubtestExp(pass, n, bCheckOpts.subRun, bCheckOpts.subTestFuncType) } + if len(runSubtestExprs) == 0 { runSubtestExprs = extractSubtestFuzzExp(pass, n, fCheckOpts.subRun) } + if len(runSubtestExprs) == 0 { + runSubtestExprs = extractSynctestExp(pass, n, tCheckOpts.subTestFuncType) + } + if len(runSubtestExprs) > 0 { for _, expr := range runSubtestExprs { reports.Filter(funcDefPosition(pass, expr)) @@ -171,6 +185,7 @@ func (t thelper) run(pass *analysis.Pass) (interface{}, error) { } else { reports.NoFilter(funcDefPosition(pass, n.Fun)) } + return default: return @@ -202,7 +217,8 @@ type checkFuncOpts struct { func (t thelper) buildCheckFuncOpts(pass *analysis.Pass) (checkFuncOpts, checkFuncOpts, checkFuncOpts, checkFuncOpts, bool) { var ctxType types.Type - ctxObj := analysisutil.ObjectOf(pass, "context", "Context") + + ctxObj := findTypeObject(pass, "context.Context") if ctxObj != nil { ctxType = ctxObj.Type() } @@ -231,7 +247,7 @@ func (t thelper) buildCheckFuncOpts(pass *analysis.Pass) (checkFuncOpts, checkFu } func (t thelper) buildTestCheckFuncOpts(pass *analysis.Pass, ctxType types.Type) (checkFuncOpts, bool) { - tObj := analysisutil.ObjectOf(pass, "testing", "T") + tObj := findTypeObject(pass, "testing.T") if tObj == nil { return checkFuncOpts{}, false } @@ -248,13 +264,14 @@ func (t thelper) buildTestCheckFuncOpts(pass *analysis.Pass, ctxType types.Type) tType := types.NewPointer(tObj.Type()) tVar := types.NewVar(token.NoPos, nil, "t", tType) + return checkFuncOpts{ skipPrefix: "Test", varName: "t", fnHelper: tHelper, subRun: tRun, hpType: tType, - subTestFuncType: types.NewSignature(nil, types.NewTuple(tVar), nil, false), + subTestFuncType: types.NewSignatureType(nil, nil, nil, types.NewTuple(tVar), nil, false), ctxType: ctxType, checkBegin: t.enabledChecks.Enabled(checkTBegin), checkFirst: t.enabledChecks.Enabled(checkTFirst), @@ -263,7 +280,7 @@ func (t thelper) buildTestCheckFuncOpts(pass *analysis.Pass, ctxType types.Type) } func (t thelper) buildFuzzCheckFuncOpts(pass *analysis.Pass, ctxType types.Type) (checkFuncOpts, bool) { - fObj := analysisutil.ObjectOf(pass, "testing", "F") + fObj := findTypeObject(pass, "testing.F") if fObj == nil { return checkFuncOpts{}, true // fuzzing supports since go1.18, it's ok, that testig.F is missed. } @@ -292,7 +309,7 @@ func (t thelper) buildFuzzCheckFuncOpts(pass *analysis.Pass, ctxType types.Type) } func (t thelper) buildBenchmarkCheckFuncOpts(pass *analysis.Pass, ctxType types.Type) (checkFuncOpts, bool) { - bObj := analysisutil.ObjectOf(pass, "testing", "B") + bObj := findTypeObject(pass, "testing.B") if bObj == nil { return checkFuncOpts{}, false } @@ -309,13 +326,14 @@ func (t thelper) buildBenchmarkCheckFuncOpts(pass *analysis.Pass, ctxType types. bType := types.NewPointer(bObj.Type()) bVar := types.NewVar(token.NoPos, nil, "b", bType) + return checkFuncOpts{ skipPrefix: "Benchmark", varName: "b", fnHelper: bHelper, subRun: bRun, hpType: types.NewPointer(bObj.Type()), - subTestFuncType: types.NewSignature(nil, types.NewTuple(bVar), nil, false), + subTestFuncType: types.NewSignatureType(nil, nil, nil, types.NewTuple(bVar), nil, false), ctxType: ctxType, checkBegin: t.enabledChecks.Enabled(checkBBegin), checkFirst: t.enabledChecks.Enabled(checkBFirst), @@ -324,7 +342,7 @@ func (t thelper) buildBenchmarkCheckFuncOpts(pass *analysis.Pass, ctxType types. } func (t thelper) buildTBCheckFuncOpts(pass *analysis.Pass, ctxType types.Type) (checkFuncOpts, bool) { - tbObj := analysisutil.ObjectOf(pass, "testing", "TB") + tbObj := findTypeObject(pass, "testing.TB") if tbObj == nil { return checkFuncOpts{}, false } @@ -370,6 +388,7 @@ func checkFunc(pass *analysis.Pass, reports *reports, funcDecl funcDecl, opts ch if opts.checkFirst { if pos != 0 { checkFirstPassed := false + if pos == 1 && opts.ctxType != nil { _, pos, ok := searchFuncParam(pass, funcDecl, opts.ctxType) checkFirstPassed = ok && (pos == 0) @@ -404,6 +423,7 @@ func searchFuncParam(pass *analysis.Pass, f funcDecl, p types.Type) (*ast.Field, return f, i, true } } + return nil, 0, false } @@ -473,6 +493,44 @@ func extractSubtestFuzzExp( return []ast.Expr{e.Args[0]} } +// extractSynctestExp analyzes that call expression 'e' is synctest.Test +// and returns the test function. +func extractSynctestExp( + pass *analysis.Pass, e *ast.CallExpr, testFuncType types.Type, +) []ast.Expr { + // Check if this is a call to synctest.Test + selExpr, ok := e.Fun.(*ast.SelectorExpr) + if !ok { + return nil + } + + // Check if the selector is "Test" + if selExpr.Sel.Name != "Test" { + return nil + } + + // Check if the package is synctest by looking at the identifier + ident, ok := selExpr.X.(*ast.Ident) + if !ok { + return nil + } + + if !isIdentPackageName(pass, ident, "testing/synctest") { + return nil + } + + // synctest.Test takes 2 arguments: t *testing.T, f func(*testing.T) + if len(e.Args) != 2 { + return nil + } + + if funcs := unwrapTestingFunctionBuilding(pass, e.Args[1], testFuncType); funcs != nil { + return funcs + } + + return []ast.Expr{e.Args[1]} +} + // unwrapTestingFunctionConstruction checks that expresion is build testing functions // and returns the result of building. func unwrapTestingFunctionBuilding(pass *analysis.Pass, expr ast.Expr, testFuncType types.Type) []ast.Expr { @@ -482,6 +540,7 @@ func unwrapTestingFunctionBuilding(pass *analysis.Pass, expr ast.Expr, testFuncT } var funcDecl funcDecl + switch f := callExpr.Fun.(type) { case *ast.FuncLit: funcDecl.Body = f.Body @@ -512,6 +571,7 @@ func unwrapTestingFunctionBuilding(pass *analysis.Pass, expr ast.Expr, testFuncT } var funcs []ast.Expr + ast.Inspect(funcDecl.Body, func(n ast.Node) bool { if n == nil { return false @@ -522,6 +582,7 @@ func unwrapTestingFunctionBuilding(pass *analysis.Pass, expr ast.Expr, testFuncT funcs = append(funcs, retStmt.Results[0]) } } + return true }) @@ -542,6 +603,7 @@ func funcDefPosition(pass *analysis.Pass, e ast.Expr) token.Pos { if !ok { return token.NoPos } + funIdent = selExpr.Sel } @@ -574,6 +636,21 @@ func isExprHasType(pass *analysis.Pass, expr ast.Expr, expType types.Type) bool return types.Identical(typeInfo.Type, expType) } +// isIdentPackageName returns true if ident refers to the specified package. +func isIdentPackageName(pass *analysis.Pass, ident *ast.Ident, pkgName string) bool { + obj := pass.TypesInfo.Uses[ident] + if obj == nil { + return false + } + + pkgObj, ok := obj.(*types.PkgName) + if !ok { + return false + } + + return pkgObj.Imported().Path() == pkgName +} + // findSelectorDeclaration returns function declaration called by selector expression. func findSelectorDeclaration(pass *analysis.Pass, expr *ast.SelectorExpr) *ast.FuncDecl { xsel, ok := pass.TypesInfo.Selections[expr] @@ -637,3 +714,22 @@ func findFunctionDeclaration(pass *analysis.Pass, ident *ast.Ident) *ast.FuncDec return nil } + +func findTypeObject(pass *analysis.Pass, typeName string) types.Object { + parts := strings.Split(typeName, ".") + pkgName := parts[0] + typeName = parts[1] + + for _, pkg := range pass.Pkg.Imports() { + if pkg.Name() != pkgName { + continue + } + + obj := pkg.Scope().Lookup(typeName) + if obj != nil { + return obj + } + } + + return nil +} diff --git a/vendor/github.com/kulti/thelper/pkg/analyzer/report.go b/vendor/github.com/kulti/thelper/pkg/analyzer/report.go index 4a23e36d5..3ee332742 100644 --- a/vendor/github.com/kulti/thelper/pkg/analyzer/report.go +++ b/vendor/github.com/kulti/thelper/pkg/analyzer/report.go @@ -31,6 +31,7 @@ func (rr *reports) Filter(pos token.Pos) { if rr.filter == nil { rr.filter = make(map[token.Pos]struct{}) } + rr.filter[pos] = struct{}{} } } @@ -40,17 +41,19 @@ func (rr *reports) NoFilter(pos token.Pos) { if rr.nofilter == nil { rr.nofilter = make(map[token.Pos]struct{}) } + rr.nofilter[pos] = struct{}{} } } -func (rr reports) Flush(pass *analysis.Pass) { +func (rr *reports) Flush(pass *analysis.Pass) { for _, r := range rr.reports { if _, ok := rr.filter[r.pos]; ok { if _, ok := rr.nofilter[r.pos]; !ok { continue } } + pass.Reportf(r.pos, r.format, r.args...) } } diff --git a/vendor/github.com/kunwardeep/paralleltest/pkg/paralleltest/paralleltest.go b/vendor/github.com/kunwardeep/paralleltest/pkg/paralleltest/paralleltest.go index e9187d6fd..6f59e8408 100644 --- a/vendor/github.com/kunwardeep/paralleltest/pkg/paralleltest/paralleltest.go +++ b/vendor/github.com/kunwardeep/paralleltest/pkg/paralleltest/paralleltest.go @@ -12,8 +12,9 @@ import ( const Doc = `check that tests use t.Parallel() method It also checks that the t.Parallel is used if multiple tests cases are run as part of single test. -As part of ensuring parallel tests works as expected it checks for reinitialising of the range value -over the test cases.(https://tinyurl.com/y6555cy6)` +As part of ensuring parallel tests works as expected it checks for reinitializing of the range value +over the test cases.(https://tinyurl.com/y6555cy6) +With the -checkcleanup flag, it also checks that defer is not used with t.Parallel (use t.Cleanup instead).` func NewAnalyzer() *analysis.Analyzer { return newParallelAnalyzer().analyzer @@ -27,6 +28,7 @@ type parallelAnalyzer struct { ignoreMissing bool ignoreMissingSubtests bool ignoreLoopVar bool + checkCleanup bool } func newParallelAnalyzer() *parallelAnalyzer { @@ -36,6 +38,7 @@ func newParallelAnalyzer() *parallelAnalyzer { flags.BoolVar(&a.ignoreMissing, "i", false, "ignore missing calls to t.Parallel") flags.BoolVar(&a.ignoreMissingSubtests, "ignoremissingsubtests", false, "ignore missing calls to t.Parallel in subtests") flags.BoolVar(&a.ignoreLoopVar, "ignoreloopVar", false, "ignore loop variable detection") + flags.BoolVar(&a.checkCleanup, "checkcleanup", false, "check that defer is not used with t.Parallel (use t.Cleanup instead)") a.analyzer = &analysis.Analyzer{ Name: "paralleltest", @@ -46,138 +49,282 @@ func newParallelAnalyzer() *parallelAnalyzer { return a } -func (a *parallelAnalyzer) run(pass *analysis.Pass) (interface{}, error) { - inspector := inspector.New(pass.Files) +type testFunctionAnalysis struct { + funcHasParallelMethod, + funcCantParallelMethod, + rangeStatementOverTestCasesExists, + rangeStatementHasParallelMethod, + rangeStatementCantParallelMethod, + funcHasDeferStatement bool + loopVariableUsedInRun *string + numberOfTestRun int + positionOfTestRunNode []ast.Node + rangeNode ast.Node + deferStatements []ast.Node +} - nodeFilter := []ast.Node{ - (*ast.FuncDecl)(nil), - } +type testRunAnalysis struct { + hasParallel bool + cantParallel bool + numberOfTestRun int + positionOfTestRunNode []ast.Node +} - inspector.Preorder(nodeFilter, func(node ast.Node) { - funcDecl := node.(*ast.FuncDecl) - var funcHasParallelMethod, - funcCantParallelMethod, - rangeStatementOverTestCasesExists, - rangeStatementHasParallelMethod, - rangeStatementCantParallelMethod bool - var loopVariableUsedInRun *string - var numberOfTestRun int - var positionOfTestRunNode []ast.Node - var rangeNode ast.Node - - // Check runs for test functions only - isTest, testVar := isTestFunction(funcDecl) - if !isTest { - return - } +func (a *parallelAnalyzer) analyzeTestRun(pass *analysis.Pass, n ast.Node, testVar string) testRunAnalysis { + var analysis testRunAnalysis - for _, l := range funcDecl.Body.List { - switch v := l.(type) { + if methodRunIsCalledInTestFunction(n, testVar) { + innerTestVar := getRunCallbackParameterName(n) + analysis.numberOfTestRun++ - case *ast.ExprStmt: - ast.Inspect(v, func(n ast.Node) bool { - // Check if the test method is calling t.Parallel - if !funcHasParallelMethod { - funcHasParallelMethod = methodParallelIsCalledInTestFunction(n, testVar) + if callExpr, ok := n.(*ast.CallExpr); ok && len(callExpr.Args) > 1 { + if funcLit, ok := callExpr.Args[1].(*ast.FuncLit); ok { + ast.Inspect(funcLit, func(p ast.Node) bool { + if !analysis.hasParallel { + analysis.hasParallel = methodParallelIsCalledInTestFunction(p, innerTestVar) } - - // Check if the test calls t.Setenv, cannot be used in parallel tests or tests with parallel ancestors - if !funcCantParallelMethod { - funcCantParallelMethod = methodSetenvIsCalledInTestFunction(n, testVar) + if !analysis.cantParallel { + analysis.cantParallel = methodSetenvIsCalledInTestFunction(p, innerTestVar) } - - // Check if the t.Run within the test function is calling t.Parallel - if methodRunIsCalledInTestFunction(n, testVar) { - // n is a call to t.Run; find out the name of the subtest's *testing.T parameter. - innerTestVar := getRunCallbackParameterName(n) - - hasParallel := false - cantParallel := false - numberOfTestRun++ - ast.Inspect(v, func(p ast.Node) bool { - if !hasParallel { - hasParallel = methodParallelIsCalledInTestFunction(p, innerTestVar) - } - if !cantParallel { - cantParallel = methodSetenvIsCalledInTestFunction(p, innerTestVar) + return true + }) + } else if ident, ok := callExpr.Args[1].(*ast.Ident); ok { + // Case 2: Direct function identifier: t.Run("name", myFunc) + foundFunc := false + for _, file := range pass.Files { + for _, decl := range file.Decls { + if funcDecl, ok := decl.(*ast.FuncDecl); ok && funcDecl.Name.Name == ident.Name { + foundFunc = true + isReceivingTestContext, testParamName := isFunctionReceivingTestContext(funcDecl) + if isReceivingTestContext { + ast.Inspect(funcDecl, func(p ast.Node) bool { + if !analysis.hasParallel { + analysis.hasParallel = methodParallelIsCalledInTestFunction(p, testParamName) + } + return true + }) } - return true - }) - if !hasParallel && !cantParallel { - positionOfTestRunNode = append(positionOfTestRunNode, n) } } - return true - }) + } + if !foundFunc { + analysis.hasParallel = false + } + } else if builderCall, ok := callExpr.Args[1].(*ast.CallExpr); ok { + // Case 3: Function call that returns a function: t.Run("name", builder()) + analysis.hasParallel = a.checkBuilderFunctionForParallel(pass, builderCall) + } + } - // Check if the range over testcases is calling t.Parallel - case *ast.RangeStmt: - rangeNode = v + if !analysis.hasParallel && !analysis.cantParallel { + analysis.positionOfTestRunNode = append(analysis.positionOfTestRunNode, n) + } + } - var loopVars []types.Object - for _, expr := range []ast.Expr{v.Key, v.Value} { - if id, ok := expr.(*ast.Ident); ok { - loopVars = append(loopVars, pass.TypesInfo.ObjectOf(id)) - } - } + return analysis +} - ast.Inspect(v, func(n ast.Node) bool { - // nolint: gocritic - switch r := n.(type) { - case *ast.ExprStmt: - if methodRunIsCalledInRangeStatement(r.X, testVar) { - // r.X is a call to t.Run; find out the name of the subtest's *testing.T parameter. - innerTestVar := getRunCallbackParameterName(r.X) +func (a *parallelAnalyzer) analyzeTestFunction(pass *analysis.Pass, funcDecl *ast.FuncDecl) { + var analysis testFunctionAnalysis - rangeStatementOverTestCasesExists = true + // Check runs for test functions only + isTest, testVar := isTestFunction(funcDecl) + if !isTest { + return + } - if !rangeStatementHasParallelMethod { - rangeStatementHasParallelMethod = methodParallelIsCalledInMethodRun(r.X, innerTestVar) - } + for _, l := range funcDecl.Body.List { + switch v := l.(type) { + case *ast.DeferStmt: + if a.checkCleanup { + analysis.funcHasDeferStatement = true + analysis.deferStatements = append(analysis.deferStatements, v) + } + + case *ast.ExprStmt: + ast.Inspect(v, func(n ast.Node) bool { + if !analysis.funcHasParallelMethod { + analysis.funcHasParallelMethod = methodParallelIsCalledInTestFunction(n, testVar) + } + if !analysis.funcCantParallelMethod { + analysis.funcCantParallelMethod = methodSetenvIsCalledInTestFunction(n, testVar) + } + runAnalysis := a.analyzeTestRun(pass, n, testVar) + analysis.numberOfTestRun += runAnalysis.numberOfTestRun + analysis.positionOfTestRunNode = append(analysis.positionOfTestRunNode, runAnalysis.positionOfTestRunNode...) + return true + }) + + case *ast.RangeStmt: + analysis.rangeNode = v + + var loopVars []types.Object + for _, expr := range []ast.Expr{v.Key, v.Value} { + if id, ok := expr.(*ast.Ident); ok { + loopVars = append(loopVars, pass.TypesInfo.ObjectOf(id)) + } + } - if !rangeStatementCantParallelMethod { - rangeStatementCantParallelMethod = methodSetenvIsCalledInMethodRun(r.X, innerTestVar) + ast.Inspect(v, func(n ast.Node) bool { + if r, ok := n.(*ast.ExprStmt); ok { + if methodRunIsCalledInRangeStatement(r.X, testVar) { + innerTestVar := getRunCallbackParameterName(r.X) + analysis.rangeStatementOverTestCasesExists = true + + if !analysis.rangeStatementHasParallelMethod { + analysis.rangeStatementHasParallelMethod = methodParallelIsCalledInMethodRun(r.X, innerTestVar) + } + if !analysis.rangeStatementCantParallelMethod { + analysis.rangeStatementCantParallelMethod = methodSetenvIsCalledInMethodRun(r.X, innerTestVar) + } + if !a.ignoreLoopVar && analysis.loopVariableUsedInRun == nil { + if run, ok := r.X.(*ast.CallExpr); ok { + analysis.loopVariableUsedInRun = loopVarReferencedInRun(run, loopVars, pass.TypesInfo) } + } - if !a.ignoreLoopVar && loopVariableUsedInRun == nil { - if run, ok := r.X.(*ast.CallExpr); ok { - loopVariableUsedInRun = loopVarReferencedInRun(run, loopVars, pass.TypesInfo) - } + // Check nested test runs + if callExpr, ok := r.X.(*ast.CallExpr); ok && len(callExpr.Args) > 1 { + if funcLit, ok := callExpr.Args[1].(*ast.FuncLit); ok { + ast.Inspect(funcLit, func(p ast.Node) bool { + runAnalysis := a.analyzeTestRun(pass, p, innerTestVar) + analysis.numberOfTestRun += runAnalysis.numberOfTestRun + analysis.positionOfTestRunNode = append(analysis.positionOfTestRunNode, runAnalysis.positionOfTestRunNode...) + return true + }) } } } - return true - }) + } + return true + }) + } + } + + if analysis.rangeStatementCantParallelMethod { + analysis.funcCantParallelMethod = true + } + + if !a.ignoreMissing && !analysis.funcHasParallelMethod && !analysis.funcCantParallelMethod { + pass.Reportf(funcDecl.Pos(), "Function %s missing the call to method parallel\n", funcDecl.Name.Name) + } + + if analysis.rangeStatementOverTestCasesExists && analysis.rangeNode != nil { + if !analysis.rangeStatementHasParallelMethod && !analysis.rangeStatementCantParallelMethod { + if !a.ignoreMissing && !a.ignoreMissingSubtests { + pass.Reportf(analysis.rangeNode.Pos(), "Range statement for test %s missing the call to method parallel in test Run\n", funcDecl.Name.Name) } + } else if analysis.loopVariableUsedInRun != nil && !a.ignoreLoopVar { + pass.Reportf(analysis.rangeNode.Pos(), "Range statement for test %s does not reinitialise the variable %s\n", funcDecl.Name.Name, *analysis.loopVariableUsedInRun) } + } - // Descendents which call Setenv, also prevent tests from calling Parallel - if rangeStatementCantParallelMethod { - funcCantParallelMethod = true + if !a.ignoreMissing && !a.ignoreMissingSubtests { + if analysis.numberOfTestRun > 1 && len(analysis.positionOfTestRunNode) > 0 { + for _, n := range analysis.positionOfTestRunNode { + pass.Reportf(n.Pos(), "Function %s missing the call to method parallel in the test run\n", funcDecl.Name.Name) + } } + } - if !a.ignoreMissing && !funcHasParallelMethod && !funcCantParallelMethod { - pass.Reportf(node.Pos(), "Function %s missing the call to method parallel\n", funcDecl.Name.Name) + if a.checkCleanup && analysis.funcHasParallelMethod && analysis.funcHasDeferStatement { + for _, deferStmt := range analysis.deferStatements { + pass.Reportf(deferStmt.Pos(), "Function %s uses defer with t.Parallel, use t.Cleanup instead to ensure cleanup runs after parallel subtests complete", funcDecl.Name.Name) } + } +} - if rangeStatementOverTestCasesExists && rangeNode != nil { - if !rangeStatementHasParallelMethod && !rangeStatementCantParallelMethod { - if !a.ignoreMissing && !a.ignoreMissingSubtests { - pass.Reportf(rangeNode.Pos(), "Range statement for test %s missing the call to method parallel in test Run\n", funcDecl.Name.Name) - } - } else if loopVariableUsedInRun != nil { - pass.Reportf(rangeNode.Pos(), "Range statement for test %s does not reinitialise the variable %s\n", funcDecl.Name.Name, *loopVariableUsedInRun) +// checkBuilderFunctionForParallel analyzes a function call that returns a test function +// to see if the returned function contains t.Parallel() +func (a *parallelAnalyzer) checkBuilderFunctionForParallel(pass *analysis.Pass, builderCall *ast.CallExpr) bool { + // Get the name of the builder function being called + var builderFuncName string + switch fun := builderCall.Fun.(type) { + case *ast.Ident: + builderFuncName = fun.Name + case *ast.SelectorExpr: + // Handle method calls like obj.Builder() + builderFuncName = fun.Sel.Name + default: + return false + } + + if builderFuncName == "" { + return false + } + + // Find the builder function declaration + for _, file := range pass.Files { + for _, decl := range file.Decls { + funcDecl, ok := decl.(*ast.FuncDecl) + if !ok || funcDecl.Name.Name != builderFuncName { + continue } - } - // Check if the t.Run is more than one as there is no point making one test parallel - if !a.ignoreMissing && !a.ignoreMissingSubtests { - if numberOfTestRun > 1 && len(positionOfTestRunNode) > 0 { - for _, n := range positionOfTestRunNode { - pass.Reportf(n.Pos(), "Function %s missing the call to method parallel in the test run\n", funcDecl.Name.Name) + // Found the builder function, analyze it and return immediately + hasParallel := false + ast.Inspect(funcDecl, func(n ast.Node) bool { + // Look for return statements + returnStmt, ok := n.(*ast.ReturnStmt) + if !ok || len(returnStmt.Results) == 0 { + return true } - } + + // Check if the return value is a function literal + for _, result := range returnStmt.Results { + if funcLit, ok := result.(*ast.FuncLit); ok { + // Get the parameter name from the returned function + var paramName string + if funcLit.Type != nil && funcLit.Type.Params != nil && len(funcLit.Type.Params.List) > 0 { + param := funcLit.Type.Params.List[0] + if len(param.Names) > 0 { + paramName = param.Names[0].Name + } + } + + // Inspect the returned function for t.Parallel() + if paramName != "" { + ast.Inspect(funcLit, func(p ast.Node) bool { + if methodParallelIsCalledInTestFunction(p, paramName) { + hasParallel = true + return false + } + return true + }) + + // Exit inspection immediately if we found t.Parallel() + if hasParallel { + return false + } + } + } + } + // Continue to next return statement if t.Parallel() not found yet + return true + }) + + // Return immediately after processing the matching function + return hasParallel } + } + + return false +} + +func (a *parallelAnalyzer) run(pass *analysis.Pass) (interface{}, error) { + inspector := inspector.New(pass.Files) + + nodeFilter := []ast.Node{ + (*ast.FuncDecl)(nil), + } + + inspector.Preorder(nodeFilter, func(node ast.Node) { + funcDecl := node.(*ast.FuncDecl) + // Only process _test.go files + if !strings.HasSuffix(pass.Fset.File(funcDecl.Pos()).Name(), "_test.go") { + return + } + a.analyzeTestFunction(pass, funcDecl) }) return nil, nil @@ -267,8 +414,38 @@ func getRunCallbackParameterName(node ast.Node) string { return "" } -// Checks if the function has the param type *testing.T; if it does, then the -// parameter name is returned, too. +// isFunctionReceivingTestContext checks if a function declaration receives a *testing.T parameter +// Returns (true, paramName) if it does, (false, "") if it doesn't +func isFunctionReceivingTestContext(funcDecl *ast.FuncDecl) (bool, string) { + testMethodPackageType := "testing" + testMethodStruct := "T" + + if funcDecl.Type.Params != nil && len(funcDecl.Type.Params.List) != 1 { + return false, "" + } + + param := funcDecl.Type.Params.List[0] + if starExp, ok := param.Type.(*ast.StarExpr); ok { + if selectExpr, ok := starExp.X.(*ast.SelectorExpr); ok { + if selectExpr.Sel.Name == testMethodStruct { + if s, ok := selectExpr.X.(*ast.Ident); ok { + if len(param.Names) > 0 { + return s.Name == testMethodPackageType, param.Names[0].Name + } + } + } + } + } + + return false, "" +} + +// isTestFunction checks if a function declaration is a test function +// A test function must: +// 1. Start with "Test" +// 2. Have exactly one parameter +// 3. Have that parameter be of type *testing.T +// Returns (true, paramName) if it is a test function, (false, "") if it isn't func isTestFunction(funcDecl *ast.FuncDecl) (bool, string) { testMethodPackageType := "testing" testMethodStruct := "T" @@ -298,6 +475,8 @@ func isTestFunction(funcDecl *ast.FuncDecl) (bool, string) { return false, "" } +// loopVarReferencedInRun checks if a loop variable is referenced within a test run +// This is important for detecting potential race conditions in parallel tests func loopVarReferencedInRun(call *ast.CallExpr, vars []types.Object, typeInfo *types.Info) (found *string) { if len(call.Args) != 2 { return diff --git a/vendor/github.com/kyoh86/exportloopref/.golangci.yml b/vendor/github.com/kyoh86/exportloopref/.golangci.yml deleted file mode 100644 index e876057f3..000000000 --- a/vendor/github.com/kyoh86/exportloopref/.golangci.yml +++ /dev/null @@ -1,4 +0,0 @@ -linters: - enable: - - unparam - - exportloopref diff --git a/vendor/github.com/kyoh86/exportloopref/.goreleaser.yml b/vendor/github.com/kyoh86/exportloopref/.goreleaser.yml deleted file mode 100644 index 95d44aaac..000000000 --- a/vendor/github.com/kyoh86/exportloopref/.goreleaser.yml +++ /dev/null @@ -1,51 +0,0 @@ -# yaml-language-server: $schema=https://goreleaser.com/static/schema.json - -project_name: exportloopref -builds: - - id: default - goos: - - linux - - darwin - - windows - goarch: - - amd64 - - arm64 - - "386" - main: ./cmd/exportloopref - binary: exportloopref -brews: - - install: | - bin.install "exportloopref" - tap: - owner: kyoh86 - name: homebrew-tap - folder: Formula - homepage: https://github.com/kyoh86/exportloopref - description: An analyzer that finds exporting pointers for loop variables. - license: MIT -nfpms: - - builds: - - default - maintainer: kyoh86 - homepage: https://github.com/kyoh86/exportloopref - description: An analyzer that finds exporting pointers for loop variables. - license: MIT - formats: - - apk - - deb - - rpm -archives: - - id: gzip - format: tar.gz - format_overrides: - - goos: windows - format: zip - files: - - licence* - - LICENCE* - - license* - - LICENSE* - - readme* - - README* - - changelog* - - CHANGELOG* diff --git a/vendor/github.com/kyoh86/exportloopref/LICENSE b/vendor/github.com/kyoh86/exportloopref/LICENSE deleted file mode 100644 index 7ac9dba4a..000000000 --- a/vendor/github.com/kyoh86/exportloopref/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2020 kyoh86 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE -OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/kyoh86/exportloopref/Makefile b/vendor/github.com/kyoh86/exportloopref/Makefile deleted file mode 100644 index 4d3ef22f7..000000000 --- a/vendor/github.com/kyoh86/exportloopref/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -.PHONY: gen lint test install man - -VERSION := `git vertag get` -COMMIT := `git rev-parse HEAD` - -gen: - go generate ./... - -lint: gen - golangci-lint run - -test: lint - go test -v --race ./... - -install: test - go install -a -ldflags "-X=main.version=$(VERSION) -X=main.commit=$(COMMIT)" ./... diff --git a/vendor/github.com/kyoh86/exportloopref/README.md b/vendor/github.com/kyoh86/exportloopref/README.md deleted file mode 100644 index 0f581ffce..000000000 --- a/vendor/github.com/kyoh86/exportloopref/README.md +++ /dev/null @@ -1,223 +0,0 @@ -# exportloopref - -An analyzer that finds exporting pointers for loop variables. -![](https://repository-images.githubusercontent.com/256768552/a1c5bb80-dd73-11eb-9453-e520f517e730) -Pin them all! - -[![PkgGoDev](https://pkg.go.dev/badge/kyoh86/exportloopref)](https://pkg.go.dev/kyoh86/exportloopref) -[![Go Report Card](https://goreportcard.com/badge/github.com/kyoh86/exportloopref)](https://goreportcard.com/report/github.com/kyoh86/exportloopref) -[![Coverage Status](https://img.shields.io/codecov/c/github/kyoh86/exportloopref.svg)](https://codecov.io/gh/kyoh86/exportloopref) -[![Release](https://github.com/kyoh86/exportloopref/workflows/Release/badge.svg)](https://github.com/kyoh86/exportloopref/releases) - -## What's this? - -Sample problem code from: https://github.com/kyoh86/exportloopref/blob/main/testdata/src/simple/simple.go - -```go -package main - -func main() { - var intArray [4]*int - var intSlice []*int - var intRef *int - var intStr struct{ x *int } - - println("loop expecting 10, 11, 12, 13") - for i, p := range []int{10, 11, 12, 13} { - printp(&p) // not a diagnostic - intSlice = append(intSlice, &p) // want "exporting a pointer for the loop variable p" - intArray[i] = &p // want "exporting a pointer for the loop variable p" - if i%2 == 0 { - intRef = &p // want "exporting a pointer for the loop variable p" - intStr.x = &p // want "exporting a pointer for the loop variable p" - } - var vStr struct{ x *int } - var vArray [4]*int - var v *int - if i%2 == 0 { - v = &p // not a diagnostic (x is local variable) - vArray[1] = &p // not a diagnostic (x is local variable) - vStr.x = &p - } - _ = v - } - - println(`slice expecting "10, 11, 12, 13" but "13, 13, 13, 13"`) - for _, p := range intSlice { - printp(p) - } - println(`array expecting "10, 11, 12, 13" but "13, 13, 13, 13"`) - for _, p := range intArray { - printp(p) - } - println(`captured value expecting "12" but "13"`) - printp(intRef) -} - -func printp(p *int) { - println(*p) -} -``` - -In Go, the `p` variable in the above loops is actually a single variable. -So in many case (like the above), using it makes for us annoying bugs. - -You can find them with `exportloopref`, and fix it. - -```go -package main - -func main() { - var intArray [4]*int - var intSlice []*int - var intRef *int - var intStr struct{ x *int } - - println("loop expecting 10, 11, 12, 13") - for i, p := range []int{10, 11, 12, 13} { - p := p // FIX variable into the local variable - printp(&p) - intSlice = append(intSlice, &p) - intArray[i] = &p - if i%2 == 0 { - intRef = &p - intStr.x = &p - } - var vStr struct{ x *int } - var vArray [4]*int - var v *int - if i%2 == 0 { - v = &p - vArray[1] = &p - vStr.x = &p - } - _ = v - } - - println(`slice expecting "10, 11, 12, 13"`) - for _, p := range intSlice { - printp(p) - } - println(`array expecting "10, 11, 12, 13"`) - for _, p := range intArray { - printp(p) - } - println(`captured value expecting "12"`) - printp(intRef) -} - -func printp(p *int) { - println(*p) -} -``` - -ref: https://github.com/kyoh86/exportloopref/blob/main/testdata/src/fixed/fixed.go - -## Sensing policy - -I want to make exportloopref as accurately as possible. -So some cases of lints will be false-negative. - -e.g. - -```go -var s Foo -for _, p := range []int{10, 11, 12, 13} { - s.Bar(&p) // If s stores the pointer, it will be bug. -} -``` - -If you want to report all of lints (with some false-positives), -you should use [looppointer](https://github.com/kyoh86/looppointer). - -### Known false negatives - -Case 1: pass the pointer to function to export. - -Case 2: pass the pointer to local variable, and export it. - -```go -package main - -type List []*int - -func (l *List) AppendP(p *int) { - *l = append(*l, p) -} - -func main() { - var slice []*int - list := List{} - - println("loop expect exporting 10, 11, 12, 13") - for _, v := range []int{10, 11, 12, 13} { - list.AppendP(&v) // Case 1: wanted "exporting a pointer for the loop variable v", but cannot be found - - p := &v // p is the local variable - slice = append(slice, p) // Case 2: wanted "exporting a pointer for the loop variable v", but cannot be found - } - - println(`slice expecting "10, 11, 12, 13" but "13, 13, 13, 13"`) - for _, p := range slice { - printp(p) - } - println(`array expecting "10, 11, 12, 13" but "13, 13, 13, 13"`) - for _, p := range ([]*int)(list) { - printp(p) - } -} - -func printp(p *int) { - println(*p) -} -``` - -## Install - -go: - -```console -$ go get github.com/kyoh86/exportloopref/cmd/exportloopref -``` - -[homebrew](https://brew.sh/): - -```console -$ brew install kyoh86/tap/exportloopref -``` - -[gordon](https://github.com/kyoh86/gordon): - -```console -$ gordon install kyoh86/exportloopref -``` - -## Usage - -``` -exportloopref [-flag] [package] -``` - -### Flags - -| Flag | Description | -| --- | --- | -| -V | print version and exit | -| -all | no effect (deprecated) | -| -c int | display offending line with this many lines of context (default -1) | -| -cpuprofile string | write CPU profile to this file | -| -debug string | debug flags, any subset of "fpstv" | -| -fix | apply all suggested fixes | -| -flags | print analyzer flags in JSON | -| -json | emit JSON output | -| -memprofile string | write memory profile to this file | -| -source | no effect (deprecated) | -| -tags string | no effect (deprecated) | -| -trace string | write trace log to this file | -| -v | no effect (deprecated) | - -# LICENSE - -[![MIT License](http://img.shields.io/badge/license-MIT-blue.svg)](http://www.opensource.org/licenses/MIT) - -This is distributed under the [MIT License](http://www.opensource.org/licenses/MIT). diff --git a/vendor/github.com/kyoh86/exportloopref/exportloopref.go b/vendor/github.com/kyoh86/exportloopref/exportloopref.go deleted file mode 100644 index d071d5c35..000000000 --- a/vendor/github.com/kyoh86/exportloopref/exportloopref.go +++ /dev/null @@ -1,334 +0,0 @@ -package exportloopref - -import ( - "fmt" - "go/ast" - "go/token" - "go/types" - - "golang.org/x/tools/go/analysis" - "golang.org/x/tools/go/analysis/passes/inspect" - "golang.org/x/tools/go/ast/inspector" -) - -var Analyzer = &analysis.Analyzer{ - Name: "exportloopref", - Doc: "checks for pointers to enclosing loop variables", - Run: run, - RunDespiteErrors: true, - Requires: []*analysis.Analyzer{inspect.Analyzer}, -} - -func run(pass *analysis.Pass) (interface{}, error) { - inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) - - search := &Searcher{ - LoopVars: map[token.Pos]struct{}{}, - LocalVars: map[token.Pos]map[token.Pos]struct{}{}, - Pass: pass, - } - - nodeFilter := []ast.Node{ - (*ast.RangeStmt)(nil), - (*ast.ForStmt)(nil), - (*ast.DeclStmt)(nil), - (*ast.AssignStmt)(nil), - (*ast.UnaryExpr)(nil), - } - - inspect.WithStack(nodeFilter, search.CheckAndReport) - - return nil, nil -} - -type Searcher struct { - // LoopVars is positions that loop-variables are declared like below. - // - for , := range ... - // - for := ; ; - LoopVars map[token.Pos]struct{} - // LocalVars is positions of loops and the variables declared in them. - // Use this to determine if a point assignment is an export outside the loop. - LocalVars map[token.Pos]map[token.Pos]struct{} - - Pass *analysis.Pass -} - -// CheckAndReport inspects each node with stack. -// It is implemented as the I/F of the "golang.org/x/tools/go/analysis/passes/inspect".Analysis.WithStack. -func (s *Searcher) CheckAndReport(n ast.Node, push bool, stack []ast.Node) bool { - id, insert, digg := s.Check(n, stack) - if id == nil { - // no prob. - return digg - } - - // suggests fix - var suggest []analysis.SuggestedFix - if insert != token.NoPos { - suggest = []analysis.SuggestedFix{{ - Message: fmt.Sprintf("loop variable %s should be pinned", id.Name), - TextEdits: []analysis.TextEdit{{ - Pos: insert, - End: insert, - NewText: []byte(fmt.Sprintf("%[1]s := %[1]s\n", id.Name)), - }}, - }} - } - - // report a diagnostic - d := analysis.Diagnostic{Pos: id.Pos(), - End: id.End(), - Message: fmt.Sprintf("exporting a pointer for the loop variable %s", id.Name), - Category: "exportloopref", - SuggestedFixes: suggest, - } - s.Pass.Report(d) - return digg -} - -// Check each node and stack, whether it exports loop variables or not. -// Finding export, report the *ast.Ident of exported loop variable, -// and token.Pos to insert assignment to fix the diagnostic. -func (s *Searcher) Check(n ast.Node, stack []ast.Node) (loopVar *ast.Ident, insertPos token.Pos, digg bool) { - switch typed := n.(type) { - case *ast.RangeStmt: - s.parseRangeStmt(typed) - case *ast.ForStmt: - s.parseForStmt(typed) - case *ast.DeclStmt: - s.parseDeclStmt(typed, stack) - case *ast.AssignStmt: - s.parseAssignStmt(typed, stack) - - case *ast.UnaryExpr: - return s.checkUnaryExpr(typed, stack) - } - return nil, token.NoPos, true -} - -// parseRangeStmt will check range statement (i.e. `for , := range ...`), -// and collect positions of and . -func (s *Searcher) parseRangeStmt(n *ast.RangeStmt) { - s.storeLoopVars(n.Key) - s.storeLoopVars(n.Value) -} - -// parseForStmt will check for statement (i.e. `for := ; ; `), -// and collect positions of . -func (s *Searcher) parseForStmt(n *ast.ForStmt) { - switch post := n.Post.(type) { - case *ast.AssignStmt: - // e.g. for p = head; p != nil; p = p.next - for _, lhs := range post.Lhs { - s.storeLoopVars(lhs) - } - case *ast.IncDecStmt: - // e.g. for i := 0; i < n; i++ - s.storeLoopVars(post.X) - } -} - -func (s *Searcher) storeLoopVars(expr ast.Expr) { - if id, ok := expr.(*ast.Ident); ok { - s.LoopVars[id.Pos()] = struct{}{} - } -} - -// parseDeclStmt will parse declaring statement (i.e. `var`, `type`, `const`), -// and store the position if it is "var" declaration and is in any loop. -func (s *Searcher) parseDeclStmt(n *ast.DeclStmt, stack []ast.Node) { - genDecl, ok := n.Decl.(*ast.GenDecl) - if !ok { - // (dead branch) - // if the Decl is not GenDecl (i.e. `var`, `type` or `const` statement), it is ignored - return - } - if genDecl.Tok != token.VAR { - // if the Decl is not `var` (may be `type` or `const`), it is ignored - return - } - - loop, _ := s.innermostLoop(stack) - if loop == nil { - return - } - - // Register declared variables - for _, spec := range genDecl.Specs { - for _, name := range spec.(*ast.ValueSpec).Names { - s.storeLocalVar(loop, name) - } - } -} - -// parseDeclStmt will parse assignment statement (i.e. ` = `), -// and store the position if it is . -func (s *Searcher) parseAssignStmt(n *ast.AssignStmt, stack []ast.Node) { - if n.Tok != token.DEFINE { - // if the statement is simple assignment (without definement), it is ignored - return - } - - loop, _ := s.innermostLoop(stack) - if loop == nil { - return - } - - // Find statements declaring local variable - for _, h := range n.Lhs { - s.storeLocalVar(loop, h) - } -} - -func (s *Searcher) storeLocalVar(loop ast.Node, expr ast.Expr) { - loopPos := loop.Pos() - id, ok := expr.(*ast.Ident) - if !ok { - return - } - vars, ok := s.LocalVars[loopPos] - if !ok { - vars = map[token.Pos]struct{}{} - } - vars[id.Obj.Pos()] = struct{}{} - s.LocalVars[loopPos] = vars -} - -func insertionPosition(block *ast.BlockStmt) token.Pos { - if len(block.List) > 0 { - return block.List[0].Pos() - } - return token.NoPos -} - -func (s *Searcher) innermostLoop(stack []ast.Node) (ast.Node, token.Pos) { - for i := len(stack) - 1; i >= 0; i-- { - switch typed := stack[i].(type) { - case *ast.RangeStmt: - return typed, insertionPosition(typed.Body) - case *ast.ForStmt: - return typed, insertionPosition(typed.Body) - } - } - return nil, token.NoPos -} - -// checkUnaryExpr check unary expression (i.e. like `-x`, `*p` or `&v`) and stack. -// THIS IS THE ESSENTIAL PART OF THIS PARSER. -func (s *Searcher) checkUnaryExpr(n *ast.UnaryExpr, stack []ast.Node) (*ast.Ident, token.Pos, bool) { - if n.Op != token.AND { - return nil, token.NoPos, true - } - - loop, insert := s.innermostLoop(stack) - if loop == nil { - return nil, token.NoPos, true - } - - // Get identity of the referred item - id := s.getIdentity(n.X) - if id == nil { - return nil, token.NoPos, true - } - - // If the identity is not the loop statement variable, - // it will not be reported. - if _, isDecl := s.LoopVars[id.Obj.Pos()]; !isDecl { - return nil, token.NoPos, true - } - - // check stack append(), []X{}, map[Type]X{}, Struct{}, &Struct{}, X.(Type), (X) - // in the = - var mayRHPos token.Pos - for i := len(stack) - 2; i >= 0; i-- { - switch typed := stack[i].(type) { - case (*ast.UnaryExpr): - // noop - case (*ast.CompositeLit): - // noop - case (*ast.KeyValueExpr): - // noop - case (*ast.CallExpr): - fun, ok := typed.Fun.(*ast.Ident) - if !ok { - return nil, token.NoPos, false // it's calling a function other of `append`. It cannot be checked - } - - if fun.Name != "append" { - return nil, token.NoPos, false // it's calling a function other of `append`. It cannot be checked - } - - case (*ast.AssignStmt): - if len(typed.Rhs) != len(typed.Lhs) { - return nil, token.NoPos, false // dead logic - } - - // search x where Rhs[x].Pos() == mayRHPos - var index int - for ri, rh := range typed.Rhs { - if rh.Pos() == mayRHPos { - index = ri - break - } - } - - // check Lhs[x] is not local variable - lh := typed.Lhs[index] - isVar := s.isVar(loop, lh) - if !isVar { - return id, insert, false - } - - return nil, token.NoPos, true - default: - // Other statement is not able to be checked. - return nil, token.NoPos, false - } - - // memory an expr that may be right-hand in the AssignStmt - mayRHPos = stack[i].Pos() - } - return nil, token.NoPos, true -} - -func (s *Searcher) isVar(loop ast.Node, expr ast.Expr) bool { - vars := s.LocalVars[loop.Pos()] // map[token.Pos]struct{} - if vars == nil { - return false - } - switch typed := expr.(type) { - case (*ast.Ident): - if typed.Obj == nil { - return false // global var in another file (ref: #13) - } - _, isVar := vars[typed.Obj.Pos()] - return isVar - case (*ast.IndexExpr): // like X[Y], check X - return s.isVar(loop, typed.X) - case (*ast.SelectorExpr): // like X.Y, check X - return s.isVar(loop, typed.X) - } - return false -} - -// Get variable identity -func (s *Searcher) getIdentity(expr ast.Expr) *ast.Ident { - switch typed := expr.(type) { - case *ast.SelectorExpr: - // Ignore if the parent is pointer ref (fix for #2) - if _, ok := s.Pass.TypesInfo.Types[typed.X].Type.(*types.Pointer); ok { - return nil - } - - // Get parent identity; i.e. `a.b` of the `a.b.c`. - return s.getIdentity(typed.X) - - case *ast.Ident: - // Get simple identity; i.e. `a` of the `a`. - if typed.Obj == nil { - return nil - } - return typed - } - return nil -} diff --git a/vendor/github.com/ldez/exptostd/.gitignore b/vendor/github.com/ldez/exptostd/.gitignore new file mode 100644 index 000000000..ec3a60398 --- /dev/null +++ b/vendor/github.com/ldez/exptostd/.gitignore @@ -0,0 +1,2 @@ +/exptostd +.idea diff --git a/vendor/github.com/ldez/exptostd/.golangci.yml b/vendor/github.com/ldez/exptostd/.golangci.yml new file mode 100644 index 000000000..2675c2863 --- /dev/null +++ b/vendor/github.com/ldez/exptostd/.golangci.yml @@ -0,0 +1,79 @@ +version: "2" + +formatters: + enable: + - gci + - gofumpt + settings: + gofumpt: + extra-rules: true + +linters: + default: all + disable: + - cyclop # duplicate of gocyclo + - dupl + - errchkjson + - exhaustive + - exhaustruct + - lll + - nilnil + - nlreturn + - nonamedreturns + - paralleltest + - prealloc + - rowserrcheck # not relevant (SQL) + - sqlclosecheck # not relevant (SQL) + - testpackage + - tparallel + - varnamelen + - wsl # deprecated + settings: + depguard: + rules: + main: + deny: + - pkg: github.com/instana/testify + desc: not allowed + - pkg: github.com/pkg/errors + desc: Should be replaced by standard lib errors package + funlen: + lines: -1 + statements: 40 + goconst: + min-len: 5 + min-occurrences: 3 + gocritic: + disabled-checks: + - sloppyReassign + - rangeValCopy + - octalLiteral + - paramTypeCombine # already handle by gofumpt.extra-rules + enabled-tags: + - diagnostic + - style + - performance + settings: + hugeParam: + sizeThreshold: 100 + gocyclo: + min-complexity: 20 + godox: + keywords: + - FIXME + govet: + disable: + - fieldalignment + enable-all: true + misspell: + locale: US + nolintlint: + require-explanation: true + require-specific: true + wsl: + force-case-trailing-whitespace: 1 + allow-trailing-comment: true + +issues: + max-issues-per-linter: 0 + max-same-issues: 0 diff --git a/vendor/github.com/ldez/exptostd/LICENSE b/vendor/github.com/ldez/exptostd/LICENSE new file mode 100644 index 000000000..c1bf0c328 --- /dev/null +++ b/vendor/github.com/ldez/exptostd/LICENSE @@ -0,0 +1,190 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2024 Fernandez Ludovic + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/ldez/exptostd/Makefile b/vendor/github.com/ldez/exptostd/Makefile new file mode 100644 index 000000000..ad7275149 --- /dev/null +++ b/vendor/github.com/ldez/exptostd/Makefile @@ -0,0 +1,15 @@ +.PHONY: clean check test build + +default: clean check test build + +clean: + rm -rf dist/ cover.out + +test: clean + go test -v -cover ./... + +check: + golangci-lint run + +build: + go build -ldflags "-s -w" -trimpath ./cmd/exptostd/ diff --git a/vendor/github.com/ldez/exptostd/exptostd.go b/vendor/github.com/ldez/exptostd/exptostd.go new file mode 100644 index 000000000..aa5dc5ada --- /dev/null +++ b/vendor/github.com/ldez/exptostd/exptostd.go @@ -0,0 +1,482 @@ +// Package exptostd It is an analyzer that detects functions from golang.org/x/exp/ that can be replaced by std functions. +package exptostd + +import ( + "bytes" + "fmt" + "go/ast" + "go/build" + "go/printer" + "go/token" + "go/types" + "os" + "slices" + "strconv" + "strings" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/ast/inspector" +) + +const ( + pkgExpMaps = "golang.org/x/exp/maps" + pkgExpSlices = "golang.org/x/exp/slices" + pkgExpConstraints = "golang.org/x/exp/constraints" +) + +const ( + pkgMaps = "maps" + pkgSlices = "slices" + pkgComp = "cmp" +) + +const ( + go123 = 123 + go121 = 121 + goDevel = 666 +) + +// Result is step analysis results. +type Result struct { + shouldKeepImport bool + Diagnostics []analysis.Diagnostic +} + +type stdReplacement[T ast.Expr] struct { + MinGo int + Text string + Suggested func(callExpr T) (analysis.SuggestedFix, error) +} + +type analyzer struct { + mapsPkgReplacements map[string]stdReplacement[*ast.CallExpr] + slicesPkgReplacements map[string]stdReplacement[*ast.CallExpr] + constraintsPkgReplacements map[string]stdReplacement[*ast.SelectorExpr] + + skipGoVersionDetection bool +} + +// NewAnalyzer create a new Analyzer. +func NewAnalyzer() *analysis.Analyzer { + _, skip := os.LookupEnv("EXPTOSTD_SKIP_GO_VERSION_CHECK") + + l := &analyzer{ + skipGoVersionDetection: skip, + mapsPkgReplacements: map[string]stdReplacement[*ast.CallExpr]{ + "Keys": {MinGo: go123, Text: "slices.AppendSeq(make([]T, 0, len(data)), maps.Keys(data))", Suggested: suggestedFixForKeysOrValues}, + "Values": {MinGo: go123, Text: "slices.AppendSeq(make([]T, 0, len(data)), maps.Values(data))", Suggested: suggestedFixForKeysOrValues}, + "Equal": {MinGo: go121, Text: "maps.Equal()"}, + "EqualFunc": {MinGo: go121, Text: "maps.EqualFunc()"}, + "Clone": {MinGo: go121, Text: "maps.Clone()"}, + "Copy": {MinGo: go121, Text: "maps.Copy()"}, + "DeleteFunc": {MinGo: go121, Text: "maps.DeleteFunc()"}, + "Clear": {MinGo: go121, Text: "clear()", Suggested: suggestedFixForClear}, + }, + slicesPkgReplacements: map[string]stdReplacement[*ast.CallExpr]{ + "Equal": {MinGo: go121, Text: "slices.Equal()"}, + "EqualFunc": {MinGo: go121, Text: "slices.EqualFunc()"}, + "Compare": {MinGo: go121, Text: "slices.Compare()"}, + "CompareFunc": {MinGo: go121, Text: "slices.CompareFunc()"}, + "Index": {MinGo: go121, Text: "slices.Index()"}, + "IndexFunc": {MinGo: go121, Text: "slices.IndexFunc()"}, + "Contains": {MinGo: go121, Text: "slices.Contains()"}, + "ContainsFunc": {MinGo: go121, Text: "slices.ContainsFunc()"}, + "Insert": {MinGo: go121, Text: "slices.Insert()"}, + "Delete": {MinGo: go121, Text: "slices.Delete()"}, + "DeleteFunc": {MinGo: go121, Text: "slices.DeleteFunc()"}, + "Replace": {MinGo: go121, Text: "slices.Replace()"}, + "Clone": {MinGo: go121, Text: "slices.Clone()"}, + "Compact": {MinGo: go121, Text: "slices.Compact()"}, + "CompactFunc": {MinGo: go121, Text: "slices.CompactFunc()"}, + "Grow": {MinGo: go121, Text: "slices.Grow()"}, + "Clip": {MinGo: go121, Text: "slices.Clip()"}, + "Reverse": {MinGo: go121, Text: "slices.Reverse()"}, + + "Sort": {MinGo: go121, Text: "slices.Sort()"}, + "SortFunc": {MinGo: go121, Text: "slices.SortFunc()"}, + "SortStableFunc": {MinGo: go121, Text: "slices.SortStableFunc()"}, + "IsSorted": {MinGo: go121, Text: "slices.IsSorted()"}, + "IsSortedFunc": {MinGo: go121, Text: "slices.IsSortedFunc()"}, + "Min": {MinGo: go121, Text: "slices.Min()"}, + "MinFunc": {MinGo: go121, Text: "slices.MinFunc()"}, + "Max": {MinGo: go121, Text: "slices.Max()"}, + "MaxFunc": {MinGo: go121, Text: "slices.MaxFunc()"}, + "BinarySearch": {MinGo: go121, Text: "slices.BinarySearch()"}, + "BinarySearchFunc": {MinGo: go121, Text: "slices.BinarySearchFunc()"}, + }, + constraintsPkgReplacements: map[string]stdReplacement[*ast.SelectorExpr]{ + "Ordered": {MinGo: go121, Text: "cmp.Ordered", Suggested: suggestedFixForConstraintsOrder}, + }, + } + + return &analysis.Analyzer{ + Name: "exptostd", + Doc: "Detects functions from golang.org/x/exp/ that can be replaced by std functions.", + Run: l.run, + Requires: []*analysis.Analyzer{inspect.Analyzer}, + } +} + +//nolint:gocognit,gocyclo // The complexity is expected by the cases to handle. +func (a *analyzer) run(pass *analysis.Pass) (any, error) { + insp, ok := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + if !ok { + return nil, nil + } + + goVersion := getGoVersion(pass) + + nodeFilter := []ast.Node{ + (*ast.CallExpr)(nil), + (*ast.FuncDecl)(nil), + (*ast.TypeSpec)(nil), + (*ast.ImportSpec)(nil), + } + + imports := map[string]*ast.ImportSpec{} + + var shouldKeepExpMaps bool + + var resultExpSlices Result + + resultExpConstraints := &Result{} + + insp.Preorder(nodeFilter, func(n ast.Node) { + switch node := n.(type) { + case *ast.ImportSpec: + // skip aliases + if node.Name == nil || node.Name.Name == "" { + imports[trimImportPath(node)] = node + } + + return + + case *ast.CallExpr: + selExpr, ok := node.Fun.(*ast.SelectorExpr) + if !ok { + return + } + + ident, ok := selExpr.X.(*ast.Ident) + if !ok { + return + } + + switch ident.Name { + case pkgMaps: + diagnostic, usage := a.detectPackageUsage(pass, a.mapsPkgReplacements, selExpr, ident, node, pkgExpMaps, goVersion) + if usage { + pass.Report(diagnostic) + } + + shouldKeepExpMaps = shouldKeepExpMaps || !usage + + case pkgSlices: + diagnostic, usage := a.detectPackageUsage(pass, a.slicesPkgReplacements, selExpr, ident, node, pkgExpSlices, goVersion) + if usage { + resultExpSlices.Diagnostics = append(resultExpSlices.Diagnostics, diagnostic) + } + + resultExpSlices.shouldKeepImport = resultExpSlices.shouldKeepImport || !usage + } + + case *ast.FuncDecl: + if node.Type.TypeParams != nil { + for _, field := range node.Type.TypeParams.List { + a.detectConstraintsUsage(pass, field.Type, resultExpConstraints, goVersion) + } + } + + case *ast.TypeSpec: + if node.TypeParams != nil { + for _, field := range node.TypeParams.List { + a.detectConstraintsUsage(pass, field.Type, resultExpConstraints, goVersion) + } + } + + interfaceType, ok := node.Type.(*ast.InterfaceType) + if !ok { + return + } + + for _, method := range interfaceType.Methods.List { + switch exp := method.Type.(type) { + case *ast.BinaryExpr: + a.detectConstraintsUsage(pass, exp.X, resultExpConstraints, goVersion) + a.detectConstraintsUsage(pass, exp.Y, resultExpConstraints, goVersion) + + case *ast.SelectorExpr: + a.detectConstraintsUsage(pass, exp, resultExpConstraints, goVersion) + } + } + } + }) + + // maps + a.suggestReplaceImport(pass, imports, shouldKeepExpMaps, pkgExpMaps, pkgMaps) + + // slices + if resultExpSlices.shouldKeepImport { + for _, diagnostic := range resultExpSlices.Diagnostics { + pass.Report(diagnostic) + } + } else { + a.suggestReplaceImport(pass, imports, resultExpSlices.shouldKeepImport, pkgExpSlices, pkgSlices) + } + + // constraints + a.suggestReplaceImport(pass, imports, resultExpConstraints.shouldKeepImport, pkgExpConstraints, pkgComp) + + return nil, nil +} + +func (a *analyzer) detectPackageUsage(pass *analysis.Pass, + replacements map[string]stdReplacement[*ast.CallExpr], + selExpr *ast.SelectorExpr, ident *ast.Ident, callExpr *ast.CallExpr, + importPath string, goVersion int, +) (analysis.Diagnostic, bool) { + rp, ok := replacements[selExpr.Sel.Name] + if !ok { + return analysis.Diagnostic{}, false + } + + if !a.skipGoVersionDetection && rp.MinGo > goVersion { + return analysis.Diagnostic{}, false + } + + if !isPackageUsed(pass, ident, importPath) { + return analysis.Diagnostic{}, false + } + + diagnostic := analysis.Diagnostic{ + Pos: callExpr.Pos(), + Message: fmt.Sprintf("%s.%s() can be replaced by %s", importPath, selExpr.Sel.Name, rp.Text), + } + + if rp.Suggested != nil { + fix, err := rp.Suggested(callExpr) + if err != nil { + diagnostic.Message = fmt.Sprintf("Suggested fix error: %v", err) + } else { + diagnostic.SuggestedFixes = append(diagnostic.SuggestedFixes, fix) + } + } + + return diagnostic, true +} + +func (a *analyzer) detectConstraintsUsage(pass *analysis.Pass, expr ast.Expr, result *Result, goVersion int) { + switch selExpr := expr.(type) { + case *ast.SelectorExpr: + ident, ok := selExpr.X.(*ast.Ident) + if !ok { + return + } + + if !isPackageUsed(pass, ident, pkgExpConstraints) { + return + } + + rp, ok := a.constraintsPkgReplacements[selExpr.Sel.Name] + if !ok { + result.shouldKeepImport = true + return + } + + if !a.skipGoVersionDetection && rp.MinGo > goVersion { + result.shouldKeepImport = true + return + } + + diagnostic := analysis.Diagnostic{ + Pos: selExpr.Pos(), + Message: fmt.Sprintf("%s.%s can be replaced by %s", pkgExpConstraints, selExpr.Sel.Name, rp.Text), + } + + if rp.Suggested != nil { + fix, err := rp.Suggested(selExpr) + if err != nil { + diagnostic.Message = fmt.Sprintf("Suggested fix error: %v", err) + } else { + diagnostic.SuggestedFixes = append(diagnostic.SuggestedFixes, fix) + } + } + + pass.Report(diagnostic) + + case *ast.BinaryExpr: + a.detectConstraintsUsage(pass, selExpr.X, result, goVersion) + a.detectConstraintsUsage(pass, selExpr.Y, result, goVersion) + + case *ast.UnaryExpr: + a.detectConstraintsUsage(pass, selExpr.X, result, goVersion) + + default: + return + } +} + +func (a *analyzer) suggestReplaceImport(pass *analysis.Pass, imports map[string]*ast.ImportSpec, shouldKeep bool, importPath, stdPackage string) { + imp, ok := imports[importPath] + if !ok || shouldKeep { + return + } + + src := trimImportPath(imp) + + pass.Report(analysis.Diagnostic{ + Pos: imp.Pos(), + End: imp.End(), + Message: fmt.Sprintf("Import statement '%s' may be replaced by '%s'", src, stdPackage), + SuggestedFixes: []analysis.SuggestedFix{{ + TextEdits: []analysis.TextEdit{{ + Pos: imp.Path.Pos(), + End: imp.Path.End(), + NewText: []byte(string(imp.Path.Value[0]) + stdPackage + string(imp.Path.Value[0])), + }}, + }}, + }) +} + +func suggestedFixForClear(callExpr *ast.CallExpr) (analysis.SuggestedFix, error) { + s := &ast.CallExpr{ + Fun: ast.NewIdent("clear"), + Args: callExpr.Args, + Ellipsis: callExpr.Ellipsis, + } + + buf := bytes.NewBuffer(nil) + + err := printer.Fprint(buf, token.NewFileSet(), s) + if err != nil { + return analysis.SuggestedFix{}, fmt.Errorf("print suggested fix: %w", err) + } + + return analysis.SuggestedFix{ + TextEdits: []analysis.TextEdit{{ + Pos: callExpr.Pos(), + End: callExpr.End(), + NewText: buf.Bytes(), + }}, + }, nil +} + +func suggestedFixForKeysOrValues(callExpr *ast.CallExpr) (analysis.SuggestedFix, error) { + s := &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{Name: "slices"}, + Sel: &ast.Ident{Name: "AppendSeq"}, + }, + Args: []ast.Expr{ + &ast.CallExpr{ + Fun: &ast.Ident{Name: "make"}, + Args: []ast.Expr{ + &ast.ArrayType{ + Elt: &ast.Ident{Name: "FIXME"}, // TODO(ldez) improve the type detection. + }, + &ast.BasicLit{Kind: token.INT, Value: "0"}, + &ast.CallExpr{ + Fun: &ast.Ident{Name: "len"}, + Args: callExpr.Args, + }, + }, + }, + callExpr, + }, + } + + buf := bytes.NewBuffer(nil) + + err := printer.Fprint(buf, token.NewFileSet(), s) + if err != nil { + return analysis.SuggestedFix{}, fmt.Errorf("print suggested fix: %w", err) + } + + return analysis.SuggestedFix{ + TextEdits: []analysis.TextEdit{{ + Pos: callExpr.Pos(), + End: callExpr.End(), + NewText: buf.Bytes(), + }}, + }, nil +} + +func suggestedFixForConstraintsOrder(selExpr *ast.SelectorExpr) (analysis.SuggestedFix, error) { + s := &ast.SelectorExpr{ + X: &ast.Ident{Name: pkgComp}, + Sel: &ast.Ident{Name: "Ordered"}, + } + + buf := bytes.NewBuffer(nil) + + err := printer.Fprint(buf, token.NewFileSet(), s) + if err != nil { + return analysis.SuggestedFix{}, fmt.Errorf("print suggested fix: %w", err) + } + + return analysis.SuggestedFix{ + TextEdits: []analysis.TextEdit{{ + Pos: selExpr.Pos(), + End: selExpr.End(), + NewText: buf.Bytes(), + }}, + }, nil +} + +func isPackageUsed(pass *analysis.Pass, ident *ast.Ident, importPath string) bool { + obj := pass.TypesInfo.Uses[ident] + if obj == nil { + return false + } + + pkg, ok := obj.(*types.PkgName) + if !ok { + return false + } + + if pkg.Imported().Path() != importPath { + return false + } + + return true +} + +func getGoVersion(pass *analysis.Pass) int { + // Prior to go1.22, versions.FileVersion returns only the toolchain version, + // which is of no use to us, + // so disable this analyzer on earlier versions. + if !slices.Contains(build.Default.ReleaseTags, "go1.22") { + return 0 // false + } + + pkgVersion := pass.Pkg.GoVersion() + if pkgVersion == "" { + // Empty means Go devel. + return goDevel // true + } + + raw := strings.TrimPrefix(pkgVersion, "go") + + // prerelease version (go1.24rc1) + idx := strings.IndexFunc(raw, func(r rune) bool { + return (r < '0' || r > '9') && r != '.' + }) + + if idx != -1 { + raw = raw[:idx] + } + + vParts := strings.Split(raw, ".") + + v, err := strconv.Atoi(strings.Join(vParts[:2], "")) + if err != nil { + v = 116 + } + + return v +} + +func trimImportPath(spec *ast.ImportSpec) string { + return spec.Path.Value[1 : len(spec.Path.Value)-1] +} diff --git a/vendor/github.com/ldez/exptostd/readme.md b/vendor/github.com/ldez/exptostd/readme.md new file mode 100644 index 000000000..bd1df8d54 --- /dev/null +++ b/vendor/github.com/ldez/exptostd/readme.md @@ -0,0 +1,116 @@ +# ExpToStd + +Detects functions from golang.org/x/exp/ that can be replaced by std functions. + +[![Sponsor](https://img.shields.io/badge/Sponsor%20me-%E2%9D%A4%EF%B8%8F-pink)](https://github.com/sponsors/ldez) + +Actual detections: + +- `golang.org/x/exp/maps`: + - `Keys` + - `Values` + - `Equal` + - `EqualFunc` + - `Clone` + - `Copy` + - `DeleteFunc` + - `Clear` + +- `golang.org/x/exp/slices`: + - `Equal` + - `EqualFunc` + - `Compare` + - `CompareFunc` + - `Index` + - `IndexFunc` + - `Contains` + - `ContainsFunc` + - `Insert` + - `Delete` + - `DeleteFunc` + - `Replace` + - `Clone` + - `Compact` + - `CompactFunc` + - `Grow` + - `Clip` + - `Reverse` + - `Sort` + - `SortFunc` + - `SortStableFunc` + - `IsSorted` + - `IsSortedFunc` + - `Min` + - `MinFunc` + - `Max` + - `MaxFunc` + - `BinarySearch` + - `BinarySearchFunc` + +- `golang.org/x/exp/constraints`: + - `Ordered` + +## Usages + +### Inside golangci-lint + +Recommended. + +```yaml +linters: + enable: + - exptostd +``` + +### As a CLI + +```bash +go install github.com/ldez/exptostd/cmd/exptostd@latest +``` + +```bash +./exptostd ./... +``` + +## Examples + +```go +package foo + +import ( + "fmt" + + "golang.org/x/exp/maps" +) + +func foo(m map[string]string) { + clone := maps.Clone(m) + + fmt.Println(clone) +} +``` + +It can be replaced by: + +```go +package foo + +import ( + "fmt" + "maps" +) + +func foo(m map[string]string) { + clone := maps.Clone(m) + + fmt.Println(clone) +} + +``` + +## References + +- https://tip.golang.org/doc/go1.21#maps +- https://tip.golang.org/doc/go1.21#slices +- https://tip.golang.org/doc/go1.23#iterators +- https://tip.golang.org/doc/go1.21#cmp diff --git a/vendor/github.com/ldez/gomoddirectives/.golangci.yml b/vendor/github.com/ldez/gomoddirectives/.golangci.yml index 034745570..8eb11ff01 100644 --- a/vendor/github.com/ldez/gomoddirectives/.golangci.yml +++ b/vendor/github.com/ldez/gomoddirectives/.golangci.yml @@ -1,102 +1,100 @@ -run: - timeout: 2m +version: "2" -linters-settings: - govet: - enable-all: true - gocyclo: - min-complexity: 12 - goconst: - min-len: 3 - min-occurrences: 3 - misspell: - locale: US - gofumpt: - extra-rules: true - depguard: - rules: - main: - deny: - - pkg: "github.com/instana/testify" - desc: not allowed - - pkg: "github.com/pkg/errors" - desc: Should be replaced by standard lib errors package - godox: - keywords: - - FIXME - gocritic: - enabled-tags: - - diagnostic - - style - - performance - disabled-checks: - - sloppyReassign - - rangeValCopy - - octalLiteral - - paramTypeCombine # already handle by gofumpt.extra-rules - settings: - hugeParam: - sizeThreshold: 100 - forbidigo: - forbid: - - '^print(ln)?$' - - '^fmt\.Print(f|ln)?$' - - '^panic$' - - '^spew\.Print(f|ln)?$' - - '^spew\.Dump$' - tagliatelle: - case: - rules: - json: pascal +formatters: + enable: + - gci + - gofumpt + settings: + gofumpt: + extra-rules: true linters: - enable-all: true + default: all disable: - - deadcode # deprecated - - exhaustivestruct # deprecated - - golint # deprecated - - ifshort # deprecated - - interfacer # deprecated - - maligned # deprecated - - nosnakecase # deprecated - - scopelint # deprecated - - structcheck # deprecated - - varcheck # deprecated - - sqlclosecheck # not relevant (SQL) - - rowserrcheck # not relevant (SQL) - - execinquery # not relevant (SQL) + - bodyclose - cyclop # duplicate of gocyclo - - lll - dupl - - prealloc - - bodyclose - - wsl + - err113 + - exhaustive + - exhaustruct + - lll + - mnd - nlreturn - - gomnd - - testpackage - paralleltest + - prealloc + - rowserrcheck # not relevant (SQL) + - sqlclosecheck # not relevant (SQL) + - testpackage - tparallel - - goerr113 - - wrapcheck - - exhaustive - - exhaustruct - varnamelen + - wrapcheck + - wsl # deprecated + + settings: + depguard: + rules: + main: + deny: + - pkg: github.com/instana/testify + desc: not allowed + - pkg: github.com/pkg/errors + desc: Should be replaced by standard lib errors package + forbidigo: + forbid: + - pattern: ^print(ln)?$ + - pattern: ^fmt\.Print(f|ln)?$ + - pattern: ^panic$ + - pattern: ^spew\.Print(f|ln)?$ + - pattern: ^spew\.Dump$ + funlen: + lines: -1 + goconst: + min-len: 3 + min-occurrences: 3 + gocritic: + disabled-checks: + - sloppyReassign + - rangeValCopy + - octalLiteral + - paramTypeCombine # already handle by gofumpt.extra-rules + enabled-tags: + - diagnostic + - style + - performance + settings: + hugeParam: + sizeThreshold: 100 + gocyclo: + min-complexity: 12 + godox: + keywords: + - FIXME + govet: + disable: + - fieldalignment + enable-all: true + misspell: + locale: US + tagliatelle: + case: + rules: + json: pascal + + exclusions: + warn-unused: true + presets: + - comments + rules: + - linters: + - funlen + - goconst + - maintidx + path: (.+)_test.go + - linters: + - forbidigo + path: cmd/gomoddirectives/gomoddirectives.go + text: use of `fmt.Println` forbidden issues: - exclude-use-default: false max-issues-per-linter: 0 max-same-issues: 0 - exclude: [ - 'package-comments: should have a package comment' - ] - exclude-rules: - - path: "(.+)_test.go" - linters: - - funlen - - goconst - - path: cmd/gomoddirectives/gomoddirectives.go - text: 'use of `fmt.Println` forbidden' - -output: - show-stats: true - sort-results: true diff --git a/vendor/github.com/ldez/gomoddirectives/LICENSE b/vendor/github.com/ldez/gomoddirectives/LICENSE index caed523b4..c1bf0c328 100644 --- a/vendor/github.com/ldez/gomoddirectives/LICENSE +++ b/vendor/github.com/ldez/gomoddirectives/LICENSE @@ -175,7 +175,7 @@ END OF TERMS AND CONDITIONS - Copyright 2021 Fernandez Ludovic + Copyright 2024 Fernandez Ludovic Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/vendor/github.com/ldez/gomoddirectives/gomoddirectives.go b/vendor/github.com/ldez/gomoddirectives/gomoddirectives.go index 2a4c90474..ae416c17f 100644 --- a/vendor/github.com/ldez/gomoddirectives/gomoddirectives.go +++ b/vendor/github.com/ldez/gomoddirectives/gomoddirectives.go @@ -1,21 +1,33 @@ -// Package gomoddirectives a linter that handle `replace`, `retract`, `exclude` directives into `go.mod`. +// Package gomoddirectives a linter that handle directives into `go.mod`. package gomoddirectives import ( + "context" "fmt" "go/token" + "regexp" + "slices" "strings" + "github.com/ldez/grignotin/gomod" "golang.org/x/mod/modfile" + "golang.org/x/mod/module" + "golang.org/x/tools/go/analysis" ) const ( - reasonRetract = "a comment is mandatory to explain why the version has been retracted" reasonExclude = "exclude directive is not allowed" - reasonReplaceLocal = "local replacement are not allowed" + reasonGoDebug = "godebug directive is not allowed" + reasonGoVersion = "go directive (%s) doesn't match the pattern '%s'" + reasonIgnore = "ignore directive is not allowed" reasonReplace = "replacement are not allowed" - reasonReplaceIdentical = "the original module and the replacement are identical" reasonReplaceDuplicate = "multiple replacement of the same module" + reasonReplaceIdentical = "the original module and the replacement are identical" + reasonReplaceLocal = "local replacement are not allowed" + reasonRetract = "a comment is mandatory to explain why the version has been retracted" + reasonTool = "tool directive is not allowed" + reasonToolchain = "toolchain directive is not allowed" + reasonToolchainPattern = "toolchain directive (%s) doesn't match the pattern '%s'" ) // Result the analysis result. @@ -43,7 +55,40 @@ type Options struct { ReplaceAllowList []string ReplaceAllowLocal bool ExcludeForbidden bool + IgnoreForbidden bool RetractAllowNoExplanation bool + ToolchainForbidden bool + ToolchainPattern *regexp.Regexp + ToolForbidden bool + GoDebugForbidden bool + GoVersionPattern *regexp.Regexp + CheckModulePath bool +} + +// AnalyzePass analyzes a pass. +func AnalyzePass(pass *analysis.Pass, opts Options) ([]Result, error) { + info, err := gomod.GetModuleInfo(context.Background()) + if err != nil { + return nil, fmt.Errorf("get information about modules: %w", err) + } + + goMod := info[0].GoMod + + if pass.Module != nil && pass.Module.Path != "" { + for _, m := range info { + if m.Path == pass.Module.Path { + goMod = m.GoMod + break + } + } + } + + f, err := parseGoMod(goMod) + if err != nil { + return nil, fmt.Errorf("parse %s: %w", goMod, err) + } + + return AnalyzeFile(f, opts), nil } // Analyze analyzes a project. @@ -58,66 +103,184 @@ func Analyze(opts Options) ([]Result, error) { // AnalyzeFile analyzes a mod file. func AnalyzeFile(file *modfile.File, opts Options) []Result { + checks := []func(file *modfile.File, opts Options) []Result{ + checkModulePath, + checkRetractDirectives, + checkExcludeDirectives, + checkToolDirectives, + checkIgnoreDirectives, + checkReplaceDirectives, + checkToolchainDirective, + checkGoDebugDirectives, + checkGoVersionDirectives, + } + var results []Result + for _, check := range checks { + results = append(results, check(file, opts)...) + } - if !opts.RetractAllowNoExplanation { - for _, r := range file.Retract { - if r.Rationale != "" { - continue - } + return results +} - results = append(results, NewResult(file, r.Syntax, reasonRetract)) - } +func checkModulePath(file *modfile.File, opts Options) []Result { + if file.Module == nil || !opts.CheckModulePath { + return nil + } + + err := module.CheckPath(file.Module.Mod.Path) + if err != nil { + return []Result{NewResult(file, file.Module.Syntax, err.Error())} + } + + return nil +} + +func checkGoVersionDirectives(file *modfile.File, opts Options) []Result { + if file == nil || file.Go == nil || opts.GoVersionPattern == nil || opts.GoVersionPattern.MatchString(file.Go.Version) { + return nil + } + + return []Result{NewResult(file, file.Go.Syntax, fmt.Sprintf(reasonGoVersion, file.Go.Version, opts.GoVersionPattern.String()))} +} + +func checkToolchainDirective(file *modfile.File, opts Options) []Result { + if file.Toolchain == nil { + return nil + } + + if opts.ToolchainForbidden { + return []Result{NewResult(file, file.Toolchain.Syntax, reasonToolchain)} + } + + if opts.ToolchainPattern == nil { + return nil + } + + if !opts.ToolchainPattern.MatchString(file.Toolchain.Name) { + return []Result{NewResult(file, file.Toolchain.Syntax, fmt.Sprintf(reasonToolchainPattern, file.Toolchain.Name, opts.ToolchainPattern.String()))} + } + + return nil +} + +func checkRetractDirectives(file *modfile.File, opts Options) []Result { + if opts.RetractAllowNoExplanation { + return nil } - if opts.ExcludeForbidden { - for _, e := range file.Exclude { - results = append(results, NewResult(file, e.Syntax, reasonExclude)) + var results []Result + + for _, retract := range file.Retract { + if retract.Rationale != "" { + continue } + + results = append(results, NewResult(file, retract.Syntax, reasonRetract)) + } + + return results +} + +func checkExcludeDirectives(file *modfile.File, opts Options) []Result { + if !opts.ExcludeForbidden { + return nil + } + + var results []Result + + for _, exclude := range file.Exclude { + results = append(results, NewResult(file, exclude.Syntax, reasonExclude)) + } + + return results +} + +func checkIgnoreDirectives(file *modfile.File, opts Options) []Result { + if !opts.IgnoreForbidden { + return nil } + var results []Result + + for _, exclude := range file.Ignore { + results = append(results, NewResult(file, exclude.Syntax, reasonIgnore)) + } + + return results +} + +func checkToolDirectives(file *modfile.File, opts Options) []Result { + if !opts.ToolForbidden { + return nil + } + + var results []Result + + for _, tool := range file.Tool { + results = append(results, NewResult(file, tool.Syntax, reasonTool)) + } + + return results +} + +func checkReplaceDirectives(file *modfile.File, opts Options) []Result { + var results []Result + uniqReplace := map[string]struct{}{} - for _, r := range file.Replace { - reason := check(opts, r) + for _, replace := range file.Replace { + reason := checkReplaceDirective(opts, replace) if reason != "" { - results = append(results, NewResult(file, r.Syntax, reason)) + results = append(results, NewResult(file, replace.Syntax, reason)) continue } - if r.Old.Path == r.New.Path && r.Old.Version == r.New.Version { - results = append(results, NewResult(file, r.Syntax, reasonReplaceIdentical)) + if replace.Old.Path == replace.New.Path && replace.Old.Version == replace.New.Version { + results = append(results, NewResult(file, replace.Syntax, reasonReplaceIdentical)) continue } - if _, ok := uniqReplace[r.Old.Path+r.Old.Version]; ok { - results = append(results, NewResult(file, r.Syntax, reasonReplaceDuplicate)) + if _, ok := uniqReplace[replace.Old.Path+replace.Old.Version]; ok { + results = append(results, NewResult(file, replace.Syntax, reasonReplaceDuplicate)) } - uniqReplace[r.Old.Path+r.Old.Version] = struct{}{} + uniqReplace[replace.Old.Path+replace.Old.Version] = struct{}{} } return results } -func check(o Options, r *modfile.Replace) string { +func checkReplaceDirective(opts Options, r *modfile.Replace) string { if isLocal(r) { - if o.ReplaceAllowLocal { + if opts.ReplaceAllowLocal { return "" } return fmt.Sprintf("%s: %s", reasonReplaceLocal, r.Old.Path) } - for _, v := range o.ReplaceAllowList { - if r.Old.Path == v { - return "" - } + if slices.Contains(opts.ReplaceAllowList, r.Old.Path) { + return "" } return fmt.Sprintf("%s: %s", reasonReplace, r.Old.Path) } +func checkGoDebugDirectives(file *modfile.File, opts Options) []Result { + if !opts.GoDebugForbidden { + return nil + } + + var results []Result + + for _, goDebug := range file.Godebug { + results = append(results, NewResult(file, goDebug.Syntax, reasonGoDebug)) + } + + return results +} + // Filesystem paths found in "replace" directives are represented by a path with an empty version. // https://github.com/golang/mod/blob/bc388b264a244501debfb9caea700c6dcaff10e2/module/module.go#L122-L124 func isLocal(r *modfile.Replace) bool { diff --git a/vendor/github.com/ldez/gomoddirectives/module.go b/vendor/github.com/ldez/gomoddirectives/module.go index 4cb365379..c3e47c8a4 100644 --- a/vendor/github.com/ldez/gomoddirectives/module.go +++ b/vendor/github.com/ldez/gomoddirectives/module.go @@ -1,45 +1,32 @@ package gomoddirectives import ( - "bytes" - "encoding/json" - "errors" + "context" "fmt" "os" - "os/exec" + "path/filepath" + "github.com/ldez/grignotin/goenv" "golang.org/x/mod/modfile" ) -type modInfo struct { - Path string `json:"Path"` - Dir string `json:"Dir"` - GoMod string `json:"GoMod"` - GoVersion string `json:"GoVersion"` - Main bool `json:"Main"` -} - // GetModuleFile gets module file. func GetModuleFile() (*modfile.File, error) { - // https://github.com/golang/go/issues/44753#issuecomment-790089020 - cmd := exec.Command("go", "list", "-m", "-json") - - raw, err := cmd.Output() + goMod, err := goenv.GetOne(context.Background(), goenv.GOMOD) if err != nil { - return nil, fmt.Errorf("command go list: %w: %s", err, string(raw)) + return nil, err } - var v modInfo - err = json.NewDecoder(bytes.NewBuffer(raw)).Decode(&v) + mod, err := parseGoMod(goMod) if err != nil { - return nil, fmt.Errorf("unmarshaling error: %w: %s", err, string(raw)) + return nil, fmt.Errorf("failed to parse go.mod (%s): %w", goMod, err) } - if v.GoMod == "" { - return nil, errors.New("working directory is not part of a module") - } + return mod, nil +} - raw, err = os.ReadFile(v.GoMod) +func parseGoMod(goMod string) (*modfile.File, error) { + raw, err := os.ReadFile(filepath.Clean(goMod)) if err != nil { return nil, fmt.Errorf("reading go.mod file: %w", err) } diff --git a/vendor/github.com/ldez/gomoddirectives/readme.md b/vendor/github.com/ldez/gomoddirectives/readme.md index 510c8502e..52c6a4cbd 100644 --- a/vendor/github.com/ldez/gomoddirectives/readme.md +++ b/vendor/github.com/ldez/gomoddirectives/readme.md @@ -1,16 +1,238 @@ # gomoddirectives +A linter that handle directives into `go.mod`. + [![Sponsor](https://img.shields.io/badge/Sponsor%20me-%E2%9D%A4%EF%B8%8F-pink)](https://github.com/sponsors/ldez) [![Build Status](https://github.com/ldez/gomoddirectives/workflows/Main/badge.svg?branch=master)](https://github.com/ldez/gomoddirectives/actions) -A linter that handle [`replace`](https://golang.org/ref/mod#go-mod-file-replace), [`retract`](https://golang.org/ref/mod#go-mod-file-retract), [`exclude`](https://golang.org/ref/mod#go-mod-file-exclude) directives into `go.mod`. +## Usage + +### Inside golangci-lint + +Recommended. + +```yml +linters: + enable: + - gomoddirectives + + settings: + gomoddirectives: + # Allow local `replace` directives. + # Default: false + replace-local: true + + # List of allowed `replace` directives. + # Default: [] + replace-allow-list: + - launchpad.net/gocheck + + # Allow to not explain why the version has been retracted in the `retract` directives. + # Default: false + retract-allow-no-explanation: true + + # Forbid the use of the `exclude` directives. + # Default: false + exclude-forbidden: true + + # Forbid the use of the `ignore` directives (go >= 1.25). + # Default: false + ignore-forbidden: true + + # Forbid the use of the `toolchain` directive. + # Default: false + toolchain-forbidden: true + + # Defines a pattern to validate `toolchain` directive. + # Default: '' (no match) + toolchain-pattern: 'go1\.22\.\d+$' + + # Forbid the use of the `tool` directives. + # Default: false + tool-forbidden: true + + # Forbid the use of the `godebug` directive. + # Default: false + go-debug-forbidden: true + + # Defines a pattern to validate `go` minimum version directive. + # Default: '' (no match) + go-version-pattern: '1\.\d+(\.0)?$' + + # Check the validity of the module path. + # Default: false + check-module-path: true +``` + +### As a CLI + +``` +gomoddirectives [flags] + +Flags: + -check-module-path + Check module path validity + -exclude + Forbid the use of exclude directives + -godebug + Forbid the use of godebug directives + -goversion string + Pattern to validate go min version directive + -h Show this help. + -ignore + Forbid the use of ignore directives + -list value + List of allowed replace directives + -local + Allow local replace directives + -retract-no-explanation + Allow to use retract directives without explanation + -tool + Forbid the use of tool directives + -toolchain + Forbid the use of toolchain directive + -toolchain-pattern string + Pattern to validate toolchain directive +``` + +## Details + +### [`retract`](https://golang.org/ref/mod#go-mod-file-retract) directives + +- Force explanation for `retract` directives. + +```go +module example.com/foo + +go 1.22 + +require ( + github.com/ldez/grignotin v0.4.1 +) + +retract ( + v1.0.0 // Explanation +) +``` + +### [`replace`](https://golang.org/ref/mod#go-mod-file-replace) directives + +- Ban all `replace` directives. +- Allow only local `replace` directives. +- Allow only some `replace` directives. +- Detect duplicated `replace` directives. +- Detect identical `replace` directives. + +```go +module example.com/foo + +go 1.22 + +require ( + github.com/ldez/grignotin v0.4.1 +) + +replace github.com/ldez/grignotin => ../grignotin/ +``` + +### [`exclude`](https://golang.org/ref/mod#go-mod-file-exclude) directives + +- Ban all `exclude` directives. + +```go +module example.com/foo + +go 1.22 + +require ( + github.com/ldez/grignotin v0.4.1 +) + +exclude ( + golang.org/x/crypto v1.4.5 + golang.org/x/text v1.6.7 +) +``` + +### [`ignore`](TODO) directives + +- Ban all `ignore` directives. + +```go +module example.com/foo + +go 1.25 + +require ( + github.com/ldez/grignotin v0.4.1 +) + +ignore ( + ./foo/bar/path + foo/bar +) +``` + +### [`tool`](https://golang.org/ref/mod#go-mod-file-tool) directives + +- Ban all `tool` directives. + +```go +module example.com/foo + +go 1.24 + +tool ( + example.com/module/cmd/a + example.com/module/cmd/b +) +``` + +### [`toolchain`](https://golang.org/ref/mod#go-mod-file-toolchain) directive + +- Ban `toolchain` directive. +- Use a regular expression to constraint the Go minimum version. + +```go +module example.com/foo + +go 1.22 + +toolchain go1.23.3 +``` + +### [`godebug`](https://go.dev/ref/mod#go-mod-file-godebug) directives + +- Ban `godebug` directive. + +```go +module example.com/foo + +go 1.22 + +godebug default=go1.21 +godebug ( + panicnil=1 + asynctimerchan=0 +) +``` + +### [`go`](https://go.dev/ref/mod#go-mod-file-go) directive + +- Use a regular expression to constraint the Go minimum version. + +```go +module example.com/foo + +go 1.22.0 +``` + +### [`module`](https://go.dev/ref/mod#module-path) path + +- Check the validity of the module path. -Features: +```go +module example.com/foo -- ban all [`replace`](https://golang.org/ref/mod#go-mod-file-replace) directives -- allow only local [`replace`](https://golang.org/ref/mod#go-mod-file-replace) directives -- allow only some [`replace`](https://golang.org/ref/mod#go-mod-file-replace) directives -- force explanation for [`retract`](https://golang.org/ref/mod#go-mod-file-retract) directives -- ban all [`exclude`](https://golang.org/ref/mod#go-mod-file-exclude) directives -- detect duplicated [`replace`](https://golang.org/ref/mod#go-mod-file-replace) directives -- detect identical [`replace`](https://golang.org/ref/mod#go-mod-file-replace) directives +go 1.22 +``` diff --git a/vendor/github.com/ldez/grignotin/LICENSE b/vendor/github.com/ldez/grignotin/LICENSE new file mode 100644 index 000000000..79f380e5c --- /dev/null +++ b/vendor/github.com/ldez/grignotin/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2024 Fernandez Ludovic + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/ldez/grignotin/goenv/goenv.go b/vendor/github.com/ldez/grignotin/goenv/goenv.go new file mode 100644 index 000000000..58dbb5f8c --- /dev/null +++ b/vendor/github.com/ldez/grignotin/goenv/goenv.go @@ -0,0 +1,51 @@ +// Package goenv A set of functions to get information from `go env`. +package goenv + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "os/exec" + "strings" +) + +// GetAll gets information from "go env". +func GetAll(ctx context.Context) (map[string]string, error) { + v, err := Get(ctx) + if err != nil { + return nil, err + } + + return v, nil +} + +// GetOne gets information from "go env" for one environment variable. +func GetOne(ctx context.Context, name string) (string, error) { + v, err := Get(ctx, name) + if err != nil { + return "", err + } + + return v[name], nil +} + +// Get gets information from "go env" for one or several environment variables. +func Get(ctx context.Context, name ...string) (map[string]string, error) { + args := append([]string{"env", "-json"}, name...) + cmd := exec.CommandContext(ctx, "go", args...) //nolint:gosec // The env var names must be checked by the user. + + out, err := cmd.Output() + if err != nil { + return nil, fmt.Errorf("command %q: %w: %s", strings.Join(cmd.Args, " "), err, string(out)) + } + + v := map[string]string{} + + err = json.NewDecoder(bytes.NewBuffer(out)).Decode(&v) + if err != nil { + return nil, err + } + + return v, nil +} diff --git a/vendor/github.com/ldez/grignotin/goenv/names.go b/vendor/github.com/ldez/grignotin/goenv/names.go new file mode 100644 index 000000000..a5d6eeeeb --- /dev/null +++ b/vendor/github.com/ldez/grignotin/goenv/names.go @@ -0,0 +1,276 @@ +package goenv + +// General-purpose environment variables. +// Reference: https://github.com/golang/go/blob/0afd7e85e5d7154161770f06a17d09bf1ffa3e94/src/cmd/go/internal/help/helpdoc.go#L490 +const ( + // GCCGO The gccgo command to run for 'go build -compiler=gccgo'. + GCCGO = "GCCGO" + // GO111MODULE Controls whether the go command runs in module-aware mode or GOPATH mode. + // May be "off", "on", or "auto". + // See https://golang.org/ref/mod#mod-commands. + GO111MODULE = "GO111MODULE" + // GOARCH The architecture, or processor, for which to compile code. + // Examples are amd64, 386, arm, ppc64. + GOARCH = "GOARCH" + // GOAUTH Controls authentication for go-import and HTTPS module mirror interactions. + // See 'go help goauth'. + GOAUTH = "GOAUTH" + // GOBIN The directory where 'go install' will install a command. + GOBIN = "GOBIN" + // GOCACHE The directory where the go command will store cached + // information for reuse in future builds. + GOCACHE = "GOCACHE" + // GOCACHEPROG A command (with optional space-separated flags) that implements an + // external go command build cache. + // See 'go doc cmd/go/internal/cacheprog'. + GOCACHEPROG = "GOCACHEPROG" + // GODEBUG Enable various debugging facilities. See https://go.dev/doc/godebug + // for details. + GODEBUG = "GODEBUG" + // GOENV The location of the Go environment configuration file. + // Cannot be set using 'go env -w'. + // Setting GOENV=off in the environment disables the use of the + // default configuration file. + GOENV = "GOENV" + // GOFLAGS A space-separated list of -flag=value settings to apply + // to go commands by default, when the given flag is known by + // the current command. Each entry must be a standalone flag. + // Because the entries are space-separated, flag values must + // not contain spaces. Flags listed on the command line + // are applied after this list and therefore override it. + GOFLAGS = "GOFLAGS" + // GOINSECURE Comma-separated list of glob patterns (in the syntax of Go's path.Match) + // of module path prefixes that should always be fetched in an insecure + // manner. Only applies to dependencies that are being fetched directly. + // GOINSECURE does not disable checksum database validation. GOPRIVATE or + // GONOSUMDB may be used to achieve that. + GOINSECURE = "GOINSECURE" + // GOMODCACHE The directory where the go command will store downloaded modules. + GOMODCACHE = "GOMODCACHE" + // GOOS The operating system for which to compile code. + // Examples are linux, darwin, windows, netbsd. + GOOS = "GOOS" + // GOPATH Controls where various files are stored. See: 'go help gopath'. + GOPATH = "GOPATH" + // GOPROXY URL of Go module proxy. See https://golang.org/ref/mod#environment-variables + // and https://golang.org/ref/mod#module-proxy for details. + GOPROXY = "GOPROXY" + // GOROOT The root of the go tree. + GOROOT = "GOROOT" + // GOSUMDB The name of checksum database to use and optionally its public key and + // URL. See https://golang.org/ref/mod#authenticating. + GOSUMDB = "GOSUMDB" + // GOTMPDIR The directory where the go command will write + // temporary source files, packages, and binaries. + GOTMPDIR = "GOTMPDIR" + // GOTOOLCHAIN Controls which Go toolchain is used. See https://go.dev/doc/toolchain. + GOTOOLCHAIN = "GOTOOLCHAIN" + // GOVCS Lists version control commands that may be used with matching servers. + // See 'go help vcs'. + GOVCS = "GOVCS" + // GOWORK In module aware mode, use the given go.work file as a workspace file. + // By default or when GOWORK is "auto", the go command searches for a + // file named go.work in the current directory and then containing directories + // until one is found. If a valid go.work file is found, the modules + // specified will collectively be used as the main modules. If GOWORK + // is "off", or a go.work file is not found in "auto" mode, workspace + // mode is disabled. + GOWORK = "GOWORK" + + // GOPRIVATE Comma-separated list of glob patterns (in the syntax of Go's path.Match) + // of module path prefixes that should always be fetched directly + // or that should not be compared against the checksum database. + // See https://golang.org/ref/mod#private-modules. + GOPRIVATE = "GOPRIVATE" + // GONOPROXY Comma-separated list of glob patterns (in the syntax of Go's path.Match) + // of module path prefixes that should always be fetched directly + // or that should not be compared against the checksum database. + // See https://golang.org/ref/mod#private-modules. + GONOPROXY = "GONOPROXY" + // GONOSUMDB Comma-separated list of glob patterns (in the syntax of Go's path.Match) + // of module path prefixes that should always be fetched directly + // or that should not be compared against the checksum database. + // See https://golang.org/ref/mod#private-modules. + GONOSUMDB = "GONOSUMDB" +) + +// Environment variables for use with cgo. +// Reference: https://github.com/golang/go/blob/0afd7e85e5d7154161770f06a17d09bf1ffa3e94/src/cmd/go/internal/help/helpdoc.go#L571 +const ( + // AR The command to use to manipulate library archives when + // building with the gccgo compiler. + // The default is 'ar'. + AR = "AR" + // CC The command to use to compile C code. + CC = "CC" + // CGO_CFLAGS Flags that cgo will pass to the compiler when compiling + // C code. + CGO_CFLAGS = "CGO_CFLAGS" + // CGO_CFLAGS_ALLOW A regular expression specifying additional flags to allow + // to appear in #cgo CFLAGS source code directives. + // Does not apply to the CGO_CFLAGS environment variable. + CGO_CFLAGS_ALLOW = "CGO_CFLAGS_ALLOW" + // CGO_CFLAGS_DISALLOW A regular expression specifying flags that must be disallowed + // from appearing in #cgo CFLAGS source code directives. + // Does not apply to the CGO_CFLAGS environment variable. + CGO_CFLAGS_DISALLOW = "CGO_CFLAGS_DISALLOW" + // CGO_ENABLED Whether the cgo command is supported. Either 0 or 1. + CGO_ENABLED = "CGO_ENABLED" + // CXX The command to use to compile C++ code. + CXX = "CXX" + // FC The command to use to compile Fortran code. + FC = "FC" + // PKG_CONFIG Path to pkg-config tool. + PKG_CONFIG = "PKG_CONFIG" + + // CGO_CPPFLAGS Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW, + // but for the C preprocessor. + CGO_CPPFLAGS = "CGO_CPPFLAGS" + // CGO_CPPFLAGS_ALLOW Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW, + // but for the C preprocessor. + CGO_CPPFLAGS_ALLOW = "CGO_CPPFLAGS_ALLOW" + // CGO_CPPFLAGS_DISALLOW Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW, + // but for the C preprocessor. + CGO_CPPFLAGS_DISALLOW = "CGO_CPPFLAGS_DISALLOW" + + // CGO_CXXFLAGS Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW, + // but for the C++ compiler. + CGO_CXXFLAGS = "CGO_CXXFLAGS" + // CGO_CXXFLAGS_ALLOW Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW, + // but for the C++ compiler. + CGO_CXXFLAGS_ALLOW = "CGO_CXXFLAGS_ALLOW" + // CGO_CXXFLAGS_DISALLOW Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW, + // but for the C++ compiler. + CGO_CXXFLAGS_DISALLOW = "CGO_CXXFLAGS_DISALLOW" + + // CGO_FFLAGS Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW, + // but for the Fortran compiler. + CGO_FFLAGS = "CGO_FFLAGS" + // CGO_FFLAGS_ALLOW Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW, + // but for the Fortran compiler. + CGO_FFLAGS_ALLOW = "CGO_FFLAGS_ALLOW" + // CGO_FFLAGS_DISALLOW Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW, + // but for the Fortran compiler. + CGO_FFLAGS_DISALLOW = "CGO_FFLAGS_DISALLOW" + + // CGO_LDFLAGS Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW, + // but for the linker. + CGO_LDFLAGS = "CGO_LDFLAGS" + // CGO_LDFLAGS_ALLOW Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW, + // but for the linker. + CGO_LDFLAGS_ALLOW = "CGO_LDFLAGS_ALLOW" + // CGO_LDFLAGS_DISALLOW Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW, + // but for the linker. + CGO_LDFLAGS_DISALLOW = "CGO_LDFLAGS_DISALLOW" +) + +// Architecture-specific environment variables. +// Reference: https://github.com/golang/go/blob/0afd7e85e5d7154161770f06a17d09bf1ffa3e94/src/cmd/go/internal/help/helpdoc.go#L611 +const ( + // GO386 For GOARCH=386, how to implement floating point instructions. + // Valid values are sse2 (default), softfloat. + GO386 = "GO386" + // GOAMD64 For GOARCH=amd64, the microarchitecture level for which to compile. + // Valid values are v1 (default), v2, v3, v4. + // See https://golang.org/wiki/MinimumRequirements#amd64 + GOAMD64 = "GOAMD64" + // GOARM For GOARCH=arm, the ARM architecture for which to compile. + // Valid values are 5, 6, 7. + // When the Go tools are built on an arm system, + // the default value is set based on what the build system supports. + // When the Go tools are not built on an arm system + // (that is, when building a cross-compiler), + // the default value is 7. + // The value can be followed by an option specifying how to implement floating point instructions. + // Valid options are ,softfloat (default for 5) and ,hardfloat (default for 6 and 7). + GOARM = "GOARM" + // GOARM64 For GOARCH=arm64, the ARM64 architecture for which to compile. + // Valid values are v8.0 (default), v8.{1-9}, v9.{0-5}. + // The value can be followed by an option specifying extensions implemented by target hardware. + // Valid options are ,lse and ,crypto. + // Note that some extensions are enabled by default starting from a certain GOARM64 version; + // for example, lse is enabled by default starting from v8.1. + GOARM64 = "GOARM64" + // GOMIPS For GOARCH=mips{,le}, whether to use floating point instructions. + // Valid values are hardfloat (default), softfloat. + GOMIPS = "GOMIPS" + // GOMIPS64 For GOARCH=mips64{,le}, whether to use floating point instructions. + // Valid values are hardfloat (default), softfloat. + GOMIPS64 = "GOMIPS64" + // GOPPC64 For GOARCH=ppc64{,le}, the target ISA (Instruction Set Architecture). + // Valid values are power8 (default), power9, power10. + GOPPC64 = "GOPPC64" + // GORISCV64 For GOARCH=riscv64, the RISC-V user-mode application profile for which + // to compile. Valid values are rva20u64 (default), rva22u64. + // See https://github.com/riscv/riscv-profiles/blob/main/src/profiles.adoc + GORISCV64 = "GORISCV64" + // GOWASM For GOARCH=wasm, comma-separated list of experimental WebAssembly features to use. + // Valid values are satconv, signext. + GOWASM = "GOWASM" +) + +// Environment variables for use with code coverage. +// Reference: https://github.com/golang/go/blob/0afd7e85e5d7154161770f06a17d09bf1ffa3e94/src/cmd/go/internal/help/helpdoc.go#L654 +const ( + // GOCOVERDIR Directory into which to write code coverage data files + // generated by running a "go build -cover" binary. + // Requires that GOEXPERIMENT=coverageredesign is enabled. + GOCOVERDIR = "GOCOVERDIR" +) + +// Special-purpose environment variables. +// Reference: https://github.com/golang/go/blob/0afd7e85e5d7154161770f06a17d09bf1ffa3e94/src/cmd/go/internal/help/helpdoc.go#L661 +const ( + // GCCGOTOOLDIR If set, where to find gccgo tools, such as cgo. + // The default is based on how gccgo was configured. + GCCGOTOOLDIR = "GCCGOTOOLDIR" + // GOEXPERIMENT Comma-separated list of toolchain experiments to enable or disable. + // The list of available experiments may change arbitrarily over time. + // See GOROOT/src/internal/goexperiment/flags.go for currently valid values. + // Warning: This variable is provided for the development and testing + // of the Go toolchain itself. Use beyond that purpose is unsupported. + GOEXPERIMENT = "GOEXPERIMENT" + // GOFIPS140 The FIPS-140 cryptography mode to use when building binaries. + // The default is GOFIPS140=off, which makes no FIPS-140 changes at all. + // Other values enable FIPS-140 compliance measures and select alternate + // versions of the cryptography source code. + // See https://go.dev/security/fips140 for details. + GOFIPS140 = "GOFIPS140" + // GO_EXTLINK_ENABLED Whether the linker should use external linking mode + // when using -linkmode=auto with code that uses cgo. + // Set to 0 to disable external linking mode, 1 to enable it. + GO_EXTLINK_ENABLED = "GO_EXTLINK_ENABLED" + // GIT_ALLOW_PROTOCOL Defined by Git. A colon-separated list of schemes that are allowed + // to be used with git fetch/clone. If set, any scheme not explicitly + // mentioned will be considered insecure by 'go get'. + // Because the variable is defined by Git, the default value cannot + // be set using 'go env -w'. + GIT_ALLOW_PROTOCOL = "GIT_ALLOW_PROTOCOL" +) + +// Additional information available from 'go env' but not read from the environment. +// Reference: https://github.com/golang/go/blob/0afd7e85e5d7154161770f06a17d09bf1ffa3e94/src/cmd/go/internal/help/helpdoc.go#L689 +const ( + // GOEXE The executable file name suffix (".exe" on Windows, "" on other systems). + GOEXE = "GOEXE" + // GOGCCFLAGS A space-separated list of arguments supplied to the CC command. + GOGCCFLAGS = "GOGCCFLAGS" + // GOHOSTARCH The architecture (GOARCH) of the Go toolchain binaries. + GOHOSTARCH = "GOHOSTARCH" + // GOHOSTOS The operating system (GOOS) of the Go toolchain binaries. + GOHOSTOS = "GOHOSTOS" + // GOMOD The absolute path to the go.mod of the main module. + // If module-aware mode is enabled, but there is no go.mod, GOMOD will be + // os.DevNull ("/dev/null" on Unix-like systems, "NUL" on Windows). + // If module-aware mode is disabled, GOMOD will be the empty string. + GOMOD = "GOMOD" + // GOTELEMETRY The current Go telemetry mode ("off", "local", or "on"). + // See "go help telemetry" for more information. + GOTELEMETRY = "GOTELEMETRY" + // GOTELEMETRYDIR The directory Go telemetry data is written is written to. + GOTELEMETRYDIR = "GOTELEMETRYDIR" + // GOTOOLDIR The directory where the go tools (compile, cover, doc, etc...) are installed. + GOTOOLDIR = "GOTOOLDIR" + // GOVERSION The version of the installed Go tree, as reported by runtime.Version. + GOVERSION = "GOVERSION" +) diff --git a/vendor/github.com/ldez/grignotin/gomod/gomod.go b/vendor/github.com/ldez/grignotin/gomod/gomod.go new file mode 100644 index 000000000..76e17870d --- /dev/null +++ b/vendor/github.com/ldez/grignotin/gomod/gomod.go @@ -0,0 +1,85 @@ +// Package gomod A set of functions to get information about module (go list). +package gomod + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/ldez/grignotin/goenv" + "golang.org/x/mod/modfile" +) + +// ModInfo Module information. +// +//nolint:tagliatelle // temporary: the next version of golangci-lint will allow configuration by package. +type ModInfo struct { + Path string `json:"Path"` + Dir string `json:"Dir"` + GoMod string `json:"GoMod"` + GoVersion string `json:"GoVersion"` + Main bool `json:"Main"` +} + +// GetModuleInfo gets modules information from `go list`. +func GetModuleInfo(ctx context.Context) ([]ModInfo, error) { + // https://github.com/golang/go/issues/44753#issuecomment-790089020 + cmd := exec.CommandContext(ctx, "go", "list", "-m", "-json") + + out, err := cmd.Output() + if err != nil { + return nil, fmt.Errorf("command %q: %w: %s", strings.Join(cmd.Args, " "), err, string(out)) + } + + var infos []ModInfo + + for dec := json.NewDecoder(bytes.NewBuffer(out)); dec.More(); { + var v ModInfo + if err := dec.Decode(&v); err != nil { + return nil, fmt.Errorf("unmarshaling error: %w: %s", err, string(out)) + } + + if v.GoMod == "" { + return nil, errors.New("working directory is not part of a module") + } + + if !v.Main || v.Dir == "" { + continue + } + + infos = append(infos, v) + } + + if len(infos) == 0 { + return nil, errors.New("go.mod file not found") + } + + return infos, nil +} + +// GetModulePath extracts module path from go.mod. +func GetModulePath(ctx context.Context) (string, error) { + p, err := goenv.GetOne(ctx, goenv.GOMOD) + if err != nil { + return "", err + } + + b, err := os.ReadFile(filepath.Clean(p)) + if err != nil { + return "", fmt.Errorf("reading go.mod: %w", err) + } + + return modfile.ModulePath(b), nil +} + +// GetGoModPath extracts go.mod path from "go env". +// Deprecated: use `goenv.GetOne(context.Background(), goenv.GOMOD)` instead. +func GetGoModPath() (string, error) { + return goenv.GetOne(context.Background(), goenv.GOMOD) +} diff --git a/vendor/github.com/golangci/modinfo/LICENSE b/vendor/github.com/ldez/structtags/LICENSE similarity index 100% rename from vendor/github.com/golangci/modinfo/LICENSE rename to vendor/github.com/ldez/structtags/LICENSE diff --git a/vendor/github.com/ldez/structtags/parser/tag.go b/vendor/github.com/ldez/structtags/parser/tag.go new file mode 100644 index 000000000..da9a97f67 --- /dev/null +++ b/vendor/github.com/ldez/structtags/parser/tag.go @@ -0,0 +1,115 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package parser + +import ( + "fmt" + "strconv" +) + +// Filler is the interface implemented by types that can fill elements from a struct tag. +type Filler[T any] interface { + // Data returns the [T] filled by the struct tag content. + Data() T + + // Fill fills the data from a struct tag. + Fill(key, value string) error +} + +// Tag parses a struct tag. +// +// Based on https://github.com/golang/go/blob/411c250d64304033181c46413a6e9381e8fe9b82/src/reflect/type.go#L1030-L1108 +// +//nolint:gocyclo +func Tag[T any](tag string, filler Filler[T]) (T, error) { + base := tag + + for tag != "" { + // Skip leading space. + i := 0 + for i < len(tag) && tag[i] == ' ' { + i++ + } + + tag = tag[i:] + if tag == "" { + break + } + + // Scan to colon. A space, a quote or a control character is a syntax error. + // Strictly speaking, control chars include the range [0x7f, 0x9f], not just + // [0x00, 0x1f], but in practice, we ignore the multi-byte control characters + // as it is simpler to inspect the tag's bytes than the tag's runes. + i = 0 + for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f { + i++ + } + + switch { + case i == 0: + var zero T + + return zero, fmt.Errorf("invalid struct tag syntax `%s`", base) + + case i+1 > len(tag): + var zero T + + return zero, fmt.Errorf("invalid struct tag syntax `%s`: missing `:`", base) + + case i+1 == len(tag): + var zero T + + return zero, fmt.Errorf("invalid struct tag value `%s`", base) + + case tag[i] != ':': + var zero T + + return zero, fmt.Errorf("invalid struct tag syntax `%s`: missing `:`", base) + + case tag[i+1] != '"': + var zero T + + return zero, fmt.Errorf("invalid struct tag value `%s`: missing opening quote", base) + } + + name := tag[:i] + tag = tag[i+1:] + + // Scan quoted string to find value. + i = 1 + for i < len(tag) && tag[i] != '"' { + if tag[i] == '\\' { + i++ + } + + i++ + } + + if i >= len(tag) { + var zero T + + return zero, fmt.Errorf("invalid struct tag value `%s`: missing closing quote", base) + } + + qvalue := tag[:i+1] + tag = tag[i+1:] + + value, err := strconv.Unquote(qvalue) + if err != nil { + var zero T + + return zero, fmt.Errorf("invalid struct tag value `%s`: %w", base, err) + } + + err = filler.Fill(name, value) + if err != nil { + var zero T + + return zero, err + } + } + + return filler.Data(), nil +} diff --git a/vendor/github.com/ldez/structtags/parser/value.go b/vendor/github.com/ldez/structtags/parser/value.go new file mode 100644 index 000000000..cea0cfa81 --- /dev/null +++ b/vendor/github.com/ldez/structtags/parser/value.go @@ -0,0 +1,83 @@ +package parser + +import "fmt" + +// Value parses a tag value. +// The value is split on comma, and escaped commas are ignored. +func Value(raw string, escapeComma bool) ([]string, error) { + if raw == "" { + return []string{""}, nil + } + + var values []string + + for raw != "" { + i := indexEscaped(raw, 0, escapeComma) + + if i == 0 { + values = append(values, "") + raw = raw[i+1:] + + if raw == "" { + values = append(values, "") + + break + } + + continue + } + + if i == len(raw) { + values = append(values, raw[:i]) + + break + } + + if i > len(raw) { + return nil, fmt.Errorf("syntax error in struct tag value %q", raw) + } + + value := raw[:i] + + endComma := raw[i] == ',' && raw[i+1:] == "" + + raw = raw[i+1:] + + values = append(values, value) + + if endComma { + values = append(values, "") + } + } + + return values, nil +} + +func indexEscaped(raw string, i int, escapeComma bool) int { + for i < len(raw) && raw[i] != ',' { + i++ + } + + if !escapeComma { + return i + } + + if i-1 >= 0 && raw[i-1] == '\\' { + j := i - 1 + + count := 1 + + for j >= 0 && raw[j] == '\\' { + count++ + j-- + } + + if count%2 == 0 { + i++ + + return indexEscaped(raw, i, escapeComma) + } + } + + return i +} diff --git a/vendor/github.com/ldez/tagliatelle/.golangci.yml b/vendor/github.com/ldez/tagliatelle/.golangci.yml index ec5c5c766..371822b51 100644 --- a/vendor/github.com/ldez/tagliatelle/.golangci.yml +++ b/vendor/github.com/ldez/tagliatelle/.golangci.yml @@ -1,88 +1,83 @@ -run: - timeout: 5m - skip-files: [ ] - skip-dirs: [ ] +version: "2" -linters-settings: - govet: - enable-all: true - disable: - - fieldalignment - gocyclo: - min-complexity: 15 - goconst: - min-len: 5 - min-occurrences: 3 - misspell: - locale: US - funlen: - lines: -1 - statements: 40 - godox: - keywords: - - FIXME - gofumpt: - extra-rules: true - depguard: - list-type: denylist - include-go-root: false - packages: - - github.com/sirupsen/logrus - - github.com/pkg/errors - gocritic: - enabled-tags: - - diagnostic - - style - - performance - disabled-checks: - - sloppyReassign - - rangeValCopy - - octalLiteral - - paramTypeCombine # already handle by gofumpt.extra-rules - settings: - hugeParam: - sizeThreshold: 100 +formatters: + enable: + - gci + - gofumpt + settings: + gofumpt: + extra-rules: true linters: - enable-all: true + default: all disable: - - deadcode # deprecated - - exhaustivestruct # deprecated - - golint # deprecated - - ifshort # deprecated - - interfacer # deprecated - - maligned # deprecated - - nosnakecase # deprecated - - scopelint # deprecated - - structcheck # deprecated - - varcheck # deprecated - - sqlclosecheck # not relevant (SQL) - - rowserrcheck # not relevant (SQL) - - execinquery # not relevant (SQL) - cyclop # duplicate of gocyclo - - lll - dupl - - wsl - - nlreturn - - gomnd - - goerr113 - - wrapcheck + - err113 + - errchkjson - exhaustive - exhaustruct - - testpackage - - tparallel - - paralleltest - - prealloc - - ifshort - forcetypeassert - - varnamelen + - lll + - mnd - nilnil - - errchkjson + - nlreturn - nonamedreturns + - paralleltest + - prealloc + - rowserrcheck # not relevant (SQL) + - sqlclosecheck # not relevant (SQL) + - testpackage + - tparallel + - varnamelen + - wrapcheck + - wsl # Deprecated + + settings: + depguard: + rules: + main: + deny: + - pkg: github.com/instana/testify + desc: not allowed + - pkg: github.com/pkg/errors + desc: Should be replaced by standard lib errors package + funlen: + lines: -1 + statements: 40 + goconst: + min-len: 5 + min-occurrences: 3 + gocritic: + disabled-checks: + - sloppyReassign + - rangeValCopy + - octalLiteral + - paramTypeCombine # already handle by gofumpt.extra-rules + enabled-tags: + - diagnostic + - style + - performance + settings: + hugeParam: + sizeThreshold: 100 + gocyclo: + min-complexity: 20 + godox: + keywords: + - FIXME + govet: + disable: + - fieldalignment + enable-all: true + misspell: + locale: US + + exclusions: + warn-unused: true + presets: + - comments issues: - exclude-use-default: false - max-per-linter: 0 + max-issues-per-linter: 0 max-same-issues: 0 - exclude: - - 'package-comments: should have a package comment' diff --git a/vendor/github.com/ldez/tagliatelle/converter.go b/vendor/github.com/ldez/tagliatelle/converter.go new file mode 100644 index 000000000..97bcf369c --- /dev/null +++ b/vendor/github.com/ldez/tagliatelle/converter.go @@ -0,0 +1,119 @@ +package tagliatelle + +import ( + "fmt" + "maps" + "strings" + + "github.com/ettle/strcase" +) + +// https://github.com/dominikh/go-tools/blob/v0.5.1/config/config.go#L167-L175 +// +//nolint:gochecknoglobals // For now I'll accept this, but I think will refactor to use a structure. +var staticcheckInitialisms = map[string]bool{ + "AMQP": true, + "DB": true, + "GID": true, + "LHS": false, + "RHS": false, + "RTP": true, + "SIP": true, + "TS": true, +} + +// Converter is the signature of a case converter. +type Converter func(s string) string + +// ConverterCallback allows to abstract `getSimpleConverter` and `ruleToConverter`. +type ConverterCallback func() (Converter, error) + +func getSimpleConverter(c string) (Converter, error) { + switch c { + case "camel": + return strcase.ToCamel, nil + case "pascal": + return strcase.ToPascal, nil + case "kebab": + return strcase.ToKebab, nil + case "snake": + return strcase.ToSnake, nil + case "goCamel": + return strcase.ToGoCamel, nil + case "goPascal": + return strcase.ToGoPascal, nil + case "goKebab": + return strcase.ToGoKebab, nil + case "goSnake": + return strcase.ToGoSnake, nil + case "upperSnake": + return strcase.ToSNAKE, nil + case "header": + return toHeader, nil + case "upper": + return strings.ToUpper, nil + case "lower": + return strings.ToLower, nil + default: + return nil, fmt.Errorf("unsupported case: %s", c) + } +} + +func toHeader(s string) string { + return strcase.ToCase(s, strcase.TitleCase, '-') +} + +func ruleToConverter(rule ExtendedRule) (Converter, error) { + initialismOverrides := maps.Clone(rule.InitialismOverrides) + + if rule.ExtraInitialisms { + for k, v := range staticcheckInitialisms { + if _, found := initialismOverrides[k]; found { + continue + } + + initialismOverrides[k] = v + } + } + + caser := strcase.NewCaser(strings.HasPrefix(rule.Case, "go"), initialismOverrides, nil) + + switch strings.ToLower(strings.TrimPrefix(rule.Case, "go")) { + case "camel": + return caser.ToCamel, nil + + case "pascal": + return caser.ToPascal, nil + + case "kebab": + return caser.ToKebab, nil + + case "snake": + return caser.ToSnake, nil + + case "uppersnake": + return caser.ToSNAKE, nil + + case "header": + return toHeaderCase(caser), nil + + case "upper": + return func(s string) string { + return caser.ToCase(s, strcase.UpperCase, 0) + }, nil + + case "lower": + return func(s string) string { + return caser.ToCase(s, strcase.LowerCase, 0) + }, nil + + default: + return nil, fmt.Errorf("unsupported case: %s", rule.Case) + } +} + +func toHeaderCase(caser *strcase.Caser) Converter { + return func(s string) string { + return caser.ToCase(s, strcase.TitleCase, '-') + } +} diff --git a/vendor/github.com/ldez/tagliatelle/readme.md b/vendor/github.com/ldez/tagliatelle/readme.md index 55a544db8..77dd416ca 100644 --- a/vendor/github.com/ldez/tagliatelle/readme.md +++ b/vendor/github.com/ldez/tagliatelle/readme.md @@ -97,34 +97,171 @@ type Foo struct { } ``` -## What this tool is about +## What this linter is about -This tool is about validating tags according to rules you define. -The tool also allows to fix tags according to the rules you defined. +This linter is about validating tags according to the rules you define. +The linter also allows you to fix tags according to the rules you defined. -This tool is not intended to validate the fact a tag in valid or not. -To do that, you can use `go vet`, or use [golangci-lint](https://golangci-lint.run) ["go vet"](https://golangci-lint.run/usage/linters/#govet) linter. +This linter is not intended to validate the fact a tag is valid or not. -## How to use the tool +## How to use the linter ### As a golangci-lint linter Define the rules, you want via your [golangci-lint](https://golangci-lint.run) configuration file: ```yaml -linters-settings: - tagliatelle: - # Check the struck tag name case. - case: - # Use the struct field name to check the name of the struct tag. - # Default: false - use-field-name: true - rules: - # Any struct tag type can be used. - # Support string case: `camel`, `pascal`, `kebab`, `snake`, `upperSnake`, `goCamel`, `goPascal`, `goKebab`, `goSnake`, `upper`, `lower`, `header`. - json: camel - yaml: camel - xml: camel +linters: + enable: + - tagliatelle + + settings: + tagliatelle: + # Checks the struct tag name case. + case: + # Defines the association between tag name and case. + # Any struct tag name can be used. + # Supported string cases: + # - `camel` + # - `pascal` + # - `kebab` + # - `snake` + # - `upperSnake` + # - `goCamel` + # - `goPascal` + # - `goKebab` + # - `goSnake` + # - `upper` + # - `lower` + # - `header` + rules: + json: camel + yaml: camel + xml: camel + toml: camel + bson: camel + avro: snake + mapstructure: kebab + env: upperSnake + envconfig: upperSnake + whatever: snake + # Defines the association between tag name and case. + # Important: the `extended-rules` overrides `rules`. + # Default: empty + extended-rules: + json: + # Supported string cases: + # - `camel` + # - `pascal` + # - `kebab` + # - `snake` + # - `upperSnake` + # - `goCamel` + # - `goPascal` + # - `goKebab` + # - `goSnake` + # - `header` + # - `lower` + # - `header` + # + # Required + case: camel + # Adds 'AMQP', 'DB', 'GID', 'RTP', 'SIP', 'TS' to initialisms, + # and removes 'LHS', 'RHS' from initialisms. + # Default: false + extra-initialisms: true + # Defines initialism additions and overrides. + # Default: empty + initialism-overrides: + DB: true # add a new initialism + LHS: false # disable a default initialism. + # ... + # Uses the struct field name to check the name of the struct tag. + # Default: false + use-field-name: true + # The field names to ignore. + # Default: [] + ignored-fields: + - Bar + - Foo + # Overrides the default/root configuration. + # Default: [] + overrides: + - + # The package path (uses `/` only as a separator). + # Required + pkg: foo/bar + # Default: empty or the same as the default/root configuration. + rules: + json: snake + xml: pascal + # Default: empty or the same as the default/root configuration. + extended-rules: + # same options as the base `extended-rules`. + # Default: false (WARNING: it doesn't follow the default/root configuration) + use-field-name: true + # The field names to ignore. + # Default: [] or the same as the default/root configuration. + ignored-fields: + - Bar + - Foo + # Ignore the package (takes precedence over all other configurations). + # Default: false + ignore: true +``` + +#### Examples + +Overrides case rules for the package `foo/bar`: + +```yaml +linters: + settings: + tagliatelle: + case: + rules: + json: camel + yaml: camel + xml: camel + overrides: + - pkg: foo/bar + rules: + json: snake + xml: pascal +``` + +Ignore fields inside the package `foo/bar`: + +```yaml +linters: + settings: + tagliatelle: + case: + rules: + json: camel + yaml: camel + xml: camel + overrides: + - pkg: foo/bar + ignored-fields: + - Bar + - Foo +``` + +Ignore the package `foo/bar`: + +```yaml +linters: + settings: + tagliatelle: + case: + rules: + json: camel + yaml: camel + xml: camel + overrides: + - pkg: foo/bar + ignore: true ``` More information here https://golangci-lint.run/usage/linters/#tagliatelle @@ -141,7 +278,7 @@ then launch it manually. ## Rules -Here are the default rules for the well known and used tags, when using tagliatelle as a binary or [golangci-lint linter](https://golangci-lint.run/usage/linters/#tagliatelle): +Here are the default rules for the well-known and used tags, when using tagliatelle as a binary or [golangci-lint linter](https://golangci-lint.run/usage/linters/#tagliatelle): - `json`: `camel` - `yaml`: `camel` @@ -149,29 +286,32 @@ Here are the default rules for the well known and used tags, when using tagliate - `bson`: `camel` - `avro`: `snake` - `header`: `header` +- `env`: `upperSnake` - `envconfig`: `upperSnake` ### Custom Rules -The tool is not limited to the tags used in example, you can use it to validate any tag. +The linter is not limited to the tags used in example, **you can use it to validate any tag**. -You can add your own tag, for example `whatever` and tells the tool you want to use `kebab`. +You can add your own tag, for example `whatever` and tells the linter you want to use `kebab`. This option is only available via [golangci-lint](https://golangci-lint.run). ```yaml -linters-settings: - tagliatelle: - # Check the struck tag name case. - case: - # Use the struct field name to check the name of the struct tag. - # Default: false - use-field-name: true - rules: - # Any struct tag type can be used. - # Support string case: `camel`, `pascal`, `kebab`, `snake`, `goCamel`, `goPascal`, `goKebab`, `goSnake`, `upper`, `lower` - json: camel - yaml: camel - xml: camel - whatever: kebab +linters: + settings: + tagliatelle: + # Check the struck tag name case. + case: + rules: + # Any struct tag type can be used. + # Support string case: `camel`, `pascal`, `kebab`, `snake`, `goCamel`, `goPascal`, `goKebab`, `goSnake`, `upper`, `lower` + json: camel + yaml: camel + xml: camel + toml: camel + whatever: kebab + # Use the struct field name to check the name of the struct tag. + # Default: false + use-field-name: true ``` diff --git a/vendor/github.com/ldez/tagliatelle/tagliatelle.go b/vendor/github.com/ldez/tagliatelle/tagliatelle.go index 22c5feb3d..ccd1b63e6 100644 --- a/vendor/github.com/ldez/tagliatelle/tagliatelle.go +++ b/vendor/github.com/ldez/tagliatelle/tagliatelle.go @@ -6,10 +6,14 @@ import ( "errors" "fmt" "go/ast" + "maps" + "path" + "path/filepath" "reflect" + "slices" "strings" - "github.com/ettle/strcase" + iradix "github.com/hashicorp/go-immutable-radix/v2" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/ast/inspector" @@ -17,8 +21,32 @@ import ( // Config the tagliatelle configuration. type Config struct { - Rules map[string]string - UseFieldName bool + Base + + Overrides []Overrides +} + +// Overrides applies configuration overrides by package. +type Overrides struct { + Base + + Package string +} + +// Base shared configuration between rules. +type Base struct { + Rules map[string]string + ExtendedRules map[string]ExtendedRule + UseFieldName bool + IgnoredFields []string + Ignore bool +} + +// ExtendedRule allows to customize rules. +type ExtendedRule struct { + Case string + ExtraInitialisms bool + InitialismOverrides map[string]bool } // New creates an analyzer. @@ -26,20 +54,18 @@ func New(config Config) *analysis.Analyzer { return &analysis.Analyzer{ Name: "tagliatelle", Doc: "Checks the struct tags.", - Run: func(pass *analysis.Pass) (interface{}, error) { - if len(config.Rules) == 0 { + Run: func(pass *analysis.Pass) (any, error) { + if len(config.Rules) == 0 && len(config.ExtendedRules) == 0 && len(config.Overrides) == 0 { return nil, nil } return run(pass, config) }, - Requires: []*analysis.Analyzer{ - inspect.Analyzer, - }, + Requires: []*analysis.Analyzer{inspect.Analyzer}, } } -func run(pass *analysis.Pass, config Config) (interface{}, error) { +func run(pass *analysis.Pass, config Config) (any, error) { isp, ok := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) if !ok { return nil, errors.New("missing inspect analyser") @@ -49,6 +75,17 @@ func run(pass *analysis.Pass, config Config) (interface{}, error) { (*ast.StructType)(nil), } + cfg := config.Base + + if pass.Module != nil { + radixTree := createRadixTree(config, pass.Module.Path) + _, cfg, _ = radixTree.Root().LongestPrefix([]byte(pass.Pkg.Path())) + } + + if cfg.Ignore { + return nil, nil + } + isp.Preorder(nodeFilter, func(n ast.Node) { node, ok := n.(*ast.StructType) if !ok { @@ -56,14 +93,14 @@ func run(pass *analysis.Pass, config Config) (interface{}, error) { } for _, field := range node.Fields.List { - analyze(pass, config, node, field) + analyze(pass, cfg, node, field) } }) return nil, nil } -func analyze(pass *analysis.Pass, config Config, n *ast.StructType, field *ast.Field) { +func analyze(pass *analysis.Pass, config Base, n *ast.StructType, field *ast.Field) { if n.Fields == nil || n.Fields.NumFields() < 1 { // skip empty structs return @@ -80,54 +117,80 @@ func analyze(pass *analysis.Pass, config Config, n *ast.StructType, field *ast.F return } + cleanRules(config) + + if slices.Contains(config.IgnoredFields, fieldName) { + return + } + + for key, extRule := range config.ExtendedRules { + report(pass, config, key, extRule.Case, fieldName, n, field, func() (Converter, error) { + return ruleToConverter(extRule) + }) + } + for key, convName := range config.Rules { - if convName == "" { - continue - } + report(pass, config, key, convName, fieldName, n, field, func() (Converter, error) { + return getSimpleConverter(convName) + }) + } +} - value, flags, ok := lookupTagValue(field.Tag, key) - if !ok { - // skip when no struct tag for the key - continue - } +func report(pass *analysis.Pass, config Base, key, convName, fieldName string, n *ast.StructType, field *ast.Field, fn ConverterCallback) { + if convName == "" { + return + } - if value == "-" { - // skip when skipped :) - continue - } + value, flags, ok := lookupTagValue(field.Tag, key) + if !ok { + // skip when no struct tag for the key + return + } - // TODO(ldez): need to be rethink. - // This is an exception because of a bug. - // https://github.com/ldez/tagliatelle/issues/8 - // For now, tagliatelle should try to remain neutral in terms of format. - if hasTagFlag(flags, "inline") { - // skip for inline children (no name to lint) - continue - } + if value == "-" { + // skip when skipped :) + return + } - if value == "" { - value = fieldName - } + // TODO(ldez): need to be rethink. + // tagliatelle should try to remain neutral in terms of format. + if key == "xml" && strings.ContainsAny(value, ">:") { + // ignore XML names than contains path + return + } - converter, err := getConverter(convName) - if err != nil { - pass.Reportf(n.Pos(), "%s(%s): %v", key, convName, err) - continue - } + // TODO(ldez): need to be rethink. + // This is an exception because of a bug. + // https://github.com/ldez/tagliatelle/issues/8 + // For now, tagliatelle should try to remain neutral in terms of format. + if slices.Contains(flags, "inline") { + // skip for inline children (no name to lint) + return + } - expected := value - if config.UseFieldName { - expected = fieldName - } + if value == "" { + value = fieldName + } - if value != converter(expected) { - pass.Reportf(field.Tag.Pos(), "%s(%s): got '%s' want '%s'", key, convName, value, converter(expected)) - } + converter, err := fn() + if err != nil { + pass.Reportf(n.Pos(), "%s(%s): %v", key, convName, err) + return + } + + expected := value + if config.UseFieldName { + expected = fieldName + } + + if value != converter(expected) { + pass.Reportf(field.Tag.Pos(), "%s(%s): got '%s' want '%s'", key, convName, value, converter(expected)) } } func getFieldName(field *ast.Field) (string, error) { var name string + for _, n := range field.Names { if n.Name != "" { name = n.Name @@ -172,47 +235,62 @@ func lookupTagValue(tag *ast.BasicLit, key string) (name string, flags []string, return values[0], values[1:], true } -func hasTagFlag(flags []string, query string) bool { - for _, flag := range flags { - if flag == query { - return true - } +func createRadixTree(config Config, modPath string) *iradix.Tree[Base] { + r := iradix.New[Base]() + + defaultRule := Base{ + Rules: maps.Clone(config.Rules), + ExtendedRules: maps.Clone(config.ExtendedRules), + UseFieldName: config.UseFieldName, + Ignore: config.Ignore, } - return false -} + defaultRule.IgnoredFields = append(defaultRule.IgnoredFields, config.IgnoredFields...) -func getConverter(c string) (func(s string) string, error) { - switch c { - case "camel": - return strcase.ToCamel, nil - case "pascal": - return strcase.ToPascal, nil - case "kebab": - return strcase.ToKebab, nil - case "snake": - return strcase.ToSnake, nil - case "goCamel": - return strcase.ToGoCamel, nil - case "goPascal": - return strcase.ToGoPascal, nil - case "goKebab": - return strcase.ToGoKebab, nil - case "goSnake": - return strcase.ToGoSnake, nil - case "header": - return toHeader, nil - case "upper": - return strings.ToUpper, nil - case "upperSnake": - return strcase.ToSNAKE, nil - case "lower": - return strings.ToLower, nil - default: - return nil, fmt.Errorf("unsupported case: %s", c) + r, _, _ = r.Insert([]byte(""), defaultRule) + + for _, override := range config.Overrides { + c := Base{ + UseFieldName: override.UseFieldName, + Ignore: override.Ignore, + } + + // If there is an override, the base configuration is ignored. + if len(override.IgnoredFields) == 0 { + c.IgnoredFields = append(c.IgnoredFields, config.IgnoredFields...) + } else { + c.IgnoredFields = append(c.IgnoredFields, override.IgnoredFields...) + } + + // Copy the rules from the base. + c.Rules = maps.Clone(config.Rules) + + // Overrides the rule from the base. + for k, v := range override.Rules { + c.Rules[k] = v + } + + // Copy the extended rules from the base. + c.ExtendedRules = maps.Clone(config.ExtendedRules) + + // Overrides the extended rule from the base. + for k, v := range override.ExtendedRules { + c.ExtendedRules[k] = v + } + + key := path.Join(modPath, override.Package) + if filepath.Base(modPath) == override.Package { + key = modPath + } + + r, _, _ = r.Insert([]byte(key), c) } + + return r } -func toHeader(s string) string { - return strcase.ToCase(s, strcase.TitleCase, '-') +func cleanRules(config Base) { + for k := range config.ExtendedRules { + delete(config.Rules, k) + } } diff --git a/vendor/github.com/ldez/usetesting/.gitignore b/vendor/github.com/ldez/usetesting/.gitignore new file mode 100644 index 000000000..0907a9069 --- /dev/null +++ b/vendor/github.com/ldez/usetesting/.gitignore @@ -0,0 +1,2 @@ +/usetesting +.idea diff --git a/vendor/github.com/ldez/usetesting/.golangci.yml b/vendor/github.com/ldez/usetesting/.golangci.yml new file mode 100644 index 000000000..1c66174ea --- /dev/null +++ b/vendor/github.com/ldez/usetesting/.golangci.yml @@ -0,0 +1,78 @@ +version: "2" + +formatters: + enable: + - gci + - gofumpt + settings: + gofumpt: + extra-rules: true + +linters: + default: all + disable: + - cyclop # duplicate of gocyclo + - dupl + - errchkjson + - exhaustive + - exhaustruct + - lll + - nilnil + - nlreturn + - nonamedreturns + - paralleltest + - prealloc + - rowserrcheck # not relevant (SQL) + - sqlclosecheck # not relevant (SQL) + - testpackage + - tparallel + - varnamelen + settings: + depguard: + rules: + main: + deny: + - pkg: github.com/instana/testify + desc: not allowed + - pkg: github.com/pkg/errors + desc: Should be replaced by standard lib errors package + funlen: + lines: -1 + statements: 40 + goconst: + min-len: 5 + min-occurrences: 3 + gocritic: + disabled-checks: + - sloppyReassign + - rangeValCopy + - octalLiteral + - paramTypeCombine # already handle by gofumpt.extra-rules + enabled-tags: + - diagnostic + - style + - performance + settings: + hugeParam: + sizeThreshold: 100 + gocyclo: + min-complexity: 20 + godox: + keywords: + - FIXME + govet: + disable: + - fieldalignment + enable-all: true + misspell: + locale: US + mnd: + ignored-numbers: + - "124" + wsl: + force-case-trailing-whitespace: 1 + allow-trailing-comment: true + +issues: + max-issues-per-linter: 0 + max-same-issues: 0 diff --git a/vendor/github.com/ldez/usetesting/LICENSE b/vendor/github.com/ldez/usetesting/LICENSE new file mode 100644 index 000000000..c1bf0c328 --- /dev/null +++ b/vendor/github.com/ldez/usetesting/LICENSE @@ -0,0 +1,190 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2024 Fernandez Ludovic + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/ldez/usetesting/Makefile b/vendor/github.com/ldez/usetesting/Makefile new file mode 100644 index 000000000..b8eca6598 --- /dev/null +++ b/vendor/github.com/ldez/usetesting/Makefile @@ -0,0 +1,15 @@ +.PHONY: clean check test build + +default: clean check test build + +clean: + rm -rf dist/ cover.out + +test: clean + go test -v -cover ./... + +check: + golangci-lint run + +build: + go build -ldflags "-s -w" -trimpath ./cmd/usetesting/ diff --git a/vendor/github.com/ldez/usetesting/readme.md b/vendor/github.com/ldez/usetesting/readme.md new file mode 100644 index 000000000..c4dd3daa1 --- /dev/null +++ b/vendor/github.com/ldez/usetesting/readme.md @@ -0,0 +1,213 @@ +# UseTesting + +Detects when some calls can be replaced by methods from the testing package. + +[![Sponsor](https://img.shields.io/badge/Sponsor%20me-%E2%9D%A4%EF%B8%8F-pink)](https://github.com/sponsors/ldez) + +## Usages + +### Inside golangci-lint + +Recommended. + +```yml +linters: + enable: + - usetesting + + settings: + usetesting: + # Enable/disable `os.CreateTemp("", ...)` detections. + # Default: true + os-create-temp: false + + # Enable/disable `os.MkdirTemp()` detections. + # Default: true + os-mkdir-temp: false + + # Enable/disable `os.Setenv()` detections. + # Default: true + os-setenv: false + + # Enable/disable `os.TempDir()` detections. + # Default: false + os-temp-dir: true + + # Enable/disable `os.Chdir()` detections. + # Disabled if Go < 1.24. + # Default: true + os-chdir: false + + # Enable/disable `context.Background()` detections. + # Disabled if Go < 1.24. + # Default: false + context-background: true + + # Enable/disable `context.TODO()` detections. + # Disabled if Go < 1.24. + # Default: false + context-todo: true +``` + +### As a CLI + +```shell +go install github.com/ldez/usetesting/cmd/usetesting@latest +``` + +``` +usetesting: Reports uses of functions with replacement inside the testing package. + +Usage: usetesting [-flag] [package] + +Flags: + -contextbackground + Enable/disable context.Background() detections (default true) + -contexttodo + Enable/disable context.TODO() detections (default true) + -oschdir + Enable/disable os.Chdir() detections (default true) + -osmkdirtemp + Enable/disable os.MkdirTemp() detections (default true) + -ossetenv + Enable/disable os.Setenv() detections (default false) + -ostempdir + Enable/disable os.TempDir() detections (default false) + -oscreatetemp + Enable/disable os.CreateTemp("", ...) detections (default true) +... +``` + +## Examples + +### `os.MkdirTemp` + +```go +func TestExample(t *testing.T) { + os.MkdirTemp("a", "b") + // ... +} +``` + +It can be replaced by: + +```go +func TestExample(t *testing.T) { + t.TempDir() + // ... +} +``` + +### `os.TempDir` + +```go +func TestExample(t *testing.T) { + os.TempDir() + // ... +} +``` + +It can be replaced by: + +```go +func TestExample(t *testing.T) { + t.TempDir() + // ... +} +``` + +### `os.CreateTemp` + +```go +func TestExample(t *testing.T) { + os.CreateTemp("", "x") + // ... +} +``` + +It can be replaced by: + +```go +func TestExample(t *testing.T) { + os.CreateTemp(t.TempDir(), "x") + // ... +} +``` + +### `os.Setenv` + +```go +func TestExample(t *testing.T) { + os.Setenv("A", "b") + // ... +} +``` + +It can be replaced by: + +```go +func TestExample(t *testing.T) { + t.Setenv("A", "b") + // ... +} +``` + +### `os.Chdir` (Go >= 1.24) + +```go +func TestExample(t *testing.T) { + os.Chdir("x") + // ... +} +``` + +It can be replaced by: + +```go +func TestExample(t *testing.T) { + t.Chdir("x") + // ... +} +``` + +### `context.Background` (Go >= 1.24) + +```go +func TestExample(t *testing.T) { + ctx := context.Background() + // ... +} +``` + +It can be replaced by: + +```go +func TestExample(t *testing.T) { + ctx := t.Context() + // ... +} +``` + +### `context.TODO` (Go >= 1.24) + +```go +func TestExample(t *testing.T) { + ctx := context.TODO() + // ... +} +``` + +It can be replaced by: + +```go +func TestExample(t *testing.T) { + ctx := t.Context() + // ... +} +``` + +## References + +- https://tip.golang.org/doc/go1.15#testingpkgtesting (`TempDir`) +- https://tip.golang.org/doc/go1.17#testingpkgtesting (`SetEnv`) +- https://tip.golang.org/doc/go1.24#testingpkgtesting (`Chdir`, `Context`) diff --git a/vendor/github.com/ldez/usetesting/report.go b/vendor/github.com/ldez/usetesting/report.go new file mode 100644 index 000000000..333931c36 --- /dev/null +++ b/vendor/github.com/ldez/usetesting/report.go @@ -0,0 +1,200 @@ +package usetesting + +import ( + "bytes" + "fmt" + "go/ast" + "go/printer" + "go/token" + "slices" + "strings" + + "golang.org/x/tools/go/analysis" +) + +// because [os.CreateTemp] takes 2 args. +const nbArgCreateTemp = 2 + +func (a *analyzer) reportCallExpr(pass *analysis.Pass, ce *ast.CallExpr, fnInfo *FuncInfo) bool { + if !a.osCreateTemp { + return false + } + + if len(ce.Args) != nbArgCreateTemp { + return false + } + + switch fun := ce.Fun.(type) { + case *ast.SelectorExpr: + if fun.Sel == nil || fun.Sel.Name != createTempName { + return false + } + + expr, ok := fun.X.(*ast.Ident) + if !ok { + return false + } + + if expr.Name == osPkgName && isFirstArgEmptyString(ce) { + pass.Report(diagnosticOSCreateTemp(ce, fnInfo)) + + return true + } + + case *ast.Ident: + if fun.Name != createTempName { + return false + } + + pkgName := getPkgNameFromType(pass, fun) + + if pkgName == osPkgName && isFirstArgEmptyString(ce) { + pass.Report(diagnosticOSCreateTemp(ce, fnInfo)) + + return true + } + } + + return false +} + +func diagnosticOSCreateTemp(ce *ast.CallExpr, fnInfo *FuncInfo) analysis.Diagnostic { + diagnostic := analysis.Diagnostic{ + Pos: ce.Pos(), + Message: fmt.Sprintf( + `%s.%s("", ...) could be replaced by %[1]s.%[2]s(%s.%s(), ...) in %s`, + osPkgName, createTempName, fnInfo.ArgName, tempDirName, fnInfo.Name, + ), + } + + // Skip `` arg names. + if !strings.Contains(fnInfo.ArgName, "<") { + g := &ast.CallExpr{ + Fun: ce.Fun, + Args: []ast.Expr{ + &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{Name: fnInfo.ArgName}, + Sel: &ast.Ident{Name: tempDirName}, + }, + }, + ce.Args[1], + }, + } + + buf := bytes.NewBuffer(nil) + + err := printer.Fprint(buf, token.NewFileSet(), g) + if err != nil { + diagnostic.Message = fmt.Sprintf("Suggested fix error: %v", err) + return diagnostic + } + + diagnostic.SuggestedFixes = append(diagnostic.SuggestedFixes, analysis.SuggestedFix{ + TextEdits: []analysis.TextEdit{{ + Pos: ce.Pos(), + End: ce.End(), + NewText: buf.Bytes(), + }}, + }) + } + + return diagnostic +} + +func (a *analyzer) reportSelector(pass *analysis.Pass, se *ast.SelectorExpr, fnInfo *FuncInfo, geGo124 bool) bool { + if se.Sel == nil || !se.Sel.IsExported() { + return false + } + + ident, ok := se.X.(*ast.Ident) + if !ok { + return false + } + + return a.report(pass, se, ident.Name, se.Sel.Name, fnInfo, geGo124) +} + +func (a *analyzer) reportIdent(pass *analysis.Pass, ident *ast.Ident, fnInfo *FuncInfo, geGo124 bool) bool { + if !ident.IsExported() { + return false + } + + if !slices.Contains(a.fieldNames, ident.Name) { + return false + } + + pkgName := getPkgNameFromType(pass, ident) + + return a.report(pass, ident, pkgName, ident.Name, fnInfo, geGo124) +} + +//nolint:gocyclo // The complexity is expected by the number of cases to check. +func (a *analyzer) report(pass *analysis.Pass, rg analysis.Range, origPkgName, origName string, fnInfo *FuncInfo, geGo124 bool) bool { + switch { + case a.osMkdirTemp && origPkgName == osPkgName && origName == mkdirTempName: + report(pass, rg, origPkgName, origName, tempDirName, fnInfo) + + case a.osTempDir && origPkgName == osPkgName && origName == tempDirName: + report(pass, rg, origPkgName, origName, tempDirName, fnInfo) + + case a.osSetenv && origPkgName == osPkgName && origName == setenvName: + report(pass, rg, origPkgName, origName, setenvName, fnInfo) + + case geGo124 && a.osChdir && origPkgName == osPkgName && origName == chdirName: + report(pass, rg, origPkgName, origName, chdirName, fnInfo) + + case geGo124 && a.contextBackground && origPkgName == contextPkgName && origName == backgroundName: + report(pass, rg, origPkgName, origName, contextName, fnInfo) + + case geGo124 && a.contextTodo && origPkgName == contextPkgName && origName == todoName: + report(pass, rg, origPkgName, origName, contextName, fnInfo) + + default: + return false + } + + return true +} + +func report(pass *analysis.Pass, rg analysis.Range, origPkgName, origName, expectName string, fnInfo *FuncInfo) { + diagnostic := analysis.Diagnostic{ + Pos: rg.Pos(), + Message: fmt.Sprintf("%s.%s() could be replaced by %s.%s() in %s", + origPkgName, origName, fnInfo.ArgName, expectName, fnInfo.Name, + ), + } + + // Skip `` arg names. + // Only applies on `context.XXX` because the nb of return parameters is the same as the replacement. + if !strings.Contains(fnInfo.ArgName, "<") && origPkgName == contextPkgName { + diagnostic.SuggestedFixes = append(diagnostic.SuggestedFixes, analysis.SuggestedFix{ + TextEdits: []analysis.TextEdit{{ + Pos: rg.Pos(), + End: rg.End(), + NewText: []byte(fmt.Sprintf("%s.%s", fnInfo.ArgName, expectName)), + }}, + }) + } + + pass.Report(diagnostic) +} + +func isFirstArgEmptyString(ce *ast.CallExpr) bool { + bl, ok := ce.Args[0].(*ast.BasicLit) + if !ok { + return false + } + + return bl.Kind == token.STRING && bl.Value == `""` +} + +func getPkgNameFromType(pass *analysis.Pass, ident *ast.Ident) string { + o := pass.TypesInfo.ObjectOf(ident) + + if o == nil || o.Pkg() == nil { + return "" + } + + return o.Pkg().Name() +} diff --git a/vendor/github.com/ldez/usetesting/usetesting.go b/vendor/github.com/ldez/usetesting/usetesting.go new file mode 100644 index 000000000..ecd113b95 --- /dev/null +++ b/vendor/github.com/ldez/usetesting/usetesting.go @@ -0,0 +1,267 @@ +// Package usetesting It is an analyzer that detects when some calls can be replaced by methods from the testing package. +package usetesting + +import ( + "go/ast" + "go/build" + "os" + "slices" + "strconv" + "strings" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/ast/inspector" +) + +const ( + chdirName = "Chdir" + mkdirTempName = "MkdirTemp" + createTempName = "CreateTemp" + setenvName = "Setenv" + tempDirName = "TempDir" + backgroundName = "Background" + todoName = "TODO" + contextName = "Context" +) + +const ( + osPkgName = "os" + contextPkgName = "context" + testingPkgName = "testing" +) + +// FuncInfo information about the test function. +type FuncInfo struct { + Name string + ArgName string +} + +// analyzer is the UseTesting linter. +type analyzer struct { + contextBackground bool + contextTodo bool + osChdir bool + osMkdirTemp bool + osTempDir bool + osSetenv bool + osCreateTemp bool + + fieldNames []string + + skipGoVersionDetection bool +} + +// NewAnalyzer create a new UseTesting. +func NewAnalyzer() *analysis.Analyzer { + _, skip := os.LookupEnv("USETESTING_SKIP_GO_VERSION_CHECK") // TODO should be removed when go1.25 will be released. + + l := &analyzer{ + fieldNames: []string{ + chdirName, + mkdirTempName, + tempDirName, + setenvName, + backgroundName, + todoName, + createTempName, + }, + skipGoVersionDetection: skip, + } + + a := &analysis.Analyzer{ + Name: "usetesting", + Doc: "Reports uses of functions with replacement inside the testing package.", + Requires: []*analysis.Analyzer{inspect.Analyzer}, + Run: l.run, + } + + a.Flags.BoolVar(&l.contextBackground, "contextbackground", false, "Enable/disable context.Background() detections") + a.Flags.BoolVar(&l.contextTodo, "contexttodo", false, "Enable/disable context.TODO() detections") + a.Flags.BoolVar(&l.osChdir, "oschdir", true, "Enable/disable os.Chdir() detections") + a.Flags.BoolVar(&l.osMkdirTemp, "osmkdirtemp", true, "Enable/disable os.MkdirTemp() detections") + a.Flags.BoolVar(&l.osSetenv, "ossetenv", false, "Enable/disable os.Setenv() detections") + a.Flags.BoolVar(&l.osTempDir, "ostempdir", false, "Enable/disable os.TempDir() detections") + a.Flags.BoolVar(&l.osCreateTemp, "oscreatetemp", true, `Enable/disable os.CreateTemp("", ...) detections`) + + return a +} + +func (a *analyzer) run(pass *analysis.Pass) (any, error) { + if !a.contextBackground && !a.contextTodo && !a.osChdir && !a.osMkdirTemp && !a.osSetenv && !a.osTempDir && !a.osCreateTemp { + return nil, nil + } + + geGo124 := a.isGoSupported(pass) + + insp, ok := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + if !ok { + return nil, nil + } + + nodeFilter := []ast.Node{ + (*ast.FuncDecl)(nil), + (*ast.FuncLit)(nil), + } + + insp.WithStack(nodeFilter, func(node ast.Node, push bool, stack []ast.Node) (proceed bool) { + if !push { + return false + } + + switch fn := node.(type) { + case *ast.FuncDecl: + a.checkFunc(pass, fn.Type, fn.Body, fn.Name.Name, geGo124) + + case *ast.FuncLit: + if hasParentFunc(stack) { + return true + } + + a.checkFunc(pass, fn.Type, fn.Body, "anonymous function", geGo124) + } + + return true + }) + + return nil, nil +} + +func (a *analyzer) checkFunc(pass *analysis.Pass, ft *ast.FuncType, block *ast.BlockStmt, fnName string, geGo124 bool) { + if len(ft.Params.List) < 1 { + return + } + + fnInfo := checkTestFunctionSignature(ft.Params.List[0], fnName) + if fnInfo == nil { + return + } + + ast.Inspect(block, func(n ast.Node) bool { + switch v := n.(type) { + case *ast.SelectorExpr: + return !a.reportSelector(pass, v, fnInfo, geGo124) + + case *ast.Ident: + return !a.reportIdent(pass, v, fnInfo, geGo124) + + case *ast.CallExpr: + return !a.reportCallExpr(pass, v, fnInfo) + } + + return true + }) +} + +func (a *analyzer) isGoSupported(pass *analysis.Pass) bool { + if a.skipGoVersionDetection { + return true + } + + // Prior to go1.22, versions.FileVersion returns only the toolchain version, + // which is of no use to us, + // so disable this analyzer on earlier versions. + if !slices.Contains(build.Default.ReleaseTags, "go1.22") { + return false + } + + pkgVersion := pass.Pkg.GoVersion() + if pkgVersion == "" { + // Empty means Go devel. + return true + } + + raw := strings.TrimPrefix(pkgVersion, "go") + + // prerelease version (go1.24rc1) + idx := strings.IndexFunc(raw, func(r rune) bool { + return (r < '0' || r > '9') && r != '.' + }) + + if idx != -1 { + raw = raw[:idx] + } + + vParts := strings.Split(raw, ".") + + v, err := strconv.Atoi(strings.Join(vParts[:2], "")) + if err != nil { + v = 116 + } + + return v >= 124 +} + +func hasParentFunc(stack []ast.Node) bool { + // -2 because the last parent is the node. + const skipSelf = 2 + + // skip 0 because it's always [*ast.File]. + for i := len(stack) - skipSelf; i > 0; i-- { + s := stack[i] + + switch fn := s.(type) { + case *ast.FuncDecl: + if len(fn.Type.Params.List) < 1 { + continue + } + + if checkTestFunctionSignature(fn.Type.Params.List[0], fn.Name.Name) != nil { + return true + } + + case *ast.FuncLit: + if len(fn.Type.Params.List) < 1 { + continue + } + + if checkTestFunctionSignature(fn.Type.Params.List[0], "anonymous function") != nil { + return true + } + } + } + + return false +} + +func checkTestFunctionSignature(arg *ast.Field, fnName string) *FuncInfo { + switch at := arg.Type.(type) { + case *ast.StarExpr: + if se, ok := at.X.(*ast.SelectorExpr); ok { + return createFuncInfo(arg, "", se, testingPkgName, fnName, "T", "B") + } + + case *ast.SelectorExpr: + return createFuncInfo(arg, "tb", at, testingPkgName, fnName, "TB") + } + + return nil +} + +func createFuncInfo(arg *ast.Field, defaultName string, se *ast.SelectorExpr, pkgName, fnName string, selectorNames ...string) *FuncInfo { + ok := checkSelectorName(se, pkgName, selectorNames...) + if !ok { + return nil + } + + return &FuncInfo{ + Name: fnName, + ArgName: getTestArgName(arg, defaultName), + } +} + +func checkSelectorName(se *ast.SelectorExpr, pkgName string, selectorNames ...string) bool { + if ident, ok := se.X.(*ast.Ident); ok { + return pkgName == ident.Name && slices.Contains(selectorNames, se.Sel.Name) + } + + return false +} + +func getTestArgName(arg *ast.Field, defaultName string) string { + if len(arg.Names) > 0 && arg.Names[0].Name != "_" { + return arg.Names[0].Name + } + + return defaultName +} diff --git a/vendor/github.com/lucasb-eyer/go-colorful/.gitignore b/vendor/github.com/lucasb-eyer/go-colorful/.gitignore new file mode 100644 index 000000000..0aa2c9228 --- /dev/null +++ b/vendor/github.com/lucasb-eyer/go-colorful/.gitignore @@ -0,0 +1,101 @@ +# Created by https://www.toptal.com/developers/gitignore/api/code,go,linux,macos,windows +# Edit at https://www.toptal.com/developers/gitignore?templates=code,go,linux,macos,windows + +### Code ### +.vscode/* +!.vscode/tasks.json +!.vscode/launch.json +*.code-workspace + +### Go ### +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +### Go Patch ### +/vendor/ +/Godeps/ + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# End of https://www.toptal.com/developers/gitignore/api/code,go,linux,macos,windows diff --git a/vendor/github.com/lucasb-eyer/go-colorful/CHANGELOG.md b/vendor/github.com/lucasb-eyer/go-colorful/CHANGELOG.md new file mode 100644 index 000000000..84f9c7b2c --- /dev/null +++ b/vendor/github.com/lucasb-eyer/go-colorful/CHANGELOG.md @@ -0,0 +1,42 @@ +# Changelog +All notable changes to this project will be documented in this file. + +This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +The format of this file is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +but only releases after v1.0.3 properly adhere to it. + + +## [1.2.0] - 2021-01-27 +### Added +- HSLuv and HPLuv color spaces (#41, #51) +- CIE LCh(uv) color space, called `LuvLCh` in code (#51) +- JSON and envconfig serialization support for `HexColor` (#42) +- `DistanceLinearRGB` (#53) + +### Fixed +- RGB to/from XYZ conversion is more accurate (#51) +- A bug in `XYZToLuvWhiteRef` that only applied to very small values was fixed (#51) +- `BlendHCL` output is clamped so that it's not invalid (#46) +- Properly documented `DistanceCIE76` (#40) +- Some small godoc fixes + + +## [1.0.3] - 2019-11-11 +- Remove SQLMock dependency + + +## [1.0.2] - 2019-04-07 +- Fixes SQLMock dependency + + +## [1.0.1] - 2019-03-24 +- Adds support for Go Modules + + +## [1.0.0] - 2018-05-26 +- API Breaking change in `MakeColor`: instead of `panic`ing when alpha is zero, it now returns a secondary, boolean return value indicating success. See [the color.Color interface](#the-colorcolor-interface) section and [this FAQ entry](#q-why-would-makecolor-ever-fail) for details. + + +## [0.9.0] - 2018-05-26 +- Initial version number after having ignored versioning for a long time :) diff --git a/vendor/github.com/lucasb-eyer/go-colorful/LICENSE b/vendor/github.com/lucasb-eyer/go-colorful/LICENSE new file mode 100644 index 000000000..4e402a00e --- /dev/null +++ b/vendor/github.com/lucasb-eyer/go-colorful/LICENSE @@ -0,0 +1,7 @@ +Copyright (c) 2013 Lucas Beyer + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/lucasb-eyer/go-colorful/README.md b/vendor/github.com/lucasb-eyer/go-colorful/README.md new file mode 100644 index 000000000..8b9bd4999 --- /dev/null +++ b/vendor/github.com/lucasb-eyer/go-colorful/README.md @@ -0,0 +1,482 @@ +go-colorful +=========== + +[![go reportcard](https://goreportcard.com/badge/github.com/lucasb-eyer/go-colorful)](https://goreportcard.com/report/github.com/lucasb-eyer/go-colorful) + +A library for playing with colors in Go. Supports Go 1.13 onwards. + +Why? +==== +I love games. I make games. I love detail and I get lost in detail. +One such detail popped up during the development of [Memory Which Does Not Suck](https://github.com/lucasb-eyer/mwdns/), +when we wanted the server to assign the players random colors. Sometimes +two players got very similar colors, which bugged me. The very same evening, +[I want hue](http://tools.medialab.sciences-po.fr/iwanthue/) was the top post +on HackerNews' frontpage and showed me how to Do It Right™. Last but not +least, there was no library for handling color spaces available in go. Colorful +does just that and implements Go's `color.Color` interface. + +What? +===== +Go-Colorful stores colors in RGB and provides methods from converting these to various color-spaces. Currently supported colorspaces are: + +- **RGB:** All three of Red, Green and Blue in [0..1]. +- **HSL:** Hue in [0..360], Saturation and Luminance in [0..1]. For legacy reasons; please forget that it exists. +- **HSV:** Hue in [0..360], Saturation and Value in [0..1]. You're better off using HCL, see below. +- **Hex RGB:** The "internet" color format, as in #FF00FF. +- **Linear RGB:** See [gamma correct rendering](http://www.sjbrown.co.uk/2004/05/14/gamma-correct-rendering/). +- **CIE-XYZ:** CIE's standard color space, almost in [0..1]. +- **CIE-xyY:** encodes chromacity in x and y and luminance in Y, all in [0..1] +- **CIE-L\*a\*b\*:** A *perceptually uniform* color space, i.e. distances are meaningful. L\* in [0..1] and a\*, b\* almost in [-1..1]. +- **CIE-L\*u\*v\*:** Very similar to CIE-L\*a\*b\*, there is [no consensus](http://en.wikipedia.org/wiki/CIELUV#Historical_background) on which one is "better". +- **CIE-L\*C\*h° (HCL):** This is generally the [most useful](http://vis4.net/blog/posts/avoid-equidistant-hsv-colors/) one; CIE-L\*a\*b\* space in polar coordinates, i.e. a *better* HSV. H° is in [0..360], C\* almost in [-1..1] and L\* as in CIE-L\*a\*b\*. +- **CIE LCh(uv):** Called `LuvLCh` in code, this is a cylindrical transformation of the CIE-L\*u\*v\* color space. Like HCL above: H° is in [0..360], C\* almost in [-1..1] and L\* as in CIE-L\*u\*v\*. +- **HSLuv:** The better alternative to HSL, see [here](https://www.hsluv.org/) and [here](https://www.kuon.ch/post/2020-03-08-hsluv/). Hue in [0..360], Saturation and Luminance in [0..1]. +- **HPLuv:** A variant of HSLuv. The color space is smoother, but only pastel colors can be included. Because the valid colors are limited, it's easy to get invalid Saturation values way above 1.0, indicating the color can't be represented in HPLuv beccause it's not pastel. + +For the colorspaces where it makes sense (XYZ, Lab, Luv, HCl), the +[D65](http://en.wikipedia.org/wiki/Illuminant_D65) is used as reference white +by default but methods for using your own reference white are provided. + +A coordinate being *almost in* a range means that generally it is, but for very +bright colors and depending on the reference white, it might overflow this +range slightly. For example, C\* of #0000ff is 1.338. + +Unit-tests are provided. + +Nice, but what's it useful for? +------------------------------- + +- Converting color spaces. Some people like to do that. +- Blending (interpolating) between colors in a "natural" look by using the right colorspace. +- Generating random colors under some constraints (e.g. colors of the same shade, or shades of one color.) +- Generating gorgeous random palettes with distinct colors of a same temperature. + +What not (yet)? +=============== +There are a few features which are currently missing and might be useful. +I just haven't implemented them yet because I didn't have the need for it. +Pull requests welcome. + +- Sorting colors (potentially using above mentioned distances) + +So which colorspace should I use? +================================= +It depends on what you want to do. I think the folks from *I want hue* are +on-spot when they say that RGB fits to how *screens produce* color, CIE L\*a\*b\* +fits how *humans perceive* color and HCL fits how *humans think* colors. + +Whenever you'd use HSV, rather go for CIE-L\*C\*h°. for fixed lightness L\* and +chroma C\* values, the hue angle h° rotates through colors of the same +perceived brightness and intensity. + +How? +==== + +### Installing +Installing the library is as easy as + +```bash +$ go get github.com/lucasb-eyer/go-colorful +``` + +The package can then be used through an + +```go +import "github.com/lucasb-eyer/go-colorful" +``` + +### Basic usage + +Create a beautiful blue color using different source space: + +```go +// Any of the following should be the same +c := colorful.Color{0.313725, 0.478431, 0.721569} +c, err := colorful.Hex("#517AB8") +if err != nil { + log.Fatal(err) +} +c = colorful.Hsv(216.0, 0.56, 0.722) +c = colorful.Xyz(0.189165, 0.190837, 0.480248) +c = colorful.Xyy(0.219895, 0.221839, 0.190837) +c = colorful.Lab(0.507850, 0.040585,-0.370945) +c = colorful.Luv(0.507849,-0.194172,-0.567924) +c = colorful.Hcl(276.2440, 0.373160, 0.507849) +fmt.Printf("RGB values: %v, %v, %v", c.R, c.G, c.B) +``` + +And then converting this color back into various color spaces: + +```go +hex := c.Hex() +h, s, v := c.Hsv() +x, y, z := c.Xyz() +x, y, Y := c.Xyy() +l, a, b := c.Lab() +l, u, v := c.Luv() +h, c, l := c.Hcl() +``` + +Note that, because of Go's unfortunate choice of requiring an initial uppercase, +the name of the functions relating to the xyY space are just off. If you have +any good suggestion, please open an issue. (I don't consider XyY good.) + +### The `color.Color` interface +Because a `colorful.Color` implements Go's `color.Color` interface (found in the +`image/color` package), it can be used anywhere that expects a `color.Color`. + +Furthermore, you can convert anything that implements the `color.Color` interface +into a `colorful.Color` using the `MakeColor` function: + +```go +c, ok := colorful.MakeColor(color.Gray16{12345}) +``` + +**Caveat:** Be aware that this latter conversion (using `MakeColor`) hits a +corner-case when alpha is exactly zero. Because `color.Color` uses pre-multiplied +alpha colors, this means the RGB values are lost (set to 0) and it's impossible +to recover them. In such a case `MakeColor` will return `false` as its second value. + +### Comparing colors +In the RGB color space, the Euclidian distance between colors *doesn't* correspond +to visual/perceptual distance. This means that two pairs of colors which have the +same distance in RGB space can look much further apart. This is fixed by the +CIE-L\*a\*b\*, CIE-L\*u\*v\* and CIE-L\*C\*h° color spaces. +Thus you should only compare colors in any of these space. +(Note that the distance in CIE-L\*a\*b\* and CIE-L\*C\*h° are the same, since it's the same space but in cylindrical coordinates) + +![Color distance comparison](doc/colordist/colordist.png) + +The two colors shown on the top look much more different than the two shown on +the bottom. Still, in RGB space, their distance is the same. +Here is a little example program which shows the distances between the top two +and bottom two colors in RGB, CIE-L\*a\*b\* and CIE-L\*u\*v\* space. You can find it in `doc/colordist/colordist.go`. + +```go +package main + +import "fmt" +import "github.com/lucasb-eyer/go-colorful" + +func main() { + c1a := colorful.Color{150.0 / 255.0, 10.0 / 255.0, 150.0 / 255.0} + c1b := colorful.Color{53.0 / 255.0, 10.0 / 255.0, 150.0 / 255.0} + c2a := colorful.Color{10.0 / 255.0, 150.0 / 255.0, 50.0 / 255.0} + c2b := colorful.Color{99.9 / 255.0, 150.0 / 255.0, 10.0 / 255.0} + + fmt.Printf("DistanceRgb: c1: %v\tand c2: %v\n", c1a.DistanceRgb(c1b), c2a.DistanceRgb(c2b)) + fmt.Printf("DistanceLab: c1: %v\tand c2: %v\n", c1a.DistanceLab(c1b), c2a.DistanceLab(c2b)) + fmt.Printf("DistanceLuv: c1: %v\tand c2: %v\n", c1a.DistanceLuv(c1b), c2a.DistanceLuv(c2b)) + fmt.Printf("DistanceCIE76: c1: %v\tand c2: %v\n", c1a.DistanceCIE76(c1b), c2a.DistanceCIE76(c2b)) + fmt.Printf("DistanceCIE94: c1: %v\tand c2: %v\n", c1a.DistanceCIE94(c1b), c2a.DistanceCIE94(c2b)) + fmt.Printf("DistanceCIEDE2000: c1: %v\tand c2: %v\n", c1a.DistanceCIEDE2000(c1b), c2a.DistanceCIEDE2000(c2b)) +} +``` + +Running the above program shows that you should always prefer any of the CIE distances: + +```bash +$ go run colordist.go +DistanceRgb: c1: 0.3803921568627451 and c2: 0.3858713931171159 +DistanceLab: c1: 0.32048458312798056 and c2: 0.24397151758565272 +DistanceLuv: c1: 0.5134369614199698 and c2: 0.2568692839860636 +DistanceCIE76: c1: 0.32048458312798056 and c2: 0.24397151758565272 +DistanceCIE94: c1: 0.19799168128511324 and c2: 0.12207136371167401 +DistanceCIEDE2000: c1: 0.17274551120971166 and c2: 0.10665210031428465 +``` + +It also shows that `DistanceLab` is more formally known as `DistanceCIE76` and +has been superseded by the slightly more accurate, but much more expensive +`DistanceCIE94` and `DistanceCIEDE2000`. + +Note that `AlmostEqualRgb` is provided mainly for (unit-)testing purposes. Use +it only if you really know what you're doing. It will eat your cat. + +### Blending colors +Blending is highly connected to distance, since it basically "walks through" the +colorspace thus, if the colorspace maps distances well, the walk is "smooth". + +Colorful comes with blending functions in RGB, HSV and any of the LAB spaces. +Of course, you'd rather want to use the blending functions of the LAB spaces since +these spaces map distances well but, just in case, here is an example showing +you how the blendings (`#fdffcc` to `#242a42`) are done in the various spaces: + +![Blending colors in different spaces.](doc/colorblend/colorblend.png) + +What you see is that HSV is really bad: it adds some green, which is not present +in the original colors at all! RGB is much better, but it stays light a little +too long. LUV and LAB both hit the right lightness but LAB has a little more +color. HCL works in the same vein as HSV (both cylindrical interpolations) but +it does it right in that there is no green appearing and the lighthness changes +in a linear manner. + +While this seems all good, you need to know one thing: When interpolating in any +of the CIE color spaces, you might get invalid RGB colors! This is important if +the starting and ending colors are user-input or random. An example of where this +happens is when blending between `#eeef61` and `#1e3140`: + +![Invalid RGB colors may crop up when blending in CIE spaces.](doc/colorblend/invalid.png) + +You can test whether a color is a valid RGB color by calling the `IsValid` method +and indeed, calling IsValid will return false for the redish colors on the bottom. +One way to "fix" this is to get a valid color close to the invalid one by calling +`Clamped`, which always returns a nearby valid color. Doing this, we get the +following result, which is satisfactory: + +![Fixing invalid RGB colors by clamping them to the valid range.](doc/colorblend/clamped.png) + +The following is the code creating the above three images; it can be found in `doc/colorblend/colorblend.go` + +```go +package main + +import "fmt" +import "github.com/lucasb-eyer/go-colorful" +import "image" +import "image/draw" +import "image/png" +import "os" + +func main() { + blocks := 10 + blockw := 40 + img := image.NewRGBA(image.Rect(0,0,blocks*blockw,200)) + + c1, _ := colorful.Hex("#fdffcc") + c2, _ := colorful.Hex("#242a42") + + // Use these colors to get invalid RGB in the gradient. + //c1, _ := colorful.Hex("#EEEF61") + //c2, _ := colorful.Hex("#1E3140") + + for i := 0 ; i < blocks ; i++ { + draw.Draw(img, image.Rect(i*blockw, 0,(i+1)*blockw, 40), &image.Uniform{c1.BlendHsv(c2, float64(i)/float64(blocks-1))}, image.Point{}, draw.Src) + draw.Draw(img, image.Rect(i*blockw, 40,(i+1)*blockw, 80), &image.Uniform{c1.BlendLuv(c2, float64(i)/float64(blocks-1))}, image.Point{}, draw.Src) + draw.Draw(img, image.Rect(i*blockw, 80,(i+1)*blockw,120), &image.Uniform{c1.BlendRgb(c2, float64(i)/float64(blocks-1))}, image.Point{}, draw.Src) + draw.Draw(img, image.Rect(i*blockw,120,(i+1)*blockw,160), &image.Uniform{c1.BlendLab(c2, float64(i)/float64(blocks-1))}, image.Point{}, draw.Src) + draw.Draw(img, image.Rect(i*blockw,160,(i+1)*blockw,200), &image.Uniform{c1.BlendHcl(c2, float64(i)/float64(blocks-1))}, image.Point{}, draw.Src) + + // This can be used to "fix" invalid colors in the gradient. + //draw.Draw(img, image.Rect(i*blockw,160,(i+1)*blockw,200), &image.Uniform{c1.BlendHcl(c2, float64(i)/float64(blocks-1)).Clamped()}, image.Point{}, draw.Src) + } + + toimg, err := os.Create("colorblend.png") + if err != nil { + fmt.Printf("Error: %v", err) + return + } + defer toimg.Close() + + png.Encode(toimg, img) +} +``` + +#### Generating color gradients +A very common reason to blend colors is creating gradients. There is an example +program in [doc/gradientgen.go](doc/gradientgen/gradientgen.go); it doesn't use any API +which hasn't been used in the previous example code, so I won't bother pasting +the code in here. Just look at that gorgeous gradient it generated in HCL space: + +!["Spectral" colorbrewer gradient in HCL space.](doc/gradientgen/gradientgen.png) + +### Getting random colors +It is sometimes necessary to generate random colors. You could simply do this +on your own by generating colors with random values. By restricting the random +values to a range smaller than [0..1] and using a space such as CIE-H\*C\*l° or +HSV, you can generate both random shades of a color or random colors of a +lightness: + +```go +random_blue := colorful.Hcl(180.0+rand.Float64()*50.0, 0.2+rand.Float64()*0.8, 0.3+rand.Float64()*0.7) +random_dark := colorful.Hcl(rand.Float64()*360.0, rand.Float64(), rand.Float64()*0.4) +random_light := colorful.Hcl(rand.Float64()*360.0, rand.Float64(), 0.6+rand.Float64()*0.4) +``` + +Since getting random "warm" and "happy" colors is quite a common task, there +are some helper functions: + +```go +colorful.WarmColor() +colorful.HappyColor() +colorful.FastWarmColor() +colorful.FastHappyColor() +``` + +The ones prefixed by `Fast` are faster but less coherent since they use the HSV +space as opposed to the regular ones which use CIE-L\*C\*h° space. The +following picture shows the warm colors in the top two rows and happy colors +in the bottom two rows. Within these, the first is the regular one and the +second is the fast one. + +![Warm, fast warm, happy and fast happy random colors, respectively.](doc/colorgens/colorgens.png) + +Don't forget to initialize the random seed! You can see the code used for +generating this picture in `doc/colorgens/colorgens.go`. + +### Getting random palettes +As soon as you need to generate more than one random color, you probably want +them to be distinguishible. Playing against an opponent which has almost the +same blue as I do is not fun. This is where random palettes can help. + +These palettes are generated using an algorithm which ensures that all colors +on the palette are as distinguishible as possible. Again, there is a `Fast` +method which works in HSV and is less perceptually uniform and a non-`Fast` +method which works in CIE spaces. For more theory on `SoftPalette`, check out +[I want hue](http://tools.medialab.sciences-po.fr/iwanthue/theory.php). Yet +again, there is a `Happy` and a `Warm` version, which do what you expect, but +now there is an additional `Soft` version, which is more configurable: you can +give a constraint on the color space in order to get colors within a certain *feel*. + +Let's start with the simple methods first, all they take is the amount of +colors to generate, which could, for example, be the player count. They return +an array of `colorful.Color` objects: + +```go +pal1, err1 := colorful.WarmPalette(10) +pal2 := colorful.FastWarmPalette(10) +pal3, err3 := colorful.HappyPalette(10) +pal4 := colorful.FastHappyPalette(10) +pal5, err5 := colorful.SoftPalette(10) +``` + +Note that the non-fast methods *may* fail if you ask for way too many colors. +Let's move on to the advanced one, namely `SoftPaletteEx`. Besides the color +count, this function takes a `SoftPaletteSettings` object as argument. The +interesting part here is its `CheckColor` member, which is a boolean function +taking three floating points as arguments: `l`, `a` and `b`. This function +should return `true` for colors which lie within the region you want and `false` +otherwise. The other members are `Iteration`, which should be within [5..100] +where higher means slower but more exact palette, and `ManySamples` which you +should set to `true` in case your `CheckColor` constraint rejects a large part +of the color space. + +For example, to create a palette of 10 brownish colors, you'd call it like this: + +```go +func isbrowny(l, a, b float64) bool { + h, c, L := colorful.LabToHcl(l, a, b) + return 10.0 < h && h < 50.0 && 0.1 < c && c < 0.5 && L < 0.5 +} +// Since the above function is pretty restrictive, we set ManySamples to true. +brownies := colorful.SoftPaletteEx(10, colorful.SoftPaletteSettings{isbrowny, 50, true}) +``` + +The following picture shows the palettes generated by all of these methods +(sourcecode in `doc/palettegens/palettegens.go`), in the order they were presented, i.e. +from top to bottom: `Warm`, `FastWarm`, `Happy`, `FastHappy`, `Soft`, +`SoftEx(isbrowny)`. All of them contain some randomness, so YMMV. + +![All example palettes](doc/palettegens/palettegens.png) + +Again, the code used for generating the above image is available as [doc/palettegens/palettegens.go](https://github.com/lucasb-eyer/go-colorful/blob/master/doc/palettegens/palettegens.go). + +### Sorting colors +TODO: Sort using dist fn. + +### Using linear RGB for computations +There are two methods for transforming RGB<->Linear RGB: a fast and almost precise one, +and a slow and precise one. + +```go +r, g, b := colorful.Hex("#FF0000").FastLinearRgb() +``` + +TODO: describe some more. + +### Want to use some other reference point? + +```go +c := colorful.LabWhiteRef(0.507850, 0.040585,-0.370945, colorful.D50) +l, a, b := c.LabWhiteRef(colorful.D50) +``` + +### Reading and writing colors from databases + +The type `HexColor` makes it easy to store colors as strings in a database. It +implements the [https://godoc.org/database/sql#Scanner](database/sql.Scanner) +and [database/sql/driver.Value](https://godoc.org/database/sql/driver.Value) +interfaces which provide automatic type conversion. + +Example: + +```go +var hc HexColor +_, err := db.QueryRow("SELECT '#ff0000';").Scan(&hc) +// hc == HexColor{R: 1, G: 0, B: 0}; err == nil +``` + +FAQ +=== + +### Q: I get all f!@#ed up values! Your library sucks! +A: You probably provided values in the wrong range. For example, RGB values are +expected to reside between 0 and 1, *not* between 0 and 255. Normalize your colors. + +### Q: Lab/Luv/HCl seem broken! Your library sucks! +They look like this: + + + +A: You're likely trying to generate and display colors that can't be represented by RGB, +and thus monitors. When you're trying to convert, say, `HCL(190.0, 1.0, 1.0).RGB255()`, +you're asking for RGB values of `(-2105.254 300.680 286.185)`, which clearly don't exist, +and the `RGB255` function just casts these numbers to `uint8`, creating wrap-around and +what looks like a completely broken gradient. What you want to do, is either use more +reasonable values of colors which actually exist in RGB, or just `Clamp()` the resulting +color to its nearest existing one, living with the consequences: +`HCL(190.0, 1.0, 1.0).Clamp().RGB255()`. It will look something like this: + + + +[Here's an issue going in-depth about this](https://github.com/lucasb-eyer/go-colorful/issues/14), +as well as [my answer](https://github.com/lucasb-eyer/go-colorful/issues/14#issuecomment-324205385), +both with code and pretty pictures. Also note that this was somewhat covered above in the +["Blending colors" section](https://github.com/lucasb-eyer/go-colorful#blending-colors). + +### Q: In a tight loop, conversion to Lab/Luv/HCl/... are slooooow! +A: Yes, they are. +This library aims for correctness, readability, and modularity; it wasn't written with speed in mind. +A large part of the slowness comes from these conversions going through `LinearRgb` which uses powers. +I implemented a fast approximation to `LinearRgb` called `FastLinearRgb` by using Taylor approximations. +The approximation is roughly 5x faster and precise up to roughly 0.5%, +the major caveat being that if the input values are outside the range 0-1, accuracy drops dramatically. +You can use these in your conversions as follows: + +```go +col := // Get your color somehow +l, a, b := XyzToLab(LinearRgbToXyz(col.LinearRgb())) +``` + +If you need faster versions of `Distance*` and `Blend*` that make use of this fast approximation, +feel free to implement them and open a pull-request, I'll happily accept. + +The derivation of these functions can be followed in [this Jupyter notebook](doc/LinearRGB Approximations.ipynb). +Here's the main figure showing the approximation quality: + +![approximation quality](doc/approx-quality.png) + +More speed could be gained by using SIMD instructions in many places. +You can also get more speed for specific conversions by approximating the full conversion function, +but that is outside the scope of this library. +Thanks to [@ZirconiumX](https://github.com/ZirconiumX) for starting this investigation, +see [issue #18](https://github.com/lucasb-eyer/go-colorful/issues/18) for details. + +### Q: Why would `MakeColor` ever fail!? +A: `MakeColor` fails when the alpha channel is zero. In that case, the +conversion is undefined. See [issue 21](https://github.com/lucasb-eyer/go-colorful/issues/21) +as well as the short caveat note in the ["The `color.Color` interface"](README.md#the-colorcolor-interface) +section above. + +Who? +==== + +This library was developed by Lucas Beyer with contributions from +Bastien Dejean (@baskerville), Phil Kulak (@pkulak) and Christian Muehlhaeuser (@muesli). + +It is now maintained by makeworld (@makeworld-the-better-one). + + +## License + +This repo is under the MIT license, see [LICENSE](LICENSE) for details. diff --git a/vendor/github.com/lucasb-eyer/go-colorful/colorgens.go b/vendor/github.com/lucasb-eyer/go-colorful/colorgens.go new file mode 100644 index 000000000..2e2e49e19 --- /dev/null +++ b/vendor/github.com/lucasb-eyer/go-colorful/colorgens.go @@ -0,0 +1,55 @@ +// Various ways to generate single random colors + +package colorful + +import ( + "math/rand" +) + +// Creates a random dark, "warm" color through a restricted HSV space. +func FastWarmColor() Color { + return Hsv( + rand.Float64()*360.0, + 0.5+rand.Float64()*0.3, + 0.3+rand.Float64()*0.3) +} + +// Creates a random dark, "warm" color through restricted HCL space. +// This is slower than FastWarmColor but will likely give you colors which have +// the same "warmness" if you run it many times. +func WarmColor() (c Color) { + for c = randomWarm(); !c.IsValid(); c = randomWarm() { + } + return +} + +func randomWarm() Color { + return Hcl( + rand.Float64()*360.0, + 0.1+rand.Float64()*0.3, + 0.2+rand.Float64()*0.3) +} + +// Creates a random bright, "pimpy" color through a restricted HSV space. +func FastHappyColor() Color { + return Hsv( + rand.Float64()*360.0, + 0.7+rand.Float64()*0.3, + 0.6+rand.Float64()*0.3) +} + +// Creates a random bright, "pimpy" color through restricted HCL space. +// This is slower than FastHappyColor but will likely give you colors which +// have the same "brightness" if you run it many times. +func HappyColor() (c Color) { + for c = randomPimp(); !c.IsValid(); c = randomPimp() { + } + return +} + +func randomPimp() Color { + return Hcl( + rand.Float64()*360.0, + 0.5+rand.Float64()*0.3, + 0.5+rand.Float64()*0.3) +} diff --git a/vendor/github.com/lucasb-eyer/go-colorful/colors.go b/vendor/github.com/lucasb-eyer/go-colorful/colors.go new file mode 100644 index 000000000..0d5bffe5d --- /dev/null +++ b/vendor/github.com/lucasb-eyer/go-colorful/colors.go @@ -0,0 +1,979 @@ +// The colorful package provides all kinds of functions for working with colors. +package colorful + +import ( + "fmt" + "image/color" + "math" +) + +// A color is stored internally using sRGB (standard RGB) values in the range 0-1 +type Color struct { + R, G, B float64 +} + +// Implement the Go color.Color interface. +func (col Color) RGBA() (r, g, b, a uint32) { + r = uint32(col.R*65535.0 + 0.5) + g = uint32(col.G*65535.0 + 0.5) + b = uint32(col.B*65535.0 + 0.5) + a = 0xFFFF + return +} + +// Constructs a colorful.Color from something implementing color.Color +func MakeColor(col color.Color) (Color, bool) { + r, g, b, a := col.RGBA() + if a == 0 { + return Color{0, 0, 0}, false + } + + // Since color.Color is alpha pre-multiplied, we need to divide the + // RGB values by alpha again in order to get back the original RGB. + r *= 0xffff + r /= a + g *= 0xffff + g /= a + b *= 0xffff + b /= a + + return Color{float64(r) / 65535.0, float64(g) / 65535.0, float64(b) / 65535.0}, true +} + +// Might come in handy sometimes to reduce boilerplate code. +func (col Color) RGB255() (r, g, b uint8) { + r = uint8(col.R*255.0 + 0.5) + g = uint8(col.G*255.0 + 0.5) + b = uint8(col.B*255.0 + 0.5) + return +} + +// Used to simplify HSLuv testing. +func (col Color) values() (float64, float64, float64) { + return col.R, col.G, col.B +} + +// This is the tolerance used when comparing colors using AlmostEqualRgb. +const Delta = 1.0 / 255.0 + +// This is the default reference white point. +var D65 = [3]float64{0.95047, 1.00000, 1.08883} + +// And another one. +var D50 = [3]float64{0.96422, 1.00000, 0.82521} + +// Checks whether the color exists in RGB space, i.e. all values are in [0..1] +func (c Color) IsValid() bool { + return 0.0 <= c.R && c.R <= 1.0 && + 0.0 <= c.G && c.G <= 1.0 && + 0.0 <= c.B && c.B <= 1.0 +} + +// clamp01 clamps from 0 to 1. +func clamp01(v float64) float64 { + return math.Max(0.0, math.Min(v, 1.0)) +} + +// Returns Clamps the color into valid range, clamping each value to [0..1] +// If the color is valid already, this is a no-op. +func (c Color) Clamped() Color { + return Color{clamp01(c.R), clamp01(c.G), clamp01(c.B)} +} + +func sq(v float64) float64 { + return v * v +} + +func cub(v float64) float64 { + return v * v * v +} + +// DistanceRgb computes the distance between two colors in RGB space. +// This is not a good measure! Rather do it in Lab space. +func (c1 Color) DistanceRgb(c2 Color) float64 { + return math.Sqrt(sq(c1.R-c2.R) + sq(c1.G-c2.G) + sq(c1.B-c2.B)) +} + +// DistanceLinearRGB computes the distance between two colors in linear RGB +// space. This is not useful for measuring how humans perceive color, but +// might be useful for other things, like dithering. +func (c1 Color) DistanceLinearRGB(c2 Color) float64 { + r1, g1, b1 := c1.LinearRgb() + r2, g2, b2 := c2.LinearRgb() + return math.Sqrt(sq(r1-r2) + sq(g1-g2) + sq(b1-b2)) +} + +// Check for equality between colors within the tolerance Delta (1/255). +func (c1 Color) AlmostEqualRgb(c2 Color) bool { + return math.Abs(c1.R-c2.R)+ + math.Abs(c1.G-c2.G)+ + math.Abs(c1.B-c2.B) < 3.0*Delta +} + +// You don't really want to use this, do you? Go for BlendLab, BlendLuv or BlendHcl. +func (c1 Color) BlendRgb(c2 Color, t float64) Color { + return Color{c1.R + t*(c2.R-c1.R), + c1.G + t*(c2.G-c1.G), + c1.B + t*(c2.B-c1.B)} +} + +// Utility used by Hxx color-spaces for interpolating between two angles in [0,360]. +func interp_angle(a0, a1, t float64) float64 { + // Based on the answer here: http://stackoverflow.com/a/14498790/2366315 + // With potential proof that it works here: http://math.stackexchange.com/a/2144499 + delta := math.Mod(math.Mod(a1-a0, 360.0)+540, 360.0) - 180.0 + return math.Mod(a0+t*delta+360.0, 360.0) +} + +/// HSV /// +/////////// +// From http://en.wikipedia.org/wiki/HSL_and_HSV +// Note that h is in [0..360] and s,v in [0..1] + +// Hsv returns the Hue [0..360], Saturation and Value [0..1] of the color. +func (col Color) Hsv() (h, s, v float64) { + min := math.Min(math.Min(col.R, col.G), col.B) + v = math.Max(math.Max(col.R, col.G), col.B) + C := v - min + + s = 0.0 + if v != 0.0 { + s = C / v + } + + h = 0.0 // We use 0 instead of undefined as in wp. + if min != v { + if v == col.R { + h = math.Mod((col.G-col.B)/C, 6.0) + } + if v == col.G { + h = (col.B-col.R)/C + 2.0 + } + if v == col.B { + h = (col.R-col.G)/C + 4.0 + } + h *= 60.0 + if h < 0.0 { + h += 360.0 + } + } + return +} + +// Hsv creates a new Color given a Hue in [0..360], a Saturation and a Value in [0..1] +func Hsv(H, S, V float64) Color { + Hp := H / 60.0 + C := V * S + X := C * (1.0 - math.Abs(math.Mod(Hp, 2.0)-1.0)) + + m := V - C + r, g, b := 0.0, 0.0, 0.0 + + switch { + case 0.0 <= Hp && Hp < 1.0: + r = C + g = X + case 1.0 <= Hp && Hp < 2.0: + r = X + g = C + case 2.0 <= Hp && Hp < 3.0: + g = C + b = X + case 3.0 <= Hp && Hp < 4.0: + g = X + b = C + case 4.0 <= Hp && Hp < 5.0: + r = X + b = C + case 5.0 <= Hp && Hp < 6.0: + r = C + b = X + } + + return Color{m + r, m + g, m + b} +} + +// You don't really want to use this, do you? Go for BlendLab, BlendLuv or BlendHcl. +func (c1 Color) BlendHsv(c2 Color, t float64) Color { + h1, s1, v1 := c1.Hsv() + h2, s2, v2 := c2.Hsv() + + // We know that h are both in [0..360] + return Hsv(interp_angle(h1, h2, t), s1+t*(s2-s1), v1+t*(v2-v1)) +} + +/// HSL /// +/////////// + +// Hsl returns the Hue [0..360], Saturation [0..1], and Luminance (lightness) [0..1] of the color. +func (col Color) Hsl() (h, s, l float64) { + min := math.Min(math.Min(col.R, col.G), col.B) + max := math.Max(math.Max(col.R, col.G), col.B) + + l = (max + min) / 2 + + if min == max { + s = 0 + h = 0 + } else { + if l < 0.5 { + s = (max - min) / (max + min) + } else { + s = (max - min) / (2.0 - max - min) + } + + if max == col.R { + h = (col.G - col.B) / (max - min) + } else if max == col.G { + h = 2.0 + (col.B-col.R)/(max-min) + } else { + h = 4.0 + (col.R-col.G)/(max-min) + } + + h *= 60 + + if h < 0 { + h += 360 + } + } + + return +} + +// Hsl creates a new Color given a Hue in [0..360], a Saturation [0..1], and a Luminance (lightness) in [0..1] +func Hsl(h, s, l float64) Color { + if s == 0 { + return Color{l, l, l} + } + + var r, g, b float64 + var t1 float64 + var t2 float64 + var tr float64 + var tg float64 + var tb float64 + + if l < 0.5 { + t1 = l * (1.0 + s) + } else { + t1 = l + s - l*s + } + + t2 = 2*l - t1 + h /= 360 + tr = h + 1.0/3.0 + tg = h + tb = h - 1.0/3.0 + + if tr < 0 { + tr++ + } + if tr > 1 { + tr-- + } + if tg < 0 { + tg++ + } + if tg > 1 { + tg-- + } + if tb < 0 { + tb++ + } + if tb > 1 { + tb-- + } + + // Red + if 6*tr < 1 { + r = t2 + (t1-t2)*6*tr + } else if 2*tr < 1 { + r = t1 + } else if 3*tr < 2 { + r = t2 + (t1-t2)*(2.0/3.0-tr)*6 + } else { + r = t2 + } + + // Green + if 6*tg < 1 { + g = t2 + (t1-t2)*6*tg + } else if 2*tg < 1 { + g = t1 + } else if 3*tg < 2 { + g = t2 + (t1-t2)*(2.0/3.0-tg)*6 + } else { + g = t2 + } + + // Blue + if 6*tb < 1 { + b = t2 + (t1-t2)*6*tb + } else if 2*tb < 1 { + b = t1 + } else if 3*tb < 2 { + b = t2 + (t1-t2)*(2.0/3.0-tb)*6 + } else { + b = t2 + } + + return Color{r, g, b} +} + +/// Hex /// +/////////// + +// Hex returns the hex "html" representation of the color, as in #ff0080. +func (col Color) Hex() string { + // Add 0.5 for rounding + return fmt.Sprintf("#%02x%02x%02x", uint8(col.R*255.0+0.5), uint8(col.G*255.0+0.5), uint8(col.B*255.0+0.5)) +} + +// Hex parses a "html" hex color-string, either in the 3 "#f0c" or 6 "#ff1034" digits form. +func Hex(scol string) (Color, error) { + format := "#%02x%02x%02x" + factor := 1.0 / 255.0 + if len(scol) == 4 { + format = "#%1x%1x%1x" + factor = 1.0 / 15.0 + } + + var r, g, b uint8 + n, err := fmt.Sscanf(scol, format, &r, &g, &b) + if err != nil { + return Color{}, err + } + if n != 3 { + return Color{}, fmt.Errorf("color: %v is not a hex-color", scol) + } + + return Color{float64(r) * factor, float64(g) * factor, float64(b) * factor}, nil +} + +/// Linear /// +////////////// +// http://www.sjbrown.co.uk/2004/05/14/gamma-correct-rendering/ +// http://www.brucelindbloom.com/Eqn_RGB_to_XYZ.html + +func linearize(v float64) float64 { + if v <= 0.04045 { + return v / 12.92 + } + return math.Pow((v+0.055)/1.055, 2.4) +} + +// LinearRgb converts the color into the linear RGB space (see http://www.sjbrown.co.uk/2004/05/14/gamma-correct-rendering/). +func (col Color) LinearRgb() (r, g, b float64) { + r = linearize(col.R) + g = linearize(col.G) + b = linearize(col.B) + return +} + +// A much faster and still quite precise linearization using a 6th-order Taylor approximation. +// See the accompanying Jupyter notebook for derivation of the constants. +func linearize_fast(v float64) float64 { + v1 := v - 0.5 + v2 := v1 * v1 + v3 := v2 * v1 + v4 := v2 * v2 + //v5 := v3*v2 + return -0.248750514614486 + 0.925583310193438*v + 1.16740237321695*v2 + 0.280457026598666*v3 - 0.0757991963780179*v4 //+ 0.0437040411548932*v5 +} + +// FastLinearRgb is much faster than and almost as accurate as LinearRgb. +// BUT it is important to NOTE that they only produce good results for valid colors r,g,b in [0,1]. +func (col Color) FastLinearRgb() (r, g, b float64) { + r = linearize_fast(col.R) + g = linearize_fast(col.G) + b = linearize_fast(col.B) + return +} + +func delinearize(v float64) float64 { + if v <= 0.0031308 { + return 12.92 * v + } + return 1.055*math.Pow(v, 1.0/2.4) - 0.055 +} + +// LinearRgb creates an sRGB color out of the given linear RGB color (see http://www.sjbrown.co.uk/2004/05/14/gamma-correct-rendering/). +func LinearRgb(r, g, b float64) Color { + return Color{delinearize(r), delinearize(g), delinearize(b)} +} + +func delinearize_fast(v float64) float64 { + // This function (fractional root) is much harder to linearize, so we need to split. + if v > 0.2 { + v1 := v - 0.6 + v2 := v1 * v1 + v3 := v2 * v1 + v4 := v2 * v2 + v5 := v3 * v2 + return 0.442430344268235 + 0.592178981271708*v - 0.287864782562636*v2 + 0.253214392068985*v3 - 0.272557158129811*v4 + 0.325554383321718*v5 + } else if v > 0.03 { + v1 := v - 0.115 + v2 := v1 * v1 + v3 := v2 * v1 + v4 := v2 * v2 + v5 := v3 * v2 + return 0.194915592891669 + 1.55227076330229*v - 3.93691860257828*v2 + 18.0679839248761*v3 - 101.468750302746*v4 + 632.341487393927*v5 + } else { + v1 := v - 0.015 + v2 := v1 * v1 + v3 := v2 * v1 + v4 := v2 * v2 + v5 := v3 * v2 + // You can clearly see from the involved constants that the low-end is highly nonlinear. + return 0.0519565234928877 + 5.09316778537561*v - 99.0338180489702*v2 + 3484.52322764895*v3 - 150028.083412663*v4 + 7168008.42971613*v5 + } +} + +// FastLinearRgb is much faster than and almost as accurate as LinearRgb. +// BUT it is important to NOTE that they only produce good results for valid inputs r,g,b in [0,1]. +func FastLinearRgb(r, g, b float64) Color { + return Color{delinearize_fast(r), delinearize_fast(g), delinearize_fast(b)} +} + +// XyzToLinearRgb converts from CIE XYZ-space to Linear RGB space. +func XyzToLinearRgb(x, y, z float64) (r, g, b float64) { + r = 3.2409699419045214*x - 1.5373831775700935*y - 0.49861076029300328*z + g = -0.96924363628087983*x + 1.8759675015077207*y + 0.041555057407175613*z + b = 0.055630079696993609*x - 0.20397695888897657*y + 1.0569715142428786*z + return +} + +func LinearRgbToXyz(r, g, b float64) (x, y, z float64) { + x = 0.41239079926595948*r + 0.35758433938387796*g + 0.18048078840183429*b + y = 0.21263900587151036*r + 0.71516867876775593*g + 0.072192315360733715*b + z = 0.019330818715591851*r + 0.11919477979462599*g + 0.95053215224966058*b + return +} + +/// XYZ /// +/////////// +// http://www.sjbrown.co.uk/2004/05/14/gamma-correct-rendering/ + +func (col Color) Xyz() (x, y, z float64) { + return LinearRgbToXyz(col.LinearRgb()) +} + +func Xyz(x, y, z float64) Color { + return LinearRgb(XyzToLinearRgb(x, y, z)) +} + +/// xyY /// +/////////// +// http://www.brucelindbloom.com/Eqn_XYZ_to_xyY.html + +// Well, the name is bad, since it's xyY but Golang needs me to start with a +// capital letter to make the method public. +func XyzToXyy(X, Y, Z float64) (x, y, Yout float64) { + return XyzToXyyWhiteRef(X, Y, Z, D65) +} + +func XyzToXyyWhiteRef(X, Y, Z float64, wref [3]float64) (x, y, Yout float64) { + Yout = Y + N := X + Y + Z + if math.Abs(N) < 1e-14 { + // When we have black, Bruce Lindbloom recommends to use + // the reference white's chromacity for x and y. + x = wref[0] / (wref[0] + wref[1] + wref[2]) + y = wref[1] / (wref[0] + wref[1] + wref[2]) + } else { + x = X / N + y = Y / N + } + return +} + +func XyyToXyz(x, y, Y float64) (X, Yout, Z float64) { + Yout = Y + + if -1e-14 < y && y < 1e-14 { + X = 0.0 + Z = 0.0 + } else { + X = Y / y * x + Z = Y / y * (1.0 - x - y) + } + + return +} + +// Converts the given color to CIE xyY space using D65 as reference white. +// (Note that the reference white is only used for black input.) +// x, y and Y are in [0..1] +func (col Color) Xyy() (x, y, Y float64) { + return XyzToXyy(col.Xyz()) +} + +// Converts the given color to CIE xyY space, taking into account +// a given reference white. (i.e. the monitor's white) +// (Note that the reference white is only used for black input.) +// x, y and Y are in [0..1] +func (col Color) XyyWhiteRef(wref [3]float64) (x, y, Y float64) { + X, Y2, Z := col.Xyz() + return XyzToXyyWhiteRef(X, Y2, Z, wref) +} + +// Generates a color by using data given in CIE xyY space. +// x, y and Y are in [0..1] +func Xyy(x, y, Y float64) Color { + return Xyz(XyyToXyz(x, y, Y)) +} + +/// L*a*b* /// +////////////// +// http://en.wikipedia.org/wiki/Lab_color_space#CIELAB-CIEXYZ_conversions +// For L*a*b*, we need to L*a*b*<->XYZ->RGB and the first one is device dependent. + +func lab_f(t float64) float64 { + if t > 6.0/29.0*6.0/29.0*6.0/29.0 { + return math.Cbrt(t) + } + return t/3.0*29.0/6.0*29.0/6.0 + 4.0/29.0 +} + +func XyzToLab(x, y, z float64) (l, a, b float64) { + // Use D65 white as reference point by default. + // http://www.fredmiranda.com/forum/topic/1035332 + // http://en.wikipedia.org/wiki/Standard_illuminant + return XyzToLabWhiteRef(x, y, z, D65) +} + +func XyzToLabWhiteRef(x, y, z float64, wref [3]float64) (l, a, b float64) { + fy := lab_f(y / wref[1]) + l = 1.16*fy - 0.16 + a = 5.0 * (lab_f(x/wref[0]) - fy) + b = 2.0 * (fy - lab_f(z/wref[2])) + return +} + +func lab_finv(t float64) float64 { + if t > 6.0/29.0 { + return t * t * t + } + return 3.0 * 6.0 / 29.0 * 6.0 / 29.0 * (t - 4.0/29.0) +} + +func LabToXyz(l, a, b float64) (x, y, z float64) { + // D65 white (see above). + return LabToXyzWhiteRef(l, a, b, D65) +} + +func LabToXyzWhiteRef(l, a, b float64, wref [3]float64) (x, y, z float64) { + l2 := (l + 0.16) / 1.16 + x = wref[0] * lab_finv(l2+a/5.0) + y = wref[1] * lab_finv(l2) + z = wref[2] * lab_finv(l2-b/2.0) + return +} + +// Converts the given color to CIE L*a*b* space using D65 as reference white. +func (col Color) Lab() (l, a, b float64) { + return XyzToLab(col.Xyz()) +} + +// Converts the given color to CIE L*a*b* space, taking into account +// a given reference white. (i.e. the monitor's white) +func (col Color) LabWhiteRef(wref [3]float64) (l, a, b float64) { + x, y, z := col.Xyz() + return XyzToLabWhiteRef(x, y, z, wref) +} + +// Generates a color by using data given in CIE L*a*b* space using D65 as reference white. +// WARNING: many combinations of `l`, `a`, and `b` values do not have corresponding +// valid RGB values, check the FAQ in the README if you're unsure. +func Lab(l, a, b float64) Color { + return Xyz(LabToXyz(l, a, b)) +} + +// Generates a color by using data given in CIE L*a*b* space, taking +// into account a given reference white. (i.e. the monitor's white) +func LabWhiteRef(l, a, b float64, wref [3]float64) Color { + return Xyz(LabToXyzWhiteRef(l, a, b, wref)) +} + +// DistanceLab is a good measure of visual similarity between two colors! +// A result of 0 would mean identical colors, while a result of 1 or higher +// means the colors differ a lot. +func (c1 Color) DistanceLab(c2 Color) float64 { + l1, a1, b1 := c1.Lab() + l2, a2, b2 := c2.Lab() + return math.Sqrt(sq(l1-l2) + sq(a1-a2) + sq(b1-b2)) +} + +// DistanceCIE76 is the same as DistanceLab. +func (c1 Color) DistanceCIE76(c2 Color) float64 { + return c1.DistanceLab(c2) +} + +// Uses the CIE94 formula to calculate color distance. More accurate than +// DistanceLab, but also more work. +func (cl Color) DistanceCIE94(cr Color) float64 { + l1, a1, b1 := cl.Lab() + l2, a2, b2 := cr.Lab() + + // NOTE: Since all those formulas expect L,a,b values 100x larger than we + // have them in this library, we either need to adjust all constants + // in the formula, or convert the ranges of L,a,b before, and then + // scale the distances down again. The latter is less error-prone. + l1, a1, b1 = l1*100.0, a1*100.0, b1*100.0 + l2, a2, b2 = l2*100.0, a2*100.0, b2*100.0 + + kl := 1.0 // 2.0 for textiles + kc := 1.0 + kh := 1.0 + k1 := 0.045 // 0.048 for textiles + k2 := 0.015 // 0.014 for textiles. + + deltaL := l1 - l2 + c1 := math.Sqrt(sq(a1) + sq(b1)) + c2 := math.Sqrt(sq(a2) + sq(b2)) + deltaCab := c1 - c2 + + // Not taking Sqrt here for stability, and it's unnecessary. + deltaHab2 := sq(a1-a2) + sq(b1-b2) - sq(deltaCab) + sl := 1.0 + sc := 1.0 + k1*c1 + sh := 1.0 + k2*c1 + + vL2 := sq(deltaL / (kl * sl)) + vC2 := sq(deltaCab / (kc * sc)) + vH2 := deltaHab2 / sq(kh*sh) + + return math.Sqrt(vL2+vC2+vH2) * 0.01 // See above. +} + +// DistanceCIEDE2000 uses the Delta E 2000 formula to calculate color +// distance. It is more expensive but more accurate than both DistanceLab +// and DistanceCIE94. +func (cl Color) DistanceCIEDE2000(cr Color) float64 { + return cl.DistanceCIEDE2000klch(cr, 1.0, 1.0, 1.0) +} + +// DistanceCIEDE2000klch uses the Delta E 2000 formula with custom values +// for the weighting factors kL, kC, and kH. +func (cl Color) DistanceCIEDE2000klch(cr Color, kl, kc, kh float64) float64 { + l1, a1, b1 := cl.Lab() + l2, a2, b2 := cr.Lab() + + // As with CIE94, we scale up the ranges of L,a,b beforehand and scale + // them down again afterwards. + l1, a1, b1 = l1*100.0, a1*100.0, b1*100.0 + l2, a2, b2 = l2*100.0, a2*100.0, b2*100.0 + + cab1 := math.Sqrt(sq(a1) + sq(b1)) + cab2 := math.Sqrt(sq(a2) + sq(b2)) + cabmean := (cab1 + cab2) / 2 + + g := 0.5 * (1 - math.Sqrt(math.Pow(cabmean, 7)/(math.Pow(cabmean, 7)+math.Pow(25, 7)))) + ap1 := (1 + g) * a1 + ap2 := (1 + g) * a2 + cp1 := math.Sqrt(sq(ap1) + sq(b1)) + cp2 := math.Sqrt(sq(ap2) + sq(b2)) + + hp1 := 0.0 + if b1 != ap1 || ap1 != 0 { + hp1 = math.Atan2(b1, ap1) + if hp1 < 0 { + hp1 += math.Pi * 2 + } + hp1 *= 180 / math.Pi + } + hp2 := 0.0 + if b2 != ap2 || ap2 != 0 { + hp2 = math.Atan2(b2, ap2) + if hp2 < 0 { + hp2 += math.Pi * 2 + } + hp2 *= 180 / math.Pi + } + + deltaLp := l2 - l1 + deltaCp := cp2 - cp1 + dhp := 0.0 + cpProduct := cp1 * cp2 + if cpProduct != 0 { + dhp = hp2 - hp1 + if dhp > 180 { + dhp -= 360 + } else if dhp < -180 { + dhp += 360 + } + } + deltaHp := 2 * math.Sqrt(cpProduct) * math.Sin(dhp/2*math.Pi/180) + + lpmean := (l1 + l2) / 2 + cpmean := (cp1 + cp2) / 2 + hpmean := hp1 + hp2 + if cpProduct != 0 { + hpmean /= 2 + if math.Abs(hp1-hp2) > 180 { + if hp1+hp2 < 360 { + hpmean += 180 + } else { + hpmean -= 180 + } + } + } + + t := 1 - 0.17*math.Cos((hpmean-30)*math.Pi/180) + 0.24*math.Cos(2*hpmean*math.Pi/180) + 0.32*math.Cos((3*hpmean+6)*math.Pi/180) - 0.2*math.Cos((4*hpmean-63)*math.Pi/180) + deltaTheta := 30 * math.Exp(-sq((hpmean-275)/25)) + rc := 2 * math.Sqrt(math.Pow(cpmean, 7)/(math.Pow(cpmean, 7)+math.Pow(25, 7))) + sl := 1 + (0.015*sq(lpmean-50))/math.Sqrt(20+sq(lpmean-50)) + sc := 1 + 0.045*cpmean + sh := 1 + 0.015*cpmean*t + rt := -math.Sin(2*deltaTheta*math.Pi/180) * rc + + return math.Sqrt(sq(deltaLp/(kl*sl))+sq(deltaCp/(kc*sc))+sq(deltaHp/(kh*sh))+rt*(deltaCp/(kc*sc))*(deltaHp/(kh*sh))) * 0.01 +} + +// BlendLab blends two colors in the L*a*b* color-space, which should result in a smoother blend. +// t == 0 results in c1, t == 1 results in c2 +func (c1 Color) BlendLab(c2 Color, t float64) Color { + l1, a1, b1 := c1.Lab() + l2, a2, b2 := c2.Lab() + return Lab(l1+t*(l2-l1), + a1+t*(a2-a1), + b1+t*(b2-b1)) +} + +/// L*u*v* /// +////////////// +// http://en.wikipedia.org/wiki/CIELUV#XYZ_.E2.86.92_CIELUV_and_CIELUV_.E2.86.92_XYZ_conversions +// For L*u*v*, we need to L*u*v*<->XYZ<->RGB and the first one is device dependent. + +func XyzToLuv(x, y, z float64) (l, a, b float64) { + // Use D65 white as reference point by default. + // http://www.fredmiranda.com/forum/topic/1035332 + // http://en.wikipedia.org/wiki/Standard_illuminant + return XyzToLuvWhiteRef(x, y, z, D65) +} + +func XyzToLuvWhiteRef(x, y, z float64, wref [3]float64) (l, u, v float64) { + if y/wref[1] <= 6.0/29.0*6.0/29.0*6.0/29.0 { + l = y / wref[1] * (29.0 / 3.0 * 29.0 / 3.0 * 29.0 / 3.0) / 100.0 + } else { + l = 1.16*math.Cbrt(y/wref[1]) - 0.16 + } + ubis, vbis := xyz_to_uv(x, y, z) + un, vn := xyz_to_uv(wref[0], wref[1], wref[2]) + u = 13.0 * l * (ubis - un) + v = 13.0 * l * (vbis - vn) + return +} + +// For this part, we do as R's graphics.hcl does, not as wikipedia does. +// Or is it the same? +func xyz_to_uv(x, y, z float64) (u, v float64) { + denom := x + 15.0*y + 3.0*z + if denom == 0.0 { + u, v = 0.0, 0.0 + } else { + u = 4.0 * x / denom + v = 9.0 * y / denom + } + return +} + +func LuvToXyz(l, u, v float64) (x, y, z float64) { + // D65 white (see above). + return LuvToXyzWhiteRef(l, u, v, D65) +} + +func LuvToXyzWhiteRef(l, u, v float64, wref [3]float64) (x, y, z float64) { + //y = wref[1] * lab_finv((l + 0.16) / 1.16) + if l <= 0.08 { + y = wref[1] * l * 100.0 * 3.0 / 29.0 * 3.0 / 29.0 * 3.0 / 29.0 + } else { + y = wref[1] * cub((l+0.16)/1.16) + } + un, vn := xyz_to_uv(wref[0], wref[1], wref[2]) + if l != 0.0 { + ubis := u/(13.0*l) + un + vbis := v/(13.0*l) + vn + x = y * 9.0 * ubis / (4.0 * vbis) + z = y * (12.0 - 3.0*ubis - 20.0*vbis) / (4.0 * vbis) + } else { + x, y = 0.0, 0.0 + } + return +} + +// Converts the given color to CIE L*u*v* space using D65 as reference white. +// L* is in [0..1] and both u* and v* are in about [-1..1] +func (col Color) Luv() (l, u, v float64) { + return XyzToLuv(col.Xyz()) +} + +// Converts the given color to CIE L*u*v* space, taking into account +// a given reference white. (i.e. the monitor's white) +// L* is in [0..1] and both u* and v* are in about [-1..1] +func (col Color) LuvWhiteRef(wref [3]float64) (l, u, v float64) { + x, y, z := col.Xyz() + return XyzToLuvWhiteRef(x, y, z, wref) +} + +// Generates a color by using data given in CIE L*u*v* space using D65 as reference white. +// L* is in [0..1] and both u* and v* are in about [-1..1] +// WARNING: many combinations of `l`, `u`, and `v` values do not have corresponding +// valid RGB values, check the FAQ in the README if you're unsure. +func Luv(l, u, v float64) Color { + return Xyz(LuvToXyz(l, u, v)) +} + +// Generates a color by using data given in CIE L*u*v* space, taking +// into account a given reference white. (i.e. the monitor's white) +// L* is in [0..1] and both u* and v* are in about [-1..1] +func LuvWhiteRef(l, u, v float64, wref [3]float64) Color { + return Xyz(LuvToXyzWhiteRef(l, u, v, wref)) +} + +// DistanceLuv is a good measure of visual similarity between two colors! +// A result of 0 would mean identical colors, while a result of 1 or higher +// means the colors differ a lot. +func (c1 Color) DistanceLuv(c2 Color) float64 { + l1, u1, v1 := c1.Luv() + l2, u2, v2 := c2.Luv() + return math.Sqrt(sq(l1-l2) + sq(u1-u2) + sq(v1-v2)) +} + +// BlendLuv blends two colors in the CIE-L*u*v* color-space, which should result in a smoother blend. +// t == 0 results in c1, t == 1 results in c2 +func (c1 Color) BlendLuv(c2 Color, t float64) Color { + l1, u1, v1 := c1.Luv() + l2, u2, v2 := c2.Luv() + return Luv(l1+t*(l2-l1), + u1+t*(u2-u1), + v1+t*(v2-v1)) +} + +/// HCL /// +/////////// +// HCL is nothing else than L*a*b* in cylindrical coordinates! +// (this was wrong on English wikipedia, I fixed it, let's hope the fix stays.) +// But it is widely popular since it is a "correct HSV" +// http://www.hunterlab.com/appnotes/an09_96a.pdf + +// Converts the given color to HCL space using D65 as reference white. +// H values are in [0..360], C and L values are in [0..1] although C can overshoot 1.0 +func (col Color) Hcl() (h, c, l float64) { + return col.HclWhiteRef(D65) +} + +func LabToHcl(L, a, b float64) (h, c, l float64) { + // Oops, floating point workaround necessary if a ~= b and both are very small (i.e. almost zero). + if math.Abs(b-a) > 1e-4 && math.Abs(a) > 1e-4 { + h = math.Mod(57.29577951308232087721*math.Atan2(b, a)+360.0, 360.0) // Rad2Deg + } else { + h = 0.0 + } + c = math.Sqrt(sq(a) + sq(b)) + l = L + return +} + +// Converts the given color to HCL space, taking into account +// a given reference white. (i.e. the monitor's white) +// H values are in [0..360], C and L values are in [0..1] +func (col Color) HclWhiteRef(wref [3]float64) (h, c, l float64) { + L, a, b := col.LabWhiteRef(wref) + return LabToHcl(L, a, b) +} + +// Generates a color by using data given in HCL space using D65 as reference white. +// H values are in [0..360], C and L values are in [0..1] +// WARNING: many combinations of `h`, `c`, and `l` values do not have corresponding +// valid RGB values, check the FAQ in the README if you're unsure. +func Hcl(h, c, l float64) Color { + return HclWhiteRef(h, c, l, D65) +} + +func HclToLab(h, c, l float64) (L, a, b float64) { + H := 0.01745329251994329576 * h // Deg2Rad + a = c * math.Cos(H) + b = c * math.Sin(H) + L = l + return +} + +// Generates a color by using data given in HCL space, taking +// into account a given reference white. (i.e. the monitor's white) +// H values are in [0..360], C and L values are in [0..1] +func HclWhiteRef(h, c, l float64, wref [3]float64) Color { + L, a, b := HclToLab(h, c, l) + return LabWhiteRef(L, a, b, wref) +} + +// BlendHcl blends two colors in the CIE-L*C*h° color-space, which should result in a smoother blend. +// t == 0 results in c1, t == 1 results in c2 +func (col1 Color) BlendHcl(col2 Color, t float64) Color { + h1, c1, l1 := col1.Hcl() + h2, c2, l2 := col2.Hcl() + + // We know that h are both in [0..360] + return Hcl(interp_angle(h1, h2, t), c1+t*(c2-c1), l1+t*(l2-l1)).Clamped() +} + +// LuvLch + +// Converts the given color to LuvLCh space using D65 as reference white. +// h values are in [0..360], C and L values are in [0..1] although C can overshoot 1.0 +func (col Color) LuvLCh() (l, c, h float64) { + return col.LuvLChWhiteRef(D65) +} + +func LuvToLuvLCh(L, u, v float64) (l, c, h float64) { + // Oops, floating point workaround necessary if u ~= v and both are very small (i.e. almost zero). + if math.Abs(v-u) > 1e-4 && math.Abs(u) > 1e-4 { + h = math.Mod(57.29577951308232087721*math.Atan2(v, u)+360.0, 360.0) // Rad2Deg + } else { + h = 0.0 + } + l = L + c = math.Sqrt(sq(u) + sq(v)) + return +} + +// Converts the given color to LuvLCh space, taking into account +// a given reference white. (i.e. the monitor's white) +// h values are in [0..360], c and l values are in [0..1] +func (col Color) LuvLChWhiteRef(wref [3]float64) (l, c, h float64) { + return LuvToLuvLCh(col.LuvWhiteRef(wref)) +} + +// Generates a color by using data given in LuvLCh space using D65 as reference white. +// h values are in [0..360], C and L values are in [0..1] +// WARNING: many combinations of `l`, `c`, and `h` values do not have corresponding +// valid RGB values, check the FAQ in the README if you're unsure. +func LuvLCh(l, c, h float64) Color { + return LuvLChWhiteRef(l, c, h, D65) +} + +func LuvLChToLuv(l, c, h float64) (L, u, v float64) { + H := 0.01745329251994329576 * h // Deg2Rad + u = c * math.Cos(H) + v = c * math.Sin(H) + L = l + return +} + +// Generates a color by using data given in LuvLCh space, taking +// into account a given reference white. (i.e. the monitor's white) +// h values are in [0..360], C and L values are in [0..1] +func LuvLChWhiteRef(l, c, h float64, wref [3]float64) Color { + L, u, v := LuvLChToLuv(l, c, h) + return LuvWhiteRef(L, u, v, wref) +} + +// BlendLuvLCh blends two colors in the cylindrical CIELUV color space. +// t == 0 results in c1, t == 1 results in c2 +func (col1 Color) BlendLuvLCh(col2 Color, t float64) Color { + l1, c1, h1 := col1.LuvLCh() + l2, c2, h2 := col2.LuvLCh() + + // We know that h are both in [0..360] + return LuvLCh(l1+t*(l2-l1), c1+t*(c2-c1), interp_angle(h1, h2, t)) +} diff --git a/vendor/github.com/lucasb-eyer/go-colorful/happy_palettegen.go b/vendor/github.com/lucasb-eyer/go-colorful/happy_palettegen.go new file mode 100644 index 000000000..bb66dfa4f --- /dev/null +++ b/vendor/github.com/lucasb-eyer/go-colorful/happy_palettegen.go @@ -0,0 +1,25 @@ +package colorful + +import ( + "math/rand" +) + +// Uses the HSV color space to generate colors with similar S,V but distributed +// evenly along their Hue. This is fast but not always pretty. +// If you've got time to spare, use Lab (the non-fast below). +func FastHappyPalette(colorsCount int) (colors []Color) { + colors = make([]Color, colorsCount) + + for i := 0; i < colorsCount; i++ { + colors[i] = Hsv(float64(i)*(360.0/float64(colorsCount)), 0.8+rand.Float64()*0.2, 0.65+rand.Float64()*0.2) + } + return +} + +func HappyPalette(colorsCount int) ([]Color, error) { + pimpy := func(l, a, b float64) bool { + _, c, _ := LabToHcl(l, a, b) + return 0.3 <= c && 0.4 <= l && l <= 0.8 + } + return SoftPaletteEx(colorsCount, SoftPaletteSettings{pimpy, 50, true}) +} diff --git a/vendor/github.com/lucasb-eyer/go-colorful/hexcolor.go b/vendor/github.com/lucasb-eyer/go-colorful/hexcolor.go new file mode 100644 index 000000000..76f31d8f9 --- /dev/null +++ b/vendor/github.com/lucasb-eyer/go-colorful/hexcolor.go @@ -0,0 +1,67 @@ +package colorful + +import ( + "database/sql/driver" + "encoding/json" + "fmt" + "reflect" +) + +// A HexColor is a Color stored as a hex string "#rrggbb". It implements the +// database/sql.Scanner, database/sql/driver.Value, +// encoding/json.Unmarshaler and encoding/json.Marshaler interfaces. +type HexColor Color + +type errUnsupportedType struct { + got interface{} + want reflect.Type +} + +func (hc *HexColor) Scan(value interface{}) error { + s, ok := value.(string) + if !ok { + return errUnsupportedType{got: reflect.TypeOf(value), want: reflect.TypeOf("")} + } + c, err := Hex(s) + if err != nil { + return err + } + *hc = HexColor(c) + return nil +} + +func (hc *HexColor) Value() (driver.Value, error) { + return Color(*hc).Hex(), nil +} + +func (e errUnsupportedType) Error() string { + return fmt.Sprintf("unsupported type: got %v, want a %s", e.got, e.want) +} + +func (hc *HexColor) UnmarshalJSON(data []byte) error { + var hexCode string + if err := json.Unmarshal(data, &hexCode); err != nil { + return err + } + + var col, err = Hex(hexCode) + if err != nil { + return err + } + *hc = HexColor(col) + return nil +} + +func (hc HexColor) MarshalJSON() ([]byte, error) { + return json.Marshal(Color(hc).Hex()) +} + +// Decode - deserialize function for https://github.com/kelseyhightower/envconfig +func (hc *HexColor) Decode(hexCode string) error { + var col, err = Hex(hexCode) + if err != nil { + return err + } + *hc = HexColor(col) + return nil +} diff --git a/vendor/github.com/lucasb-eyer/go-colorful/hsluv-snapshot-rev4.json b/vendor/github.com/lucasb-eyer/go-colorful/hsluv-snapshot-rev4.json new file mode 100644 index 000000000..16354abf5 --- /dev/null +++ b/vendor/github.com/lucasb-eyer/go-colorful/hsluv-snapshot-rev4.json @@ -0,0 +1 @@ +{"#11ee00":{"lch":[82.5213119008325577,127.202882727266427,127.478988192005161],"luv":[82.5213119008325577,-77.3991947082883627,100.945222931227221],"rgb":[0.0666666666666666657,0.933333333333333348,0],"xyz":[0.308043578886299796,0.612655858810891907,0.102019012460713238],"hpluv":[127.478988192005161,308.195222762673438,82.5213119008325577],"hsluv":[127.478988192005161,100.000000000002416,82.5213119008325577]},"#11ee11":{"lch":[82.5429986110943759,126.352581314528209,127.715012949240403],"luv":[82.5429986110943759,-77.2942129186682,99.9528861720763473],"rgb":[0.0666666666666666657,0.933333333333333348,0.0666666666666666657],"xyz":[0.3090552443859369,0.613060525010746815,0.107347117425468874],"hpluv":[127.715012949240403,306.573296560288782,82.5429986110943759],"hsluv":[127.715012949240403,98.9038130800949205,82.5429986110943759]},"#11ee22":{"lch":[82.5831747617793184,124.791738379333623,128.158354445562821],"luv":[82.5831747617793184,-77.1009570540098,98.1245147202868253],"rgb":[0.0666666666666666657,0.933333333333333348,0.133333333333333331],"xyz":[0.310930602524413957,0.613810668266137616,0.117224003621448067],"hpluv":[128.158354445562821,303.59085997924285,82.5831747617793184],"hsluv":[128.158354445562821,98.9085620232469864,82.5831747617793184]},"#11ee33":{"lch":[82.6492529720821381,122.265269823008623,128.905098358231896],"luv":[82.6492529720821381,-76.7865393115689301,95.1452762119380537],"rgb":[0.0666666666666666657,0.933333333333333348,0.2],"xyz":[0.314018353256871663,0.615045768559120742,0.133486157479059203],"hpluv":[128.905098358231896,298.749143147736106,82.6492529720821381],"hsluv":[128.905098358231896,98.916292078887,82.6492529720821381]},"#11ee44":{"lch":[82.7444986901015511,118.712635154498344,130.021230388522838],"luv":[82.7444986901015511,-76.3407023620842,90.9108734321077],"rgb":[0.0666666666666666657,0.933333333333333348,0.266666666666666663],"xyz":[0.318476348501090578,0.616828966656808308,0.156964932431945842],"hpluv":[130.021230388522838,291.911386756693616,82.7444986901015511],"hsluv":[130.021230388522838,98.9272612770947148,82.7444986901015511]},"#11ee55":{"lch":[82.8716000285422894,114.135934527262179,131.587310643629934],"luv":[82.8716000285422894,-75.758934185545,85.3674144008224],"rgb":[0.0666666666666666657,0.933333333333333348,0.333333333333333315],"xyz":[0.324438762540452563,0.619213932272553058,0.188366979705919757],"hpluv":[131.587310643629934,283.052591495130912,82.8716000285422894],"hsluv":[131.587310643629934,98.941589727101146,82.8716000285422894]},"#11ee66":{"lch":[83.0328193013522622,108.602333046050703,133.707640253052432],"luv":[83.0328193013522622,-75.0419109433949103,78.5059128028513697],"rgb":[0.0666666666666666657,0.933333333333333348,0.4],"xyz":[0.332023758313960748,0.622247930581956377,0.228314624113063719],"hpluv":[133.707640253052432,272.269449526145593,83.0328193013522622],"hsluv":[133.707640253052432,98.9592735060659,83.0328193013522622]},"#11ee77":{"lch":[83.2300736177455747,102.250357200027821,136.520544097163679],"luv":[83.2300736177455747,-74.1950209885278866,70.3579022430685228],"rgb":[0.0666666666666666657,0.933333333333333348,0.466666666666666674],"xyz":[0.341337771334162654,0.625973535790037228,0.277368426019461656],"hpluv":[136.520544097163679,259.803949175129901,83.2300736177455747],"hsluv":[136.520544097163679,98.9801962733070155,83.2300736177455747]},"#11ee88":{"lch":[83.4649827070576151,95.3003261118453651,140.209511574476238],"luv":[83.4649827070576151,-73.2277962837693082,60.990507527375577],"rgb":[0.0666666666666666657,0.933333333333333348,0.533333333333333326],"xyz":[0.352478188436106454,0.63042970263081477,0.336041289423033795],"hpluv":[140.209511574476238,246.084644167270028,83.4649827070576151],"hsluv":[140.209511574476238,99.0041428894333109,83.4649827070576151]},"#11ee99":{"lch":[83.7388997377875626,88.07037792773761,145.011549795441141],"luv":[83.7388997377875626,-72.1532115864445416,50.5005497603372433],"rgb":[0.0666666666666666657,0.933333333333333348,0.6],"xyz":[0.365535152545179209,0.635652488274444,0.404807967064151675],"hpluv":[145.011549795441141,231.793725377578141,83.7388997377875626],"hsluv":[145.011549795441141,99.0308160530368582,83.7388997377875626]},"#11eeaa":{"lch":[84.0529327571252907,80.9984265129003802,151.210882439188083],"luv":[84.0529327571252907,-70.9868724309634729,39.0078074241021824],"rgb":[0.0666666666666666657,0.933333333333333348,0.66666666666666663],"xyz":[0.38059284551043171,0.641675565460545,0.484111816681150331],"hpluv":[151.210882439188083,217.967504021816438,84.0529327571252907],"hsluv":[151.210882439188083,99.0598554997167895,84.0529327571252907]},"#11eebb":{"lch":[84.4079608499599914,74.6634505604909435,159.089705667287262],"luv":[84.4079608499599914,-69.7461428935043273,26.6478216947980826],"rgb":[0.0666666666666666657,0.933333333333333348,0.733333333333333282],"xyz":[0.397730437617768384,0.648530602303479808,0.574369801779792],"hpluv":[159.089705667287262,206.122134265545043,84.4079608499599914],"hsluv":[159.089705667287262,99.0908585861444209,84.4079608499599914]},"#11eecc":{"lch":[84.8046473826435,69.7804076798411,168.790807110150524],"luv":[84.8046473826435,-68.449275126866155,13.5647348138992196],"rgb":[0.0666666666666666657,0.933333333333333348,0.8],"xyz":[0.417022813061490139,0.656247552480968666,0.675976312450062178],"hpluv":[168.790807110150524,198.342538571842852,84.8046473826435],"hsluv":[168.790807110150524,99.123400814408285,84.8046473826435]},"#11eedd":{"lch":[85.2434517572140749,67.1146678094459,180.081412911690762],"luv":[85.2434517572140749,-67.114600056421537,-0.0953647673755886743],"rgb":[0.0666666666666666657,0.933333333333333348,0.866666666666666696],"xyz":[0.438541138612123627,0.664854882701222172,0.789306160350068176],"hpluv":[180.081412911690762,197.173954094180345,85.2434517572140749],"hsluv":[180.081412911690762,99.1570549081779546,85.2434517572140749]},"#11eeee":{"lch":[85.7246405502341275,67.2734484234975,192.17705063006116],"luv":[85.7246405502341275,-65.759826803247222,-14.1902093570146306],"rgb":[0.0666666666666666657,0.933333333333333348,0.933333333333333348],"xyz":[0.462353318878298392,0.674379754807692189,0.914716976418591399],"hpluv":[192.17705063006116,205.138082793863816,85.7246405502341275],"hsluv":[192.17705063006116,99.1914073274009098,85.7246405502341275]},"#11eeff":{"lch":[86.2482985645723517,70.4606934075819282,203.935071880927921],"luv":[86.2482985645723517,-64.401481656171029,-28.585983907627277],"rgb":[0.0666666666666666657,0.933333333333333348,1],"xyz":[0.488524367288129757,0.684848174171624913,1.05255116471037335],"hpluv":[203.935071880927921,224.026806300523,86.2482985645723517],"hsluv":[203.935071880927921,99.9999999999942304,86.2482985645723517]},"#11ff00":{"lch":[87.7931168603164,135.408535196841626,127.513270797457935],"luv":[87.7931168603164,-82.4563732780469,107.407718111808407],"rgb":[0.0666666666666666657,1,0],"xyz":[0.359895951315973628,0.716360603670241,0.119303136603937349],"hpluv":[127.513270797457935,491.310985978769054,87.7931168603164],"hsluv":[127.513270797457935,100.000000000002373,87.7931168603164]},"#11ff11":{"lch":[87.8126571401035108,134.634318462908169,127.715012949240432],"luv":[87.8126571401035108,-82.3604359259359313,106.50426424355777],"rgb":[0.0666666666666666657,1,0.0666666666666666657],"xyz":[0.360907616815610732,0.716765269870095922,0.124631241568692985],"hpluv":[127.715012949240432,489.364334505449051,87.8126571401035108],"hsluv":[127.715012949240432,99.999999999991914,87.8126571401035108]},"#11ff22":{"lch":[87.848860165327963,133.211117719966126,128.093229681784152],"luv":[87.848860165327963,-82.1836510367646,104.838205757586152],"rgb":[0.0666666666666666657,1,0.133333333333333331],"xyz":[0.362782974954087789,0.717515413125486723,0.134508127764672164],"hpluv":[128.093229681784152,485.7796458877379,87.848860165327963],"hsluv":[128.093229681784152,99.9999999999918572,87.848860165327963]},"#11ff33":{"lch":[87.9084130007832698,130.901693692038833,128.728166832562891],"luv":[87.9084130007832698,-81.8955348861488659,102.119414300885666],"rgb":[0.0666666666666666657,1,0.2],"xyz":[0.365870725686545495,0.71875051341846985,0.150770281622283314],"hpluv":[128.728166832562891,479.945632467831388,87.9084130007832698],"hsluv":[128.728166832562891,99.9999999999919567,87.9084130007832698]},"#11ff44":{"lch":[87.9942732352876,127.641489512823171,129.672386074694657],"luv":[87.9942732352876,-81.4859348177847806,98.2465891108891185],"rgb":[0.0666666666666666657,1,0.266666666666666663],"xyz":[0.37032872093076441,0.720533711516157416,0.174249056575169953],"hpluv":[129.672386074694657,471.674193406224788,87.9942732352876],"hsluv":[129.672386074694657,99.9999999999918856,87.9942732352876]},"#11ff55":{"lch":[88.1088871723243727,123.41738800901625,130.987994113812931],"luv":[88.1088871723243727,-80.9495722978130772,93.1612494966077662],"rgb":[0.0666666666666666657,1,0.333333333333333315],"xyz":[0.376291134970126395,0.722918677131902165,0.205651103849143868],"hpluv":[130.987994113812931,460.897243009671797,88.1088871723243727],"hsluv":[130.987994113812931,99.9999999999917,88.1088871723243727]},"#11ff66":{"lch":[88.2543278429396,118.268592142924746,132.753132104158254],"luv":[88.2543278429396,-80.2855559529031382,86.8429006471038],"rgb":[0.0666666666666666657,1,0.4],"xyz":[0.38387613074363458,0.725952675441305484,0.24559874825628783],"hpluv":[132.753132104158254,447.675525940365219,88.2543278429396],"hsluv":[132.753132104158254,99.9999999999916724,88.2543278429396]},"#11ff77":{"lch":[88.4323687925046613,112.290518027227137,135.069051083024959],"luv":[88.4323687925046613,-79.4970211443964558,79.3056370505300521],"rgb":[0.0666666666666666657,1,0.466666666666666674],"xyz":[0.393190143763836486,0.729678280649386335,0.294652550162685767],"hpluv":[135.069051083024959,432.222948715922314,88.4323687925046613],"hsluv":[135.069051083024959,99.999999999991644,88.4323687925046613]},"#11ff88":{"lch":[88.6445280109338825,105.641380676940045,138.068036362648229],"luv":[88.6445280109338825,-78.5907289650887577,70.5946076698930369],"rgb":[0.0666666666666666657,1,0.533333333333333326],"xyz":[0.404330560865780286,0.734134447490163877,0.353325413566257907],"hpluv":[138.068036362648229,414.95023459347243,88.6445280109338825],"hsluv":[138.068036362648229,99.9999999999915,88.6445280109338825]},"#11ff99":{"lch":[88.8920961876840465,98.552301258979881,141.921030988541872],"luv":[88.8920961876840465,-77.5765731609304225,60.7818342932124338],"rgb":[0.0666666666666666657,1,0.6],"xyz":[0.417387524974853,0.73935723313379309,0.422092091207375786],"hpluv":[141.921030988541872,396.537381185702543,88.8920961876840465],"hsluv":[141.921030988541872,99.9999999999913456,88.8920961876840465]},"#11ffaa":{"lch":[89.1761561490339147,91.3418654410923523,146.840553381528281],"luv":[89.1761561490339147,-76.4669946123218,49.9613362233014158],"rgb":[0.0666666666666666657,1,0.66666666666666663],"xyz":[0.432445217940105542,0.745380310319894157,0.501395940824374442],"hpluv":[146.840553381528281,378.048392077141443,89.1761561490339147],"hsluv":[146.840553381528281,99.9999999999913,89.1761561490339147]},"#11ffbb":{"lch":[89.4975971674113,84.4340589142561413,153.067388238784645],"luv":[89.4975971674113,-75.2763296710648859,38.2437510711127],"rgb":[0.0666666666666666657,1,0.733333333333333282],"xyz":[0.449582810047442216,0.752235347162828916,0.591653925923016133],"hpluv":[153.067388238784645,361.099415032935838,89.4975971674113],"hsluv":[153.067388238784645,99.9999999999909335,89.4975971674113]},"#11ffcc":{"lch":[89.8571262823018628,78.3714319324892159,160.817799258328876],"luv":[89.8571262823018628,-74.0201316086282901,25.7507564896672143],"rgb":[0.0666666666666666657,1,0.8],"xyz":[0.468875185491163915,0.759952297340317773,0.693260436593286289],"hpluv":[160.817799258328876,348.067615225706845,89.8571262823018628],"hsluv":[160.817799258328876,99.999999999991,89.8571262823018628]},"#11ffdd":{"lch":[90.2552779380141317,73.7997451229305,170.162013498752287],"luv":[90.2552779380141317,-72.7145076797264238,12.6096293801408788],"rgb":[0.0666666666666666657,1,0.866666666666666696],"xyz":[0.490393511041797514,0.768559627560571279,0.806590284493292287],"hpluv":[170.162013498752287,342.256686666565315,90.2552779380141317],"hsluv":[170.162013498752287,99.999999999990834,90.2552779380141317]},"#11ffee":{"lch":[90.6924227584195819,71.3832589696730793,180.844217403257659],"luv":[90.6924227584195819,-71.3755103944163665,-1.05174952720347981],"rgb":[0.0666666666666666657,1,0.933333333333333348],"xyz":[0.514205691307972224,0.778084499667041296,0.93200110056181551],"hpluv":[180.844217403257659,347.82122947809512,90.6924227584195819],"hsluv":[180.844217403257659,99.9999999999901803,90.6924227584195819]},"#11ffff":{"lch":[91.1687759776689859,71.6302608322469467,192.17705063006116],"luv":[91.1687759776689859,-70.0186129384549361,-15.1092061032524665],"rgb":[0.0666666666666666657,1,1],"xyz":[0.540376739717803645,0.788552919030974,1.06983528885359735],"hpluv":[192.17705063006116,369.258709956275879,91.1687759776689859],"hsluv":[192.17705063006116,99.9999999999898108,91.1687759776689859]},"#00aa00":{"lch":[60.5587499434736287,93.727653253516209,127.71501294924046],"luv":[60.5587499434736287,-57.3364240886418415,74.1445038903004559],"rgb":[0,0.66666666666666663,0],"xyz":[0.143740958848290495,0.287481917696585,0.0479136529494288144],"hpluv":[127.71501294924046,196.394882900214554,60.5587499434736287],"hsluv":[127.71501294924046,100.000000000002359,60.5587499434736287]},"#00aa11":{"lch":[60.5946550577951939,92.4075267438518182,128.220974416403209],"luv":[60.5946550577951939,-57.1721703645967665,72.5981675713458543],"rgb":[0,0.66666666666666663,0.0666666666666666657],"xyz":[0.144752624347927628,0.28788658389643984,0.0532417579141844441],"hpluv":[128.220974416403209,193.513984665985475,60.5946550577951939],"hsluv":[128.220974416403209,99.9999999999907772,60.5946550577951939]},"#00aa22":{"lch":[60.661124672570665,90.0113827545795715,129.185497299711983],"luv":[60.661124672570665,-56.8721735728637725,69.7682226983709199],"rgb":[0,0.66666666666666663,0.133333333333333331],"xyz":[0.146627982486404629,0.288636727151830641,0.0631186441101636436],"hpluv":[129.185497299711983,188.289586599726533,60.661124672570665],"hsluv":[129.185497299711983,99.9999999999908624,60.661124672570665]},"#00aa33":{"lch":[60.7703154938824355,86.2098857925288513,130.852037745481823],"luv":[60.7703154938824355,-56.3905639077229353,65.2092685937350751],"rgb":[0,0.66666666666666663,0.2],"xyz":[0.14971573321886239,0.289871827444813768,0.0793807979677747799],"hpluv":[130.852037745481823,180.013429236819462,60.7703154938824355],"hsluv":[130.852037745481823,99.9999999999908,60.7703154938824355]},"#00aa44":{"lch":[60.9274158721733841,81.0355822964375108,133.441426631804489],"luv":[60.9274158721733841,-55.7210928860807044,58.8381288426430444],"rgb":[0,0.66666666666666663,0.266666666666666663],"xyz":[0.15417372846308125,0.291655025542501334,0.102859572920661418],"hpluv":[133.441426631804489,168.77274926729055,60.9274158721733841],"hsluv":[133.441426631804489,99.9999999999908908,60.9274158721733841]},"#00aa55":{"lch":[61.1365343944832915,74.6960845180523592,137.272019015051796],"luv":[61.1365343944832915,-54.8704978500827636,50.6826746335676717],"rgb":[0,0.66666666666666663,0.333333333333333315],"xyz":[0.160136142502443235,0.294039991158246194,0.134261620194635334],"hpluv":[137.272019015051796,155.037353806827582,61.1365343944832915],"hsluv":[137.272019015051796,99.9999999999910614,61.1365343944832915]},"#00aa66":{"lch":[61.4009335299549264,67.6053275851037512,142.80970662058607],"luv":[61.4009335299549264,-53.8565898531593703,40.8649978254956139],"rgb":[0,0.66666666666666663,0.4],"xyz":[0.16772113827595142,0.297073989467649513,0.174209264601779296],"hpluv":[142.80970662058607,139.715720243970395,61.4009335299549264],"hsluv":[142.80970662058607,99.9999999999911893,61.4009335299549264]},"#00aa77":{"lch":[61.7231520087844814,60.4394033477847188,150.696962972825474],"luv":[61.7231520087844814,-52.7057786154446859,29.5807771631501382],"rgb":[0,0.66666666666666663,0.466666666666666674],"xyz":[0.177035151296153326,0.300799594675730309,0.223263066508177205],"hpluv":[150.696962972825474,124.254291935777843,61.7231520087844814],"hsluv":[150.696962972825474,99.9999999999911893,61.7231520087844814]},"#00aa88":{"lch":[62.1050795642419615,54.2095218153359397,161.640221068188367],"luv":[62.1050795642419615,-51.4501140589855126,17.0750700954568337],"rgb":[0,0.66666666666666663,0.533333333333333326],"xyz":[0.188175568398097182,0.305255761516507906,0.281935929911749372],"hpluv":[161.640221068188367,110.761232665855573,62.1050795642419615],"hsluv":[161.640221068188367,99.9999999999911466,62.1050795642419615]},"#00aa99":{"lch":[62.5480102999456307,50.2545412813378576,175.872445658321794],"luv":[62.5480102999456307,-50.1241952468173793,3.61717711159146882],"rgb":[0,0.66666666666666663,0.6],"xyz":[0.201232532507169881,0.310478547160137064,0.350702607552867307],"hpluv":[175.872445658321794,101.95326553071466,62.5480102999456307],"hsluv":[175.872445658321794,99.9999999999913314,62.5480102999456307]},"#00aaaa":{"lch":[63.0526871437625829,49.8847230087107931,192.17705063006116],"luv":[63.0526871437625829,-48.762339705407328,-10.5223484123201398],"rgb":[0,0.66666666666666663,0.66666666666666663],"xyz":[0.216290225472422437,0.316501624346238186,0.430006457169865852],"hpluv":[192.17705063006116,100.392967527320806,63.0526871437625829],"hsluv":[192.17705063006116,99.9999999999914451,63.0526871437625829]},"#00aabb":{"lch":[63.6193436646561565,53.6276681768737,207.895374658889665],"luv":[63.6193436646561565,-47.3963155750249143,-25.0901587081772526],"rgb":[0,0.66666666666666663,0.733333333333333282],"xyz":[0.233427817579759056,0.323356661189172945,0.520264442268507654],"hpluv":[207.895374658889665,106.964349821245364,63.6193436646561565],"hsluv":[207.895374658889665,99.9999999999916,63.6193436646561565]},"#00aacc":{"lch":[64.2477463386430259,60.9097449106327886,220.878520684721707],"luv":[64.2477463386430259,-46.0537892020538,-39.8628338833449],"rgb":[0,0.66666666666666663,0.8],"xyz":[0.25272019302348081,0.331073611366661746,0.62187095293877781],"hpluv":[220.878520684721707,120.300715116377788,64.2477463386430259],"hsluv":[220.878520684721707,99.9999999999916298,64.2477463386430259]},"#00aadd":{"lch":[64.9372385342214926,70.6418801813473465,230.685034316882962],"luv":[64.9372385342214926,-44.7574928469198525,-54.6538385624811625],"rgb":[0,0.66666666666666663,0.866666666666666696],"xyz":[0.274238518574114354,0.339680941586915253,0.735200800838783808],"hpluv":[230.685034316882962,138.04089297290011,64.9372385342214926],"hsluv":[230.685034316882962,99.9999999999918145,64.9372385342214926]},"#00aaee":{"lch":[65.6867863979168618,81.8478503674051,237.87423205753521],"luv":[65.6867863979168618,-43.5250094774703129,-69.3155405356638283],"rgb":[0,0.66666666666666663,0.933333333333333348],"xyz":[0.298050698840289119,0.34920581369338527,0.860611616907307],"hpluv":[237.87423205753521,158.11336767521891,65.6867863979168618],"hsluv":[237.87423205753521,99.999999999991843,65.6867863979168618]},"#00aaff":{"lch":[66.4950261675888,93.8462134827344,243.161780722675303],"luv":[66.4950261675888,-42.369016683119284,-83.7375555551541],"rgb":[0,0.66666666666666663,1],"xyz":[0.324221747250120484,0.359674233057318,0.998445805199088876],"hpluv":[243.161780722675303,179.088178632175044,66.4950261675888],"hsluv":[243.161780722675303,99.9999999999982805,66.4950261675888]},"#00bb00":{"lch":[66.1662429166961772,102.406451239047826,127.71501294924046],"luv":[66.1662429166961772,-62.6455428450044352,81.0099822060849135],"rgb":[0,0.733333333333333282,0],"xyz":[0.177695456756889275,0.355390913513783546,0.0592318189189614333],"hpluv":[127.71501294924046,196.39488290021464,66.1662429166961772],"hsluv":[127.71501294924046,100.000000000002373,66.1662429166961772]},"#00bb11":{"lch":[66.1974173108447559,101.237205455569821,128.123527834983577],"luv":[66.1974173108447559,-62.4996967519340956,79.6414444518024425],"rgb":[0,0.733333333333333282,0.0666666666666666657],"xyz":[0.178707122256526407,0.355795579713638399,0.064559923883717063],"hpluv":[128.123527834983577,194.061073356438868,66.1974173108447559],"hsluv":[128.123527834983577,99.9999999999909335,66.1974173108447559]},"#00bb22":{"lch":[66.2551438620851911,99.1062916374383747,128.898124119483072],"luv":[66.2551438620851911,-62.232564676438038,77.1308299962987718],"rgb":[0,0.733333333333333282,0.133333333333333331],"xyz":[0.180582480395003409,0.3565457229690292,0.0744368100796962556],"hpluv":[128.898124119483072,189.810813804630897,66.2551438620851911],"hsluv":[128.898124119483072,99.9999999999908624,66.2551438620851911]},"#00bb33":{"lch":[66.3500136661217255,95.7008075372637137,130.224174268563928],"luv":[66.3500136661217255,-61.8016571104716235,73.0698278476423155],"rgb":[0,0.733333333333333282,0.2],"xyz":[0.18367023112746117,0.357780823262012326,0.0906989639373074],"hpluv":[130.224174268563928,183.02647365261987,66.3500136661217255],"hsluv":[130.224174268563928,99.9999999999909335,66.3500136661217255]},"#00bb44":{"lch":[66.4865992404304,91.0092453899789859,132.255785626190885],"luv":[66.4865992404304,-61.1983980271068,67.3605138443080875],"rgb":[0,0.733333333333333282,0.266666666666666663],"xyz":[0.18812822637168003,0.359564021359699892,0.114177738890194044],"hpluv":[132.255785626190885,173.696361176634838,66.4865992404304],"hsluv":[132.255785626190885,99.9999999999909619,66.4865992404304]},"#00bb55":{"lch":[66.6685736373934219,85.1496193371524,135.204737263674588],"luv":[66.6685736373934219,-60.4246386982598,59.9943389949978751],"rgb":[0,0.733333333333333282,0.333333333333333315],"xyz":[0.194090640411042015,0.361948986975444753,0.145579786164167946],"hpluv":[135.204737263674588,162.069343805127659,66.6685736373934219],"hsluv":[135.204737263674588,99.9999999999909477,66.6685736373934219]},"#00bb66":{"lch":[66.8989180170192412,78.3861452968700689,139.371990675590268],"luv":[66.8989180170192412,-59.4914065933894,51.0407711152765629],"rgb":[0,0.733333333333333282,0.4],"xyz":[0.2016756361845502,0.364982985284848072,0.185527430571311908],"hpluv":[139.371990675590268,148.682392510907704,66.8989180170192412],"hsluv":[139.371990675590268,99.9999999999911182,66.8989180170192412]},"#00bb77":{"lch":[67.1800303821267448,71.1598447269708316,145.178146497089472],"luv":[67.1800303821267448,-58.4173559625633061,40.6341731047866617],"rgb":[0,0.733333333333333282,0.466666666666666674],"xyz":[0.210989649204752105,0.368708590492928867,0.234581232477709817],"hpluv":[145.178146497089472,134.410786503463328,67.1800303821267448],"hsluv":[145.178146497089472,99.9999999999910898,67.1800303821267448]},"#00bb88":{"lch":[67.5137905946342,64.1363411600919,153.159702568813543],"luv":[67.5137905946342,-57.2268359754185525,28.9578918715820954],"rgb":[0,0.733333333333333282,0.533333333333333326],"xyz":[0.222130066306695961,0.373164757333706465,0.293254095881282],"hpluv":[153.159702568813543,120.545503395456095,67.5137905946342],"hsluv":[153.159702568813543,99.9999999999911608,67.5137905946342]},"#00bb99":{"lch":[67.9016044714860811,58.2533417764790187,163.826150797364875],"luv":[67.9016044714860811,-55.9477282230567141,16.2266304205851419],"rgb":[0,0.733333333333333282,0.6],"xyz":[0.235187030415768661,0.378387542977335622,0.362020773522399919],"hpluv":[163.826150797364875,108.862958898475256,67.9016044714860811],"hsluv":[163.826150797364875,99.9999999999912461,67.9016044714860811]},"#00bbaa":{"lch":[68.3444379186728384,54.6744668749029543,177.202021912208522],"luv":[68.3444379186728384,-54.6092872876890922,2.66890801368250408],"rgb":[0,0.733333333333333282,0.66666666666666663],"xyz":[0.250244723381021217,0.384410620163436745,0.44132462313939852],"hpluv":[177.202021912208522,101.512776720033713,68.3444379186728384],"hsluv":[177.202021912208522,99.9999999999913598,68.3444379186728384]},"#00bbbb":{"lch":[68.8428468315880338,54.4656619866929645,192.177050630061132],"luv":[68.8428468315880338,-53.2402096652165113,-11.4886209116881091],"rgb":[0,0.733333333333333282,0.733333333333333282],"xyz":[0.267382315488357836,0.391265657006371503,0.531582608238040266],"hpluv":[192.177050630061132,100.392967527320806,68.8428468315880338],"hsluv":[192.177050630061132,99.9999999999914451,68.8428468315880338]},"#00bbcc":{"lch":[69.3970058395379397,58.0340346662075675,206.653495587531239],"luv":[69.3970058395379397,-51.8670935918889384,-26.0337047299998297],"rgb":[0,0.733333333333333282,0.8],"xyz":[0.28667469093207959,0.398982607183860305,0.633189118908310422],"hpluv":[206.653495587531239,106.116119046155191,69.3970058395379397],"hsluv":[206.653495587531239,99.9999999999915161,69.3970058395379397]},"#00bbdd":{"lch":[70.0067374807312461,64.9183055759271923,218.91244904401708],"luv":[70.0067374807312461,-50.5133677649133119,-40.7772740125682844],"rgb":[0,0.733333333333333282,0.866666666666666696],"xyz":[0.308193016482713134,0.407589937404113811,0.74651896680831642],"hpluv":[218.91244904401708,117.670246608059514,70.0067374807312461],"hsluv":[218.91244904401708,99.999999999991644,70.0067374807312461]},"#00bbee":{"lch":[70.6715424904064236,74.2108860535778,228.474155043258463],"luv":[70.6715424904064236,-49.1986871961444336,-55.5584807840624819],"rgb":[0,0.733333333333333282,0.933333333333333348],"xyz":[0.332005196748887843,0.417114809510583828,0.871929782876839643],"hpluv":[228.474155043258463,133.248513578578667,70.6715424904064236],"hsluv":[228.474155043258463,99.9999999999918288,70.6715424904064236]},"#00bbff":{"lch":[71.3906313155650167,85.0452269855302,235.688960914523477],"luv":[71.3906313155650167,-47.9387359102869155,-70.246481992653],"rgb":[0,0.733333333333333282,1],"xyz":[0.358176245158719264,0.427583228874516552,1.00976397116862149],"hpluv":[235.688960914523477,151.163886263776277,71.3906313155650167],"hsluv":[235.688960914523477,99.9999999999978,71.3906313155650167]},"#00cc00":{"lch":[71.6795694698327139,110.939506494120423,127.71501294924046],"luv":[71.6795694698327139,-67.8655057683618566,87.7601688009055181],"rgb":[0,0.8,0],"xyz":[0.215919200066506195,0.431838400133018441,0.0719730666888333814],"hpluv":[127.71501294924046,196.394882900214611,71.6795694698327139],"hsluv":[127.71501294924046,100.000000000002359,71.6795694698327139]},"#00cc11":{"lch":[71.7069484470386698,109.895339051400697,128.05073784188761],"luv":[71.7069484470386698,-67.7349868616780668,86.5387606802328548],"rgb":[0,0.8,0.0666666666666666657],"xyz":[0.216930865566143327,0.432243066332873294,0.0773011716535890181],"hpluv":[128.05073784188761,194.472124503698296,71.7069484470386698],"hsluv":[128.05073784188761,99.9999999999908766,71.7069484470386698]},"#00cc22":{"lch":[71.7576566073484,107.986601617430239,128.68476606632143],"luv":[71.7576566073484,-67.4954197535952289,84.2939763041676287],"rgb":[0,0.8,0.133333333333333331],"xyz":[0.218806223704620328,0.432993209588264094,0.0871780578495682107],"hpluv":[128.68476606632143,190.959361108477,71.7576566073484],"hsluv":[128.68476606632143,99.9999999999909193,71.7576566073484]},"#00cc33":{"lch":[71.8410194320707,104.91966800737103,129.762682813168567],"luv":[71.8410194320707,-67.1075822658835364,80.6517770244687853],"rgb":[0,0.8,0.2],"xyz":[0.22189397443707809,0.434228309881247221,0.103440211707179347],"hpluv":[129.762682813168567,185.320621425294917,71.8410194320707],"hsluv":[129.762682813168567,99.9999999999909761,71.8410194320707]},"#00cc44":{"lch":[71.9610975929873717,100.65733905537941,131.396818004218431],"luv":[71.9610975929873717,-66.561699323308261,75.5078809721416491],"rgb":[0,0.8,0.266666666666666663],"xyz":[0.226351969681296949,0.436011507978934787,0.126918986660065986],"hpluv":[131.396818004218431,177.495355343216744,71.9610975929873717],"hsluv":[131.396818004218431,99.9999999999909903,71.9610975929873717]},"#00cc55":{"lch":[72.1211872877728837,95.2615727691762828,133.734892870047815],"luv":[72.1211872877728837,-65.8564749898269639,68.8308938513177],"rgb":[0,0.8,0.333333333333333315],"xyz":[0.232314383720658935,0.438396473594679648,0.158321033934039901],"hpluv":[133.734892870047815,167.607792551030144,72.1211872877728837],"hsluv":[133.734892870047815,99.999999999991033,72.1211872877728837]},"#00cc66":{"lch":[72.3240060759138,88.9026050634798821,136.980115521422647],"luv":[72.3240060759138,-64.9982032665013207,60.6539921126355495],"rgb":[0,0.8,0.4],"xyz":[0.23989937949416712,0.441430471904082966,0.198268678341183863],"hpluv":[136.980115521422647,155.980870440536961,72.3240060759138],"hsluv":[136.980115521422647,99.9999999999910614,72.3240060759138]},"#00cc77":{"lch":[72.5717906268391459,81.8763194870781206,141.413175407098493],"luv":[72.5717906268391459,-63.9997644777707464,51.066249515114805],"rgb":[0,0.8,0.466666666666666674],"xyz":[0.249213392514369025,0.445156077112163762,0.247322480247581772],"hpluv":[141.413175407098493,143.162673336571032,72.5717906268391459],"hsluv":[141.413175407098493,99.9999999999910756,72.5717906268391459]},"#00cc88":{"lch":[72.8663546950801,74.6325704710961162,147.40707881161012],"luv":[72.8663546950801,-62.8793552775828672,40.2020802322297683],"rgb":[0,0.8,0.533333333333333326],"xyz":[0.260353809616312881,0.449612243952941359,0.305995343651153939],"hpluv":[147.40707881161012,129.969270924532168,72.8663546950801],"hsluv":[147.40707881161012,99.9999999999911608,72.8663546950801]},"#00cc99":{"lch":[73.2091273059676695,67.813783770663278,155.40051707617576],"luv":[73.2091273059676695,-61.6589956558222809,28.2290191825639418],"rgb":[0,0.8,0.6],"xyz":[0.273410773725385581,0.454835029596570517,0.374762021292271874],"hpluv":[155.40051707617576,117.541728748843539,73.2091273059676695],"hsluv":[155.40051707617576,99.9999999999911893,73.2091273059676695]},"#00ccaa":{"lch":[73.6011808048110368,62.2803364521242102,165.745935171574274],"luv":[73.6011808048110368,-60.3629393869259374,15.3347923742089414],"rgb":[0,0.8,0.66666666666666663],"xyz":[0.288468466690638137,0.460858106782671639,0.454065870909270419],"hpluv":[165.745935171574274,107.375573062224,73.6011808048110368],"hsluv":[165.745935171574274,99.9999999999912887,73.6011808048110368]},"#00ccbb":{"lch":[74.043253901593,59.041045922693165,178.335616576813749],"luv":[74.043253901593,-59.0161369965186395,1.7148404163965667],"rgb":[0,0.8,0.733333333333333282],"xyz":[0.305606058797974756,0.467713143625606398,0.544323856007912221],"hpluv":[178.335616576813749,101.183074845522739,74.043253901593],"hsluv":[178.335616576813749,99.9999999999913882,74.043253901593]},"#00cccc":{"lch":[74.5357725840108714,58.9696734274942429,192.177050630061132],"luv":[74.5357725840108714,-57.64288292201784,-12.4386668330598962],"rgb":[0,0.8,0.8],"xyz":[0.32489843424169651,0.4754300938030952,0.645930366678182377],"hpluv":[192.177050630061132,100.392967527320835,74.5357725840108714],"hsluv":[192.177050630061132,99.9999999999914877,74.5357725840108714]},"#00ccdd":{"lch":[75.0788705190671,62.3850861111967063,205.58971515357635],"luv":[75.0788705190671,-56.2657375800620656,-26.9456071312750254],"rgb":[0,0.8,0.866666666666666696],"xyz":[0.346416759792330053,0.484037424023348706,0.759260214578188375],"hpluv":[205.58971515357635,105.439266222061761,75.0788705190671],"hsluv":[205.58971515357635,99.9999999999915588,75.0788705190671]},"#00ccee":{"lch":[75.672409810316779,68.9113069897593,217.179575991302841],"luv":[75.672409810316779,-54.9047659259632326,-41.6441461630807765],"rgb":[0,0.8,0.933333333333333348],"xyz":[0.370228940058504818,0.493562296129818723,0.884671030646711598],"hpluv":[217.179575991302841,115.555933163518176,75.672409810316779],"hsluv":[217.179575991302841,99.9999999999916,75.672409810316779]},"#00ccff":{"lch":[76.3160024985922263,77.7871508482342193,226.46755023570978],"luv":[76.3160024985922263,-53.5770891110031471,-56.3944710009551713],"rgb":[0,0.8,1],"xyz":[0.396399988468336184,0.504030715493751447,1.02250521893849333],"hpluv":[226.46755023570978,131.600547876461974,76.3160024985922263],"hsluv":[226.46755023570978,99.9999999999969731,76.3160024985922263]},"#00dd00":{"lch":[77.1074905447145369,119.34037845513086,127.715012949240503],"luv":[77.1074905447145369,-73.004607631587163,94.4057900468603],"rgb":[0,0.866666666666666696,0],"xyz":[0.258553190613681372,0.51710638122737,0.0861843968712247],"hpluv":[127.715012949240503,210.385995725156505,77.1074905447145369],"hsluv":[127.715012949240503,100.000000000002203,77.1074905447145369]},"#00dd11":{"lch":[77.1317715771024268,118.40111864948102,127.995077421524911],"luv":[77.1317715771024268,-72.8869911141770359,93.3076171797906255],"rgb":[0,0.866666666666666696,0.0666666666666666657],"xyz":[0.259564856113318476,0.517511047427224868,0.0915125018359803366],"hpluv":[127.995077421524911,208.997725019578468,77.1317715771024268],"hsluv":[127.995077421524911,99.9999999999909193,77.1317715771024268]},"#00dd22":{"lch":[77.1767486793617081,116.680170458435171,128.522366120948305],"luv":[77.1767486793617081,-72.6707542705971434,91.2864921658838568],"rgb":[0,0.866666666666666696,0.133333333333333331],"xyz":[0.261440214251795533,0.518261190682615669,0.101389388031959529],"hpluv":[128.522366120948305,206.449864525990506,77.1767486793617081],"hsluv":[128.522366120948305,99.9999999999909335,77.1767486793617081]},"#00dd33":{"lch":[77.2507083817471312,113.903613467858165,129.414072915332611],"luv":[77.2507083817471312,-72.3197155087496668,87.9993858488157485],"rgb":[0,0.866666666666666696,0.2],"xyz":[0.264527964984253239,0.519496290975598796,0.117651541889570666],"hpluv":[129.414072915332611,202.327676795977681,77.2507083817471312],"hsluv":[129.414072915332611,99.9999999999909335,77.2507083817471312]},"#00dd44":{"lch":[77.3572825066044,110.019432359123073,130.755032484191332],"luv":[77.3572825066044,-71.8235777962907633,83.3405613681826907],"rgb":[0,0.866666666666666696,0.266666666666666663],"xyz":[0.268985960228472154,0.521279489073286362,0.141130316842457304],"hpluv":[130.755032484191332,196.537344059934071,77.3572825066044],"hsluv":[130.755032484191332,99.9999999999909193,77.3572825066044]},"#00dd55":{"lch":[77.499442461574418,105.05363654061,132.652443872197409],"luv":[77.499442461574418,-71.1790335676869717,77.2645567564888],"rgb":[0,0.866666666666666696,0.333333333333333315],"xyz":[0.274948374267834139,0.523664454689031111,0.172532364116431219],"hpluv":[132.652443872197409,189.094972829508237,77.499442461574418],"hsluv":[132.652443872197409,99.9999999999909477,77.499442461574418]},"#00dd66":{"lch":[77.6796666807438,99.1151742217995,135.249123061333165],"luv":[77.6796666807438,-70.3890792332532413,69.7796194150732276],"rgb":[0,0.866666666666666696,0.4],"xyz":[0.282533370041342324,0.52669845299843443,0.212480008523575181],"hpluv":[135.249123061333165,180.139247328423863,77.6796666807438],"hsluv":[135.249123061333165,99.9999999999909903,77.6796666807438]},"#00dd77":{"lch":[77.9000291762011301,92.4061998396230138,138.73841210181584],"luv":[77.9000291762011301,-69.4623356452591878,60.9416909472136155],"rgb":[0,0.866666666666666696,0.466666666666666674],"xyz":[0.29184738306154423,0.530424058206515281,0.26153381042997309],"hpluv":[138.73841210181584,169.957910917592017,77.9000291762011301],"hsluv":[138.73841210181584,99.9999999999910187,77.9000291762011301]},"#00dd88":{"lch":[78.1622519856154,85.2389230174627386,143.3784757437721],"luv":[78.1622519856154,-68.4122000424903,50.8472701580255091],"rgb":[0,0.866666666666666696,0.533333333333333326],"xyz":[0.30298780016348803,0.534880225047292823,0.320206673833545286],"hpluv":[143.3784757437721,159.033158409305884,78.1622519856154],"hsluv":[143.3784757437721,99.9999999999911608,78.1622519856154]},"#00dd99":{"lch":[78.4677391993035798,78.0607504013048583,149.494791226300919],"luv":[78.4677391993035798,-67.2558167964087801,39.6249398770864545],"rgb":[0,0.866666666666666696,0.6],"xyz":[0.316044764272560785,0.540103010690922,0.388973351474663165],"hpluv":[149.494791226300919,148.113090063328627,78.4677391993035798],"hsluv":[149.494791226300919,99.9999999999911466,78.4677391993035798]},"#00ddaa":{"lch":[78.8176011215583401,71.4835041270533225,157.438879868811341],"luv":[78.8176011215583401,-66.0129273361177,27.4259874352573583],"rgb":[0,0.866666666666666696,0.66666666666666663],"xyz":[0.331102457237813286,0.546126087877023103,0.468277201091661766],"hpluv":[157.438879868811341,138.307036304413771,78.8176011215583401],"hsluv":[157.438879868811341,99.9999999999912319,78.8176011215583401]},"#00ddbb":{"lch":[79.21267314937,66.2909050184163675,167.440816272526462],"luv":[79.21267314937,-64.7046905962200896,14.4148223370296193],"rgb":[0,0.866666666666666696,0.733333333333333282],"xyz":[0.34824004934514996,0.552981124719957862,0.558535186190303512],"hpluv":[167.440816272526462,131.160951364069831,79.21267314937],"hsluv":[167.440816272526462,99.9999999999912319,79.21267314937]},"#00ddcc":{"lch":[79.6535319864315738,63.3571261830985,179.312753048293331],"luv":[79.6535319864315738,-63.3525685364998381,0.759932897798095253],"rgb":[0,0.866666666666666696,0.8],"xyz":[0.367532424788871714,0.560698074897446719,0.660141696860573668],"hpluv":[179.312753048293331,128.577362979680402,79.6535319864315738],"hsluv":[179.312753048293331,99.9999999999913314,79.6535319864315738]},"#00dddd":{"lch":[80.1405107346531338,63.4039144225475795,192.177050630061245],"luv":[80.1405107346531338,-61.9773555359817649,-13.3739958452306631],"rgb":[0,0.866666666666666696,0.866666666666666696],"xyz":[0.389050750339505202,0.569305405117700225,0.773471544760579666],"hpluv":[192.177050630061245,132.399857962191078,80.1405107346531338],"hsluv":[192.177050630061245,99.9999999999915,80.1405107346531338]},"#00ddee":{"lch":[80.6737137665329,66.6843941199945078,204.668960845135786],"luv":[80.6737137665329,-60.59840405426975,-27.8323884211582282],"rgb":[0,0.866666666666666696,0.933333333333333348],"xyz":[0.412862930605679967,0.578830277224170242,0.898882360829102889],"hpluv":[204.668960845135786,143.769811077134563,80.6737137665329],"hsluv":[204.668960845135786,99.9999999999914735,80.6737137665329]},"#00ddff":{"lch":[81.2530318771427,72.8883394631876627,215.643856178856652],"luv":[81.2530318771427,-59.2330695533496296,-42.475328144570291],"rgb":[0,0.866666666666666696,1],"xyz":[0.439033979015511333,0.589298696588103,1.03671654912088473],"hpluv":[215.643856178856652,162.831862460855405,81.2530318771427],"hsluv":[215.643856178856652,99.9999999999960636,81.2530318771427]},"#00ee00":{"lch":[82.4573791946470749,127.620478503329409,127.715012949240503],"luv":[82.4573791946470749,-78.0698291684561241,100.955873068518613],"rgb":[0,0.933333333333333348,0],"xyz":[0.305731966954196188,0.611463933908400925,0.101910655651395884],"hpluv":[127.715012949240503,307.908475174189959,82.4573791946470749],"hsluv":[127.715012949240503,100.000000000002217,82.4573791946470749]},"#00ee11":{"lch":[82.4790940690076582,126.770138643430457,127.951660682688043],"luv":[82.4790940690076582,-77.963182339567652,99.9620440525398],"rgb":[0,0.933333333333333348,0.0666666666666666657],"xyz":[0.306743632453833293,0.611868600108255833,0.107238760616151521],"hpluv":[127.951660682688043,306.293921948395678,82.4790940690076582],"hsluv":[127.951660682688043,99.9999999999909193,82.4790940690076582]},"#00ee22":{"lch":[82.5193223464761729,125.209295581045268,128.396138884075839],"luv":[82.5193223464761729,-77.7668632323815814,98.1309466116455],"rgb":[0,0.933333333333333348,0.133333333333333331],"xyz":[0.308618990592310349,0.612618743363646634,0.117115646812130714],"hpluv":[128.396138884075839,303.325246698320768,82.5193223464761729],"hsluv":[128.396138884075839,99.9999999999907914,82.5193223464761729]},"#00ee33":{"lch":[82.5854861516441616,122.683025615083068,129.144698003447559],"luv":[82.5854861516441616,-77.4474668310457304,95.1473313105795881],"rgb":[0,0.933333333333333348,0.2],"xyz":[0.311706741324768055,0.613853843656629761,0.133377800669741864],"hpluv":[129.144698003447559,298.506449004286878,82.5854861516441616],"hsluv":[129.144698003447559,99.9999999999910187,82.5854861516441616]},"#00ee44":{"lch":[82.680854944152216,119.131104912681948,130.263308305441626],"luv":[82.680854944152216,-76.994580956063885,90.9068460629701889],"rgb":[0,0.933333333333333348,0.266666666666666663],"xyz":[0.31616473656898697,0.615637041754317327,0.156856575622628502],"hpluv":[130.263308305441626,291.702339981024693,82.680854944152216],"hsluv":[130.263308305441626,99.9999999999908624,82.680854944152216]},"#00ee55":{"lch":[82.8081199656530913,114.556122924925475,131.832385242542614],"luv":[82.8081199656530913,-76.4036333062175572,85.3556683366704192],"rgb":[0,0.933333333333333348,0.333333333333333315],"xyz":[0.322127150608348956,0.618022007370062076,0.18825862289660239],"hpluv":[131.832385242542614,282.889526663711365,82.8081199656530913],"hsluv":[131.832385242542614,99.9999999999908908,82.8081199656530913]},"#00ee66":{"lch":[82.9695459516691756,109.025909834785097,133.955863991345211],"luv":[82.9695459516691756,-75.6753248662734137,78.4849936082476347],"rgb":[0,0.933333333333333348,0.4],"xyz":[0.329712146381857141,0.621056005679465395,0.22820626730374638],"hpluv":[133.955863991345211,272.166364406401044,82.9695459516691756],"hsluv":[133.955863991345211,99.9999999999909193,82.9695459516691756]},"#00ee77":{"lch":[83.167051813506589,102.679799146220446,136.771308753659213],"luv":[83.167051813506589,-74.8151450958190338,70.3266323450776127],"rgb":[0,0.933333333333333348,0.466666666666666674],"xyz":[0.339026159402059046,0.624781610887546246,0.277260069210144289],"hpluv":[136.771308753659213,259.776444306911685,83.167051813506589],"hsluv":[136.771308753659213,99.9999999999910898,83.167051813506589]},"#00ee88":{"lch":[83.4022585136551839,95.7389522528198427,140.46074817536558],"luv":[83.4022585136551839,-73.8327925713246742,60.9480575538504],"rgb":[0,0.933333333333333348,0.533333333333333326],"xyz":[0.350166576504002847,0.629237777728323788,0.335932932613716428],"hpluv":[140.46074817536558,246.149488794882956,83.4022585136551839],"hsluv":[140.46074817536558,99.999999999991033,83.4022585136551839]},"#00ee99":{"lch":[83.6765199188301096,88.5221307628359142,145.258543938418427],"luv":[83.6765199188301096,-72.7414610621927,50.4464813176313],"rgb":[0,0.933333333333333348,0.6],"xyz":[0.363223540613075602,0.634460563371953,0.404699610254834363],"hpluv":[145.258543938418427,231.96752956627526,83.6765199188301096],"hsluv":[145.258543938418427,99.9999999999911,83.6765199188301096]},"#00eeaa":{"lch":[83.9909442670452364,81.4671227341597159,151.444498676017645],"luv":[83.9909442670452364,-71.557012704351564,38.9420854527837363],"rgb":[0,0.933333333333333348,0.66666666666666663],"xyz":[0.378281233578328102,0.640483640558054068,0.484003459871832964],"hpluv":[151.444498676017645,218.263507316576721,83.9909442670452364],"hsluv":[151.444498676017645,99.9999999999911893,83.9909442670452364]},"#00eebb":{"lch":[84.3464103530465366,75.1511025294100392,159.294479220170871],"luv":[84.3464103530465366,-70.2970903476626319,26.5707978811035801],"rgb":[0,0.933333333333333348,0.733333333333333282],"xyz":[0.395418825685664777,0.647338677400988827,0.57426144497047471],"hpluv":[159.294479220170871,206.543608310772072,84.3464103530465366],"hsluv":[159.294479220170871,99.9999999999912,84.3464103530465366]},"#00eecc":{"lch":[84.743580800257746,70.2844566194431195,168.945018717488722],"luv":[84.743580800257746,-68.9802322625990456,13.4771064879770393],"rgb":[0,0.933333333333333348,0.8],"xyz":[0.414711201129386531,0.655055627578477684,0.675867955640744866],"hpluv":[168.945018717488722,198.871854707918374,84.743580800257746],"hsluv":[168.945018717488722,99.9999999999913,84.743580800257746]},"#00eedd":{"lch":[85.1829138464002114,67.6253239558150625,180.163192871920216],"luv":[85.1829138464002114,-67.6250496492668418,-0.192613766721418916],"rgb":[0,0.933333333333333348,0.866666666666666696],"xyz":[0.43622952668002,0.66366295779873119,0.789197803540750864],"hpluv":[180.163192871920216,197.760624486431198,85.1829138464002114],"hsluv":[180.163192871920216,99.9999999999913882,85.1829138464002114]},"#00eeee":{"lch":[85.6646745174910507,67.7744082531008303,192.177050630061217],"luv":[85.6646745174910507,-66.2495152673009358,-14.2958784586901881],"rgb":[0,0.933333333333333348,0.933333333333333348],"xyz":[0.460041706946194784,0.673187829905201207,0.914608619609274087],"hpluv":[192.177050630061217,205.696714727687493,85.6646745174910507],"hsluv":[192.177050630061217,99.9999999999914309,85.6646745174910507]},"#00eeff":{"lch":[86.1889457184888,70.9350767712842867,203.864647638418489],"luv":[86.1889457184888,-64.8703943995767247,-28.6987290135183635],"rgb":[0,0.933333333333333348,1],"xyz":[0.486212755356026149,0.683656249269133931,1.05244280790105593],"hpluv":[203.864647638418489,224.453619733699583,86.1889457184888],"hsluv":[203.864647638418489,99.9999999999939888,86.1889457184888]},"#00ff00":{"lch":[87.7355191096597338,135.789531996666284,127.715012949240474],"luv":[87.7355191096597338,-83.0671197143942663,107.418111239344327],"rgb":[0,1,0],"xyz":[0.35758433938387,0.71516867876775,0.11919477979462],"hpluv":[127.715012949240474,490.145375063702204,87.7355191096597338],"hsluv":[127.715012949240474,100.000000000002217,87.7355191096597338]},"#00ff11":{"lch":[87.7550810882892165,135.01527678270574,127.917210072153054],"luv":[87.7550810882892165,-82.9698837721702915,106.513489059100834],"rgb":[0,1,0.0666666666666666657],"xyz":[0.358596004883507125,0.715573344967604941,0.124522884759375632],"hpluv":[127.917210072153054,488.208403570135204,87.7550810882892165],"hsluv":[127.917210072153054,99.9999999999917719,87.7550810882892165]},"#00ff22":{"lch":[87.7913242833811864,133.592052176160422,128.296258949772664],"luv":[87.7913242833811864,-82.7907071985999892,104.845291769319132],"rgb":[0,1,0.133333333333333331],"xyz":[0.360471363021984181,0.716323488222995741,0.134399770955354825],"hpluv":[128.296258949772664,484.641757887342919,87.7913242833811864],"hsluv":[128.296258949772664,99.9999999999919,87.7913242833811864]},"#00ff33":{"lch":[87.850943105558116,131.282721750620482,128.932531697131338],"luv":[87.850943105558116,-82.4986966230128616,102.123053644879462],"rgb":[0,1,0.2],"xyz":[0.363559113754441887,0.717558588515978868,0.150661924812965975],"hpluv":[128.932531697131338,478.837727878060548,87.850943105558116],"hsluv":[128.932531697131338,99.999999999991843,87.850943105558116]},"#00ff44":{"lch":[87.9368982766027756,128.022939247233296,129.878593634905172],"luv":[87.9368982766027756,-82.0835673214571528,98.245411848516369],"rgb":[0,1,0.266666666666666663],"xyz":[0.368017108998660802,0.719341786613666434,0.174140699765852613],"hpluv":[129.878593634905172,470.610169071279643,87.9368982766027756],"hsluv":[129.878593634905172,99.9999999999916724,87.9368982766027756]},"#00ff55":{"lch":[88.0516385770734189,123.799916713223595,131.196479790431113],"luv":[88.0516385770734189,-81.5399771501718362,93.1539129857171133],"rgb":[0,1,0.333333333333333315],"xyz":[0.373979523038022788,0.721726752229411184,0.205542747039826501],"hpluv":[131.196479790431113,459.892953467552729,88.0516385770734189],"hsluv":[131.196479790431113,99.9999999999917719,88.0516385770734189]},"#00ff66":{"lch":[88.197238997611,118.653311588493224,132.964137709394919],"luv":[88.197238997611,-80.8670327043222557,86.8281715373192498],"rgb":[0,1,0.4],"xyz":[0.381564518811531,0.724760750538814502,0.245490391446970491],"hpluv":[132.964137709394919,446.748834194207859,88.197238997611],"hsluv":[132.964137709394919,99.9999999999917719,88.197238997611]},"#00ff77":{"lch":[88.3754745956423164,112.679107800887323,135.2824164931273],"luv":[88.3754745956423164,-80.0679233099649537,79.2824633297525452],"rgb":[0,1,0.466666666666666674],"xyz":[0.390878531831732878,0.728486355746895353,0.2945441933533684],"hpluv":[135.2824164931273,431.3936933951166,88.3754745956423164],"hsluv":[135.2824164931273,99.9999999999915445,88.3754745956423164]},"#00ff88":{"lch":[88.587864465470858,106.036155512425779,138.2828406903445],"luv":[88.587864465470858,-79.1495135423216425,70.5621767086956311],"rgb":[0,1,0.533333333333333326],"xyz":[0.402018948933676679,0.732942522587672896,0.353217056756940539],"hpluv":[138.2828406903445,414.239888157084465,88.587864465470858],"hsluv":[138.2828406903445,99.9999999999914,88.587864465470858]},"#00ff99":{"lch":[88.8357000190422,98.9561663203651278,142.1349886621461],"luv":[88.8357000190422,-78.1218422027535695,60.739613298668921],"rgb":[0,1,0.6],"xyz":[0.415075913042749378,0.738165308231302109,0.421983734398058474],"hpluv":[142.1349886621461,395.967958147281365,88.8357000190422],"hsluv":[142.1349886621461,99.9999999999915303,88.8357000190422]},"#00ffaa":{"lch":[89.1200644426462674,91.7580340339716258,147.049061977519528],"luv":[89.1200644426462674,-76.997527549554917,49.9090929694682828],"rgb":[0,1,0.66666666666666663],"xyz":[0.430133606008001934,0.744188385417403175,0.501287584015057],"hpluv":[147.049061977519528,377.639750156066668,89.1200644426462674],"hsluv":[147.049061977519528,99.9999999999913,89.1200644426462674]},"#00ffbb":{"lch":[89.4418470234824241,84.8653215767476468,153.262243037154207],"luv":[89.4418470234824241,-75.791105608661141,38.1815546689964407],"rgb":[0,1,0.733333333333333282],"xyz":[0.447271198115338608,0.751043422260337934,0.591545569113698821],"hpluv":[153.262243037154207,360.863433446149145,89.4418470234824241],"hsluv":[153.262243037154207,99.9999999999912,89.4418470234824241]},"#00ffcc":{"lch":[89.801754487955634,78.8187300060100569,160.986090443114392],"luv":[89.801754487955634,-74.5183415032407197,25.6789598575702236],"rgb":[0,1,0.8],"xyz":[0.466563573559060307,0.758760372437826791,0.693152079783969],"hpluv":[160.986090443114392,347.997153451554084,89.801754487955634],"hsluv":[160.986090443114392,99.9999999999912461,89.801754487955634]},"#00ffdd":{"lch":[90.2003206582774339,74.260092310928,170.286849800478649],"luv":[90.2003206582774339,-73.1955569867131572,12.5288366352336915],"rgb":[0,1,0.866666666666666696],"xyz":[0.488081899109693906,0.767367702658080297,0.806481927683975],"hpluv":[170.286849800478649,342.308208972166483,90.2003206582774339],"hsluv":[170.286849800478649,99.9999999999913314,90.2003206582774339]},"#00ffee":{"lch":[90.6379152481429458,71.8480695265374294,180.909719109957],"luv":[90.6379152481429458,-71.8390133400929898,-1.14072652818200426],"rgb":[0,1,0.933333333333333348],"xyz":[0.511894079375868616,0.776892574764550314,0.931892743752498198],"hpluv":[180.909719109957,347.895283980605143,90.6379152481429458],"hsluv":[180.909719109957,99.999999999991374,90.6379152481429458]},"#00ffff":{"lch":[91.114752316705065,72.0862882649682,192.17705063006116],"luv":[91.114752316705065,-70.4643799638718207,-15.205397466925735],"rgb":[0,1,1],"xyz":[0.5380651277857,0.787360994128483,1.06972693204428],"hpluv":[192.17705063006116,369.190533917051368,91.114752316705065],"hsluv":[192.17705063006116,99.9999999999914877,91.114752316705065]},"#ff0000":{"lch":[53.23711559542933,179.038096923620287,12.1770506300617765],"luv":[53.23711559542933,175.009822162883836,37.7650936255616],"rgb":[1,0,0],"xyz":[0.41239079926595,0.21263900587151,0.019330818715591],"hpluv":[12.1770506300617765,426.746789183125202,53.23711559542933],"hsluv":[12.1770506300617765,100.000000000002203,53.23711559542933]},"#ff0011":{"lch":[53.2810087118185294,177.689248384364731,11.7592124156573554],"luv":[53.2810087118185294,173.960033822228979,36.2129206771479346],"rgb":[1,0,0.0666666666666666657],"xyz":[0.413402464765587119,0.213043672071364848,0.0246589236803466325],"hpluv":[11.7592124156573554,423.182830024727082,53.2810087118185294],"hsluv":[11.7592124156573554,99.9999999999986073,53.2810087118185294]},"#ff0022":{"lch":[53.362228057366309,175.255817292919801,10.9800713678561319],"luv":[53.362228057366309,172.047495148921342,33.3805468497921751],"rgb":[1,0,0.133333333333333331],"xyz":[0.415277822904064176,0.213793815326755676,0.0345358098763258251],"hpluv":[10.9800713678561319,416.75211680728853,53.362228057366309],"hsluv":[10.9800713678561319,99.9999999999986215,53.362228057366309]},"#ff0033":{"lch":[53.4955416476677499,171.43316235878109,9.68478250033725],"luv":[53.4955416476677499,168.989928530586468,28.8397852204116347],"rgb":[1,0,0.2],"xyz":[0.418365573636521881,0.215028915619738775,0.0507979637339369683],"hpluv":[9.68478250033725,406.646064741178918,53.4955416476677499],"hsluv":[9.68478250033725,99.9999999999986215,53.4955416476677499]},"#ff0044":{"lch":[53.6871179383659722,166.29954793496961,7.78930386328567259],"luv":[53.6871179383659722,164.765128442936401,22.5386799204815809],"rgb":[1,0,0.266666666666666663],"xyz":[0.422823568880740797,0.216812113717426369,0.0742767386868236],"hpluv":[7.78930386328567259,393.061316669856922,53.6871179383659722],"hsluv":[7.78930386328567259,99.9999999999987637,53.6871179383659722]},"#ff0055":{"lch":[53.9417095924386558,160.100368719231,5.2128969892355661],"luv":[53.9417095924386558,159.438189183864722,14.5461986032050437],"rgb":[1,0,0.333333333333333315],"xyz":[0.428785982920102782,0.219197079333171202,0.105678785960797522],"hpluv":[5.2128969892355661,376.623098544524225,53.9417095924386558],"hsluv":[5.2128969892355661,99.9999999999988,53.9417095924386558]},"#ff0066":{"lch":[54.2629295430466669,153.227313284557312,1.88082466234467849],"luv":[54.2629295430466669,153.144763004983872,5.02902580538230204],"rgb":[1,0,0.4],"xyz":[0.436370978693610967,0.222231077642574493,0.145626430367941484],"hpluv":[1.88082466234467849,358.321012364802243,54.2629295430466669],"hsluv":[1.88082466234467849,99.99999999999892,54.2629295430466669]},"#ff0077":{"lch":[54.6533978532017244,146.184101175375929,357.735148851436577],"luv":[54.6533978532017244,146.06990602550718,-5.77702260269427281],"rgb":[1,0,0.466666666666666674],"xyz":[0.445684991713812872,0.225956682850655316,0.194680232274339393],"hpluv":[357.735148851436577,339.408176675868503,54.6533978532017244],"hsluv":[357.735148851436577,99.9999999999990479,54.6533978532017244]},"#ff0088":{"lch":[55.1148373309560782,139.538803635294983,352.754628092234327],"luv":[55.1148373309560782,138.424605854630585,-17.5984719211521572],"rgb":[1,0,0.533333333333333326],"xyz":[0.456825408815756673,0.230412849691432914,0.253353095677911533],"hpluv":[352.754628092234327,321.26675874055752,55.1148373309560782],"hsluv":[352.754628092234327,99.9999999999991616,55.1148373309560782]},"#ff0099":{"lch":[55.6481496721619493,133.863929319774144,346.981903482220218],"luv":[55.6481496721619493,130.423488026195145,-30.1540269949209758],"rgb":[1,0,0.6],"xyz":[0.469882372924829372,0.235635635335062071,0.322119773319029468],"hpluv":[346.981903482220218,305.247535929832054,55.6481496721619493],"hsluv":[346.981903482220218,99.9999999999993463,55.6481496721619493]},"#ff00aa":{"lch":[56.2534865150640258,129.667114810270476,340.549180922221581],"luv":[56.2534865150640258,122.266710865918853,-43.1788383036143273],"rgb":[1,0,0.66666666666666663],"xyz":[0.484940065890081928,0.241658712521163166,0.401423622936028068],"hpluv":[340.549180922221581,292.495864077812769,56.2534865150640258],"hsluv":[340.549180922221581,99.9999999999994742,56.2534865150640258]},"#ff00bb":{"lch":[56.9303217870161689,127.321325924901956,333.685619315648239],"luv":[56.9303217870161689,114.127678427447606,-56.4410582115202928],"rgb":[1,0,0.733333333333333282],"xyz":[0.502077657997418547,0.248513749364097924,0.491681608034669815],"hpluv":[333.685619315648239,283.789838362024682,56.9303217870161689],"hsluv":[333.685619315648239,99.9999999999995879,56.9303217870161689]},"#ff00cc":{"lch":[57.6775275187384153,127.012826563172382,326.690520651062286],"luv":[57.6775275187384153,106.146716951325558,-69.7505024499586312],"rgb":[1,0,0.8],"xyz":[0.521370033441140301,0.256230699541586726,0.593288118704939915],"hpluv":[326.690520651062286,279.434659423159303,57.6775275187384153],"hsluv":[326.690520651062286,99.9999999999997726,57.6775275187384153]},"#ff00dd":{"lch":[58.4934529509690151,128.727977043064641,319.874434183361473],"luv":[58.4934529509690151,98.4297766537384149,-82.9606602040687],"rgb":[1,0,0.866666666666666696],"xyz":[0.542888358991773901,0.264838029761840288,0.706617966604945913],"hpluv":[319.874434183361473,279.257606739571429,58.4934529509690151],"hsluv":[319.874434183361473,99.9999999999999716,58.4934529509690151]},"#ff00ee":{"lch":[59.3760054748790367,132.286429048213932,313.494468670954461],"luv":[59.3760054748790367,91.0507046157626,-95.9659757377649214],"rgb":[1,0,0.933333333333333348],"xyz":[0.56670053925794861,0.274362901868310305,0.832028782673469136],"hpluv":[313.494468670954461,282.711609251625362,59.3760054748790367],"hsluv":[313.494468670954461,100.000000000000156,59.3760054748790367]},"#ff00ff":{"lch":[60.3227313545512942,137.405400537897037,307.715012949243601],"luv":[60.3227313545512942,84.0556019897527875,-108.696365491768773],"rgb":[1,0,1],"xyz":[0.59287158766778,0.284831321232243,0.969862970965251],"hpluv":[307.715012949243601,289.042783730483336,60.3227313545512942],"hsluv":[307.715012949243601,100.000000000000384,60.3227313545512942]},"#ff1100":{"lch":[53.6695097624616864,176.771562285449363,12.5954542867932275],"luv":[53.6695097624616864,172.517389506501019,38.5478345786208934],"rgb":[1,0.0666666666666666657,0],"xyz":[0.414395199526878422,0.216647806393366865,0.019998952135900451],"hpluv":[12.5954542867932275,417.949777534481484,53.6695097624616864],"hsluv":[12.5954542867932275,100.000000000002245,53.6695097624616864]},"#ff1111":{"lch":[53.7128602445647658,175.445128796306847,12.1770506300617765],"luv":[53.7128602445647658,171.497694164414924,37.0072170615611569],"rgb":[1,0.0666666666666666657,0.0666666666666666657],"xyz":[0.415406865026515526,0.217052472593221718,0.0253270571006560807],"hpluv":[12.1770506300617765,414.478837946685644,53.7128602445647658],"hsluv":[12.1770506300617765,99.9999999999986215,53.7128602445647658]},"#ff1122":{"lch":[53.7930781791116743,173.051572118951754,11.3967197916969329],"luv":[53.7930781791116743,169.639425839354459,34.1952016185739538],"rgb":[1,0.0666666666666666657,0.133333333333333331],"xyz":[0.417282223164992583,0.217802615848612546,0.0352039432966352803],"hpluv":[11.3967197916969329,408.214548988049671,53.7930781791116743],"hsluv":[11.3967197916969329,99.9999999999987,53.7930781791116743]},"#ff1133":{"lch":[53.9247555399676912,169.290109899416,10.0990648343251674],"luv":[53.9247555399676912,166.667136068812482,29.6851320424264138],"rgb":[1,0.0666666666666666657,0.2],"xyz":[0.420369973897450289,0.219037716141595645,0.0514660971542464235],"hpluv":[10.0990648343251674,398.366425235699353,53.9247555399676912],"hsluv":[10.0990648343251674,99.9999999999987,53.9247555399676912]},"#ff1144":{"lch":[54.1139966850166445,164.235972949617775,8.19925898659400154],"luv":[54.1139966850166445,162.55716522781,23.4226993279181244],"rgb":[1,0.0666666666666666657,0.266666666666666663],"xyz":[0.424827969141669204,0.220820914239283239,0.074944872107133062],"hpluv":[8.19925898659400154,385.121711929848118,54.1139966850166445],"hsluv":[8.19925898659400154,99.9999999999988489,54.1139966850166445]},"#ff1155":{"lch":[54.365514290002,158.12888296709221,5.61535385404219856],"luv":[54.365514290002,157.370056367003059,15.4728467796533362],"rgb":[1,0.0666666666666666657,0.333333333333333315],"xyz":[0.430790383181031189,0.223205879855028072,0.106346919381106964],"hpluv":[5.61535385404219856,369.085538340858477,54.365514290002],"hsluv":[5.61535385404219856,99.9999999999988916,54.365514290002]},"#ff1166":{"lch":[54.6829025612910442,151.353597545298243,2.27091305216541839],"luv":[54.6829025612910442,151.234730451097789,5.99731567352495443],"rgb":[1,0.0666666666666666657,0.4],"xyz":[0.438375378954539374,0.226239878164431363,0.146294563788250925],"hpluv":[2.27091305216541839,351.221033033747858,54.6829025612910442],"hsluv":[2.27091305216541839,99.999999999999,54.6829025612910442]},"#ff1177":{"lch":[55.0687823252034292,144.407362773795285,358.105880212246802],"luv":[55.0687823252034292,144.328460520523464,-4.77303960367160496],"rgb":[1,0.0666666666666666657,0.466666666666666674],"xyz":[0.44768939197474128,0.229965483372512186,0.195348365694648834],"hpluv":[358.105880212246802,332.753927221166919,55.0687823252034292],"hsluv":[358.105880212246802,99.9999999999990905,55.0687823252034292]},"#ff1188":{"lch":[55.5248949860500716,137.85386672349216,353.096828842063303],"luv":[55.5248949860500716,136.85452147125136,-16.5689023019976744],"rgb":[1,0.0666666666666666657,0.533333333333333326],"xyz":[0.45882980907668508,0.234421650213289784,0.254021229098221],"hpluv":[353.096828842063303,315.043506786171235,55.5248949860500716],"hsluv":[353.096828842063303,99.9999999999992,55.5248949860500716]},"#ff1199":{"lch":[56.0521767726019249,132.264360312052816,347.28491936957397],"luv":[56.0521767726019249,129.020794472918823,-29.1117777254046715],"rgb":[1,0.0666666666666666657,0.6],"xyz":[0.47188677318575778,0.239644435856918941,0.322787906739338937],"hpluv":[347.28491936957397,299.426117704125659,56.0521767726019249],"hsluv":[347.28491936957397,99.9999999999993605,56.0521767726019249]},"#ff11aa":{"lch":[56.6508275614924912,128.148315107741439,340.802676353967],"luv":[56.6508275614924912,121.022209124101792,-42.1380536294115586],"rgb":[1,0.0666666666666666657,0.66666666666666663],"xyz":[0.486944466151010336,0.245667513043020036,0.402091756356337537],"hpluv":[340.802676353967,287.042344439162662,56.6508275614924912],"hsluv":[340.802676353967,99.9999999999995168,56.6508275614924912]},"#ff11bb":{"lch":[57.3203806938084455,125.882364893771992,333.882217516525884],"luv":[57.3203806938084455,113.02864145467457,-55.4156656746030762],"rgb":[1,0.0666666666666666657,0.733333333333333282],"xyz":[0.504082058258347,0.252522549885954795,0.492349741454979284],"hpluv":[333.882217516525884,278.673167271969135,57.3203806938084455],"hsluv":[333.882217516525884,99.9999999999996163,57.3203806938084455]},"#ff11cc":{"lch":[58.0597760671947754,125.656277294901628,326.828156543045054],"luv":[58.0597760671947754,105.178488239830273,-68.7530772780178694],"rgb":[1,0.0666666666666666657,0.8],"xyz":[0.523374433702068709,0.260239500063443596,0.593956252125249384],"hpluv":[326.828156543045054,274.630115267561905,58.0597760671947754],"hsluv":[326.828156543045054,99.9999999999997868,58.0597760671947754]},"#ff11dd":{"lch":[58.8674364673636177,127.458097444326981,319.957026901825429],"luv":[58.8674364673636177,97.5770916499376568,-82.0016938195011846],"rgb":[1,0.0666666666666666657,0.866666666666666696],"xyz":[0.544892759252702308,0.268846830283697158,0.707286100025255382],"hpluv":[319.957026901825429,274.746161939823423,58.8674364673636177],"hsluv":[319.957026901825429,100.000000000000028,58.8674364673636177]},"#ff11ee":{"lch":[59.7413458233107519,131.106916258937218,313.5305052972667],"luv":[59.7413458233107519,90.2986667085849319,-95.0535337669245877],"rgb":[1,0.0666666666666666657,0.933333333333333348],"xyz":[0.568704939518877,0.278371702390167175,0.832696916093778605],"hpluv":[313.5305052972667,278.477381794919836,59.7413458233107519],"hsluv":[313.5305052972667,100.000000000000199,59.7413458233107519]},"#ff11ff":{"lch":[60.6791274610807534,136.317870534400242,307.715012949243601],"luv":[60.6791274610807534,83.3903225409976,-107.83606045076894],"rgb":[1,0.0666666666666666657,1],"xyz":[0.594875987928708438,0.288840121754099899,0.97053110438556045],"hpluv":[307.715012949243601,285.070838096226908,60.6791274610807534],"hsluv":[307.715012949243601,100.000000000000398,60.6791274610807534]},"#ff2200":{"lch":[54.4571507543770679,172.725520469573979,13.3786813235288875],"luv":[54.4571507543770679,168.038102184023103,39.9662562154253393],"rgb":[1,0.133333333333333331,0],"xyz":[0.418110823261646336,0.224079053862902833,0.0212374933808230602],"hpluv":[13.3786813235288875,402.476865089738737,54.4571507543770679],"hsluv":[13.3786813235288875,100.00000000000216,54.4571507543770679]},"#ff2211":{"lch":[54.4995382972682876,171.437527349711331,12.9593558016228254],"luv":[54.4995382972682876,167.070909686171433,38.446546274251638],"rgb":[1,0.133333333333333331,0.0666666666666666657],"xyz":[0.41912248876128344,0.224483720062757686,0.0265655983455786934],"hpluv":[12.9593558016228254,399.164948195999784,54.4995382972682876],"hsluv":[12.9593558016228254,99.999999999998721,54.4995382972682876]},"#ff2222":{"lch":[54.5779789595956117,169.112342257331477,12.1770506300617924],"luv":[54.5779789595956117,165.307392407273255,35.6714216042562171],"rgb":[1,0.133333333333333331,0.133333333333333331],"xyz":[0.420997846899760497,0.225233863318148514,0.036442484541557886],"hpluv":[12.1770506300617924,393.185217729465933,54.5779789595956117],"hsluv":[12.1770506300617924,99.9999999999987494,54.5779789595956117]},"#ff2233":{"lch":[54.7067518227456,165.455769736233549,10.8753803895539445],"luv":[54.7067518227456,162.484163442906947,31.2171166072114978],"rgb":[1,0.133333333333333331,0.2],"xyz":[0.424085597632218203,0.226468963611131613,0.0527046383991690293],"hpluv":[10.8753803895539445,383.778210348001721,54.7067518227456],"hsluv":[10.8753803895539445,99.9999999999987779,54.7067518227456]},"#ff2244":{"lch":[54.8918465894738148,160.537768894747074,8.96806115251763103],"luv":[54.8918465894738148,158.575257224785304,25.0252480066910863],"rgb":[1,0.133333333333333331,0.266666666666666663],"xyz":[0.428543592876437118,0.228252161708819207,0.0761834133520556678],"hpluv":[8.96806115251763103,371.115171122776133,54.8918465894738148],"hsluv":[8.96806115251763103,99.9999999999988347,54.8918465894738148]},"#ff2255":{"lch":[55.1379036013317432,154.588213330392733,6.3708707633682522],"luv":[55.1379036013317432,153.633547891150499,17.1536778289841081],"rgb":[1,0.133333333333333331,0.333333333333333315],"xyz":[0.434506006915799103,0.23063712732456404,0.107585460626029583],"hpluv":[6.3708707633682522,355.76683037739258,55.1379036013317432],"hsluv":[6.3708707633682522,99.9999999999989342,55.1379036013317432]},"#ff2266":{"lch":[55.4484819892530254,147.979820726080618,3.00414546296194196],"luv":[55.4484819892530254,147.776458796099433,7.75535736170059753],"rgb":[1,0.133333333333333331,0.4],"xyz":[0.442091002689307289,0.23367112563396733,0.147533105033173545],"hpluv":[3.00414546296194196,338.650844053811227,55.4484819892530254],"hsluv":[3.00414546296194196,99.9999999999990763,55.4484819892530254]},"#ff2277":{"lch":[55.8262016697843961,141.198613687408425,358.803757025958646],"luv":[55.8262016697843961,141.167840095073672,-2.94778393674187145],"rgb":[1,0.133333333333333331,0.466666666666666674],"xyz":[0.451405015709509194,0.237396730842048154,0.196586906939571454],"hpluv":[358.803757025958646,320.945787006908631,55.8262016697843961],"hsluv":[358.803757025958646,99.9999999999991616,55.8262016697843961]},"#ff2288":{"lch":[56.2728344602164299,134.800794021339357,353.742009538390391],"luv":[56.2728344602164299,133.997535770156077,-14.694028593592142],"rgb":[1,0.133333333333333331,0.533333333333333326],"xyz":[0.462545432811453,0.241852897682825752,0.255259770343143622],"hpluv":[353.742009538390391,303.971583410200083,56.2728344602164299],"hsluv":[353.742009538390391,99.9999999999992752,56.2728344602164299]},"#ff2299":{"lch":[56.7893750973531866,129.355771045476672,347.857065824102108],"luv":[56.7893750973531866,126.461550291410035,-27.2101415039127161],"rgb":[1,0.133333333333333331,0.6],"xyz":[0.47560239692052575,0.247075683326454909,0.324026447984261501],"hpluv":[347.857065824102108,289.040064659782502,56.7893750973531866],"hsluv":[347.857065824102108,99.9999999999994316,56.7893750973531866]},"#ff22aa":{"lch":[57.3761062638205743,125.376808270539939,341.281866819384959],"luv":[57.3761062638205743,118.745473604842076,-40.2350164715945766],"rgb":[1,0.133333333333333331,0.66666666666666663],"xyz":[0.49066008988577825,0.253098760512556031,0.403330297601260102],"hpluv":[341.281866819384959,277.284417349873706,57.3761062638205743],"hsluv":[341.281866819384959,99.999999999999531,57.3761062638205743]},"#ff22bb":{"lch":[58.0326640845464112,123.247659375493754,334.254064951888324],"luv":[58.0326640845464112,111.01274832153284,-53.5364852379920606],"rgb":[1,0.133333333333333331,0.733333333333333282],"xyz":[0.507797681993114924,0.25995379735549079,0.493588282699901848],"hpluv":[334.254064951888324,269.491764983662165,58.0326640845464112],"hsluv":[334.254064951888324,99.9999999999997726,58.0326640845464112]},"#ff22cc":{"lch":[58.7581065478829316,123.164795236141373,327.088444575119183],"luv":[58.7581065478829316,103.398114188518221,-66.9208246199849128],"rgb":[1,0.133333333333333331,0.8],"xyz":[0.527090057436836679,0.267670747532979592,0.595194793370172],"hpluv":[327.088444575119183,265.985598747154427,58.7581065478829316],"hsluv":[327.088444575119183,99.9999999999998721,58.7581065478829316]},"#ff22dd":{"lch":[59.550985046801415,125.119413407905796,320.113090366201448],"luv":[59.550985046801415,96.0055877759378,-80.2358693312108358],"rgb":[1,0.133333333333333331,0.866666666666666696],"xyz":[0.548608382987470167,0.276278077753233098,0.708524641270178],"hpluv":[320.113090366201448,266.609166102550091,59.550985046801415],"hsluv":[320.113090366201448,100.000000000000028,59.550985046801415]},"#ff22ee":{"lch":[60.4094179672163705,128.929416765847606,313.598505937960113],"luv":[60.4094179672163705,88.9098108664153273,-93.3693742041783281],"rgb":[1,0.133333333333333331,0.933333333333333348],"xyz":[0.572420563253645,0.285802949859703115,0.833935457338701225],"hpluv":[313.598505937960113,270.823716236275,60.4094179672163705],"hsluv":[313.598505937960113,100.000000000000227,60.4094179672163705]},"#ff22ff":{"lch":[61.3311646171935223,134.305840538380238,307.715012949243601],"luv":[61.3311646171935223,82.1594946996257249,-106.244417422389745],"rgb":[1,0.133333333333333331,1],"xyz":[0.598591611663476297,0.296271369223635839,0.97176964563048307],"hpluv":[307.715012949243601,277.877263991976,61.3311646171935223],"hsluv":[307.715012949243601,100.000000000000398,61.3311646171935223]},"#ff3300":{"lch":[55.7168894472394811,166.476173059961667,14.689559134518138],"luv":[55.7168894472394811,161.034729269155179,42.2153072463082495],"rgb":[1,0.2,0],"xyz":[0.424228545350657182,0.236314498040924637,0.0232767340771599419],"hpluv":[14.689559134518138,379.144314271077917,55.7168894472394811],"hsluv":[14.689559134518138,100.000000000002203,55.7168894472394811]},"#ff3311":{"lch":[55.7578022303213,165.243627812887922,14.2690908575150317],"luv":[55.7578022303213,160.145669888681539,40.7286256663500339],"rgb":[1,0.2,0.0666666666666666657],"xyz":[0.425240210850294287,0.236719164240779489,0.0286048390419155751],"hpluv":[14.2690908575150317,376.06108995847427,55.7578022303213],"hsluv":[14.2690908575150317,99.9999999999988,55.7578022303213]},"#ff3322":{"lch":[55.8335204651182835,163.01701714894287,13.4842232594842422],"luv":[55.8335204651182835,158.523316810386802,38.0119179675594552],"rgb":[1,0.2,0.133333333333333331],"xyz":[0.427115568988771344,0.237469307496170318,0.0384817252378947677],"hpluv":[13.4842232594842422,370.490653647292163,55.8335204651182835],"hsluv":[13.4842232594842422,99.9999999999987494,55.8335204651182835]},"#ff3333":{"lch":[55.9578428172660267,159.511521097175432,12.1770506300617853],"luv":[55.9578428172660267,155.922585303490365,33.6462888742638455],"rgb":[1,0.2,0.2],"xyz":[0.430203319721229049,0.238704407789153417,0.0547438790955059179],"hpluv":[12.1770506300617853,361.718248261175631,55.9578428172660267],"hsluv":[12.1770506300617853,99.9999999999988773,55.9578428172660267]},"#ff3344":{"lch":[56.1365811585215368,154.789240798906889,10.2588910791084782],"luv":[56.1365811585215368,152.31463646984821,27.5673826135157078],"rgb":[1,0.2,0.266666666666666663],"xyz":[0.434661314965447965,0.240487605886841,0.0782226540483925564],"hpluv":[10.2588910791084782,349.892100101075414,56.1365811585215368],"hsluv":[10.2588910791084782,99.9999999999989626,56.1365811585215368]},"#ff3355":{"lch":[56.3742616664660403,149.065442517766684,7.64169944339336649],"luv":[56.3742616664660403,147.741595680550319,19.8223878173745902],"rgb":[1,0.2,0.333333333333333315],"xyz":[0.44062372900480995,0.242872571502585843,0.109624701322366458],"hpluv":[7.64169944339336649,335.533149366899124,56.3742616664660403],"hsluv":[7.64169944339336649,99.9999999999990195,56.3742616664660403]},"#ff3366":{"lch":[56.674385203130754,142.694983818340035,4.24028319431916056],"luv":[56.674385203130754,142.304390380845462,10.550776523662277],"rgb":[1,0.2,0.4],"xyz":[0.448208724778318135,0.245906569811989134,0.14957234572951042],"hpluv":[4.24028319431916056,319.492902958598108,56.674385203130754],"hsluv":[4.24028319431916056,99.9999999999991758,56.674385203130754]},"#ff3377":{"lch":[57.0395646827704468,136.14730874514737,359.983392279567909],"luv":[57.0395646827704468,136.147303025702882,-0.0394635770517579934],"rgb":[1,0.2,0.466666666666666674],"xyz":[0.457522737798520041,0.249632175020069957,0.198626147635908329],"hpluv":[359.983392279567909,302.881107814185,57.0395646827704468],"hsluv":[359.983392279567909,99.9999999999992895,57.0395646827704468]},"#ff3388":{"lch":[57.4716120619286954,129.967879448766553,354.83565117969431],"luv":[57.4716120619286954,129.440287861866665,-11.6987848363070146],"rgb":[1,0.2,0.533333333333333326],"xyz":[0.468663154900463841,0.254088341860847555,0.257299011039480496],"hpluv":[354.83565117969431,286.960407533356261,57.4716120619286954],"hsluv":[354.83565117969431,99.9999999999993889,57.4716120619286954]},"#ff3399":{"lch":[57.9716047421228353,124.724336507791776,348.82951213288959],"luv":[57.9716047421228353,122.361442957788952,-24.1627273832372573],"rgb":[1,0.2,0.6],"xyz":[0.481720119009536596,0.259311127504476713,0.326065688680598431],"hpluv":[348.82951213288959,273.007894976207297,57.9716047421228353],"hsluv":[348.82951213288959,99.9999999999995737,57.9716047421228353]},"#ff33aa":{"lch":[58.5399451724763935,120.937271340322638,342.098036856126953],"luv":[58.5399451724763935,115.081956962752116,-37.174813797329108],"rgb":[1,0.2,0.66666666666666663],"xyz":[0.496777811974789096,0.265334204690577835,0.405369538297597032],"hpluv":[342.098036856126953,262.148381504719794,58.5399451724763935],"hsluv":[342.098036856126953,99.9999999999996732,58.5399451724763935]},"#ff33bb":{"lch":[59.1764201449825862,119.003132790944747,334.888094830460091],"luv":[59.1764201449825862,107.755032536641394,-50.5034511403585498],"rgb":[1,0.2,0.733333333333333282],"xyz":[0.513915404082125771,0.272189241533512594,0.495627523396238778],"hpluv":[334.888094830460091,255.181409444549388,59.1764201449825862],"hsluv":[334.888094830460091,99.9999999999998295,59.1764201449825862]},"#ff33cc":{"lch":[59.8802624584280494,119.13012657470172,327.532171012183937],"luv":[59.8802624584280494,100.509254029343069,-63.9521454852723039],"rgb":[1,0.2,0.8],"xyz":[0.533207779525847525,0.279906191711001395,0.597234034066508879],"hpluv":[327.532171012183937,252.451080902073329,59.8802624584280494],"hsluv":[327.532171012183937,100.000000000000043,59.8802624584280494]},"#ff33dd":{"lch":[60.650215463767978,121.314823858854638,320.378757122173454],"luv":[60.650215463767978,93.4460015542912146,-77.3636302238999747],"rgb":[1,0.2,0.866666666666666696],"xyz":[0.554726105076481,0.288513521931254902,0.710563881966514876],"hpluv":[320.378757122173454,253.817084039055629,60.650215463767978],"hsluv":[320.378757122173454,100.000000000000171,60.650215463767978]},"#ff33ee":{"lch":[61.484599762034378,125.372817174433621,313.71398784253438],"luv":[61.484599762034378,86.6400000332951805,-90.6192787462169775],"rgb":[1,0.2,0.933333333333333348],"xyz":[0.578538285342655723,0.298038394037724919,0.8359746980350381],"hpluv":[313.71398784253438,258.747618308410438,61.484599762034378],"hsluv":[313.71398784253438,100.000000000000242,61.484599762034378]},"#ff33ff":{"lch":[62.3813806681475,131.007738376122177,307.715012949243658],"luv":[62.3813806681475,80.141932350642,-103.635409940481253],"rgb":[1,0.2,1],"xyz":[0.604709333752487144,0.308506813401657642,0.97380888632682],"hpluv":[307.715012949243658,266.490230971107223,62.3813806681475],"hsluv":[307.715012949243658,100.000000000000597,62.3813806681475]},"#ff4400":{"lch":[57.461133143380664,158.273971604467,16.6278363926044079],"luv":[57.461133143380664,151.655533944896689,45.2907177172089845],"rgb":[1,0.266666666666666663,0],"xyz":[0.433061115833623222,0.253979639006856939,0.0262209242381485352],"hpluv":[16.6278363926044079,349.522099776260404,57.461133143380664],"hsluv":[16.6278363926044079,100.000000000002203,57.461133143380664]},"#ff4411":{"lch":[57.500127691013958,157.107055615985729,16.2066010587584444],"luv":[57.500127691013958,150.863862649088418,43.84885256105823],"rgb":[1,0.266666666666666663,0.0666666666666666657],"xyz":[0.434072781333260327,0.254384305206711792,0.031549029202904165],"hpluv":[16.2066010587584444,346.709871357654038,57.500127691013958],"hsluv":[16.2066010587584444,99.9999999999990195,57.500127691013958]},"#ff4422":{"lch":[57.5723039440668174,154.996970095022306,15.4196600073807488],"luv":[57.5723039440668174,149.417734299680745,41.2116660108183908],"rgb":[1,0.266666666666666663,0.133333333333333331],"xyz":[0.435948139471737384,0.255134448462102592,0.0414259153988833645],"hpluv":[15.4196600073807488,341.624434338608523,57.5723039440668174],"hsluv":[15.4196600073807488,99.9999999999990195,57.5723039440668174]},"#ff4433":{"lch":[57.6908335218327437,151.669616752661852,14.1071803519879388],"luv":[57.6908335218327437,147.095485225188412,36.9674298845038223],"rgb":[1,0.266666666666666663,0.2],"xyz":[0.439035890204195089,0.256369548755085719,0.0576880692564945077],"hpluv":[14.1071803519879388,333.603886972203838,57.6908335218327437],"hsluv":[14.1071803519879388,99.9999999999991189,57.6908335218327437]},"#ff4444":{"lch":[57.8612930010941682,147.177084719743902,12.177050630061812],"luv":[57.8612930010941682,143.865668066403089,31.0445457111261],"rgb":[1,0.266666666666666663,0.266666666666666663],"xyz":[0.443493885448414,0.258152746852773285,0.0811668442093811393],"hpluv":[12.177050630061812,322.76868159643891,57.8612930010941682],"hsluv":[12.177050630061812,99.9999999999991616,57.8612930010941682]},"#ff4455":{"lch":[58.088054010202,141.716285969530816,9.53556562214303405],"luv":[58.088054010202,139.758186425649882,23.4766913344092778],"rgb":[1,0.266666666666666663,0.333333333333333315],"xyz":[0.449456299487776,0.260537712468518146,0.112568891483355055],"hpluv":[9.53556562214303405,309.579547415252762,58.088054010202],"hsluv":[9.53556562214303405,99.9999999999992184,58.088054010202]},"#ff4466":{"lch":[58.3745334436288772,135.619673907166316,6.08910281061040859],"luv":[58.3745334436288772,134.854526247228307,14.3858507333331573],"rgb":[1,0.266666666666666663,0.4],"xyz":[0.457041295261284175,0.263571710777921464,0.152516535890499016],"hpluv":[6.08910281061040859,294.807548797669426,58.3745334436288772],"hsluv":[6.08910281061040859,99.9999999999992468,58.3745334436288772]},"#ff4477":{"lch":[58.7233249761193292,129.336052383116169,1.75519751784143763],"luv":[58.7233249761193292,129.275370036155351,3.96145782045869943],"rgb":[1,0.266666666666666663,0.466666666666666674],"xyz":[0.466355308281486081,0.26729731598600226,0.201570337796896926],"hpluv":[1.75519751784143763,279.478426792191101,58.7233249761193292],"hsluv":[1.75519751784143763,99.99999999999946,58.7233249761193292]},"#ff4488":{"lch":[59.1362810655005831,123.398173767481396,356.485857706034096],"luv":[59.1362810655005831,123.16614811103635,-7.56367957014252212],"rgb":[1,0.266666666666666663,0.533333333333333326],"xyz":[0.477495725383429881,0.271753482826779857,0.260243201200469065],"hpluv":[356.485857706034096,264.785408966002421,59.1362810655005831],"hsluv":[356.485857706034096,99.9999999999995595,59.1362810655005831]},"#ff4499":{"lch":[59.6145739069951901,118.37348532064955,350.303370213710309],"luv":[59.6145739069951901,116.682328099077466,-19.9378117238896806],"rgb":[1,0.266666666666666663,0.6],"xyz":[0.490552689492502636,0.276976268470409,0.329009878841587],"hpluv":[350.303370213710309,251.965637795338,59.6145739069951901],"hsluv":[350.303370213710309,99.9999999999997158,59.6145739069951901]},"#ff44aa":{"lch":[60.1587486598557177,114.795436800176844,343.339450530546515],"luv":[60.1587486598557177,109.976338996192666,-32.9119609129858475],"rgb":[1,0.266666666666666663,0.66666666666666663],"xyz":[0.505610382457755136,0.282999345656510137,0.408313728458585601],"hpluv":[343.339450530546515,242.139230170638513,60.1587486598557177],"hsluv":[343.339450530546515,99.9999999999997726,60.1587486598557177]},"#ff44bb":{"lch":[60.768775409955694,113.081121999454581,335.854341209703],"luv":[60.768775409955694,103.187483930843442,-46.2567110015126133],"rgb":[1,0.266666666666666663,0.733333333333333282],"xyz":[0.522747974565091811,0.289854382499444896,0.498571713557227347],"hpluv":[335.854341209703,236.128794952899398,60.768775409955694],"hsluv":[335.854341209703,99.9999999999999716,60.768775409955694]},"#ff44cc":{"lch":[61.4441027606342232,113.457557937670586,328.208302422827],"luv":[61.4441027606342232,96.4354118722023088,-59.7731443895883743],"rgb":[1,0.266666666666666663,0.8],"xyz":[0.542040350008813565,0.297571332676933697,0.600178224227497559],"hpluv":[328.208302422827,234.310931883055929,61.4441027606342232],"hsluv":[328.208302422827,100.000000000000128,61.4441027606342232]},"#ff44dd":{"lch":[62.1837139115479403,115.929787300919912,320.782684481283354],"luv":[62.1837139115479403,89.8170022013310358,-73.2981698216444357],"rgb":[1,0.266666666666666663,0.866666666666666696],"xyz":[0.563558675559447,0.306178662897187204,0.713508072127503556],"hpluv":[320.782684481283354,236.568931830040128,62.1837139115479403],"hsluv":[320.782684481283354,100.000000000000384,62.1837139115479403]},"#ff44ee":{"lch":[62.986184892514558,120.309477517885213,313.888915695758442],"luv":[62.986184892514558,83.4060394378513195,-86.7052649261745643],"rgb":[1,0.266666666666666663,0.933333333333333348],"xyz":[0.587370855825621874,0.315703535003657221,0.83891888819602678],"hpluv":[313.888915695758442,242.378371703623515,62.986184892514558],"hsluv":[313.888915695758442,100.000000000000512,62.986184892514558]},"#ff44ff":{"lch":[63.8497439492436,126.288239910703226,307.715012949243771],"luv":[63.8497439492436,77.2548530724802447,-99.9019880507531468],"rgb":[1,0.266666666666666663,1],"xyz":[0.613541904235453184,0.326171954367589945,0.976753076487808514],"hpluv":[307.715012949243771,250.982289693600563,63.8497439492436],"hsluv":[307.715012949243771,100.000000000000711,63.8497439492436]},"#ff5500":{"lch":[59.6718499915998279,148.630700843778015,19.3008598736449528],"luv":[59.6718499915998279,140.27705963161867,49.1266910591374923],"rgb":[1,0.333333333333333315,0],"xyz":[0.444874372547969188,0.277606152435549203,0.030158676476263746],"hpluv":[19.3008598736449528,316.066414507984518,59.6718499915998279],"hsluv":[19.3008598736449528,100.00000000000226,59.6718499915998279]},"#ff5511":{"lch":[59.7086010657385486,147.530698996531413,18.8803784611224046],"luv":[59.7086010657385486,139.59299153240957,47.7399608445355526],"rgb":[1,0.333333333333333315,0.0666666666666666657],"xyz":[0.445886038047606292,0.278010818635404056,0.0354867814410193758],"hpluv":[18.8803784611224046,313.53413530658878,59.7086010657385486],"hsluv":[18.8803784611224046,99.9999999999992184,59.7086010657385486]},"#ff5522":{"lch":[59.7766335415963255,145.539064184811622,18.0939597274483681],"luv":[59.7766335415963255,138.341936048844929,45.2009727113036],"rgb":[1,0.333333333333333315,0.133333333333333331],"xyz":[0.447761396186083349,0.278760961890794856,0.0453636676369985753],"hpluv":[18.0939597274483681,308.949467849715688,59.7766335415963255],"hsluv":[18.0939597274483681,99.9999999999993,59.7766335415963255]},"#ff5533":{"lch":[59.8883826376776085,142.391759670631302,16.7797766500676033],"luv":[59.8883826376776085,136.328925827546385,41.1076295206398825],"rgb":[1,0.333333333333333315,0.2],"xyz":[0.450849146918541055,0.279996062183778,0.0616258214946097185],"hpluv":[16.7797766500676033,301.704368813615531,59.8883826376776085],"hsluv":[16.7797766500676033,99.9999999999992752,59.8883826376776085]},"#ff5544":{"lch":[60.0491441299879654,138.129067713899872,14.841281480974498],"luv":[60.0491441299879654,133.520956258941027,35.3806951204903228],"rgb":[1,0.333333333333333315,0.266666666666666663],"xyz":[0.45530714216275997,0.281779260281465549,0.0851045964474963501],"hpluv":[14.841281480974498,291.888903616465711,60.0491441299879654],"hsluv":[14.841281480974498,99.9999999999994458,60.0491441299879654]},"#ff5555":{"lch":[60.2631003442631936,132.926854505406169,12.1770506300618191],"luv":[60.2631003442631936,129.936061471805857,28.0386978637829927],"rgb":[1,0.333333333333333315,0.333333333333333315],"xyz":[0.461269556202121955,0.28416422589721041,0.116506643721470265],"hpluv":[12.1770506300618191,279.898508055628838,60.2631003442631936],"hsluv":[12.1770506300618191,99.99999999999946,60.2631003442631936]},"#ff5566":{"lch":[60.5335583680784168,127.091978224389294,8.68145952340772098],"luv":[60.5335583680784168,125.635857711143842,19.1833830742614],"rgb":[1,0.333333333333333315,0.4],"xyz":[0.468854551975630141,0.287198224206613728,0.156454288128614227],"hpluv":[8.68145952340772098,266.416588145649541,60.5335583680784168],"hsluv":[8.68145952340772098,99.9999999999995737,60.5335583680784168]},"#ff5577":{"lch":[60.8630749033481351,121.049870295691591,4.25532383082281918],"luv":[60.8630749033481351,120.716171483201308,8.98203991541407],"rgb":[1,0.333333333333333315,0.466666666666666674],"xyz":[0.478168564995832046,0.290923829414694524,0.205508090035012136],"hpluv":[4.25532383082281918,252.376995060411161,60.8630749033481351],"hsluv":[4.25532383082281918,99.9999999999997158,60.8630749033481351]},"#ff5588":{"lch":[61.2535329118914404,115.319895978664789,358.830706871579594],"luv":[61.2535329118914404,115.295882188952703,-2.35328680810625102],"rgb":[1,0.333333333333333315,0.533333333333333326],"xyz":[0.489308982097775846,0.295379996255472121,0.264180953438584276],"hpluv":[358.830706871579594,238.897951612134108,61.2535329118914404],"hsluv":[358.830706871579594,99.9999999999997868,61.2535329118914404]},"#ff5599":{"lch":[61.7061969251912075,110.472562823261683,352.412124726619879],"luv":[61.7061969251912075,109.505210454219565,-14.5875296097928366],"rgb":[1,0.333333333333333315,0.6],"xyz":[0.502365946206848601,0.300602781899101279,0.332947631079702211],"hpluv":[352.412124726619879,227.177321581811952,61.7061969251912075],"hsluv":[352.412124726619879,99.9999999999998721,61.7061969251912075]},"#ff55aa":{"lch":[62.2217597266614177,107.062368992166355,345.125792918237266],"luv":[62.2217597266614177,103.474894783269619,-27.4826673342684735],"rgb":[1,0.333333333333333315,0.66666666666666663],"xyz":[0.517423639172101102,0.306625859085202401,0.412251480696700812],"hpluv":[345.125792918237266,218.340291577764589,62.2217597266614177],"hsluv":[345.125792918237266,100.000000000000071,62.2217597266614177]},"#ff55bb":{"lch":[62.8003867495987862,105.538663220643826,337.249357740418191],"luv":[62.8003867495987862,97.3274002701012,-40.8140489422941855],"rgb":[1,0.333333333333333315,0.733333333333333282],"xyz":[0.534561231279437776,0.31348089592813716,0.502509465795342614],"hpluv":[337.249357740418191,213.249782655969199,62.8003867495987862],"hsluv":[337.249357740418191,100.000000000000284,62.8003867495987862]},"#ff55cc":{"lch":[63.441761241476712,106.157882562261193,329.184616986090759],"luv":[63.441761241476712,91.1707664760994447,-54.3818661895983837],"rgb":[1,0.333333333333333315,0.8],"xyz":[0.553853606723159531,0.321197846105625961,0.60411597646561277],"hpluv":[329.184616986090759,212.332436268611161,63.441761241476712],"hsluv":[329.184616986090759,100.000000000000441,63.441761241476712]},"#ff55dd":{"lch":[64.1451313698934769,108.938462409011748,321.364198961949114],"luv":[64.1451313698934769,85.0951546537234549,-68.0176686346904518],"rgb":[1,0.333333333333333315,0.866666666666666696],"xyz":[0.575371932273793,0.329805176325879468,0.717445824365618767],"hpluv":[321.364198961949114,215.504760823814451,64.1451313698934769],"hsluv":[321.364198961949114,100.000000000000597,64.1451313698934769]},"#ff55ee":{"lch":[64.9093593252901258,113.686114680552976,314.13939983200612],"luv":[64.9093593252901258,79.1717442713053288,-81.5865649491316418],"rgb":[1,0.333333333333333315,0.933333333333333348],"xyz":[0.599184112539967728,0.339330048432349485,0.842856640434142],"hpluv":[314.13939983200612,222.248801840624651,64.9093593252901258],"hsluv":[314.13939983200612,100.000000000000753,64.9093593252901258]},"#ff55ff":{"lch":[65.7329718140353378,120.074032289562709,307.715012949243885],"luv":[65.7329718140353378,73.4534088756767147,-94.9861566483116633],"rgb":[1,0.333333333333333315,1],"xyz":[0.625355160949799149,0.349798467796282209,0.980690828725923724],"hpluv":[307.715012949243885,231.795582155087629,65.7329718140353378],"hsluv":[307.715012949243885,100.000000000000981,65.7329718140353378]},"#ff6600":{"lch":[62.3097916023938438,138.227046243322206,22.8239093069931798],"luv":[62.3097916023938438,127.404056867086908,53.6183047751569717],"rgb":[1,0.4,0],"xyz":[0.459902430253815608,0.307662267847242543,0.03516802904487909],"hpluv":[22.8239093069931798,281.498480884542573,62.3097916023938438],"hsluv":[22.8239093069931798,100.000000000002359,62.3097916023938438]},"#ff6611":{"lch":[62.344110015411573,137.186959502953613,22.4076195476895244],"luv":[62.344110015411573,126.828705913080029,52.2947532174930245],"rgb":[1,0.4,0.0666666666666666657],"xyz":[0.460914095753452713,0.308066934047097396,0.0404961340096347197],"hpluv":[22.4076195476895244,279.226561167599414,62.344110015411573],"hsluv":[22.4076195476895244,99.9999999999995737,62.344110015411573]},"#ff6622":{"lch":[62.4076477973658257,135.300699513710725,21.6278909170268392],"luv":[62.4076477973658257,125.775148313603225,49.8687412673566115],"rgb":[1,0.4,0.133333333333333331],"xyz":[0.46278945389192977,0.308817077302488197,0.0503730202056139192],"hpluv":[21.6278909170268392,275.106945224361368,62.4076477973658257],"hsluv":[21.6278909170268392,99.9999999999996163,62.4076477973658257]},"#ff6633":{"lch":[62.5120380635233346,132.311574345484274,20.3215228987586443],"luv":[62.5120380635233346,124.076309265494103,45.9502141979128851],"rgb":[1,0.4,0.2],"xyz":[0.465877204624387475,0.310052177595471323,0.0666351740632250555],"hpluv":[20.3215228987586443,268.579898420339646,62.5120380635233346],"hsluv":[20.3215228987586443,99.9999999999995879,62.5120380635233346]},"#ff6644":{"lch":[62.6622654373265675,128.246261163642686,18.3868048135947362],"luv":[62.6622654373265675,121.699120282046835,40.4527826611364603],"rgb":[1,0.4,0.266666666666666663],"xyz":[0.470335199868606391,0.311835375693158889,0.0901139490161117],"hpluv":[18.3868048135947362,259.703586528718,62.6622654373265675],"hsluv":[18.3868048135947362,99.9999999999997726,62.6622654373265675]},"#ff6655":{"lch":[62.8622967709428764,123.257362768531593,15.7125644918265355],"luv":[62.8622967709428764,118.651528823693667,33.3795174388964284],"rgb":[1,0.4,0.333333333333333315],"xyz":[0.476297613907968376,0.31422034130890375,0.121515996290085609],"hpluv":[15.7125644918265355,248.806632458920831,62.8622967709428764],"hsluv":[15.7125644918265355,99.9999999999997158,62.8622967709428764]},"#ff6666":{"lch":[63.1153061541487119,117.623502253606588,12.1770506300618742],"luv":[63.1153061541487119,114.97702760078576,24.8107115273291683],"rgb":[1,0.4,0.4],"xyz":[0.483882609681476561,0.317254339618307069,0.161463640697229571],"hpluv":[12.1770506300618742,236.482353971627703,63.1153061541487119],"hsluv":[12.1770506300618742,99.9999999999999,63.1153061541487119]},"#ff6677":{"lch":[63.4237926928396121,111.744324598031497,7.65713975886231157],"luv":[63.4237926928396121,110.747917341816802,14.8893547314965815],"rgb":[1,0.4,0.466666666666666674],"xyz":[0.493196622701678467,0.320979944826387864,0.21051744260362748],"hpluv":[7.65713975886231157,223.569519019308729,63.4237926928396121],"hsluv":[7.65713975886231157,100.000000000000071,63.4237926928396121]},"#ff6688":{"lch":[63.7896518301749751,106.125321016318935,2.05404070639815961],"luv":[63.7896518301749751,106.057131857198982,3.80375380925921824],"rgb":[1,0.4,0.533333333333333326],"xyz":[0.504337039803622322,0.325436111667165462,0.26919030600719962],"hpluv":[2.05404070639815961,211.109662635719985,63.7896518301749751],"hsluv":[2.05404070639815961,100.000000000000128,63.7896518301749751]},"#ff6699":{"lch":[64.2142253202301276,101.344202045456129,355.341285926877504],"luv":[64.2142253202301276,101.009378125853075,-8.23121004826552394],"rgb":[1,0.4,0.6],"xyz":[0.517394003912695,0.330658897310794619,0.337956983648317555],"hpluv":[355.341285926877504,200.265890662959123,64.2142253202301276],"hsluv":[355.341285926877504,100.000000000000199,64.2142253202301276]},"#ff66aa":{"lch":[64.6983418323177233,97.9876087444390436,347.629516841099075],"luv":[64.6983418323177233,95.7126081968365838,-20.9920961224008664],"rgb":[1,0.4,0.66666666666666663],"xyz":[0.532451696877947578,0.336681974496895742,0.417260833265316156],"hpluv":[347.629516841099075,192.184047560801417,64.6983418323177233],"hsluv":[347.629516841099075,100.000000000000441,64.6983418323177233]},"#ff66bb":{"lch":[65.2423543089962408,96.5541832870936787,339.215698562051898],"luv":[65.2423543089962408,90.270720679111,-34.2623306024503123],"rgb":[1,0.4,0.733333333333333282],"xyz":[0.549589288985284141,0.3435370113398305,0.507518818363957847],"hpluv":[339.215698562051898,187.793604034801348,65.2423543089962408],"hsluv":[339.215698562051898,100.000000000000597,65.2423543089962408]},"#ff66cc":{"lch":[65.8461771980182533,97.3465701370285,330.562118792095362],"luv":[65.8461771980182533,84.7780628468697159,-47.8438583036069218],"rgb":[1,0.4,0.8],"xyz":[0.568881664429005895,0.351253961517319302,0.609125329034228],"hpluv":[330.562118792095362,187.598522894675455,65.8461771980182533],"hsluv":[330.562118792095362,100.000000000000711,65.8461771980182533]},"#ff66dd":{"lch":[66.5093249736543157,100.405273498350255,322.181562409870594],"luv":[66.5093249736543157,79.3159229397089831,-61.5646271368605298],"rgb":[1,0.4,0.866666666666666696],"xyz":[0.590399989979639495,0.359861291737572808,0.722455176934234],"hpluv":[322.181562409870594,191.563741116159406,66.5093249736543157],"hsluv":[322.181562409870594,100.000000000000952,66.5093249736543157]},"#ff66ee":{"lch":[67.2309523334132706,105.527911758853008,314.488878023448478],"luv":[67.2309523334132706,73.9508789773533408,-75.2821868615750702],"rgb":[1,0.4,0.933333333333333348],"xyz":[0.614212170245814204,0.369386163844042825,0.847865993002757223],"hpluv":[314.488878023448478,199.176184031939982,67.2309523334132706],"hsluv":[314.488878023448478,100.000000000001066,67.2309523334132706]},"#ff66ff":{"lch":[68.0098958254125137,112.360313920932768,307.715012949244056],"luv":[68.0098958254125137,68.7346624616611592,-88.8841173702707437],"rgb":[1,0.4,1],"xyz":[0.640383218655645625,0.379854583207975549,0.985700181294539179],"hpluv":[307.715012949244056,209.642901019847784,68.0098958254125137],"hsluv":[307.715012949244056,100.000000000001421,68.0098958254125137]},"#ff7700":{"lch":[65.3236824647912755,127.817378582796977,27.3102887077963814],"luv":[65.3236824647912755,113.570196302134065,58.6437786953806466],"rgb":[1,0.466666666666666674,0],"xyz":[0.478356168307233265,0.344569743954078356,0.0413192750626848],"hpluv":[27.3102887077963814,248.289625700463205,65.3236824647912755],"hsluv":[27.3102887077963814,100.00000000000226,65.3236824647912755]},"#ff7711":{"lch":[65.3555057958206476,126.824695098806032,26.9045059733925385],"luv":[65.3555057958206476,113.097436843789765,57.3887886809793],"rgb":[1,0.466666666666666674,0.0666666666666666657],"xyz":[0.479367833806870369,0.344974410153933209,0.0466473800274404271],"hpluv":[26.9045059733925385,246.24134425049084,65.3555057958206476],"hsluv":[26.9045059733925385,99.9999999999999716,65.3555057958206476]},"#ff7722":{"lch":[65.4144320044565291,125.020679344179442,26.1430666348463],"luv":[65.4144320044565291,112.230643754756542,55.0858681158159058],"rgb":[1,0.466666666666666674,0.133333333333333331],"xyz":[0.481243191945347426,0.345724553409324,0.0565242662234196266],"hpluv":[26.1430666348463,242.520026060215031,65.4144320044565291],"hsluv":[26.1430666348463,100.000000000000156,65.4144320044565291]},"#ff7733":{"lch":[65.511267747206432,122.151716277204869,24.8632302030062533],"luv":[65.511267747206432,110.829965834679456,51.3591322215488688],"rgb":[1,0.466666666666666674,0.2],"xyz":[0.484330942677805132,0.346959653702307136,0.0727864200810307699],"hpluv":[24.8632302030062533,236.604443239770575,65.511267747206432],"hsluv":[24.8632302030062533,100.000000000000128,65.511267747206432]},"#ff7744":{"lch":[65.6506715027637853,118.22870540382597,22.9581907744090898],"luv":[65.6506715027637853,108.863777518532288,46.1162089276663139],"rgb":[1,0.466666666666666674,0.266666666666666663],"xyz":[0.488788937922024047,0.348742851799994702,0.0962651950339174084],"hpluv":[22.9581907744090898,228.519406804146513,65.6506715027637853],"hsluv":[22.9581907744090898,100.000000000000199,65.6506715027637853]},"#ff7755":{"lch":[65.8363783536997857,113.378413750733145,20.3056908730066645],"luv":[65.8363783536997857,106.332452226692425,39.3455754576116092],"rgb":[1,0.466666666666666674,0.333333333333333315],"xyz":[0.494751351961386032,0.351127817415739563,0.12766724230789131],"hpluv":[20.3056908730066645,218.526329281612362,65.8363783536997857],"hsluv":[20.3056908730066645,100.000000000000171,65.8363783536997857]},"#ff7766":{"lch":[66.0714111968285351,107.847817312906827,16.7638759706376135],"luv":[66.0714111968285351,103.264450834403533,31.1063481146080676],"rgb":[1,0.466666666666666674,0.4],"xyz":[0.502336347734894217,0.354161815725142881,0.167614886715035272],"hpluv":[16.7638759706376135,207.127185394700234,66.0714111968285351],"hsluv":[16.7638759706376135,100.000000000000426,66.0714111968285351]},"#ff7777":{"lch":[66.3581913431115851,102.006782949974053,12.1770506300619488],"luv":[66.3581913431115851,99.7116772923406671,21.5166256497442419],"rgb":[1,0.466666666666666674,0.466666666666666674],"xyz":[0.511650360755096067,0.357887420933223677,0.216668688621433181],"hpluv":[12.1770506300619488,195.062523033846361,66.3581913431115851],"hsluv":[12.1770506300619488,100.000000000000355,66.3581913431115851]},"#ff7788":{"lch":[66.6986047917809,96.3441833198397291,6.39999172914420456],"luv":[66.6986047917809,95.7437601312525,10.7393694179903871],"rgb":[1,0.466666666666666674,0.533333333333333326],"xyz":[0.52279077785704,0.362343587774001274,0.275341552025005376],"hpluv":[6.39999172914420456,183.293927388427107,66.6986047917809],"hsluv":[6.39999172914420456,100.000000000000639,66.6986047917809]},"#ff7799":{"lch":[67.0940474565320244,91.4474963932601,359.352586865695173],"luv":[67.0940474565320244,91.4416585161261679,-1.0332881570442134],"rgb":[1,0.466666666666666674,0.6],"xyz":[0.535847741966112623,0.367566373417630432,0.344108229666123255],"hpluv":[359.352586865695173,172.952623850798517,67.0940474565320244],"hsluv":[359.352586865695173,100.000000000000782,67.0940474565320244]},"#ff77aa":{"lch":[67.5454605183692,87.9484746627524,351.107126776790835],"luv":[67.5454605183692,86.8912550098467449,-13.5957345634056814],"rgb":[1,0.466666666666666674,0.66666666666666663],"xyz":[0.550905434931365234,0.373589450603731554,0.423412079283121856],"hpluv":[351.107126776790835,165.223368139110704,67.5454605183692],"hsluv":[351.107126776790835,100.000000000000938,67.5454605183692]},"#ff77bb":{"lch":[68.0533617234635244,86.4195813509952,341.973592157308417],"luv":[68.0533617234635244,82.1775887588569,-26.7429980866295693],"rgb":[1,0.466666666666666674,0.733333333333333282],"xyz":[0.568043027038701798,0.380444487446666313,0.513670064381763658],"hpluv":[341.973592157308417,161.139458954487083,68.0533617234635244],"hsluv":[341.973592157308417,100.000000000001037,68.0533617234635244]},"#ff77cc":{"lch":[68.6178757233526682,87.2373067072756214,332.49967924393593],"luv":[68.6178757233526682,77.3802105983984347,-40.2821385887937],"rgb":[1,0.466666666666666674,0.8],"xyz":[0.587335402482423552,0.388161437624155115,0.615276575052033814],"hpluv":[332.49967924393593,161.325977991170333,68.6178757233526682],"hsluv":[332.49967924393593,100.000000000001265,68.6178757233526682]},"#ff77dd":{"lch":[69.238765020261809,90.480647802514838,323.326201907778],"luv":[69.238765020261809,72.5699004301545756,-54.0403291840472],"rgb":[1,0.466666666666666674,0.866666666666666696],"xyz":[0.608853728033057151,0.396768767844408621,0.728606422952039812],"hpluv":[323.326201907778,165.823361543811586,69.238765020261809],"hsluv":[323.326201907778,100.00000000000145,69.238765020261809]},"#ff77ee":{"lch":[69.9154621504300593,95.9376886025569604,314.973456368277198],"luv":[69.9154621504300593,67.8067552495039791,-67.8696105553513149],"rgb":[1,0.466666666666666674,0.933333333333333348],"xyz":[0.632665908299231861,0.406293639950878638,0.854017239020563],"hpluv":[314.973456368277198,174.122680701596721,69.9154621504300593],"hsluv":[314.973456368277198,100.000000000001535,69.9154621504300593]},"#ff77ff":{"lch":[70.6471031550122,103.213892868752552,307.715012949244283],"luv":[70.6471031550122,63.1394826173239494,-81.6487196221654],"rgb":[1,0.466666666666666674,1],"xyz":[0.658836956709063282,0.416762059314811362,0.99185142731234488],"hpluv":[307.715012949244283,185.388643374650655,70.6471031550122],"hsluv":[307.715012949244283,100.000000000001975,70.6471031550122]},"#ff8800":{"lch":[68.6580440198892603,118.150361410828182,32.8458067740872153],"luv":[68.6580440198892603,99.2620471866307383,64.0823992202883375],"rgb":[1,0.533333333333333326,0],"xyz":[0.500428538032203774,0.388714483404019873,0.0486767316376747472],"hpluv":[32.8458067740872153,218.364961888913399,68.6580440198892603],"hsluv":[32.8458067740872153,100.000000000002245,68.6580440198892603]},"#ff8811":{"lch":[68.6874112197728408,117.19102013872596,32.4606037779481582],"luv":[68.6874112197728408,98.8811760474647485,62.89871401408422],"rgb":[1,0.533333333333333326,0.0666666666666666657],"xyz":[0.501440203531840933,0.389119149603874726,0.0540048366024303769],"hpluv":[32.4606037779481582,216.499308154785638,68.6874112197728408],"hsluv":[32.4606037779481582,100.000000000000739,68.6874112197728408]},"#ff8822":{"lch":[68.7417963707939492,115.443262249268372,31.7362513605757321],"luv":[68.7417963707939492,98.1820090833864754,60.724294076614548],"rgb":[1,0.533333333333333326,0.133333333333333331],"xyz":[0.503315561670317879,0.389869292859265526,0.0638817227984095765],"hpluv":[31.7362513605757321,213.101761826290613,68.7417963707939492],"hsluv":[31.7362513605757321,100.000000000000668,68.7417963707939492]},"#ff8833":{"lch":[68.8311889682804292,112.651741292777714,30.5141745142023382],"luv":[68.8311889682804292,97.0498776480180823,57.1990914683060439],"rgb":[1,0.533333333333333326,0.2],"xyz":[0.506403312402775696,0.391104393152248653,0.0801438766560207128],"hpluv":[30.5141745142023382,207.678703624478942,68.8311889682804292],"hsluv":[30.5141745142023382,100.000000000000824,68.8311889682804292]},"#ff8844":{"lch":[68.9599197258043688,108.808998086617962,28.6842020071901302],"luv":[68.9599197258043688,95.4557990826346554,52.2263198599069725],"rgb":[1,0.533333333333333326,0.266666666666666663],"xyz":[0.510861307646994556,0.392887591249936219,0.103622651608907351],"hpluv":[28.6842020071901302,200.2199693629492,68.9599197258043688],"hsluv":[28.6842020071901302,100.000000000000838,68.9599197258043688]},"#ff8855":{"lch":[69.1314852187197602,104.012526361958052,26.1137258191789492],"luv":[69.1314852187197602,93.395152113439849,45.7815596272609682],"rgb":[1,0.533333333333333326,0.333333333333333315],"xyz":[0.516823721686356485,0.39527255686568108,0.135024698882881267],"hpluv":[26.1137258191789492,190.918970683811096,69.1314852187197602],"hsluv":[26.1137258191789492,100.000000000000867,69.1314852187197602]},"#ff8866":{"lch":[69.3487452092138881,98.4723154092605171,22.6389332988698087],"luv":[69.3487452092138881,90.8849122177262529,37.9042165627661802],"rgb":[1,0.533333333333333326,0.4],"xyz":[0.524408717459864726,0.398306555175084398,0.174972343290025228],"hpluv":[22.6389332988698087,180.183437843423292,69.3487452092138881],"hsluv":[22.6389332988698087,100.000000000001066,69.3487452092138881]},"#ff8877":{"lch":[69.6140261744794344,92.5206854303452246,18.0637242730473773],"luv":[69.6140261744794344,87.9605480867009248,28.6883114314535526],"rgb":[1,0.533333333333333326,0.466666666666666674],"xyz":[0.533722730480066576,0.402032160383165194,0.224026145196423138],"hpluv":[18.0637242730473773,168.648085666048672,69.6140261744794344],"hsluv":[18.0637242730473773,100.000000000001108,69.6140261744794344]},"#ff8888":{"lch":[69.9291829132988596,86.6211090413054,12.1770506300619186],"luv":[69.9291829132988596,84.672173963834382,18.2712749359175248],"rgb":[1,0.533333333333333326,0.533333333333333326],"xyz":[0.544863147582010487,0.406488327223942791,0.282699008599995305],"hpluv":[12.1770506300619186,157.182652238587849,69.9291829132988596],"hsluv":[12.1770506300619186,100.000000000001251,69.9291829132988596]},"#ff8899":{"lch":[70.29563969089034,81.3665448969888274,4.80888772903122597],"luv":[70.29563969089034,81.0801238487794791,6.82115423812421362],"rgb":[1,0.533333333333333326,0.6],"xyz":[0.557920111691083132,0.411711112867571949,0.351465686241113184],"hpluv":[4.80888772903122597,146.878021536398364,70.29563969089034],"hsluv":[4.80888772903122597,100.00000000000135,70.29563969089034]},"#ff88aa":{"lch":[70.7144212664750427,77.4442353273614827,355.944797831634332],"luv":[70.7144212664750427,77.2503443699940533,-5.47666688388778589],"rgb":[1,0.533333333333333326,0.66666666666666663],"xyz":[0.572977804656335743,0.417734190053673071,0.430769535858111841],"hpluv":[355.944797831634332,138.969799542374091,70.7144212664750427],"hsluv":[355.944797831634332,100.000000000001648,70.7144212664750427]},"#ff88bb":{"lch":[71.1861792611668847,75.5334875912487718,345.875835641341098],"luv":[71.1861792611668847,73.2500487000805,-18.431986141845023],"rgb":[1,0.533333333333333326,0.733333333333333282],"xyz":[0.590115396763672306,0.42458922689660783,0.521027520956753532],"hpluv":[345.875835641341098,134.642814203514433,71.1861792611668847],"hsluv":[345.875835641341098,100.000000000001776,71.1861792611668847]},"#ff88cc":{"lch":[71.711216864189268,76.1313589407537563,335.260476444218114],"luv":[71.711216864189268,69.1440007334156377,-31.8604924121286039],"rgb":[1,0.533333333333333326,0.8],"xyz":[0.609407772207394061,0.432306177074096631,0.622634031627023687],"hpluv":[335.260476444218114,134.714956877670915,71.711216864189268],"hsluv":[335.260476444218114,100.000000000001933,71.711216864189268]},"#ff88dd":{"lch":[72.2895135005839649,79.3885839073469413,324.950129439258774],"luv":[72.2895135005839649,64.9916618916399784,-45.5920074067441803],"rgb":[1,0.533333333333333326,0.866666666666666696],"xyz":[0.63092609775802766,0.440913507294350138,0.735963879527029685],"hpluv":[324.950129439258774,139.354847315526115,72.2895135005839649],"hsluv":[324.950129439258774,100.000000000002245,72.2895135005839649]},"#ff88ee":{"lch":[72.9207502525545124,85.0855243828499,315.651995307064169],"luv":[72.9207502525545124,60.845281511842515,-59.4760302748021203],"rgb":[1,0.533333333333333326,0.933333333333333348],"xyz":[0.654738278024202369,0.450438379400820155,0.861374695595552908],"hpluv":[315.651995307064169,148.062090862911901,72.9207502525545124],"hsluv":[315.651995307064169,100.000000000002444,72.9207502525545124]},"#ff88ff":{"lch":[73.6043362991539709,92.7672005781522842,307.715012949244624],"luv":[73.6043362991539709,56.7488822053271349,-73.3847250560567375],"rgb":[1,0.533333333333333326,1],"xyz":[0.68090932643403379,0.460906798764752879,0.999208883887334753],"hpluv":[307.715012949244624,159.930161835956909,73.6043362991539709],"hsluv":[307.715012949244624,100.000000000002771,73.6043362991539709]},"#ff9900":{"lch":[72.2588108283115389,109.907462524380705,39.4434130396340095],"luv":[72.2588108283115389,84.8763034831777077,69.8259509464759418],"rgb":[1,0.6,0],"xyz":[0.526298138484671219,0.440453684308955595,0.057299931788497],"hpluv":[39.4434130396340095,193.008172097547572,72.2588108283115389],"hsluv":[39.4434130396340095,100.000000000002288,72.2588108283115389]},"#ff9911":{"lch":[72.2858317740783889,108.970035258541955,39.0927051304156805],"luv":[72.2858317740783889,84.5745536570817791,68.7139975401902348],"rgb":[1,0.6,0.0666666666666666657],"xyz":[0.527309803984308378,0.440858350508810448,0.0626280367532526389],"hpluv":[39.0927051304156805,191.2904264008464,72.2858317740783889],"hsluv":[39.0927051304156805,100.000000000001506,72.2858317740783889]},"#ff9922":{"lch":[72.3358777005795304,107.257428554778556,38.4317580680427469],"luv":[72.3358777005795304,84.0200042697796,66.6692947517044274],"rgb":[1,0.6,0.133333333333333331],"xyz":[0.529185162122785324,0.441608493764201249,0.0725049229492318315],"hpluv":[38.4317580680427469,188.15378179700545,72.3358777005795304],"hsluv":[38.4317580680427469,100.00000000000145,72.3358777005795304]},"#ff9933":{"lch":[72.418154282067718,104.508625212907305,37.3122251519614778],"luv":[72.418154282067718,83.1203251002183237,63.3487513620113845],"rgb":[1,0.6,0.2],"xyz":[0.532272912855243141,0.442843594057184375,0.0887670768068429816],"hpluv":[37.3122251519614778,183.123470124205028,72.418154282067718],"hsluv":[37.3122251519614778,100.00000000000162,72.418154282067718]},"#ff9944":{"lch":[72.5366731246789556,100.695423976150749,35.6250099256014607],"luv":[72.5366731246789556,81.8499313718691326,58.6528528219818952],"rgb":[1,0.6,0.266666666666666663],"xyz":[0.536730908099462,0.444626792154871942,0.11224585175972962],"hpluv":[35.6250099256014607,176.153561585765658,72.5366731246789556],"hsluv":[35.6250099256014607,100.000000000001748,72.5366731246789556]},"#ff9955":{"lch":[72.6946936633514582,95.8821930466240673,33.2320443565807508],"luv":[72.6946936633514582,80.201421842029859,52.5464259293328269],"rgb":[1,0.6,0.333333333333333315],"xyz":[0.54269332213882393,0.447011757770616802,0.143647899033703508],"hpluv":[33.2320443565807508,167.368827825995851,72.6946936633514582],"hsluv":[33.2320443565807508,100.000000000001705,72.6946936633514582]},"#ff9966":{"lch":[72.8949069034106,90.2347392462793749,29.9516480142673025],"luv":[72.8949069034106,78.1836232693519406,45.0514064077924345],"rgb":[1,0.6,0.4],"xyz":[0.550278317912332171,0.450045756080020121,0.183595543440847497],"hpluv":[29.9516480142673025,157.078197331028889,72.8949069034106],"hsluv":[29.9516480142673025,100.000000000001819,72.8949069034106]},"#ff9977":{"lch":[73.1395321193821,84.0351966301436,25.5464816978182121],"luv":[73.1395321193821,75.8195571045914,36.2396058633438045],"rgb":[1,0.6,0.466666666666666674],"xyz":[0.559592330932534,0.453771361288100916,0.232649345347245406],"hpluv":[25.5464816978182121,145.796926659053128,73.1395321193821],"hsluv":[25.5464816978182121,100.000000000002018,73.1395321193821]},"#ff9988":{"lch":[73.430374185650777,77.702838567593929,19.7240568661095921],"luv":[73.430374185650777,73.1439295084068419,26.2239718107454713],"rgb":[1,0.6,0.533333333333333326],"xyz":[0.570732748034477932,0.458227528128878514,0.291322208750817546],"hpluv":[19.7240568661095921,134.276641294628575,73.430374185650777],"hsluv":[19.7240568661095921,100.000000000002203,73.430374185650777]},"#ff9999":{"lch":[73.76886125649402,71.8160022700114098,12.1770506300620251],"luv":[73.76886125649402,70.2001752793754,15.1483851545719261],"rgb":[1,0.6,0.6],"xyz":[0.583789712143550577,0.463450313772507672,0.360088886391935481],"hpluv":[12.1770506300620251,123.534275619879125,73.76886125649402],"hsluv":[12.1770506300620251,100.000000000002331,73.76886125649402]},"#ff99aa":{"lch":[74.1560723225582592,67.1124973440613,2.7130535693684088],"luv":[74.1560723225582592,67.0372720786985923,3.17670458229478481],"rgb":[1,0.6,0.66666666666666663],"xyz":[0.598847405108803188,0.469473390958608794,0.439392736008934082],"hpluv":[2.7130535693684088,114.840746523486033,74.1560723225582592],"hsluv":[2.7130535693684088,100.00000000000253,74.1560723225582592]},"#ff99bb":{"lch":[74.5927597146433925,64.4136927281220864,351.502648062184],"luv":[74.5927597146433925,63.7066038913843187,-9.51800564715024322],"rgb":[1,0.6,0.733333333333333282],"xyz":[0.615984997216139751,0.476328427801543552,0.529650721107575828],"hpluv":[351.502648062184,109.577363966618833,74.5927597146433925],"hsluv":[351.502648062184,100.000000000002615,74.5927597146433925]},"#ff99cc":{"lch":[75.0793694015197,64.4152606478183145,339.305696269483292],"luv":[75.0793694015197,60.259134450288677,-22.7631834247409977],"rgb":[1,0.6,0.8],"xyz":[0.635277372659861506,0.484045377979032354,0.631257231777846],"hpluv":[339.305696269483292,108.869813431806975,75.0793694015197],"hsluv":[339.305696269483292,100.000000000002871,75.0793694015197]},"#ff99dd":{"lch":[75.6160606971696296,67.4118390527965232,327.324068761847229],"luv":[75.6160606971696296,56.7430830794555,-36.3947601601954887],"rgb":[1,0.6,0.866666666666666696],"xyz":[0.656795698210495105,0.49265270819928586,0.744587079677852],"hpluv":[327.324068761847229,113.125745227459021,75.6160606971696296],"hsluv":[327.324068761847229,100.00000000000324,75.6160606971696296]},"#ff99ee":{"lch":[76.202726253448489,73.1905233351813393,316.627151984536795],"luv":[76.202726253448489,53.2022056350908201,-50.2630880631028845],"rgb":[1,0.6,0.933333333333333348],"xyz":[0.680607878476669814,0.502177580305755877,0.869997895746375205],"hpluv":[316.627151984536795,123.107716827744753,76.202726253448489],"hsluv":[316.627151984536795,100.000000000003524,76.202726253448489]},"#ff99ff":{"lch":[76.8390127436129,81.2030526869262275,307.715012949245],"luv":[76.8390127436129,49.6746958291708154,-64.2367524082209229],"rgb":[1,0.6,1],"xyz":[0.706778926886501235,0.512645999669688601,1.00783208403815694],"hpluv":[307.715012949245,141.150312559224801,76.8390127436129],"hsluv":[307.715012949245,100.000000000003752,76.8390127436129]},"#ee0000":{"lch":[49.7142799595632,167.190689697178925,12.1770506300617765],"luv":[49.7142799595632,163.428976145092918,35.2660811203203934],"rgb":[0.933333333333333348,0,0],"xyz":[0.352591085030832,0.181804778219026603,0.0165277071108199],"hpluv":[12.1770506300617765,426.746789183125202,49.7142799595632],"hsluv":[12.1770506300617765,100.000000000002217,49.7142799595632]},"#ee0011":{"lch":[49.7630000621001756,165.722449822455,11.6881730851639158],"luv":[49.7630000621001756,162.286136628676445,33.5729092170260728],"rgb":[0.933333333333333348,0,0.0666666666666666657],"xyz":[0.353602750530469079,0.182209444418881455,0.0218558120755755342],"hpluv":[11.6881730851639158,422.585038037937124,49.7630000621001756],"hsluv":[11.6881730851639158,99.9999999999963762,49.7630000621001756]},"#ee0022":{"lch":[49.8531236873270558,163.0858535413212,10.7756858750078184],"luv":[49.8531236873270558,160.210108449799208,30.4912573667411486],"rgb":[0.933333333333333348,0,0.133333333333333331],"xyz":[0.355478108668946136,0.182959587674272284,0.0317326982715547268],"hpluv":[10.7756858750078184,415.110044299310516,49.8531236873270558],"hsluv":[10.7756858750078184,99.9999999999964473,49.8531236873270558]},"#ee0033":{"lch":[50.000975779064234,158.977402767524836,9.25647316775448559],"luv":[50.000975779064234,156.907230803998146,25.5721628363475],"rgb":[0.933333333333333348,0,0.2],"xyz":[0.358565859401403841,0.184194687967255383,0.047994852129165877],"hpluv":[9.25647316775448559,403.456061197389261,50.000975779064234],"hsluv":[9.25647316775448559,99.9999999999965183,50.000975779064234]},"#ee0044":{"lch":[50.2132784041556164,153.529579514286212,7.02933300215353],"luv":[50.2132784041556164,152.375594335021788,18.7885613308314312],"rgb":[0.933333333333333348,0,0.266666666666666663],"xyz":[0.363023854645622757,0.185977886064942977,0.0714736270820525155],"hpluv":[7.02933300215353,387.983100931209492,50.2132784041556164],"hsluv":[7.02933300215353,99.9999999999966462,50.2132784041556164]},"#ee0055":{"lch":[50.4951150037793326,147.071833727726926,3.99754465361350508],"luv":[50.4951150037793326,146.714013644902735,10.2529252527975352],"rgb":[0.933333333333333348,0,0.333333333333333315],"xyz":[0.368986268684984742,0.188362851680687809,0.102875674356026417],"hpluv":[3.99754465361350508,369.589367027053072,50.4951150037793326],"hsluv":[3.99754465361350508,99.999999999996831,50.4951150037793326]},"#ee0066":{"lch":[50.8502318550204109,140.098840030056522,0.0757634158231174915],"luv":[50.8502318550204109,140.0987175463531,0.185255592479522613],"rgb":[0.933333333333333348,0,0.4],"xyz":[0.376571264458492927,0.1913968499900911,0.142823318763170393],"hpluv":[0.0757634158231174915,349.60765112382461,50.8502318550204109],"hsluv":[0.0757634158231174915,99.9999999999970584,50.8502318550204109]},"#ee0077":{"lch":[51.2812017254514956,133.219993530026585,355.209470699020642],"luv":[51.2812017254514956,132.754613083251769,-11.1256182415379214],"rgb":[0.933333333333333348,0,0.466666666666666674],"xyz":[0.385885277478694833,0.195122455198171924,0.191877120669568302],"hpluv":[355.209470699020642,329.648072606093592,51.2812017254514956],"hsluv":[355.209470699020642,99.9999999999973284,51.2812017254514956]},"#ee0088":{"lch":[51.7895361854883163,127.090944021268115,349.407446028193533],"luv":[51.7895361854883163,124.925218603260163,-23.3623160055840167],"rgb":[0.933333333333333348,0,0.533333333333333326],"xyz":[0.397025694580638633,0.199578622038949521,0.250549984073140442],"hpluv":[349.407446028193533,311.395197619459395,51.7895361854883163],"hsluv":[349.407446028193533,99.9999999999974705,51.7895361854883163]},"#ee0099":{"lch":[52.3757812732210652,122.329563392952366,342.780178840499048],"luv":[52.3757812732210652,116.846263825073436,-36.2142611415956637],"rgb":[0.933333333333333348,0,0.6],"xyz":[0.410082658689711388,0.204801407682578679,0.319316661714258376],"hpluv":[342.780178840499048,296.374093031221,52.3757812732210652],"hsluv":[342.780178840499048,99.9999999999978,52.3757812732210652]},"#ee00aa":{"lch":[53.0396114453995722,119.424239873739239,335.563712743666827],"luv":[53.0396114453995722,108.726436909364494,-49.403552366347],"rgb":[0.933333333333333348,0,0.66666666666666663],"xyz":[0.425140351654963888,0.210824484868679773,0.398620511331257],"hpluv":[335.563712743666827,285.713971708863653,53.0396114453995722],"hsluv":[335.563712743666827,99.999999999998,53.0396114453995722]},"#ee00bb":{"lch":[53.779927529436435,118.655378520732356,328.101249142938343],"luv":[53.779927529436435,100.736423933687789,-62.6998544252744381],"rgb":[0.933333333333333348,0,0.733333333333333282],"xyz":[0.442277943762300563,0.217679521711614532,0.488878496429898723],"hpluv":[328.101249142938343,279.966806180862307,53.779927529436435],"hsluv":[328.101249142938343,99.9999999999982094,53.779927529436435]},"#ee00cc":{"lch":[54.5949595671901,120.061129768120921,320.773339602207614],"luv":[54.5949595671901,93.0053918954961,-75.9254368414351575],"rgb":[0.933333333333333348,0,0.8],"xyz":[0.461570319206022317,0.225396471889103334,0.590485007100168824],"hpluv":[320.773339602207614,279.054611328209262,54.5949595671901],"hsluv":[320.773339602207614,99.9999999999984,54.5949595671901]},"#ee00dd":{"lch":[55.4823728661035744,123.466264594666441,313.907226483092529],"luv":[55.4823728661035744,85.6229535549924634,-88.9529556421808252],"rgb":[0.933333333333333348,0,0.866666666666666696],"xyz":[0.483088644756655805,0.234003802109356868,0.703814855000174822],"hpluv":[313.907226483092529,282.379138449157608,55.4823728661035744],"hsluv":[313.907226483092529,99.9999999999986215,55.4823728661035744]},"#ee00ee":{"lch":[56.4393743497109597,128.559742977308588,307.715012949243601],"luv":[56.4393743497109597,78.644409501394918,-101.698890694877051],"rgb":[0.933333333333333348,0,0.933333333333333348],"xyz":[0.506900825022830626,0.243528674215826912,0.829225671068698],"hpluv":[307.715012949243601,289.042783730483393,56.4393743497109597],"hsluv":[307.715012949243601,99.9999999999988489,56.4393743497109597]},"#ee00ff":{"lch":[57.4628159598150745,134.982567880189606,302.284502363601803],"luv":[57.4628159598150745,72.0973885084188879,-114.115118199983058],"rgb":[0.933333333333333348,0,1],"xyz":[0.533071873432661936,0.253997093579759636,0.96705985936047989],"hpluv":[302.284502363601803,298.078126285043766,57.4628159598150745],"hsluv":[302.284502363601803,99.9999999999989484,57.4628159598150745]},"#ee1100":{"lch":[50.1937733395544683,164.746074066243921,12.6667024036514828],"luv":[50.1937733395544683,160.736507742479517,36.1253927174799117],"rgb":[0.933333333333333348,0.0666666666666666657,0],"xyz":[0.354595485291760382,0.185813578740883473,0.0171958405311293527],"hpluv":[12.6667024036514828,416.489977947977081,50.1937733395544683],"hsluv":[12.6667024036514828,100.000000000002245,50.1937733395544683]},"#ee1111":{"lch":[50.2417909300708345,163.305921695383518,12.1770506300617907],"luv":[50.2417909300708345,159.631613634988071,34.4466542507197317],"rgb":[0.933333333333333348,0.0666666666666666657,0.0666666666666666657],"xyz":[0.355607150791397486,0.186218244940738326,0.0225239454958849825],"hpluv":[12.1770506300617907,412.454596338970589,50.2417909300708345],"hsluv":[12.1770506300617907,96.6508962208003197,50.2417909300708345]},"#ee1122":{"lch":[50.3306190654122219,160.718934991358793,11.2629010575952293],"luv":[50.3306190654122219,157.623701713525833,31.390201064696047],"rgb":[0.933333333333333348,0.0666666666666666657,0.133333333333333331],"xyz":[0.357482508929874543,0.186968388196129154,0.032400831691864182],"hpluv":[11.2629010575952293,405.204351077732667,50.3306190654122219],"hsluv":[11.2629010575952293,96.6948337079543592,50.3306190654122219]},"#ee1133":{"lch":[50.4763571232054318,156.685700791802191,9.74029685215880647],"luv":[50.4763571232054318,154.427033260746356,26.5084935615454427],"rgb":[0.933333333333333348,0.0666666666666666657,0.2],"xyz":[0.360570259662332249,0.188203488489112253,0.0486629855494753252],"hpluv":[9.74029685215880647,393.895198182016713,50.4763571232054318],"hsluv":[9.74029685215880647,96.7647175585846,50.4763571232054318]},"#ee1144":{"lch":[50.6856484752898382,151.333831494518165,7.50679337730589413],"luv":[50.6856484752898382,150.036806479185287,19.7708183022028514],"rgb":[0.933333333333333348,0.0666666666666666657,0.266666666666666663],"xyz":[0.365028254906551164,0.189986686586799847,0.0721417605023619568],"hpluv":[7.50679337730589413,378.870112575267399,50.6856484752898382],"hsluv":[7.50679337730589413,96.8605546889772455,50.6856484752898382]},"#ee1155":{"lch":[50.9635312364098496,144.984673036864649,4.46374659640210858],"luv":[50.9635312364098496,144.544902405536135,11.283909082431693],"rgb":[0.933333333333333348,0.0666666666666666657,0.333333333333333315],"xyz":[0.370990668945913149,0.19237165220254468,0.103543807776335872],"hpluv":[4.46374659640210858,360.995599227985224,50.9635312364098496],"hsluv":[4.46374659640210858,96.9801964566503,50.9635312364098496]},"#ee1166":{"lch":[51.3137360134299598,138.123816003378664,0.523151936541392],"luv":[51.3137360134299598,138.118058344046318,1.26115288756691357],"rgb":[0.933333333333333348,0.0666666666666666657,0.4],"xyz":[0.378575664719421334,0.19540565051194797,0.143491452183479834],"hpluv":[0.523151936541392,341.565705345826359,51.3137360134299598],"hsluv":[0.523151936541392,97.1198273857598764,51.3137360134299598]},"#ee1177":{"lch":[51.7388469835676119,131.353183798903302,355.627348241097309],"luv":[51.7388469835676119,130.970848560864681,-10.014775152519368],"rgb":[0.933333333333333348,0.0666666666666666657,0.466666666666666674],"xyz":[0.38788967773962324,0.199131255720028794,0.192545254089877743],"hpluv":[355.627348241097309,322.153744971780554,51.7388469835676119],"hsluv":[355.627348241097309,97.2745732157476,51.7388469835676119]},"#ee1188":{"lch":[52.2404115410600411,125.324707533591734,349.782339698165117],"luv":[52.2404115410600411,123.337180279157977,-22.2311106147846438],"rgb":[0.933333333333333348,0.0666666666666666657,0.533333333333333326],"xyz":[0.39903009484156704,0.203587422560806391,0.251218117493449911],"hpluv":[349.782339698165117,304.417375015566734,52.2404115410600411],"hsluv":[349.782339698165117,97.4391430985313605,52.2404115410600411]},"#ee1199":{"lch":[52.819032808459994,120.657103381490217,343.097768544337384],"luv":[52.819032808459994,115.44498939014953,-35.079780802050081],"rgb":[0.933333333333333348,0.0666666666666666657,0.6],"xyz":[0.412087058950639795,0.208810208204435549,0.31998479513456779],"hpluv":[343.097768544337384,289.869003225703352,52.819032808459994],"hsluv":[343.097768544337384,97.6083995478766298,52.819032808459994]},"#ee11aa":{"lch":[53.4744599034404615,117.843047501566133,335.812437212199143],"luv":[53.4744599034404615,107.497497568615216,-48.2832461723726496],"rgb":[0.933333333333333348,0.0666666666666666657,0.66666666666666663],"xyz":[0.427144751915892296,0.214833285390536644,0.399288644751566446],"hpluv":[335.812437212199143,279.638449078323276,53.4744599034404615],"hsluv":[335.812437212199143,97.7777799659692,53.4744599034404615]},"#ee11bb":{"lch":[54.205681814132376,117.167943285093472,328.276238054291071],"luv":[54.205681814132376,99.6622453247977376,-61.6097702517929662],"rgb":[0.933333333333333348,0.0666666666666666657,0.733333333333333282],"xyz":[0.44428234402322897,0.221688322233471402,0.489546629850208137],"hpluv":[328.276238054291071,274.285798241860448,54.205681814132376],"hsluv":[328.276238054291071,97.9435422525978652,54.205681814132376]},"#ee11cc":{"lch":[55.0110259993956703,118.672848043699901,320.878255441103249],"luv":[55.0110259993956703,92.0672263164348266,-74.8790404666182781],"rgb":[0.933333333333333348,0.0666666666666666657,0.8],"xyz":[0.463574719466950724,0.229405272410960204,0.591153140520478293],"hpluv":[320.878255441103249,273.741691636115945,55.0110259993956703],"hsluv":[320.878255441103249,98.102849778989,55.0110259993956703]},"#ee11dd":{"lch":[55.8882602794840864,122.182226882396691,313.952719233652829],"luv":[55.8882602794840864,84.8023500190691522,-87.9605479586430334],"rgb":[0.933333333333333348,0.0666666666666666657,0.866666666666666696],"xyz":[0.485093045017584212,0.238012602631213738,0.704482988420484291],"hpluv":[313.952719233652829,277.412976370396279,55.8882602794840864],"hsluv":[313.952719233652829,98.2537358693348608,55.8882602794840864]},"#ee11ee":{"lch":[56.83469533821048,127.382376320214306,307.715012949243601],"luv":[56.83469533821048,77.9241738866570302,-100.767519176899128],"rgb":[0.933333333333333348,0.0666666666666666657,0.933333333333333348],"xyz":[0.508905225283758922,0.247537474737683783,0.829893804489007514],"hpluv":[307.715012949243601,284.403630900032795,56.83469533821048],"hsluv":[307.715012949243601,98.3949944120453495,56.83469533821048]},"#ee11ff":{"lch":[57.8472847680859275,133.910906422249354,302.2526850652647],"luv":[57.8472847680859275,71.4621107907268254,-113.248830369952643],"rgb":[0.933333333333333348,0.0666666666666666657,1],"xyz":[0.535076273693590343,0.258005894101616451,0.967727992780789359],"hpluv":[302.2526850652647,293.746227206253536,57.8472847680859275],"hsluv":[302.2526850652647,99.99999999999892,57.8472847680859275]},"#ee2200":{"lch":[51.0646940471157222,160.407609402057773,13.5847947923325787],"luv":[51.0646940471157222,155.919944837816502,37.677207378671163],"rgb":[0.933333333333333348,0.133333333333333331,0],"xyz":[0.358311109026528296,0.19324482621041944,0.018434381776051962],"hpluv":[13.5847947923325787,398.605749597291435,51.0646940471157222],"hsluv":[13.5847947923325787,100.000000000002203,51.0646940471157222]},"#ee2211":{"lch":[51.1114738997186322,159.015005648229618,13.0939108674416342],"luv":[51.1114738997186322,154.880623331235768,36.0244991337056817],"rgb":[0.933333333333333348,0.133333333333333331,0.0666666666666666657],"xyz":[0.3593227745261654,0.193649492410274293,0.0237624867408075952],"hpluv":[13.0939108674416342,394.783534202752207,51.1114738997186322],"hsluv":[13.0939108674416342,96.7702863870018462,51.1114738997186322]},"#ee2222":{"lch":[51.1980191888258105,156.511980987808,12.1770506300618031],"luv":[51.1980191888258105,152.990533465747774,33.0135860305098348],"rgb":[0.933333333333333348,0.133333333333333331,0.133333333333333331],"xyz":[0.361198132664642457,0.194399635665665121,0.0336393729367867877],"hpluv":[12.1770506300618031,387.912483642854795,51.1980191888258105],"hsluv":[12.1770506300618031,90.899918517349,51.1980191888258105]},"#ee2233":{"lch":[51.340031013958,152.605977320930094,10.6487510890373542],"luv":[51.340031013958,149.977869701108148,28.1996970549978769],"rgb":[0.933333333333333348,0.133333333333333331,0.2],"xyz":[0.364285883397100163,0.19563473595864822,0.0499015267943979379],"hpluv":[10.6487510890373542,377.185287566809563,51.340031013958],"hsluv":[10.6487510890373542,91.0856949770771,51.340031013958]},"#ee2244":{"lch":[51.5440125284501391,147.416232714385046,8.4042516634418849],"luv":[51.5440125284501391,145.833202035739902,21.5458314229178391],"rgb":[0.933333333333333348,0.133333333333333331,0.266666666666666663],"xyz":[0.368743878641319078,0.197417934056335814,0.0733803017472845764],"hpluv":[8.4042516634418849,362.916246958463432,51.5440125284501391],"hsluv":[8.4042516634418849,91.3409150161676848,51.5440125284501391]},"#ee2255":{"lch":[51.8149196409757,141.25016266814734,5.34127242035781613],"luv":[51.8149196409757,140.636840571385164,13.1486701942394504],"rgb":[0.933333333333333348,0.133333333333333331,0.333333333333333315],"xyz":[0.374706292680681063,0.199802899672080647,0.104782349021258478],"hpluv":[5.34127242035781613,345.918233291596209,51.8149196409757],"hsluv":[5.34127242035781613,91.6602615743055082,51.8149196409757]},"#ee2266":{"lch":[52.1564522427987924,134.577740656965489,1.36671179444129165],"luv":[52.1564522427987924,134.539455426625494,3.20986196595936],"rgb":[0.933333333333333348,0.133333333333333331,0.4],"xyz":[0.382291288454189249,0.202836897981483938,0.144729993428402454],"hpluv":[1.36671179444129165,327.419481975304109,52.1564522427987924],"hsluv":[1.36671179444129165,92.0339967122243365,52.1564522427987924]},"#ee2277":{"lch":[52.5712108639856694,127.988129961564283,356.416786702014292],"luv":[52.5712108639856694,127.737923683219179,-7.99901644943552803],"rgb":[0.933333333333333348,0.133333333333333331,0.466666666666666674],"xyz":[0.391605301474391154,0.206562503189564761,0.193783795334800363],"hpluv":[356.416786702014292,308.930679724572485,52.5712108639856694],"hsluv":[356.416786702014292,92.4494947830095,52.5712108639856694]},"#ee2288":{"lch":[53.0608018273771194,122.127216672078461,350.491948161024197],"luv":[53.0608018273771194,120.449481512132621,-20.1737318195523763],"rgb":[0.933333333333333348,0.133333333333333331,0.533333333333333326],"xyz":[0.402745718576334955,0.211018670030342359,0.25245665873837253],"hpluv":[350.491948161024197,292.063965437042782,53.0608018273771194],"hsluv":[350.491948161024197,92.892885362452958,53.0608018273771194]},"#ee2299":{"lch":[53.6259244704506557,117.615935516390621,343.699890485995525],"luv":[53.6259244704506557,112.888334232708232,-33.0110933105844282],"rgb":[0.933333333333333348,0.133333333333333331,0.6],"xyz":[0.415802682685407654,0.216241455673971517,0.32122333637949041],"hpluv":[343.699890485995525,278.311211390643507,53.6259244704506557],"hsluv":[343.699890485995525,93.3505397228777412,53.6259244704506557]},"#ee22aa":{"lch":[54.266455218013121,114.955451111725907,336.284451026203612],"luv":[54.266455218013121,105.247863162980167,-46.2346519390706305],"rgb":[0.933333333333333348,0.133333333333333331,0.66666666666666663],"xyz":[0.43086037565066021,0.222264532860072611,0.400527185996489],"hpluv":[336.284451026203612,268.805062052359688,54.266455218013121],"hsluv":[336.284451026203612,93.8102001508292,54.266455218013121]},"#ee22bb":{"lch":[54.981534566577821,114.440827463928798,328.608334651454868],"luv":[54.981534566577821,97.6897319326175,-59.6105633722921],"rgb":[0.933333333333333348,0.133333333333333331,0.733333333333333282],"xyz":[0.447997967757996884,0.22911956970300737,0.490785171095130757],"hpluv":[328.608334651454868,264.121319791368,54.981534566577821],"hsluv":[328.608334651454868,94.2616688954678636,54.981534566577821]},"#ee22cc":{"lch":[55.7696584616915629,116.118636638570607,321.077185717181408],"luv":[55.7696584616915629,90.3394913251054419,-72.9541916679335856],"rgb":[0.933333333333333348,0.133333333333333331,0.8],"xyz":[0.467290343201718583,0.236836519880496171,0.592391681765400913],"hpluv":[321.077185717181408,264.206361207665168,55.7696584616915629],"hsluv":[321.077185717181408,94.6970823725699518,55.7696584616915629]},"#ee22dd":{"lch":[56.6287730491083749,119.812596042269817,314.038835862099],"luv":[56.6287730491083749,83.2872216309056,-86.1295354880806201],"rgb":[0.933333333333333348,0.133333333333333331,0.866666666666666696],"xyz":[0.488808668752352182,0.245443850100749705,0.70572152966540691],"hpluv":[314.038835862099,268.475495638829329,56.6287730491083749],"hsluv":[314.038835862099,95.1108639535381,56.6287730491083749]},"#ee22ee":{"lch":[57.5563705104872128,125.203701850491953,307.715012949243658],"luv":[57.5563705104872128,76.5914038981754,-99.0440498261932163],"rgb":[0.933333333333333348,0.133333333333333331,0.933333333333333348],"xyz":[0.512620849018526892,0.254968722207219722,0.831132345733930133],"hpluv":[307.715012949243658,276.03432908057755,57.5563705104872128],"hsluv":[307.715012949243658,95.4994708803944263,57.5563705104872128]},"#ee22ff":{"lch":[58.5495832280214046,131.922896299071255,302.192710378625122],"luv":[58.5495832280214046,70.2843784028787582,-111.641196341030223],"rgb":[0.933333333333333348,0.133333333333333331,1],"xyz":[0.538791897428358313,0.265437141571152446,0.968966534025712],"hpluv":[302.192710378625122,285.914180736870946,58.5495832280214046],"hsluv":[302.192710378625122,99.9999999999989,58.5495832280214046]},"#ee3300":{"lch":[52.4512471844783761,153.77210005382733,15.1254552240259841],"luv":[52.4512471844783761,148.444942331914945,40.1242800687903269],"rgb":[0.933333333333333348,0.2,0],"xyz":[0.364428831115539142,0.205480270388441244,0.0204736224723888437],"hpluv":[15.1254552240259841,372.015515114283232,52.4512471844783761],"hsluv":[15.1254552240259841,100.000000000002174,52.4512471844783761]},"#ee3311":{"lch":[52.4961529429458693,152.446596739109111,14.6331501802662043],"luv":[52.4961529429458693,147.501711829562538,38.5124637576621893],"rgb":[0.933333333333333348,0.2,0.0666666666666666657],"xyz":[0.365440496615176247,0.205884936588296097,0.0258017274371444769],"hpluv":[14.6331501802662043,368.493287978140756,52.4961529429458693],"hsluv":[14.6331501802662043,96.9493433827183395,52.4961529429458693]},"#ee3322":{"lch":[52.5792408568970302,150.061966488521733,13.7129404445972121],"luv":[52.5792408568970302,145.784540850223095,35.5733247742160685],"rgb":[0.933333333333333348,0.2,0.133333333333333331],"xyz":[0.367315854753653304,0.206635079843686925,0.0356786136331236695],"hpluv":[13.7129404445972121,362.155969729293304,52.5792408568970302],"hsluv":[13.7129404445972121,91.3983957113456,52.5792408568970302]},"#ee3333":{"lch":[52.7156069212027916,146.335083442311,12.177050630061796],"luv":[52.7156069212027916,143.042611430097821,30.8669396171076365],"rgb":[0.933333333333333348,0.2,0.2],"xyz":[0.370403605486111,0.207870180136670024,0.0519407674907348127],"hpluv":[12.177050630061796,352.248031751653059,52.7156069212027916],"hsluv":[12.177050630061796,82.5426319963487316,52.7156069212027916]},"#ee3344":{"lch":[52.9115382124740705,141.372894204534333,9.91688783885485314],"luv":[52.9115382124740705,139.260586308771792,24.3471623953096028],"rgb":[0.933333333333333348,0.2,0.266666666666666663],"xyz":[0.374861600730329925,0.209653378234357618,0.0754195424436214512],"hpluv":[9.91688783885485314,339.043238938553714,52.9115382124740705],"hsluv":[9.91688783885485314,83.0163224279527867,52.9115382124740705]},"#ee3355":{"lch":[53.1718605143623222,135.462446214194244,6.82400118051175664],"luv":[53.1718605143623222,134.502806079917804,16.0956357737583851],"rgb":[0.933333333333333348,0.2,0.333333333333333315],"xyz":[0.38082401476969191,0.212038343850102451,0.106821589717595367],"hpluv":[6.82400118051175664,323.278173463789,53.1718605143623222],"hsluv":[6.82400118051175664,83.6110915378108,53.1718605143623222]},"#ee3366":{"lch":[53.5002196972096158,129.050901787066266,2.79642975700151464],"luv":[53.5002196972096158,128.89722530875369,6.29607494868134765],"rgb":[0.933333333333333348,0.2,0.4],"xyz":[0.388409010543200095,0.215072342159505742,0.146769234124739328],"hpluv":[2.79642975700151464,306.086943567777439,53.5002196972096158],"hsluv":[2.79642975700151464,84.310080928774866,53.5002196972096158]},"#ee3377":{"lch":[53.8992319384372252,122.709031404530748,357.759441587930837],"luv":[53.8992319384372252,122.615219389586755,-4.79732866099687261],"rgb":[0.933333333333333348,0.2,0.466666666666666674],"xyz":[0.397723023563402,0.218797947367586565,0.195823036031137238],"hpluv":[357.759441587930837,288.89051161323988,53.8992319384372252],"hsluv":[357.759441587930837,85.0909052409050872,53.8992319384372252]},"#ee3388":{"lch":[54.3705825415329,117.074862235921088,351.703100554939169],"luv":[54.3705825415329,115.849509832295894,-16.8942131860788436],"rgb":[0.933333333333333348,0.2,0.533333333333333326],"xyz":[0.408863440665345801,0.223254114208364163,0.254495899434709405],"hpluv":[351.703100554939169,273.2366774905733,54.3705825415329],"hsluv":[351.703100554939169,85.9285066952877,54.3705825415329]},"#ee3399":{"lch":[54.9151057717267292,112.774715889061866,344.730687431692274],"luv":[54.9151057717267292,108.793611621096844,-29.6999430015709507],"rgb":[0.933333333333333348,0.2,0.6],"xyz":[0.4219204047744185,0.22847689985199332,0.323262577075827284],"hpluv":[344.730687431692274,260.590898768244074,54.9151057717267292],"hsluv":[344.730687431692274,86.7978129198036896,54.9151057717267292]},"#ee33aa":{"lch":[55.5328602544255,110.325325240584178,337.093995035693695],"luv":[55.5328602544255,101.625579555338021,-42.9408776049389047],"rgb":[0.933333333333333348,0.2,0.66666666666666663],"xyz":[0.436978097739671056,0.234499977038094415,0.402566426692825885],"hpluv":[337.093995035693695,252.095155701888757,55.5328602544255],"hsluv":[337.093995035693695,87.6758366884225779,55.5328602544255]},"#ee33bb":{"lch":[56.2232062298057826,110.03895679054483,329.178007243031175],"luv":[56.2232062298057826,94.4974163460242664,-56.3809392922602726],"rgb":[0.933333333333333348,0.2,0.733333333333333282],"xyz":[0.454115689847007731,0.241355013881029173,0.492824411791467631],"hpluv":[329.178007243031175,248.353441541401367,56.2232062298057826],"hsluv":[329.178007243031175,88.5430404155392665,56.2232062298057826]},"#ee33cc":{"lch":[56.9848866198670123,111.971807156825847,321.417898872172259],"luv":[56.9848866198670123,87.5300782585605788,-69.8295854062993726],"rgb":[0.933333333333333348,0.2,0.8],"xyz":[0.47340806529072943,0.249071964058517975,0.594430922461737787],"hpluv":[321.417898872172259,249.337916143678171,56.9848866198670123],"hsluv":[321.417898872172259,89.3839737673679764,56.9848866198670123]},"#ee33dd":{"lch":[57.8161114567543848,115.945977330727956,314.185904182223908],"luv":[57.8161114567543848,80.813036999634221,-83.1427850752753557],"rgb":[0.933333333333333348,0.2,0.866666666666666696],"xyz":[0.494926390841363029,0.257679294278771509,0.707760770361743785],"hpluv":[314.185904182223908,254.475591939392586,57.8161114567543848],"hsluv":[314.185904182223908,90.1873197259471482,57.8161114567543848]},"#ee33ee":{"lch":[58.7146439354817886,121.632779311923699,307.715012949243715],"luv":[58.7146439354817886,74.4069479563921448,-96.2192241652253415],"rgb":[0.933333333333333348,0.2,0.933333333333333348],"xyz":[0.518738571107537738,0.267204166385241526,0.833171586430267],"hpluv":[307.715012949243715,262.87151341613469,58.7146439354817886],"hsluv":[307.715012949243715,90.9455375510239747,58.7146439354817886]},"#ee33ff":{"lch":[59.6778857977730581,128.651158016084139,302.091050100274117],"luv":[59.6778857977730581,68.3480180420837229,-108.993893813362092],"rgb":[0.933333333333333348,0.2,1],"xyz":[0.544909619517369159,0.27767258574917425,0.971005774722048853],"hpluv":[302.091050100274117,273.551812848380507,59.6778857977730581],"hsluv":[302.091050100274117,99.9999999999986784,59.6778857977730581]},"#ee4400":{"lch":[54.3591594970822598,145.188828472067655,17.4116852889838647],"luv":[54.3591594970822598,138.536177662057611,43.4456372018905412],"rgb":[0.933333333333333348,0.266666666666666663,0],"xyz":[0.373261401598505183,0.223145411354373546,0.023417812633377437],"hpluv":[17.4116852889838647,338.922026437804789,54.3591594970822598],"hsluv":[17.4116852889838647,100.000000000002217,54.3591594970822598]},"#ee4411":{"lch":[54.4016650840252112,143.940172045268554,16.9187727396215735],"luv":[54.4016650840252112,137.710194578710485,41.8888462184768713],"rgb":[0.933333333333333348,0.266666666666666663,0.0666666666666666657],"xyz":[0.374273067098142287,0.223550077554228399,0.0287459175981330667],"hpluv":[16.9187727396215735,335.744689025208913,54.4016650840252112],"hsluv":[16.9187727396215735,97.1754310281257574,54.4016650840252112]},"#ee4422":{"lch":[54.4803236312215944,141.690847159829417,15.9963876830432117],"luv":[54.4803236312215944,136.204446081142294,39.0467032744039173],"rgb":[0.933333333333333348,0.266666666666666663,0.133333333333333331],"xyz":[0.376148425236619344,0.224300220809619227,0.0386228037941122662],"hpluv":[15.9963876830432117,330.020900264600868,54.4803236312215944],"hsluv":[15.9963876830432117,92.0288025918740118,54.4803236312215944]},"#ee4433":{"lch":[54.6094526105793534,138.167821982121467,14.4538486850626899],"luv":[54.6094526105793534,133.794673004457735,34.4867004352900608],"rgb":[0.933333333333333348,0.266666666666666663,0.2],"xyz":[0.37923617596907705,0.225535321102602326,0.0548849576517234095],"hpluv":[14.4538486850626899,321.054243711338643,54.6094526105793534],"hsluv":[14.4538486850626899,83.7991355104008591,54.6094526105793534]},"#ee4444":{"lch":[54.7950558424119549,133.462657054844783,12.1770506300618084],"luv":[54.7950558424119549,130.459808710538397,28.151716454753565],"rgb":[0.933333333333333348,0.266666666666666663,0.266666666666666663],"xyz":[0.383694171213295965,0.22731851920028992,0.078363732604610048],"hpluv":[12.1770506300618084,309.070617226475065,54.7950558424119549],"hsluv":[12.1770506300618084,79.6495466444067546,54.7950558424119549]},"#ee4455":{"lch":[55.04178262974213,127.837203216659944,9.0482956458548145],"luv":[55.04178262974213,126.246413461005446,20.1045670057943724],"rgb":[0.933333333333333348,0.266666666666666663,0.333333333333333315],"xyz":[0.38965658525265795,0.229703484816034753,0.109765779878583963],"hpluv":[9.0482956458548145,294.716259365516066,55.04178262974213],"hsluv":[9.0482956458548145,80.0457187830871106,55.04178262974213]},"#ee4466":{"lch":[55.3531965298607105,121.710491561886229,4.95183922571805102],"luv":[55.3531965298607105,121.256220070521849,10.5058483924504795],"rgb":[0.933333333333333348,0.266666666666666663,0.4],"xyz":[0.397241581026166135,0.232737483125438044,0.149713424285727925],"hpluv":[4.95183922571805102,279.013127650855779,55.3531965298607105],"hsluv":[4.95183922571805102,80.511500113091131,55.3531965298607105]},"#ee4477":{"lch":[55.7319177265462855,115.631099927359429,359.795147057523252],"luv":[55.7319177265462855,115.63036086114974,-0.41342173536332294],"rgb":[0.933333333333333348,0.266666666666666663,0.466666666666666674],"xyz":[0.406555594046368041,0.236463088333518867,0.198767226192125834],"hpluv":[359.795147057523252,263.275227085929203,55.7319177265462855],"hsluv":[359.795147057523252,81.0316034214938412,55.7319177265462855]},"#ee4488":{"lch":[56.1797144871475069,110.229334232011354,353.550243523911263],"luv":[56.1797144871475069,109.531664472369371,-12.3822697089333467],"rgb":[0.933333333333333348,0.266666666666666663,0.533333333333333326],"xyz":[0.417696011148311841,0.240919255174296465,0.257440089595698],"hpluv":[353.550243523911263,248.975712077739217,56.1797144871475069],"hsluv":[353.550243523911263,81.5885451367485217,56.1797144871475069]},"#ee4499":{"lch":[56.6975745677487,106.142668326601637,346.310852745323245],"luv":[56.6975745677487,103.127575819694869,-25.1190992084518889],"rgb":[0.933333333333333348,0.266666666666666663,0.6],"xyz":[0.430752975257384541,0.246142040817925623,0.326206767236815909],"hpluv":[346.310852745323245,237.55536706581762,56.6975745677487],"hsluv":[346.310852745323245,82.1643886194057,56.6975745677487]},"#ee44aa":{"lch":[57.2857706939250164,103.913945498461985,338.339047623856459],"luv":[57.2857706939250164,96.5759938315173798,-38.356035828954532],"rgb":[0.933333333333333348,0.266666666666666663,0.66666666666666663],"xyz":[0.445810668222637096,0.252165118004026745,0.405510616853814509],"hpluv":[338.339047623856459,230.179372132151769,57.2857706939250164],"hsluv":[338.339047623856459,82.742186475039972,57.2857706939250164]},"#ee44bb":{"lch":[57.9439265752057224,103.883653730246948,330.054621671216069],"luv":[57.9439265752057224,90.015359877018625,-51.8560362788815183],"rgb":[0.933333333333333348,0.266666666666666663,0.733333333333333282],"xyz":[0.462948260329973771,0.259020154846961503,0.495768601952456256],"hpluv":[330.054621671216069,227.498543532010189,57.9439265752057224],"hsluv":[330.054621671216069,83.3069826860278,57.9439265752057224]},"#ee44cc":{"lch":[58.6710858878032866,106.123661593235155,321.940977409416575],"luv":[58.6710858878032866,83.5592367986741493,-65.4223623509468837],"rgb":[0.933333333333333348,0.266666666666666663,0.8],"xyz":[0.48224063577369547,0.266737105024450305,0.597375112622726356],"hpluv":[321.940977409416575,229.523641905846944,58.6710858878032866],"hsluv":[321.940977409416575,83.8463488142865288,58.6710858878032866]},"#ee44dd":{"lch":[59.4657843936948041,110.45324904546132,314.41066654104867],"luv":[59.4657843936948041,77.2947793232282407,-78.9014405069524116],"rgb":[0.933333333333333348,0.266666666666666663,0.866666666666666696],"xyz":[0.503758961324329069,0.275344435244703811,0.710704960522732354],"hpluv":[314.41066654104867,235.695163072106425,59.4657843936948041],"hsluv":[314.41066654104867,84.3505154479208699,59.4657843936948041]},"#ee44ee":{"lch":[60.3261240941145189,116.527805305600168,307.715012949243771],"luv":[60.3261240941145189,71.28406005268711,-92.180866733529669],"rgb":[0.933333333333333348,0.266666666666666663,0.933333333333333348],"xyz":[0.527571141590503778,0.284869307351173828,0.836115776591255577],"hpluv":[307.715012949243771,245.111377339321677,60.3261240941145189],"hsluv":[307.715012949243771,84.8122051950840898,60.3261240941145189]},"#ee44ff":{"lch":[61.2498476847862321,123.946828366557639,301.937515996566106],"luv":[61.2498476847862321,65.5671420475233617,-105.184438705774298],"rgb":[0.933333333333333348,0.266666666666666663,1],"xyz":[0.553742190000335199,0.295337726715106552,0.973949964883037422],"hpluv":[301.937515996566106,256.785047727470896,61.2498476847862321],"hsluv":[301.937515996566106,99.9999999999986073,61.2498476847862321]},"#ee5500":{"lch":[56.7595334156469136,135.29504726150742,20.5772435658132551],"luv":[56.7595334156469136,126.663115619922038,47.5521288161507414],"rgb":[0.933333333333333348,0.333333333333333315,0],"xyz":[0.385074658312851148,0.24677192478306581,0.0273555648714926478],"hpluv":[20.5772435658132551,302.470071141489655,56.7595334156469136],"hsluv":[20.5772435658132551,100.000000000002331,56.7595334156469136]},"#ee5511":{"lch":[56.7992830001534799,134.121232245619609,20.0864579205919],"luv":[56.7992830001534799,125.963368804879124,46.0622910677426],"rgb":[0.933333333333333348,0.333333333333333315,0.0666666666666666657],"xyz":[0.386086323812488252,0.247176590982920663,0.0326836698362482775],"hpluv":[20.0864579205919,299.636011805134103,56.7992830001534799],"hsluv":[20.0864579205919,97.4301566790671245,56.7992830001534799]},"#ee5522":{"lch":[56.8728535321199331,132.003018379302972,19.1666168944474329],"luv":[56.8728535321199331,124.685803630375247,43.3387498007741385],"rgb":[0.933333333333333348,0.333333333333333315,0.133333333333333331],"xyz":[0.387961681950965309,0.247926734238311491,0.042560556032227477],"hpluv":[19.1666168944474329,294.522290528054612,56.8728535321199331],"hsluv":[19.1666168944474329,92.7404035063857748,56.8728535321199331]},"#ee5533":{"lch":[56.9936637318031813,128.675597773649343,17.6241311186411558],"luv":[56.9936637318031813,122.635981466153211,38.9592801812266671],"rgb":[0.933333333333333348,0.333333333333333315,0.2],"xyz":[0.391049432683423,0.24916183453129459,0.0588227098898386203],"hpluv":[17.6241311186411558,286.489655583397507,56.9936637318031813],"hsluv":[17.6241311186411558,85.2217597168545353,56.9936637318031813]},"#ee5544":{"lch":[57.1673833238913431,124.212647444540593,15.3377586553938237],"luv":[57.1673833238913431,119.788604494467549,32.8553194848226298],"rgb":[0.933333333333333348,0.333333333333333315,0.266666666666666663],"xyz":[0.39550742792764193,0.250945032628982156,0.0823014848427252588],"hpluv":[15.3377586553938237,275.712737821839653,57.1673833238913431],"hsluv":[15.3377586553938237,78.8138286806830308,57.1673833238913431]},"#ee5555":{"lch":[57.3984455800741813,118.847398490007407,12.1770506300618084],"luv":[57.3984455800741813,116.173386735287238,25.068871978930396],"rgb":[0.933333333333333348,0.333333333333333315,0.333333333333333315],"xyz":[0.401469841967003915,0.253329998244727,0.113703532116699174],"hpluv":[12.1770506300618084,262.741620924066638,57.3984455800741813],"hsluv":[12.1770506300618084,79.1862648733910817,57.3984455800741813]},"#ee5566":{"lch":[57.6903015433249777,112.967028718059339,8.00617638558467881],"luv":[57.6903015433249777,111.865945908872092,15.7340307391382019],"rgb":[0.933333333333333348,0.333333333333333315,0.4],"xyz":[0.409054837740512101,0.256363996554130336,0.153651176523843136],"hpluv":[8.00617638558467881,248.478160638648092,57.6903015433249777],"hsluv":[8.00617638558467881,79.626682914648967,57.6903015433249777]},"#ee5577":{"lch":[58.0455538260385,107.095574323644513,2.70497781295448236],"luv":[58.0455538260385,106.976246145051803,5.05418642558356],"rgb":[0.933333333333333348,0.333333333333333315,0.466666666666666674],"xyz":[0.418368850760714,0.260089601762211131,0.202704978430241045],"hpluv":[2.70497781295448236,234.121819944652458,58.0455538260385],"hsluv":[2.70497781295448236,80.121743738144815,58.0455538260385]},"#ee5588":{"lch":[58.4660405277881523,101.857434077675435,356.214905006905212],"luv":[58.4660405277881523,101.63524992227579,-6.72405012805051783],"rgb":[0.933333333333333348,0.333333333333333315,0.533333333333333326],"xyz":[0.429509267862657806,0.264545768602988729,0.261377841833813185],"hpluv":[356.214905006905212,221.069268787819283,58.4660405277881523],"hsluv":[356.214905006905212,80.6557447307456385,58.4660405277881523]},"#ee5599":{"lch":[58.9528982622070714,97.9100075268454475,348.609359498013816],"luv":[58.9528982622070714,95.9815181358717808,-19.3369529719717974],"rgb":[0.933333333333333348,0.333333333333333315,0.6],"xyz":[0.442566231971730506,0.269768554246617887,0.33014451947493112],"hpluv":[348.609359498013816,210.746926462762332,58.9528982622070714],"hsluv":[348.609359498013816,81.2121283261168685,58.9528982622070714]},"#ee55aa":{"lch":[59.5066178042993812,95.8379147411847327,340.160257686713578],"luv":[59.5066178042993812,90.1495111294489817,-32.5264745255299346],"rgb":[0.933333333333333348,0.333333333333333315,0.66666666666666663],"xyz":[0.457623924936983062,0.275791631432719,0.40944836909192972],"hpluv":[340.160257686713578,204.36730380296666,59.5066178042993812],"hsluv":[340.160257686713578,81.7747968800248515,59.5066178042993812]},"#ee55bb":{"lch":[60.1270988419473156,96.02691270708236,331.338718337462637],"luv":[60.1270988419473156,84.2607812264238305,-46.0574501157669],"rgb":[0.933333333333333348,0.333333333333333315,0.733333333333333282],"xyz":[0.474761517044319736,0.282646668275653767,0.499706354190571467],"hpluv":[331.338718337462637,202.657202566236862,60.1270988419473156],"hsluv":[331.338718337462637,82.3290961128101202,60.1270988419473156]},"#ee55cc":{"lch":[60.8137066481247359,98.5745380895967855,322.704854800823],"luv":[60.8137066481247359,78.4184921400445774,-59.728382282288],"rgb":[0.933333333333333348,0.333333333333333315,0.8],"xyz":[0.494053892488041435,0.290363618453142569,0.601312864860841567],"hpluv":[322.704854800823,205.68499115665557,60.8137066481247359],"hsluv":[322.704854800823,82.862416210457269,60.8137066481247359]},"#ee55dd":{"lch":[61.5653314057239669,103.296154527471415,314.73674606959],"luv":[61.5653314057239669,72.7050419742243577,-73.3762387404091925],"rgb":[0.933333333333333348,0.333333333333333315,0.866666666666666696],"xyz":[0.515572218038675,0.298970948673396075,0.714642712760847565],"hpluv":[314.73674606959,212.905685416828703,61.5653314057239669],"hsluv":[314.73674606959,83.3644351442966496,61.5653314057239669]},"#ee55ee":{"lch":[62.3804497031794796,109.822432229930158,307.715012949243942],"luv":[62.3804497031794796,67.1821530808003473,-86.8764923804219364],"rgb":[0.933333333333333348,0.333333333333333315,0.933333333333333348],"xyz":[0.539384398304849744,0.308495820779866092,0.840053528829370788],"hpluv":[307.715012949243942,223.399338603574023,62.3804497031794796],"hsluv":[307.715012949243942,83.8270760150894318,62.3804497031794796]},"#ee55ff":{"lch":[63.2571870514493355,117.722992850638121,301.718618818209791],"luv":[63.2571870514493355,61.8926401270512301,-100.139922827085911],"rgb":[0.933333333333333348,0.333333333333333315,1],"xyz":[0.565555446714681165,0.318964240143798816,0.977887717121152633],"hpluv":[301.718618818209791,236.15152010236153,63.2571870514493355],"hsluv":[301.718618818209791,99.9999999999986358,63.2571870514493355]},"#ee6600":{"lch":[59.6010827175637274,124.896403377083828,24.7633991985742],"luv":[59.6010827175637274,113.411584725929117,52.315619335764687],"rgb":[0.933333333333333348,0.4,0],"xyz":[0.400102716018697624,0.276828040194759151,0.032364917440108],"hpluv":[24.7633991985742,265.910269095548301,59.6010827175637274],"hsluv":[24.7633991985742,100.000000000002458,59.6010827175637274]},"#ee6611":{"lch":[59.6379025762155521,123.785593795891074,24.2806773941880323],"luv":[59.6379025762155521,112.835768380983566,50.9014990474188],"rgb":[0.933333333333333348,0.4,0.0666666666666666657],"xyz":[0.401114381518334728,0.277232706394614,0.0376930224048636284],"hpluv":[24.2806773941880323,263.38259338209491,59.6379025762155521],"hsluv":[24.2806773941880323,97.6946368166697425,59.6379025762155521]},"#ee6622":{"lch":[59.7060621192549235,121.776511986799889,23.3741045361832462],"luv":[59.7060621192549235,111.782804083827386,48.312768320888857],"rgb":[0.933333333333333348,0.4,0.133333333333333331],"xyz":[0.402989739656811785,0.277982849650004804,0.0475699086008428279],"hpluv":[23.3741045361832462,258.812011755725052,59.7060621192549235],"hsluv":[23.3741045361832462,93.4807634058905847,59.7060621192549235]},"#ee6633":{"lch":[59.818019190990654,118.60827278102343,21.848413141726418],"luv":[59.818019190990654,110.088842330137865,44.1403349161252621],"rgb":[0.933333333333333348,0.4,0.2],"xyz":[0.406077490389269491,0.279217949942987931,0.0638320624584539642],"hpluv":[21.848413141726418,251.606745577849637,59.818019190990654],"hsluv":[21.848413141726418,86.7067277856042722,59.818019190990654]},"#ee6644":{"lch":[59.9790782653121,114.334087778781978,19.5741908506499591],"luv":[59.9790782653121,107.726545105393242,38.3050271878496318],"rgb":[0.933333333333333348,0.4,0.266666666666666663],"xyz":[0.410535485633488406,0.281001148040675497,0.0873108374113406],"hpluv":[19.5741908506499591,241.888527179759762,59.9790782653121],"hsluv":[19.5741908506499591,77.7164494297015551,59.9790782653121]},"#ee6655":{"lch":[60.1934276072459227,109.155383321287928,16.4048569251700904],"luv":[60.1934276072459227,104.711671726378157,30.827966398783424],"rgb":[0.933333333333333348,0.4,0.333333333333333315],"xyz":[0.416497899672850391,0.283386113656420358,0.118712884685314518],"hpluv":[16.4048569251700904,230.109957101660228,60.1934276072459227],"hsluv":[16.4048569251700904,78.0627041699660822,60.1934276072459227]},"#ee6666":{"lch":[60.4643778553048179,103.423697151150392,12.1770506300619203],"luv":[60.4643778553048179,101.096711576265875,21.8155000143976636],"rgb":[0.933333333333333348,0.4,0.4],"xyz":[0.424082895446358576,0.286420111965823676,0.15866052909245848],"hpluv":[12.1770506300619203,217.050003231938149,60.4643778553048179],"hsluv":[12.1770506300619203,78.4746058088251601,60.4643778553048179]},"#ee6677":{"lch":[60.7944870758990845,97.6355083856116,6.72933164538236728],"luv":[60.7944870758990845,96.9628770314166388,11.4408468002682859],"rgb":[0.933333333333333348,0.4,0.466666666666666674],"xyz":[0.433396908466560482,0.290145717173904472,0.207714330998856389],"hpluv":[6.72933164538236728,203.79002370037793,60.7944870758990845],"hsluv":[6.72933164538236728,78.9407958828298177,60.7944870758990845]},"#ee6688":{"lch":[61.1856375663111294,92.4106294683140419,359.951978350089689],"luv":[61.1856375663111294,92.4105970103857,-0.0774526573243247418],"rgb":[0.933333333333333348,0.4,0.533333333333333326],"xyz":[0.444537325568504282,0.294601884014682069,0.266387194402428529],"hpluv":[359.951978350089689,191.6512981090967,61.1856375663111294],"hsluv":[359.951978350089689,79.4474583444281706,61.1856375663111294]},"#ee6699":{"lch":[61.6390913266860281,88.437141466109523,351.875732288608958],"luv":[61.6390913266860281,87.5495765855601746,-12.4979850530316181],"rgb":[0.933333333333333348,0.4,0.6],"xyz":[0.457594289677577,0.299824669658311227,0.335153872043546464],"hpluv":[351.875732288608958,182.061365307506776,61.6390913266860281],"hsluv":[351.875732288608958,79.9795786975914353,61.6390913266860281]},"#ee66aa":{"lch":[62.1555369290736337,86.3639450462453624,342.77320214224],"luv":[62.1555369290736337,82.489654306882187,-25.5770978862333536],"rgb":[0.933333333333333348,0.4,0.66666666666666663],"xyz":[0.472651982642829538,0.305847746844412349,0.414457721660545064],"hpluv":[342.77320214224,176.316102232879075,62.1555369290736337],"hsluv":[342.77320214224,80.5221008496243,62.1555369290736337]},"#ee66bb":{"lch":[62.735134131647655,86.6495273870251168,333.187217955259598],"luv":[62.735134131647655,77.3334216921159765,-39.0855790002422907],"rgb":[0.933333333333333348,0.4,0.733333333333333282],"xyz":[0.489789574750166212,0.312702783687347108,0.504715706759186755],"hpluv":[333.187217955259598,175.264796900814019,62.735134131647655],"hsluv":[333.187217955259598,81.0608551813628679,62.735134131647655]},"#ee66cc":{"lch":[63.3775592853136516,89.4351699392481549,323.800511847500275],"luv":[63.3775592853136516,72.1711045195964545,-52.8202735176909144],"rgb":[0.933333333333333348,0.4,0.8],"xyz":[0.509081950193887911,0.320419733864835909,0.606322217429456911],"hpluv":[323.800511847500275,179.065596131410075,63.3775592853136516],"hsluv":[323.800511847500275,81.5831918811758072,63.3775592853136516]},"#ee66dd":{"lch":[64.0820526997291751,94.5324861988586918,315.200217206616742],"luv":[64.0820526997291751,67.0777383779463179,-66.6105694393704795],"rgb":[0.933333333333333348,0.4,0.866666666666666696],"xyz":[0.53060027574452151,0.329027064085089416,0.719652065329462909],"hpluv":[315.200217206616742,187.190580763285084,64.0820526997291751],"hsluv":[315.200217206616742,82.0783141076240241,64.0820526997291751]},"#ee66ee":{"lch":[64.8474680131467,101.534802649490857,307.715012949244169],"luv":[64.8474680131467,62.1123254704966499,-80.32045302236628],"rgb":[0.933333333333333348,0.4,0.933333333333333348],"xyz":[0.55441245601069622,0.338551936191559433,0.845062881397986132],"hpluv":[307.715012949244169,198.683239249207219,64.8474680131467],"hsluv":[307.715012949244169,82.5373501246235,64.8474680131467]},"#ee66ff":{"lch":[65.6723229483953759,109.966867844968618,301.415067453827589],"luv":[65.6723229483953759,57.3184789471434897,-93.8472375449520797],"rgb":[0.933333333333333348,0.4,1],"xyz":[0.580583504420527641,0.349020355555492157,0.982897069689768088],"hpluv":[301.415067453827589,212.480364902930489,65.6723229483953759],"hsluv":[301.415067453827589,99.9999999999984794,65.6723229483953759]},"#ee7700":{"lch":[62.8217158048736763,114.851740825540901,30.0981414692213356],"luv":[62.8217158048736763,99.3660150566978,57.5961580525066097],"rgb":[0.933333333333333348,0.466666666666666674,0],"xyz":[0.418556454072115225,0.313735516301594908,0.0385161634579137],"hpluv":[30.0981414692213356,231.988851559171735,62.8217158048736763],"hsluv":[30.0981414692213356,100.000000000002203,62.8217158048736763]},"#ee7711":{"lch":[62.8555901763931075,113.786950077776382,29.6341042910547],"luv":[62.8555901763931075,98.9037041004629458,56.2630191441096059],"rgb":[0.933333333333333348,0.466666666666666674,0.0666666666666666657],"xyz":[0.419568119571752329,0.314140182501449761,0.0438442684226693288],"hpluv":[29.6341042910547,229.71421718860654,62.8555901763931075],"hsluv":[29.6341042910547,97.9532933827149463,62.8555901763931075]},"#ee7722":{"lch":[62.9183073649527955,111.855609649988921,28.7604537228304977],"luv":[62.9183073649527955,98.0569879769147406,53.8191835600085398],"rgb":[0.933333333333333348,0.466666666666666674,0.133333333333333331],"xyz":[0.421443477710229386,0.314890325756840561,0.0537211546186485284],"hpluv":[28.7604537228304977,225.59011469442973,62.9183073649527955],"hsluv":[28.7604537228304977,94.206312745702121,62.9183073649527955]},"#ee7733":{"lch":[63.0213536795682501,108.794922632811733,27.2836719807386174],"luv":[63.0213536795682501,96.6912591797812411,49.8711899688373208],"rgb":[0.933333333333333348,0.466666666666666674,0.2],"xyz":[0.424531228442687092,0.316125426049823688,0.0699833084762596647],"hpluv":[27.2836719807386174,219.058559128587405,63.0213536795682501],"hsluv":[27.2836719807386174,88.1668112455654,63.0213536795682501]},"#ee7744":{"lch":[63.1696562136619235,104.634411539935968,25.0668522383795889],"luv":[63.1696562136619235,94.7793214210065571,44.3310309972846497],"rgb":[0.933333333333333348,0.466666666666666674,0.266666666666666663],"xyz":[0.428989223686906,0.317908624147511254,0.0934620834291463],"hpluv":[25.0668522383795889,210.186756956079222,63.1696562136619235],"hsluv":[25.0668522383795889,79.7210233436604199,63.1696562136619235]},"#ee7755":{"lch":[63.3671413614491286,99.5393983003294096,21.9455950678528],"luv":[63.3671413614491286,92.3266881357997278,37.2004633286522051],"rgb":[0.933333333333333348,0.466666666666666674,0.333333333333333315],"xyz":[0.434951637726268,0.320293589763256115,0.124864130703120219],"hpluv":[21.9455950678528,199.328877993420377,63.3671413614491286],"hsluv":[21.9455950678528,76.6090179557391,63.3671413614491286]},"#ee7766":{"lch":[63.6169573916324822,93.8195852400781263,17.7221756586824775],"luv":[63.6169573916324822,89.367258373090749,28.5588463614608763],"rgb":[0.933333333333333348,0.466666666666666674,0.4],"xyz":[0.442536633499776177,0.323327588072659433,0.16481177511026418],"hpluv":[17.7221756586824775,187.13711975631665,63.6169573916324822],"hsluv":[17.7221756586824775,76.9903860669667,63.6169573916324822]},"#ee7777":{"lch":[63.9215909451051232,87.936547917610838,12.1770506300618937],"luv":[63.9215909451051232,85.9580160709841863,18.5487447771187846],"rgb":[0.933333333333333348,0.466666666666666674,0.466666666666666674],"xyz":[0.451850646519978083,0.327053193280740229,0.21386557701666209],"hpluv":[12.1770506300618937,174.56660414904394,63.9215909451051232],"hsluv":[12.1770506300618937,77.4248320836617268,63.9215909451051232]},"#ee7788":{"lch":[64.2829374304473,82.5014209284754543,5.11726519711922112],"luv":[64.2829374304473,82.1725895095950847,7.35866757674724514],"rgb":[0.933333333333333348,0.466666666666666674,0.533333333333333326],"xyz":[0.462991063621921883,0.331509360121517827,0.272538440420234229],"hpluv":[5.11726519711922112,162.85647909200884,64.2829374304473],"hsluv":[5.11726519711922112,77.9003779592442669,64.2829374304473]},"#ee7799":{"lch":[64.7023501026032477,78.2413537817778177,356.48599323172067],"luv":[64.7023501026032477,78.0942478632934893,-4.79561177242263259],"rgb":[0.933333333333333348,0.466666666666666674,0.6],"xyz":[0.476048027730994638,0.336732145765147,0.341305118061352164],"hpluv":[356.48599323172067,153.446019679421255,64.7023501026032477],"hsluv":[356.48599323172067,78.4035888028378167,64.7023501026032477]},"#ee77aa":{"lch":[65.1806796634753596,75.8992199041959,346.522692233148291],"luv":[65.1806796634753596,73.8091300431969302,-17.6890899803221124],"rgb":[0.933333333333333348,0.466666666666666674,0.66666666666666663],"xyz":[0.491105720696247139,0.342755222951248106,0.420608967678350765],"hpluv":[346.522692233148291,147.76029654451807,65.1806796634753596],"hsluv":[346.522692233148291,78.9205551316135256,65.1806796634753596]},"#ee77bb":{"lch":[65.7183104585581646,76.0514193956389875,335.85959217762661],"luv":[65.7183104585581646,69.4004166910179094,-31.1030634376174824],"rgb":[0.933333333333333348,0.466666666666666674,0.733333333333333282],"xyz":[0.508243312803583813,0.349610259794182865,0.510866952776992456],"hpluv":[335.85959217762661,146.845370988132231,65.7183104585581646],"hsluv":[335.85959217762661,79.4377328719524627,65.7183104585581646]},"#ee77cc":{"lch":[66.3151963922866,78.9180750862202416,325.378996221060731],"luv":[66.3151963922866,64.9439055461397459,-44.8369457894756067],"rgb":[0.933333333333333348,0.466666666666666674,0.8],"xyz":[0.527535688247305568,0.357327209971671667,0.612473463447262612],"hpluv":[325.378996221060731,151.008971652655617,66.3151963922866],"hsluv":[325.378996221060731,79.9425706591808307,66.3151963922866]},"#ee77dd":{"lch":[66.9708980107196652,84.3115421117289543,315.859798591258766],"luv":[66.9708980107196652,60.5051526262217152,-58.7159487612646842],"rgb":[0.933333333333333348,0.466666666666666674,0.866666666666666696],"xyz":[0.549054013797939056,0.365934540191925173,0.725803311347268609],"hpluv":[315.859798591258766,159.749768323538632,66.9708980107196652],"hsluv":[315.859798591258766,80.4238985377879345,66.9708980107196652]},"#ee77ee":{"lch":[67.6846211881785251,91.7687338274624409,307.715012949244453],"luv":[67.6846211881785251,56.1380858067324056,-72.5948746830766112],"rgb":[0.933333333333333348,0.466666666666666674,0.933333333333333348],"xyz":[0.572866194064113765,0.37545941229839519,0.851214127415791832],"hpluv":[307.715012949244453,172.045795420537047,67.6846211881785251],"hsluv":[307.715012949244453,80.8720902094370757,67.6846211881785251]},"#ee77ff":{"lch":[68.4552572311626761,100.746525491660947,300.997699928034137],"luv":[68.4552572311626761,51.8848298156272918,-86.3587102361150585],"rgb":[0.933333333333333348,0.466666666666666674,1],"xyz":[0.599037242473945186,0.385927831662327914,0.989048315707573789],"hpluv":[300.997699928034137,186.750854251257437,68.4552572311626761],"hsluv":[300.997699928034137,99.9999999999982,68.4552572311626761]},"#ee8800":{"lch":[66.3576417146455,105.981377873447272,36.6492300119340797],"luv":[66.3576417146455,85.0293774107247771,63.2618165491550428],"rgb":[0.933333333333333348,0.533333333333333326,0],"xyz":[0.440628823797085678,0.35788025575153648,0.045873620032903642],"hpluv":[36.6492300119340797,202.664622836431278,66.3576417146455],"hsluv":[36.6492300119340797,100.000000000002288,66.3576417146455]},"#ee8811":{"lch":[66.3886714607036907,104.946342152180421,36.2201184819273792],"luv":[66.3886714607036907,84.6657638625926552,62.0116373004794923],"rgb":[0.933333333333333348,0.533333333333333326,0.0666666666666666657],"xyz":[0.441640489296722782,0.358284921951391333,0.0512017249976592717],"hpluv":[36.2201184819273792,200.591559481147556,66.3886714607036907],"hsluv":[36.2201184819273792,98.1954604930108701,66.3886714607036907]},"#ee8822":{"lch":[66.4461305943750773,103.062674429887437,35.4099902294173745],"luv":[66.4461305943750773,83.9988395226221201,59.7169140151578],"rgb":[0.933333333333333348,0.533333333333333326,0.133333333333333331],"xyz":[0.443515847435199839,0.359035065206782134,0.0610786111936384712],"hpluv":[35.4099902294173745,196.820821024497235,66.4461305943750773],"hsluv":[35.4099902294173745,94.8869488142181581,66.4461305943750773]},"#ee8833":{"lch":[66.5405621290638578,100.059958052790449,34.0337853874148877],"luv":[66.5405621290638578,82.920456825626232,56.0017235927220369],"rgb":[0.933333333333333348,0.533333333333333326,0.2],"xyz":[0.446603598167657545,0.36027016549976526,0.0773407650512496214],"hpluv":[34.0337853874148877,190.815292572549708,66.5405621290638578],"hsluv":[34.0337853874148877,89.5408718212573689,66.5405621290638578]},"#ee8844":{"lch":[66.6765193585480347,95.9403990837829639,31.9512880443390657],"luv":[66.6765193585480347,81.4052672986078107,50.7714745934935223],"rgb":[0.933333333333333348,0.533333333333333326,0.266666666666666663],"xyz":[0.45106159341187646,0.362053363597452826,0.10081954000413626],"hpluv":[31.9512880443390657,182.586190035925256,66.6765193585480347],"hsluv":[31.9512880443390657,82.0371002457568608,66.6765193585480347]},"#ee8855":{"lch":[66.8576614114874559,90.8274017958005,28.983496619036984],"luv":[66.8576614114874559,79.4521157428502391,44.0111147434430805],"rgb":[0.933333333333333348,0.533333333333333326,0.333333333333333315],"xyz":[0.457024007451238445,0.364438329213197687,0.132221587278110175],"hpluv":[28.983496619036984,172.387208051834335,66.8576614114874559],"hsluv":[28.983496619036984,74.7174368883009663,66.8576614114874559]},"#ee8866":{"lch":[67.0869600103699213,84.978663004295683,24.8971939400565283],"luv":[67.0869600103699213,77.081139807049837,35.7752854921339249],"rgb":[0.933333333333333348,0.533333333333333326,0.4],"xyz":[0.464609003224746631,0.367472327522601,0.172169231685254109],"hpluv":[24.8971939400565283,160.735241770302764,67.0869600103699213],"hsluv":[24.8971939400565283,75.0669061044520447,67.0869600103699213]},"#ee8877":{"lch":[67.3668077908477727,78.8051510957513841,19.4009345351312952],"luv":[67.3668077908477727,74.3303771171996743,26.1772205713113095],"rgb":[0.933333333333333348,0.533333333333333326,0.466666666666666674],"xyz":[0.473923016244948536,0.371197932730681801,0.221223033591652019],"hpluv":[19.4009345351312952,148.438980876884,67.3668077908477727],"hsluv":[19.4009345351312952,75.4672397967126329,67.3668077908477727]},"#ee8888":{"lch":[67.6990830402889117,72.8916076032019191,12.177050630062066],"luv":[67.6990830402889117,71.2515799877231757,15.3752661190709663],"rgb":[0.933333333333333348,0.533333333333333326,0.533333333333333326],"xyz":[0.485063433346892336,0.375654099571459399,0.279895896995224214],"hpluv":[12.177050630062066,136.626224949154164,67.6990830402889117],"hsluv":[12.177050630062066,75.9081099773692927,67.6990830402889117]},"#ee8899":{"lch":[68.0851935471165319,67.9986383575237312,2.99916583787236446],"luv":[68.0851935471165319,67.9055003914663615,3.55778513430191889],"rgb":[0.933333333333333348,0.533333333333333326,0.6],"xyz":[0.498120397455965036,0.380876885215088556,0.348662574636342093],"hpluv":[2.99916583787236446,126.732168582193651,68.0851935471165319],"hsluv":[2.99916583787236446,76.3775584855855385,68.0851935471165319]},"#ee88aa":{"lch":[68.5261104708773274,64.9933943358063573,351.976176804910949],"luv":[68.5261104708773274,64.3571165389368,-9.07209226602857832],"rgb":[0.933333333333333348,0.533333333333333326,0.66666666666666663],"xyz":[0.513178090421217648,0.386899962401189679,0.427966424253340694],"hpluv":[351.976176804910949,120.351764916629207,68.5261104708773274],"hsluv":[351.976176804910949,76.8628030471707859,68.5261104708773274]},"#ee88bb":{"lch":[69.0223979406526098,64.6433047463018,339.810246341231903],"luv":[69.0223979406526098,60.6712812589502875,-22.3103670727442456],"rgb":[0.933333333333333348,0.533333333333333326,0.733333333333333282],"xyz":[0.530315682528554211,0.393754999244124437,0.51822440935198244],"hpluv":[339.810246341231903,118.842788638920595,69.0223979406526098],"hsluv":[339.810246341231903,77.3509666785266887,69.0223979406526098]},"#ee88cc":{"lch":[69.5742414545850778,67.3203562589766307,327.709288072293873],"luv":[69.5742414545850778,56.9091584539883399,-35.9635656031820687],"rgb":[0.933333333333333348,0.533333333333333326,0.8],"xyz":[0.549608057972276,0.401471949421613239,0.619830920022252596],"hpluv":[327.709288072293873,122.782720563937247,69.5742414545850778],"hsluv":[327.709288072293873,77.8296635442389686,69.5742414545850778]},"#ee88dd":{"lch":[70.1814766713242,72.856404222049747,316.817937357318669],"luv":[70.1814766713242,53.1256441200966663,-49.8570112721525547],"rgb":[0.933333333333333348,0.533333333333333326,0.866666666666666696],"xyz":[0.571126383522909564,0.410079279641866745,0.733160767922258594],"hpluv":[316.817937357318669,131.729959343498166,70.1814766713242],"hsluv":[316.817937357318669,78.2874043120714163,70.1814766713242]},"#ee88ee":{"lch":[70.8436192863675558,80.7013698438951224,307.715012949244851],"luv":[70.8436192863675558,49.367799206375345,-63.839889537812887],"rgb":[0.933333333333333348,0.533333333333333326,0.933333333333333348],"xyz":[0.594938563789084274,0.419604151748336762,0.858571583990781817],"hpluv":[307.715012949244851,144.550464850223619,70.8436192863675558],"hsluv":[307.715012949244851,78.7138135635212848,70.8436192863675558]},"#ee88ff":{"lch":[71.5598961203093182,90.2054153167292583,300.42003582834775],"luv":[71.5598961203093182,45.674190228859068,-77.7874366424399426],"rgb":[0.933333333333333348,0.533333333333333326,1],"xyz":[0.621109612198915695,0.430072571112269486,0.996405772282563662],"hpluv":[300.42003582834775,159.956626210428567,71.5598961203093182],"hsluv":[300.42003582834775,99.99999999999784,71.5598961203093182]},"#ee9900":{"lch":[70.1492527845175715,98.9919938823364731,44.3502140795235036],"luv":[70.1492527845175715,70.7872313214223112,69.1995862317686772],"rgb":[0.933333333333333348,0.6,0],"xyz":[0.466498424249553179,0.409619456656472147,0.0544968201837259],"hpluv":[44.3502140795235036,179.06732625175573,70.1492527845175715],"hsluv":[44.3502140795235036,100.000000000002217,70.1492527845175715]},"#ee9911":{"lch":[70.1776126165771785,97.9766822185852533,43.9766782844564119],"luv":[70.1776126165771785,70.5062245085518526,68.0316291449155273],"rgb":[0.933333333333333348,0.6,0.0666666666666666657],"xyz":[0.467510089749190283,0.410024122856327,0.0598249251484815267],"hpluv":[43.9766782844564119,177.15910010767405,70.1776126165771785],"hsluv":[43.9766782844564119,98.4152296143538337,70.1776126165771785]},"#ee9922":{"lch":[70.2301348691785,96.1222676294158447,43.2696050504519505],"luv":[70.2301348691785,69.9901292501651824,65.8852953379296622],"rgb":[0.933333333333333348,0.6,0.133333333333333331],"xyz":[0.46938544788766734,0.410774266111717801,0.0697018113444607262],"hpluv":[43.2696050504519505,173.676009463775955,70.2301348691785],"hsluv":[43.2696050504519505,95.5057584668238,70.2301348691785]},"#ee9933":{"lch":[70.3164728806357573,93.1473438817036339,42.0626701373461103],"luv":[70.3164728806357573,69.1537511222041417,62.4034163964169508],"rgb":[0.933333333333333348,0.6,0.2],"xyz":[0.472473198620125046,0.412009366404700927,0.0859639652020718625],"hpluv":[42.0626701373461103,168.094198140054317,70.3164728806357573],"hsluv":[42.0626701373461103,90.7937976503380213,70.3164728806357573]},"#ee9944":{"lch":[70.4408210614760719,89.024296887742608,40.221678197216157],"luv":[70.4408210614760719,67.9746586813449483,57.4871395488729533],"rgb":[0.933333333333333348,0.6,0.266666666666666663],"xyz":[0.476931193864343961,0.413792564502388494,0.109442740154958501],"hpluv":[40.221678197216157,160.370125602871781,70.4408210614760719],"hsluv":[40.221678197216157,84.1577311163605657,70.4408210614760719]},"#ee9955":{"lch":[70.6065752665828654,83.8291063606938138,37.5652459120346904],"luv":[70.6065752665828654,66.4479455240540631,51.1076276974862154],"rgb":[0.933333333333333348,0.6,0.333333333333333315],"xyz":[0.482893607903705946,0.416177530118133354,0.140844787428932416],"hpluv":[37.5652459120346904,150.656896294971034,70.6065752665828654],"hsluv":[37.5652459120346904,75.5772228053980797,70.6065752665828654]},"#ee9966":{"lch":[70.8165243284349373,77.7550236522342,33.8383101580563],"luv":[70.8165243284349373,64.5842808158336652,43.297971946282189],"rgb":[0.933333333333333348,0.6,0.4],"xyz":[0.490478603677214131,0.419211528427536673,0.180792431836076378],"hpluv":[33.8383101580563,139.326323276972687,70.8165243284349373],"hsluv":[33.8383101580563,72.525293376848623,70.8165243284349373]},"#ee9977":{"lch":[71.0729506656700778,71.1378337295946,28.6840524218341386],"luv":[71.0729506656700778,62.4077841236731601,34.1446901949989154],"rgb":[0.933333333333333348,0.6,0.466666666666666674],"xyz":[0.499792616697416037,0.422937133635617468,0.229846233742474287],"hpluv":[28.6840524218341386,127.009327518651787,71.0729506656700778],"hsluv":[28.6840524218341386,72.8885787597460677,71.0729506656700778]},"#ee9988":{"lch":[71.3776900371935312,64.4963091800695878,21.6331741754282376],"luv":[71.3776900371935312,59.9533946760230378,23.7773918811996943],"rgb":[0.933333333333333348,0.6,0.533333333333333326],"xyz":[0.510933033799359837,0.427393300476395066,0.288519097146046455],"hpluv":[21.6331741754282376,114.659937381049531,71.3776900371935312],"hsluv":[21.6331741754282376,73.2902809537896189,71.3776900371935312]},"#ee9999":{"lch":[71.732171153908709,58.5818834203282179,12.1770506300621602],"luv":[71.732171153908709,57.263818011494017,12.3568690136061505],"rgb":[0.933333333333333348,0.6,0.6],"xyz":[0.523989997908432592,0.432616086120024224,0.35728577478716439],"hpluv":[12.1770506300621602,103.630759412975706,71.732171153908709],"hsluv":[12.1770506300621602,73.7196701825771186,71.732171153908709]},"#ee99aa":{"lch":[72.1374451439022408,54.3863410009709725,0.0659165211073427237],"luv":[72.1374451439022408,54.3863050092105,0.0625693137293968082],"rgb":[0.933333333333333348,0.6,0.66666666666666663],"xyz":[0.539047690873685093,0.438639163306125346,0.436589624404162935],"hpluv":[0.0659165211073427237,95.6683780017161,72.1374451439022408],"hsluv":[0.0659165211073427237,74.1649147609968082,72.1374451439022408]},"#ee99bb":{"lch":[72.5942101669252366,52.9692652640659247,345.882936464906891],"luv":[72.5942101669252366,51.3695627363271683,-12.9194073739288822],"rgb":[0.933333333333333348,0.6,0.733333333333333282],"xyz":[0.556185282981021767,0.445494200149060104,0.526847609502804737],"hpluv":[345.882936464906891,92.5894045166522091,72.5942101669252366],"hsluv":[345.882936464906891,74.6136876066909878,72.5942101669252366]},"#ee99cc":{"lch":[73.1028341171650737,55.013164482536844,331.314039518972208],"luv":[73.1028341171650737,48.2610582375421515,-26.4067893575727517],"rgb":[0.933333333333333348,0.6,0.8],"xyz":[0.575477658424743521,0.453211150326548906,0.628454120173074893],"hpluv":[331.314039518972208,95.4930444317639342,73.1028341171650737],"hsluv":[331.314039518972208,75.0536815693659491,73.1028341171650737]},"#ee99dd":{"lch":[73.6633770412179274,60.4388711558699896,318.269971219550712],"luv":[73.6633770412179274,45.1048908137830935,-40.2294167403973049],"rgb":[0.933333333333333348,0.6,0.866666666666666696],"xyz":[0.596995983975377,0.461818480546802412,0.74178396807308089],"hpluv":[318.269971219550712,104.112780668711437,73.6633770412179274],"hsluv":[318.269971219550712,75.472992612571872,73.6633770412179274]},"#ee99ee":{"lch":[74.2756141069900337,68.5596754700476083,307.71501294924542],"luv":[74.2756141069900337,41.9403078139404499,-54.2350410807456953],"rgb":[0.933333333333333348,0.6,0.933333333333333348],"xyz":[0.620808164241551719,0.471343352653272429,0.867194784141604114],"hpluv":[307.71501294924542,117.128296895720368,74.2756141069900337],"hsluv":[307.71501294924542,75.8603506282489235,74.2756141069900337]},"#ee99ff":{"lch":[74.9390594560707,78.5455210447045857,299.603294913962486],"luv":[74.9390594560707,38.8008486558083519,-68.2927010724659],"rgb":[0.933333333333333348,0.6,1],"xyz":[0.64697921265138314,0.481811772017205153,1.00502897243338585],"hpluv":[299.603294913962486,133.000267199001968,74.9390594560707],"hsluv":[299.603294913962486,99.9999999999973284,74.9390594560707]},"#dd0000":{"lch":[46.1435564305616239,155.182233977468201,12.1770506300617765],"luv":[46.1435564305616239,151.69070515099267,32.7330981276182555],"rgb":[0.866666666666666696,0,0],"xyz":[0.298181282529475455,0.153749723804264049,0.0139772476185688679],"hpluv":[12.1770506300617765,426.746789183125316,46.1435564305616239],"hsluv":[12.1770506300617765,100.000000000002217,46.1435564305616239]},"#dd0011":{"lch":[46.1980288678146636,153.577384001942391,11.5987087531524224],"luv":[46.1980288678146636,150.441300178721519,30.8776306962803169],"rgb":[0.866666666666666696,0,0.0666666666666666657],"xyz":[0.29919294802911256,0.154154390004118902,0.0193053525833244977],"hpluv":[11.5987087531524224,421.835520233675084,46.1980288678146636],"hsluv":[11.5987087531524224,99.9999999999964473,46.1980288678146636]},"#dd0022":{"lch":[46.2987546285526292,150.712226421231577,10.5179424282654246],"luv":[46.2987546285526292,148.17992816752087,27.5115263319381462],"rgb":[0.866666666666666696,0,0.133333333333333331],"xyz":[0.301068306167589617,0.15490453325950973,0.0291822387793036972],"hpluv":[10.5179424282654246,413.065099977246746,46.2987546285526292],"hsluv":[10.5179424282654246,99.9999999999964615,46.2987546285526292]},"#dd0033":{"lch":[46.4638920568500637,146.293058552209629,8.71533624525386585],"luv":[46.4638920568500637,144.603865814948932,22.1671146505918131],"rgb":[0.866666666666666696,0,0.2],"xyz":[0.304156056900047322,0.156139633552492829,0.0454443926369148404],"hpluv":[8.71533624525386585,399.528220173505417,46.4638920568500637],"hsluv":[8.71533624525386585,99.9999999999966,46.4638920568500637]},"#dd0044":{"lch":[46.7007828741672242,140.527307525302433,6.06736355557067153],"luv":[46.7007828741672242,139.740117429456177,14.853408400522655],"rgb":[0.866666666666666696,0,0.266666666666666663],"xyz":[0.308614052144266238,0.157922831650180423,0.0689231675898014789],"hpluv":[6.06736355557067153,381.835137536210595,46.7007828741672242],"hsluv":[6.06736355557067153,99.9999999999967315,46.7007828741672242]},"#dd0055":{"lch":[47.0148448700731194,133.854751810486647,2.4577968894866693],"luv":[47.0148448700731194,133.731616129679537,5.74015936982693],"rgb":[0.866666666666666696,0,0.333333333333333315],"xyz":[0.314576466183628223,0.160307797265925256,0.10032521486377538],"hpluv":[2.4577968894866693,361.275168455412427,47.0148448700731194],"hsluv":[2.4577968894866693,99.9999999999969873,47.0148448700731194]},"#dd0066":{"lch":[47.4099042919878073,126.898325188331157,357.792852491951692],"luv":[47.4099042919878073,126.80418183984473,-4.88716722969802841],"rgb":[0.866666666666666696,0,0.4],"xyz":[0.322161461957136408,0.163341795575328547,0.140272859270919342],"hpluv":[357.792852491951692,339.645713706877359,47.4099042919878073],"hsluv":[357.792852491951692,99.9999999999972857,47.4099042919878073]},"#dd0077":{"lch":[47.8883827301537,120.388643903007392,352.036106438093952],"luv":[47.8883827301537,119.227564738695264,-16.6797298325047478],"rgb":[0.866666666666666696,0,0.466666666666666674],"xyz":[0.331475474977338314,0.16706740078340937,0.189326661177317251],"hpluv":[352.036106438093952,319.002934776287759,47.8883827301537],"hsluv":[352.036106438093952,99.9999999999974136,47.8883827301537]},"#dd0088":{"lch":[48.4514347566520058,115.064311489444805,345.260130057314882],"luv":[48.4514347566520058,111.277652945923506,-29.2759241252361342],"rgb":[0.866666666666666696,0,0.533333333333333326],"xyz":[0.342615892079282114,0.171523567624186968,0.247999524580889419],"hpluv":[345.260130057314882,301.351479235409442,48.4514347566520058],"hsluv":[345.260130057314882,99.9999999999976836,48.4514347566520058]},"#dd0099":{"lch":[49.0990738312553816,111.554442433955828,337.69359677942],"luv":[49.0990738312553816,103.206522936464793,-42.3415546492536166],"rgb":[0.866666666666666696,0,0.6],"xyz":[0.355672856188354869,0.176746353267816125,0.316766202222007354],"hpluv":[337.69359677942,288.305479360883112,49.0990738312553816],"hsluv":[337.69359677942,99.9999999999979252,49.0990738312553816]},"#dd00aa":{"lch":[49.8303011832281442,110.265023964610052,329.72204926251294],"luv":[49.8303011832281442,95.2237329190616606,-55.5951094870335041],"rgb":[0.866666666666666696,0,0.66666666666666663],"xyz":[0.370730549153607369,0.18276943045391722,0.396070051839005954],"hpluv":[329.72204926251294,280.791263168904948,49.8303011832281442],"hsluv":[329.72204926251294,99.9999999999981526,49.8303011832281442]},"#dd00bb":{"lch":[50.6432416523731064,111.311454300018838,321.811503537589374],"luv":[50.6432416523731064,87.4886923962170613,-68.8183737179635244],"rgb":[0.866666666666666696,0,0.733333333333333282],"xyz":[0.387868141260944044,0.189624467296851978,0.486328036937647701],"hpluv":[321.811503537589374,278.905890401213071,50.6432416523731064],"hsluv":[321.811503537589374,99.9999999999984,50.6432416523731064]},"#dd00cc":{"lch":[51.5352850119508901,114.534817141075266,314.3830496716472],"luv":[51.5352850119508901,80.1116001600253753,-81.8557014345352201],"rgb":[0.866666666666666696,0,0.8],"xyz":[0.407160516704665798,0.19734141747434078,0.587934547607917857],"hpluv":[314.3830496716472,282.014975724645751,51.5352850119508901],"hsluv":[314.3830496716472,99.9999999999986215,51.5352850119508901]},"#dd00dd":{"lch":[52.5032286812834883,119.593841400887641,307.715012949243601],"luv":[52.5032286812834883,73.1596596193909647,-94.6062952735996419],"rgb":[0.866666666666666696,0,0.866666666666666696],"xyz":[0.428678842255299286,0.205948747694594314,0.701264395507923854],"hpluv":[307.715012949243601,289.042783730483222,52.5032286812834883],"hsluv":[307.715012949243601,99.9999999999987779,52.5032286812834883]},"#dd00ee":{"lch":[53.5434168792756111,126.080010820296707,301.921476351261958],"luv":[53.5434168792756111,66.6656277920787659,-107.01337860068783],"rgb":[0.866666666666666696,0,0.933333333333333348],"xyz":[0.452491022521474051,0.215473619801064359,0.826675211576447078],"hpluv":[301.921476351261958,298.799235277631283,53.5434168792756111],"hsluv":[301.921476351261958,99.999999999998991,53.5434168792756111]},"#dd00ff":{"lch":[54.6518715304170399,133.605457484958208,296.990855958497434],"luv":[54.6518715304170399,60.6366090811706258,-119.053013019000375],"rgb":[0.866666666666666696,0,1],"xyz":[0.478662070931305417,0.225942039164997055,0.964509399868228923],"hpluv":[296.990855958497434,310.211923209940835,54.6518715304170399],"hsluv":[296.990855958497434,99.99999999999919,54.6518715304170399]},"#dd1100":{"lch":[46.6790301132195,152.538998994032681,12.7564763340959253],"luv":[46.6790301132195,148.773935032481603,33.6817824506429915],"rgb":[0.866666666666666696,0.0666666666666666657,0],"xyz":[0.300185682790403863,0.157758524326120919,0.0146453810388783197],"hpluv":[12.7564763340959253,414.665968881342394,46.6790301132195],"hsluv":[12.7564763340959253,100.000000000002373,46.6790301132195]},"#dd1111":{"lch":[46.7325769897078942,150.969760125239,12.1770506300617818],"luv":[46.7325769897078942,147.573010021229663,31.8445471870185592],"rgb":[0.866666666666666696,0.0666666666666666657,0.0666666666666666657],"xyz":[0.301197348290040967,0.158163190525975772,0.0199734860036339529],"hpluv":[12.1770506300617818,409.92986676092562,46.7325769897078942],"hsluv":[12.1770506300617818,96.0592738250283,46.7325769897078942]},"#dd1122":{"lch":[46.8315975390355774,148.166934443607602,11.093898425687982],"luv":[46.8315975390355774,145.398162733087418,28.509905932130728],"rgb":[0.866666666666666696,0.0666666666666666657,0.133333333333333331],"xyz":[0.303072706428518,0.1589133337813666,0.0298503721996131455],"hpluv":[11.093898425687982,401.468660625611221,46.8315975390355774],"hsluv":[11.093898425687982,96.1199649520447821,46.8315975390355774]},"#dd1133":{"lch":[46.9939567691892393,143.840838530693645,9.28627571582045697],"luv":[46.9939567691892393,141.955717705878527,23.2112265902085468],"rgb":[0.866666666666666696,0.0666666666666666657,0.2],"xyz":[0.30616045716097573,0.160148434074349699,0.0461125260572242957],"hpluv":[9.28627571582045697,388.400266865181436,46.9939567691892393],"hsluv":[9.28627571582045697,96.2159198798013477,46.9939567691892393]},"#dd1144":{"lch":[47.2268997120704555,138.191174032002039,6.62861883301083665],"luv":[47.2268997120704555,137.267398010546174,15.951865839373701],"rgb":[0.866666666666666696,0.0666666666666666657,0.266666666666666663],"xyz":[0.310618452405194645,0.161931632172037293,0.0695913010101109342],"hpluv":[6.62861883301083665,371.304486157060069,47.2268997120704555],"hsluv":[6.62861883301083665,96.346372634165391,47.2268997120704555]},"#dd1155":{"lch":[47.5357948285950442,131.646215003298352,3.00154982487266553],"luv":[47.5357948285950442,131.465612026054913,6.89338663571585908],"rgb":[0.866666666666666696,0.0666666666666666657,0.333333333333333315],"xyz":[0.31658086644455663,0.164316597787782126,0.100993348284084836],"hpluv":[3.00154982487266553,351.420379681935685,47.5357948285950442],"hsluv":[3.00154982487266553,96.5074087268808114,47.5357948285950442]},"#dd1166":{"lch":[47.9244613368761776,124.817323026056556,358.307054390798669],"luv":[47.9244613368761776,124.762840903711279,-3.68750010524401839],"rgb":[0.866666666666666696,0.0666666666666666657,0.4],"xyz":[0.324165862218064815,0.167350596097185417,0.140940992691228811],"hpluv":[358.307054390798669,330.488955339688346,47.9244613368761776],"hsluv":[358.307054390798669,96.6928417837132912,47.9244613368761776]},"#dd1177":{"lch":[48.3953520744879313,118.427317384197096,352.504166614065639],"luv":[48.3953520744879313,117.415279069986227,-15.4493282615978131],"rgb":[0.866666666666666696,0.0666666666666666657,0.466666666666666674],"xyz":[0.333479875238266721,0.17107620130526624,0.189994794597626721],"hpluv":[352.504166614065639,310.51856077863863,48.3953520744879313],"hsluv":[352.504166614065639,96.8952584834877229,48.3953520744879313]},"#dd1188":{"lch":[48.949686611979061,113.213254375126112,345.662599129740954],"luv":[48.949686611979061,109.687147393784173,-28.0351683216148473],"rgb":[0.866666666666666696,0.0666666666666666657,0.533333333333333326],"xyz":[0.344620292340210521,0.175532368146043838,0.248667658001198888],"hpluv":[345.662599129740954,293.48552443008623,48.949686611979061],"hsluv":[345.662599129740954,97.1070447043031209,48.949686611979061]},"#dd1199":{"lch":[49.5875717372425,109.808639676001164,338.012756373247385],"luv":[49.5875717372425,101.821953610845213,-41.1123717433662961],"rgb":[0.866666666666666696,0.0666666666666666657,0.6],"xyz":[0.357677256449283276,0.180755153789673,0.317434335642316767],"hpluv":[338.012756373247385,280.997849503034615,49.5875717372425],"hsluv":[338.012756373247385,97.321211179253126,49.5875717372425]},"#dd11aa":{"lch":[50.3081241313593779,108.626384639058173,329.948207544292131],"luv":[50.3081241313593779,94.0240738412992556,-54.3982074892042462],"rgb":[0.866666666666666696,0.0666666666666666657,0.66666666666666663],"xyz":[0.372734949414535777,0.18677823097577409,0.396738185259315368],"hpluv":[329.948207544292131,273.991145484396441,50.3081241313593779],"hsluv":[329.948207544292131,97.5319211216277751,50.3081241313593779]},"#dd11bb":{"lch":[51.1095995740137,109.78676639377484,321.947120969557943],"luv":[51.1095995740137,86.4507346157054855,-67.6712979010019495],"rgb":[0.866666666666666696,0.0666666666666666657,0.733333333333333282],"xyz":[0.389872541521872451,0.193633267818708849,0.486996170357957114],"hpluv":[321.947120969557943,272.57551535007633,51.1095995740137],"hsluv":[321.947120969557943,97.7347175386083791,51.1095995740137]},"#dd11cc":{"lch":[51.9895276454598303,113.13117809908816,314.441471026924035],"luv":[51.9895276454598303,79.2122218564644527,-80.7718228508547469],"rgb":[0.866666666666666696,0.0666666666666666657,0.8],"xyz":[0.409164916965594205,0.20135021799619765,0.588602681028227326],"hpluv":[314.441471026924035,276.12502270002949,51.9895276454598303],"hsluv":[314.441471026924035,97.9265130550616,51.9895276454598303]},"#dd11dd":{"lch":[52.9448482611329325,118.314931067086022,307.715012949243601],"luv":[52.9448482611329325,72.3773062506166553,-93.594596282658145],"rgb":[0.866666666666666696,0.0666666666666666657,0.866666666666666696],"xyz":[0.430683242516227693,0.209957548216451184,0.701932528928233324],"hpluv":[307.715012949243601,283.566663729067216,52.9448482611329325],"hsluv":[307.715012949243601,98.1054292618058525,52.9448482611329325]},"#dd11ee":{"lch":[53.9720454332022257,124.924845967379298,301.881652150577509],"luv":[53.9720454332022257,65.9811112999591103,-106.078791902980541],"rgb":[0.866666666666666696,0.0666666666666666657,0.933333333333333348],"xyz":[0.454495422782402458,0.219482420322921229,0.827343344996756547],"hpluv":[301.881652150577509,293.71036424495378,53.9720454332022257],"hsluv":[301.881652150577509,98.2705657762439841,53.9720454332022257]},"#dd11ff":{"lch":[55.067273793018515,132.56906123155207,296.926443611211937],"luv":[55.067273793018515,60.0334023394080774,-118.197066796810802],"rgb":[0.866666666666666696,0.0666666666666666657,1],"xyz":[0.480666471192233824,0.229950839686853925,0.965177533288538392],"hpluv":[296.926443611211937,305.483621811531123,55.067273793018515],"hsluv":[296.926443611211937,99.9999999999990763,55.067273793018515]},"#dd2200":{"lch":[47.6481385708110494,147.881667770992,13.8451074484812633],"luv":[47.6481385708110494,143.585141583480663,35.3877772568702937],"rgb":[0.866666666666666696,0.133333333333333331,0],"xyz":[0.303901306525171777,0.165189771795656887,0.0158839222838009289],"hpluv":[13.8451074484812633,393.829031299888356,47.6481385708110494],"hsluv":[13.8451074484812633,100.000000000002302,47.6481385708110494]},"#dd2211":{"lch":[47.7000692420668,146.371743885583,13.2640103652051735],"luv":[47.7000692420668,142.467011758872331,33.583298953557744],"rgb":[0.866666666666666696,0.133333333333333331,0.0666666666666666657],"xyz":[0.304912972024808882,0.16559443799551174,0.0212120272485565586],"hpluv":[13.2640103652051735,389.383517616197651,47.7000692420668],"hsluv":[13.2640103652051735,96.2235359913314596,47.7000692420668]},"#dd2222":{"lch":[47.796111526211412,143.672697420673273,12.1770506300617871],"luv":[47.796111526211412,140.440127868319678,30.3053537920670948],"rgb":[0.866666666666666696,0.133333333333333331,0.133333333333333331],"xyz":[0.306788330163285938,0.166344581250902568,0.0310889134445357582],"hpluv":[12.1770506300617871,381.435408792809369,47.796111526211412],"hsluv":[12.1770506300617871,89.3821391188339618,47.796111526211412]},"#dd2233":{"lch":[47.9536166692339805,139.501418135148583,10.3611027729364178],"luv":[47.9536166692339805,137.226679529052944,25.0895214611231978],"rgb":[0.866666666666666696,0.133333333333333331,0.2],"xyz":[0.309876080895743644,0.167579681543885667,0.0473510673021469],"hpluv":[10.3611027729364178,369.144652707036585,47.9536166692339805],"hsluv":[10.3611027729364178,89.634195646670733,47.9536166692339805]},"#dd2244":{"lch":[48.1796580724099073,134.044487106872765,7.68678657448498281],"luv":[48.1796580724099073,132.839973125453383,17.9294747210675],"rgb":[0.866666666666666696,0.133333333333333331,0.266666666666666663],"xyz":[0.314334076139962559,0.169362879641573261,0.0708298422550335399],"hpluv":[7.68678657448498281,353.040533161258963,48.1796580724099073],"hsluv":[7.68678657448498281,89.9776949827144819,48.1796580724099073]},"#dd2255":{"lch":[48.4795139291676236,127.710640494506933,4.02871777991100277],"luv":[48.4795139291676236,127.395062601571667,8.9724979943620351],"rgb":[0.866666666666666696,0.133333333333333331,0.333333333333333315],"xyz":[0.320296490179324544,0.171747845257318094,0.102231889529007441],"hpluv":[4.02871777991100277,334.278275235680212,48.4795139291676236],"hsluv":[4.02871777991100277,90.4030378986951746,48.4795139291676236]},"#dd2266":{"lch":[48.8569858046774499,121.091623353111601,359.280669781128381],"luv":[48.8569858046774499,121.082080247128843,-1.52022673298942879],"rgb":[0.866666666666666696,0.133333333333333331,0.4],"xyz":[0.32788148595283273,0.174781843566721384,0.142179533936151403],"hpluv":[359.280669781128381,314.504423311283745,48.8569858046774499],"hsluv":[359.280669781128381,90.8946273178398627,48.8569858046774499]},"#dd2277":{"lch":[49.3145747506863046,114.897314975199777,353.392641366134796],"luv":[49.3145747506863046,114.134166521370943,-13.2206286152450421],"rgb":[0.866666666666666696,0.133333333333333331,0.466666666666666674],"xyz":[0.337195498973034635,0.178507448774802208,0.191233335842549312],"hpluv":[353.392641366134796,295.64729776044,49.3145747506863046],"hsluv":[353.392641366134796,91.4334620569677128,49.3145747506863046]},"#dd2288":{"lch":[49.8536069462695934,109.863045744465836,346.42832123602642],"luv":[49.8536069462695934,106.795352255968297,-25.780643063628979],"rgb":[0.866666666666666696,0.133333333333333331,0.533333333333333326],"xyz":[0.348335916074978436,0.182963615615579805,0.24990619924612148],"hpluv":[346.42832123602642,279.636833718457694,49.8536069462695934],"hsluv":[346.42832123602642,91.999736258284841,49.8536069462695934]},"#dd2299":{"lch":[50.4743452384724947,106.631383564155598,338.620922954440232],"luv":[50.4743452384724947,99.2939711585852507,-38.8710593162073792],"rgb":[0.866666666666666696,0.133333333333333331,0.6],"xyz":[0.361392880184051135,0.188186401259208963,0.318672876887239387],"hpluv":[338.620922954440232,268.07337181170567,50.4743452384724947],"hsluv":[338.620922954440232,92.5749897333771088,50.4743452384724947]},"#dd22aa":{"lch":[51.176101525576982,105.62881092572934,330.379319008457628],"luv":[51.176101525576982,91.8248770713425699,-52.2076397514415902],"rgb":[0.866666666666666696,0.133333333333333331,0.66666666666666663],"xyz":[0.376450573149303691,0.194209478445310058,0.397976726504238],"hpluv":[330.379319008457628,261.911470041672374,51.176101525576982],"hsluv":[330.379319008457628,93.1435427232804898,51.176101525576982]},"#dd22bb":{"lch":[51.9573548685870321,106.984993341056935,322.205396597718504],"luv":[51.9573548685870321,84.5409044706425306,-65.5638945721781425],"rgb":[0.866666666666666696,0.133333333333333331,0.733333333333333282],"xyz":[0.393588165256640365,0.201064515288244816,0.488234711602879734],"hpluv":[322.205396597718504,261.285408571692301,51.9573548685870321],"hsluv":[322.205396597718504,93.6931794305449301,51.9573548685870321]},"#dd22cc":{"lch":[52.8158750154556174,110.541708291411879,314.55250800555325],"luv":[52.8158750154556174,77.5519304210182838,-78.7728846745956],"rgb":[0.866666666666666696,0.133333333333333331,0.8],"xyz":[0.412880540700362064,0.208781465465733618,0.58984122227315],"hpluv":[314.55250800555325,265.583456637160452,52.8158750154556174],"hsluv":[314.55250800555325,94.2152138812719073,52.8158750154556174]},"#dd22dd":{"lch":[53.7488483860564088,115.947384169062644,307.715012949243658],"luv":[53.7488483860564088,70.9289965118926204,-91.721716891171],"rgb":[0.866666666666666696,0.133333333333333331,0.866666666666666696],"xyz":[0.434398866250995663,0.217388795685987152,0.703171070173155943],"hpluv":[307.715012949243658,273.735496610715643,53.7488483860564088],"hsluv":[307.715012949243658,94.704144859729837,53.7488483860564088]},"#dd22ee":{"lch":[54.7530025006588374,122.779599443276055,301.806367069585178],"luv":[54.7530025006588374,64.7110170709106,-104.342293961267828],"rgb":[0.866666666666666696,0.133333333333333331,0.933333333333333348],"xyz":[0.458211046517170373,0.226913667792457197,0.828581886241679166],"hpluv":[301.806367069585178,284.549350776984397,54.7530025006588374],"hsluv":[301.806367069585178,95.1571011878196629,54.7530025006588374]},"#dd22ff":{"lch":[55.8247247862810525,130.638613434108407,296.804995701950531],"luv":[55.8247247862810525,58.9121835814083425,-116.601037498200881],"rgb":[0.866666666666666696,0.133333333333333331,1],"xyz":[0.484382094927001794,0.237382087156389893,0.966416074533461],"hpluv":[296.804995701950531,296.950662194199822,55.8247247862810525],"hsluv":[296.804995701950531,99.9999999999989768,55.8247247862810525]},"#dd3300":{"lch":[49.1823134049741526,140.84390252957769,15.6779143459349193],"luv":[49.1823134049741526,135.603943521894649,38.06015476941716],"rgb":[0.866666666666666696,0.2,0],"xyz":[0.310019028614182623,0.17742521597367869,0.0179231629801378106],"hpluv":[15.6779143459349193,363.386194305474646,49.1823134049741526],"hsluv":[15.6779143459349193,100.000000000002331,49.1823134049741526]},"#dd3311":{"lch":[49.2318310772226226,139.415415721210906,15.0950854994101622],"luv":[49.2318310772226226,134.60488288385605,36.3067988748864323],"rgb":[0.866666666666666696,0.2,0.0666666666666666657],"xyz":[0.311030694113819728,0.177829882173533543,0.0232512679448934403],"hpluv":[15.0950854994101622,359.338818773581409,49.2318310772226226],"hsluv":[15.0950854994101622,96.4660724045404834,49.2318310772226226]},"#dd3322":{"lch":[49.3234253076193,136.858666305461554,14.0037238091571297],"luv":[49.3234253076193,132.791226888227897,33.117738516222083],"rgb":[0.866666666666666696,0.2,0.133333333333333331],"xyz":[0.312906052252296785,0.178580025428924372,0.0331281541408726399],"hpluv":[14.0037238091571297,352.093818956611813,49.3234253076193],"hsluv":[14.0037238091571297,90.0546185843159321,49.3234253076193]},"#dd3333":{"lch":[49.4736766963079901,132.899088309008249,12.1770506300618315],"luv":[49.4736766963079901,129.908920002044738,28.0328410488111714],"rgb":[0.866666666666666696,0.2,0.2],"xyz":[0.31599380298475449,0.179815125721907471,0.0493903079984837831],"hpluv":[12.1770506300618315,340.868713502871344,49.4736766963079901],"hsluv":[12.1770506300618315,79.876105021286179,49.4736766963079901]},"#dd3344":{"lch":[49.6893958667399289,127.704341644457742,9.47932118493828391],"luv":[49.6893958667399289,125.960552293014786,21.031836364974712],"rgb":[0.866666666666666696,0.2,0.266666666666666663],"xyz":[0.320451798228973406,0.181598323819595064,0.0728690829513704286],"hpluv":[9.47932118493828391,326.122882655454703,49.6893958667399289],"hsluv":[9.47932118493828391,80.502956859434363,49.6893958667399289]},"#dd3355":{"lch":[49.9757165444531495,121.655077778432485,5.77481987360355742],"luv":[49.9757165444531495,121.037681249067731,12.2408197080725127],"rgb":[0.866666666666666696,0.2,0.333333333333333315],"xyz":[0.326414212268335391,0.183983289435339897,0.10427113022534433],"hpluv":[5.77481987360355742,308.89475746512926,49.9757165444531495],"hsluv":[5.77481987360355742,81.2827465905028674,49.9757165444531495]},"#dd3366":{"lch":[50.3364012453720164,115.314978813651479,0.942739432835561],"luv":[50.3364012453720164,115.29936949267524,1.8972963354308543],"rgb":[0.866666666666666696,0.2,0.4],"xyz":[0.333999208041843576,0.187017287744743188,0.144218774632488278],"hpluv":[0.942739432835561,290.698564526315124,50.3364012453720164],"hsluv":[0.942739432835561,82.1889615211792375,50.3364012453720164]},"#dd3377":{"lch":[50.77400791740952,109.376176789803836,354.916348657894],"luv":[50.77400791740952,108.945933542464203,-9.69183231981436],"rgb":[0.866666666666666696,0.2,0.466666666666666674],"xyz":[0.343313221062045482,0.190742892952824,0.193272576538886187],"hpluv":[354.916348657894,273.35096965093777,50.77400791740952],"hsluv":[354.916348657894,83.1884512053650269,50.77400791740952]},"#dd3388":{"lch":[51.2900053848270545,104.574014460431073,347.747121452304157],"luv":[51.2900053848270545,102.191864987712989,-22.1934051173651383],"rgb":[0.866666666666666696,0.2,0.533333333333333326],"xyz":[0.354453638163989282,0.195199059793601609,0.251945439942458382],"hpluv":[347.747121452304157,258.720214242298141,51.2900053848270545],"hsluv":[347.747121452304157,84.245872474104587,51.2900053848270545]},"#dd3399":{"lch":[51.8848727297214509,101.568582070491487,339.671486537323062],"luv":[51.8848727297214509,95.2425012264059347,-35.2851643605103433],"rgb":[0.866666666666666696,0.2,0.6],"xyz":[0.367510602273062,0.200421845437230767,0.320712117583576262],"hpluv":[339.671486537323062,248.403642764366595,51.8848727297214509],"hsluv":[339.671486537323062,85.3275173092541763,51.8848727297214509]},"#dd33aa":{"lch":[52.5581975758694284,100.811065681036794,331.124654782349864],"luv":[52.5581975758694284,88.2774684157494,-48.6822301651504219],"rgb":[0.866666666666666696,0.2,0.66666666666666663],"xyz":[0.382568295238314537,0.206444922623331861,0.400015967200574862],"hpluv":[331.124654782349864,243.392431352391867,52.5581975758694284],"hsluv":[331.124654782349864,86.4040244757801,52.5581975758694284]},"#dd33bb":{"lch":[53.3087788146031301,102.447919096954379,322.651217662355],"luv":[53.3087788146031301,81.4417156804123579,-62.1516136100020091],"rgb":[0.866666666666666696,0.2,0.733333333333333282],"xyz":[0.399705887345651212,0.21329995946626662,0.490273952299216609],"hpluv":[322.651217662355,243.861776984359892,53.3087788146031301],"hsluv":[322.651217662355,87.4518397844355633,53.3087788146031301]},"#dd33cc":{"lch":[54.1347343907921612,106.321268361530926,314.743497623169446],"luv":[54.1347343907921612,74.8431687457043751,-75.5163041872859253],"rgb":[0.866666666666666696,0.2,0.8],"xyz":[0.418998262789372911,0.221016909643755421,0.59188046296948682],"hpluv":[314.743497623169446,249.220329072313831,54.1347343907921612],"hsluv":[314.743497623169446,88.4535853271675734,54.1347343907921612]},"#dd33dd":{"lch":[55.033612168624586,112.066789743934578,307.715012949243715],"luv":[55.033612168624586,68.5551036430149,-88.6519211749340741],"rgb":[0.866666666666666696,0.2,0.866666666666666696],"xyz":[0.44051658834000651,0.229624239864008955,0.705210310869492818],"hpluv":[307.715012949243715,258.397459164480438,55.033612168624586],"hsluv":[307.715012949243715,89.3976510430439077,55.033612168624586]},"#dd33ee":{"lch":[56.0025007026426351,119.245240694744666,301.678101579798295],"luv":[56.0025007026426351,62.6212128139869506,-101.479116738632214],"rgb":[0.866666666666666696,0.2,0.933333333333333348],"xyz":[0.464328768606181219,0.239149111970479,0.830621126938016],"hpluv":[301.678101579798295,270.192295422478139,56.0025007026426351],"hsluv":[301.678101579798295,90.277343199481848,56.0025007026426351]},"#dd33ff":{"lch":[57.0381364623091116,127.442655532056975,296.59904001960814],"luv":[57.0381364623091116,57.0616979163907772,-113.954346472440875],"rgb":[0.866666666666666696,0.2,1],"xyz":[0.49049981701601264,0.249617531334411696,0.968455315229797886],"hpluv":[296.59904001960814,283.523336448078851,57.0381364623091116],"hsluv":[296.59904001960814,99.9999999999989626,57.0381364623091116]},"#dd4400":{"lch":[51.2775121999195278,131.902040393952689,18.409420821930695],"luv":[51.2775121999195278,125.151834557466444,41.6553305951168156],"rgb":[0.866666666666666696,0.266666666666666663,0],"xyz":[0.318851599097148664,0.19509035693961102,0.0208673531411264039],"hpluv":[18.409420821930695,326.410329295551833,51.2775121999195278],"hsluv":[18.409420821930695,100.000000000002245,51.2775121999195278]},"#dd4411":{"lch":[51.3239968707682124,130.563017922041524,17.8265447991253865],"luv":[51.3239968707682124,124.294382399750674,39.9700907276414128],"rgb":[0.866666666666666696,0.266666666666666663,0.0666666666666666657],"xyz":[0.319863264596785768,0.195495023139465873,0.0261954581058820371],"hpluv":[17.8265447991253865,322.804096021626094,51.3239968707682124],"hsluv":[17.8265447991253865,96.7659447415066154,51.3239968707682124]},"#dd4422":{"lch":[51.4099976690743148,128.162025810787327,16.7333496749677373],"luv":[51.4099976690743148,122.735013936090269,36.9001519513490237],"rgb":[0.866666666666666696,0.266666666666666663,0.133333333333333331],"xyz":[0.321738622735262825,0.196245166394856702,0.0360723443018612297],"hpluv":[16.7333496749677373,316.337811591652041,51.4099976690743148],"hsluv":[16.7333496749677373,90.8878404873512551,51.4099976690743148]},"#dd4433":{"lch":[51.551120550377874,124.432504768689228,14.8985084842763058],"luv":[51.551120550377874,120.249428964759446,31.9925472049216744],"rgb":[0.866666666666666696,0.266666666666666663,0.2],"xyz":[0.324826373467720531,0.197480266687839801,0.0523344981594723729],"hpluv":[14.8985084842763058,306.291581325991444,51.551120550377874],"hsluv":[14.8985084842763058,81.5276169642245634,51.551120550377874]},"#dd4444":{"lch":[51.7538349343952575,119.518854000271219,12.1770506300618191],"luv":[51.7538349343952575,116.829734805674121,25.2105042943215345],"rgb":[0.866666666666666696,0.266666666666666663,0.266666666666666663],"xyz":[0.329284368711939446,0.199263464785527394,0.0758132731123590115],"hpluv":[12.1770506300618191,293.044254198223086,51.7538349343952575],"hsluv":[12.1770506300618191,68.6693518559736,51.7538349343952575]},"#dd4455":{"lch":[52.0230766847265045,113.767549619287195,8.41751308754220773],"luv":[52.0230766847265045,112.542004033713866,16.6539086839248256],"rgb":[0.866666666666666696,0.266666666666666663,0.333333333333333315],"xyz":[0.335246782751301431,0.201648430401272227,0.107215320386332927],"hpluv":[8.41751308754220773,277.499175779034886,52.0230766847265045],"hsluv":[8.41751308754220773,69.8262296658756867,52.0230766847265045]},"#dd4466":{"lch":[52.3625377834239316,107.708396397149357,3.47572472865958737],"luv":[52.3625377834239316,107.51027478189765,6.52989056311981209],"rgb":[0.866666666666666696,0.266666666666666663,0.4],"xyz":[0.342831778524809616,0.204682428710675518,0.147162964793476875],"hpluv":[3.47572472865958737,261.016642983210886,52.3625377834239316],"hsluv":[3.47572472865958737,71.1800009153795088,52.3625377834239316]},"#dd4477":{"lch":[52.7748219535637304,102.013560717275851,357.256373562230806],"luv":[52.7748219535637304,101.896624345108023,-4.88308481282748108],"rgb":[0.866666666666666696,0.266666666666666663,0.466666666666666674],"xyz":[0.352145791545011522,0.208408033918756341,0.196216766699874784],"hpluv":[357.256373562230806,245.284698321799027,52.7748219535637304],"hsluv":[357.256373562230806,72.6848757644217898,52.7748219535637304]},"#dd4488":{"lch":[53.2615487789460502,97.4233940898595137,349.787328406912707],"luv":[53.2615487789460502,95.8798587184095368,-17.273401753155067],"rgb":[0.866666666666666696,0.266666666666666663,0.533333333333333326],"xyz":[0.363286208646955322,0.212864200759533939,0.254889630103446951],"hpluv":[349.787328406912707,232.107295472344475,53.2615487789460502],"hsluv":[349.787328406912707,74.290572198007979,53.2615487789460502]},"#dd4499":{"lch":[53.8234397136373133,94.6288173232078123,341.30539151945959],"luv":[53.8234397136373133,89.63624285692255,-30.330793502376995],"rgb":[0.866666666666666696,0.266666666666666663,0.6],"xyz":[0.376343172756028,0.218086986403163097,0.323656307744564886],"hpluv":[341.30539151945959,223.095746339835301,53.8234397136373133],"hsluv":[341.30539151945959,75.9477058190526577,53.8234397136373133]},"#dd44aa":{"lch":[54.4604007326765327,94.1226543521493539,332.285935566136516],"luv":[54.4604007326765327,83.3248558176969425,-43.7726223255380802],"rgb":[0.866666666666666696,0.266666666666666663,0.66666666666666663],"xyz":[0.391400865721280578,0.224110063589264191,0.402960157361563487],"hpluv":[332.285935566136516,219.307083848265933,54.4604007326765327],"hsluv":[332.285935566136516,77.6118806813578175,54.4604007326765327]},"#dd44bb":{"lch":[55.1716077278512387,96.0796222427451596,323.344264550451],"luv":[55.1716077278512387,77.0786382371216,-57.3600674495728526],"rgb":[0.866666666666666696,0.266666666666666663,0.733333333333333282],"xyz":[0.408538457828617252,0.23096510043219895,0.493218142460205233],"hpluv":[323.344264550451,220.981019921853772,55.1716077278512387],"hsluv":[323.344264550451,79.2461809113807334,55.1716077278512387]},"#dd44cc":{"lch":[55.9555962107488511,100.342448880687911,315.038748994660807],"luv":[55.9555962107488511,71.0007950362134,-70.9048246002984],"rgb":[0.866666666666666696,0.266666666666666663,0.8],"xyz":[0.427830833272338951,0.238682050609687751,0.594824653130475389],"hpluv":[315.038748994660807,227.551915064947707,55.9555962107488511],"hsluv":[315.038748994660807,80.8221578956601547,55.9555962107488511]},"#dd44dd":{"lch":[56.8103543983327484,106.525561993860563,307.715012949243828],"luv":[56.8103543983327484,65.1653443433699664,-84.2684594300729515],"rgb":[0.866666666666666696,0.266666666666666663,0.866666666666666696],"xyz":[0.44934915882297255,0.247289380829941285,0.708154501030481387],"hpluv":[307.715012949243828,237.939016458104504,56.8103543983327484],"hsluv":[307.715012949243828,82.3196529548951474,56.8103543983327484]},"#dd44ee":{"lch":[57.7334174818232384,114.162073161526394,301.482814132357476],"luv":[57.7334174818232384,59.6203198077272134,-97.3570563162323452],"rgb":[0.866666666666666696,0.266666666666666663,0.933333333333333348],"xyz":[0.473161339089147259,0.256814252936411302,0.83356531709900461],"hpluv":[301.482814132357476,250.91920763959763,57.7334174818232384],"hsluv":[301.482814132357476,85.8927976857303577,57.7334174818232384]},"#dd44ff":{"lch":[58.721960397178492,122.814959128704743,296.287773174859751],"luv":[58.721960397178492,54.3922733794591196,-110.113554035820684],"rgb":[0.866666666666666696,0.266666666666666663,1],"xyz":[0.49933238749897868,0.267282672300344,0.971399505390786455],"hpluv":[296.287773174859751,265.393357493052918,58.721960397178492],"hsluv":[296.287773174859751,99.9999999999987779,58.721960397178492]},"#dd5500":{"lch":[53.8905970004369834,121.845910621274882,22.2085433527856502],"luv":[53.8905970004369834,112.806678507237621,46.055175814369008],"rgb":[0.866666666666666696,0.333333333333333315,0],"xyz":[0.330664855811494629,0.218716870368303284,0.0248051053792416147],"hpluv":[22.2085433527856502,286.904453583707834,53.8905970004369834],"hsluv":[22.2085433527856502,100.000000000002217,53.8905970004369834]},"#dd5511":{"lch":[53.9336739056601573,120.58904296901602,21.6306448037720749],"luv":[53.9336739056601573,112.097097503939963,44.4517492948856656],"rgb":[0.866666666666666696,0.333333333333333315,0.0666666666666666657],"xyz":[0.331676521311131733,0.219121536568158137,0.0301332103439972479],"hpluv":[21.6306448037720749,283.71818310283129,53.9336739056601573],"hsluv":[21.6306448037720749,97.0955711707227493,53.9336739056601573]},"#dd5522":{"lch":[54.0133869328819856,118.329807147086328,20.5443811064534074],"luv":[54.0133869328819856,110.804107011743554,41.5258128011568957],"rgb":[0.866666666666666696,0.333333333333333315,0.133333333333333331],"xyz":[0.33355187944960879,0.219871679823548966,0.0400100965399764405],"hpluv":[20.5443811064534074,277.99185559962018,54.0133869328819856],"hsluv":[20.5443811064534074,91.805999212684128,54.0133869328819856]},"#dd5533":{"lch":[54.1442392255445526,114.805940194650788,18.7140712474621722],"luv":[54.1442392255445526,108.736323489647134,36.8349814433582736],"rgb":[0.866666666666666696,0.333333333333333315,0.2],"xyz":[0.336639630182066496,0.221106780116532065,0.0562722503975875837],"hpluv":[18.7140712474621722,269.061420184977408,54.1442392255445526],"hsluv":[18.7140712474621722,83.3546452149230674,54.1442392255445526]},"#dd5544":{"lch":[54.3323026853354207,110.135081135525823,15.9827981501284579],"luv":[54.3323026853354207,105.877744255237971,30.3255563535325479],"rgb":[0.866666666666666696,0.333333333333333315,0.266666666666666663],"xyz":[0.341097625426285411,0.222889978214219658,0.0797510253504742223],"hpluv":[15.9827981501284579,257.221277658214035,54.3323026853354207],"hsluv":[15.9827981501284579,71.6878656400709104,54.3323026853354207]},"#dd5555":{"lch":[54.5822696158357132,104.625049281135261,12.1770506300618937],"luv":[54.5822696158357132,102.271033836367579,22.0689051636128752],"rgb":[0.866666666666666696,0.333333333333333315,0.333333333333333315],"xyz":[0.347060039465647396,0.225274943829964491,0.111153072624448138],"hpluv":[12.1770506300618937,243.233512665758,54.5822696158357132],"hsluv":[12.1770506300618937,61.8784513389384,54.5822696158357132]},"#dd5566":{"lch":[54.8977244977922254,98.7674373059184205,7.11744080010036573],"luv":[54.8977244977922254,98.0063618739055897,12.2376347477602359],"rgb":[0.866666666666666696,0.333333333333333315,0.4],"xyz":[0.354645035239155582,0.228308942139367782,0.151100717031592086],"hpluv":[7.11744080010036573,228.296245111676484,54.8977244977922254],"hsluv":[7.11744080010036573,62.7979151590930655,54.8977244977922254]},"#dd5577":{"lch":[55.2812881935381597,93.2135187108595886,0.661514811515945267],"luv":[55.2812881935381597,93.2073060454778783,1.07618316489082022],"rgb":[0.866666666666666696,0.333333333333333315,0.466666666666666674],"xyz":[0.363959048259357487,0.232034547347448605,0.20015451893799],"hpluv":[0.661514811515945267,213.963687644495565,55.2812881935381597],"hsluv":[0.661514811515945267,63.8225359413096456,55.2812881935381597]},"#dd5588":{"lch":[55.7347110848163538,88.7163187329837,352.791835078768599],"luv":[55.7347110848163538,88.0151786426913532,-11.1316457915027787],"rgb":[0.866666666666666696,0.333333333333333315,0.533333333333333326],"xyz":[0.375099465361301287,0.236490714188226203,0.258827382341562162],"hpluv":[352.791835078768599,201.984054112510194,55.7347110848163538],"hsluv":[352.791835078768599,64.9173177009572,55.7347110848163538]},"#dd5599":{"lch":[56.2589463845586408,86.0173277442407169,343.733753082454825],"luv":[56.2589463845586408,82.5740942724548717,-24.0935598727929836],"rgb":[0.866666666666666696,0.333333333333333315,0.6],"xyz":[0.388156429470374,0.241713499831855361,0.327594059982680097],"hpluv":[343.733753082454825,194.014271994181229,56.2589463845586408],"hsluv":[343.733753082454825,66.0466553819121,56.2589463845586408]},"#dd55aa":{"lch":[56.8542178605490278,85.677853149792881,334.018383993549605],"luv":[56.8542178605490278,77.0187914763158545,-37.5339883290498477],"rgb":[0.866666666666666696,0.333333333333333315,0.66666666666666663],"xyz":[0.403214122435626543,0.247736577017956455,0.406897909599678698],"hpluv":[334.018383993549605,191.225239227061849,56.8542178605490278],"hsluv":[334.018383993549605,67.3075554564469485,56.8542178605490278]},"#dd55bb":{"lch":[57.5200884026389332,87.9206422548043633,324.375348896731964],"luv":[57.5200884026389332,71.4663144117056817,-51.2113780219251638],"rgb":[0.866666666666666696,0.333333333333333315,0.733333333333333282],"xyz":[0.420351714542963217,0.254591613860891242,0.497155894698320444],"hpluv":[324.375348896731964,193.959311397505388,57.5200884026389332],"hsluv":[324.375348896731964,69.5366313504716,57.5200884026389332]},"#dd55cc":{"lch":[58.2555317670128829,92.5910381182408315,315.474469199465034],"luv":[58.2555317670128829,66.0116746837007895,-64.9273374262858596],"rgb":[0.866666666666666696,0.333333333333333315,0.8],"xyz":[0.439644089986684916,0.262308564038380043,0.5987624053685906],"hpluv":[315.474469199465034,201.683843426221756,58.2555317670128829],"hsluv":[315.474469199465034,71.7082017587958802,58.2555317670128829]},"#dd55dd":{"lch":[59.0590075291469532,99.2700295618383848,307.715012949244056],"luv":[59.0590075291469532,60.7268860008133231,-78.5288742174016363],"rgb":[0.866666666666666696,0.333333333333333315,0.866666666666666696],"xyz":[0.461162415537318515,0.270915894258633549,0.712092253268596598],"hpluv":[307.715012949244056,213.290412049590259,59.0590075291469532],"hsluv":[307.715012949244056,73.7919865345850923,59.0590075291469532]},"#dd55ee":{"lch":[59.9285380001613674,107.447476486145689,301.201070052482692],"luv":[59.9285380001613674,55.6624113436061592,-91.905691698915],"rgb":[0.866666666666666696,0.333333333333333315,0.933333333333333348],"xyz":[0.484974595803493225,0.280440766365103566,0.837503069337119821],"hpluv":[301.201070052482692,227.510719406260364,59.9285380001613674],"hsluv":[301.201070052482692,84.9240358585231405,59.9285380001613674]},"#dd55ff":{"lch":[60.8617852443614,116.651127585902827,295.843561463814751],"luv":[60.8617852443614,50.8500320114402413,-104.984569397117028],"rgb":[0.866666666666666696,0.333333333333333315,1],"xyz":[0.511145644213324646,0.29090918572903629,0.975337257628901666],"hpluv":[295.843561463814751,243.211205533984923,60.8617852443614],"hsluv":[295.843561463814751,99.9999999999987,60.8617852443614]},"#dd6600":{"lch":[56.9556719941368783,111.624872970007345,27.247071009398578],"luv":[56.9556719941368783,99.2390381331236568,51.1050445257873349],"rgb":[0.866666666666666696,0.4,0],"xyz":[0.345692913517341105,0.248772985779996625,0.0298144579478569621],"hpluv":[27.247071009398578,248.69286407076,56.9556719941368783],"hsluv":[27.247071009398578,100.000000000002402,56.9556719941368783]},"#dd6611":{"lch":[56.9952083090352204,110.431802069127656,26.6846840374429064],"luv":[56.9952083090352204,98.6698726856829325,49.5927326573774181],"rgb":[0.866666666666666696,0.4,0.0666666666666666657],"xyz":[0.346704579016978209,0.249177651979851478,0.0351425629126125919],"hpluv":[26.6846840374429064,245.864111809588593,56.9952083090352204],"hsluv":[26.6846840374429064,97.4289366186781,56.9952083090352204]},"#dd6622":{"lch":[57.0683850250612181,108.280332786330632,25.6245441521289443],"luv":[57.0683850250612181,97.630674939023308,46.8282156319165637],"rgb":[0.866666666666666696,0.4,0.133333333333333331],"xyz":[0.348579937155455266,0.249927795235242306,0.0450194491085917914],"hpluv":[25.6245441521289443,240.764984433182946,57.0683850250612181],"hsluv":[25.6245441521289443,92.7369917538900239,57.0683850250612181]},"#dd6633":{"lch":[57.1885511035567617,104.905985735707603,23.8291565941278485],"luv":[57.1885511035567617,95.9631904105633566,42.3831561992078036],"rgb":[0.866666666666666696,0.4,0.2],"xyz":[0.351667687887912972,0.251162895528225405,0.0612816029662029346],"hpluv":[23.8291565941278485,232.771873337598265,57.1885511035567617],"hsluv":[23.8291565941278485,85.2149281001260306,57.1885511035567617]},"#dd6644":{"lch":[57.3613500282636153,100.395707721520722,21.1283100845564071],"luv":[57.3613500282636153,93.6466609873464222,36.1884099516133162],"rgb":[0.866666666666666696,0.4,0.266666666666666663],"xyz":[0.356125683132131887,0.252946093625912971,0.0847603779190895801],"hpluv":[21.1283100845564071,222.093121414046323,57.3613500282636153],"hsluv":[21.1283100845564071,74.7790089775498785,57.3613500282636153]},"#dd6655":{"lch":[57.5911977652478555,95.0134939889914136,17.3206113628181804],"luv":[57.5911977652478555,90.7049894048208927,28.2872575034667619],"rgb":[0.866666666666666696,0.4,0.333333333333333315],"xyz":[0.362088097171493872,0.255331059241657832,0.116162425193063482],"hpluv":[17.3206113628181804,209.347849744778358,57.5911977652478555],"hsluv":[17.3206113628181804,61.5516693045169205,57.5911977652478555]},"#dd6666":{"lch":[57.8815358558834703,89.2064417623026742,12.1770506300619559],"luv":[57.8815358558834703,87.1993378887650579,18.8166076552624659],"rgb":[0.866666666666666696,0.4,0.4],"xyz":[0.369673092945002058,0.25836505755106115,0.156110069600207457],"hpluv":[12.1770506300619559,195.566965385494854,57.8815358558834703],"hsluv":[12.1770506300619559,60.6635523422702,57.8815358558834703]},"#dd6677":{"lch":[58.2349645673757834,83.6008411979688901,5.48003957367995387],"luv":[58.2349645673757834,83.2187459143753188,7.98379467713524704],"rgb":[0.866666666666666696,0.4,0.466666666666666674],"xyz":[0.378987105965203963,0.262090662759141946,0.205163871506605366],"hpluv":[5.48003957367995387,182.165511808695555,58.2349645673757834],"hsluv":[5.48003957367995387,61.6238417996400329,58.2349645673757834]},"#dd6688":{"lch":[58.6533262634944208,78.9686504698842,357.125632416080862],"luv":[58.6533262634944208,78.8692993006444,-3.95997283577995],"rgb":[0.866666666666666696,0.4,0.533333333333333326],"xyz":[0.390127523067147763,0.266546829599919544,0.263836734910177506],"hpluv":[357.125632416080862,170.8446551494321,58.6533262634944208],"hsluv":[357.125632416080862,62.6596910240402778,58.6533262634944208]},"#dd6699":{"lch":[59.1377678367746853,76.1279623836736192,347.292482429378936],"luv":[59.1377678367746853,74.2632604984211184,-16.746187531306056],"rgb":[0.866666666666666696,0.4,0.6],"xyz":[0.403184487176220463,0.271769615243548701,0.332603412551295441],"hpluv":[347.292482429378936,163.349798950832565,59.1377678367746853],"hsluv":[347.292482429378936,63.7390009960191435,59.1377678367746853]},"#dd66aa":{"lch":[59.6887956605557406,75.751758533498986,336.577260120739709],"luv":[59.6887956605557406,69.5095811529117,-30.1122408476074845],"rgb":[0.866666666666666696,0.4,0.66666666666666663],"xyz":[0.418242180141473,0.277792692429649823,0.411907262168294042],"hpluv":[336.577260120739709,161.042027442088397,59.6887956605557406],"hsluv":[336.577260120739709,64.8305690383666473,59.6887956605557406]},"#dd66bb":{"lch":[60.3063295400458372,78.1477005551706,325.894443158435308],"luv":[60.3063295400458372,64.706761589723726,-43.8189240697585518],"rgb":[0.866666666666666696,0.4,0.733333333333333282],"xyz":[0.435379772248809693,0.284647729272584582,0.502165247266935788],"hpluv":[325.894443158435308,164.434383230317081,60.3063295400458372],"hsluv":[325.894443158435308,65.9059953936301213,60.3063295400458372]},"#dd66cc":{"lch":[60.9897585015337427,83.1712006992562891,316.109248272524042],"luv":[60.9897585015337427,59.9384091909213694,-57.6613885491638314],"rgb":[0.866666666666666696,0.4,0.8],"xyz":[0.454672147692531392,0.292364679450073384,0.603771757937205944],"hpluv":[316.109248272524042,173.043537218511,60.9897585015337427],"hsluv":[316.109248272524042,66.9408479310096709,60.9897585015337427]},"#dd66dd":{"lch":[61.7379991889007158,90.3518241723814555,307.715012949244283],"luv":[61.7379991889007158,55.2713135142553753,-71.4740094977595675],"rgb":[0.866666666666666696,0.4,0.866666666666666696],"xyz":[0.476190473243165,0.30097200967032689,0.717101605837211942],"hpluv":[307.715012949244283,185.705044478150711,61.7379991889007158],"hsluv":[307.715012949244283,67.9151328937623759,61.7379991889007158]},"#dd66ee":{"lch":[62.5495564285741779,99.1126076890086125,300.803780654240427],"luv":[62.5495564285741779,50.7555210146825431,-85.1304063742412183],"rgb":[0.866666666666666696,0.4,0.933333333333333348],"xyz":[0.500002653509339701,0.310496881776796907,0.842512421905735165],"hpluv":[300.803780654240427,201.068480083703747,62.5495564285741779],"hsluv":[300.803780654240427,83.670703518064812,62.5495564285741779]},"#dd66ff":{"lch":[63.4225848554444696,108.928953372808309,295.226788235463459],"luv":[63.4225848554444696,46.4257694276883512,-98.5401685402585628],"rgb":[0.866666666666666696,0.4,1],"xyz":[0.526173701919171122,0.320965301140729631,0.980346610197517],"hpluv":[295.226788235463459,217.940889521273107,63.4225848554444696],"hsluv":[295.226788235463459,99.9999999999986073,63.4225848554444696]},"#dd7700":{"lch":[60.3985006876916088,102.209421710697811,33.6568691403047779],"luv":[60.3985006876916088,85.0762157619203,56.6463008330327753],"rgb":[0.866666666666666696,0.466666666666666674,0],"xyz":[0.364146651570758706,0.285680461886832382,0.0359657039656626626],"hpluv":[33.6568691403047779,214.735624532269611,60.3985006876916088],"hsluv":[33.6568691403047779,100.000000000002245,60.3985006876916088]},"#dd7711":{"lch":[60.4345564785723894,101.058408313912437,33.1281817520222],"luv":[60.4345564785723894,84.6313647704988,55.2298287886556736],"rgb":[0.866666666666666696,0.466666666666666674,0.0666666666666666657],"xyz":[0.36515831707039581,0.286085128086687235,0.0412938089304182923],"hpluv":[33.1281817520222,212.190746676882327,60.4345564785723894],"hsluv":[33.1281817520222,97.7465438968969238,60.4345564785723894]},"#dd7722":{"lch":[60.5013044729937803,98.9745052833742136,32.1281810047412648],"luv":[60.5013044729937803,83.8175940663154364,52.6361436754539582],"rgb":[0.866666666666666696,0.466666666666666674,0.133333333333333331],"xyz":[0.367033675208872867,0.286835271342078035,0.0511706951263974918],"hpluv":[32.1281810047412648,207.585936448863947,60.5013044729937803],"hsluv":[32.1281810047412648,93.6262478826975126,60.5013044729937803]},"#dd7733":{"lch":[60.6109510167574115,95.6833141687104813,30.4242910043150516],"luv":[60.6109510167574115,82.5076313520097813,48.4539717565960331],"rgb":[0.866666666666666696,0.466666666666666674,0.2],"xyz":[0.370121425941330573,0.288070371635061162,0.067432848984008642],"hpluv":[30.4242910043150516,200.320058173129354,60.6109510167574115],"hsluv":[30.4242910043150516,86.9991150080846722,60.6109510167574115]},"#dd7744":{"lch":[60.7687036553482756,91.2360291121886888,27.8356422373186483],"luv":[60.7687036553482756,80.6791699404734857,42.6014617809804932],"rgb":[0.866666666666666696,0.466666666666666674,0.266666666666666663],"xyz":[0.374579421185549488,0.289853569732748728,0.0909116239368952805],"hpluv":[27.8356422373186483,190.513488615549676,60.7687036553482756],"hsluv":[27.8356422373186483,77.760618312285672,60.7687036553482756]},"#dd7755":{"lch":[60.9786842032445122,85.8448802225428125,24.131655223886618],"luv":[60.9786842032445122,78.3427622472179479,35.096368243717265],"rgb":[0.866666666666666696,0.466666666666666674,0.333333333333333315],"xyz":[0.380541835224911473,0.292238535348493589,0.122313671210869182],"hpluv":[24.131655223886618,178.63875223296418,60.9786842032445122],"hsluv":[24.131655223886618,65.9765814384596894,60.9786842032445122]},"#dd7766":{"lch":[61.2441632046235895,79.8999585154359693,19.0216316495787474],"luv":[61.2441632046235895,75.5370685872685073,26.0414024201977448],"rgb":[0.866666666666666696,0.466666666666666674,0.4],"xyz":[0.388126830998419659,0.295272533657896907,0.162261315618013158],"hpluv":[19.0216316495787474,165.546946717194828,61.2441632046235895],"hsluv":[19.0216316495787474,57.9572057581871576,61.2441632046235895]},"#dd7777":{"lch":[61.5676827516498122,73.9875996712566,12.1770506300619097],"luv":[61.5676827516498122,72.3229127387857318,15.6064473244910626],"rgb":[0.866666666666666696,0.466666666666666674,0.466666666666666674],"xyz":[0.397440844018621564,0.298998138865977703,0.211315117524411067],"hpluv":[12.1770506300619097,152.491436777287873,61.5676827516498122],"hsluv":[12.1770506300619097,58.8480912007490744,61.5676827516498122]},"#dd7788":{"lch":[61.9511315612573,68.8928540500868252,3.33484257213660307],"luv":[61.9511315612573,68.7761927043778769,4.00757485979294081],"rgb":[0.866666666666666696,0.466666666666666674,0.533333333333333326],"xyz":[0.408581261120565364,0.303454305706755301,0.269987980927983207],"hpluv":[3.33484257213660307,141.112101622994089,61.9511315612573],"hsluv":[3.33484257213660307,59.8177792812577849,61.9511315612573]},"#dd7799":{"lch":[62.395798681375723,65.5359342889949659,352.534540584191575],"luv":[62.395798681375723,64.9804103256140309,-8.5149842657693231],"rgb":[0.866666666666666696,0.466666666666666674,0.6],"xyz":[0.421638225229638119,0.308677091350384458,0.338754658569101141],"hpluv":[352.534540584191575,133.27953643418,62.395798681375723],"hsluv":[352.534540584191575,60.8378233331756135,62.395798681375723]},"#dd77aa":{"lch":[62.9024183325334576,64.7691926058513587,340.409048511657261],"luv":[62.9024183325334576,61.0197310981447743,-21.7172909803219412],"rgb":[0.866666666666666696,0.466666666666666674,0.66666666666666663],"xyz":[0.43669591819489062,0.314700168536485581,0.418058508186099742],"hpluv":[340.409048511657261,130.659342151792146,62.9024183325334576],"hsluv":[340.409048511657261,61.8795186032410598,62.9024183325334576]},"#dd77bb":{"lch":[63.4712121738611472,67.0588140204747,328.168414880738283],"luv":[63.4712121738611472,56.973307333119962,-35.3684434115847779],"rgb":[0.866666666666666696,0.466666666666666674,0.733333333333333282],"xyz":[0.453833510302227294,0.321555205379420339,0.508316493284741489],"hpluv":[328.168414880738283,134.065922948238125,63.4712121738611472],"hsluv":[328.168414880738283,62.9156692244191049,63.4712121738611472]},"#dd77cc":{"lch":[64.1019320742502856,72.2937871392105649,317.045265551381931],"luv":[64.1019320742502856,52.9112642996390861,-49.2624580095555586],"rgb":[0.866666666666666696,0.466666666666666674,0.8],"xyz":[0.473125885745949049,0.329272155556909141,0.609923003955011644],"hpluv":[317.045265551381931,143.109736775843601,64.1019320742502856],"hsluv":[317.045265551381931,63.9218174738772262,64.1019320742502856]},"#dd77dd":{"lch":[64.7939046430230547,79.9242419089019904,307.715012949244624],"luv":[64.7939046430230547,48.8924033620837761,-63.225132172198613],"rgb":[0.866666666666666696,0.466666666666666674,0.866666666666666696],"xyz":[0.494644211296582537,0.337879485777162647,0.723252851855017642],"hpluv":[307.715012949244624,156.524995415635317,64.7939046430230547],"hsluv":[307.715012949244624,64.8769154463944,64.7939046430230547]},"#dd77ee":{"lch":[65.5460776792256,89.2673698488479772,300.244676230176196],"luv":[65.5460776792256,44.9634126652007424,-77.116501743983946],"rgb":[0.866666666666666696,0.466666666666666674,0.933333333333333348],"xyz":[0.518456391562757357,0.347404357883632664,0.848663667923540865],"hpluv":[300.244676230176196,172.816560464305326,65.5460776792256],"hsluv":[300.244676230176196,82.07388698168063,65.5460776792256]},"#dd77ff":{"lch":[66.3570680439545,99.7204006423648366,294.377473048092611],"luv":[66.3570680439545,41.1592308753033436,-90.8299290874281837],"rgb":[0.866666666666666696,0.466666666666666674,1],"xyz":[0.544627439972588667,0.357872777247565388,0.98649785621532271],"hpluv":[294.377473048092611,190.693615319177383,66.3570680439545],"hsluv":[294.377473048092611,99.9999999999983373,66.3570680439545]},"#dd8800":{"lch":[64.1467534130096766,94.4821411478558701,41.4445641191571781],"luv":[64.1467534130096766,70.8234804869986192,62.5372657508392],"rgb":[0.866666666666666696,0.533333333333333326,0],"xyz":[0.386219021295729159,0.329825201336773954,0.0433231605406526124],"hpluv":[41.4445641191571781,186.902182331454583,64.1467534130096766],"hsluv":[41.4445641191571781,100.000000000002416,64.1467534130096766]},"#dd8811":{"lch":[64.1795176641247593,93.3565504581455,40.9755438084832377],"luv":[64.1795176641247593,70.4832194968749235,61.2173282886440333],"rgb":[0.866666666666666696,0.533333333333333326,0.0666666666666666657],"xyz":[0.387230686795366263,0.330229867536628807,0.0486512655054082421],"hpluv":[40.9755438084832377,184.581288668542754,64.1795176641247593],"hsluv":[40.9755438084832377,98.0366401848460072,64.1795176641247593]},"#dd8822":{"lch":[64.2401831232140665,91.3094921720035444,40.0852847486271529],"luv":[64.2401831232140665,69.8596876954725303,58.7966614341343359],"rgb":[0.866666666666666696,0.533333333333333326,0.133333333333333331],"xyz":[0.38910604493384332,0.330980010792019608,0.0585281517013874417],"hpluv":[40.0852847486271529,180.363429125237786,64.2401831232140665],"hsluv":[40.0852847486271529,94.440421143342,64.2401831232140665]},"#dd8833":{"lch":[64.3398685532121704,88.0506151089842319,38.5586382769189342],"luv":[64.3398685532121704,68.8529964065635,54.8832916916272],"rgb":[0.866666666666666696,0.533333333333333326,0.2],"xyz":[0.392193795666301,0.332215111085002734,0.0747903055589985849],"hpluv":[38.5586382769189342,173.656703033806934,64.3398685532121704],"hsluv":[38.5586382769189342,88.6389494712849171,64.3398685532121704]},"#dd8844":{"lch":[64.4833562447751376,83.590391105324656,36.2144134416389392],"luv":[64.4833562447751376,67.4417066096926305,49.3859260793323571],"rgb":[0.866666666666666696,0.533333333333333326,0.266666666666666663],"xyz":[0.396651790910519941,0.333998309182690301,0.0982690805118852234],"hpluv":[36.2144134416389392,164.493238171948974,64.4833562447751376],"hsluv":[36.2144134416389392,80.515719620269337,64.4833562447751376]},"#dd8855":{"lch":[64.6744699451661234,78.0792033713498768,32.8038905377638059],"luv":[64.6744699451661234,65.6278986079903746,42.3006019272060527],"rgb":[0.866666666666666696,0.533333333333333326,0.333333333333333315],"xyz":[0.402614204949881926,0.336383274798435161,0.129671127785859125],"hpluv":[32.8038905377638059,153.194023310958244,64.6744699451661234],"hsluv":[32.8038905377638059,70.0933757373770874,64.6744699451661234]},"#dd8866":{"lch":[64.9162913059566762,71.8298791231791114,27.9793586637294176],"luv":[64.9162913059566762,63.4341634455056251,33.69923504798588],"rgb":[0.866666666666666696,0.533333333333333326,0.4],"xyz":[0.410199200723390112,0.33941727310783848,0.169618772193003087],"hpluv":[27.9793586637294176,140.40764710249897,64.9162913059566762],"hsluv":[27.9793586637294176,57.516131894534638,64.9162913059566762]},"#dd8877":{"lch":[65.211273186305,65.3549274640793243,21.2774014292581],"luv":[65.211273186305,60.8999714810578325,23.7162395299384023],"rgb":[0.866666666666666696,0.533333333333333326,0.466666666666666674],"xyz":[0.419513213743592,0.343142878315919275,0.218672574099401],"hpluv":[21.2774014292581,127.173019810527066,65.211273186305],"hsluv":[21.2774014292581,55.3192807564291797,65.211273186305]},"#dd8888":{"lch":[65.5613077882642585,59.4140252364257222,12.17705063006205],"luv":[65.5613077882642585,58.0772370198051675,12.5323954190731097],"rgb":[0.866666666666666696,0.533333333333333326,0.533333333333333326],"xyz":[0.430653630845535818,0.347599045156696873,0.277345437502973191],"hpluv":[12.17705063006205,114.995459986814794,65.5613077882642585],"hsluv":[12.17705063006205,56.217054427929,65.5613077882642585]},"#dd8899":{"lch":[65.9677735951440809,55.0265961591163304,0.371909902430330563],"luv":[65.9677735951440809,55.0254369244830599,0.357178006339119947],"rgb":[0.866666666666666696,0.533333333333333326,0.6],"xyz":[0.443710594954608517,0.352821830800326031,0.34611211514409107],"hpluv":[0.371909902430330563,105.847388780281833,65.9677735951440809],"hsluv":[0.371909902430330563,57.1692646853200088,65.9677735951440809]},"#dd88aa":{"lch":[66.4315725960282,53.3143351650078756,346.342357286170909],"luv":[66.4315725960282,51.8068159744011751,-12.5885723051236678],"rgb":[0.866666666666666696,0.533333333333333326,0.66666666666666663],"xyz":[0.458768287919861073,0.358844907986427153,0.425415964761089671],"hpluv":[346.342357286170909,101.837748961685463,66.4315725960282],"hsluv":[346.342357286170909,58.1497775423036174,66.4315725960282]},"#dd88bb":{"lch":[66.9531637379342754,55.0554122119122695,331.715662007953938],"luv":[66.9531637379342754,48.482176665295448,-26.0878699709014299],"rgb":[0.866666666666666696,0.533333333333333326,0.733333333333333282],"xyz":[0.475905880027197747,0.365699944829361911,0.515673949859731473],"hpluv":[331.715662007953938,104.344182679937973,66.9531637379342754],"hsluv":[331.715662007953938,59.1328526037280824,66.9531637379342754]},"#dd88cc":{"lch":[67.5325957217288391,60.2482932018326949,318.477460357427788],"luv":[67.5325957217288391,45.1075955230381,-39.9394749572899741],"rgb":[0.866666666666666696,0.533333333333333326,0.8],"xyz":[0.495198255470919446,0.373416895006850713,0.617280460530001629],"hpluv":[318.477460357427788,113.206309259525241,67.5325957217288391],"hsluv":[318.477460357427788,60.0943355072680134,67.5325957217288391]},"#dd88dd":{"lch":[68.1695406599531566,68.219499196860184,307.715012949245079],"luv":[68.1695406599531566,41.7322103060295,-53.965940125636024],"rgb":[0.866666666666666696,0.533333333333333326,0.866666666666666696],"xyz":[0.516716581021553,0.382024225227104219,0.730610308430007627],"hpluv":[307.715012949245079,126.986480244117786,68.1695406599531566],"hsluv":[307.715012949245079,61.0124281772922785,68.1695406599531566]},"#dd88ee":{"lch":[68.8633291469121,78.1074456653267504,299.445313850889818],"luv":[68.8633291469121,38.3970440138518896,-68.0179393936650456],"rgb":[0.866666666666666696,0.533333333333333326,0.933333333333333348],"xyz":[0.540528761287727755,0.391549097333574236,0.85602112449853085],"hpluv":[299.445313850889818,143.92748858218269,68.8633291469121],"hsluv":[299.445313850889818,80.0342386911036385,68.8633291469121]},"#dd88ff":{"lch":[69.6129866887261244,89.1875622693819281,293.199992160066699],"luv":[69.6129866887261244,35.1347073752451706,-81.975445111391565],"rgb":[0.866666666666666696,0.533333333333333326,1],"xyz":[0.566699809697559176,0.40201751669750696,0.993855312790312695],"hpluv":[293.199992160066699,162.574846632166981,69.6129866887261244],"hsluv":[293.199992160066699,99.9999999999981242,69.6129866887261244]},"#dd9900":{"lch":[68.1357569139589287,89.1370219700488775,50.3810095729648921],"luv":[68.1357569139589287,56.8408371488252229,68.6624199829113735],"rgb":[0.866666666666666696,0.6,0],"xyz":[0.41208862174819666,0.381564402241709621,0.0519463606914748674],"hpluv":[50.3810095729648921,166.005456049637957,68.1357569139589287],"hsluv":[50.3810095729648921,100.000000000002245,68.1357569139589287]},"#dd9911":{"lch":[68.1654896561650077,88.0318570495471278,50.0002977758109424],"luv":[68.1654896561650077,56.5854364905009248,67.4366089951992507],"rgb":[0.866666666666666696,0.6,0.0666666666666666657],"xyz":[0.413100287247833764,0.381969068441564474,0.0572744656562305],"hpluv":[50.0002977758109424,163.875726960716179,68.1654896561650077],"hsluv":[50.0002977758109424,98.2940371374324826,68.1654896561650077]},"#dd9922":{"lch":[68.2205507365204,86.012937831153792,49.27558445879027],"luv":[68.2205507365204,56.1166821435168472,65.1854543556261774],"rgb":[0.866666666666666696,0.6,0.133333333333333331],"xyz":[0.414975645386310821,0.382719211696955275,0.0671513518522096897],"hpluv":[49.27558445879027,159.988175949224541,68.2205507365204],"hsluv":[49.27558445879027,95.1643810214000325,68.2205507365204]},"#dd9933":{"lch":[68.3110514885433133,82.7730333151944677,48.0261582829398179],"luv":[68.3110514885433133,55.3578808500206918,61.5376313485756867],"rgb":[0.866666666666666696,0.6,0.2],"xyz":[0.418063396118768527,0.383954311989938402,0.0834135057098208399],"hpluv":[48.0261582829398179,153.757824966526499,68.3110514885433133],"hsluv":[48.0261582829398179,90.1021642959546512,68.3110514885433133]},"#dd9944":{"lch":[68.4413718194248,78.2806718730308688,46.0898611008159875],"luv":[68.4413718194248,54.2899414547091936,56.3956190296495805],"rgb":[0.866666666666666696,0.6,0.266666666666666663],"xyz":[0.422521391362987442,0.385737510087625968,0.106892280662707478],"hpluv":[46.0898611008159875,145.136005207448051,68.4413718194248],"hsluv":[46.0898611008159875,82.9860784920926449,68.4413718194248]},"#dd9955":{"lch":[68.615044439797245,72.617894762441864,43.2298844404699452],"luv":[68.615044439797245,52.9102318436571935,49.7379734808277689],"rgb":[0.866666666666666696,0.6,0.333333333333333315],"xyz":[0.428483805402349427,0.388122475703370828,0.138294327936681394],"hpluv":[43.2298844404699452,134.296171447129637,68.615044439797245],"hsluv":[43.2298844404699452,73.8078183466747362,68.615044439797245]},"#dd9966":{"lch":[68.8349542760461333,65.9999398631214262,39.0839575312566296],"luv":[68.8349542760461333,51.2306688139135815,41.6102227200810404],"rgb":[0.866666666666666696,0.6,0.4],"xyz":[0.436068801175857612,0.391156474012774147,0.178241972343825356],"hpluv":[39.0839575312566296,121.667290932950721,68.8349542760461333],"hsluv":[39.0839575312566296,62.6592399312796076,68.8349542760461333]},"#dd9977":{"lch":[69.1034430542988929,58.8170492635600723,33.0939178586399834],"luv":[69.1034430542988929,49.2755524050587468,32.1148753578207291],"rgb":[0.866666666666666696,0.6,0.466666666666666674],"xyz":[0.445382814196059518,0.394882079220854942,0.227295774250223265],"hpluv":[33.0939178586399834,108.004754244465147,69.1034430542988929],"hsluv":[33.0939178586399834,50.7393036295826789,69.1034430542988929]},"#dd9988":{"lch":[69.4223715869125328,51.7141196395305656,24.4437159362198635],"luv":[69.4223715869125328,47.0788901370553745,21.3992587150758773],"rgb":[0.866666666666666696,0.6,0.533333333333333326],"xyz":[0.456523231298003318,0.39933824606163254,0.285968637653795432],"hpluv":[24.4437159362198635,94.5255072345235305,69.4223715869125328],"hsluv":[24.4437159362198635,51.5589665528693786,69.4223715869125328]},"#dd9999":{"lch":[69.7931614924381591,45.7097919546320597,12.1770506300622632],"luv":[69.7931614924381591,44.6813426781189875,9.64171649740066705],"rgb":[0.866666666666666696,0.6,0.6],"xyz":[0.469580195407076073,0.404561031705261698,0.354735315294913311],"hpluv":[12.1770506300622632,83.1066353202273689,69.7931614924381591],"hsluv":[12.1770506300622632,52.4335711570844438,69.7931614924381591]},"#dd99aa":{"lch":[70.2168268189972196,42.2311183685245624,355.977290330288042],"luv":[70.2168268189972196,42.1270745474506256,-2.96259155636920823],"rgb":[0.866666666666666696,0.6,0.66666666666666663],"xyz":[0.484637888372328574,0.41058410889136282,0.434039164911911912],"hpluv":[355.977290330288042,76.3186553239153369,70.2168268189972196],"hsluv":[355.977290330288042,53.3392978779897788,70.2168268189972196]},"#dd99bb":{"lch":[70.694001085559151,42.6623948649138427,337.661645838825223],"luv":[70.694001085559151,39.4608168046039651,-16.2149274658665163],"rgb":[0.866666666666666696,0.6,0.733333333333333282],"xyz":[0.501775480479665248,0.417439145734297579,0.524297150010553659],"hpluv":[337.661645838825223,76.5776430619999502,70.694001085559151],"hsluv":[337.661645838825223,54.2517942883204398,70.694001085559151]},"#dd99cc":{"lch":[71.2249627580945912,47.3730793907595,320.82657583403028],"luv":[71.2249627580945912,36.7253906259007294,-29.9241430008982121],"rgb":[0.866666666666666696,0.6,0.8],"xyz":[0.521067855923387,0.42515609591178638,0.625903660680823815],"hpluv":[320.82657583403028,84.3992741769230719,71.2249627580945912],"hsluv":[320.82657583403028,55.1472527266246075,71.2249627580945912]},"#dd99dd":{"lch":[71.8096607795551876,55.5140341348433424,307.715012949246],"luv":[71.8096607795551876,33.9598410238411077,-43.9151133843462844],"rgb":[0.866666666666666696,0.6,0.866666666666666696],"xyz":[0.54258618147402049,0.433763426132039887,0.739233508580829812],"hpluv":[307.715012949246,98.0977936102115677,71.8096607795551876],"hsluv":[307.715012949246,56.0031828352742878,71.8096607795551876]},"#dd99ee":{"lch":[72.447740927007942,65.8885644567307907,298.26171852853804],"luv":[72.447740927007942,31.1982236173053273,-58.0342465212858656],"rgb":[0.866666666666666696,0.6,0.933333333333333348],"xyz":[0.566398361740195311,0.443288298238509904,0.864644324649353],"hpluv":[298.26171852853804,115.404973126410823,72.447740927007942],"hsluv":[298.26171852853804,77.3800261839098908,72.447740927007942]},"#dd99ff":{"lch":[73.1385732331520302,77.5656763031263,291.532620718417377],"luv":[73.1385732331520302,28.4689992262389602,-72.1522710898123592],"rgb":[0.866666666666666696,0.6,1],"xyz":[0.592569410150026621,0.453756717602442627,1.00247851294113488],"hpluv":[291.532620718417377,134.574391894016571,73.1385732331520302],"hsluv":[291.532620718417377,99.9999999999977689,73.1385732331520302]},"#cc0000":{"lch":[42.5207510295766156,142.998625281495549,12.1770506300617818],"luv":[42.5207510295766156,139.781222041964895,30.163169542547891],"rgb":[0.8,0,0],"xyz":[0.249012838889184379,0.128397245052238429,0.0116724768229302719],"hpluv":[12.1770506300617818,426.746789183124861,42.5207510295766156],"hsluv":[12.1770506300617818,100.000000000002174,42.5207510295766156]},"#cc0011":{"lch":[42.5821659889152784,141.236718626044905,11.4841194603559],"luv":[42.5821659889152784,138.409148973409117,28.119711390930437],"rgb":[0.8,0,0.0666666666666666657],"xyz":[0.250024504388821511,0.128801911252093282,0.0170005817876859033],"hpluv":[11.4841194603559,420.880880123779207,42.5821659889152784],"hsluv":[11.4841194603559,99.9999999999964331,42.5821659889152784]},"#cc0022":{"lch":[42.6956735686566518,138.114600243667155,10.1872609469282853],"luv":[42.6956735686566518,135.937217546775798,24.4277646564013864],"rgb":[0.8,0,0.133333333333333331],"xyz":[0.251899862527298513,0.12955205450748411,0.0268774679836651],"hpluv":[10.1872609469282853,410.482879191578036,42.6956735686566518],"hsluv":[10.1872609469282853,99.9999999999964615,42.6956735686566518]},"#cc0033":{"lch":[42.881611378965772,133.362165770655935,8.01952044887972626],"luv":[42.881611378965772,132.057963211529,18.6054188736068511],"rgb":[0.8,0,0.2],"xyz":[0.254987613259756274,0.130787154800467209,0.0431396218412762461],"hpluv":[8.01952044887972626,394.639788400466045,42.881611378965772],"hsluv":[8.01952044887972626,99.9999999999966604,42.881611378965772]},"#cc0044":{"lch":[43.1480085091585153,127.29097956278504,4.82801781999359658],"luv":[43.1480085091585153,126.839328429887985,10.7134607624411853],"rgb":[0.8,0,0.266666666666666663],"xyz":[0.259445608503975134,0.132570352898154803,0.0666183967941628846],"hpluv":[4.82801781999359658,374.34858804079829,43.1480085091585153],"hsluv":[4.82801781999359658,99.9999999999967741,43.1480085091585153]},"#cc0055":{"lch":[43.5005971125795,120.485699890795146,0.473888563816867114],"luv":[43.5005971125795,120.481578818580687,0.996515708296922487],"rgb":[0.8,0,0.333333333333333315],"xyz":[0.265408022543337119,0.134955318513899636,0.0980204440681367861],"hpluv":[0.473888563816867114,351.463000970195878,43.5005971125795],"hsluv":[0.473888563816867114,99.999999999997,43.5005971125795]},"#cc0066":{"lch":[43.9431844272177372,113.726547538665841,354.863826263116096],"luv":[43.9431844272177372,113.269906269789104,-10.1811565500985228],"rgb":[0.8,0,0.4],"xyz":[0.272993018316845304,0.137989316823302927,0.137968088475280748],"hpluv":[354.863826263116096,328.404920869645196,43.9431844272177372],"hsluv":[354.863826263116096,99.9999999999972857,43.9431844272177372]},"#cc0077":{"lch":[44.4778741065655,107.874648109024193,348.012259047653401],"luv":[44.4778741065655,105.522124609829902,-22.4058234053856609],"rgb":[0.8,0,0.466666666666666674],"xyz":[0.28230703133704721,0.14171492203138375,0.187021890381678657],"hpluv":[348.012259047653401,307.761788629886667,44.4778741065655],"hsluv":[348.012259047653401,99.9999999999975273,44.4778741065655]},"#cc0088":{"lch":[45.1052440924579,103.725434836726933,340.1176986346278],"luv":[45.1052440924579,97.5426962017022703,-35.2758876538989838],"rgb":[0.8,0,0.533333333333333326],"xyz":[0.293447448438991065,0.146171088872161348,0.245694753785250825],"hpluv":[340.1176986346278,291.808241377507443,45.1052440924579],"hsluv":[340.1176986346278,99.9999999999978,45.1052440924579]},"#cc0099":{"lch":[45.8245205562958589,101.850048541314862,331.598662995615],"luv":[45.8245205562958589,89.5911194129305102,-48.4444394147173441],"rgb":[0.8,0,0.6],"xyz":[0.306504412548063765,0.151393874515790505,0.314461431426368732],"hpluv":[331.598662995615,282.034759885138044,45.8245205562958589],"hsluv":[331.598662995615,99.9999999999981,45.8245205562958589]},"#cc00aa":{"lch":[46.633760692471931,102.477609530343315,323.022725489580409],"luv":[46.633760692471931,81.8667129915779,-61.640098629123905],"rgb":[0.8,0,0.66666666666666663],"xyz":[0.321562105513316321,0.1574169517018916,0.393765281043367332],"hpluv":[323.022725489580409,278.848217687739293,46.633760692471931],"hsluv":[323.022725489580409,99.9999999999983658,46.633760692471931]},"#cc00bb":{"lch":[47.5300446684938933,105.484027274260768,314.937463984289479],"luv":[47.5300446684938933,74.5070162947061903,-74.6698368342758414],"rgb":[0.8,0,0.733333333333333282],"xyz":[0.33869969762065294,0.164271988544826358,0.484023266142009079],"hpluv":[314.937463984289479,281.616311803476265,47.5300446684938933],"hsluv":[314.937463984289479,99.9999999999986,47.5300446684938933]},"#cc00cc":{"lch":[48.5096711653281147,110.497164945278598,307.715012949243601],"luv":[48.5096711653281147,67.5949102529980621,-87.4102486487325],"rgb":[0.8,0,0.8],"xyz":[0.357992073064374694,0.17198893872231516,0.585629776812279235],"hpluv":[307.715012949243601,289.042783730483393,48.5096711653281147],"hsluv":[307.715012949243601,99.9999999999988,48.5096711653281147]},"#cc00dd":{"lch":[49.5683488162236614,117.049051317219835,301.506761454082039],"luv":[49.5683488162236614,61.1697383356450075,-99.7935044289451],"rgb":[0.8,0,0.866666666666666696],"xyz":[0.379510398615008238,0.180596268942568694,0.698959624712285232],"hpluv":[301.506761454082039,299.64205877637869,49.5683488162236614],"hsluv":[301.506761454082039,99.9999999999990337,49.5683488162236614]},"#cc00ee":{"lch":[50.7013760136427862,124.695255359169607,296.294949026353493],"luv":[50.7013760136427862,55.2390203059142522,-111.792474454818787],"rgb":[0.8,0,0.933333333333333348],"xyz":[0.403322578881182947,0.190121141049038739,0.824370440780808456],"hpluv":[296.294949026353493,312.082566880879938,50.7013760136427862],"hsluv":[296.294949026353493,99.99999999999919,50.7013760136427862]},"#cc00ff":{"lch":[51.9038030272213,133.072735088441448,291.971633700566258],"luv":[51.9038030272213,49.7888328026579075,-123.407556300526],"rgb":[0.8,0,1],"xyz":[0.429493627291014368,0.200589560412971435,0.962204629072590301],"hpluv":[291.971633700566258,325.333832743425603,51.9038030272213],"hsluv":[291.971633700566258,99.9999999999993321,51.9038030272213]},"#cc1100":{"lch":[43.1235624482234172,140.134259476931788,12.8715382160273855],"luv":[43.1235624482234172,136.61296213687416,31.2171307992428524],"rgb":[0.8,0.0666666666666666657,0],"xyz":[0.251017239150112814,0.132406045574095299,0.0123406102432397219],"hpluv":[12.8715382160273855,412.352867097941,43.1235624482234172],"hsluv":[12.8715382160273855,100.000000000002245,43.1235624482234172]},"#cc1111":{"lch":[43.1837333530957892,138.41807101963343,12.1770506300617676],"luv":[43.1837333530957892,135.303728142340162,29.196978192614182],"rgb":[0.8,0.0666666666666666657,0.0666666666666666657],"xyz":[0.252028904649749919,0.132810711773950152,0.0176687152079953516],"hpluv":[12.1770506300617676,406.735363437937394,43.1837333530957892],"hsluv":[12.1770506300617676,95.3107026807431197,43.1837333530957892]},"#cc1122":{"lch":[43.294951674171287,135.375047793376126,10.8766574447476163],"luv":[43.294951674171287,132.943125696930394,25.5446451333550044],"rgb":[0.8,0.0666666666666666657,0.133333333333333331],"xyz":[0.253904262788227,0.13356085502934098,0.0275456014039745511],"hpluv":[10.8766574447476163,396.771701832449367,43.294951674171287],"hsluv":[10.8766574447476163,95.396390587568618,43.294951674171287]},"#cc1133":{"lch":[43.4771672841157724,130.73841758888139,8.7012157385065958],"luv":[43.4771672841157724,129.233706917218683,19.7783424502448213],"rgb":[0.8,0.0666666666666666657,0.2],"xyz":[0.256992013520684681,0.134795955322324079,0.0438077552615856944],"hpluv":[8.7012157385065958,381.576227833431062,43.4771672841157724],"hsluv":[8.7012157385065958,95.5308510527687389,43.4771672841157724]},"#cc1144":{"lch":[43.7382910834512586,124.807582872189826,5.49437317543092796],"luv":[43.7382910834512586,124.234167693991893,11.9500761411646046],"rgb":[0.8,0.0666666666666666657,0.266666666666666663],"xyz":[0.261450008764903596,0.136579153420011673,0.0672865302144723398],"hpluv":[5.49437317543092796,362.091632024479338,43.7382910834512586],"hsluv":[5.49437317543092796,95.7116850897169229,43.7382910834512586]},"#cc1155":{"lch":[44.0840061747103107,118.151091154502552,1.11194247693657511],"luv":[44.0840061747103107,118.128842001262925,2.29282106589917234],"rgb":[0.8,0.0666666666666666657,0.333333333333333315],"xyz":[0.267412422804265582,0.138964119035756506,0.0986885774884462413],"hpluv":[1.11194247693657511,340.091681007194666,44.0840061747103107],"hsluv":[1.11194247693657511,95.9318436200579754,44.0840061747103107]},"#cc1166":{"lch":[44.5181325219627837,111.53522478210337,355.453854482233226],"luv":[44.5181325219627837,111.184314904818763,-8.84050260677650712],"rgb":[0.8,0.0666666666666666657,0.4],"xyz":[0.274997418577773767,0.141998117345159797,0.138636221895590217],"hpluv":[355.453854482233226,317.917500588946211,44.5181325219627837],"hsluv":[355.453854482233226,96.1812476973727115,44.5181325219627837]},"#cc1177":{"lch":[45.0428415016287857,105.814757555455103,348.528515458334311],"luv":[45.0428415016287857,103.700981473984271,-21.0444614531261323],"rgb":[0.8,0.0666666666666666657,0.466666666666666674],"xyz":[0.284311431597975672,0.14572372255324062,0.187690023801988126],"hpluv":[348.528515458334311,298.098498005115459,45.0428415016287857],"hsluv":[348.528515458334311,96.4486017572014589,45.0428415016287857]},"#cc1188":{"lch":[45.6588256994622341,101.788242110562607,340.533613155211185],"luv":[45.6588256994622341,95.9697371205835594,-33.9213176183443323],"rgb":[0.8,0.0666666666666666657,0.533333333333333326],"xyz":[0.295451848699919473,0.150179889394018218,0.246362887205560266],"hpluv":[340.533613155211185,282.886487347344485,45.6588256994622341],"hsluv":[340.533613155211185,96.7230145871901215,45.6588256994622341]},"#cc1199":{"lch":[46.3654632546324876,100.035938879036408,331.896400713626349],"luv":[46.3654632546324876,88.2414291467186,-47.1236591273953138],"rgb":[0.8,0.0666666666666666657,0.6],"xyz":[0.308508812808992228,0.155402675037647375,0.315129564846678201],"hpluv":[331.896400713626349,273.779405248492822,46.3654632546324876],"hsluv":[331.896400713626349,96.9951405388504355,46.3654632546324876]},"#cc11aa":{"lch":[47.1609900317596882,100.794975336059878,323.201580807901109],"luv":[47.1609900317596882,80.7113646178594735,-60.3763420100941488],"rgb":[0.8,0.0666666666666666657,0.66666666666666663],"xyz":[0.323566505774244728,0.16142575222374847,0.394433414463676801],"hpluv":[323.201580807901109,271.203503720358924,47.1609900317596882],"hsluv":[323.201580807901109,97.2577546113476075,47.1609900317596882]},"#cc11bb":{"lch":[48.0426807208370548,103.942897448445919,315.013990059648165],"luv":[48.0426807208370548,73.5166718264647727,-73.4807790754699681],"rgb":[0.8,0.0666666666666666657,0.733333333333333282],"xyz":[0.340704097881581403,0.168280789066683228,0.484691399562318548],"hpluv":[315.013990059648165,274.540811344802705,48.0426807208370548],"hsluv":[315.013990059648165,97.5058443216483,48.0426807208370548]},"#cc11cc":{"lch":[49.0070341259591515,109.103198367120783,307.715012949243601],"luv":[49.0070341259591515,66.7421730285370387,-86.3075328888743769],"rgb":[0.8,0.0666666666666666657,0.8],"xyz":[0.359996473325303157,0.17599773924417203,0.586297910232588704],"hpluv":[307.715012949243601,282.499958642668389,49.0070341259591515],"hsluv":[307.715012949243601,97.7363817897909541,49.0070341259591515]},"#cc11dd":{"lch":[50.0499556366759037,115.801352096543823,301.456118533327128],"luv":[50.0499556366759037,60.4304023076134555,-98.7831950502093292],"rgb":[0.8,0.0666666666666666657,0.866666666666666696],"xyz":[0.381514798875936645,0.184605069464425564,0.699627758132594701],"hpluv":[301.456118533327128,293.595408819402792,50.0499556366759037],"hsluv":[301.456118533327128,97.9479403979501342,50.0499556366759037]},"#cc11ee":{"lch":[51.1669298024285837,123.587345912593733,296.214453457233276],"luv":[51.1669298024285837,54.5925079172689109,-110.876012505059137],"rgb":[0.8,0.0666666666666666657,0.933333333333333348],"xyz":[0.40532697914211141,0.194129941570895609,0.825038574201117925],"hpluv":[296.214453457233276,306.495409047480564,51.1669298024285837],"hsluv":[296.214453457233276,98.1402788193950215,51.1669298024285837]},"#cc11ff":{"lch":[52.3531771468210678,132.094610043027387,291.87590029388349],"luv":[52.3531771468210678,49.2181193296501576,-122.582881072651375],"rgb":[0.8,0.0666666666666666657,1],"xyz":[0.431498027551942775,0.204598360934828305,0.96287276249289977],"hpluv":[291.87590029388349,320.170549145207644,52.3531771468210678],"hsluv":[291.87590029388349,99.9999999999991189,52.3531771468210678]},"#cc2200":{"lch":[44.2095884480383674,135.132222138307952,14.1797238149512133],"luv":[44.2095884480383674,131.015027118873576,33.102569825888537],"rgb":[0.8,0.133333333333333331,0],"xyz":[0.254732862884880729,0.139837293043631267,0.0135791514881623328],"hpluv":[14.1797238149512133,387.866054960954045,44.2095884480383674],"hsluv":[14.1797238149512133,100.00000000000226,44.2095884480383674]},"#cc2211":{"lch":[44.2676114068871129,133.490625771231663,13.482935392010976],"luv":[44.2676114068871129,129.81154471696064,31.1241068464871375],"rgb":[0.8,0.133333333333333331,0.0666666666666666657],"xyz":[0.255744528384517833,0.14024195924348612,0.0189072564529179643],"hpluv":[13.482935392010976,382.652016671578622,44.2676114068871129],"hsluv":[13.482935392010976,95.5414705532830197,44.2676114068871129]},"#cc2222":{"lch":[44.3748759613401162,130.576558981694717,12.1770506300617747],"luv":[44.3748759613401162,127.638646515421286,27.5429423121666019],"rgb":[0.8,0.133333333333333331,0.133333333333333331],"xyz":[0.25761988652299489,0.140992102498876948,0.0287841426488971604],"hpluv":[12.1770506300617747,373.394050741154899,44.3748759613401162],"hsluv":[12.1770506300617747,87.4977996802062847,44.3748759613401162]},"#cc2233":{"lch":[44.5506596541482907,126.128431434884163,9.98899557195718657],"luv":[44.5506596541482907,124.216461430809,21.8781152257824267],"rgb":[0.8,0.133333333333333331,0.2],"xyz":[0.260707637255452596,0.142227202791860047,0.0450462965065083071],"hpluv":[9.98899557195718657,359.251162664680805,44.5506596541482907],"hsluv":[9.98899557195718657,87.8457930667704829,44.5506596541482907]},"#cc2244":{"lch":[44.8026641682027602,120.425301369152351,6.75586226508684629],"luv":[44.8026641682027602,119.589119356054482,14.1667124448306829],"rgb":[0.8,0.133333333333333331,0.266666666666666663],"xyz":[0.265165632499671511,0.144010400889547641,0.0685250714593949456],"hpluv":[6.75586226508684629,341.077623618219945,44.8026641682027602],"hsluv":[6.75586226508684629,88.3153597242729,44.8026641682027602]},"#cc2255":{"lch":[45.136480402373536,114.008772215671115,2.323188749975583],"luv":[45.136480402373536,113.915065115628011,4.62148047999889577],"rgb":[0.8,0.133333333333333331,0.333333333333333315],"xyz":[0.271128046539033496,0.146395366505292474,0.0999271187333688471],"hpluv":[2.323188749975583,320.51614012782295,45.136480402373536],"hsluv":[2.323188749975583,88.8894607126765663,45.136480402373536]},"#cc2266":{"lch":[45.5559407124691731,107.622008592458101,356.577515499379103],"luv":[45.5559407124691731,107.430062323442542,-6.42483016556681452],"rgb":[0.8,0.133333333333333331,0.4],"xyz":[0.278713042312541681,0.149429364814695764,0.139874763140512809],"hpluv":[356.577515499379103,299.774992396016216,45.5559407124691731],"hsluv":[356.577515499379103,89.543058875786258,45.5559407124691731]},"#cc2277":{"lch":[46.0633224094211542,102.110102175352239,349.514816334356908],"luv":[46.0633224094211542,100.405067655344695,-18.5821246198201955],"rgb":[0.8,0.133333333333333331,0.466666666666666674],"xyz":[0.288027055332743587,0.153154970022776588,0.188928565046910718],"hpluv":[349.514816334356908,281.289018816444,46.0633224094211542],"hsluv":[349.514816334356908,90.2475430222303174,46.0633224094211542]},"#cc2288":{"lch":[46.6595045299101443,98.2790088680822294,341.330158110485115],"luv":[46.6595045299101443,93.107459692013677,-31.4605234189234864],"rgb":[0.8,0.133333333333333331,0.533333333333333326],"xyz":[0.299167472434687387,0.157611136863554185,0.247601428450482886],"hpluv":[341.330158110485115,267.276005324070297,46.6595045299101443],"hsluv":[341.330158110485115,90.9748001704168,46.6595045299101443]},"#cc2299":{"lch":[47.3441166442187154,96.727251962869147,332.467163788405],"luv":[47.3441166442187154,85.772509513995189,-44.7128380217581167],"rgb":[0.8,0.133333333333333331,0.6],"xyz":[0.312224436543760087,0.162833922507183343,0.31636810609160082],"hpluv":[332.467163788405,259.252025571181889,47.3441166442187154],"hsluv":[332.467163788405,91.7002075152857259,47.3441166442187154]},"#cc22aa":{"lch":[48.1156936783416285,97.7076198445846131,323.544141865814368],"luv":[48.1156936783416285,78.5876931080813534,-58.0581903579838254],"rgb":[0.8,0.133333333333333331,0.66666666666666663],"xyz":[0.327282129509012643,0.168856999693284437,0.395671955708599421],"hpluv":[323.544141865814368,257.680176436907345,48.1156936783416285],"hsluv":[323.544141865814368,92.4042695013683328,48.1156936783416285]},"#cc22bb":{"lch":[48.9718390817589295,101.100583268181566,315.160199675634601],"luv":[48.9718390817589295,71.6885121422158846,-71.2887450022924867],"rgb":[0.8,0.133333333333333331,0.733333333333333282],"xyz":[0.344419721616349317,0.175712036536219196,0.485929940807241167],"hpluv":[315.160199675634601,261.96699229126267,48.9718390817589295],"hsluv":[315.160199675634601,93.0730408422972602,48.9718390817589295]},"#cc22cc":{"lch":[49.9093929354593513,106.520702596514482,307.715012949243658],"luv":[49.9093929354593513,65.1623716831421405,-84.2646153393173876],"rgb":[0.8,0.133333333333333331,0.8],"xyz":[0.363712097060071,0.183428986713708,0.587536451477511323],"hpluv":[307.715012949243658,270.826440261226253,49.9093929354593513],"hsluv":[307.715012949243658,93.6976999618693327,49.9093929354593513]},"#cc22dd":{"lch":[50.9245991417877377,113.480326695625976,301.360030221234524],"luv":[50.9245991417877377,59.0567580516805819,-96.9024451465042347],"rgb":[0.8,0.133333333333333331,0.866666666666666696],"xyz":[0.385230422610704615,0.192036316933961532,0.700866299377517321],"hpluv":[301.360030221234524,282.769318292038,50.9245991417877377],"hsluv":[301.360030221234524,94.2736696463096848,50.9245991417877377]},"#cc22ee":{"lch":[52.0132654143591964,121.518329969744158,296.062236941936249],"luv":[52.0132654143591964,53.3887372455597244,-109.162022947361166],"rgb":[0.8,0.133333333333333331,0.933333333333333348],"xyz":[0.409042602876879324,0.201561189040431576,0.826277115446040544],"hpluv":[296.062236941936249,296.460610812118318,52.0132654143591964],"hsluv":[296.062236941936249,94.7995997265514,52.0132654143591964]},"#cc22ff":{"lch":[53.170910599170611,130.261070707018604,291.695402941657903],"luv":[53.170910599170611,48.1538976563848422,-121.033667556747687],"rgb":[0.8,0.133333333333333331,1],"xyz":[0.435213651286710745,0.212029608404364273,0.964111303737822389],"hpluv":[291.695402941657903,310.870757963074425,53.170910599170611],"hsluv":[291.695402941657903,99.9999999999990621,53.170910599170611]},"#cc3300":{"lch":[45.9167915379707807,127.686226573765651,16.3911473443809399],"luv":[45.9167915379707807,122.496750231663356,36.0321889333482446],"rgb":[0.8,0.2,0],"xyz":[0.260850584973891519,0.15207273722165307,0.0156183921844992128],"hpluv":[16.3911473443809399,352.867650162608584,45.9167915379707807],"hsluv":[16.3911473443809399,100.000000000002288,45.9167915379707807]},"#cc3311":{"lch":[45.9716631772740811,126.14350976506573,15.6923563051461095],"luv":[45.9716631772740811,121.44186843726601,34.118289029712578],"rgb":[0.8,0.2,0.0666666666666666657],"xyz":[0.261862250473528624,0.152477403421507923,0.020946497149254846],"hpluv":[15.6923563051461095,348.188177538365835,45.9716631772740811],"hsluv":[15.6923563051461095,95.8756509753329595,45.9716631772740811]},"#cc3322":{"lch":[46.0731243265426613,123.399991281457972,14.3806932854006604],"luv":[46.0731243265426613,119.533487768482047,30.6480529588105668],"rgb":[0.8,0.2,0.133333333333333331],"xyz":[0.263737608612005681,0.153227546676898752,0.0308233833452340386],"hpluv":[14.3806932854006604,339.865273437066321,46.0731243265426613],"hsluv":[14.3806932854006604,88.4197842587317524,46.0731243265426613]},"#cc3333":{"lch":[46.2394596481243951,119.199958247304309,12.1770506300617924],"luv":[46.2394596481243951,116.518014060345578,25.1432385661076303],"rgb":[0.8,0.2,0.2],"xyz":[0.266825359344463386,0.154462646969881851,0.0470855372028451818],"hpluv":[12.1770506300617924,327.11667224844831,46.2394596481243951],"hsluv":[12.1770506300617924,76.6535755019082,46.2394596481243951]},"#cc3344":{"lch":[46.4780522046582405,113.793717346871745,8.90746564227168669],"luv":[46.4780522046582405,112.421330819758609,17.6197186224449389],"rgb":[0.8,0.2,0.266666666666666663],"xyz":[0.271283354588682302,0.156245845067569444,0.0705643121557318204],"hpluv":[8.90746564227168669,310.677421508065,46.4780522046582405],"hsluv":[8.90746564227168669,77.4930753906613887,46.4780522046582405]},"#cc3355":{"lch":[46.7943405275181661,107.68493286266704,4.39945159143432907],"luv":[46.7943405275181661,107.367637754253522,8.26045572038872855],"rgb":[0.8,0.2,0.333333333333333315],"xyz":[0.277245768628044287,0.158630810683314277,0.101966359429705736],"hpluv":[4.39945159143432907,292.012160158640199,46.7943405275181661],"hsluv":[4.39945159143432907,78.5258346284665265,46.7943405275181661]},"#cc3366":{"lch":[47.192153202602185,101.584765682520938,358.514989280316684],"luv":[47.192153202602185,101.55064731932022,-2.63261235272558647],"rgb":[0.8,0.2,0.4],"xyz":[0.284830764401552472,0.161664808992717568,0.141914003836849684],"hpluv":[358.514989280316684,273.148057687163259,47.192153202602185],"hsluv":[358.514989280316684,79.7102211537212781,47.192153202602185]},"#cc3377":{"lch":[47.6738975277608859,96.3272258277819589,351.225603296168742],"luv":[47.6738975277608859,95.1998742335289876,-14.6941614798792699],"rgb":[0.8,0.2,0.466666666666666674],"xyz":[0.294144777421754378,0.165390414200798391,0.190967805743247593],"hpluv":[351.225603296168742,256.39391915093114,47.6738975277608859],"hsluv":[351.225603296168742,80.9972134637005894,47.6738975277608859]},"#cc3388":{"lch":[48.2406991607903279,92.7347249941698095,342.718318936463845],"luv":[48.2406991607903279,88.5482927213948301,-27.5486674064369161],"rgb":[0.8,0.2,0.533333333333333326],"xyz":[0.305285194523698178,0.169846581041576,0.24964066914681976],"hpluv":[342.718318936463845,243.93163202064531,48.2406991607903279],"hsluv":[342.718318936463845,82.3372641433758758,48.2406991607903279]},"#cc3399":{"lch":[48.8925304323200436,91.4400639314067405,333.463846826874658],"luv":[48.8925304323200436,81.8070942553503926,-40.8519843003490877],"rgb":[0.8,0.2,0.6],"xyz":[0.318342158632770933,0.175069366685205147,0.318407346787937695],"hpluv":[333.463846826874658,237.319449797121564,48.8925304323200436],"hsluv":[333.463846826874658,83.6856508008112,48.8925304323200436]},"#cc33aa":{"lch":[49.6283419748853873,92.7248127600779242,324.141487451800515],"luv":[49.6283419748853873,75.1503095778714254,-54.3168654447363792],"rgb":[0.8,0.2,0.66666666666666663],"xyz":[0.333399851598023433,0.181092443871306241,0.397711196404936296],"hpluv":[324.141487451800515,237.085790295602294,49.6283419748853873],"hsluv":[324.141487451800515,85.0057245198840263,49.6283419748853873]},"#cc33bb":{"lch":[50.4462014889725054,96.4744776262418355,315.414049480091705],"luv":[50.4462014889725054,68.7089492450233905,-67.7230029377097],"rgb":[0.8,0.2,0.733333333333333282],"xyz":[0.350537443705360108,0.187947480714241,0.487969181503578042],"hpluv":[315.414049480091705,242.674024226837219,50.4462014889725054],"hsluv":[315.414049480091705,86.2701296035756258,50.4462014889725054]},"#cc33cc":{"lch":[51.3434379695087273,102.286811532428814,307.715012949243771],"luv":[51.3434379695087273,62.5723551280607779,-80.915339628518268],"rgb":[0.8,0.2,0.8],"xyz":[0.369829819149081862,0.195664430891729801,0.589575692173848198],"hpluv":[307.715012949243771,252.798225898109365,51.3434379695087273],"hsluv":[307.715012949243771,87.4604868647498,51.3434379695087273]},"#cc33dd":{"lch":[52.3167871114961827,109.649949983538605,301.195256028086874],"luv":[52.3167871114961827,56.7938698017029751,-93.7953510806358],"rgb":[0.8,0.2,0.866666666666666696],"xyz":[0.39134814469971535,0.204271761111983335,0.702905540073854196],"hpluv":[301.195256028086874,265.954105752122757,52.3167871114961827],"hsluv":[301.195256028086874,88.5661577004671,52.3167871114961827]},"#cc33ee":{"lch":[53.3625327970638494,118.082474280319559,295.802769884900215],"luv":[53.3625327970638494,51.3983045372134626,-106.309383512755787],"rgb":[0.8,0.2,0.933333333333333348],"xyz":[0.415160324965890115,0.21379663321845338,0.828316356142377419],"hpluv":[295.802769884900215,280.794331636146467,53.3625327970638494],"hsluv":[295.802769884900215,89.5826266077864375,53.3625327970638494]},"#cc33ff":{"lch":[54.4766398815527566,127.197777570935344,291.389330811727291],"luv":[54.4766398815527566,46.3894624378335,-118.436870921660102],"rgb":[0.8,0.2,1],"xyz":[0.441331373375721481,0.224265052582386076,0.966150544434159264],"hpluv":[291.389330811727291,296.284230666095709,54.4766398815527566],"hsluv":[291.389330811727291,99.9999999999990195,54.4766398815527566]},"#cc4400":{"lch":[48.2269914221542848,118.435883841274119,19.7039935064818295],"luv":[48.2269914221542848,111.501113106022,39.9319465764175447],"rgb":[0.8,0.266666666666666663,0],"xyz":[0.26968315545685756,0.1697378781875854,0.0185625823454878096],"hpluv":[19.7039935064818295,311.625122342549162,48.2269914221542848],"hsluv":[19.7039935064818295,100.000000000002174,48.2269914221542848]},"#cc4411":{"lch":[48.2779913635395,116.996103035931512,19.0066631306561966],"luv":[48.2779913635395,110.617558299276112,38.1030697123021],"rgb":[0.8,0.266666666666666663,0.0666666666666666657],"xyz":[0.270694820956494664,0.170142544387440253,0.0238906873102434428],"hpluv":[19.0066631306561966,307.511619232155283,48.2779913635395],"hsluv":[19.0066631306561966,96.278384876640132,48.2779913635395]},"#cc4422":{"lch":[48.3723181772035389,114.428966114904512,17.6946931608209894],"luv":[48.3723181772035389,109.015290220227484,34.7800917814421453],"rgb":[0.8,0.266666666666666663,0.133333333333333331],"xyz":[0.272570179094971721,0.170892687642831081,0.0337675735062226354],"hpluv":[17.6946931608209894,300.177682052924467,48.3723181772035389],"hsluv":[17.6946931608209894,89.5341066932624869,48.3723181772035389]},"#cc4433":{"lch":[48.5270263662828114,110.48209503335984,15.4815426750504042],"luv":[48.5270263662828114,106.473417017787412,29.4907577304601034],"rgb":[0.8,0.266666666666666663,0.2],"xyz":[0.275657929827429427,0.17212778793581418,0.0500297273638337786],"hpluv":[15.4815426750504042,288.900004133964501,48.5270263662828114],"hsluv":[15.4815426750504042,78.8475327486048,48.5270263662828114]},"#cc4444":{"lch":[48.7490888960709725,105.371058014361893,12.1770506300618457],"luv":[48.7490888960709725,103.000257716521162,22.2262632351064191],"rgb":[0.8,0.266666666666666663,0.266666666666666663],"xyz":[0.280115925071648342,0.173910986033501774,0.0735085023167204171],"hpluv":[12.1770506300618457,274.28001464324592,48.7490888960709725],"hsluv":[12.1770506300618457,64.2723089184284788,48.7490888960709725]},"#cc4455":{"lch":[49.0437296069087,99.5540950311582691,7.58056168126664254],"luv":[49.0437296069087,98.6840273694228074,13.1331861946711772],"rgb":[0.8,0.266666666666666663,0.333333333333333315],"xyz":[0.286078339111010327,0.176295951649246607,0.104910549590694333],"hpluv":[7.58056168126664254,257.581676799067395,49.0437296069087],"hsluv":[7.58056168126664254,65.7689369270132858,49.0437296069087]},"#cc4466":{"lch":[49.4147368002801244,93.7049448509207679,1.51289058041819868],"luv":[49.4147368002801244,93.6722802728102835,2.47398423725391092],"rgb":[0.8,0.266666666666666663,0.4],"xyz":[0.293663334884518512,0.179329949958649898,0.14485819399783828],"hpluv":[1.51289058041819868,240.627550105868352,49.4147368002801244],"hsluv":[1.51289058041819868,67.500804726855,49.4147368002801244]},"#cc4477":{"lch":[49.8646356184384132,88.6490107187132566,353.900159994018],"luv":[49.8646356184384132,88.1471013723349586,-9.41995865499641383],"rgb":[0.8,0.266666666666666663,0.466666666666666674],"xyz":[0.302977347904720418,0.183055555166730721,0.19391199590423619],"hpluv":[353.900159994018,225.590377060975072,49.8646356184384132],"hsluv":[353.900159994018,69.4017616341687784,49.8646356184384132]},"#cc4488":{"lch":[50.3948096201307436,85.2405150759366279,344.907000147604322],"luv":[50.3948096201307436,82.3000967091543743,-22.1954835963269055],"rgb":[0.8,0.266666666666666663,0.533333333333333326],"xyz":[0.314117765006664218,0.187511722007508319,0.252584859307808385],"hpluv":[344.907000147604322,214.634525667930632,50.3948096201307436],"hsluv":[344.907000147604322,71.4025087995354824,50.3948096201307436]},"#cc4499":{"lch":[51.0056074652318046,84.1718897613591679,335.041688295241613],"luv":[51.0056074652318046,76.3115014820887581,-35.5170630478867793],"rgb":[0.8,0.266666666666666663,0.6],"xyz":[0.327174729115737,0.192734507651137477,0.321351536948926264],"hpluv":[335.041688295241613,209.40569084337892,51.0056074652318046],"hsluv":[335.041688295241613,73.4381222823911344,51.0056074652318046]},"#cc44aa":{"lch":[51.6964496814969152,85.7749410926589348,325.085448007895536],"luv":[51.6964496814969152,70.3360122964612913,-49.093644127128691],"rgb":[0.8,0.266666666666666663,0.66666666666666663],"xyz":[0.342232422080989473,0.198757584837238571,0.400655386565924865],"hpluv":[325.085448007895536,210.542141790665795,51.6964496814969152],"hsluv":[325.085448007895536,75.4531429469973602,51.6964496814969152]},"#cc44bb":{"lch":[52.465940673938249,89.9444778306290829,315.812454406659811],"luv":[52.465940673938249,64.4957791941851326,-62.692133145710109],"rgb":[0.8,0.266666666666666663,0.733333333333333282],"xyz":[0.359370014188326148,0.20561262168017333,0.490913371664566611],"hpluv":[315.812454406659811,217.538619181736436,52.465940673938249],"hsluv":[315.812454406659811,77.4040753157756143,52.465940673938249]},"#cc44cc":{"lch":[53.3119860408958175,96.2498903650287758,307.715012949243885],"luv":[53.3119860408958175,58.8793631430003828,-76.1397530279337502],"rgb":[0.8,0.266666666666666663,0.8],"xyz":[0.378662389632047902,0.213329571857662131,0.592519882334836767],"hpluv":[307.715012949243885,229.094523932317799,53.3119860408958175],"hsluv":[307.715012949243885,79.2597279113993,53.3119860408958175]},"#cc44dd":{"lch":[54.2319126329379486,104.138844540210442,300.941773361922515],"luv":[54.2319126329379486,53.5447276840333259,-89.31887303035586],"rgb":[0.8,0.266666666666666663,0.866666666666666696],"xyz":[0.40018071518268139,0.221936902077915665,0.705849730234842765],"hpluv":[300.941773361922515,243.66724889744043,54.2319126329379486],"hsluv":[300.941773361922515,81.0000946003390538,54.2319126329379486]},"#cc44ee":{"lch":[55.2225876682288401,113.096616320403683,295.407423092027],"luv":[55.2225876682288401,48.5243479249087528,-102.157879194837463],"rgb":[0.8,0.266666666666666663,0.933333333333333348],"xyz":[0.423992895448856155,0.23146177418438571,0.831260546303366],"hpluv":[295.407423092027,259.879597148300718,55.2225876682288401],"hsluv":[295.407423092027,86.8652077390175634,55.2225876682288401]},"#cc44ff":{"lch":[56.2805330741479537,122.715491745326418,290.92682559337851],"luv":[56.2805330741479537,43.8309487146615382,-114.62085259266739],"rgb":[0.8,0.266666666666666663,1],"xyz":[0.450163943858687521,0.241930193548318406,0.969094734595147833],"hpluv":[290.92682559337851,276.681751484143376,56.2805330741479537],"hsluv":[290.92682559337851,99.9999999999989768,56.2805330741479537]},"#cc5500":{"lch":[51.07852272981998,108.355754132896138,24.3337665629108457],"luv":[51.07852272981998,98.7294936728878838,44.6481414260866],"rgb":[0.8,0.333333333333333315,0],"xyz":[0.281496412171203525,0.193364391616277664,0.0225003345836030169],"hpluv":[24.3337665629108457,269.186315008697875,51.07852272981998],"hsluv":[24.3337665629108457,100.000000000002217,51.07852272981998]},"#cc5511":{"lch":[51.1252833166066,107.003417336388864,23.6474066829241423],"luv":[51.1252833166066,98.0184651549503201,42.91983003616388],"rgb":[0.8,0.333333333333333315,0.0666666666666666657],"xyz":[0.282508077670840629,0.193769057816132517,0.0278284395483586466],"hpluv":[23.6474066829241423,265.583595811902,51.1252833166066],"hsluv":[23.6474066829241423,96.7082849697218307,51.1252833166066]},"#cc5522":{"lch":[51.2117930688627467,104.583581473170284,22.351909846807331],"luv":[51.2117930688627467,96.7257518395109486,39.7725337995530808],"rgb":[0.8,0.333333333333333315,0.133333333333333331],"xyz":[0.284383435809317686,0.194519201071523345,0.0377053257443378462],"hpluv":[22.351909846807331,259.139045481141636,51.2117930688627467],"hsluv":[22.351909846807331,90.7274756498525079,51.2117930688627467]},"#cc5533":{"lch":[51.3537468781662625,100.840694749975015,20.1540565840537802],"luv":[51.3537468781662625,94.6661789932146718,34.7442120716858369],"rgb":[0.8,0.333333333333333315,0.2],"xyz":[0.287471186541775392,0.195754301364506444,0.0539674796019489894],"hpluv":[20.1540565840537802,249.174169543579183,51.3537468781662625],"hsluv":[20.1540565840537802,81.2092815218714321,51.3537468781662625]},"#cc5544":{"lch":[51.5576456995760424,95.9504499860225764,16.842752904303623],"luv":[51.5576456995760424,91.8345174188591074,27.8012636936791502],"rgb":[0.8,0.333333333333333315,0.266666666666666663],"xyz":[0.291929181785994307,0.197537499462194038,0.0774462545548356279],"hpluv":[16.842752904303623,236.152889903020736,51.5576456995760424],"hsluv":[16.842752904303623,68.1451659970290109,51.5576456995760424]},"#cc5555":{"lch":[51.8284441386287114,90.3192908744292851,12.1770506300618919],"luv":[51.8284441386287114,88.2871484081680364,19.0513445723360242],"rgb":[0.8,0.333333333333333315,0.333333333333333315],"xyz":[0.297891595825356292,0.199922465077938871,0.108848301828809529],"hpluv":[12.1770506300618919,221.132040760117775,51.8284441386287114],"hsluv":[12.1770506300618919,51.8180912815801,51.8284441386287114]},"#cc5566":{"lch":[52.1698415772242612,84.57836719340618,5.91246023067467696],"luv":[52.1698415772242612,84.1284474176031836,8.71232071300305577],"rgb":[0.8,0.333333333333333315,0.4],"xyz":[0.305476591598864478,0.202956463387342162,0.148795946235953491],"hpluv":[5.91246023067467696,205.721226704565879,52.1698415772242612],"hsluv":[5.91246023067467696,54.0130370973951415,52.1698415772242612]},"#cc5577":{"lch":[52.5844387621358607,79.5477054283049654,357.892334615122479],"luv":[52.5844387621358607,79.493890006545314,-2.92555815796844554],"rgb":[0.8,0.333333333333333315,0.466666666666666674],"xyz":[0.314790604619066383,0.206682068595422985,0.1978497481423514],"hpluv":[357.892334615122479,191.959557587962337,52.5844387621358607],"hsluv":[357.892334615122479,56.4492590331968884,52.5844387621358607]},"#cc5588":{"lch":[53.0738428910491962,76.1348505840982,348.222799824086337],"luv":[53.0738428910491962,74.5321119975331072,-15.5396188708133902],"rgb":[0.8,0.333333333333333315,0.533333333333333326],"xyz":[0.325931021721010183,0.211138235436200583,0.256522611545923596],"hpluv":[348.222799824086337,182.029716109510787,53.0738428910491962],"hsluv":[348.222799824086337,59.0443947768825339,53.0738428910491962]},"#cc5599":{"lch":[53.6387547547300443,75.1322702050955655,337.451566852479516],"luv":[53.6387547547300443,69.3888374020903314,-28.8105409556599774],"rgb":[0.8,0.333333333333333315,0.6],"xyz":[0.338987985830082938,0.216361021079829741,0.325289289187041475],"hpluv":[337.451566852479516,177.740808472615271,53.6387547547300443],"hsluv":[337.451566852479516,61.7180151219793274,53.6387547547300443]},"#cc55aa":{"lch":[54.2790527162633651,76.9604755372169507,326.525055670409472],"luv":[54.2790527162633651,64.1948187783047359,-42.449264268479169],"rgb":[0.8,0.333333333333333315,0.66666666666666663],"xyz":[0.354045678795335439,0.222384098265930835,0.404593138804040076],"hpluv":[326.525055670409472,179.918080614224607,54.2790527162633651],"hsluv":[326.525055670409472,64.3982563598392517,54.2790527162633651]},"#cc55bb":{"lch":[54.9938795911038767,81.534325182187132,316.414019967357433],"luv":[54.9938795911038767,59.0586208757266817,-56.2132144888709888],"rgb":[0.8,0.333333333333333315,0.733333333333333282],"xyz":[0.371183270902672113,0.229239135108865594,0.494851123902681822],"hpluv":[316.414019967357433,188.133202867989326,54.9938795911038767],"hsluv":[316.414019967357433,67.0257727218245378,54.9938795911038767]},"#cc55cc":{"lch":[55.7817339145568667,88.3780574248019,307.715012949244169],"luv":[55.7817339145568667,54.0638926159085145,-69.9126351198200382],"rgb":[0.8,0.333333333333333315,0.8],"xyz":[0.390475646346393868,0.236956085286354395,0.596457634572952],"hpluv":[307.715012949244169,201.044301715196383,55.7817339145568667],"hsluv":[307.715012949244169,69.5552053299685156,55.7817339145568667]},"#cc55dd":{"lch":[56.6405645837994882,96.8744721490496232,300.570417552325068],"luv":[56.6405645837994882,49.2700598324241312,-83.4093793183137],"rgb":[0.8,0.333333333333333315,0.866666666666666696],"xyz":[0.411993971897027356,0.245563415506607929,0.709787482472958],"hpluv":[300.570417552325068,217.030665421015726,56.6405645837994882],"hsluv":[300.570417552325068,72.1703256475756234,56.6405645837994882]},"#cc55ee":{"lch":[57.5678665910353118,106.457154357221242,294.836459829444038],"luv":[57.5678665910353118,44.7151619549172707,-96.6109724885468],"rgb":[0.8,0.333333333333333315,0.933333333333333348],"xyz":[0.435806152163202121,0.255088287613077946,0.835198298541481199],"hpluv":[294.836459829444038,234.657286550118499,57.5678665910353118],"hsluv":[294.836459829444038,85.8995510844284809,57.5678665910353118]},"#cc55ff":{"lch":[58.560775097021633,116.686665261471418,290.266986003053091],"luv":[58.560775097021633,40.4196983751927874,-109.462440284789551],"rgb":[0.8,0.333333333333333315,1],"xyz":[0.461977200573033486,0.26555670697701067,0.973032486833263],"hpluv":[290.266986003053091,252.844632524376181,58.560775097021633],"hsluv":[290.266986003053091,99.9999999999988,58.560775097021633]},"#cc6600":{"lch":[54.388060759003551,98.5584029412379579,30.482787603130209],"luv":[54.388060759003551,84.9358174587045482,49.9966569177284157],"rgb":[0.8,0.4,0],"xyz":[0.29652446987705,0.223420507027971,0.0275096871522183678],"hpluv":[30.482787603130209,229.947880001204965,54.388060759003551],"hsluv":[30.482787603130209,100.000000000002359,54.388060759003551]},"#cc6611":{"lch":[54.430531479182676,97.2669366851907711,29.8266301777559697],"luv":[54.430531479182676,84.3824110244092367,48.3783596438383583],"rgb":[0.8,0.4,0.0666666666666666657],"xyz":[0.297536135376687105,0.223825173227825858,0.032837792116974],"hpluv":[29.8266301777559697,226.757672191171366,54.430531479182676],"hsluv":[29.8266301777559697,97.1300271864182463,54.430531479182676]},"#cc6622":{"lch":[54.5091256699603548,94.945229062596681,28.5830621108902889],"luv":[54.5091256699603548,83.3737269438019695,45.4248629854764],"rgb":[0.8,0.4,0.133333333333333331],"xyz":[0.299411493515164162,0.224575316483216686,0.0427146783129532],"hpluv":[28.5830621108902889,221.025945543219876,54.5091256699603548],"hsluv":[28.5830621108902889,91.902111940908739,54.5091256699603548]},"#cc6633":{"lch":[54.6381494647888388,91.324965774397,26.4577509745500876],"luv":[54.6381494647888388,81.7598754062496624,40.688722605278663],"rgb":[0.8,0.4,0.2],"xyz":[0.302499244247621868,0.225810416776199785,0.0589768321705643403],"hpluv":[26.4577509745500876,212.096187894217309,54.6381494647888388],"hsluv":[26.4577509745500876,83.5463344335908289,54.6381494647888388]},"#cc6644":{"lch":[54.8236025158742137,86.5353782352002,23.2174871910251],"luv":[54.8236025158742137,79.5273159773273903,34.1141861950638798],"rgb":[0.8,0.4,0.266666666666666663],"xyz":[0.306957239491840783,0.227593614873887379,0.0824556071234509858],"hpluv":[23.2174871910251,200.292852977212362,54.8236025158742137],"hsluv":[23.2174871910251,72.0055590941951635,54.8236025158742137]},"#cc6655":{"lch":[55.0701314820163077,80.921365039871,18.5706632184066578],"luv":[55.0701314820163077,76.7079190692017505,25.7713498286149552],"rgb":[0.8,0.4,0.333333333333333315],"xyz":[0.312919653531202768,0.229978580489632212,0.113857654397424887],"hpluv":[18.5706632184066578,186.460314881725708,55.0701314820163077],"hsluv":[18.5706632184066578,57.463707489477386,55.0701314820163077]},"#cc6666":{"lch":[55.3812986167643686,75.0592421503045841,12.1770506300619576],"luv":[55.3812986167643686,73.3704437553848834,15.8324923911544637],"rgb":[0.8,0.4,0.4],"xyz":[0.320504649304710953,0.233012578799035502,0.153805298804568835],"hpluv":[12.1770506300619576,171.980959079196282,55.3812986167643686],"hsluv":[12.1770506300619576,45.9214429163451925,55.3812986167643686]},"#cc6677":{"lch":[55.7597240294908403,69.7578535305897702,3.7339069954147126],"luv":[55.7597240294908403,69.6097753289024,4.54283037928401079],"rgb":[0.8,0.4,0.466666666666666674],"xyz":[0.329818662324912859,0.236738184007116326,0.202859100710966744],"hpluv":[3.7339069954147126,158.749300244695775,55.7597240294908403],"hsluv":[3.7339069954147126,47.4001946683844935,55.7597240294908403]},"#cc6688":{"lch":[56.2071770412836855,65.9988703650454198,353.20230012342131],"luv":[56.2071770412836855,65.534915505775615,-7.81189727997758432],"rgb":[0.8,0.4,0.533333333333333326],"xyz":[0.340959079426856659,0.241194350847893924,0.26153196411453894],"hpluv":[353.20230012342131,148.999240608904586,56.2071770412836855],"hsluv":[353.20230012342131,48.9818497710332537,56.2071770412836855]},"#cc6699":{"lch":[56.7246474757154573,64.7364860461136544,341.13073016495332],"luv":[56.7246474757154573,61.2574795353059756,-20.9364234428957907],"rgb":[0.8,0.4,0.6],"xyz":[0.354016043535929414,0.246417136491523081,0.330298641755656819],"hpluv":[341.13073016495332,144.81603174775961,56.7246474757154573],"hsluv":[341.13073016495332,50.615240188358726,56.7246474757154573]},"#cc66aa":{"lch":[57.3124110050500661,66.5536753014576874,328.724652687595039],"luv":[57.3124110050500661,56.882247269492467,-34.5514347271451925],"rgb":[0.8,0.4,0.66666666666666663],"xyz":[0.369073736501181915,0.252440213677624203,0.40960249137265542],"hpluv":[328.724652687595039,147.354258527000582,57.3124110050500661],"hsluv":[328.724652687595039,52.5782983823555057,57.3124110050500661]},"#cc66bb":{"lch":[57.9700950113726634,71.4140361316817831,317.320615294889421],"luv":[57.9700950113726634,52.5006394421278628,-48.4112323204526405],"rgb":[0.8,0.4,0.733333333333333282],"xyz":[0.386211328608518589,0.259295250520558962,0.499860476471297166],"hpluv":[317.320615294889421,156.321564636453559,57.9700950113726634],"hsluv":[317.320615294889421,55.7867325729046044,57.9700950113726634]},"#cc66cc":{"lch":[58.6967474031167882,78.7715159072838844,307.71501294924451],"luv":[58.6967474031167882,48.1872412824568599,-62.3132529717215391],"rgb":[0.8,0.4,0.8],"xyz":[0.405503704052240344,0.267012200698047764,0.601466987141567322],"hpluv":[307.71501294924451,170.292097080892688,58.6967474031167882],"hsluv":[307.71501294924451,58.9158791245518429,58.6967474031167882]},"#cc66dd":{"lch":[59.4909085631812928,87.9045601549668589,300.035118747227784],"luv":[59.4909085631812928,43.9989332886277964,-76.1006278916348151],"rgb":[0.8,0.4,0.866666666666666696],"xyz":[0.427022029602873832,0.27561953091830127,0.71479683504157332],"hpluv":[300.035118747227784,187.499506963343748,59.4909085631812928],"hsluv":[300.035118747227784,69.8010448945604907,59.4909085631812928]},"#cc66ee":{"lch":[60.3506853352839272,98.1678970647401314,294.030303780460372],"luv":[60.3506853352839272,39.9759075841908498,-89.6597057040320919],"rgb":[0.8,0.4,0.933333333333333348],"xyz":[0.450834209869048597,0.285144403024771287,0.840207651110096543],"hpluv":[294.030303780460372,206.408039079415715,60.3506853352839272],"hsluv":[294.030303780460372,84.6650997716967169,60.3506853352839272]},"#cc66ff":{"lch":[61.2738253236974799,109.076950193692937,289.351384827957531],"luv":[61.2738253236974799,36.143813792667018,-102.914555763887847],"rgb":[0.8,0.4,1],"xyz":[0.477005258278879962,0.295612822388704,0.978041839401878388],"hpluv":[289.351384827957531,225.890163025573315,61.2738253236974799],"hsluv":[289.351384827957531,99.9999999999987,61.2738253236974799]},"#cc7700":{"lch":[58.0681687130694684,90.1274111260576,38.2527636780657616],"luv":[58.0681687130694684,70.775890411238,55.8007488550273862],"rgb":[0.8,0.466666666666666674,0],"xyz":[0.314978207930467602,0.260327983134806762,0.0336609331700240683],"hpluv":[38.2527636780657616,196.95095583694345,58.0681687130694684],"hsluv":[38.2527636780657616,100.00000000000226,58.0681687130694684]},"#cc7711":{"lch":[58.1065272060428,88.8714225311590837,37.658223554494576],"luv":[58.1065272060428,70.356768805075,54.2959927252558288],"rgb":[0.8,0.466666666666666674,0.0666666666666666657],"xyz":[0.315989873430104706,0.260732649334661615,0.0389890381347797],"hpluv":[37.658223554494576,194.078102813960953,58.1065272060428],"hsluv":[37.658223554494576,97.5201736027742925,58.1065272060428]},"#cc7722":{"lch":[58.1775287784180364,86.6008188207648573,36.5262538454337786],"luv":[58.1775287784180364,69.5910513475594286,51.5440335321973748],"rgb":[0.8,0.466666666666666674,0.133333333333333331],"xyz":[0.317865231568581763,0.261482792590052415,0.0488659243307589],"hpluv":[36.5262538454337786,188.888733728089306,58.1775287784180364],"hsluv":[36.5262538454337786,92.9922153048462832,58.1775287784180364]},"#cc7733":{"lch":[58.2941365993826111,83.0249283524691606,34.5753600294232513],"luv":[58.2941365993826111,68.3611064237300781,47.1157920070976459],"rgb":[0.8,0.466666666666666674,0.2],"xyz":[0.320952982301039469,0.262717892883035542,0.0651280781883700477],"hpluv":[34.5753600294232513,180.726967614303447,58.2941365993826111],"hsluv":[34.5753600294232513,85.7262720770138458,58.2941365993826111]},"#cc7744":{"lch":[58.4618482438389577,78.2181767747613321,31.5590767862408974],"luv":[58.4618482438389577,66.6497843857434447,40.9376284034837923],"rgb":[0.8,0.466666666666666674,0.266666666666666663],"xyz":[0.325410977545258384,0.264501090980723108,0.0886068531412566862],"hpluv":[31.5590767862408974,169.775287201810244,58.4618482438389577],"hsluv":[31.5590767862408974,75.6318325574838,58.4618482438389577]},"#cc7755":{"lch":[58.6849825995062133,72.4480337937475,27.1381330463907204],"luv":[58.6849825995062133,64.4721877935720187,33.0462494345479811],"rgb":[0.8,0.466666666666666674,0.333333333333333315],"xyz":[0.331373391584620369,0.266886056596467969,0.120008900415230588],"hpluv":[27.1381330463907204,156.653084219512607,58.6849825995062133],"hsluv":[27.1381330463907204,62.8141161752895059,58.6849825995062133]},"#cc7766":{"lch":[58.9669266929607829,66.2083874258113667,20.8554290651987451],"luv":[58.9669266929607829,61.8705265372573407,23.5709251309504673],"rgb":[0.8,0.466666666666666674,0.4],"xyz":[0.338958387358128554,0.269920054905871287,0.159956544822374536],"hpluv":[20.8554290651987451,142.476698671576116,58.9669266929607829],"hsluv":[20.8554290651987451,47.542957476979069,58.9669266929607829]},"#cc7777":{"lch":[59.3102652975897229,60.2635194006596251,12.177050630062082],"luv":[59.3102652975897229,58.907617956407762,12.7115820123061383],"rgb":[0.8,0.466666666666666674,0.466666666666666674],"xyz":[0.34827240037833046,0.273645660113952083,0.209010346728772445],"hpluv":[12.177050630062082,128.932959302114057,59.3102652975897229],"hsluv":[12.177050630062082,43.5373021749198443,59.3102652975897229]},"#cc7788":{"lch":[59.7168613687891963,55.6638868177661834,0.734433949810619269],"luv":[59.7168613687891963,55.6593138534775917,0.713496335773026069],"rgb":[0.8,0.466666666666666674,0.533333333333333326],"xyz":[0.35941281748027426,0.278101826954729681,0.26768321013234464],"hpluv":[0.734433949810619269,118.281243349182901,59.7168613687891963],"hsluv":[0.734433949810619269,45.0130000154657779,59.7168613687891963]},"#cc7799":{"lch":[60.187915321807921,53.6038783156568073,346.890122071781263],"luv":[60.187915321807921,52.2067938730354371,-12.1583898596044406],"rgb":[0.8,0.466666666666666674,0.6],"xyz":[0.37246978158934696,0.283324612598358838,0.336449887773462519],"hpluv":[346.890122071781263,113.012436406344946,60.187915321807921],"hsluv":[346.890122071781263,46.5549497102544,60.187915321807921]},"#cc77aa":{"lch":[60.7240163061688349,54.9761438743297148,332.197464335395125],"luv":[60.7240163061688349,48.6297161920954863,-25.6422912074417866],"rgb":[0.8,0.466666666666666674,0.66666666666666663],"xyz":[0.387527474554599516,0.28934768978445996,0.41575373739046112],"hpluv":[332.197464335395125,114.882297594683308,60.7240163061688349],"hsluv":[332.197464335395125,48.1189262345266471,60.7240163061688349]},"#cc77bb":{"lch":[61.3251919150652043,59.875823087291181,318.726648244723037],"luv":[61.3251919150652043,45.0009333565193046,-39.4972174643062743],"rgb":[0.8,0.466666666666666674,0.733333333333333282],"xyz":[0.40466506666193619,0.296202726627394719,0.506011722489102866],"hpluv":[318.726648244723037,123.894465684476771,61.3251919150652043],"hsluv":[318.726648244723037,49.6642191709372156,61.3251919150652043]},"#cc77cc":{"lch":[61.9909592768387228,67.6487625915650881,307.715012949244965],"luv":[61.9909592768387228,41.3830711255614219,-53.514451360232222],"rgb":[0.8,0.466666666666666674,0.8],"xyz":[0.423957442105657889,0.303919676804883521,0.607618233159373],"hpluv":[307.715012949244965,138.474825543749517,61.9909592768387228],"hsluv":[307.715012949244965,51.1553628289834066,61.9909592768387228]},"#cc77dd":{"lch":[62.7203784873954362,77.3966796673740305,299.257833182927357],"luv":[62.7203784873954362,37.8268934727942252,-67.5231231041040161],"rgb":[0.8,0.466666666666666674,0.866666666666666696],"xyz":[0.445475767656291488,0.312527007025137,0.720948081059379],"hpluv":[299.257833182927357,156.586020071329443,62.7203784873954362],"hsluv":[299.257833182927357,66.8390608629672158,62.7203784873954362]},"#cc77ee":{"lch":[63.5121081687847351,88.3507940057556453,292.894169444170245],"luv":[63.5121081687847351,34.371127600373157,-81.3909601179783],"rgb":[0.8,0.466666666666666674,0.933333333333333348],"xyz":[0.469287947922466198,0.322051879131607044,0.846358897127902243],"hpluv":[292.894169444170245,176.519730115921618,63.5121081687847351],"hsluv":[292.894169444170245,83.1130682001540322,63.5121081687847351]},"#cc77ff":{"lch":[64.3644622692190467,99.9639900757921112,288.092077643344339],"luv":[64.3644622692190467,31.0433170684360782,-95.0216384686225553],"rgb":[0.8,0.466666666666666674,1],"xyz":[0.495458996332297619,0.332520298495539768,0.984193085419684088],"hpluv":[288.092077643344339,197.077372703744913,64.3644622692190467],"hsluv":[288.092077643344339,99.9999999999984794,64.3644622692190467]},"#cc8800":{"lch":[62.03823759594124,83.9779445354575813,47.4964941193052752],"luv":[62.03823759594124,56.738465406715342,61.9115636346826221],"rgb":[0.8,0.533333333333333326,0],"xyz":[0.337050577655438111,0.304472722584748334,0.0410183897450140181],"hpluv":[47.4964941193052752,171.769129739761638,62.03823759594124],"hsluv":[47.4964941193052752,100.000000000002245,62.03823759594124]},"#cc8811":{"lch":[62.0727951053461879,82.7448035916202542,47.0033697453910904],"luv":[62.0727951053461879,56.4282611354359744,60.519037225048919],"rgb":[0.8,0.533333333333333326,0.0666666666666666657],"xyz":[0.338062243155075215,0.304877388784603187,0.0463464947097696478],"hpluv":[47.0033697453910904,169.152629782786704,62.0727951053461879],"hsluv":[47.0033697453910904,97.8669953021426,62.0727951053461879]},"#cc8822":{"lch":[62.1367747194074127,80.5023095814055836,46.0605806208152728],"luv":[62.1367747194074127,55.8603434591127268,57.9676105818622389],"rgb":[0.8,0.533333333333333326,0.133333333333333331],"xyz":[0.339937601293552272,0.305627532039994,0.0562233809057488473],"hpluv":[46.0605806208152728,164.398919884807611,62.1367747194074127],"hsluv":[46.0605806208152728,93.9640765124603,62.1367747194074127]},"#cc8833":{"lch":[62.2418885518498541,76.9329948636363241,44.4230175211057343],"luv":[62.2418885518498541,54.9448944756850963,53.8492736231801246],"rgb":[0.8,0.533333333333333326,0.2],"xyz":[0.34302535202601,0.306862632332977114,0.0724855347633599906],"hpluv":[44.4230175211057343,156.844467463147254,62.2418885518498541],"hsluv":[44.4230175211057343,87.678806867525978,62.2418885518498541]},"#cc8844":{"lch":[62.3931521103864668,72.0506908450526424,41.8566920827827929],"luv":[62.3931521103864668,53.6645163812677168,48.0772475586321661],"rgb":[0.8,0.533333333333333326,0.266666666666666663],"xyz":[0.347483347270228893,0.30864583043066468,0.0959643097162466291],"hpluv":[41.8566920827827929,146.534723453778,62.3931521103864668],"hsluv":[41.8566920827827929,78.900857077449,62.3931521103864668]},"#cc8855":{"lch":[62.5945538889838673,66.028576146577123,38.0101307109045408],"luv":[62.5945538889838673,52.0240395147187513,40.6604498316892062],"rgb":[0.8,0.533333333333333326,0.333333333333333315],"xyz":[0.353445761309590878,0.311030796046409541,0.127366356990220531],"hpluv":[38.0101307109045408,133.855034432196135,62.5945538889838673],"hsluv":[38.0101307109045408,67.6770944211119314,62.5945538889838673]},"#cc8866":{"lch":[62.8492816845599265,59.2369010326618337,32.3420191431213624],"luv":[62.8492816845599265,50.047464385327217,31.6900891849924626],"rgb":[0.8,0.533333333333333326,0.4],"xyz":[0.361030757083099063,0.31406479435581286,0.167314001397364492],"hpluv":[32.3420191431213624,119.60004374597824,62.8492816845599265],"hsluv":[32.3420191431213624,54.1901780257147436,62.8492816845599265]},"#cc8877":{"lch":[63.1598410661450771,52.3169991415742,24.053169540805424],"luv":[63.1598410661450771,47.7741895619322392,21.3235834436907119],"rgb":[0.8,0.533333333333333326,0.466666666666666674],"xyz":[0.370344770103300969,0.317790399563893655,0.216367803303762402],"hpluv":[24.053169540805424,105.109295035123296,63.1598410661450771],"hsluv":[24.053169540805424,38.7316682482548558,63.1598410661450771]},"#cc8888":{"lch":[63.5281271999152182,46.2961098245983322,12.1770506300622312],"luv":[63.5281271999152182,45.2544686659219906,9.76539045078869528],"rgb":[0.8,0.533333333333333326,0.533333333333333326],"xyz":[0.381485187205244769,0.322246566404671253,0.275040666707334569],"hpluv":[12.1770506300622312,92.4736018048895403,63.5281271999152182],"hsluv":[12.1770506300622312,40.0703189706204199,63.5281271999152182]},"#cc8899":{"lch":[63.9554753143552119,42.6335463086933615,356.296984030050055],"luv":[63.9554753143552119,42.5445368433351,-2.7534806412255004],"rgb":[0.8,0.533333333333333326,0.6],"xyz":[0.394542151314317469,0.327469352048300411,0.343807344348452504],"hpluv":[356.296984030050055,84.588837176407921,63.9554753143552119],"hsluv":[356.296984030050055,41.5088242950414781,63.9554753143552119]},"#cc88aa":{"lch":[64.442701858069384,42.8028595258545153,338.056731442080661],"luv":[64.442701858069384,39.701977128446444,-15.9949303118941444],"rgb":[0.8,0.533333333333333326,0.66666666666666663],"xyz":[0.40959984427957,0.333492429234401533,0.423111193965451104],"hpluv":[338.056731442080661,84.28268641071584,64.442701858069384],"hsluv":[338.056731442080661,42.9831867606486924,64.442701858069384]},"#cc88bb":{"lch":[64.9901424985427099,47.2946673003310707,321.051918945199532],"luv":[64.9901424985427099,36.7818149859187784,-29.7301806484697622],"rgb":[0.8,0.533333333333333326,0.733333333333333282],"xyz":[0.426737436386906699,0.340347466077336291,0.513369179064092851],"hpluv":[321.051918945199532,92.3430068912496296,64.9901424985427099],"hsluv":[321.051918945199532,44.4548878388224864,64.9901424985427099]},"#cc88cc":{"lch":[65.5976900795525637,55.3077284551996158,307.715012949245761],"luv":[65.5976900795525637,33.8336367550969399,-43.751912538747959],"rgb":[0.8,0.533333333333333326,0.8],"xyz":[0.446029811830628398,0.348064416254825093,0.614975689734363],"hpluv":[307.715012949245761,106.988377595373095,65.5976900795525637],"hsluv":[307.715012949245761,45.8886814173124122,65.5976900795525637]},"#cc88dd":{"lch":[66.2648339334855905,65.6132669537387727,298.095232643272539],"luv":[66.2648339334855905,30.8998122908772608,-57.8817967994354774],"rgb":[0.8,0.533333333333333326,0.866666666666666696],"xyz":[0.467548137381262,0.356671746475078599,0.728305537634369],"hpluv":[298.095232643272539,125.645770778198369,66.2648339334855905],"hsluv":[298.095232643272539,63.1276078601331037,66.2648339334855905]},"#cc88ee":{"lch":[66.9907009061042,77.2337728548956193,291.267726386147558],"luv":[66.9907009061042,28.0147259973813227,-71.9738202174461463],"rgb":[0.8,0.533333333333333326,0.933333333333333348],"xyz":[0.491360317647436706,0.366196618581548616,0.853716353702892228],"hpluv":[291.267726386147558,146.295866424915545,66.9907009061042],"hsluv":[291.267726386147558,81.1585487563552874,66.9907009061042]},"#cc88ff":{"lch":[67.7740978167257,89.535143384050329,286.350196506734335],"luv":[67.7740978167257,25.2048126805589376,-85.914255618845857],"rgb":[0.8,0.533333333333333326,1],"xyz":[0.517531366057268127,0.37666503794548134,0.991550541994674073],"hpluv":[286.350196506734335,167.63670457649863,67.7740978167257],"hsluv":[286.350196506734335,99.9999999999982379,67.7740978167257]},"#cc9900":{"lch":[66.2294666531998217,80.7116888085701163,57.6888018595631422],"luv":[66.2294666531998217,43.1418134232290527,68.2140795209226383],"rgb":[0.8,0.6,0],"xyz":[0.362920178107905556,0.356211923489684,0.0496415898958362731],"hpluv":[57.6888018595631422,154.64094800189136,66.2294666531998217],"hsluv":[57.6888018595631422,100.000000000002331,66.2294666531998217]},"#cc9911":{"lch":[66.2605931548954459,79.5070460268624,57.3307205104302042],"luv":[66.2605931548954459,42.9170325725223805,66.9290570909725915],"rgb":[0.8,0.6,0.0666666666666666657],"xyz":[0.36393184360754266,0.356616589689538854,0.0549696948605919],"hpluv":[57.3307205104302042,152.261332222626407,66.2605931548954459],"hsluv":[57.3307205104302042,98.1673920986410877,66.2605931548954459]},"#cc9922":{"lch":[66.318231165714252,77.3048675578901339,56.6444543825244],"luv":[66.318231165714252,42.5047546114663533,64.5708013235236535],"rgb":[0.8,0.6,0.133333333333333331],"xyz":[0.365807201746019717,0.357366732944929655,0.0648465810565711],"hpluv":[56.6444543825244,147.915345655385721,66.318231165714252],"hsluv":[56.6444543825244,94.8079930897652901,66.318231165714252]},"#cc9933":{"lch":[66.4129558628457772,73.7662990604099207,55.446788144651876],"luv":[66.4129558628457772,41.8381333944198062,60.7539091017242114],"rgb":[0.8,0.6,0.2],"xyz":[0.368894952478477423,0.358601833237912782,0.0811087349141822456],"hpluv":[55.446788144651876,140.943324602767206,66.4129558628457772],"hsluv":[55.446788144651876,89.3812598244831804,66.4129558628457772]},"#cc9944":{"lch":[66.5493334014023361,68.8491039809152596,53.5533094328142383],"luv":[66.5493334014023361,40.9015039610359423,55.3829043360877122],"rgb":[0.8,0.6,0.266666666666666663],"xyz":[0.373352947722696338,0.360385031335600348,0.104587509867068884],"hpluv":[53.5533094328142383,131.278591794008349,66.5493334014023361],"hsluv":[53.5533094328142383,81.7675495661837459,66.5493334014023361]},"#cc9955":{"lch":[66.7310322275847341,62.6300376921671571,50.6698876242401539],"luv":[66.7310322275847341,39.6941340540006422,48.4447865412296466],"rgb":[0.8,0.6,0.333333333333333315],"xyz":[0.379315361762058323,0.362769996951345208,0.135989557141042799],"hpluv":[50.6698876242401539,119.095172229338388,66.7310322275847341],"hsluv":[50.6698876242401539,71.9728873324543912,66.7310322275847341]},"#cc9966":{"lch":[66.9610303820851,55.3290996264574488,46.2964172073191236],"luv":[66.9610303820851,38.2284030091626121,39.9987308404091877],"rgb":[0.8,0.6,0.4],"xyz":[0.386900357535566508,0.365803995260748527,0.175937201548186761],"hpluv":[46.2964172073191236,104.850571413887963,66.9610303820851],"hsluv":[46.2964172073191236,60.1139469393688586,66.9610303820851]},"#cc9977":{"lch":[67.2417240975963608,47.3725698769106316,39.5497292985384448],"luv":[67.2417240975963608,36.5276723895038842,30.1643751227811094],"rgb":[0.8,0.6,0.466666666666666674],"xyz":[0.396214370555768414,0.369529600468829322,0.22499100345458467],"hpluv":[39.5497292985384448,89.3979234879296598,67.2417240975963608],"hsluv":[39.5497292985384448,46.4000360859745484,67.2417240975963608]},"#cc9988":{"lch":[67.5749927230407508,39.5461637624335367,28.8927829606528306],"luv":[67.5749927230407508,34.6236706423047593,19.1076031876950658],"rgb":[0.8,0.6,0.533333333333333326],"xyz":[0.407354787657712214,0.37398576730960692,0.28366386685815681],"hpluv":[28.8927829606528306,74.2604675709266076,67.5749927230407508],"hsluv":[28.8927829606528306,33.7758353105824227,67.5749927230407508]},"#cc9999":{"lch":[67.962242737641,33.3028609095241,12.177050630062606],"luv":[67.962242737641,32.5535618700051401,7.02468179598591647],"rgb":[0.8,0.6,0.6],"xyz":[0.420411751766784914,0.379208552953236078,0.352430544499274745],"hpluv":[12.177050630062606,62.1803508213615217,67.962242737641],"hsluv":[12.177050630062606,35.0991912912463349,67.962242737641]},"#cc99aa":{"lch":[68.4044417972397838,30.9200145018949506,349.049331623372325],"luv":[68.4044417972397838,30.3569952347367966,-5.87368173427548168],"rgb":[0.8,0.6,0.66666666666666663],"xyz":[0.43546944473203747,0.3852316301393372,0.431734394116273346],"hpluv":[349.049331623372325,57.3580941092039609,68.4044417972397838],"hsluv":[349.049331623372325,36.4663034143199312,68.4044417972397838]},"#cc99bb":{"lch":[68.9021485343020856,34.1112448474386483,325.385883063702067],"luv":[68.9021485343020856,28.0734328763681233,-19.3767745401024669],"rgb":[0.8,0.6,0.733333333333333282],"xyz":[0.452607036839374144,0.392086666982271959,0.521992379214915],"hpluv":[325.385883063702067,62.8208966420876678,68.9021485343020856],"hsluv":[325.385883063702067,37.8410036888738404,68.9021485343020856]},"#cc99cc":{"lch":[69.4555411877739601,42.0770553751994854,307.715012949247],"luv":[69.4555411877739601,25.7399796927440505,-33.285613025220492],"rgb":[0.8,0.6,0.8],"xyz":[0.471899412283095843,0.39980361715976076,0.623598889885185192],"hpluv":[307.715012949247,76.8736967911951581,69.4555411877739601],"hsluv":[307.715012949247,39.1886552488513473,69.4555411877739601]},"#cc99dd":{"lch":[70.0644466506374215,52.8759829560521695,296.254085335195782],"luv":[70.0644466506374215,23.3898305690433475,-47.4213601610093534],"rgb":[0.8,0.6,0.866666666666666696],"xyz":[0.493417737833729442,0.408410947380014266,0.73692873778519119],"hpluv":[296.254085335195782,95.7635162234915498,70.0644466506374215],"hsluv":[296.254085335195782,58.3905887561973813,70.0644466506374215]},"#cc99ee":{"lch":[70.7283706212672,65.1265075826905218,288.858843135035954],"luv":[70.7283706212672,21.0513451251656711,-61.6303728557552191],"rgb":[0.8,0.6,0.933333333333333348],"xyz":[0.517229918099904151,0.417935819486484283,0.862339553853714413],"hpluv":[288.858843135035954,116.843205481858362,70.7283706212672],"hsluv":[288.858843135035954,78.6530020758075494,70.7283706212672]},"#cc99ff":{"lch":[71.4465289765693115,78.0706881495843561,283.894640570210413],"luv":[71.4465289765693115,18.7476796475605703,-75.7862576987549517],"rgb":[0.8,0.6,1],"xyz":[0.543400966509735572,0.428404238850417,1.00017374214549637],"hpluv":[283.894640570210413,138.658404713871533,71.4465289765693115],"hsluv":[283.894640570210413,99.9999999999978,71.4465289765693115]},"#990000":{"lch":[31.2857235930303546,105.214874065330946,12.1770506300617765],"luv":[31.2857235930303546,102.847587834444283,22.1933188419334826],"rgb":[0.6,0,0],"xyz":[0.131365760434599882,0.067735470224092,0.00615777002037173893],"hpluv":[12.1770506300617765,426.746789183125316,31.2857235930303546],"hsluv":[12.1770506300617765,100.000000000002217,31.2857235930303546]},"#990011":{"lch":[31.379701704172021,102.819321078199806,10.8595456684147944],"luv":[31.379701704172021,100.978030711674904,19.3713732237542438],"rgb":[0.6,0,0.0666666666666666657],"xyz":[0.132377425934237014,0.0681401364239468538,0.0114858749851273704],"hpluv":[10.8595456684147944,415.781582167217948,31.379701704172021],"hsluv":[10.8595456684147944,99.9999999999964473,31.379701704172021]},"#990022":{"lch":[31.5529326060038784,98.7447775317108807,8.37468971343924729],"luv":[31.5529326060038784,97.6918390895904309,14.3817824027706251],"rgb":[0.6,0,0.133333333333333331],"xyz":[0.134252784072714015,0.0688902796793376682,0.0213627611811065682],"hpluv":[8.37468971343924729,397.112659756655944,31.5529326060038784],"hsluv":[8.37468971343924729,99.999999999996632,31.5529326060038784]},"#990033":{"lch":[31.8354354483696653,92.9837515463916162,4.18138532137367758],"luv":[31.8354354483696653,92.7362491408617586,6.7798338419980837],"rgb":[0.6,0,0.2],"xyz":[0.137340534805171777,0.070125379972320781,0.0376249150387177114],"hpluv":[4.18138532137367758,370.62575576901952,31.8354354483696653],"hsluv":[4.18138532137367758,99.9999999999969,31.8354354483696653]},"#990044":{"lch":[32.2375108843075537,86.4821897260425771,357.977822115898675],"luv":[32.2375108843075537,86.4283323676992552,-3.05163955108307716],"rgb":[0.6,0,0.266666666666666663],"xyz":[0.141798530049390636,0.071908578070008361,0.0611036899916043499],"hpluv":[357.977822115898675,340.411718586576399,32.2375108843075537],"hsluv":[357.977822115898675,99.9999999999971294,32.2375108843075537]},"#990055":{"lch":[32.7650133258702,80.5606445545256804,349.629319937368109],"luv":[32.7650133258702,79.244583226626645,-14.502188809930411],"rgb":[0.6,0,0.333333333333333315],"xyz":[0.147760944088752622,0.0742935436857532,0.0925057372655782584],"hpluv":[349.629319937368109,311.998071704954214,32.7650133258702],"hsluv":[349.629319937368109,99.9999999999974847,32.7650133258702]},"#990066":{"lch":[33.4199981031921354,76.5714397631706589,339.419101050621862],"luv":[33.4199981031921354,71.6844038684648268,-26.9171252073414813],"rgb":[0.6,0,0.4],"xyz":[0.155345939862260807,0.0773275419951565124,0.13245338167272222],"hpluv":[339.419101050621862,290.7366076723265,33.4199981031921354],"hsluv":[339.419101050621862,99.9999999999978257,33.4199981031921354]},"#990077":{"lch":[34.2012599030024091,75.4745938555541187,328.234093427391315],"luv":[34.2012599030024091,64.1689603650959413,-39.7335984190155429],"rgb":[0.6,0,0.466666666666666674],"xyz":[0.164659952882462712,0.0810531472032373218,0.181507183579120129],"hpluv":[328.234093427391315,280.025774017920355,34.2012599030024091],"hsluv":[328.234093427391315,99.9999999999982094,34.2012599030024091]},"#990088":{"lch":[35.1048906557013396,77.5195253213057214,317.327493504651898],"luv":[35.1048906557013396,56.9954501323273419,-52.5432723595889613],"rgb":[0.6,0,0.533333333333333326],"xyz":[0.175800369984406568,0.0855093140440149196,0.240180046982692297],"hpluv":[317.327493504651898,280.209468657326,35.1048906557013396],"hsluv":[317.327493504651898,99.9999999999985505,35.1048906557013396]},"#990099":{"lch":[36.1248689761228263,82.286593786153162,307.715012949243601],"luv":[36.1248689761228263,50.3375351282041592,-65.0939019735657922],"rgb":[0.6,0,0.6],"xyz":[0.188857334093479268,0.0907320996876440772,0.308946724623810232],"hpluv":[307.715012949243601,289.042783730483336,36.1248689761228263],"hsluv":[307.715012949243601,99.9999999999988205,36.1248689761228263]},"#9900aa":{"lch":[37.2536516336468,89.0432435337247,299.813571633796073],"luv":[37.2536516336468,44.2704748017611038,-77.2581664281054685],"rgb":[0.6,0,0.66666666666666663],"xyz":[0.203915027058731824,0.0967551768737451856,0.388250574240808777],"hpluv":[299.813571633796073,303.299328566743952,37.2536516336468],"hsluv":[299.813571633796073,99.9999999999990905,37.2536516336468]},"#9900bb":{"lch":[38.4827280957899163,97.0854614833978786,293.557760104203282],"luv":[38.4827280957899163,38.802472411223853,-88.9941288300556579],"rgb":[0.6,0,0.733333333333333282],"xyz":[0.221052619166068443,0.103610213716679944,0.478508559339450579],"hpluv":[293.557760104203282,320.130957524774431,38.4827280957899163],"hsluv":[293.557760104203282,99.9999999999993179,38.4827280957899163]},"#9900cc":{"lch":[39.8031058181596933,105.884836559305498,288.673688741635],"luv":[39.8031058181596933,33.9019931565070394,-100.310784431221492],"rgb":[0.6,0,0.8],"xyz":[0.240344994609790197,0.111327163894168746,0.580115070009720735],"hpluv":[288.673688741635,337.564008898092311,39.8031058181596933],"hsluv":[288.673688741635,99.9999999999995879,39.8031058181596933]},"#9900dd":{"lch":[41.2057071388761145,115.092674624289529,284.860629917023232],"luv":[41.2057071388761145,29.5176685469448401,-111.243116621772529],"rgb":[0.6,0,0.866666666666666696],"xyz":[0.26186332016042374,0.11993449411442228,0.693444917909726732],"hpluv":[284.860629917023232,354.429316861661562,41.2057071388761145],"hsluv":[284.860629917023232,99.9999999999996732,41.2057071388761145]},"#9900ee":{"lch":[42.6816722484951754,124.494824438150232,281.862271937449748],"luv":[42.6816722484951754,25.5911328567321625,-121.836181945245357],"rgb":[0.6,0,0.933333333333333348],"xyz":[0.285675500426598505,0.129459366220892297,0.81885573397825],"hpluv":[281.862271937449748,370.125661914021862,42.6816722484951754],"hsluv":[281.862271937449748,99.9999999999998437,42.6816722484951754]},"#9900ff":{"lch":[44.2225734052255817,133.965544030308308,279.479958267333473],"luv":[44.2225734052255817,22.0644732467518,-132.136013288126151],"rgb":[0.6,0,1],"xyz":[0.311846548836429871,0.139927785584825,0.956689922270031801],"hpluv":[279.479958267333473,384.404468177447882,44.2225734052255817],"hsluv":[279.479958267333473,99.9999999999999574,44.2225734052255817]},"#bb0000":{"lch":[38.8409426943877918,130.623313921981463,12.1770506300617818],"luv":[38.8409426943877918,127.684349491075153,27.5528044852332741],"rgb":[0.733333333333333282,0,0],"xyz":[0.20493059501477473,0.105667338054495463,0.00960612164131736251],"hpluv":[12.1770506300617818,426.746789183125145,38.8409426943877918],"hsluv":[12.1770506300617818,100.000000000002217,38.8409426943877918]},"#bb0011":{"lch":[38.9108602521517142,128.680110500437479,11.3344428162225856],"luv":[38.9108602521517142,126.170422440132384,25.2902222149853806],"rgb":[0.733333333333333282,0,0.0666666666666666657],"xyz":[0.205942260514411862,0.106072004254350316,0.014934226606072994],"hpluv":[11.3344428162225856,419.642938315359174,38.9108602521517142],"hsluv":[11.3344428162225856,99.9999999999964189,38.9108602521517142]},"#bb0022":{"lch":[39.0399998564474373,125.270257566289573,9.75441483214293292],"luv":[39.0399998564474373,123.459226352671962,21.2239689767074431],"rgb":[0.733333333333333282,0,0.133333333333333331],"xyz":[0.207817618652888864,0.10682214750974113,0.0248111128020521918],"hpluv":[9.75441483214293292,407.171610230013243,39.0399998564474373],"hsluv":[9.75441483214293292,99.9999999999965326,39.0399998564474373]},"#bb0033":{"lch":[39.2513155564018916,120.169209623826248,7.10634666793171554],"luv":[39.2513155564018916,119.246098647877318,14.866300779810846],"rgb":[0.733333333333333282,0,0.2],"xyz":[0.210905369385346597,0.108057247802724243,0.041073266659663335],"hpluv":[7.10634666793171554,388.488631169232178,39.2513155564018916],"hsluv":[7.10634666793171554,99.9999999999967173,39.2513155564018916]},"#bb0044":{"lch":[39.5535843326651886,113.833969399977519,3.19865110237705785],"luv":[39.5535843326651886,113.656624965458903,6.3517077086437],"rgb":[0.733333333333333282,0,0.266666666666666663],"xyz":[0.215363364629565485,0.109840445900411823,0.0645520416125499735],"hpluv":[3.19865110237705785,365.195452768261646,39.5535843326651886],"hsluv":[3.19865110237705785,99.9999999999968878,39.5535843326651886]},"#bb0055":{"lch":[39.9527871554326666,107.03859947839959,357.869864695501747],"luv":[39.9527871554326666,106.964633924407806,-3.97855095665153691],"rgb":[0.733333333333333282,0,0.333333333333333315],"xyz":[0.221325778668927498,0.112225411516156656,0.095954088886523875],"hpluv":[357.869864695501747,339.963790558847222,39.9527871554326666],"hsluv":[357.869864695501747,99.9999999999971436,39.9527871554326666]},"#bb0066":{"lch":[40.452535568346093,100.749762000256624,351.053086521713055],"luv":[40.452535568346093,99.5239253968718884,-15.6685295004423661],"rgb":[0.733333333333333282,0,0.4],"xyz":[0.228910774442435655,0.115259409825559975,0.135901733293667837],"hpluv":[351.053086521713055,316.036764522848955,40.452535568346093],"hsluv":[351.053086521713055,99.999999999997442,40.452535568346093]},"#bb0077":{"lch":[41.0543478797665813,95.9494038996296581,342.883287985183927],"luv":[41.0543478797665813,91.699536963203,-28.2397420212797314],"rgb":[0.733333333333333282,0,0.466666666666666674],"xyz":[0.238224787462637588,0.118985015033640784,0.184955535200065746],"hpluv":[342.883287985183927,296.56674422547627,41.0543478797665813],"hsluv":[342.883287985183927,99.9999999999977,41.0543478797665813]},"#bb0088":{"lch":[41.7578935904565398,93.4210879643116243,333.788939203308246],"luv":[41.7578935904565398,83.8148890966975699,-41.2621381189091565],"rgb":[0.733333333333333282,0,0.533333333333333326],"xyz":[0.249365204564581389,0.123441181874418382,0.243628398603637913],"hpluv":[333.788939203308246,283.887103643995431,41.7578935904565398],"hsluv":[333.788939203308246,99.9999999999980531,41.7578935904565398]},"#bb0099":{"lch":[42.5612451572515,93.5592166386053918,324.452137443226093],"luv":[42.5612451572515,76.1225984195714318,-54.3937223205229472],"rgb":[0.733333333333333282,0,0.6],"xyz":[0.262422168673654088,0.12866396751804754,0.31239507624475582],"hpluv":[324.452137443226093,278.940502109978524,42.5612451572515],"hsluv":[324.452137443226093,99.9999999999983089,42.5612451572515]},"#bb00aa":{"lch":[43.461144448190268,96.3048592888224562,315.591494301740738],"luv":[43.461144448190268,68.7971872487792,-67.3911934105362747],"rgb":[0.733333333333333282,0,0.66666666666666663],"xyz":[0.277479861638906644,0.134687044704148634,0.391698925861754421],"hpluv":[315.591494301740738,281.181257774391042,43.461144448190268],"hsluv":[315.591494301740738,99.9999999999985647,43.461144448190268]},"#bb00bb":{"lch":[44.4532771259814652,101.257357078489918,307.715012949243601],"luv":[44.4532771259814652,61.9426024872754866,-80.100976021670192],"rgb":[0.733333333333333282,0,0.733333333333333282],"xyz":[0.294617453746243319,0.141542081547083393,0.481956910960396168],"hpluv":[307.715012949243601,289.042783730483507,44.4532771259814652],"hsluv":[307.715012949243601,99.9999999999988205,44.4532771259814652]},"#bb00cc":{"lch":[45.5325428123826796,107.876917991024385,301.028560594476971],"luv":[45.5325428123826796,55.6068066637028551,-92.44085940701639],"rgb":[0.733333333333333282,0,0.8],"xyz":[0.313909829189965,0.149259031724572194,0.583563421630666324],"hpluv":[301.028560594476971,300.639438898355309,45.5325428123826796],"hsluv":[301.028560594476971,99.999999999999,45.5325428123826796]},"#bb00dd":{"lch":[46.6933085129957348,115.650155059812704,295.504945579136574],"luv":[46.6933085129957348,49.7976850024997,-104.379830109799173],"rgb":[0.733333333333333282,0,0.866666666666666696],"xyz":[0.335428154740598616,0.157866361944825728,0.696893269530672321],"hpluv":[295.504945579136574,314.290242754568055,46.6933085129957348],"hsluv":[295.504945579136574,99.9999999999992468,46.6933085129957348]},"#bb00ee":{"lch":[47.929635203682146,124.167261181765113,290.999747870951808],"luv":[47.929635203682146,44.4970566855085821,-115.920320460682433],"rgb":[0.733333333333333282,0,0.933333333333333348],"xyz":[0.359240335006773326,0.167391234051295773,0.822304085599195544],"hpluv":[290.999747870951808,328.732244305823656,47.929635203682146],"hsluv":[290.999747870951808,99.9999999999993889,47.929635203682146]},"#bb00ff":{"lch":[49.2354711183318727,133.13261796854033,287.33664116340708],"luv":[49.2354711183318727,39.6715752597668896,-127.084460433075606],"rgb":[0.733333333333333282,0,1],"xyz":[0.385411383416604747,0.177859653415228469,0.96013827389097739],"hpluv":[287.33664116340708,343.119737385630629,49.2354711183318727],"hsluv":[287.33664116340708,99.9999999999995595,49.2354711183318727]},"#991100":{"lch":[32.2007428060931531,101.551746681272988,13.5001929330929755],"luv":[32.2007428060931531,98.7457840078795,23.707116962774041],"rgb":[0.6,0.0666666666666666657,0],"xyz":[0.133370160695528289,0.071744270745948871,0.00682590344068119],"hpluv":[13.5001929330929755,400.185025755779861,32.2007428060931531],"hsluv":[13.5001929330929755,100.000000000002359,32.2007428060931531]},"#991111":{"lch":[32.2911967351305,99.2607003603350506,12.1770506300617907],"luv":[32.2911967351305,97.0273802968116854,20.9373854328113431],"rgb":[0.6,0.0666666666666666657,0.0666666666666666657],"xyz":[0.134381826195165421,0.0721489369458037239,0.0121540084054368204],"hpluv":[12.1770506300617907,390.060992150638072,32.2911967351305],"hsluv":[12.1770506300617907,91.4033806551417,32.2911967351305]},"#991122":{"lch":[32.4579836187547883,95.3555453821432337,9.67722696349737355],"luv":[32.4579836187547883,93.9986702773161085,16.0290368151797],"rgb":[0.6,0.0666666666666666657,0.133333333333333331],"xyz":[0.136257184333642423,0.0728990802011945382,0.0220308946014160165],"hpluv":[9.67722696349737355,372.789562407290305,32.4579836187547883],"hsluv":[9.67722696349737355,91.6870397393079,32.4579836187547883]},"#991133":{"lch":[32.7301206059751877,89.8170234432985382,5.44607482402752385],"luv":[32.7301206059751877,89.4115862394302,8.52443231910342547],"rgb":[0.6,0.0666666666666666657,0.2],"xyz":[0.139344935066100184,0.0741341804941776511,0.0382930484590271597],"hpluv":[5.44607482402752385,348.217328437078379,32.7301206059751877],"hsluv":[5.44607482402752385,92.1153976677825312,32.7301206059751877]},"#991144":{"lch":[33.1177416447746893,83.547386161100178,359.159050762907725],"luv":[33.1177416447746893,83.5383872622118275,-1.22620878349376072],"rgb":[0.6,0.0666666666666666657,0.266666666666666663],"xyz":[0.143802930310319044,0.0759173785918652311,0.0617718234119138],"hpluv":[359.159050762907725,320.119020896680809,33.1177416447746893],"hsluv":[359.159050762907725,92.6613616101701609,33.1177416447746893]},"#991155":{"lch":[33.6267967661613341,77.8365467514172451,350.652860745276428],"luv":[33.6267967661613341,76.8030661853154,-12.6418762341523276],"rgb":[0.6,0.0666666666666666657,0.333333333333333315],"xyz":[0.149765344349681029,0.078302344207610064,0.0931738706858877136],"hpluv":[350.652860745276428,293.722615948770908,33.6267967661613341],"hsluv":[350.652860745276428,93.2833986807069664,33.6267967661613341]},"#991166":{"lch":[34.2596587707945375,74.039902428482776,340.197584074025258],"luv":[34.2596587707945375,69.661662743272629,-25.0830599301957804],"rgb":[0.6,0.0666666666666666657,0.4],"xyz":[0.157350340123189214,0.0813363425170133825,0.133121515093031662],"hpluv":[340.197584074025258,274.234525914752396,34.2596587707945375],"hsluv":[340.197584074025258,93.9371476037906774,34.2596587707945375]},"#991177":{"lch":[35.0156115165229096,73.1458980715855773,328.71391057162549],"luv":[35.0156115165229096,62.509382661628635,-37.9855167657472848],"rgb":[0.6,0.0666666666666666657,0.466666666666666674],"xyz":[0.16666435314339112,0.0850619477250941919,0.182175316999429571],"hpluv":[328.71391057162549,265.074278305330154,35.0156115165229096],"hsluv":[328.71391057162549,94.5844210689808165,35.0156115165229096]},"#991188":{"lch":[35.8913494409224185,75.4242755669397269,317.528981112118743],"luv":[35.8913494409224185,55.6343762077295239,-50.9277677576239398],"rgb":[0.6,0.0666666666666666657,0.533333333333333326],"xyz":[0.177804770245334975,0.0895181145658717897,0.240848180403001738],"hpluv":[317.528981112118743,266.661726649655066,35.8913494409224185],"hsluv":[317.528981112118743,95.1976582537924116,35.8913494409224185]},"#991199":{"lch":[36.8815072257793,80.448343562419069,307.715012949243601],"luv":[36.8815072257793,49.2130143411107568,-63.6397297401445599],"rgb":[0.6,0.0666666666666666657,0.6],"xyz":[0.190861734354407675,0.0947409002095009473,0.309614858044119645],"hpluv":[307.715012949243601,276.788327826692239,36.8815072257793],"hsluv":[307.715012949243601,95.7603314825458511,36.8815072257793]},"#9911aa":{"lch":[37.9791974354050694,87.4639739592788,299.695850237394552],"luv":[37.9791974354050694,43.3292813921454609,-75.9771025690614152],"rgb":[0.6,0.0666666666666666657,0.66666666666666663],"xyz":[0.205919427319660231,0.100763977395602056,0.388918707661118246],"hpluv":[299.695850237394552,292.228621346341356,37.9791974354050694],"hsluv":[299.695850237394552,96.26500390067784,37.9791974354050694]},"#9911bb":{"lch":[39.176522525078866,95.7489617369993624,293.383950362709356],"luv":[39.176522525078866,38.0018814997404846,-87.8847010360338459],"rgb":[0.6,0.0666666666666666657,0.733333333333333282],"xyz":[0.22305701942699685,0.107619014238536814,0.47917669275976],"hpluv":[293.383950362709356,310.132668732371314,39.176522525078866],"hsluv":[293.383950362709356,96.7106400677762537,39.176522525078866]},"#9911cc":{"lch":[40.465031277763515,104.765415075180798,288.480743990765689],"luv":[40.465031277763515,33.2091620218187842,-99.3626879350770622],"rgb":[0.6,0.0666666666666666657,0.8],"xyz":[0.242349394870718604,0.115335964416025616,0.580783203430030204],"hpluv":[288.480743990765689,328.531778006508034,40.465031277763515],"hsluv":[288.480743990765689,97.1001366995766,40.465031277763515]},"#9911dd":{"lch":[41.8361001822542917,114.161763941518927,284.668123617886636],"luv":[41.8361001822542917,28.9080153835727351,-110.441092863219225],"rgb":[0.6,0.0666666666666666657,0.866666666666666696],"xyz":[0.263867720421352148,0.12394329463627915,0.694113051330036201],"hpluv":[284.668123617886636,346.265164959266087,41.8361001822542917],"hsluv":[284.668123617886636,97.4384492036098,41.8361001822542917]},"#9911ee":{"lch":[43.2812320372341617,123.724619665436521,281.679545129349094],"luv":[43.2812320372341617,25.0465268392882301,-121.162919264293635],"rgb":[0.6,0.0666666666666666657,0.933333333333333348],"xyz":[0.287679900687526913,0.133468166742749167,0.819523867398559425],"hpluv":[281.679545129349094,362.740326129136179,43.2812320372341617],"hsluv":[281.679545129349094,97.7313369542794561,43.2812320372341617]},"#9911ff":{"lch":[44.7922739406791948,133.33068560825987,279.310828677429186],"luv":[44.7922739406791948,21.5716156333953251,-131.574074664174219],"rgb":[0.6,0.0666666666666666657,1],"xyz":[0.313850949097358278,0.143936586106681863,0.95735805569034127],"hpluv":[279.310828677429186,377.716823123197173,44.7922739406791948],"hsluv":[279.310828677429186,99.9999999999993179,44.7922739406791948]},"#bb1100":{"lch":[39.5258701457598747,127.514079962112703,13.0219609303782402],"luv":[39.5258701457598747,124.2348987579322,28.7320469022032583],"rgb":[0.733333333333333282,0.0666666666666666657,0],"xyz":[0.206934995275703137,0.109676138576352333,0.0102742550616268143],"hpluv":[13.0219609303782402,409.370014873310311,39.5258701457598747],"hsluv":[13.0219609303782402,100.000000000002203,39.5258701457598747]},"#bb1111":{"lch":[39.5940766091873897,125.63034182067031,12.177050630061796],"luv":[39.5940766091873897,122.803716963532779,26.4996204863200759],"rgb":[0.733333333333333282,0.0666666666666666657,0.0666666666666666657],"xyz":[0.20794666077534027,0.110080804776207186,0.0156023600263824457],"hpluv":[12.177050630061796,402.627698793753552,39.5940766091873897],"hsluv":[12.177050630061796,94.3481495348726753,39.5940766091873897]},"#bb1122":{"lch":[39.7200723855077413,122.321798686612851,10.5915831721034426],"luv":[39.7200723855077413,120.23772406897838,22.4835972353282152],"rgb":[0.733333333333333282,0.0666666666666666657,0.133333333333333331],"xyz":[0.209822018913817271,0.110830948031598,0.0254792462223616401],"hpluv":[10.5915831721034426,390.780742551338619,39.7200723855077413],"hsluv":[10.5915831721034426,94.4721603032542561,39.7200723855077413]},"#bb1133":{"lch":[39.9262897734852,117.365304386249704,7.93115519261489421],"luv":[39.9262897734852,116.242655940639409,16.194431559742192],"rgb":[0.733333333333333282,0.0666666666666666657,0.2],"xyz":[0.212909769646275,0.112066048324581113,0.0417414000799727902],"hpluv":[7.93115519261489421,373.009679290071517,39.9262897734852],"hsluv":[7.93115519261489421,94.6648992051481173,39.9262897734852]},"#bb1144":{"lch":[40.2213637516280755,111.198866264944101,3.99799547396429888],"luv":[40.2213637516280755,110.928262725239179,7.75295991020434627],"rgb":[0.733333333333333282,0.0666666666666666657,0.266666666666666663],"xyz":[0.217367764890493892,0.113849246422268693,0.0652201750328594287],"hpluv":[3.99799547396429888,350.818828640487084,40.2213637516280755],"hsluv":[3.99799547396429888,94.920595316052,40.2213637516280755]},"#bb1155":{"lch":[40.6112374139617245,104.574630781207446,358.621384873601698],"luv":[40.6112374139617245,104.544360517453882,-2.51596641918957786],"rgb":[0.733333333333333282,0.0666666666666666657,0.333333333333333315],"xyz":[0.223330178929855905,0.116234212038013526,0.0966222223068333302],"hpluv":[358.621384873601698,326.752894857139097,40.6112374139617245],"hsluv":[358.621384873601698,95.2265760165129791,40.6112374139617245]},"#bb1166":{"lch":[41.0995768863194755,98.4443929415329251,351.723860164231496],"luv":[41.0995768863194755,97.4191751888273672,-14.1704907168206535],"rgb":[0.733333333333333282,0.0666666666666666657,0.4],"xyz":[0.230915174703364062,0.119268210347416845,0.136569866713977306],"hpluv":[351.723860164231496,303.943570446579713,41.0995768863194755],"hsluv":[351.723860164231496,95.5663396203906643,41.0995768863194755]},"#bb1177":{"lch":[41.688035181331955,93.7889310063258,343.43446060875408],"luv":[41.688035181331955,89.8961490854954093,-26.7403432832812094],"rgb":[0.733333333333333282,0.0666666666666666657,0.466666666666666674],"xyz":[0.240229187723566,0.122993815555497654,0.185623668620375215],"hpluv":[343.43446060875408,285.48249634694713,41.688035181331955],"hsluv":[343.43446060875408,95.9227087501184883,41.688035181331955]},"#bb1188":{"lch":[42.3764815581906475,91.4027083669889606,334.189166164708297],"luv":[42.3764815581906475,82.2840505377722309,-39.7968607294366805],"rgb":[0.733333333333333282,0.0666666666666666657,0.533333333333333326],"xyz":[0.251369604825509796,0.127449982396275252,0.244296532023947383],"hpluv":[334.189166164708297,273.699179760613617,42.3764815581906475],"hsluv":[334.189166164708297,96.2803174994205,42.3764815581906475]},"#bb1199":{"lch":[43.1632358766101092,91.692942572352564,324.693570122963422],"luv":[43.1632358766101092,74.8281105443768269,-52.9938637007650755],"rgb":[0.733333333333333282,0.0666666666666666657,0.6],"xyz":[0.264426568934582495,0.13267276803990441,0.31306320966506529],"hpluv":[324.693570122963422,269.563595898888195,43.1632358766101092],"hsluv":[324.693570122963422,96.6270445785018239,43.1632358766101092]},"#bb11aa":{"lch":[44.0453166933651,94.6050581990027553,315.694091730478135],"luv":[44.0453166933651,67.7013389352867847,-66.0806003544619784],"rgb":[0.733333333333333282,0.0666666666666666657,0.66666666666666663],"xyz":[0.279484261899835051,0.138695845226005504,0.39236705928206389],"hpluv":[315.694091730478135,272.554870225691275,44.0453166933651],"hsluv":[315.694091730478135,96.9544350138240105,44.0453166933651]},"#bb11bb":{"lch":[45.0186979872658242,99.7328976909900717,307.715012949243601],"luv":[45.0186979872658242,61.0100383302365472,-78.8950321933172205],"rgb":[0.733333333333333282,0.0666666666666666657,0.733333333333333282],"xyz":[0.296621854007171726,0.145550882068940263,0.482625044380705637],"hpluv":[307.715012949243601,281.115526817766181,45.0186979872658242],"hsluv":[307.715012949243601,97.2574105430315115,45.0186979872658242]},"#bb11cc":{"lch":[46.0785638011469771,106.527215460047387,300.962972083371881],"luv":[46.0785638011469771,54.8065495444917161,-91.3470840295328372],"rgb":[0.733333333333333282,0.0666666666666666657,0.8],"xyz":[0.315914229450893425,0.153267832246429064,0.584231555050975793],"hpluv":[300.962972083371881,293.360047474541318,46.0785638011469771],"hsluv":[300.962972083371881,97.5336183018287528,46.0785638011469771]},"#bb11dd":{"lch":[47.2195492447565,114.4666153484132,295.402801066287566],"luv":[47.2195492447565,49.1038079522977853,-103.3993330438134],"rgb":[0.733333333333333282,0.0666666666666666657,0.866666666666666696],"xyz":[0.337432555001527,0.161875162466682598,0.69756140295098179],"hpluv":[295.402801066287566,307.607082675331128,47.2195492447565],"hsluv":[295.402801066287566,97.7826899351839813,47.2195492447565]},"#bb11ee":{"lch":[48.4359581768354701,123.136484869400022,290.880608651701721],"luv":[48.4359581768354701,43.8885280811888,-115.049515465553711],"rgb":[0.733333333333333282,0.0666666666666666657,0.933333333333333348],"xyz":[0.361244735267701733,0.171400034573152643,0.822972219019505],"hpluv":[290.880608651701721,322.595409245987128,48.4359581768354701],"hsluv":[290.880608651701721,98.0055710342431325,48.4359581768354701]},"#bb11ff":{"lch":[49.7219510368964,132.239138283310353,287.21247838519713],"luv":[49.7219510368964,39.1316890181496575,-126.316667975763593],"rgb":[0.733333333333333282,0.0666666666666666657,1],"xyz":[0.387415783677533154,0.181868453937085339,0.960806407311286859],"hpluv":[287.21247838519713,337.482436204013879,49.7219510368964],"hsluv":[287.21247838519713,99.9999999999991758,49.7219510368964]},"#992200":{"lch":[33.8105832897308716,95.4307991554818358,16.0266852535062476],"luv":[33.8105832897308716,91.7217107848809263,26.3470149760569932],"rgb":[0.6,0.133333333333333331,0],"xyz":[0.137085784430296231,0.0791755182154848525,0.0080644446856038],"hpluv":[16.0266852535062476,358.158468302090569,33.8105832897308716],"hsluv":[16.0266852535062476,100.000000000002331,33.8105832897308716]},"#992211":{"lch":[33.8952997814050718,93.2922690289088195,14.6972380002076104],"luv":[33.8952997814050718,90.239744522062125,23.669304365681274],"rgb":[0.6,0.133333333333333331,0.0666666666666666657],"xyz":[0.138097449929933364,0.0795801844153397,0.0133925496503594314],"hpluv":[14.6972380002076104,349.257308780581,33.8952997814050718],"hsluv":[14.6972380002076104,92.1483909924374274,33.8952997814050718]},"#992222":{"lch":[34.0515850466810335,89.6330213591727,12.1770506300618084],"luv":[34.0515850466810335,87.6163196410811338,18.9065874902323579],"rgb":[0.6,0.133333333333333331,0.133333333333333331],"xyz":[0.139972808068410365,0.0803303276707305197,0.0232694358463386292],"hpluv":[12.1770506300618084,334.018122077437397,34.0515850466810335],"hsluv":[12.1770506300618084,78.2707991117683,34.0515850466810335]},"#992233":{"lch":[34.3068003204445446,84.4135643942939282,7.88651435003668233],"luv":[34.3068003204445446,83.6151628365757773,11.58250394183076],"rgb":[0.6,0.133333333333333331,0.2],"xyz":[0.143060558800868098,0.0815654279637136326,0.0395315897039497724],"hpluv":[7.88651435003668233,312.227643050581207,34.3068003204445446],"hsluv":[7.88651435003668233,79.3008398259009226,34.3068003204445446]},"#992244":{"lch":[34.6707661525426,78.4682482149262199,1.45557545410962708],"luv":[34.6707661525426,78.4429281517087134,1.99323879782018309],"rgb":[0.6,0.133333333333333331,0.266666666666666663],"xyz":[0.147518554045086986,0.0833486260614012126,0.0630103646568364],"hpluv":[1.45557545410962708,287.190351340663,34.6707661525426],"hsluv":[1.45557545410962708,80.6267396657693212,34.6707661525426]},"#992255":{"lch":[35.149531709850983,73.0418005898087443,352.659616011821072],"luv":[35.149531709850983,72.4431965063170082,-9.33209051330535821],"rgb":[0.6,0.133333333333333331,0.333333333333333315],"xyz":[0.153480968084449,0.0857335916771460455,0.0944124119308103193],"hpluv":[352.659616011821072,263.688538908073838,35.149531709850983],"hsluv":[352.659616011821072,82.1555178352066804,35.149531709850983]},"#992266":{"lch":[35.7459223236079495,69.5043059181480203,341.734006615383123],"luv":[35.7459223236079495,66.0021002604389793,-21.7846574995905513],"rgb":[0.6,0.133333333333333331,0.4],"xyz":[0.161065963857957156,0.0887675899865493639,0.134360056337954281],"hpluv":[341.734006615383123,246.731460763727796,35.7459223236079495],"hsluv":[341.734006615383123,83.7834402291280753,35.7459223236079495]},"#992277":{"lch":[36.4599553630224946,68.9051746310403104,329.662355423262511],"luv":[36.4599553630224946,59.4695672743266783,-34.8036443370302],"rgb":[0.6,0.133333333333333331,0.466666666666666674],"xyz":[0.17037997687815909,0.0924931951946301734,0.18341385824435219],"hpluv":[329.662355423262511,239.814275331209444,36.4599553630224946],"hsluv":[329.662355423262511,85.4170781092293225,36.4599553630224946]},"#992288":{"lch":[37.2892540647929,71.5563678213307242,317.925484235555643],"luv":[37.2892540647929,53.1144286836587369,-47.9496740488411],"rgb":[0.6,0.133333333333333331,0.533333333333333326],"xyz":[0.18152039398010289,0.0969493620354077712,0.242086721647924358],"hpluv":[317.925484235555643,243.502777039008038,37.2892540647929],"hsluv":[317.925484235555643,86.9852623869732,37.2892540647929]},"#992299":{"lch":[38.2294870734457888,77.015786119064046,307.715012949243771],"luv":[38.2294870734457888,47.1132010795059841,-60.9243596238766827],"rgb":[0.6,0.133333333333333331,0.6],"xyz":[0.194577358089175617,0.102172147679036929,0.310853399289042265],"hpluv":[307.715012949243771,255.635172818446421,38.2294870734457888],"hsluv":[307.715012949243771,88.441984096309227,38.2294870734457888]},"#9922aa":{"lch":[39.2748221448681178,84.484081905089468,299.468150353755561],"luv":[39.2748221448681178,41.5610713460956234,-73.5543162833468],"rgb":[0.6,0.133333333333333331,0.66666666666666663],"xyz":[0.209635051054428145,0.108195224865138023,0.390157248906040865],"hpluv":[299.468150353755561,272.960615272696657,39.2748221448681178],"hsluv":[299.468150353755561,89.7633288768494708,39.2748221448681178]},"#9922bb":{"lch":[40.4183688993281436,93.2013493596814726,293.05045530637],"luv":[40.4183688993281436,36.4922039393154094,-85.7601922462677919],"rgb":[0.6,0.133333333333333331,0.733333333333333282],"xyz":[0.22677264316176482,0.115050261708072782,0.480415234004682612],"hpluv":[293.05045530637,292.605673863240838,40.4183688993281436],"hsluv":[293.05045530637,90.9419133161227222,40.4183688993281436]},"#9922cc":{"lch":[41.6525852773545182,102.609691310931794,288.11294916137831],"luv":[41.6525852773545182,31.900454524651952,-97.5249186210648702],"rgb":[0.6,0.133333333333333331,0.8],"xyz":[0.246065018605486546,0.122767211885561583,0.582021744674952712],"hpluv":[288.11294916137831,312.597676326075884,41.6525852773545182],"hsluv":[288.11294916137831,91.9812251551093851,41.6525852773545182]},"#9922dd":{"lch":[42.969628845807982,112.350489371469905,284.303043907998301],"luv":[42.969628845807982,27.7562437333976213,-108.867917201630149],"rgb":[0.6,0.133333333333333331,0.866666666666666696],"xyz":[0.267583344156120062,0.131374542105815117,0.69535159257495871],"hpluv":[284.303043907998301,331.781902020401162,42.969628845807982],"hsluv":[284.303043907998301,92.8910125551507235,42.969628845807982]},"#9922ee":{"lch":[44.361642902098545,122.210344632057584,281.334390799049743],"luv":[44.361642902098545,24.018574136526297,-119.826860225637532],"rgb":[0.6,0.133333333333333331,0.933333333333333348],"xyz":[0.291395524422294827,0.140899414212285162,0.820762408643481933],"hpluv":[281.334390799049743,349.574442537581717,44.361642902098545],"hsluv":[281.334390799049743,93.6839973987951566,44.361642902098545]},"#9922ff":{"lch":[45.8209755847726612,132.069283427413211,278.992348895848238],"luv":[45.8209755847726612,20.6427685166220094,-130.446049127597433],"rgb":[0.6,0.133333333333333331,1],"xyz":[0.317566572832126193,0.151367833576217858,0.958596596935263889],"hpluv":[278.992348895848238,365.74366826955071,45.8209755847726612],"hsluv":[278.992348895848238,99.9999999999993179,45.8209755847726612]},"#bb2200":{"lch":[40.7526421249889452,122.145166616692975,14.6188079362681389],"luv":[40.7526421249889452,118.190884669319914,30.8278528104570881],"rgb":[0.733333333333333282,0.133333333333333331,0],"xyz":[0.21065061901047108,0.117107386045888315,0.0115127963065494235],"hpluv":[14.6188079362681389,380.329350781024857,40.7526421249889452],"hsluv":[14.6188079362681389,100.000000000002217,40.7526421249889452]},"#bb2211":{"lch":[40.8179368215716849,120.355879944515436,13.7706881972771793],"luv":[40.8179368215716849,116.896392622501153,28.6491052053056343],"rgb":[0.733333333333333282,0.133333333333333331,0.0666666666666666657],"xyz":[0.211662284510108212,0.117512052245743168,0.0168409012713050532],"hpluv":[13.7706881972771793,374.158477594779924,40.8179368215716849],"hsluv":[13.7706881972771793,94.6800257514418,40.8179368215716849]},"#bb2222":{"lch":[40.9385803904414161,117.208042434762348,12.1770506300618102],"luv":[40.9385803904414161,114.570915436608942,24.7230772236478238],"rgb":[0.733333333333333282,0.133333333333333331,0.133333333333333331],"xyz":[0.213537642648585213,0.118262195501133982,0.0267177874672842527],"hpluv":[12.1770506300618102,363.298797482753,40.9385803904414161],"hsluv":[12.1770506300618102,85.1321689328196101,40.9385803904414161]},"#bb2233":{"lch":[41.136111673530813,112.480172956632245,9.49666640172232235],"luv":[41.136111673530813,110.938654987290519,18.5581286223806821],"rgb":[0.733333333333333282,0.133333333333333331,0.2],"xyz":[0.216625393381042974,0.119497295794117095,0.042979941324895396],"hpluv":[9.49666640172232235,346.970109935861444,41.136111673530813],"hsluv":[9.49666640172232235,85.6217357677037398,41.136111673530813]},"#bb2244":{"lch":[41.4189140922405201,106.57909239531196,5.51995404221549],"luv":[41.4189140922405201,106.084859394728952,10.2520994439692306],"rgb":[0.733333333333333282,0.133333333333333331,0.266666666666666663],"xyz":[0.221083388625261834,0.121280493891804675,0.0664587162777820345],"hpluv":[5.51995404221549,326.522141050690152,41.4189140922405201],"hsluv":[5.51995404221549,86.2742612371986297,41.4189140922405201]},"#bb2255":{"lch":[41.7928521194743823,100.22104851316422,0.0579838467833058424],"luv":[41.7928521194743823,100.220997191859041,0.101424589714973798],"rgb":[0.733333333333333282,0.133333333333333331,0.333333333333333315],"xyz":[0.227045802664623819,0.123665459507549508,0.097860763551755936],"hpluv":[0.0579838467833058424,304.296010337655673,41.7928521194743823],"hsluv":[0.0579838467833058424,87.0597094656736772,41.7928521194743823]},"#bb2266":{"lch":[42.2616671880265216,94.3342448936905,353.011685321171171],"luv":[42.2616671880265216,93.6334344607092106,-11.4773564358193614],"rgb":[0.733333333333333282,0.133333333333333331,0.4],"xyz":[0.234630798438132,0.126699457816952826,0.137808407958899898],"hpluv":[353.011685321171171,283.244886623536,42.2616671880265216],"hsluv":[353.011685321171171,87.937804292381287,42.2616671880265216]},"#bb2277":{"lch":[42.8272221099346666,89.9002723684957,344.496654306277264],"luv":[42.8272221099346666,86.6292371691086771,-24.0298614109202155],"rgb":[0.733333333333333282,0.133333333333333331,0.466666666666666674],"xyz":[0.24394481145833391,0.13042506302503365,0.186862209865297807],"hpluv":[344.496654306277264,266.367005402095344,42.8272221099346666],"hsluv":[344.496654306277264,88.8655868844719805,42.8272221099346666]},"#bb2288":{"lch":[43.4897067779173554,87.7363054907772693,334.961981200390596],"luv":[43.4897067779173554,79.4914755013727898,-37.1317199141871441],"rgb":[0.733333333333333282,0.133333333333333331,0.533333333333333326],"xyz":[0.255085228560277766,0.13488122986581122,0.245535073268869974],"hpluv":[334.961981200390596,255.995416581420926,43.4897067779173554],"hsluv":[334.961981200390596,89.8036443318747786,43.4897067779173554]},"#bb2299":{"lch":[44.2478449340908639,88.2751432264235092,325.159464012784042],"luv":[44.2478449340908639,72.4514028672968635,-50.4310929309115],"rgb":[0.733333333333333282,0.133333333333333331,0.6],"xyz":[0.268142192669350465,0.140104015509440405,0.314301750909987909],"hpluv":[325.159464012784042,253.154489640486645,44.2478449340908639],"hsluv":[325.159464012784042,90.7199745934293844,44.2478449340908639]},"#bb22aa":{"lch":[45.0991127685299062,91.4705260319517919,315.891475419905078],"luv":[45.0991127685299062,65.6779186933914758,-63.6652819727222195],"rgb":[0.733333333333333282,0.133333333333333331,0.66666666666666663],"xyz":[0.283199885634603,0.146127092695541499,0.39360560052698651],"hpluv":[315.891475419905078,257.366789521381691,45.0991127685299062],"hsluv":[315.891475419905078,91.5914304646717,45.0991127685299062]},"#bb22bb":{"lch":[46.0399667792549678,96.9048462314552,307.715012949243658],"luv":[46.0399667792549678,59.2800221375787615,-76.6578645574617497],"rgb":[0.733333333333333282,0.133333333333333331,0.733333333333333282],"xyz":[0.30033747774193964,0.152982129538476258,0.483863585625628256],"hpluv":[307.715012949243658,267.0851991180906,46.0399667792549678],"hsluv":[307.715012949243658,92.4033444706684,46.0399667792549678]},"#bb22cc":{"lch":[47.066072507765945,104.009692587178989,300.837938637053412],"luv":[47.066072507765945,53.3165662395356,-89.3048706202785496],"rgb":[0.733333333333333282,0.133333333333333331,0.8],"xyz":[0.319629853185661394,0.16069907971596506,0.585470096295898412],"hpluv":[300.837938637053412,280.417543020287,47.066072507765945],"hsluv":[300.837938637053412,93.1481326309998,47.066072507765945]},"#bb22dd":{"lch":[48.1725242595717589,112.247547842848149,295.20893392435471],"luv":[48.1725242595717589,47.808517424121824,-101.557164486017044],"rgb":[0.733333333333333282,0.133333333333333331,0.866666666666666696],"xyz":[0.341148178736294938,0.169306409936218594,0.69879994419590441],"hpluv":[295.20893392435471,295.676483579310798,48.1725242595717589],"hsluv":[295.20893392435471,93.8235497257627316,48.1725242595717589]},"#bb22ee":{"lch":[49.3540469689012724,121.194036197623419,290.655339197387],"luv":[49.3540469689012724,42.7506603945962169,-113.403595382583688],"rgb":[0.733333333333333282,0.133333333333333331,0.933333333333333348],"xyz":[0.364960359002469703,0.178831282042688611,0.824210760264427633],"hpluv":[290.655339197387,311.600255956968681,49.3540469689012724],"hsluv":[290.655339197387,94.4310255689598,49.3540469689012724]},"#bb22ff":{"lch":[50.6051737457033397,130.547024148317973,286.97844412333734],"luv":[50.6051737457033397,38.1212848334983647,-124.85709093449519],"rgb":[0.733333333333333282,0.133333333333333331,1],"xyz":[0.391131407412301069,0.189299701406621335,0.962044948556209478],"hpluv":[286.97844412333734,327.349274436557835,50.6051737457033397],"hsluv":[286.97844412333734,99.9999999999991616,50.6051737457033397]},"#993300":{"lch":[36.2545465004255476,86.9834057059747749,20.3835344027483316],"luv":[36.2545465004255476,81.5366895093473,30.2965531383769893],"rgb":[0.6,0.2,0],"xyz":[0.14320350651930705,0.0914109623935066423,0.0101036853819406816],"hpluv":[20.3835344027483316,304.448092478673459,36.2545465004255476],"hsluv":[20.3835344027483316,100.00000000000226,36.2545465004255476]},"#993311":{"lch":[36.3315413581227133,85.0112276295678839,19.0571063974297203],"luv":[36.3315413581227133,80.3520694714869279,27.7570487396543],"rgb":[0.6,0.2,0.0666666666666666657],"xyz":[0.144215172018944182,0.0918156285933615,0.0154317903466963131],"hpluv":[19.0571063974297203,296.914762557758195,36.3315413581227133],"hsluv":[19.0571063974297203,93.1288353931581,36.3315413581227133]},"#993322":{"lch":[36.4736730302835852,81.6150828115545863,16.5278497598068661],"luv":[36.4736730302835852,78.2428757472059573,23.217970134019108],"rgb":[0.6,0.2,0.133333333333333331],"xyz":[0.146090530157421183,0.0925657718487523096,0.0253086765426755109],"hpluv":[16.5278497598068661,283.942401799749632,36.4736730302835852],"hsluv":[16.5278497598068661,80.9121244795507124,36.4736730302835852]},"#993333":{"lch":[36.7060271438600836,76.7221326388105638,12.1770506300618369],"luv":[36.7060271438600836,74.9959199734098121,16.1832513417159589],"rgb":[0.6,0.2,0.2],"xyz":[0.149178280889878945,0.0938008721417354224,0.0415708304002866541],"hpluv":[12.1770506300618369,265.229979343802,36.7060271438600836],"hsluv":[12.1770506300618369,62.1516051360361459,36.7060271438600836]},"#993344":{"lch":[37.0379214664673668,71.077614272095758,5.55118145677439934],"luv":[37.0379214664673668,70.7442733159460744,6.87568495580995354],"rgb":[0.6,0.2,0.266666666666666663],"xyz":[0.153636276134097804,0.095584070239423,0.0650496053531732926],"hpluv":[5.55118145677439934,243.514912685509444,37.0379214664673668],"hsluv":[5.55118145677439934,64.3097526797848644,37.0379214664673668]},"#993355":{"lch":[37.4754277574064858,65.8722356173568073,356.298722520573506],"luv":[37.4754277574064858,65.7348379379961614,-4.25235305377523254],"rgb":[0.6,0.2,0.333333333333333315],"xyz":[0.15959869017345979,0.0979690358551678353,0.0964516526271472],"hpluv":[356.298722520573506,223.046355214908289,37.4754277574064858],"hsluv":[356.298722520573506,66.8387430740197885,37.4754277574064858]},"#993366":{"lch":[38.0218512407041942,62.5198646461221941,344.559385799457459],"luv":[38.0218512407041942,60.2633303059628602,-16.6452544529622166],"rgb":[0.6,0.2,0.4],"xyz":[0.167183685946967975,0.101003034164571154,0.136399297034291156],"hpluv":[344.559385799457459,208.652742449272864,38.0218512407041942],"hsluv":[344.559385799457459,69.5808124884664778,38.0218512407041942]},"#993377":{"lch":[38.6780657603296234,62.1964572713534949,331.414072321130675],"luv":[38.6780657603296234,54.6147414507713478,-29.7595247504508862],"rgb":[0.6,0.2,0.466666666666666674],"xyz":[0.17649769896716988,0.104728639372651963,0.185453098940689065],"hpluv":[331.414072321130675,204.051704505442274,38.6780657603296234],"hsluv":[331.414072321130675,72.3848063102254571,38.6780657603296234]},"#993388":{"lch":[39.4428302118465908,65.3028355433768155,318.6521895607018],"luv":[39.4428302118465908,49.0236963230770257,-43.1409031990296086],"rgb":[0.6,0.2,0.533333333333333326],"xyz":[0.187638116069113736,0.109184806213429561,0.244125962344261233],"hpluv":[318.6521895607018,210.08899125401652,39.4428302118465908],"hsluv":[318.6521895607018,75.1271370389489306,39.4428302118465908]},"#993399":{"lch":[40.3131218316236897,71.3679900272828149,307.715012949243942],"luv":[40.3131218316236897,43.6582502656979656,-56.4565955781255226],"rgb":[0.6,0.2,0.6],"xyz":[0.200695080178186436,0.114407591857058719,0.31289263998537914],"hpluv":[307.715012949243942,224.64479534599792,40.3131218316236897],"hsluv":[307.715012949243942,77.7202573427554313,40.3131218316236897]},"#9933aa":{"lch":[41.2844862133256925,79.5040030135899372,299.063916375798101],"luv":[41.2844862133256925,38.6218522191785354,-69.4927264276258825],"rgb":[0.6,0.2,0.66666666666666663],"xyz":[0.215752773143439,0.120430669043159827,0.39219648960237774],"hpluv":[299.063916375798101,244.366370382710016,41.2844862133256925],"hsluv":[299.063916375798101,80.1114582016200814,41.2844862133256925]},"#9933bb":{"lch":[42.3513893410192637,88.8787943355742,292.467029257400327],"luv":[42.3513893410192637,33.9651845170614,-82.1328577566084],"rgb":[0.6,0.2,0.733333333333333282],"xyz":[0.232890365250775611,0.127285705886094586,0.482454474701019487],"hpluv":[292.467029257400327,266.299173904300574,42.3513893410192637],"hsluv":[292.467029257400327,82.2764131802073848,42.3513893410192637]},"#9933cc":{"lch":[43.5075532005759911,98.8962106119506785,287.477062230467],"luv":[43.5075532005759911,29.700902070050418,-94.3308904316533],"rgb":[0.6,0.2,0.8],"xyz":[0.252182740694497365,0.135002656063583387,0.584060985371289698],"hpluv":[287.477062230467,288.439223502221068,43.5075532005759911],"hsluv":[287.477062230467,84.2111914011780129,43.5075532005759911]},"#9933dd":{"lch":[44.7462588110156716,109.182503226938962,283.677602435208257],"luv":[44.7462588110156716,25.8171133061496079,-106.086265234656878],"rgb":[0.6,0.2,0.866666666666666696],"xyz":[0.273701066245130908,0.143609986283836921,0.697390833271295696],"hpluv":[283.677602435208257,309.624731809924413,44.7462588110156716],"hsluv":[283.677602435208257,85.9249592908513478,44.7462588110156716]},"#9933ee":{"lch":[46.0606056636097208,119.52114969179982,280.747238708189116],"luv":[46.0606056636097208,22.2879081330132465,-117.42467532296601],"rgb":[0.6,0.2,0.933333333333333348],"xyz":[0.297513246511305618,0.153134858390306938,0.822801649339818919],"hpluv":[280.747238708189116,329.271729063034456,46.0606056636097208],"hsluv":[280.747238708189116,90.0471632149093324,46.0606056636097208]},"#9933ff":{"lch":[47.4437223771408512,129.794782591236896,278.453521985212944],"luv":[47.4437223771408512,19.0807517890999456,-128.38461940228359],"rgb":[0.6,0.2,1],"xyz":[0.323684294921137039,0.163603277754239662,0.960635837631600764],"hpluv":[278.453521985212944,347.150508646733101,47.4437223771408512],"hsluv":[278.453521985212944,99.999999999999261,47.4437223771408512]},"#bb3300":{"lch":[42.6640590509798585,114.303280915030754,17.3320761189885637],"luv":[42.6640590509798585,109.113245500432,34.0520143942012652],"rgb":[0.733333333333333282,0.2,0],"xyz":[0.216768341099481898,0.129342830223910105,0.0135520370028863052],"hpluv":[17.3320761189885637,339.966286272656077,42.6640590509798585],"hsluv":[17.3320761189885637,100.000000000002302,42.6640590509798585]},"#bb3311":{"lch":[42.7251747888925806,112.6335820513806,16.4819551739351198],"luv":[42.7251747888925806,108.005370801027979,31.9556518296457135],"rgb":[0.733333333333333282,0.2,0.0666666666666666657],"xyz":[0.21778000659911903,0.129747496423764958,0.0188801419676419349],"hpluv":[16.4819551739351198,334.52099084556113,42.7251747888925806],"hsluv":[16.4819551739351198,95.1490253673008368,42.7251747888925806]},"#bb3322":{"lch":[42.8381318005571785,109.688338781622747,14.8808580240480524],"luv":[42.8381318005571785,106.009603708482885,28.1690536980292627],"rgb":[0.733333333333333282,0.2,0.133333333333333331],"xyz":[0.219655364737596032,0.130497639679155786,0.0287570281636211345],"hpluv":[14.8808580240480524,324.914627119009424,42.8381318005571785],"hsluv":[14.8808580240480524,86.4181297836030211,42.8381318005571785]},"#bb3333":{"lch":[43.023174549414108,105.246046554892928,12.1770506300618351],"luv":[43.023174549414108,102.878058957341324,22.1998941575065203],"rgb":[0.733333333333333282,0.2,0.2],"xyz":[0.222743115470053765,0.131732739972138885,0.0450191820212322777],"hpluv":[12.1770506300618351,310.414975564112126,43.023174549414108],"hsluv":[12.1770506300618351,72.7398502888125762,43.023174549414108]},"#bb3344":{"lch":[43.2883038991094082,99.6704509181560496,8.14070356751482116],"luv":[43.2883038991094082,98.6661026897846085,14.1137863891102171],"rgb":[0.733333333333333282,0.2,0.266666666666666663],"xyz":[0.227201110714272653,0.133515938069826479,0.0684979569741189231],"hpluv":[8.14070356751482116,292.169703441320848,43.2883038991094082],"hsluv":[8.14070356751482116,73.8775464962187556,43.2883038991094082]},"#bb3355":{"lch":[43.6392404977582515,93.6285749325397632,2.54995992142812078],"luv":[43.6392404977582515,93.5358645919991289,4.16558266337591299],"rgb":[0.733333333333333282,0.2,0.333333333333333315],"xyz":[0.233163524753634666,0.135900903685571312,0.0999000042480928246],"hpluv":[2.54995992142812078,272.251672456619758,43.6392404977582515],"hsluv":[2.54995992142812078,75.2585830443305781,43.6392404977582515]},"#bb3366":{"lch":[44.0797950159491521,88.0182600678664784,355.263953050872033],"luv":[44.0797950159491521,87.7177339493983794,-7.26727295188107547],"rgb":[0.733333333333333282,0.2,0.4],"xyz":[0.240748520527142823,0.138934901994974602,0.1398476486552368],"hpluv":[355.263953050872033,253.380121177946961,44.0797950159491521],"hsluv":[355.263953050872033,76.8177075569623753,44.0797950159491521]},"#bb3377":{"lch":[44.6120878205181057,83.829516929164356,346.367941021132197],"luv":[44.6120878205181057,81.4679789337245239,-19.757437005625782],"rgb":[0.733333333333333282,0.2,0.466666666666666674],"xyz":[0.250062533547344756,0.142660507203055426,0.188901450561634709],"hpluv":[346.367941021132197,238.442541154787421,44.6120878205181057],"hsluv":[346.367941021132197,78.4827471040858597,44.6120878205181057]},"#bb3388":{"lch":[45.2367248685103078,81.924239827592,336.329010851829594],"luv":[45.2367248685103078,75.03162551729379,-32.8912791414593499],"rgb":[0.733333333333333282,0.2,0.533333333333333326],"xyz":[0.261202950649288557,0.147116674043833023,0.247574313965206849],"hpluv":[336.329010851829594,229.805591899252,45.2367248685103078],"hsluv":[336.329010851829594,80.18501002925629,45.2367248685103078]},"#bb3399":{"lch":[45.9529692994627226,82.7837935230449347,325.982908927834501],"luv":[45.9529692994627226,68.6170634488305495,-46.3125800806357404],"rgb":[0.733333333333333282,0.2,0.6],"xyz":[0.274259914758361312,0.152339459687462181,0.316340991606324784],"hpluv":[325.982908927834501,228.597286714525296,45.9529692994627226],"hsluv":[325.982908927834501,81.8663863744617402,45.9529692994627226]},"#bb33aa":{"lch":[46.7589216358443664,86.3774619636168524,316.238480868355282],"luv":[46.7589216358443664,62.3839556422166126,-59.7436859735489136],"rgb":[0.733333333333333282,0.2,0.66666666666666663],"xyz":[0.289317607723613812,0.158362536873563275,0.395644841223323385],"hpluv":[316.238480868355282,234.409537876970433,46.7589216358443664],"hsluv":[316.238480868355282,83.4827024616804181,46.7589216358443664]},"#bb33bb":{"lch":[47.6517090930198108,92.2657594707273461,307.715012949243828],"luv":[47.6517090930198108,56.4421334605023191,-72.9880534138084585],"rgb":[0.733333333333333282,0.2,0.733333333333333282],"xyz":[0.306455199830950487,0.165217573716498034,0.485902826321965131],"hpluv":[307.715012949243828,245.697877980233102,47.6517090930198108],"hsluv":[307.715012949243828,85.0039827354176,47.6517090930198108]},"#bb33cc":{"lch":[48.6276786348411179,99.8443429984049402,300.621719827817344],"luv":[48.6276786348411179,50.8574804969275078,-85.9209491700817551],"rgb":[0.733333333333333282,0.2,0.8],"xyz":[0.325747575274672241,0.172934523893986836,0.587509336992235287],"hpluv":[300.621719827817344,260.542905615006589,48.6276786348411179],"hsluv":[300.621719827817344,86.4127454729900535,48.6276786348411179]},"#bb33dd":{"lch":[49.6825862492002273,108.545865187730342,294.87630802524211],"luv":[49.6825862492002273,45.6609809337446322,-98.4747666639588459],"rgb":[0.733333333333333282,0.2,0.866666666666666696],"xyz":[0.347265900825305729,0.18154185411424037,0.700839184892241285],"hpluv":[294.87630802524211,277.235228758227834,49.6825862492002273],"hsluv":[294.87630802524211,87.70141038259,49.6825862492002273]},"#bb33ee":{"lch":[50.8117750205940695,117.927813495206621,290.271422146528892],"luv":[50.8117750205940695,40.8581913283156268,-110.623584271795281],"rgb":[0.733333333333333282,0.2,0.933333333333333348],"xyz":[0.371078081091480494,0.191066726220710414,0.826250000960764508],"hpluv":[290.271422146528892,294.504005794210514,50.8117750205940695],"hsluv":[290.271422146528892,88.8695912604113687,50.8117750205940695]},"#bb33ff":{"lch":[52.0103359867018611,127.679308171663493,286.581788346289272],"luv":[52.0103359867018611,36.4375993761859931,-122.36955130625914],"rgb":[0.733333333333333282,0.2,1],"xyz":[0.39724912950131186,0.201535145584643111,0.964084189252546353],"hpluv":[286.581788346289272,311.508705442628695,52.0103359867018611],"hsluv":[286.581788346289272,99.9999999999991616,52.0103359867018611]},"#994400":{"lch":[39.4244247356725168,77.6708634712958315,27.0445710144404678],"luv":[39.4244247356725168,69.1777945884316097,35.3156589667733627],"rgb":[0.6,0.266666666666666663,0],"xyz":[0.152036077002273062,0.109076103359438958,0.0130478755429292749],"hpluv":[27.0445710144404678,249.995444431237956,39.4244247356725168],"hsluv":[27.0445710144404678,100.000000000002302,39.4244247356725168]},"#994411":{"lch":[39.4928806474909351,75.8240556098730849,25.7566327743493559],"luv":[39.4928806474909351,68.2907795083206395,32.9493071744317447],"rgb":[0.6,0.266666666666666663,0.0666666666666666657],"xyz":[0.153047742501910194,0.109480769559293811,0.0183759805076849081],"hpluv":[25.7566327743493559,243.628181561178451,39.4928806474909351],"hsluv":[25.7566327743493559,94.1783894720599,39.4928806474909351]},"#994422":{"lch":[39.6193348047394807,72.6128884539244268,23.2788782073808527],"luv":[39.6193348047394807,66.7016282141236161,28.6971141964989123],"rgb":[0.6,0.266666666666666663,0.133333333333333331],"xyz":[0.154923100640387196,0.110230912814684626,0.0282528667036641],"hpluv":[23.2788782073808527,232.565805292122405,39.6193348047394807],"hsluv":[23.2788782073808527,83.7619004180350402,39.6193348047394807]},"#994433":{"lch":[39.8262957210095,67.9099451463512764,18.9473520481579776],"luv":[39.8262957210095,64.2304033034813671,22.0503047882012062],"rgb":[0.6,0.266666666666666663,0.2],"xyz":[0.158010851372844929,0.111466013107667739,0.0445150205612752509],"hpluv":[18.9473520481579776,216.372863201479333,39.8262957210095],"hsluv":[18.9473520481579776,67.5996848307310358,39.8262957210095]},"#994444":{"lch":[40.1224193460439267,62.3513134554678956,12.1770506300619097],"luv":[40.1224193460439267,60.9484376060972082,13.1519672672071142],"rgb":[0.6,0.266666666666666663,0.266666666666666663],"xyz":[0.162468846617063817,0.113249211205355318,0.0679937955141618894],"hpluv":[12.1770506300619097,197.195872414250289,40.1224193460439267],"hsluv":[12.1770506300619097,46.2091051210312429,40.1224193460439267]},"#994455":{"lch":[40.5136546800823041,57.0624194645929776,2.37288379618767387],"luv":[40.5136546800823041,57.0134905267935324,2.36254377830001205],"rgb":[0.6,0.266666666666666663,0.333333333333333315],"xyz":[0.16843126065642583,0.115634176821100151,0.0993958427881357909],"hpluv":[2.37288379618767387,178.726144329621945,40.5136546800823041],"hsluv":[2.37288379618767387,49.5312591923758063,40.5136546800823041]},"#994466":{"lch":[41.0036603670202382,53.5416261730848646,349.413399835018254],"luv":[41.0036603670202382,52.6302589877717111,-9.83674601372026558],"rgb":[0.6,0.266666666666666663,0.4],"xyz":[0.176016256429934,0.11866817513050347,0.139343487195279753],"hpluv":[349.413399835018254,165.694562401887765,41.0036603670202382],"hsluv":[349.413399835018254,53.2076295784804643,41.0036603670202382]},"#994477":{"lch":[41.594070304433572,53.2098960104776424,334.460192523955527],"luv":[41.594070304433572,48.0105420863306946,-22.9408125841809181],"rgb":[0.6,0.266666666666666663,0.466666666666666674],"xyz":[0.18533026945013592,0.122393780338584279,0.188397289101677662],"hpluv":[334.460192523955527,162.330570569563577,41.594070304433572],"hsluv":[334.460192523955527,57.0495308436177666,41.594070304433572]},"#994488":{"lch":[42.2847251453823887,56.6612659292255287,319.901700116735],"luv":[42.2847251453823887,43.3424978513170416,-36.4955742071691631],"rgb":[0.6,0.266666666666666663,0.533333333333333326],"xyz":[0.196470686552079721,0.126849947179361877,0.247070152505249829],"hpluv":[319.901700116735,170.036472949794188,42.2847251453823887],"hsluv":[319.901700116735,60.8903164523640683,42.2847251453823887]},"#994499":{"lch":[43.0739091348830314,63.3829857303906,307.715012949244226],"luv":[43.0739091348830314,38.7735489334465555,-50.1399519665159232],"rgb":[0.6,0.266666666666666663,0.6],"xyz":[0.209527650661152448,0.132072732822991035,0.315836830146367764],"hpluv":[307.715012949244226,186.722963823125951,43.0739091348830314],"hsluv":[307.715012949244226,64.600458594127474,43.0739091348830314]},"#9944aa":{"lch":[43.9586008361636686,72.3252063731545,298.405725418599673],"luv":[43.9586008361636686,34.4059763632637896,-63.6173267861038099],"rgb":[0.6,0.266666666666666663,0.66666666666666663],"xyz":[0.224585343626404976,0.138095810009092129,0.395140679763366365],"hpluv":[298.405725418599673,208.77819920337123,43.9586008361636686],"hsluv":[298.405725418599673,68.0913106207235,43.9586008361636686]},"#9944bb":{"lch":[44.9347323991438827,82.5300732915554676,291.540124858279853],"luv":[44.9347323991438827,30.3011407548278626,-76.7662286846607316],"rgb":[0.6,0.266666666666666663,0.733333333333333282],"xyz":[0.241722935733741651,0.144950846852026888,0.485398664862008111],"hpluv":[291.540124858279853,233.060888419388505,44.9347323991438827],"hsluv":[291.540124858279853,71.3111773355981882,44.9347323991438827]},"#9944cc":{"lch":[45.9974464532923903,93.3382836250318206,286.486143775676851],"luv":[45.9974464532923903,26.4878609436744341,-89.5009967134190561],"rgb":[0.6,0.266666666666666663,0.8],"xyz":[0.261015311177463349,0.152667797029515689,0.587005175532278267],"hpluv":[286.486143775676851,257.492992496327645,45.9974464532923903],"hsluv":[286.486143775676851,74.2376853125076792,45.9974464532923903]},"#9944dd":{"lch":[47.1413389271288139,104.350309752399141,282.717215233582351],"luv":[47.1413389271288139,22.9716047676972792,-101.790434323753402],"rgb":[0.6,0.266666666666666663,0.866666666666666696],"xyz":[0.282533636728096949,0.161275127249769223,0.700335023432284265],"hpluv":[282.717215233582351,280.886686990529654,47.1413389271288139],"hsluv":[282.717215233582351,78.691216526215527,47.1413389271288139]},"#9944ee":{"lch":[48.3606780479664593,115.341161543855208,279.855683836472622],"luv":[48.3606780479664593,19.7426125181249787,-113.638958096441911],"rgb":[0.6,0.266666666666666663,0.933333333333333348],"xyz":[0.306345816994271658,0.170799999356239268,0.825745839500807488],"hpluv":[279.855683836472622,302.643440789384783,48.3606780479664593],"hsluv":[279.855683836472622,89.2619995530309325,48.3606780479664593]},"#9944ff":{"lch":[49.6495929972458185,126.19285787586071,277.642335930208503],"luv":[49.6495929972458185,16.7822322716138856,-125.071955525044785],"rgb":[0.6,0.266666666666666663,1],"xyz":[0.332516865404103079,0.181268418720171964,0.963580027792589333],"hpluv":[277.642335930208503,322.521305960549284,49.6495929972458185],"hsluv":[277.642335930208503,99.9999999999991616,49.6495929972458185]},"#bb4400":{"lch":[45.2216387767487547,104.837609625168909,21.4216552556228201],"luv":[45.2216387767487547,97.5952013308911,38.2896992558330354],"rgb":[0.733333333333333282,0.266666666666666663,0],"xyz":[0.225600911582447911,0.147007971189842435,0.0164962271638749],"hpluv":[21.4216552556228201,294.177965476355098,45.2216387767487547],"hsluv":[21.4216552556228201,100.000000000002373,45.2216387767487547]},"#bb4411":{"lch":[45.2777618800582076,103.283777149094803,20.576768268141489],"luv":[45.2777618800582076,96.6944911384892123,36.3003306548646947],"rgb":[0.733333333333333282,0.266666666666666663,0.0666666666666666657],"xyz":[0.226612577082085043,0.147412637389697287,0.0218243321286305317],"hpluv":[20.576768268141489,289.458620037032802,45.2777618800582076],"hsluv":[20.576768268141489,95.6967439910137614,45.2777618800582076]},"#bb4422":{"lch":[45.3815280810129238,100.53232916519147,18.9799525675269258],"luv":[45.3815280810129238,95.0666309197234,32.6968636561903381],"rgb":[0.733333333333333282,0.266666666666666663,0.133333333333333331],"xyz":[0.228487935220562044,0.148162780645088116,0.0317012183246097243],"hpluv":[18.9799525675269258,281.103307599105051,45.3815280810129238],"hsluv":[18.9799525675269258,87.925891065222288,45.3815280810129238]},"#bb4433":{"lch":[45.5516172521931111,96.3559005693685862,16.2666991179303722],"luv":[45.5516172521931111,92.4986058403436147,26.9901369416087924],"rgb":[0.733333333333333282,0.266666666666666663,0.2],"xyz":[0.231575685953019805,0.149397880938071215,0.0479633721822208675],"hpluv":[16.2666991179303722,268.419362556396,45.5516172521931111],"hsluv":[16.2666991179303722,75.6846484949249572,45.5516172521931111]},"#bb4444":{"lch":[45.7955406359936816,91.066890863790789,12.177050630061844],"luv":[45.7955406359936816,89.0179277419259734,19.2090382927107299],"rgb":[0.733333333333333282,0.266666666666666663,0.266666666666666663],"xyz":[0.236033681197238665,0.151181079035758809,0.0714421471351075],"hpluv":[12.177050630061844,252.334507458167678,45.7955406359936816],"hsluv":[12.177050630061844,59.1297963696904461,45.7955406359936816]},"#bb4455":{"lch":[46.1187996938414813,85.2741675307746,6.43569277192082279],"luv":[46.1187996938414813,84.7367941199702273,9.55820957796975],"rgb":[0.733333333333333282,0.266666666666666663,0.333333333333333315],"xyz":[0.24199609523660065,0.153566044651503641,0.102844194409081421],"hpluv":[6.43569277192082279,234.627449284537505,46.1187996938414813],"hsluv":[6.43569277192082279,61.0765315010866274,46.1187996938414813]},"#bb4466":{"lch":[46.5252276318027427,79.8426568240615637,358.82639812637143],"luv":[46.5252276318027427,79.8259079304732779,-1.63532009113408461],"rgb":[0.733333333333333282,0.266666666666666663,0.4],"xyz":[0.249581091010108835,0.156600042960906932,0.142791838816225369],"hpluv":[358.82639812637143,217.763856882437722,46.5252276318027427],"hsluv":[358.82639812637143,63.3003300169989842,46.5252276318027427]},"#bb4477":{"lch":[47.0171837667790697,75.785442181693,349.367581794189107],"luv":[47.0171837667790697,74.484290362097866,-13.9829802234512588],"rgb":[0.733333333333333282,0.266666666666666663,0.466666666666666674],"xyz":[0.258895104030310741,0.160325648168987756,0.191845640722623278],"hpluv":[349.367581794189107,204.535408840651428,47.0171837667790697],"hsluv":[349.367581794189107,65.7062458495858266,47.0171837667790697]},"#bb4488":{"lch":[47.5956997014540235,74.0450948660102,338.538246495536782],"luv":[47.5956997014540235,68.9109568360576219,-27.0916241974425098],"rgb":[0.733333333333333282,0.266666666666666663,0.533333333333333326],"xyz":[0.270035521132254597,0.164781815009765353,0.250518504126195474],"hpluv":[338.538246495536782,197.409434601059019,47.5956997014540235],"hsluv":[338.538246495536782,68.1997676790361,47.5956997014540235]},"#bb4499":{"lch":[48.2606154557730633,75.1911240047971,327.313188255720945],"luv":[48.2606154557730633,63.2834900243205496,-40.6067115074158309],"rgb":[0.733333333333333282,0.266666666666666663,0.6],"xyz":[0.283092485241327296,0.170004600653394511,0.319285181767313353],"hpluv":[327.313188255720945,197.702903480158483,48.2606154557730633],"hsluv":[327.313188255720945,70.6969578310621074,48.2606154557730633]},"#bb44aa":{"lch":[49.0107199856960278,79.2228796099941093,316.794363507436401],"luv":[49.0107199856960278,57.7456584584256944,-54.2374739723603838],"rgb":[0.733333333333333282,0.266666666666666663,0.66666666666666663],"xyz":[0.298150178206579852,0.176027677839495605,0.398589031384311954],"hpluv":[316.794363507436401,205.115683333718124,49.0107199856960278],"hsluv":[316.794363507436401,73.1302855273877128,49.0107199856960278]},"#bb44bb":{"lch":[49.8438993628519427,85.6636869410227746,307.715012949243942],"luv":[49.8438993628519427,52.4034189799077268,-67.7653963284049752],"rgb":[0.733333333333333282,0.266666666666666663,0.733333333333333282],"xyz":[0.315287770313916471,0.182882714682430364,0.4888470164829537],"hpluv":[307.715012949243942,218.084137693810391,49.8438993628519427],"hsluv":[307.715012949243942,75.450469608388417,49.8438993628519427]},"#bb44cc":{"lch":[50.757290285110841,93.8478600934752905,300.284565440631638],"luv":[50.757290285110841,47.3270085455435918,-81.0405769121528152],"rgb":[0.733333333333333282,0.266666666666666663,0.8],"xyz":[0.334580145757638225,0.190599664859919166,0.590453527153223856],"hpluv":[300.284565440631638,234.620130462749955,50.757290285110841],"hsluv":[300.284565440631638,77.6254237907312898,50.757290285110841]},"#bb44dd":{"lch":[51.7474340276366291,103.158361374368454,294.364201848969515],"luv":[51.7474340276366291,42.5564715489483518,-93.971241615445],"rgb":[0.733333333333333282,0.266666666666666663,0.866666666666666696],"xyz":[0.356098471308271769,0.1992069950801727,0.703783375053229854],"hpluv":[294.364201848969515,252.961799427415912,51.7474340276366291],"hsluv":[294.364201848969515,79.6375689955678467,51.7474340276366291]},"#bb44ee":{"lch":[52.8104252671910217,113.122924260907325,289.686672533024307],"luv":[52.8104252671910217,38.1084271425454304,-106.510768347901248],"rgb":[0.733333333333333282,0.266666666666666663,0.933333333333333348],"xyz":[0.379910651574446478,0.208731867186642744,0.829194191121753077],"hpluv":[289.686672533024307,271.813038246621943,52.8104252671910217],"hsluv":[289.686672533024307,87.7449679178180872,52.8104252671910217]},"#bb44ff":{"lch":[53.942050711908152,123.415863319803691,285.982908620336502],"luv":[53.942050711908152,33.9826318144238115,-118.645084406973112],"rgb":[0.733333333333333282,0.266666666666666663,1],"xyz":[0.4060816999842779,0.219200286550575441,0.967028379413534922],"hpluv":[285.982908620336502,290.323946696930363,53.942050711908152],"hsluv":[285.982908620336502,99.9999999999990621,53.942050711908152]},"#995500":{"lch":[43.167672396478018,69.2675138179999,36.3951762413548678],"luv":[43.167672396478018,55.7564526526882105,41.099956911356287],"rgb":[0.6,0.333333333333333315,0],"xyz":[0.163849333716619028,0.132702616788131222,0.0169856277810444857],"hpluv":[36.3951762413548678,203.615246511519132,43.167672396478018],"hsluv":[36.3951762413548678,100.000000000002288,43.167672396478018]},"#995511":{"lch":[43.2277537555276865,67.4837391190291385,35.2266717066771307],"luv":[43.2277537555276865,55.1258789529511333,38.9254738590266101],"rgb":[0.6,0.333333333333333315,0.0666666666666666657],"xyz":[0.16486099921625616,0.133107282987986075,0.0223137327458001189],"hpluv":[35.2266717066771307,198.096040704981476,43.2277537555276865],"hsluv":[35.2266717066771307,95.1659583326808303,43.2277537555276865]},"#995522":{"lch":[43.3388072781739,64.3407602415628475,32.9528815923873708],"luv":[43.3388072781739,53.9895016234129059,34.998101990218963],"rgb":[0.6,0.333333333333333315,0.133333333333333331],"xyz":[0.166736357354733161,0.133857426243376904,0.0321906189417793115],"hpluv":[32.9528815923873708,188.385971738918272,43.3388072781739],"hsluv":[32.9528815923873708,86.4646465379692302,43.3388072781739]},"#995533":{"lch":[43.5207548807750584,59.6262244551406582,28.8908620435756234],"luv":[43.5207548807750584,52.2052395636471,28.8079781462883915],"rgb":[0.6,0.333333333333333315,0.2],"xyz":[0.169824108087190895,0.13509252653636,0.0484527727993904617],"hpluv":[28.8908620435756234,173.852210644027934,43.5207548807750584],"hsluv":[28.8908620435756234,72.8304069554253601,43.5207548807750584]},"#995544":{"lch":[43.7814988718974831,53.8284560366537335,22.2989672577237812],"luv":[43.7814988718974831,49.8029788080235036,20.4246415179685634],"rgb":[0.6,0.333333333333333315,0.266666666666666663],"xyz":[0.174282103331409782,0.136875724634047596,0.0719315477522771],"hpluv":[22.2989672577237812,156.01294104827457,43.7814988718974831],"hsluv":[22.2989672577237812,54.5318604429391058,43.7814988718974831]},"#995555":{"lch":[44.1267187000120629,47.9518139182857226,12.1770506300620411],"luv":[44.1267187000120629,46.8729201797035,10.1146335514957979],"rgb":[0.6,0.333333333333333315,0.333333333333333315],"xyz":[0.180244517370771795,0.139260690249792429,0.103333595026251],"hpluv":[12.1770506300620411,137.893162706519348,44.1267187000120629],"hsluv":[12.1770506300620411,32.3126421104369754,44.1267187000120629]},"#995566":{"lch":[44.5602350881765048,43.578232165907,357.727809148728397],"luv":[44.5602350881765048,43.5439690351937116,-1.72773822316436432],"rgb":[0.6,0.333333333333333315,0.4],"xyz":[0.187829513144279953,0.14229468855919572,0.143281239433394963],"hpluv":[357.727809148728397,124.097051059849122,44.5602350881765048],"hsluv":[357.727809148728397,36.5660257696708157,44.5602350881765048]},"#995577":{"lch":[45.0842241078155226,42.5628566452735342,339.858530865537546],"luv":[45.0842241078155226,39.9599368331855729,-14.6560640723873874],"rgb":[0.6,0.333333333333333315,0.466666666666666674],"xyz":[0.197143526164481886,0.146020293767276543,0.192335041339792873],"hpluv":[339.858530865537546,119.796876557388956,45.0842241078155226],"hsluv":[339.858530865537546,41.1101378179314167,45.0842241078155226]},"#995588":{"lch":[45.699386409692309,45.957423726275,322.088602167082399],"luv":[45.699386409692309,36.2586549471185506,-28.2381787122006145],"rgb":[0.6,0.333333333333333315,0.533333333333333326],"xyz":[0.208283943266425686,0.150476460608054141,0.25100790474336504],"hpluv":[322.088602167082399,127.609977655436467,45.699386409692309],"hsluv":[322.088602167082399,45.7577454208568852,45.699386409692309]},"#995599":{"lch":[46.4051108942887964,53.2218555896971921,307.715012949244795],"luv":[46.4051108942887964,32.5576366947089113,-42.1018551285561102],"rgb":[0.6,0.333333333333333315,0.6],"xyz":[0.221340907375498414,0.155699246251683299,0.319774582384483],"hpluv":[307.715012949244795,145.533684272522947,46.4051108942887964],"hsluv":[307.715012949244795,50.3502223422482516,46.4051108942887964]},"#9955aa":{"lch":[47.1996461355186625,63.0010233462712037,297.353030705211779],"luv":[47.1996461355186625,28.9471952899390068,-55.9570266143899246],"rgb":[0.6,0.333333333333333315,0.66666666666666663],"xyz":[0.236398600340750942,0.161722323437784393,0.399078432001481576],"hpluv":[297.353030705211779,169.374563019623821,47.1996461355186625],"hsluv":[297.353030705211779,54.7667714505238337,47.1996461355186625]},"#9955bb":{"lch":[48.0802807126223541,74.1194144420538,290.114722102094788],"luv":[48.0802807126223541,25.4897394646759068,-69.5985688017783701],"rgb":[0.6,0.333333333333333315,0.733333333333333282],"xyz":[0.253536192448087616,0.168577360280719152,0.489336417100123322],"hpluv":[290.114722102094788,195.615971831826613,48.0802807126223541],"hsluv":[290.114722102094788,58.9252289891592866,48.0802807126223541]},"#9955cc":{"lch":[49.0435277691913,85.8237639836856658,285.007043429489613],"luv":[49.0435277691913,22.2230153813451068,-82.8966588692685491],"rgb":[0.6,0.333333333333333315,0.8],"xyz":[0.272828567891809315,0.176294310458207953,0.590942927770393478],"hpluv":[285.007043429489613,222.057364979540267,49.0435277691913],"hsluv":[285.007043429489613,65.256702758776143,49.0435277691913]},"#9955dd":{"lch":[50.0853068419578875,97.6800340866365104,281.315028513382344],"luv":[50.0853068419578875,19.1651498984824649,-95.7814496055220843],"rgb":[0.6,0.333333333333333315,0.866666666666666696],"xyz":[0.294346893442442914,0.184901640678461487,0.704272775670399476],"hpluv":[281.315028513382344,247.476970093373268,50.0853068419578875],"hsluv":[281.315028513382344,76.6956878028438638,50.0853068419578875]},"#9955ee":{"lch":[51.2011159126469266,109.450459224116145,278.575243894560685],"luv":[51.2011159126469266,16.3199513369978568,-108.226901520499666],"rgb":[0.6,0.333333333333333315,0.933333333333333348],"xyz":[0.318159073708617623,0.194426512784931532,0.829683591738922699],"hpluv":[278.575243894560685,271.254835109068836,51.2011159126469266],"hsluv":[278.575243894560685,88.2491190723243335,51.2011159126469266]},"#9955ff":{"lch":[52.3861878346365444,121.012399839465246,276.491711029928183],"luv":[52.3861878346365444,13.6815981187824764,-120.2364952409323],"rgb":[0.6,0.333333333333333315,1],"xyz":[0.344330122118449045,0.204894932148864228,0.967517780030704544],"hpluv":[276.491711029928183,293.124692446110771,52.3861878346365444],"hsluv":[276.491711029928183,99.9999999999991,52.3861878346365444]},"#bb5500":{"lch":[48.3398816318057811,94.9450628471467724,27.1627331553413143],"luv":[48.3398816318057811,84.4739036935134,43.344256295703957],"rgb":[0.733333333333333282,0.333333333333333315,0],"xyz":[0.237414168296793876,0.170634484618534699,0.0204339794019901093],"hpluv":[27.1627331553413143,249.233335779464397,48.3398816318057811],"hsluv":[27.1627331553413143,100.000000000002217,48.3398816318057811]},"#bb5511":{"lch":[48.3907029738951735,93.4795954244126364,26.3417432533787057],"luv":[48.3907029738951735,83.7729911103365907,41.4791600823755289],"rgb":[0.733333333333333282,0.333333333333333315,0.0666666666666666657],"xyz":[0.238425833796431,0.171039150818389551,0.0257620843667457425],"hpluv":[26.3417432533787057,245.128732426237889,48.3907029738951735],"hsluv":[26.3417432533787057,96.2613278044251786,48.3907029738951735]},"#bb5522":{"lch":[48.4847005727335869,90.8707197847641623,24.7826102649670759],"luv":[48.4847005727335869,82.5019575685759321,38.090874386840035],"rgb":[0.733333333333333282,0.333333333333333315,0.133333333333333331],"xyz":[0.240301191934908,0.17178929407378038,0.0356389705627249351],"hpluv":[24.7826102649670759,237.825586669453713,48.4847005727335869],"hsluv":[24.7826102649670759,89.48684037186257,48.4847005727335869]},"#bb5533":{"lch":[48.6388719159228629,86.8743588299812473,22.1104535643633149],"luv":[48.6388719159228629,80.4856161939384407,32.6989267102511363],"rgb":[0.733333333333333282,0.333333333333333315,0.2],"xyz":[0.243388942667365771,0.173024394366763479,0.0519011244203360783],"hpluv":[22.1104535643633149,226.64567974804504,48.6388719159228629],"hsluv":[22.1104535643633149,78.7542493880857393,48.6388719159228629]},"#bb5544":{"lch":[48.8601705631915,81.7431600256382751,18.0266646696809296],"luv":[48.8601705631915,77.730600917119915,25.2962031151029265],"rgb":[0.733333333333333282,0.333333333333333315,0.266666666666666663],"xyz":[0.24784693791158463,0.174807592464451073,0.0753798993732227168],"hpluv":[18.0266646696809296,212.293047020031764,48.8601705631915],"hsluv":[18.0266646696809296,64.1199207289341,48.8601705631915]},"#bb5555":{"lch":[49.1538097277392154,76.0172073873862075,12.1770506300619399],"luv":[49.1538097277392154,74.3068552156307,16.0345591439297159],"rgb":[0.733333333333333282,0.333333333333333315,0.333333333333333315],"xyz":[0.253809351950946616,0.177192558080195905,0.106781946647196632],"hpluv":[12.1770506300619399,196.242945408672853,49.1538097277392154],"hsluv":[12.1770506300619399,45.9858047870319879,49.1538097277392154]},"#bb5566":{"lch":[49.523574907380123,70.5220596563995,4.21567942747197],"luv":[49.523574907380123,70.3312550088346882,5.18415538569556134],"rgb":[0.733333333333333282,0.333333333333333315,0.4],"xyz":[0.261394347724454801,0.180226556389599196,0.14672959105434058],"hpluv":[4.21567942747197,180.697576197923894,49.523574907380123],"hsluv":[4.21567942747197,48.7291682320237527,49.523574907380123]},"#bb5577":{"lch":[49.971995559373525,66.3094111666939341,354.014227306533371],"luv":[49.971995559373525,65.9478803557508257,-6.91484532417379327],"rgb":[0.733333333333333282,0.333333333333333315,0.466666666666666674],"xyz":[0.270708360744656706,0.18395216159768002,0.195783392960738489],"hpluv":[354.014227306533371,168.378953180241098,49.971995559373525],"hsluv":[354.014227306533371,51.7390719561838495,49.971995559373525]},"#bb5588":{"lch":[50.5004659153875508,64.4571905510646275,342.016521446261379],"luv":[50.5004659153875508,61.308172080607541,-19.9006896832966476],"rgb":[0.733333333333333282,0.333333333333333315,0.533333333333333326],"xyz":[0.281848777846600562,0.188408328438457617,0.254456256364310685],"hpluv":[342.016521446261379,161.962814057843559,50.5004659153875508],"hsluv":[342.016521446261379,54.9055054808170055,50.5004659153875508]},"#bb5599":{"lch":[51.1093507584050286,65.6961991151429459,329.411862939203161],"luv":[51.1093507584050286,56.5544024759803,-33.4303774845774342],"rgb":[0.733333333333333282,0.333333333333333315,0.6],"xyz":[0.294905741955673262,0.193631114082086775,0.323222934005428564],"hpluv":[329.411862939203161,163.109481188372769,51.1093507584050286],"hsluv":[329.411862939203161,58.1255686218068561,51.1093507584050286]},"#bb55aa":{"lch":[51.7980911374347386,70.0901192661774246,317.660759061539352],"luv":[51.7980911374347386,51.8085124997667563,-47.2070212077450151],"rgb":[0.733333333333333282,0.333333333333333315,0.66666666666666663],"xyz":[0.309963434920925818,0.199654191268187869,0.402526783622427164],"hpluv":[317.660759061539352,171.704773930815691,51.7980911374347386],"hsluv":[317.660759061539352,61.3115173935257403,51.7980911374347386]},"#bb55bb":{"lch":[52.5653152299933737,77.1031380177621344,307.715012949244226],"luv":[52.5653152299933737,47.1666372355911179,-60.9934605025180332],"rgb":[0.733333333333333282,0.333333333333333315,0.733333333333333282],"xyz":[0.327101027028262437,0.206509228111122628,0.492784768721068911],"hpluv":[307.715012949244226,186.128169856082764,52.5653152299933737],"hsluv":[307.715012949244226,64.3946779967479,52.5653152299933737]},"#bb55cc":{"lch":[53.4089544864585,85.9678373228364308,299.780474196008072],"luv":[53.4089544864585,42.6983512805399883,-74.6144748148057175],"rgb":[0.733333333333333282,0.333333333333333315,0.8],"xyz":[0.346393402471984191,0.21422617828861143,0.594391279391339067],"hpluv":[299.780474196008072,204.249617293250537,53.4089544864585],"hsluv":[299.780474196008072,67.3259326792693855,53.4089544864585]},"#bb55dd":{"lch":[54.3263625650166944,95.9883710948233926,293.613183872979789],"luv":[54.3263625650166944,38.4490902963257213,-87.9513208588848698],"rgb":[0.733333333333333282,0.333333333333333315,0.866666666666666696],"xyz":[0.367911728022617734,0.222833508508864964,0.707721127291345065],"hpluv":[293.613183872979789,224.206046477737118,54.3263625650166944],"hsluv":[293.613183872979789,73.8407928406032283,54.3263625650166944]},"#bb55ee":{"lch":[55.314433433552054,106.647677925948784,288.842761327535072],"luv":[55.314433433552054,34.444226028074695,-100.932266893812525],"rgb":[0.733333333333333282,0.333333333333333315,0.933333333333333348],"xyz":[0.391723908288792444,0.232358380615335,0.833131943359868288],"hpluv":[288.842761327535072,244.653966901481454,55.314433433552054],"hsluv":[288.842761327535072,86.7715876359309135,55.314433433552054]},"#bb55ff":{"lch":[56.3697148536960526,117.598184211748716,285.129655441003138],"luv":[56.3697148536960526,30.6936185759692179,-113.521956944959783],"rgb":[0.733333333333333282,0.333333333333333315,1],"xyz":[0.417894956698623865,0.242826799979267705,0.970966131651650133],"hpluv":[285.129655441003138,264.724480425834031,56.3697148536960526],"hsluv":[285.129655441003138,99.9999999999989,56.3697148536960526]},"#996600":{"lch":[47.3343652017352454,63.4240894393546952,48.3260196362919672],"luv":[47.3343652017352454,42.1701199842588,47.3740023823666476],"rgb":[0.6,0.4,0],"xyz":[0.178877391422465504,0.162758732199824563,0.0219949803496598331],"hpluv":[48.3260196362919672,170.026654750900292,47.3343652017352454],"hsluv":[48.3260196362919672,100.000000000002288,47.3343652017352454]},"#996611":{"lch":[47.3868110627231189,61.667674323653,47.4017350737566616],"luv":[47.3868110627231189,41.7399921999205,45.3946594616449133],"rgb":[0.6,0.4,0.0666666666666666657],"xyz":[0.179889056922102636,0.163163398399679416,0.0273230853144154628],"hpluv":[47.4017350737566616,165.135107398016657,47.3868110627231189],"hsluv":[47.4017350737566616,96.0239926064661,47.3868110627231189]},"#996622":{"lch":[47.4838028017404099,58.5263777304533406,45.5834379771503322],"luv":[47.4838028017404099,40.9608465044279413,41.8036594557031336],"rgb":[0.6,0.4,0.133333333333333331],"xyz":[0.181764415060579637,0.163913541655070244,0.0371999715103946624],"hpluv":[45.5834379771503322,156.40314428015364,47.4838028017404099],"hsluv":[45.5834379771503322,88.8298219708016177,47.4838028017404099]},"#996633":{"lch":[47.642855645786625,53.6803525088045674,42.2629253198225712],"luv":[47.642855645786625,39.7270268335614887,36.1018501525199724],"rgb":[0.6,0.4,0.2],"xyz":[0.184852165793037371,0.165148641948053343,0.0534621253680058056],"hpluv":[42.2629253198225712,142.973945144987511,47.642855645786625],"hsluv":[42.2629253198225712,77.4596172761956865,47.642855645786625]},"#996644":{"lch":[47.8710980897590872,47.4159845831850149,36.6424092143452071],"luv":[47.8710980897590872,38.045445264132745,28.298757722676072],"rgb":[0.6,0.4,0.266666666666666663],"xyz":[0.189310161037256258,0.166931840045740937,0.0769409003208924441],"hpluv":[36.6424092143452071,125.687101185572914,47.8710980897590872],"hsluv":[36.6424092143452071,62.0095295256686185,47.8710980897590872]},"#996655":{"lch":[48.173837669734425,40.4765536471140521,27.3183313201514686],"luv":[48.173837669734425,35.9622216701857838,18.5760600691352664],"rgb":[0.6,0.4,0.333333333333333315],"xyz":[0.195272575076618271,0.16931680566148577,0.108342947594866346],"hpluv":[27.3183313201514686,106.618264590322553,48.173837669734425],"hsluv":[27.3183313201514686,42.9499413016611484,48.173837669734425]},"#996666":{"lch":[48.5548823199147819,34.3240193245421,12.1770506300621335],"luv":[48.5548823199147819,33.551744690774747,7.24007809326721219],"rgb":[0.6,0.4,0.4],"xyz":[0.202857570850126429,0.17235080397088906,0.148290592002010307],"hpluv":[12.1770506300621335,89.702502372613651,48.5548823199147819],"hsluv":[12.1770506300621335,21.0200766933302461,48.5548823199147819]},"#996677":{"lch":[49.0167186013709,31.3606600839303482,350.2076113500313],"luv":[49.0167186013709,30.9037509766054157,-5.33377694282222681],"rgb":[0.6,0.4,0.466666666666666674],"xyz":[0.212171583870328362,0.176076409178969884,0.197344393908408217],"hpluv":[350.2076113500313,81.185839798992177,49.0167186013709],"hsluv":[350.2076113500313,25.8881256225468483,49.0167186013709]},"#996688":{"lch":[49.5606396668562752,33.7929953796712823,326.289263208678278],"luv":[49.5606396668562752,28.1107077320421368,-18.7551232343109682],"rgb":[0.6,0.4,0.533333333333333326],"xyz":[0.223312000972272162,0.180532576019747482,0.256017257311980384],"hpluv":[326.289263208678278,86.5225105267045365,49.5606396668562752],"hsluv":[326.289263208678278,30.9767265160446463,49.5606396668562752]},"#996699":{"lch":[50.1868595811773304,41.2886932006772,307.715012949245818],"luv":[50.1868595811773304,25.2577114783499113,-32.6619686653465351],"rgb":[0.6,0.4,0.6],"xyz":[0.236368965081344889,0.185755361663376639,0.324783934953098319],"hpluv":[307.715012949245818,104.395179003902854,50.1868595811773304],"hsluv":[307.715012949245818,36.1175524455388413,50.1868595811773304]},"#9966aa":{"lch":[50.8946289106688141,51.8448774557822,295.617938374847199],"luv":[50.8946289106688141,22.4160699516755599,-46.7483810021979451],"rgb":[0.6,0.4,0.66666666666666663],"xyz":[0.251426658046597418,0.191778438849477734,0.40408778457009692],"hpluv":[295.617938374847199,129.262701065701,50.8946289106688141],"hsluv":[295.617938374847199,41.1705422178494445,50.8946289106688141]},"#9966bb":{"lch":[51.6823563026294,63.8712345518136,287.908782454232437],"luv":[51.6823563026294,19.6405628457828776,-60.776499523036378],"rgb":[0.6,0.4,0.733333333333333282],"xyz":[0.268564250153934092,0.198633475692412492,0.494345769668738666],"hpluv":[287.908782454232437,156.820318415219759,51.6823563026294],"hsluv":[287.908782454232437,49.349420166275209,51.6823563026294]},"#9966cc":{"lch":[52.5477355185796569,76.4825896496335389,282.819195018988751],"luv":[52.5477355185796569,16.9695880464031816,-74.5762670093482285],"rgb":[0.6,0.4,0.8],"xyz":[0.287856625597655791,0.206350425869901294,0.595952280339008822],"hpluv":[282.819195018988751,184.691924030055,52.5477355185796569],"hsluv":[282.819195018988751,61.7185051859638136,52.5477355185796569]},"#9966dd":{"lch":[53.4878747475352725,89.2117449852098758,279.306611445978092],"luv":[53.4878747475352725,14.4271177471338046,-88.0374563286358],"rgb":[0.6,0.4,0.866666666666666696],"xyz":[0.30937495114828939,0.214957756090154828,0.70928212823901482],"hpluv":[279.306611445978092,211.644028054176175,53.4878747475352725],"hsluv":[279.306611445978092,74.2596178074049362,53.4878747475352725]},"#9966ee":{"lch":[54.4994239962059339,101.810849438236403,276.783380903602506],"luv":[54.4994239962059339,12.0254847729914225,-101.098154183495325],"rgb":[0.6,0.4,0.933333333333333348],"xyz":[0.333187131414464099,0.224482628196624873,0.834692944307538],"hpluv":[276.783380903602506,237.050827216632513,54.4994239962059339],"hsluv":[276.783380903602506,86.9990828065156734,54.4994239962059339]},"#9966ff":{"lch":[55.5786963614876,114.151421142661491,274.908981870437117],"luv":[55.5786963614876,9.76829238934238475,-113.732701597586171],"rgb":[0.6,0.4,1],"xyz":[0.359358179824295521,0.234951047560557569,0.972527132599319888],"hpluv":[274.908981870437117,260.622732185953453,55.5786963614876],"hsluv":[274.908981870437117,99.999999999998991,55.5786963614876]},"#bb6600":{"lch":[51.9152024616159622,85.9194467179265899,34.7713476038742],"luv":[51.9152024616159622,70.5771984524152884,49.0001059480794936],"rgb":[0.733333333333333282,0.4,0],"xyz":[0.252442226002640324,0.200690600030228039,0.0254433319706054567],"hpluv":[34.7713476038742,210.008196913669821,51.9152024616159622],"hsluv":[34.7713476038742,100.000000000002217,51.9152024616159622]},"#bb6611":{"lch":[51.960819173128,84.5067938711160735,34.0102696578751846],"luv":[51.960819173128,70.0508360673827184,47.2681560528436],"rgb":[0.733333333333333282,0.4,0.0666666666666666657],"xyz":[0.253453891502277429,0.201095266230082892,0.0307714369353610864],"hpluv":[34.0102696578751846,206.373990798532162,51.960819173128],"hsluv":[34.0102696578751846,96.7960731817087492,51.960819173128]},"#bb6622":{"lch":[52.0452187907305586,81.9745670334704215,32.5563816919222901],"luv":[52.0452187907305586,69.0932729256005587,44.1129150788451909],"rgb":[0.733333333333333282,0.4,0.133333333333333331],"xyz":[0.255329249640754485,0.20184540948547372,0.040648323131340286],"hpluv":[32.5563816919222901,199.865401092535734,52.0452187907305586],"hsluv":[32.5563816919222901,90.9716633106406221,52.0452187907305586]},"#bb6633":{"lch":[52.1837271506259412,78.04817012610809,30.0375791414029081],"luv":[52.1837271506259412,67.5660884046363,39.0684086920722109],"rgb":[0.733333333333333282,0.4,0.2],"xyz":[0.258417000373212191,0.203080509778456819,0.0569104769889514292],"hpluv":[30.0375791414029081,189.787216830323956,52.1837271506259412],"hsluv":[30.0375791414029081,81.6941023093515639,52.1837271506259412]},"#bb6644":{"lch":[52.3827138306128859,72.9081368603095257,26.1184165145312406],"luv":[52.3827138306128859,65.4632041398932,32.0961886238895318],"rgb":[0.733333333333333282,0.4,0.266666666666666663],"xyz":[0.262874995617431106,0.204863707876144413,0.0803892519418380747],"hpluv":[26.1184165145312406,176.614896915735159,52.3827138306128859],"hsluv":[26.1184165145312406,68.9437006343278824,52.3827138306128859]},"#bb6655":{"lch":[52.6470547760809637,67.004522830646,20.3474245095699864],"luv":[52.6470547760809637,62.823537757634746,23.2982656731697979],"rgb":[0.733333333333333282,0.4,0.333333333333333315],"xyz":[0.268837409656793092,0.207248673491889246,0.111791299215811976],"hpluv":[20.3474245095699864,161.498824171429789,52.6470547760809637],"hsluv":[20.3474245095699864,52.9816895309479534,52.6470547760809637]},"#bb6666":{"lch":[52.9804174131186727,61.0960132663801261,12.1770506300620109],"luv":[52.9804174131186727,59.7213810933874498,12.8871826767560087],"rgb":[0.733333333333333282,0.4,0.4],"xyz":[0.276422405430301277,0.210282671801292537,0.151738943622955924],"hpluv":[12.1770506300620109,146.331162504643544,52.9804174131186727],"hsluv":[12.1770506300620109,34.2899270044314335,52.9804174131186727]},"#bb6677":{"lch":[53.3854132757716826,56.2661599102721226,1.17050216666979279],"luv":[53.3854132757716826,56.2544190111897535,1.14938799445880213],"rgb":[0.733333333333333282,0.4,0.466666666666666674],"xyz":[0.285736418450503182,0.21400827700937336,0.200792745529353833],"hpluv":[1.17050216666979279,133.74082367080041,53.3854132757716826],"hsluv":[1.17050216666979279,37.694842795415525,53.3854132757716826]},"#bb6688":{"lch":[53.8636991644475387,53.7950791600554297,347.554026547444039],"luv":[53.8636991644475387,52.5308766640911458,-11.5938578022448873],"rgb":[0.733333333333333282,0.4,0.533333333333333326],"xyz":[0.296876835552447,0.218464443850150958,0.259465608932926028],"hpluv":[347.554026547444039,126.731828674836166,53.8636991644475387],"hsluv":[347.554026547444039,41.3310399817098855,53.8636991644475387]},"#bb6699":{"lch":[54.4160596975863484,54.7145736516266723,332.78581188167891],"luv":[54.4160596975863484,48.6578429809048814,-25.0219680745716886],"rgb":[0.733333333333333282,0.4,0.6],"xyz":[0.309933799661519682,0.223687229493780115,0.328232286574043908],"hpluv":[332.78581188167891,127.589593839900076,54.4160596975863484],"hsluv":[332.78581188167891,45.0871489409768813,54.4160596975863484]},"#bb66aa":{"lch":[55.0424859024436,59.2427277394444332,319.03138367428437],"luv":[55.0424859024436,44.7323366642012274,-38.8422301956323963],"rgb":[0.733333333333333282,0.4,0.66666666666666663],"xyz":[0.324991492626772238,0.22971030667988121,0.407536136191042508],"hpluv":[319.03138367428437,136.57661144398341,55.0424859024436],"hsluv":[319.03138367428437,48.8627280546895548,55.0424859024436]},"#bb66bb":{"lch":[55.7422560614222,66.7541112543564168,307.715012949244738],"luv":[55.7422560614222,40.8357821803987235,-52.8067255477370452],"rgb":[0.733333333333333282,0.4,0.733333333333333282],"xyz":[0.342129084734108913,0.236565343522815968,0.497794121289684255],"hpluv":[307.715012949244738,151.961230908585406,55.7422560614222],"hsluv":[307.715012949244738,52.5739577191036176,55.7422560614222]},"#bb66cc":{"lch":[56.5140206008290704,76.3075420390205466,299.031845144425],"luv":[56.5140206008290704,37.0317190732607671,-66.7195080506142801],"rgb":[0.733333333333333282,0.4,0.8],"xyz":[0.361421460177830611,0.24428229370030477,0.599400631959954411],"hpluv":[299.031845144425,171.336773989457299,56.5140206008290704],"hsluv":[299.031845144425,57.7422914315118732,56.5140206008290704]},"#bb66dd":{"lch":[57.3558903641351208,87.0819801731049523,292.529347086481266],"luv":[57.3558903641351208,33.3660351201831276,-80.4361794917420809],"rgb":[0.733333333333333282,0.4,0.866666666666666696],"xyz":[0.38293978572846421,0.252889623920558304,0.712730479859960409],"hpluv":[292.529347086481266,192.659130793538424,57.3558903641351208],"hsluv":[292.529347086481266,71.4699790991907,57.3558903641351208]},"#bb66ee":{"lch":[58.2655263288606164,98.4965661150924916,287.652756970849339],"luv":[58.2655263288606164,29.8688319231142287,-93.8585447149780805],"rgb":[0.733333333333333282,0.4,0.933333333333333348],"xyz":[0.40675196599463892,0.262414496027028321,0.838141295928483632],"hpluv":[287.652756970849339,214.510592558062115,58.2655263288606164],"hsluv":[287.652756970849339,85.5420625539119186,58.2655263288606164]},"#bb66ff":{"lch":[59.2402283004695533,110.175409569553764,283.948158265715847],"luv":[59.2402283004695533,26.5571064878979755,-106.926801919861816],"rgb":[0.733333333333333282,0.4,1],"xyz":[0.432923014404470341,0.272882915390961045,0.975975484220265477],"hpluv":[283.948158265715847,235.997431668916079,59.2402283004695533],"hsluv":[283.948158265715847,99.9999999999988205,59.2402283004695533]},"#997700":{"lch":[51.799451349173637,61.2288227532233265,61.7368019650066202],"luv":[51.799451349173637,28.9932293289078338,53.9292257391759406],"rgb":[0.6,0.466666666666666674,0],"xyz":[0.197331129475883132,0.19966620830666032,0.028146226367465537],"hpluv":[61.7368019650066202,149.992683828924328,51.799451349173637],"hsluv":[61.7368019650066202,100.000000000002373,51.799451349173637]},"#997711":{"lch":[51.8452237949875752,59.5195003520895298,61.1595916745536812],"luv":[51.8452237949875752,28.7105152364728049,52.1371003894409952],"rgb":[0.6,0.466666666666666674,0.0666666666666666657],"xyz":[0.198342794975520265,0.200070874506515173,0.0334743313322211702],"hpluv":[61.1595916745536812,145.676617799321178,51.8452237949875752],"hsluv":[61.1595916745536812,96.7355174862457687,51.8452237949875752]},"#997722":{"lch":[51.9299107218419778,56.4237897442973448,60.0184197539949],"luv":[51.9299107218419778,28.1961842142201746,48.8735024820856836],"rgb":[0.6,0.466666666666666674,0.133333333333333331],"xyz":[0.200218153113997266,0.200821017761906,0.0433512175282003628],"hpluv":[60.0184197539949,137.874516690543771,51.9299107218419778],"hsluv":[60.0184197539949,90.8032063934702762,51.9299107218419778]},"#997733":{"lch":[52.0688882655341843,51.532107019520943,57.9108306747127841],"luv":[52.0688882655341843,27.375836028403171,43.6591531710973797],"rgb":[0.6,0.466666666666666674,0.2],"xyz":[0.203305903846455027,0.2020561180548891,0.0596133713858115061],"hpluv":[57.9108306747127841,125.585333003110208,52.0688882655341843],"hsluv":[57.9108306747127841,81.359583819486275,52.0688882655341843]},"#997744":{"lch":[52.2685439893789265,44.9234500117750244,54.2507061045172563],"luv":[52.2685439893789265,26.2460613351246792,36.4590266649196622],"rgb":[0.6,0.466666666666666674,0.266666666666666663],"xyz":[0.207763899090673887,0.203839316152576694,0.0830921463386981446],"hpluv":[54.2507061045172563,109.061640425204757,52.2685439893789265],"hsluv":[54.2507061045172563,68.3925961892813632,52.2685439893789265]},"#997755":{"lch":[52.5337646967731615,36.9638675487782962,47.8040559904272229],"luv":[52.5337646967731615,24.8274523779219614,27.3847605902560787],"rgb":[0.6,0.466666666666666674,0.333333333333333315],"xyz":[0.213726313130035872,0.206224281768321527,0.11449419361267206],"hpluv":[47.8040559904272229,89.2849392346346,52.5337646967731615],"hsluv":[47.8040559904272229,52.1784042692219217,52.5337646967731615]},"#997766":{"lch":[52.8682223623880958,28.5307109293219519,35.7342712802299047],"luv":[52.8682223623880958,23.1593577603421643,16.6627012894371447],"rgb":[0.6,0.466666666666666674,0.4],"xyz":[0.221311308903544057,0.209258280077724818,0.154441838019816],"hpluv":[35.7342712802299047,68.4789688439394695,52.8682223623880958],"hsluv":[35.7342712802299047,33.2180784313787072,52.8682223623880958]},"#997777":{"lch":[53.2745272921510349,21.7835186536615062,12.1770506300626185],"luv":[53.2745272921510349,21.2933995119794766,4.59486911213486],"rgb":[0.6,0.466666666666666674,0.466666666666666674],"xyz":[0.230625321923745963,0.212983885285805641,0.203495639926213917],"hpluv":[12.1770506300626185,51.8857087556556777,53.2745272921510349],"hsluv":[12.1770506300626185,12.1864056638809046,53.2745272921510349]},"#997788":{"lch":[53.7543298043441524,21.0694932264164443,336.259644884191403],"luv":[53.7543298043441524,19.28657717102978,-8.48242216845644492],"rgb":[0.6,0.466666666666666674,0.533333333333333326],"xyz":[0.241765739025689819,0.217440052126583239,0.262168503329786085],"hpluv":[336.259644884191403,49.7370433553737143,53.7543298043441524],"hsluv":[336.259644884191403,17.3594920402921318,53.7543298043441524]},"#997799":{"lch":[54.308403390094881,28.1087123643927,307.715012949247921],"luv":[54.308403390094881,17.1950646022419384,-22.235769923906151],"rgb":[0.6,0.466666666666666674,0.6],"xyz":[0.254822703134762518,0.222662837770212396,0.330935180970904],"hpluv":[307.715012949247921,65.67699031054849,54.308403390094881],"hsluv":[307.715012949247921,22.7222383700086681,54.308403390094881]},"#9977aa":{"lch":[54.9367240193748785,39.361724048309469,292.510155009375],"luv":[54.9367240193748785,15.0695247856183894,-36.3628208860492137],"rgb":[0.6,0.466666666666666674,0.66666666666666663],"xyz":[0.269880396100015074,0.228685914956313491,0.41023903058790262],"hpluv":[292.510155009375,90.9181689788077847,54.9367240193748785],"hsluv":[292.510155009375,30.8964586946041671,54.9367240193748785]},"#9977bb":{"lch":[55.6385517902762388,52.2405182414828104,284.355371582691191],"luv":[55.6385517902762388,12.9522722169503091,-50.6093903397058824],"rgb":[0.6,0.466666666666666674,0.733333333333333282],"xyz":[0.287017988207351693,0.235540951799248249,0.500497015686544366],"hpluv":[284.355371582691191,119.143673365147691,55.6385517902762388],"hsluv":[284.355371582691191,44.025050152294007,55.6385517902762388]},"#9977cc":{"lch":[56.4125166695819615,65.6830300518217172,279.531250686135081],"luv":[56.4125166695819615,10.8761592408186605,-64.7763042860340192],"rgb":[0.6,0.466666666666666674,0.8],"xyz":[0.306310363651073447,0.243257901976737051,0.602103526356814522],"hpluv":[279.531250686135081,147.746441920881637,56.4125166695819615],"hsluv":[279.531250686135081,57.5215558896316352,56.4125166695819615]},"#9977dd":{"lch":[57.256707620000924,79.2159287347205,276.425234899334782],"luv":[57.256707620000924,8.86478593594131858,-78.718351962006011],"rgb":[0.6,0.466666666666666674,0.866666666666666696],"xyz":[0.327828689201707,0.251865232196990585,0.71543337425682052],"hpluv":[276.425234899334782,175.559960004438778,57.256707620000924],"hsluv":[276.425234899334782,71.3413917340773764,57.256707620000924]},"#9977ee":{"lch":[58.1687631275758434,92.5981917117116211,274.294200356840065],"luv":[58.1687631275758434,6.93354781471817905,-92.3382424728774822],"rgb":[0.6,0.466666666666666674,0.933333333333333348],"xyz":[0.351640869467881756,0.261390104303460602,0.840844190325343743],"hpluv":[274.294200356840065,202.000294664132923,58.1687631275758434],"hsluv":[274.294200356840065,85.4864748016987903,58.1687631275758434]},"#9977ff":{"lch":[59.1459606243173,105.700835267318482,272.760722153075335],"luv":[59.1459606243173,5.0910859147335179,-105.578157875659116],"rgb":[0.6,0.466666666666666674,1],"xyz":[0.377811917877713122,0.271858523667393326,0.978678378617125588],"hpluv":[272.760722153075335,226.773684284234889,59.1459606243173],"hsluv":[272.760722153075335,99.9999999999988,59.1459606243173]},"#bb7700":{"lch":[55.8465021194210323,78.9426527823167703,44.2288975260652037],"luv":[55.8465021194210323,56.5670601566064,55.0645996403160751],"rgb":[0.733333333333333282,0.466666666666666674,0],"xyz":[0.270895964056058,0.237598076137063796,0.0315945779884111572],"hpluv":[44.2288975260652037,179.372171604304526,55.8465021194210323],"hsluv":[44.2288975260652037,100.000000000002402,55.8465021194210323]},"#bb7711":{"lch":[55.8872675460691113,77.5581898683241775,43.5811171927028127],"luv":[55.8872675460691113,56.1830827877517081,53.4671303149482782],"rgb":[0.733333333333333282,0.466666666666666674,0.0666666666666666657],"xyz":[0.271907629555695085,0.238002742336918649,0.0369226829531667869],"hpluv":[43.5811171927028127,176.097874689063588,55.8872675460691113],"hsluv":[43.5811171927028127,97.2747266570755613,55.8872675460691113]},"#bb7722":{"lch":[55.9627137258116534,75.0570685818031365,42.3362918908129799],"luv":[55.9627137258116534,55.4825342436315907,50.549499878809371],"rgb":[0.733333333333333282,0.466666666666666674,0.133333333333333331],"xyz":[0.273782987694172142,0.238752885592309477,0.0467995691491459864],"hpluv":[42.3362918908129799,170.189263625481374,55.9627137258116534],"hsluv":[42.3362918908129799,92.3060252972229875,55.9627137258116534]},"#bb7733":{"lch":[56.086591241629975,71.12386069085467,40.1553843778465094],"luv":[56.086591241629975,54.3598535070873652,45.8651271257379562],"rgb":[0.733333333333333282,0.466666666666666674,0.2],"xyz":[0.276870738426629848,0.239987985885292576,0.0630617230067571366],"hpluv":[40.1553843778465094,160.914656808849855,56.086591241629975],"hsluv":[40.1553843778465094,84.3528141134219425,56.086591241629975]},"#bb7744":{"lch":[56.2646940492590346,65.8532423012147632,36.6949041745596887],"luv":[56.2646940492590346,52.8030258036740747,39.3508575199960617],"rgb":[0.733333333333333282,0.466666666666666674,0.266666666666666663],"xyz":[0.281328733670848763,0.24177118398298017,0.0865404979596437751],"hpluv":[36.6949041745596887,148.518490760970963,56.2646940492590346],"hsluv":[36.6949041745596887,73.3442464951488517,56.2646940492590346]},"#bb7755":{"lch":[56.5015366957073866,59.5720019456390375,31.4313823601585],"luv":[56.5015366957073866,50.8307220514796256,31.0654327434279267],"rgb":[0.733333333333333282,0.466666666666666674,0.333333333333333315],"xyz":[0.287291147710210748,0.244156149598725,0.117942545233617677],"hpluv":[31.4313823601585,133.789263155984059,56.5015366957073866],"hsluv":[31.4313823601585,59.433527841274838,56.5015366957073866]},"#bb7766":{"lch":[56.8006139195957758,52.9060784141758376,23.584548946691168],"luv":[56.8006139195957758,48.4868685528452588,21.1678225404983067],"rgb":[0.733333333333333282,0.466666666666666674,0.4],"xyz":[0.294876143483718933,0.247190147908128294,0.157890189640761625],"hpluv":[23.584548946691168,118.193030459121616,56.8006139195957758],"hsluv":[23.584548946691168,42.9582981176577476,56.8006139195957758]},"#bb7777":{"lch":[57.1645375630264851,46.8887603377642677,12.1770506300621175],"luv":[57.1645375630264851,45.8337848153679062,9.89040016939892652],"rgb":[0.733333333333333282,0.466666666666666674,0.466666666666666674],"xyz":[0.304190156503920839,0.250915753116209117,0.206943991547159534],"hpluv":[12.1770506300621175,104.083378979503351,57.1645375630264851],"hsluv":[12.1770506300621175,30.9338815185941769,57.1645375630264851]},"#bb7788":{"lch":[57.5951231639082408,43.0166042307866761,356.679907444569722],"luv":[57.5951231639082408,42.9444038116514264,-2.49126891562360298],"rgb":[0.733333333333333282,0.466666666666666674,0.533333333333333326],"xyz":[0.315330573605864639,0.255371919956986715,0.265616854950731729],"hpluv":[356.679907444569722,94.7741152880685149,57.5951231639082408],"hsluv":[356.679907444569722,32.9204937798227419,57.5951231639082408]},"#bb7799":{"lch":[58.0934559183715322,42.8683503206465062,338.533521874652],"luv":[58.0934559183715322,39.8946515879682408,-15.6879646190414519],"rgb":[0.733333333333333282,0.466666666666666674,0.6],"xyz":[0.328387537714937339,0.260594705600615872,0.334383532591849608],"hpluv":[338.533521874652,93.6373004736019823,58.0934559183715322],"hsluv":[338.533521874652,34.9811369830312131,58.0934559183715322]},"#bb77aa":{"lch":[58.6599497668646706,47.0820583870944276,321.324781752589786],"luv":[58.6599497668646706,36.7569990603765,-29.4218157502430451],"rgb":[0.733333333333333282,0.466666666666666674,0.66666666666666663],"xyz":[0.343445230680189895,0.266617782786717,0.413687382208848209],"hpluv":[321.324781752589786,101.848135129910219,58.6599497668646706],"hsluv":[321.324781752589786,37.0556810629478051,58.6599497668646706]},"#bb77bb":{"lch":[59.2944060970233693,54.9189596898792303,307.71501294924542],"luv":[59.2944060970233693,33.5958135510894706,-43.4443718479046765],"rgb":[0.733333333333333282,0.466666666666666674,0.733333333333333282],"xyz":[0.360582822787526569,0.273472819629651753,0.50394536730749],"hpluv":[307.71501294924542,117.529775077760561,59.2944060970233693],"hsluv":[307.71501294924542,40.6617226560308467,59.2944060970233693]},"#bb77cc":{"lch":[59.9960747587738155,65.1135012197087519,297.896140559284788],"luv":[59.9960747587738155,30.4646722292654815,-57.5471266620014177],"rgb":[0.733333333333333282,0.466666666666666674,0.8],"xyz":[0.379875198231248268,0.281189769807140555,0.605551877977760111],"hpluv":[297.896140559284788,137.716994859863917,59.9960747587738155],"hsluv":[297.896140559284788,53.5682479917909,59.9960747587738155]},"#bb77dd":{"lch":[60.7637179337253599,76.6332290650186394,290.953982706702106],"luv":[60.7637179337253599,27.4054240934965065,-71.5653165100750357],"rgb":[0.733333333333333282,0.466666666666666674,0.866666666666666696],"xyz":[0.401393523781881867,0.289797100027394061,0.718881725877766109],"hpluv":[290.953982706702106,160.033945707839,60.7637179337253599],"hsluv":[290.953982706702106,68.5485010485900119,60.7637179337253599]},"#bb77ee":{"lch":[61.5956761624293563,88.8082274030350902,285.979672103614405],"luv":[61.5956761624293563,24.4485758512518743,-85.3766267389077456],"rgb":[0.733333333333333282,0.466666666666666674,0.933333333333333348],"xyz":[0.425205704048056576,0.299321972133864078,0.844292541946289332],"hpluv":[285.979672103614405,182.954165183101395,61.5956761624293563],"hsluv":[285.979672103614405,84.0163684558434909,61.5956761624293563]},"#bb77ff":{"lch":[62.4899351736807773,101.23109143545085,282.328516880108566],"luv":[62.4899351736807773,21.6145233767131266,-98.8966442929694693],"rgb":[0.733333333333333282,0.466666666666666674,1],"xyz":[0.451376752457888,0.309790391497796802,0.982126730238071177],"hpluv":[282.328516880108566,205.562159598045383,62.4899351736807773],"hsluv":[282.328516880108566,99.9999999999986784,62.4899351736807773]},"#998800":{"lch":[56.4673516485332527,62.834492950420568,74.7562721675545561],"luv":[56.4673516485332527,16.5207966112614884,60.6237311922136897],"rgb":[0.6,0.533333333333333326,0],"xyz":[0.219403499200853586,0.243810947756601892,0.0355036829424554834],"hpluv":[74.7562721675545561,141.201731332299261,56.4673516485332527],"hsluv":[74.7562721675545561,100.000000000002331,56.4673516485332527]},"#998811":{"lch":[56.5074221469723881,61.2259080808398366,74.51872844438833],"luv":[56.5074221469723881,16.3426261455871646,59.0044946676862878],"rgb":[0.6,0.533333333333333326,0.0666666666666666657],"xyz":[0.220415164700490718,0.244215613956456745,0.0408317879072111131],"hpluv":[74.51872844438833,137.489352382480689,56.5074221469723881],"hsluv":[74.51872844438833,97.3110722480099781,56.5074221469723881]},"#998822":{"lch":[56.5815852437789744,58.2905156727598666,74.0508275651119],"luv":[56.5815852437789744,16.0173304476746452,56.0466711119068961],"rgb":[0.6,0.533333333333333326,0.133333333333333331],"xyz":[0.222290522838967719,0.244965757211847573,0.0507086741031903127],"hpluv":[74.0508275651119,130.726042229432494,56.5815852437789744],"hsluv":[74.0508275651119,92.4075523300517574,56.5815852437789744]},"#998833":{"lch":[56.7033645714083,53.5858970619529273,73.1917859227149],"luv":[56.7033645714083,15.4953822971072128,51.2966031175623911],"rgb":[0.6,0.533333333333333326,0.2],"xyz":[0.22537827357142548,0.246200857504830672,0.066970827960801449],"hpluv":[73.1917859227149,119.917068416956084,56.7033645714083],"hsluv":[73.1917859227149,84.5557602276611533,56.7033645714083]},"#998844":{"lch":[56.8784692361674189,47.0662938677721456,71.7105236832421156],"luv":[56.8784692361674189,14.7702533586865563,44.6886521856241927],"rgb":[0.6,0.533333333333333326,0.266666666666666663],"xyz":[0.22983626881564434,0.247984055602518266,0.0904496029136880875],"hpluv":[71.7105236832421156,105.00293267331034,56.8784692361674189],"hsluv":[71.7105236832421156,73.6816499137771075,56.8784692361674189]},"#998855":{"lch":[57.1113583918905761,38.8337969655052433,69.1066660847648393],"luv":[57.1113583918905761,13.8492700909341142,36.2803184206870242],"rgb":[0.6,0.533333333333333326,0.333333333333333315],"xyz":[0.235798682855006325,0.250369021218263099,0.121851650187662],"hpluv":[69.1066660847648393,86.2832891510872599,57.1113583918905761],"hsluv":[69.1066660847648393,59.9309888570698774,57.1113583918905761]},"#998866":{"lch":[57.4054971647218224,29.1657433305745144,64.0747883902216],"luv":[57.4054971647218224,12.7511922431808031,26.2306629806110223],"rgb":[0.6,0.533333333333333326,0.4],"xyz":[0.24338367862851451,0.253403019527666418,0.161799294594805965],"hpluv":[64.0747883902216,64.4701815948561574,57.4054971647218224],"hsluv":[64.0747883902216,43.6310875702010321,57.4054971647218224]},"#998877":{"lch":[57.7634914296009612,18.7238256654584347,52.0945218145914097],"luv":[57.7634914296009612,11.5031815844705712,14.773573060880608],"rgb":[0.6,0.533333333333333326,0.466666666666666674],"xyz":[0.252697691648716416,0.257128624735747213,0.210853096501203874],"hpluv":[52.0945218145914097,41.1320618043462858,57.7634914296009612],"hsluv":[52.0945218145914097,25.2418236256697028,57.7634914296009612]},"#998888":{"lch":[58.1871725604667489,10.3706980586515272,12.1770506300640946],"luv":[58.1871725604667489,10.1373621264743505,2.18752539195365081],"rgb":[0.6,0.533333333333333326,0.533333333333333326],"xyz":[0.263838108750660272,0.261584791576524811,0.269525959904776],"hpluv":[12.1770506300640946,22.6162221883482317,58.1871725604667489],"hsluv":[12.1770506300640946,7.14421708061451799,58.1871725604667489]},"#998899":{"lch":[58.6776613659523605,14.2013195506443459,307.715012949254117],"luv":[58.6776613659523605,8.6874348403017283,-11.2341422847952668],"rgb":[0.6,0.533333333333333326,0.6],"xyz":[0.276895072859732971,0.266807577220153969,0.338292637545893948],"hpluv":[307.715012949254117,30.7110899398720818,58.6776613659523605],"hsluv":[307.715012949254117,10.6251017733449729,58.6776613659523605]},"#9988aa":{"lch":[59.2354248002074399,26.2127450059066938,285.910383521223935],"luv":[59.2354248002074399,7.18579172527609789,-25.2085778659891844],"rgb":[0.6,0.533333333333333326,0.66666666666666663],"xyz":[0.291952765824985527,0.272830654406255091,0.417596487162892549],"hpluv":[285.910383521223935,56.1526584479988173,59.2354248002074399],"hsluv":[285.910383521223935,23.5088603674401817,59.2354248002074399]},"#9988bb":{"lch":[59.8603319378123189,39.8857557696632696,278.160160819701673],"luv":[59.8603319378123189,5.66141142610705117,-39.4819190767314581],"rgb":[0.6,0.533333333333333326,0.733333333333333282],"xyz":[0.309090357932322146,0.279685691249189849,0.507854472261534351],"hpluv":[278.160160819701673,84.5508603994872,59.8603319378123189],"hsluv":[278.160160819701673,37.7262541103550291,59.8603319378123189]},"#9988cc":{"lch":[60.55171199345871,53.9990869041691823,274.395593429514747],"luv":[60.55171199345871,4.13861667015410095,-53.8402566723222264],"rgb":[0.6,0.533333333333333326,0.8],"xyz":[0.3283827333760439,0.287402641426678651,0.609460982931804507],"hpluv":[274.395593429514747,113.161661700826286,60.55171199345871],"hsluv":[274.395593429514747,52.5240219153236723,60.55171199345871]},"#9988dd":{"lch":[61.3084150605589855,68.1648195931338563,272.216747448240312],"luv":[61.3084150605589855,2.63660773112319324,-68.1138086575451],"rgb":[0.6,0.533333333333333326,0.866666666666666696],"xyz":[0.349901058926677444,0.296009971646932157,0.722790830831810505],"hpluv":[272.216747448240312,141.084572716849891,61.3084150605589855],"hsluv":[272.216747448240312,67.8395486149695,61.3084150605589855]},"#9988ee":{"lch":[62.128875020953032,82.18421866163294,270.815422264053723],"luv":[62.128875020953032,1.1695901512833331,-82.1758958326656597],"rgb":[0.6,0.533333333333333326,0.933333333333333348],"xyz":[0.373713239192852154,0.305534843753402174,0.848201646900333728],"hpluv":[270.815422264053723,167.854994169255662,62.128875020953032],"hsluv":[270.815422264053723,83.6558877567472905,62.128875020953032]},"#9988ff":{"lch":[63.0111734122257303,95.9388777898474387,269.8490772999765],"luv":[63.0111734122257303,-0.252712116882344406,-95.9385449554102],"rgb":[0.6,0.533333333333333326,1],"xyz":[0.399884287602683575,0.316003263117334898,0.986035835192115462],"hpluv":[269.8490772999765,193.204124490752207,63.0111734122257303],"hsluv":[269.8490772999765,99.9999999999985363,63.0111734122257303]},"#bb8800":{"lch":[60.0458653136574,74.8864062555341832,55.056379834278971],"luv":[60.0458653136574,42.8926945435799,61.3855894869476728],"rgb":[0.733333333333333282,0.533333333333333326,0],"xyz":[0.292968333781028434,0.281742815587005313,0.038952034563401107],"hpluv":[55.056379834278971,158.255644288368103,60.0458653136574],"hsluv":[55.056379834278971,100.000000000002288,60.0458653136574]},"#bb8811":{"lch":[60.0822560315187957,73.5298298886522161,54.5759299869630823],"luv":[60.0822560315187957,42.619621560372849,59.9183089005750773],"rgb":[0.733333333333333282,0.533333333333333326,0.0666666666666666657],"xyz":[0.293979999280665538,0.282147481786860166,0.0442801395281567367],"hpluv":[54.5759299869630823,155.294707870281485,60.0822560315187957],"hsluv":[54.5759299869630823,97.6878818876268866,60.0822560315187957]},"#bb8822":{"lch":[60.1496227929862499,71.0610449842002367,53.6488709316330343],"luv":[60.1496227929862499,42.1201645307819774,57.2325419158225586],"rgb":[0.733333333333333282,0.533333333333333326,0.133333333333333331],"xyz":[0.295855357419142595,0.282897625042250966,0.0541570257241359362],"hpluv":[53.6488709316330343,149.912555699661567,60.1496227929862499],"hsluv":[53.6488709316330343,93.46183514856709,60.1496227929862499]},"#bb8833":{"lch":[60.2602822329103844,67.1261991777524,52.0115270519145412],"luv":[60.2602822329103844,41.3163720666953154,52.9044801061090197],"rgb":[0.733333333333333282,0.533333333333333326,0.2],"xyz":[0.298943108151600301,0.284132725335234093,0.0704191795817470795],"hpluv":[52.0115270519145412,141.351435183858257,60.2602822329103844],"hsluv":[52.0115270519145412,86.668700859176,60.2602822329103844]},"#bb8844":{"lch":[60.4194844691316746,61.7320119628667285,49.374045706205429],"luv":[60.4194844691316746,40.1948297943626258,46.8531424643613406],"rgb":[0.733333333333333282,0.533333333333333326,0.266666666666666663],"xyz":[0.303401103395819216,0.285915923432921659,0.093897954534633718],"hpluv":[49.374045706205429,129.650066203053939,60.4194844691316746],"hsluv":[49.374045706205429,77.207197386412,60.4194844691316746]},"#bb8855":{"lch":[60.6313805732006585,55.0590005000961682,45.2500033552910708],"luv":[60.6313805732006585,38.7623447760430935,39.1020992215604082],"rgb":[0.733333333333333282,0.533333333333333326,0.333333333333333315],"xyz":[0.309363517435181201,0.28830088904866652,0.125300001808607619],"hpluv":[45.2500033552910708,115.231228654446355,60.6313805732006585],"hsluv":[45.2500033552910708,65.1528926573884775,60.6313805732006585]},"#bb8866":{"lch":[60.8992588402534949,47.519038379270981,38.7816256818529581],"luv":[60.8992588402534949,37.0429375720225096,29.7637327048519147],"rgb":[0.733333333333333282,0.533333333333333326,0.4],"xyz":[0.316948513208689386,0.291334887358069838,0.165247646215751581],"hpluv":[38.7816256818529581,99.0136254476035305,60.8992588402534949],"hsluv":[38.7816256818529581,50.7321114426118,60.8992588402534949]},"#bb8877":{"lch":[61.2256685857267087,39.8992767652027354,28.4701407483744688],"luv":[61.2256685857267087,35.0740840991728362,19.0200134329710231],"rgb":[0.733333333333333282,0.533333333333333326,0.466666666666666674],"xyz":[0.326262526228891292,0.295060492566150634,0.21430144812214949],"hpluv":[28.4701407483744688,82.6933933486175761,61.2256685857267087],"hsluv":[28.4701407483744688,34.2887258466009897,61.2256685857267087]},"#bb8888":{"lch":[61.6124959728340684,33.6595928281588499,12.1770506300623627],"luv":[61.6124959728340684,32.9022674846918903,7.09992843085263114],"rgb":[0.733333333333333282,0.533333333333333326,0.533333333333333326],"xyz":[0.337402943330835092,0.299516659406928232,0.272974311525721658],"hpluv":[12.1770506300623627,69.3233245158679,61.6124959728340684],"hsluv":[12.1770506300623627,26.8235367690150284,61.6124959728340684]},"#bb8899":{"lch":[62.0610184830546388,31.1131530731089718,349.361203223606594],"luv":[62.0610184830546388,30.5783355372127765,-5.74401339869088723],"rgb":[0.733333333333333282,0.533333333333333326,0.6],"xyz":[0.350459907439907847,0.304739445050557389,0.341740989166839593],"hpluv":[349.361203223606594,63.6157209963685091,62.0610184830546388],"hsluv":[349.361203223606594,28.7433747177793393,62.0610184830546388]},"#bb88aa":{"lch":[62.5719506337331097,34.1093853871598185,325.627133749050586],"luv":[62.5719506337331097,28.1532372220531357,-19.2573467904743723],"rgb":[0.733333333333333282,0.533333333333333326,0.66666666666666663],"xyz":[0.365517600405160348,0.310762522236658512,0.421044838783838193],"hpluv":[325.627133749050586,69.1725086761469328,62.5719506337331097],"hsluv":[325.627133749050586,30.7007491098828176,62.5719506337331097]},"#bb88bb":{"lch":[63.1454872588298,41.9701566603395477,307.715012949246614],"luv":[63.1454872588298,25.674586077978244,-33.2010493782640808],"rgb":[0.733333333333333282,0.533333333333333326,0.733333333333333282],"xyz":[0.382655192512497,0.31761755907959327,0.51130282388247994],"hpluv":[307.715012949246614,84.3407770596407,63.1454872588298],"hsluv":[307.715012949246614,32.6446535119142354,63.1454872588298]},"#bb88cc":{"lch":[63.7813474201422,52.7335158558763055,296.081540752202443],"luv":[63.7813474201422,23.1842810338905281,-47.3636232510092228],"rgb":[0.733333333333333282,0.533333333333333326,0.8],"xyz":[0.401947567956218776,0.325334509257082072,0.612909334552750096],"hpluv":[296.081540752202443,104.913738848088499,63.7813474201422],"hsluv":[296.081540752202443,48.441096457031712,63.7813474201422]},"#bb88dd":{"lch":[64.4788201663492089,64.9599578897110916,288.597779393076337],"luv":[64.4788201663492089,20.7171971389296665,-61.56779898404492],"rgb":[0.733333333333333282,0.533333333333333326,0.866666666666666696],"xyz":[0.423465893506852264,0.333941839477335578,0.726239182452756094],"hpluv":[288.597779393076337,127.840358269428478,64.4788201663492089],"hsluv":[288.597779393076337,64.9415793589177,64.4788201663492089]},"#bb88ee":{"lch":[65.2368122498474463,77.8541115668441392,283.595470556329246],"luv":[65.2368122498474463,18.300798164755431,-75.6726071600252084],"rgb":[0.733333333333333282,0.533333333333333326,0.933333333333333348],"xyz":[0.44727807377302703,0.343466711583805595,0.851649998521279317],"hpluv":[283.595470556329246,151.435657753316406,65.2368122498474463],"hsluv":[283.595470556329246,82.1213401763518789,65.2368122498474463]},"#bb88ff":{"lch":[66.0538972531437452,90.9819525935223652,280.100148709787334],"luv":[66.0538972531437452,15.9554396417090967,-89.5719802369565201],"rgb":[0.733333333333333282,0.533333333333333326,1],"xyz":[0.473449122182858395,0.353935130947738319,0.989484186813061162],"hpluv":[280.100148709787334,174.781769995450787,66.0538972531437452],"hsluv":[280.100148709787334,99.99999999999838,66.0538972531437452]},"#999900":{"lch":[61.2683639221826866,67.5422828804358772,85.8743202181747449],"luv":[61.2683639221826866,4.85929488236129092,67.3672563635114869],"rgb":[0.6,0.6,0],"xyz":[0.245273099653321058,0.295550148661537559,0.0441268830932777384],"hpluv":[85.8743202181747449,139.887458074797593,61.2683639221826866],"hsluv":[85.8743202181747449,100.000000000002359,61.2683639221826866]},"#999911":{"lch":[61.3036130280217861,66.0751339072958785,85.8743202181746881],"luv":[61.3036130280217861,4.75374160235953358,65.9039093047224185],"rgb":[0.6,0.6,0.0666666666666666657],"xyz":[0.24628476515295819,0.295954814861392412,0.0494549880580333681],"hpluv":[85.8743202181746881,136.770144995815713,61.3036130280217861],"hsluv":[85.8743202181746881,97.7715564197957718,61.3036130280217861]},"#999922":{"lch":[61.3688705786650104,63.38848415762304,85.8743202181745744],"luv":[61.3688705786650104,4.56045196477970372,63.2242216375825663],"rgb":[0.6,0.6,0.133333333333333331],"xyz":[0.248160123291435192,0.296704958116783213,0.0593318742540125676],"hpluv":[85.8743202181745744,131.069475710796667,61.3688705786650104],"hsluv":[85.8743202181745744,93.6963738669960691,61.3688705786650104]},"#999933":{"lch":[61.4760769955270945,59.0559618954583243,85.8743202181743754],"luv":[61.4760769955270945,4.24875087387181871,58.9029265097210484],"rgb":[0.6,0.6,0.2],"xyz":[0.251247874023892925,0.29794005840976634,0.0755940281116237178],"hpluv":[85.8743202181743754,121.898097720990123,61.4760769955270945],"hsluv":[85.8743202181743754,87.1401192062652683,61.4760769955270945]},"#999944":{"lch":[61.6303367515695,52.9921690524208,85.8743202181739775],"luv":[61.6303367515695,3.81249440942850049,52.8548471500809569],"rgb":[0.6,0.6,0.266666666666666663],"xyz":[0.255705869268111841,0.299723256507453906,0.0990728030645103563],"hpluv":[85.8743202181739775,109.10797160418339,61.6303367515695],"hsluv":[85.8743202181739775,77.9969649215058,61.6303367515695]},"#999955":{"lch":[61.8357003743425935,45.2147461889200173,85.8743202181734517],"luv":[61.8357003743425935,3.25295171251598125,45.0975784059909],"rgb":[0.6,0.6,0.333333333333333315],"xyz":[0.261668283307473826,0.302108222123198766,0.130474850338484272],"hpluv":[85.8743202181734517,92.7855058259100218,61.8357003743425935],"hsluv":[85.8743202181734517,66.3286810003367577,61.8357003743425935]},"#999966":{"lch":[62.0953945325949377,35.8293841981041083,85.874320218172457],"luv":[62.0953945325949377,2.57772666020637553,35.7365372872164784],"rgb":[0.6,0.6,0.4],"xyz":[0.269253279080982,0.305142220432602085,0.170422494745628206],"hpluv":[85.874320218172457,73.2182390722606,62.0953945325949377],"hsluv":[85.874320218172457,52.3408174542086542,62.0953945325949377]},"#999977":{"lch":[62.4119425079225749,25.0116267171883422,85.8743202181703],"luv":[62.4119425079225749,1.79944864939855109,24.9468125338318],"rgb":[0.6,0.6,0.466666666666666674],"xyz":[0.278567292101183916,0.30886782564068288,0.219476296652026115],"hpluv":[85.8743202181703,50.8526471570801775,62.4119425079225749],"hsluv":[85.8743202181703,36.3525421484824918,62.4119425079225749]},"#999988":{"lch":[62.7872374999600567,12.9853368609797517,85.8743202181639589],"luv":[62.7872374999600567,0.934223397011331502,12.9516871502363],"rgb":[0.6,0.6,0.533333333333333326],"xyz":[0.289707709203127717,0.313323992481460478,0.27814916005559831],"hpluv":[85.8743202181639589,26.2434647477884546,62.7872374999600567],"hsluv":[85.8743202181639589,18.7604129126121961,62.7872374999600567]},"#999999":{"lch":[63.2225945523589843,3.33307052034688283e-12,0],"luv":[63.2225945523589843,3.14807442966336163e-12,1.09498241031769098e-12],"rgb":[0.6,0.6,0.6],"xyz":[0.302764673312200472,0.318546778125089636,0.346915837696716189],"hpluv":[0,6.68977504875838914e-12,63.2225945523589843],"hsluv":[0,3.10313074237261963e-12,63.2225945523589843]},"#9999aa":{"lch":[63.7187933641432238,13.6904464527836414,265.874320218190064],"luv":[63.7187933641432238,-0.984952144759020598,-13.6549695477167123],"rgb":[0.6,0.6,0.66666666666666663],"xyz":[0.317822366277453,0.324569855311190758,0.42621968731371479],"hpluv":[265.874320218190064,27.2639887848552753,63.7187933641432238],"hsluv":[265.874320218190064,14.5770868731616492,63.7187933641432238]},"#9999bb":{"lch":[64.276118203606174,27.8450519356751158,265.874320218183641],"luv":[64.276118203606174,-2.00329797275791854,-27.7728953213882335],"rgb":[0.6,0.6,0.733333333333333282],"xyz":[0.334959958384789647,0.331424892154125517,0.516477672412356537],"hpluv":[265.874320218183641,54.9715165011475904,64.276118203606174],"hsluv":[265.874320218183641,30.0955931685464577,64.276118203606174]},"#9999cc":{"lch":[64.8943980299807635,42.2483295275786332,265.874320218181538],"luv":[64.8943980299807635,-3.03953438803302189,-42.138848804575062],"rgb":[0.6,0.6,0.8],"xyz":[0.354252333828511401,0.339141842331614318,0.618084183082626692],"hpluv":[265.874320218181538,82.6117192029769,64.8943980299807635],"hsluv":[265.874320218181538,46.4456834766813316,64.8943980299807635]},"#9999dd":{"lch":[65.5730481583578353,56.7175687031348,265.874320218180458],"luv":[65.5730481583578353,-4.08051637559571567,-56.570592941061804],"rgb":[0.6,0.6,0.866666666666666696],"xyz":[0.375770659379144889,0.347749172551867824,0.73141403098263269],"hpluv":[265.874320218180458,109.756831209262941,65.5730481583578353],"hsluv":[265.874320218180458,63.5568222493012627,65.5730481583578353]},"#9999ee":{"lch":[66.311113738117,71.1055788100052695,265.874320218179832],"luv":[66.311113738117,-5.11565437949467672,-70.9213185027987691],"rgb":[0.6,0.6,0.933333333333333348],"xyz":[0.399582839645319654,0.357274044658337842,0.856824847051155913],"hpluv":[265.874320218179832,136.068212717368169,66.311113738117],"hsluv":[265.874320218179832,81.4020980414818922,66.311113738117]},"#9999ff":{"lch":[67.1073146704137145,85.2999068143523829,265.874320218179378],"luv":[67.1073146704137145,-6.13685802391602486,-85.0788638624864149],"rgb":[0.6,0.6,1],"xyz":[0.425753888055151,0.367742464022270565,0.994659035342937758],"hpluv":[265.874320218179378,161.293929533565688,67.1073146704137145],"hsluv":[265.874320218179378,99.9999999999983,67.1073146704137145]},"#bb9900":{"lch":[64.4418646198176219,74.1135014806344117,66.2793330800256228],"luv":[64.4418646198176219,29.8142337654579457,67.8522112145111],"rgb":[0.733333333333333282,0.6,0],"xyz":[0.318837934233495934,0.333482016491941036,0.047575234714223362],"hpluv":[66.2793330800256228,145.938057142603384,64.4418646198176219],"hsluv":[66.2793330800256228,100.000000000002416,64.4418646198176219]},"#bb9911":{"lch":[64.4743890579801331,72.806990252212529,65.9899074816349],"luv":[64.4743890579801331,29.6249863695688624,66.5072778888794147],"rgb":[0.733333333333333282,0.6,0.0666666666666666657],"xyz":[0.319849599733133039,0.333886682691795889,0.0529033396789789917],"hpluv":[65.9899074816349,143.29306400111571,64.4743890579801331],"hsluv":[65.9899074816349,98.0367215419372542,64.4743890579801331]},"#bb9922":{"lch":[64.5346112536789,70.4161712525116599,65.4311312102869636],"luv":[64.5346112536789,29.2781077929992222,64.0408430450799671],"rgb":[0.733333333333333282,0.6,0.133333333333333331],"xyz":[0.321724957871610096,0.334636825947186689,0.0627802258749581843],"hpluv":[65.4311312102869636,138.458312961065701,64.5346112536789],"hsluv":[65.4311312102869636,94.4406497380354892,64.5346112536789]},"#bb9933":{"lch":[64.6335704733000398,66.566957174521292,64.4427367566729146],"luv":[64.6335704733000398,28.7178476591491503,60.0536844273559396],"rgb":[0.733333333333333282,0.6,0.2],"xyz":[0.324812708604067801,0.335871926240169816,0.0790423797325693345],"hpluv":[64.4427367566729146,130.689255588928205,64.6335704733000398],"hsluv":[64.4427367566729146,88.6394107340449153,64.6335704733000398]},"#bb9944":{"lch":[64.7760175449466828,61.1991201001527685,62.8442649593615386],"luv":[64.7760175449466828,27.9319304868930693,54.4530950480162872],"rgb":[0.733333333333333282,0.6,0.266666666666666663],"xyz":[0.329270703848286717,0.337655124337857382,0.102521154685455973],"hpluv":[62.8442649593615386,119.886494259466,64.7760175449466828],"hsluv":[62.8442649593615386,80.5164965868838607,64.7760175449466828]},"#bb9955":{"lch":[64.965753761967747,54.3684881208399204,60.3198292286154],"luv":[64.965753761967747,26.9209928274273445,47.235501963369849],"rgb":[0.733333333333333282,0.6,0.333333333333333315],"xyz":[0.335233117887648702,0.340040089953602243,0.133923201959429888],"hpluv":[60.3198292286154,106.194518749025775,64.965753761967747],"hsluv":[60.3198292286154,70.0945405394646883,64.965753761967747]},"#bb9966":{"lch":[65.2058459998609,46.2670609228556557,56.2614414361724258],"luv":[65.2058459998609,25.6969192719684436,38.4747874116176689],"rgb":[0.733333333333333282,0.6,0.4],"xyz":[0.342818113661156887,0.343074088263005561,0.17387084636657385],"hpluv":[56.2614414361724258,90.0377647384168,65.2058459998609],"hsluv":[56.2614414361724258,57.5177389460533064,65.2058459998609]},"#bb9977":{"lch":[65.4987393303808147,37.2952826673053153,49.3796729345645886],"luv":[65.4987393303808147,24.280853083902965,28.3086255892461871],"rgb":[0.733333333333333282,0.6,0.466666666666666674],"xyz":[0.352132126681358792,0.346799693471086357,0.222924648272971759],"hpluv":[49.3796729345645886,72.2537327682772172,65.4987393303808147],"hsluv":[49.3796729345645886,43.0302399575574199,65.4987393303808147]},"#bb9988":{"lch":[65.8463246780106601,28.3139420599436384,36.7022131699001193],"luv":[65.8463246780106601,22.7007755052872291,16.9220006628175241],"rgb":[0.733333333333333282,0.6,0.533333333333333326],"xyz":[0.363272543783302593,0.351255860311863954,0.281597511676543899],"hpluv":[36.7022131699001193,54.564242001153282,65.8463246780106601],"hsluv":[36.7022131699001193,26.9495650592517677,65.8463246780106601]},"#bb9999":{"lch":[66.2499853133799377,21.4719543680734333,12.1770506300627517],"luv":[66.2499853133799377,20.9888452793887552,4.52914983440691099],"rgb":[0.733333333333333282,0.6,0.6],"xyz":[0.376329507892375292,0.356478645955493112,0.350364189317661834],"hpluv":[12.1770506300627517,41.1268186121042731,66.2499853133799377],"hsluv":[12.1770506300627517,20.948078856310218,66.2499853133799377]},"#bb99aa":{"lch":[66.7106335886793715,21.0368039825091344,335.738246937474969],"luv":[66.7106335886793715,19.1787866223333445,-8.64414631375011489],"rgb":[0.733333333333333282,0.6,0.66666666666666663],"xyz":[0.391387200857627848,0.362501723141594234,0.429668038934660435],"hpluv":[335.738246937474969,40.0151105801343192,66.7106335886793715],"hsluv":[335.738246937474969,22.766845509204984,66.7106335886793715]},"#bb99bb":{"lch":[67.2287438260669887,28.2861274819753,307.715012949249171],"luv":[67.2287438260669887,17.3035955220760833,-22.3761165070024362],"rgb":[0.733333333333333282,0.6,0.733333333333333282],"xyz":[0.408524792964964523,0.369356759984529,0.519926024033302125],"hpluv":[307.715012949249171,53.3897422679679323,67.2287438260669887],"hsluv":[307.715012949249171,24.5905380245485432,67.2287438260669887]},"#bb99cc":{"lch":[67.8043844715017343,39.5775547497090656,292.889275489017223],"luv":[67.8043844715017343,15.393749985076461,-36.4611478338680044],"rgb":[0.733333333333333282,0.6,0.8],"xyz":[0.427817168408686221,0.377073710162017794,0.621532534703572281],"hpluv":[292.889275489017223,74.0679810995506642,67.8043844715017343],"hsluv":[292.889275489017223,42.0187450252511,67.8043844715017343]},"#bb99dd":{"lch":[68.4372510447458353,52.4777928084534082,284.879936967142157],"luv":[68.4372510447458353,13.4760025497769718,-50.718005612655638],"rgb":[0.733333333333333282,0.6,0.866666666666666696],"xyz":[0.449335493959319821,0.385681040382271301,0.734862382603578279],"hpluv":[284.879936967142157,97.3021261982971737,68.4372510447458353],"hsluv":[284.879936967142157,60.4059975969609724,68.4372510447458353]},"#bb99ee":{"lch":[69.1267004581107898,66.0165196934359244,280.096152477623832],"luv":[69.1267004581107898,11.5727364631099334,-64.9942508472035456],"rgb":[0.733333333333333282,0.6,0.933333333333333348],"xyz":[0.47314767422549453,0.395205912488741318,0.860273198672101502],"hpluv":[280.096152477623832,121.184234531677617,69.1267004581107898],"hsluv":[280.096152477623832,79.7264365589122548,69.1267004581107898]},"#bb99ff":{"lch":[69.8717866786541,79.7596884688517207,276.986638727898821],"luv":[69.8717866786541,9.70179942494587877,-79.1674364405365765],"rgb":[0.733333333333333282,0.6,1],"xyz":[0.499318722635325951,0.405674331852674042,0.998107386963883347],"hpluv":[276.986638727898821,144.850809586534439,69.8717866786541],"hsluv":[276.986638727898821,99.9999999999980247,69.8717866786541]},"#880000":{"lch":[27.3946073685119416,92.1289276169810876,12.1770506300617765],"luv":[27.3946073685119416,90.0560691570773,19.4330571920800175],"rgb":[0.533333333333333326,0,0],"xyz":[0.101531161901381561,0.0523520053554009795,0.00475927321412716],"hpluv":[12.1770506300617765,426.746789183125316,27.3946073685119416],"hsluv":[12.1770506300617765,100.000000000002245,27.3946073685119416]},"#880011":{"lch":[27.5061298630582485,89.4551794237446529,10.4692299831444977],"luv":[27.5061298630582485,87.9659862388495242,16.254672889999533],"rgb":[0.533333333333333326,0,0.0666666666666666657],"xyz":[0.10254282740101868,0.0527566715552558324,0.0100873781788827915],"hpluv":[10.4692299831444977,412.68181181873,27.5061298630582485],"hsluv":[10.4692299831444977,99.9999999999965,27.5061298630582485]},"#880022":{"lch":[27.711363673312789,85.0234292319238421,7.23413932290422057],"luv":[27.711363673312789,84.3466296586470463,10.7065206104973338],"rgb":[0.533333333333333326,0,0.133333333333333331],"xyz":[0.104418185539495709,0.0535068148106466537,0.0199642643748619876],"hpluv":[7.23413932290422057,389.331950846774873,27.711363673312789],"hsluv":[7.23413932290422057,99.9999999999967,27.711363673312789]},"#880033":{"lch":[28.0451389930846,79.0521177396887396,1.75350406004841131],"luv":[28.0451389930846,79.0150993176991392,2.41896650323101259],"rgb":[0.533333333333333326,0,0.2],"xyz":[0.107505936271953442,0.0547419151036297666,0.0362264182324731343],"hpluv":[1.75350406004841131,357.680479105960103,28.0451389930846],"hsluv":[1.75350406004841131,99.9999999999969589,28.0451389930846]},"#880044":{"lch":[28.5182895144164306,72.8806899851902585,353.674121255230034],"luv":[28.5182895144164306,72.4369406321056459,-8.0302306678086488],"rgb":[0.533333333333333326,0,0.266666666666666663],"xyz":[0.111963931516172316,0.0565251132013173396,0.0597051931853597728],"hpluv":[353.674121255230034,324.286096087098713,28.5182895144164306],"hsluv":[353.674121255230034,99.9999999999972857,28.5182895144164306]},"#880055":{"lch":[29.1358047874334787,68.1690091719341922,343.056201782139055],"luv":[29.1358047874334787,65.2098664506571453,-19.866734230132252],"rgb":[0.533333333333333326,0,0.333333333333333315],"xyz":[0.117926345555534315,0.0589100788170621725,0.0911072404593336743],"hpluv":[343.056201782139055,296.892542908362316,29.1358047874334787],"hsluv":[343.056201782139055,99.9999999999977405,29.1358047874334787]},"#880066":{"lch":[29.8977347275108087,66.3157421691867768,330.790160549998632],"luv":[29.8977347275108087,57.8829185884671915,-32.3627161272186115],"rgb":[0.533333333333333326,0,0.4],"xyz":[0.125511341329042486,0.0619440771264654841,0.13105488486647765],"hpluv":[330.790160549998632,281.460643767249167,29.8977347275108087],"hsluv":[330.790160549998632,99.9999999999981384,29.8977347275108087]},"#880077":{"lch":[30.8000475559674527,67.8890879971799,318.512376228514142],"luv":[30.8000475559674527,50.8556366042998462,-44.9736866918894549],"rgb":[0.533333333333333326,0,0.466666666666666674],"xyz":[0.13482535434924442,0.0656696823345463,0.180108686772875559],"hpluv":[318.512376228514142,279.697068124812404,30.8000475559674527],"hsluv":[318.512376228514142,99.9999999999984652,30.8000475559674527]},"#880088":{"lch":[31.8355421357531156,72.5162027692933862,307.715012949243601],"luv":[31.8355421357531156,44.3606514294377803,-57.3649045046986288],"rgb":[0.533333333333333326,0,0.533333333333333326],"xyz":[0.14596577145118822,0.0701258491753239,0.238781550176447727],"hpluv":[307.715012949243601,289.042783730483279,31.8355421357531156],"hsluv":[307.715012949243601,99.9999999999987921,31.8355421357531156]},"#880099":{"lch":[32.9947769935272675,79.3376809512942,299.026215263792551],"luv":[32.9947769935272675,38.4954159686478121,-69.3726932454703444],"rgb":[0.533333333333333326,0,0.6],"xyz":[0.159022735560260947,0.0753486348189530558,0.307548227817565634],"hpluv":[299.026215263792551,305.122076286487129,32.9947769935272675],"hsluv":[299.026215263792551,99.9999999999991189,32.9947769935272675]},"#8800aa":{"lch":[34.2669429307518527,87.5167556566874651,292.341813883439613],"luv":[34.2669429307518527,33.2678552259606306,-80.9470958672197298],"rgb":[0.533333333333333326,0,0.66666666666666663],"xyz":[0.174080428525513475,0.0813717120050541642,0.386852077434564234],"hpluv":[292.341813883439613,324.082197305514,34.2669429307518527],"hsluv":[292.341813883439613,99.9999999999993605,34.2669429307518527]},"#8800bb":{"lch":[35.6406160405817047,96.4510237672048589,287.271351738157534],"luv":[35.6406160405817047,28.6360630376966157,-92.1019862947753296],"rgb":[0.533333333333333326,0,0.733333333333333282],"xyz":[0.19121802063285015,0.0882267488479889228,0.477110062533206],"hpluv":[287.271351738157534,343.400533998367337,35.6406160405817047],"hsluv":[287.271351738157534,99.999999999999531,35.6406160405817047]},"#8800cc":{"lch":[37.1043554501127346,105.765919518381835,283.413875530142832],"luv":[37.1043554501127346,24.5359458020369345,-102.880596300606314],"rgb":[0.533333333333333326,0,0.8],"xyz":[0.210510396076571876,0.0959436990254777244,0.578716573203476137],"hpluv":[283.413875530142832,361.709723992276565,37.1043554501127346],"hsluv":[283.413875530142832,99.9999999999998,37.1043554501127346]},"#8800dd":{"lch":[38.6471386159700145,115.245648848701009,280.44740978906907],"luv":[38.6471386159700145,20.8978330626497737,-113.335079087825761],"rgb":[0.533333333333333326,0,0.866666666666666696],"xyz":[0.23202872162720542,0.104551029245731258,0.692046421103482134],"hpluv":[280.44740978906907,378.39598449622531,38.6471386159700145],"hsluv":[280.44740978906907,99.9999999999998863,38.6471386159700145]},"#8800ee":{"lch":[40.258648150966188,124.7713904223,278.13468614008417],"luv":[40.258648150966188,17.6552208530237813,-123.515962711485074],"rgb":[0.533333333333333326,0,0.933333333333333348],"xyz":[0.255840901893380157,0.114075901352201275,0.817457237172005358],"hpluv":[278.13468614008417,393.273926011730225,40.258648150966188],"hsluv":[278.13468614008417,99.9999999999999858,40.258648150966188]},"#8800ff":{"lch":[41.9294357887748674,134.280036872974534,276.305800055850909],"luv":[41.9294357887748674,14.7486383519278057,-133.467621426964229],"rgb":[0.533333333333333326,0,1],"xyz":[0.282011950303211578,0.124544320716133985,0.955291425463787203],"hpluv":[276.305800055850909,406.37947026199555,41.9294357887748674],"hsluv":[276.305800055850909,100.000000000000171,41.9294357887748674]},"#aa0000":{"lch":[35.0982840320529732,118.036634932245676,12.1770506300617765],"luv":[35.0982840320529732,115.380864984340803,24.8978549596859438],"rgb":[0.66666666666666663,0,0],"xyz":[0.165771937912151307,0.08547615548595483,0.00777055958963192815],"hpluv":[12.1770506300617765,426.746789183125145,35.0982840320529732],"hsluv":[12.1770506300617765,100.000000000002217,35.0982840320529732]},"#aa0011":{"lch":[35.178794604810534,115.883637018633408,11.1343823918443601],"luv":[35.178794604810534,113.702354404428164,22.3783808966644813],"rgb":[0.66666666666666663,0,0.0666666666666666657],"xyz":[0.166783603411788439,0.0858808216858096829,0.0130986645543875596],"hpluv":[11.1343823918443601,418.004049663923468,35.178794604810534],"hsluv":[11.1343823918443601,99.9999999999964473,35.178794604810534]},"#aa0022":{"lch":[35.327373324777,112.154849255399441,9.17432067350408431],"luv":[35.327373324777,110.720144559212301,17.8818287736043224],"rgb":[0.66666666666666663,0,0.133333333333333331],"xyz":[0.16865896155026544,0.0866309649412005,0.0229755507503667557],"hpluv":[9.17432067350408431,402.852473647417696,35.327373324777],"hsluv":[9.17432067350408431,99.9999999999965752,35.327373324777]},"#aa0033":{"lch":[35.5701485089931921,106.706281850707128,5.8788523359554592],"luv":[35.5701485089931921,106.14508040487398,10.9294323844098908],"rgb":[0.66666666666666663,0,0.2],"xyz":[0.171746712282723202,0.0878660652341836101,0.0392377046079779],"hpluv":[5.8788523359554592,380.665602767339294,35.5701485089931921],"hsluv":[5.8788523359554592,99.9999999999967741,35.5701485089931921]},"#aa0044":{"lch":[35.9166782648329104,100.198740700315142,1.0062433800652546],"luv":[35.9166782648329104,100.183288799466339,1.75962588401964615],"rgb":[0.66666666666666663,0,0.266666666666666663],"xyz":[0.176204707526942062,0.0896492633318711901,0.0627164795608645409],"hpluv":[1.0062433800652546,354.001763490246503,35.9166782648329104],"hsluv":[1.0062433800652546,99.999999999997,35.9166782648329104]},"#aa0055":{"lch":[36.3730398367095,93.6502679946689369,354.384147096436777],"luv":[36.3730398367095,93.2007806216229113,-9.16445235643848832],"rgb":[0.66666666666666663,0,0.333333333333333315],"xyz":[0.182167121566304047,0.092034228947616023,0.0941185268348384424],"hpluv":[354.384147096436777,326.714758289773386,36.3730398367095],"hsluv":[354.384147096436777,99.9999999999973,36.3730398367095]},"#aa0066":{"lch":[36.9423385777606228,88.2319659172366926,346.039412913085584],"luv":[36.9423385777606228,85.6257622699194,-21.2863488018886251],"rgb":[0.66666666666666663,0,0.4],"xyz":[0.189752117339812232,0.0950682272570193415,0.134066171241982418],"hpluv":[346.039412913085584,303.068568849792825,36.9423385777606228],"hsluv":[346.039412913085584,99.9999999999976126,36.9423385777606228]},"#aa0077":{"lch":[37.6250775946346891,84.9907340508927689,336.365700313169],"luv":[37.6250775946346891,77.8619577045834319,-34.0725757306260348],"rgb":[0.66666666666666663,0,0.466666666666666674],"xyz":[0.199066130360014137,0.0987938324651001509,0.183119973148380327],"hpluv":[336.365700313169,286.637826777930513,37.6250775946346891],"hsluv":[336.365700313169,99.9999999999979536,37.6250775946346891]},"#aa0088":{"lch":[38.4195160158879432,84.5572797483387717,326.161033183527252],"luv":[38.4195160158879432,70.2337789048813761,-47.0866208086656215],"rgb":[0.66666666666666663,0,0.533333333333333326],"xyz":[0.210206547461958,0.103249999305877749,0.241792836551952495],"hpluv":[326.161033183527252,279.279102381419364,38.4195160158879432],"hsluv":[326.161033183527252,99.9999999999982379,38.4195160158879432]},"#aa0099":{"lch":[39.3220484546604681,86.9871636461465272,316.374304421046759],"luv":[39.3220484546604681,62.9667468975572859,-60.0162929906574334],"rgb":[0.66666666666666663,0,0.6],"xyz":[0.223263511571030693,0.108472784949506906,0.310559514193070374],"hpluv":[316.374304421046759,280.710309296009257,39.3220484546604681],"hsluv":[316.374304421046759,99.9999999999986,39.3220484546604681]},"#aa00aa":{"lch":[40.3276007574525863,91.8597353001339627,307.715012949243601],"luv":[40.3276007574525863,56.1937545325413,-72.6668626056414411],"rgb":[0.66666666666666663,0,0.66666666666666663],"xyz":[0.238321204536283249,0.114495862135608,0.389863363810069],"hpluv":[307.715012949243601,289.042783730483393,40.3276007574525863],"hsluv":[307.715012949243601,99.9999999999988205,40.3276007574525863]},"#aa00bb":{"lch":[41.4300227805658849,98.5480850422065089,300.471226581677797],"luv":[41.4300227805658849,49.974285465742625,-84.9370111180893304],"rgb":[0.66666666666666663,0,0.733333333333333282],"xyz":[0.255458796643619868,0.121350898978542759,0.480121348908710721],"hpluv":[300.471226581677797,301.836908489583834,41.4300227805658849],"hsluv":[300.471226581677797,99.9999999999990621,41.4300227805658849]},"#aa00cc":{"lch":[42.6224565622471445,106.453892931925211,294.601049164416338],"luv":[42.6224565622471445,44.3164832708711813,-96.7909119228886681],"rgb":[0.66666666666666663,0,0.8],"xyz":[0.274751172087341622,0.129067849156031561,0.581727859578980877],"hpluv":[294.601049164416338,316.929304470761622,42.6224565622471445],"hsluv":[294.601049164416338,99.9999999999992895,42.6224565622471445]},"#aa00dd":{"lch":[43.8976622887243266,115.112632227118652,289.907671140995035],"luv":[43.8976622887243266,39.1964773946494063,-108.233794436426436],"rgb":[0.66666666666666663,0,0.866666666666666696],"xyz":[0.296269497637975165,0.137675179376285095,0.695057707478986875],"hpluv":[289.907671140995035,332.752186796280228,43.8976622887243266],"hsluv":[289.907671140995035,99.9999999999994174,43.8976622887243266]},"#aa00ee":{"lch":[45.2482911917969233,124.202454763835647,286.162342623679535],"luv":[45.2482911917969233,34.5729825657367655,-119.293581746345012],"rgb":[0.66666666666666663,0,0.933333333333333348],"xyz":[0.320081677904149875,0.14720005148275514,0.820468523547510098],"hpluv":[286.162342623679535,348.311106794177135,45.2482911917969233],"hsluv":[286.162342623679535,99.9999999999996589,45.2482911917969233]},"#aa00ff":{"lch":[46.667101462293175,133.514790614533382,283.159905061129905],"luv":[46.667101462293175,30.397247590160724,-130.008486845225434],"rgb":[0.66666666666666663,0,1],"xyz":[0.346252726313981296,0.157668470846687836,0.958302711839291943],"hpluv":[283.159905061129905,363.042841924949244,46.667101462293175],"hsluv":[283.159905061129905,99.9999999999998153,46.667101462293175]},"#881100":{"lch":[28.4751123640698864,88.1761994811112,13.8943544232398857],"luv":[28.4751123640698864,85.5961768878489124,21.1739617718743069],"rgb":[0.533333333333333326,0.0666666666666666657,0],"xyz":[0.103535562162309969,0.0563608058772578496,0.00542740663443661096],"hpluv":[13.8943544232398857,392.939109149716501,28.4751123640698864],"hsluv":[13.8943544232398857,100.000000000002331,28.4751123640698864]},"#881111":{"lch":[28.5813012406410962,85.6429421929893522,12.1770506300617782],"luv":[28.5813012406410962,83.7160154193071548,18.0649469909557752],"rgb":[0.533333333333333326,0.0666666666666666657,0.0666666666666666657],"xyz":[0.104547227661947087,0.0567654720771127,0.0107555115991922433],"hpluv":[12.1770506300617782,380.232213605760478,28.5813012406410962],"hsluv":[12.1770506300617782,89.1001931926906536,28.5813012406410962]},"#881122":{"lch":[28.776819878520115,81.4294437186752589,8.91447414891876377],"luv":[28.776819878520115,80.445837197505071,12.6183034487767767],"rgb":[0.533333333333333326,0.0666666666666666657,0.133333333333333331],"xyz":[0.106422585800424116,0.0575156153325035238,0.0206323977951714393],"hpluv":[8.91447414891876377,359.069069298387092,28.776819878520115],"hsluv":[8.91447414891876377,89.5522119422979,28.776819878520115]},"#881133":{"lch":[29.0950676619922959,75.7256767264573227,3.35964558590209394],"luv":[29.0950676619922959,75.5955308554484162,4.43777313107212557],"rgb":[0.533333333333333326,0.0666666666666666657,0.2],"xyz":[0.10951033653288185,0.0587507156254866367,0.0368945516527825826],"hpluv":[3.35964558590209394,330.265430862114329,29.0950676619922959],"hsluv":[3.35964558590209394,90.2199940579986475,29.0950676619922959]},"#881144":{"lch":[29.5467689283324617,69.8105982852884779,355.112641815866198],"luv":[29.5467689283324617,69.5567752183087435,-5.94765955478224484],"rgb":[0.533333333333333326,0.0666666666666666657,0.266666666666666663],"xyz":[0.113968331777100723,0.0605339137231742097,0.0603733266056692211],"hpluv":[355.112641815866198,299.81315922456514,29.5467689283324617],"hsluv":[355.112641815866198,91.0462468049379083,29.5467689283324617]},"#881155":{"lch":[30.1372440361953267,65.3247498846549,344.189828060851937],"luv":[30.1372440361953267,62.8534910411243928,-17.7977979378353552],"rgb":[0.533333333333333326,0.0666666666666666657,0.333333333333333315],"xyz":[0.119930745816462722,0.0629188793389190426,0.0917753738796431295],"hpluv":[344.189828060851937,275.05120204756264,30.1372440361953267],"hsluv":[344.189828060851937,91.9552565263170294,30.1372440361953267]},"#881166":{"lch":[30.8672249177773494,63.7021552959616173,331.50461515751158],"luv":[30.8672249177773494,55.9849923977636479,-30.3915319714745138],"rgb":[0.533333333333333326,0.0666666666666666657,0.4],"xyz":[0.127515741589970893,0.0659528776483223611,0.131723018286787091],"hpluv":[331.50461515751158,261.876101180723595,30.8672249177773494],"hsluv":[331.50461515751158,92.8754029221989299,30.8672249177773494]},"#881177":{"lch":[31.7336031237729514,65.5512880923603376,318.81152503011009],"luv":[31.7336031237729514,49.3304506912780525,-43.1680206305895737],"rgb":[0.533333333333333326,0.0666666666666666657,0.466666666666666674],"xyz":[0.136829754610172827,0.0696784828564031705,0.180776820193185],"hpluv":[318.81152503011009,262.120610410187965,31.7336031237729514],"hsluv":[318.81152503011009,93.7528273751248094,31.7336031237729514]},"#881188":{"lch":[32.7302234117729114,70.4946015177073377,307.715012949243658],"luv":[32.7302234117729114,43.1239685223607268,-55.7656900075914663],"rgb":[0.533333333333333326,0.0666666666666666657,0.533333333333333326],"xyz":[0.147970171712116627,0.0741346496971807684,0.239449683596757168],"hpluv":[307.715012949243658,273.304143969878908,32.7302234117729114],"hsluv":[307.715012949243658,94.5549099834012736,32.7302234117729114]},"#881199":{"lch":[33.8487030992268245,77.6382380820710836,298.861624073140206],"luv":[33.8487030992268245,37.4756592651389795,-67.9946393117248249],"rgb":[0.533333333333333326,0.0666666666666666657,0.6],"xyz":[0.161027135821189354,0.0793574353408099259,0.308216361237875103],"hpluv":[298.861624073140206,291.053592363859707,33.8487030992268245],"hsluv":[298.861624073140206,95.267111116431,33.8487030992268245]},"#8811aa":{"lch":[35.0792182273937954,86.1162494337963551,292.107316515455238],"luv":[35.0792182273937954,32.4092110837954692,-79.7850327659882623],"rgb":[0.533333333333333326,0.0666666666666666657,0.66666666666666663],"xyz":[0.176084828786441883,0.0853805125269110343,0.387520210854873703],"hpluv":[292.107316515455238,311.511817997128389,35.0792182273937954],"hsluv":[292.107316515455238,95.8874450484264571,35.0792182273937954]},"#8811bb":{"lch":[36.4111998559147381,95.3124415598142,287.019214731984619],"luv":[36.4111998559147381,27.8972267898096504,-91.1383906678789515],"rgb":[0.533333333333333326,0.0666666666666666657,0.733333333333333282],"xyz":[0.193222420893778557,0.0922355493698457929,0.47777819595351545],"hpluv":[287.019214731984619,332.16504711372977,36.4111998559147381],"hsluv":[287.019214731984619,96.4212920970111753,36.4111998559147381]},"#8811cc":{"lch":[37.8339039869932847,104.849214202707898,283.169050576302368],"luv":[37.8339039869932847,23.8872658659353974,-102.091900993053514],"rgb":[0.533333333333333326,0.0666666666666666657,0.8],"xyz":[0.212514796337500284,0.0999524995473346,0.579384706623785606],"hpluv":[283.169050576302368,351.660305548048939,37.8339039869932847],"hsluv":[283.169050576302368,96.8775739500717776,37.8339039869932847]},"#8811dd":{"lch":[39.3368423655390274,114.513051177954694,280.22024610097435],"luv":[39.3368423655390274,20.3183376083265372,-112.696069349906494],"rgb":[0.533333333333333326,0.0666666666666666657,0.866666666666666696],"xyz":[0.234033121888133827,0.108559829767588129,0.692714554523791604],"hpluv":[280.22024610097435,369.398236331583689,39.3368423655390274],"hsluv":[280.22024610097435,97.2663289333616348,39.3368423655390274]},"#8811ee":{"lch":[40.9100807353410261,124.189527798253138,277.928390028110698],"luv":[40.9100807353410261,17.130123009315259,-123.002429652583771],"rgb":[0.533333333333333326,0.0666666666666666657,0.933333333333333348],"xyz":[0.257845302154308564,0.118084701874058146,0.818125370592314827],"hpluv":[277.928390028110698,385.206818333834917,40.9100807353410261],"hsluv":[277.928390028110698,97.5973562787359867,40.9100807353410261]},"#8811ff":{"lch":[42.5444231432324926,133.820472646418182,276.120297984259253],"luv":[42.5444231432324926,14.2674470621751119,-133.057727523202459],"rgb":[0.533333333333333326,0.0666666666666666657,1],"xyz":[0.28401635056414,0.128553121237990842,0.955959558884096672],"hpluv":[276.120297984259253,399.134479754608662,42.5444231432324926],"hsluv":[276.120297984259253,99.9999999999993605,42.5444231432324926]},"#aa1100":{"lch":[35.8849415951509485,114.659477700983,13.2232466646238507],"luv":[35.8849415951509485,111.619416231509064,26.2278810962561089],"rgb":[0.66666666666666663,0.0666666666666666657,0],"xyz":[0.167776338173079714,0.0894849560078117,0.00843869300994137816],"hpluv":[13.2232466646238507,405.449754626827882,35.8849415951509485],"hsluv":[13.2232466646238507,100.000000000002245,35.8849415951509485]},"#aa1111":{"lch":[35.9630348414680086,112.584844162769954,12.1770506300617871],"luv":[35.9630348414680086,110.051736997450746,23.747890832642895],"rgb":[0.66666666666666663,0.0666666666666666657,0.0666666666666666657],"xyz":[0.168788003672716846,0.089889622207666553,0.0137667979746970096],"hpluv":[12.1770506300617871,397.249101663635656,35.9630348414680086],"hsluv":[12.1770506300617871,93.0877775141683514,35.9630348414680086]},"#aa1122":{"lch":[36.1071812157442409,108.986817867719594,10.2082214608018411],"luv":[36.1071812157442409,107.261576994584843,19.3152936702042],"rgb":[0.66666666666666663,0.0666666666666666657,0.133333333333333331],"xyz":[0.170663361811193848,0.0906397654630573674,0.0236436841706762074],"hpluv":[10.2082214608018411,383.018466712830786,36.1071812157442409],"hsluv":[10.2082214608018411,93.272361347425246,36.1071812157442409]},"#aa1133":{"lch":[36.3427932754706546,103.718469067724868,6.89182233030552727],"luv":[36.3427932754706546,102.969049051934846,12.4457126390109512],"rgb":[0.66666666666666663,0.0666666666666666657,0.2],"xyz":[0.173751112543651609,0.0918748657560404802,0.0399058380282873507],"hpluv":[6.89182233030552727,362.140519718911037,36.3427932754706546],"hsluv":[6.89182233030552727,93.5557024333493388,36.3427932754706546]},"#aa1144":{"lch":[36.6792659124992824,97.4113439982971698,1.97455903872184],"luv":[36.6792659124992824,97.3535035649005778,3.35637947697775552],"rgb":[0.66666666666666663,0.0666666666666666657,0.266666666666666663],"xyz":[0.178209107787870469,0.0936580638537280602,0.0633846129811739822],"hpluv":[1.97455903872184,336.99870087691761,36.6792659124992824],"hsluv":[1.97455903872184,93.9250914747756696,36.6792659124992824]},"#aa1155":{"lch":[37.1226754299384396,91.055498296574811,355.267689161716703],"luv":[37.1226754299384396,90.7450919896636634,-7.51212685096688926],"rgb":[0.66666666666666663,0.0666666666666666657,0.333333333333333315],"xyz":[0.184171521827232454,0.0960430294694729,0.0947866602551479],"hpluv":[355.267689161716703,311.247759321881176,37.1226754299384396],"hsluv":[355.267689161716703,94.3576556410013154,37.1226754299384396]},"#aa1166":{"lch":[37.6762679798416,85.8108023849569577,346.783206271719791],"luv":[37.6762679798416,83.5378398512485205,-19.6194576616503156],"rgb":[0.66666666666666663,0.0666666666666666657,0.4],"xyz":[0.191756517600740639,0.0990770277788762116,0.134734304662291859],"hpluv":[346.783206271719791,289.010360822200312,37.6762679798416],"hsluv":[346.783206271719791,94.8263018378468558,37.6762679798416]},"#aa1177":{"lch":[38.3408051028578285,82.7345113545946163,336.916515476294876],"luv":[38.3408051028578285,76.110335477500783,-32.4378822148708],"rgb":[0.66666666666666663,0.0666666666666666657,0.466666666666666674],"xyz":[0.201070530620942545,0.102802632986957021,0.183788106568689769],"hpluv":[336.916515476294876,273.819772016881302,38.3408051028578285],"hsluv":[336.916515476294876,95.3051408978498387,38.3408051028578285]},"#aa1188":{"lch":[39.1148927869010379,82.477083595297529,326.495944929629673],"luv":[39.1148927869010379,68.7732486834780445,-45.5270203714912753],"rgb":[0.66666666666666663,0.0666666666666666657,0.533333333333333326],"xyz":[0.212210947722886401,0.107258799827734619,0.242460969972261936],"hpluv":[326.495944929629673,267.565723971153261,39.1148927869010379],"hsluv":[326.495944929629673,95.7730681487448,39.1148927869010379]},"#aa1199":{"lch":[39.9953287808464424,85.1038505069809617,316.515705271857257],"luv":[39.9953287808464424,61.7482074461545665,-58.5647013848890552],"rgb":[0.66666666666666663,0.0666666666666666657,0.6],"xyz":[0.2252679118319591,0.112481585471363776,0.311227647613379843],"hpluv":[316.515705271857257,270.00963724100518,39.9953287808464424],"hsluv":[316.515705271857257,96.2151887572794,39.9953287808464424]},"#aa11aa":{"lch":[40.9774666162921406,90.1875437006381588,307.715012949243601],"luv":[40.9774666162921406,55.1708175083225498,-71.3440532505540261],"rgb":[0.66666666666666663,0.0666666666666666657,0.66666666666666663],"xyz":[0.240325604797211656,0.118504662657464871,0.390531497230378444],"hpluv":[307.715012949243601,279.28060733669264,40.9774666162921406],"hsluv":[307.715012949243601,96.6225842874192864,40.9774666162921406]},"#aa11bb":{"lch":[42.0555802442747719,97.087212137786878,300.384453602166161],"luv":[42.0555802442747719,49.106684193967304,-83.7523750598249705],"rgb":[0.66666666666666663,0.0666666666666666657,0.733333333333333282],"xyz":[0.257463196904548275,0.12535969950039963,0.48078948232902019],"hpluv":[300.384453602166161,292.939359498794147,42.0555802442747719],"hsluv":[300.384453602166161,96.9911870522472697,42.0555802442747719]},"#aa11cc":{"lch":[43.2232098485165395,105.192683835863036,294.469145625450437],"luv":[43.2232098485165395,43.5711419401365,-95.7447456658814247],"rgb":[0.66666666666666663,0.0666666666666666657,0.8],"xyz":[0.276755572348270029,0.133076649677888431,0.582395992999290346],"hpluv":[294.469145625450437,308.821726609797679,43.2232098485165395],"hsluv":[294.469145625450437,97.3204020480748255,43.2232098485165395]},"#aa11dd":{"lch":[44.4734721926781518,114.032755796715193,289.757274940509092],"luv":[44.4734721926781518,38.5472014936014489,-107.320001172218454],"rgb":[0.66666666666666663,0.0666666666666666657,0.866666666666666696],"xyz":[0.298273897898903573,0.141683979898141965,0.695725840899296344],"hpluv":[289.757274940509092,325.362808980276498,44.4734721926781518],"hsluv":[289.757274940509092,97.611854654502622,44.4734721926781518]},"#aa11ee":{"lch":[45.7993244881172,123.283094749558884,286.008743686799619],"luv":[45.7993244881172,33.9995108001485136,-118.502129585840351],"rgb":[0.66666666666666663,0.0666666666666666657,0.933333333333333348],"xyz":[0.322086078165078282,0.151208852004612,0.821136656967819567],"hpluv":[286.008743686799619,341.573194884792258,45.7993244881172],"hsluv":[286.008743686799619,97.8684161167955153,45.7993244881172]},"#aa11ff":{"lch":[47.1937769411101868,132.735165800167636,283.011169167098501],"luv":[47.1937769411101868,29.8841269734434611,-129.327348983241365],"rgb":[0.66666666666666663,0.0666666666666666657,1],"xyz":[0.348257126574909703,0.161677271368544706,0.958970845259601412],"hpluv":[283.011169167098501,356.89510187446183,47.1937769411101868],"hsluv":[283.011169167098501,99.9999999999993321,47.1937769411101868]},"#882200":{"lch":[30.3496916993887922,81.7292062801124786,17.2000641303745212],"luv":[30.3496916993887922,78.0741152618852254,24.1680716080335465],"rgb":[0.533333333333333326,0.133333333333333331,0],"xyz":[0.107251185897077911,0.0637920533467938311,0.00666594787935922105],"hpluv":[17.2000641303745212,341.713647377264522,30.3496916993887922],"hsluv":[17.2000641303745212,100.000000000002359,30.3496916993887922]},"#882211":{"lch":[30.4474919309639347,79.3871193031655338,15.4743840495427136],"luv":[30.4474919309639347,76.5093230935452908,21.181080969170015],"rgb":[0.533333333333333326,0.133333333333333331,0.0666666666666666657],"xyz":[0.108262851396715029,0.064196719546648684,0.0119940528441148525],"hpluv":[15.4743840495427136,330.855109199112462,30.4474919309639347],"hsluv":[15.4743840495427136,90.2707057474005,30.4474919309639347]},"#882222":{"lch":[30.6277058928754826,75.4670009360781648,12.1770506300618102],"luv":[30.6277058928754826,73.7690281561900321,15.9185022906448506],"rgb":[0.533333333333333326,0.133333333333333331,0.133333333333333331],"xyz":[0.110138209535192058,0.0649468628020395,0.0218709390400940486],"hpluv":[12.1770506300618102,312.666930334371557,30.6277058928754826],"hsluv":[12.1770506300618102,73.2675530922876277,30.6277058928754826]},"#882233":{"lch":[30.9214262019897674,70.1124269978110135,6.50693872003014],"luv":[30.9214262019897674,69.6607724946186266,7.94538828354938],"rgb":[0.533333333333333326,0.133333333333333331,0.2],"xyz":[0.113225960267649792,0.0661819630950226112,0.0381330928977051953],"hpluv":[6.50693872003014,287.723152758323693,30.9214262019897674],"hsluv":[6.50693872003014,74.8097141082451458,30.9214262019897674]},"#882244":{"lch":[31.3391119188553589,64.5127804411509,357.965654494967],"luv":[31.3391119188553589,64.472119792654567,-2.29011128326569047],"rgb":[0.533333333333333326,0.133333333333333331,0.266666666666666663],"xyz":[0.117683955511868665,0.0679651611927101912,0.0616118678505918338],"hpluv":[357.965654494967,261.215173773686786,31.3391119188553589],"hsluv":[357.965654494967,76.7464797952550839,31.3391119188553589]},"#882255":{"lch":[31.8864840032734449,60.2907989794282599,346.464164292394514],"luv":[31.8864840032734449,58.6161449596217778,-14.1112717942230379],"rgb":[0.533333333333333326,0.133333333333333331,0.333333333333333315],"xyz":[0.123646369551230664,0.0703501268084550241,0.0930139151245657353],"hpluv":[346.464164292394514,239.929545755427228,31.8864840032734449],"hsluv":[346.464164292394514,78.9147131880069566,31.8864840032734449]},"#882266":{"lch":[32.565220274416383,58.9629659850378189,332.945096803324191],"luv":[32.565220274416383,52.5107124518348698,-26.8189566455043362],"rgb":[0.533333333333333326,0.133333333333333331,0.4],"xyz":[0.131231365324738836,0.0733841251178583426,0.132961559531709711],"hpluv":[332.945096803324191,229.754818264706444,32.565220274416383],"hsluv":[332.945096803324191,81.1505919454384923,32.565220274416383]},"#882277":{"lch":[33.3735533542235316,61.2256527964903086,319.411642653163199],"luv":[33.3735533542235316,46.4949769025583564,-39.8346291960518499],"rgb":[0.533333333333333326,0.133333333333333331,0.466666666666666674],"xyz":[0.140545378344940741,0.077109730325939152,0.18201536143810762],"hpluv":[319.411642653163199,232.79320602780777,33.3735533542235316],"hsluv":[319.411642653163199,83.3222334130424116,33.3735533542235316]},"#882288":{"lch":[34.3068967831130962,66.691064714973308,307.715012949243771],"luv":[34.3068967831130962,40.7972144472485709,-52.7568517461189046],"rgb":[0.533333333333333326,0.133333333333333331,0.533333333333333326],"xyz":[0.151685795446884597,0.0815658971667167498,0.240688224841679788],"hpluv":[307.715012949243771,246.675229855048,34.3068967831130962],"hsluv":[307.715012949243771,85.3421167175917,34.3068967831130962]},"#882299":{"lch":[35.3585028262625087,74.3915148492043699,298.539568373309862],"luv":[35.3585028262625087,35.5417034620318262,-65.3520068289902554],"rgb":[0.533333333333333326,0.133333333333333331,0.6],"xyz":[0.164742759555957297,0.0867886828103459074,0.309454902482797667],"hpluv":[298.539568373309862,266.973934190138948,35.3585028262625087],"hsluv":[298.539568373309862,87.1641407220543556,35.3585028262625087]},"#8822aa":{"lch":[36.5201138266519365,83.3993900511107142,291.653660077047903],"luv":[36.5201138266519365,30.7739719973965897,-77.5140045953036463],"rgb":[0.533333333333333326,0.133333333333333331,0.66666666666666663],"xyz":[0.179800452521209853,0.092811759996447,0.388758752099796268],"hpluv":[291.653660077047903,289.781114528802732,36.5201138266519365],"hsluv":[291.653660077047903,88.7734689989794532,36.5201138266519365]},"#8822bb":{"lch":[37.7825623664262196,93.0686060696910857,286.53575696187113],"luv":[37.7825623664262196,26.4885972028076893,-89.2195026548722],"rgb":[0.533333333333333326,0.133333333333333331,0.733333333333333282],"xyz":[0.196938044628546471,0.0996667968393817605,0.479016737198438],"hpluv":[286.53575696187113,312.57276028475934,37.7825623664262196],"hsluv":[286.53575696187113,90.1753980157506874,37.7825623664262196]},"#8822cc":{"lch":[39.1362858369643476,103.012880313051866,282.702767559286599],"luv":[39.1362858369643476,22.6518448072254479,-100.491529181421669],"rgb":[0.533333333333333326,0.133333333333333331,0.8],"xyz":[0.216230420072268226,0.107383747016870562,0.580623247868708225],"hpluv":[282.702767559286599,334.003678399645651,39.1362858369643476],"hsluv":[282.702767559286599,91.3862929083300628,39.1362858369643476]},"#8822dd":{"lch":[40.5717373677475379,113.020349666590874,279.789793007972776],"luv":[40.5717373677475379,19.2172965257181652,-111.374570495248548],"rgb":[0.533333333333333326,0.133333333333333331,0.866666666666666696],"xyz":[0.237748745622901769,0.115991077237124096,0.693953095768714223],"hpluv":[279.789793007972776,353.486121759760863,40.5717373677475379],"hsluv":[279.789793007972776,92.4273238443811209,40.5717373677475379]},"#8822ee":{"lch":[42.0796906219744145,122.982600065668066,277.538986095624125],"luv":[42.0796906219744145,16.1354126197819454,-121.919515986988074],"rgb":[0.533333333333333326,0.133333333333333331,0.933333333333333348],"xyz":[0.261560925889076534,0.125515949343594141,0.819363911837237446],"hpluv":[277.538986095624125,370.860397035002336,42.0796906219744145],"hsluv":[277.538986095624125,93.320628909539181,42.0796906219744145]},"#8822ff":{"lch":[43.6514473624058752,132.848943476626658,275.771185477405766],"luv":[43.6514473624058752,13.3587518063908028,-132.175585994657865],"rgb":[0.533333333333333326,0.133333333333333331,1],"xyz":[0.2877319742989079,0.135984368707526837,0.957198100129019291],"hpluv":[275.771185477405766,386.188007357759091,43.6514473624058752],"hsluv":[275.771185477405766,99.9999999999994,43.6514473624058752]},"#ffaa00":{"lch":[76.0766826449234799,103.646966048157225,46.9849230608437125],"luv":[76.0766826449234799,70.7070052858721,75.7839889059127785],"rgb":[1,0.66666666666666663,0],"xyz":[0.556131758114240538,0.500120923568095,0.0672444716650198171],"hpluv":[46.9849230608437125,173.218766512771339,76.0766826449234799],"hsluv":[46.9849230608437125,100.0000000000028,76.0766826449234799]},"#ffaa11":{"lch":[76.1015101579349533,102.726050652762069,46.6846637022245687],"luv":[76.1015101579349533,70.4714195905473275,74.7423608377930719],"rgb":[1,0.66666666666666663,0.0666666666666666657],"xyz":[0.557143423613877697,0.500525589767949919,0.0725725766297754538],"hpluv":[46.6846637022245687,171.896872437304751,76.1015101579349533],"hsluv":[46.6846637022245687,100.000000000002771,76.1015101579349533]},"#ffaa22":{"lch":[76.1474983763177,101.038792737361192,46.1176753587789605],"luv":[76.1474983763177,70.0380208569547591,72.8252241483965719],"rgb":[1,0.66666666666666663,0.133333333333333331],"xyz":[0.559018781752354643,0.501275733023340719,0.0824494628257546464],"hpluv":[46.1176753587789605,169.470349592440897,76.1474983763177],"hsluv":[46.1176753587789605,100.0000000000028,76.1474983763177]},"#ffaa33":{"lch":[76.2231174741888395,98.3169656691378577,45.1538509265191337],"luv":[76.2231174741888395,69.3336656617894533,69.7070193329597885],"rgb":[1,0.66666666666666663,0.2],"xyz":[0.56210653248481246,0.502510833316323846,0.0987116166833657827],"hpluv":[45.1538509265191337,165.543337136749699,76.2231174741888395],"hsluv":[45.1538509265191337,100.000000000002927,76.2231174741888395]},"#ffaa44":{"lch":[76.3320756204529118,94.5107446089494516,43.6926927141772694],"luv":[76.3320756204529118,68.3364903114306514,65.2870962629968119],"rgb":[1,0.66666666666666663,0.266666666666666663],"xyz":[0.56656452772903132,0.504294031414011412,0.122190391636252421],"hpluv":[43.6926927141772694,160.025535099593441,76.3320756204529118],"hsluv":[43.6926927141772694,100.000000000003,76.3320756204529118]},"#ffaa55":{"lch":[76.4774026026215,89.6489515946998807,41.6012791226812411],"luv":[76.4774026026215,67.0379860163697288,59.5217855318358247],"rgb":[1,0.66666666666666663,0.333333333333333315],"xyz":[0.572526941768393249,0.506678997029756162,0.153592438910226337],"hpluv":[41.6012791226812411,152.933128718005122,76.4774026026215],"hsluv":[41.6012791226812411,100.000000000003,76.4774026026215]},"#ffaa66":{"lch":[76.6616205587261,83.8466863985853905,38.6944265301345354],"luv":[76.6616205587261,65.4416029270402788,52.418159318716242],"rgb":[1,0.66666666666666663,0.4],"xyz":[0.58011193754190149,0.50971299533915948,0.193540083317370298],"hpluv":[38.6944265301345354,144.405277715469396,76.6616205587261],"hsluv":[38.6944265301345354,100.000000000003197,76.6616205587261]},"#ffaa77":{"lch":[76.8868341725165,77.3210793721064533,34.7099370327462324],"luv":[76.8868341725165,63.5614296008349058,44.0283315873505927],"rgb":[1,0.66666666666666663,0.466666666666666674],"xyz":[0.58942595056210334,0.513438600547240331,0.242593885223768208],"hpluv":[34.7099370327462324,134.738986801151128,76.8868341725165],"hsluv":[34.7099370327462324,100.000000000003354,76.8868341725165]},"#ffaa88":{"lch":[77.1547840912050873,70.4186738688562741,29.282319230158226],"luv":[77.1547840912050873,61.4205932059712723,34.4427112706728948],"rgb":[1,0.66666666666666663,0.533333333333333326],"xyz":[0.600566367664047251,0.517894767388017874,0.301266748627340375],"hpluv":[29.282319230158226,124.451835787871019,77.1547840912050873],"hsluv":[29.282319230158226,100.000000000003638,77.1547840912050873]},"#ffaa99":{"lch":[77.466881654564645,63.658531214354845,21.9370110659791244],"luv":[77.466881654564645,59.0493431107362383,23.7820031654092716],"rgb":[1,0.66666666666666663,0.6],"xyz":[0.613623331773119896,0.523117553031647087,0.370033426268458254],"hpluv":[21.9370110659791244,114.385173247539697,77.466881654564645],"hsluv":[21.9370110659791244,100.000000000003624,77.466881654564645]},"#ffaaaa":{"lch":[77.8242336850598,57.783013099698,12.1770506300621957],"luv":[77.8242336850598,56.482921905318662,12.1883606739193855],"rgb":[1,0.66666666666666663,0.66666666666666663],"xyz":[0.628681024738372507,0.529140630217748154,0.44933727588545691],"hpluv":[12.1770506300621957,105.841692205508735,77.8242336850598],"hsluv":[12.1770506300621957,100.000000000003837,77.8242336850598]},"#ffaabb":{"lch":[78.227662021793833,53.7597014753195,359.804273109779956],"luv":[78.227662021793833,53.7593877986938224,-0.183647012281759531],"rgb":[1,0.66666666666666663,0.733333333333333282],"xyz":[0.64581861684570907,0.535995667060682912,0.539595260984098601],"hpluv":[359.804273109779956,100.661858044669231,78.227662021793833],"hsluv":[359.804273109779956,100.000000000004135,78.227662021793833]},"#ffaacc":{"lch":[78.6777204654413254,52.5946111834740293,345.492217824016791],"luv":[78.6777204654413254,50.9175596191628586,-13.1755549397286202],"rgb":[1,0.66666666666666663,0.8],"xyz":[0.665110992289430825,0.543712617238171769,0.641201771654368757],"hpluv":[345.492217824016791,100.966318741741958,78.6777204654413254],"hsluv":[345.492217824016791,100.000000000004306,78.6777204654413254]},"#ffaadd":{"lch":[79.1747106956411244,54.8892328831665353,330.97422205899818],"luv":[79.1747106956411244,47.9952274547753177,-26.6324243745640352],"rgb":[1,0.66666666666666663,0.866666666666666696],"xyz":[0.686629317840064424,0.552319947458425275,0.754531619554374755],"hpluv":[330.97422205899818,108.36723319715793,79.1747106956411244],"hsluv":[330.97422205899818,100.000000000004704,79.1747106956411244]},"#ffaaee":{"lch":[79.718698064048283,60.5009523664383337,318.094564198374599],"luv":[79.718698064048283,45.0277239197174595,-40.4087777080146822],"rgb":[1,0.66666666666666663,0.933333333333333348],"xyz":[0.710441498106239133,0.561844819564895293,0.879942435622898],"hpluv":[318.094564198374599,123.247069988098687,79.718698064048283],"hsluv":[318.094564198374599,100.000000000004945,79.718698064048283]},"#ffaaff":{"lch":[80.3095277487323074,68.733917080261989,307.715012949245647],"luv":[80.3095277487323074,42.0468973903394,-54.3728772187255203],"rgb":[1,0.66666666666666663,1],"xyz":[0.736612546516070554,0.572313238928828,1.01777662391468],"hpluv":[307.715012949245647,144.979279509576116,80.3095277487323074],"hsluv":[307.715012949245647,100.000000000005301,80.3095277487323074]},"#aa2200":{"lch":[37.2831780533064929,108.910935722579069,15.2092016225530191],"luv":[37.2831780533064929,105.096262108869439,28.5721474641225],"rgb":[0.66666666666666663,0.133333333333333331,0],"xyz":[0.171491961907847656,0.0969162034773476816,0.00967723425486398912],"hpluv":[15.2092016225530191,370.67892165569458,37.2831780533064929],"hsluv":[15.2092016225530191,100.000000000002217,37.2831780533064929]},"#aa2211":{"lch":[37.3572350214345619,106.95640568906397,14.158492547926917],"luv":[37.3572350214345619,103.707370245599336,26.1620732103901794],"rgb":[0.66666666666666663,0.133333333333333331,0.0666666666666666657],"xyz":[0.172503627407484789,0.0973208696772025345,0.0150053392196196206],"hpluv":[14.158492547926917,363.305022455593,37.3572350214345619],"hsluv":[14.158492547926917,93.5777596020973732,37.3572350214345619]},"#aa2222":{"lch":[37.4939757158163331,103.55828406892158,12.1770506300617907],"luv":[37.4939757158163331,101.228270350344232,21.8438888748564],"rgb":[0.66666666666666663,0.133333333333333331,0.133333333333333331],"xyz":[0.17437898554596179,0.0980710129325933488,0.0248822254155988166],"hpluv":[12.1770506300617907,350.479546677114797,37.4939757158163331],"hsluv":[12.1770506300617907,82.128221128038831,37.4939757158163331]},"#aa2233":{"lch":[37.7176061419824791,98.5638584928897359,8.82735266140639],"luv":[37.7176061419824791,97.3963926843060506,15.125372494284127],"rgb":[0.66666666666666663,0.133333333333333331,0.2],"xyz":[0.177466736278419523,0.0993061132255764617,0.0411443792732099634],"hpluv":[8.82735266140639,331.598763076121088,37.7176061419824791],"hsluv":[8.82735266140639,82.8309253801110401,37.7176061419824791]},"#aa2244":{"lch":[38.0372287502177358,92.5577577991589209,3.83362915136278648],"luv":[38.0372287502177358,92.350650343690134,6.18836892123021798],"rgb":[0.66666666666666663,0.133333333333333331,0.266666666666666663],"xyz":[0.181924731522638411,0.101089311323264042,0.0646231542260966],"hpluv":[3.83362915136278648,308.775819843535,38.0372287502177358],"hsluv":[3.83362915136278648,83.7532195801290698,38.0372287502177358]},"#aa2255":{"lch":[38.4588905236098242,86.4856662057644172,356.973865768881865],"luv":[38.4588905236098242,86.3650670431288603,-4.56570407393633459],"rgb":[0.66666666666666663,0.133333333333333331,0.333333333333333315],"xyz":[0.187887145562000424,0.103474276939008875,0.0960252015000705],"hpluv":[356.973865768881865,285.355803984318584,38.4588905236098242],"hsluv":[356.973865768881865,84.8422496447961,38.4588905236098242]},"#aa2266":{"lch":[38.9860395203518237,81.4924101374980268,348.227712846231327],"luv":[38.9860395203518237,79.7783138580272464,-16.6262908668256522],"rgb":[0.66666666666666663,0.133333333333333331,0.4],"xyz":[0.195472141335508581,0.106508275248412193,0.135972845907214479],"hpluv":[348.227712846231327,265.245100213362434,38.9860395203518237],"hsluv":[348.227712846231327,86.0332228090823747,38.9860395203518237]},"#aa2277":{"lch":[39.619833929041036,78.6591168776988354,337.990195281021442],"luv":[39.619833929041036,72.9264197190586572,-29.4787037526953952],"rgb":[0.66666666666666663,0.133333333333333331,0.466666666666666674],"xyz":[0.204786154355710515,0.110233880456493,0.185026647813612388],"hpluv":[337.990195281021442,251.92759566726761,39.619833929041036],"hsluv":[337.990195281021442,87.2621982611374278,39.619833929041036]},"#aa2288":{"lch":[40.3594266716885386,78.6767938432408,327.148786779116733],"luv":[40.3594266716885386,66.0949636498191637,-42.6789605025813046],"rgb":[0.66666666666666663,0.133333333333333331,0.533333333333333326],"xyz":[0.215926571457654315,0.1146900472972706,0.243699511217184556],"hpluv":[327.148786779116733,247.366561360315984,40.3594266716885386],"hsluv":[327.148786779116733,88.4751585260979283,40.3594266716885386]},"#aa2299":{"lch":[41.2022629883412748,81.6302410017403162,316.790315261789033],"luv":[41.2022629883412748,59.4964385039503,-55.8898027492302489],"rgb":[0.66666666666666663,0.133333333333333331,0.6],"xyz":[0.228983535566727042,0.119912832940899758,0.312466188858302463],"hpluv":[316.790315261789033,251.402351399829286,41.2022629883412748],"hsluv":[316.790315261789033,89.6322731802278554,41.2022629883412748]},"#aa22aa":{"lch":[42.1443943233873242,87.0780915666379229,307.715012949243715],"luv":[42.1443943233873242,53.2686588598376076,-68.8842798769212834],"rgb":[0.66666666666666663,0.133333333333333331,0.66666666666666663],"xyz":[0.24404122853197957,0.125935910127000866,0.391770038475301063],"hpluv":[307.715012949243715,262.185344504614818,42.1443943233873242],"hsluv":[307.715012949243715,90.7081440057972515,42.1443943233873242]},"#aa22bb":{"lch":[43.1807973125030387,94.3504956605328573,300.218008125398399],"luv":[43.1807973125030387,47.4858085519839577,-81.5298351375283801],"rgb":[0.66666666666666663,0.133333333333333331,0.733333333333333282],"xyz":[0.261178820639316245,0.132790946969935625,0.48202802357394281],"hpluv":[300.218008125398399,277.263598469343151,43.1807973125030387],"hsluv":[300.218008125398399,91.6896384965505291,43.1807973125030387]},"#aa22cc":{"lch":[44.3056820912093627,102.813108633557576,294.217612554784239],"luv":[44.3056820912093627,42.1742864712375294,-93.764944769021767],"rgb":[0.66666666666666663,0.133333333333333331,0.8],"xyz":[0.280471196083037944,0.140507897147424426,0.583634534244213],"hpluv":[294.217612554784239,294.461411899371626,44.3056820912093627],"hsluv":[294.217612554784239,92.5728114271618097,44.3056820912093627]},"#aa22dd":{"lch":[45.5127751844210451,111.980933923074502,289.471886144522102],"luv":[45.5127751844210451,37.3282042805071441,-105.576203414769125],"rgb":[0.66666666666666663,0.133333333333333331,0.866666666666666696],"xyz":[0.301989521633671543,0.14911522736767796,0.696964382144219],"hpluv":[289.471886144522102,312.212361278410071,45.5127751844210451],"hsluv":[289.471886144522102,93.3598993754704622,45.5127751844210451]},"#aa22ee":{"lch":[46.7955661660676938,121.524022862348417,285.718434714393425],"luv":[46.7955661660676938,32.9220942551774698,-116.979587289842115],"rgb":[0.66666666666666663,0.133333333333333331,0.933333333333333348],"xyz":[0.325801701899846252,0.158640099474147978,0.822375198212742187],"hpluv":[285.718434714393425,329.531365671141714,46.7955661660676938],"hsluv":[285.718434714393425,94.0568560040361348,46.7955661660676938]},"#aa22ff":{"lch":[48.1475121680676921,131.233078667623346,282.730941389390409],"luv":[48.1475121680676921,28.9202258451599548,-128.006802450680539],"rgb":[0.66666666666666663,0.133333333333333331,1],"xyz":[0.351972750309677673,0.169108518838080701,0.960209386504524],"hpluv":[282.730941389390409,345.866733454918517,48.1475121680676921],"hsluv":[282.730941389390409,99.9999999999992,48.1475121680676921]},"#883300":{"lch":[33.1414787667816597,73.2165592554870841,22.9600016117944072],"luv":[33.1414787667816597,67.4161530625393084,28.5609323282788417],"rgb":[0.533333333333333326,0.2,0],"xyz":[0.113368907986088716,0.076027497524815621,0.00870518857569610102],"hpluv":[22.9600016117944072,280.334636286210525,33.1414787667816597],"hsluv":[22.9600016117944072,100.000000000002245,33.1414787667816597]},"#883311":{"lch":[33.2285118286029402,71.0572306739368287,21.2511434941679589],"luv":[33.2285118286029402,66.2253841559006844,25.7551650053430592],"rgb":[0.533333333333333326,0.2,0.0666666666666666657],"xyz":[0.114380573485725834,0.0764321637246704738,0.0140332935404517325],"hpluv":[21.2511434941679589,271.354302974885854,33.2285118286029402],"hsluv":[21.2511434941679589,91.7325092821930355,33.2285118286029402]},"#883322":{"lch":[33.389038834633638,67.403958774683133,17.9527330699243208],"luv":[33.389038834633638,64.1221355411587126,20.7760774002325519],"rgb":[0.533333333333333326,0.2,0.133333333333333331],"xyz":[0.116255931624202863,0.0771823069800612882,0.0239101797364309268],"hpluv":[17.9527330699243208,256.165602847605,33.389038834633638],"hsluv":[17.9527330699243208,77.1564226992543354,33.389038834633638]},"#883333":{"lch":[33.6510932573449324,62.3280121609532785,12.1770506300618564],"luv":[33.6510932573449324,60.9256605799824484,13.1470522486492083],"rgb":[0.533333333333333326,0.2,0.2],"xyz":[0.119343682356660596,0.0784174072730444,0.04017233359404207],"hpluv":[12.1770506300618564,235.030067027939708,33.6510932573449324],"hsluv":[12.1770506300618564,55.0748296144977,33.6510932573449324]},"#883344":{"lch":[34.0246284162643136,56.9037682047597428,3.23132728809417369],"luv":[34.0246284162643136,56.8132965471078748,3.20751794249172528],"rgb":[0.533333333333333326,0.2,0.266666666666666663],"xyz":[0.12380167760087947,0.080200605370731981,0.0636511085469287086],"hpluv":[3.23132728809417369,212.220318588139889,34.0246284162643136],"hsluv":[3.23132728809417369,58.083398150148156,34.0246284162643136]},"#883355":{"lch":[34.5156618951709859,52.7529688087382524,350.767304332875],"luv":[34.5156618951709859,52.0695471674777721,-8.46392201697997137],"rgb":[0.533333333333333326,0.2,0.333333333333333315],"xyz":[0.129764091640241469,0.0825855709864768139,0.0950531558209026239],"hpluv":[350.767304332875,193.941176615342812,34.5156618951709859],"hsluv":[350.767304332875,61.5291535706030714,34.5156618951709859]},"#883366":{"lch":[35.1268460128593318,51.5738240122621576,335.705329263136434],"luv":[35.1268460128593318,47.0065260432940519,-21.2189969741481157],"rgb":[0.533333333333333326,0.2,0.4],"xyz":[0.137349087413749654,0.0856195692958801324,0.135000800228046586],"hpluv":[335.705329263136434,186.307141954737205,35.1268460128593318],"hsluv":[335.705329263136434,65.1713869724459869,35.1268460128593318]},"#883377":{"lch":[35.8579115963162849,54.2604071268956929,320.552373035814298],"luv":[35.8579115963162849,41.9001950458929713,-34.4755773946224],"rgb":[0.533333333333333326,0.2,0.466666666666666674],"xyz":[0.14666310043395156,0.0893451745039609418,0.184054602134444495],"hpluv":[320.552373035814298,192.015984070736607,35.8579115963162849],"hsluv":[320.552373035814298,68.798738775930957,35.8579115963162849]},"#883388":{"lch":[36.7061150242973682,60.4128011412536097,307.715012949244056],"luv":[36.7061150242973682,36.9565850245806402,-47.7903480323547711],"rgb":[0.533333333333333326,0.2,0.533333333333333326],"xyz":[0.157803517535895388,0.0938013413447385397,0.242727465538016662],"hpluv":[307.715012949244056,208.847787272345244,36.7061150242973682],"hsluv":[307.715012949244056,72.2549736675254479,36.7061150242973682]},"#883399":{"lch":[37.6667130487112445,68.9141309342046213,297.955533412138379],"luv":[37.6667130487112445,32.3059919210196611,-60.8726566564636684],"rgb":[0.533333333333333326,0.2,0.6],"xyz":[0.170860481644968087,0.0990241269883677,0.311494143179134542],"hpluv":[297.955533412138379,232.161331922109071,37.6667130487112445],"hsluv":[297.955533412138379,75.4431641885032604,37.6667130487112445]},"#8833aa":{"lch":[38.7334497692602824,78.7159372772915162,290.848124870138179],"luv":[38.7334497692602824,28.0143748789862741,-73.5621749378178436],"rgb":[0.533333333333333326,0.2,0.66666666666666663],"xyz":[0.185918174610220643,0.105047204174468806,0.390797992796133142],"hpluv":[290.848124870138179,257.878905714084965,38.7334497692602824],"hsluv":[290.848124870138179,78.3166072053086282,38.7334497692602824]},"#8833bb":{"lch":[39.8990272727434743,89.1142300257769193,285.691107407551272],"luv":[39.8990272727434743,24.1010351313191435,-85.7932753698447073],"rgb":[0.533333333333333326,0.2,0.733333333333333282],"xyz":[0.20305576671755729,0.111902241017403564,0.481055977894774889],"hpluv":[285.691107407551272,283.415812953045702,39.8990272727434743],"hsluv":[285.691107407551272,80.8649153118493444,39.8990272727434743]},"#8833cc":{"lch":[41.1555326498064318,99.7027359993818578,281.897918690971494],"luv":[41.1555326498064318,20.5555775093346966,-97.560769774639283],"rgb":[0.533333333333333326,0.2,0.8],"xyz":[0.222348142161279017,0.119619191194892366,0.5826624885650451],"hpluv":[281.897918690971494,307.410130900702256,41.1555326498064318],"hsluv":[281.897918690971494,83.1006969987668356,41.1555326498064318]},"#8833dd":{"lch":[42.4948021164729042,110.266949448261684,279.053462184119098],"luv":[42.4948021164729042,17.3511661022166734,-108.893237510502843],"rgb":[0.533333333333333326,0.2,0.866666666666666696],"xyz":[0.24386646771191256,0.1282265214151459,0.695992336465051098],"hpluv":[279.053462184119098,329.267506795456711,42.4948021164729042],"hsluv":[279.053462184119098,85.0491409670088103,42.4948021164729042]},"#8833ee":{"lch":[43.9087129541284185,120.703343561802441,276.877390721452173],"luv":[43.9087129541284185,14.4536316684396038,-119.834843341123431],"rgb":[0.533333333333333326,0.2,0.933333333333333348],"xyz":[0.267678647978087325,0.137751393521615917,0.821403152533574321],"hpluv":[276.877390721452173,348.825254458779511,43.9087129541284185],"hsluv":[276.877390721452173,90.7214777394212177,43.9087129541284185]},"#8833ff":{"lch":[45.3894029264418037,130.969293653816607,275.181129330284705],"luv":[45.3894029264418037,11.8271264623124566,-130.43417864894198],"rgb":[0.533333333333333326,0.2,1],"xyz":[0.293849696387918691,0.148219812885548641,0.959237340825356166],"hpluv":[275.181129330284705,366.146040402293636,45.3894029264418037],"hsluv":[275.181129330284705,99.9999999999993179,45.3894029264418037]},"#ffbb00":{"lch":[80.0686585320779614,99.7432534700870832,55.1804439586775146],"luv":[80.0686585320779614,56.9527800089419642,81.8846595037867928],"rgb":[1,0.733333333333333282,0],"xyz":[0.590086256022839262,0.568029919385293569,0.0785626376345524291],"hpluv":[55.1804439586775146,207.400278899961506,80.0686585320779614],"hsluv":[55.1804439586775146,100.000000000004661,80.0686585320779614]},"#ffbb11":{"lch":[80.0914663159454,98.8408701901197304,54.9443852376931758],"luv":[80.0914663159454,56.7713575947746136,80.9106332739172558],"rgb":[1,0.733333333333333282,0.0666666666666666657],"xyz":[0.591097921522476422,0.568434585585148477,0.0838907425993080658],"hpluv":[54.9443852376931758,205.801067903733326,80.0914663159454],"hsluv":[54.9443852376931758,100.000000000004746,80.0914663159454]},"#ffbb22":{"lch":[80.1337172522408849,97.1832370837577173,54.4980435584705063],"luv":[80.1337172522408849,56.4372945908461148,79.11645435270664],"rgb":[1,0.733333333333333282,0.133333333333333331],"xyz":[0.592973279660953367,0.569184728840539278,0.0937676287952872584],"hpluv":[54.4980435584705063,202.856099527528187,80.1337172522408849],"hsluv":[54.4980435584705063,100.00000000000469,80.1337172522408849]},"#ffbb33":{"lch":[80.2032020182086569,94.4967793168558643,53.7374633716008248],"luv":[80.2032020182086569,55.8935303906135772,76.1941898161015558],"rgb":[1,0.733333333333333282,0.2],"xyz":[0.596061030393411184,0.570419829133522405,0.110029782652898395],"hpluv":[53.7374633716008248,198.062979410590685,80.2032020182086569],"hsluv":[53.7374633716008248,100.000000000004576,80.2032020182086569]},"#ffbb44":{"lch":[80.3033451682561,90.7120739700224874,52.5796541788809932],"luv":[80.3033451682561,55.1219083097901148,72.0434284874749835],"rgb":[1,0.733333333333333282,0.266666666666666663],"xyz":[0.60051902563763,0.57220302723121,0.133508557605785033],"hpluv":[52.5796541788809932,191.266883403483888,80.3033451682561],"hsluv":[52.5796541788809932,100.000000000004732,80.3033451682561]},"#ffbb55":{"lch":[80.4369584648287343,85.824023801574981,50.9113466162360169],"luv":[80.4369584648287343,54.1139445833304435,66.614143116349922],"rgb":[1,0.733333333333333282,0.333333333333333315],"xyz":[0.606481439676992,0.57458799284695472,0.164910604879758949],"hpluv":[50.9113466162360169,182.412290123698938,80.4369584648287343],"hsluv":[50.9113466162360169,100.000000000004846,80.4369584648287343]},"#ffbb66":{"lch":[80.6063993458739532,79.8959983704508545,48.5678239065140147],"luv":[80.6063993458739532,52.8698192869345931,59.9011916757752374],"rgb":[1,0.733333333333333282,0.4],"xyz":[0.614066435450500214,0.577621991156358,0.20485824928690291],"hpluv":[48.5678239065140147,171.553596694327723,80.6063993458739532],"hsluv":[48.5678239065140147,100.000000000004945,80.6063993458739532]},"#ffbb77":{"lch":[80.8136549908608828,73.0715029906331353,45.3006510664637219],"luv":[80.8136549908608828,51.397517928562209,51.9397699272266067],"rgb":[1,0.733333333333333282,0.466666666666666674],"xyz":[0.623380448470702064,0.58134759636443889,0.253912051193300847],"hpluv":[45.3006510664637219,158.885762577352,80.8136549908608828],"hsluv":[45.3006510664637219,100.000000000005144,80.8136549908608828]},"#ffbb88":{"lch":[81.0603921498240823,65.5982066090816,40.7273497798256443],"luv":[81.0603921498240823,49.7118280718431649,42.8002203275083914],"rgb":[1,0.733333333333333282,0.533333333333333326],"xyz":[0.634520865572646,0.585803763205216432,0.312584914596873],"hpluv":[40.7273497798256443,144.809180382553194,81.0603921498240823],"hsluv":[40.7273497798256443,100.0000000000054,81.0603921498240823]},"#ffbb99":{"lch":[81.347989327564818,57.8755898316684423,34.2609783084776538],"luv":[81.347989327564818,47.8331272298795724,32.5818329406692087],"rgb":[1,0.733333333333333282,0.6],"xyz":[0.64757782968171862,0.591026548848845645,0.381351592237990866],"hpluv":[34.2609783084776538,130.060421106466862,81.347989327564818],"hsluv":[34.2609783084776538,100.000000000005514,81.347989327564818]},"#ffbbaa":{"lch":[81.6775593509345725,50.5427251754064883,25.056975338279841],"luv":[81.6775593509345725,45.7860019440054415,21.405819165362459],"rgb":[1,0.733333333333333282,0.66666666666666663],"xyz":[0.662635522646971231,0.597049626034946712,0.460655441854989522],"hpluv":[25.056975338279841,115.96007016550756,81.6775593509345725],"hsluv":[25.056975338279841,100.000000000005954,81.6775593509345725]},"#ffbbbb":{"lch":[82.0499666293022,44.6012959670408264,12.1770506300623094],"luv":[82.0499666293022,43.5977873399533138,9.40789779917804125],"rgb":[1,0.733333333333333282,0.733333333333333282],"xyz":[0.679773114754307795,0.603904662877881471,0.550913426953631213],"hpluv":[12.1770506300623094,104.793068167285782,82.0499666293022],"hsluv":[12.1770506300623094,100.000000000006168,82.0499666293022]},"#ffbbcc":{"lch":[82.4658415859876,41.4263127316455169,355.474040938847054],"luv":[82.4658415859876,41.2971323922898534,-3.26898190783910625],"rgb":[1,0.733333333333333282,0.8],"xyz":[0.699065490198029549,0.611621613055370328,0.652519937623901369],"hpluv":[355.474040938847054,100.004408983591958,82.4658415859876],"hsluv":[355.474040938847054,100.000000000006509,82.4658415859876]},"#ffbbdd":{"lch":[82.9255937413379,42.2590852539423381,337.045135839305544],"luv":[82.9255937413379,38.9126886018087319,-16.4812909773061058],"rgb":[1,0.733333333333333282,0.866666666666666696],"xyz":[0.720583815748663148,0.620228943275623834,0.765849785523907367],"hpluv":[337.045135839305544,105.181583048825317,82.9255937413379],"hsluv":[337.045135839305544,100.000000000006992,82.9255937413379]},"#ffbbee":{"lch":[83.4294243398036315,47.2826492521794748,320.476273654572083],"luv":[83.4294243398036315,36.4719970678196077,-30.0905691237235686],"rgb":[1,0.733333333333333282,0.933333333333333348],"xyz":[0.744395996014837857,0.629753815382093851,0.89126060159243059],"hpluv":[320.476273654572083,121.793886282549721,83.4294243398036315],"hsluv":[320.476273654572083,100.000000000007375,83.4294243398036315]},"#ffbbff":{"lch":[83.9773390427358493,55.5806936350452148,307.715012949246614],"luv":[83.9773390427358493,34.0006189291922496,-43.9678452665650781],"rgb":[1,0.733333333333333282,1],"xyz":[0.770567044424669279,0.640222234746026575,1.02909478988421244],"hpluv":[307.715012949246614,148.765749509941259,83.9773390427358493],"hsluv":[307.715012949246614,100.00000000000793,83.9773390427358493]},"#aa3300":{"lch":[39.4372171279304595,100.717281062042773,18.6056676884160446],"luv":[39.4372171279304595,95.4534790945485838,32.1341568004684959],"rgb":[0.66666666666666663,0.2,0],"xyz":[0.177609683996858475,0.109151647655369471,0.0117164749512008691],"hpluv":[18.6056676884160446,324.068678498457416,39.4372171279304595],"hsluv":[18.6056676884160446,100.00000000000226,39.4372171279304595]},"#aa3311":{"lch":[39.5056415087576553,98.9056898290362199,17.5539290045831464],"luv":[39.5056415087576553,94.2999972712563,29.8302865423477179],"rgb":[0.66666666666666663,0.2,0.0666666666666666657],"xyz":[0.178621349496495607,0.109556313855224324,0.0170445799159565023],"hpluv":[17.5539290045831464,317.688492914835,39.5056415087576553],"hsluv":[17.5539290045831464,94.2489803369173558,39.5056415087576553]},"#aa3322":{"lch":[39.6320377265530155,95.7434230458582789,15.5633947922033684],"luv":[39.6320377265530155,92.2329117474569102,25.688383505468213],"rgb":[0.66666666666666663,0.2,0.133333333333333331],"xyz":[0.180496707634972609,0.110306457110615139,0.0269214661119356949],"hpluv":[15.5633947922033684,306.55039093266322,39.6320377265530155],"hsluv":[15.5633947922033684,83.9544037116345123,39.6320377265530155]},"#aa3333":{"lch":[39.8389046640011415,91.0660982539230162,12.1770506300618351],"luv":[39.8389046640011415,89.0171529654153488,19.2088711049089049],"rgb":[0.66666666666666663,0.2,0.2],"xyz":[0.18358445836743037,0.111541557403598252,0.0431836199695468381],"hpluv":[12.1770506300618351,290.060550373943784,39.8389046640011415],"hsluv":[12.1770506300618351,67.9701775681036366,39.8389046640011415]},"#aa3344":{"lch":[40.1348956250933142,85.3951569144799691,7.07959423789482756],"luv":[40.1348956250933142,84.7440953003879116,10.5247867516366789],"rgb":[0.66666666666666663,0.2,0.266666666666666663],"xyz":[0.18804245361164923,0.113324755501285832,0.0666623949224334766],"hpluv":[7.07959423789482756,269.991710008472637,40.1348956250933142],"hsluv":[7.07959423789482756,69.5294395234689659,40.1348956250933142]},"#aa3355":{"lch":[40.5259588707466,79.61783322386637,359.98582832830067],"luv":[40.5259588707466,79.6178307884273693,-0.0196928603108827253],"rgb":[0.66666666666666663,0.2,0.333333333333333315],"xyz":[0.194004867651011215,0.115709721117030664,0.098064442196407392],"hpluv":[359.98582832830067,249.296614878837403,40.5259588707466],"hsluv":[359.98582832830067,71.3920974276079079,40.5259588707466]},"#aa3366":{"lch":[41.0157539995587683,74.8661602955128558,350.806369630673316],"luv":[41.0157539995587683,73.9044320805857,-11.9614746682639641],"rgb":[0.66666666666666663,0.2,0.4],"xyz":[0.2015898634245194,0.118743719426433983,0.138012086603551354],"hpluv":[350.806369630673316,231.619002340768361,41.0157539995587683],"hsluv":[350.806369630673316,73.4562780141226597,41.0157539995587683]},"#aa3377":{"lch":[41.6059173351841167,72.2728884464882668,339.921631600955322],"luv":[41.6059173351841167,67.8804264173117531,-24.8116527825629412],"rgb":[0.66666666666666663,0.2,0.466666666666666674],"xyz":[0.210903876444721305,0.122469324634514792,0.187065888509949263],"hpluv":[339.921631600955322,220.424384448141751,41.6059173351841167],"hsluv":[339.921631600955322,75.6166865764569138,41.6059173351841167]},"#aa3388":{"lch":[42.296293156356171,72.6091331125239918,328.324027314743319],"luv":[42.296293156356171,61.7926517819245191,-38.1281313089174],"rgb":[0.66666666666666663,0.2,0.533333333333333326],"xyz":[0.222044293546665161,0.12692549147529239,0.24573875191352143],"hpluv":[328.324027314743319,217.83530631356345,42.296293156356171],"hsluv":[328.324027314743319,77.7798333688196237,42.296293156356171]},"#aa3399":{"lch":[43.0851702185186838,75.9982874692542794,317.281450106519685],"luv":[43.0851702185186838,55.835561651799118,-51.5570533805758799],"rgb":[0.66666666666666663,0.2,0.6],"xyz":[0.235101257655737861,0.132148277118921548,0.314505429554639337],"hpluv":[317.281450106519685,223.828466633931441,43.0851702185186838],"hsluv":[317.281450106519685,79.8726039522015441,43.0851702185186838]},"#aa33aa":{"lch":[43.9695321467927229,81.9717995507402861,307.715012949243828],"luv":[43.9695321467927229,50.1449646844158607,-64.8448798162617521],"rgb":[0.66666666666666663,0.2,0.66666666666666663],"xyz":[0.250158950620990417,0.138171354305022642,0.393809279171637938],"hpluv":[307.715012949243828,236.565795567314069,43.9695321467927229],"hsluv":[307.715012949243828,81.8445603498948628,43.9695321467927229]},"#aa33bb":{"lch":[44.9453163823579231,89.8045713491188593,299.92695612823394],"luv":[44.9453163823579231,44.8030997809084,-77.8302208992172],"rgb":[0.66666666666666663,0.2,0.733333333333333282],"xyz":[0.267296542728327036,0.145026391147957401,0.484067264270279685],"hpluv":[299.92695612823394,253.543994890590483,44.9453163823579231],"hsluv":[299.92695612823394,83.6659201788580305,44.9453163823579231]},"#aa33cc":{"lch":[46.0076707905516145,98.8168321279874249,293.782406660809556],"luv":[46.0076707905516145,39.8493034294229815,-90.425656359246986],"rgb":[0.66666666666666663,0.2,0.8],"xyz":[0.28658891817204879,0.152743341325446202,0.585673774940549841],"hpluv":[293.782406660809556,272.546121846523647,46.0076707905516145],"hsluv":[293.782406660809556,85.323407183561244,46.0076707905516145]},"#aa33dd":{"lch":[47.1511962508372804,108.497592079042477,288.982430572084695],"luv":[47.1511962508372804,35.2919015872993782,-102.597315604759743],"rgb":[0.66666666666666663,0.2,0.866666666666666696],"xyz":[0.308107243722682334,0.161350671545699736,0.699003622840555838],"hpluv":[288.982430572084695,291.989148013150611,47.1511962508372804],"hsluv":[288.982430572084695,86.8156421407842771,47.1511962508372804]},"#aa33ee":{"lch":[48.3701654903461247,118.505438755587946,285.224041333998457],"luv":[48.3701654903461247,31.1188262963008349,-114.346655677352729],"rgb":[0.66666666666666663,0.2,0.933333333333333348],"xyz":[0.331919423988857099,0.170875543652169781,0.824414438909079061],"hpluv":[285.224041333998457,310.885191630161273,48.3701654903461247],"hsluv":[285.224041333998457,89.3017266962351215,48.3701654903461247]},"#aa33ff":{"lch":[49.6587116356326135,128.627945638670809,282.256374557143658],"luv":[49.6587116356326135,27.305962831451918,-125.696192436653462],"rgb":[0.66666666666666663,0.2,1],"xyz":[0.358090472398688464,0.181343963016102477,0.962248627200860907],"hpluv":[282.256374557143658,328.684490794403757,49.6587116356326135],"hsluv":[282.256374557143658,99.9999999999991616,49.6587116356326135]},"#884400":{"lch":[36.685747441671559,64.5393704655657814,31.8123524502136021],"luv":[36.685747441671559,54.844205976921188,34.0212200082916922],"rgb":[0.533333333333333326,0.266666666666666663,0],"xyz":[0.122201478469054756,0.093692638490747937,0.0116493787366846978],"hpluv":[31.8123524502136021,223.237258003095718,36.685747441671559],"hsluv":[31.8123524502136021,100.000000000002245,36.685747441671559]},"#884411":{"lch":[36.7614898568215622,62.4864851085245405,30.2058215583615599],"luv":[36.7614898568215622,54.0023006087270119,31.4374354899146],"rgb":[0.533333333333333326,0.266666666666666663,0.0666666666666666657],"xyz":[0.123213143968691874,0.0940973046906027899,0.016977483701440331],"hpluv":[30.2058215583615599,215.691146343233044,36.7614898568215622],"hsluv":[30.2058215583615599,93.206231917801162,36.7614898568215622]},"#884422":{"lch":[36.9013237077522405,58.9550348899468375,27.0578850153250627],"luv":[36.9013237077522405,52.5022536375556825,26.8180816214102],"rgb":[0.533333333333333326,0.266666666666666663,0.133333333333333331],"xyz":[0.125088502107168903,0.0948474479459936,0.0268543698974195236],"hpluv":[27.0578850153250627,202.730122118290922,36.9013237077522405],"hsluv":[27.0578850153250627,81.1214838671569822,36.9013237077522405]},"#884433":{"lch":[37.1299605496210461,53.9021323280231357,21.3870333458705382],"luv":[37.1299605496210461,50.1903435049312,19.6562785990819577],"rgb":[0.533333333333333326,0.266666666666666663,0.2],"xyz":[0.128176252839626637,0.0960825482389767171,0.0431165237550306668],"hpluv":[21.3870333458705382,184.213216030002656,37.1299605496210461],"hsluv":[21.3870333458705382,62.5495295304316272,37.1299605496210461]},"#884444":{"lch":[37.4566279620983806,48.2433933618324389,12.1770506300619505],"luv":[37.4566279620983806,47.157939219998795,10.1761373608750691],"rgb":[0.533333333333333326,0.266666666666666663,0.266666666666666663],"xyz":[0.132634248083845524,0.0978657463366643,0.0665952987079173],"hpluv":[12.1770506300619505,163.436290620587812,37.4566279620983806],"hsluv":[12.1770506300619505,38.2981887065726,37.4566279620983806]},"#884455":{"lch":[37.8873893879065804,43.5926938841600631,358.470393497241901],"luv":[37.8873893879065804,43.5771602849424937,-1.16364151632571566],"rgb":[0.533333333333333326,0.266666666666666663,0.333333333333333315],"xyz":[0.138596662123207509,0.10025071195240913,0.0979973459818912207],"hpluv":[358.470393497241901,146.001848007416612,37.8873893879065804],"hsluv":[358.470393497241901,42.6300163695831245,37.8873893879065804]},"#884466":{"lch":[38.425613648805637,41.9872152878557756,340.815857604715632],"luv":[38.425613648805637,39.6555541095459816,-13.7972198610307206],"rgb":[0.533333333333333326,0.266666666666666663,0.4],"xyz":[0.146181657896715694,0.103284710261812449,0.137944990389035183],"hpluv":[340.815857604715632,138.655016432961,38.425613648805637],"hsluv":[340.815857604715632,47.3337116796912767,38.425613648805637]},"#884477":{"lch":[39.0722986805963117,44.7783217464764363,322.645837420375756],"luv":[39.0722986805963117,35.5943002873345478,-27.1688035343115608],"rgb":[0.533333333333333326,0.266666666666666663,0.466666666666666674],"xyz":[0.1554956709169176,0.107010315469893258,0.186998792295433092],"hpluv":[322.645837420375756,145.424700121889231,39.0722986805963117],"hsluv":[322.645837420375756,52.1510622716411,39.0722986805963117]},"#884488":{"lch":[39.8263740522966856,51.5911203050634839,307.71501294924451],"luv":[39.8263740522966856,31.5600599218946343,-40.8118403414738609],"rgb":[0.533333333333333326,0.266666666666666663,0.533333333333333326],"xyz":[0.166636088018861428,0.111466482310670856,0.245671655699005259],"hpluv":[307.71501294924451,164.377933698467302,39.8263740522966856],"hsluv":[307.71501294924451,56.8697587177058,39.8263740522966856]},"#884499":{"lch":[40.6850187117946192,61.0189075542410393,296.969581150574243],"luv":[40.6850187117946192,27.6731358367265301,-54.3829443123034295],"rgb":[0.533333333333333326,0.266666666666666663,0.6],"xyz":[0.179693052127934128,0.116689267954300013,0.314438333340123166],"hpluv":[296.969581150574243,190.313341437332326,40.6850187117946192],"hsluv":[296.969581150574243,61.3383523001243134,40.6850187117946192]},"#8844aa":{"lch":[41.643995358805,71.7935926347933417,289.536616505740085],"luv":[41.643995358805,24.0084388126510113,-67.6602897510042141],"rgb":[0.533333333333333326,0.266666666666666663,0.66666666666666663],"xyz":[0.194750745093186683,0.122712345140401108,0.393742182957121767],"hpluv":[289.536616505740085,218.762371943685849,41.643995358805],"hsluv":[289.536616505740085,65.4647221474276506,41.643995358805]},"#8844bb":{"lch":[42.6979882651059626,83.1164887776927515,284.352541737053286],"luv":[42.6979882651059626,20.6035404121657031,-80.5223250360828757],"rgb":[0.533333333333333326,0.266666666666666663,0.733333333333333282],"xyz":[0.21188833720052333,0.129567381983335866,0.484000168055763513],"hpluv":[284.352541737053286,247.012596783276,42.6979882651059626],"hsluv":[284.352541737053286,69.2054262339616741,42.6979882651059626]},"#8844cc":{"lch":[43.840927241858644,94.5481620176080924,280.647262826657595],"luv":[43.840927241858644,17.4689172853010533,-92.9203522904814463],"rgb":[0.533333333333333326,0.266666666666666663,0.8],"xyz":[0.231180712644245057,0.137284332160824668,0.585606678726033669],"hpluv":[280.647262826657595,273.660859280114778,43.840927241858644],"hsluv":[280.647262826657595,72.5522514276637764,43.840927241858644]},"#8844dd":{"lch":[45.0662821798681108,105.864396975636453,277.925647559652191],"luv":[45.0662821798681108,14.5974213234566292,-104.853163222292139],"rgb":[0.533333333333333326,0.266666666666666663,0.866666666666666696],"xyz":[0.2526990381948786,0.145891662381078202,0.698936526626039667],"hpluv":[277.925647559652191,298.083215805211921,45.0662821798681108],"hsluv":[277.925647559652191,79.9664783418063649,45.0662821798681108]},"#8844ee":{"lch":[46.3673172023828,116.961454232737537,275.874868362231723],"luv":[46.3673172023828,11.97173240994087,-116.347150370524886],"rgb":[0.533333333333333326,0.266666666666666663,0.933333333333333348],"xyz":[0.276511218461053365,0.155416534487548247,0.82434734269456289],"hpluv":[275.874868362231723,320.088534026972411,46.3673172023828],"hsluv":[275.874868362231723,89.9071832422553,46.3673172023828]},"#8844ff":{"lch":[47.7372988913525091,127.801124524511906,274.29427304351259],"luv":[47.7372988913525091,9.5696272486796623,-127.442338585146516],"rgb":[0.533333333333333326,0.266666666666666663,1],"xyz":[0.302682266870884731,0.165884953851480943,0.962181530986344735],"hpluv":[274.29427304351259,339.716123682654541,47.7372988913525091],"hsluv":[274.29427304351259,99.9999999999992468,47.7372988913525091]},"#ffcc00":{"lch":[84.1983464973243,98.3335943421723613,63.5926937648685069],"luv":[84.1983464973243,43.7338065737115329,88.0729807536005751],"rgb":[1,0.8,0],"xyz":[0.628309999332456237,0.644477406004528408,0.0913038854044243842],"hpluv":[63.5926937648685069,267.385577483165775,84.1983464973243],"hsluv":[63.5926937648685069,100.000000000007688,84.1983464973243]},"#ffcc11":{"lch":[84.2193135631731877,97.4576917861448777,63.4272907637844199],"luv":[84.2193135631731877,43.5960552023901897,87.1629833075564164],"rgb":[1,0.8,0.0666666666666666657],"xyz":[0.629321664832093397,0.644882072204383316,0.0966319903691800208],"hpluv":[63.4272907637844199,265.403720884510847,84.2193135631731877],"hsluv":[63.4272907637844199,100.000000000007645,84.2193135631731877]},"#ffcc22":{"lch":[84.2581577251319516,95.845309095571892,63.1144413478925301],"luv":[84.2581577251319516,43.342199386504106,85.4855369519677168],"rgb":[1,0.8,0.133333333333333331],"xyz":[0.631197022970570343,0.645632215459774117,0.106508876565159213],"hpluv":[63.1144413478925301,261.744085553517664,84.2581577251319516],"hsluv":[63.1144413478925301,100.00000000000766,84.2581577251319516]},"#ffcc33":{"lch":[84.3220485899852719,93.2224175872051148,62.5809741236821822],"luv":[84.3220485899852719,42.9284172035605494,82.7500461462124832],"rgb":[1,0.8,0.2],"xyz":[0.63428477370302816,0.646867315752757244,0.12277103042277035],"hpluv":[62.5809741236821822,255.758846695652977,84.3220485899852719],"hsluv":[62.5809741236821822,100.000000000007859,84.3220485899852719]},"#ffcc44":{"lch":[84.41414885501203,89.5051620308737,61.7678249437873745],"luv":[84.41414885501203,42.3400226901080785,78.8574442191356439],"rgb":[1,0.8,0.266666666666666663],"xyz":[0.638742768947247,0.64865051385044481,0.146249805375657],"hpluv":[61.7678249437873745,247.206609954939694,84.41414885501203],"hsluv":[61.7678249437873745,100.000000000007887,84.41414885501203]},"#ffcc55":{"lch":[84.5370662928161,84.6613331238571476,60.5932597011580469],"luv":[84.5370662928161,41.569242864558305,73.7532329730438221],"rgb":[1,0.8,0.333333333333333315],"xyz":[0.644705182986609,0.651035479466189559,0.177651852649630904],"hpluv":[60.5932597011580469,235.935294148211483,84.5370662928161],"hsluv":[60.5932597011580469,100.000000000008015,84.5370662928161]},"#ffcc66":{"lch":[84.6930007913096,78.7104448491835456,58.9357730127494222],"luv":[84.6930007913096,40.6144802919859131,67.4225342075500151],"rgb":[1,0.8,0.4],"xyz":[0.65229017876011719,0.654069477775592878,0.217599497056774865],"hpluv":[58.9357730127494222,221.881579382217893,84.6930007913096],"hsluv":[58.9357730127494222,100.000000000008285,84.6930007913096]},"#ffcc77":{"lch":[84.8838226897762809,71.7288671198513441,56.6053668146737863],"luv":[84.8838226897762809,39.4797505573258718,59.8863897244492378],"rgb":[1,0.8,0.466666666666666674],"xyz":[0.661604191780319,0.657795082983673729,0.266653298963172802],"hpluv":[56.6053668146737863,205.087229042099608,84.8838226897762809],"hsluv":[56.6053668146737863,100.000000000008399,84.8838226897762809]},"#ffcc88":{"lch":[85.1111193079521371,63.8628893840605159,53.2910582019814285],"luv":[85.1111193079521371,38.1740592359010691,51.1977523133063457],"rgb":[1,0.8,0.533333333333333326],"xyz":[0.672744608882263,0.662251249824451271,0.325326162366744942],"hpluv":[53.2910582019814285,185.743844227516831,85.1111193079521371],"hsluv":[53.2910582019814285,100.000000000008683,85.1111193079521371]},"#ffcc99":{"lch":[85.3762249003348899,55.3594884395636555,48.4608196634464292],"luv":[85.3762249003348899,36.710650975629143,41.436711563970924],"rgb":[1,0.8,0.6],"xyz":[0.685801572991335595,0.667474035468080484,0.394092840007862821],"hpluv":[48.4608196634464292,164.300705026796521,85.3762249003348899],"hsluv":[48.4608196634464292,100.000000000008811,85.3762249003348899]},"#ffccaa":{"lch":[85.6802414041430467,46.6394331206389836,41.1740083194267896],"luv":[85.6802414041430467,35.1061374539925311,30.7049806200222122],"rgb":[1,0.8,0.66666666666666663],"xyz":[0.700859265956588207,0.673497112654181551,0.473396689624861478],"hpluv":[41.1740083194267896,141.724192848301414,85.6802414041430467],"hsluv":[41.1740083194267896,100.000000000009393,85.6802414041430467]},"#ffccbb":{"lch":[86.0240539433014106,38.4677176438646384,29.8042196075727404],"luv":[86.0240539433014106,33.3795484258888635,19.1199123327444944],"rgb":[1,0.8,0.733333333333333282],"xyz":[0.71799685806392477,0.68035214949711631,0.563654674723503168],"hpluv":[29.8042196075727404,120.116808153279436,86.0240539433014106],"hsluv":[29.8042196075727404,100.000000000009621,86.0240539433014106]},"#ffcccc":{"lch":[86.4083433793485,32.2775975377643,12.1770506300627517],"luv":[86.4083433793485,31.5513664521307504,6.80841962670093892],"rgb":[1,0.8,0.8],"xyz":[0.737289233507646524,0.688069099674605167,0.665261185393773324],"hpluv":[12.1770506300627517,103.973607583717524,86.4083433793485],"hsluv":[12.1770506300627517,100.000000000010388,86.4083433793485]},"#ffccdd":{"lch":[86.8335972965778637,30.2635044437543748,348.373924949033096],"luv":[86.8335972965778637,29.6426074465171432,-6.09881340826452867],"rgb":[1,0.8,0.866666666666666696],"xyz":[0.758807559058280123,0.696676429894858673,0.778591033293779322],"hpluv":[348.373924949033096,100.994037434302086,86.8335972965778637],"hsluv":[348.373924949033096,100.000000000011042,86.8335972965778637]},"#ffccee":{"lch":[87.3001202800073344,33.8382691858854301,324.868297683069],"luv":[87.3001202800073344,27.6740002852911822,-19.4724977777928352],"rgb":[1,0.8,0.933333333333333348],"xyz":[0.782619739324454833,0.70620130200132869,0.904001849362302545],"hpluv":[324.868297683069,117.528800717138253,87.3001202800073344],"hsluv":[324.868297683069,100.000000000011482,87.3001202800073344]},"#ffccff":{"lch":[87.8080440143565255,41.9549825399590404,307.715012949248376],"luv":[87.8080440143565255,25.6653035474654807,-33.1890456889728],"rgb":[1,0.8,1],"xyz":[0.808790787734286254,0.716669721365261414,1.0418360376540845],"hpluv":[307.715012949248376,152.433043069806,87.8080440143565255],"hsluv":[307.715012949248376,100.000000000012506,87.8080440143565255]},"#aa4400":{"lch":[42.2796461632011074,91.196234940608619,23.7609213617016479],"luv":[42.2796461632011074,83.4659581293579578,36.7448921741641357],"rgb":[0.66666666666666663,0.266666666666666663,0],"xyz":[0.186442254479824487,0.126816788621301801,0.0146606651121894659],"hpluv":[23.7609213617016479,273.706361359402308,42.2796461632011074],"hsluv":[23.7609213617016479,100.000000000002331,42.2796461632011074]},"#aa4411":{"lch":[42.3415695164373815,89.5099073241138399,22.7237862619920179],"luv":[42.3415695164373815,82.5619515402106572,34.5766925405446202],"rgb":[0.66666666666666663,0.266666666666666663,0.0666666666666666657],"xyz":[0.18745391997946162,0.127221454821156654,0.0199887700769451],"hpluv":[22.7237862619920179,268.252316854423896,42.3415695164373815],"hsluv":[22.7237862619920179,95.0030043013494634,42.3415695164373815]},"#aa4422":{"lch":[42.4560124733741162,86.5487219398638,20.7501492775311753],"luv":[42.4560124733741162,80.9346773489764075,30.663647399501361],"rgb":[0.66666666666666663,0.266666666666666663,0.133333333333333331],"xyz":[0.189329278117938621,0.127971598076547483,0.0298656562729242916],"hpluv":[20.7501492775311753,258.678767688655569,42.4560124733741162],"hsluv":[20.7501492775311753,86.0172479577967692,42.4560124733741162]},"#aa4433":{"lch":[42.643470741830761,82.1252826930209494,17.3597256589108966],"luv":[42.643470741830761,78.3845002494828691,24.5037176372775498],"rgb":[0.66666666666666663,0.266666666666666663,0.2],"xyz":[0.192417028850396354,0.129206698369530582,0.0461278101305354349],"hpluv":[17.3597256589108966,244.378874013338617,42.643470741830761],"hsluv":[17.3597256589108966,71.9602068881057733,42.643470741830761]},"#aa4444":{"lch":[42.9120210749329871,76.685866981555165,12.1770506300619239],"luv":[42.9120210749329871,74.9604702767477704,16.1756017075590073],"rgb":[0.66666666666666663,0.266666666666666663,0.266666666666666663],"xyz":[0.196875024094615242,0.130989896467218175,0.0696065850834220734],"hpluv":[12.1770506300619239,226.764824908056937,42.9120210749329871],"hsluv":[12.1770506300619239,53.1380271992519795,42.9120210749329871]},"#aa4455":{"lch":[43.2674147484635299,71.0489272172787594,4.80785478807657096],"luv":[43.2674147484635299,70.7989329223205,5.9549270177674023],"rgb":[0.66666666666666663,0.266666666666666663,0.333333333333333315],"xyz":[0.202837438133977255,0.133374862082963,0.101008632357395989],"hpluv":[4.80785478807657096,208.370342069187018,43.2674147484635299],"hsluv":[4.80785478807657096,55.6796565441877931,43.2674147484635299]},"#aa4466":{"lch":[43.7134526285125489,66.3411716499448261,355.020980864279068],"luv":[43.7134526285125489,66.0908363196155477,-5.75781299290188],"rgb":[0.66666666666666663,0.266666666666666663,0.4],"xyz":[0.210422433907485412,0.136408860392366299,0.140956276764539951],"hpluv":[355.020980864279068,192.578302395247789,43.7134526285125489],"hsluv":[355.020980864279068,58.5402216503940949,43.7134526285125489]},"#aa4477":{"lch":[44.252209356870793,63.7921835342278598,343.127789968560137],"luv":[44.252209356870793,61.046215168807521,-18.5149208377531842],"rgb":[0.66666666666666663,0.266666666666666663,0.466666666666666674],"xyz":[0.219736446927687346,0.140134465600447122,0.19001007867093786],"hpluv":[343.127789968560137,182.924482874911519,44.252209356870793],"hsluv":[343.127789968560137,61.5848400189491372,44.252209356870793]},"#aa4488":{"lch":[44.8842146397509367,64.3242328637060865,330.281311898752961],"luv":[44.8842146397509367,55.8636578331810938,-31.8882214461946916],"rgb":[0.66666666666666663,0.266666666666666663,0.533333333333333326],"xyz":[0.230876864029631146,0.14459063244122472,0.248682942074510027],"hpluv":[330.281311898752961,181.852933643495049,44.8842146397509367],"hsluv":[330.281311898752961,64.6866121014520274,44.8842146397509367]},"#aa4499":{"lch":[45.6086312393750077,68.1395242873703779,318.091147538790551],"luv":[45.6086312393750077,50.7100032224043318,-45.5136281051387854],"rgb":[0.66666666666666663,0.266666666666666663,0.6],"xyz":[0.243933828138703873,0.149813418084853878,0.317449619715627906],"hpluv":[318.091147538790551,189.579504981677246,45.6086312393750077],"hsluv":[318.091147538790551,67.7395528675925,45.6086312393750077]},"#aa44aa":{"lch":[46.4234422285949293,74.7240378323112822,307.715012949244056],"luv":[46.4234422285949293,45.7112599542092468,-59.1114417296972476],"rgb":[0.66666666666666663,0.266666666666666663,0.66666666666666663],"xyz":[0.258991521103956401,0.155836495270954972,0.396753469332626507],"hpluv":[307.715012949244056,204.25011915803762,46.4234422285949293],"hsluv":[307.715012949244056,70.6643205278868862,46.4234422285949293]},"#aa44bb":{"lch":[47.3256474704596144,83.2556513741305224,299.464802712285689],"luv":[47.3256474704596144,40.9525224701243289,-72.4872015535482177],"rgb":[0.66666666666666663,0.266666666666666663,0.733333333333333282],"xyz":[0.276129113211293076,0.162691532113889731,0.487011454431268254],"hpluv":[299.464802712285689,223.2320179514779,47.3256474704596144],"hsluv":[299.464802712285689,73.4081717041738244,47.3256474704596144]},"#aa44cc":{"lch":[48.311463406953564,92.9774863668884564,293.103270963637385],"luv":[48.311463406953564,36.4834012629607827,-85.5206080625642073],"rgb":[0.66666666666666663,0.266666666666666663,0.8],"xyz":[0.29542148865501483,0.170408482291378532,0.58861796510153841],"hpluv":[293.103270963637385,244.211962975346665,48.311463406953564],"hsluv":[293.103270963637385,75.9413806031634806,48.311463406953564]},"#aa44dd":{"lch":[49.376518181476186,103.335675962773564,288.229438001673088],"luv":[49.376518181476186,32.3257723855767125,-98.1494083851717676],"rgb":[0.66666666666666663,0.266666666666666663,0.866666666666666696],"xyz":[0.316939814205648318,0.179015812511632066,0.701947813001544407],"hpluv":[288.229438001673088,265.563967984367252,49.376518181476186],"hsluv":[288.229438001673088,78.2521754793284572,49.376518181476186]},"#aa44ee":{"lch":[50.5160343838387149,113.969241853628489,284.471970959088878],"luv":[50.5160343838387149,28.4816380653286,-110.35299897060564],"rgb":[0.66666666666666663,0.266666666666666663,0.933333333333333348],"xyz":[0.340751994471823083,0.188540684618102111,0.82735862907006763],"hpluv":[284.471970959088878,286.284434407824506,50.5160343838387149],"hsluv":[284.471970959088878,88.5420288112715355,50.5160343838387149]},"#aa44ff":{"lch":[51.7249932896939271,124.658572052901789,281.540806859048416],"luv":[51.7249932896939271,24.9399169363974949,-122.138282816953421],"rgb":[0.66666666666666663,0.266666666666666663,1],"xyz":[0.366923042881654449,0.199009103982034807,0.965192817361849476],"hpluv":[281.540806859048416,305.816582895375404,51.7249932896939271],"hsluv":[281.540806859048416,99.9999999999991189,51.7249932896939271]},"#885500":{"lch":[40.7868302215615941,57.8204075903908716,44.0255445375638317],"luv":[40.7868302215615941,41.5746091122878738,40.1839695784202107],"rgb":[0.533333333333333326,0.333333333333333315,0],"xyz":[0.134014735183400707,0.117319151919440201,0.0155871309747999068],"hpluv":[44.0255445375638317,179.887306981779091,40.7868302215615941],"hsluv":[44.0255445375638317,100.000000000002402,40.7868302215615941]},"#885511":{"lch":[40.8520464566488215,55.8013246771799061,42.6953812551229817],"luv":[40.8520464566488215,41.012258348334349,37.838901951530346],"rgb":[0.533333333333333326,0.333333333333333315,0.0666666666666666657],"xyz":[0.135026400683037839,0.117723818119295054,0.0209152359395555383],"hpluv":[42.6953812551229817,173.328515822040885,40.8520464566488215],"hsluv":[42.6953812551229817,94.5141207032234121,40.8520464566488215]},"#885522":{"lch":[40.9725457623763205,52.2529579480882163,40.0436802938645613],"luv":[40.9725457623763205,40.0024704692244413,33.6180601862079769],"rgb":[0.533333333333333326,0.333333333333333315,0.133333333333333331],"xyz":[0.136901758821514841,0.118473961374685868,0.0307921221355347344],"hpluv":[40.0436802938645613,161.829338044896133,40.9725457623763205],"hsluv":[40.0436802938645613,84.6783920295854813,40.9725457623763205]},"#885533":{"lch":[41.169842808691,46.965215190705,35.0963808532685348],"luv":[41.169842808691,38.426283274472091,27.0028182162390955],"rgb":[0.533333333333333326,0.333333333333333315,0.2],"xyz":[0.139989509553972602,0.119709061667668981,0.0470542759931458776],"hpluv":[35.0963808532685348,144.75595347357384,41.169842808691],"hsluv":[35.0963808532685348,69.3663942781120113,41.169842808691]},"#885544":{"lch":[41.4523140669009891,40.5881659839312263,26.5063976077417607],"luv":[41.4523140669009891,36.321721997537459,18.1144066718387258],"rgb":[0.533333333333333326,0.333333333333333315,0.266666666666666663],"xyz":[0.144447504798191462,0.121492259765356561,0.0705330509460325161],"hpluv":[26.5063976077417607,124.248162385526584,41.4523140669009891],"hsluv":[26.5063976077417607,49.0053368988820708,41.4523140669009891]},"#885555":{"lch":[41.8258216452066449,34.5587016635497619,12.1770506300621708],"luv":[41.8258216452066449,33.7811467851905647,7.28958040957408926],"rgb":[0.533333333333333326,0.333333333333333315,0.333333333333333315],"xyz":[0.150409918837553447,0.123877225381101394,0.101935098220006432],"hpluv":[12.1770506300621708,104.846095879990827,41.8258216452066449],"hsluv":[12.1770506300621708,24.5686900376428454,41.8258216452066449]},"#885566":{"lch":[42.2941086985740071,31.3312262907584227,350.801819307985852],"luv":[42.2941086985740071,30.9283487442626033,-5.00829160852097477],"rgb":[0.533333333333333326,0.333333333333333315,0.4],"xyz":[0.157994914611061632,0.126911223690504699,0.141882742627150393],"hpluv":[350.801819307985852,94.0019456509277092,42.2941086985740071],"hsluv":[350.801819307985852,29.8132814869556348,42.2941086985740071]},"#885577":{"lch":[42.8590433503379202,33.3514130793808121,326.760730108285],"luv":[42.8590433503379202,27.8947491372056646,-18.2811302977648822],"rgb":[0.533333333333333326,0.333333333333333315,0.466666666666666674],"xyz":[0.167308927631263538,0.130636828898585522,0.190936544533548302],"hpluv":[326.760730108285,98.7440857113442263,42.8590433503379202],"hsluv":[326.760730108285,35.3342565461126838,42.8590433503379202]},"#885588":{"lch":[43.5208237898043535,40.5407907233736822,307.71501294924542],"luv":[43.5208237898043535,24.8001938501248809,-32.0703304858651137],"rgb":[0.533333333333333326,0.333333333333333315,0.533333333333333326],"xyz":[0.178449344733207393,0.13509299573936312,0.24960940793712047],"hpluv":[307.71501294924542,118.204615389413121,43.5208237898043535],"hsluv":[307.71501294924542,40.8951968507306276,43.5208237898043535]},"#885599":{"lch":[44.278184332936334,50.8805981998246,295.296495298175159],"luv":[44.278184332936334,21.7414099229374891,-46.0015909261276477],"rgb":[0.533333333333333326,0.333333333333333315,0.6],"xyz":[0.191506308842280093,0.140315781382992277,0.318376085578238377],"hpluv":[295.296495298175159,145.814841874582299,44.278184332936334],"hsluv":[295.296495298175159,46.3068912836000735,44.278184332936334]},"#8855aa":{"lch":[45.1286132569148819,62.6826496939872868,287.441560465434577],"luv":[45.1286132569148819,18.7880516159354372,-59.8006997378464717],"rgb":[0.533333333333333326,0.333333333333333315,0.66666666666666663],"xyz":[0.206564001807532649,0.146338858569093372,0.397679935195237],"hpluv":[287.441560465434577,176.252255995348207,45.1286132569148819],"hsluv":[287.441560465434577,51.4349240401982044,45.1286132569148819]},"#8855bb":{"lch":[46.0685799041538857,75.0110486022347374,282.303621490188448],"luv":[46.0685799041538857,15.9842650126874819,-73.2882029006783284],"rgb":[0.533333333333333326,0.333333333333333315,0.733333333333333282],"xyz":[0.223701593914869268,0.15319389541202813,0.487937920293878724],"hpluv":[282.303621490188448,206.613996430434867,46.0685799041538857],"hsluv":[282.303621490188448,56.1963190544194191,46.0685799041538857]},"#8855cc":{"lch":[47.0937627302438173,87.3889723072186229,278.789341148015808],"luv":[47.0937627302438173,13.3532090014702405,-86.3627482788434406],"rgb":[0.533333333333333326,0.333333333333333315,0.8],"xyz":[0.242993969358591022,0.160910845589516932,0.58954443096414888],"hpluv":[278.789341148015808,235.468364438494291,47.0937627302438173],"hsluv":[278.789341148015808,67.0071532265272083,47.0937627302438173]},"#8855dd":{"lch":[48.1992684502362323,99.579643468316263,276.285619014825784],"luv":[48.1992684502362323,10.9024601244232162,-98.9810171523426163],"rgb":[0.533333333333333326,0.333333333333333315,0.866666666666666696],"xyz":[0.264512294909224566,0.169518175809770466,0.702874278864154878],"hpluv":[276.285619014825784,262.161822059859048,48.1992684502362323],"hsluv":[276.285619014825784,77.9008511174594673,48.1992684502362323]},"#8855ee":{"lch":[49.3798334670730128,111.473561000814087,274.439637972028379],"luv":[49.3798334670730128,8.62903279282213198,-111.139077714648238],"rgb":[0.533333333333333326,0.333333333333333315,0.933333333333333348],"xyz":[0.288324475175399275,0.179043047916240511,0.828285094932678101],"hpluv":[274.439637972028379,286.45841220928196,49.3798334670730128],"hsluv":[274.439637972028379,88.8665998649397295,49.3798334670730128]},"#8855ff":{"lch":[50.6300011250937416,123.030386306339324,273.039422554437692],"luv":[50.6300011250937416,6.52344684402536235,-122.857318039912712],"rgb":[0.533333333333333326,0.333333333333333315,1],"xyz":[0.314495523585230696,0.189511467280173207,0.96611928322446],"hpluv":[273.039422554437692,308.349875308867752,50.6300011250937416],"hsluv":[273.039422554437692,99.9999999999992,50.6300011250937416]},"#ffdd00":{"lch":[88.435570144315335,99.3071523162376195,71.7429005549186911],"luv":[88.435570144315335,31.1110916577435432,94.3080615696447211],"rgb":[1,0.866666666666666696,0],"xyz":[0.670943989879631442,0.729745387098879927,0.105515215586815703],"hpluv":[71.7429005549186911,382.363935262913174,88.435570144315335],"hsluv":[71.7429005549186911,100.000000000012946,88.435570144315335]},"#ffdd11":{"lch":[88.454870819445,98.4678340856778,71.6448189166009826],"luv":[88.454870819445,31.0081800872079896,93.4580500395971683],"rgb":[1,0.866666666666666696,0.0666666666666666657],"xyz":[0.671955655379268602,0.730150053298734836,0.110843320551571339],"hpluv":[71.6448189166009826,379.826472639876158,88.454870819445],"hsluv":[71.6448189166009826,100.00000000001296,88.454870819445]},"#ffdd22":{"lch":[88.4906302718539735,96.9204819130462,71.4594307996413],"luv":[88.4906302718539735,30.8183922605744947,91.8901872494037093],"rgb":[1,0.866666666666666696,0.133333333333333331],"xyz":[0.673831013517745547,0.730900196554125636,0.120720206747550532],"hpluv":[71.4594307996413,375.129750349680876,88.4906302718539735],"hsluv":[71.4594307996413,100.00000000001296,88.4906302718539735]},"#ffdd33":{"lch":[88.5494544369894641,94.3967280931520776,71.1436744567929793],"luv":[88.5494544369894641,30.5086598694284135,89.330643945199526],"rgb":[1,0.866666666666666696,0.2],"xyz":[0.676918764250203364,0.732135296847108763,0.136982360605161668],"hpluv":[71.1436744567929793,367.416320973762822,88.5494544369894641],"hsluv":[71.1436744567929793,100.000000000013216,88.5494544369894641]},"#ffdd44":{"lch":[88.6342662809689301,90.8049878425315455,70.6631891871382152],"luv":[88.6342662809689301,30.0674100616276441,85.6825342136204284],"rgb":[1,0.866666666666666696,0.266666666666666663],"xyz":[0.681376759494422224,0.733918494944796329,0.160461135558048307],"hpluv":[70.6631891871382152,356.322085242203968,88.6342662809689301],"hsluv":[70.6631891871382152,100.000000000013173,88.6342662809689301]},"#ffdd55":{"lch":[88.7474847112806486,86.0957791731635353,69.970644696948483],"luv":[88.7474847112806486,29.4879375414461293,80.8884709398435433],"rgb":[1,0.866666666666666696,0.333333333333333315],"xyz":[0.687339173533784153,0.736303460560541079,0.191863182832022222],"hpluv":[69.970644696948483,341.559684906391112,88.7474847112806486],"hsluv":[69.970644696948483,100.000000000013429,88.7474847112806486]},"#ffdd66":{"lch":[88.8911610589964454,80.258955992054581,68.9956984045855819],"luv":[88.8911610589964454,28.7678627944319345,74.9260307715235427],"rgb":[1,0.866666666666666696,0.4],"xyz":[0.694924169307292394,0.739337458869944397,0.231810827239166184],"hpluv":[68.9956984045855819,322.902183683526573,88.8911610589964454],"hsluv":[68.9956984045855819,100.000000000013586,88.8911610589964454]},"#ffdd77":{"lch":[89.0670520916409885,73.323747836811151,67.6276760217336346],"luv":[89.0670520916409885,27.9087592291374555,67.8046691248198812],"rgb":[1,0.866666666666666696,0.466666666666666674],"xyz":[0.704238182327494244,0.743063064078025248,0.280864629145564093],"hpluv":[67.6276760217336346,300.178104609939055,89.0670520916409885],"hsluv":[67.6276760217336346,100.000000000014367,89.0670520916409885]},"#ffdd88":{"lch":[89.2766635023192379,65.3617696880632622,65.6822421460803554],"luv":[89.2766635023192379,26.9157684368328205,59.5625918359016637],"rgb":[1,0.866666666666666696,0.533333333333333326],"xyz":[0.715378599429438156,0.747519230918802791,0.339537492549136233],"hpluv":[65.6822421460803554,273.280966903928913,89.2766635023192379],"hsluv":[65.6822421460803554,100.00000000001468,89.2766635023192379]},"#ffdd99":{"lch":[89.5212778802452362,56.4966374008110606,62.8311838382076928],"luv":[89.5212778802452362,25.7971434460875209,50.2630821540094814],"rgb":[1,0.866666666666666696,0.6],"xyz":[0.7284355635385108,0.752742016562432,0.408304170190254168],"hpluv":[62.8311838382076928,242.212083001239,89.5212778802452362],"hsluv":[62.8311838382076928,100.000000000014893,89.5212778802452362]},"#ffddaa":{"lch":[89.8019739344538408,46.9317870748453103,58.439957868293348],"luv":[89.8019739344538408,24.5637119196041205,39.9902074859498],"rgb":[1,0.866666666666666696,0.66666666666666663],"xyz":[0.743493256503763411,0.75876509374853307,0.487608019807252768],"hpluv":[58.439957868293348,207.216087370130765,89.8019739344538408],"hsluv":[58.439957868293348,100.000000000015916,89.8019739344538408]},"#ffddbb":{"lch":[90.1196406145249114,37.0342016806554142,51.1553076529108282],"luv":[90.1196406145249114,23.228278171915747,28.8440494260352231],"rgb":[1,0.866666666666666696,0.733333333333333282],"xyz":[0.7606308486111,0.765620130591467829,0.57786600490589457],"hpluv":[51.1553076529108282,169.207898233907059,90.1196406145249114],"hsluv":[51.1553076529108282,100.00000000001647,90.1196406145249114]},"#ffddcc":{"lch":[90.4749882420216665,27.6093496047032829,37.8361109659034085],"luv":[90.4749882420216665,21.8049964890922183,16.9357111957368183],"rgb":[1,0.866666666666666696,0.8],"xyz":[0.779923224054821729,0.773337080768956686,0.679472515576164726],"hpluv":[37.8361109659034085,131.228146902908946,90.4749882420216665],"hsluv":[37.8361109659034085,100.000000000017565,90.4749882420216665]},"#ffdddd":{"lch":[90.8685579434819743,20.7762078419716971,12.1770506300632935],"luv":[90.8685579434819743,20.3087527298379129,4.38239373528981613],"rgb":[1,0.866666666666666696,0.866666666666666696],"xyz":[0.801441549605455328,0.781944410989210192,0.792802363476170724],"hpluv":[12.1770506300632935,103.332662997484363,90.8685579434819743],"hsluv":[12.1770506300632935,100.000000000018645,90.8685579434819743]},"#ffddee":{"lch":[91.3007301977477255,20.6730653908416642,335.121130580225611],"luv":[91.3007301977477255,18.7545890012647547,-8.69718483462634318],"rgb":[1,0.866666666666666696,0.933333333333333348],"xyz":[0.82525372987163,0.791469283095680209,0.918213179544694],"hpluv":[335.121130580225611,108.301670079840079,91.3007301977477255],"hsluv":[335.121130580225611,100.000000000019696,91.3007301977477255]},"#ffddff":{"lch":[91.7717330140538081,28.0468143452174594,307.715012949251673],"luv":[91.7717330140538081,17.1571994583452359,-22.1868046744377736],"rgb":[1,0.866666666666666696,1],"xyz":[0.851424778281461458,0.801937702459612933,1.05604736783647568],"hpluv":[307.715012949251673,155.925616416863875,91.7717330140538081],"hsluv":[307.715012949251673,100.000000000021274,91.7717330140538081]},"#aa5500":{"lch":[45.6948541105979729,81.8101604081173406,31.0178153240564285],"luv":[45.6948541105979729,70.1118895783240674,42.1571498770823254],"rgb":[0.66666666666666663,0.333333333333333315,0],"xyz":[0.198255511194170453,0.150443302049994065,0.0185984173503046732],"hpluv":[31.0178153240564285,227.184802334875343,45.6948541105979729],"hsluv":[31.0178153240564285,100.000000000002132,45.6948541105979729]},"#aa5511":{"lch":[45.7501207141343542,80.2053049231342357,30.0334267749456458],"luv":[45.7501207141343542,69.4364235827854088,40.1431690060082786],"rgb":[0.66666666666666663,0.333333333333333315,0.0666666666666666657],"xyz":[0.199267176693807585,0.150847968249848918,0.0239265223150603029],"hpluv":[30.0334267749456458,222.459100300712947,45.7501207141343542],"hsluv":[30.0334267749456458,95.7485290168496874,45.7501207141343542]},"#aa5522":{"lch":[45.8523093955831129,77.3637164970789826,28.1463245173948593],"luv":[45.8523093955831129,68.2151287979892231,36.4943945464800308],"rgb":[0.66666666666666663,0.333333333333333315,0.133333333333333331],"xyz":[0.201142534832284586,0.151598111505239747,0.0338034085110395],"hpluv":[28.1463245173948593,214.099393521154866,45.8523093955831129],"hsluv":[28.1463245173948593,88.0687786146531835,45.8523093955831129]},"#aa5533":{"lch":[46.0198296754266707,73.057054041475979,24.8605966968797674],"luv":[46.0198296754266707,66.2871018342682845,30.7140566456547255],"rgb":[0.66666666666666663,0.333333333333333315,0.2],"xyz":[0.20423028556474232,0.152833211798222846,0.0500655623686506457],"hpluv":[24.8605966968797674,201.444992058953261,46.0198296754266707],"hsluv":[24.8605966968797674,75.9647480733224683,46.0198296754266707]},"#aa5544":{"lch":[46.260105303202792,67.6400753638857,19.7251402693972757],"luv":[46.260105303202792,63.6711277752059743,22.829088529013422],"rgb":[0.66666666666666663,0.333333333333333315,0.266666666666666663],"xyz":[0.208688280808961207,0.154616409895910439,0.0735443373215372842],"hpluv":[19.7251402693972757,185.539675327038225,46.260105303202792],"hsluv":[19.7251402693972757,59.5831884891410581,46.260105303202792]},"#aa5555":{"lch":[46.5785950143652201,61.8404850960729462,12.1770506300619488],"luv":[46.5785950143652201,60.4491026496292108,13.0442165641410206],"rgb":[0.66666666666666663,0.333333333333333315,0.333333333333333315],"xyz":[0.21465069484832322,0.157001375511655272,0.1049463845955112],"hpluv":[12.1770506300619488,168.471262237657498,46.5785950143652201],"hsluv":[12.1770506300619488,39.4780386186733381,46.5785950143652201]},"#aa5566":{"lch":[46.9791292969753727,56.7719582569154682,1.70455911852653919],"luv":[46.9791292969753727,56.7468364589401801,1.68872621441415594],"rgb":[0.66666666666666663,0.333333333333333315,0.4],"xyz":[0.222235690621831378,0.160035373821058563,0.144894029002655161],"hpluv":[1.70455911852653919,153.34451205140752,46.9791292969753727],"hsluv":[1.70455911852653919,42.9013314457092818,46.9791292969753727]},"#aa5577":{"lch":[47.4641008255870247,53.815805251865207,348.374645401059922],"luv":[47.4641008255870247,52.7118371029350072,-10.8444974129891012],"rgb":[0.66666666666666663,0.333333333333333315,0.466666666666666674],"xyz":[0.231549703642033311,0.163760979029139386,0.193947830909053071],"hpluv":[348.374645401059922,143.874527939012694,47.4641008255870247],"hsluv":[348.374645401059922,46.6096363259647291,47.4641008255870247]},"#aa5588":{"lch":[48.0346061313586716,54.1759936988691209,333.519859036575326],"luv":[48.0346061313586716,48.4923339918738,-24.1564036495598238],"rgb":[0.66666666666666663,0.333333333333333315,0.533333333333333326],"xyz":[0.242690120743977111,0.168217145869916984,0.252620694312625238],"hpluv":[333.519859036575326,143.117248614217317,48.0346061313586716],"hsluv":[333.519859036575326,50.4580944804944309,48.0346061313586716]},"#aa5599":{"lch":[48.6905763376225,58.2309730669685877,319.412334073918828],"luv":[48.6905763376225,44.2212637341432782,-37.885697275903027],"rgb":[0.66666666666666663,0.333333333333333315,0.6],"xyz":[0.255747084853049866,0.173439931513546142,0.321387371953743117],"hpluv":[319.412334073918828,151.756904292295189,48.6905763376225],"hsluv":[319.412334073918828,54.3174516364451492,48.6905763376225]},"#aa55aa":{"lch":[49.4309115490906095,65.3990862514302904,307.715012949244453],"luv":[49.4309115490906095,40.0068668547544135,-51.7348150377284242],"rgb":[0.66666666666666663,0.333333333333333315,0.66666666666666663],"xyz":[0.270804777818302367,0.179463008699647236,0.400691221570741718],"hpluv":[307.715012949244453,167.885190443837445,49.4309115490906095],"hsluv":[307.715012949244453,58.0831627335764651,49.4309115490906095]},"#aa55bb":{"lch":[50.2536225490081137,74.6889496830887651,298.754319252296796],"luv":[50.2536225490081137,35.9294822147829578,-65.4790921786531896],"rgb":[0.66666666666666663,0.333333333333333315,0.733333333333333282],"xyz":[0.287942369925639041,0.186318045542582,0.490949206669383464],"hpluv":[298.754319252296796,188.594188212432869,50.2536225490081137],"hsluv":[298.754319252296796,61.6784311565058445,50.2536225490081137]},"#aa55cc":{"lch":[51.1559779262539394,85.2173265065914194,292.086991032215337],"luv":[51.1559779262539394,32.0428980728004476,-78.9635702082114],"rgb":[0.66666666666666663,0.333333333333333315,0.8],"xyz":[0.307234745369360795,0.194034995720070796,0.59255571733965362],"hpluv":[292.086991032215337,211.383381159177,51.1559779262539394],"hsluv":[292.086991032215337,65.0527897247966536,51.1559779262539394]},"#aa55dd":{"lch":[52.1346521614624407,96.3659410029227,287.126655540846059],"luv":[52.1346521614624407,28.3783197098194826,-92.0927008824589137],"rgb":[0.66666666666666663,0.333333333333333315,0.866666666666666696],"xyz":[0.328753070919994284,0.20264232594032433,0.705885565239659618],"hpluv":[287.126655540846059,234.550526854663673,52.1346521614624407],"hsluv":[287.126655540846059,75.3446722268955256,52.1346521614624407]},"#aa55ee":{"lch":[53.1858694266106227,107.745747725204239,283.388779775386126],"luv":[53.1858694266106227,24.9493252566021582,-104.817352199450397],"rgb":[0.66666666666666663,0.333333333333333315,0.933333333333333348],"xyz":[0.352565251186169049,0.212167198046794375,0.831296381308182841],"hpluv":[283.388779775386126,257.065149407391289,53.1858694266106227],"hsluv":[283.388779775386126,87.5522298773574335,53.1858694266106227]},"#aa55ff":{"lch":[54.3055382240479361,119.125691570750178,280.523377624217346],"luv":[54.3055382240479361,21.7567225446561139,-117.12205350114192],"rgb":[0.66666666666666663,0.333333333333333315,1],"xyz":[0.378736299596000414,0.222635617410727071,0.969130569599964686],"hpluv":[280.523377624217346,278.356033354379861,54.3055382240479361],"hsluv":[280.523377624217346,99.999999999999,54.3055382240479361]},"#886600":{"lch":[45.272583339231268,54.7393681124008964,58.6614018365849361],"luv":[45.272583339231268,28.4696504737342408,46.7533680417607513],"rgb":[0.533333333333333326,0.4,0],"xyz":[0.149042792889247183,0.147375267331133541,0.020596483543415256],"hpluv":[58.6614018365849361,153.427719347991228,45.272583339231268],"hsluv":[58.6614018365849361,100.000000000002288,45.272583339231268]},"#886611":{"lch":[45.3286132830504442,52.7569286908504935,57.8019218571504112],"luv":[45.3286132830504442,28.1114182485843394,44.6434954830448234],"rgb":[0.533333333333333326,0.4,0.0666666666666666657],"xyz":[0.150054458388884315,0.147779933530988394,0.0259245885081708857],"hpluv":[57.8019218571504112,147.688404254652824,45.3286132830504442],"hsluv":[57.8019218571504112,95.5933263309827765,45.3286132830504442]},"#886622":{"lch":[45.4322079122274616,49.2027541487777427,56.0700181971155658],"luv":[45.4322079122274616,27.4639619392241023,40.8245246197174367],"rgb":[0.533333333333333326,0.4,0.133333333333333331],"xyz":[0.151929816527361317,0.148530076786379223,0.0358014747041500853],"hpluv":[56.0700181971155658,137.424731357888106,45.4322079122274616],"hsluv":[56.0700181971155658,87.640709221506242,45.4322079122274616]},"#886633":{"lch":[45.6020177209920377,43.6934420281053448,52.7580970187872822],"luv":[45.6020177209920377,26.4424624059276816,34.7838045385277539],"rgb":[0.533333333333333326,0.4,0.2],"xyz":[0.155017567259819078,0.149765177079362322,0.0520636285617612285],"hpluv":[52.7580970187872822,121.582627853675135,45.6020177209920377],"hsluv":[52.7580970187872822,75.126145239043538,45.6020177209920377]},"#886644":{"lch":[45.8455444844743383,36.5157977851307862,46.6690567683987183],"luv":[45.8455444844743383,25.057552877875338,26.56167411246971],"rgb":[0.533333333333333326,0.4,0.266666666666666663],"xyz":[0.159475562504037938,0.151548375177049915,0.0755424035146478601],"hpluv":[46.6690567683987183,101.07016738030697,45.8455444844743383],"hsluv":[46.6690567683987183,58.2269221932267413,45.8455444844743383]},"#886655":{"lch":[46.1682850891648,28.5288655346450497,35.057100942904512],"luv":[46.1682850891648,23.3531590809093643,16.3867669061227161],"rgb":[0.533333333333333326,0.4,0.333333333333333315],"xyz":[0.165437976543399923,0.153933340792794748,0.106944450788621775],"hpluv":[35.057100942904512,78.4115584201214517,46.1682850891648],"hsluv":[35.057100942904512,37.5458750067509825,46.1682850891648]},"#886666":{"lch":[46.5740725388720946,21.8884171395184417,12.1770506300623786],"luv":[46.5740725388720946,21.3959378301945833,4.61699569417310141],"rgb":[0.533333333333333326,0.4,0.4],"xyz":[0.173022972316908108,0.156967339102198039,0.146892095195765737],"hpluv":[12.1770506300623786,59.6361320849851921,46.5740725388720946],"hsluv":[12.1770506300623786,13.9745942082290213,46.5740725388720946]},"#886677":{"lch":[47.0652698878111053,20.9860757761626395,336.621799391030947],"luv":[47.0652698878111053,19.2632377900225293,-8.32724722389627559],"rgb":[0.533333333333333326,0.4,0.466666666666666674],"xyz":[0.18233698533711,0.160692944310278862,0.195945897102163646],"hpluv":[336.621799391030947,56.5809206524471051,47.0652698878111053],"hsluv":[336.621799391030947,19.7183189325496855,47.0652698878111053]},"#886688":{"lch":[47.6429159175320649,27.8420771343032278,307.715012949247239],"luv":[47.6429159175320649,17.0319546757823481,-22.0248445868429776],"rgb":[0.533333333333333326,0.4,0.533333333333333326],"xyz":[0.193477402439053869,0.16514911115105646,0.254618760505735842],"hpluv":[307.715012949247239,74.1553731862279335,47.6429159175320649],"hsluv":[307.715012949247239,25.6555006249089494,47.6429159175320649]},"#886699":{"lch":[48.306860672000596,39.0046617113806562,292.251886736336132],"luv":[48.306860672000596,14.770249996667463,-36.0999078981538304],"rgb":[0.533333333333333326,0.4,0.6],"xyz":[0.206534366548126569,0.170371896794685618,0.323385438146853721],"hpluv":[292.251886736336132,102.458272059709785,48.306860672000596],"hsluv":[292.251886736336132,31.5854767603208231,48.306860672000596]},"#8866aa":{"lch":[49.0559053000777112,51.7871044207240132,284.005102499462396],"luv":[49.0559053000777112,12.5329093477081912,-50.2476901714407305],"rgb":[0.533333333333333326,0.4,0.66666666666666663],"xyz":[0.221592059513379125,0.176394973980786712,0.402689287763852322],"hpluv":[284.005102499462396,133.958310232957899,49.0559053000777112],"hsluv":[284.005102499462396,39.6059098285329867,49.0559053000777112]},"#8866bb":{"lch":[49.8879495217490074,65.0723394771694501,279.16089377463328],"luv":[49.8879495217490074,10.3599978518109275,-64.242352148271],"rgb":[0.533333333333333326,0.4,0.733333333333333282],"xyz":[0.238729651620715744,0.183250010823721471,0.492947272862494068],"hpluv":[279.16089377463328,165.516042277675325,49.8879495217490074],"hsluv":[279.16089377463328,51.4342030459355897,49.8879495217490074]},"#8866cc":{"lch":[50.800144438276476,78.3702679805165161,276.063171305995638],"luv":[50.800144438276476,8.2778522611756955,-77.9318680982312912],"rgb":[0.533333333333333326,0.4,0.8],"xyz":[0.258022027064437498,0.190966961001210273,0.594553783532764224],"hpluv":[276.063171305995638,195.760791019658512,50.800144438276476],"hsluv":[276.063171305995638,63.370404435102877,50.800144438276476]},"#8866dd":{"lch":[51.7890458420015278,91.4433004674113903,273.951375062119212],"luv":[51.7890458420015278,6.3013441888180548,-91.225929766636682],"rgb":[0.533333333333333326,0.4,0.866666666666666696],"xyz":[0.279540352615071042,0.199574291221463807,0.707883631432770222],"hpluv":[273.951375062119212,224.054313572832513,51.7890458420015278],"hsluv":[273.951375062119212,75.4110532620532,51.7890458420015278]},"#8866ee":{"lch":[52.8507624936088831,104.176067138923727,272.440799986921],"luv":[52.8507624936088831,4.4365578942807,-104.081554170680207],"rgb":[0.533333333333333326,0.4,0.933333333333333348],"xyz":[0.303352532881245751,0.209099163327933851,0.833294447501293445],"hpluv":[272.440799986921,250.124381092910085,52.8507624936088831],"hsluv":[272.440799986921,87.5962217171162365,52.8507624936088831]},"#8866ff":{"lch":[53.9810943197935273,116.520298408763196,271.319576027424205],"luv":[53.9810943197935273,2.6833355157121912,-116.48939716462327],"rgb":[0.533333333333333326,0.4,1],"xyz":[0.329523581291077172,0.219567582691866547,0.97112863579307529],"hpluv":[271.319576027424205,273.904539658900717,53.9810943197935273],"hsluv":[271.319576027424205,99.9999999999990621,53.9810943197935273]},"#ffee00":{"lch":[92.75564548426334,102.358730475882979,79.2433869538170228],"luv":[92.75564548426334,19.1039702538988,100.560171167180329],"rgb":[1,0.933333333333333348,0],"xyz":[0.718122766220146147,0.824102939779910892,0.121241474366986887],"hpluv":[79.2433869538170228,651.393632104361359,92.75564548426334],"hsluv":[79.2433869538170228,100.000000000024428,92.75564548426334]},"#ffee11":{"lch":[92.7734436379168,101.564402459740549,79.2015044483446218],"luv":[92.7734436379168,19.0286516433192254,99.765917344759373],"rgb":[1,0.933333333333333348,0.0666666666666666657],"xyz":[0.719134431719783307,0.824507605979765801,0.12656957933174251],"hpluv":[79.2015044483446218,648.021125158270593,92.7734436379168],"hsluv":[79.2015044483446218,100.000000000024428,92.7734436379168]},"#ffee22":{"lch":[92.8064212727168183,100.098587827824673,79.1224559985664797],"luv":[92.8064212727168183,18.8896613956421291,98.3000914418838079],"rgb":[1,0.933333333333333348,0.133333333333333331],"xyz":[0.721009789858260253,0.825257749235156601,0.136446465527721716],"hpluv":[79.1224559985664797,641.762708667564539,92.8064212727168183],"hsluv":[79.1224559985664797,100.000000000024357,92.8064212727168183]},"#ffee33":{"lch":[92.8606749716073665,97.7038183815635506,78.9881622996309147],"luv":[92.8606749716073665,18.6625824309063972,95.9048702796014396],"rgb":[1,0.933333333333333348,0.2],"xyz":[0.72409754059071807,0.826492849528139728,0.152708619385332867],"hpluv":[78.9881622996309147,631.438241912838748,92.8606749716073665],"hsluv":[78.9881622996309147,100.000000000024599,92.8606749716073665]},"#ffee44":{"lch":[92.9389094487226828,94.2867391890675606,78.7846200921967181],"luv":[92.9389094487226828,18.3385503337116411,92.4861436030564192],"rgb":[1,0.933333333333333348,0.266666666666666663],"xyz":[0.728555535834936929,0.828276047625827294,0.176187394338219505],"hpluv":[78.7846200921967181,616.484076987319668,92.9389094487226828],"hsluv":[78.7846200921967181,100.000000000025381,92.9389094487226828]},"#ffee55":{"lch":[93.0433700241155179,89.7896797607108,78.4929149488566082],"luv":[93.0433700241155179,17.9120631143144244,87.984911129805738],"rgb":[1,0.933333333333333348,0.333333333333333315],"xyz":[0.734517949874298859,0.830661013241572,0.207589441612193393],"hpluv":[78.4929149488566082,596.384103057951847,93.0433700241155179],"hsluv":[78.4929149488566082,100.000000000025906,93.0433700241155179]},"#ffee66":{"lch":[93.1759694096933,84.1867368500463,78.0854442567743661],"luv":[93.1759694096933,17.3805845725397461,82.3730656305550895],"rgb":[1,0.933333333333333348,0.4],"xyz":[0.7421029456478071,0.833695011550975362,0.247537086019337382],"hpluv":[78.0854442567743661,570.62648367707834,93.1759694096933],"hsluv":[78.0854442567743661,100.000000000026517,93.1759694096933]},"#ffee77":{"lch":[93.3383558005883742,77.4816602435733586,77.5195453952684659],"luv":[93.3383558005883742,16.7442947506152713,75.6507519288807515],"rgb":[1,0.933333333333333348,0.466666666666666674],"xyz":[0.751416958668009,0.837420616759056213,0.296590887925735291],"hpluv":[77.5195453952684659,538.663675570032183,93.3383558005883742],"hsluv":[77.5195453952684659,100.00000000002693,93.3383558005883742]},"#ffee88":{"lch":[93.5319535615141433,69.7063855050026433,76.7254067288761235],"luv":[93.5319535615141433,16.0058531534094222,67.8438858336072599],"rgb":[1,0.933333333333333348,0.533333333333333326],"xyz":[0.762557375769952861,0.841876783599833756,0.355263751329307431],"hpluv":[76.7254067288761235,499.867858345774721,93.5319535615141433],"hsluv":[76.7254067288761235,100.000000000028109,93.5319535615141433]},"#ffee99":{"lch":[93.7579894103796647,60.9203426164438397,75.5807218945013517],"luv":[93.7579894103796647,15.1701259512809905,59.0013171304435744],"rgb":[1,0.933333333333333348,0.6],"xyz":[0.775614339879025505,0.847099569243463,0.424030428970425366],"hpluv":[75.5807218945013517,453.479030486808085,93.7579894103796647],"hsluv":[75.5807218945013517,100.000000000029459,93.7579894103796647]},"#ffeeaa":{"lch":[94.0175103342715204,51.2122166590618946,73.8511258956299],"luv":[94.0175103342715204,14.2438643230739057,49.191497886124175],"rgb":[1,0.933333333333333348,0.66666666666666663],"xyz":[0.790672032844278116,0.853122646429564,0.503334278587424],"hpluv":[73.8511258956299,398.552269307706354,94.0175103342715204],"hsluv":[73.8511258956299,100.00000000003169,94.0175103342715204]},"#ffeebb":{"lch":[94.3113965930375855,40.7102572776027571,71.0277189369888],"luv":[94.3113965930375855,13.2353397134719373,38.4987120599845625],"rgb":[1,0.933333333333333348,0.733333333333333282],"xyz":[0.80780962495161468,0.859977683272498794,0.593592263686065658],"hpluv":[71.0277189369888,333.94796839081863,94.3113965930375855],"hsluv":[71.0277189369888,100.000000000032855,94.3113965930375855]},"#ffeecc":{"lch":[94.6403717602024841,29.6267857036886042,65.7803861656043125],"luv":[94.6403717602024841,12.1539519061426287,27.0190281874729799],"rgb":[1,0.933333333333333348,0.8],"xyz":[0.827102000395336434,0.867694633449987651,0.695198774356335814],"hpluv":[65.7803861656043125,258.601677072085806,94.6403717602024841],"hsluv":[65.7803861656043125,100.000000000035726,94.6403717602024841]},"#ffeedd":{"lch":[95.0050109981125814,18.4911495042727,53.4580761074439366],"luv":[95.0050109981125814,11.0098304435300403,14.8561853648264481],"rgb":[1,0.933333333333333348,0.866666666666666696],"xyz":[0.84862032594597,0.876301963670241157,0.808528622256341811],"hpluv":[53.4580761074439366,173.670551799097524,95.0050109981125814],"hsluv":[53.4580761074439366,100.000000000039279,95.0050109981125814]},"#ffeeee":{"lch":[95.4057483293867,10.0393308083340358,12.1770506300655121],"luv":[95.4057483293867,9.81345048674430487,2.11762900985580904],"rgb":[1,0.933333333333333348,0.933333333333333348],"xyz":[0.872432506212144743,0.885826835776711174,0.933939438324865],"hpluv":[12.1770506300655121,102.829227108855335,95.4057483293867],"hsluv":[12.1770506300655121,100.000000000042746,95.4057483293867]},"#ffeeff":{"lch":[95.8428833991312104,14.017983351086059,307.715012949261848],"luv":[95.8428833991312104,8.57528179129596,-11.0891117512266888],"rgb":[1,0.933333333333333348,1],"xyz":[0.898603554621976164,0.896295255140643898,1.07177362661664688],"hpluv":[307.715012949261848,159.207478793902965,95.8428833991312104],"hsluv":[307.715012949261848,100.000000000047876,95.8428833991312104]},"#aa6600":{"lch":[49.5566255632669623,74.0434564420528574,40.5370999312324685],"luv":[49.5566255632669623,56.2719368465296,48.1238253407432595],"rgb":[0.66666666666666663,0.4,0],"xyz":[0.213283568900016929,0.180499417461687406,0.0236077699189200241],"hpluv":[40.5370999312324685,189.593866720893345,49.5566255632669623],"hsluv":[40.5370999312324685,100.000000000002302,49.5566255632669623]},"#aa6611":{"lch":[49.6055800152373934,72.4782904829715449,39.6736286483530876],"luv":[49.6055800152373934,55.7860674256664097,46.2711278500211662],"rgb":[0.66666666666666663,0.4,0.0666666666666666657],"xyz":[0.214295234399654061,0.180904083661542259,0.0289358748836756538],"hpluv":[39.6736286483530876,185.402990863318706,49.6055800152373934],"hsluv":[39.6736286483530876,96.4267217319678878,49.6055800152373934]},"#aa6622":{"lch":[49.6961357673044404,69.6784302133091,38.0044715349972151],"luv":[49.6961357673044404,54.9040042209680124,42.902610147809348],"rgb":[0.66666666666666663,0.4,0.133333333333333331],"xyz":[0.216170592538131062,0.181654226916933087,0.0388127610796548533],"hpluv":[38.0044715349972151,177.916023719914563,49.6961357673044404],"hsluv":[38.0044715349972151,89.9454244119252593,49.6961357673044404]},"#aa6633":{"lch":[49.8446929303716502,65.3554895773238798,35.0519229290669685],"luv":[49.8446929303716502,53.5020897896209959,37.5348692023167061],"rgb":[0.66666666666666663,0.4,0.2],"xyz":[0.219258343270588796,0.182889327209916186,0.055074914937266],"hpluv":[35.0519229290669685,166.380518722129068,49.8446929303716502],"hsluv":[35.0519229290669685,79.6601301034586,49.8446929303716502]},"#aa6644":{"lch":[50.0579996788189163,59.7471791719702878,30.3078082111971625],"luv":[50.0579996788189163,51.5813401714318687,30.1511320703974341],"rgb":[0.66666666666666663,0.4,0.266666666666666663],"xyz":[0.223716338514807683,0.18467252530760378,0.0785536898901526282],"hpluv":[30.3078082111971625,151.454869534606559,50.0579996788189163],"hsluv":[30.3078082111971625,65.6016329960131,50.0579996788189163]},"#aa6655":{"lch":[50.3411543587309183,53.4384070136854916,23.0123473649378063],"luv":[50.3411543587309183,49.1858121787411307,20.8906492114991877],"rgb":[0.66666666666666663,0.4,0.333333333333333315],"xyz":[0.229678752554169696,0.187057490923348613,0.109955737164126544],"hpluv":[23.0123473649378063,134.70064023894011,50.3411543587309183],"hsluv":[23.0123473649378063,48.1262851503794238,50.3411543587309183]},"#aa6666":{"lch":[50.6979081899742283,47.4599132867605107,12.1770506300620198],"luv":[50.6979081899742283,46.3920870859415544,10.0108753362152232],"rgb":[0.66666666666666663,0.4,0.4],"xyz":[0.237263748327677854,0.190091489232751903,0.149903381571270505],"hpluv":[12.1770506300620198,118.788999996072334,50.6979081899742283],"hsluv":[12.1770506300620198,27.8359446414257086,50.6979081899742283]},"#aa6677":{"lch":[51.1308297914663399,43.3502150416948382,357.146673366158041],"luv":[51.1308297914663399,43.29647113668576,-2.15794607701909591],"rgb":[0.66666666666666663,0.4,0.466666666666666674],"xyz":[0.246577761347879787,0.193817094440832727,0.198957183477668414],"hpluv":[357.146673366158041,107.584013476394517,51.1308297914663399],"hsluv":[357.146673366158041,31.9217683762365354,51.1308297914663399]},"#aa6688":{"lch":[51.6414184020027,42.8134625942885876,339.120025752150127],"luv":[51.6414184020027,40.0018640870324234,-15.2592086582212207],"rgb":[0.66666666666666663,0.4,0.533333333333333326],"xyz":[0.257718178449823587,0.198273261281610325,0.257630046881240582],"hpluv":[339.120025752150127,105.201399585535427,51.6414184020027],"hsluv":[339.120025752150127,36.2396804223311,51.6414184020027]},"#aa6699":{"lch":[52.2302006219705675,46.6703467022409342,321.661853982703349],"luv":[52.2302006219705675,36.6065194780657563,-28.949680361091449],"rgb":[0.66666666666666663,0.4,0.6],"xyz":[0.270775142558896342,0.203496046925239482,0.326396724522358461],"hpluv":[321.661853982703349,113.385797667979,52.2302006219705675],"hsluv":[321.661853982703349,40.6514838109423,52.2302006219705675]},"#aa66aa":{"lch":[52.8968256208086274,54.2656136904176165,307.715012949245079],"luv":[52.8968256208086274,33.1961393674155048,-42.9275338250028753],"rgb":[0.66666666666666663,0.4,0.66666666666666663],"xyz":[0.285832835524148843,0.209519124111340577,0.405700574139357117],"hpluv":[307.715012949245079,130.177052782763241,52.8968256208086274],"hsluv":[307.715012949245079,45.0372955528084091,52.8968256208086274]},"#aa66bb":{"lch":[53.6401644756464293,64.2916348467718848,297.653919381785329],"luv":[53.6401644756464293,29.8396642728746109,-56.9474209016772193],"rgb":[0.66666666666666663,0.4,0.733333333333333282],"xyz":[0.302970427631485517,0.216374160954275335,0.495958559237998808],"hpluv":[297.653919381785329,152.091062924306783,53.6401644756464293],"hsluv":[297.653919381785329,49.3013965401631964,53.6401644756464293]},"#aa66cc":{"lch":[54.4584144535918853,75.6506824974921699,290.576693925999962],"luv":[54.4584144535918853,26.5882539678026326,-70.824363839571447],"rgb":[0.66666666666666663,0.4,0.8],"xyz":[0.322262803075207271,0.224091111131764137,0.597565069908269],"hpluv":[290.576693925999962,176.273563499159138,54.4584144535918853],"hsluv":[290.576693925999962,59.8478295858589107,54.4584144535918853]},"#aa66dd":{"lch":[55.3492064676394619,87.6329338161637423,285.539109011475546],"luv":[55.3492064676394619,23.4765185392287,-84.4297587732275],"rgb":[0.66666666666666663,0.4,0.866666666666666696],"xyz":[0.343781128625840759,0.232698441352017671,0.710894917808275],"hpluv":[285.539109011475546,200.907097340780666,55.3492064676394619],"hsluv":[285.539109011475546,72.9499123576365,55.3492064676394619]},"#aa66ee":{"lch":[56.3097127205812171,99.8160041995885337,281.866291349003632],"luv":[56.3097127205812171,20.525011879724925,-97.6829492885499775],"rgb":[0.66666666666666663,0.4,0.933333333333333348],"xyz":[0.367593308892015525,0.242223313458487716,0.836305733876798185],"hpluv":[281.866291349003632,224.934563930918017,56.3097127205812171],"hsluv":[281.866291349003632,86.3166325899195215,56.3097127205812171]},"#aa66ff":{"lch":[57.3367512293125543,111.956114799504135,279.118878442970129],"luv":[57.3367512293125543,17.7431860168323468,-110.541173283857603],"rgb":[0.66666666666666663,0.4,1],"xyz":[0.39376435730184689,0.252691732822420412,0.97413992216858],"hpluv":[279.118878442970129,247.773048158040382,57.3367512293125543],"hsluv":[279.118878442970129,99.9999999999988631,57.3367512293125543]},"#887700":{"lch":[50.0114915023736586,55.8665567864094825,73.357205010908],"luv":[50.0114915023736586,16.0004093344436384,53.5262465366231766],"rgb":[0.533333333333333326,0.466666666666666674,0],"xyz":[0.167496530942664812,0.184282743437969299,0.0267477295612209565],"hpluv":[73.357205010908,141.749463920516746,50.0114915023736586],"hsluv":[73.357205010908,100.000000000002359,50.0114915023736586]},"#887711":{"lch":[50.0597743565714524,53.993823922257576,73.0031869817398302],"luv":[50.0597743565714524,15.783394234863108,51.6354286142242103],"rgb":[0.533333333333333326,0.466666666666666674,0.0666666666666666657],"xyz":[0.168508196442301944,0.184687409637824151,0.0320758345259765862],"hpluv":[73.0031869817398302,136.865669051735267,50.0597743565714524],"hsluv":[73.0031869817398302,96.4507191106164328,50.0597743565714524]},"#887722":{"lch":[50.1490916772086592,50.5946145563497751,72.2920831328592755],"luv":[50.1490916772086592,15.3890953737340599,48.1974145124374616],"rgb":[0.533333333333333326,0.466666666666666674,0.133333333333333331],"xyz":[0.170383554580778945,0.18543755289321498,0.0419527207219557857],"hpluv":[72.2920831328592755,128.020802989304741,50.1490916772086592],"hsluv":[72.2920831328592755,90.012010730737714,50.1490916772086592]},"#887733":{"lch":[50.2956280558193356,45.1970113165044083,70.9372107781068735],"luv":[50.2956280558193356,14.7615306672340392,42.718462569532349],"rgb":[0.533333333333333326,0.466666666666666674,0.2],"xyz":[0.173471305313236679,0.186672653186198079,0.058214874579566929],"hpluv":[70.9372107781068735,114.029917097227894,50.2956280558193356],"hsluv":[70.9372107781068735,79.7918184760720237,50.2956280558193356]},"#887744":{"lch":[50.5060566549544916,37.8272673959478567,68.4411772520018076],"luv":[50.5060566549544916,13.89986571870684,35.1809023711225777],"rgb":[0.533333333333333326,0.466666666666666674,0.266666666666666663],"xyz":[0.177929300557455566,0.188455851283885673,0.0816936495324535605],"hpluv":[68.4411772520018076,95.0387759917387598,50.5060566549544916],"hsluv":[68.4411772520018076,65.8173762074568316,50.5060566549544916]},"#887755":{"lch":[50.7854328179731453,28.7445471843262688,63.5083223958924279],"luv":[50.7854328179731453,12.8220173934607509,25.7263456945161408],"rgb":[0.533333333333333326,0.466666666666666674,0.333333333333333315],"xyz":[0.183891714596817579,0.190840816899630505,0.113095696806427476],"hpluv":[63.5083223958924279,71.82169329487634,50.7854328179731453],"hsluv":[63.5083223958924279,48.4385690265679756,50.7854328179731453]},"#887766":{"lch":[51.1374932189691549,18.6360854649452037,51.6613245975388082],"luv":[51.1374932189691549,11.5601245482137447,14.6173596072111405],"rgb":[0.533333333333333326,0.466666666666666674,0.4],"xyz":[0.191476710370325737,0.193874815209033796,0.153043341213571438],"hpluv":[51.6613245975388082,46.2439140208651,51.1374932189691549],"hsluv":[51.6613245975388082,28.2492665088726049,51.1374932189691549]},"#887777":{"lch":[51.5648179079599629,10.388802862097231,12.1770506300635812],"luv":[51.5648179079599629,10.1550595801770775,2.19134429758843829],"rgb":[0.533333333333333326,0.466666666666666674,0.466666666666666674],"xyz":[0.20079072339052767,0.197600420417114619,0.202097143119969347],"hpluv":[12.1770506300635812,25.5653264810281158,51.5648179079599629],"hsluv":[12.1770506300635812,5.9907484084339373,51.5648179079599629]},"#887788":{"lch":[52.0689409540354262,14.1414171783799034,307.715012949252923],"luv":[52.0689409540354262,8.65079050214889378,-11.1867557182995974],"rgb":[0.533333333333333326,0.466666666666666674,0.533333333333333326],"xyz":[0.21193114049247147,0.202056587257892217,0.260770006523541542],"hpluv":[307.715012949252923,34.4630346227371902,52.0689409540354262],"hsluv":[307.715012949252923,11.9231603633022036,52.0689409540354262]},"#887799":{"lch":[52.6504441343355154,26.1446518461971777,285.73365348909897],"luv":[52.6504441343355154,7.08953673880610147,-25.1650807467009763],"rgb":[0.533333333333333326,0.466666666666666674,0.6],"xyz":[0.224988104601544198,0.207279372901521375,0.329536684164659421],"hpluv":[285.73365348909897,63.0115482025775862,52.6504441343355154],"hsluv":[285.73365348909897,20.7849368541844512,52.6504441343355154]},"#8877aa":{"lch":[53.3090485775123142,39.8165287152511951,277.951975125090712],"luv":[53.3090485775123142,5.50833871717125412,-39.4336678931764482],"rgb":[0.533333333333333326,0.466666666666666674,0.66666666666666663],"xyz":[0.240045797566796726,0.213302450087622469,0.408840533781658],"hpluv":[277.951975125090712,94.7767450693341118,53.3090485775123142],"hsluv":[277.951975125090712,33.2193336653547036,53.3090485775123142]},"#8877bb":{"lch":[54.043710164283695,53.8841311835491,274.190220195010625],"luv":[54.043710164283695,3.93720379281895738,-53.7400969453883732],"rgb":[0.533333333333333326,0.466666666666666674,0.733333333333333282],"xyz":[0.2571833896741334,0.220157486930557228,0.499098518880299769],"hpluv":[274.190220195010625,126.518797380186697,54.043710164283695],"hsluv":[274.190220195010625,46.027457746288988,54.043710164283695]},"#8877cc":{"lch":[54.8527197178713095,67.9360625264533695,272.023364737824068],"luv":[54.8527197178713095,2.39862107173988059,-67.8937052203839215],"rgb":[0.533333333333333326,0.466666666666666674,0.8],"xyz":[0.276475765117855099,0.22787443710804603,0.600705029550569924],"hpluv":[272.023364737824068,157.159823716941304,54.8527197178713095],"hsluv":[272.023364737824068,59.1220253911564413,54.8527197178713095]},"#8877dd":{"lch":[55.7338064566187228,81.7667290312133,270.636302714775695],"luv":[55.7338064566187228,0.90804807322034331,-81.7616867803042595],"rgb":[0.533333333333333326,0.466666666666666674,0.866666666666666696],"xyz":[0.297994090668488698,0.236481767328299564,0.714034877450575922],"hpluv":[270.636302714775695,186.164661983392193,55.7338064566187228],"hsluv":[270.636302714775695,72.4679508704990809,55.7338064566187228]},"#8877ee":{"lch":[56.6842419440431939,95.2620356561917419,269.684203716511661],"luv":[56.6842419440431939,-0.525051666249150784,-95.2605886928551229],"rgb":[0.533333333333333326,0.466666666666666674,0.933333333333333348],"xyz":[0.321806270934663408,0.246006639434769608,0.839445693519099145],"hpluv":[269.684203716511661,213.253830698535069,56.6842419440431939],"hsluv":[269.684203716511661,86.076772525698,56.6842419440431939]},"#8877ff":{"lch":[57.7009414002340577,108.362660778640901,268.997474997449615],"luv":[57.7009414002340577,-1.89596396936046907,-108.346073171359961],"rgb":[0.533333333333333326,0.466666666666666674,1],"xyz":[0.347977319344494829,0.256475058798702304,0.977279881810881],"hpluv":[268.997474997449615,238.306609639193027,57.7009414002340577],"hsluv":[268.997474997449615,99.9999999999988631,57.7009414002340577]},"#ffff00":{"lch":[97.1385593417967357,107.085608846920664,85.8743202181747307],"luv":[97.1385593417967357,7.70421917727499928,106.808111250898],"rgb":[1,1,0],"xyz":[0.76997513864982,0.92780768463926,0.138525598510210984],"hpluv":[85.8743202181747307,1784.23591835690763,97.1385593417967357],"hsluv":[85.8743202181747307,100.000000000072717,97.1385593417967357]},"#ffff11":{"lch":[97.1550055288865337,106.340968495662651,85.8743202181747307],"luv":[97.1550055288865337,7.65064640931757278,106.065400532478591],"rgb":[1,1,0.0666666666666666657],"xyz":[0.770986804149457194,0.928212350839114908,0.143853703474966621],"hpluv":[85.8743202181747307,1782.29032599077573,97.1550055288865337],"hsluv":[85.8743202181747307,100.000000000072447,97.1550055288865337]},"#ffff22":{"lch":[97.1854797367251564,104.966044999604463,85.8743202181747],"luv":[97.1854797367251564,7.5517282439387623,104.694039961158666],"rgb":[1,1,0.133333333333333331],"xyz":[0.77286216228793414,0.928962494094505709,0.1537305896709458],"hpluv":[85.8743202181747,1778.69938503976459,97.1854797367251564],"hsluv":[85.8743202181747,100.00000000007401,97.1854797367251564]},"#ffff33":{"lch":[97.2356193677236291,102.717517786777336,85.8743202181746312],"luv":[97.2356193677236291,7.38995910744871409,102.451339496695468],"rgb":[1,1,0.2],"xyz":[0.775949913020392,0.930197594387488835,0.16999274352855695],"hpluv":[85.8743202181746312,1772.83090468185333,97.2356193677236291],"hsluv":[85.8743202181746312,100.000000000075445,97.2356193677236291]},"#ffff44":{"lch":[97.3079311184623776,99.5042093292491,85.874320218174546],"luv":[97.3079311184623776,7.15877927938833114,99.2463578851537704],"rgb":[1,1,0.266666666666666663],"xyz":[0.780407908264610817,0.931980792485176401,0.193471518481443588],"hpluv":[85.874320218174546,1764.45330998562531,97.3079311184623776],"hsluv":[85.874320218174546,100.000000000077918,97.3079311184623776]},"#ffff55":{"lch":[97.4045015397841212,95.2663481722239283,85.8743202181744323],"luv":[97.4045015397841212,6.8538885331141568,95.0194785612246875],"rgb":[1,1,0.333333333333333315],"xyz":[0.786370322303972746,0.934365758100921151,0.224873565755417504],"hpluv":[85.8743202181744323,1753.42077174454698,97.4045015397841212],"hsluv":[85.8743202181744323,100.000000000080163,97.4045015397841212]},"#ffff66":{"lch":[97.5271149532436539,89.9715947326486258,85.8743202181742333],"luv":[97.5271149532436539,6.47296021391862286,89.7384457454272706],"rgb":[1,1,0.4],"xyz":[0.793955318077481,0.93739975641032447,0.264821210162561438],"hpluv":[85.8743202181742333,1739.66322518688298,97.5271149532436539],"hsluv":[85.8743202181742333,100.000000000084981,97.5271149532436539]},"#ffff77":{"lch":[97.6773170086398608,83.6127156419164663,85.8743202181740202],"luv":[97.6773170086398608,6.01547392080898469,83.3960448134325389],"rgb":[1,1,0.466666666666666674],"xyz":[0.803269331097682837,0.941125361618405321,0.313875012068959403],"hpluv":[85.8743202181740202,1723.18045161093028,97.6773170086398608],"hsluv":[85.8743202181740202,100.00000000009112,97.6773170086398608]},"#ffff88":{"lch":[97.8564527859654589,76.2055692953657342,85.8743202181736791],"luv":[97.8564527859654589,5.48257057790026181,76.0080930657330214],"rgb":[1,1,0.533333333333333326],"xyz":[0.814409748199626748,0.945581528459182863,0.372547875472531542],"hpluv":[85.8743202181736791,1704.03672017478311,97.8564527859654589],"hsluv":[85.8743202181736791,100.000000000099803,97.8564527859654589]},"#ffff99":{"lch":[98.0656913545514612,67.7868897983338741,85.8743202181732102],"luv":[98.0656913545514612,4.87689300155069283,67.6112294162950889],"rgb":[1,1,0.6],"xyz":[0.827466712308699393,0.950804314102812076,0.441314553113649422],"hpluv":[85.8743202181732102,1682.35465810463256,98.0656913545514612],"hsluv":[85.8743202181732102,100.000000000112891,98.0656913545514612]},"#ffffaa":{"lch":[98.3060425431328611,58.4116937234916094,85.8743202181725707],"luv":[98.3060425431328611,4.20239933084915052,58.260327869924204],"rgb":[1,1,0.66666666666666663],"xyz":[0.842524405273952,0.956827391288913143,0.520618402730648078],"hpluv":[85.8743202181725707,1658.30791632356272,98.3060425431328611],"hsluv":[85.8743202181725707,100.000000000127613,98.3060425431328611]},"#ffffbb":{"lch":[98.5783690162300559,48.1503065934375414,85.8743202181715759],"luv":[98.5783690162300559,3.46414909943131732,48.0255317103199246],"rgb":[1,1,0.733333333333333282],"xyz":[0.859661997381288567,0.963682428131847901,0.610876387829289769],"hpluv":[85.8743202181715759,1632.1126639545671,98.5783690162300559],"hsluv":[85.8743202181715759,100.000000000152809,98.5783690162300559]},"#ffffcc":{"lch":[98.8833954570195317,37.0851031688938804,85.8743202181698706],"luv":[98.8833954570195317,2.66806871718659799,36.9890022353654899],"rgb":[1,1,0.8],"xyz":[0.878954372825010322,0.971399378309336758,0.712482898499559925],"hpluv":[85.8743202181698706,1604.018210645404,98.8833954570195317],"hsluv":[85.8743202181698706,100.00000000019709,98.8833954570195317]},"#ffffdd":{"lch":[99.2217159651800245,25.3071072074552177,85.8743202181663889],"luv":[99.2217159651800245,1.82070684164607655,25.2415273271332552],"rgb":[1,1,0.866666666666666696],"xyz":[0.900472698375643921,0.980006708529590265,0.825812746399565922],"hpluv":[85.8743202181663889,1574.29719653830034,99.2217159651800245],"hsluv":[85.8743202181663889,100.000000000286278,99.2217159651800245]},"#ffffee":{"lch":[99.5938003805277248,12.9126149352850259,85.8743202181558161],"luv":[99.5938003805277248,0.928991455386458775,12.8791536733888243],"rgb":[1,1,0.933333333333333348],"xyz":[0.92428487864181863,0.989531580636060282,0.951223562468089145],"hpluv":[85.8743202181558161,1543.23583838085528,99.5938003805277248],"hsluv":[85.8743202181558161,100.000000000556355,99.5938003805277248]},"#ffffff":{"lch":[99.99999999999973,5.29610712429325706e-12,0],"luv":[99.99999999999973,4.97935026544381416e-12,1.80411241501587473e-12],"rgb":[1,1,1],"xyz":[0.95045592705165,0.999999999999993,1.0890577507598711],"hpluv":[0,0,100],"hsluv":[0,0,100]},"#aa7700":{"lch":[53.7507838912622304,69.116848270999057,51.9676330333141223],"luv":[53.7507838912622304,42.5833417137676875,54.4407726194696622],"rgb":[0.66666666666666663,0.466666666666666674,0],"xyz":[0.231737306953434558,0.217406893568523163,0.0297590159367257245],"hpluv":[51.9676330333141223,163.169299961930307,53.7507838912622304],"hsluv":[51.9676330333141223,100.000000000002359,53.7507838912622304]},"#aa7711":{"lch":[53.7940335015026,67.5786316453491906,51.3090056740019378],"luv":[53.7940335015026,42.244752971039,52.7470596476588653],"rgb":[0.66666666666666663,0.466666666666666674,0.0666666666666666657],"xyz":[0.23274897245307169,0.217811559768378016,0.0350871209014813543],"hpluv":[51.3090056740019378,159.40965108533166,53.7940335015026],"hsluv":[51.3090056740019378,97.0120153186068,53.7940335015026]},"#aa7722":{"lch":[53.874065271669366,64.7981771198060272,50.0272013346139],"luv":[53.874065271669366,41.6278947732915157,49.6580520640260588],"rgb":[0.66666666666666663,0.466666666666666674,0.133333333333333331],"xyz":[0.234624330591548691,0.218561703023768844,0.0449640070974605538],"hpluv":[50.0272013346139,152.623836787181489,53.874065271669366],"hsluv":[50.0272013346139,91.5730337049880632,53.874065271669366]},"#aa7733":{"lch":[54.0054384284815,60.4215101577181812,47.7291529037971785],"luv":[54.0054384284815,40.6416884431496115,44.7103125713654705],"rgb":[0.66666666666666663,0.466666666666666674,0.2],"xyz":[0.237712081324006452,0.219796803316751943,0.0612261609550717],"hpluv":[47.7291529037971785,141.968961696257139,54.0054384284815],"hsluv":[47.7291529037971785,82.890357503842381,54.0054384284815]},"#aa7744":{"lch":[54.1942453736720324,54.5501661616690754,43.9413891432679051],"luv":[54.1942453736720324,39.2788485799816911,37.8535689532252277],"rgb":[0.66666666666666663,0.466666666666666674,0.266666666666666663],"xyz":[0.242170076568225312,0.221580001414439537,0.0847049359079583286],"hpluv":[43.9413891432679051,127.726858599491337,54.1942453736720324],"hsluv":[43.9413891432679051,70.9191698542686453,54.1942453736720324]},"#aa7755":{"lch":[54.4451912879813307,47.55778496198932,37.8352816528713],"luv":[54.4451912879813307,37.5600659479400178,29.1716361638701045],"rgb":[0.66666666666666663,0.466666666666666674,0.333333333333333315],"xyz":[0.248132490607587297,0.22396496703018437,0.116106983181932244],"hpluv":[37.8352816528713,110.841250641501858,54.4451912879813307],"hsluv":[37.8352816528713,55.8697139193963039,54.4451912879813307]},"#aa7766":{"lch":[54.7618668139504621,40.2221891209492881,27.9562221290694595],"luv":[54.7618668139504621,35.5285027246357359,18.8560333004309904],"rgb":[0.66666666666666663,0.466666666666666674,0.4],"xyz":[0.255717486381095482,0.226998965339587661,0.156054627589076206],"hpluv":[27.9562221290694595,93.2023334238246264,54.7618668139504621],"hsluv":[27.9562221290694595,38.157009054435612,54.7618668139504621]},"#aa7777":{"lch":[55.1468928183874851,34.0080558607991321,12.1770506300622881],"luv":[55.1468928183874851,33.2428902595124569,7.17343088244713467],"rgb":[0.66666666666666663,0.466666666666666674,0.466666666666666674],"xyz":[0.265031499401297388,0.230724570547668484,0.205108429495474115],"hpluv":[12.1770506300622881,78.2528356679829074,55.1468928183874851],"hsluv":[12.1770506300622881,20.6006796366476941,55.1468928183874851]},"#aa7788":{"lch":[55.6020140468043849,31.2700131437067519,349.739442339375785],"luv":[55.6020140468043849,30.7699397165362107,-5.56996695217490778],"rgb":[0.66666666666666663,0.466666666666666674,0.533333333333333326],"xyz":[0.276171916503241244,0.235180737388446082,0.263781292899046282],"hpluv":[349.739442339375785,71.363619208349732,55.6020140468043849],"hsluv":[349.739442339375785,23.0952607722130772,55.6020140468043849]},"#aa7799":{"lch":[56.1281730235999845,34.0192547961324365,325.92167501088062],"luv":[56.1281730235999845,28.1772086346441704,-19.0618627223027133],"rgb":[0.66666666666666663,0.466666666666666674,0.6],"xyz":[0.289228880612313943,0.240403523032075239,0.332547970540164162],"hpluv":[325.92167501088062,76.9100717288581706,56.1281730235999845],"hsluv":[325.92167501088062,27.5449434619861648,56.1281730235999845]},"#aa77aa":{"lch":[56.7255784680210127,41.7295245342496131,307.715012949246272],"luv":[56.7255784680210127,25.5273831431779215,-33.0106941416859],"rgb":[0.66666666666666663,0.466666666666666674,0.66666666666666663],"xyz":[0.304286573577566499,0.246426600218176334,0.411851820157162818],"hpluv":[307.715012949246272,93.3477446513022642,56.7255784680210127],"hsluv":[307.715012949246272,32.2954766233998285,56.7255784680210127]},"#aa77bb":{"lch":[57.3937746480490176,52.417961949749369,295.873528074876958],"luv":[57.3937746480490176,22.8744713506946127,-47.1635589771554891],"rgb":[0.66666666666666663,0.466666666666666674,0.733333333333333282],"xyz":[0.321424165684903118,0.25328163706111112,0.502109805255804509],"hpluv":[295.873528074876958,115.892323381948941,57.3937746480490176],"hsluv":[295.873528074876958,41.7229864085831679,57.3937746480490176]},"#aa77cc":{"lch":[58.1317139736185,64.5762938068646548,288.286403622885132],"luv":[58.1317139736185,20.2619194712353625,-61.3151885031081],"rgb":[0.66666666666666663,0.466666666666666674,0.8],"xyz":[0.340716541128624872,0.260998587238599922,0.603716315926074665],"hpluv":[288.286403622885132,140.961111207958226,58.1317139736185],"hsluv":[288.286403622885132,55.678510160825347,58.1317139736185]},"#aa77dd":{"lch":[58.9378328182195759,77.3666791836153,283.242275299631103],"luv":[58.9378328182195759,17.7223199365118553,-75.3095108466943088],"rgb":[0.66666666666666663,0.466666666666666674,0.866666666666666696],"xyz":[0.362234866679258416,0.269605917458853428,0.717046163826080662],"hpluv":[283.242275299631103,166.570895286205939,58.9378328182195759],"hsluv":[283.242275299631103,70.0408478070886105,58.9378328182195759]},"#aa77ee":{"lch":[59.8101292792768646,90.3373867943789151,279.736895248195651],"luv":[59.8101292792768646,15.2782276108220607,-89.0360556960445138],"rgb":[0.66666666666666663,0.466666666666666674,0.933333333333333348],"xyz":[0.386047046945433125,0.279130789565323445,0.842456979894603886],"hpluv":[279.736895248195651,191.660275847677298,59.8101292792768646],"hsluv":[279.736895248195651,84.8029379630096685,59.8101292792768646]},"#aa77ff":{"lch":[60.7462409754246551,103.238062985892157,277.202485092995744],"luv":[60.7462409754246551,12.9436026905507742,-102.423438716283115],"rgb":[0.66666666666666663,0.466666666666666674,1],"xyz":[0.412218095355264547,0.289599208929256169,0.980291168186385731],"hpluv":[277.202485092995744,215.655115976047284,60.7462409754246551],"hsluv":[277.202485092995744,99.999999999998721,60.7462409754246551]},"#888800":{"lch":[54.9099926918455452,60.532810441385358,85.8743202181747449],"luv":[54.9099926918455452,4.35500198466006783,60.375948006191166],"rgb":[0.533333333333333326,0.533333333333333326,0],"xyz":[0.189568900667635265,0.228427482887910871,0.0341051861362109063],"hpluv":[85.8743202181747449,139.887458074797593,54.9099926918455452],"hsluv":[85.8743202181747449,100.000000000002331,54.9099926918455452]},"#888811":{"lch":[54.9518410557904673,58.8347385736240369,85.8743202181746739],"luv":[54.9518410557904673,4.23283507550337568,58.6822764576347353],"rgb":[0.533333333333333326,0.533333333333333326,0.0666666666666666657],"xyz":[0.190580566167272397,0.228832149087765724,0.039433291100966536],"hpluv":[85.8743202181746739,135.85978011465275,54.9518410557904673],"hsluv":[85.8743202181746739,97.1207726442580395,54.9518410557904673]},"#888822":{"lch":[55.0292864560463215,55.7361292450240882,85.8743202181745602],"luv":[55.0292864560463215,4.00990721741558787,55.5916967480373643],"rgb":[0.533333333333333326,0.533333333333333326,0.133333333333333331],"xyz":[0.192455924305749398,0.229582292343156552,0.0493101772969457355],"hpluv":[85.8743202181745602,128.523412903997382,55.0292864560463215],"hsluv":[85.8743202181745602,91.8762944675706,55.0292864560463215]},"#888833":{"lch":[55.1564325013520573,50.7686053645684225,85.8743202181742902],"luv":[55.1564325013520573,3.65252126093227947,50.6370455210582335],"rgb":[0.533333333333333326,0.533333333333333326,0.2],"xyz":[0.195543675038207132,0.230817392636139651,0.0655723311545568788],"hpluv":[85.8743202181742902,116.798802852822334,55.1564325013520573],"hsluv":[85.8743202181742902,83.4948353914423,55.1564325013520573]},"#888844":{"lch":[55.3392041906722767,43.8756115710196184,85.8743202181737786],"luv":[55.3392041906722767,3.15660835961073616,43.7619139708837039],"rgb":[0.533333333333333326,0.533333333333333326,0.266666666666666663],"xyz":[0.20000167028242602,0.232600590733827245,0.0890511061074435173],"hpluv":[85.8743202181737786,100.607324583255647,55.3392041906722767],"hsluv":[85.8743202181737786,71.9201892491773833,55.3392041906722767]},"#888855":{"lch":[55.5822005995452173,35.1333862553221152,85.8743202181729],"luv":[55.5822005995452173,2.5276534453655044,35.0423429271758167],"rgb":[0.533333333333333326,0.533333333333333326,0.333333333333333315],"xyz":[0.205964084321788032,0.234985556349572078,0.120453153381417433],"hpluv":[85.8743202181729,80.2090919262666233,55.5822005995452173],"hsluv":[85.8743202181729,57.3383011101545321,55.5822005995452173]},"#888866":{"lch":[55.8889601924437187,24.7258905438507242,85.874320218171],"luv":[55.8889601924437187,1.778891507033598,24.6618168064052092],"rgb":[0.533333333333333326,0.533333333333333326,0.4],"xyz":[0.21354908009529619,0.238019554658975369,0.160400797788561394],"hpluv":[85.874320218171,56.1390732800859524,55.8889601924437187],"hsluv":[85.874320218171,40.1315986813270698,55.8889601924437187]},"#888877":{"lch":[56.2621011123828509,12.9137749110131566,85.8743202181651668],"luv":[56.2621011123828509,0.929074909242871283,12.8803106431998842],"rgb":[0.533333333333333326,0.533333333333333326,0.466666666666666674],"xyz":[0.222863093115498123,0.241745159867056192,0.209454599694959304],"hpluv":[85.8743202181651668,29.1257147579972724,56.2621011123828509],"hsluv":[85.8743202181651668,20.8208192205656601,56.2621011123828509]},"#888888":{"lch":[56.703410756754252,2.95076376078202623e-12,0],"luv":[56.703410756754252,2.78254170310414444e-12,9.82073542272051e-13],"rgb":[0.533333333333333326,0.533333333333333326,0.533333333333333326],"xyz":[0.234003510217441923,0.24620132670783379,0.268127463098531471],"hpluv":[0,6.60335407213460764e-12,56.703410756754252],"hsluv":[0,2.14018342731852893e-12,56.703410756754252]},"#888899":{"lch":[57.2139150634865246,13.7029898302256612,265.874320218188814],"luv":[57.2139150634865246,-0.985854571612734376,-13.6674804207248872],"rgb":[0.533333333333333326,0.533333333333333326,0.6],"xyz":[0.247060474326514651,0.251424112351462947,0.33689414073964935],"hpluv":[265.874320218188814,30.3915601408835876,57.2139150634865246],"hsluv":[265.874320218188814,12.5386286039598396,57.2139150634865246]},"#8888aa":{"lch":[57.7939415002624486,27.9001972781706051,265.874320218182902],"luv":[57.7939415002624486,-2.00726537612613365,-27.8278977623291475],"rgb":[0.533333333333333326,0.533333333333333326,0.66666666666666663],"xyz":[0.262118167291767179,0.25744718953756407,0.416197990356647951],"hpluv":[265.874320218182902,61.2582077856443377,57.7939415002624486],"hsluv":[265.874320218182902,25.8334660761224093,57.7939415002624486]},"#8888bb":{"lch":[58.4431822360017605,42.3326731508362428,265.874320218181083],"luv":[58.4431822360017605,-3.04560244672749647,-42.2229738629578222],"rgb":[0.533333333333333326,0.533333333333333326,0.733333333333333282],"xyz":[0.279255759399103853,0.264302226380498828,0.506455975455289753],"hpluv":[265.874320218181083,91.9138937804104756,58.4431822360017605],"hsluv":[265.874320218181083,39.7348050695490116,58.4431822360017605]},"#8888cc":{"lch":[59.1607600358786812,56.7874726838639603,265.874320218180117],"luv":[59.1607600358786812,-4.0855455816182138,-56.6403157752595448],"rgb":[0.533333333333333326,0.533333333333333326,0.8],"xyz":[0.298548134842825608,0.27201917655798763,0.608062486125559909],"hpluv":[265.874320218180117,121.803038601679276,59.1607600358786812],"hsluv":[265.874320218180117,54.1372084350884322,59.1607600358786812]},"#8888dd":{"lch":[59.9452971965242654,71.1002375720468649,265.874320218179605],"luv":[59.9452971965242654,-5.11527010687093497,-70.9159911059223447],"rgb":[0.533333333333333326,0.533333333333333326,0.866666666666666696],"xyz":[0.320066460393459096,0.280626506778241136,0.721392334025565907],"hpluv":[265.874320218179605,150.506501481916018,59.9452971965242654],"hsluv":[265.874320218179605,68.9826297466640881,59.9452971965242654]},"#8888ee":{"lch":[60.7949865781877747,85.1524606014505,265.874320218179207],"luv":[60.7949865781877747,-6.12625008179143,-84.9317997361231676],"rgb":[0.533333333333333326,0.533333333333333326,0.933333333333333348],"xyz":[0.343878640659633861,0.290151378884711153,0.84680315009408913],"hpluv":[265.874320218179207,177.733282428962553,60.7949865781877747],"hsluv":[265.874320218179207,84.2595641984559194,60.7949865781877747]},"#8888ff":{"lch":[61.7076631467729726,98.8655769196339,265.874320218179],"luv":[61.7076631467729726,-7.11283319838656247,-98.6093804034077408],"rgb":[0.533333333333333326,0.533333333333333326,1],"xyz":[0.370049689069465226,0.300619798248643877,0.984637338385871],"hpluv":[265.874320218179,203.303722842755434,61.7076631467729726],"hsluv":[265.874320218179,99.9999999999986073,61.7076631467729726]},"#aa8800":{"lch":[58.1840377660698493,67.6904417424552634,64.2288134226940173],"luv":[58.1840377660698493,29.4303340948507071,60.9577832467208225],"rgb":[0.66666666666666663,0.533333333333333326,0],"xyz":[0.253809676678405038,0.261551633018464735,0.0371164725117156744],"hpluv":[64.2288134226940173,147.625988392398114,58.1840377660698493],"hsluv":[64.2288134226940173,100.000000000002373,58.1840377660698493]},"#aa8811":{"lch":[58.2222766199063955,66.2027965316335809,63.8264905250604926],"luv":[58.2222766199063955,29.2014551434886229,59.4145208354969085],"rgb":[0.66666666666666663,0.533333333333333326,0.0666666666666666657],"xyz":[0.254821342178042143,0.261956299218319588,0.0424445774764713041],"hpluv":[63.8264905250604926,144.286759049554206,58.2222766199063955],"hsluv":[63.8264905250604926,97.5015111084285877,58.2222766199063955]},"#aa8822":{"lch":[58.2930572278629,63.4916551128893474,63.0419050459203],"luv":[58.2930572278629,28.7832252220538578,56.5925455761676304],"rgb":[0.66666666666666663,0.533333333333333326,0.133333333333333331],"xyz":[0.2566967003165192,0.262706442473710389,0.0523214636724505036],"hpluv":[63.0419050459203,138.209896631886636,58.2930572278629],"hsluv":[63.0419050459203,92.9399945222758106,58.2930572278629]},"#aa8833":{"lch":[58.4093035212624585,59.1585039849960737,61.628621374019076],"luv":[58.4093035212624585,28.1112178941065629,52.0527426967384628],"rgb":[0.66666666666666663,0.533333333333333326,0.2],"xyz":[0.259784451048976905,0.263941542766693515,0.0685836175300616468],"hpluv":[61.628621374019076,128.521114132395894,58.4093035212624585],"hsluv":[61.628621374019076,85.621599137751673,58.4093035212624585]},"#aa8844":{"lch":[58.5764981609594315,53.1878639814319953,59.2736460930020499],"luv":[58.5764981609594315,27.1757201885359478,45.7212106919940453],"rgb":[0.66666666666666663,0.533333333333333326,0.266666666666666663],"xyz":[0.264242446293195821,0.265724740864381082,0.0920623924829482854],"hpluv":[59.2736460930020499,115.22015920662389,58.5764981609594315],"hsluv":[59.2736460930020499,75.4571473133808581,58.5764981609594315]},"#aa8855":{"lch":[58.7989500318507083,45.736161182952344,55.3795129841665315],"luv":[58.7989500318507083,25.9844527075537677,37.6378088793954433],"rgb":[0.66666666666666663,0.533333333333333326,0.333333333333333315],"xyz":[0.270204860332557806,0.268109706480125942,0.123464439756922201],"hpluv":[55.3795129841665315,98.7027982667044483,58.7989500318507083],"hsluv":[55.3795129841665315,62.5553187882680319,58.7989500318507083]},"#aa8866":{"lch":[59.0800404303715112,37.1980666756204,48.681601920545944],"luv":[59.0800404303715112,24.5597583059268025,27.9376884576795419],"rgb":[0.66666666666666663,0.533333333333333326,0.4],"xyz":[0.277789856106066,0.271143704789529261,0.163412084164066163],"hpluv":[48.681601920545944,79.8948730878687883,59.0800404303715112],"hsluv":[48.681601920545944,47.1909371341698645,59.0800404303715112]},"#aa8877":{"lch":[59.4223523155875881,28.4467220316745042,36.2691810942760355],"luv":[59.4223523155875881,22.9350730451589406,16.8285001934390941],"rgb":[0.66666666666666663,0.533333333333333326,0.466666666666666674],"xyz":[0.287103869126267897,0.274869309997610056,0.212465886070464072],"hpluv":[36.2691810942760355,60.7465636644032,59.4223523155875881],"hsluv":[36.2691810942760355,29.7643761063162415,59.4223523155875881]},"#aa8888":{"lch":[59.8277504540149323,21.6376696880998622,12.1770506300627677],"luv":[59.8277504540149323,21.1508320810015036,4.56410471095846049],"rgb":[0.66666666666666663,0.533333333333333326,0.533333333333333326],"xyz":[0.298244286228211697,0.279325476838387654,0.271138749474036211],"hpluv":[12.1770506300627677,45.8930730764781174,59.8277504540149323],"hsluv":[12.1770506300627677,15.9793094134510145,59.8277504540149323]},"#aa8899":{"lch":[60.2974403890441693,21.076671863141442,335.972081494736813],"luv":[60.2974403890441693,19.2503183610400761,-8.58203587880762697],"rgb":[0.66666666666666663,0.533333333333333326,0.6],"xyz":[0.311301250337284396,0.284548262482016812,0.339905427115154146],"hpluv":[335.972081494736813,44.3549898137704872,60.2974403890441693],"hsluv":[335.972081494736813,18.3674189175529285,60.2974403890441693]},"#aa88aa":{"lch":[60.8320193568852119,28.2409959286201691,307.715012949248376],"luv":[60.8320193568852119,17.2759870010776844,-22.3404145928166677],"rgb":[0.66666666666666663,0.533333333333333326,0.66666666666666663],"xyz":[0.326358943302536952,0.290571339668117934,0.419209276732152747],"hpluv":[307.715012949248376,58.9097393716334068,60.8320193568852119],"hsluv":[307.715012949248376,20.7885743891348937,60.8320193568852119]},"#aa88bb":{"lch":[61.4315255818646904,39.5305448534603343,292.718173175904553],"luv":[61.4315255818646904,15.2666424694527869,-36.4635928581008],"rgb":[0.66666666666666663,0.533333333333333326,0.733333333333333282],"xyz":[0.343496535409873627,0.297426376511052692,0.509467261830794493],"hpluv":[292.718173175904553,81.6546320542196185,61.4315255818646904],"hsluv":[292.718173175904553,35.3775178816614826,61.4315255818646904]},"#aa88cc":{"lch":[62.0954889075932783,52.4408733717370339,284.64164926901276],"luv":[62.0954889075932783,13.2556230251873277,-50.737891739849438],"rgb":[0.66666666666666663,0.533333333333333326,0.8],"xyz":[0.362788910853595326,0.305143326688541494,0.611073772501064649],"hpluv":[284.64164926901276,107.164068097081099,62.0954889075932783],"hsluv":[284.64164926901276,50.6369924233865092,62.0954889075932783]},"#aa88dd":{"lch":[62.8229837406334894,65.9589053782665644,279.83800714750987],"luv":[62.8229837406334894,11.2699451472508105,-64.988964717689413],"rgb":[0.66666666666666663,0.533333333333333326,0.866666666666666696],"xyz":[0.384307236404228925,0.313750656908795,0.724403620401070647],"hpluv":[279.83800714750987,133.227600809414753,62.8229837406334894],"hsluv":[279.83800714750987,66.50088929558828,62.8229837406334894]},"#aa88ee":{"lch":[63.6126841134072,79.6308922643202237,276.728713669089302],"luv":[63.6126841134072,9.33022805769535,-79.0823990986816767],"rgb":[0.66666666666666663,0.533333333333333326,0.933333333333333348],"xyz":[0.408119416670403634,0.323275529015265,0.84981443646959387],"hpluv":[276.728713669089302,158.846330872338797,63.6126841134072],"hsluv":[276.728713669089302,82.9476730407324112,63.6126841134072]},"#aa88ff":{"lch":[64.4629200033750323,93.219110130063271,274.584640952303687],"luv":[64.4629200033750323,7.4511637136690565,-92.9208407880221756],"rgb":[0.66666666666666663,0.533333333333333326,1],"xyz":[0.434290465080235055,0.333743948379197741,0.987648624761375715],"hpluv":[274.584640952303687,183.499254977583263,64.4629200033750323],"hsluv":[274.584640952303687,99.999999999998451,64.4629200033750323]},"#889900":{"lch":[59.9037942457991477,67.5360782410098892,95.4734085527772578],"luv":[59.9037942457991477,-6.44184579214223074,67.2281524881211396],"rgb":[0.533333333333333326,0.6,0],"xyz":[0.215438501120102766,0.280166683792846538,0.0427283862870331613],"hpluv":[95.4734085527772578,143.060860652479761,59.9037942457991477],"hsluv":[95.4734085527772578,100.000000000002359,59.9037942457991477]},"#889911":{"lch":[59.9403212197486,66.0293008977046867,95.6505578181906628],"luv":[59.9403212197486,-6.50131434341495318,65.7084582747741166],"rgb":[0.533333333333333326,0.6,0.0666666666666666657],"xyz":[0.216450166619739898,0.280571349992701391,0.048056491251788791],"hpluv":[95.6505578181906628,139.783837686775883,59.9403212197486],"hsluv":[95.6505578181906628,97.642419329775592,59.9403212197486]},"#889922":{"lch":[60.0079397017320275,63.2737960078627495,95.9966659299995655],"luv":[60.0079397017320275,-6.6102508868722456,62.9275602932231308],"rgb":[0.533333333333333326,0.6,0.133333333333333331],"xyz":[0.218325524758216899,0.281321493248092191,0.0579333774477679905],"hpluv":[95.9966659299995655,133.799503075015934,60.0079397017320275],"hsluv":[95.9966659299995655,93.3344688530494864,60.0079397017320275]},"#889933":{"lch":[60.1190111745068521,58.8410136656902196,96.6225595920901696],"luv":[60.1190111745068521,-6.78603238946032139,58.4483930798370039],"rgb":[0.533333333333333326,0.6,0.2],"xyz":[0.221413275490674633,0.282556593541075318,0.0741955313053791338],"hpluv":[96.6225595920901696,124.196009967059197,60.1190111745068521],"hsluv":[96.6225595920901696,86.4129060235578,60.1190111745068521]},"#889944":{"lch":[60.2788030378330859,52.6619605596060651,97.6740140778758104],"luv":[60.2788030378330859,-7.03230554676784081,52.1903129773946],"rgb":[0.533333333333333326,0.6,0.266666666666666663],"xyz":[0.22587127073489352,0.284339791638762884,0.0976743062582657723],"hpluv":[97.6740140778758104,110.859197411007315,60.2788030378330859],"hsluv":[97.6740140778758104,76.7791514013919,60.2788030378330859]},"#889955":{"lch":[60.491478208304315,44.7890969420590679,99.4433583384469557],"luv":[60.491478208304315,-7.34865909500015935,44.1821277711999301],"rgb":[0.533333333333333326,0.6,0.333333333333333315],"xyz":[0.231833684774255533,0.286724757254507745,0.129076353532239674],"hpluv":[99.4433583384469557,93.954467458231008,60.491478208304315],"hsluv":[99.4433583384469557,64.5165507795669555,60.491478208304315]},"#889966":{"lch":[60.7603321241253269,35.3998784596055387,102.614945913325585],"luv":[60.7603321241253269,-7.73125582812020351,34.5453191948634597],"rgb":[0.533333333333333326,0.6,0.4],"xyz":[0.23941868054776369,0.289758755563911063,0.169023997939383636],"hpluv":[102.614945913325585,73.9300429237522394,60.7603321241253269],"hsluv":[102.614945913325585,49.862982431557576,60.7603321241253269]},"#889977":{"lch":[61.0879169406466644,24.8557994274465628,109.198389045907604],"luv":[61.0879169406466644,-8.17358342252196,23.4734594640953418],"rgb":[0.533333333333333326,0.6,0.466666666666666674],"xyz":[0.248732693567965624,0.293484360771991859,0.218077799845781545],"hpluv":[109.198389045907604,51.6311437806165543,61.0879169406466644],"hsluv":[109.198389045907604,33.1759220302134779,61.0879169406466644]},"#889988":{"lch":[61.4761176658877702,14.1684419896747276,127.715012949229816],"luv":[61.4761176658877702,-8.66732250724137,11.2081340539023326],"rgb":[0.533333333333333326,0.6,0.533333333333333326],"xyz":[0.259873110669909424,0.297940527612769457,0.276750663249353712],"hpluv":[127.715012949229816,29.2452265306994263,61.4761176658877702],"hsluv":[127.715012949229816,14.8910328511789984,61.4761176658877702]},"#889999":{"lch":[61.9262069462763094,9.41507553536713537,192.177050630058915],"luv":[61.9262069462763094,-9.20324067004397861,-1.98595279549067061],"rgb":[0.533333333333333326,0.6,0.6],"xyz":[0.272930074778982124,0.303163313256398614,0.345517340890471647],"hpluv":[192.177050630058915,19.2925065058214678,61.9262069462763094],"hsluv":[192.177050630058915,19.2169899754877207,61.9262069462763094]},"#8899aa":{"lch":[62.4388911462841207,18.6148502867865133,238.334617604481764],"luv":[62.4388911462841207,-9.77200531832159669,-15.8436284751369474],"rgb":[0.533333333333333326,0.6,0.66666666666666663],"xyz":[0.28798776774423468,0.309186390442499737,0.424821190507470248],"hpluv":[238.334617604481764,37.8306403353000036,62.4388911462841207],"hsluv":[238.334617604481764,23.6900457250072343,62.4388911462841207]},"#8899bb":{"lch":[63.0143540484962,31.8509402607766567,251.009167860858838],"luv":[63.0143540484962,-10.3648329189902189,-30.1173145226625429],"rgb":[0.533333333333333326,0.6,0.733333333333333282],"xyz":[0.305125359851571354,0.316041427285434495,0.515079175606111939],"hpluv":[251.009167860858838,64.1389868285616132,63.0143540484962],"hsluv":[251.009167860858838,32.2218698989210282,63.0143540484962]},"#8899cc":{"lch":[63.6523012354060143,45.9199042321153357,256.173658840600297],"luv":[63.6523012354060143,-10.9739341944061159,-44.5893526863026821],"rgb":[0.533333333333333326,0.6,0.8],"xyz":[0.324417735295293053,0.323758377462923297,0.616685686276382095],"hpluv":[256.173658840600297,91.543221315317254,63.6523012354060143],"hsluv":[256.173658840600297,48.1563502503440546,63.6523012354060143]},"#8899dd":{"lch":[64.3520063546654,60.2052734177332738,258.898139298145679],"luv":[64.3520063546654,-11.5927562398827622,-59.0786166905309358],"rgb":[0.533333333333333326,0.6,0.866666666666666696],"xyz":[0.345936060845926652,0.332365707683176803,0.730015534176388092],"hpluv":[258.898139298145679,118.716686841439611,64.3520063546654],"hsluv":[258.898139298145679,64.7736147673059435,64.3520063546654]},"#8899ee":{"lch":[65.1123593572591091,74.4513212160393465,260.556144021857],"luv":[65.1123593572591091,-12.2160522582942246,-73.442271874149526],"rgb":[0.533333333333333326,0.6,0.933333333333333348],"xyz":[0.369748241112101361,0.34189057978964682,0.855426350244911315],"hpluv":[260.556144021857,145.093615685215838,65.1123593572591091],"hsluv":[260.556144021857,82.0482136329290626,65.1123593572591091]},"#8899ff":{"lch":[65.9319161385595862,88.5102230179824829,261.65889869963604],"luv":[65.9319161385595862,-12.8398242875011679,-87.5739601191992],"rgb":[0.533333333333333326,0.6,1],"xyz":[0.395919289521932782,0.352358999153579544,0.993260538536693161],"hpluv":[261.65889869963604,170.348009793708229,65.9319161385595862],"hsluv":[261.65889869963604,99.9999999999983373,65.9319161385595862]},"#aa9900":{"lch":[62.7844580943873609,69.6780489210530618,75.8779002673010297],"luv":[62.7844580943873609,17.0006834702273615,67.5722373685362072],"rgb":[0.66666666666666663,0.6,0],"xyz":[0.279679277130872483,0.313290833923400402,0.0457396726625379293],"hpluv":[75.8779002673010297,140.82610179048271,62.7844580943873609],"hsluv":[75.8779002673010297,100.000000000002217,62.7844580943873609]},"#aa9911":{"lch":[62.8183644916567232,68.2796688580209548,75.7117398414304],"luv":[62.8183644916567232,16.8514534980901978,66.1675274916835576],"rgb":[0.66666666666666663,0.6,0.0666666666666666657],"xyz":[0.280690942630509588,0.313695500123255255,0.0510677776272935591],"hpluv":[75.7117398414304,137.925354096716262,62.8183644916567232],"hsluv":[75.7117398414304,97.9039601429264792,62.8183644916567232]},"#aa9922":{"lch":[62.8811408657966098,65.7186920323652259,75.3888160486312415],"luv":[62.8811408657966098,16.5780820569936154,63.5933461751813311],"rgb":[0.66666666666666663,0.6,0.133333333333333331],"xyz":[0.282566300768986645,0.314445643378646056,0.0609446638232727586],"hpluv":[75.3888160486312415,132.619634057532949,62.8811408657966098],"hsluv":[75.3888160486312415,94.0678156084237287,62.8811408657966098]},"#aa9933":{"lch":[62.984284118013818,61.5887344728930373,74.8105333616033477],"luv":[62.984284118013818,16.1369729495721401,59.4371122952427768],"rgb":[0.66666666666666663,0.6,0.2],"xyz":[0.28565405150144435,0.315680743671629183,0.0772068176808839],"hpluv":[74.8105333616033477,124.08189266143988,62.984284118013818],"hsluv":[74.8105333616033477,87.8877322232676335,62.984284118013818]},"#aa9944":{"lch":[63.1327254984845325,55.810649390305,73.8551623649617284],"luv":[63.1327254984845325,15.5190685808424753,53.6095802609072862],"rgb":[0.66666666666666663,0.6,0.266666666666666663],"xyz":[0.290112046745663266,0.317463941769316749,0.10068559263377054],"hpluv":[73.8551623649617284,112.176494362550613,63.1327254984845325],"hsluv":[73.8551623649617284,79.2518346201028407,63.1327254984845325]},"#aa9955":{"lch":[63.330394330910508,48.4114193249398497,72.2912631539462893],"luv":[63.330394330910508,14.725704471349518,46.1174495053405593],"rgb":[0.66666666666666663,0.6,0.333333333333333315],"xyz":[0.296074460785025251,0.319848907385061609,0.132087639907744442],"hpluv":[72.2912631539462893,97.0007181904759,63.330394330910508],"hsluv":[72.2912631539462893,68.2014618333714253,63.330394330910508]},"#aa9966":{"lch":[63.5804407621292285,39.5252766283835086,69.6158026784446662],"luv":[63.5804407621292285,13.7671883687516523,37.0501284339143524],"rgb":[0.66666666666666663,0.6,0.4],"xyz":[0.303659456558533436,0.322882905694464928,0.172035284314888404],"hpluv":[69.6158026784446662,78.8843243984218105,63.5804407621292285],"hsluv":[69.6158026784446662,54.9106459007729129,63.5804407621292285]},"#aa9977":{"lch":[63.8853523521207762,29.4269320044373437,64.5162682653354835],"luv":[63.8853523521207762,12.6610788645847681,26.563911782313685],"rgb":[0.66666666666666663,0.6,0.466666666666666674],"xyz":[0.312973469578735342,0.326608510902545723,0.221089086221286313],"hpluv":[64.5162682653354835,58.4497984351079,63.8853523521207762],"hsluv":[64.5162682653354835,39.6604297676390303,63.8853523521207762]},"#aa9988":{"lch":[64.2470245358341288,18.7498828458428441,52.4386898809200943],"luv":[64.2470245358341288,11.4301164327749429,14.8630597477787205],"rgb":[0.66666666666666663,0.6,0.533333333333333326],"xyz":[0.324113886680679142,0.331064677743323321,0.279761949624858508],"hpluv":[52.4386898809200943,37.0326564248891472,64.2470245358341288],"hsluv":[52.4386898809200943,22.8076315183033955,64.2470245358341288]},"#aa9999":{"lch":[64.6668097656484,10.3324715423982241,12.1770506300641514],"luv":[64.6668097656484,10.0999956892392,2.17946214737001709],"rgb":[0.66666666666666663,0.6,0.6],"xyz":[0.337170850789751841,0.336287463386952479,0.348528627265976387],"hpluv":[12.1770506300641514,20.2750581327120152,64.6668097656484],"hsluv":[12.1770506300641514,9.39861318597140283,64.6668097656484]},"#aa99aa":{"lch":[65.1455571833188,14.2173372068657535,307.715012949255367],"luv":[65.1455571833188,8.69723339065650514,-11.2468132643064216],"rgb":[0.66666666666666663,0.6,0.66666666666666663],"xyz":[0.352228543755004397,0.342310540573053601,0.427832476882975],"hpluv":[307.715012949255367,27.6931773999722353,65.1455571833188],"hsluv":[307.715012949255367,11.6506794595111955,65.1455571833188]},"#aa99bb":{"lch":[65.6836488991384186,26.2061362707181722,286.054514249721478],"luv":[65.6836488991384186,7.24735484809431529,-25.1840708771488],"rgb":[0.66666666666666663,0.6,0.733333333333333282],"xyz":[0.369366135862341072,0.34916557741598836,0.51809046198161679],"hpluv":[286.054514249721478,50.6273330900370553,65.6836488991384186],"hsluv":[286.054514249721478,27.5721610485895,65.6836488991384186]},"#aa99cc":{"lch":[66.2810360009151651,39.8419200501833544,278.33213307587846],"luv":[66.2810360009151651,5.77353773601307907,-39.4213756139487757],"rgb":[0.66666666666666663,0.6,0.8],"xyz":[0.388658511306062771,0.356882527593477161,0.619696972651887],"hpluv":[278.33213307587846,76.2764194246967,66.2810360009151651],"hsluv":[278.33213307587846,44.416066179202609,66.2810360009151651]},"#aa99dd":{"lch":[66.937275739096421,53.9476968390211695,274.567192844176702],"luv":[66.937275739096421,4.29575598209881182,-53.7763932853180151],"rgb":[0.66666666666666663,0.6,0.866666666666666696],"xyz":[0.41017683685669637,0.365489857813730668,0.733026820551892944],"hpluv":[274.567192844176702,102.269045280662851,66.937275739096421],"hsluv":[274.567192844176702,62.1125641321495365,66.937275739096421]},"#aa99ee":{"lch":[67.6515703211096309,68.1578213039093299,272.380002942583644],"luv":[67.6515703211096309,2.83038594926376286,-68.0990273078393358],"rgb":[0.66666666666666663,0.6,0.933333333333333348],"xyz":[0.433989017122871079,0.375014729920200685,0.858437636620416167],"hpluv":[272.380002942583644,127.843056183363871,67.6515703211096309],"hsluv":[272.380002942583644,80.63443597048024,67.6515703211096309]},"#aa99ff":{"lch":[68.4228071241374778,82.2834014236355387,270.968064044661787],"luv":[68.4228071241374778,1.39018638405132466,-82.2716569157370543],"rgb":[0.66666666666666663,0.6,1],"xyz":[0.4601600655327025,0.385483149284133408,0.996271824912198],"hpluv":[270.968064044661787,152.598644218259693,68.4228071241374778],"hsluv":[270.968064044661787,99.9999999999981668,68.4228071241374778]},"#770000":{"lch":[23.4140868272264697,78.7423116347599432,12.177050630061796],"luv":[23.4140868272264697,76.9706458719381317,16.6093743302492847],"rgb":[0.466666666666666674,0,0],"xyz":[0.0760757904266185919,0.0392265794387260461,0.00356605267624767169],"hpluv":[12.177050630061796,426.746789183125429,23.4140868272264697],"hsluv":[12.177050630061796,100.000000000002359,23.4140868272264697]},"#770011":{"lch":[23.5491569362977273,75.7570426868466456,9.89164947332394462],"luv":[23.5491569362977273,74.6308667748156864,13.0139633123970793],"rgb":[0.466666666666666674,0,0.0666666666666666657],"xyz":[0.0770874559262557102,0.0396312456385809,0.00889415764100330228],"hpluv":[9.89164947332394462,408.213135586655085,23.5491569362977273],"hsluv":[9.89164947332394462,99.9999999999965183,23.5491569362977273]},"#770022":{"lch":[23.7971287372198219,70.9964864167640854,5.53723409440817704],"luv":[23.7971287372198219,70.6651956613751224,6.85063542055327357],"rgb":[0.466666666666666674,0,0.133333333333333331],"xyz":[0.0789628140647327392,0.0403813888939717203,0.0187710438369825],"hpluv":[5.53723409440817704,378.574731225432288,23.7971287372198219],"hsluv":[5.53723409440817704,99.9999999999967741,23.7971287372198219]},"#770033":{"lch":[24.198804347572846,65.0463245726941182,358.140059561726389],"luv":[24.198804347572846,65.0120550988218895,-2.11116845467566527],"rgb":[0.466666666666666674,0,0.2],"xyz":[0.0820505647971904728,0.0416164891869548331,0.0350331976945936416],"hpluv":[358.140059561726389,341.089366306392606,24.198804347572846],"hsluv":[358.140059561726389,99.9999999999971578,24.198804347572846]},"#770044":{"lch":[24.764944554878376,59.7650645123016702,347.391874641304071],"luv":[24.764944554878376,58.3238787679626398,-13.0456161839744915],"rgb":[0.466666666666666674,0,0.266666666666666663],"xyz":[0.0865085600414093464,0.0433996872846424062,0.0585119726474802801],"hpluv":[347.391874641304071,306.231145677972847,24.764944554878376],"hsluv":[347.391874641304071,99.9999999999975557,24.764944554878376]},"#770055":{"lch":[25.4983947844981387,57.0853266397623571,333.997796644431901],"luv":[25.4983947844981387,51.3069893372134587,-25.0265331742018731],"rgb":[0.466666666666666674,0,0.333333333333333315],"xyz":[0.0924709740807713454,0.0457846529003872391,0.0899140199214541885],"hpluv":[333.997796644431901,284.086748448009075,25.4983947844981387],"hsluv":[333.997796644431901,99.999999999998,25.4983947844981387]},"#770066":{"lch":[26.3955149445472088,58.0812929265372375,320.022905340944305],"luv":[26.3955149445472088,44.5077732621065394,-37.3161453966930949],"rgb":[0.466666666666666674,0,0.4],"xyz":[0.100055969854279517,0.0488186512097905506,0.129861664328598164],"hpluv":[320.022905340944305,279.219318659546161,26.3955149445472088],"hsluv":[320.022905340944305,99.9999999999984,26.3955149445472088]},"#770077":{"lch":[27.4476614837194361,62.5213221502200156,307.715012949243601],"luv":[27.4476614837194361,38.2464397320582776,-49.4583215569799322],"rgb":[0.466666666666666674,0,0.466666666666666674],"xyz":[0.109369982874481436,0.052544256417871367,0.178915466234996073],"hpluv":[307.715012949243601,289.04278373048345,27.4476614837194361],"hsluv":[307.715012949243601,99.9999999999988631,27.4476614837194361]},"#770088":{"lch":[28.6427236217895711,69.3985842918787341,298.067280282401043],"luv":[28.6427236217895711,32.6525926425722872,-61.2370124633397808],"rgb":[0.466666666666666674,0,0.533333333333333326],"xyz":[0.120510399976425264,0.0570004232586489579,0.237588329638568241],"hpluv":[298.067280282401043,307.450798390810235,28.6427236217895711],"hsluv":[298.067280282401043,99.9999999999991473,28.6427236217895711]},"#770099":{"lch":[29.9665727349335924,77.70857748467688,290.909274437861086],"luv":[29.9665727349335924,27.7333531267432782,-72.5912125469701],"rgb":[0.466666666666666674,0,0.6],"xyz":[0.133567364085497964,0.0622232089022781223,0.30635500727968612],"hpluv":[290.909274437861086,329.057057444315717,29.9665727349335924],"hsluv":[290.909274437861086,99.9999999999993605,29.9665727349335924]},"#7700aa":{"lch":[31.4042918618800115,86.7647813143177,285.668616902051383],"luv":[31.4042918618800115,23.4328336498598695,-83.5405864455078415],"rgb":[0.466666666666666674,0,0.66666666666666663],"xyz":[0.14862505705075052,0.0682462860883792238,0.385658856896684721],"hpluv":[285.668616902051383,350.585377409449279,31.4042918618800115],"hsluv":[285.668616902051383,99.9999999999996447,31.4042918618800115]},"#7700bb":{"lch":[32.9411141237069387,96.170393631615,281.802895608829544],"luv":[32.9411141237069387,19.6712233173334745,-94.1370680681067853],"rgb":[0.466666666666666674,0,0.733333333333333282],"xyz":[0.165762649158087166,0.0751013229313139824,0.475916841995326467],"hpluv":[281.802895608829544,370.460950364720645,32.9411141237069387],"hsluv":[281.802895608829544,99.9999999999998295,32.9411141237069387]},"#7700cc":{"lch":[34.5630635499026226,105.713400517707811,278.906152205018032],"luv":[34.5630635499026226,16.3661753747823724,-104.438840249301762],"rgb":[0.466666666666666674,0,0.8],"xyz":[0.185055024601808893,0.082818273108802784,0.577523352665596623],"hpluv":[278.906152205018032,388.112061604616713,34.5630635499026226],"hsluv":[278.906152205018032,99.9999999999998721,34.5630635499026226]},"#7700dd":{"lch":[36.2573361534597964,115.285120662302717,276.696107756350386],"luv":[36.2573361534597964,13.4426218553338188,-114.498711624961956],"rgb":[0.466666666666666674,0,0.866666666666666696],"xyz":[0.206573350152442436,0.091425603329056318,0.690853200565602621],"hpluv":[276.696107756350386,403.475057258468723,36.2573361534597964],"hsluv":[276.696107756350386,100.000000000000156,36.2573361534597964]},"#7700ee":{"lch":[38.012479203832,124.831519574090535,274.979891409884715],"luv":[38.012479203832,10.8361388436516783,-124.360308676593633],"rgb":[0.466666666666666674,0,0.933333333333333348],"xyz":[0.230385530418617201,0.100950475435526349,0.816264016634125844],"hpluv":[274.979891409884715,416.713325299391272,38.012479203832],"hsluv":[274.979891409884715,100.000000000000156,38.012479203832]},"#7700ff":{"lch":[39.8184284160989037,134.326708962856742,273.625091115001112],"luv":[39.8184284160989037,8.49315165227522861,-134.057939398617776],"rgb":[0.466666666666666674,0,1],"xyz":[0.256556578828448567,0.111418894799459045,0.954098204925907689],"hpluv":[273.625091115001112,428.072753406140123,39.8184284160989037],"hsluv":[273.625091115001112,100.000000000000313,39.8184284160989037]},"#771100":{"lch":[24.7134353555624457,74.5310598854495794,14.479461840222152],"luv":[24.7134353555624457,72.1637543524892351,18.6352205622059],"rgb":[0.466666666666666674,0.0666666666666666657,0],"xyz":[0.078080190687547,0.0432353799605829231,0.00423418609655712257],"hpluv":[14.479461840222152,382.686818993669249,24.7134353555624457],"hsluv":[14.479461840222152,100.000000000002174,24.7134353555624457]},"#771111":{"lch":[24.8400617115613187,71.7342088143168723,12.1770506300618244],"luv":[24.8400617115613187,70.1202221387804912,15.1311321924069837],"rgb":[0.466666666666666674,0.0666666666666666657,0.0666666666666666657],"xyz":[0.0790918561871841175,0.043640046160437776,0.00956229106131275403],"hpluv":[12.1770506300618244,366.448517223619376,24.8400617115613187],"hsluv":[12.1770506300618244,85.8702458957174173,24.8400617115613187]},"#771122":{"lch":[25.0727380413203562,67.2476760425649616,7.76714475492354417],"luv":[25.0727380413203562,66.6307123231625,9.0883501491595],"rgb":[0.466666666666666674,0.0666666666666666657,0.133333333333333331],"xyz":[0.0809672143256611465,0.0443901894158286,0.0194391772572919501],"hpluv":[7.76714475492354417,340.341449223453765,25.0727380413203562],"hsluv":[7.76714475492354417,86.6206298981217,25.0727380413203562]},"#771133":{"lch":[25.4501908259833556,61.6001849310061189,0.209311103178295294],"luv":[25.4501908259833556,61.599773884646936,0.225035318388215971],"rgb":[0.466666666666666674,0.0666666666666666657,0.2],"xyz":[0.0840549650581188801,0.0456252897088117101,0.0357013311149031],"hpluv":[0.209311103178295294,307.135699817562568,25.4501908259833556],"hsluv":[0.209311103178295294,87.6964449022470802,25.4501908259833556]},"#771144":{"lch":[25.9833113937366775,56.5829308746863688,349.098656617234155],"luv":[25.9833113937366775,55.5618510799655,-10.7008771106518541],"rgb":[0.466666666666666674,0.0666666666666666657,0.266666666666666663],"xyz":[0.0885129603023377537,0.0474084878064992832,0.0591801060677897353],"hpluv":[349.098656617234155,276.331419289390624,25.9833113937366775],"hsluv":[349.098656617234155,88.9762099121112442,25.9833113937366775]},"#771155":{"lch":[26.6758393728738312,54.157242934368746,335.112354986374442],"luv":[26.6758393728738312,49.127918835603694,-22.7915456504066185],"rgb":[0.466666666666666674,0.0666666666666666657,0.333333333333333315],"xyz":[0.0944753743416997527,0.0497934534222441161,0.0905821533417636438],"hpluv":[335.112354986374442,257.618934567198892,26.6758393728738312],"hsluv":[335.112354986374442,90.3225181656420375,26.6758393728738312]},"#771166":{"lch":[27.5255776115618076,55.4731266930874796,320.490705765847224],"luv":[27.5255776115618076,42.7987039146097388,-35.2921907557026557],"rgb":[0.466666666666666674,0.0666666666666666657,0.4],"xyz":[0.102060370115207924,0.0528274517316474276,0.130529797748907606],"hpluv":[320.490705765847224,255.732268141411282,27.5255776115618076],"hsluv":[320.490705765847224,91.6238582413064364,27.5255776115618076]},"#771177":{"lch":[28.525624322061,60.3055315504910538,307.715012949243658],"luv":[28.525624322061,36.8909645322892956,-47.7054909990940672],"rgb":[0.466666666666666674,0.0666666666666666657,0.466666666666666674],"xyz":[0.111374383135409843,0.056553056939728244,0.179583599655305515],"hpluv":[307.715012949243658,268.263334170626,28.525624322061],"hsluv":[307.715012949243658,92.8109433172232201,28.525624322061]},"#771188":{"lch":[29.665668786552871,67.5901402176946,297.828537901307072],"luv":[29.665668786552871,31.5529142063876336,-59.77324367751811],"rgb":[0.466666666666666674,0.0666666666666666657,0.533333333333333326],"xyz":[0.122514800237353672,0.0610092237805058418,0.238256463058877682],"hpluv":[297.828537901307072,289.113605882780575,29.665668786552871],"hsluv":[297.828537901307072,93.8529472884676892,29.665668786552871]},"#771199":{"lch":[30.9332504381216253,76.2730393291315494,290.583951381139741],"luv":[30.9332504381216253,26.816032696200331,-71.4036197887723461],"rgb":[0.466666666666666674,0.0666666666666666657,0.6],"xyz":[0.135571764346426371,0.066232009424135,0.307023140699995589],"hpluv":[290.583951381139741,312.885056330098905,30.9332504381216253],"hsluv":[290.583951381139741,94.745562802664864,30.9332504381216253]},"#7711aa":{"lch":[32.3148680584756391,85.6471240548678452,285.332056603477554],"luv":[32.3148680584756391,22.6461849228904,-82.5989114172104166],"rgb":[0.466666666666666674,0.0666666666666666657,0.66666666666666663],"xyz":[0.150629457311678927,0.0722550866102361078,0.38632699031699419],"hpluv":[285.332056603477554,336.317699636744408,32.3148680584756391],"hsluv":[285.332056603477554,95.4992611083078771,32.3148680584756391]},"#7711bb":{"lch":[33.796865882550442,95.3131880713117,281.486339493443666],"luv":[33.796865882550442,18.9801244444786903,-93.4042755787407],"rgb":[0.466666666666666674,0.0666666666666666657,0.733333333333333282],"xyz":[0.167767049419015574,0.0791101234531708664,0.476584975415635936],"hpluv":[281.486339493443666,357.862255189103962,33.796865882550442],"hsluv":[281.486339493443666,96.130904738193,33.796865882550442]},"#7711cc":{"lch":[35.36607449089243,105.064609202725904,278.619980375929231],"luv":[35.36607449089243,15.7470979978009513,-103.877817707002151],"rgb":[0.466666666666666674,0.0666666666666666657,0.8],"xyz":[0.1870594248627373,0.086827073630659668,0.578191486085906092],"hpluv":[278.619980375929231,376.971848031202455,35.36607449089243],"hsluv":[278.619980375929231,96.6587778670915441,35.36607449089243]},"#7711dd":{"lch":[37.0102245888209,114.800572621107989,276.441726024966442],"luv":[37.0102245888209,12.8797770828984923,-114.075776641796878],"rgb":[0.466666666666666674,0.0666666666666666657,0.866666666666666696],"xyz":[0.208577750413370844,0.0954344038509132,0.69152133398591209],"hpluv":[276.441726024966442,393.605954910771402,37.0102245888209],"hsluv":[276.441726024966442,97.1000737310191084,37.0102245888209]},"#7711ee":{"lch":[38.7181742300654648,124.475046910670883,274.755182332196796],"luv":[38.7181742300654648,10.3187754184265525,-124.046604859938796],"rgb":[0.466666666666666674,0.0666666666666666657,0.933333333333333348],"xyz":[0.232389930679545609,0.104959275957383219,0.816932150054435313],"hpluv":[274.755182332196796,407.949828918098,38.7181742300654648],"hsluv":[274.755182332196796,97.4698666617264706,38.7181742300654648]},"#7711ff":{"lch":[40.4799968781786,134.069342311184641,273.42679883886251],"luv":[40.4799968781786,8.01376323316973682,-133.829623576382744],"rgb":[0.466666666666666674,0.0666666666666666657,1],"xyz":[0.258560979089377,0.115427695321315929,0.954766338346217158],"hpluv":[273.42679883886251,420.269946860795244,40.4799968781786],"hsluv":[273.42679883886251,99.99999999999946,40.4799968781786]},"#772200":{"lch":[26.9238486490213944,67.8779226750429814,18.9619118830866213],"luv":[26.9238486490213944,64.1945131058521241,22.0562207502031953],"rgb":[0.466666666666666674,0.133333333333333331,0],"xyz":[0.0817958144223149414,0.0506666274301188907,0.00547272734147973266],"hpluv":[18.9619118830866213,319.912145739235086,26.9238486490213944],"hsluv":[18.9619118830866213,100.000000000002203,26.9238486490213944]},"#772211":{"lch":[27.0378210495853537,65.3114997865878451,16.6506371445360628],"luv":[27.0378210495853537,62.5729698674152957,18.7140440938083152],"rgb":[0.466666666666666674,0.133333333333333331,0.0666666666666666657],"xyz":[0.0828074799219520596,0.0510712936299737436,0.0108008323062353633],"hpluv":[16.6506371445360628,306.518925183772069,27.0378210495853537],"hsluv":[16.6506371445360628,87.77659617077137,27.0378210495853537]},"#772222":{"lch":[27.2475131582451553,61.1491638550902934,12.1770506300618262],"luv":[27.2475131582451553,59.7733358183195094,12.8983939049434628],"rgb":[0.466666666666666674,0.133333333333333331,0.133333333333333331],"xyz":[0.0846828380604290887,0.0518214368853645649,0.0206777185022145593],"hpluv":[12.1770506300618262,284.775733052529233,27.2475131582451553],"hsluv":[12.1770506300618262,66.7317810633447,27.2475131582451553]},"#772233":{"lch":[27.5884028886125066,55.830319472153235,4.36926883706767555],"luv":[27.5884028886125066,55.668063043001986,4.25339034219168255],"rgb":[0.466666666666666674,0.133333333333333331,0.2],"xyz":[0.0877705887928868222,0.0530565371783476777,0.0369398723598257],"hpluv":[4.36926883706767555,256.792821962959806,27.5884028886125066],"hsluv":[4.36926883706767555,69.0869865520346,27.5884028886125066]},"#772244":{"lch":[28.0713586292933357,51.0577981227000137,352.597218961633928],"luv":[28.0713586292933357,50.6322267647614197,-6.57847717790113862],"rgb":[0.466666666666666674,0.133333333333333331,0.266666666666666663],"xyz":[0.0922285840371057,0.0548397352760352508,0.0604186473127123411],"hpluv":[352.597218961633928,230.801153887638264,28.0713586292933357],"hsluv":[352.597218961633928,71.9536276136468871,28.0713586292933357]},"#772255":{"lch":[28.7011983995690869,48.8793621784160877,337.425357822166575],"luv":[28.7011983995690869,45.134235573623549,-18.7641367015226166],"rgb":[0.466666666666666674,0.133333333333333331,0.333333333333333315],"xyz":[0.0981909980764677,0.0572247008917800837,0.0918206945866862495],"hpluv":[337.425357822166575,216.105005327694982,28.7011983995690869],"hsluv":[337.425357822166575,75.0482997779786416,28.7011983995690869]},"#772266":{"lch":[29.4776386596593341,50.6214045611569148,321.457127980188602],"luv":[29.4776386596593341,39.5931335065919541,-31.5421999688275427],"rgb":[0.466666666666666674,0.133333333333333331,0.4],"xyz":[0.105775993849975866,0.0602586992011833952,0.131768338993830225],"hpluv":[321.457127980188602,217.911839443782668,29.4776386596593341],"hsluv":[321.457127980188602,78.1196257410634871,29.4776386596593341]},"#772277":{"lch":[30.3962065887853328,56.0773495547330114,307.715012949243828],"luv":[30.3962065887853328,34.3044404103525125,-44.3607315225559375],"rgb":[0.466666666666666674,0.133333333333333331,0.466666666666666674],"xyz":[0.115090006870177786,0.0639843044092642116,0.180822140900228134],"hpluv":[307.715012949243828,234.103236488433623,30.3962065887853328],"hsluv":[307.715012949243828,80.9925899090149,30.3962065887853328]},"#772288":{"lch":[31.4492100235983827,64.0564791390884,297.353574907339521],"luv":[31.4492100235983827,29.432687880373738,-56.8941948166328118],"rgb":[0.466666666666666674,0.133333333333333331,0.533333333333333326],"xyz":[0.126230423972121614,0.0684404712500418094,0.239495004303800302],"hpluv":[297.353574907339521,258.459589193709576,31.4492100235983827],"hsluv":[297.353574907339521,83.5725358287189692,31.4492100235983827]},"#772299":{"lch":[32.6267183371791276,73.3979299617999885,289.947447059718741],"luv":[32.6267183371791276,25.040297814612174,-68.9944896932561136],"rgb":[0.466666666666666674,0.133333333333333331,0.6],"xyz":[0.139287388081194341,0.073663256893670967,0.308261681944918209],"hpluv":[289.947447059718741,285.462946683821,32.6267183371791276],"hsluv":[289.947447059718741,85.8272099061853169,32.6267183371791276]},"#7722aa":{"lch":[33.91747454857272,83.3484305918169213,284.681710760769079],"luv":[33.91747454857272,21.1245907707188039,-80.6269963900962],"rgb":[0.466666666666666674,0.133333333333333331,0.66666666666666663],"xyz":[0.154345081046446869,0.0796863340797720754,0.38756553156191681],"hpluv":[284.681710760769079,311.826661765562392,33.91747454857272],"hsluv":[284.681710760769079,87.7639475735253,33.91747454857272]},"#7722bb":{"lch":[35.3096729107126137,93.4985765466947,280.880145280973409],"luv":[35.3096729107126137,17.6483381470917493,-91.8178630599952186],"rgb":[0.466666666666666674,0.133333333333333331,0.733333333333333282],"xyz":[0.171482673153783516,0.086541370922706834,0.477823516660558556],"hpluv":[280.880145280973409,336.008784107710085,35.3096729107126137],"hsluv":[280.880145280973409,89.410850129911168,35.3096729107126137]},"#7722cc":{"lch":[36.7915673195940158,103.646851370476796,278.075561058441508],"luv":[36.7915673195940158,14.5601992392030191,-102.619054746808203],"rgb":[0.466666666666666674,0.133333333333333331,0.8],"xyz":[0.19077504859750527,0.0942583211001956356,0.579430027330828712],"hpluv":[278.075561058441508,357.476214898523438,36.7915673195940158],"hsluv":[278.075561058441508,90.8041771911133395,36.7915673195940158]},"#7722dd":{"lch":[38.351906528896663,113.703099806952181,275.960131804992216],"luv":[38.351906528896663,11.8065226659589069,-113.088465053903391],"rgb":[0.466666666666666674,0.133333333333333331,0.866666666666666696],"xyz":[0.212293374148138814,0.10286565132044917,0.69275987523083471],"hpluv":[275.960131804992216,376.205095027198126,38.351906528896663],"hsluv":[275.960131804992216,91.9810564333708101,38.351906528896663]},"#7722ee":{"lch":[39.9802139341708269,123.633267676123751,274.331320845995606],"luv":[39.9802139341708269,9.33725773346982812,-123.280170726255989],"rgb":[0.466666666666666674,0.133333333333333331,0.933333333333333348],"xyz":[0.236105554414313523,0.112390523426919187,0.818170691299357933],"hpluv":[274.331320845995606,392.400507860275241,39.9802139341708269],"hsluv":[274.331320845995606,92.975835565241681,39.9802139341708269]},"#7722ff":{"lch":[41.6669409214524222,133.430100966175758,273.053819065229],"luv":[41.6669409214524222,7.10835060884393233,-133.240621416539511],"rgb":[0.466666666666666674,0.133333333333333331,1],"xyz":[0.262276602824144944,0.122858942790851897,0.956004879591139778],"hpluv":[273.053819065229,406.351179140502,41.6669409214524222],"hsluv":[273.053819065229,99.9999999999994,41.6669409214524222]},"#eeaa00":{"lch":[74.1441199778221716,94.3993067628715323,52.9277228913731435],"luv":[74.1441199778221716,56.9059790518510553,75.3189130661151438],"rgb":[0.933333333333333348,0.66666666666666663,0],"xyz":[0.496332043879122442,0.469286695915611562,0.0644413600602487119],"hpluv":[52.9277228913731435,161.559096825574699,74.1441199778221716],"hsluv":[52.9277228913731435,100.00000000000226,74.1441199778221716]},"#eeaa11":{"lch":[74.170022976797469,93.4032488378738748,52.6298301838218165],"luv":[74.170022976797469,56.6922374254564474,74.2304325001913412],"rgb":[0.933333333333333348,0.66666666666666663,0.0666666666666666657],"xyz":[0.497343709378759546,0.469691362115466415,0.0697694650250043485],"hpluv":[52.6298301838218165,159.798572537124,74.170022976797469],"hsluv":[52.6298301838218165,98.6103970010943698,74.170022976797469]},"#eeaa22":{"lch":[74.2180009061856794,91.5777923210439866,52.06484069365154],"luv":[74.2180009061856794,56.2992155036066038,72.2280442769616],"rgb":[0.933333333333333348,0.66666666666666663,0.133333333333333331],"xyz":[0.499219067517236603,0.470441505370857216,0.0796463512209835411],"hpluv":[52.06484069365154,156.574215350823607,74.2180009061856794],"hsluv":[52.06484069365154,96.0561964998804427,74.2180009061856794]},"#eeaa33":{"lch":[74.296884894391,88.6315089581908353,51.0969321655322659],"luv":[74.296884894391,55.6610065739707096,68.9738843866158646],"rgb":[0.933333333333333348,0.66666666666666663,0.2],"xyz":[0.502306818249694365,0.471676605663840343,0.0959085050785946913],"hpluv":[51.0969321655322659,151.375944062314744,74.296884894391],"hsluv":[51.0969321655322659,91.9112466174575786,74.296884894391]},"#eeaa44":{"lch":[74.4105324975616,84.5080331915566,49.6113532778883268],"luv":[74.4105324975616,54.7585847399730952,64.3669563610119582],"rgb":[0.933333333333333348,0.66666666666666663,0.266666666666666663],"xyz":[0.506764813493913224,0.473459803761527909,0.11938728003148133],"hpluv":[49.6113532778883268,144.112916810009352,74.4105324975616],"hsluv":[49.6113532778883268,86.056132752536,74.4105324975616]},"#eeaa55":{"lch":[74.5620870475656545,79.2349762990306203,47.4460085751506284],"luv":[74.5620870475656545,53.5853993814341081,58.3676832008958897],"rgb":[0.933333333333333348,0.66666666666666663,0.333333333333333315],"xyz":[0.512727227533275154,0.475844769377272769,0.150789327305455245],"hpluv":[47.4460085751506284,134.846041865267,74.5620870475656545],"hsluv":[47.4460085751506284,78.4547380743125302,74.5620870475656545]},"#eeaa66":{"lch":[74.7541548019056705,72.9335579755352512,44.3584242628533616],"luv":[74.7541548019056705,52.1460491859645643,50.9911113162453518],"rgb":[0.933333333333333348,0.66666666666666663,0.4],"xyz":[0.520312223306783395,0.478878767686676088,0.190736971712599179],"hpluv":[44.3584242628533616,123.803063546095515,74.7541548019056705],"hsluv":[44.3584242628533616,69.1456590086766,74.7541548019056705]},"#eeaa77":{"lch":[74.988898345165353,65.8409092602829702,39.9757578623994689],"luv":[74.988898345165353,50.4549646902964213,42.3003767160737851],"rgb":[0.933333333333333348,0.66666666666666663,0.466666666666666674],"xyz":[0.529626236326985245,0.482604372894756883,0.239790773618997088],"hpluv":[39.9757578623994689,111.41359114675457,74.988898345165353],"hsluv":[39.9757578623994689,69.3768546233612398,74.988898345165353]},"#eeaa88":{"lch":[75.268091919562039,58.355059996267,33.7246537035848917],"luv":[75.268091919562039,48.5347963512250544,32.3988668060016],"rgb":[0.933333333333333348,0.66666666666666663,0.533333333333333326],"xyz":[0.540766653428929156,0.487060539735534481,0.298463637022569284],"hpluv":[33.7246537035848917,98.3800275430836706,75.268091919562039],"hsluv":[33.7246537035848917,69.7313730072723388,75.268091919562039]},"#eeaa99":{"lch":[75.5931575717450102,51.1191249468368198,24.7740386445795764],"luv":[75.5931575717450102,46.4145012045046172,21.4209946843594],"rgb":[0.933333333333333348,0.66666666666666663,0.6],"xyz":[0.5538236175380018,0.492283325379163639,0.367230314663687163],"hpluv":[24.7740386445795764,85.8104641434512274,75.5931575717450102],"hsluv":[24.7740386445795764,70.1099573125584925,75.5931575717450102]},"#eeaaaa":{"lch":[75.9651912478537,45.142946910964838,12.1770506300622827],"luv":[75.9651912478537,44.1272513869876164,9.52215001119964199],"rgb":[0.933333333333333348,0.66666666666666663,0.66666666666666663],"xyz":[0.568881310503254412,0.498306402565264761,0.446534164280685764],"hpluv":[12.1770506300622827,75.4075094474617771,75.9651912478537],"hsluv":[12.1770506300622827,70.5013292017584661,75.9651912478537]},"#eeaabb":{"lch":[76.3849837125259512,41.8257198613105743,355.706426922992932],"luv":[76.3849837125259512,41.7083375548448743,-3.13136077895000353],"rgb":[0.933333333333333348,0.66666666666666663,0.733333333333333282],"xyz":[0.586018902610591,0.505161439408199464,0.53679214937932751],"hpluv":[355.706426922992932,71.0120800923082243,76.3849837125259512],"hsluv":[355.706426922992932,70.8933377227291857,76.3849837125259512]},"#eeaacc":{"lch":[76.8530390510081,42.4751513806234229,337.329003704434115],"luv":[76.8530390510081,39.1932374848878169,-16.3715796507258275],"rgb":[0.933333333333333348,0.66666666666666663,0.8],"xyz":[0.605311278054312729,0.512878389585688321,0.638398660049597666],"hpluv":[337.329003704434115,73.8860979443606283,76.8530390510081],"hsluv":[337.329003704434115,71.273377003825658,76.8530390510081]},"#eeaadd":{"lch":[77.3695923472492666,47.3596417233686893,320.637369166639587],"luv":[77.3695923472492666,36.6159833837478814,-30.0367345929437413],"rgb":[0.933333333333333348,0.66666666666666663,0.866666666666666696],"xyz":[0.626829603604946328,0.521485719805941828,0.751728507949603664],"hpluv":[320.637369166639587,84.6581146126829,77.3695923472492666],"hsluv":[320.637369166639587,71.6287050870027144,77.3695923472492666]},"#eeaaee":{"lch":[77.9346274334411078,55.5926087174301244,307.715012949246329],"luv":[77.9346274334411078,34.00790779424905,-43.9772708506012506],"rgb":[0.933333333333333348,0.66666666666666663,0.933333333333333348],"xyz":[0.650641783871121,0.531010591912411845,0.877139324018126887],"hpluv":[307.715012949246329,102.440850498764817,77.9346274334411078],"hsluv":[307.715012949246329,71.9466349992656,77.9346274334411078]},"#eeaaff":{"lch":[78.5478951631237123,66.0054362136172,298.40296943037481],"luv":[78.5478951631237123,31.3967924706888546,-58.0599606639755166],"rgb":[0.933333333333333348,0.66666666666666663,1],"xyz":[0.676812832280952459,0.541479011276344568,1.01497351230990884],"hpluv":[298.40296943037481,125.797711632464541,78.5478951631237123],"hsluv":[298.40296943037481,99.9999999999967457,78.5478951631237123]},"#773300":{"lch":[30.1331354048611715,59.6402239078303253,26.8671398719653283],"luv":[30.1331354048611715,53.2024709950710601,26.952799257122777],"rgb":[0.466666666666666674,0.2,0],"xyz":[0.0879135365113257461,0.0629020716081407,0.0075119680378166135],"hpluv":[26.8671398719653283,251.150628123644026,30.1331354048611715],"hsluv":[26.8671398719653283,100.000000000002174,30.1331354048611715]},"#773311":{"lch":[30.23185303241101,57.2493346092074376,24.6191658238461528],"luv":[30.23185303241101,52.0451874365790204,23.8492091669378929],"rgb":[0.466666666666666674,0.2,0.0666666666666666657],"xyz":[0.0889252020109628644,0.0633067378079955473,0.012840073002572245],"hpluv":[24.6191658238461528,240.295148301589592,30.23185303241101],"hsluv":[24.6191658238461528,89.9983576544591131,30.23185303241101]},"#773322":{"lch":[30.4137421865898716,53.2944669038914185,20.1857997859538507],"luv":[30.4137421865898716,50.0210446853216055,18.3900867632275506],"rgb":[0.466666666666666674,0.2,0.133333333333333331],"xyz":[0.0908005601494399,0.0640568810633863617,0.022716959198551441],"hpluv":[20.1857997859538507,222.35740076876786,30.4137421865898716],"hsluv":[20.1857997859538507,72.5478159849102,30.4137421865898716]},"#773333":{"lch":[30.7101510688592612,48.0738359215612618,12.1770506300619186],"luv":[30.7101510688592612,46.9921967440780932,10.1403720532853221],"rgb":[0.466666666666666674,0.2,0.2],"xyz":[0.093888310881897627,0.0652919813563694745,0.0389791130561625843],"hpluv":[12.1770506300619186,198.639745699191,30.7101510688592612],"hsluv":[12.1770506300619186,46.5474493854848177,30.7101510688592612]},"#773344":{"lch":[31.1315732769052218,43.177963340605487,359.450637080068248],"luv":[31.1315732769052218,43.1759786068728815,-0.413992248148033204],"rgb":[0.466666666666666674,0.2,0.266666666666666663],"xyz":[0.0983463061261165,0.0670751794540570545,0.0624578880090492228],"hpluv":[359.450637080068248,175.995032884643848,31.1315732769052218],"hsluv":[359.450637080068248,50.753084379908266,31.1315732769052218]},"#773355":{"lch":[31.6836931484193158,40.8566925980369149,342.103665666318761],"luv":[31.6836931484193158,38.8798033655970627,-12.5550874271345432],"rgb":[0.466666666666666674,0.2,0.333333333333333315],"xyz":[0.1043087201654785,0.0694601450698018874,0.0938599352830231382],"hpluv":[342.103665666318761,163.631433468067485,31.6836931484193158],"hsluv":[342.103665666318761,55.4419897041632623,31.6836931484193158]},"#773366":{"lch":[32.368092831934419,42.8604868736005429,323.403106692152903],"luv":[32.368092831934419,34.4105334223914952,-25.55262265656037],"rgb":[0.466666666666666674,0.2,0.4],"xyz":[0.111893715938986671,0.0724941433792052,0.1338075796901671],"hpluv":[323.403106692152903,168.027093700417197,32.368092831934419],"hsluv":[323.403106692152903,60.2559031079253913,32.368092831934419]},"#773377":{"lch":[33.18286532501061,49.0630735877418189,307.715012949244226],"luv":[33.18286532501061,30.0135669321659,-38.8119954380674201],"rgb":[0.466666666666666674,0.2,0.466666666666666674],"xyz":[0.12120772895918859,0.0762197485872860153,0.182861381596565],"hpluv":[307.715012949244226,187.620458725202155,33.18286532501061],"hsluv":[307.715012949244226,64.9109644958811458,33.18286532501061]},"#773388":{"lch":[34.1232577260479,58.0074356166469371,296.464975996700218],"luv":[34.1232577260479,25.8510525803809479,-51.9286594021626868],"rgb":[0.466666666666666674,0.2,0.533333333333333326],"xyz":[0.132348146061132432,0.0806759154280636132,0.241534245000137177],"hpluv":[296.464975996700218,215.711106662248483,34.1232577260479],"hsluv":[296.464975996700218,69.2226633917654226,34.1232577260479]},"#773399":{"lch":[35.1823459678372572,68.3160830057283,288.793689920994325],"luv":[35.1823459678372572,22.0088074868374761,-64.6737936899706369],"rgb":[0.466666666666666674,0.2,0.6],"xyz":[0.145405110170205132,0.0858987010716927707,0.310300922641255084],"hpluv":[288.793689920994325,246.398176299420243,35.1823459678372572],"hsluv":[288.793689920994325,73.0971646513407,35.1823459678372572]},"#7733aa":{"lch":[36.3517007299652,79.1457370086552316,283.529620316849901],"luv":[36.3517007299652,18.5159885211015585,-76.9493720294691741],"rgb":[0.466666666666666674,0.2,0.66666666666666663],"xyz":[0.160462803135457688,0.0919217782577938791,0.389604772258253684],"hpluv":[283.529620316849901,276.275338575971432,36.3517007299652],"hsluv":[283.529620316849901,76.5077273075914093,36.3517007299652]},"#7733bb":{"lch":[37.6219984216960484,90.0609255961329183,279.823655256592],"luv":[37.6219984216960484,15.3658639022925581,-88.7404110074345596],"rgb":[0.466666666666666674,0.2,0.733333333333333282],"xyz":[0.177600395242794307,0.0987768151007286377,0.479862757356895431],"hpluv":[279.823655256592,303.762299466947354,37.6219984216960484],"hsluv":[279.823655256592,79.4699002038008615,37.6219984216960484]},"#7733cc":{"lch":[38.9835424310364687,100.85881095677091,277.137789072490136],"luv":[38.9835424310364687,12.5323059717609908,-100.077175492935524],"rgb":[0.466666666666666674,0.2,0.8],"xyz":[0.196892770686516061,0.106493765278217439,0.581469268027165587],"hpluv":[277.137789072490136,328.300745951509327,38.9835424310364687],"hsluv":[277.137789072490136,82.0218198813884,38.9835424310364687]},"#7733dd":{"lch":[40.4266769703902469,111.457640409912926,275.137669231249674],"luv":[40.4266769703902469,9.98093438608736,-111.009848907770674],"rgb":[0.466666666666666674,0.2,0.866666666666666696],"xyz":[0.218411096237149605,0.115101095498470973,0.694799115927171584],"hpluv":[275.137669231249674,349.849394775278881,40.4266769703902469],"hsluv":[275.137669231249674,84.2108753320266459,40.4266769703902469]},"#7733ee":{"lch":[41.9420918590451066,121.83559331992231,273.612094072304103],"luv":[41.9420918590451066,7.67578650940870766,-121.593561100411392],"rgb":[0.466666666666666674,0.2,0.933333333333333348],"xyz":[0.242223276503324342,0.12462596760494099,0.820209931995694808],"hpluv":[273.612094072304103,368.606867281158145,41.9420918590451066],"hsluv":[273.612094072304103,91.3228806729277665,41.9420918590451066]},"#7733ff":{"lch":[43.521028110395612,131.998699032970592,272.424037139620168],"luv":[43.521028110395612,5.58285979872954208,-131.88058319125102],"rgb":[0.466666666666666674,0.2,1],"xyz":[0.268394324913155735,0.135094386968873714,0.958044120287476653],"hpluv":[272.424037139620168,384.866252510120546,43.521028110395612],"hsluv":[272.424037139620168,99.9999999999993605,43.521028110395612]},"#eebb00":{"lch":[78.2979307719844115,92.4506686575273307,61.8965912674010781],"luv":[78.2979307719844115,43.5502151824584587,81.5506277890334275],"rgb":[0.933333333333333348,0.733333333333333282,0],"xyz":[0.530286541787721277,0.537195691732810121,0.0757595260297813378],"hpluv":[61.8965912674010781,173.778692590363192,78.2979307719844115],"hsluv":[61.8965912674010781,100.000000000002373,78.2979307719844115]},"#eebb11":{"lch":[78.3216028454340858,91.4822746680663528,61.6861071172261504],"luv":[78.3216028454340858,43.3901974999079059,80.5375523551748],"rgb":[0.933333333333333348,0.733333333333333282,0.0666666666666666657],"xyz":[0.531298207287358437,0.537600357932665,0.0810876309945369744],"hpluv":[61.6861071172261504,172.182825477748111,78.3216028454340858],"hsluv":[61.6861071172261504,98.7812238781787642,78.3216028454340858]},"#eebb22":{"lch":[78.3654531575016335,89.702527227679937,61.2866058237147371],"luv":[78.3654531575016335,43.0956539167563477,78.672155204492924],"rgb":[0.933333333333333348,0.733333333333333282,0.133333333333333331],"xyz":[0.533173565425835383,0.53835050118805583,0.090964517190516167],"hpluv":[61.2866058237147371,169.241982225815036,78.3654531575016335],"hsluv":[61.2866058237147371,96.5386826089343,78.3654531575016335]},"#eebb33":{"lch":[78.4375634156200192,86.8156112143301897,60.6012126372659665],"luv":[78.4375634156200192,42.6165086308843897,75.6358614853528906],"rgb":[0.933333333333333348,0.733333333333333282,0.2],"xyz":[0.5362613161582932,0.539585601481039,0.107226671048127303],"hpluv":[60.6012126372659665,164.44952499458185,78.4375634156200192],"hsluv":[60.6012126372659665,92.89304460263088,78.4375634156200192]},"#eebb44":{"lch":[78.5414800230656,82.7424491039972878,59.5464137785053],"luv":[78.5414800230656,41.9372005918819397,71.3273025583039839],"rgb":[0.933333333333333348,0.733333333333333282,0.266666666666666663],"xyz":[0.540719311402512059,0.541368799578726523,0.130705446001013942],"hpluv":[59.5464137785053,157.640041580932575,78.5414800230656],"hsluv":[59.5464137785053,87.729612164687,78.5414800230656]},"#eebb55":{"lch":[78.6801087960333,77.4695312482544,58.0014729567720551],"luv":[78.6801087960333,41.0509080282697809,65.6989438414256455],"rgb":[0.933333333333333348,0.733333333333333282,0.333333333333333315],"xyz":[0.546681725441874,0.543753765194471272,0.162107493274987857],"hpluv":[58.0014729567720551,148.738759066450825,78.6801087960333],"hsluv":[58.0014729567720551,81.0022494643358613,78.6801087960333]},"#eebb66":{"lch":[78.8558787138066748,71.0520814803831229,55.7790951769469174],"luv":[78.8558787138066748,39.9586324736418845,58.7512210386423703],"rgb":[0.933333333333333348,0.733333333333333282,0.4],"xyz":[0.55426672121538223,0.546787763503874591,0.202055137682131819],"hpluv":[55.7790951769469174,137.768430134850121,78.8558787138066748],"hsluv":[55.7790951769469174,72.7264864885570574,78.8558787138066748]},"#eebb77":{"lch":[79.0708286262536,63.6259938562226566,52.5733668905169],"luv":[79.0708286262536,38.6683825737350801,50.5274507898760348],"rgb":[0.933333333333333348,0.733333333333333282,0.466666666666666674],"xyz":[0.56358073423558408,0.550513368711955442,0.251108939588529756],"hpluv":[52.5733668905169,124.876553308513152,79.0708286262536],"hsluv":[52.5733668905169,64.3532422469102841,79.0708286262536]},"#eebb88":{"lch":[79.3266586201773833,55.4370708593257149,47.8613800964459557],"luv":[79.3266586201773833,37.1942049853437169,41.1079060640423961],"rgb":[0.933333333333333348,0.733333333333333282,0.533333333333333326],"xyz":[0.574721151337528,0.554969535552733,0.309781802992101896],"hpluv":[47.8613800964459557,110.403075040931697,79.3266586201773833],"hsluv":[47.8613800964459557,64.6428486235092379,79.3266586201773833]},"#eebb99":{"lch":[79.6247632766216071,46.9114913521919519,40.7190885070752131],"luv":[79.6247632766216071,35.5550187983100727,30.6027557441907163],"rgb":[0.933333333333333348,0.733333333333333282,0.6],"xyz":[0.587778115446600635,0.560192321196362197,0.378548480633219775],"hpluv":[40.7190885070752131,95.0436922052712845,79.6247632766216071],"hsluv":[40.7190885070752131,64.94797236425741,79.6247632766216071]},"#eebbaa":{"lch":[79.9662551563314,38.821829319770238,29.5464132636418633],"luv":[79.9662551563314,33.7733033676501,19.1441482278540249],"rgb":[0.933333333333333348,0.733333333333333282,0.66666666666666663],"xyz":[0.602835808411853247,0.566215398382463264,0.457852330250218431],"hpluv":[29.5464132636418633,80.2381481795300573,79.9662551563314],"hsluv":[29.5464132636418633,65.2570717669902081,79.9662551563314]},"#eebbbb":{"lch":[80.3519829843595,32.6073830473385868,12.1770506300627979],"luv":[80.3519829843595,31.8737319395561,6.87798236703069765],"rgb":[0.933333333333333348,0.733333333333333282,0.733333333333333282],"xyz":[0.61997340051918981,0.573070435225398,0.548110315348860122],"hpluv":[12.1770506300627979,68.9527679352530498,80.3519829843595],"hsluv":[12.1770506300627979,65.5572779496269646,80.3519829843595]},"#eebbcc":{"lch":[80.7825470949933,30.4869713003172755,348.56539147946927],"luv":[80.7825470949933,29.8818538307637169,-6.04402437976891349],"rgb":[0.933333333333333348,0.733333333333333282,0.8],"xyz":[0.639265775962911564,0.58078738540288688,0.649716826019130278],"hpluv":[348.56539147946927,66.1649916626687542,80.7825470949933],"hsluv":[348.56539147946927,65.8346704867411,80.7825470949933]},"#eebbdd":{"lch":[81.2583136554081165,33.9595526191752555,325.014354592586812],"luv":[81.2583136554081165,27.8229160969035512,-19.4714291709468021],"rgb":[0.933333333333333348,0.733333333333333282,0.866666666666666696],"xyz":[0.660784101513545163,0.589394715623140386,0.763046673919136276],"hpluv":[325.014354592586812,75.8902298772919721,81.2583136554081165],"hsluv":[325.014354592586812,66.0744631525984119,81.2583136554081165]},"#eebbee":{"lch":[81.7794285687783429,42.0458499431423576,307.715012949247921],"luv":[81.7794285687783429,25.7208902583653902,-33.2609275540891716],"rgb":[0.933333333333333348,0.733333333333333282,0.933333333333333348],"xyz":[0.684596281779719873,0.598919587729610403,0.888457489987659499],"hpluv":[307.715012949247921,97.0917602325266245,81.7794285687783429],"hsluv":[307.715012949247921,66.2610602343042103,81.7794285687783429]},"#eebbff":{"lch":[82.3458315671937697,52.842459086223478,296.523687653639684],"luv":[82.3458315671937697,23.5977388768935938,-47.2807804734349446],"rgb":[0.933333333333333348,0.733333333333333282,1],"xyz":[0.710767330189551294,0.609388007093543127,1.02629167827944134],"hpluv":[296.523687653639684,126.563624284615543,82.3458315671937697],"hsluv":[296.523687653639684,99.9999999999958504,82.3458315671937697]},"#774400":{"lch":[34.1007355557283631,52.2824067620925845,38.9690248280103901],"luv":[34.1007355557283631,40.6488429776156863,32.8804139483986475],"rgb":[0.466666666666666674,0.266666666666666663,0],"xyz":[0.0967461069942917862,0.0805672125740730105,0.0104561581988052085],"hpluv":[38.9690248280103901,194.549962435525771,34.1007355557283631],"hsluv":[38.9690248280103901,100.000000000002302,34.1007355557283631]},"#774411":{"lch":[34.1844760931178726,49.9480603042207,37.0032460066389604],"luv":[34.1844760931178726,39.8885915773263164,30.0617529450848728],"rgb":[0.466666666666666674,0.266666666666666663,0.0666666666666666657],"xyz":[0.0977577724939289,0.0809718787739278634,0.0157842631635608383],"hpluv":[37.0032460066389604,185.408237524396696,34.1844760931178726],"hsluv":[37.0032460066389604,92.0774266797174477,34.1844760931178726]},"#774422":{"lch":[34.3389737161705639,45.9687551907429608,33.0232295817012798],"luv":[34.3389737161705639,38.542488289151045,25.0520069109664867],"rgb":[0.466666666666666674,0.266666666666666663,0.133333333333333331],"xyz":[0.0996331306324059335,0.0817220220293186778,0.0256611493595400378],"hpluv":[33.0232295817012798,169.869245826721482,34.3389737161705639],"hsluv":[33.0232295817012798,78.0803941927279794,34.3389737161705639]},"#774433":{"lch":[34.5913049894652787,40.4066166426811861,25.4401077009201266],"luv":[34.5913049894652787,36.4885814660887746,17.357364174931714],"rgb":[0.466666666666666674,0.266666666666666663,0.2],"xyz":[0.102720881364863667,0.0829571223223017906,0.041923303217151181],"hpluv":[25.4401077009201266,148.226163260119392,34.5913049894652787],"hsluv":[25.4401077009201266,56.8050953227402715,34.5913049894652787]},"#774444":{"lch":[34.9512320153617324,34.6101233100924119,12.1770506300620909],"luv":[34.9512320153617324,33.8314114683579277,7.30042694631360689],"rgb":[0.466666666666666674,0.266666666666666663,0.266666666666666663],"xyz":[0.107178876609082541,0.0847403204199893706,0.0654020781700378195],"hpluv":[12.1770506300620909,125.655060642768362,34.9512320153617324],"hsluv":[12.1770506300620909,29.4448754689639038,34.9512320153617324]},"#774455":{"lch":[35.4248138391838907,31.0799263948782318,351.580242092888511],"luv":[35.4248138391838907,30.7449438027498871,-4.55085214842230634],"rgb":[0.466666666666666674,0.266666666666666663,0.333333333333333315],"xyz":[0.11314129064844454,0.0871252860357342,0.0968041254440117349],"hpluv":[351.580242092888511,111.329877567225012,35.4248138391838907],"hsluv":[351.580242092888511,35.0525071981411855,35.4248138391838907]},"#774466":{"lch":[36.0149447056398699,32.55773059028094,327.386935336661793],"luv":[36.0149447056398699,27.4243377055297302,-17.5474078599198116],"rgb":[0.466666666666666674,0.266666666666666663,0.4],"xyz":[0.120726286421952711,0.090159284345137522,0.136751769851155697],"hpluv":[327.386935336661793,114.712488009680612,36.0149447056398699],"hsluv":[327.386935336661793,41.0162201785438469,36.0149447056398699]},"#774477":{"lch":[36.7217587051522898,39.3078830273429531,307.715012949244965],"luv":[36.7217587051522898,24.0459818745983789,-31.0950224919964064],"rgb":[0.466666666666666674,0.266666666666666663,0.466666666666666674],"xyz":[0.130040299442154617,0.0938848895532183314,0.185805571757553606],"hpluv":[307.715012949244965,135.82994003022975,36.7217587051522898],"hsluv":[307.715012949244965,46.9930223744603381,36.7217587051522898]},"#774488":{"lch":[37.5430301686231331,49.3077922843884906,294.880307130505798],"luv":[37.5430301686231331,20.7449732069104158,-44.731470651041306],"rgb":[0.466666666666666674,0.266666666666666663,0.533333333333333326],"xyz":[0.141180716544098472,0.0983410563939959292,0.244478435161125773],"hpluv":[294.880307130505798,166.657768282509579,37.5430301686231331],"hsluv":[294.880307130505798,52.7229750286883814,37.5430301686231331]},"#774499":{"lch":[38.4745988052595678,60.7540316024919775,286.849160899925266],"luv":[38.4745988052595678,17.609743748149274,-58.1459309073396042],"rgb":[0.466666666666666674,0.266666666666666663,0.6],"xyz":[0.154237680653171172,0.103563842037625087,0.313245112802243653],"hpluv":[286.849160899925266,200.373520820200838,38.4745988052595678],"hsluv":[286.849160899925266,58.0391908614757739,38.4745988052595678]},"#7744aa":{"lch":[39.5108096650206306,72.6607854160185695,281.662296555210446],"luv":[39.5108096650206306,14.6878600390207232,-71.1607792589909423],"rgb":[0.466666666666666674,0.266666666666666663,0.66666666666666663],"xyz":[0.169295373618423728,0.109586919223726181,0.392548962419242253],"hpluv":[281.662296555210446,233.358425064810547,39.5108096650206306],"hsluv":[281.662296555210446,62.855979622580108,39.5108096650206306]},"#7744bb":{"lch":[40.6449442050895,84.5532389367896684,278.156646558388104],"luv":[40.6449442050895,11.9964108827533504,-83.6978873128468],"rgb":[0.466666666666666674,0.266666666666666663,0.733333333333333282],"xyz":[0.186432965725760347,0.11644195606666094,0.482806947517884],"hpluv":[278.156646558388104,263.975148792079324,40.6449442050895],"hsluv":[278.156646558388104,67.1480450168623832,40.6449442050895]},"#7744cc":{"lch":[41.8696179576200223,96.2178725735773099,275.685728840067554],"luv":[41.8696179576200223,9.53248740063005151,-95.7445073439828747],"rgb":[0.466666666666666674,0.266666666666666663,0.8],"xyz":[0.205725341169482101,0.124158906244149742,0.584413458188154156],"hpluv":[275.685728840067554,291.605746800226,41.8696179576200223],"hsluv":[275.685728840067554,71.7563947172966721,41.8696179576200223]},"#7744dd":{"lch":[43.1771261833787037,107.572507589609089,273.881356516641858],"luv":[43.1771261833787037,7.28165300546471084,-107.325774717094461],"rgb":[0.466666666666666674,0.266666666666666663,0.866666666666666696],"xyz":[0.227243666720115645,0.132766236464403276,0.697743306088160153],"hpluv":[273.881356516641858,316.145413845169799,43.1771261833787037],"hsluv":[273.881356516641858,81.1040313116107683,43.1771261833787037]},"#7744ee":{"lch":[44.5597272061305958,118.600491111934247,272.524492751992966],"luv":[44.5597272061305958,5.22393127379498168,-118.485387428318177],"rgb":[0.466666666666666674,0.266666666666666663,0.933333333333333348],"xyz":[0.251055846986290354,0.14229110857087332,0.823154122156683377],"hpluv":[272.524492751992966,337.740615485066769,44.5597272061305958],"hsluv":[272.524492751992966,90.4775463334620866,44.5597272061305958]},"#7744ff":{"lch":[46.0098610845945188,129.316457315512423,271.478956563127554],"luv":[46.0098610845945188,3.33763127257498882,-129.273378350389976],"rgb":[0.466666666666666674,0.266666666666666663,1],"xyz":[0.277226895396121775,0.152759527934806016,0.960988310448465222],"hpluv":[271.478956563127554,356.649979093308843,46.0098610845945188],"hsluv":[271.478956563127554,99.9999999999992752,46.0098610845945188]},"#eecc00":{"lch":[82.5742071813858161,93.0890420253441278,70.6743105766144737],"luv":[82.5742071813858161,30.8066573410433797,87.8437226480516529],"rgb":[0.933333333333333348,0.8,0],"xyz":[0.568510285097338142,0.613643178352045071,0.088500773799653279],"hpluv":[70.6743105766144737,226.330948640265689,82.5742071813858161],"hsluv":[70.6743105766144737,100.000000000002331,82.5742071813858161]},"#eecc11":{"lch":[82.5958706312260773,92.1609271203023,70.5494354113464226],"luv":[82.5958706312260773,30.6889817522442812,86.9012248859824297],"rgb":[0.933333333333333348,0.8,0.0666666666666666657],"xyz":[0.569521950596975302,0.6140478445519,0.0938288787644089156],"hpluv":[70.5494354113464226,224.395635781555484,82.5958706312260773],"hsluv":[70.5494354113464226,98.9293851282895389,82.5958706312260773]},"#eecc22":{"lch":[82.636003730849751,90.4517890224530277,70.3125751850760849],"luv":[82.636003730849751,30.4721781878481224,85.1643851257694848],"rgb":[0.933333333333333348,0.8,0.133333333333333331],"xyz":[0.571397308735452247,0.61479798780729078,0.103705764960388108],"hpluv":[70.3125751850760849,220.820363432361461,82.636003730849751],"hsluv":[70.3125751850760849,96.9576791715233668,82.636003730849751]},"#eecc33":{"lch":[82.7020112487531,87.6695564091762236,69.9066450473675332],"luv":[82.7020112487531,30.1189443150749909,82.3334701948554084],"rgb":[0.933333333333333348,0.8,0.2],"xyz":[0.574485059467910064,0.616033088100273907,0.119967918817999258],"hpluv":[69.9066450473675332,214.968262161852493,82.7020112487531],"hsluv":[69.9066450473675332,93.7473974454290726,82.7020112487531]},"#eecc44":{"lch":[82.7971553193909102,83.7217279628800242,69.2828434677537786],"luv":[82.7971553193909102,29.6169744667019792,78.3081257375581],"rgb":[0.933333333333333348,0.8,0.266666666666666663],"xyz":[0.578943054712128924,0.617816286197961473,0.143446693770885897],"hpluv":[69.2828434677537786,206.594355258371763,82.7971553193909102],"hsluv":[69.2828434677537786,89.1900904304584685,82.7971553193909102]},"#eecc55":{"lch":[82.9241214704336471,78.5673404382155098,68.3706518767947387],"luv":[82.9241214704336471,28.9599810639926183,73.0352413585910085],"rgb":[0.933333333333333348,0.8,0.333333333333333315],"xyz":[0.584905468751490853,0.620201251813706222,0.174848741044859812],"hpluv":[68.3706518767947387,195.532369916851508,82.9241214704336471],"hsluv":[68.3706518767947387,83.2339277722755497,82.9241214704336471]},"#eecc66":{"lch":[83.0851700146488241,72.2150018940459688,67.0599726095305186],"luv":[83.0851700146488241,28.1470538355007811,66.503758231685552],"rgb":[0.933333333333333348,0.8,0.4],"xyz":[0.592490464524999094,0.623235250123109541,0.214796385452003746],"hpluv":[67.0599726095305186,181.688085793908328,83.0851700146488241],"hsluv":[67.0599726095305186,75.8779818086204898,83.0851700146488241]},"#eecc77":{"lch":[83.2822165713090925,64.7250307453925586,65.1677162202921778],"luv":[83.2822165713090925,27.1821511319325673,58.740618526133936],"rgb":[0.933333333333333348,0.8,0.466666666666666674],"xyz":[0.601804477545200944,0.626960855331190392,0.263850187358401655],"hpluv":[65.1677162202921778,165.044758034407693,83.2822165713090925],"hsluv":[65.1677162202921778,67.1675472191497533,83.2822165713090925]},"#eecc88":{"lch":[83.5168798492942699,56.2182636624862511,62.3679934299132839],"luv":[83.5168798492942699,26.0735255024375405,49.8062690541919793],"rgb":[0.933333333333333348,0.8,0.533333333333333326],"xyz":[0.612944894647144856,0.631417022171967934,0.322523050761973851],"hpluv":[62.3679934299132839,145.689263900370548,83.5168798492942699],"hsluv":[62.3679934299132839,57.1887031148042198,83.5168798492942699]},"#eecc99":{"lch":[83.79051243806407,46.9027423702446598,58.0311593919332083],"luv":[83.79051243806407,24.8330316313984234,39.7892923013655633],"rgb":[0.933333333333333348,0.8,0.6],"xyz":[0.6260018587562175,0.636639807815597147,0.39128972840309173],"hpluv":[58.0311593919332083,123.89218615802821,83.79051243806407],"hsluv":[58.0311593919332083,56.9799526918745158,83.79051243806407]},"#eeccaa":{"lch":[84.1042222244633,37.1556922719042646,50.8162292091241454],"luv":[84.1042222244633,23.475329457535171,28.8002495660129298],"rgb":[0.933333333333333348,0.8,0.66666666666666663],"xyz":[0.641059551721470111,0.642662885001698214,0.470593578020090331],"hpluv":[50.8162292091241454,100.353156070069275,84.1042222244633],"hsluv":[50.8162292091241454,57.1375361174420533,84.1042222244633]},"#eeccbb":{"lch":[84.4588885299527,27.7950211383377486,37.6158086991229084],"luv":[84.4588885299527,22.0170273242058485,16.9650731765535063],"rgb":[0.933333333333333348,0.8,0.733333333333333282],"xyz":[0.658197143828806674,0.649517921844633,0.560851563118732077],"hpluv":[37.6158086991229084,77.0182985337263517,84.4588885299527],"hsluv":[37.6158086991229084,57.2612530554736736,84.4588885299527]},"#eecccc":{"lch":[84.8551753311588897,20.9471233587290264,12.1770506300631585],"luv":[84.8551753311588897,20.4758227261490333,4.41844550641173317],"rgb":[0.933333333333333348,0.8,0.8],"xyz":[0.677489519272528429,0.65723487202212183,0.662458073789002233],"hpluv":[12.1770506300631585,59.764130158742411,84.8551753311588897],"hsluv":[12.1770506300631585,57.3329985994000637,84.8551753311588897]},"#eeccdd":{"lch":[85.2935429882433596,20.7797326136980232,335.241604291037675],"luv":[85.2935429882433596,18.8696973425293919,-8.70240252448279],"rgb":[0.933333333333333348,0.8,0.866666666666666696],"xyz":[0.699007844823162,0.665842202242375336,0.775787921689008231],"hpluv":[335.241604291037675,61.2821093808529582,85.2935429882433596],"hsluv":[335.241604291037675,57.3323512744098664,85.2935429882433596]},"#eeccee":{"lch":[85.7742593547863805,28.14328338963319,307.715012949251047],"luv":[85.7742593547863805,17.2162128855465397,-22.2631177921859056],"rgb":[0.933333333333333348,0.8,0.933333333333333348],"xyz":[0.722820025089336737,0.675367074348845353,0.901198737757531454],"hpluv":[307.715012949251047,86.153290074940827,85.7742593547863805],"hsluv":[307.715012949251047,57.2362127773837557,85.7742593547863805]},"#eeccff":{"lch":[86.2974107975625344,39.333162863939684,293.258584701896098],"luv":[86.2974107975625344,15.5319389668875889,-36.1366375415599919],"rgb":[0.933333333333333348,0.8,1],"xyz":[0.748991073499168158,0.685835493712778077,1.03903292604931341],"hpluv":[293.258584701896098,125.558261528980708,86.2974107975625344],"hsluv":[293.258584701896098,99.9999999999940314,86.2974107975625344]},"#775500":{"lch":[38.5848153490983421,48.2339285723334328,54.8056311564330656],"luv":[38.5848153490983421,27.7997213245256276,39.4168410682499868],"rgb":[0.466666666666666674,0.333333333333333315,0],"xyz":[0.108559363708637752,0.104193726002765275,0.0143939104369204193],"hpluv":[54.8056311564330656,158.626424871442595,38.5848153490983421],"hsluv":[54.8056311564330656,100.000000000002302,38.5848153490983421]},"#775511":{"lch":[38.6553893217116595,45.9150245993572952,53.4685955296553956],"luv":[38.6553893217116595,27.3315290852913257,36.8941323494598521],"rgb":[0.466666666666666674,0.333333333333333315,0.0666666666666666657],"xyz":[0.10957102920827487,0.104598392202620127,0.0197220154016760491],"hpluv":[53.4685955296553956,150.724584795248319,38.6553893217116595],"hsluv":[53.4685955296553956,93.8009130268131344,38.6553893217116595]},"#775522":{"lch":[38.7857346943923531,41.8305053308362176,50.7011784026830412],"luv":[38.7857346943923531,26.4939762066725,32.3706719268134577],"rgb":[0.466666666666666674,0.333333333333333315,0.133333333333333331],"xyz":[0.111446387346751899,0.105348535458010942,0.0295989015976552486],"hpluv":[50.7011784026830412,136.854920013655288,38.7857346943923531],"hsluv":[50.7011784026830412,82.7342982429400138,38.7857346943923531]},"#775533":{"lch":[38.9990050188249739,35.7224202133018096,45.1472123185964946],"luv":[38.9990050188249739,25.1945818654867857,25.3243825298663161],"rgb":[0.466666666666666674,0.333333333333333315,0.2],"xyz":[0.114534138079209633,0.106583635750994055,0.0458610554552663918],"hpluv":[45.1472123185964946,116.232257903435652,38.9990050188249739],"hsluv":[45.1472123185964946,65.6272728324870656,38.9990050188249739]},"#775544":{"lch":[39.3040305977305735,28.372964966311546,34.1730058033032336],"luv":[39.3040305977305735,23.4742392428959334,15.9369141601135258],"rgb":[0.466666666666666674,0.333333333333333315,0.266666666666666663],"xyz":[0.118992133323428506,0.108366833848681635,0.0693398304081530303],"hpluv":[34.1730058033032336,91.6024225041024,39.3040305977305735],"hsluv":[34.1730058033032336,43.1049791856067799,39.3040305977305735]},"#775555":{"lch":[39.7068052905653701,21.9117916496410494,12.1770506300624941],"luv":[39.7068052905653701,21.4187864245998618,4.62192615633957704],"rgb":[0.466666666666666674,0.333333333333333315,0.333333333333333315],"xyz":[0.124954547362790505,0.110751799464426468,0.100741877682126946],"hpluv":[12.1770506300624941,70.0248633547080601,39.7068052905653701],"hsluv":[12.1770506300624941,16.4089959502104463,39.7068052905653701]},"#775566":{"lch":[40.21091767922141,20.7753835118276839,337.09176723456028],"luv":[40.21091767922141,19.1368182791551824,-8.08694912894311],"rgb":[0.466666666666666674,0.333333333333333315,0.4],"xyz":[0.132539543136298676,0.113785797773829786,0.140689522089270908],"hpluv":[337.09176723456028,65.5608222190156482,40.21091767922141],"hsluv":[337.09176723456028,22.8015335286909036,40.21091767922141]},"#775577":{"lch":[40.8178321801082404,27.3616881241227183,307.715012949246557],"luv":[40.8178321801082404,16.7380842217685313,-21.6448264854847388],"rgb":[0.466666666666666674,0.333333333333333315,0.466666666666666674],"xyz":[0.141853556156500582,0.117511402981910595,0.189743323995668817],"hpluv":[307.715012949246557,85.0613515767839,40.8178321801082404],"hsluv":[307.715012949246557,29.4286369924042717,40.8178321801082404]},"#775588":{"lch":[41.5271394874135922,38.3484586217177892,291.922773984013077],"luv":[41.5271394874135922,14.317648223710199,-35.5754020076188269],"rgb":[0.466666666666666674,0.333333333333333315,0.533333333333333326],"xyz":[0.152993973258444438,0.121967569822688193,0.248416187399240984],"hpluv":[291.922773984013077,117.180466459805771,41.5271394874135922],"hsluv":[291.922773984013077,36.0000576829853429,41.5271394874135922]},"#775599":{"lch":[42.336815252734,50.9328741768069335,283.566916489070877],"luv":[42.336815252734,11.9478768110398388,-49.5116744982298442],"rgb":[0.466666666666666674,0.333333333333333315,0.6],"xyz":[0.166050937367517137,0.127190355466317351,0.317182865040358863],"hpluv":[283.566916489070877,152.657914615048412,42.336815252734],"hsluv":[283.566916489070877,42.2975255710275704,42.336815252734]},"#7755aa":{"lch":[43.2434937800222059,63.9392804809027098,278.705184193400783],"luv":[43.2434937800222059,9.67722671121172517,-63.202712533524668],"rgb":[0.466666666666666674,0.333333333333333315,0.66666666666666663],"xyz":[0.181108630332769693,0.133213432652418445,0.396486714657357464],"hpluv":[278.705184193400783,187.623095354238075,43.2434937800222059],"hsluv":[278.705184193400783,48.1780536314011272,43.2434937800222059]},"#7755bb":{"lch":[44.2427493107278096,76.8690732738289171,275.624120681329657],"luv":[44.2427493107278096,7.53331271169703509,-76.4990432983646116],"rgb":[0.466666666666666674,0.333333333333333315,0.733333333333333282],"xyz":[0.198246222440106312,0.140068469495353204,0.486744699755999211],"hpluv":[275.624120681329657,220.469676556121556,44.2427493107278096],"hsluv":[275.624120681329657,58.1137757976744496,44.2427493107278096]},"#7755cc":{"lch":[45.3293721892173949,89.4999308488430785,273.541003165926895],"luv":[45.3293721892173949,5.52776894932058127,-89.3290624175056536],"rgb":[0.466666666666666674,0.333333333333333315,0.8],"xyz":[0.217538597883828067,0.147785419672842,0.588351210426269366],"hpluv":[273.541003165926895,250.543028147628775,45.3293721892173949],"hsluv":[273.541003165926895,68.560007412736141,45.3293721892173949]},"#7755dd":{"lch":[46.4976270234735622,101.740884988783861,272.062259876532949],"luv":[46.4976270234735622,3.66119191329505167,-101.674988822595736],"rgb":[0.466666666666666674,0.333333333333333315,0.866666666666666696],"xyz":[0.23905692343446161,0.15639274989309554,0.701681058326275364],"hpluv":[272.062259876532949,277.654072578046794,46.4976270234735622],"hsluv":[272.062259876532949,78.9623412233913911,46.4976270234735622]},"#7755ee":{"lch":[47.7414825998049253,113.569026574645434,270.972372145675877],"luv":[47.7414825998049253,1.92729827623402139,-113.552672000560818],"rgb":[0.466666666666666674,0.333333333333333315,0.933333333333333348],"xyz":[0.26286910370063632,0.165917621999565584,0.827091874394798587],"hpluv":[270.972372145675877,301.858443342198598,47.7414825998049253],"hsluv":[270.972372145675877,89.4067229175139175,47.7414825998049253]},"#7755ff":{"lch":[49.0548071408334749,124.996939079083958,270.144864217432826],"luv":[49.0548071408334749,0.31603661949764611,-124.996539552082652],"rgb":[0.466666666666666674,0.333333333333333315,1],"xyz":[0.289040152110467741,0.17638604136349828,0.964926062686580432],"hpluv":[270.144864217432826,323.338286172745597,49.0548071408334749],"hsluv":[270.144864217432826,99.9999999999992184,49.0548071408334749]},"#eedd00":{"lch":[86.9434330779808562,96.0018853881048528,78.7633058197047831],"luv":[86.9434330779808562,18.7071720605167293,94.1615829920517],"rgb":[0.933333333333333348,0.866666666666666696,0],"xyz":[0.611144275644513346,0.69891115944639659,0.102712103982044597],"hpluv":[78.7633058197047831,323.365375109368927,86.9434330779808562],"hsluv":[78.7633058197047831,100.000000000002331,86.9434330779808562]},"#eedd11":{"lch":[86.9632971622836,95.1251800329902153,78.7103442402005555],"luv":[86.9632971622836,18.6225708681111755,93.2845095960255293],"rgb":[0.933333333333333348,0.866666666666666696,0.0666666666666666657],"xyz":[0.612155941144150506,0.699315825646251499,0.108040208946800234],"hpluv":[78.7103442402005555,320.953864246165836,86.9632971622836],"hsluv":[78.7103442402005555,99.0572185708442134,86.9632971622836]},"#eedd22":{"lch":[87.0000996195567,93.508678235103929,78.6100630695382421],"luv":[87.0000996195567,18.466577094457584,91.6671066178629559],"rgb":[0.933333333333333348,0.866666666666666696,0.133333333333333331],"xyz":[0.614031299282627452,0.700065968901642299,0.117917095142779427],"hpluv":[78.6100630695382421,316.490280961531141,87.0000996195567],"hsluv":[78.6100630695382421,97.3195837272491104,87.0000996195567]},"#eedd33":{"lch":[87.0606371109171704,90.8714304533391157,78.438725785200063],"luv":[87.0606371109171704,18.2120693177914781,89.0277339024194561],"rgb":[0.933333333333333348,0.866666666666666696,0.2],"xyz":[0.617119050015085269,0.701301069194625426,0.134179249000390577],"hpluv":[78.438725785200063,309.159510866930361,87.0606371109171704],"hsluv":[78.438725785200063,94.4866487647953335,87.0606371109171704]},"#eedd44":{"lch":[87.1479139339873399,87.1163282896156375,78.1766823729436737],"luv":[87.1479139339873399,17.8496481580416315,85.2680755927926839],"rgb":[0.933333333333333348,0.866666666666666696,0.266666666666666663],"xyz":[0.621577045259304128,0.703084267292313,0.157658023953277215],"hpluv":[78.1766823729436737,298.614243514229941,87.1479139339873399],"hsluv":[78.1766823729436737,90.4569971269957449,87.1479139339873399]},"#eedd55":{"lch":[87.2644132886328,82.1887294441124823,77.7961103956051119],"luv":[87.2644132886328,17.3739699699556027,80.3313912186301],"rgb":[0.933333333333333348,0.866666666666666696,0.333333333333333315],"xyz":[0.627539459298666058,0.705469232908057742,0.189060071227251103],"hpluv":[77.7961103956051119,284.577035202400168,87.2644132886328],"hsluv":[77.7961103956051119,85.1762064326895114,87.2644132886328]},"#eedd66":{"lch":[87.4122373516825775,76.0722975624531,77.2543738936701],"luv":[87.4122373516825775,16.7832968217641607,74.1978126646801428],"rgb":[0.933333333333333348,0.866666666666666696,0.4],"xyz":[0.635124455072174299,0.70850323121746106,0.229007715634395093],"hpluv":[77.2543738936701,266.820521177772889,87.4122373516825775],"hsluv":[77.2543738936701,78.6319742502837187,87.4122373516825775]},"#eedd77":{"lch":[87.5931821049200323,68.7867162946957,76.4818073814204666],"luv":[87.5931821049200323,16.0791769624109904,66.8810317415814524],"rgb":[0.933333333333333348,0.866666666666666696,0.466666666666666674],"xyz":[0.644438468092376149,0.712228836425541911,0.278061517540793],"hpluv":[76.4818073814204666,245.153905791490757,87.5931821049200323],"hsluv":[76.4818073814204666,70.850552214552053,87.5931821049200323]},"#eedd88":{"lch":[87.8087818591101694,60.3863988515096,75.3563176494847],"luv":[87.8087818591101694,15.266108392374667,58.4248500280990655],"rgb":[0.933333333333333348,0.866666666666666696,0.533333333333333326],"xyz":[0.65557888519432006,0.716685003266319454,0.336734380944365141],"hpluv":[75.3563176494847,219.413652035392374,87.8087818591101694],"hsluv":[75.3563176494847,61.8928475378351,87.8087818591101694]},"#eedd99":{"lch":[88.0603378936253165,50.9615259485641658,73.6438422487017164],"luv":[88.0603378936253165,14.3511385044238935,48.8990996914362483],"rgb":[0.933333333333333348,0.866666666666666696,0.6],"xyz":[0.668635849303392704,0.721907788909948667,0.405501058585483076],"hpluv":[73.6438422487017164,189.463858183723431,88.0603378936253165],"hsluv":[73.6438422487017164,51.8496821371243328,88.0603378936253165]},"#eeddaa":{"lch":[88.3489381850503719,40.6474355343677374,70.8361013393810595],"luv":[88.3489381850503719,13.3433963411670824,38.3948927541556],"rgb":[0.933333333333333348,0.866666666666666696,0.66666666666666663],"xyz":[0.683693542268645316,0.727930866096049733,0.484804908202481677],"hpluv":[70.8361013393810595,155.230940371192503,88.3489381850503719],"hsluv":[70.8361013393810595,42.897511243529749,88.3489381850503719]},"#eeddbb":{"lch":[88.6754719765582422,29.6681200622416164,65.6052069824857256],"luv":[88.6754719765582422,12.2535763784239329,27.0193858917206811],"rgb":[0.933333333333333348,0.866666666666666696,0.733333333333333282],"xyz":[0.700831134375981879,0.734785902938984492,0.575062893301123368],"hpluv":[65.6052069824857256,116.881954111652547,88.6754719765582422],"hsluv":[65.6052069824857256,42.5880034653653823,88.6754719765582422]},"#eeddcc":{"lch":[89.0406413623298,18.5684245799280596,53.3136761054906927],"luv":[89.0406413623298,11.093403559257359,14.8903589228712931],"rgb":[0.933333333333333348,0.866666666666666696,0.8],"xyz":[0.720123509819703633,0.742502853116473349,0.676669403971393524],"hpluv":[53.3136761054906927,75.8171941810365837,89.0406413623298],"hsluv":[53.3136761054906927,42.1389745374101,89.0406413623298]},"#eedddd":{"lch":[89.4449712115231677,10.1024117660870978,12.1770506300652031],"luv":[89.4449712115231677,9.87511215198720294,2.13093488339032255],"rgb":[0.933333333333333348,0.866666666666666696,0.866666666666666696],"xyz":[0.741641835370337232,0.751110183336726855,0.789999251871399522],"hpluv":[12.1770506300652031,42.9711785560074802,89.4449712115231677],"hsluv":[12.1770506300652031,41.5103310668104939,89.4449712115231677]},"#eeddee":{"lch":[89.8888182614484919,14.0763196099440542,307.715012949260654],"luv":[89.8888182614484919,8.61096808409750203,-11.1352594229299271],"rgb":[0.933333333333333348,0.866666666666666696,0.933333333333333348],"xyz":[0.765454015636511942,0.760635055443196872,0.915410067939922745],"hpluv":[307.715012949260654,62.7286135322124423,89.8888182614484919],"hsluv":[307.715012949260654,40.6526002298302203,89.8888182614484919]},"#eeddff":{"lch":[90.3723799019863776,25.8444533047225526,286.436741223308786],"luv":[90.3723799019863776,7.31285770395748802,-24.7882609075678033],"rgb":[0.933333333333333348,0.866666666666666696,1],"xyz":[0.791625064046343363,0.771103474807129596,1.05324425623170459],"hpluv":[286.436741223308786,121.429851146909542,90.3723799019863776],"hsluv":[286.436741223308786,99.9999999999912461,90.3723799019863776]},"#776600":{"lch":[43.3967364031710616,48.7618731822316747,71.5665709091534836],"luv":[43.3967364031710616,15.4186312136361749,46.2599836547520695],"rgb":[0.466666666666666674,0.4,0],"xyz":[0.123587421414484214,0.134249841414458615,0.0194032630055357667],"hpluv":[71.5665709091534836,142.581321953300886,43.3967364031710616],"hsluv":[71.5665709091534836,100.000000000002203,43.3967364031710616]},"#776611":{"lch":[43.4563559440565683,46.5521225716425278,71.0105555334865812],"luv":[43.4563559440565683,15.1477793781447385,44.0186880294754204],"rgb":[0.466666666666666674,0.4,0.0666666666666666657],"xyz":[0.124599086914121332,0.134654507614313468,0.0247313679702914],"hpluv":[71.0105555334865812,135.933189968578517,43.4563559440565683],"hsluv":[71.0105555334865812,95.1446041192036,43.4563559440565683]},"#776622":{"lch":[43.5665595032511135,42.5748985848782695,69.8598868578742582],"luv":[43.5665595032511135,14.6592646006394602,39.9715892964128727],"rgb":[0.466666666666666674,0.4,0.133333333333333331],"xyz":[0.126474445052598361,0.135404650869704296,0.0346082541662705925],"hpluv":[69.8598868578742582,124.005139157578384,43.5665595032511135],"hsluv":[69.8598868578742582,86.4059851293991699,43.5665595032511135]},"#776633":{"lch":[43.7471247164395862,36.3538810550032,67.535659471968259],"luv":[43.7471247164395862,13.8911218179866047,33.5952586297408544],"rgb":[0.466666666666666674,0.4,0.2],"xyz":[0.129562195785056095,0.136639751162687395,0.0508704080238817358],"hpluv":[67.535659471968259,105.448545621014873,43.7471247164395862],"hsluv":[67.535659471968259,72.7162107178341,43.7471247164395862]},"#776644":{"lch":[44.0059094002531381,28.0798421405657628,62.7556004259007807],"luv":[44.0059094002531381,12.8545871201011757,24.9647175952547435],"rgb":[0.466666666666666674,0.4,0.266666666666666663],"xyz":[0.134020191029274982,0.138422949260375,0.0743491829767683743],"hpluv":[62.7556004259007807,80.969785387169,44.0059094002531381],"hsluv":[62.7556004259007807,54.3487361937933,44.0059094002531381]},"#776655":{"lch":[44.348573895236818,18.4503377813959695,51.0995937541716287],"luv":[44.348573895236818,11.5862323365157813,14.3587668165439446],"rgb":[0.466666666666666674,0.4,0.333333333333333315],"xyz":[0.139982605068636967,0.140807914876119822,0.10575123025074229],"hpluv":[51.0995937541716287,52.7914984191523473,44.348573895236818],"hsluv":[51.0995937541716287,32.0544530960382303,44.348573895236818]},"#776666":{"lch":[44.7789425039584543,10.3722772339139464,12.177050630063178],"luv":[44.7789425039584543,10.1389057710203723,2.18785849257654696],"rgb":[0.466666666666666674,0.4,0.4],"xyz":[0.147567600842145152,0.143841913185523113,0.145698874657886251],"hpluv":[12.177050630063178,29.3927086392471182,44.7789425039584543],"hsluv":[12.177050630063178,6.88762268030489189,44.7789425039584543]},"#776677":{"lch":[45.2992151274866899,14.0123007519981453,307.715012949251729],"luv":[45.2992151274866899,8.57180555029232849,-11.0846164558105222],"rgb":[0.466666666666666674,0.4,0.466666666666666674],"xyz":[0.156881613862347058,0.147567518393603936,0.194752676564284161],"hpluv":[307.715012949251729,39.2516664249610088,45.2992151274866899],"hsluv":[307.715012949251729,13.5798811229143528,45.2992151274866899]},"#776688":{"lch":[45.9101336093725934,25.9566305949561666,285.511882327844],"luv":[45.9101336093725934,6.94179491604529719,-25.0111606125461954],"rgb":[0.466666666666666674,0.4,0.533333333333333326],"xyz":[0.168022030964290886,0.152023685234381534,0.253425539967856328],"hpluv":[285.511882327844,71.7429261821633304,45.9101336093725934],"hsluv":[285.511882327844,20.4210179876919788,45.9101336093725934]},"#776699":{"lch":[46.6111419677041781,39.5636276789354753,277.694853057332239],"luv":[46.6111419677041781,5.29745753469698322,-39.2073663842078446],"rgb":[0.466666666666666674,0.4,0.6],"xyz":[0.181078995073363613,0.157246470878010691,0.322192217608974207],"hpluv":[277.694853057332239,107.707436484347127,46.6111419677041781],"hsluv":[277.694853057332239,30.3115853005661187,46.6111419677041781]},"#7766aa":{"lch":[47.4005539940279945,53.5010996637438936,273.94010537559177],"luv":[47.4005539940279945,3.67625443841083355,-53.3746458398921959],"rgb":[0.466666666666666674,0.4,0.66666666666666663],"xyz":[0.196136688038616142,0.163269548064111786,0.401496067225972808],"hpluv":[273.94010537559177,143.224929654224553,47.4005539940279945],"hsluv":[273.94010537559177,41.7476492103462178,47.4005539940279945]},"#7766bb":{"lch":[48.2757296522395052,67.3356727079262356,271.790784098674919],"luv":[48.2757296522395052,2.10423911354751,-67.3027859511178],"rgb":[0.466666666666666674,0.4,0.733333333333333282],"xyz":[0.213274280145952788,0.170124584907046544,0.491754052324614555],"hpluv":[271.790784098674919,176.992833999799871,48.2757296522395052],"hsluv":[271.790784098674919,53.26174830093764,48.2757296522395052]},"#7766cc":{"lch":[49.2332558923506838,80.8618894300095263,270.423298283194697],"luv":[49.2332558923506838,0.597398061184884921,-80.8596826468393886],"rgb":[0.466666666666666674,0.4,0.8],"xyz":[0.232566655589674542,0.177841535084535346,0.59336056299488471],"hpluv":[270.423298283194697,208.412927467485218,49.2332558923506838],"hsluv":[270.423298283194697,64.812294986267446,49.2332558923506838]},"#7766dd":{"lch":[50.2691251722936698,93.9789905273776327,269.490145829531343],"luv":[50.2691251722936698,-0.836273601566472236,-93.9752696564806769],"rgb":[0.466666666666666674,0.4,0.866666666666666696],"xyz":[0.254084981140308086,0.18644886530478888,0.706690410894890708],"hpluv":[269.490145829531343,237.229544488008315,50.2691251722936698],"hsluv":[269.490145829531343,76.411365903071939,50.2691251722936698]},"#7766ee":{"lch":[51.378904811117593,106.647241299318011,268.82087794331261],"luv":[51.378904811117593,-2.19459861633770803,-106.624658562961542],"rgb":[0.466666666666666674,0.4,0.933333333333333348],"xyz":[0.277897161406482796,0.195973737411258925,0.832101226963413931],"hpluv":[268.82087794331261,263.392927722023558,51.378904811117593],"hsluv":[268.82087794331261,88.1124589032604177,51.378904811117593]},"#7766ff":{"lch":[52.5578914047646748,118.864223743766644,268.322642340607558],"luv":[52.5578914047646748,-3.47930230784918848,-118.81329109850806],"rgb":[0.466666666666666674,0.4,1],"xyz":[0.304068209816314217,0.206442156775191621,0.969935415255195776],"hpluv":[268.322642340607558,286.980608281330717,52.5578914047646748],"hsluv":[268.322642340607558,99.9999999999990621,52.5578914047646748]},"#eeee00":{"lch":[91.3819857871042416,100.73955854358779,85.8743202181747591],"luv":[91.3819857871042416,7.24765584469138,100.478505862268193],"rgb":[0.933333333333333348,0.933333333333333348,0],"xyz":[0.658323051985028163,0.793268712127427555,0.118438362762215782],"hpluv":[85.8743202181747591,533.074105620447313,91.3819857871042416],"hsluv":[85.8743202181747591,100.000000000002302,91.3819857871042416]},"#eeee11":{"lch":[91.4002420948697,99.9206079899190485,85.8743202181747449],"luv":[91.4002420948697,7.18873686735402107,99.6616775060856526],"rgb":[0.933333333333333348,0.933333333333333348,0.0666666666666666657],"xyz":[0.659334717484665322,0.793673378327282464,0.123766467726971419],"hpluv":[85.8743202181747449,529.940172906192515,91.4002420948697],"hsluv":[85.8743202181747449,99.1672499526241182,91.4002420948697]},"#eeee22":{"lch":[91.4340680155716,98.4094794247264559,85.8743202181747],"luv":[91.4340680155716,7.08001949817026599,98.1544648222952105],"rgb":[0.933333333333333348,0.933333333333333348,0.133333333333333331],"xyz":[0.661210075623142268,0.794423521582673264,0.133643353922950597],"hpluv":[85.8743202181747,524.128135432551403,91.4340680155716],"hsluv":[85.8743202181747,97.631382664670781,91.4340680155716]},"#eeee33":{"lch":[91.4897155548310224,95.9410009888260475,85.874320218174617],"luv":[91.4897155548310224,6.90242608380469225,95.6923831080380864],"rgb":[0.933333333333333348,0.933333333333333348,0.2],"xyz":[0.664297826355600085,0.795658621875656391,0.149905507780561748],"hpluv":[85.874320218174617,514.550466890897383,91.4897155548310224],"hsluv":[85.874320218174617,95.1245282264191,91.4897155548310224]},"#eeee44":{"lch":[91.569956182858661,92.4193611961338917,85.8743202181745],"luv":[91.569956182858661,6.64906351605686385,92.1798691594911],"rgb":[0.933333333333333348,0.933333333333333348,0.266666666666666663],"xyz":[0.668755821599819,0.797441819973344,0.173384282733448386],"hpluv":[85.8743202181745,500.701064757674544,91.569956182858661],"hsluv":[85.8743202181745,91.5525623856835438,91.569956182858661]},"#eeee55":{"lch":[91.6770884747666912,87.7855710128071536,85.8743202181743612],"luv":[91.6770884747666912,6.31568785915728625,87.5580868047623682],"rgb":[0.933333333333333348,0.933333333333333348,0.333333333333333315],"xyz":[0.674718235639180874,0.799826785589088707,0.204786330007422301],"hpluv":[85.8743202181743612,482.129233036801622,91.6770884747666912],"hsluv":[85.8743202181743612,86.8606098102410584,91.6770884747666912]},"#eeee66":{"lch":[91.8130678710263197,82.0131153940214261,85.8743202181741481],"luv":[91.8130678710263197,5.90039150181238092,81.8005897091115912],"rgb":[0.933333333333333348,0.933333333333333348,0.4],"xyz":[0.682303231412689115,0.802860783898492,0.244733974414566263],"hpluv":[85.8743202181741481,458.402522986492727,91.8130678710263197],"hsluv":[85.8743202181741481,81.0287908474737435,91.8130678710263197]},"#eeee77":{"lch":[91.9795762822891163,75.1051560234190703,85.8743202181738923],"luv":[91.9795762822891163,5.40340190972927914,74.9105313631138],"rgb":[0.933333333333333348,0.933333333333333348,0.466666666666666674],"xyz":[0.691617244432891,0.806586389106572876,0.2937877763209642],"hpluv":[85.8743202181738923,429.072804464814112,91.9795762822891163],"hsluv":[85.8743202181738923,74.0694118243717838,91.9795762822891163]},"#eeee88":{"lch":[92.1780636375363542,67.0918310376028444,85.8743202181734233],"luv":[92.1780636375363542,4.82688735568056,66.9179718045445497],"rgb":[0.933333333333333348,0.933333333333333348,0.533333333333333326],"xyz":[0.702757661534834877,0.811042555947350419,0.35246063972453634],"hpluv":[85.8743202181734233,393.637417052406249,92.1780636375363542],"hsluv":[85.8743202181734233,66.0241185279663085,92.1780636375363542]},"#eeee99":{"lch":[92.4097746137617264,58.0271343519240759,85.8743202181728549],"luv":[92.4097746137617264,4.17473240419888647,57.8767650309654],"rgb":[0.933333333333333348,0.933333333333333348,0.6],"xyz":[0.715814625643907521,0.816265341590979632,0.421227317365654219],"hpluv":[85.8743202181728549,351.489405737917593,92.4097746137617264],"hsluv":[85.8743202181728549,56.9604957584853295,92.4097746137617264]},"#eeeeaa":{"lch":[92.6757669457712,47.9852530272659195,85.8743202181718885],"luv":[92.6757669457712,3.45227440531043239,47.8609058577161903],"rgb":[0.933333333333333348,0.933333333333333348,0.66666666666666663],"xyz":[0.730872318609160132,0.822288418777080699,0.500531166982652875],"hpluv":[85.8743202181718885,301.850049763156903,92.6757669457712],"hsluv":[85.8743202181718885,46.9680087594427178,92.6757669457712]},"#eeeebb":{"lch":[92.9769247593952741,37.0564456712956627,85.8743202181703253],"luv":[92.9769247593952741,2.66600696822725,36.9604189997225347],"rgb":[0.933333333333333348,0.933333333333333348,0.733333333333333282],"xyz":[0.748009910716496695,0.829143455620015457,0.590789152081294566],"hpluv":[85.8743202181703253,243.673832720465015,92.9769247593952741],"hsluv":[85.8743202181703253,36.1533987495139,92.9769247593952741]},"#eeeecc":{"lch":[93.3139689281547788,25.3426537884513579,85.8743202181670711],"luv":[93.3139689281547788,1.82326422217474082,25.2769817940640493],"rgb":[0.933333333333333348,0.933333333333333348,0.8],"xyz":[0.76730228616021845,0.836860405797504314,0.692395662751564722],"hpluv":[85.8743202181670711,175.509740066336235,93.3139689281547788],"hsluv":[85.8743202181670711,24.635760697738192,93.3139689281547788]},"#eeeedd":{"lch":[93.6874656794852143,12.9530841337210045,85.8743202181571377],"luv":[93.6874656794852143,0.931902991100789779,12.919518001474831],"rgb":[0.933333333333333348,0.933333333333333348,0.866666666666666696],"xyz":[0.788820611710852,0.84546773601775782,0.80572551065157072],"hpluv":[85.8743202181571377,95.2907564198152812,93.6874656794852143],"hsluv":[85.8743202181571377,12.5415797244653469,93.6874656794852143]},"#eeeeee":{"lch":[94.0978342288501466,4.90671076366048496e-12,0],"luv":[94.0978342288501466,4.6515081442594671e-12,1.56182025281704723e-12],"rgb":[0.933333333333333348,0.933333333333333348,0.933333333333333348],"xyz":[0.812632791977026758,0.854992608124227838,0.931136326720093943],"hpluv":[0,3.87295813278393312e-11,94.0978342288501466],"hsluv":[0,3.8714510065860851e-11,94.0978342288501466]},"#eeeeff":{"lch":[94.5453539438838391,13.4050739145486393,265.874320218197],"luv":[94.5453539438838391,-0.964421163933715353,-13.3703365130825738],"rgb":[0.933333333333333348,0.933333333333333348,1],"xyz":[0.838803840386858179,0.865461027488160561,1.06897051501187579],"hpluv":[265.874320218197,114.885858328026472,94.5453539438838391],"hsluv":[265.874320218197,99.999999999981938,94.5453539438838391]},"#777700":{"lch":[48.4055282063088868,53.3622847060179737,85.8743202181747],"luv":[48.4055282063088868,3.83912219020021839,53.2240036999738706],"rgb":[0.466666666666666674,0.466666666666666674,0],"xyz":[0.142041159467901856,0.171157317521294372,0.0255545090233414707],"hpluv":[85.8743202181747,139.887458074797621,48.4055282063088868],"hsluv":[85.8743202181747,100.000000000002331,48.4055282063088868]},"#777711":{"lch":[48.4562461221814829,51.3697569370731628,85.874320218174617],"luv":[48.4562461221814829,3.69577080233359201,51.2366392921178502],"rgb":[0.466666666666666674,0.466666666666666674,0.0666666666666666657],"xyz":[0.143052824967539,0.171561983721149225,0.0308826139880971],"hpluv":[85.874320218174617,134.523163178361983,48.4562461221814829],"hsluv":[85.874320218174617,96.1652781669932324,48.4562461221814829]},"#777722":{"lch":[48.5500530694338579,47.7524066126053768,85.8743202181744323],"luv":[48.5500530694338579,3.43552238949120969,47.6286628324468282],"rgb":[0.466666666666666674,0.466666666666666674,0.133333333333333331],"xyz":[0.144928183106016,0.172312126976540053,0.0407595001840763],"hpluv":[85.8743202181744323,124.808706278838557,48.5500530694338579],"hsluv":[85.8743202181744323,89.2207979160694293,48.5500530694338579]},"#777733":{"lch":[48.7039135074563063,42.0024110114446501,85.874320218174],"luv":[48.7039135074563063,3.02184190658892726,41.8935675523809934],"rgb":[0.466666666666666674,0.466666666666666674,0.2],"xyz":[0.148015933838473723,0.173547227269523152,0.0570216540416874432],"hpluv":[85.874320218174,109.433348296247431,48.7039135074563063],"hsluv":[85.874320218174,78.2295638238963704,48.7039135074563063]},"#777744":{"lch":[48.9247697387985312,34.1210359912247227,85.8743202181732528],"luv":[48.9247697387985312,2.45482042510454956,34.0326160292585],"rgb":[0.466666666666666674,0.466666666666666674,0.266666666666666663],"xyz":[0.152473929082692611,0.175330425367210746,0.0805004289945740747],"hpluv":[85.8743202181732528,88.497855114462908,48.9247697387985312],"hsluv":[85.8743202181732528,63.2636094274766378,48.9247697387985312]},"#777755":{"lch":[49.2178287935421537,24.2815247917763841,85.8743202181716327],"luv":[49.2178287935421537,1.74692184102758041,24.2186025669317253],"rgb":[0.466666666666666674,0.466666666666666674,0.333333333333333315],"xyz":[0.158436343122054624,0.177715390982955579,0.11190247626854799],"hpluv":[85.8743202181716327,62.6026663147617,49.2178287935421537],"hsluv":[85.8743202181716327,44.7521651878825324,49.2178287935421537]},"#777766":{"lch":[49.5868745078829676,12.7836483150604128,85.8743202181664742],"luv":[49.5868745078829676,0.919713018071489197,12.750521252385596],"rgb":[0.466666666666666674,0.466666666666666674,0.4],"xyz":[0.166021338895562781,0.18074938929235887,0.151850120675691952],"hpluv":[85.8743202181664742,32.7135296885410085,49.5868745078829676],"hsluv":[85.8743202181664742,23.385605928338574,49.5868745078829676]},"#777777":{"lch":[50.0344387925380687,2.67192546523751356e-12,0],"luv":[50.0344387925380687,2.52749706171116152e-12,8.66570421158112546e-13],"rgb":[0.466666666666666674,0.466666666666666674,0.466666666666666674],"xyz":[0.175335351915764714,0.184474994500439693,0.200903922582089861],"hpluv":[0,6.77633132918180515e-12,50.0344387925380687],"hsluv":[0,1.94020402484744743e-12,50.0344387925380687]},"#777788":{"lch":[50.5619220099523545,13.6772258441596737,265.874320218187563],"luv":[50.5619220099523545,-0.984000994856362388,-13.6417831984777926],"rgb":[0.466666666666666674,0.466666666666666674,0.533333333333333326],"xyz":[0.186475769017708515,0.188931161341217291,0.259576785985662029],"hpluv":[265.874320218187563,34.3252548472133,50.5619220099523545],"hsluv":[265.874320218187563,11.1797639211738336,50.5619220099523545]},"#777799":{"lch":[51.1696982290560669,27.8798810968622455,265.87432021818239],"luv":[51.1696982290560669,-2.00580373888746255,-27.8076342276045096],"rgb":[0.466666666666666674,0.466666666666666674,0.6],"xyz":[0.199532733126781242,0.194153946984846448,0.328343463626779908],"hpluv":[265.87432021818239,69.1380916549642563,51.1696982290560669],"hsluv":[265.87432021818239,22.9846011782403536,51.1696982290560669]},"#7777aa":{"lch":[51.8572203345112,42.2927406525888614,265.874320218180628],"luv":[51.8572203345112,-3.04272952363285398,-42.1831448442758443],"rgb":[0.466666666666666674,0.466666666666666674,0.66666666666666663],"xyz":[0.21459042609203377,0.200177024170947543,0.407647313243778564],"hpluv":[265.874320218180628,103.489412577951782,51.8572203345112],"hsluv":[265.874320218180628,35.2207148819814435,51.8572203345112]},"#7777bb":{"lch":[52.6231302285762439,56.6671214785474,265.874320218179832],"luv":[52.6231302285762439,-4.07688697591046,-56.5202764435038816],"rgb":[0.466666666666666674,0.466666666666666674,0.733333333333333282],"xyz":[0.231728018199370445,0.207032061013882301,0.497905298342420255],"hpluv":[265.874320218179832,136.645017565491173,52.6231302285762439],"hsluv":[265.874320218179832,47.751077300634,52.6231302285762439]},"#7777cc":{"lch":[53.4653742998309696,70.8221320427834513,265.874320218179378],"luv":[53.4653742998309696,-5.09526194727884452,-70.6386062488075],"rgb":[0.466666666666666674,0.466666666666666674,0.8],"xyz":[0.251020393643092143,0.214749011191371103,0.599511809012690411],"hpluv":[265.874320218179378,168.087613695837888,53.4653742998309696],"hsluv":[265.874320218179378,60.4968982098403671,53.4653742998309696]},"#7777dd":{"lch":[54.3813217092404102,84.6378263199215581,265.874320218179037],"luv":[54.3813217092404102,-6.08922498249284594,-84.4184990584042083],"rgb":[0.466666666666666674,0.466666666666666674,0.866666666666666696],"xyz":[0.272538719193725743,0.223356341411624637,0.712841656912696409],"hpluv":[265.874320218179037,197.494074150637061,54.3813217092404102],"hsluv":[265.874320218179037,73.4330970128385445,54.3813217092404102]},"#7777ee":{"lch":[55.3678819060931,98.0443353361264656,265.874320218178809],"luv":[55.3678819060931,-7.05374939408338086,-97.7902669542745713],"rgb":[0.466666666666666674,0.466666666666666674,0.933333333333333348],"xyz":[0.296350899459900452,0.232881213518094682,0.838252472981219632],"hpluv":[265.874320218178809,224.700440227144242,55.3678819060931],"hsluv":[265.874320218178809,86.5809092876847,55.3678819060931]},"#7777ff":{"lch":[56.4216176153771158,111.010032393554411,265.874320218178696],"luv":[56.4216176153771158,-7.98655981550332,-110.722365194803288],"rgb":[0.466666666666666674,0.466666666666666674,1],"xyz":[0.322521947869731873,0.243349632882027378,0.976086661273001477],"hpluv":[265.874320218178696,249.664056525023511,56.4216176153771158],"hsluv":[265.874320218178696,99.99999999999892,56.4216176153771158]},"#eeff00":{"lch":[95.8710857598618702,106.837421111995667,91.929871543819857],"luv":[95.8710857598618702,-3.59788306357601462,106.776822332015158],"rgb":[0.933333333333333348,1,0],"xyz":[0.710175424414702,0.896973456986776663,0.135722486905439893],"hpluv":[91.929871543819857,1221.941869030823,95.8710857598618702],"hsluv":[91.929871543819857,100.000000000002217,95.8710857598618702]},"#eeff11":{"lch":[95.8879066370154192,106.077593073364397,91.9648080695471748],"luv":[95.8879066370154192,-3.63693915095535747,106.015227330089402],"rgb":[0.933333333333333348,1,0.0666666666666666657],"xyz":[0.71118708991433921,0.897378123186631571,0.14105059187019553],"hpluv":[91.9648080695471748,1218.36968740939687,95.8879066370154192],"hsluv":[91.9648080695471748,99.9999999999846096,95.8879066370154192]},"#eeff22":{"lch":[95.9190746883988083,104.674935415410417,92.0306447189025221],"luv":[95.9190746883988083,-3.7090534526558554,104.609201443781629],"rgb":[0.933333333333333348,1,0.133333333333333331],"xyz":[0.713062448052816156,0.898128266442022372,0.150927478066174708],"hpluv":[92.0306447189025221,1211.72771901411761,95.9190746883988083],"hsluv":[92.0306447189025221,99.9999999999843254,95.9190746883988083]},"#eeff33":{"lch":[95.9703546560603,102.38192729680722,92.1421884898051076],"luv":[95.9703546560603,-3.826988551916231,102.31037677397255],"rgb":[0.933333333333333348,1,0.2],"xyz":[0.716150198785274,0.899363366735005498,0.167189631923785859],"hpluv":[92.1421884898051076,1200.73225066318059,95.9703546560603],"hsluv":[92.1421884898051076,99.9999999999843,95.9703546560603]},"#eeff44":{"lch":[96.0443082677326316,99.1069805797193482,92.3105231291127666],"luv":[96.0443082677326316,-3.99552836231266495,99.0264073504377],"rgb":[0.933333333333333348,1,0.266666666666666663],"xyz":[0.720608194029492832,0.901146564832693064,0.190668406876672497],"hpluv":[92.3105231291127666,1184.71704479359755,96.0443082677326316],"hsluv":[92.3105231291127666,99.999999999984,96.0443082677326316]},"#eeff55":{"lch":[96.1430663154878,94.7914212488158086,92.5502587525383831],"luv":[96.1430663154878,-4.21781218752730513,94.6975374691506744],"rgb":[0.933333333333333348,1,0.333333333333333315],"xyz":[0.726570608068854762,0.903531530448437814,0.222070454150646412],"hpluv":[92.5502587525383831,1163.01160371768833,96.1430663154878],"hsluv":[92.5502587525383831,99.9999999999832312,96.1430663154878]},"#eeff66":{"lch":[96.2684490440968261,89.4056432425818315,92.8821944044194083],"luv":[96.2684490440968261,-4.49554545672610839,89.2925479234763912],"rgb":[0.933333333333333348,1,0.4],"xyz":[0.734155603842363,0.906565528757841133,0.262018098557790347],"hpluv":[92.8821944044194083,1134.86447310352946,96.2684490440968261],"hsluv":[92.8821944044194083,99.9999999999826912,96.2684490440968261]},"#eeff77":{"lch":[96.4220309754045104,82.947030730659,93.3376121292550494],"luv":[96.4220309754045104,-4.82912482473711879,82.8063370791148827],"rgb":[0.933333333333333348,1,0.466666666666666674],"xyz":[0.743469616862564853,0.910291133965922,0.311071900464188311],"hpluv":[93.3376121292550494,1099.34916045901696,96.4220309754045104],"hsluv":[93.3376121292550494,99.9999999999824354,96.4220309754045104]},"#eeff88":{"lch":[96.6051797330544559,75.4384320618763553,93.966065888554354],"luv":[96.6051797330544559,-5.21774760700183382,75.2577713054536446],"rgb":[0.933333333333333348,1,0.533333333333333326],"xyz":[0.754610033964508764,0.914747300806699526,0.369744763867760451],"hpluv":[93.966065888554354,1055.22684316018899,96.6051797330544559],"hsluv":[93.966065888554354,99.9999999999810711,96.6051797330544559]},"#eeff99":{"lch":[96.8190810543072,66.9270103141668926,94.8508818247366],"luv":[96.8190810543072,-5.65953211211599072,66.6872881879637589],"rgb":[0.933333333333333348,1,0.6],"xyz":[0.767666998073581408,0.919970086450328739,0.43851144150887833],"hpluv":[94.8508818247366,1000.72847038880911,96.8190810543072],"hsluv":[94.8508818247366,99.9999999999804,96.8190810543072]},"#eeffaa":{"lch":[97.0647558759300182,57.4841926777339438,96.1432585072641785],"luv":[97.0647558759300182,-6.15165762861061438,57.1540857352402938],"rgb":[0.933333333333333348,1,0.66666666666666663],"xyz":[0.782724691038834,0.925993163636429806,0.517815291125877],"hpluv":[96.1432585072641785,933.191048721381,97.0647558759300182],"hsluv":[96.1432585072641785,99.9999999999786127,97.0647558759300182]},"#eeffbb":{"lch":[97.3430726615411857,47.2094061136043166,98.1473956779809242],"luv":[97.3430726615411857,-6.69052372550339935,46.7329104366258861],"rgb":[0.933333333333333348,1,0.733333333333333282],"xyz":[0.799862283146170583,0.932848200479364564,0.608073276224518677],"hpluv":[98.1473956779809242,848.432918810296883,97.3430726615411857],"hsluv":[98.1473956779809242,99.9999999999760689,97.3430726615411857]},"#eeffcc":{"lch":[97.6547568121604,36.2474903433398126,101.573139749476653],"luv":[97.6547568121604,-7.27192346215819718,35.5105573787715443],"rgb":[0.933333333333333348,1,0.8],"xyz":[0.819154658589892337,0.940565150656853421,0.709679786894788833],"hpluv":[101.573139749476653,739.717147432346792,97.6547568121604],"hsluv":[101.573139749476653,99.999999999972971,97.6547568121604]},"#eeffdd":{"lch":[98.0003982932414743,24.8675243497069864,108.50155795297276],"luv":[98.0003982932414743,-7.89122250686935445,23.5822470225029335],"rgb":[0.933333333333333348,1,0.866666666666666696],"xyz":[0.840672984140525936,0.949172480877106928,0.823009634794794831],"hpluv":[108.50155795297276,596.728870831386416,98.0003982932414743],"hsluv":[108.50155795297276,99.9999999999688072,98.0003982932414743]},"#eeffee":{"lch":[98.3804582036479,13.96608756186059,127.715012949221688],"luv":[98.3804582036479,-8.54353535492541205,11.0480588984987129],"rgb":[0.933333333333333348,1,0.933333333333333348],"xyz":[0.864485164406700646,0.958697352983577,0.948420450863318],"hpluv":[127.715012949221688,414.943064796341446,98.3804582036479],"hsluv":[127.715012949221688,99.9999999999608491,98.3804582036479]},"#eeffff":{"lch":[98.7952747621608438,9.43620053547767768,192.177050630058204],"luv":[98.7952747621608438,-9.22389036737693679,-1.99040876112424892],"rgb":[0.933333333333333348,1,1],"xyz":[0.890656212816532067,0.969165772347509669,1.0862546391551],"hpluv":[192.177050630058204,378.040319927501173,98.7952747621608438],"hsluv":[192.177050630058204,99.999999999948713,98.7952747621608438]},"#778800":{"lch":[53.5249548615687303,60.5938372915660253,96.5029793655947259],"luv":[53.5249548615687303,-6.86254771619202231,60.2039745910497572],"rgb":[0.466666666666666674,0.533333333333333326,0],"xyz":[0.164113529192872309,0.215302056971235917,0.0329119655983314136],"hpluv":[96.5029793655947259,143.651932639250902,53.5249548615687303],"hsluv":[96.5029793655947259,100.000000000002373,53.5249548615687303]},"#778811":{"lch":[53.5684856288310272,58.8481082257442409,96.7583563096261088],"luv":[53.5684856288310272,-6.9253766303469888,58.4391906196240143],"rgb":[0.466666666666666674,0.533333333333333326,0.0666666666666666657],"xyz":[0.165125194692509442,0.21570672317109077,0.0382400705630870433],"hpluv":[96.7583563096261088,139.399900460742,53.5684856288310272],"hsluv":[96.7583563096261088,96.9357421545617,53.5684856288310272]},"#778822":{"lch":[53.6490362820541407,55.6690512282284615,97.2652817371477],"luv":[53.6490362820541407,-7.04010577997538,55.2220986133077147],"rgb":[0.466666666666666674,0.533333333333333326,0.133333333333333331],"xyz":[0.167000552830986443,0.216456866426481598,0.0481169567590662428],"hpluv":[97.2652817371477,131.671329649176641,53.6490362820541407],"hsluv":[97.2652817371477,91.3605066517003337,53.6490362820541407]},"#778833":{"lch":[53.7812573057213,50.5917713326567053,98.2096275165039856],"luv":[53.7812573057213,-7.22426441450666346,50.0733195448945381],"rgb":[0.466666666666666674,0.533333333333333326,0.2],"xyz":[0.170088303563444176,0.217691966719464697,0.064379110616677393],"hpluv":[98.2096275165039856,119.368094402160139,53.7812573057213],"hsluv":[98.2096275165039856,82.4672262716137539,53.7812573057213]},"#778844":{"lch":[53.9712743947247162,43.5928841845235198,99.8805739619221811],"luv":[53.9712743947247162,-7.48032491712259429,42.9462954241638357],"rgb":[0.466666666666666674,0.533333333333333326,0.266666666666666663],"xyz":[0.174546298807663064,0.219475164817152291,0.0878578855695640315],"hpluv":[99.8805739619221811,102.492540276722124,53.9712743947247162],"hsluv":[99.8805739619221811,70.2195807792145672,53.9712743947247162]},"#778855":{"lch":[54.2238135722873,34.8221097745323078,102.954066597198249],"luv":[54.2238135722873,-7.80606678579386326,33.9358903004666175],"rgb":[0.466666666666666674,0.533333333333333326,0.333333333333333315],"xyz":[0.180508712847025077,0.221860130432897124,0.119259932843537933],"hpluv":[102.954066597198249,81.4900057495692636,54.2238135722873],"hsluv":[102.954066597198249,54.8454134878709638,54.2238135722873]},"#778866":{"lch":[54.542475349788262,24.6519214642532667,109.417534351990682],"luv":[54.542475349788262,-8.19552569001744224,23.2497438812554442],"rgb":[0.466666666666666674,0.533333333333333326,0.4],"xyz":[0.188093708620533234,0.224894128742300414,0.159207577250681909],"hpluv":[109.417534351990682,57.3528835536874197,54.542475349788262],"hsluv":[109.417534351990682,36.7830408334215164,54.542475349788262]},"#778877":{"lch":[54.9298804020046703,14.1239929232838151,127.715012949231166],"luv":[54.9298804020046703,-8.6401314869560828,11.1729720300858784],"rgb":[0.466666666666666674,0.533333333333333326,0.466666666666666674],"xyz":[0.197407721640735168,0.228619733950381238,0.208261379157079818],"hpluv":[127.715012949231166,32.6278280107521041,54.9298804020046703],"hsluv":[127.715012949231166,16.6133799052879709,54.9298804020046703]},"#778888":{"lch":[55.3877640712208574,9.3400800844087577,192.177050630059369],"luv":[55.3877640712208574,-9.12993258220805437,-1.97013375878514596],"rgb":[0.466666666666666674,0.533333333333333326,0.533333333333333326],"xyz":[0.208548138742678968,0.233075900791158835,0.266934242560651958],"hpluv":[192.177050630059369,21.3981433643613,55.3877640712208574],"hsluv":[192.177050630059369,21.3143847536295468,55.3877640712208574]},"#778899":{"lch":[55.9170512374386703,18.5603965019494623,238.655736169794807],"luv":[55.9170512374386703,-9.65472976501325597,-15.851640655596027],"rgb":[0.466666666666666674,0.533333333333333326,0.6],"xyz":[0.221605102851751695,0.238298686434788,0.335700920201769892],"hpluv":[238.655736169794807,42.1194135101242679,55.9170512374386703],"hsluv":[238.655736169794807,26.1912729818073053,55.9170512374386703]},"#7788aa":{"lch":[56.5179258756863732,31.8473117719276075,251.310804784322386],"luv":[56.5179258756863732,-10.2049729927717898,-30.1680260095876527],"rgb":[0.466666666666666674,0.533333333333333326,0.66666666666666663],"xyz":[0.236662795817004223,0.244321763620889087,0.415004769818768493],"hpluv":[251.310804784322386,71.5032678590983721,56.5179258756863732],"hsluv":[251.310804784322386,31.1149405392867244,56.5179258756863732]},"#7788bb":{"lch":[57.1899017055338845,45.9393215269311881,256.438388794294667],"luv":[57.1899017055338845,-10.7723499078102041,-44.6584565319768387],"rgb":[0.466666666666666674,0.533333333333333326,0.733333333333333282],"xyz":[0.253800387924340898,0.251176800463823846,0.505262754917410239],"hpluv":[256.438388794294667,101.930593576715296,57.1899017055338845],"hsluv":[256.438388794294667,41.4357647235180622,57.1899017055338845]},"#7788cc":{"lch":[57.9318961804226547,60.1932243037694406,259.131204763586595],"luv":[57.9318961804226547,-11.3500713849249486,-59.1134513595764233],"rgb":[0.466666666666666674,0.533333333333333326,0.8],"xyz":[0.273092763368062652,0.258893750641312648,0.606869265587680395],"hpluv":[259.131204763586595,131.8466774878151,57.9318961804226547],"hsluv":[259.131204763586595,55.5026255722761661,57.9318961804226547]},"#7788dd":{"lch":[58.7423077351926679,74.3397271130694861,260.762999043897821],"luv":[58.7423077351926679,-11.9329115646152975,-73.3757497327060264],"rgb":[0.466666666666666674,0.533333333333333326,0.866666666666666696],"xyz":[0.29461108891869614,0.267501080861566209,0.720199113487686393],"hpluv":[260.762999043897821,160.586593274196787,58.7423077351926679],"hsluv":[260.762999043897821,69.9489143241080598,58.7423077351926679]},"#7788ee":{"lch":[59.6190949291064101,88.2283098571320465,261.84384456781811],"luv":[59.6190949291064101,-12.5170812067924775,-87.3358880318318285],"rgb":[0.466666666666666674,0.533333333333333326,0.933333333333333348],"xyz":[0.318423269184870905,0.277025952968036226,0.845609929556209616],"hpluv":[261.84384456781811,187.785436290663455,59.6190949291064101],"hsluv":[261.84384456781811,84.7689484415743237,59.6190949291064101]},"#7788ff":{"lch":[60.55985551741054,101.77153783075579,262.604380260147],"luv":[60.55985551741054,-13.1000102630052879,-100.924901008354297],"rgb":[0.466666666666666674,0.533333333333333326,1],"xyz":[0.344594317594702271,0.28749437233196895,0.983444117847991461],"hpluv":[262.604380260147,213.245970352856943,60.55985551741054],"hsluv":[262.604380260147,99.9999999999987921,60.55985551741054]},"#779900":{"lch":[58.6994568897504223,69.1976359459353603,103.993850276975294],"luv":[58.6994568897504223,-16.7332165977800322,67.1439668384135899],"rgb":[0.466666666666666674,0.6,0],"xyz":[0.189983129645339782,0.267041257876171612,0.0415351657491536685],"hpluv":[103.993850276975294,149.587912305351722,58.6994568897504223],"hsluv":[103.993850276975294,100.000000000002444,58.6994568897504223]},"#779911":{"lch":[58.7371702745588493,67.6759907780605232,104.326162498332039],"luv":[58.7371702745588493,-16.7458460058928829,65.5714600214076],"rgb":[0.466666666666666674,0.6,0.0666666666666666657],"xyz":[0.190994795144976914,0.267445924076026464,0.0468632707139093],"hpluv":[104.326162498332039,146.20456366036808,58.7371702745588493],"hsluv":[104.326162498332039,97.5197891999702,58.7371702745588493]},"#779922":{"lch":[58.8069803361006223,64.8997387816913,104.97431376012679],"luv":[58.8069803361006223,-16.7691829588827659,62.6958578920751464],"rgb":[0.466666666666666674,0.6,0.133333333333333331],"xyz":[0.192870153283453916,0.268196067331417265,0.0567401569098885],"hpluv":[104.97431376012679,140.04041716275114,58.8069803361006223],"hsluv":[104.97431376012679,92.9911396041894704,58.8069803361006223]},"#779933":{"lch":[58.9216385591388132,60.4528100001228097,106.14237332279157],"luv":[58.9216385591388132,-16.8074000849803582,58.0693855598141369],"rgb":[0.466666666666666674,0.6,0.2],"xyz":[0.195957904015911677,0.269431167624400392,0.0730023107674996341],"hpluv":[106.14237332279157,130.191012221085145,58.9216385591388132],"hsluv":[106.14237332279157,85.724115661044948,58.9216385591388132]},"#779944":{"lch":[59.0865618982540752,54.3006768161790845,108.091337704968765],"luv":[59.0865618982540752,-16.8621369683366211,51.6161974534756354],"rgb":[0.466666666666666674,0.6,0.266666666666666663],"xyz":[0.200415899260130537,0.271214365722087958,0.0964810857203862726],"hpluv":[108.091337704968765,116.615384645059635,59.0865618982540752],"hsluv":[108.091337704968765,75.6282332091309399,59.0865618982540752]},"#779955":{"lch":[59.3060149965037056,46.5647823410072945,111.326222899357617],"luv":[59.3060149965037056,-16.9345685221747893,43.3762532203180413],"rgb":[0.466666666666666674,0.6,0.333333333333333315],"xyz":[0.206378313299492522,0.273599331337832818,0.127883132994360188],"hpluv":[111.326222899357617,99.6318422422000367,59.3060149965037056],"hsluv":[111.326222899357617,62.8087826319283806,59.3060149965037056]},"#779966":{"lch":[59.5833535636433282,37.5662597340720836,116.949978591108717],"luv":[59.5833535636433282,-17.0254963867212936,33.4866591823296957],"rgb":[0.466666666666666674,0.6,0.4],"xyz":[0.213963309073000707,0.276633329647236137,0.16783077740150415],"hpluv":[116.949978591108717,80.0041177209304522,59.5833535636433282],"hsluv":[116.949978591108717,47.5357009492008,59.5833535636433282]},"#779977":{"lch":[59.921152065724,28.0111989307655129,127.71501294923614],"luv":[59.921152065724,-17.1354122862910181,22.1586306282167591],"rgb":[0.466666666666666674,0.6,0.466666666666666674],"xyz":[0.223277322093202613,0.280358934855316932,0.216884579307902059],"hpluv":[127.71501294923614,59.3185968765002301,59.921152065724],"hsluv":[127.71501294923614,30.2037385091367128,59.921152065724]},"#779988":{"lch":[60.3212826107906608,19.7788738743410271,150.794869664161695],"luv":[60.3212826107906608,-17.2645515875173317,9.65086059473676272],"rgb":[0.466666666666666674,0.6,0.533333333333333326],"xyz":[0.234417739195146468,0.28481510169609453,0.275557442711474199],"hpluv":[150.794869664161695,41.6073752981458043,60.3212826107906608],"hsluv":[150.794869664161695,33.5278156565034706,60.3212826107906608]},"#779999":{"lch":[60.7849725890424537,17.8137422376051369,192.177050630060307],"luv":[60.7849725890424537,-17.4129412378011317,-3.75751113860251662],"rgb":[0.466666666666666674,0.6,0.6],"xyz":[0.247474703304219168,0.290037887339723688,0.344324120352592133],"hpluv":[192.177050630060307,37.1876097830212373,60.7849725890424537],"hsluv":[192.177050630060307,37.0420465685486562,60.7849725890424537]},"#7799aa":{"lch":[61.3128540464897895,25.0117677757311512,225.340924984985747],"luv":[61.3128540464897895,-17.5804418295499474,-17.7909131959243076],"rgb":[0.466666666666666674,0.6,0.66666666666666663],"xyz":[0.262532396269471724,0.29606096452582481,0.423627969969590734],"hpluv":[225.340924984985747,51.7645188682129742,61.3128540464897895],"hsluv":[225.340924984985747,40.6599304384258815,61.3128540464897895]},"#7799bb":{"lch":[61.9050111975332129,36.7727368637825478,241.108601392342877],"luv":[61.9050111975332129,-17.766782778670386,-32.1958942436537],"rgb":[0.466666666666666674,0.6,0.733333333333333282],"xyz":[0.279669988376808343,0.302916001368759569,0.513885955068232425],"hpluv":[241.108601392342877,75.37710856774234,61.9050111975332129],"hsluv":[241.108601392342877,44.3026829048042927,61.9050111975332129]},"#7799cc":{"lch":[62.5610290710097274,50.0883036089361084,248.973595844380469],"luv":[62.5610290710097274,-17.971590279241223,-46.7531827927901],"rgb":[0.466666666666666674,0.6,0.8],"xyz":[0.298962363820530097,0.31063295154624837,0.615492465738502581],"hpluv":[248.973595844380469,101.594866952252644,62.5610290710097274],"hsluv":[248.973595844380469,49.5852758814030068,62.5610290710097274]},"#7799dd":{"lch":[63.2800443412030518,63.9273589508424962,253.464421950176984],"luv":[63.2800443412030518,-18.1944086519195096,-61.2835272829234228],"rgb":[0.466666666666666674,0.6,0.866666666666666696],"xyz":[0.320480689371163641,0.319240281766501877,0.728822313638508579],"hpluv":[253.464421950176984,128.191525099113591,63.2800443412030518],"hsluv":[253.464421950176984,65.7895471985927429,63.2800443412030518]},"#7799ee":{"lch":[64.0607982423263138,77.8622331281598292,256.304567564122067],"luv":[64.0607982423263138,-18.434716379612933,-75.6484539148497106],"rgb":[0.466666666666666674,0.6,0.933333333333333348],"xyz":[0.344292869637338406,0.328765153872971894,0.854233129707031802],"hpluv":[256.304567564122067,154.231767587931557,64.0607982423263138],"hsluv":[256.304567564122067,82.5871459557978085,64.0607982423263138]},"#7799ff":{"lch":[64.9016907971027,91.67329289213788,258.23504341307023],"luv":[64.9016907971027,-18.6919383586334327,-89.7474460365571929],"rgb":[0.466666666666666674,0.6,1],"xyz":[0.370463918047169771,0.339233573236904618,0.992067317998813758],"hpluv":[258.23504341307023,179.236372955016122,64.9016907971027],"hsluv":[258.23504341307023,99.9999999999984368,64.9016907971027]},"#660000":{"lch":[19.330201679573328,65.0080772249371819,12.1770506300617765],"luv":[19.330201679573328,63.5454254137925432,13.7123671721378795],"rgb":[0.4,0,0],"xyz":[0.0547936733227042463,0.0282529878070199789,0.00256845343700170745],"hpluv":[12.1770506300617765,426.746789183125202,19.330201679573328],"hsluv":[12.1770506300617765,100.000000000002217,19.330201679573328]},"#660011":{"lch":[19.4980803058243595,61.695772445130423,8.9911342856641614],"luv":[19.4980803058243595,60.9376877881905799,9.641916024853316],"rgb":[0.4,0,0.0666666666666666657],"xyz":[0.0558053388223413716,0.0286576540068748317,0.0078965584017573389],"hpluv":[8.9911342856641614,401.51602003210553,19.4980803058243595],"hsluv":[8.9911342856641614,99.9999999999966178,19.4980803058243595]},"#660022":{"lch":[19.8051492014688648,56.728751528179842,2.87530221933591967],"luv":[19.8051492014688648,56.6573341637173584,2.84565201787440492],"rgb":[0.4,0,0.133333333333333331],"xyz":[0.0576806969608183867,0.029407797262265653,0.0177734445977365332],"hpluv":[2.87530221933591967,363.466537566247382,19.8051492014688648],"hsluv":[2.87530221933591967,99.9999999999968594,19.8051492014688648]},"#660033":{"lch":[20.2995520444984123,51.2727836305606957,352.516911450402631],"luv":[20.2995520444984123,50.836110988726972,-6.67743669143524787],"rgb":[0.4,0,0.2],"xyz":[0.0607684476932761272,0.0306428975552487659,0.0340355984553476765],"hpluv":[352.516911450402631,320.508659944055125,20.2995520444984123],"hsluv":[352.516911450402631,99.9999999999973852,20.2995520444984123]},"#660044":{"lch":[20.9904438433464762,47.7800185043531087,338.095292373375855],"luv":[20.9904438433464762,44.3305689635839855,-17.8250055719836844],"rgb":[0.4,0,0.266666666666666663],"xyz":[0.0652264429374950078,0.0324260956529363389,0.057514373408234315],"hpluv":[338.095292373375855,288.844444062118953,20.9904438433464762],"hsluv":[338.095292373375855,99.999999999997911,20.9904438433464762]},"#660055":{"lch":[21.8759682447435324,48.0792454528985687,322.009867044845],"luv":[21.8759682447435324,37.8920594608334085,-29.5940141436867741],"rgb":[0.4,0,0.333333333333333315],"xyz":[0.071188856976857,0.0348110612686811718,0.0889164206822082304],"hpluv":[322.009867044845,278.887908627948889,21.8759682447435324],"hsluv":[322.009867044845,99.9999999999984,21.8759682447435324]},"#660066":{"lch":[22.9458380566939866,52.2668983658326383,307.715012949243601],"luv":[22.9458380566939866,31.9734565677830815,-41.3464235441515271],"rgb":[0.4,0,0.4],"xyz":[0.0787738527503651781,0.0378450595780844834,0.128864065089352192],"hpluv":[307.715012949243601,289.042783730483393,22.9458380566939866],"hsluv":[307.715012949243601,99.9999999999988,22.9458380566939866]},"#660077":{"lch":[24.1840444716539054,59.1802438936044553,296.875135467660698],"luv":[24.1840444716539054,26.7522904844618061,-52.7884099129864097],"rgb":[0.4,0,0.466666666666666674],"xyz":[0.0880878657705671,0.0415706647861653,0.177917866995750101],"hpluv":[296.875135467660698,310.518260327731298,24.1840444716539054],"hsluv":[296.875135467660698,99.9999999999992326,24.1840444716539054]},"#660088":{"lch":[25.5714349826340381,67.6035320092512819,289.201479741547303],"luv":[25.5714349826340381,22.2341957091879898,-63.8426039670327725],"rgb":[0.4,0,0.533333333333333326],"xyz":[0.0992282828725109256,0.0460268316269428907,0.236590730399322269],"hpluv":[289.201479741547303,335.469941782198191,25.5714349826340381],"hsluv":[289.201479741547303,99.9999999999995168,25.5714349826340381]},"#660099":{"lch":[27.0878540213863559,76.7583277742970296,283.827270614430063],"luv":[27.0878540213863559,18.3449067131383,-74.5339203342523291],"rgb":[0.4,0,0.6],"xyz":[0.112285246981583625,0.0512496172705720551,0.305357408040440148],"hpluv":[283.827270614430063,359.575614235331898,27.0878540213863559],"hsluv":[283.827270614430063,99.9999999999996732,27.0878540213863559]},"#6600aa":{"lch":[28.7136916664512327,86.2331190336617226,280.0081392435834],"luv":[28.7136916664512327,14.9862877024472088,-84.9209161465722246],"rgb":[0.4,0,0.66666666666666663],"xyz":[0.127342939946836181,0.0572726944566731566,0.384661257657438749],"hpluv":[280.0081392435834,381.087223541781498,28.7136916664512327],"hsluv":[280.0081392435834,99.9999999999998863,28.7136916664512327]},"#6600bb":{"lch":[30.4308478844127208,95.8259209373334784,277.232006261077231],"luv":[30.4308478844127208,12.063278317584528,-95.06358103774852],"rgb":[0.4,0,0.733333333333333282],"xyz":[0.144480532054172828,0.0641277312996079152,0.474919242756080495],"hpluv":[277.232006261077231,399.584170303460496,30.4308478844127208],"hsluv":[277.232006261077231,100.000000000000071,30.4308478844127208]},"#6600cc":{"lch":[32.2232190058254631,105.440117399912424,275.16595430901134],"luv":[32.2232190058254631,9.49391256045434,-105.011827817640437],"rgb":[0.4,0,0.8],"xyz":[0.163772907497894554,0.0718446814770967168,0.576525753426350707],"hpluv":[275.16595430901134,415.218107165999243,32.2232190058254631],"hsluv":[275.16595430901134,100.000000000000284,32.2232190058254631]},"#6600dd":{"lch":[34.0768449366564425,115.029794578821409,273.594219506454294],"luv":[34.0768449366564425,7.21119822634443164,-114.803537667557165],"rgb":[0.4,0,0.866666666666666696],"xyz":[0.185291233048528098,0.0804520116973502508,0.689855601326356704],"hpluv":[273.594219506454294,428.341637585051217,34.0768449366564425],"hsluv":[273.594219506454294,100.000000000000313,34.0768449366564425]},"#6600ee":{"lch":[35.9798440153965657,124.573148355199,272.374748889870204],"luv":[35.9798440153965657,5.16172842086039729,-124.466163477612255],"rgb":[0.4,0,0.933333333333333348],"xyz":[0.209103413314702835,0.0899768838038202817,0.815266417394879928],"hpluv":[272.374748889870204,439.343788723350144,35.9798440153965657],"hsluv":[272.374748889870204,100.000000000000313,35.9798440153965657]},"#6600ff":{"lch":[37.9222328155672699,134.059876636217865,271.411957283269032],"luv":[37.9222328155672699,3.30334385288953181,-134.01917192367489],"rgb":[0.4,0,1],"xyz":[0.235274461724534228,0.100445303167752992,0.953100605686661773],"hpluv":[271.411957283269032,448.58447779597617,37.9222328155672699],"hsluv":[271.411957283269032,100.00000000000054,37.9222328155672699]},"#661100":{"lch":[20.9278595225824304,60.6482483509225645,15.3961031612090817],"luv":[20.9278595225824304,58.4717927536604165,16.1015365791022269],"rgb":[0.4,0.0666666666666666657,0],"xyz":[0.0567980735836326536,0.0322617883288768559,0.00323658685731115833],"hpluv":[15.3961031612090817,367.733145903292666,20.9278595225824304],"hsluv":[15.3961031612090817,100.00000000000216,20.9278595225824304]},"#661111":{"lch":[21.0816163302651134,57.5811303886473453,12.1770506300618102],"luv":[21.0816163302651134,56.2855814623301782,12.1457768908291825],"rgb":[0.4,0.0666666666666666657,0.0666666666666666657],"xyz":[0.0578097390832697788,0.0326664545287317087,0.00856469182206678892],"hpluv":[12.1770506300618102,346.589664487627374,21.0816163302651134],"hsluv":[12.1770506300618102,81.2167011616125762,21.0816163302651134]},"#661122":{"lch":[21.363314856368774,52.932385078801687,5.93410154371749865],"luv":[21.363314856368774,52.6487447994206548,5.4723908098767966],"rgb":[0.4,0.0666666666666666657,0.133333333333333331],"xyz":[0.059685097221746794,0.0334165977841225301,0.018441578018045985],"hpluv":[5.93410154371749865,314.406957937895,21.363314856368774],"hsluv":[5.93410154371749865,82.5199513610387356,21.363314856368774]},"#661133":{"lch":[21.8180817632255923,47.7742586248590229,355.183549580278111],"luv":[21.8180817632255923,47.6055578330604661,-4.01131531521171425],"rgb":[0.4,0.0666666666666666657,0.2],"xyz":[0.0627728479542045414,0.0346516980771056429,0.0347037318756571317],"hpluv":[355.183549580278111,277.854041301729922,21.8180817632255923],"hsluv":[355.183549580278111,84.3121175303292603,21.8180817632255923]},"#661144":{"lch":[22.4559756968324393,44.5402485804784689,339.935360677682411],"luv":[22.4559756968324393,41.8369301419790247,-15.2808710453946635],"rgb":[0.4,0.0666666666666666657,0.266666666666666663],"xyz":[0.0672308431984234151,0.036434896174793216,0.0581825068285437702],"hpluv":[339.935360677682411,251.686564911624259,22.4559756968324393],"hsluv":[339.935360677682411,86.3348863624116518,22.4559756968324393]},"#661155":{"lch":[23.2773926977910151,45.1903944783221903,322.792583995755933],"luv":[23.2773926977910151,35.9919645110905364,-27.3267313035930464],"rgb":[0.4,0.0666666666666666657,0.333333333333333315],"xyz":[0.073193257237785414,0.0388198617905380489,0.0895845541025176717],"hpluv":[322.792583995755933,246.349182588766354,23.2773926977910151],"hsluv":[322.792583995755933,88.344826800164725,23.2773926977910151]},"#661166":{"lch":[24.275087751098269,49.8658315110702119,307.715012949243715],"luv":[24.275087751098269,30.5046415204515107,-39.4470277460696508],"rgb":[0.4,0.0666666666666666657,0.4],"xyz":[0.0807782530112935854,0.0418538600999413604,0.129532198509661634],"hpluv":[307.715012949243715,260.664316843383688,24.275087751098269],"hsluv":[307.715012949243715,90.1819147598703239,24.275087751098269]},"#661177":{"lch":[25.4363091503391701,57.3032374709331265,296.512546946797],"luv":[25.4363091503391701,25.5798087859014238,-51.2770358652572114],"rgb":[0.4,0.0666666666666666657,0.466666666666666674],"xyz":[0.0900922660314955,0.0455794653080221768,0.178586000416059543],"hpluv":[296.512546946797,285.867241464858182,25.4363091503391701],"hsluv":[296.512546946797,91.7740463972148461,25.4363091503391701]},"#661188":{"lch":[26.7449145171680129,66.1973281861227179,288.734792076243366],"luv":[26.7449145171680129,21.2617948521868456,-62.6898902427238127],"rgb":[0.4,0.0666666666666666657,0.533333333333333326],"xyz":[0.101232683133439333,0.0500356321487997746,0.23725886381963171],"hpluv":[288.734792076243366,314.078764213635395,26.7449145171680129],"hsluv":[288.734792076243366,93.110372692245349,26.7449145171680129]},"#661199":{"lch":[28.1832309630650286,75.7381406209258614,283.36677781159608],"luv":[28.1832309630650286,17.5094321789343716,-73.6864012521064637],"rgb":[0.4,0.0666666666666666657,0.6],"xyz":[0.114289647242512032,0.0552584177924289321,0.306025541460749617],"hpluv":[283.36677781159608,341.006914961476241,28.1832309630650286],"hsluv":[283.36677781159608,94.2123428080992,28.1832309630650286]},"#6611aa":{"lch":[29.733500038717203,85.5146667147819102,279.591039159426828],"luv":[29.733500038717203,14.2479867443400359,-84.3193518539685],"rgb":[0.4,0.0666666666666666657,0.66666666666666663],"xyz":[0.129347340207764588,0.0612814949785300336,0.385329391077748218],"hpluv":[279.591039159426828,364.950446526832081,29.733500038717203],"hsluv":[279.591039159426828,95.1136535912152254,29.733500038717203]},"#6611bb":{"lch":[31.378866229854367,95.3367425151459287,276.866082014695],"luv":[31.378866229854367,11.3974241300945351,-94.6530147253534153],"rgb":[0.4,0.0666666666666666657,0.733333333333333282],"xyz":[0.146484932315101235,0.0681365318214647853,0.475587376176389964],"hpluv":[276.866082014695,385.533736621086632,31.378866229854367],"hsluv":[276.866082014695,95.8493220980777636,31.378866229854367]},"#6611cc":{"lch":[33.1039576367877899,105.121866511028642,274.848446148865946],"luv":[33.1039576367877899,8.88494143701037409,-104.745714157780327],"rgb":[0.4,0.0666666666666666657,0.8],"xyz":[0.165777307758822962,0.0758534819989535869,0.577193886846660176],"hpluv":[274.848446148865946,402.951217622234481,33.1039576367877899],"hsluv":[274.848446148865946,96.4508528344463372,33.1039576367877899]},"#6611dd":{"lch":[34.8951509835915559,114.837148656435488,273.319244536407894],"luv":[34.8951509835915559,6.64899595047804048,-114.644500803094743],"rgb":[0.4,0.0666666666666666657,0.866666666666666696],"xyz":[0.187295633309456505,0.0844608122192071209,0.690523734746666173],"hpluv":[273.319244536407894,417.596303228590671,34.8951509835915559],"hsluv":[273.319244536407894,96.944722371929771,34.8951509835915559]},"#6611ee":{"lch":[36.7406193088150914,124.471664845310258,272.136065946829319],"luv":[36.7406193088150914,4.63940101804097527,-124.385173182164465],"rgb":[0.4,0.0666666666666666657,0.933333333333333348],"xyz":[0.211107813575631242,0.0939856843256771657,0.815934550815189397],"hpluv":[272.136065946829319,429.895948632666091,36.7406193088150914],"hsluv":[272.136065946829319,97.3524117238680446,36.7406193088150914]},"#6611ff":{"lch":[38.6302462525687815,134.023748920536207,271.203906716280642],"luv":[38.6302462525687815,2.81591803113255,-133.994163605572282],"rgb":[0.4,0.0666666666666666657,1],"xyz":[0.237278861985462636,0.104454103689609862,0.953768739106971242],"hpluv":[271.203906716280642,440.244168299440901,38.6302462525687815],"hsluv":[271.203906716280642,99.999999999999531,38.6302462525687815]},"#662200":{"lch":[23.5697003211059126,54.0433218319152,21.7646438431993481],"luv":[23.5697003211059126,50.1908335966774928,20.038983444740694],"rgb":[0.4,0.133333333333333331,0],"xyz":[0.0605136973184005889,0.0396930357984128235,0.00447512810223376842],"hpluv":[21.7646438431993481,290.955989204018863,23.5697003211059126],"hsluv":[21.7646438431993481,100.000000000002302,23.5697003211059126]},"#662211":{"lch":[23.7037155268300239,51.2256671637292627,18.5481266113504795],"luv":[23.7037155268300239,48.5648418325832196,16.2949413667354186],"rgb":[0.4,0.133333333333333331,0.0666666666666666657],"xyz":[0.0615253628180377071,0.0400977019982676763,0.0098032330669894],"hpluv":[18.5481266113504795,274.227196288753476,23.7037155268300239],"hsluv":[18.5481266113504795,84.4421944630679775,23.7037155268300239]},"#662222":{"lch":[23.9497782760704823,46.8639841586094761,12.177050630061828],"luv":[23.9497782760704823,45.8095660888384515,9.88517404858116],"rgb":[0.4,0.133333333333333331,0.133333333333333331],"xyz":[0.0634007209565147362,0.0408478452536585,0.0196801192629685942],"hpluv":[12.177050630061828,248.300181449835577,23.9497782760704823],"hsluv":[12.177050630061828,58.184428739378582,23.9497782760704823]},"#662233":{"lch":[24.3484354577474491,41.8866591548313139,0.79920805816821483],"luv":[24.3484354577474491,41.8825842907357284,0.584250188216085209],"rgb":[0.4,0.133333333333333331,0.2],"xyz":[0.0664884716889724697,0.0420829455466416105,0.0359422731205797374],"hpluv":[0.79920805816821483,218.295100847162672,24.3484354577474491],"hsluv":[0.79920805816821483,61.8388407102714908,24.3484354577474491]},"#662244":{"lch":[24.9104705449366364,38.7518995195090881,343.921953822216381],"luv":[24.9104705449366364,37.2361321960480467,-10.7322027305005232],"rgb":[0.4,0.133333333333333331,0.266666666666666663],"xyz":[0.0709464669331913433,0.0438661436443291836,0.059421048073466376],"hpluv":[343.921953822216381,197.40147375767063,24.9104705449366364],"hsluv":[343.921953822216381,66.1143919991375,24.9104705449366364]},"#662255":{"lch":[25.6388481254070371,39.7515606661792376,324.488651014584605],"luv":[25.6388481254070371,32.3577893991285421,-23.0902585650003651],"rgb":[0.4,0.133333333333333331,0.333333333333333315],"xyz":[0.0769088809725533423,0.0462511092600740165,0.0908230953474402913],"hpluv":[324.488651014584605,196.74105716675524,25.6388481254070371],"hsluv":[324.488651014584605,70.5303777194930746,25.6388481254070371]},"#662266":{"lch":[26.530115175026431,45.1550068711170525,307.715012949244],"luv":[26.530115175026431,27.6228683191850166,-35.7204674010796381],"rgb":[0.4,0.133333333333333331,0.4],"xyz":[0.0844938767460615137,0.049285107569477328,0.130770739754584253],"hpluv":[307.715012949244,215.976303505553034,26.530115175026431],"hsluv":[307.715012949244,74.7212231760600076,26.530115175026431]},"#662277":{"lch":[27.5758503181253047,53.47184404785515,295.772994892671647],"luv":[27.5758503181253047,23.2499163509258366,-48.1526686233805137],"rgb":[0.4,0.133333333333333331,0.466666666666666674],"xyz":[0.0938078897662634331,0.0530107127775581444,0.179824541660982162],"hpluv":[295.772994892671647,246.056915236342576,27.5758503181253047],"hsluv":[295.772994892671647,78.4792949436714622,27.5758503181253047]},"#662288":{"lch":[28.7641691288539221,63.1969785740596492,287.807032602413699],"luv":[28.7641691288539221,19.3264050913403267,-60.169329123196718],"rgb":[0.4,0.133333333333333331,0.533333333333333326],"xyz":[0.104948306868207261,0.0574668796183357422,0.23849740506455433],"hpluv":[287.807032602413699,278.794247273594806,28.7641691288539221],"hsluv":[287.807032602413699,81.7283139306751565,28.7641691288539221]},"#662299":{"lch":[30.081149723697223,73.446586603294,282.467625610713],"luv":[30.081149723697223,15.8562317990126083,-71.7145800853016766],"rgb":[0.4,0.133333333333333331,0.6],"xyz":[0.118005270977279975,0.0626896652619649,0.307264082705672237],"hpluv":[282.467625610713,309.825038390781458,30.081149723697223],"hsluv":[282.467625610713,84.475317587044259,30.081149723697223]},"#6622aa":{"lch":[31.512047889249807,83.7990879252892569,278.786617054458873],"luv":[31.512047889249807,12.8007301136733549,-82.8156292354725565],"rgb":[0.4,0.133333333333333331,0.66666666666666663],"xyz":[0.133062963942532531,0.068712742448066,0.386567932322670837],"hpluv":[278.786617054458873,337.444217562648532,31.512047889249807],"hsluv":[278.786617054458873,86.7692530837111349,31.512047889249807]},"#6622bb":{"lch":[33.0422299311305281,94.07636648958254,276.16643073789237],"luv":[33.0422299311305281,10.1053888262289746,-93.5320471739658643],"rgb":[0.4,0.133333333333333331,0.733333333333333282],"xyz":[0.150200556049869149,0.0755677792910007529,0.476825917421312584],"hpluv":[276.16643073789237,361.285484259324733,33.0422299311305281],"hsluv":[276.16643073789237,88.6739591516067662,33.0422299311305281]},"#6622cc":{"lch":[34.6578144612334853,104.214655833315277,274.245119058655746],"luv":[34.6578144612334853,7.71433729467952212,-103.928742369761551],"rgb":[0.4,0.133333333333333331,0.8],"xyz":[0.169492931493590904,0.0832847294684895545,0.578432428091582684],"hpluv":[274.245119058655746,381.563613242959605,34.6578144612334853],"hsluv":[274.245119058655746,90.2534916489383079,34.6578144612334853]},"#6622dd":{"lch":[36.346058304563158,114.200305800004017,272.799119030217753],"luv":[36.346058304563158,5.5769048208672336,-114.064052082299],"rgb":[0.4,0.133333333333333331,0.866666666666666696],"xyz":[0.191011257044224447,0.0918920596887430885,0.691762275991588682],"hpluv":[272.799119030217753,398.702789727268566,36.346058304563158],"hsluv":[272.799119030217753,91.5654894217155118,36.346058304563158]},"#6622ee":{"lch":[38.0955422395423,124.039689220569301,271.686141036519132],"luv":[38.0955422395423,3.64980151132168062,-123.985980864222597],"rgb":[0.4,0.133333333333333331,0.933333333333333348],"xyz":[0.214823437310399185,0.101416931795213133,0.817173092060111905],"hpluv":[271.686141036519132,413.167199445381073,38.0955422395423],"hsluv":[271.686141036519132,92.6590152569973498,38.0955422395423]},"#6622ff":{"lch":[39.8962147757429264,133.745689778340022,270.812765394378914],"luv":[39.8962147757429264,1.89717678294479941,-133.732233416399],"rgb":[0.4,0.133333333333333331,1],"xyz":[0.240994485720230578,0.111885351159145829,0.95500728035189375],"hpluv":[270.812765394378914,425.390148773484384,39.8962147757429264],"hsluv":[270.812765394378914,99.99999999999946,39.8962147757429264]},"#ddaa00":{"lch":[72.3107430320736881,86.5721801417344494,59.9465914104400071],"luv":[72.3107430320736881,43.355958426121056,74.9333253195491267],"rgb":[0.866666666666666696,0.66666666666666663,0],"xyz":[0.441922241377765923,0.441231641500849037,0.0618909005679976823],"hpluv":[59.9465914104400071,151.919966798177825,72.3107430320736881],"hsluv":[59.9465914104400071,100.000000000002402,72.3107430320736881]},"#ddaa11":{"lch":[72.3377322217577188,85.4954146103564625,59.6744594052448178],"luv":[72.3377322217577188,43.1676990261245663,73.7971251485224],"rgb":[0.866666666666666696,0.66666666666666663,0.0666666666666666657],"xyz":[0.442933906877403,0.44163630770070389,0.067219005532753312],"hpluv":[59.6744594052448178,149.974443711406025,72.3377322217577188],"hsluv":[59.6744594052448178,98.5180859943944398,72.3377322217577188]},"#ddaa22":{"lch":[72.3877194091470386,83.5208789068112623,59.1557200492863586],"luv":[72.3877194091470386,42.8217010650181038,71.708013019916109],"rgb":[0.866666666666666696,0.66666666666666663,0.133333333333333331],"xyz":[0.444809265015880084,0.44238645095609469,0.0770958917287325],"hpluv":[59.1557200492863586,146.409577733002152,72.3877194091470386],"hsluv":[59.1557200492863586,95.7957425728033911,72.3877194091470386]},"#ddaa33":{"lch":[72.4698996386445771,80.3304907566891,58.2589820164620633],"luv":[72.4698996386445771,42.2603136650720543,68.3158373595774435],"rgb":[0.866666666666666696,0.66666666666666663,0.2],"xyz":[0.44789701574833779,0.443621551249077817,0.0933580455863436548],"hpluv":[58.2589820164620633,140.657238526484292,72.4698996386445771],"hsluv":[58.2589820164620633,91.3821490755410082,72.4698996386445771]},"#ddaa44":{"lch":[72.5882801580772679,75.8571050863154,56.8623293870095949],"luv":[72.5882801580772679,41.467485474955744,63.5196665644635701],"rgb":[0.866666666666666696,0.66666666666666663,0.266666666666666663],"xyz":[0.452355010992556705,0.445404749346765383,0.116836820539230293],"hpluv":[56.8623293870095949,132.607804442486071,72.5882801580772679],"hsluv":[56.8623293870095949,85.1564308385751332,72.5882801580772679]},"#ddaa55":{"lch":[72.7461171317656579,70.1198989219024469,54.780917696258733],"luv":[72.7461171317656579,40.4384565855633085,57.2846528644045065],"rgb":[0.866666666666666696,0.66666666666666663,0.333333333333333315],"xyz":[0.45831742503191869,0.447789714962510244,0.148238867813204195],"hpluv":[54.780917696258733,122.3124851735341,72.7461171317656579],"hsluv":[54.780917696258733,77.0893717991816345,72.7461171317656579]},"#ddaa66":{"lch":[72.9460991959627307,63.2340905833455835,51.7145858463931702],"luv":[72.9460991959627307,39.17852917707404,49.6345954292357661],"rgb":[0.866666666666666696,0.66666666666666663,0.4],"xyz":[0.465902420805426876,0.450823713271913562,0.188186512220348157],"hpluv":[51.7145858463931702,109.998947735143361,72.9460991959627307],"hsluv":[51.7145858463931702,67.2337497701281421,72.9460991959627307]},"#ddaa77":{"lch":[73.1904440644495651,55.4382228560327377,47.150998877343909],"luv":[73.1904440644495651,37.7017926183457632,40.6444508733775294],"rgb":[0.866666666666666696,0.66666666666666663,0.466666666666666674],"xyz":[0.475216433825628781,0.454549318479994358,0.237240314126746066],"hpluv":[47.150998877343909,96.1156803308001173,73.1904440644495651],"hsluv":[47.150998877343909,55.7140089565642214,73.1904440644495651]},"#ddaa88":{"lch":[73.4809558021361511,47.1613293807763228,40.1850915920125189],"luv":[73.4809558021361511,36.0295555463961819,30.4312687229965526],"rgb":[0.866666666666666696,0.66666666666666663,0.533333333333333326],"xyz":[0.486356850927572582,0.459005485320771955,0.295913177530318261],"hpluv":[40.1850915920125189,81.4424009312931645,73.4809558021361511],"hsluv":[40.1850915920125189,45.325944585658668,73.4809558021361511]},"#ddaa99":{"lch":[73.8190624606049539,39.1833139250455389,29.2463480703396321],"luv":[73.8190624606049539,34.1885051927702435,19.1436204212419021],"rgb":[0.866666666666666696,0.66666666666666663,0.6],"xyz":[0.499413815036645281,0.464228270964401113,0.36467985517143614],"hpluv":[29.2463480703396321,67.3553294964948,73.8190624606049539],"hsluv":[29.2463480703396321,46.1073405736803323,73.8190624606049539]},"#ddaaaa":{"lch":[74.2058435914849923,32.9500913661112946,12.1770506300625296],"luv":[74.2058435914849923,32.2087294789219527,6.95027095793437244],"rgb":[0.866666666666666696,0.66666666666666663,0.66666666666666663],"xyz":[0.514471508001897893,0.470251348150502235,0.443983704788434741],"hpluv":[12.1770506300625296,56.3453191386000114,74.2058435914849923],"hsluv":[12.1770506300625296,46.9171896008106,74.2058435914849923]},"#ddaabb":{"lch":[74.6420527030620633,30.7078714289026884,348.787813428378513],"luv":[74.6420527030620633,30.1217754775259223,-5.97093039446416807],"rgb":[0.866666666666666696,0.66666666666666663,0.733333333333333282],"xyz":[0.531609100109234456,0.477106384993437,0.534241689887076543],"hpluv":[348.787813428378513,52.2042025244198,74.6420527030620633],"hsluv":[348.787813428378513,47.7320050944543937,74.6420527030620633]},"#ddaacc":{"lch":[75.1281375044867445,34.0548346014018435,325.184688201169763],"luv":[75.1281375044867445,27.9589055182432595,-19.4430286208394669],"rgb":[0.866666666666666696,0.66666666666666663,0.8],"xyz":[0.55090147555295621,0.484823335170925795,0.635848200557346699],"hpluv":[325.184688201169763,57.5195499622066393,75.1281375044867445],"hsluv":[325.184688201169763,48.5278754329488109,75.1281375044867445]},"#ddaadd":{"lch":[75.6642595524878772,42.092894356631966,307.715012949247466],"luv":[75.6642595524878772,25.749668941594777,-33.2981426616688125],"rgb":[0.866666666666666696,0.66666666666666663,0.866666666666666696],"xyz":[0.572419801103589809,0.493430665391179302,0.749178048457352697],"hpluv":[307.715012949247466,70.5922995729826255,75.6642595524878772],"hsluv":[307.715012949247466,49.2811497501269855,75.6642595524878772]},"#ddaaee":{"lch":[76.2503141773092636,52.9001531738191915,296.399494755977059],"luv":[76.2503141773092636,23.5208512504545659,-47.3834967290038875],"rgb":[0.866666666666666696,0.66666666666666663,0.933333333333333348],"xyz":[0.596231981369764519,0.502955537497649319,0.87458886452587592],"hpluv":[296.399494755977059,89.1958388421213,76.2503141773092636],"hsluv":[296.399494755977059,73.8038640729286,76.2503141773092636]},"#ddaaff":{"lch":[76.8859510948180542,65.1444004641461447,289.080822119258073],"luv":[76.8859510948180542,21.295808093697417,-61.565261872824486],"rgb":[0.866666666666666696,0.66666666666666663,1],"xyz":[0.62240302977959594,0.513423956861582,1.01242305281765765],"hpluv":[289.080822119258073,113.514774922986319,76.8859510948180542],"hsluv":[289.080822119258073,99.9999999999968736,76.8859510948180542]},"#663300":{"lch":[27.2772702365161024,46.6784293424923,33.1138040531735385],"luv":[27.2772702365161024,39.0972512948193938,25.5006020923387098],"rgb":[0.4,0.2,0],"xyz":[0.0666314194074114075,0.0519284799764346272,0.00651436879857064926],"hpluv":[33.1138040531735385,217.147410386557254,27.2772702365161024],"hsluv":[33.1138040531735385,100.000000000002288,27.2772702365161024]},"#663311":{"lch":[27.3893959478715772,43.971204952951652,30.1269617465812196],"luv":[27.3893959478715772,38.0313691656755353,22.0699303215615963],"rgb":[0.4,0.2,0.0666666666666666657],"xyz":[0.0676430849070485257,0.0523331461762894801,0.0118424737633262799],"hpluv":[30.1269617465812196,203.716046393577358,27.3893959478715772],"hsluv":[30.1269617465812196,87.8713966090680572,27.3893959478715772]},"#663322":{"lch":[27.5957277293980781,39.608651287835805,23.9834802389854467],"luv":[27.5957277293980781,36.1889469500517436,16.0998563809655693],"rgb":[0.4,0.2,0.133333333333333331],"xyz":[0.0695184430455255548,0.0530832894316803,0.0217193599593054759],"hpluv":[23.9834802389854467,182.132533879714401,27.5957277293980781],"hsluv":[23.9834802389854467,66.9779468056010501,27.5957277293980781]},"#663333":{"lch":[27.9312558147072,34.2527069144242517,12.1770506300619683],"luv":[27.9312558147072,33.482036777055967,7.2250359324586606],"rgb":[0.4,0.2,0.2],"xyz":[0.0726061937779832883,0.0543183897246634143,0.0379815138169166192],"hpluv":[12.1770506300619683,155.612242967619039,27.9312558147072],"hsluv":[12.1770506300619683,36.4647718300342518,27.9312558147072]},"#663344":{"lch":[28.4068233476218452,30.4023991370198274,352.642674566889241],"luv":[28.4068233476218452,30.1520905841737843,-3.89323858637544307],"rgb":[0.4,0.2,0.266666666666666663],"xyz":[0.0770641890222021619,0.0561015878223509873,0.0614602887698032577],"hpluv":[352.642674566889241,135.807736934047625,28.4068233476218452],"hsluv":[352.642674566889241,42.3197568133242044,28.4068233476218452]},"#663355":{"lch":[29.027378781744666,31.164203729876963,328.257954430910445],"luv":[29.027378781744666,26.5028264215118483,-16.3953586660521324],"rgb":[0.4,0.2,0.333333333333333315],"xyz":[0.0830266030615641609,0.0584865534380958202,0.0928623360437771661],"hpluv":[328.257954430910445,136.234637721643935,29.027378781744666],"hsluv":[328.257954430910445,48.648881209958347,29.027378781744666]},"#663366":{"lch":[29.7928910898429251,37.2833882928919067,307.715012949244567],"luv":[29.7928910898429251,22.8075289246907325,-29.4935190668720466],"rgb":[0.4,0.2,0.4],"xyz":[0.0906115988350723323,0.0615205517474991317,0.132809980450921128],"hpluv":[307.715012949244567,158.796911496206434,29.7928910898429251],"hsluv":[307.715012949244567,54.9388950129523792,29.7928910898429251]},"#663377":{"lch":[30.6992208566667273,46.7654342463890345,294.320996437271049],"luv":[30.6992208566667273,19.2602655771695837,-42.6151148086008646],"rgb":[0.4,0.2,0.466666666666666674],"xyz":[0.0999256118552742517,0.0652461569555799481,0.181863782357319037],"hpluv":[294.320996437271049,193.302265796468333,30.6992208566667273],"hsluv":[294.320996437271049,60.8304716126584424,30.6992208566667273]},"#663388":{"lch":[31.7390466224972485,57.6768981875091811,286.074834637191429],"luv":[31.7390466224972485,15.9703082974272554,-55.4217812544619122],"rgb":[0.4,0.2,0.533333333333333326],"xyz":[0.11106602895721808,0.0697023237963575459,0.240536645760891205],"hpluv":[286.074834637191429,230.593651019326217,31.7390466224972485],"hsluv":[286.074834637191429,66.1275975958513,31.7390466224972485]},"#663399":{"lch":[32.9028065942714818,68.9918273860838696,280.844497617061506],"luv":[32.9028065942714818,12.9804074562249703,-67.7597319087197292],"rgb":[0.4,0.2,0.6],"xyz":[0.124122993066290793,0.0749251094399867,0.309303323402009112],"hpluv":[280.844497617061506,266.074975063872387,32.9028065942714818],"hsluv":[280.844497617061506,70.7618769362906761,32.9028065942714818]},"#6633aa":{"lch":[34.1795810026756612,80.2563017922262,277.366876751775067],"luv":[34.1795810026756612,10.2906460265496023,-79.5938225097975],"rgb":[0.4,0.2,0.66666666666666663],"xyz":[0.139180686031543321,0.0809481866260878,0.388607173019007712],"hpluv":[277.366876751775067,297.955725741163178,34.1795810026756612],"hsluv":[277.366876751775067,74.7463951454814293,34.1795810026756612]},"#6633bb":{"lch":[35.5578512622049701,91.2933310256451875,274.950579703742051],"luv":[35.5578512622049701,7.87828999249439477,-90.9527615663878208],"rgb":[0.4,0.2,0.733333333333333282],"xyz":[0.15631827813888,0.0878032234690225566,0.478865158117649459],"hpluv":[274.950579703742051,325.793841875348,35.5578512622049701],"hsluv":[274.950579703742051,78.1373397599298158,35.5578512622049701]},"#6633cc":{"lch":[37.0261004663704369,102.052471518039624,273.208108112313198],"luv":[37.0261004663704369,5.71114175070883,-101.892540467119574],"rgb":[0.4,0.2,0.8],"xyz":[0.175610653582601722,0.0955201736465113582,0.58047166878791967],"hpluv":[273.208108112313198,349.747708937339723,37.0261004663704369],"hsluv":[273.208108112313198,81.008127051099,37.0261004663704369]},"#6633dd":{"lch":[38.5732487885037258,112.538160698021628,271.912259810227567],"luv":[38.5732487885037258,3.75528971541350476,-112.475488051606391],"rgb":[0.4,0.2,0.866666666666666696],"xyz":[0.197128979133235266,0.104127503866764892,0.693801516687925668],"hpluv":[271.912259810227567,370.214070757058153,38.5732487885037258],"hsluv":[271.912259810227567,83.8924044294761,38.5732487885037258]},"#6633ee":{"lch":[40.1889386764538372,122.775879994578517,270.923585069715159],"luv":[40.1889386764538372,1.97901241536538453,-122.759929204537158],"rgb":[0.4,0.2,0.933333333333333348],"xyz":[0.22094115939941,0.113652375973234937,0.819212332756448891],"hpluv":[270.923585069715159,387.655406037674595,40.1889386764538372],"hsluv":[270.923585069715159,91.8481370725274502,40.1889386764538372]},"#6633ff":{"lch":[41.8636962738951581,132.796565847050772,270.152898062524457],"luv":[41.8636962738951581,0.354377123439640451,-132.796093005873018],"rgb":[0.4,0.2,1],"xyz":[0.247112207809241397,0.124120795337167633,0.957046521048230736],"hpluv":[270.152898062524457,402.521052726566381,41.8636962738951581],"hsluv":[270.152898062524457,99.9999999999993747,41.8636962738951581]},"#ddbb00":{"lch":[76.6269242453545871,86.8164471599593,69.4373142874166263],"luv":[76.6269242453545871,30.4927107526369845,81.2852390562642],"rgb":[0.866666666666666696,0.733333333333333282,0],"xyz":[0.475876739286364758,0.509140637318047595,0.0732090665375303],"hpluv":[69.4373142874166263,149.25100710879434,76.6269242453545871],"hsluv":[69.4373142874166263,100.000000000002373,76.6269242453545871]},"#ddbb11":{"lch":[76.6514577805917412,85.7837129406502754,69.2755127455160391],"luv":[76.6514577805917412,30.3566774947925779,80.2328956062352461],"rgb":[0.866666666666666696,0.733333333333333282,0.0666666666666666657],"xyz":[0.476888404786001863,0.509545303517902504,0.0785371715022859379],"hpluv":[69.2755127455160391,147.663405788509436,76.6514577805917412],"hsluv":[69.2755127455160391,98.710789014839,76.6514577805917412]},"#ddbb22":{"lch":[76.6969020797125722,83.8847347199512257,68.9672438614109353],"luv":[76.6969020797125722,30.1063672837106679,78.2959473281657523],"rgb":[0.866666666666666696,0.733333333333333282,0.133333333333333331],"xyz":[0.478763762924478919,0.510295446773293304,0.0884140576982651305],"hpluv":[68.9672438614109353,144.735860207932831,76.6969020797125722],"hsluv":[68.9672438614109353,96.3396664069398554,76.6969020797125722]},"#ddbb33":{"lch":[76.7716285455552452,80.8014056767331823,68.4347482297151828],"luv":[76.7716285455552452,29.6994133556607949,75.1452726767666093],"rgb":[0.866666666666666696,0.733333333333333282,0.2],"xyz":[0.481851513656936625,0.511530547066276431,0.104676211555876281],"hpluv":[68.4347482297151828,139.9591753538609,76.7716285455552452],"hsluv":[68.4347482297151828,92.4878111801133542,76.7716285455552452]},"#ddbb44":{"lch":[76.8793043130786771,76.4437058057830683,67.6060651816737277],"luv":[76.8793043130786771,29.122950030038453,70.6788082728408398],"rgb":[0.866666666666666696,0.733333333333333282,0.266666666666666663],"xyz":[0.486309508901155541,0.513313745163964,0.128154986508762919],"hpluv":[67.6060651816737277,133.157612926581692,76.8793043130786771],"hsluv":[67.6060651816737277,87.0382611213693167,76.8793043130786771]},"#ddbb55":{"lch":[77.0229278214451654,70.786451757311653,66.3713649049339551],"luv":[77.0229278214451654,28.3717024864450664,64.851894732620238],"rgb":[0.866666666666666696,0.733333333333333282,0.333333333333333315],"xyz":[0.492271922940517526,0.515698710779708747,0.159557033782736835],"hpluv":[66.3713649049339551,124.235507886155276,77.0229278214451654],"hsluv":[66.3713649049339551,79.9485715087726,77.0229278214451654]},"#ddbb66":{"lch":[77.2049977781888259,63.8693414267369732,64.5489675558404912],"luv":[77.2049977781888259,27.4471820183984,57.6710063509733359],"rgb":[0.866666666666666696,0.733333333333333282,0.4],"xyz":[0.499856918714025711,0.518732709089112065,0.199504678189880769],"hpluv":[64.5489675558404912,113.177180957201557,77.2049977781888259],"hsluv":[64.5489675558404912,71.2432689272834665,77.2049977781888259]},"#ddbb77":{"lch":[77.4276024714994264,55.80459657383539,61.8158033937064815],"luv":[77.4276024714994264,26.3569386858829375,49.1880552764299495],"rgb":[0.866666666666666696,0.733333333333333282,0.466666666666666674],"xyz":[0.509170931734227561,0.522458314297192916,0.248558480096278678],"hpluv":[61.8158033937064815,100.062778032150931,77.4276024714994264],"hsluv":[61.8158033937064815,61.00659046349368,77.4276024714994264]},"#ddbb88":{"lch":[77.6924726660212883,46.8021917196541537,57.5480835848938881],"luv":[77.6924726660212883,25.1136643841879952,39.4936578574539112],"rgb":[0.866666666666666696,0.733333333333333282,0.533333333333333326],"xyz":[0.520311348836171472,0.526914481137970458,0.307231343499850873],"hpluv":[57.5480835848938881,85.1204314231653285,77.6924726660212883],"hsluv":[57.5480835848938881,49.3735690170151145,77.6924726660212883]},"#ddbb99":{"lch":[78.001015952892,37.2494741955694195,50.4191367157405352],"luv":[78.001015952892,23.7341209657771088,28.7091419207933036],"rgb":[0.866666666666666696,0.733333333333333282,0.6],"xyz":[0.533368312945244116,0.532137266781599672,0.375998021140968752],"hpluv":[50.4191367157405352,68.8881727109007471,78.001015952892],"hsluv":[50.4191367157405352,37.2278198354843894,78.001015952892]},"#ddbbaa":{"lch":[78.3543411988951135,27.9779961680489,37.3601297670291643],"luv":[78.3543411988951135,22.2379488027189254,16.9776883770144309],"rgb":[0.866666666666666696,0.733333333333333282,0.66666666666666663],"xyz":[0.548426005910496728,0.538160343967700738,0.455301870757967353],"hpluv":[37.3601297670291643,52.7537881236722086,78.3543411988951135],"hsluv":[37.3601297670291643,37.9002282962103152,78.3543411988951135]},"#ddbbbb":{"lch":[78.7532777240269724,21.1216737069600953,12.1770506300632171],"luv":[78.7532777240269724,20.6464457718990104,4.45526398447083238],"rgb":[0.866666666666666696,0.733333333333333282,0.733333333333333282],"xyz":[0.565563598017833291,0.545015380810635497,0.545559855856609155],"hpluv":[12.1770506300632171,40.7192307977840144,78.7532777240269724],"hsluv":[12.1770506300632171,38.5653299871361952,78.7532777240269724]},"#ddbbcc":{"lch":[79.1983918483363425,20.8793784390591419,335.381067074864461],"luv":[79.1983918483363425,18.9814116783666442,-8.69795692664743747],"rgb":[0.866666666666666696,0.733333333333333282,0.8],"xyz":[0.584855973461555,0.552732330988124354,0.647166366526879311],"hpluv":[335.381067074864461,41.2776027841095186,79.1983918483363425],"hsluv":[335.381067074864461,39.1976988204569,79.1983918483363425]},"#ddbbdd":{"lch":[79.6900023594157858,28.2216267397768341,307.715012949250536],"luv":[79.6900023594157858,17.264138203128045,-22.325092338948604],"rgb":[0.866666666666666696,0.733333333333333282,0.866666666666666696],"xyz":[0.606374299012188644,0.56133966120837786,0.760496214426885309],"hpluv":[307.715012949250536,57.3946451248898555,79.6900023594157858],"hsluv":[307.715012949250536,39.7709084435557401,79.6900023594157858]},"#ddbbee":{"lch":[80.2281958041266,39.4567857635703447,293.154060026294076],"luv":[80.2281958041266,15.5145982189510505,-36.2785774927409221],"rgb":[0.866666666666666696,0.733333333333333282,0.933333333333333348],"xyz":[0.630186479278363354,0.570864533314847877,0.885907030495408532],"hpluv":[293.154060026294076,82.8233888781043674,80.2281958041266],"hsluv":[293.154060026294076,68.7191774169969278,80.2281958041266]},"#ddbbff":{"lch":[80.8128420975971409,52.2658591287574765,285.253756774661895],"luv":[80.8128420975971409,13.7508586713070624,-50.4245368473411],"rgb":[0.866666666666666696,0.733333333333333282,1],"xyz":[0.656357527688194775,0.581332952678780601,1.02374121878719038],"hpluv":[285.253756774661895,113.64059963508393,80.8128420975971409],"hsluv":[285.253756774661895,99.9999999999962768,80.8128420975971409]},"#664400":{"lch":[31.7142168878436834,41.7146560735594463,49.9018869072924431],"luv":[31.7142168878436834,26.8683448374877969,31.9093180282686859],"rgb":[0.4,0.266666666666666663,0],"xyz":[0.0754639898903774337,0.0695936209423669294,0.00945855895955924342],"hpluv":[49.9018869072924431,166.906788900061372,31.7142168878436834],"hsluv":[49.9018869072924431,100.000000000002103,31.7142168878436834]},"#664411":{"lch":[31.8065195391856221,38.988494662362406,47.7128576067384387],"luv":[31.8065195391856221,26.2332728657793552,28.8429906699465946],"rgb":[0.4,0.266666666666666663,0.0666666666666666657],"xyz":[0.0764756553900145519,0.0699982871422217823,0.0147866639243148749],"hpluv":[47.7128576067384387,155.546285842055198,31.8065195391856221],"hsluv":[47.7128576067384387,90.7993319288460157,31.8065195391856221]},"#664422":{"lch":[31.9766874661881033,34.3475437583520318,43.0092135947734064],"luv":[31.9766874661881033,25.116436032279772,23.4290077311931029],"rgb":[0.4,0.266666666666666663,0.133333333333333331],"xyz":[0.078351013528491581,0.0707484303976126,0.0246635501202940727],"hpluv":[43.0092135947734064,136.301783870263904,31.9766874661881033],"hsluv":[43.0092135947734064,74.6688439558526227,31.9766874661881033]},"#664433":{"lch":[32.2542649002247757,27.9288783689085562,32.9719795273007179],"luv":[32.2542649002247757,23.4305644913898661,15.1997004759998031],"rgb":[0.4,0.266666666666666663,0.2],"xyz":[0.0814387642609493145,0.0719835306905957095,0.0409257039779052159],"hpluv":[32.9719795273007179,109.876716511985933,32.2542649002247757],"hsluv":[32.9719795273007179,50.4508902462759465,32.2542649002247757]},"#664444":{"lch":[32.6494757012261942,21.7704999617243,12.1770506300622419],"luv":[32.6494757012261942,21.2806737346177428,4.59212303669972144],"rgb":[0.4,0.266666666666666663,0.266666666666666663],"xyz":[0.0858967595051681881,0.0737667287882832895,0.0644044789307918475],"hpluv":[12.1770506300622419,84.6119136876739,32.6494757012261942],"hsluv":[12.1770506300622419,19.8271939783404392,32.6494757012261942]},"#664455":{"lch":[33.1682230288457163,20.3425996427482829,337.72581918360828],"luv":[33.1682230288457163,18.8246474429619,-7.71064257201243208],"rgb":[0.4,0.266666666666666663,0.333333333333333315],"xyz":[0.0918591735445301871,0.0761516944040281224,0.0958065262047657629],"hpluv":[337.72581918360828,77.8257963773028649,33.1682230288457163],"hsluv":[337.72581918360828,26.9902218950403885,33.1682230288457163]},"#664466":{"lch":[33.8127168447387447,26.5268160416637819,307.715012949245931],"luv":[33.8127168447387447,16.2273642995468066,-20.9843898457416387],"rgb":[0.4,0.266666666666666663,0.4],"xyz":[0.0994441693180383585,0.0791856927134314409,0.135754170611909725],"hpluv":[307.715012949245931,99.5507152142919125,33.8127168447387447],"hsluv":[307.715012949245931,34.4415155187259359,33.8127168447387447]},"#664477":{"lch":[34.5819879544663067,37.1994974310500766,291.489286484323088],"luv":[34.5819879544663067,13.6271894146704895,-34.6136146303646512],"rgb":[0.4,0.266666666666666663,0.466666666666666674],"xyz":[0.108758182338240278,0.0829112979215122503,0.184807972518307634],"hpluv":[291.489286484323088,136.49804898345451,34.5819879544663067],"hsluv":[291.489286484323088,41.7425383187140824,34.5819879544663067]},"#664488":{"lch":[35.4724176022540263,49.4256461635840623,283.003444619748336],"luv":[35.4724176022540263,11.1212465051830698,-48.1582015326441066],"rgb":[0.4,0.266666666666666663,0.533333333333333326],"xyz":[0.119898599440184106,0.0873674647622898481,0.243480835921879801],"hpluv":[283.003444619748336,176.807585609029246,35.4724176022540263],"hsluv":[283.003444619748336,48.5905204317402166,35.4724176022540263]},"#664499":{"lch":[36.4782980897457563,61.9753280698008169,278.131406705371774],"luv":[36.4782980897457563,8.76603164871553453,-61.3522450974139844],"rgb":[0.4,0.266666666666666663,0.6],"xyz":[0.132955563549256806,0.092590250405919,0.312247513562997736],"hpluv":[278.131406705371774,215.5875082467536,36.4782980897457563],"hsluv":[278.131406705371774,54.8155424382278511,36.4782980897457563]},"#6644aa":{"lch":[37.5923984663849922,74.3597011725147468,275.081334091822],"luv":[37.5923984663849922,6.58602388672208239,-74.0674655150911576],"rgb":[0.4,0.266666666666666663,0.66666666666666663],"xyz":[0.148013256514509361,0.0986133275920201,0.391551363179996281],"hpluv":[275.081334091822,251.001852587777108,37.5923984663849922],"hsluv":[275.081334091822,60.3520360208115179,37.5923984663849922]},"#6644bb":{"lch":[38.8064988843830392,86.3901107279874765,273.04172423936518],"luv":[38.8064988843830392,4.58413310153298603,-86.2684006766171905],"rgb":[0.4,0.266666666666666663,0.733333333333333282],"xyz":[0.165150848621846,0.105468364434954859,0.481809348278638083],"hpluv":[273.04172423936518,282.487278503057098,38.8064988843830392],"hsluv":[273.04172423936518,65.2044789549227346,38.8064988843830392]},"#6644cc":{"lch":[40.1118623747323184,98.0126069922284415,271.608181870646],"luv":[40.1118623747323184,2.75066337520804938,-97.9740015535209],"rgb":[0.4,0.266666666666666663,0.8],"xyz":[0.184443224065567735,0.11318531461244366,0.583415858948908239],"hpluv":[271.608181870646,310.061926380003911,40.1118623747323184],"hsluv":[271.608181870646,73.249037078124374,40.1118623747323184]},"#6644dd":{"lch":[41.4996246628331491,109.23540368219534,270.561113733160255],"luv":[41.4996246628331491,1.06975602599714947,-109.230165429047204],"rgb":[0.4,0.266666666666666663,0.866666666666666696],"xyz":[0.205961549616201278,0.121792644832697194,0.696745706848914237],"hpluv":[270.561113733160255,334.009312605211903,41.4996246628331491],"hsluv":[270.561113733160255,82.0982912580276434,41.4996246628331491]},"#6644ee":{"lch":[42.9610953823040305,120.093362966476874,269.772657810053431],"luv":[42.9610953823040305,-0.476513570908160711,-120.092417593346411],"rgb":[0.4,0.266666666666666663,0.933333333333333348],"xyz":[0.229773729882376043,0.131317516939167239,0.82215652291743746],"hpluv":[269.772657810053431,354.717803858999673,42.9610953823040305],"hsluv":[269.772657810053431,90.971694410809846,42.9610953823040305]},"#6644ff":{"lch":[44.4879743720372502,130.630057251556309,269.16406595263021],"luv":[44.4879743720372502,-1.90579898569535566,-130.61615439053088],"rgb":[0.4,0.266666666666666663,1],"xyz":[0.255944778292207409,0.141785936303099935,0.959990711209219305],"hpluv":[269.16406595263021,372.597392941492103,44.4879743720372502],"hsluv":[269.16406595263021,99.9999999999993463,44.4879743720372502]},"#ddcc00":{"lch":[81.0484811072975475,89.5621409057231119,78.2088923998372394],"luv":[81.0484811072975475,18.3014975440108643,87.6723004789036224],"rgb":[0.866666666666666696,0.8,0],"xyz":[0.514100482595981623,0.585588123937282434,0.0859503143074022424],"hpluv":[78.2088923998372394,197.564965691755532,81.0484811072975475],"hsluv":[78.2088923998372394,100.000000000002245,81.0484811072975475]},"#ddcc11":{"lch":[81.070830830397739,88.588371741804238,78.1407504993947413],"luv":[81.070830830397739,18.2056357525625714,86.6974880530521261],"rgb":[0.866666666666666696,0.8,0.0666666666666666657],"xyz":[0.515112148095618783,0.585992790137137343,0.0912784192721578791],"hpluv":[78.1407504993947413,195.686226016320433,81.070830830397739],"hsluv":[78.1407504993947413,98.8754134531589699,81.070830830397739]},"#ddcc22":{"lch":[81.1122340585289265,86.7947856050049751,78.0111959233441894],"luv":[81.1122340585289265,18.0290607078827385,84.9016358983162149],"rgb":[0.866666666666666696,0.8,0.133333333333333331],"xyz":[0.516987506234095728,0.586742933392528143,0.101155305468137072],"hpluv":[78.0111959233441894,192.214732219338657,81.1122340585289265],"hsluv":[78.0111959233441894,96.8049917221618443,81.1122340585289265]},"#ddcc33":{"lch":[81.1803270736657367,83.8738846457710139,77.7882255314295747],"luv":[81.1803270736657367,17.7414783140301893,81.9760237679585089],"rgb":[0.866666666666666696,0.8,0.2],"xyz":[0.520075256966553545,0.58797803368551127,0.117417459325748208],"hpluv":[77.7882255314295747,186.530107062901806,81.1803270736657367],"hsluv":[77.7882255314295747,93.4358723678778631,81.1803270736657367]},"#ddcc44":{"lch":[81.2784695635313312,79.7261575767135469,77.443216014682],"luv":[81.2784695635313312,17.3330313363216426,77.8191893214074213],"rgb":[0.866666666666666696,0.8,0.266666666666666663],"xyz":[0.524533252210772405,0.589761231783198836,0.140896234278634847],"hpluv":[77.443216014682,178.389435414851135,81.2784695635313312],"hsluv":[77.443216014682,88.6570950843060643,81.2784695635313312]},"#ddcc55":{"lch":[81.4094229919429893,74.303525235023784,76.9333685993953509],"luv":[81.4094229919429893,16.7988406729037365,72.37964364652683],"rgb":[0.866666666666666696,0.8,0.333333333333333315],"xyz":[0.530495666250134335,0.592146197398943586,0.172298281552608762],"hpluv":[76.9333685993953509,167.620308244181615,81.4094229919429893],"hsluv":[76.9333685993953509,82.4185745103993668,81.4094229919429893]},"#ddcc66":{"lch":[81.5755062452221154,67.6049359495878406,76.1891492108976252],"luv":[81.5755062452221154,16.1384724175358123,65.6504156329288548],"rgb":[0.866666666666666696,0.8,0.4],"xyz":[0.538080662023642575,0.595180195708346904,0.212245925959752724],"hpluv":[76.1891492108976252,154.10859642349061,81.5755062452221154],"hsluv":[76.1891492108976252,74.724981631947216,81.5755062452221154]},"#ddcc77":{"lch":[81.7786782860545571,59.6741108071854,75.0887439649445554],"luv":[81.7786782860545571,15.3554995822328237,57.6646176889111857],"rgb":[0.866666666666666696,0.8,0.466666666666666674],"xyz":[0.547394675043844425,0.598905800916427755,0.261299727866150633],"hpluv":[75.0887439649445554,137.792143148878608,81.7786782860545571],"hsluv":[75.0887439649445554,65.6305091544174104,81.7786782860545571]},"#ddcc88":{"lch":[82.020587165389415,50.599662209211,73.3985048227604722],"luv":[82.020587165389415,14.4570002873895778,48.4904213054152891],"rgb":[0.866666666666666696,0.8,0.533333333333333326],"xyz":[0.558535092145788337,0.603361967757205298,0.319972591269722773],"hpluv":[73.3985048227604722,118.661765286999071,82.020587165389415],"hsluv":[73.3985048227604722,55.2326761810852389,82.020587165389415]},"#ddcc99":{"lch":[82.3026016456871901,40.5232855707982438,70.6109505258247765],"luv":[82.3026016456871901,13.4529549720920478,38.2250529884698622],"rgb":[0.866666666666666696,0.8,0.6],"xyz":[0.571592056254861,0.608584753400834511,0.388739268910840707],"hpluv":[70.6109505258247765,96.7842051030752231,82.3026016456871901],"hsluv":[70.6109505258247765,43.6647666281718685,82.3026016456871901]},"#ddccaa":{"lch":[82.6258332993788542,29.6818113573176419,65.4008685536862231],"luv":[82.6258332993788542,12.3555588351715961,26.9879619705157374],"rgb":[0.866666666666666696,0.8,0.66666666666666663],"xyz":[0.586649749220113592,0.614607830586935577,0.468043118527839308],"hpluv":[65.4008685536862231,72.4135107626852,82.6258332993788542],"hsluv":[65.4008685536862231,31.0871436920773085,82.6258332993788542]},"#ddccbb":{"lch":[82.9911533066729419,18.6379527757414252,53.1465475992889],"luv":[82.9911533066729419,11.1784915779275345,14.9135713265793797],"rgb":[0.866666666666666696,0.8,0.733333333333333282],"xyz":[0.603787341327450156,0.621462867429870336,0.55830110362648111],"hpluv":[53.1465475992889,46.5946179098545272,82.9911533066729419],"hsluv":[53.1465475992889,24.678645774572626,82.9911533066729419]},"#ddcccc":{"lch":[83.3992063850657,10.164901186858037,12.1770506300648638],"luv":[83.3992063850657,9.93619558955776228,2.14411598208697862],"rgb":[0.866666666666666696,0.8,0.8],"xyz":[0.62307971677117191,0.629179817607359193,0.659907614296751266],"hpluv":[12.1770506300648638,26.1289592314662436,83.3992063850657],"hsluv":[12.1770506300648638,25.0002112827592455,83.3992063850657]},"#ddccdd":{"lch":[83.8504233095379163,14.1290270468723165,307.715012949259346],"luv":[83.8504233095379163,8.64321103323171513,-11.1769543403501022],"rgb":[0.866666666666666696,0.8,0.866666666666666696],"xyz":[0.644598042321805509,0.637787147827612699,0.773237462196757264],"hpluv":[307.715012949259346,37.4791950150616557,83.8504233095379163],"hsluv":[307.715012949259346,25.214872966603707,83.8504233095379163]},"#ddccee":{"lch":[84.3450329093034,25.9620569722210597,286.361909425528779],"luv":[84.3450329093034,7.31360586969829818,-24.9106316943502399],"rgb":[0.866666666666666696,0.8,0.933333333333333348],"xyz":[0.668410222587980218,0.647312019934082716,0.898648278265280487],"hpluv":[286.361909425528779,71.3464154396222199,84.3450329093034],"hsluv":[286.361909425528779,60.879598082714125,84.3450329093034]},"#ddccff":{"lch":[84.8830740665913623,39.380529428060008,278.705583312848262],"luv":[84.8830740665913623,5.96052452183370107,-38.926831947371717],"rgb":[0.866666666666666696,0.8,1],"xyz":[0.694581270997811639,0.65778043929801544,1.03648246655706222],"hpluv":[278.705583312848262,112.590543218900592,84.8830740665913623],"hsluv":[278.705583312848262,99.9999999999947704,84.8830740665913623]},"#665500":{"lch":[36.5970311204425656,41.5054710368830655,69.2006364019199651],"luv":[36.5970311204425656,14.7384507745119784,38.800543743107859],"rgb":[0.4,0.333333333333333315,0],"xyz":[0.0872772466047234,0.0932201343710592,0.0133963111976744542],"hpluv":[69.2006364019199651,143.912599562803223,36.5970311204425656],"hsluv":[69.2006364019199651,100.000000000002359,36.5970311204425656]},"#665511":{"lch":[36.673028710438345,38.8606023214232366,68.2658014049057869],"luv":[36.673028710438345,14.3901304021596417,36.0980686435250391],"rgb":[0.4,0.333333333333333315,0.0666666666666666657],"xyz":[0.0882889121043605174,0.0936248005709140463,0.0187244161624300839],"hpluv":[68.2658014049057869,134.462776824764262,36.673028710438345],"hsluv":[68.2658014049057869,93.0449405246809107,36.673028710438345]},"#665522":{"lch":[36.8133307706753357,34.1687527519613923,66.2355675996872719],"luv":[36.8133307706753357,13.769229594380441,31.2715842419585037],"rgb":[0.4,0.333333333333333315,0.133333333333333331],"xyz":[0.0901642702428375464,0.0943749438263048607,0.0286013023584092835],"hpluv":[66.2355675996872719,117.777773408929676,36.8133307706753357],"hsluv":[66.2355675996872719,80.6853283069105629,36.8133307706753357]},"#665533":{"lch":[37.0427251812615097,27.0303271109949854,61.7081001991288645],"luv":[37.0427251812615097,12.8113945713483854,23.8014023297917383],"rgb":[0.4,0.333333333333333315,0.2],"xyz":[0.09325202097529528,0.0956100441192879735,0.0448634562160204267],"hpluv":[61.7081001991288645,92.5950345984193177,37.0427251812615097],"hsluv":[61.7081001991288645,61.7209513910547045,37.0427251812615097]},"#665544":{"lch":[37.3704580906404473,18.1024774089589755,50.3425610862832542],"luv":[37.3704580906404473,11.5529306171195891,13.9366237840407656],"rgb":[0.4,0.333333333333333315,0.266666666666666663],"xyz":[0.0977100162195141536,0.0973932422169755535,0.0683422311689070583],"hpluv":[50.3425610862832542,61.4679768710498351,37.3704580906404473],"hsluv":[50.3425610862832542,37.0117339514184067,37.3704580906404473]},"#665555":{"lch":[37.8025949068387348,10.2943047784276782,12.1770506300631105],"luv":[37.8025949068387348,10.0626876598879917,2.1714115065313786],"rgb":[0.4,0.333333333333333315,0.333333333333333315],"xyz":[0.103672430258876153,0.0997782078327203864,0.0997442784428809737],"hpluv":[12.1770506300631105,34.5553054430909654,37.8025949068387348],"hsluv":[12.1770506300631105,8.09737912949257321,37.8025949068387348]},"#665566":{"lch":[38.3424918197480693,13.7697499972876347,307.715012949250308],"luv":[38.3424918197480693,8.42342892447929,-10.8927434626015351],"rgb":[0.4,0.333333333333333315,0.4],"xyz":[0.111257426032384324,0.102812206142123705,0.139691922850024935],"hpluv":[307.715012949250308,45.570631638882567,38.3424918197480693],"hsluv":[307.715012949250308,15.7660506346962208,38.3424918197480693]},"#665577":{"lch":[38.9911218270375812,25.5692820710091411,285.225395910208761],"luv":[38.9911218270375812,6.71492531026355,-24.671805035392353],"rgb":[0.4,0.333333333333333315,0.466666666666666674],"xyz":[0.120571439052586243,0.106537811350204514,0.188745724756422845],"hpluv":[285.225395910208761,83.2131821356252885,38.9911218270375812],"hsluv":[285.225395910208761,23.5948697041559434,38.9911218270375812]},"#665588":{"lch":[39.7473800461840554,39.003702064123587,277.369365694294345],"luv":[39.7473800461840554,5.00282395952989312,-38.6815269493963],"rgb":[0.4,0.333333333333333315,0.533333333333333326],"xyz":[0.131711856154530071,0.110993978190982112,0.247418588159995],"hpluv":[277.369365694294345,124.519293959659265,39.7473800461840554],"hsluv":[277.369365694294345,31.2388068533835614,39.7473800461840554]},"#665599":{"lch":[40.6084045881889466,52.6763518020623636,273.629018089310307],"luv":[40.6084045881889466,3.33420095564239061,-52.5707251534733189],"rgb":[0.4,0.333333333333333315,0.6],"xyz":[0.144768820263602771,0.11621676383461127,0.316185265801112947],"hpluv":[273.629018089310307,164.603508765513965,40.6084045881889466],"hsluv":[273.629018089310307,39.2894117268144569,40.6084045881889466]},"#6655aa":{"lch":[41.5699140891343575,66.1399121177165,271.505962745252077],"luv":[41.5699140891343575,1.73822184255944534,-66.1170670838121168],"rgb":[0.4,0.333333333333333315,0.66666666666666663],"xyz":[0.159826513228855327,0.122239841020712364,0.395489115418111492],"hpluv":[271.505962745252077,201.894186201954597,41.5699140891343575],"hsluv":[271.505962745252077,49.6682832978127067,41.5699140891343575]},"#6655bb":{"lch":[42.6265484117568647,79.2031960637105499,270.166039680829499],"luv":[42.6265484117568647,0.229525718995523903,-79.2028634876978],"rgb":[0.4,0.333333333333333315,0.733333333333333282],"xyz":[0.176964105336191974,0.129094877863647123,0.485747100516753294],"hpluv":[270.166039680829499,235.777232293519603,42.6265484117568647],"hsluv":[270.166039680829499,59.8653820834470309,42.6265484117568647]},"#6655cc":{"lch":[43.7721949853351333,91.7929775852419,269.258674658723919],"luv":[43.7721949853351333,-1.18763654850412936,-91.7852943199147688],"rgb":[0.4,0.333333333333333315,0.8],"xyz":[0.1962564807799137,0.136811828041135924,0.58735361118702345],"hpluv":[269.258674658723919,266.103421792879146,43.7721949853351333],"hsluv":[269.258674658723919,69.9112236392489734,43.7721949853351333]},"#6655dd":{"lch":[45.0002850881211458,103.899953671233533,268.61259940679895],"luv":[45.0002850881211458,-2.51566121975990953,-103.869494181457682],"rgb":[0.4,0.333333333333333315,0.866666666666666696],"xyz":[0.217774806330547244,0.145419158261389458,0.700683459087029448],"hpluv":[268.61259940679895,292.98097185143456,45.0002850881211458],"hsluv":[268.61259940679895,79.8793625185682714,45.0002850881211458]},"#6655ee":{"lch":[46.3040490971424106,115.549020689755764,268.134901078425969],"luv":[46.3040490971424106,-3.7607010001107648,-115.487805894602445],"rgb":[0.4,0.333333333333333315,0.933333333333333348],"xyz":[0.241586986596722,0.154944030367859503,0.826094275155552671],"hpluv":[268.134901078425969,316.655201018988919,46.3040490971424106],"hsluv":[268.134901078425969,89.8701820385079344,46.3040490971424106]},"#6655ff":{"lch":[47.6767252326213651,126.781348408818275,267.771145841725911],"luv":[47.6767252326213651,-4.93065761335473951,-126.685432942615918],"rgb":[0.4,0.333333333333333315,1],"xyz":[0.267758035006553374,0.165412449731792199,0.963928463447334516],"hpluv":[267.771145841725911,337.433561350206048,47.6767252326213651],"hsluv":[267.771145841725911,99.9999999999992468,47.6767252326213651]},"#dddd00":{"lch":[85.547159878993142,94.3072427966830844,85.8743202181747449],"luv":[85.547159878993142,6.78488618903739749,94.0628585750738466],"rgb":[0.866666666666666696,0.866666666666666696,0],"xyz":[0.556734473143156827,0.670856105031634,0.100161644489793561],"hpluv":[85.8743202181747449,283.614606809988061,85.547159878993142],"hsluv":[85.8743202181747449,100.000000000002203,85.547159878993142]},"#dddd11":{"lch":[85.5675738163798627,93.4011806547303394,85.8743202181746881],"luv":[85.5675738163798627,6.71970001318247423,93.159144368282],"rgb":[0.866666666666666696,0.866666666666666696,0.0666666666666666657],"xyz":[0.557746138642794,0.671260771231488862,0.105489749454549198],"hpluv":[85.8743202181746881,281.335749103468061,85.5675738163798627],"hsluv":[85.8743202181746881,99.0156164862488,85.5675738163798627]},"#dddd22":{"lch":[85.6053941241358558,91.7307060091609401,85.8743202181746739],"luv":[85.6053941241358558,6.59951857201479086,91.4929985275198447],"rgb":[0.866666666666666696,0.866666666666666696,0.133333333333333331],"xyz":[0.559621496781270933,0.672010914486879662,0.11536663565052839],"hpluv":[85.8743202181746739,277.118842420723468,85.6053941241358558],"hsluv":[85.8743202181746739,97.2017654403352083,85.6053941241358558]},"#dddd33":{"lch":[85.667603455332241,89.0058006932873,85.8743202181745602],"luv":[85.667603455332241,6.4034766573555908,88.775154428206335],"rgb":[0.866666666666666696,0.866666666666666696,0.2],"xyz":[0.56270924751372875,0.673246014779862789,0.131628789508139526],"hpluv":[85.8743202181745602,270.196330508983522,85.667603455332241],"hsluv":[85.8743202181745602,94.2458512979473113,85.667603455332241]},"#dddd44":{"lch":[85.7572852094861418,85.1265937151141117,85.8743202181744607],"luv":[85.7572852094861418,6.12438910193468278,84.9059998802570419],"rgb":[0.866666666666666696,0.866666666666666696,0.266666666666666663],"xyz":[0.567167242757947609,0.675029212877550355,0.155107564461026165],"hpluv":[85.8743202181744607,260.24482525674506,85.7572852094861418],"hsluv":[85.8743202181744607,90.0440000232135844,85.7572852094861418]},"#dddd55":{"lch":[85.8769849033878074,80.0369945631262,85.874320218174276],"luv":[85.8769849033878074,5.75822050268421481,79.8295897229865545],"rgb":[0.866666666666666696,0.866666666666666696,0.333333333333333315],"xyz":[0.573129656797309539,0.677414178493295105,0.18650961173500008],"hpluv":[85.874320218174276,247.008869171162701,85.8769849033878074],"hsluv":[85.874320218174276,84.5423921226573327,85.8769849033878074]},"#dddd66":{"lch":[86.0288537292730098,73.7198014533942398,85.8743202181739775],"luv":[86.0288537292730098,5.30373328608645522,73.5287667485177252],"rgb":[0.866666666666666696,0.866666666666666696,0.4],"xyz":[0.58071465257081778,0.680448176802698423,0.226457256142144042],"hpluv":[85.8743202181739775,230.281095596483937,86.0288537292730098],"hsluv":[85.8743202181739775,77.7321300368988,86.0288537292730098]},"#dddd77":{"lch":[86.2147251389940834,66.1931358813644124,85.8743202181736365],"luv":[86.2147251389940834,4.76223119383214133,66.0216054929389315],"rgb":[0.866666666666666696,0.866666666666666696,0.466666666666666674],"xyz":[0.59002866559101963,0.684173782010779274,0.275511058048541924],"hpluv":[85.8743202181736365,209.886373280136951,86.2147251389940834],"hsluv":[85.8743202181736365,69.6453389130317362,86.2147251389940834]},"#dddd88":{"lch":[86.4361603707972,57.5066396271378224,85.8743202181730823],"luv":[86.4361603707972,4.13728567831694072,57.3576190965201391],"rgb":[0.866666666666666696,0.866666666666666696,0.533333333333333326],"xyz":[0.601169082692963541,0.688629948851556817,0.334183921452114119],"hpluv":[85.8743202181730823,185.665493576193455,86.4361603707972],"hsluv":[85.8743202181730823,60.3508056243124429,86.4361603707972]},"#dddd99":{"lch":[86.6944777431662,47.7369558995854888,85.8743202181722154],"luv":[86.6944777431662,3.43441079587341314,47.613252157820078],"rgb":[0.866666666666666696,0.866666666666666696,0.6],"xyz":[0.614226046802036185,0.693852734495186,0.402950599093232054],"hpluv":[85.8743202181722154,157.456397081560084,86.6944777431662],"hsluv":[85.8743202181722154,49.9486591868920939,86.6944777431662]},"#ddddaa":{"lch":[86.990772885999732,36.9824894935128,85.874320218170638],"luv":[86.990772885999732,2.66068622896724838,36.886654469181245],"rgb":[0.866666666666666696,0.866666666666666696,0.66666666666666663],"xyz":[0.629283739767288797,0.699875811681287097,0.482254448710230599],"hpluv":[85.874320218170638,125.071764704863014,86.990772885999732],"hsluv":[85.874320218170638,38.5641267001819443,86.990772885999732]},"#ddddbb":{"lch":[87.3259337660435477,25.3576808227713499,85.8743202181676821],"luv":[87.3259337660435477,1.82434533444747116,25.2919698878957568],"rgb":[0.866666666666666696,0.866666666666666696,0.733333333333333282],"xyz":[0.64642133187462536,0.706730848524221855,0.572512433808872401],"hpluv":[85.8743202181676821,88.2719508819342735,87.3259337660435477],"hsluv":[85.8743202181676821,26.340671416181145,87.3259337660435477]},"#ddddcc":{"lch":[87.7006527393466797,12.9871390430395461,85.8743202181585445],"luv":[87.7006527393466797,0.934353054076054512,12.9534846621895881],"rgb":[0.866666666666666696,0.866666666666666696,0.8],"xyz":[0.665713707318347114,0.714447798701710712,0.674118944479142557],"hpluv":[85.8743202181585445,46.7319159493201113,87.7006527393466797],"hsluv":[85.8743202181585445,13.4329442518860063,87.7006527393466797]},"#dddddd":{"lch":[88.1154369871094,4.67545248961294327e-12,0],"luv":[88.1154369871094,4.4193702762792188e-12,1.52611347670073729e-12],"rgb":[0.866666666666666696,0.866666666666666696,0.866666666666666696],"xyz":[0.687232032868980713,0.723055128921964219,0.787448792379148554],"hpluv":[0,1.74708563976297451e-11,88.1154369871094],"hsluv":[0,1.74437740136320375e-11,88.1154369871094]},"#ddddee":{"lch":[88.5706181797242209,13.4751686036456029,265.874320218195521],"luv":[88.5706181797242209,-0.969464090371862097,-13.4402495614536726],"rgb":[0.866666666666666696,0.866666666666666696,0.933333333333333348],"xyz":[0.711044213135155423,0.732580001028434236,0.912859608447671778],"hpluv":[265.874320218195521,52.5550848411252431,88.5706181797242209],"hsluv":[265.874320218195521,47.1269490590101725,88.5706181797242209]},"#ddddff":{"lch":[89.0663618949558753,27.3146757005029208,265.874320218186369],"luv":[89.0663618949558753,-1.9651403266809826,-27.2438934831293338],"rgb":[0.866666666666666696,0.866666666666666696,1],"xyz":[0.737215261544986844,0.743048420392367,1.05069379673945362],"hpluv":[265.874320218186369,111.815120511018762,89.0663618949558753],"hsluv":[265.874320218186369,99.9999999999922125,89.0663618949558753]},"#666600":{"lch":[41.7321583215394583,46.0055575524193685,85.8743202181747449],"luv":[41.7321583215394583,3.30984623025532709,45.8863404908370924],"rgb":[0.4,0.4,0],"xyz":[0.102305304310569861,0.123276249782752534,0.0184056637662898],"hpluv":[85.8743202181747449,139.887458074797365,41.7321583215394583],"hsluv":[85.8743202181747449,100.000000000002203,41.7321583215394583]},"#666611":{"lch":[41.7952597887023742,43.6298127640598423,85.8743202181746],"luv":[41.7952597887023742,3.13892449057558931,43.5167521176544625],"rgb":[0.4,0.4,0.0666666666666666657],"xyz":[0.103316969810206979,0.123680915982607387,0.0237337687310454348],"hpluv":[85.8743202181746,132.463323325332908,41.7952597887023742],"hsluv":[85.8743202181746,94.6927802880713756,41.7952597887023742]},"#666622":{"lch":[41.9118699845736913,39.3503176022612067,85.874320218174276],"luv":[41.9118699845736913,2.83103840719259514,39.248346677737],"rgb":[0.4,0.4,0.133333333333333331],"xyz":[0.105192327948684008,0.124431059237998201,0.0336106549270246274],"hpluv":[85.874320218174276,119.138061739500813,41.9118699845736913],"hsluv":[85.874320218174276,85.1670788640685288,41.9118699845736913]},"#666633":{"lch":[42.1028501842444953,32.6344620115447057,85.8743202181736507],"luv":[42.1028501842444953,2.34786962297492563,32.5498943011565842],"rgb":[0.4,0.4,0.2],"xyz":[0.108280078681141742,0.125666159530981314,0.0498728087846357776],"hpluv":[85.8743202181736507,98.3567766096709306,42.1028501842444953],"hsluv":[85.8743202181736507,70.3113616926845,42.1028501842444953]},"#666644":{"lch":[42.3763861696741557,23.5947988734222314,85.8743202181723575],"luv":[42.3763861696741557,1.69751569722617934,23.5336562041455402],"rgb":[0.4,0.4,0.266666666666666663],"xyz":[0.112738073925360616,0.127449357628668908,0.0733515837375224161],"hpluv":[85.8743202181723575,70.6531759312171346,42.3763861696741557],"hsluv":[85.8743202181723575,50.5071554688203506,42.3763861696741557]},"#666655":{"lch":[42.7382714661199543,12.562340839470254,85.87432021816781],"luv":[42.7382714661199543,0.903791165304248856,12.5297872646162745],"rgb":[0.4,0.4,0.333333333333333315],"xyz":[0.118700487964722615,0.129834323244413741,0.104753631011496318],"hpluv":[85.87432021816781,37.2986356199978459,42.7382714661199543],"hsluv":[85.87432021816781,26.6633164497530721,42.7382714661199543]},"#666666":{"lch":[43.1922895629847048,2.27708065554704512e-12,0],"luv":[43.1922895629847048,2.15069538500574498e-12,7.48067960001998255e-13],"rgb":[0.4,0.4,0.4],"xyz":[0.126285483738230786,0.132868321553817031,0.144701275418640279],"hpluv":[0,6.68977504875838914e-12,43.1922895629847048],"hsluv":[0,1.91542116883063395e-12,43.1922895629847048]},"#666677":{"lch":[43.7404449074606489,13.5883126365404472,265.874320218186085],"luv":[43.7404449074606489,-0.977604179760566572,-13.5531003971814314],"rgb":[0.4,0.4,0.466666666666666674],"xyz":[0.135599496758432692,0.136593926761897855,0.193755077325038189],"hpluv":[265.874320218186085,39.4204575510779804,43.7404449074606489],"hsluv":[265.874320218186085,10.3527957183817456,43.7404449074606489]},"#666688":{"lch":[44.3831523723879684,27.7327571842679852,265.874320218181708],"luv":[44.3831523723879684,-1.9952189844931838,-27.660891566352042],"rgb":[0.4,0.4,0.533333333333333326],"xyz":[0.146739913860376547,0.141050093602675453,0.252427940728610356],"hpluv":[265.874320218181708,79.2892354857961692,44.3831523723879684],"hsluv":[265.874320218181708,21.2254167484079588,44.3831523723879684]},"#666699":{"lch":[45.1194249231942308,42.0446421145154,265.87432021818023],"luv":[45.1194249231942308,-3.02488020162380478,-41.9356892193690598],"rgb":[0.4,0.4,0.6],"xyz":[0.159796877969449247,0.14627287924630461,0.321194618369728291],"hpluv":[265.87432021818023,118.245992523098394,45.1194249231942308],"hsluv":[265.87432021818023,32.3647541960069702,45.1194249231942308]},"#6666aa":{"lch":[45.9470714788517682,56.2348015337582652,265.874320218179548],"luv":[45.9470714788517682,-4.04578393932889835,-56.0890767962662125],"rgb":[0.4,0.4,0.66666666666666663],"xyz":[0.174854570934701803,0.152295956432405705,0.400498467986726892],"hpluv":[265.874320218179548,155.305436018888514,45.9470714788517682],"hsluv":[265.874320218179548,43.5990379455573205,45.9470714788517682]},"#6666bb":{"lch":[46.8629040956598786,70.1103551977131,265.874320218179093],"luv":[46.8629040956598786,-5.04405352741049562,-69.9286738753289541],"rgb":[0.4,0.4,0.733333333333333282],"xyz":[0.191992163042038422,0.159150993275340463,0.490756453085368638],"hpluv":[265.874320218179093,189.841997809706953,46.8629040956598786],"hsluv":[265.874320218179093,54.8353857399755285,46.8629040956598786]},"#6666cc":{"lch":[47.8629477245616854,83.5592716582008,265.874320218178866],"luv":[47.8629477245616854,-6.01162892081844,-83.3427393224351505],"rgb":[0.4,0.4,0.8],"xyz":[0.211284538485760176,0.166867943452829265,0.592362963755638794],"hpluv":[265.874320218178866,221.531011478982748,47.8629477245616854],"hsluv":[265.874320218178866,66.0482344892977693,47.8629477245616854]},"#6666dd":{"lch":[48.9426439028117102,96.5306872715973583,265.874320218178696],"luv":[48.9426439028117102,-6.94485076081307,-96.2805413000828736],"rgb":[0.4,0.4,0.866666666666666696],"xyz":[0.23280286403639372,0.175475273673082799,0.705692811655644792],"hpluv":[265.874320218178696,250.274901054084751,48.9426439028117102],"hsluv":[265.874320218178696,77.2646968282616911,48.9426439028117102]},"#6666ee":{"lch":[50.0970402589656203,109.016062738443594,265.874320218178525],"luv":[50.0970402589656203,-7.84310469187671711,-108.73356263723052],"rgb":[0.4,0.4,0.933333333333333348],"xyz":[0.256615044302568429,0.185000145779552844,0.831103627724168],"hpluv":[265.874320218178525,276.132643737939816,50.0970402589656203],"hsluv":[265.874320218178525,88.5507283896609181,50.0970402589656203]},"#6666ff":{"lch":[51.3209595583197142,121.033610519319112,265.874320218178411],"luv":[51.3209595583197142,-8.70770100014002502,-120.719968599376287],"rgb":[0.4,0.4,1],"xyz":[0.28278609271239985,0.19546856514348554,0.96893781601594986],"hpluv":[265.874320218178411,299.261292593223402,51.3209595583197142],"hsluv":[265.874320218178411,99.9999999999991616,51.3209595583197142]},"#ddee00":{"lch":[90.1008574130140261,100.518542770188731,92.3281002120423295],"luv":[90.1008574130140261,-4.08324753875312307,100.435574027231638],"rgb":[0.866666666666666696,0.933333333333333348,0],"xyz":[0.603913249483671644,0.765213657712664919,0.115887903269964759],"hpluv":[92.3281002120423295,458.324419080212692,90.1008574130140261],"hsluv":[92.3281002120423295,100.000000000002288,90.1008574130140261]},"#ddee11":{"lch":[90.1195571422023676,99.6821059706602739,92.3717344777628284],"luv":[90.1195571422023676,-4.12512016496088219,99.5967149778072667],"rgb":[0.866666666666666696,0.933333333333333348,0.0666666666666666657],"xyz":[0.604924914983308804,0.765618323912519827,0.121216008234720396],"hpluv":[92.3717344777628284,455.439701471196656,90.1195571422023676],"hsluv":[92.3717344777628284,99.1349582088955827,90.1195571422023676]},"#ddee22":{"lch":[90.1542040339558213,98.139145338163118,92.4541942657322409],"luv":[90.1542040339558213,-4.20238430415396635,98.0491295925940562],"rgb":[0.866666666666666696,0.933333333333333348,0.133333333333333331],"xyz":[0.606800273121785749,0.766368467167910628,0.131092894430699575],"hpluv":[92.4541942657322409,450.094002053356689,90.1542040339558213],"hsluv":[92.4541942657322409,97.539848527320828,90.1542040339558213]},"#ddee33":{"lch":[90.2112004280082402,95.6198982889531237,92.5945991605726562],"luv":[90.2112004280082402,-4.32860020636881337,95.5218727257959728],"rgb":[0.866666666666666696,0.933333333333333348,0.2],"xyz":[0.609888023854243566,0.767603567460893754,0.147355048288310725],"hpluv":[92.5945991605726562,441.296742170845221,90.2112004280082402],"hsluv":[92.5945991605726562,94.9371734060285348,90.2112004280082402]},"#ddee44":{"lch":[90.2933822328294582,92.028546743238266,92.808164678773025],"luv":[90.2933822328294582,-4.50867173729536486,91.9180357429253689],"rgb":[0.866666666666666696,0.933333333333333348,0.266666666666666663],"xyz":[0.614346019098462426,0.76938676555858132,0.170833823241197363],"hpluv":[92.808164678773025,428.602609406071736,90.2933822328294582],"hsluv":[92.808164678773025,91.2305485856041827,90.2933822328294582]},"#ddee55":{"lch":[90.4030992965535,87.3081168904988658,93.1158428735316477],"luv":[90.4030992965535,-4.74562541158387852,87.1790474507375137],"rgb":[0.866666666666666696,0.933333333333333348,0.333333333333333315],"xyz":[0.620308433137824355,0.77177173117432607,0.202235870515171279],"hpluv":[93.1158428735316477,411.63119840797242,90.4030992965535],"hsluv":[93.1158428735316477,86.365058197250562,90.4030992965535]},"#ddee66":{"lch":[90.5423480313319828,81.4363754503924,93.5488244177654451],"luv":[90.5423480313319828,-5.04083628618753,81.2802141731499717],"rgb":[0.866666666666666696,0.933333333333333348,0.4],"xyz":[0.627893428911332596,0.774805729483729388,0.242183514922315241],"hpluv":[93.5488244177654451,390.03815237863023,90.5423480313319828],"hsluv":[93.5488244177654451,80.3228278296054583,90.5423480313319828]},"#ddee77":{"lch":[90.7128424721769449,74.4235139877598613,94.1564113073248],"luv":[90.7128424721769449,-5.39417557361030209,74.2277731322134855],"rgb":[0.866666666666666696,0.933333333333333348,0.466666666666666674],"xyz":[0.637207441931534446,0.77853133469181024,0.291237316828713122],"hpluv":[94.1564113073248,363.492124647987794,90.7128424721769449],"hsluv":[94.1564113073248,73.1200108954656116,90.7128424721769449]},"#ddee88":{"lch":[90.9160566530372449,66.3104835404903099,95.0215233218939801],"luv":[90.9160566530372449,-5.80415396856009735,66.0559764448523197],"rgb":[0.866666666666666696,0.933333333333333348,0.533333333333333326],"xyz":[0.648347859033478358,0.782987501532587782,0.349910180232285317],"hpluv":[95.0215233218939801,331.65301907995223,90.9160566530372449],"hsluv":[95.0215233218939801,64.803658473982523,90.9160566530372449]},"#ddee99":{"lch":[91.1532518637430798,57.1683554138076389,96.2947128608995513],"luv":[91.1532518637430798,-6.26808654843775237,56.8236918172404799],"rgb":[0.866666666666666696,0.933333333333333348,0.6],"xyz":[0.661404823142551,0.788210287176217,0.418676857873403252],"hpluv":[96.2947128608995513,294.152965661212647,91.1532518637430798],"hsluv":[96.2947128608995513,55.4479539090275679,91.1532518637430798]},"#ddeeaa":{"lch":[91.4254953447680805,47.1012792006961263,98.2790075719046712],"luv":[91.4254953447680805,-6.78228473243696595,46.6104185365255219],"rgb":[0.866666666666666696,0.933333333333333348,0.66666666666666663],"xyz":[0.676462516107803613,0.794233364362318062,0.497980707490401797],"hpluv":[98.2790075719046712,250.593114601078071,91.4254953447680805],"hsluv":[98.2790075719046712,45.1497304611624699,91.4254953447680805]},"#ddeebb":{"lch":[91.7336739482950634,36.2629153409390739,101.681625346389353],"luv":[91.7336739482950634,-7.34227032126066,35.5118303605101318],"rgb":[0.866666666666666696,0.933333333333333348,0.733333333333333282],"xyz":[0.693600108215140176,0.80108840120525282,0.588238692589043599],"hpluv":[101.681625346389353,200.613962446551909,91.7336739482950634],"hsluv":[101.681625346389353,34.0234190840686495,91.7336739482950634]},"#ddeecc":{"lch":[92.0785048140775189,24.9340669502590622,108.575873850927678],"luv":[92.0785048140775189,-7.94300120518182506,23.6350677285782567],"rgb":[0.866666666666666696,0.933333333333333348,0.8],"xyz":[0.712892483658861931,0.808805351382741677,0.689845203259313755],"hpluv":[108.575873850927678,144.339382081965653,92.0785048140775189],"hsluv":[108.575873850927678,22.1956929245148693,92.0785048140775189]},"#ddeedd":{"lch":[92.4605443140240908,14.0242187757329084,127.71501294922345],"luv":[92.4605443140240908,-8.57909621466854766,11.0940443666446207],"rgb":[0.866666666666666696,0.933333333333333348,0.866666666666666696],"xyz":[0.73441080920949553,0.817412681602995184,0.803175051159319753],"hpluv":[127.71501294922345,85.5555802205660854,92.4605443140240908],"hsluv":[127.71501294922345,19.0167034911391681,92.4605443140240908]},"#ddeeee":{"lch":[92.8801960589335636,9.45784403502816851,192.177050630058346],"luv":[92.8801960589335636,-9.24504689815110403,-1.99497409554724747],"rgb":[0.866666666666666696,0.933333333333333348,0.933333333333333348],"xyz":[0.758222989475670239,0.826937553709465201,0.928585867227843],"hpluv":[192.177050630058346,61.3009405779386327,92.8801960589335636],"hsluv":[192.177050630058346,16.5065503962475049,92.8801960589335636]},"#ddeeff":{"lch":[93.3377184761608305,18.4254994321377019,237.36941304521946],"luv":[93.3377184761608305,-9.93540601395951306,-15.5173044263971267],"rgb":[0.866666666666666696,0.933333333333333348,1],"xyz":[0.78439403788550166,0.837405973073397925,1.06642005551962482],"hpluv":[237.36941304521946,128.083838047846456,93.3377184761608305],"hsluv":[237.36941304521946,99.9999999999860592,93.3377184761608305]},"#667700":{"lch":[46.9985837429297462,53.5023535392226,97.7743932102929705],"luv":[46.9985837429297462,-7.23741162388150272,53.0105810873873509],"rgb":[0.4,0.466666666666666674,0],"xyz":[0.12075904236398749,0.160183725889588319,0.0245569097840955056],"hpluv":[97.7743932102929705,144.453291553004675,46.9985837429297462],"hsluv":[97.7743932102929705,100.000000000002416,46.9985837429297462]},"#667711":{"lch":[47.0515894602548315,51.4525286527524344,98.1592061252685681],"luv":[47.0515894602548315,-7.3023584206057679,50.9317019768564],"rgb":[0.4,0.466666666666666674,0.0666666666666666657],"xyz":[0.121770707863624608,0.160588392089443172,0.0298850147488511353],"hpluv":[98.1592061252685681,138.762383385982389,47.0515894602548315],"hsluv":[98.1592061252685681,95.8888552433840573,47.0515894602548315]},"#667722":{"lch":[47.1496128779850068,47.7434140964333835,98.9413563019921],"luv":[47.1496128779850068,-7.4204465613794337,47.1632331632727],"rgb":[0.4,0.466666666666666674,0.133333333333333331],"xyz":[0.123646066002101637,0.161338535344834,0.0397619009448303348],"hpluv":[98.9413563019921,128.491579290861381,47.1496128779850068],"hsluv":[98.9413563019921,88.4562635009272071,47.1496128779850068]},"#667733":{"lch":[47.3103471969426579,41.884713336750373,100.466311561708949],"luv":[47.3103471969426579,-7.6086666810921777,41.1878307590699961],"rgb":[0.4,0.466666666666666674,0.2],"xyz":[0.126733816734559357,0.162573635637817099,0.0560240548024414781],"hpluv":[100.466311561708949,112.341117260385403,47.3103471969426579],"hsluv":[100.466311561708949,76.7252257071794,47.3103471969426579]},"#667744":{"lch":[47.5409803755201068,33.9506682862991624,103.399633201782777],"luv":[47.5409803755201068,-7.86778476785512915,33.0264415269496823],"rgb":[0.4,0.466666666666666674,0.266666666666666663],"xyz":[0.131191811978778244,0.164356833735504693,0.0795028297553281166],"hpluv":[103.399633201782777,90.6190532449782324,47.5409803755201068],"hsluv":[103.399633201782777,60.8161329795325543,47.5409803755201068]},"#667755":{"lch":[47.8468512336942808,24.3055974565694441,109.700167733355244],"luv":[47.8468512336942808,-8.19336864569332768,22.8829800934354815],"rgb":[0.4,0.466666666666666674,0.333333333333333315],"xyz":[0.137154226018140257,0.166741799351249526,0.110904877029302018],"hpluv":[109.700167733355244,64.4602914823941262,47.8468512336942808],"hsluv":[109.700167733355244,41.23982633361328,47.8468512336942808]},"#667766":{"lch":[48.2317738399223543,14.0211946941261125,127.715012949232488],"luv":[48.2317738399223543,-8.57724628010491408,11.0916521267580634],"rgb":[0.4,0.466666666666666674,0.4],"xyz":[0.144739221791648415,0.169775797660652816,0.15085252143644598],"hpluv":[127.715012949232488,36.8885098590324958,48.2317738399223543],"hsluv":[127.715012949232488,18.7828263722028552,48.2317738399223543]},"#667777":{"lch":[48.6982180758881356,9.21652694043341,192.177050630059739],"luv":[48.6982180758881356,-9.00915932709454736,-1.94407228846053126],"rgb":[0.4,0.466666666666666674,0.466666666666666674],"xyz":[0.154053234811850348,0.17350140286873364,0.199906323342843889],"hpluv":[192.177050630059739,24.0156061835451808,48.6982180758881356],"hsluv":[192.177050630059739,23.9216020554503501,48.6982180758881356]},"#667788":{"lch":[49.2474401880289605,18.4334880243097601,239.056580638027469],"luv":[49.2474401880289605,-9.47834019220879398,-15.8099509152663327],"rgb":[0.4,0.466666666666666674,0.533333333333333326],"xyz":[0.165193651913794148,0.177957569709511237,0.258579186746416056],"hpluv":[239.056580638027469,47.4966726259429564,49.2474401880289605],"hsluv":[239.056580638027469,29.274081353383373,49.2474401880289605]},"#667799":{"lch":[49.8796002039077422,31.7351192214463786,251.680675473596239],"luv":[49.8796002039077422,-9.97474964621831,-30.126768188683684],"rgb":[0.4,0.466666666666666674,0.6],"xyz":[0.178250616022866876,0.183180355353140395,0.327345864387534],"hpluv":[251.680675473596239,80.734004933806176,49.8796002039077422],"hsluv":[251.680675473596239,34.661761655835349,49.8796002039077422]},"#6677aa":{"lch":[50.5938810850088174,45.7960576637453798,256.758518919433186],"luv":[50.5938810850088174,-10.4898463625666416,-44.5784928057335676],"rgb":[0.4,0.466666666666666674,0.66666666666666663],"xyz":[0.193308308988119404,0.18920343253924149,0.406649714004532592],"hpluv":[256.758518919433186,114.860161977636537,50.5938810850088174],"hsluv":[256.758518919433186,39.9381656359214858,50.5938810850088174]},"#6677bb":{"lch":[51.388614147457119,59.9444468574027738,259.409682348511467],"luv":[51.388614147457119,-11.0169047239158306,-58.9233783768730106],"rgb":[0.4,0.466666666666666674,0.733333333333333282],"xyz":[0.210445901095456078,0.196058469382176248,0.496907699103174338],"hpluv":[259.409682348511467,148.020333314730891,51.388614147457119],"hsluv":[259.409682348511467,49.2101017344363356,51.388614147457119]},"#6677cc":{"lch":[52.2614099661724225,73.9004259234932306,261.00752312302825],"luv":[52.2614099661724225,-11.5509895931656974,-72.9921063615257566],"rgb":[0.4,0.466666666666666674,0.8],"xyz":[0.229738276539177805,0.20377541955966505,0.598514209773444494],"hpluv":[261.00752312302825,179.434168102703751,52.2614099661724225],"hsluv":[261.00752312302825,61.6581230008595327,52.2614099661724225]},"#6677dd":{"lch":[53.2092913421323,87.5170631601914266,262.060353074135],"luv":[53.2092913421323,-12.0887245225321198,-86.6781349799548],"rgb":[0.4,0.466666666666666674,0.866666666666666696],"xyz":[0.251256602089811376,0.212382749779918584,0.711844057673450492],"hpluv":[262.060353074135,208.710638687620559,53.2092913421323],"hsluv":[262.060353074135,74.2459971892304083,53.2092913421323]},"#6677ee":{"lch":[54.2288239257805884,100.719531231348427,262.797438231409785],"luv":[54.2288239257805884,-12.6279723106459851,-99.9247631309883531],"rgb":[0.4,0.466666666666666674,0.933333333333333348],"xyz":[0.275068782355986086,0.221907621886388629,0.837254873741973715],"hpluv":[262.797438231409785,235.68005803746027,54.2288239257805884],"hsluv":[262.797438231409785,87.0042080584200193,54.2288239257805884]},"#6677ff":{"lch":[55.3162401631211793,113.47857319487936,263.336661992011841],"luv":[55.3162401631211793,-13.1675101506557386,-112.712036849566218],"rgb":[0.4,0.466666666666666674,1],"xyz":[0.301239830765817507,0.232376041250321325,0.97508906203375556],"hpluv":[263.336661992011841,260.315806593762318,55.3162401631211793],"hsluv":[263.336661992011841,99.999999999999,55.3162401631211793]},"#ddff00":{"lch":[94.69236188875891,107.73563953931891,97.6513944636985],"luv":[94.69236188875891,-14.3445112693176284,106.77641604488548],"rgb":[0.866666666666666696,1,0],"xyz":[0.65576562191334542,0.868918402572014,0.13317202741318887],"hpluv":[97.6513944636985,949.977135711580445,94.69236188875891],"hsluv":[97.6513944636985,100.000000000002302,94.69236188875891]},"#ddff11":{"lch":[94.7095428290633237,106.965998536257018,97.7198690947758308],"luv":[94.7095428290633237,-14.3687245726656343,105.996531061225838],"rgb":[0.866666666666666696,1,0.0666666666666666657],"xyz":[0.65677728741298258,0.869323068771868934,0.138500132377944507],"hpluv":[97.7198690947758308,946.378692368412885,94.7095428290633237],"hsluv":[97.7198690947758308,99.9999999999867697,94.7095428290633237]},"#ddff22":{"lch":[94.7413776147606086,105.545731309599958,97.8489007917202827],"luv":[94.7413776147606086,-14.4134418215914106,104.556941866783148],"rgb":[0.866666666666666696,1,0.133333333333333331],"xyz":[0.658652645551459526,0.870073212027259735,0.148377018573923686],"hpluv":[97.8489007917202827,939.695870823628752,94.7413776147606086],"hsluv":[97.8489007917202827,99.9999999999872,94.7413776147606086]},"#ddff33":{"lch":[94.7937532988665197,103.225383790498825,98.0674915546983],"luv":[94.7937532988665197,-14.4865977424562669,102.203807876928138],"rgb":[0.866666666666666696,1,0.2],"xyz":[0.661740396283917343,0.871308312320242861,0.164639172431534836],"hpluv":[98.0674915546983,928.656435156239354,94.7937532988665197],"hsluv":[98.0674915546983,99.9999999999868834,94.7937532988665197]},"#ddff44":{"lch":[94.8692843830354491,99.9146373114600692,98.397314807396512],"luv":[94.8692843830354491,-14.5912004882884094,98.8434702820129729],"rgb":[0.866666666666666696,1,0.266666666666666663],"xyz":[0.666198391528136202,0.873091510417930428,0.188117947384421474],"hpluv":[98.397314807396512,912.633071017653265,94.8692843830354491],"hsluv":[98.397314807396512,99.9999999999866276,94.8692843830354491]},"#ddff55":{"lch":[94.9701440016210654,95.558111661139634,98.8668834316730738],"luv":[94.9701440016210654,-14.7292629682473848,94.4161083536863828],"rgb":[0.866666666666666696,1,0.333333333333333315],"xyz":[0.672160805567498132,0.875476476033675177,0.21951999465839539],"hpluv":[98.8668834316730738,891.031026100052486,94.9701440016210654],"hsluv":[98.8668834316730738,99.9999999999861586,94.9701440016210654]},"#ddff66":{"lch":[95.0981866754888,90.1320341607989235,99.5166683548804798],"luv":[95.0981866754888,-14.9019372161492765,88.8915960547979438],"rgb":[0.866666666666666696,1,0.4],"xyz":[0.679745801341006373,0.878510474343078496,0.259467639065539379],"hpluv":[99.5166683548804798,863.234823568518,95.0981866754888],"hsluv":[99.5166683548804798,99.9999999999856186,95.0981866754888]},"#ddff77":{"lch":[95.2550143462764396,83.6430269583913599,100.407261812829162],"luv":[95.2550143462764396,-15.1095945804084604,82.2669806810598487],"rgb":[0.866666666666666696,1,0.466666666666666674],"xyz":[0.689059814361208223,0.882236079551159347,0.308521440971937233],"hpluv":[100.407261812829162,828.556184265804632,95.2550143462764396],"hsluv":[100.407261812829162,99.9999999999855476,95.2550143462764396]},"#ddff88":{"lch":[95.4420158908659175,76.1281736437493,101.633961649281417],"luv":[95.4420158908659175,-15.3518949618923237,74.5641880758576434],"rgb":[0.866666666666666696,1,0.533333333333333326],"xyz":[0.700200231463152134,0.886692246391936889,0.367194304375509428],"hpluv":[101.633961649281417,786.17501332264635,95.4420158908659175],"hsluv":[101.633961649281417,99.9999999999848512,95.4420158908659175]},"#ddff99":{"lch":[95.6603925662724208,67.6570848719276086,103.355147801887099],"luv":[95.6603925662724208,-15.6278614338241617,65.8274341013866859],"rgb":[0.866666666666666696,1,0.6],"xyz":[0.713257195572224778,0.891915032035566102,0.435960982016627363],"hpluv":[103.355147801887099,735.074270676232231,95.6603925662724208],"hsluv":[103.355147801887099,99.9999999999844107,95.6603925662724208]},"#ddffaa":{"lch":[95.9111754000973775,58.338925144698,105.852499131344544],"luv":[95.9111754000973775,-15.935965587620279,56.1201852084333268],"rgb":[0.866666666666666696,1,0.66666666666666663],"xyz":[0.72831488853747739,0.897938109221667169,0.515264831633625908],"hpluv":[105.852499131344544,673.992295850936557,95.9111754000973775],"hsluv":[105.852499131344544,99.9999999999831886,95.9111754000973775]},"#ddffbb":{"lch":[96.1952377631310185,48.3433070572267596,109.672211431084662],"luv":[96.1952377631310185,-16.2742233848326485,45.5216980180866813],"rgb":[0.866666666666666696,1,0.733333333333333282],"xyz":[0.745452480644814,0.904793146064601927,0.60552281673226771],"hpluv":[109.672211431084662,601.502194015230771,96.1952377631310185],"hsluv":[109.672211431084662,99.9999999999821654,96.1952377631310185]},"#ddffcc":{"lch":[96.513305005727517,37.9644197829535202,115.996292551248089],"luv":[96.513305005727517,-16.6402982513575566,34.1232712904577653],"rgb":[0.866666666666666696,1,0.8],"xyz":[0.764744856088535707,0.912510096242090785,0.707129327402537866],"hpluv":[115.996292551248089,516.693096965009204,96.513305005727517],"hsluv":[115.996292551248089,99.9999999999804885,96.513305005727517]},"#ddffdd":{"lch":[96.8659623148576,27.841508205801528,127.715012949232161],"luv":[96.8659623148576,-17.0316066426751398,22.0243945284064],"rgb":[0.866666666666666696,1,0.866666666666666696],"xyz":[0.786263181639169306,0.921117426462344291,0.820459175302543864],"hpluv":[127.715012949232161,422.676993554754517,96.8659623148576],"hsluv":[127.715012949232161,99.9999999999786411,96.8659623148576]},"#ddffee":{"lch":[97.2536615310726802,19.7831433293950418,151.864226334417424],"luv":[97.2536615310726802,-17.4454209009420502,9.32898974060759478],"rgb":[0.866666666666666696,1,0.933333333333333348],"xyz":[0.810075361905344,0.930642298568814308,0.945869991371067087],"hpluv":[151.864226334417424,343.73229759561508,97.2536615310726802],"hsluv":[151.864226334417424,99.9999999999752,97.2536615310726802]},"#ddffff":{"lch":[97.6767274082888406,18.2904922799610645,192.177050630059568],"luv":[97.6767274082888406,-17.878964623675607,-3.85807359036494368],"rgb":[0.866666666666666696,1,1],"xyz":[0.836246410315175437,0.941110717932747,1.08370417966284882],"hpluv":[192.177050630059568,376.852754928906336,97.6767274082888406],"hsluv":[192.177050630059568,99.9999999999715072,97.6767274082888406]},"#668800":{"lch":[52.32310792684153,62.4331707825390509,105.73052795354684],"luv":[52.32310792684153,-16.9264656143939405,60.0948881001240167],"rgb":[0.4,0.533333333333333326,0],"xyz":[0.142831412088957943,0.204328465339529863,0.0319143663590854554],"hpluv":[105.73052795354684,151.412310196323318,52.32310792684153],"hsluv":[105.73052795354684,100.000000000002359,52.32310792684153]},"#668811":{"lch":[52.3681821172622222,60.6739112189649603,106.201766876928076],"luv":[52.3681821172622222,-16.9292783492562116,58.26425179456308],"rgb":[0.4,0.533333333333333326,0.0666666666666666657],"xyz":[0.143843077588595075,0.204733131539384716,0.0372424713238410851],"hpluv":[106.201766876928076,147.019120365759306,52.3681821172622222],"hsluv":[106.201766876928076,96.7617570127925859,52.3681821172622222]},"#668822":{"lch":[52.4515808002199,57.4815115963739842,107.134347730867304],"luv":[52.4515808002199,-16.9348150675510247,54.9302850350507796],"rgb":[0.4,0.533333333333333326,0.133333333333333331],"xyz":[0.145718435727072076,0.205483274794775544,0.0471193575198202846],"hpluv":[107.134347730867304,139.062145386582984,52.4515808002199],"hsluv":[107.134347730867304,90.8761910280814647,52.4515808002199]},"#668833":{"lch":[52.5884544541714121,52.4173031151438593,108.860637572968898],"luv":[52.5884544541714121,-16.9448041098426323,49.6028958786070291],"rgb":[0.4,0.533333333333333326,0.2],"xyz":[0.14880618645952981,0.206718375087758643,0.0633815113774314209],"hpluv":[108.860637572968898,126.480505252334424,52.5884544541714121],"hsluv":[108.860637572968898,81.504484256448066,52.5884544541714121]},"#668844":{"lch":[52.7851097594501937,45.5231929703366234,111.874794573011059],"luv":[52.7851097594501937,-16.9610118856818559,42.2455343678863215],"rgb":[0.4,0.533333333333333326,0.266666666666666663],"xyz":[0.153264181703748698,0.208501573185446237,0.0868602863303180595],"hpluv":[111.874794573011059,109.436101408621766,52.7851097594501937],"hsluv":[111.874794573011059,68.6312430201703734,52.7851097594501937]},"#668855":{"lch":[53.0463844713544859,37.0894540992544819,117.255878513522262],"luv":[53.0463844713544859,-16.9856764955971045,32.9714179156375593],"rgb":[0.4,0.533333333333333326,0.333333333333333315],"xyz":[0.15922659574311071,0.21088653880119107,0.118262333604291975],"hpluv":[117.255878513522262,88.7225425584692715,53.0463844713544859],"hsluv":[117.255878513522262,52.5261258187504225,53.0463844713544859]},"#668866":{"lch":[53.3759296841588906,27.8248149657310222,127.715012949236794],"luv":[53.3759296841588906,-17.0213948144824521,22.0111891193247189],"rgb":[0.4,0.533333333333333326,0.4],"xyz":[0.166811591516618868,0.213920537110594361,0.158209978011435937],"hpluv":[127.715012949236794,66.1494380276081415,53.3759296841588906],"hsluv":[127.715012949236794,33.681854155652033,53.3759296841588906]},"#668877":{"lch":[53.7763606180623839,19.6211535767711887,150.461713858693599],"luv":[53.7763606180623839,-17.0709226847205855,9.67332757511772101],"rgb":[0.4,0.533333333333333326,0.466666666666666674],"xyz":[0.176125604536820801,0.217646142318675184,0.207263779917833846],"hpluv":[150.461713858693599,46.2990901048939207,53.7763606180623839],"hsluv":[150.461713858693599,37.1484166060608132,53.7763606180623839]},"#668888":{"lch":[54.2493559855519436,17.5313913512660982,192.17705063006045],"luv":[54.2493559855519436,-17.1369431164247104,-3.69795393909545],"rgb":[0.4,0.533333333333333326,0.533333333333333326],"xyz":[0.187266021638764601,0.222102309159452782,0.265936643321406],"hpluv":[192.17705063006045,41.0072951616226788,54.2493559855519436],"hsluv":[192.17705063006045,40.8467805779917228,54.2493559855519436]},"#668899":{"lch":[54.7957384612029728,24.7393499057112685,225.882505108050964],"luv":[54.7957384612029728,-17.2218541013304964,-17.7607200042594577],"rgb":[0.4,0.533333333333333326,0.6],"xyz":[0.200322985747837329,0.22732509480308194,0.33470332096252392],"hpluv":[225.882505108050964,57.2902642666713859,54.7957384612029728],"hsluv":[225.882505108050964,44.6631352998217963,54.7957384612029728]},"#6688aa":{"lch":[55.4155508256813363,36.5699037808867828,241.717344836465486],"luv":[55.4155508256813363,-17.3276119763631087,-32.2042190673817643],"rgb":[0.4,0.533333333333333326,0.66666666666666663],"xyz":[0.215380678713089857,0.233348171989183034,0.414007170579522521],"hpluv":[241.717344836465486,83.7397171719788389,55.4155508256813363],"hsluv":[241.717344836465486,48.4952118884804193,55.4155508256813363]},"#6688bb":{"lch":[56.1081340603271457,49.918102431374308,249.531909378681803],"luv":[56.1081340603271457,-17.4556451944419777,-46.7666270025424495],"rgb":[0.4,0.533333333333333326,0.733333333333333282],"xyz":[0.232518270820426531,0.240203208832117793,0.504265155678164323],"hpluv":[249.531909378681803,112.8941838879785,56.1081340603271457],"hsluv":[249.531909378681803,52.2580147864780216,56.1081340603271457]},"#6688cc":{"lch":[56.8722093096567107,63.7230017864969795,253.960340799970709],"luv":[56.8722093096567107,-17.6068348542363715,-61.2423082770199372],"rgb":[0.4,0.533333333333333326,0.8],"xyz":[0.251810646264148286,0.247920159009606594,0.605871666348434479],"hpluv":[253.960340799970709,142.178999158492672,56.8722093096567107],"hsluv":[253.960340799970709,56.6402695601832349,56.8722093096567107]},"#6688dd":{"lch":[57.7059632125805564,77.5471512008463719,256.744147904563079],"luv":[57.7059632125805564,-17.7815469636593271,-75.4809727477468755],"rgb":[0.4,0.533333333333333326,0.866666666666666696],"xyz":[0.273328971814781774,0.256527489229860128,0.719201514248440477],"hpluv":[256.744147904563079,170.523595036459966,57.7059632125805564],"hsluv":[256.744147904563079,70.7529337108087475,57.7059632125805564]},"#6688ee":{"lch":[58.6071348177704721,91.1720868217648501,258.626369492504523],"luv":[58.6071348177704721,-17.979697586292076,-89.3816529839368599],"rgb":[0.4,0.533333333333333326,0.933333333333333348],"xyz":[0.297141152080956539,0.266052361336330145,0.8446123303169637],"hpluv":[258.626369492504523,197.40162879311913,58.6071348177704721],"hsluv":[258.626369492504523,85.1920367601911295,58.6071348177704721]},"#6688ff":{"lch":[59.57310174908622,104.481663139573541,259.967822360236937],"luv":[59.57310174908622,-18.2008336002305597,-102.884146439906075],"rgb":[0.4,0.533333333333333326,1],"xyz":[0.323312200490787904,0.276520780700262869,0.982446518608745434],"hpluv":[259.967822360236937,222.550815911907222,59.57310174908622],"hsluv":[259.967822360236937,99.9999999999987352,59.57310174908622]},"#669900":{"lch":[57.6618978033021961,71.9113437902946373,111.072092359847389],"luv":[57.6618978033021961,-25.8551729794803826,67.1025438856612624],"rgb":[0.4,0.6,0],"xyz":[0.168701012541425444,0.25606766624446553,0.0405375665099077104],"hpluv":[111.072092359847389,158.251486754186431,57.6618978033021961],"hsluv":[111.072092359847389,100.000000000002444,57.6618978033021961]},"#669911":{"lch":[57.7006802499588929,70.3894808316696867,111.521292839157113],"luv":[57.7006802499588929,-25.8221679479897865,65.4820177928093727],"rgb":[0.4,0.6,0.0666666666666666657],"xyz":[0.169712678041062576,0.256472332444320383,0.0458656714746633401],"hpluv":[111.521292839157113,154.798288730060023,57.7006802499588929],"hsluv":[111.521292839157113,97.4070268725327821,57.7006802499588929]},"#669922":{"lch":[57.7724648019637499,67.6202459496272326,112.394641072548438],"luv":[57.7724648019637499,-25.7622250908158499,62.5204400229094404],"rgb":[0.4,0.6,0.133333333333333331],"xyz":[0.171588036179539577,0.257222475699711184,0.0557425576706425396],"hpluv":[112.394641072548438,148.523500329687067,57.7724648019637499],"hsluv":[112.394641072548438,92.6757293451634183,57.7724648019637499]},"#669933":{"lch":[57.8903535973237524,63.206621217633213,113.958803391015238],"luv":[57.8903535973237524,-25.6669247559924365,57.7605915769530824],"rgb":[0.4,0.6,0.2],"xyz":[0.174675786911997311,0.258457575992694311,0.0720047115282536898],"hpluv":[113.958803391015238,138.546544821103367,57.8903535973237524],"hsluv":[113.958803391015238,85.092275495173979,57.8903535973237524]},"#669944":{"lch":[58.0598969225296457,57.1535921702901888,116.538768682419729],"luv":[58.0598969225296457,-25.5364113217858204,51.131446241744662],"rgb":[0.4,0.6,0.266666666666666663],"xyz":[0.179133782156216198,0.260240774090381877,0.0954834864811403283],"hpluv":[116.538768682419729,124.912700512594284,58.0598969225296457],"hsluv":[116.538768682419729,74.5746503624431796,58.0598969225296457]},"#669955":{"lch":[58.2854489010818355,49.6561447471622515,120.7300937454592],"luv":[58.2854489010818355,-25.3740154630121886,42.6836274282534163],"rgb":[0.4,0.6,0.333333333333333315],"xyz":[0.185096196195578211,0.262625739706126737,0.126885533755114244],"hpluv":[120.7300937454592,108.106592630407334,58.2854489010818355],"hsluv":[120.7300937454592,61.2495338993745833,58.2854489010818355]},"#669966":{"lch":[58.5704165792398754,41.1710358166226,127.715012949238272],"luv":[58.5704165792398754,-25.1857364161826034,32.5688942303571949],"rgb":[0.4,0.6,0.4],"xyz":[0.192681191969086368,0.265659738015530056,0.166833178162258178],"hpluv":[127.715012949238272,89.1975256314243552,58.5704165792398754],"hsluv":[127.715012949238272,45.4174387408809324,58.5704165792398754]},"#669977":{"lch":[58.9173908027988489,32.643461159974926,139.926834832055846],"luv":[58.9173908027988489,-24.9795271581232114,21.0147276798767138],"rgb":[0.4,0.6,0.466666666666666674],"xyz":[0.201995204989288302,0.269385343223610851,0.215886980068656087],"hpluv":[139.926834832055846,70.3059403526018514,58.9173908027988489],"hsluv":[139.926834832055846,47.7876005322921813,58.9173908027988489]},"#669988":{"lch":[59.328227692638464,26.116847909850911,161.480821243886396],"luv":[59.328227692638464,-24.7644493579715288,8.29528738156475498],"rgb":[0.4,0.6,0.533333333333333326],"xyz":[0.213135622091232102,0.273841510064388449,0.274559843472228282],"hpluv":[161.480821243886396,55.8597144892801083,59.328227692638464],"hsluv":[161.480821243886396,50.3655359274122105,59.328227692638464]},"#669999":{"lch":[59.8041090330486043,25.1148951486962346,192.17705063006062],"luv":[59.8041090330486043,-24.5498215694726056,-5.29756729424584893],"rgb":[0.4,0.6,0.6],"xyz":[0.226192586200304829,0.279064295708017607,0.343326521113346161],"hpluv":[192.17705063006062,53.2892577697712042,59.8041090330486043],"hsluv":[192.17705063006062,53.0806679813151447,59.8041090330486043]},"#6699aa":{"lch":[60.3455948386344119,31.1785657150768039,218.6653689057203],"luv":[60.3455948386344119,-24.3444790905776323,-19.4794583563761137],"rgb":[0.4,0.6,0.66666666666666663],"xyz":[0.241250279165557358,0.285087372894118729,0.422630370730344762],"hpluv":[218.6653689057203,65.5616517705923911,60.3455948386344119],"hsluv":[218.6653689057203,55.8649153078387357,60.3455948386344119]},"#6699bb":{"lch":[60.9526745558420231,41.7013653705125407,234.60099737489486],"luv":[60.9526745558420231,-24.1562241025528444,-33.9923625373734168],"rgb":[0.4,0.6,0.733333333333333282],"xyz":[0.258387871272894032,0.291942409737053488,0.512888355828986509],"hpluv":[234.60099737489486,86.8154127469588,60.9526745558420231],"hsluv":[234.60099737489486,58.6571249967150123,60.9526745558420231]},"#6699cc":{"lch":[61.6248198105828493,54.2138016672169485,243.734276496040906],"luv":[61.6248198105828493,-23.9914938552849968,-48.6162988492970101],"rgb":[0.4,0.6,0.8],"xyz":[0.277680246716615731,0.299659359914542289,0.614494866499256664],"hpluv":[243.734276496040906,111.633239234030881,61.6248198105828493],"hsluv":[243.734276496040906,61.4057918386087067,61.6248198105828493]},"#6699dd":{"lch":[62.361039595623,67.5283063616342361,249.312993820438976],"luv":[62.361039595623,-23.8552311607989473,-63.1743627299522288],"rgb":[0.4,0.6,0.866666666666666696],"xyz":[0.29919857226724933,0.308266690134795796,0.727824714399262662],"hpluv":[249.312993820438976,137.407942777337979,62.361039595623],"hsluv":[249.312993820438976,66.62550454031512,62.361039595623]},"#6699ee":{"lch":[63.1599376048740453,81.0888167917790526,252.968345076420633],"luv":[63.1599376048740453,-23.7509145884581336,-77.5325110189427278],"rgb":[0.4,0.6,0.933333333333333348],"xyz":[0.323010752533424039,0.317791562241265813,0.853235530467785885],"hpluv":[252.968345076420633,162.914071535813093,63.1599376048740453],"hsluv":[252.968345076420633,83.0301883133999183,63.1599376048740453]},"#6699ff":{"lch":[64.0197707514621186,94.6074384193794771,255.504450424431923],"luv":[64.0197707514621186,-23.6806962224400728,-91.5958079318982499],"rgb":[0.4,0.6,1],"xyz":[0.34918180094325546,0.328259981605198536,0.99106971875956773],"hpluv":[255.504450424431923,187.521252715437782,64.0197707514621186],"hsluv":[255.504450424431923,99.9999999999985079,64.0197707514621186]},"#550000":{"lch":[15.1243819173422267,50.8637728648741643,12.1770506300617765],"luv":[15.1243819173422267,49.7193613905117289,10.7288626130266547],"rgb":[0.333333333333333315,0,0],"xyz":[0.0374622858816120868,0.019316491157706641,0.00175604465070052949],"hpluv":[12.1770506300617765,426.746789183125202,15.1243819173422267],"hsluv":[12.1770506300617765,100.000000000002203,15.1243819173422267]},"#550011":{"lch":[15.3402258633588957,47.2707050856887108,7.4875089370669734],"luv":[15.3402258633588957,46.8676416739534929,6.15984766208174239],"rgb":[0.333333333333333315,0,0.0666666666666666657],"xyz":[0.0384739513812492051,0.0197211573575614939,0.00708414961545616138],"hpluv":[7.4875089370669734,391.020613457768548,15.3402258633588957],"hsluv":[7.4875089370669734,99.9999999999966889,15.3402258633588957]},"#550022":{"lch":[15.7326592199860933,42.4312907985821823,358.411234527054887],"luv":[15.7326592199860933,42.4149789665186745,-1.17643448760390168],"rgb":[0.333333333333333315,0,0.133333333333333331],"xyz":[0.0403493095197262272,0.0204713006129523117,0.0169610358114353557],"hpluv":[358.411234527054887,342.234221563623748,15.7326592199860933],"hsluv":[358.411234527054887,99.9999999999971578,15.7326592199860933]},"#550033":{"lch":[16.358416636328208,38.360101220613565,343.406058671947278],"luv":[16.358416636328208,36.7625096026365128,-10.9551473459637485],"rgb":[0.333333333333333315,0,0.2],"xyz":[0.0434370602521839677,0.0217064009059354281,0.0332231896690465],"hpluv":[343.406058671947278,297.562230749163234,16.358416636328208],"hsluv":[343.406058671947278,99.9999999999977547,16.358416636328208]},"#550044":{"lch":[17.2212923868602061,37.8614359764106112,324.728975934647224],"luv":[17.2212923868602061,30.9112016871952413,-21.8628896637516235],"rgb":[0.333333333333333315,0,0.266666666666666663],"xyz":[0.0478950554964028483,0.0234895990036230046,0.0567019646219331375],"hpluv":[324.728975934647224,278.978456842737614,17.2212923868602061],"hsluv":[324.728975934647224,99.9999999999983089,17.2212923868602061]},"#550055":{"lch":[18.3096014215038,41.7063030886972754,307.715012949243544],"luv":[18.3096014215038,25.5131777875110508,-32.9923245090298636],"rgb":[0.333333333333333315,0,0.333333333333333315],"xyz":[0.0538574695357648403,0.025874564619367834,0.0881040118959070528],"hpluv":[307.715012949243544,289.042783730483393,18.3096014215038],"hsluv":[307.715012949243544,99.9999999999988,18.3096014215038]},"#550066":{"lch":[19.6013792550641099,48.6148100748190828,295.355623011865077],"luv":[19.6013792550641099,20.818580180871372,-43.9316113733990079],"rgb":[0.333333333333333315,0,0.4],"xyz":[0.0614424653092730116,0.028908562928771149,0.128051656303051015],"hpluv":[295.355623011865077,314.717786655224245,19.6013792550641099],"hsluv":[295.355623011865077,99.9999999999992468,19.6013792550641099]},"#550077":{"lch":[21.069395574911745,57.1127554515679421,287.139622223683091],"luv":[21.069395574911745,16.83119884103942,-54.5763463493480572],"rgb":[0.333333333333333315,0,0.466666666666666674],"xyz":[0.0707564783294749311,0.0326341681368519654,0.177105458209448924],"hpluv":[287.139622223683091,343.969838941793114,21.069395574911745],"hsluv":[287.139622223683091,99.9999999999995737,21.069395574911745]},"#550088":{"lch":[22.6852054601189934,66.3294491167530822,281.703433904835379],"luv":[22.6852054601189934,13.454662288017035,-64.9505033302079084],"rgb":[0.333333333333333315,0,0.533333333333333326],"xyz":[0.0818968954314187592,0.0370903349776295563,0.235778321613021091],"hpluv":[281.703433904835379,371.024851449370942,22.6852054601189934],"hsluv":[281.703433904835379,99.9999999999998721,22.6852054601189934]},"#550099":{"lch":[24.4218644362266417,75.8503102235033424,278.01254475278904],"luv":[24.4218644362266417,10.5727682252252198,-75.1098271403773339],"rgb":[0.333333333333333315,0,0.6],"xyz":[0.0949538595404914726,0.0423131206212587208,0.304544999254138971],"hpluv":[278.01254475278904,394.110378481836165,24.4218644362266417],"hsluv":[278.01254475278904,100.000000000000071,24.4218644362266417]},"#5500aa":{"lch":[26.2553935553790794,85.4876195151354,275.424483319872081],"luv":[26.2553935553790794,8.0814629277942,-85.1047768771603614],"rgb":[0.333333333333333315,0,0.66666666666666663],"xyz":[0.110011552505744015,0.0483361978073598153,0.383848848871137571],"hpluv":[275.424483319872081,413.165469396605374,26.2553935553790794],"hsluv":[275.424483319872081,100.00000000000027,26.2553935553790794]},"#5500bb":{"lch":[28.1653177219846,95.1546470205467756,273.553022331801344],"luv":[28.1653177219846,5.89694295360029841,-94.9717479748942708],"rgb":[0.333333333333333315,0,0.733333333333333282],"xyz":[0.127149144613080661,0.0551912346502945739,0.474106833969779318],"hpluv":[273.553022331801344,428.701175528050442,28.1653177219846],"hsluv":[273.553022331801344,100.000000000000355,28.1653177219846]},"#5500cc":{"lch":[30.1346298593711452,104.80902699908826,272.162345307959299],"luv":[30.1346298593711452,3.95455850560158062,-104.734395532324456],"rgb":[0.333333333333333315,0,0.8],"xyz":[0.146441520056802388,0.0629081848277833755,0.575713344640049529],"hpluv":[272.162345307959299,441.338845171454864,30.1346298593711452],"hsluv":[272.162345307959299,100.000000000000441,30.1346298593711452]},"#5500dd":{"lch":[32.1494591091083208,114.428501102308275,271.104225820707256],"luv":[32.1494591091083208,2.20517261265448461,-114.407250986418532],"rgb":[0.333333333333333315,0,0.866666666666666696],"xyz":[0.167959845607435931,0.0715155150480369095,0.689043192540055527],"hpluv":[271.104225820707256,451.647764573950099,32.1494591091083208],"hsluv":[271.104225820707256,100.000000000000483,32.1494591091083208]},"#5500ee":{"lch":[34.1986254005705774,124.000502171291956,270.282536199645165],"luv":[34.1986254005705774,0.611467178704377612,-123.998994538754019],"rgb":[0.333333333333333315,0,0.933333333333333348],"xyz":[0.191772025873610696,0.0810403871545069404,0.81445400860857875],"hpluv":[270.282536199645165,460.101999214721616,34.1986254005705774],"hsluv":[270.282536199645165,100.000000000000597,34.1986254005705774]},"#5500ff":{"lch":[36.2731838611955055,133.517545782829444,269.6330586770423],"luv":[36.2731838611955055,-0.855085145745556,-133.514807647929],"rgb":[0.333333333333333315,0,1],"xyz":[0.217943074283442062,0.0915088065184396504,0.952288196900360595],"hpluv":[269.6330586770423,467.080772865482345,36.2731838611955055],"hsluv":[269.6330586770423,100.000000000000668,36.2731838611955055]},"#551100":{"lch":[17.1436512350983392,46.6418802884309827,16.9386517648024579],"luv":[17.1436512350983392,44.618427652544149,13.5889996193616174],"rgb":[0.333333333333333315,0.0666666666666666657,0],"xyz":[0.0394666861425404941,0.0233252916795635146,0.00242417807100998037],"hpluv":[16.9386517648024579,345.232802292268,17.1436512350983392],"hsluv":[16.9386517648024579,100.000000000002245,17.1436512350983392]},"#551111":{"lch":[17.3342210988239742,43.3325537190722372,12.1770506300618173],"luv":[17.3342210988239742,42.3575912084996133,9.14027783111198566],"rgb":[0.333333333333333315,0.0666666666666666657,0.0666666666666666657],"xyz":[0.0404783516421776124,0.0237299578794183674,0.0077522830357656114],"hpluv":[12.1770506300618173,317.211759513802576,17.3342210988239742],"hsluv":[12.1770506300618173,74.3325474389658751,17.3342210988239742]},"#551122":{"lch":[17.681833534927847,38.7809423842287515,2.75476418742331486],"luv":[17.681833534927847,38.7361268795629599,1.86385798259144919],"rgb":[0.333333333333333315,0.0666666666666666657,0.133333333333333331],"xyz":[0.0423537097806546345,0.0244801011348091888,0.0176291692317448075],"hpluv":[2.75476418742331486,278.311009894887945,17.681833534927847],"hsluv":[2.75476418742331486,76.7057995287142234,17.681833534927847]},"#551133":{"lch":[18.2390179286851222,34.9181665436168771,346.660743506282301],"luv":[18.2390179286851222,33.9761101882180157,-8.05619582966011727],"rgb":[0.333333333333333315,0.0666666666666666657,0.2],"xyz":[0.045441460513112375,0.0257152014277923,0.0338913230893559542],"hpluv":[346.660743506282301,242.9345634355779,18.2390179286851222],"hsluv":[346.660743506282301,79.7834922439867285,18.2390179286851222]},"#551144":{"lch":[19.0128230091186055,34.7408929356053093,326.164658676814156],"luv":[19.0128230091186055,28.8572161490225767,-19.3440098762325228],"rgb":[0.333333333333333315,0.0666666666666666657,0.266666666666666663],"xyz":[0.0498994557573312555,0.0274983995254798746,0.0573700980422425927],"hpluv":[326.164658676814156,231.864199750183133,19.0128230091186055],"hsluv":[326.164658676814156,83.0221027238197706,19.0128230091186055]},"#551155":{"lch":[19.9971255718025702,39.1813209297373,307.715012949243771],"luv":[19.9971255718025702,23.9685594933690105,-30.9949038651824331],"rgb":[0.333333333333333315,0.0666666666666666657,0.333333333333333315],"xyz":[0.0558618697966932476,0.0298833651412247076,0.0887721453162165],"hpluv":[307.715012949243771,248.628452083429778,19.9971255718025702],"hsluv":[307.715012949243771,86.0178721207098391,19.9971255718025702]},"#551166":{"lch":[21.1763147828962417,46.7756191769153702,294.771362117319313],"luv":[21.1763147828962417,19.5989049109657927,-42.4716549674572263],"rgb":[0.333333333333333315,0.0666666666666666657,0.4],"xyz":[0.0634468655702014189,0.0329173634506280191,0.128719789723360456],"hpluv":[294.771362117319313,280.29057047770084,21.1763147828962417],"hsluv":[294.771362117319313,88.5810746573468464,21.1763147828962417]},"#551177":{"lch":[22.529041607596703,55.8726050260016436,286.442196236272423],"luv":[22.529041607596703,15.8146223861076685,-53.5877384405836494],"rgb":[0.333333333333333315,0.0666666666666666657,0.466666666666666674],"xyz":[0.0727608785904033384,0.0366429686587088355,0.177773591629758365],"hpluv":[286.442196236272423,314.699121073082495,22.529041607596703],"hsluv":[286.442196236272423,90.6792509168865166,22.529041607596703]},"#551188":{"lch":[24.0315326783493077,65.5523157673088548,281.05474383939486],"luv":[24.0315326783493077,12.5694476912001676,-64.3359548557037613],"rgb":[0.333333333333333315,0.0666666666666666657,0.533333333333333326],"xyz":[0.0839012956923471664,0.0410991354994864333,0.236446455033330533],"hpluv":[281.05474383939486,346.135302225987516,24.0315326783493077],"hsluv":[281.05474383939486,92.3586421581981654,24.0315326783493077]},"#551199":{"lch":[25.6600874124784752,75.409923320082811,277.450872837297311],"luv":[25.6600874124784752,9.77886091464338847,-74.7731931533810439],"rgb":[0.333333333333333315,0.0666666666666666657,0.6],"xyz":[0.0969582598014198799,0.0463219211431155908,0.30521313267444844],"hpluv":[277.450872837297311,372.914863977489176,25.6600874124784752],"hsluv":[277.450872837297311,93.6909530677945099,25.6600874124784752]},"#5511aa":{"lch":[27.3926712394503795,85.2829889480110097,274.948569823839534],"luv":[27.3926712394503795,7.3566383451248436,-84.9650991652784882],"rgb":[0.333333333333333315,0.0666666666666666657,0.66666666666666663],"xyz":[0.112015952766672422,0.0523449983292166923,0.38451698229144704],"hpluv":[274.948569823839534,395.063906765864772,27.3926712394503795],"hsluv":[274.948569823839534,94.7471527755802185,27.3926712394503795]},"#5511bb":{"lch":[29.2097366740877575,95.1102004757886732,273.151254165932869],"luv":[29.2097366740877575,5.22840137893499524,-94.9663838079847125],"rgb":[0.333333333333333315,0.0666666666666666657,0.733333333333333282],"xyz":[0.129153544874009069,0.0592000351721514509,0.474774967390088787],"hpluv":[273.151254165932869,413.179515249173164,29.2097366740877575],"hsluv":[273.151254165932869,95.5878244802283,29.2097366740877575]},"#5511cc":{"lch":[31.0944914716528729,104.870266468627406,271.822015936655589],"luv":[31.0944914716528729,3.33433100744475697,-104.81724584215],"rgb":[0.333333333333333315,0.0666666666666666657,0.8],"xyz":[0.148445920317730795,0.0669169853496402456,0.576381478060359],"hpluv":[271.822015936655589,427.964986778194486,31.0944914716528729],"hsluv":[271.822015936655589,96.2613872132177733,31.0944914716528729]},"#5511dd":{"lch":[33.0328257175950526,114.557035031638449,270.814150293263936],"luv":[33.0328257175950526,1.62775523553093748,-114.545469959022128],"rgb":[0.333333333333333315,0.0666666666666666657,0.866666666666666696],"xyz":[0.169964245868364339,0.0755243155698937796,0.689711325960365],"hpluv":[270.814150293263936,440.063516862193467,33.0328257175950526],"hsluv":[270.814150293263936,96.8053522828386832,33.0328257175950526]},"#5511ee":{"lch":[35.0130604571318926,124.169729525043778,270.033521846843314],"luv":[35.0130604571318926,0.0726475571782520396,-124.169708273213573],"rgb":[0.333333333333333315,0.0666666666666666657,0.933333333333333348],"xyz":[0.193776426134539104,0.0850491876763638244,0.815122142028888219],"hpluv":[270.033521846843314,450.012925469310176,35.0130604571318926],"hsluv":[270.033521846843314,97.2483877085506663,35.0130604571318926]},"#5511ff":{"lch":[37.0256255288684244,133.709282746677673,269.417732433602225],"luv":[37.0256255288684244,-1.35879534673770408,-133.702378317802101],"rgb":[0.333333333333333315,0.0666666666666666657,1],"xyz":[0.219947474544370469,0.0955176070402965205,0.952956330320670064],"hpluv":[269.417732433602225,458.245787382607887,37.0256255288684244],"hsluv":[269.417732433602225,99.999999999999531,37.0256255288684244]},"#552200":{"lch":[20.34436993371488,40.5799496107340403,26.5709502396200712],"luv":[20.34436993371488,36.2939416756913289,18.1516420207988389],"rgb":[0.333333333333333315,0.133333333333333331,0],"xyz":[0.0431823098773084293,0.0307565391490994891,0.0036627193159325909],"hpluv":[26.5709502396200712,253.10841584108,20.34436993371488],"hsluv":[26.5709502396200712,100.000000000002359,20.34436993371488]},"#552211":{"lch":[20.5030711832139332,37.4561676233306144,21.8926823519782197],"luv":[20.5030711832139332,34.7549742653004543,13.9662542166947503],"rgb":[0.333333333333333315,0.133333333333333331,0.0666666666666666657],"xyz":[0.0441939753769455546,0.031161205348954342,0.00899082428068822236],"hpluv":[21.8926823519782197,231.816181029165051,20.5030711832139332],"hsluv":[21.8926823519782197,79.998991439989,20.5030711832139332]},"#552222":{"lch":[20.7936643332181177,32.9512801850020054,12.1770506300619488],"luv":[20.7936643332181177,32.2098915499349658,6.95052171940595098],"rgb":[0.333333333333333315,0.133333333333333331,0.133333333333333331],"xyz":[0.0460693335154225697,0.0319113486043451633,0.0188677104766674167],"hpluv":[12.1770506300619488,201.08542320769223,20.7936643332181177],"hsluv":[12.1770506300619488,47.1205474310924046,20.7936643332181177]},"#552233":{"lch":[21.2623572347893699,28.8586800011052311,354.1745907436],"luv":[21.2623572347893699,28.7096478626609084,-2.92908364650122532],"rgb":[0.333333333333333315,0.133333333333333331,0.2],"xyz":[0.0491570842478803102,0.0331464488973282762,0.0351298643342785599],"hpluv":[354.1745907436,172.228245917758017,21.2623572347893699],"hsluv":[354.1745907436,52.8325366869496236,21.2623572347893699]},"#552244":{"lch":[21.9189283311679688,28.7014290952845421,329.54904741067952],"luv":[21.9189283311679688,24.7424491748557642,-14.5459011732283336],"rgb":[0.333333333333333315,0.133333333333333331,0.266666666666666663],"xyz":[0.0536150794920991908,0.0349296469950158492,0.0586086392871652],"hpluv":[329.54904741067952,166.158870546468904,21.9189283311679688],"hsluv":[329.54904741067952,59.1960886419386,21.9189283311679688]},"#552255":{"lch":[22.7630226511172538,33.9275210993755394,307.715012949244226],"luv":[22.7630226511172538,20.7546297224435,-26.8388157904337739],"rgb":[0.333333333333333315,0.133333333333333331,0.333333333333333315],"xyz":[0.0595774935314611828,0.0373146126107606821,0.0900106865611391138],"hpluv":[307.715012949244226,189.13048019699076,22.7630226511172538],"hsluv":[307.715012949244226,65.4333859354686211,22.7630226511172538]},"#552266":{"lch":[23.7863579144178132,42.6539605518829816,293.531429927677038],"luv":[23.7863579144178132,17.0296819355444384,-39.1069083914310625],"rgb":[0.333333333333333315,0.133333333333333331,0.4],"xyz":[0.0671624893049693611,0.0403486109201639936,0.129958330968283076],"hpluv":[293.531429927677038,227.546804006344104,23.7863579144178132],"hsluv":[293.531429927677038,71.0608597854246,23.7863579144178132]},"#552277":{"lch":[24.975052770659552,52.81712200152176,285.022920758889427],"luv":[24.975052770659552,13.6904851349353347,-51.0119495147337858],"rgb":[0.333333333333333315,0.133333333333333331,0.466666666666666674],"xyz":[0.0764765023251712805,0.04407421612824481,0.179012132874680985],"hpluv":[285.022920758889427,268.353735360872861,24.975052770659552],"hsluv":[285.022920758889427,75.8822745115455604,24.975052770659552]},"#552288":{"lch":[26.3119033569515395,63.3751525334233818,279.769698022236867],"luv":[26.3119033569515395,10.754023379801918,-62.4560720809542573],"rgb":[0.333333333333333315,0.133333333333333331,0.533333333333333326],"xyz":[0.0876169194271151086,0.0485303829690224,0.237684996278253152],"hpluv":[279.769698022236867,305.637106002952862,26.3119033569515395],"hsluv":[279.769698022236867,79.8897505498065357,26.3119033569515395]},"#552299":{"lch":[27.7783456471686065,73.9162973481211,276.357347681517297],"luv":[27.7783456471686065,8.18468635974612368,-73.4617582341209783],"rgb":[0.333333333333333315,0.133333333333333331,0.6],"xyz":[0.100673883536187808,0.0537531686126515654,0.306451673919371059],"hpluv":[276.357347681517297,337.654974874305083,27.7783456471686065],"hsluv":[276.357347681517297,83.1678045973750102,27.7783456471686065]},"#5522aa":{"lch":[29.3559430420228864,84.3037876124251824,274.032676149589577],"luv":[29.3559430420228864,5.92869585954675404,-84.0950603258353482],"rgb":[0.333333333333333315,0.133333333333333331,0.66666666666666663],"xyz":[0.115731576501440364,0.0597762457987526669,0.38575552353636966],"hpluv":[274.032676149589577,364.410076381253305,29.3559430420228864],"hsluv":[274.032676149589577,85.8312635149374898,29.3559430420228864]},"#5522bb":{"lch":[31.0273723986379082,94.5090555446981568,272.384235640696716],"luv":[31.0273723986379082,3.93164792491766635,-94.4272403734501324],"rgb":[0.333333333333333315,0.133333333333333331,0.733333333333333282],"xyz":[0.132869168608777,0.0666312826416874254,0.476013508635011406],"hpluv":[272.384235640696716,386.516244750379769,31.0273723986379082],"hsluv":[272.384235640696716,87.9935415010939437,31.0273723986379082]},"#5522cc":{"lch":[32.7769760620793207,104.54175742802569,271.176024316906762],"luv":[32.7769760620793207,2.1456208028374788,-104.519736688869415],"rgb":[0.333333333333333315,0.133333333333333331,0.8],"xyz":[0.152161544052498737,0.0743482328191762271,0.577620019305281507],"hpluv":[271.176024316906762,404.725193356887132,32.7769760620793207],"hsluv":[271.176024316906762,89.7538092894248507,32.7769760620793207]},"#5522dd":{"lch":[34.5909880118612847,114.421842397276407,270.265889656874094],"luv":[34.5909880118612847,0.530989812409553341,-114.420610326139567],"rgb":[0.333333333333333315,0.133333333333333331,0.866666666666666696],"xyz":[0.173679869603132281,0.0829555630394297611,0.690949867205287505],"hpluv":[270.265889656874094,419.744772471420788,34.5909880118612847],"hsluv":[270.265889656874094,91.1938440016712519,34.5909880118612847]},"#5522ee":{"lch":[36.4575428526747132,124.16924767107497,269.564389707514863],"luv":[36.4575428526747132,-0.94402906580191559,-124.165659005715739],"rgb":[0.333333333333333315,0.133333333333333331,0.933333333333333348],"xyz":[0.197492049869307018,0.092480435145899792,0.816360683273810728],"hpluv":[269.564389707514863,432.181309790662738,36.4575428526747132],"hsluv":[269.564389707514863,92.960018101107309,36.4575428526747132]},"#5522ff":{"lch":[38.3665568136218695,133.800754994484379,269.013084090219763],"luv":[38.3665568136218695,-2.30459494965050871,-133.780906258001124],"rgb":[0.333333333333333315,0.133333333333333331,1],"xyz":[0.223663098279138411,0.102948854509832488,0.954194871565592573],"hpluv":[269.013084090219763,442.532391911887146,38.3665568136218695],"hsluv":[269.013084090219763,99.9999999999994458,38.3665568136218695]},"#ccaa00":{"lch":[70.5858735612972623,80.4904122142546186,67.9906634155396],"luv":[70.5858735612972623,30.1643998932495876,74.6244962294604335],"rgb":[0.8,0.66666666666666663,0],"xyz":[0.392753797737474875,0.415879162748823417,0.059586129772359088],"hpluv":[67.9906634155396,144.699051457387782,70.5858735612972623],"hsluv":[67.9906634155396,100.000000000002373,70.5858735612972623]},"#ccaa11":{"lch":[70.6139482370970342,79.3332745728624786,67.7767588069511078],"luv":[70.6139482370970342,30.0051392857341135,73.4401802210267078],"rgb":[0.8,0.66666666666666663,0.0666666666666666657],"xyz":[0.393765463237112,0.416283828948678269,0.0649142347371147177],"hpluv":[67.7767588069511078,142.56214209062793,70.6139482370970342],"hsluv":[67.7767588069511078,98.4234445622979308,70.6139482370970342]},"#ccaa22":{"lch":[70.6659431154106,77.2098224605726529,67.3668792611096166],"luv":[70.6659431154106,29.7125737342128318,71.263733037795],"rgb":[0.8,0.66666666666666663,0.133333333333333331],"xyz":[0.395640821375589036,0.41703397220406907,0.0747911209330939103],"hpluv":[67.3668792611096166,138.644204697820271,70.6659431154106],"hsluv":[67.3668792611096166,95.5289103121581746,70.6659431154106]},"#ccaa33":{"lch":[70.7514162745237911,73.7740913884545,66.6515854645136159],"luv":[70.7514162745237911,29.2382542862800783,67.7328653349528622],"rgb":[0.8,0.66666666666666663,0.2],"xyz":[0.398728572108046742,0.418269072497052197,0.0910532747907050605],"hpluv":[66.6515854645136159,132.314688307412609,70.7514162745237911],"hsluv":[66.6515854645136159,90.8407422295077822,70.7514162745237911]},"#ccaa44":{"lch":[70.8745233475107597,68.9449101039795096,65.5199261400916271],"luv":[70.8745233475107597,28.5691680681362534,62.74713750555],"rgb":[0.8,0.66666666666666663,0.266666666666666663],"xyz":[0.403186567352265657,0.420052270594739763,0.114532049743591699],"hpluv":[65.5199261400916271,123.438713002021714,70.8745233475107597],"hsluv":[65.5199261400916271,84.237349466135143,70.8745233475107597]},"#ccaa55":{"lch":[71.0386313772099,62.7256766939065713,63.7915144306433959],"luv":[71.0386313772099,27.7020883768036121,56.2770363138665672],"rgb":[0.8,0.66666666666666663,0.333333333333333315],"xyz":[0.409148981391627642,0.422437236210484623,0.1459340970175656],"hpluv":[63.7915144306433959,112.044384698186093,71.0386313772099],"hsluv":[63.7915144306433959,75.6976413431368229,71.0386313772099]},"#ccaa66":{"lch":[71.2465086991263661,55.2096541299921952,61.1466680322388356],"luv":[71.2465086991263661,26.6424757380098143,48.3558103613508123],"rgb":[0.8,0.66666666666666663,0.4],"xyz":[0.416733977165135827,0.425471234519887942,0.185881741424709562],"hpluv":[61.1466680322388356,98.331070119416168,71.2465086991263661],"hsluv":[61.1466680322388356,65.2901205751262,71.2465086991263661]},"#ccaa77":{"lch":[71.5004247203994794,46.6032511345785068,56.9687004258729388],"luv":[71.5004247203994794,25.4032971934547263,39.0709035986321638],"rgb":[0.8,0.66666666666666663,0.466666666666666674],"xyz":[0.426047990185337733,0.429196839727968737,0.234935543331107471],"hpluv":[56.9687004258729388,82.707885898124573,71.5004247203994794],"hsluv":[56.9687004258729388,53.160756563752912,71.5004247203994794]},"#ccaa88":{"lch":[71.8022091544958556,37.3024926838847648,49.9478623796008847],"luv":[71.8022091544958556,24.003572993357885,28.5535364531929083],"rgb":[0.8,0.66666666666666663,0.533333333333333326],"xyz":[0.437188407287281533,0.433653006568746335,0.293608406734679639],"hpluv":[49.9478623796008847,65.9233659814751149,71.8022091544958556],"hsluv":[49.9478623796008847,39.5178130280575743,71.8022091544958556]},"#ccaa99":{"lch":[72.1532912119235874,28.1535194843350283,37.0598425499876214],"luv":[72.1532912119235874,22.4666918036374241,16.9666855559712388],"rgb":[0.8,0.66666666666666663,0.6],"xyz":[0.450245371396354233,0.438875792212375493,0.362375084375797574],"hpluv":[37.0598425499876214,49.5126161932360702,72.1532912119235874],"hsluv":[37.0598425499876214,26.6696495224772221,72.1532912119235874]},"#ccaaaa":{"lch":[72.5547286434336,21.297823518763618,12.177050630063027],"luv":[72.5547286434336,20.8186322940273918,4.49241984263274841],"rgb":[0.8,0.66666666666666663,0.66666666666666663],"xyz":[0.465303064361606789,0.444898869398476615,0.441678933992796174],"hpluv":[12.177050630063027,37.2485034287350203,72.5547286434336],"hsluv":[12.177050630063027,27.9047031904792959,72.5547286434336]},"#ccaabb":{"lch":[73.0072318845295,20.9674028584132515,335.544386587188285],"luv":[73.0072318845295,19.0862548050106788,-8.68025691700441193],"rgb":[0.8,0.66666666666666663,0.733333333333333282],"xyz":[0.482440656468943463,0.451753906241411374,0.531936919091437921],"hpluv":[335.544386587188285,36.4433325399841053,73.0072318845295],"hsluv":[335.544386587188285,29.1493731958161852,73.0072318845295]},"#ccaacc":{"lch":[73.5111862218870442,28.2733952257813925,307.715012949249683],"luv":[73.5111862218870442,17.2958067637387,-22.366044486780595],"rgb":[0.8,0.66666666666666663,0.8],"xyz":[0.501733031912665162,0.459470856418900175,0.633543429761708077],"hpluv":[307.715012949249683,48.8049486057506,73.5111862218870442],"hsluv":[307.715012949249683,30.3693282248248444,73.5111862218870442]},"#ccaadd":{"lch":[74.0666736076556,39.5441054640130645,293.032470315564865],"luv":[74.0666736076556,15.4717391639018693,-36.3917787995197202],"rgb":[0.8,0.66666666666666663,0.866666666666666696],"xyz":[0.523251357463298761,0.468078186639153682,0.746873277661714075],"hpluv":[293.032470315564865,67.7482749884916871,74.0666736076556],"hsluv":[293.032470315564865,52.1368854824616719,74.0666736076556]},"#ccaaee":{"lch":[74.6734949675833093,52.4074038625381462,285.081329657377239],"luv":[74.6734949675833093,13.6358764846886817,-50.6023601436286],"rgb":[0.8,0.66666666666666663,0.933333333333333348],"xyz":[0.54706353772947347,0.477603058745623699,0.872284093730237298],"hpluv":[285.081329657377239,89.0564736794959799,74.6734949675833093],"hsluv":[285.081329657377239,75.3315532053798194,74.6734949675833093]},"#ccaaff":{"lch":[75.3311933526529316,65.9300530396585458,280.316334998223624],"luv":[75.3311933526529316,11.8069327652914797,-64.8642292214135239],"rgb":[0.8,0.66666666666666663,1],"xyz":[0.573234586139304891,0.488071478109556423,1.01011828202201914],"hpluv":[280.316334998223624,111.057502918871393,75.3311933526529316],"hsluv":[280.316334998223624,99.9999999999973426,75.3311933526529316]},"#553300":{"lch":[24.6368918170402651,35.1311640480653367,43.6144672720514848],"luv":[24.6368918170402651,25.4348822629288698,24.2335604409056025],"rgb":[0.333333333333333315,0.2,0],"xyz":[0.049300031966319241,0.0429919833271212859,0.00570196001226947087],"hpluv":[43.6144672720514848,180.944734702515461,24.6368918170402651],"hsluv":[43.6144672720514848,100.000000000002245,24.6368918170402651]},"#553311":{"lch":[24.7639934196671305,31.9442274162558917,39.8156129865950632],"luv":[24.7639934196671305,24.536650698978292,20.4544967598277161],"rgb":[0.333333333333333315,0.2,0.0666666666666666657],"xyz":[0.0503116974659563593,0.0433966495269761388,0.0110300649770251023],"hpluv":[39.8156129865950632,163.685811409294416,24.7639934196671305],"hsluv":[39.8156129865950632,85.3309596574143256,24.7639934196671305]},"#553322":{"lch":[24.9975315322943885,26.9096454002331456,31.2519949010175395],"luv":[24.9975315322943885,23.0048892205904032,13.9608054035092266],"rgb":[0.333333333333333315,0.2,0.133333333333333331],"xyz":[0.0521870556044333814,0.0441467927823669601,0.0209069511730043],"hpluv":[31.2519949010175395,136.59983556614165,24.9975315322943885],"hsluv":[31.2519949010175395,60.4417762068684823,24.9975315322943885]},"#553333":{"lch":[25.3763514371309924,21.2787516643900716,12.1770506300621495],"luv":[25.3763514371309924,20.7999895475976082,4.48839695377019332],"rgb":[0.333333333333333315,0.2,0.2],"xyz":[0.0552748063368911219,0.0453818930753500729,0.0371691050306154416],"hpluv":[12.1770506300621495,106.403592780468983,25.3763514371309924],"hsluv":[12.1770506300621495,24.9336598370546909,25.3763514371309924]},"#553344":{"lch":[25.9113402150992655,19.4972565515274532,338.627269772390264],"luv":[25.9113402150992655,18.1564179844864455,-7.10545558065754257],"rgb":[0.333333333333333315,0.2,0.266666666666666663],"xyz":[0.05973280158111,0.047165091173037646,0.0606478799835020801],"hpluv":[338.627269772390264,95.4823185470749536,25.9113402150992655],"hsluv":[338.627269772390264,32.9723178491547841,25.9113402150992655]},"#553355":{"lch":[26.6061908173450519,25.0719265662328183,307.715012949245363],"luv":[26.6061908173450519,15.3373584467403763,-19.8334802195371829],"rgb":[0.333333333333333315,0.2,0.333333333333333315],"xyz":[0.065695215620472,0.0495500567887824789,0.0920499272574759886],"hpluv":[307.715012949245363,119.576085528419512,26.6061908173450519],"hsluv":[307.715012949245363,41.369683748934996,26.6061908173450519]},"#553366":{"lch":[27.4586282592714284,35.2024776289392847,290.893042573756475],"luv":[27.4586282592714284,12.5540679631371699,-32.8878367910220533],"rgb":[0.333333333333333315,0.2,0.4],"xyz":[0.0732802113939801658,0.0525840550981857904,0.13199757166461995],"hpluv":[290.893042573756475,162.679833835368925,27.4586282592714284],"hsluv":[290.893042573756475,49.429407074258,27.4586282592714284]},"#553377":{"lch":[28.461655060413058,46.8206771520520633,282.253113271302652],"luv":[28.461655060413058,9.93678843358592445,-45.7540822725452898],"rgb":[0.333333333333333315,0.2,0.466666666666666674],"xyz":[0.0825942244141820853,0.0563096603062666068,0.18105137357101786],"hpluv":[282.253113271302652,208.74537696470955,28.461655060413058],"hsluv":[282.253113271302652,56.732994513665389,28.461655060413058]},"#553388":{"lch":[29.6048600369324433,58.6666973974172876,277.388246485053742],"luv":[29.6048600369324433,7.54407762538358551,-58.1796207988872567],"rgb":[0.333333333333333315,0.2,0.533333333333333326],"xyz":[0.0937346415161259133,0.0607658271470442046,0.239724236974590027],"hpluv":[277.388246485053742,251.459446283522851,29.6048600369324433],"hsluv":[277.388246485053742,63.1061783000114715,29.6048600369324433]},"#553399":{"lch":[30.8756880539778678,70.2946203588512759,274.394660626066695],"luv":[30.8756880539778678,5.38640350826703,-70.0879469569565714],"rgb":[0.333333333333333315,0.2,0.6],"xyz":[0.106791605625198627,0.0659886127906733622,0.308490914615707934],"hpluv":[274.394660626066695,288.898157334443908,30.8756880539778678],"hsluv":[274.394660626066695,68.537799314251,30.8756880539778678]},"#5533aa":{"lch":[32.2605562861205,81.571224268378316,272.422737250332261],"luv":[32.2605562861205,3.44819039224039026,-81.498310483475251],"rgb":[0.333333333333333315,0.2,0.66666666666666663],"xyz":[0.121849298590451169,0.0720116899767744567,0.387794764232706535],"hpluv":[272.422737250332261,320.851781583216223,32.2605562861205],"hsluv":[272.422737250332261,73.1042224024611897,32.2605562861205]},"#5533bb":{"lch":[33.7457437232739395,92.4864953275551755,271.055064965734516],"luv":[33.7457437232739395,1.70298313903478205,-92.4708152143261231],"rgb":[0.333333333333333315,0.2,0.733333333333333282],"xyz":[0.138986890697787802,0.0788667268197092153,0.478052749331348281],"hpluv":[271.055064965734516,347.775228922495899,33.7457437232739395],"hsluv":[271.055064965734516,76.9172199670655772,33.7457437232739395]},"#5533cc":{"lch":[35.3180325241442,103.075547069605378,270.067872161558512],"luv":[35.3180325241442,0.12210251098248695,-103.075474748725966],"rgb":[0.333333333333333315,0.2,0.8],"xyz":[0.158279266141509556,0.0865836769971980169,0.579659260001618493],"hpluv":[270.067872161558512,370.338167129355497,35.3180325241442],"hsluv":[270.067872161558512,80.0940957669769205,35.3180325241442]},"#5533dd":{"lch":[36.9651203282397915,113.385246995104879,269.332372034398134],"luv":[36.9651203282397915,-1.32116971635525937,-113.377549570986602],"rgb":[0.333333333333333315,0.2,0.866666666666666696],"xyz":[0.179797591692143099,0.0951910072174515509,0.69298910790162449],"hpluv":[269.332372034398134,389.227711455139399,36.9651203282397915],"hsluv":[269.332372034398134,84.8119298710034855,36.9651203282397915]},"#5533ee":{"lch":[38.6758450270606247,123.460606758128,268.77009087446072],"luv":[38.6758450270606247,-2.64999738284680575,-123.432163292052948],"rgb":[0.333333333333333315,0.2,0.933333333333333348],"xyz":[0.203609771958317837,0.104715879323921596,0.818399923970147714],"hpluv":[268.77009087446072,405.067987408818738,38.6758450270606247],"hsluv":[268.77009087446072,92.2936685874649356,38.6758450270606247]},"#5533ff":{"lch":[40.4402700894382363,133.340096114557781,268.33094335317071],"luv":[40.4402700894382363,-3.88371885476632706,-133.283524712158766],"rgb":[0.333333333333333315,0.2,1],"xyz":[0.22978082036814923,0.115184298687854292,0.956234112261929559],"hpluv":[268.33094335317071,418.394573227645935,40.4402700894382363],"hsluv":[268.33094335317071,99.99999999999946,40.4402700894382363]},"#ccbb00":{"lch":[75.0632334950121418,83.0331806403360275,77.5616137481136292],"luv":[75.0632334950121418,17.8844849446013434,81.0842419062853423],"rgb":[0.8,0.733333333333333282,0],"xyz":[0.426708295646073654,0.483788158566022,0.0709042957418917],"hpluv":[77.5616137481136292,140.366584388758554,75.0632334950121418],"hsluv":[77.5616137481136292,100.000000000002373,75.0632334950121418]},"#ccbb11":{"lch":[75.0886164663743898,81.9438461169387438,77.472162284636525],"luv":[75.0886164663743898,17.7747618107910519,79.9928231718707394],"rgb":[0.8,0.733333333333333282,0.0666666666666666657],"xyz":[0.427719961145710759,0.484192824765876828,0.0762324007066473436],"hpluv":[77.472162284636525,138.478250548668058,75.0886164663743898],"hsluv":[77.472162284636525,98.6397508878022222,75.0886164663743898]},"#ccbb22":{"lch":[75.1356323460541802,79.9401497843360289,77.301186242421764],"luv":[75.1356323460541802,17.5729239259544805,77.9847414064744839],"rgb":[0.8,0.733333333333333282,0.133333333333333331],"xyz":[0.429595319284187815,0.484942968021267629,0.0861092869026265362],"hpluv":[77.301186242421764,135.007637737713509,75.1356323460541802],"hsluv":[77.301186242421764,96.1390577710114087,75.1356323460541802]},"#ccbb33":{"lch":[75.2129378077961235,76.6847204783522471,77.0041162235267223],"luv":[75.2129378077961235,17.2449407213965777,74.720535158405653],"rgb":[0.8,0.733333333333333282,0.2],"xyz":[0.432683070016645521,0.486178068314250755,0.102371440760237686],"hpluv":[77.0041162235267223,129.376563997369885,75.2129378077961235],"hsluv":[77.0041162235267223,92.0797058264172392,75.2129378077961235]},"#ccbb44":{"lch":[75.3243183189310628,72.0782997366288,76.5373230188340585],"luv":[75.3243183189310628,16.7806861485978907,70.0977165484408431],"rgb":[0.8,0.733333333333333282,0.266666666666666663],"xyz":[0.437141065260864436,0.487961266411938321,0.125850215713124325],"hpluv":[76.5373230188340585,121.425150369898518,75.3243183189310628],"hsluv":[76.5373230188340585,86.34290383100182,75.3243183189310628]},"#ccbb55":{"lch":[75.4728625341146397,66.0852327898053,75.831238609121371],"luv":[75.4728625341146397,16.1762634357197506,64.0748507149330351],"rgb":[0.8,0.733333333333333282,0.333333333333333315],"xyz":[0.443103479300226422,0.490346232027683182,0.157252262987098212],"hpluv":[75.831238609121371,111.10994393806304,75.4728625341146397],"hsluv":[75.831238609121371,78.8905565478608395,75.4728625341146397]},"#ccbb66":{"lch":[75.6611363515091284,58.7289677793131,74.7643785098968863],"luv":[75.6611363515091284,15.4333320312120961,56.6648384700597134],"rgb":[0.8,0.733333333333333282,0.4],"xyz":[0.450688475073734607,0.493380230337086501,0.197199907394242202],"hpluv":[74.7643785098968863,98.4960546107130739,75.6611363515091284],"hsluv":[74.7643785098968863,69.7569980114599701,75.6611363515091284]},"#ccbb77":{"lch":[75.8912747684230737,50.090867045562554,73.1036630558194389],"luv":[75.8912747684230737,14.5584607724557671,47.9285528814827799],"rgb":[0.8,0.733333333333333282,0.466666666666666674],"xyz":[0.460002488093936512,0.497105835545167296,0.246253709300640111],"hpluv":[73.1036630558194389,83.7540906733876795,75.8912747684230737],"hsluv":[73.1036630558194389,59.0406908273499624,75.8912747684230737]},"#ccbb88":{"lch":[76.1650362860674335,40.3168412407358332,70.3426656865815119],"luv":[76.1650362860674335,13.5623472284534756,37.9672283066009157],"rgb":[0.8,0.733333333333333282,0.533333333333333326],"xyz":[0.471142905195880313,0.501562002385944838,0.304926572704212251],"hpluv":[70.3426656865815119,67.6831847004182379,76.1650362860674335],"hsluv":[70.3426656865815119,46.8939441374685586,76.1650362860674335]},"#ccbb99":{"lch":[76.4838383644648871,29.6573629081618826,65.1594516064859732],"luv":[76.4838383644648871,12.4588924968264081,26.9134756658990248],"rgb":[0.8,0.733333333333333282,0.6],"xyz":[0.484199869304953068,0.506784788029574,0.373693250345330186],"hpluv":[65.1594516064859732,50.6096239917615662,76.4838383644648871],"hsluv":[65.1594516064859732,33.5105935092195324,76.4838383644648871]},"#ccbbaa":{"lch":[76.8487828748923,18.695758935396551,52.9508743401004551],"luv":[76.8487828748923,11.26418644921627,14.9214444946778713],"rgb":[0.8,0.733333333333333282,0.66666666666666663],"xyz":[0.499257562270205568,0.512807865215675118,0.452997099962328786],"hpluv":[52.9508743401004551,32.5142912020767696,76.8487828748923],"hsluv":[52.9508743401004551,19.1124274046376854,76.8487828748923]},"#ccbbbb":{"lch":[77.2606763328388126,10.2255548171674207,12.1770506300639045],"luv":[77.2606763328388126,9.99548454110707,2.15690985147396086],"rgb":[0.8,0.733333333333333282,0.733333333333333282],"xyz":[0.516395154377542243,0.519662902058609877,0.543255085060970533],"hpluv":[12.1770506300639045,18.1733155366010308,77.2606763328388126],"hsluv":[12.1770506300639045,17.1437484893634,77.2606763328388126]},"#ccbbcc":{"lch":[77.7200476270310361,14.1732404034447406,307.715012949257925],"luv":[77.7200476270310361,8.67025786172679247,-11.2119299027867267],"rgb":[0.8,0.733333333333333282,0.8],"xyz":[0.535687529821264,0.527379852236098734,0.644861595731240689],"hpluv":[307.715012949257925,25.815587331502627,77.7200476270310361],"hsluv":[307.715012949257925,18.1614974693692588,77.7200476270310361]},"#ccbbdd":{"lch":[78.2271648233418375,26.0669286991650679,286.275412631614586],"luv":[78.2271648233418375,7.3053819239814537,-25.022313377306272],"rgb":[0.8,0.733333333333333282,0.866666666666666696],"xyz":[0.557205855371897485,0.53598718245635224,0.758191443631246687],"hpluv":[286.275412631614586,48.8074477639820898,78.2271648233418375],"hsluv":[286.275412631614586,43.4510455050629929,78.2271648233418375]},"#ccbbee":{"lch":[78.7820519440635,39.5678846485468299,278.599571826643512],"luv":[78.7820519440635,5.9165048525659989,-39.1230426461218741],"rgb":[0.8,0.733333333333333282,0.933333333333333348],"xyz":[0.581018035638072305,0.545512054562822257,0.88360225969976991],"hpluv":[278.599571826643512,76.4037468789834,78.7820519440635],"hsluv":[278.599571826643512,70.6968150087455314,78.7820519440635]},"#ccbbff":{"lch":[79.3845061922316546,53.5695670840829834,274.837592460092935],"luv":[79.3845061922316546,4.51760925339512553,-53.3787385033564235],"rgb":[0.8,0.733333333333333282,1],"xyz":[0.607189084047903616,0.555980473926755,1.02143644799155164],"hpluv":[274.837592460092935,107.038572744282547,79.3845061922316546],"hsluv":[274.837592460092935,99.9999999999963762,79.3845061922316546]},"#554400":{"lch":[29.5776499109456879,34.0768703371065413,65.9474553070004674],"luv":[29.5776499109456879,13.8888553561515469,31.1180460322924546],"rgb":[0.333333333333333315,0.266666666666666663,0],"xyz":[0.0581326024492852811,0.0606571242930536,0.0086461501732580659],"hpluv":[65.9474553070004674,146.195957524823825,29.5776499109456879],"hsluv":[65.9474553070004674,100.000000000002217,29.5776499109456879]},"#554411":{"lch":[29.6787804923011507,30.8713815411758574,64.2244588846852906],"luv":[29.6787804923011507,13.4243191404277429,27.7998175151708296],"rgb":[0.333333333333333315,0.266666666666666663,0.0666666666666666657],"xyz":[0.0591442679489224,0.0610617904929084548,0.0139742551380136974],"hpluv":[64.2244588846852906,131.992525946838612,29.6787804923011507],"hsluv":[64.2244588846852906,89.4077694450363509,29.6787804923011507]},"#554422":{"lch":[29.8650740872788916,25.3442505658492152,60.1547603291711539],"luv":[29.8650740872788916,12.6127938179319639,21.9829131111162219],"rgb":[0.333333333333333315,0.266666666666666663,0.133333333333333331],"xyz":[0.0610196260873994215,0.0618119337482992762,0.0238511413339928952],"hpluv":[60.1547603291711539,107.684992873038837,29.8650740872788916],"hsluv":[60.1547603291711539,70.9921927199271892,29.8650740872788916]},"#554433":{"lch":[30.1685472793317686,17.4710669916127905,49.2680266756281497],"luv":[30.1685472793317686,11.400244593092479,13.2390560480378525],"rgb":[0.333333333333333315,0.266666666666666663,0.2],"xyz":[0.064107376819857162,0.0630470340412823821,0.0401132951916040384],"hpluv":[49.2680266756281497,73.4859575586117302,30.1685472793317686],"hsluv":[49.2680266756281497,43.7071568358896,30.1685472793317686]},"#554444":{"lch":[30.5997780424982437,10.1013456632853149,12.1770506300629258],"luv":[30.5997780424982437,9.87407003600776356,2.13071000682558],"rgb":[0.333333333333333315,0.266666666666666663,0.266666666666666663],"xyz":[0.0685653720640760356,0.0648302321389699621,0.06359207014449067],"hpluv":[12.1770506300629258,41.8890279889816597,30.5997780424982437],"hsluv":[12.1770506300629258,9.81589763549682282,30.5997780424982437]},"#554455":{"lch":[31.1643459369041338,13.3310860490153988,307.715012949249],"luv":[31.1643459369041338,8.15508312366709198,-10.5457325251654854],"rgb":[0.333333333333333315,0.266666666666666663,0.333333333333333315],"xyz":[0.0745277861034380346,0.0672151977547148,0.0949941174184645853],"hpluv":[307.715012949249,54.2808752323906702,31.1643459369041338],"hsluv":[307.715012949249,18.7795296363480162,31.1643459369041338]},"#554466":{"lch":[31.8635722620044533,24.8340912161126894,284.841165372516684],"luv":[31.8635722620044533,6.36101223964894835,-24.005616214070443],"rgb":[0.333333333333333315,0.266666666666666663,0.4],"xyz":[0.0821127818769462,0.0702491960641181135,0.134941761825608547],"hpluv":[284.841165372516684,98.8992811700442331,31.8635722620044533],"hsluv":[284.841165372516684,27.8963704264996828,31.8635722620044533]},"#554477":{"lch":[32.6951743277909443,37.9095930577936784,276.944338121378166],"luv":[32.6951743277909443,4.58346102749711282,-37.6314912117090259],"rgb":[0.333333333333333315,0.266666666666666663,0.466666666666666674],"xyz":[0.0914267948971481254,0.0739748012721989229,0.183995563732006456],"hpluv":[276.944338121378166,147.131204947893167,32.6951743277909443],"hsluv":[276.944338121378166,36.6308714978363952,32.6951743277909443]},"#554488":{"lch":[33.6539551717380903,51.1018638808679526,273.231940865766],"luv":[33.6539551717380903,2.88102600900669881,-51.0205858574182116],"rgb":[0.333333333333333315,0.266666666666666663,0.533333333333333326],"xyz":[0.102567211999091953,0.0784309681129765207,0.242668427135578624],"hpluv":[273.231940865766,192.681471981123309,33.6539551717380903],"hsluv":[273.231940865766,44.6505812495932801,33.6539551717380903]},"#554499":{"lch":[34.7325237210335871,63.9719124096453271,271.149517924849135],"luv":[34.7325237210335871,1.28337422751110575,-63.9590378909774913],"rgb":[0.333333333333333315,0.266666666666666663,0.6],"xyz":[0.115624176108164667,0.0836537537566056782,0.311435104776696559],"hpluv":[271.149517924849135,233.718085138698228,34.7325237210335871],"hsluv":[271.149517924849135,51.7999710200133876,34.7325237210335871]},"#5544aa":{"lch":[35.9219992682327671,76.3678985235758461,269.849629436139082],"luv":[35.9219992682327671,-0.200424374653859844,-76.367635520403681],"rgb":[0.333333333333333315,0.266666666666666663,0.66666666666666663],"xyz":[0.130681869073417223,0.0896768309427067867,0.390738954393695104],"hpluv":[269.849629436139082,269.767524553786757,35.9219992682327671],"hsluv":[269.849629436139082,58.0490239963672465,35.9219992682327671]},"#5544bb":{"lch":[37.2126506061998725,88.2627815084196925,268.978337620063314],"luv":[37.2126506061998725,-1.57376312233016602,-88.2487499584998574],"rgb":[0.333333333333333315,0.266666666666666663,0.733333333333333282],"xyz":[0.147819461180753842,0.0965318677856415452,0.480996939492336906],"hpluv":[268.978337620063314,300.972163983169935,37.2126506061998725],"hsluv":[268.978337620063314,66.0075029321504729,37.2126506061998725]},"#5544cc":{"lch":[38.5944341452357733,99.6871153018899605,268.363808876145868],"luv":[38.5944341452357733,-2.84637030136680202,-99.6464707519528758],"rgb":[0.333333333333333315,0.266666666666666663,0.8],"xyz":[0.167111836624475596,0.104248817963130347,0.582603450162607062],"hpluv":[268.363808876145868,327.758284181939189,38.5944341452357733],"hsluv":[268.363808876145868,74.5283681063652352,38.5944341452357733]},"#5544dd":{"lch":[40.0574145710935738,110.694467066426,267.913412719582],"luv":[40.0574145710935738,-4.03035995406870118,-110.621070496360275],"rgb":[0.333333333333333315,0.266666666666666663,0.866666666666666696],"xyz":[0.18863016217510914,0.112856148183383881,0.695933298062613059],"hpluv":[267.913412719582,350.65684831918054,40.0574145710935738],"hsluv":[267.913412719582,82.9425769408534,40.0574145710935738]},"#5544ee":{"lch":[41.5920687629554777,121.343449115737442,267.573227144435918],"luv":[41.5920687629554777,-5.13798666158471651,-121.23462268002875],"rgb":[0.333333333333333315,0.266666666666666663,0.933333333333333348],"xyz":[0.212442342441283877,0.122381020289853898,0.821344114131136283],"hpluv":[267.573227144435918,370.207437425804358,41.5920687629554777],"hsluv":[267.573227144435918,91.3878688389195872,41.5920687629554777]},"#5544ff":{"lch":[43.1894854939413833,131.689092168021887,267.309962581974105],"luv":[43.1894854939413833,-6.18053297470727,-131.543977468321657],"rgb":[0.333333333333333315,0.266666666666666663,1],"xyz":[0.23861339085111527,0.132849439653786594,0.959178302422918128],"hpluv":[267.309962581974105,386.911020330846497,43.1894854939413833],"hsluv":[267.309962581974105,99.9999999999994174,43.1894854939413833]},"#cccc00":{"lch":[79.627228346343,87.7811065558180132,85.8743202181747449],"luv":[79.627228346343,6.31536666608958797,87.5536339167982192],"rgb":[0.8,0.8,0],"xyz":[0.464932038955690574,0.560235645185256814,0.0836455435117636481],"hpluv":[85.8743202181747449,177.871840357077815,79.627228346343],"hsluv":[85.8743202181747449,100.000000000002245,79.627228346343]},"#cccc11":{"lch":[79.6502471087807891,86.7718911178833707,85.8743202181747],"luv":[79.6502471087807891,6.24275917928854351,86.5470337215737],"rgb":[0.8,0.8,0.0666666666666666657],"xyz":[0.465943704455327679,0.560640311385111723,0.0889736484765192848],"hpluv":[85.8743202181747,176.061859354342118,79.6502471087807891],"hsluv":[85.8743202181747,98.8217369524532927,79.6502471087807891]},"#cccc22":{"lch":[79.6928884771461838,84.9132131482774497,85.8743202181746597],"luv":[79.6928884771461838,6.10903754655005482,84.6931722597497298],"rgb":[0.8,0.8,0.133333333333333331],"xyz":[0.467819062593804735,0.561390454640502523,0.0988505346724984774],"hpluv":[85.8743202181746597,172.717957044242922,79.6928884771461838],"hsluv":[85.8743202181746597,96.653203912443459,79.6928884771461838]},"#cccc33":{"lch":[79.7630142061039891,81.8867831673476445,85.8743202181745602],"luv":[79.7630142061039891,5.89130259459140682,81.6745848549912665],"rgb":[0.8,0.8,0.2],"xyz":[0.470906813326262441,0.56262555493348565,0.115112688530109614],"hpluv":[85.8743202181745602,167.243641009868185,79.7630142061039891],"hsluv":[85.8743202181745602,93.1263971058523623,79.7630142061039891]},"#cccc44":{"lch":[79.8640786601047523,77.5899505798540901,85.8743202181744],"luv":[79.8640786601047523,5.58216917901353593,77.3888869169280156],"rgb":[0.8,0.8,0.266666666666666663],"xyz":[0.475364808570481356,0.564408753031173216,0.138591463482996252],"hpluv":[85.8743202181744,159.406599578518,79.8640786601047523],"hsluv":[85.8743202181744,88.1281264379617113,79.8640786601047523]},"#cccc55":{"lch":[79.9989166638852396,71.9729259129294832,85.8743202181741481],"luv":[79.9989166638852396,5.17805522174052,71.7864179952492236],"rgb":[0.8,0.8,0.333333333333333315],"xyz":[0.481327222609843342,0.566793718646918,0.169993510756970168],"hpluv":[85.8743202181741481,149.042041148428552,79.9989166638852396],"hsluv":[85.8743202181741481,81.6104176612222147,79.9989166638852396]},"#cccc66":{"lch":[80.1699032642976448,65.0330295388014,85.8743202181738],"luv":[80.1699032642976448,4.67876793832737103,64.8645054060685453],"rgb":[0.8,0.8,0.4],"xyz":[0.488912218383351527,0.569827716956321284,0.209941155164114129],"hpluv":[85.8743202181738,136.038559250079544,80.1699032642976448],"hsluv":[85.8743202181738,73.5839630734023,80.1699032642976448]},"#cccc77":{"lch":[80.3790384438565724,56.8098315426934803,85.8743202181733096],"luv":[80.3790384438565724,4.0871541782499472,56.6626166941875837],"rgb":[0.8,0.8,0.466666666666666674],"xyz":[0.498226231403553432,0.573553322164402135,0.258994957070512],"hpluv":[85.8743202181733096,120.326663009793734,80.3790384438565724],"hsluv":[85.8743202181733096,64.1122831116318252,80.3790384438565724]},"#cccc88":{"lch":[80.6279973255091704,47.3795499902223085,85.8743202181724854],"luv":[80.6279973255091704,3.40869741112766222,47.2567724166107865],"rgb":[0.8,0.8,0.533333333333333326],"xyz":[0.509366648505497288,0.578009489005179677,0.317667820474084206],"hpluv":[85.8743202181724854,101.866799769447482,80.6279973255091704],"hsluv":[85.8743202181724854,53.3047126681541172,80.6279973255091704]},"#cccc99":{"lch":[80.9181626169042119,36.8483625211582861,85.8743202181711496],"luv":[80.9181626169042119,2.65103653276840934,36.7528750683892724],"rgb":[0.8,0.8,0.6],"xyz":[0.522423612614569932,0.58323227464880889,0.386434498115202141],"hpluv":[85.8743202181711496,80.635831276566,80.9181626169042119],"hsluv":[85.8743202181711496,41.30786304104587,80.9181626169042119]},"#ccccaa":{"lch":[81.2506473976222452,25.3448572993520607,85.8743202181683216],"luv":[81.2506473976222452,1.82342275263520492,25.27917959487],"rgb":[0.8,0.8,0.66666666666666663],"xyz":[0.537481305579822544,0.58925535183491,0.465738347732200686],"hpluv":[85.8743202181683216,56.6117825452175509,81.2506473976222452],"hsluv":[85.8743202181683216,28.2959036617823898,81.2506473976222452]},"#ccccbb":{"lch":[81.6263125989092657,13.0121158497344798,85.8743202181599],"luv":[81.6263125989092657,0.936149997616518514,12.9783967449324749],"rgb":[0.8,0.8,0.733333333333333282],"xyz":[0.554618897687159107,0.596110388677844716,0.555996332830842488],"hpluv":[85.8743202181599,29.7570160502500514,81.6263125989092657],"hsluv":[85.8743202181599,14.4603328966824272,81.6263125989092657]},"#cccccc":{"lch":[82.0457816743453,4.34523248843710382e-12,0],"luv":[82.0457816743453,4.08534684758697557e-12,1.48019813318368677e-12],"rgb":[0.8,0.8,0.8],"xyz":[0.573911273130880861,0.603827338855333573,0.657602843501112644],"hpluv":[0,1.02065966511349575e-11,82.0457816743453],"hsluv":[0,1.01642596056880755e-11,82.0457816743453]},"#ccccdd":{"lch":[82.5094539517328087,13.5418343873660199,265.874320218194214],"luv":[82.5094539517328087,-0.974260325972223118,-13.5067425899839115],"rgb":[0.8,0.8,0.866666666666666696],"xyz":[0.59542959868151446,0.612434669075587079,0.770932691401118642],"hpluv":[265.874320218194214,32.7843842039110882,82.5094539517328087],"hsluv":[265.874320218194214,30.4637656032122131,82.5094539517328087]},"#ccccee":{"lch":[83.0175175610870895,27.4698052042972165,265.874320218185687],"luv":[83.0175175610870895,-1.97630103922669687,-27.3986209901955817],"rgb":[0.8,0.8,0.933333333333333348],"xyz":[0.61924177894768917,0.621959541182057096,0.896343507469641865],"hpluv":[265.874320218185687,68.7964750954906776,83.0175175610870895],"hsluv":[265.874320218185687,63.7216981471091941,83.0175175610870895]},"#ccccff":{"lch":[83.5699624582004219,41.6509292947620153,265.874320218182845],"luv":[83.5699624582004219,-2.99655473483939438,-41.5429966521238825],"rgb":[0.8,0.8,1],"xyz":[0.645412827357520591,0.63242796054598982,1.03417769576142371],"hpluv":[265.874320218182845,108.336501116640306,83.5699624582004219],"hsluv":[265.874320218182845,99.9999999999952536,83.5699624582004219]},"#555500":{"lch":[34.8595382729148753,38.4291768930055397,85.8743202181747307],"luv":[34.8595382729148753,2.76476741155027961,38.3295929776711901],"rgb":[0.333333333333333315,0.333333333333333315,0],"xyz":[0.0699458591636312466,0.084283637721745866,0.0125839024113732767],"hpluv":[85.8743202181747307,139.887458074797564,34.8595382729148753],"hsluv":[85.8743202181747307,100.000000000002331,34.8595382729148753]},"#555511":{"lch":[34.9408046802893,35.5443725161734108,85.8743202181745318],"luv":[34.9408046802893,2.55722164100294558,35.4522641737772517],"rgb":[0.333333333333333315,0.333333333333333315,0.0666666666666666657],"xyz":[0.0709575246632683648,0.0846883039216007188,0.0179120073761289064],"hpluv":[85.8743202181745318,129.085444875460666,34.9408046802893],"hsluv":[85.8743202181745318,92.2780688504912,34.9408046802893]},"#555522":{"lch":[35.0907688239250604,30.4130442263608813,85.8743202181740202],"luv":[35.0907688239250604,2.18805086034508589,30.3342330139914047],"rgb":[0.333333333333333315,0.333333333333333315,0.133333333333333331],"xyz":[0.0728328828017454,0.0854384471769915332,0.027788893572108106],"hpluv":[85.8743202181740202,109.978131404858061,35.0907688239250604],"hsluv":[85.8743202181740202,78.6190076783406653,35.0907688239250604]},"#555533":{"lch":[35.3357817552570097,22.5221214621125654,85.8743202181728549],"luv":[35.3357817552570097,1.62034247131604014,22.4637584885032275],"rgb":[0.333333333333333315,0.333333333333333315,0.2],"xyz":[0.0759206335342031274,0.0866735474699746461,0.0440510474297192492],"hpluv":[85.8743202181728549,80.8786547215116656,35.3357817552570097],"hsluv":[85.8743202181728549,57.8169450175211566,35.3357817552570097]},"#555544":{"lch":[35.6854507669058592,12.1926559388895619,85.8743202181691743],"luv":[35.6854507669058592,0.877194374836262392,12.1610603515028455],"rgb":[0.333333333333333315,0.333333333333333315,0.266666666666666663],"xyz":[0.080378628778422,0.0884567455676622261,0.0675298223826058808],"hpluv":[85.8743202181691743,43.355725530805,35.6854507669058592],"hsluv":[85.8743202181691743,30.9932899828832262,35.6854507669058592]},"#555555":{"lch":[36.1458508397197278,1.89718584003012571e-12,0],"luv":[36.1458508397197278,1.79982851973451413e-12,5.9994283991150471e-13],"rgb":[0.333333333333333315,0.333333333333333315,0.333333333333333315],"xyz":[0.086341042817784,0.090841711183407059,0.0989318696565798],"hpluv":[0,6.66025333978279224e-12,36.1458508397197278],"hsluv":[0,1.90696849203660445e-12,36.1458508397197278]},"#555566":{"lch":[36.7200402720523087,13.391014832031539,265.874320218184835],"luv":[36.7200402720523087,-0.963409690459316,-13.3563138627398903],"rgb":[0.333333333333333315,0.333333333333333315,0.4],"xyz":[0.0939260385912921714,0.0938757094928103775,0.138879514063723758],"hpluv":[265.874320218184835,46.2753453717946712,36.7200402720523087],"hsluv":[265.874320218184835,10.0205788523093844,36.7200402720523087]},"#555577":{"lch":[37.4084382237490445,27.3651172837118537,265.874320218181],"luv":[37.4084382237490445,-1.96876932050326592,-27.294204353927416],"rgb":[0.333333333333333315,0.333333333333333315,0.466666666666666674],"xyz":[0.103240051611494091,0.0976013147008911869,0.187933315970121667],"hpluv":[265.874320218181,92.8254499938530131,37.4084382237490445],"hsluv":[265.874320218181,20.457601163446,37.4084382237490445]},"#555588":{"lch":[38.2091925227490421,41.4380747403329508,265.874320218179832],"luv":[38.2091925227490421,-2.98124102314999906,-41.330693680935326],"rgb":[0.333333333333333315,0.333333333333333315,0.533333333333333326],"xyz":[0.114380468713437919,0.102057481541668785,0.246606179373693835],"hpluv":[265.874320218179832,137.616667264503377,38.2091925227490421],"hsluv":[265.874320218179832,30.9677616121988244,38.2091925227490421]},"#555599":{"lch":[39.1185695394092079,55.2798607696674651,265.874320218179207],"luv":[39.1185695394092079,-3.97708121608675258,-55.1366106295487626],"rgb":[0.333333333333333315,0.333333333333333315,0.6],"xyz":[0.127437432822510632,0.107280267185297942,0.315372857014811769],"hpluv":[265.874320218179207,179.317758559659353,39.1185695394092079],"hsluv":[265.874320218179207,41.3377460212352688,39.1185695394092079]},"#5555aa":{"lch":[40.1313601009005083,68.6985541131433166,265.874320218178866],"luv":[40.1313601009005083,-4.94248222285034178,-68.5205312786852829],"rgb":[0.333333333333333315,0.333333333333333315,0.66666666666666663],"xyz":[0.142495125787763188,0.113303344371399051,0.394676706631810315],"hpluv":[265.874320218178866,217.221618066114,40.1313601009005083],"hsluv":[265.874320218178866,51.4705865731736907,40.1313601009005083]},"#5555bb":{"lch":[41.2412811653463791,81.6070675548115787,265.874320218178639],"luv":[41.2412811653463791,-5.8711785983783864,-81.3955940869131],"rgb":[0.333333333333333315,0.333333333333333315,0.733333333333333282],"xyz":[0.159632717895099807,0.120158381214333809,0.484934691730452117],"hpluv":[265.874320218178639,251.093199488524249,41.2412811653463791],"hsluv":[265.874320218178639,61.3584924374872642,41.2412811653463791]},"#5555cc":{"lch":[42.4413509436270431,93.9883543596933,265.874320218178468],"luv":[42.4413509436270431,-6.76194392407029365,-93.7447964935174838],"rgb":[0.333333333333333315,0.333333333333333315,0.8],"xyz":[0.178925093338821561,0.127875331391822611,0.586541202400722272],"hpluv":[265.874320218178468,281.011551484187919,42.4413509436270431],"hsluv":[265.874320218178468,71.0546332315999791,42.4413509436270431]},"#5555dd":{"lch":[43.7242196004532389,105.866759380085014,265.874320218178411],"luv":[43.7242196004532389,-7.61652967783202328,-105.592420264465588],"rgb":[0.333333333333333315,0.333333333333333315,0.866666666666666696],"xyz":[0.200443418889455105,0.136482661612076145,0.69987105030072827],"hpluv":[265.874320218178411,307.239379297131052,43.7242196004532389],"hsluv":[265.874320218178411,80.6500300064864462,43.7242196004532389]},"#5555ee":{"lch":[45.0824447652298588,117.287521338877212,265.874320218178354],"luv":[45.0824447652298588,-8.43819053636753402,-116.983586892732674],"rgb":[0.333333333333333315,0.333333333333333315,0.933333333333333348],"xyz":[0.224255599155629842,0.146007533718546162,0.825281866369251493],"hpluv":[265.874320218178354,330.128999417958312,45.0824447652298588],"hsluv":[265.874320218178354,90.2572110855712708,45.0824447652298588]},"#5555ff":{"lch":[46.508708270344421,128.30356479361032,265.874320218178241],"luv":[46.508708270344421,-9.23073412981071,-127.971083789162734],"rgb":[0.333333333333333315,0.333333333333333315,1],"xyz":[0.250426647565461236,0.156475953082478858,0.963116054661033338],"hpluv":[265.874320218178241,350.061034522531031,46.508708270344421],"hsluv":[265.874320218178241,99.9999999999992468,46.508708270344421]},"#ccdd00":{"lch":[84.2515012159558552,94.1174138813685772,92.7819892835375555],"luv":[84.2515012159558552,-4.56806363508048818,94.0064912138661128],"rgb":[0.8,0.866666666666666696,0],"xyz":[0.507566029502865779,0.645503626279608334,0.0978568736941549666],"hpluv":[92.7819892835375555,256.902059824464118,84.2515012159558552],"hsluv":[92.7819892835375555,100.000000000002373,84.2515012159558552]},"#ccdd11":{"lch":[84.2724460606142287,93.1910749716768692,92.8373396690251695],"luv":[84.2724460606142287,-4.61302172096193619,93.0768310858219508],"rgb":[0.8,0.866666666666666696,0.0666666666666666657],"xyz":[0.508577695002502939,0.645908292479463242,0.103184978658910603],"hpluv":[92.8373396690251695,254.758074317949962,84.2724460606142287],"hsluv":[92.8373396690251695,98.9747327605244465,84.2724460606142287]},"#ccdd22":{"lch":[84.3112490917695396,91.4838404394451175,92.9423140418060711],"luv":[84.3112490917695396,-4.69591125178302349,91.3632392106652],"rgb":[0.8,0.866666666666666696,0.133333333333333331],"xyz":[0.510453053140979884,0.646658435734854,0.113061864854889796],"hpluv":[92.9423140418060711,250.792999873820406,84.3112490917695396],"hsluv":[92.9423140418060711,97.0860193213801637,84.3112490917695396]},"#ccdd33":{"lch":[84.3750724084435291,88.7007441607730271,93.1221866378423329],"luv":[84.3750724084435291,-4.83112791130122865,88.5690816130525],"rgb":[0.8,0.866666666666666696,0.2],"xyz":[0.513540803873437701,0.647893536027837169,0.129324018712500932],"hpluv":[93.1221866378423329,244.290353733928498,84.3750724084435291],"hsluv":[93.1221866378423329,94.0094146319777,84.3750724084435291]},"#ccdd44":{"lch":[84.4670755276021197,84.7426243382763857,93.3985511967960491],"luv":[84.4670755276021197,-5.02363867224446459,84.5935897939611152],"rgb":[0.8,0.866666666666666696,0.266666666666666663],"xyz":[0.517998799117656561,0.649676734125524735,0.152802793665387571],"hpluv":[93.3985511967960491,234.956854948695792,84.4670755276021197],"hsluv":[93.3985511967960491,89.638788485123,84.4670755276021197]},"#ccdd55":{"lch":[84.5898637292301601,79.5568981087007359,93.8026723407881633],"luv":[84.5898637292301601,-5.27624840258561711,79.3817437416967095],"rgb":[0.8,0.866666666666666696,0.333333333333333315],"xyz":[0.523961213157018491,0.652061699741269485,0.184204840939361486],"hpluv":[93.8026723407881633,222.570337020009788,84.5898637292301601],"hsluv":[93.8026723407881633,83.9211409492819485,84.5898637292301601]},"#ccdd66":{"lch":[84.7456349568684857,73.1331501088793772,94.3836122863904],"luv":[84.7456349568684857,-5.58984810871231,72.9192103836116],"rgb":[0.8,0.866666666666666696,0.4],"xyz":[0.531546208930526731,0.655095698050672803,0.224152485346505448],"hpluv":[94.3836122863904,206.963810787645969,84.7456349568684857],"hsluv":[94.3836122863904,76.851201462777,84.7456349568684857]},"#ccdd77":{"lch":[84.9362580835765186,65.5005774458529828,95.2238145131341156],"luv":[84.9362580835765186,-5.96359854749608687,65.2285300930849274],"rgb":[0.8,0.866666666666666696,0.466666666666666674],"xyz":[0.540860221950728581,0.658821303258753654,0.273206287252903357],"hpluv":[95.2238145131341156,188.015270942662227,84.9362580835765186],"hsluv":[95.2238145131341156,68.4671748287691,84.9362580835765186]},"#ccdd88":{"lch":[85.1633194008604733,56.7265968622164536,96.4730545580279],"luv":[85.1633194008604733,-6.39512608731957588,56.3649638862273221],"rgb":[0.8,0.866666666666666696,0.533333333333333326],"xyz":[0.552000639052672493,0.663277470099531197,0.331879150656475552],"hpluv":[96.4730545580279,165.642146962004915,85.1633194008604733],"hsluv":[96.4730545580279,58.8458897999489707,85.1633194008604733]},"#ccdd99":{"lch":[85.4281525463895548,46.9188240443766134,98.432972024211054],"luv":[85.4281525463895548,-6.88075351903593724,46.4115425375783843],"rgb":[0.8,0.866666666666666696,0.6],"xyz":[0.565057603161745137,0.66850025574316041,0.400645828297593432],"hpluv":[98.432972024211054,139.807612964747022,85.4281525463895548],"hsluv":[98.432972024211054,48.0968721297954644,85.4281525463895548]},"#ccddaa":{"lch":[85.7318592309590457,36.2402041704229134,101.807730551991185],"luv":[85.7318592309590457,-7.41576493035038453,35.4733537857886176],"rgb":[0.8,0.866666666666666696,0.66666666666666663],"xyz":[0.580115296126997748,0.674523332929261477,0.479949677914592032],"hpluv":[101.807730551991185,110.570541660882469,85.7318592309590457],"hsluv":[101.807730551991185,36.355428538792907,85.7318592309590457]},"#ccddbb":{"lch":[86.0753247228475828,24.9849555175277693,108.661729708420211],"luv":[86.0753247228475828,-7.99469198849898,23.671351930590518],"rgb":[0.8,0.866666666666666696,0.733333333333333282],"xyz":[0.597252888234334312,0.681378369772196235,0.570207663013233779],"hpluv":[108.661729708420211,78.3375416693066313,86.0753247228475828],"hsluv":[108.661729708420211,23.7751141135998658,86.0753247228475828]},"#ccddcc":{"lch":[86.4592303781436158,14.0773589090278701,127.715012949224516],"luv":[86.4592303781436158,-8.61160385902942771,11.1360815742673065],"rgb":[0.8,0.866666666666666696,0.8],"xyz":[0.616545263678056066,0.689095319949685092,0.671814173683503935],"hpluv":[127.715012949224516,45.5363150686036633,86.4592303781436158],"hsluv":[127.715012949224516,10.5200784033656536,86.4592303781436158]},"#ccdddd":{"lch":[86.8840646031333677,9.47353258269296106,192.177050630057835],"luv":[86.8840646031333677,-9.26038246071566817,-1.99828333241680145],"rgb":[0.8,0.866666666666666696,0.866666666666666696],"xyz":[0.638063589228689665,0.697702650169938599,0.785144021583509932],"hpluv":[192.177050630057835,31.7497104564534354,86.8840646031333677],"hsluv":[192.177050630057835,13.7818607651735867,86.8840646031333677]},"#ccddee":{"lch":[87.3501331068194276,18.4943223550678582,237.507437159903361],"luv":[87.3501331068194276,-9.9349674143158051,-15.5992429896340141],"rgb":[0.8,0.866666666666666696,0.933333333333333348],"xyz":[0.661875769494864374,0.707227522276408616,0.910554837652033155],"hpluv":[237.507437159903361,64.5162574350921432,87.3501331068194276],"hsluv":[237.507437159903361,51.9237885878372083,87.3501331068194276]},"#ccddff":{"lch":[87.8575689716950876,31.3946063828198874,250.2096672964189],"luv":[87.8575689716950876,-10.6295595905023852,-29.5403752996496962],"rgb":[0.8,0.866666666666666696,1],"xyz":[0.688046817904695795,0.717695941640341339,1.04838902594381489],"hpluv":[250.2096672964189,114.576774718516177,87.8575689716950876],"hsluv":[250.2096672964189,99.999999999992923,87.8575689716950876]},"#556600":{"lch":[40.3019892206732919,46.2375853800199934,99.381148915360626],"luv":[40.3019892206732919,-7.53678920078613679,45.6191967302971264],"rgb":[0.333333333333333315,0.4,0],"xyz":[0.0849739168694777086,0.114339753133439206,0.0175932549799886241],"hpluv":[99.381148915360626,145.582103533726,40.3019892206732919],"hsluv":[99.381148915360626,100.000000000002302,40.3019892206732919]},"#556611":{"lch":[40.3683315206726334,43.7939991819964618,99.9948312384981364],"luv":[40.3683315206726334,-7.60085740022420797,43.1293557931736729],"rgb":[0.333333333333333315,0.4,0.0666666666666666657],"xyz":[0.0859855823691148269,0.114744419333294059,0.0229213599447442573],"hpluv":[99.9948312384981364,137.661701347396985,40.3683315206726334],"hsluv":[99.9948312384981364,94.2576138599214204,40.3683315206726334]},"#556622":{"lch":[40.4909010608148421,39.4175015547736436,101.28961011017671],"luv":[40.4909010608148421,-7.7166980000465113,38.6547797923705758],"rgb":[0.333333333333333315,0.4,0.133333333333333331],"xyz":[0.0878609405075918559,0.115494562588684874,0.0327982461407234499],"hpluv":[101.28961011017671,123.529583899053776,40.4909010608148421],"hsluv":[101.28961011017671,83.977954812826539,40.4909010608148421]},"#556633":{"lch":[40.6915589391927455,32.6300466430477343,104.01044750968255],"luv":[40.6915589391927455,-7.89969574444685207,31.6593548745491518],"rgb":[0.333333333333333315,0.4,0.2],"xyz":[0.0909486912400495895,0.116729662881667987,0.0490603999983346],"hpluv":[104.01044750968255,101.754281640855311,40.6915589391927455],"hsluv":[104.01044750968255,68.015525760737134,40.6915589391927455]},"#556644":{"lch":[40.9787805135115306,23.7356999706126039,110.078417815454017],"luv":[40.9787805135115306,-8.1486066005911173,22.2931304119395044],"rgb":[0.333333333333333315,0.4,0.266666666666666663],"xyz":[0.0954066864842684631,0.118512860979355567,0.0725391749512212386],"hpluv":[110.078417815454017,73.4991539757345436,40.9787805135115306],"hsluv":[110.078417815454017,46.8659194429644117,40.9787805135115306]},"#556655":{"lch":[41.3584605937638372,13.8246485480389332,127.71501294923371],"luv":[41.3584605937638372,-8.45701225317865202,10.9361716896901875],"rgb":[0.333333333333333315,0.4,0.333333333333333315],"xyz":[0.101369100523630462,0.120897826595100399,0.10394122222519514],"hpluv":[127.71501294923371,42.4159365242361659,41.3584605937638372],"hsluv":[127.71501294923371,21.5972717302380097,41.3584605937638372]},"#556666":{"lch":[41.8343160733152146,9.01834401177998402,192.177050630060307],"luv":[41.8343160733152146,-8.8154354231024481,-1.90226891261946607],"rgb":[0.333333333333333315,0.4,0.4],"xyz":[0.108954096297138633,0.123931824904503718,0.143888866632339102],"hpluv":[192.177050630060307,27.3547941496945484,41.8343160733152146],"hsluv":[192.177050630060307,27.2477194602778816,41.8343160733152146]},"#556677":{"lch":[42.4081371223492525,18.1914318380534858,239.570903430569189],"luv":[42.4081371223492525,-9.21344558994119289,-15.6856817728697795],"rgb":[0.333333333333333315,0.4,0.466666666666666674],"xyz":[0.118268109317340553,0.127657430112584541,0.192942668538737],"hpluv":[239.570903430569189,54.4323412384199443,42.4081371223492525],"hsluv":[239.570903430569189,33.1626844996427934,42.4081371223492525]},"#556688":{"lch":[43.0800011190655425,31.444407039181371,252.144687081813345],"luv":[43.0800011190655425,-9.64130614192028546,-29.9298504828121246],"rgb":[0.333333333333333315,0.4,0.533333333333333326],"xyz":[0.129408526419284381,0.132113596953362111,0.251615531942309179],"hpluv":[252.144687081813345,92.6204805766441694,43.0800011190655425],"hsluv":[252.144687081813345,39.0862788716996903,43.0800011190655425]},"#556699":{"lch":[43.8484890486876964,45.3842681536749,257.153237313451427],"luv":[43.8484890486876964,-10.090933534038701,-44.2482186789059639],"rgb":[0.333333333333333315,0.4,0.6],"xyz":[0.142465490528357108,0.137336382596991269,0.320382209583427113],"hpluv":[257.153237313451427,131.337888607863903,43.8484890486876964],"hsluv":[257.153237313451427,44.8182326355090055,43.8484890486876964]},"#5566aa":{"lch":[44.7109144588579,59.3119903927914223,259.748012643434],"luv":[44.7109144588579,-10.5562103110165033,-58.3650462882037928],"rgb":[0.333333333333333315,0.4,0.66666666666666663],"xyz":[0.157523183493609636,0.143359459783092391,0.399686059200425714],"hpluv":[259.748012643434,168.332615885742257,44.7109144588579],"hsluv":[259.748012643434,50.2202557252039341,44.7109144588579]},"#5566bb":{"lch":[45.6635615252987463,72.9454914642558805,261.300749278862554],"luv":[45.6635615252987463,-11.0328519112314041,-72.1063166696695532],"rgb":[0.333333333333333315,0.4,0.733333333333333282],"xyz":[0.174660775600946283,0.15021449662602715,0.48994404429906746],"hpluv":[261.300749278862554,202.706651650989187,45.6635615252987463],"hsluv":[261.300749278862554,56.1551480082100767,45.6635615252987463]},"#5566cc":{"lch":[46.7019230239281953,86.153038102066219,262.316955218783903],"luv":[46.7019230239281953,-11.5180515282988498,-85.3796255742992],"rgb":[0.333333333333333315,0.4,0.8],"xyz":[0.193953151044668037,0.157931446803515951,0.591550554969337616],"hpluv":[262.316955218783903,234.085848684940913,46.7019230239281953],"hsluv":[262.316955218783903,67.0801136297732086,46.7019230239281953]},"#5566dd":{"lch":[47.8209277182799539,98.8836589551542,263.023825475898036],"luv":[47.8209277182799539,-12.010072956506761,-98.1515978267222664],"rgb":[0.333333333333333315,0.4,0.866666666666666696],"xyz":[0.215471476595301581,0.166538777023769485,0.704880402869343614],"hpluv":[263.023825475898036,262.38914084011509,47.8209277182799539],"hsluv":[263.023825475898036,77.9738615315733909,47.8209277182799539]},"#5566ee":{"lch":[49.0151480019121095,111.133834597019145,263.537783903780621],"luv":[49.0151480019121095,-12.5078880087352609,-110.427722650603215],"rgb":[0.333333333333333315,0.4,0.933333333333333348],"xyz":[0.23928365686147629,0.176063649130239502,0.830291218937866837],"hpluv":[263.537783903780621,287.710232398192659,49.0151480019121095],"hsluv":[263.537783903780621,88.9133133505171145,49.0151480019121095]},"#5566ff":{"lch":[50.2789812841098751,122.927042369796439,263.924295565134457],"luv":[50.2789812841098751,-13.0108962765956715,-122.236550687040406],"rgb":[0.333333333333333315,0.4,1],"xyz":[0.265454705271307712,0.186532068494172198,0.968125407229648682],"hpluv":[263.924295565134457,310.2417842032321,50.2789812841098751],"hsluv":[263.924295565134457,99.99999999999919,50.2789812841098751]},"#ccee00":{"lch":[88.9159222564839382,101.512339113439552,98.3897184755654],"luv":[88.9159222564839382,-14.8112090817394879,100.426007975120399],"rgb":[0.8,0.933333333333333348,0],"xyz":[0.554744805843380595,0.739861178960639299,0.113583132474326151],"hpluv":[98.3897184755654,409.405376777149172,88.9159222564839382],"hsluv":[98.3897184755654,100.000000000002402,88.9159222564839382]},"#ccee11":{"lch":[88.9350466502285855,100.665090554083037,98.4749110233884863],"luv":[88.9350466502285855,-14.8356507509631186,99.5658773027044],"rgb":[0.8,0.933333333333333348,0.0666666666666666657],"xyz":[0.555756471343017755,0.740265845160494207,0.118911237439081788],"hpluv":[98.4749110233884863,406.753799510206477,88.9350466502285855],"hsluv":[98.4749110233884863,99.103544824997428,88.9350466502285855]},"#ccee22":{"lch":[88.9704797513205108,99.1029038393990191,98.635890718104875],"luv":[88.9704797513205108,-14.8807650249594605,97.9793262973016823],"rgb":[0.8,0.933333333333333348,0.133333333333333331],"xyz":[0.557631829481494701,0.741015988415885,0.12878812363506098],"hpluv":[98.635890718104875,401.844579090604725,88.9704797513205108],"hsluv":[98.635890718104875,97.4508266239822376,88.9704797513205108]},"#ccee33":{"lch":[89.0287677898111696,96.5543294248683281,98.9099371535565837],"luv":[89.0287677898111696,-14.95450175665089,95.3892101230339335],"rgb":[0.8,0.933333333333333348,0.2],"xyz":[0.560719580213952518,0.742251088708868134,0.145050277492672131],"hpluv":[98.9099371535565837,393.778440936160052,89.0287677898111696],"hsluv":[98.9099371535565837,94.7550356083218333,89.0287677898111696]},"#ccee44":{"lch":[89.1128082270408157,92.9258219449750698,99.3266297509707101],"luv":[89.1128082270408157,-15.0597883526499068,91.6973890518296],"rgb":[0.8,0.933333333333333348,0.266666666666666663],"xyz":[0.565177575458171377,0.7440342868065557,0.168529052445558769],"hpluv":[99.3266297509707101,382.168331694223468,89.1128082270408157],"hsluv":[99.3266297509707101,90.9176847425828782,89.1128082270408157]},"#ccee55":{"lch":[89.224999764075946,88.1655281542066263,99.9265688821158591],"luv":[89.224999764075946,-15.1984931464969293,86.8456456063635187],"rgb":[0.8,0.933333333333333348,0.333333333333333315],"xyz":[0.571139989497533307,0.74641925242230045,0.199931099719532657],"hpluv":[99.9265688821158591,366.702481299920066,89.224999764075946],"hsluv":[99.9265688821158591,85.8839575374920372,89.224999764075946]},"#ccee66":{"lch":[89.3673776950467555,82.2600687786622444,100.76990980050725],"luv":[89.3673776950467555,-15.3715621348797811,80.8111006793235873],"rgb":[0.8,0.933333333333333348,0.4],"xyz":[0.578724985271041548,0.749453250731703768,0.239878744126676646],"hpluv":[100.76990980050725,347.124780760482849,89.3673776950467555],"hsluv":[100.76990980050725,79.6381055931254451,89.3673776950467555]},"#ccee77":{"lch":[89.5416863487684651,75.2338064272131817,101.95104715507324],"luv":[89.5416863487684651,-15.5791079616514043,73.6031047215169707],"rgb":[0.8,0.933333333333333348,0.466666666666666674],"xyz":[0.588038998291243398,0.753178855939784619,0.288932546033074555],"hpluv":[101.95104715507324,323.225079834159544,89.5416863487684651],"hsluv":[101.95104715507324,72.2002225208687349,89.5416863487684651]},"#ccee88":{"lch":[89.7494222523926481,67.150335761217363,103.626883623375818],"luv":[89.7494222523926481,-15.8204941270879562,65.2600916212887654],"rgb":[0.8,0.933333333333333348,0.533333333333333326],"xyz":[0.599179415393187309,0.757635022780562162,0.347605409436646695],"hpluv":[103.626883623375818,294.840431689210504,89.7494222523926481],"hsluv":[103.626883623375818,63.6228180815060256,89.7494222523926481]},"#ccee99":{"lch":[89.9918618926625697,58.1187887690418705,106.076645299715267],"luv":[89.9918618926625697,-16.094429395756972,55.8458857070554586],"rgb":[0.8,0.933333333333333348,0.6],"xyz":[0.61223637950226,0.762857808424191375,0.41637208707776463],"hpluv":[106.076645299715267,261.881276027636488,89.9918618926625697],"hsluv":[106.076645299715267,53.9866751643902418,89.9918618926625697]},"#cceeaa":{"lch":[90.2700807835134071,48.3136880988356481,109.842100564752428],"luv":[90.2700807835134071,-16.3990756203548145,45.4453823452884791],"rgb":[0.8,0.933333333333333348,0.66666666666666663],"xyz":[0.627294072467512565,0.768880885610292442,0.495675936694763231],"hpluv":[109.842100564752428,224.429228200920562,90.2700807835134071],"hsluv":[109.842100564752428,43.3959332818477037,90.2700807835134071]},"#cceebb":{"lch":[90.5849674500281736,38.0375276056681,116.096591597387416],"luv":[90.5849674500281736,-16.7321662581560417,34.1597441246474745],"rgb":[0.8,0.933333333333333348,0.733333333333333282],"xyz":[0.644431664574849128,0.7757359224532272,0.585933921793405],"hpluv":[116.096591597387416,183.067580850930824,90.5849674500281736],"hsluv":[116.096591597387416,31.9725829176952736,90.5849674500281736]},"#cceecc":{"lch":[90.9372344233822,27.9388105970907,127.715012949233042],"luv":[90.9372344233822,-17.0911298567764973,22.1013668762570106],"rgb":[0.8,0.933333333333333348,0.8],"xyz":[0.663724040018570882,0.783452872630716057,0.687540432463675133],"hpluv":[127.715012949233042,140.086760618050221,90.9372344233822],"hsluv":[127.715012949233042,30.3633811556705,90.9372344233822]},"#cceedd":{"lch":[91.327427526889025,19.8359452431300802,151.749458426713772],"luv":[91.327427526889025,-17.4732117028180483,9.38890816213244861],"rgb":[0.8,0.933333333333333348,0.866666666666666696],"xyz":[0.685242365569204481,0.792060202850969564,0.800870280363681131],"hpluv":[151.749458426713772,104.258293798779974,91.327427526889025],"hsluv":[151.749458426713772,29.0871711351253381,91.327427526889025]},"#cceeee":{"lch":[91.7559342603931,18.2870370266976643,192.177050630059739],"luv":[91.7559342603931,-17.87558711202,-3.8573447624494035],"rgb":[0.8,0.933333333333333348,0.933333333333333348],"xyz":[0.709054545835379191,0.801585074957439581,0.926281096432204354],"hpluv":[192.177050630059739,101.458793010104,91.7559342603931],"hsluv":[192.177050630059739,27.4217374065650326,91.7559342603931]},"#cceeff":{"lch":[92.2229917973594553,25.3309747642836847,223.758903531404655],"luv":[92.2229917973594553,-18.2954610486514362,-17.5195430170439934],"rgb":[0.8,0.933333333333333348,1],"xyz":[0.735225594245210612,0.812053494321372304,1.06411528472398609],"hpluv":[223.758903531404655,149.53216426558339,92.2229917973594553],"hsluv":[223.758903531404655,99.9999999999890861,92.2229917973594553]},"#557700":{"lch":[45.8045523271613533,55.5294361467329836,107.801769483020877],"luv":[45.8045523271613533,-16.9767207468495087,52.8706840456749276],"rgb":[0.333333333333333315,0.466666666666666674,0],"xyz":[0.103427654922895337,0.151247229240274977,0.023744500997794328],"hpluv":[107.801769483020877,153.83457187868342,45.8045523271613533],"hsluv":[107.801769483020877,100.000000000002288,45.8045523271613533]},"#557711":{"lch":[45.859623178970125,53.470483995502839,108.496139146384877],"luv":[45.859623178970125,-16.9630166203079504,50.7084679896019068],"rgb":[0.333333333333333315,0.466666666666666674,0.0666666666666666657],"xyz":[0.104439320422532456,0.15165189544012983,0.0290726059625499578],"hpluv":[108.496139146384877,147.952722071756682,45.859623178970125],"hsluv":[108.496139146384877,95.6324690191426,45.859623178970125]},"#557722":{"lch":[45.9614512879267494,49.76586948312967,109.899607245517743],"luv":[45.9614512879267494,-16.93896350220896,46.7943723206405409],"rgb":[0.333333333333333315,0.466666666666666674,0.133333333333333331],"xyz":[0.106314678561009485,0.152402038695520659,0.0389494921585291573],"hpluv":[109.899607245517743,137.396980684000368,45.9614512879267494],"hsluv":[109.899607245517743,87.7486210093461239,45.9614512879267494]},"#557733":{"lch":[46.1283843073061,43.9801463057798472,112.602269297118809],"luv":[46.1283843073061,-16.9029726498973396,40.6022509803905223],"rgb":[0.333333333333333315,0.466666666666666674,0.2],"xyz":[0.109402429293467218,0.153637138988503757,0.0552116460161403],"hpluv":[112.602269297118809,120.983948144693443,46.1283843073061],"hsluv":[112.602269297118809,75.3373974156097432,46.1283843073061]},"#557744":{"lch":[46.3678258482665413,36.3216896494577526,117.654446368962965],"luv":[46.3678258482665413,-16.8582748313623227,32.1724060135666861],"rgb":[0.333333333333333315,0.466666666666666674,0.266666666666666663],"xyz":[0.113860424537686092,0.155420337086191351,0.0786904209690269391],"hpluv":[117.654446368962965,99.4005156049610861,46.3678258482665413],"hsluv":[117.654446368962965,58.5682493514162346,46.3678258482665413]},"#557755":{"lch":[46.6852246722490349,27.4798560002662136,127.715012949237362],"luv":[46.6852246722490349,-16.8103715694690621,21.7383047520213317],"rgb":[0.333333333333333315,0.466666666666666674,0.333333333333333315],"xyz":[0.119822838577048091,0.157805302701936184,0.110092468243000841],"hpluv":[127.715012949237362,74.6920408293198506,46.6852246722490349],"hsluv":[127.715012949237362,38.0315615795731219,46.6852246722490349]},"#557766":{"lch":[47.0844103757355299,19.3533005907945039,150.034269154893224],"luv":[47.0844103757355299,-16.7662346577491,9.66662397939114371],"rgb":[0.333333333333333315,0.466666666666666674,0.4],"xyz":[0.127407834350556276,0.160839301011339475,0.150040112650144802],"hpluv":[150.034269154893224,52.1575559127659147,47.0844103757355299],"hsluv":[150.034269154893224,41.6155983808333403,47.0844103757355299]},"#557777":{"lch":[47.5677829408255519,17.1184872206298522,192.177050630060563],"luv":[47.5677829408255519,-16.733329138647683,-3.61085871511915846],"rgb":[0.333333333333333315,0.466666666666666674,0.466666666666666674],"xyz":[0.136721847370758182,0.164564906219420298,0.199093914556542712],"hpluv":[192.177050630060563,45.665876663612373,47.5677829408255519],"hsluv":[192.177050630060563,45.4871270252879683,47.5677829408255519]},"#557788":{"lch":[48.1364533988364371,24.3189053895014062,226.569261606948],"luv":[48.1364533988364371,-16.7186932071720697,-17.6605338760746164],"rgb":[0.333333333333333315,0.466666666666666674,0.533333333333333326],"xyz":[0.147862264472702,0.169021073060197896,0.257766777960114879],"hpluv":[226.569261606948,64.1075619232690173,48.1364533988364371],"hsluv":[226.569261606948,49.4930397679002567,48.1364533988364371]},"#557799":{"lch":[48.7903733600049776,36.1922931768580227,242.470518495943224],"luv":[48.7903733600049776,-16.7282575252316086,-32.0943528610435749],"rgb":[0.333333333333333315,0.466666666666666674,0.6],"xyz":[0.160919228581774709,0.174243858703827054,0.326533455601232814],"hpluv":[242.470518495943224,94.128532149155447,48.7903733600049776],"hsluv":[242.470518495943224,53.4981409183259657,48.7903733600049776]},"#5577aa":{"lch":[49.5284680294880957,49.5215284063763121,250.210257263218182],"luv":[49.5284680294880957,-16.7664778987851584,-46.5968560588918308],"rgb":[0.333333333333333315,0.466666666666666674,0.66666666666666663],"xyz":[0.175976921547027265,0.180266935889928148,0.405837305218231414],"hpluv":[250.210257263218182,126.875705911364861,49.5284680294880957],"hsluv":[250.210257263218182,57.3943781585142503,49.5284680294880957]},"#5577bb":{"lch":[50.3487764471929324,63.2168000831305,254.554261837862072],"luv":[50.3487764471929324,-16.8362555209572413,-60.9336057753316069],"rgb":[0.333333333333333315,0.466666666666666674,0.733333333333333282],"xyz":[0.193114513654363912,0.187121972732862907,0.496095290316873161],"hpluv":[254.554261837862072,159.324628464713726,50.3487764471929324],"hsluv":[254.554261837862072,61.1035457400689737,50.3487764471929324]},"#5577cc":{"lch":[51.2485971738404942,76.8367273058076279,257.264224247337211],"luv":[51.2485971738404942,-16.9390629845235594,-74.9463195111900546],"rgb":[0.333333333333333315,0.466666666666666674,0.8],"xyz":[0.212406889098085638,0.194838922910351708,0.597701800987143317],"hpluv":[257.264224247337211,190.250673687597981,51.2485971738404942],"hsluv":[257.264224247337211,64.5753193228694329,51.2485971738404942]},"#5577dd":{"lch":[52.2246350466270428,90.1721178795433502,259.084439545341468],"luv":[52.2246350466270428,-17.075183181685393,-88.5406627612090347],"rgb":[0.333333333333333315,0.466666666666666674,0.866666666666666696],"xyz":[0.233925214648719182,0.203446253130605242,0.711031648887149315],"hpluv":[259.084439545341468,219.096874823476185,52.2246350466270428],"hsluv":[259.084439545341468,74.9139940771913757,52.2246350466270428]},"#5577ee":{"lch":[53.2731438322457791,103.123503170291656,260.373961187264626],"luv":[53.2731438322457791,-17.2439851141504441,-101.671539200978515],"rgb":[0.333333333333333315,0.466666666666666674,0.933333333333333348],"xyz":[0.257737394914893947,0.212971125237075287,0.836442464955672538],"hpluv":[260.373961187264626,245.63410016831412,53.2731438322457791],"hsluv":[260.373961187264626,87.3510385353649,53.2731438322457791]},"#5577ff":{"lch":[54.3900599484937572,115.652149768064447,261.324783585170792],"luv":[54.3900599484937572,-17.4441870719707097,-114.32899931064253],"rgb":[0.333333333333333315,0.466666666666666674,1],"xyz":[0.283908443324725313,0.223439544601007983,0.974276653247454383],"hpluv":[261.324783585170792,269.819603010977914,54.3900599484937572],"hsluv":[261.324783585170792,99.9999999999989768,54.3900599484937572]},"#ccff00":{"lch":[93.605159534834371,109.568762044642341,102.903766821995461],"luv":[93.605159534834371,-24.4682604068618268,106.801768939739262],"rgb":[0.8,1,0],"xyz":[0.606597178273054372,0.843565923819988406,0.130867256617550276],"hpluv":[102.903766821995461,795.170643052662513,93.605159534834371],"hsluv":[102.903766821995461,100.000000000002359,93.605159534834371]},"#ccff11":{"lch":[93.6226829283917681,108.793716578542018,103.00230683973929],"luv":[93.6226829283917681,-24.4775292120886689,106.004355243751533],"rgb":[0.8,1,0.0666666666666666657],"xyz":[0.607608843772691531,0.843970590019843314,0.136195361582305913],"hpluv":[103.00230683973929,791.823376913543598,93.6226829283917681],"hsluv":[103.00230683973929,99.9999999999883755,93.6226829283917681]},"#ccff22":{"lch":[93.6551518183817535,107.364125357399203,103.187929529698394],"luv":[93.6551518183817535,-24.4946701604029187,104.532609971684906],"rgb":[0.8,1,0.133333333333333331],"xyz":[0.609484201911168477,0.844720733275234115,0.146072247778285091],"hpluv":[103.187929529698394,785.615721446726184,93.6551518183817535],"hsluv":[103.187929529698394,99.9999999999883613,93.6551518183817535]},"#ccff33":{"lch":[93.7085695338431464,105.030410790236445,103.502196488744218],"luv":[93.7085695338431464,-24.5227776356263192,102.127472150246831],"rgb":[0.8,1,0.2],"xyz":[0.612571952643626294,0.845955833568217241,0.162334401635896242],"hpluv":[103.502196488744218,775.386532390006209,93.7085695338431464],"hsluv":[103.502196488744218,99.9999999999882334,93.7085695338431464]},"#ccff44":{"lch":[93.7856006692118456,101.704796230104463,103.975902087852319],"luv":[93.7856006692118456,-24.5631097372148304,98.6940687997238],"rgb":[0.8,1,0.266666666666666663],"xyz":[0.617029947887845154,0.847739031665904808,0.18581317658878288],"hpluv":[103.975902087852319,760.597322717251814,93.7856006692118456],"hsluv":[103.975902087852319,99.9999999999883329,93.7856006692118456]},"#ccff55":{"lch":[93.8884584724407887,97.3367975087049473,104.649262803016768],"luv":[93.8884584724407887,-24.6166025777849207,94.1725810773922802],"rgb":[0.8,1,0.333333333333333315],"xyz":[0.622992361927207083,0.850123997281649557,0.217215223862756796],"hpluv":[104.649262803016768,740.773636872505676,93.8884584724407887],"hsluv":[104.649262803016768,99.999999999988,93.8884584724407887]},"#ccff66":{"lch":[94.0190298395239381,91.9106503723783561,105.578857731119598],"luv":[94.0190298395239381,-24.6839280463924027,88.5340123798424514],"rgb":[0.8,1,0.4],"xyz":[0.630577357700715324,0.853157995591052876,0.257162868269900757],"hpluv":[105.578857731119598,715.472563222964368,94.0190298395239381],"hsluv":[105.578857731119598,99.9999999999875371,94.0190298395239381]},"#ccff77":{"lch":[94.1789424927264349,85.4453105292158597,106.848417981185563],"luv":[94.1789424927264349,-24.7655268674123263,81.7775627566241781],"rgb":[0.8,1,0.466666666666666674],"xyz":[0.639891370720917174,0.856883600799133727,0.306216670176298666],"hpluv":[106.848417981185563,684.262206540111833,94.1789424927264349],"hsluv":[106.848417981185563,99.9999999999873381,94.1789424927264349]},"#ccff88":{"lch":[94.3696051468525781,77.9966506735583778,108.587502777405675],"luv":[94.3696051468525781,-24.8616333733667219,73.92818611532],"rgb":[0.8,1,0.533333333333333326],"xyz":[0.651031787822861086,0.861339767639911269,0.364889533579870862],"hpluv":[108.587502777405675,646.714804777793233,94.3696051468525781],"hsluv":[108.587502777405675,99.9999999999870397,94.3696051468525781]},"#ccff99":{"lch":[94.5922333645115572,69.6635615227201868,111.00626449694991],"luv":[94.5922333645115572,-24.9722983929036886,65.0338074927618],"rgb":[0.8,1,0.6],"xyz":[0.66408875193193373,0.866562553283540482,0.433656211220988741],"hpluv":[111.00626449694991,602.43247210261859,94.5922333645115572],"hsluv":[111.00626449694991,99.999999999986656,94.5922333645115572]},"#ccffaa":{"lch":[94.8478672375315881,60.6030718965076574,114.464397640121035],"luv":[94.8478672375315881,-25.0974127381864349,55.1620539605116],"rgb":[0.8,1,0.66666666666666663],"xyz":[0.679146444897186341,0.872585630469641549,0.512960060837987397],"hpluv":[114.464397640121035,551.164539659931279,94.8478672375315881],"hsluv":[114.464397640121035,99.9999999999858886,94.8478672375315881]},"#ccffbb":{"lch":[95.1373841969384,51.0680528276179899,119.615591899534252],"luv":[95.1373841969384,-25.2367319023901224,44.3965469658538439],"rgb":[0.8,1,0.733333333333333282],"xyz":[0.696284037004522904,0.879440667312576307,0.603218045936629088],"hpluv":[119.615591899534252,493.192076617112832,95.1373841969384],"hsluv":[119.615591899534252,99.999999999985036,95.1373841969384]},"#ccffcc":{"lch":[95.4615088709507802,41.5047839306073527,127.715012949235671],"luv":[95.4615088709507802,-25.3899015983654444,32.8329101048280876],"rgb":[0.8,1,0.8],"xyz":[0.715576412448244659,0.887157617490065165,0.704824556606899244],"hpluv":[127.715012949235671,430.524428546451247,95.4615088709507802],"hsluv":[127.715012949235671,99.9999999999844,95.4615088709507802]},"#ccffdd":{"lch":[95.8208211701733603,32.8093273722257,141.163585516297758],"luv":[95.8208211701733603,-25.5564832849791728,20.5746962243056899],"rgb":[0.8,1,0.866666666666666696],"xyz":[0.737094737998878258,0.895764947710318671,0.818154404506905242],"hpluv":[141.163585516297758,370.598640927928557,95.8208211701733603],"hsluv":[141.163585516297758,99.9999999999829612,95.8208211701733603]},"#ccffee":{"lch":[96.2157633520208293,26.8716381406037179,163.283084738459195],"luv":[96.2157633520208293,-25.7359786647352209,7.72944619800421506],"rgb":[0.8,1,0.933333333333333348],"xyz":[0.760906918265053,0.905289819816788688,0.943565220575428465],"hpluv":[163.283084738459195,336.210724351278486,96.2157633520208293],"hsluv":[163.283084738459195,99.9999999999813411,96.2157633520208293]},"#ccffff":{"lch":[96.6466465538527899,26.5246444827845806,192.177050630060279],"luv":[96.6466465538527899,-25.9278521925209873,-5.59493034995961125],"rgb":[0.8,1,1],"xyz":[0.787077966674884388,0.915758239180721412,1.08139940886721031],"hpluv":[192.177050630060279,375.729722461639881,96.6466465538527899],"hsluv":[192.177050630060279,99.9999999999789111,96.6466465538527899]},"#558800":{"lch":[51.3121649295003266,65.2833526322192,113.133039202335894],"luv":[51.3121649295003266,-25.6477049188799029,60.0342515843809466],"rgb":[0.333333333333333315,0.533333333333333326,0],"xyz":[0.125500024647865804,0.195391968690216522,0.0311019575727842744],"hpluv":[113.133039202335894,161.443824642532,51.3121649295003266],"hsluv":[113.133039202335894,100.000000000002416,51.3121649295003266]},"#558811":{"lch":[51.3586018009433758,63.5282336791645363,113.757082680238781],"luv":[51.3586018009433758,-25.5929736747770171,58.1449582756467862],"rgb":[0.333333333333333315,0.533333333333333326,0.0666666666666666657],"xyz":[0.126511690147502937,0.195796634890071375,0.0364300625375399076],"hpluv":[113.757082680238781,156.961418592175818,51.3586018009433758],"hsluv":[113.757082680238781,96.6047658949560315,51.3586018009433758]},"#558822":{"lch":[51.4445144263052754,60.3557257759597761,114.985955444381503],"luv":[51.4445144263052754,-25.4940226670596211,54.707115096615226],"rgb":[0.333333333333333315,0.533333333333333326,0.133333333333333331],"xyz":[0.128387048285979938,0.196546778145462203,0.0463069487335191],"hpluv":[114.985955444381503,148.873956641671725,51.4445144263052754],"hsluv":[114.985955444381503,90.4397474873449454,51.4445144263052754]},"#558833":{"lch":[51.5854933484676366,55.3603846502330512,117.238150003797628],"luv":[51.5854933484676366,-25.3378965271949284,49.2215723864945502],"rgb":[0.333333333333333315,0.533333333333333326,0.2],"xyz":[0.131474799018437671,0.197781878438445302,0.0625691025911302434],"hpluv":[117.238150003797628,136.179218375975154,51.5854933484676366],"hsluv":[117.238150003797628,80.6386945119108844,51.5854933484676366]},"#558844":{"lch":[51.788002513998137,48.6519311113283521,121.094634958525788],"luv":[51.788002513998137,-25.1264429677671792,41.6614001762900799],"rgb":[0.333333333333333315,0.533333333333333326,0.266666666666666663],"xyz":[0.135932794262656559,0.199565076536132896,0.0860478775440168819],"hpluv":[121.094634958525788,119.20933058927335,51.788002513998137],"hsluv":[121.094634958525788,67.2069053574962112,51.788002513998137]},"#558855":{"lch":[52.0569745246593669,40.6501953066927229,127.715012949238655],"luv":[52.0569745246593669,-24.8671203906742271,32.1568764333225801],"rgb":[0.333333333333333315,0.533333333333333326,0.333333333333333315],"xyz":[0.141895208302018572,0.201950042151877729,0.117449924817990797],"hpluv":[127.715012949238655,99.0884509425644495,52.0569745246593669],"hsluv":[127.715012949238655,50.4536826414745647,52.0569745246593669]},"#558866":{"lch":[52.3961000606252156,32.296627997442414,139.535908661945541],"luv":[52.3961000606252156,-24.57168930668605,20.9595864611130054],"rgb":[0.333333333333333315,0.533333333333333326,0.4],"xyz":[0.149480204075526729,0.20498404046128102,0.157397569225134759],"hpluv":[139.535908661945541,78.2163498792783258,52.3961000606252156],"hsluv":[139.535908661945541,52.7717106037122505,52.3961000606252156]},"#558877":{"lch":[52.8079833364028417,25.6675371494617757,160.900154113051656],"luv":[52.8079833364028417,-24.2545338981935465,8.39881233868101873],"rgb":[0.333333333333333315,0.533333333333333326,0.466666666666666674],"xyz":[0.158794217095728663,0.208709645669361843,0.206451371131532668],"hpluv":[160.900154113051656,61.6770996704155934,52.8079833364028417],"hsluv":[160.900154113051656,55.3375604028527732,52.8079833364028417]},"#558888":{"lch":[53.2942460543653311,24.4817100724115,192.177050630060762],"luv":[53.2942460543653311,-23.9308828659180151,-5.16400748714853908],"rgb":[0.333333333333333315,0.533333333333333326,0.533333333333333326],"xyz":[0.169934634197672463,0.213165812510139441,0.265124234535104808],"hpluv":[192.177050630060762,58.2908991249141764,53.2942460543653311],"hsluv":[192.177050630060762,58.0627314448554515,53.2942460543653311]},"#558899":{"lch":[53.8556132197311399,30.5464388010487,219.367537814697016],"luv":[53.8556132197311399,-23.6152401502492637,-19.3753801529742589],"rgb":[0.333333333333333315,0.533333333333333326,0.6],"xyz":[0.18299159830674519,0.218388598153768598,0.333890912176222743],"hpluv":[219.367537814697016,71.9728892793730921,53.8556132197311399],"hsluv":[219.367537814697016,60.861676067449,53.8556132197311399]},"#5588aa":{"lch":[54.491995562986105,41.1624410064978434,235.49057853568965],"luv":[54.491995562986105,-23.3202411533326384,-33.9192114024460452],"rgb":[0.333333333333333315,0.533333333333333326,0.66666666666666663],"xyz":[0.198049291271997718,0.224411675339869693,0.413194761793221343],"hpluv":[235.49057853568965,95.8534470006528494,54.491995562986105],"hsluv":[235.49057853568965,63.6587877222075207,54.491995562986105]},"#5588bb":{"lch":[55.2025746803936102,53.7318677649407164,244.589939769846183],"luv":[55.2025746803936102,-23.0560079965343867,-48.5338449823709865],"rgb":[0.333333333333333315,0.533333333333333326,0.733333333333333282],"xyz":[0.215186883379334393,0.231266712182804451,0.503452746891863],"hpluv":[244.589939769846183,123.512789385845494,55.2025746803936102],"hsluv":[244.589939769846183,66.3923972476147,55.2025746803936102]},"#5588cc":{"lch":[55.9858924676882,67.0258402153595227,250.085698604565607],"luv":[55.9858924676882,-22.8299557310329213,-63.0179052166444436],"rgb":[0.333333333333333315,0.533333333333333326,0.8],"xyz":[0.234479258823056119,0.238983662360293253,0.60505925756213319],"hpluv":[250.085698604565607,151.915814945370954,55.9858924676882],"hsluv":[250.085698604565607,69.0160689386852653,55.9858924676882]},"#5588dd":{"lch":[56.8399439373084761,80.4799585659197589,253.656315856923044],"luv":[56.8399439373084761,-22.6469326722406379,-77.2278458285038596],"rgb":[0.333333333333333315,0.533333333333333326,0.866666666666666696],"xyz":[0.255997584373689691,0.247590992580546787,0.718389105462139188],"hpluv":[253.656315856923044,179.669115472769334,56.8399439373084761],"hsluv":[253.656315856923044,71.4978966707909791,56.8399439373084761]},"#5588ee":{"lch":[57.7622712344346212,93.8110643698785083,256.11666422549024],"luv":[57.7622712344346212,-22.5095618551803298,-91.0704969970917517],"rgb":[0.333333333333333315,0.533333333333333326,0.933333333333333348],"xyz":[0.2798097646398644,0.257115864687016804,0.843799921530662411],"hpluv":[256.11666422549024,206.086302990026525,57.7622712344346212],"hsluv":[256.11666422549024,85.5354286092897098,57.7622712344346212]},"#5588ff":{"lch":[58.7500561820581169,106.871298098059711,257.890974112124525],"luv":[58.7500561820581169,-22.4186692043534066,-104.493433421771144],"rgb":[0.333333333333333315,0.533333333333333326,1],"xyz":[0.305980813049695821,0.267584284050949528,0.981634109822444256],"hpluv":[257.890974112124525,230.829932612430156,58.7500561820581169],"hsluv":[257.890974112124525,99.9999999999988489,58.7500561820581169]},"#559900":{"lch":[56.7948235068901113,75.0667586450735769,116.650835958582277],"luv":[56.7948235068901113,-33.6713638042581849,67.0914116190665766],"rgb":[0.333333333333333315,0.6,0],"xyz":[0.151369625100333277,0.247131169595152217,0.0397251577236065259],"hpluv":[116.650835958582277,167.717444253109818,56.7948235068901113],"hsluv":[116.650835958582277,100.000000000002373,56.7948235068901113]},"#559911":{"lch":[56.8345345919718,73.5501475520203343,117.179331557793219],"luv":[56.8345345919718,-33.596019870913949,65.4288289193465431],"rgb":[0.333333333333333315,0.6,0.0666666666666666657],"xyz":[0.152381290599970409,0.24753583579500707,0.0450532626883621556],"hpluv":[117.179331557793219,164.214146288467191,56.8345345919718],"hsluv":[117.179331557793219,97.3073310640873501,56.8345345919718]},"#559922":{"lch":[56.9080340332033785,70.7973668034807559,118.203267177206257],"luv":[56.9080340332033785,-33.458907670269852,62.3920559351826256],"rgb":[0.333333333333333315,0.6,0.133333333333333331],"xyz":[0.154256648738447411,0.248285979050397898,0.0549301488843413552],"hpluv":[118.203267177206257,157.863907732936383,56.9080340332033785],"hsluv":[118.203267177206257,92.3971004449738444,56.9080340332033785]},"#559933":{"lch":[57.0287279601738675,66.4302504595433163,120.024921583566851],"luv":[57.0287279601738675,-33.2401456716524066,57.5158316626386181],"rgb":[0.333333333333333315,0.6,0.2],"xyz":[0.157344399470905172,0.249521079343381,0.0711923027419525],"hpluv":[120.024921583566851,147.812625691912672,57.0287279601738675],"hsluv":[120.024921583566851,84.5348632876942645,57.0287279601738675]},"#559944":{"lch":[57.2022813646338335,60.4886548808755862,122.993651447985457],"luv":[57.2022813646338335,-32.9388613723515604,50.7337045837447178],"rgb":[0.333333333333333315,0.6,0.266666666666666663],"xyz":[0.161802394715124032,0.251304277441068591,0.0946710776948391369],"hpluv":[122.993651447985457,134.183743453609452,57.2022813646338335],"hsluv":[122.993651447985457,73.6468983233054075,57.2022813646338335]},"#559955":{"lch":[57.4331244004656583,53.227141365646645,127.715012949239252],"luv":[57.4331244004656583,-32.5608701853658573,42.1060365117673499],"rgb":[0.333333333333333315,0.6,0.333333333333333315],"xyz":[0.167764808754486017,0.253689243056813396,0.126073124968813038],"hpluv":[127.715012949239252,117.600732304920115,57.4331244004656583],"hsluv":[127.715012949239252,59.8797334066369444,57.4331244004656583]},"#559966":{"lch":[57.7247064038159152,45.1954856350919556,135.286653522876605],"luv":[57.7247064038159152,-32.1175213159608433,31.7977475037242847],"rgb":[0.333333333333333315,0.6,0.4],"xyz":[0.175349804527994202,0.256723241366216715,0.166020769375957],"hpluv":[135.286653522876605,99.3510934192793371,57.7247064038159152],"hsluv":[135.286653522876605,61.4133131906424055,57.7247064038159152]},"#559977":{"lch":[58.0796295741768631,37.4448814339638858,147.624029462041108],"luv":[58.0796295741768631,-31.624170974627738,20.0507096076703846],"rgb":[0.333333333333333315,0.6,0.466666666666666674],"xyz":[0.184663817548196107,0.260448846574297566,0.215074571282354909],"hpluv":[147.624029462041108,81.8102930750829671,58.0796295741768631],"hsluv":[147.624029462041108,63.1432913181764448,58.0796295741768631]},"#559988":{"lch":[58.4997327930321092,31.9103493306277741,167.047427400638497],"luv":[58.4997327930321092,-31.0984204046450543,7.15252701768072],"rgb":[0.333333333333333315,0.6,0.533333333333333326],"xyz":[0.195804234650139963,0.264905013415075108,0.273747434685927105],"hpluv":[167.047427400638497,69.2176742514874093,58.4997327930321092],"hsluv":[167.047427400638497,65.0191416919107752,58.4997327930321092]},"#559999":{"lch":[58.9861545428406373,31.2617491707160085,192.177050630060933],"luv":[58.9861545428406373,-30.5583742056962677,-6.59414339527129822],"rgb":[0.333333333333333315,0.6,0.6],"xyz":[0.208861198759212663,0.270127799058704321,0.342514112327045],"hpluv":[192.177050630060933,67.2515837667627494,58.9861545428406373],"hsluv":[192.177050630060933,66.9883413382070216,58.9861545428406373]},"#5599aa":{"lch":[59.5393884281606915,36.5784761777074152,214.841775998693208],"luv":[59.5393884281606915,-30.0211576326403424,-20.8977274812183715],"rgb":[0.333333333333333315,0.6,0.66666666666666663],"xyz":[0.223918891724465219,0.276150876244805388,0.421817961944043585],"hpluv":[214.841775998693208,77.957978019602777,59.5393884281606915],"hsluv":[214.841775998693208,69.0007957908225,59.5393884281606915]},"#5599bb":{"lch":[60.1593377819191488,46.1560476826162613,230.269588518041076],"luv":[60.1593377819191488,-29.5018430010724479,-35.4967885479802],"rgb":[0.333333333333333315,0.6,0.733333333333333282],"xyz":[0.241056483831801838,0.283005913087740146,0.512075947042685331],"hpluv":[230.269588518041076,97.3564866347465312,60.1593377819191488],"hsluv":[230.269588518041076,71.0120526680823758,60.1593377819191488]},"#5599cc":{"lch":[60.8453721774886276,57.9560381686168284,239.960256152221575],"luv":[60.8453721774886276,-29.0128279276179057,-50.1712883614184761],"rgb":[0.333333333333333315,0.6,0.8],"xyz":[0.260348859275523592,0.290722863265228948,0.613682457712955487],"hpluv":[239.960256152221575,120.867757439807349,60.8453721774886276],"hsluv":[239.960256152221575,72.9851794318318667,60.8453721774886276]},"#5599dd":{"lch":[61.596386585270082,70.7674616346471623,246.194917025964173],"luv":[61.596386585270082,-28.563620381934669,-64.7468394355121],"rgb":[0.333333333333333315,0.6,0.866666666666666696],"xyz":[0.281867184826157136,0.29933019348548251,0.727012305612961485],"hpluv":[246.194917025964173,145.7866339341696,61.596386585270082],"hsluv":[246.194917025964173,74.8914393241793164,61.596386585270082]},"#5599ee":{"lch":[62.4108626997728209,83.9573424358243,250.401946751580681],"luv":[62.4108626997728209,-28.1609349474859023,-79.0935970339554757],"rgb":[0.333333333333333315,0.6,0.933333333333333348],"xyz":[0.305679365092331845,0.308855065591952527,0.852423121681484708],"hpluv":[250.401946751580681,170.701691169737018,62.4108626997728209],"hsluv":[250.401946751580681,83.3865807682554845,62.4108626997728209]},"#5599ff":{"lch":[63.2869312953637,97.1853240423286309,253.372761171991215],"luv":[63.2869312953637,-27.8089904224615658,-93.1216798650875859],"rgb":[0.333333333333333315,0.6,1],"xyz":[0.331850413502163266,0.319323484955885251,0.990257309973266553],"hpluv":[253.372761171991215,194.861470594675211,63.2869312953637],"hsluv":[253.372761171991215,99.9999999999986215,63.2869312953637]},"#440000":{"lch":[10.7708306123528814,36.2226426723970221,12.1770506300617765],"luv":[10.7708306123528814,35.407649887332731,7.64056094984030221],"rgb":[0.266666666666666663,0,0],"xyz":[0.0238384275584062923,0.0122916892098035059,0.00111742629180027137],"hpluv":[12.1770506300617765,426.746789183125145,10.7708306123528814],"hsluv":[12.1770506300617765,100.000000000002203,10.7708306123528814]},"#440011":{"lch":[11.0614468716721248,32.5827232355020158,4.73042674181564848],"luv":[11.0614468716721248,32.4717377839629151,2.68702414036008763],"rgb":[0.266666666666666663,0,0.0666666666666666657],"xyz":[0.024850093058043414,0.0126963554096583605,0.00644553125655590239],"hpluv":[4.73042674181564848,373.778888471265759,11.0614468716721248],"hsluv":[4.73042674181564848,99.999999999996831,11.0614468716721248]},"#440022":{"lch":[11.5842423793746683,28.6540476811609395,350.304317532446703],"luv":[11.5842423793746683,28.2447579299318896,-4.82577434136679706],"rgb":[0.266666666666666663,0,0.133333333333333331],"xyz":[0.0267254511965204326,0.0134464986650491784,0.0163224174525351],"hpluv":[350.304317532446703,313.875682434467763,11.5842423793746683],"hsluv":[350.304317532446703,99.9999999999974847,11.5842423793746683]},"#440033":{"lch":[12.4041921203750505,27.3919603751935874,328.642516788172941],"luv":[12.4041921203750505,23.3910134404871357,-14.2541216293086901],"rgb":[0.266666666666666663,0,0.2],"xyz":[0.0298132019289781731,0.0146815989580322912,0.0325845713101462417],"hpluv":[328.642516788172941,280.216663156604227,12.4041921203750505],"hsluv":[328.642516788172941,99.9999999999981668,12.4041921203750505]},"#440044":{"lch":[13.5105146335658439,30.7747615701782742,307.715012949243601],"luv":[13.5105146335658439,18.8259784531467211,-24.3447835271332202],"rgb":[0.266666666666666663,0,0.266666666666666663],"xyz":[0.0342711971731970502,0.0164647970557198695,0.0560633462630328802],"hpluv":[307.715012949243601,289.042783730483222,13.5105146335658439],"hsluv":[307.715012949243601,99.9999999999987779,13.5105146335658439]},"#440055":{"lch":[14.871657786523194,37.5926423334987589,293.358518425732086],"luv":[14.871657786523194,14.9048564440935021,-34.5116214049025416],"rgb":[0.266666666666666663,0,0.333333333333333315],"xyz":[0.0402336112125590423,0.0188497626714647,0.0874653935370067886],"hpluv":[293.358518425732086,320.761913781574776,14.871657786523194],"hsluv":[293.358518425732086,99.999999999999261,14.871657786523194]},"#440066":{"lch":[16.4463097679727497,46.0898544445027,284.618444278650202],"luv":[16.4463097679727497,11.6321972733021664,-44.597832562922008],"rgb":[0.266666666666666663,0,0.4],"xyz":[0.0478186069860672205,0.0218837609808680139,0.127413037944150764],"hpluv":[284.618444278650202,355.611827609674208,16.4463097679727497],"hsluv":[284.618444278650202,99.9999999999996447,16.4463097679727497]},"#440077":{"lch":[18.1919811936642475,55.3198462112611651,279.251207899416613],"luv":[18.1919811936642475,8.8934050845755,-54.6002997321373],"rgb":[0.266666666666666663,0,0.466666666666666674],"xyz":[0.0571326200062691331,0.0256093661889488303,0.176466839850548673],"hpluv":[279.251207899416613,385.869357778503058,18.1919811936642475],"hsluv":[279.251207899416613,100.000000000000028,18.1919811936642475]},"#440088":{"lch":[20.0701231572475791,64.8751824688912,275.807883046004235],"luv":[20.0701231572475791,6.56492582220058196,-64.5421648949036353],"rgb":[0.266666666666666663,0,0.533333333333333326],"xyz":[0.0682730371082129611,0.0300655330297264212,0.235139703254120841],"hpluv":[275.807883046004235,410.173767132845569,20.0701231572475791],"hsluv":[275.807883046004235,100.000000000000284,20.0701231572475791]},"#440099":{"lch":[22.0482755473713041,74.5764302852581267,273.495279820248],"luv":[22.0482755473713041,4.54664979059262,-74.4377050275844283],"rgb":[0.266666666666666663,0,0.6],"xyz":[0.0813300012172856746,0.0352883186733555787,0.303906380895238748],"hpluv":[273.495279820248,429.20649964036636,22.0482755473713041],"hsluv":[273.495279820248,100.000000000000384,22.0482755473713041]},"#4400aa":{"lch":[24.1003299188330615,84.3353594354864811,271.878389761009714],"luv":[24.1003299188330615,2.7643624238057809,-84.290041828810061],"rgb":[0.266666666666666663,0,0.66666666666666663],"xyz":[0.0963876941825382166,0.0413113958594566871,0.383210230512237349],"hpluv":[271.878389761009714,444.044033459252,24.1003299188330615],"hsluv":[271.878389761009714,100.000000000000398,24.1003299188330615]},"#4400bb":{"lch":[26.2058661049044161,94.1030045511215434,270.708980538846049],"luv":[26.2058661049044161,1.16440507249082947,-94.0958002589677704],"rgb":[0.266666666666666663,0,0.733333333333333282],"xyz":[0.113525286289874863,0.0481664327023914457,0.473468215610879095],"hpluv":[270.708980538846049,455.663559843794246,26.2058661049044161],"hsluv":[270.708980538846049,100.000000000000597,26.2058661049044161]},"#4400cc":{"lch":[28.3491756730399374,103.84959146554381,269.838851579513857],"luv":[28.3491756730399374,-0.292083914573144032,-103.849180711969012],"rgb":[0.266666666666666663,0,0.8],"xyz":[0.132817661733596604,0.0558833828798802473,0.575074726281149196],"hpluv":[269.838851579513857,464.840204698682,28.3491756730399374],"hsluv":[269.838851579513857,100.00000000000054,28.3491756730399374]},"#4400dd":{"lch":[30.5182871942398464,113.556060117994207,269.175711116484081],"luv":[30.5182871942398464,-1.63362415099869285,-113.544308803456943],"rgb":[0.266666666666666663,0,0.866666666666666696],"xyz":[0.154335987284230147,0.0644907131001337813,0.688404574181155193],"hpluv":[269.175711116484081,472.160320460814546,30.5182871942398464],"hsluv":[269.175711116484081,100.000000000000583,30.5182871942398464]},"#4400ee":{"lch":[32.7041215904695406,123.209994802530275,268.6598990566049],"luv":[32.7041215904695406,-2.88151723804096926,-123.176295112519156],"rgb":[0.266666666666666663,0,0.933333333333333348],"xyz":[0.178148167550404884,0.0740155852066038122,0.813815390249678416],"hpluv":[268.6598990566049,478.060407115886846,32.7041215904695406],"hsluv":[268.6598990566049,100.000000000000682,32.7041215904695406]},"#4400ff":{"lch":[34.8998090420324161,132.803387625161918,268.251574356178935],"luv":[34.8998090420324161,-4.05197057625710322,-132.741558297197031],"rgb":[0.266666666666666663,0,1],"xyz":[0.204319215960236278,0.0844840045705365084,0.951649578541460262],"hpluv":[268.251574356178935,482.864668803745815,34.8998090420324161],"hsluv":[268.251574356178935,100.000000000000824,34.8998090420324161]},"#441100":{"lch":[13.412021407860891,32.8203905090178907,19.8063713084711637],"luv":[13.412021407860891,30.878837797926078,11.1209446277644677],"rgb":[0.266666666666666663,0.0666666666666666657,0],"xyz":[0.025842827819334703,0.0163004897316603795,0.00178555971210972225],"hpluv":[19.8063713084711637,310.519467471828818,13.412021407860891],"hsluv":[19.8063713084711637,100.00000000000226,13.412021407860891]},"#441111":{"lch":[13.6534230745514442,29.3615880370140658,12.1770506300618155],"luv":[13.6534230745514442,28.7009658227648572,6.19333616848069],"rgb":[0.266666666666666663,0.0666666666666666657,0.0666666666666666657],"xyz":[0.0268544933189718248,0.0167051559315152323,0.00711366467686535414],"hpluv":[12.1770506300618155,272.883526996448495,13.6534230745514442],"hsluv":[12.1770506300618155,63.9450685777404857,13.6534230745514442]},"#441122":{"lch":[14.0908014406849,25.4444274015795777,356.558123350094036],"luv":[14.0908014406849,25.3985311285907684,-1.52758053936917793],"rgb":[0.266666666666666663,0.0666666666666666657,0.133333333333333331],"xyz":[0.0287298514574488434,0.0174552991869060536,0.0169905508728445502],"hpluv":[356.558123350094036,229.137575437366081,14.0908014406849],"hsluv":[356.558123350094036,68.4589860949294,14.0908014406849]},"#441133":{"lch":[14.7844111345271223,24.27011571268606,331.648240125609],"luv":[14.7844111345271223,21.358884082162259,-11.5254755854986932],"rgb":[0.266666666666666663,0.0666666666666666657,0.2],"xyz":[0.0318176021899065839,0.0186903994798891665,0.0332527047304557],"hpluv":[331.648240125609,208.308572243058649,14.7844111345271223],"hsluv":[331.648240125609,73.8494669394836762,14.7844111345271223]},"#441144":{"lch":[15.733846020816415,28.3218749128348932,307.715012949243942],"luv":[15.733846020816415,17.3254634530922189,-22.4043949865608347],"rgb":[0.266666666666666663,0.0666666666666666657,0.266666666666666663],"xyz":[0.0362755974341254644,0.0204735975775767395,0.0567314796833423354],"hpluv":[307.715012949243942,228.415952286272613,15.733846020816415],"hsluv":[307.715012949243942,79.0249627886423127,15.733846020816415]},"#441155":{"lch":[16.9210970319156715,36.0495621705848492,292.339268883647492],"luv":[16.9210970319156715,13.7020846665308547,-33.3440220801582683],"rgb":[0.266666666666666663,0.0666666666666666657,0.333333333333333315],"xyz":[0.0422380114734874565,0.0228585631933215724,0.0881335269573162439],"hpluv":[292.339268883647492,270.340308544513618,16.9210970319156715],"hsluv":[292.339268883647492,83.4150097743113292,16.9210970319156715]},"#441166":{"lch":[18.3175541838796221,45.305096001334384,283.521508601515677],"luv":[18.3175541838796221,10.592801308498224,-44.0493392019540195],"rgb":[0.266666666666666663,0.0666666666666666657,0.4],"xyz":[0.0498230072469956348,0.025892561502724884,0.128081171364460206],"hpluv":[283.521508601515677,313.84766122316239,18.3175541838796221],"hsluv":[283.521508601515677,86.9023417707839485,18.3175541838796221]},"#441177":{"lch":[19.8903241139664431,55.0653797371295326,278.304914930180701],"luv":[19.8903241139664431,7.95370312292975612,-54.4879312529533735],"rgb":[0.266666666666666663,0.0666666666666666657,0.466666666666666674],"xyz":[0.0591370202671975473,0.0296181667108057,0.177134973270858115],"hpluv":[278.304914930180701,351.298345972174616,19.8903241139664431],"hsluv":[278.304914930180701,89.590178354910762,19.8903241139664431]},"#441188":{"lch":[21.6068634066631873,64.9598488176177824,275.03199667533886],"luv":[21.6068634066631873,5.69776159856002,-64.7094851716016422],"rgb":[0.266666666666666663,0.0666666666666666657,0.533333333333333326],"xyz":[0.0702774373691413823,0.0340743335515832912,0.235807836674430282],"hpluv":[275.03199667533886,381.498298720028686,21.6068634066631873],"hsluv":[275.03199667533886,91.6417594317348545,21.6068634066631873]},"#441199":{"lch":[23.437698327746169,74.8628785955689153,272.864058339832695],"luv":[23.437698327746169,3.74063102269824954,-74.769367197849931],"rgb":[0.266666666666666663,0.0666666666666666657,0.6],"xyz":[0.0833344014782140818,0.0392971191952124557,0.304574514315548162],"hpluv":[272.864058339832695,405.313331644098525,23.437698327746169],"hsluv":[272.864058339832695,93.2101268622270283,23.437698327746169]},"#4411aa":{"lch":[25.3575925472355337,84.7316846097945273,271.361966301038933],"luv":[25.3575925472355337,2.01394993465393446,-84.7077468858332878],"rgb":[0.266666666666666663,0.0666666666666666657,0.66666666666666663],"xyz":[0.0983920944434666378,0.0453201963813135572,0.383878363932546762],"hpluv":[271.361966301038933,424.011024215555381,25.3575925472355337],"hsluv":[271.361966301038933,94.4180404350203872,25.3575925472355337]},"#4411bb":{"lch":[27.345710117802,94.5503656807627,270.282295464151048],"luv":[27.345710117802,0.465846378280231621,-94.5492180693092337],"rgb":[0.266666666666666663,0.0666666666666666657,0.733333333333333282],"xyz":[0.115529686550803284,0.0521752332242483158,0.474136349031188509],"hpluv":[270.282295464151048,438.746165283595928,27.345710117802],"hsluv":[270.282295464151048,95.3579307613671,27.345710117802]},"#4411cc":{"lch":[29.3852471201757481,104.311620276565549,269.482476007084244],"luv":[29.3852471201757481,-0.942181651797373232,-104.307365120864873],"rgb":[0.266666666666666663,0.0666666666666666657,0.8],"xyz":[0.134822061994525,0.0598921834017371174,0.575742859701458665],"hpluv":[269.482476007084244,450.445933463405538,29.3852471201757481],"hsluv":[269.482476007084244,96.097629526357963,29.3852471201757481]},"#4411dd":{"lch":[31.4628506304707116,114.011096091836691,268.874895171215144],"luv":[31.4628506304707116,-2.23866735310417164,-113.989115272223103],"rgb":[0.266666666666666663,0.0666666666666666657,0.866666666666666696],"xyz":[0.156340387545158555,0.0684995136219906514,0.689072707601464662],"hpluv":[268.874895171215144,459.820552568088715,31.4628506304707116],"hsluv":[268.874895171215144,96.6865382756064378,31.4628506304707116]},"#4411ee":{"lch":[33.5680052377948073,123.64577428881995,268.40345713539682],"luv":[33.5680052377948073,-3.44493495426529961,-123.597774747940718],"rgb":[0.266666666666666663,0.0666666666666666657,0.933333333333333348],"xyz":[0.180152567811333292,0.0780243857284606823,0.814483523669987886],"hpluv":[268.40345713539682,467.404695294247745,33.5680052377948073],"hsluv":[268.40345713539682,97.1606953094382817,33.5680052377948073]},"#4411ff":{"lch":[35.6924730299026081,133.21354134861582,268.030966648817412],"luv":[35.6924730299026081,-4.57713081064657,-133.134884505082312],"rgb":[0.266666666666666663,0.0666666666666666657,1],"xyz":[0.206323616221164685,0.0884928050923933784,0.952317711961769731],"hpluv":[268.030966648817412,473.599309181226886,35.6924730299026081],"hsluv":[268.030966648817412,99.999999999999531,35.6924730299026081]},"#99aa00":{"lch":[66.1528677227115907,74.3468963767982842,94.6234982733471384],"luv":[66.1528677227115907,-5.99293371363564553,74.1049643840839565],"rgb":[0.6,0.66666666666666663,0],"xyz":[0.275106719282890377,0.355217387920677,0.0540714229698005533],"hpluv":[94.6234982733471384,142.611154102436132,66.1528677227115907],"hsluv":[94.6234982733471384,100.000000000002217,66.1528677227115907]},"#99aa11":{"lch":[66.184052262829,73.0311244080130706,94.7508326892346275],"luv":[66.184052262829,-6.04863423256243316,72.7802112955118901],"rgb":[0.6,0.66666666666666663,0.0666666666666666657],"xyz":[0.276118384782527482,0.355622054120531828,0.059399527934556183],"hpluv":[94.7508326892346275,140.021252931940353,66.184052262829],"hsluv":[94.7508326892346275,98.1390759685954,66.184052262829]},"#99aa22":{"lch":[66.2417975711995695,70.6178785015108872,94.9968669170454376],"luv":[66.2417975711995695,-6.15090676716144458,70.3494926065273],"rgb":[0.6,0.66666666666666663,0.133333333333333331],"xyz":[0.277993742921004539,0.356372197375922628,0.0692764141305353826],"hpluv":[94.9968669170454376,135.276352185575888,66.2417975711995695],"hsluv":[94.9968669170454376,94.7283581868373403,66.2417975711995695]},"#99aa33":{"lch":[66.3366981156763273,66.7162457715457,95.432805623918],"luv":[66.3366981156763273,-6.31658226271684953,66.416550937003791],"rgb":[0.6,0.66666666666666663,0.2],"xyz":[0.281081493653462244,0.357607297668905755,0.0855385679881465189],"hpluv":[95.432805623918,127.619510800204154,66.3366981156763273],"hsluv":[95.432805623918,89.220332613511431,66.3366981156763273]},"#99aa44":{"lch":[66.4733277612737652,61.2361369282317085,96.1403021162386],"luv":[66.4733277612737652,-6.55002950525979344,60.8848222414533211],"rgb":[0.6,0.66666666666666663,0.266666666666666663],"xyz":[0.28553948889768116,0.359390495766593321,0.109017342941033157],"hpluv":[96.1403021162386,116.896010950353556,66.4733277612737652],"hsluv":[96.1403021162386,81.495914591183535,66.4733277612737652]},"#99aa55":{"lch":[66.6553605356915853,54.1785870660784568,97.2658616968833769],"luv":[66.6553605356915853,-6.85216039608048888,53.7435316515674231],"rgb":[0.6,0.66666666666666663,0.333333333333333315],"xyz":[0.291501902937043145,0.361775461382338182,0.140419390215007073],"hpluv":[97.2658616968833769,103.141138146130345,66.6553605356915853],"hsluv":[97.2658616968833769,71.5645731506566563,66.6553605356915853]},"#99aa66":{"lch":[66.8857782590742573,45.6318272725976186,99.1048787772859328],"luv":[66.8857782590742573,-7.22087825912546055,45.0568815765480224],"rgb":[0.6,0.66666666666666663,0.4],"xyz":[0.29908689871055133,0.3648094596917415,0.180367034622151035],"hpluv":[99.1048787772859328,86.5711928674077882,66.8857782590742573],"hsluv":[99.1048787772859328,59.5487850828384495,66.8857782590742573]},"#99aa77":{"lch":[67.16697930835997,35.7793898766585272,102.348317274789],"luv":[67.16697930835997,-7.65157453727816339,34.9516544250255947],"rgb":[0.6,0.66666666666666663,0.466666666666666674],"xyz":[0.308400911730753235,0.368535064899822296,0.229420836528548944],"hpluv":[102.348317274789,67.5952906506277742,67.16697930835997],"hsluv":[102.348317274789,45.6652750399669927,67.16697930835997]},"#99aa88":{"lch":[67.5008436530857523,24.9656779050761699,109.02352802026725],"luv":[67.5008436530857523,-8.13772239581267165,23.6021725158659379],"rgb":[0.6,0.66666666666666663,0.533333333333333326],"xyz":[0.319541328832697036,0.372991231740599893,0.288093699932121083],"hpluv":[109.02352802026725,46.9324783865521482,67.5008436530857523],"hsluv":[109.02352802026725,30.201776912068496,67.5008436530857523]},"#99aa99":{"lch":[67.8887769686822509,14.1753245834603039,127.715012949228395],"luv":[67.8887769686822509,-8.67153282620695443,11.213578621049983],"rgb":[0.6,0.66666666666666663,0.6],"xyz":[0.332598292941769791,0.378214017384229051,0.356860377573239],"hpluv":[127.715012949228395,26.4956363039349618,67.8887769686822509],"hsluv":[127.715012949228395,13.4910013502760879,67.8887769686822509]},"#99aaaa":{"lch":[68.3317447891119798,9.45739632834534838,192.177050630059227],"luv":[68.3317447891119798,-9.24460926466251642,-1.99487965930680966],"rgb":[0.6,0.66666666666666663,0.66666666666666663],"xyz":[0.347655985907022291,0.384237094570330173,0.436164227190237619],"hpluv":[192.177050630059227,17.5625836428344968,68.3317447891119798],"hsluv":[192.177050630059227,17.4938385380963979,68.3317447891119798]},"#99aabb":{"lch":[68.8303024285350205,18.6222464744475609,238.07162859052869],"luv":[68.8303024285350205,-9.84853629911531137,-15.8048852105949411],"rgb":[0.6,0.66666666666666663,0.733333333333333282],"xyz":[0.364793578014358966,0.391092131413264932,0.52642221228887931],"hpluv":[238.07162859052869,34.3314162301526622,68.8303024285350205],"hsluv":[238.07162859052869,21.6214176811966929,68.8303024285350205]},"#99aacc":{"lch":[69.3846237501618646,31.7868422871013969,250.758533684062627],"luv":[69.3846237501618646,-10.475354770609286,-30.0111693376804425],"rgb":[0.6,0.66666666666666663,0.8],"xyz":[0.38408595345808072,0.398809081590753733,0.628028722959149466],"hpluv":[250.758533684062627,58.1330991079694357,69.3846237501618646],"hsluv":[250.758533684062627,38.7837447081888556,69.3846237501618646]},"#99aadd":{"lch":[69.9945303682966,45.800012761152324,255.951164454091042],"luv":[69.9945303682966,-11.1178995355210173,-44.4300965432191859],"rgb":[0.6,0.66666666666666663,0.866666666666666696],"xyz":[0.405604279008714208,0.40741641181100724,0.741358570859155463],"hpluv":[255.951164454091042,83.0311057452140346,69.9945303682966],"hsluv":[255.951164454091042,58.1375555879370935,69.9945303682966]},"#99aaee":{"lch":[70.6595219654936,60.0690973767372896,258.700300270425373],"luv":[70.6595219654936,-11.7699993169592201,-58.9046990972259],"rgb":[0.6,0.66666666666666663,0.933333333333333348],"xyz":[0.429416459274889,0.416941283917477257,0.866769386927678687],"hpluv":[258.700300270425373,107.874733956899746,70.6595219654936],"hsluv":[258.700300270425373,78.5353046306170199,70.6595219654936]},"#99aaff":{"lch":[71.378807837336737,74.3523754541628676,260.378973553217],"luv":[71.378807837336737,-12.4265554124673407,-73.3065921746310636],"rgb":[0.6,0.66666666666666663,1],"xyz":[0.455587507684720339,0.42740970328141,1.00460357521946064],"hpluv":[260.378973553217,132.179737350703419,71.378807837336737],"hsluv":[260.378973553217,99.99999999999784,71.378807837336737]},"#442200":{"lch":[17.3350542344952459,28.221345162136295,35.6239292836567927],"luv":[17.3350542344952459,22.9399340369809366,16.4378754448194186],"rgb":[0.266666666666666663,0.133333333333333331,0],"xyz":[0.0295584515541026382,0.023731737201196354,0.00302410095703233277],"hpluv":[35.6239292836567927,206.581692971425213,17.3350542344952459],"hsluv":[35.6239292836567927,100.000000000002331,17.3350542344952459]},"#442211":{"lch":[17.5234603686317101,24.6335663377647,28.604455948929278],"luv":[17.5234603686317101,21.6269347365689519,11.7935696215031331],"rgb":[0.266666666666666663,0.133333333333333331,0.0666666666666666657],"xyz":[0.03057011705373976,0.0241364034010512069,0.00835220592178796337],"hpluv":[28.604455948929278,178.380241443971528,17.5234603686317101],"hsluv":[28.604455948929278,74.2089163354216765,17.5234603686317101]},"#442222":{"lch":[17.8672188947691239,19.9697171584766728,12.1770506300619807],"luv":[17.8672188947691239,19.520407715454283,4.21227800744330061],"rgb":[0.266666666666666663,0.133333333333333331,0.133333333333333331],"xyz":[0.0324454751922167786,0.0248865466564420282,0.0182290921177671594],"hpluv":[12.1770506300619807,141.825486578211439,17.8672188947691239],"hsluv":[12.1770506300619807,33.2341074785113406,17.8672188947691239]},"#442233":{"lch":[18.4184657925371695,17.8165085202964129,340.00784749027008],"luv":[18.4184657925371695,16.7428760354525643,-6.09131167444770583],"rgb":[0.266666666666666663,0.133333333333333331,0.2],"xyz":[0.0355332259246745191,0.026121646949425141,0.0344912459753783],"hpluv":[340.00784749027008,122.746318288975218,18.4184657925371695],"hsluv":[340.00784749027008,42.0888291674463915,18.4184657925371695]},"#442244":{"lch":[19.1844846541763658,22.4593922221866436,307.715012949244738],"luv":[19.1844846541763658,13.7391814744519145,-17.7668002578431441],"rgb":[0.266666666666666663,0.133333333333333331,0.266666666666666663],"xyz":[0.0399912211688934,0.0279048450471127141,0.0579700209282649412],"hpluv":[307.715012949244738,148.554970924606664,19.1844846541763658],"hsluv":[307.715012949244738,51.3954955066877517,19.1844846541763658]},"#442255":{"lch":[20.1595909359386596,31.6741463862469885,290.023039430837684],"luv":[20.1595909359386596,10.8451637140407797,-29.7596030436068872],"rgb":[0.266666666666666663,0.133333333333333331,0.333333333333333315],"xyz":[0.0459536352082553917,0.030289810662857547,0.0893720682022388496],"hpluv":[290.023039430837684,199.371249454156271,20.1595909359386596],"hsluv":[290.023039430837684,59.9942694866150177,20.1595909359386596]},"#442266":{"lch":[21.3287002071660226,42.3208084503031685,281.207510247893651],"luv":[21.3287002071660226,8.22559640374024781,-41.5137373852322256],"rgb":[0.266666666666666663,0.133333333333333331,0.4],"xyz":[0.0535386309817635631,0.0333238089722608585,0.129319712609382825],"hpluv":[281.207510247893651,251.784442505332123,21.3287002071660226],"hsluv":[281.207510247893651,67.3437899952651406,21.3287002071660226]},"#442277":{"lch":[22.6709734328231463,53.1747129073287113,276.391210783405313],"luv":[22.6709734328231463,5.91922219198187882,-52.8442324328661215],"rgb":[0.266666666666666663,0.133333333333333331,0.466666666666666674],"xyz":[0.0628526440019654825,0.0370494141803416749,0.178373514515780734],"hpluv":[276.391210783405313,297.628360698128461,22.6709734328231463],"hsluv":[276.391210783405313,73.3546851738733,22.6709734328231463]},"#442288":{"lch":[24.1630625686767715,63.8732961962266543,273.501787345358252],"luv":[24.1630625686767715,3.90136026108148481,-63.7540379512086801],"rgb":[0.266666666666666663,0.133333333333333331,0.533333333333333326],"xyz":[0.0739930611039093106,0.0415055810211192727,0.237046377919352902],"hpluv":[273.501787345358252,335.433687598002,24.1630625686767715],"hsluv":[273.501787345358252,78.1624380374364875,24.1630625686767715]},"#442299":{"lch":[25.7815797239733442,74.3421908873045112,271.638748742297366],"luv":[25.7815797239733442,2.1260128283266071,-74.3117851715204836],"rgb":[0.266666666666666663,0.133333333333333331,0.6],"xyz":[0.087050025212982024,0.0467283666647484303,0.305813055560470781],"hpluv":[271.638748742297366,365.902315457699217,25.7815797239733442],"hsluv":[271.638748742297366,81.974423252689391,25.7815797239733442]},"#4422aa":{"lch":[27.5046927955253,84.5952413694672885,270.370058715866037],"luv":[27.5046927955253,0.546375125789773097,-84.5934769150692176],"rgb":[0.266666666666666663,0.133333333333333331,0.66666666666666663],"xyz":[0.102107718178234566,0.0527514438508495317,0.385116905177469382],"hpluv":[270.370058715866037,390.281946032504152,27.5046927955253],"hsluv":[270.370058715866037,84.9950544768410765,27.5046927955253]},"#4422bb":{"lch":[29.3129652277151251,94.666070770970677,269.4687873747244],"luv":[29.3129652277151251,-0.87767531850734,-94.6620020982533],"rgb":[0.266666666666666663,0.133333333333333331,0.733333333333333282],"xyz":[0.119245310285571213,0.0596064806937842903,0.475374890276111128],"hpluv":[269.4687873747244,409.801860030343846,29.3129652277151251],"hsluv":[269.4687873747244,87.3984435941311517,29.3129652277151251]},"#4422cc":{"lch":[31.1896477872922873,104.586362634530047,268.806646243455475],"luv":[31.1896477872922873,-2.17816227055809408,-104.563678484665701],"rgb":[0.266666666666666663,0.133333333333333331,0.8],"xyz":[0.138537685729292953,0.0673234308712731,0.576981400946381284],"hpluv":[268.806646243455475,425.504262664631483,31.1896477872922873],"hsluv":[268.806646243455475,89.3235413687926325,31.1896477872922873]},"#4422dd":{"lch":[33.1206275871571,114.38069493574325,268.306702684458742],"luv":[33.1206275871571,-3.37987077956927,-114.330747603157818],"rgb":[0.266666666666666663,0.133333333333333331,0.866666666666666696],"xyz":[0.160056011279926497,0.0759307610915266329,0.690311248846387282],"hpluv":[268.306702684458742,438.22131720165,33.1206275871571],"hsluv":[268.306702684458742,90.877884626449017,33.1206275871571]},"#4422ee":{"lch":[35.0941942457284952,124.066768949832422,267.920557621455941],"luv":[35.0941942457284952,-4.50178121539094178,-123.985068147498538],"rgb":[0.266666666666666663,0.133333333333333331,0.933333333333333348],"xyz":[0.183868191546101234,0.0854556331979966499,0.815722064914910505],"hpluv":[267.920557621455941,448.600262181889605,35.0941942457284952],"hsluv":[267.920557621455941,93.3452679661598523,35.0941942457284952]},"#4422ff":{"lch":[37.1007304630435,133.656986375695226,267.616535799179189],"luv":[37.1007304630435,-5.55843332369103926,-133.54135623850334],"rgb":[0.266666666666666663,0.133333333333333331,1],"xyz":[0.210039239955932627,0.0959240525619293599,0.95355625320669235],"hpluv":[267.616535799179189,457.139270395610822,37.1007304630435],"hsluv":[267.616535799179189,99.999999999999531,37.1007304630435]},"#bbaa00":{"lch":[68.9787767407419,76.4078567958722346,76.7962953219783344],"luv":[68.9787767407419,17.4526104568015299,74.3879490803561652],"rgb":[0.733333333333333282,0.66666666666666663,0],"xyz":[0.348671553863065253,0.393149255751080451,0.0575197745907461769],"hpluv":[76.7962953219783344,140.560034871296551,68.9787767407419],"hsluv":[76.7962953219783344,100.000000000002245,68.9787767407419]},"#bbaa11":{"lch":[69.0079227935645747,75.1793224892161902,76.6760735029220797],"luv":[69.0079227935645747,17.325534429098667,73.1556996185784811],"rgb":[0.733333333333333282,0.66666666666666663,0.0666666666666666657],"xyz":[0.349683219362702358,0.393553921950935304,0.0628478795555018],"hpluv":[76.6760735029220797,138.241608756115426,69.0079227935645747],"hsluv":[76.6760735029220797,98.327691673723,69.0079227935645747]},"#bbaa22":{"lch":[69.0618990033698168,72.923722885125926,76.4446579961253718],"luv":[69.0618990033698168,17.0921879270318975,70.8923583420220496],"rgb":[0.733333333333333282,0.66666666666666663,0.133333333333333331],"xyz":[0.351558577501179415,0.394304065206326104,0.072724765751481],"hpluv":[76.4446579961253718,133.98915323660276,69.0618990033698168],"hsluv":[76.4446579961253718,95.2591470849694701,69.0618990033698168]},"#bbaa33":{"lch":[69.1506211183474448,69.2704933393546298,76.037430434814425],"luv":[69.1506211183474448,16.7141363744442764,67.2237970716773248],"rgb":[0.733333333333333282,0.66666666666666663,0.2],"xyz":[0.35464632823363712,0.395539165499309231,0.0889869196090921494],"hpluv":[76.037430434814425,127.113454601419591,69.1506211183474448],"hsluv":[76.037430434814425,90.2940538071316752,69.1506211183474448]},"#bbaa44":{"lch":[69.2783900215706439,64.125663575375043,75.3840533289293688],"luv":[69.2783900215706439,16.1813855024742246,62.0504914743025964],"rgb":[0.733333333333333282,0.66666666666666663,0.266666666666666663],"xyz":[0.359104323477856036,0.397322363596996797,0.112465694561978788],"hpluv":[75.3840533289293688,117.455514697890109,69.2783900215706439],"hsluv":[75.3840533289293688,83.3108908827552455,69.2783900215706439]},"#bbaa55":{"lch":[69.4486803199850158,57.4759826537307603,74.3632861967268752],"luv":[69.4486803199850158,15.4919003466967737,55.3487994961044762],"rgb":[0.733333333333333282,0.66666666666666663,0.333333333333333315],"xyz":[0.365066737517218,0.399707329212741658,0.143867741835952689],"hpluv":[74.3632861967268752,105.017514149864908,69.4486803199850158],"hsluv":[74.3632861967268752,74.2978448337225501,69.4486803199850158]},"#bbaa66":{"lch":[69.6643364030220766,49.3851711615203186,72.7428070953876],"luv":[69.6643364030220766,14.6506772614363818,47.1619845472377079],"rgb":[0.733333333333333282,0.66666666666666663,0.4],"xyz":[0.372651733290726206,0.402741327522145,0.183815386243096651],"hpluv":[72.7428070953876,89.9550160304510342,69.6643364030220766],"hsluv":[72.7428070953876,63.3404983901227254,69.6643364030220766]},"#bbaa77":{"lch":[69.927675331165787,39.998456174204172,70.017617272721],"luv":[69.927675331165787,13.6687200676018641,37.5904587366697314],"rgb":[0.733333333333333282,0.66666666666666663,0.466666666666666674],"xyz":[0.381965746310928111,0.406466932730225772,0.23286918814949456],"hpluv":[70.017617272721,72.5827577171275635,69.927675331165787],"hsluv":[70.017617272721,50.6076787731359303,69.927675331165787]},"#bbaa88":{"lch":[70.2405480333122,29.5797452752191568,64.8698942165899837],"luv":[70.2405480333122,12.5617839686329518,26.7798975739685403],"rgb":[0.733333333333333282,0.66666666666666663,0.533333333333333326],"xyz":[0.393106163412871912,0.41092309957100337,0.291542051553066728],"hpluv":[64.8698942165899837,53.4374671266607422,70.2405480333122],"hsluv":[64.8698942165899837,36.3337734813298923,70.2405480333122]},"#bbaa99":{"lch":[70.6043801086793,18.7359983934483161,52.7186742094296079],"luv":[70.6043801086793,11.3489394865138475,14.907689570511744],"rgb":[0.733333333333333282,0.66666666666666663,0.6],"xyz":[0.406163127521944611,0.416145885214632527,0.360308729194184663],"hpluv":[52.7186742094296079,33.6732102985619051,70.6043801086793],"hsluv":[52.7186742094296079,20.7983697782308,70.6043801086793]},"#bbaaaa":{"lch":[71.0202025015365876,10.2824341490213804,12.177050630064155],"luv":[71.0202025015365876,10.0510841141786607,2.16890759569567715],"rgb":[0.733333333333333282,0.66666666666666663,0.66666666666666663],"xyz":[0.421220820487197167,0.422168962400733649,0.439612578811183263],"hpluv":[12.177050630064155,18.3718697222702261,71.0202025015365876],"hsluv":[12.177050630064155,12.5020210815887047,71.0202025015365876]},"#bbaabb":{"lch":[71.4886774714552615,14.2047670368859897,307.715012949256788],"luv":[71.4886774714552615,8.68954378602241562,-11.236869464535129],"rgb":[0.733333333333333282,0.66666666666666663,0.733333333333333282],"xyz":[0.438358412594533842,0.429023999243668408,0.529870563909825],"hpluv":[307.715012949256788,25.2136766683934965,71.4886774714552615],"hsluv":[307.715012949256788,14.1682246563909,71.4886774714552615]},"#bbaacc":{"lch":[72.010122844957138,26.1519063744379174,286.174295641089373],"luv":[72.010122844957138,7.28488198445553525,-25.1167812724863673],"rgb":[0.733333333333333282,0.66666666666666663,0.8],"xyz":[0.45765078803825554,0.43674094942115721,0.631477074580095166],"hpluv":[286.174295641089373,46.0838895939184923,72.010122844957138],"hsluv":[286.174295641089373,33.6938059680335442,72.010122844957138]},"#bbaadd":{"lch":[72.5845361735228494,39.7272427931479,278.476565574149959],"luv":[72.5845361735228494,5.85598959517198825,-39.2932717625671799],"rgb":[0.733333333333333282,0.66666666666666663,0.866666666666666696],"xyz":[0.47916911358888914,0.445348279641410716,0.744806922480101163],"hpluv":[278.476565574149959,69.451822258827633,72.5845361735228494],"hsluv":[278.476565574149959,54.5084651382981775,72.5845361735228494]},"#bbaaee":{"lch":[73.2116196006959825,53.7916684525604,274.71268656160521],"luv":[73.2116196006959825,4.41947960396952144,-53.6098106221266093],"rgb":[0.733333333333333282,0.66666666666666663,0.933333333333333348],"xyz":[0.502981293855063849,0.454873151747880733,0.870217738548624387],"hpluv":[274.71268656160521,93.2340021292866084,73.2116196006959825],"hsluv":[274.71268656160521,76.5987468488048506,73.2116196006959825]},"#bbaaff":{"lch":[73.8908057188696574,67.9996555049746121,272.519622378571285],"luv":[73.8908057188696574,2.98936916429642707,-67.9339150998584671],"rgb":[0.733333333333333282,0.66666666666666663,1],"xyz":[0.52915234226489527,0.465341571111813457,1.00805192684040623],"hpluv":[272.519622378571285,116.776549017196231,73.8908057188696574],"hsluv":[272.519622378571285,99.9999999999974847,73.8908057188696574]},"#99bb00":{"lch":[71.0859361318702696,82.3913749493211327,101.26222245755217],"luv":[71.0859361318702696,-16.0909976916487061,80.8048170552163185],"rgb":[0.6,0.733333333333333282,0],"xyz":[0.309061217191489157,0.423126383737875533,0.0653895889393331653],"hpluv":[101.26222245755217,147.074503152999483,71.0859361318702696],"hsluv":[101.26222245755217,100.000000000002302,71.0859361318702696]},"#99bb11":{"lch":[71.1136894680978457,81.2167121813616291,101.442926834262664],"luv":[71.1136894680978457,-16.1127230849120338,79.6023523040561685],"rgb":[0.6,0.733333333333333282,0.0666666666666666657],"xyz":[0.310072882691126261,0.423531049937730386,0.0707176939040888],"hpluv":[101.442926834262664,144.921066000062638,71.1136894680978457],"hsluv":[101.442926834262664,98.4331733262411,71.1136894680978457]},"#99bb22":{"lch":[71.1650900316793837,79.0601549481488917,101.789083890819583],"luv":[71.1650900316793837,-16.1527448632600859,77.392486287802754],"rgb":[0.6,0.733333333333333282,0.133333333333333331],"xyz":[0.311948240829603318,0.424281193193121187,0.080594580100068],"hpluv":[101.789083890819583,140.971066242853169,71.1650900316793837],"hsluv":[101.789083890819583,95.5563304227746357,71.1650900316793837]},"#99bb33":{"lch":[71.2495884989653,75.5680342451554168,102.392870056849247],"luv":[71.2495884989653,-16.2179420391938294,73.807222923575253],"rgb":[0.6,0.733333333333333282,0.2],"xyz":[0.315035991562061,0.425516293486104313,0.0968567339576791309],"hpluv":[102.392870056849247,134.584514176993849,71.2495884989653],"hsluv":[102.392870056849247,90.8963478676004826,71.2495884989653]},"#99bb44":{"lch":[71.3712967033779648,70.652786516275043,103.347443045401377],"luv":[71.3712967033779648,-16.3105834167977157,68.7443169368786471],"rgb":[0.6,0.733333333333333282,0.266666666666666663],"xyz":[0.319493986806279939,0.427299491583791879,0.120335508910565769],"hpluv":[103.347443045401377,125.616021445862458,71.3712967033779648],"hsluv":[103.347443045401377,84.331672265085615,71.3712967033779648]},"#99bb55":{"lch":[71.5335490617920442,64.3081830776187502,104.804237401434776],"luv":[71.5335490617920442,-16.4318507493525949,62.1734404042074189],"rgb":[0.6,0.733333333333333282,0.333333333333333315],"xyz":[0.325456400845641924,0.42968445719953674,0.151737556184539685],"hpluv":[104.804237401434776,114.076396323867073,71.5335490617920442],"hsluv":[104.804237401434776,75.8403293762878263,71.5335490617920442]},"#99bb66":{"lch":[71.7390905918245494,56.6109161874071347,107.032342660002968],"luv":[71.7390905918245494,-16.5819871692753225,54.1279367156704367],"rgb":[0.6,0.733333333333333282,0.4],"xyz":[0.33304139661915011,0.432718455508940059,0.191685200591683647],"hpluv":[107.032342660002968,100.134479122606095,71.7390905918245494],"hsluv":[107.032342660002968,65.4891515707011,71.7390905918245494]},"#99bb77":{"lch":[71.9901757540345102,47.73532562127712,110.555323727161408],"luv":[71.9901757540345102,-16.7604289857032249,44.6961892378372099],"rgb":[0.6,0.733333333333333282,0.466666666666666674],"xyz":[0.342355409639352,0.436444060717020854,0.240739002498081556],"hpluv":[110.555323727161408,84.1406731320706,71.9901757540345102],"hsluv":[110.555323727161408,53.4218452589237,71.9901757540345102]},"#99bb88":{"lch":[72.2886271035685581,38.007890289968195,116.511646356383693],"luv":[72.2886271035685581,-16.9659512259030869,34.0111191126451473],"rgb":[0.6,0.733333333333333282,0.533333333333333326],"xyz":[0.353495826741295815,0.440900227557798452,0.299411865901653695],"hpluv":[116.511646356383693,66.7180145269523592,72.2886271035685581],"hsluv":[116.511646356383693,39.8440619041218724,72.2886271035685581]},"#99bb99":{"lch":[72.6358740128595315,28.1115962970155238,127.715012949234961],"luv":[72.6358740128595315,-17.1968288028560856,22.2380512970816788],"rgb":[0.6,0.733333333333333282,0.6],"xyz":[0.366552790850368515,0.44612301320142761,0.36817854354277163],"hpluv":[127.715012949234961,49.1104221429672094,72.6358740128595315],"hsluv":[127.715012949234961,25.0059581073328268,72.6358740128595315]},"#99bbaa":{"lch":[73.0329812495468929,19.8989345424194468,151.280397210880039],"luv":[73.0329812495468929,-17.4510036711552878,9.56190706882358654],"rgb":[0.6,0.733333333333333282,0.66666666666666663],"xyz":[0.381610483815621071,0.452146090387528732,0.447482393159770231],"hpluv":[151.280397210880039,34.5740392557976648,73.0329812495468929],"hsluv":[151.280397210880039,28.0327457551748473,73.0329812495468929]},"#99bbbb":{"lch":[73.4806726048520602,18.1342571597367979,192.177050630060279],"luv":[73.4806726048520602,-17.7262447217336288,-3.82511840348453136],"rgb":[0.6,0.733333333333333282,0.733333333333333282],"xyz":[0.398748075922957745,0.45900112723046349,0.537740378258412],"hpluv":[192.177050630060279,31.3159775944509384,73.4806726048520602],"hsluv":[192.177050630060279,31.1933976709334857,73.4806726048520602]},"#99bbcc":{"lch":[73.9793524714423,25.2831678504957686,224.541830016242],"luv":[73.9793524714423,-18.0202882726228886,-17.734367401402082],"rgb":[0.6,0.733333333333333282,0.8],"xyz":[0.418040451366679444,0.466718077407952292,0.639346888928682189],"hpluv":[224.541830016242,43.3670907410057183,73.9793524714423],"hsluv":[224.541830016242,34.4349286550277398,73.9793524714423]},"#99bbdd":{"lch":[74.5291269946933284,36.8692317824205347,240.185846709470951],"luv":[74.5291269946933284,-18.3309507682094441,-31.9893184697537762],"rgb":[0.6,0.733333333333333282,0.866666666666666696],"xyz":[0.439558776917313043,0.475325407628205798,0.752676736828688187],"hpluv":[240.185846709470951,62.7736499155611796,74.5291269946933284],"hsluv":[240.185846709470951,50.9371920612126914,74.5291269946933284]},"#99bbee":{"lch":[75.129825653719962,50.0395173115419851,248.109771752659725],"luv":[75.129825653719962,-18.6562099892881648,-46.4316607672792],"rgb":[0.6,0.733333333333333282,0.933333333333333348],"xyz":[0.463370957183487753,0.484850279734675815,0.87808755289721141],"hpluv":[248.109771752659725,84.5162185097210568,75.129825653719962],"hsluv":[248.109771752659725,74.708817528734329,75.129825653719962]},"#99bbff":{"lch":[75.7810236401202104,63.8171103470632701,252.684342225014],"luv":[75.7810236401202104,-18.9942553989637197,-60.9248868270445527],"rgb":[0.6,0.733333333333333282,1],"xyz":[0.489542005593319174,0.495318699098608539,1.01592174118899314],"hpluv":[252.684342225014,106.860202909060845,75.7810236401202104],"hsluv":[252.684342225014,99.9999999999971,75.7810236401202104]},"#443300":{"lch":[22.2907133772276609,26.4379209369795269,61.2454831359909],"luv":[22.2907133772276609,12.7181702882918319,23.1778300966244757],"rgb":[0.266666666666666663,0.2,0],"xyz":[0.0356761736431134499,0.0359671813792181508,0.00506334165336921362],"hpluv":[61.2454831359909,150.502134175174433,22.2907133772276609],"hsluv":[61.2454831359909,100.000000000002217,22.2907133772276609]},"#443311":{"lch":[22.433780901835803,22.5495741902090607,57.6291729330006959],"luv":[22.433780901835803,12.072970412625418,19.0453847841311372],"rgb":[0.266666666666666663,0.2,0.0666666666666666657],"xyz":[0.0366878391427505751,0.0363718475790730036,0.0103914466181248451],"hpluv":[57.6291729330006959,127.548453681164943,22.433780901835803],"hsluv":[57.6291729330006959,82.4396262904162853,22.433780901835803]},"#443322":{"lch":[22.6962080128251955,16.3034653251506185,47.6268315603120129],"luv":[22.6962080128251955,10.9878263584328284,12.044527949459761],"rgb":[0.266666666666666663,0.2,0.133333333333333331],"xyz":[0.0385631972812275903,0.037121990834463825,0.0202683328141040411],"hpluv":[47.6268315603120129,91.1519465603444,22.6962080128251955],"hsluv":[47.6268315603120129,53.1527363908354289,22.6962080128251955]},"#443333":{"lch":[23.1206934094119845,9.67437860897999613,12.1770506300626202],"luv":[23.1206934094119845,9.4567095438703852,2.04064844418642899],"rgb":[0.266666666666666663,0.2,0.2],"xyz":[0.0416509480136853308,0.0383570911274469378,0.0365304866717151844],"hpluv":[12.1770506300626202,53.0959690287213917,23.1206934094119845],"hsluv":[12.1770506300626202,12.4420312875371923,23.1206934094119845]},"#443344":{"lch":[23.7177668131648574,12.5269391023357528,307.715012949247694],"luv":[23.7177668131648574,7.66315882209806354,-9.90960141180911],"rgb":[0.266666666666666663,0.2,0.266666666666666663],"xyz":[0.0461089432579042113,0.0401402892251345109,0.0600092616246018229],"hpluv":[307.715012949247694,67.0209373905010608,23.7177668131648574],"hsluv":[307.715012949247694,23.1872031280306743,23.7177668131648574]},"#443355":{"lch":[24.4893027034144382,23.4497607107203301,284.299245815683662],"luv":[24.4893027034144382,5.79176863833153277,-22.7232632654309157],"rgb":[0.266666666666666663,0.2,0.333333333333333315],"xyz":[0.0520713572972662,0.0425252548408793438,0.0914113088985757383],"hpluv":[284.299245815683662,121.507006770462795,24.4893027034144382],"hsluv":[284.299245815683662,34.0172562824217479,24.4893027034144382]},"#443366":{"lch":[25.4301832846655458,35.8361728283181407,276.366541048647719],"luv":[25.4301832846655458,3.97382245046802396,-35.6151655634680964],"rgb":[0.266666666666666663,0.2,0.4],"xyz":[0.0596563530707743817,0.0455592531502826553,0.1313589533057197],"hpluv":[276.366541048647719,178.818092823782393,25.4301832846655458],"hsluv":[276.366541048647719,44.0521665839457555,25.4301832846655458]},"#443377":{"lch":[26.5300434901181958,48.2102429207408818,272.708376965990851],"luv":[26.5300434901181958,2.27805419202829862,-48.1563909733176416],"rgb":[0.266666666666666663,0.2,0.466666666666666674],"xyz":[0.0689703660909762872,0.0492848583583634717,0.180412755212117609],"hpluv":[272.708376965990851,230.590114205629249,26.5300434901181958],"hsluv":[272.708376965990851,52.8563285469964583,26.5300434901181958]},"#443388":{"lch":[27.7750487339787355,60.1896827108213373,270.691543734184165],"luv":[27.7750487339787355,0.726454682878815761,-60.1852986070773568],"rgb":[0.266666666666666663,0.2,0.533333333333333326],"xyz":[0.0801107831929201153,0.0537410251991410626,0.239085618615689777],"hpluv":[270.691543734184165,274.983446475144433,27.7750487339787355],"hsluv":[270.691543734184165,60.324174233719404,27.7750487339787355]},"#443399":{"lch":[29.1495234429961272,71.6961686956082218,269.452076389218803],"luv":[29.1495234429961272,-0.685625105343165342,-71.6928903298230438],"rgb":[0.266666666666666663,0.2,0.6],"xyz":[0.0931677473019928426,0.058963810842770227,0.307852296256807656],"hpluv":[269.452076389218803,312.107220431461315,29.1495234429961272],"hsluv":[269.452076389218803,66.5368599437509,29.1495234429961272]},"#4433aa":{"lch":[30.6372824460415245,82.7612763398458924,268.632918119842316],"luv":[30.6372824460415245,-1.97450330946598829,-82.7377193188284821],"rgb":[0.266666666666666663,0.2,0.66666666666666663],"xyz":[0.108225440267245371,0.0649868880288713285,0.387156145873806257],"hpluv":[268.632918119842316,342.78062465137026,30.6372824460415245],"hsluv":[268.632918119842316,71.6553387322885698,30.6372824460415245]},"#4433bb":{"lch":[32.2226022397772525,93.4505902198726375,268.062492493372758],"luv":[32.2226022397772525,-3.15951219941267691,-93.3971642776391633],"rgb":[0.266666666666666663,0.2,0.733333333333333282],"xyz":[0.125363032374582017,0.0718419248718060871,0.477414130972448],"hpluv":[268.062492493372758,368.010970109266054,32.2226022397772525],"hsluv":[268.062492493372758,75.8581190135042789,32.2226022397772525]},"#4433cc":{"lch":[33.8908458580626331,103.832026214070311,267.649236367220567],"luv":[33.8908458580626331,-4.25888397543315911,-103.744646006447894],"rgb":[0.266666666666666663,0.2,0.8],"xyz":[0.144655407818303772,0.0795588750492948887,0.579020641642718159],"hpluv":[267.649236367220567,388.765974213008576,33.8908458580626331],"hsluv":[267.649236367220567,79.3114034284002,33.8908458580626331]},"#4433dd":{"lch":[35.628800942302739,113.96424557581804,267.340372831489958],"luv":[35.628800942302739,-5.28823530427115518,-113.841485571087048],"rgb":[0.266666666666666663,0.2,0.866666666666666696],"xyz":[0.166173733368937315,0.0881662052695484227,0.692350489542724157],"hpluv":[267.340372831489958,405.888493424646128,35.628800942302739],"hsluv":[267.340372831489958,85.5677988674314,35.628800942302739]},"#4433ee":{"lch":[37.4248062251042484,123.894025620863303,267.103630337901393],"luv":[37.4248062251042484,-6.26032296204841732,-123.73575853791813],"rgb":[0.266666666666666663,0.2,0.933333333333333348],"xyz":[0.189985913635112053,0.0976910773760184536,0.81776130561124738],"hpluv":[267.103630337901393,420.078186698807599,37.4248062251042484],"hsluv":[267.103630337901393,92.6566888343209,37.4248062251042484]},"#4433ff":{"lch":[39.2687372084732473,133.657198385904053,266.918330051954797],"luv":[39.2687372084732473,-7.18532525912719411,-133.4639193988003],"rgb":[0.266666666666666663,0.2,1],"xyz":[0.216156962044943446,0.10815949673995115,0.955595493903029225],"hpluv":[266.918330051954797,431.901531941155895,39.2687372084732473],"hsluv":[266.918330051954797,99.99999999999946,39.2687372084732473]},"#bbbb00":{"lch":[73.6141498101152223,81.1522849996882485,85.8743202181747591],"luv":[73.6141498101152223,5.83845950082822274,80.9419900380996],"rgb":[0.733333333333333282,0.733333333333333282,0],"xyz":[0.382626051771664,0.461058251568279,0.0688379405602788],"hpluv":[85.8743202181747591,139.887458074797564,73.6141498101152223],"hsluv":[85.8743202181747591,100.000000000002331,73.6141498101152223]},"#bbbb11":{"lch":[73.6403599567658205,80.0195247391518478,85.8743202181747449],"luv":[73.6403599567658205,5.75696364516240155,79.8121651696532695],"rgb":[0.733333333333333282,0.733333333333333282,0.0666666666666666657],"xyz":[0.383637717271301082,0.461462917768133862,0.0741660455250344325],"hpluv":[85.8743202181747449,137.885751829634614,73.6403599567658205],"hsluv":[85.8743202181747449,98.5690595334933732,73.6403599567658205]},"#bbbb22":{"lch":[73.6889060807276763,77.9361940700347873,85.8743202181746597],"luv":[73.6889060807276763,5.60707948923862176,77.7342331648256817],"rgb":[0.733333333333333282,0.733333333333333282,0.133333333333333331],"xyz":[0.385513075409778139,0.462213061023524663,0.0840429317210136251],"hpluv":[85.8743202181746597,134.207383902194948,73.6889060807276763],"hsluv":[85.8743202181746597,95.9395400768792541,73.6889060807276763]},"#bbbb33":{"lch":[73.768722281637082,74.5519121144895536,85.8743202181745318],"luv":[73.768722281637082,5.36359906059884217,74.3587211095223],"rgb":[0.733333333333333282,0.733333333333333282,0.2],"xyz":[0.388600826142235845,0.46344816131650779,0.100305085578624775],"hpluv":[85.8743202181745318,128.24069174643796,73.768722281637082],"hsluv":[85.8743202181745318,91.6741883163470419,73.768722281637082]},"#bbbb44":{"lch":[73.8837085661944144,69.7637661309282464,85.8743202181743328],"luv":[73.8837085661944144,5.01911835485944824,69.5829829463408629],"rgb":[0.733333333333333282,0.733333333333333282,0.266666666666666663],"xyz":[0.39305882138645476,0.465231359414195356,0.123783860531511414],"hpluv":[85.8743202181743328,119.817583791868643,73.8837085661944144],"hsluv":[85.8743202181743328,85.652842249664161,73.8837085661944144]},"#bbbb55":{"lch":[74.0370403615741,63.5337415760462747,85.8743202181740628],"luv":[74.0370403615741,4.57090243520957262,63.3691026414263376],"rgb":[0.733333333333333282,0.733333333333333282,0.333333333333333315],"xyz":[0.399021235425816745,0.467616325029940216,0.155185907805485301],"hpluv":[85.8743202181740628,108.891682763750694,74.0370403615741],"hsluv":[85.8743202181740628,77.8423486010655239,74.0370403615741]},"#bbbb66":{"lch":[74.2313474843288361,55.8815023675101799,85.8743202181735512],"luv":[74.2313474843288361,4.02036601211528843,55.7366931561128212],"rgb":[0.733333333333333282,0.733333333333333282,0.4],"xyz":[0.40660623119932493,0.470650323339343535,0.195133552212629291],"hpluv":[85.8743202181735512,95.5256619678334857,74.2313474843288361],"hsluv":[85.8743202181735512,68.2875100330713138,74.2313474843288361]},"#bbbb77":{"lch":[74.468808451125966,46.8772880877030289,85.8743202181728549],"luv":[74.468808451125966,3.37256243628739805,46.7558120565865849],"rgb":[0.733333333333333282,0.733333333333333282,0.466666666666666674],"xyz":[0.415920244219526836,0.47437592854742433,0.2441873541190272],"hpluv":[85.8743202181728549,79.8780401793102328,74.468808451125966],"hsluv":[85.8743202181728549,57.1016453359253688,74.468808451125966]},"#bbbb88":{"lch":[74.7512063572608128,36.6333476151433146,85.874320218171647],"luv":[74.7512063572608128,2.63556739569020726,36.5384173438683746],"rgb":[0.733333333333333282,0.733333333333333282,0.533333333333333326],"xyz":[0.427060661321470636,0.478832095388201928,0.30286021752259934],"hpluv":[85.874320218171647,62.1867310089120195,74.7512063572608128],"hsluv":[85.874320218171647,44.4548295213588744,74.7512063572608128]},"#bbbb99":{"lch":[75.079965438194165,25.2938928616919938,85.8743202181691316],"luv":[75.079965438194165,1.81975614231989979,25.2283472245258693],"rgb":[0.733333333333333282,0.733333333333333282,0.6],"xyz":[0.440117625430543336,0.484054881031831086,0.371626895163717275],"hpluv":[85.8743202181691316,42.7494899193068392,75.079965438194165],"hsluv":[85.8743202181691316,30.559916169503893,75.079965438194165]},"#bbbbaa":{"lch":[75.4561775549407372,13.0242335847304886,85.8743202181613583],"luv":[75.4561775549407372,0.937021801842234714,12.9904830784884187],"rgb":[0.733333333333333282,0.733333333333333282,0.66666666666666663],"xyz":[0.455175318395795891,0.490077958217932208,0.450930744780715875],"hpluv":[85.8743202181613583,21.9026519543336242,75.4561775549407372],"hsluv":[85.8743202181613583,15.6573378741524305,75.4561775549407372]},"#bbbbbb":{"lch":[75.8806235332097856,3.97454725928322e-12,0],"luv":[75.8806235332097856,3.75098259432623098e-12,1.31421287976393485e-12],"rgb":[0.733333333333333282,0.733333333333333282,0.733333333333333282],"xyz":[0.472312910503132566,0.496932995060866967,0.541188729879357622],"hpluv":[0,6.64654731741433278e-12,75.8806235332097856],"hsluv":[0,6.51507609526145538e-12,75.8806235332097856]},"#bbbbcc":{"lch":[76.3537921403793,13.6026726964261613,265.874320218192793],"luv":[76.3537921403793,-0.97863730689855577,-13.5674232449512715],"rgb":[0.733333333333333282,0.733333333333333282,0.8],"xyz":[0.491605285946854265,0.504649945238355713,0.642795240549627778],"hpluv":[265.874320218192793,23.0577392955455913,76.3537921403793],"hsluv":[265.874320218192793,22.3559583930985184,76.3537921403793]},"#bbbbdd":{"lch":[76.875898300454,27.6153317552162676,265.874320218184891],"luv":[76.875898300454,-1.98677087225565296,-27.543770429115412],"rgb":[0.733333333333333282,0.733333333333333282,0.866666666666666696],"xyz":[0.513123611497487864,0.51325727545860933,0.756125088449633775],"hpluv":[265.874320218184891,48.094692651754464,76.875898300454],"hsluv":[265.874320218184891,46.4508399898830717,76.875898300454]},"#bbbbee":{"lch":[77.4469014383288794,41.8833893600305487,265.874320218182334],"luv":[77.4469014383288794,-3.01327895494808,-41.7748543291725554],"rgb":[0.733333333333333282,0.733333333333333282,0.933333333333333348],"xyz":[0.536935791763662573,0.522782147565079347,0.881535904518157],"hpluv":[265.874320218182334,75.1781465494946,77.4469014383288794],"hsluv":[265.874320218182334,72.306149300046286,77.4469014383288794]},"#bbbbff":{"lch":[78.0665243938900915,56.270213901735211,265.874320218181083],"luv":[78.0665243938900915,-4.04833166396953814,-56.1243973979724444],"rgb":[0.733333333333333282,0.733333333333333282,1],"xyz":[0.563106840173494,0.533250566929012,1.01937009280993873],"hpluv":[265.874320218181083,104.437018855576454,78.0665243938900915],"hsluv":[265.874320218181083,99.9999999999968,78.0665243938900915]},"#99cc00":{"lch":[76.0430979526319,91.0941172293808,106.263360497649074],"luv":[76.0430979526319,-25.5111694560196547,87.4489475453331124],"rgb":[0.6,0.8,0],"xyz":[0.347284960501106077,0.499573870357110428,0.0781308367092051204],"hpluv":[106.263360497649074,152.00919412554731,76.0430979526319],"hsluv":[106.263360497649074,100.000000000002444,76.0430979526319]},"#99cc11":{"lch":[76.0679435797449202,90.0431717383104342,106.457693210299354],"luv":[76.0679435797449202,-25.5098862277023812,86.3540299079582496],"rgb":[0.6,0.8,0.0666666666666666657],"xyz":[0.348296626000743181,0.499978536556965281,0.083458941673960757],"hpluv":[106.457693210299354,150.416675371578,76.0679435797449202],"hsluv":[106.457693210299354,98.6698238814781377,76.0679435797449202]},"#99cc22":{"lch":[76.1139653123302224,88.1120975577654235,106.827460928226145],"luv":[76.1139653123302224,-25.5076232207001254,84.3392132620406301],"rgb":[0.6,0.8,0.133333333333333331],"xyz":[0.350171984139220238,0.500728679812356137,0.0933358278699399496],"hpluv":[106.827460928226145,147.536178080277807,76.1139653123302224],"hsluv":[106.827460928226145,96.2239688839219554,76.1139653123302224]},"#99cc33":{"lch":[76.1896394090333615,84.9806694979027668,107.464683868975555],"luv":[76.1896394090333615,-25.5042190273125513,81.0632407452271195],"rgb":[0.6,0.8,0.2],"xyz":[0.353259734871677944,0.501963780105339263,0.109597981727551086],"hpluv":[107.464683868975555,142.843382477451314,76.1896394090333615],"hsluv":[107.464683868975555,92.2523981769505497,76.1896394090333615]},"#99cc44":{"lch":[76.2986765643697566,80.5641186971074461,108.452476349375274],"luv":[76.2986765643697566,-25.4999909675489818,76.4220366262018445],"rgb":[0.6,0.8,0.266666666666666663],"xyz":[0.357717730115896859,0.503746978203026829,0.133076756680437724],"hpluv":[108.452476349375274,136.177549938509202,76.2986765643697566],"hsluv":[108.452476349375274,86.6370393323296,76.2986765643697566]},"#99cc55":{"lch":[76.4441084930992645,74.8483308647658276,109.915235611542258],"luv":[76.4441084930992645,-25.4955548836031696,70.3722197633315858],"rgb":[0.6,0.8,0.333333333333333315],"xyz":[0.363680144155258844,0.506131943818771579,0.16447880395441164],"hpluv":[109.915235611542258,127.465568679298812,76.4441084930992645],"hsluv":[109.915235611542258,79.3378797119037245,76.4441084930992645]},"#99cc66":{"lch":[76.6284587708723279,67.8919791104198111,112.053749389120497],"luv":[76.6284587708723279,-25.4918238993559072,62.9244606001029396],"rgb":[0.6,0.8,0.4],"xyz":[0.37126513992876703,0.509165942128174898,0.204426448361555602],"hpluv":[112.053749389120497,116.726185086844026,76.6284587708723279],"hsluv":[112.053749389120497,70.3850130172815796,76.6284587708723279]},"#99cc77":{"lch":[76.8538330837355801,59.8379910057359723,115.212918879407354],"luv":[76.8538330837355801,-25.4899847789994141,54.1372869986012262],"rgb":[0.6,0.8,0.466666666666666674],"xyz":[0.380579152948968935,0.512891547336255749,0.253480250267953511],"hpluv":[115.212918879407354,104.093311342856381,76.8538330837355801],"hsluv":[115.212918879407354,59.8707914454029577,76.8538330837355801]},"#99cc88":{"lch":[77.1219726780439885,50.9458531819172649,120.024060615406185],"luv":[77.1219726780439885,-25.4914521322680621,44.1097021597488919],"rgb":[0.6,0.8,0.533333333333333326],"xyz":[0.391719570050912735,0.517347714177033291,0.31215311367152565],"hpluv":[120.024060615406185,89.8814395273866324,77.1219726780439885],"hsluv":[120.024060615406185,47.9401368886289845,77.1219726780439885]},"#99cc99":{"lch":[77.4342891130262103,41.681173098632776,127.715012949236964],"luv":[77.4342891130262103,-25.4978049096247332,32.9724450969124447],"rgb":[0.6,0.8,0.6],"xyz":[0.40477653415998549,0.522570499820662504,0.380919791312643585],"hpluv":[127.715012949236964,74.7648437658604337,77.4342891130262103],"hsluv":[127.715012949236964,34.7788947556027495,77.4342891130262103]},"#99ccaa":{"lch":[77.7918890721377352,32.9651751214879525,140.702563314804109],"luv":[77.7918890721377352,-25.5107121176450882,20.8783701002018844],"rgb":[0.6,0.8,0.66666666666666663],"xyz":[0.419834227125238,0.528593577006763571,0.460223640929642186],"hpluv":[140.702563314804109,60.2770963674260756,77.7918890721377352],"hsluv":[140.702563314804109,37.0803100068772622,77.7918890721377352]},"#99ccbb":{"lch":[78.1955939192693421,26.7536671513630395,162.617393192268167],"luv":[78.1955939192693421,-25.5318556358660231,7.9926875226808507],"rgb":[0.6,0.8,0.733333333333333282],"xyz":[0.436971819232574665,0.535448613849698329,0.550481626028283877],"hpluv":[162.617393192268167,50.006554278151107,78.1955939192693421],"hsluv":[162.617393192268167,39.5096284608221353,78.1955939192693421]},"#99cccc":{"lch":[78.6459566685868481,26.1512486118356264,192.177050630060364],"luv":[78.6459566685868481,-25.562857556775878,-5.51616873291790277],"rgb":[0.6,0.8,0.8],"xyz":[0.45626419467629642,0.543165564027187187,0.652088136698554],"hpluv":[192.177050630060364,50.1138147500145,78.6459566685868481],"hsluv":[192.177050630060364,42.0292910605185952,78.6459566685868481]},"#99ccdd":{"lch":[79.1432779300782,32.1756084020034763,217.269502822152816],"luv":[79.1432779300782,-25.6052179328205156,-19.4844191766612091],"rgb":[0.6,0.8,0.866666666666666696],"xyz":[0.477782520226929908,0.551772894247440693,0.76541798459856],"hpluv":[217.269502822152816,63.4104034428488532,79.1432779300782],"hsluv":[217.269502822152816,44.6030324020319142,79.1432779300782]},"#99ccee":{"lch":[79.6876217339600146,42.4043636674930298,232.761609201673764],"luv":[79.6876217339600146,-25.6602666815912279,-33.7591583407321],"rgb":[0.6,0.8,0.933333333333333348],"xyz":[0.501594700493104728,0.56129776635391071,0.890828800667083254],"hpluv":[232.761609201673764,86.2263034184575901,79.6876217339600146],"hsluv":[232.761609201673764,69.2463215394111842,79.6876217339600146]},"#99ccff":{"lch":[80.278831719152322,54.6396736698167231,241.908088190648726],"luv":[80.278831719152322,-25.7291311718118969,-48.2027566419988105],"rgb":[0.6,0.8,1],"xyz":[0.527765748902936,0.571766185717843434,1.02866298895886521],"hpluv":[241.908088190648726,115.039816302159181,80.278831719152322],"hsluv":[241.908088190648726,99.9999999999963762,80.278831719152322]},"#444400":{"lch":[27.7455139749470092,30.5866720374503593,85.8743202181747307],"luv":[27.7455139749470092,2.20054242411605072,30.5074108925390952],"rgb":[0.266666666666666663,0.266666666666666663,0],"xyz":[0.044508744126079483,0.0536323223451504599,0.00800753181435780864],"hpluv":[85.8743202181747307,139.887458074797593,27.7455139749470092],"hsluv":[85.8743202181747307,100.000000000002331,27.7455139749470092]},"#444411":{"lch":[27.8552611903384602,27.0161424908788135,85.8743202181744],"luv":[27.8552611903384602,1.9436625081132386,26.9461338811715763],"rgb":[0.266666666666666663,0.266666666666666663,0.0666666666666666657],"xyz":[0.0455204096257166,0.0540369885450053128,0.0133356367791134401],"hpluv":[85.8743202181744,123.070915058641674,27.8552611903384602],"hsluv":[85.8743202181744,87.9785198418851451,27.8552611903384602]},"#444422":{"lch":[28.0572627170229296,20.802612285424587,85.8743202181735086],"luv":[28.0572627170229296,1.49663326596887214,20.7487051828516122],"rgb":[0.266666666666666663,0.266666666666666663,0.133333333333333331],"xyz":[0.0473957677641936234,0.0547871318003961341,0.0232125229750926379],"hpluv":[85.8743202181735086,94.0831614915658463,28.0572627170229296],"hsluv":[85.8743202181735086,67.2563236092702539,28.0572627170229296]},"#444433":{"lch":[28.3858756417530103,11.5666907278610811,85.8743202181704],"luv":[28.3858756417530103,0.832159628943940688,11.5367172430437677],"rgb":[0.266666666666666663,0.266666666666666663,0.2],"xyz":[0.0504835184966513639,0.056022232093379247,0.0394746768327037811],"hpluv":[85.8743202181704,51.7066205750809758,28.3858756417530103],"hsluv":[85.8743202181704,36.9630139018145201,28.3858756417530103]},"#444444":{"lch":[28.8519023983998864,1.56211738287899238e-12,0],"luv":[28.8519023983998864,1.45745810878583046e-12,5.6216241338882039e-13],"rgb":[0.266666666666666663,0.266666666666666663,0.266666666666666663],"xyz":[0.0549415137408702445,0.05780543019106682,0.0629534517855904197],"hpluv":[0,6.87034486140541504e-12,28.8519023983998864],"hsluv":[0,1.96712204652458306e-12,28.8519023983998864]},"#444455":{"lch":[29.4604491554767947,12.996237632929807,265.874320218183527],"luv":[29.4604491554767947,-0.935007647451096213,-12.9625596743385874],"rgb":[0.266666666666666663,0.266666666666666663,0.333333333333333315],"xyz":[0.0609039277802322365,0.0601903958068116529,0.094355499059564335],"hpluv":[265.874320218183527,55.9780294653588157,29.4604491554767947],"hsluv":[265.874320218183527,10.903125265393685,29.4604491554767947]},"#444466":{"lch":[30.2117995944983235,26.5936989313503034,265.874320218180401],"luv":[30.2117995944983235,-1.9132700229980284,-26.52478502590359],"rgb":[0.266666666666666663,0.266666666666666663,0.4],"xyz":[0.0684889235537404079,0.0632243941162149714,0.134303143466708297],"hpluv":[265.874320218180401,111.69699235114156,30.2117995944983235],"hsluv":[265.874320218180401,21.7557908165695544,30.2117995944983235]},"#444477":{"lch":[31.1022350000615333,40.188693881548005,265.874320218179378],"luv":[31.1022350000615333,-2.89135495838767076,-40.084550420447286],"rgb":[0.266666666666666663,0.266666666666666663,0.466666666666666674],"xyz":[0.0778029365739423273,0.0669499993242957808,0.183356945373106206],"hpluv":[265.874320218179378,163.965176201048621,31.1022350000615333],"hsluv":[265.874320218179378,31.9363305989270607,31.1022350000615333]},"#444488":{"lch":[32.1249060438116132,53.4239352836437,265.874320218178923],"luv":[32.1249060438116132,-3.84355760936744639,-53.2854945186250859],"rgb":[0.266666666666666663,0.266666666666666663,0.533333333333333326],"xyz":[0.0889433536758861554,0.0714061661650733787,0.242029808776678373],"hpluv":[265.874320218178923,211.024721596932807,32.1249060438116132],"hsluv":[265.874320218178923,41.1023574005893479,32.1249060438116132]},"#444499":{"lch":[33.2707247827276404,66.1374776044503818,265.874320218178639],"luv":[33.2707247827276404,-4.75822688765494473,-65.9660914467787336],"rgb":[0.266666666666666663,0.266666666666666663,0.6],"xyz":[0.102000317784958869,0.0766289518087025362,0.31079648641779628],"hpluv":[265.874320218178639,252.246234683596128,33.2707247827276404],"hsluv":[265.874320218178639,50.2337582903708224,33.2707247827276404]},"#4444aa":{"lch":[34.5292085317775772,78.2936422443982707,265.874320218178468],"luv":[34.5292085317775772,-5.63279591471267516,-78.090755061511743],"rgb":[0.266666666666666663,0.266666666666666663,0.66666666666666663],"xyz":[0.117058010750211411,0.0826520289948036446,0.390100336034794881],"hpluv":[265.874320218178468,287.726060771882089,34.5292085317775772],"hsluv":[265.874320218178468,59.0260968416557645,34.5292085317775772]},"#4444bb":{"lch":[35.8892144652077647,89.9250819913669801,265.874320218178354],"luv":[35.8892144652077647,-6.46961387860876,-89.6920535355044],"rgb":[0.266666666666666663,0.266666666666666663,0.733333333333333282],"xyz":[0.134195602857548058,0.0895070658377384,0.480358321133436628],"hpluv":[265.874320218178354,317.948086985701252,35.8892144652077647],"hsluv":[265.874320218178354,67.4283717547759807,35.8892144652077647]},"#4444cc":{"lch":[37.3395287853000397,101.093816173965237,265.874320218178298],"luv":[37.3395287853000397,-7.27314272811459173,-100.831845482823283],"rgb":[0.266666666666666663,0.266666666666666663,0.8],"xyz":[0.153487978301269812,0.0972240160152272,0.581964831803706728],"hpluv":[265.874320218178298,343.55405942077391,37.3395287853000397],"hsluv":[265.874320218178298,75.5808548987534294,37.3395287853000397]},"#4444dd":{"lch":[38.8693012328948697,111.868746538356049,265.874320218178241],"luv":[38.8693012328948697,-8.04833956400084105,-111.578854100252741],"rgb":[0.266666666666666663,0.266666666666666663,0.866666666666666696],"xyz":[0.175006303851903355,0.105831346235480739,0.695294679703712726],"hpluv":[265.874320218178241,365.208910634554,38.8693012328948697],"hsluv":[265.874320218178241,83.6313726076760702,38.8693012328948697]},"#4444ee":{"lch":[40.4683363226646691,122.314460404417545,265.874320218178127],"luv":[40.4683363226646691,-8.799851087852959,-121.997499338533331],"rgb":[0.266666666666666663,0.266666666666666663,0.933333333333333348],"xyz":[0.198818484118078065,0.115356218341950756,0.820705495772236],"hpluv":[265.874320218178127,383.532154053589807,40.4683363226646691],"hsluv":[265.874320218178127,91.7249319236633625,40.4683363226646691]},"#4444ff":{"lch":[42.1272645151277203,132.4867415013303,265.874320218178127],"luv":[42.1272645151277203,-9.53169063144130568,-132.143420370999962],"rgb":[0.266666666666666663,0.266666666666666663,1],"xyz":[0.224989532527909486,0.12582463770588348,0.958539684064017794],"hpluv":[265.874320218178127,399.069452944254863,42.1272645151277203],"hsluv":[265.874320218178127,99.9999999999994458,42.1272645151277203]},"#bbcc00":{"lch":[78.3160688649495711,87.6272661942945916,93.3039767998847651],"luv":[78.3160688649495711,-5.05025027162958828,87.4816137990130471],"rgb":[0.733333333333333282,0.8,0],"xyz":[0.420849795081280953,0.537505738187513904,0.081579188330150737],"hpluv":[93.3039767998847651,164.876849582678972,78.3160688649495711],"hsluv":[93.3039767998847651,100.000000000002302,78.3160688649495711]},"#bbcc11":{"lch":[78.3397318378619332,86.5943586896397193,93.3754549086192],"luv":[78.3397318378619332,-5.09856582429126703,86.4441298377475249],"rgb":[0.733333333333333282,0.8,0.0666666666666666657],"xyz":[0.421861460580918057,0.537910404387368812,0.0869072932949063737],"hpluv":[93.3754549086192,163.146061131239662,78.3397318378619332],"hsluv":[93.3754549086192,98.7690619278293,78.3397318378619332]},"#bbcc22":{"lch":[78.3835653101130134,84.6929692802742125,93.5116381573829329],"luv":[78.3835653101130134,-5.18755307791811582,84.5339478468458481],"rgb":[0.733333333333333282,0.8,0.133333333333333331],"xyz":[0.423736818719395114,0.538660547642759613,0.0967841794908855663],"hpluv":[93.5116381573829329,159.95035726483485,78.3835653101130134],"hsluv":[93.5116381573829329,96.5043106774720343,78.3835653101130134]},"#bbcc33":{"lch":[78.4556479267243,81.5996211754986405,93.7468972468941644],"luv":[78.4556479267243,-5.33246113691784,81.4251990123951],"rgb":[0.733333333333333282,0.8,0.2],"xyz":[0.42682456945185282,0.53989564793574274,0.113046333348496703],"hpluv":[93.7468972468941644,154.72407311273281,78.4556479267243],"hsluv":[93.7468972468941644,92.8230308779070157,78.4556479267243]},"#bbcc44":{"lch":[78.5595248117047475,77.2136355312914873,94.1131309849175],"luv":[78.5595248117047475,-5.53822791342104281,77.0147618547127877],"rgb":[0.733333333333333282,0.8,0.266666666666666663],"xyz":[0.431282564696071735,0.541678846033430306,0.136525108301383341],"hpluv":[94.1131309849175,147.254264694427633,78.5595248117047475],"hsluv":[94.1131309849175,87.6101015600037556,78.5595248117047475]},"#bbcc55":{"lch":[78.6981007967589079,71.4912273296626921,94.6593076474989488],"luv":[78.6981007967589079,-5.80727962831129307,71.2549723768110823],"rgb":[0.733333333333333282,0.8,0.333333333333333315],"xyz":[0.43724497873543372,0.544063811649175,0.167927155575357256],"hpluv":[94.6593076474989488,137.398731222980217,78.6981007967589079],"hsluv":[94.6593076474989488,80.8199795518833639,78.6981007967589079]},"#bbcc66":{"lch":[78.8738041161037273,64.440755538040392,95.4673459440295176],"luv":[78.8738041161037273,-6.13981465986491681,64.1475927081912403],"rgb":[0.733333333333333282,0.8,0.4],"xyz":[0.444829974508941905,0.547097809958578374,0.207874799982501218],"hpluv":[95.4673459440295176,125.075317361724217,78.8738041161037273],"hsluv":[95.4673459440295176,72.4696955468646848,78.8738041161037273]},"#bbcc77":{"lch":[79.0886730863018244,56.1202023011108153,96.6860819525870454],"luv":[79.0886730863018244,-6.5340457953894715,55.7385266387743386],"rgb":[0.733333333333333282,0.8,0.466666666666666674],"xyz":[0.454143987529143811,0.550823415166659225,0.2569286018888991],"hpluv":[96.6860819525870454,110.256785788709905,79.0886730863018244],"hsluv":[96.6860819525870454,62.6323703341884,79.0886730863018244]},"#bbcc88":{"lch":[79.3444074564468451,46.6379090458556931,98.6154841820407],"luv":[79.3444074564468451,-6.9864776714612713,46.1116437563841473],"rgb":[0.733333333333333282,0.8,0.533333333333333326],"xyz":[0.465284404631087611,0.555279582007436767,0.315601465292471295],"hpluv":[98.6154841820407,92.9740665461038702,79.3444074564468451],"hsluv":[98.6154841820407,51.4293340198482483,79.3444074564468451]},"#bbcc99":{"lch":[79.6424016540563,36.1659853952486898,101.956116252097843],"luv":[79.6424016540563,-7.49223418159530397,35.3814206410296137],"rgb":[0.733333333333333282,0.8,0.6],"xyz":[0.478341368740160311,0.560502367651066,0.38436814293358923],"hpluv":[101.956116252097843,73.3480812445522616,79.6424016540563],"hsluv":[101.956116252097843,39.0205672484538439,79.6424016540563]},"#bbccaa":{"lch":[79.9837682606211899,25.01387761080953,108.762036830266098],"luv":[79.9837682606211899,-8.04542335958215382,23.6847046866463593],"rgb":[0.733333333333333282,0.8,0.66666666666666663],"xyz":[0.493399061705412867,0.566525444837167,0.463671992550587775],"hpluv":[108.762036830266098,51.7527419020047645,79.9837682606211899],"hsluv":[108.762036830266098,25.5939208298632828,79.9837682606211899]},"#bbccbb":{"lch":[80.3693561861161356,14.1229851396422195,127.715012949226079],"luv":[80.3693561861161356,-8.63951499109438892,11.1721748094634776],"rgb":[0.733333333333333282,0.8,0.733333333333333282],"xyz":[0.510536653812749486,0.573380481680101806,0.553929977649229577],"hpluv":[127.715012949226079,29.8960175179438359,80.3693561861161356],"hsluv":[127.715012949226079,11.3539027840963094,80.3693561861161356]},"#bbcccc":{"lch":[80.7997661027856537,9.48102181692548207,192.177050630058517],"luv":[80.7997661027856537,-9.26770319062559622,-1.99986306118322021],"rgb":[0.733333333333333282,0.8,0.8],"xyz":[0.52982902925647124,0.581097431857590663,0.655536488319499733],"hpluv":[192.177050630058517,20.5979746439306091,80.7997661027856537],"hsluv":[192.177050630058517,14.8313634310922779,80.7997661027856537]},"#bbccdd":{"lch":[81.2753646562375138,18.5534915910332536,237.666646406054781],"luv":[81.2753646562375138,-9.9232294288842251,-15.6767843616051454],"rgb":[0.733333333333333282,0.8,0.866666666666666696],"xyz":[0.551347354807104839,0.589704762077844169,0.76886633621950573],"hpluv":[237.666646406054781,41.5059211719903089,81.2753646562375138],"hsluv":[237.666646406054781,34.6395739712995834,81.2753646562375138]},"#bbccee":{"lch":[81.7962983545147466,31.5457627715974915,250.366116177600304],"luv":[81.7962983545147466,-10.5996485000078611,-29.7116576534899401],"rgb":[0.733333333333333282,0.8,0.933333333333333348],"xyz":[0.575159535073279549,0.599229634184314186,0.894277152288029],"hpluv":[250.366116177600304,72.9233806917818725,81.7962983545147466],"hsluv":[250.366116177600304,65.9765826509477478,81.7962983545147466]},"#bbccff":{"lch":[82.3625076456434329,45.3963265868234203,255.598148289110497],"luv":[82.3625076456434329,-11.2910283768039683,-43.9697526234994669],"rgb":[0.733333333333333282,0.8,1],"xyz":[0.601330583483111,0.60969805354824691,1.0321113405798108],"hpluv":[255.598148289110497,108.847942718229262,82.3625076456434329],"hsluv":[255.598148289110497,99.9999999999958789,82.3625076456434329]},"#99dd00":{"lch":[81.0072374435841738,100.100388992767378,110.059278565234735],"luv":[81.0072374435841738,-34.3336498242400623,94.028125400062109],"rgb":[0.6,0.866666666666666696,0],"xyz":[0.389918951048281226,0.584841851451462,0.0923421668915964389],"hpluv":[110.059278565234735,220.251619684458433,81.0072374435841738],"hsluv":[110.059278565234735,100.000000000002245,81.0072374435841738]},"#99dd11":{"lch":[81.0296061686003,99.1554895677318626,110.248463134872608],"luv":[81.0296061686003,-34.3169109383134483,93.0277417498051733],"rgb":[0.6,0.866666666666666696,0.0666666666666666657],"xyz":[0.39093061654791833,0.585246517651316855,0.0976702718563520755],"hpluv":[110.248463134872608,218.472914234601802,81.0296061686003],"hsluv":[110.248463134872608,98.8616036668283,81.0296061686003]},"#99dd22":{"lch":[81.0710445633976,97.4178442494470431,110.606606003803336],"luv":[81.0710445633976,-34.2861684396920552,91.184949591117217],"rgb":[0.6,0.866666666666666696,0.133333333333333331],"xyz":[0.392805974686395387,0.585996660906707656,0.107547158052331268],"hpluv":[110.606606003803336,215.192819254761019,81.0710445633976],"hsluv":[110.606606003803336,96.7659338960775131,81.0710445633976]},"#99dd33":{"lch":[81.1391953168863154,94.5961335984436857,111.218234049095599],"luv":[81.1391953168863154,-34.2363517117206513,88.1833358024404106],"rgb":[0.6,0.866666666666666696,0.2],"xyz":[0.395893725418853093,0.587231761199690783,0.123809311909942404],"hpluv":[111.218234049095599,209.840835623165077,81.1391953168863154],"hsluv":[111.218234049095599,93.3562182204636599,81.1391953168863154]},"#99dd44":{"lch":[81.2374208116197565,90.6080011845065343,112.152709421166279],"luv":[81.2374208116197565,-34.1661449288095653,83.9195115533635487],"rgb":[0.6,0.866666666666666696,0.266666666666666663],"xyz":[0.400351720663072,0.589014959297378349,0.147288086862829043],"hpluv":[112.152709421166279,202.22119953609328,81.2374208116197565],"hsluv":[112.152709421166279,88.5208972681928827,81.2374208116197565]},"#99dd55":{"lch":[81.3684846041416421,85.4315699411036604,113.506988965296216],"luv":[81.3684846041416421,-34.0753153837539244,78.3417259453695607],"rgb":[0.6,0.866666666666666696,0.333333333333333315],"xyz":[0.406314134702434,0.591399924913123098,0.178690134136802958],"hpluv":[113.506988965296216,192.231211336261111,81.3684846041416421],"hsluv":[113.506988965296216,82.2103932307851579,81.3684846041416421]},"#99dd66":{"lch":[81.5347071887187695,79.1067404569191837,115.426438711198742],"luv":[81.5347071887187695,-33.9646313013793,71.4442454385217758],"rgb":[0.6,0.866666666666666696,0.4],"xyz":[0.413899130475942179,0.594433923222526417,0.21863777854394692],"hpluv":[115.426438711198742,179.864586291563711,81.5347071887187695],"hsluv":[115.426438711198742,74.4308834765056,81.5347071887187695]},"#99dd77":{"lch":[81.7380487099571,71.7428264562351217,118.139890255285593],"luv":[81.7380487099571,-33.8357763954940651,63.2627329764024324],"rgb":[0.6,0.866666666666666696,0.466666666666666674],"xyz":[0.423213143496144084,0.598159528430607268,0.267691580450344802],"hpluv":[118.139890255285593,165.232292085670224,81.7380487099571],"hsluv":[118.139890255285593,65.2389156719347,81.7380487099571]},"#99dd88":{"lch":[81.9801580086414248,63.5371271244577898,122.023063704989269],"luv":[81.9801580086414248,-33.6912346765093815,53.8689820694792942],"rgb":[0.6,0.866666666666666696,0.533333333333333326],"xyz":[0.434353560598087884,0.60261569527138481,0.326364443853917],"hpluv":[122.023063704989269,148.614644251947254,81.9801580086414248],"hsluv":[122.023063704989269,54.7350081565161943,81.9801580086414248]},"#99dd99":{"lch":[82.2624042681600827,54.8181455895933,127.715012949238044],"luv":[82.2624042681600827,-33.5341421039979721,43.3646215160552],"rgb":[0.6,0.866666666666666696,0.6],"xyz":[0.447410524707160584,0.607838480915014,0.395131121495034932],"hpluv":[127.715012949238044,130.58293025992694,82.2624042681600827],"hsluv":[127.715012949238044,43.0558433261763724,82.2624042681600827]},"#99ddaa":{"lch":[82.5858991321833855,46.1452119261310898,136.311935434488049],"luv":[82.5858991321833855,-33.3681126370237138,31.8739649675161907],"rgb":[0.6,0.866666666666666696,0.66666666666666663],"xyz":[0.46246821767241314,0.61386155810111509,0.474434971112033477],"hpluv":[136.311935434488049,112.281381223378744,82.5858991321833855],"hsluv":[136.311935434488049,44.8180878493830122,82.5858991321833855]},"#99ddbb":{"lch":[82.9515135213076,38.5190468703316,149.523212457301526],"luv":[82.9515135213076,-33.1970516149390349,19.536446347119437],"rgb":[0.6,0.866666666666666696,0.733333333333333282],"xyz":[0.479605809779749814,0.620716594944049849,0.564692956210675279],"hpluv":[149.523212457301526,96.0401150933983416,82.9515135213076],"hsluv":[149.523212457301526,46.6955526922259807,82.9515135213076]},"#99ddcc":{"lch":[83.3598915829196585,33.6584009809739158,168.866706644517421],"luv":[83.3598915829196585,-33.0249710093605202,6.49917274942921],"rgb":[0.6,0.866666666666666696,0.8],"xyz":[0.498898185223471513,0.628433545121538706,0.666299466880945435],"hpluv":[168.866706644517421,86.2854242091523,83.3598915829196585],"hsluv":[168.866706644517421,48.6618587245334879,83.3598915829196585]},"#99dddd":{"lch":[83.811463234187741,33.6120761253887,192.17705063006062],"luv":[83.811463234187741,-32.85581988586,-7.08990557672323529],"rgb":[0.6,0.866666666666666696,0.866666666666666696],"xyz":[0.520416510774105112,0.637040875341792212,0.779629314780951432],"hpluv":[192.17705063006062,88.9162454401141,83.811463234187741],"hsluv":[192.17705063006062,50.6906605199231777,83.811463234187741]},"#99ddee":{"lch":[84.3064561843391402,38.9043785470910208,212.822778279485817],"luv":[84.3064561843391402,-32.6933403312743565,-21.0878203738277712],"rgb":[0.6,0.866666666666666696,0.933333333333333348],"xyz":[0.544228691040279822,0.646565747448262229,0.905040130849474656],"hpluv":[212.822778279485817,106.615167592423816,84.3064561843391402],"hsluv":[212.822778279485817,60.6575363344623781,84.3064561843391402]},"#99ddff":{"lch":[84.8449079615810575,48.055447414973429,227.378328123916845],"luv":[84.8449079615810575,-32.5409551013358396,-35.3611689193969099],"rgb":[0.6,0.866666666666666696,1],"xyz":[0.570399739450111243,0.657034166812195,1.04287431914125639],"hpluv":[227.378328123916845,137.001856984753886,84.8449079615810575],"hsluv":[227.378328123916845,99.999999999994813,84.8449079615810575]},"#445500":{"lch":[33.4053570608210535,38.7644311760376397,101.469350612776353],"luv":[33.4053570608210535,-7.7080633936099785,37.9903525006263791],"rgb":[0.266666666666666663,0.333333333333333315,0],"xyz":[0.0563220008404254485,0.0772588357738427239,0.0119452840524730177],"hpluv":[101.469350612776353,147.25044771073371,33.4053570608210535],"hsluv":[101.469350612776353,100.000000000002245,33.4053570608210535]},"#445511":{"lch":[33.4914653280992525,35.8039831739898275,102.524785035338],"luv":[33.4914653280992525,-7.76452054412734,34.9519303021045076],"rgb":[0.266666666666666663,0.333333333333333315,0.0666666666666666657],"xyz":[0.0573336663400625668,0.0776635019736975768,0.0172733890172286492],"hpluv":[102.524785035338,135.655223597469387,33.4914653280992525],"hsluv":[102.524785035338,91.5452633494882093,33.4914653280992525]},"#445522":{"lch":[33.6502992474903806,30.5965852313305291,104.897478349629381],"luv":[33.6502992474903806,-7.86608410210478493,29.5681543001366229],"rgb":[0.266666666666666663,0.333333333333333315,0.133333333333333331],"xyz":[0.0592090244785395889,0.0784136452290883912,0.0271502752132078452],"hpluv":[104.897478349629381,115.378092601865731,33.6502992474903806],"hsluv":[104.897478349629381,76.6558497494370243,33.6502992474903806]},"#445533":{"lch":[33.9096245159150911,22.79863905315759,110.61032755328398],"luv":[33.9096245159150911,-8.02535730567797501,21.3394372651287],"rgb":[0.266666666666666663,0.333333333333333315,0.2],"xyz":[0.0622967752109973294,0.0796487455220715,0.0434124290708189919],"hpluv":[110.61032755328398,85.3149751467856419,33.9096245159150911],"hsluv":[110.61032755328398,54.1403397653178331,33.9096245159150911]},"#445544":{"lch":[34.2793424585633204,13.4702363502677187,127.715012949235046],"luv":[34.2793424585633204,-8.24020614134090401,10.6558092175245633],"rgb":[0.266666666666666663,0.333333333333333315,0.266666666666666663],"xyz":[0.0667547704552162,0.081431943619759084,0.0668912040237056305],"hpluv":[127.715012949235046,49.8634197051089814,34.2793424585633204],"hsluv":[127.715012949235046,25.3893680776039865,34.2793424585633204]},"#445555":{"lch":[34.7654846399243738,8.70030094248716424,192.177050630060222],"luv":[34.7654846399243738,-8.50454817645784544,-1.83518304377262664],"rgb":[0.266666666666666663,0.333333333333333315,0.333333333333333315],"xyz":[0.0727171844945782,0.0838169092355039169,0.098293251297679532],"hpluv":[192.177050630060222,31.7559649298661668,34.7654846399243738],"hsluv":[192.177050630060222,31.6316627668381969,34.7654846399243738]},"#445566":{"lch":[35.3707740335649916,17.7582093223154978,240.254504050727519],"luv":[35.3707740335649916,-8.81070452432763318,-15.4183489427423961],"rgb":[0.266666666666666663,0.333333333333333315,0.4],"xyz":[0.0803021802680863733,0.0868509075449072354,0.138240895704823508],"hpluv":[240.254504050727519,63.7079944588343352,35.3707740335649916],"hsluv":[240.254504050727519,38.2083413049732812,35.3707740335649916]},"#445577":{"lch":[36.0950574442792913,30.8488081821149329,252.743594747999822],"luv":[36.0950574442792913,-9.15124765847803623,-29.4602042177260124],"rgb":[0.266666666666666663,0.333333333333333315,0.466666666666666674],"xyz":[0.0896161932882882928,0.0905765127529880448,0.187294697611221417],"hpluv":[252.743594747999822,108.450105614435046,36.0950574442792913],"hsluv":[252.743594747999822,44.7362415879762878,36.0950574442792913]},"#445588":{"lch":[36.935739068143242,44.5159055243500319,257.651563208142],"luv":[36.935739068143242,-9.5200062368872409,-43.4860359874579245],"rgb":[0.266666666666666663,0.333333333333333315,0.533333333333333326],"xyz":[0.100756610390232121,0.0950326795937656427,0.245967561014793584],"hpluv":[257.651563208142,152.935302017774575,36.935739068143242],"hsluv":[257.651563208142,50.9359550606187952,36.935739068143242]},"#445599":{"lch":[37.8882410462664865,58.0440865604997711,260.167284745959819],"luv":[37.8882410462664865,-9.91231220062277885,-57.1914508600732674],"rgb":[0.266666666666666663,0.333333333333333315,0.6],"xyz":[0.113813574499304834,0.1002554652373948,0.314734238655911491],"hpluv":[260.167284745959819,194.398479571090235,37.8882410462664865],"hsluv":[260.167284745959819,56.6374271499956805,37.8882410462664865]},"#4455aa":{"lch":[38.9464770503006932,71.1678309986128141,261.658277796723496],"luv":[38.9464770503006932,-10.3247958657557941,-70.4149043837850144],"rgb":[0.266666666666666663,0.333333333333333315,0.66666666666666663],"xyz":[0.128871267464557376,0.106278542423495909,0.394038088272910092],"hpluv":[261.658277796723496,231.875507383352442,38.9464770503006932],"hsluv":[261.658277796723496,61.7617646139185652,38.9464770503006932]},"#4455bb":{"lch":[40.1033117689144,83.7900384834958,262.625350778636744],"luv":[40.1033117689144,-10.7550224317659584,-83.0969316013408417],"rgb":[0.266666666666666663,0.333333333333333315,0.733333333333333282],"xyz":[0.146008859571894023,0.113133579266430667,0.484296073371551838],"hpluv":[262.625350778636744,265.125486140416797,40.1033117689144],"hsluv":[262.625350778636744,66.2950009745661,40.1033117689144]},"#4455cc":{"lch":[41.3509797710146,95.8983760986006075,263.292411358069444],"luv":[41.3509797710146,-11.2011488171863753,-95.24196975873555],"rgb":[0.266666666666666663,0.333333333333333315,0.8],"xyz":[0.165301235015615777,0.120850529443919469,0.585902584041821939],"hpluv":[263.292411358069444,294.28272942652967,41.3509797710146],"hsluv":[263.292411358069444,71.9850161095278906,41.3509797710146]},"#4455dd":{"lch":[42.6814446156526657,107.523441304607104,263.773623462042394],"luv":[42.6814446156526657,-11.661670844638417,-106.88917561239117],"rgb":[0.266666666666666663,0.333333333333333315,0.866666666666666696],"xyz":[0.186819560566249321,0.129457859664173,0.699232431941827937],"hpluv":[263.773623462042394,319.67109728436958,42.6814446156526657],"hsluv":[263.773623462042394,81.2732363837730247,42.6814446156526657]},"#4455ee":{"lch":[44.0866885883675,118.714724855013472,264.132858108854521],"luv":[44.0866885883675,-12.1352655753704255,-118.092850024109339],"rgb":[0.266666666666666663,0.333333333333333315,0.933333333333333348],"xyz":[0.21063174083242403,0.13898273177064302,0.82464324801035116],"hpluv":[264.132858108854521,341.693279595385377,44.0866885883675],"hsluv":[264.132858108854521,90.5684283810677186,44.0866885883675]},"#4455ff":{"lch":[45.5589321196955765,129.526958246416882,264.408404412275218],"luv":[45.5589321196955765,-12.6207071057408875,-128.910630534181024],"rgb":[0.266666666666666663,0.333333333333333315,1],"xyz":[0.236802789242255451,0.149451151134575744,0.962477436302133],"hpluv":[264.408404412275218,360.766296003954039,45.5589321196955765],"hsluv":[264.408404412275218,99.9999999999992752,45.5589321196955765]},"#bbdd00":{"lch":[83.0607051195576673,95.2176030862527796,99.223939245402],"luv":[83.0607051195576673,-15.2627740644400269,93.9863802119702427],"rgb":[0.733333333333333282,0.866666666666666696,0],"xyz":[0.463483785628456102,0.622773719281865423,0.0957905185125420555],"hpluv":[99.223939245402,239.164338292747971,83.0607051195576673],"hsluv":[99.223939245402,100.00000000000216,83.0607051195576673]},"#bbdd11":{"lch":[83.082156377860457,94.2793845093074765,99.3314951275217481],"luv":[83.082156377860457,-15.2870500651298524,93.0317604034238457],"rgb":[0.733333333333333282,0.866666666666666696,0.0666666666666666657],"xyz":[0.464495451128093206,0.623178385481720332,0.101118623477297692],"hpluv":[99.3314951275217481,237.15213625798873,83.082156377860457],"hsluv":[99.3314951275217481,98.93507934353417,83.082156377860457]},"#bbdd22":{"lch":[83.1218967422411765,92.5513012339483794,99.5354402549794486],"luv":[83.1218967422411765,-15.3318301742674485,91.2725497814347],"rgb":[0.733333333333333282,0.866666666666666696,0.133333333333333331],"xyz":[0.466370809266570263,0.623928528737111132,0.110995509673276885],"hpluv":[99.5354402549794486,233.433860498438293,83.1218967422411765],"hsluv":[99.5354402549794486,96.9737920722735538,83.1218967422411765]},"#bbdd33":{"lch":[83.1872593514570298,89.7372330308786,99.8847694763800718],"luv":[83.1872593514570298,-15.4049421957575614,88.4050832700449263],"rgb":[0.733333333333333282,0.866666666666666696,0.2],"xyz":[0.469458559999027969,0.625163629030094259,0.127257663530888021],"hpluv":[99.8847694763800718,227.34486653748678,83.1872593514570298],"hsluv":[99.8847694763800718,93.7802848880547373,83.1872593514570298]},"#bbdd44":{"lch":[83.2814760883348697,85.7419087717973,100.421139587323779],"luv":[83.2814760883348697,-15.5091702542505097,84.3275788686944452],"rgb":[0.733333333333333282,0.866666666666666696,0.266666666666666663],"xyz":[0.473916555243246884,0.626946827127781825,0.15073643848377466],"hpluv":[100.421139587323779,218.62539011377612,83.2814760883348697],"hsluv":[100.421139587323779,89.2463889616074511,83.2814760883348697]},"#bbdd55":{"lch":[83.4072088624658,80.5207963453540572,101.204557559233223],"luv":[83.4072088624658,-15.6461875861262687,78.9860459708531835],"rgb":[0.733333333333333282,0.866666666666666696,0.333333333333333315],"xyz":[0.479878969282608869,0.629331792743526575,0.182138485757748575],"hpluv":[101.204557559233223,207.093501481883948,83.4072088624658],"hsluv":[101.204557559233223,83.3201121340644448,83.4072088624658]},"#bbdd66":{"lch":[83.5666996797624364,74.0772937371066149,102.328486133362119],"luv":[83.5666996797624364,-15.816696660053216,72.3690372616455164],"rgb":[0.733333333333333282,0.866666666666666696,0.4],"xyz":[0.487463965056117055,0.632365791052929893,0.222086130164892537],"hpluv":[102.328486133362119,192.635686460640301,83.5666996797624364],"hsluv":[102.328486133362119,75.9999631534792854,83.5666996797624364]},"#bbdd77":{"lch":[83.7618505003220122,66.4632811318093388,103.948126608074304],"luv":[83.7618505003220122,-16.0205304866066705,64.5035684418593149],"rgb":[0.733333333333333282,0.866666666666666696,0.466666666666666674],"xyz":[0.49677797807631896,0.636091396261010744,0.271139932071290446],"hpluv":[103.948126608074304,175.207590447676779,83.7618505003220122],"hsluv":[103.948126608074304,67.3303268013154,83.7618505003220122]},"#bbdd88":{"lch":[83.9942706402616,57.7845188457632091,106.339844930601203],"luv":[83.9942706402616,-16.2567564016803381,55.4505950331715454],"rgb":[0.733333333333333282,0.866666666666666696,0.533333333333333326],"xyz":[0.50791839517826276,0.640547563101788286,0.329812795474862641],"hpluv":[106.339844930601203,154.850612540446264,83.9942706402616],"hsluv":[106.339844930601203,57.39610210967858,83.9942706402616]},"#bbdd99":{"lch":[84.2653073070245711,48.2191913160874819,110.040291826115165],"luv":[84.2653073070245711,-16.5237946272095257,45.2996095159246153],"rgb":[0.733333333333333282,0.866666666666666696,0.6],"xyz":[0.520975359287335515,0.6457703487454175,0.39857947311598052],"hpluv":[110.040291826115165,131.749772406416298,84.2653073070245711],"hsluv":[110.040291826115165,46.3161497548768466,84.2653073070245711]},"#bbddaa":{"lch":[84.5760668100806328,38.0784660246866622,116.212889721452115],"luv":[84.5760668100806328,-16.8195514991441222,34.1624393473425059],"rgb":[0.733333333333333282,0.866666666666666696,0.66666666666666663],"xyz":[0.536033052252588,0.651793425931518566,0.477883322732979121],"hpluv":[116.212889721452115,106.421399158629868,84.5760668100806328],"hsluv":[116.212889721452115,34.2356923349747433,84.5760668100806328]},"#bbddbb":{"lch":[84.9274305013996553,28.0212505683590543,127.715012949233824],"luv":[84.9274305013996553,-17.1415612181778,22.1665821095230058],"rgb":[0.733333333333333282,0.866666666666666696,0.733333333333333282],"xyz":[0.55317064435992469,0.658648462774453325,0.568141307831620868],"hpluv":[127.715012949233824,80.3800713533813109,84.9274305013996553],"hsluv":[127.715012949233824,21.3181094477761164,84.9274305013996553]},"#bbddcc":{"lch":[85.3200677868051,19.876471170849122,151.617083508593169],"luv":[85.3200677868051,-17.4871274790593141,9.44851727715650291],"rgb":[0.733333333333333282,0.866666666666666696,0.8],"xyz":[0.572463019803646445,0.666365412951942182,0.669747818501891],"hpluv":[151.617083508593169,58.7374284962306703,85.3200677868051],"hsluv":[151.617083508593169,24.0698773292010699,85.3200677868051]},"#bbdddd":{"lch":[85.7544476215988,18.2643967282432129,192.177050630059739],"luv":[85.7544476215988,-17.8534562098583329,-3.85256916996079246],"rgb":[0.733333333333333282,0.866666666666666696,0.866666666666666696],"xyz":[0.593981345354279933,0.674972743172195688,0.783077666401897],"hpluv":[192.177050630059739,55.8245506661868234,85.7544476215988],"hsluv":[192.177050630059739,26.9205986284609722,85.7544476215988]},"#bbddee":{"lch":[86.2308493598319359,25.3453434934362818,223.980933900351914],"luv":[86.2308493598319359,-18.2377721186398958,-17.6002870700688909],"rgb":[0.733333333333333282,0.866666666666666696,0.933333333333333348],"xyz":[0.617793525620454753,0.684497615278665705,0.908488482470420244],"hpluv":[223.980933900351914,80.4705047412629142,86.2308493598319359],"hsluv":[223.980933900351914,55.5800524236117397,86.2308493598319359]},"#bbddff":{"lch":[86.7493734858622076,36.743147173338194,239.520163688183],"luv":[86.7493734858622076,-18.6374141011141354,-31.6655279416778761],"rgb":[0.733333333333333282,0.866666666666666696,1],"xyz":[0.643964574030286063,0.694966034642598429,1.0463226707622022],"hpluv":[239.520163688183,121.752323062157373,86.7493734858622076],"hsluv":[239.520163688183,99.9999999999938325,86.7493734858622076]},"#99ee00":{"lch":[85.9664003491010646,109.204546268980621,112.979852313128234],"luv":[85.9664003491010646,-42.6342645949387915,100.538313136150634],"rgb":[0.6,0.933333333333333348,0],"xyz":[0.437097727388796042,0.679199404132492912,0.108068425671767623],"hpluv":[112.979852313128234,339.428934639809256,85.9664003491010646],"hsluv":[112.979852313128234,100.000000000002444,85.9664003491010646]},"#99ee11":{"lch":[85.9866468155118326,108.350123359521945,113.156064955940181],"luv":[85.9866468155118326,-42.6072764400583495,99.6211284135251702],"rgb":[0.6,0.933333333333333348,0.0666666666666666657],"xyz":[0.438109392888433147,0.67960407033234782,0.11339653063652326],"hpluv":[113.156064955940181,337.317445797395,85.9866468155118326],"hsluv":[113.156064955940181,99.0182391276988,85.9866468155118326]},"#99ee22":{"lch":[86.0241571186350455,106.77763062148405,113.488368653358094],"luv":[86.0241571186350455,-42.5576013317541353,97.9301433166804287],"rgb":[0.6,0.933333333333333348,0.133333333333333331],"xyz":[0.439984751026910204,0.680354213587738621,0.123273416832502453],"hpluv":[113.488368653358094,333.419677856626379,86.0241571186350455],"hsluv":[113.488368653358094,97.2091916908085238,86.0241571186350455]},"#99ee33":{"lch":[86.0858572784747906,104.220652596579697,114.05202992935186],"luv":[86.0858572784747906,-42.476800751453851,95.1717701084636],"rgb":[0.6,0.933333333333333348,0.2],"xyz":[0.443072501759367909,0.681589313880721748,0.139535570690113603],"hpluv":[114.05202992935186,327.048640581280779,86.0858572784747906],"hsluv":[114.05202992935186,94.2610252844147709,86.0858572784747906]},"#99ee44":{"lch":[86.1748066309051239,100.599171066032113,114.904029942881266],"luv":[86.1748066309051239,-42.3622716989010186,91.2448966007484756],"rgb":[0.6,0.933333333333333348,0.266666666666666663],"xyz":[0.447530497003586825,0.683372511978409314,0.163014345643000241],"hpluv":[114.904029942881266,317.953677409096201,86.1748066309051239],"hsluv":[114.904029942881266,90.0700159696272777,86.1748066309051239]},"#99ee55":{"lch":[86.2935317577421586,95.884762204841536,116.119599614249481],"luv":[86.2935317577421586,-42.2129155656731854,86.0927254913233355],"rgb":[0.6,0.933333333333333348,0.333333333333333315],"xyz":[0.45349291104294881,0.685757477594154063,0.194416392916974157],"hpluv":[116.119599614249481,305.984138616458665,86.2935317577421586],"hsluv":[116.119599614249481,84.5822993375075924,86.2935317577421586]},"#99ee66":{"lch":[86.4441689863048879,90.1009507230509143,117.805124209421223],"luv":[86.4441689863048879,-42.0290075887870955,79.6978283411745565],"rgb":[0.6,0.933333333333333348,0.4],"xyz":[0.461077906816457,0.688791475903557382,0.234364037324118091],"hpluv":[117.805124209421223,291.090686380889622,86.4441689863048879],"hsluv":[117.805124209421223,77.7887546135139587,86.4441689863048879]},"#99ee77":{"lch":[86.6285404402691199,83.3280712532883712,120.117619079442107],"luv":[86.6285404402691199,-41.8120893585486826,72.0785449510868261],"rgb":[0.6,0.933333333333333348,0.466666666666666674],"xyz":[0.470391919836658901,0.692517081111638233,0.283417839230516],"hpluv":[120.117619079442107,273.344218704658658,86.6285404402691199],"hsluv":[120.117619079442107,69.7211272565473,86.6285404402691199]},"#99ee88":{"lch":[86.8481992617441563,75.7142340291470646,123.296374810060541],"luv":[86.8481992617441563,-41.5648380664255939,63.2851441582641],"rgb":[0.6,0.933333333333333348,0.533333333333333326],"xyz":[0.481532336938602701,0.696973247952415775,0.342090702634088195],"hpluv":[123.296374810060541,252.981665625798911,86.8481992617441563],"hsluv":[123.296374810060541,60.4476982156994964,86.8481992617441563]},"#99ee99":{"lch":[87.1044587056640864,67.4980907628946483,127.715012949238613],"luv":[87.1044587056640864,-41.2908999939099388,53.3952604107227131],"rgb":[0.6,0.933333333333333348,0.6],"xyz":[0.4945893010476754,0.702196033596045,0.410857380275206074],"hpluv":[127.715012949238613,230.504268403717248,87.1044587056640864],"hsluv":[127.715012949238613,50.0680020008431583,87.1044587056640864]},"#99eeaa":{"lch":[87.3984122167822477,59.0554460818204134,133.961345837807],"luv":[87.3984122167822477,-40.9946911699179566,42.5085992218733182],"rgb":[0.6,0.933333333333333348,0.66666666666666663],"xyz":[0.509646994012928,0.708219110782146,0.490161229892204675],"hpluv":[133.961345837807,206.883546406693341,87.3984122167822477],"hsluv":[133.961345837807,51.4281429353489514,87.3984122167822477]},"#99eebb":{"lch":[87.7309483141988409,50.9899623050450046,142.923108379062683],"luv":[87.7309483141988409,-40.6811762109167603,30.7411476358032338],"rgb":[0.6,0.933333333333333348,0.733333333333333282],"xyz":[0.526784586120264575,0.715074147625080814,0.580419214990846477],"hpluv":[142.923108379062683,183.977628608542716,87.7309483141988409],"hsluv":[142.923108379062683,52.8887094272277523,87.7309483141988409]},"#99eecc":{"lch":[88.1027624984453581,44.2777406304916781,155.702396707036257],"luv":[88.1027624984453581,-40.3556400464907483,18.219237958245273],"rgb":[0.6,0.933333333333333348,0.8],"xyz":[0.546076961563986329,0.722791097802569671,0.682025725661116633],"hpluv":[155.702396707036257,165.259943503195302,88.1027624984453581],"hsluv":[155.702396707036257,54.4312604691531305,88.1027624984453581]},"#99eedd":{"lch":[88.514367527899708,40.3437945821223494,172.775068456479858],"luv":[88.514367527899708,-40.023467685182176,5.07383442158517628],"rgb":[0.6,0.933333333333333348,0.866666666666666696],"xyz":[0.567595287114619929,0.731398428022823177,0.795355573561122631],"hpluv":[172.775068456479858,156.503534311163719,88.514367527899708],"hsluv":[172.775068456479858,56.0368199873083199,88.514367527899708]},"#99eeee":{"lch":[88.9661029048661476,40.6035054290346196,192.177050630060762],"luv":[88.9661029048661476,-39.6899452486728,-8.56463071492281891],"rgb":[0.6,0.933333333333333348,0.933333333333333348],"xyz":[0.591407467380794638,0.740923300129293194,0.920766389629645854],"hpluv":[192.177050630060762,164.568757380081195,88.9661029048661476],"hsluv":[192.177050630060762,57.6866071933722324,88.9661029048661476]},"#99eeff":{"lch":[89.4581440962481338,45.3723498615675496,209.831659516829347],"luv":[89.4581440962481338,-39.3600920674606272,-22.5706287994267498],"rgb":[0.6,0.933333333333333348,1],"xyz":[0.617578515790626059,0.751391719493225918,1.05860057792142759],"hpluv":[209.831659516829347,193.255751503994162,89.4581440962481338],"hsluv":[209.831659516829347,99.9999999999917293,89.4581440962481338]},"#446600":{"lch":[39.1245088935371612,48.4489514943966242,110.29724752770484],"luv":[39.1245088935371612,-16.806485623906017,45.4405429311736668],"rgb":[0.266666666666666663,0.4,0],"xyz":[0.0713500585462719106,0.107314951185536064,0.0169546366210883669],"hpluv":[110.29724752770484,157.13568029472475,39.1245088935371612],"hsluv":[110.29724752770484,100.000000000002302,39.1245088935371612]},"#446611":{"lch":[39.1937103273453289,46.0071342898824156,111.370502443062165],"luv":[39.1937103273453289,-16.7648801632844737,42.843846683952],"rgb":[0.266666666666666663,0.4,0.0666666666666666657],"xyz":[0.0723617240459090288,0.107719617385390917,0.022282741585844],"hpluv":[111.370502443062165,148.9526145018813,39.1937103273453289],"hsluv":[111.370502443062165,93.861989786091,39.1937103273453289]},"#446622":{"lch":[39.3215343087732165,41.6757739733598,113.610346420587263],"luv":[39.3215343087732165,-16.6917518579939177,38.1871124358693947],"rgb":[0.266666666666666663,0.4,0.133333333333333331],"xyz":[0.0742370821843860579,0.108469760640781732,0.0321596277818231926],"hpluv":[113.610346420587263,134.490790122462073,39.3215343087732165],"hsluv":[113.610346420587263,82.9003633409612,39.3215343087732165]},"#446633":{"lch":[39.530716823468623,35.0960892868442684,118.194686061271412],"luv":[39.530716823468623,-16.5818151114938139,30.931842668007679],"rgb":[0.266666666666666663,0.4,0.2],"xyz":[0.0773248329168437915,0.109704860933764844,0.0484217816394343359],"hpluv":[118.194686061271412,112.658344014206364,39.530716823468623],"hsluv":[118.194686061271412,65.945418212904,39.530716823468623]},"#446644":{"lch":[39.8299759493166761,26.8801274380109838,127.715012949238059],"luv":[39.8299759493166761,-16.4434970133495142,21.2638815143349724],"rgb":[0.266666666666666663,0.4,0.266666666666666663],"xyz":[0.0817828281610626651,0.111488059031452424,0.0719005565923209744],"hpluv":[127.715012949238059,85.6368345314009,39.8299759493166761],"hsluv":[127.715012949238059,43.6044123282566858,39.8299759493166761]},"#446655":{"lch":[40.2252775564066809,18.9132283301115756,149.466153210293243],"luv":[40.2252775564066809,-16.2905155992652197,9.6088140463343148],"rgb":[0.266666666666666663,0.4,0.333333333333333315],"xyz":[0.087745242200424664,0.113873024647197257,0.10330260386629489],"hpluv":[149.466153210293243,59.6631175613842473,40.2252775564066809],"hsluv":[149.466153210293243,47.2452022491104273,40.2252775564066809]},"#446666":{"lch":[40.7202569602655728,16.510473073285187,192.177050630060847],"luv":[40.7202569602655728,-16.1389950297194247,-3.48260829470770128],"rgb":[0.266666666666666663,0.4,0.4],"xyz":[0.0953302379739328354,0.116907022956600576,0.143250248273438852],"hpluv":[192.177050630060847,51.4503500463259655,40.7202569602655728],"hsluv":[192.177050630060847,51.2489582821824214,40.7202569602655728]},"#446677":{"lch":[41.3164898648363632,23.6752994583974647,227.46784435344162],"luv":[41.3164898648363632,-16.0045942322577233,-17.4462823519963166],"rgb":[0.266666666666666663,0.4,0.466666666666666674],"xyz":[0.104644250994134755,0.120632628164681385,0.192304050179836761],"hpluv":[227.46784435344162,72.7128872034151783,41.3164898648363632],"hsluv":[227.46784435344162,55.4049423234493261,41.3164898648363632]},"#446688":{"lch":[42.0137303768536654,35.5424939627414,243.425378218088099],"luv":[42.0137303768536654,-15.9003964812462133,-31.7875175002811758],"rgb":[0.266666666666666663,0.4,0.533333333333333326],"xyz":[0.115784668096078583,0.125088795005458969,0.2509769135834089],"hpluv":[243.425378218088099,107.348500116853913,42.0137303768536654],"hsluv":[243.425378218088099,59.5313600522085409,42.0137303768536654]},"#446699":{"lch":[42.8101553746289696,48.7666560663799089,251.050944767945737],"luv":[42.8101553746289696,-15.8358652521886238,-46.1238779333558782],"rgb":[0.266666666666666663,0.4,0.6],"xyz":[0.128841632205151296,0.130311580649088155,0.319743591224526835],"hpluv":[251.050944767945737,144.549135771893674,42.8101553746289696],"hsluv":[251.050944767945737,63.4907652576423231,42.8101553746289696]},"#4466aa":{"lch":[43.7026231888915078,62.2363741998113298,255.27738032783347],"luv":[43.7026231888915078,-15.8167390859625119,-60.1929982491778404],"rgb":[0.266666666666666663,0.4,0.66666666666666663],"xyz":[0.143899325170403825,0.136334657835189249,0.399047440841525436],"hpluv":[255.27738032783347,180.707469421570693,43.7026231888915078],"hsluv":[255.27738032783347,67.1924648453768896,43.7026231888915078]},"#4466bb":{"lch":[44.6869405362706402,75.5191451090451409,257.888120209084718],"luv":[44.6869405362706402,-15.8455247037125186,-73.83807029483539],"rgb":[0.266666666666666663,0.4,0.733333333333333282],"xyz":[0.161036917277740499,0.143189694678124,0.489305425940167182],"hpluv":[257.888120209084718,214.444923406304468,44.6869405362706402],"hsluv":[257.888120209084718,70.5866413561882098,44.6869405362706402]},"#4466cc":{"lch":[45.7581261645645299,88.428992560325014,259.626929599743789],"luv":[45.7581261645645299,-15.9222446749778896,-86.983727499712],"rgb":[0.266666666666666663,0.4,0.8],"xyz":[0.180329292721462225,0.150906644855612809,0.590911936610437283],"hpluv":[259.626929599743789,245.225581131482073,45.7581261645645299],"hsluv":[259.626929599743789,73.6549291646736179,45.7581261645645299]},"#4466dd":{"lch":[46.9106590907269165,100.895184366494064,260.849495088158733],"luv":[46.9106590907269165,-16.0451985527389489,-99.6111933055317422],"rgb":[0.266666666666666663,0.4,0.866666666666666696],"xyz":[0.201847618272095769,0.159513975075866343,0.704241784510443281],"hpluv":[260.849495088158733,272.92180192815988,46.9106590907269165],"hsluv":[260.849495088158733,78.541907894368677,46.9106590907269165]},"#4466ee":{"lch":[48.1387014995781897,112.90717489320852,261.744736192665698],"luv":[48.1387014995781897,-16.2116120228509466,-111.737253313235385],"rgb":[0.266666666666666663,0.4,0.933333333333333348],"xyz":[0.225659798538270506,0.16903884718233636,0.829652600578966504],"hpluv":[261.744736192665698,297.623004098842955,48.1387014995781897],"hsluv":[261.744736192665698,89.2025828989012126,48.1387014995781897]},"#4466ff":{"lch":[49.4362898036433194,124.485902067172418,262.421323096893047],"luv":[49.4362898036433194,-16.4181334215125325,-123.398479360286501],"rgb":[0.266666666666666663,0.4,1],"xyz":[0.251830846948101872,0.179507266546269084,0.967486788870748349],"hpluv":[262.421323096893047,319.531462910383539,49.4362898036433194],"hsluv":[262.421323096893047,99.9999999999992,49.4362898036433194]},"#bbee00":{"lch":[87.830324097455545,103.474670767003104,103.901308289378321],"luv":[87.830324097455545,-24.8598111448325625,100.444000717728017],"rgb":[0.733333333333333282,0.933333333333333348,0],"xyz":[0.510662561968970863,0.717131271962896388,0.111516777292713254],"hpluv":[103.901308289378321,376.707439149390723,87.830324097455545],"hsluv":[103.901308289378321,100.000000000002331,87.830324097455545]},"#bbee11":{"lch":[87.8498503793181413,102.621932764236291,104.023160127863235],"luv":[87.8498503793181413,-24.8667401733108697,99.5635792718425705],"rgb":[0.733333333333333282,0.933333333333333348,0.0666666666666666657],"xyz":[0.511674227468608,0.717535938162751297,0.116844882257468891],"hpluv":[104.023160127863235,374.263941750279344,87.8498503793181413],"hsluv":[104.023160127863235,99.0733759990956315,87.8498503793181413]},"#bbee22":{"lch":[87.8860274909110757,101.050540606732312,104.253301125000391],"luv":[87.8860274909110757,-24.8795662288424886,97.9398741125263],"rgb":[0.733333333333333282,0.933333333333333348,0.133333333333333331],"xyz":[0.513549585607085,0.718286081418142097,0.126721768453448069],"hpluv":[104.253301125000391,369.744422226518111,87.8860274909110757],"hsluv":[104.253301125000391,97.3653524759520224,87.8860274909110757]},"#bbee33":{"lch":[87.9455377581158899,98.4895893313188111,104.644745385959411],"luv":[87.9455377581158899,-24.9006321902472507,95.2898615970127878],"rgb":[0.733333333333333282,0.933333333333333348,0.2],"xyz":[0.516637336339542785,0.719521181711125224,0.142983922311059219],"hpluv":[104.644745385959411,362.331462484484575,87.9455377581158899],"hsluv":[104.644745385959411,94.5802259429375454,87.9455377581158899]},"#bbee44":{"lch":[88.03133674845418,94.8494424101932339,105.239087045756335],"luv":[88.03133674845418,-24.9309340294718567,91.5142898892991781],"rgb":[0.733333333333333282,0.933333333333333348,0.266666666666666663],"xyz":[0.521095331583761645,0.72130437980881279,0.166462697263945858],"hpluv":[105.239087045756335,351.690778632920285,88.03133674845418],"hsluv":[105.239087045756335,90.61757843521751,88.03133674845418]},"#bbee55":{"lch":[88.145869167101,90.085489786575252,106.092871571181419],"luv":[88.145869167101,-24.9712578135623886,86.5553681367929499],"rgb":[0.733333333333333282,0.933333333333333348,0.333333333333333315],"xyz":[0.527057745623123575,0.72368934542455754,0.197864744537919773],"hpluv":[106.092871571181419,337.573290416608245,88.145869167101],"hsluv":[106.092871571181419,85.422816781051381,88.145869167101]},"#bbee66":{"lch":[88.2912067804751786,84.1961694748550116,107.288882190620882],"luv":[88.2912067804751786,-25.0222263001917433,80.3920589686599527],"rgb":[0.733333333333333282,0.933333333333333348,0.4],"xyz":[0.534642741396631815,0.726723343733960858,0.237812388945063735],"hpluv":[107.288882190620882,319.804166688067426,88.2912067804751786],"hsluv":[107.288882190620882,78.9823949944632631,88.2912067804751786]},"#bbee77":{"lch":[88.4691221578712828,77.2243366572971439,108.954917992899311],"luv":[88.4691221578712828,-25.0843250262429365,73.0368044901840534],"rgb":[0.733333333333333282,0.933333333333333348,0.466666666666666674],"xyz":[0.543956754416833665,0.730448948942041709,0.286866190851461644],"hpluv":[108.954917992899311,298.285685525501094,88.4691221578712828],"hsluv":[108.954917992899311,71.3203705839542,88.4691221578712828]},"#bbee88":{"lch":[88.6811325759484106,69.2626802552854599,111.298371855766348],"luv":[88.6811325759484106,-25.1579200624522237,64.5321465184381822],"rgb":[0.733333333333333282,0.933333333333333348,0.533333333333333326],"xyz":[0.555097171518777577,0.734905115782819252,0.34553905425503384],"hpluv":[111.298371855766348,273.019747479454225,88.6811325759484106],"hsluv":[111.298371855766348,62.4946759175697224,88.6811325759484106]},"#bbee99":{"lch":[88.9285282571087095,60.4678989000773228,114.674688063820184],"luv":[88.9285282571087095,-25.2432722518949362,54.9467378777547069],"rgb":[0.733333333333333282,0.933333333333333348,0.6],"xyz":[0.568154135627850221,0.740127901426448465,0.414305731896151719],"hpluv":[114.674688063820184,244.173567048365754,88.9285282571087095],"hsluv":[114.674688063820184,52.5925914284503548,88.9285282571087095]},"#bbeeaa":{"lch":[89.2123917942545148,51.0969811847688931,119.731125412935242],"luv":[89.2123917942545148,-25.3405499711494109,44.3706886734509212],"rgb":[0.733333333333333282,0.933333333333333348,0.66666666666666663],"xyz":[0.583211828593102832,0.746150978612549531,0.493609581513150319],"hpluv":[119.731125412935242,212.254877789093854,89.2123917942545148],"hsluv":[119.731125412935242,41.7253920748903084,89.2123917942545148]},"#bbeebb":{"lch":[89.5336124490095,41.6027669810227181,127.715012949236097],"luv":[89.5336124490095,-25.4498411950279184,32.9104208971130276],"rgb":[0.733333333333333282,0.933333333333333348,0.733333333333333282],"xyz":[0.600349420700439396,0.75300601545548429,0.583867566611792066],"hpluv":[127.715012949236097,178.587287563939924,89.5336124490095],"hsluv":[127.715012949236097,37.7465419844818,89.5336124490095]},"#bbeecc":{"lch":[89.8928974614309766,32.8889663829363883,141.03222670888556],"luv":[89.8928974614309766,-25.571165029146556,20.6833176446640721],"rgb":[0.733333333333333282,0.933333333333333348,0.8],"xyz":[0.61964179614416115,0.760722965632973147,0.685474077282062222],"hpluv":[141.03222670888556,146.627829178506289,89.8928974614309766],"hsluv":[141.03222670888556,37.1073685119788,89.8928974614309766]},"#bbeedd":{"lch":[90.290781675649967,26.8655052232995288,163.094148385079734],"luv":[90.290781675649967,-25.704482585445124,7.81248653872008436],"rgb":[0.733333333333333282,0.933333333333333348,0.866666666666666696],"xyz":[0.641160121694794749,0.769330295853226653,0.79880392518206822],"hpluv":[163.094148385079734,125.084011642469022,90.290781675649967],"hsluv":[163.094148385079734,36.2429238875219255,90.290781675649967]},"#bbeeee":{"lch":[90.7276363011350782,26.4447005646089579,192.177050630060336],"luv":[90.7276363011350782,-25.8497069757021904,-5.5780675168164624],"rgb":[0.733333333333333282,0.933333333333333348,0.933333333333333348],"xyz":[0.664972301960969459,0.77885516795969667,0.924214741250591443],"hpluv":[192.177050630060336,129.38009793870765,90.7276363011350782],"hsluv":[192.177050630060336,36.8413123479339077,90.7276363011350782]},"#bbeeff":{"lch":[91.2036773284388289,32.4261328799939648,216.675663960190036],"luv":[91.2036773284388289,-26.0067122100428421,-19.367627980086624],"rgb":[0.733333333333333282,0.933333333333333348,1],"xyz":[0.69114335037080088,0.789323587323629394,1.06204892954237318],"hpluv":[216.675663960190036,167.86892764061264,91.2036773284388289],"hsluv":[216.675663960190036,99.9999999999901235,91.2036773284388289]},"#99ff00":{"lch":[90.9122626200542214,118.290950299530564,115.261698016578393],"luv":[90.9122626200542214,-50.4810643573161286,106.978554225220847],"rgb":[0.6,1,0],"xyz":[0.48895009981846993,0.782904148991842,0.125352549814991721],"hpluv":[115.261698016578393,591.369219456757151,90.9122626200542214],"hsluv":[115.261698016578393,100.000000000002402,90.9122626200542214]},"#99ff11":{"lch":[90.9306796583728,117.513960007406183,115.422432906031332],"luv":[90.9306796583728,-50.4474247175277384,106.134764031356056],"rgb":[0.6,1,0.0666666666666666657],"xyz":[0.489961765318107034,0.783308815191696928,0.130680654779747357],"hpluv":[115.422432906031332,588.764777700997797,90.9306796583728],"hsluv":[115.422432906031332,99.9999999999905356,90.9306796583728]},"#99ff22":{"lch":[90.9648031673089577,116.082935310332914,115.724658723180369],"luv":[90.9648031673089577,-50.3854319755480944,104.577990585497247],"rgb":[0.6,1,0.133333333333333331],"xyz":[0.491837123456584091,0.784058958447087728,0.140557540975726536],"hpluv":[115.724658723180369,583.951350293788323,90.9648031673089577],"hsluv":[115.724658723180369,99.9999999999904219,90.9648031673089577]},"#99ff33":{"lch":[91.0209396556716399,113.753057852482627,116.234667099004312],"luv":[91.0209396556716399,-50.2843870930134642,102.035477092383132],"rgb":[0.6,1,0.2],"xyz":[0.494924874189041797,0.785294058740070855,0.156819694833337686],"hpluv":[116.234667099004312,576.067585056329449,91.0209396556716399],"hsluv":[116.234667099004312,99.9999999999905924,91.0209396556716399]},"#99ff44":{"lch":[91.1018839706868562,110.446777199697451,116.999375135233294],"luv":[91.1018839706868562,-50.1407143313292565,98.409345898362929],"rgb":[0.6,1,0.266666666666666663],"xyz":[0.499382869433260712,0.787077256837758421,0.180298469786224325],"hpluv":[116.999375135233294,564.777897061868,91.1018839706868562],"hsluv":[116.999375135233294,99.9999999999903793,91.1018839706868562]},"#99ff55":{"lch":[91.2099533036034558,106.130684884370282,118.07780645420398],"luv":[91.2099533036034558,-49.9525457622324112,93.6400846106921279],"rgb":[0.6,1,0.333333333333333315],"xyz":[0.505345283472622642,0.789462222453503171,0.21170051706019824],"hpluv":[118.07780645420398,549.854625367801646,91.2099533036034558],"hsluv":[118.07780645420398,99.9999999999901377,91.2099533036034558]},"#99ff66":{"lch":[91.3471179899501351,100.815112661229691,119.549522622156928],"luv":[91.3471179899501351,-49.7195590247369807,87.7020660605103899],"rgb":[0.6,1,0.4],"xyz":[0.512930279246130882,0.792496220762906489,0.251648161467342202],"hpluv":[119.549522622156928,531.176396965461777,91.3471179899501351],"hsluv":[119.549522622156928,99.9999999999902656,91.3471179899501351]},"#99ff77":{"lch":[91.5150716426202,94.5571579863012488,121.52621580287979],"luv":[91.5150716426202,-49.442863485124569,80.6006164792656534],"rgb":[0.6,1,0.466666666666666674],"xyz":[0.522244292266332732,0.79622182597098734,0.300701963373740111],"hpluv":[121.52621580287979,508.746904082031563,91.5150716426202],"hsluv":[121.52621580287979,99.9999999999900098,91.5150716426202]},"#99ff88":{"lch":[91.7152730008064481,87.4673964918121385,124.169042550433474],"luv":[91.7152730008064481,-49.1248751175299461,72.3691377159004077],"rgb":[0.6,1,0.533333333333333326],"xyz":[0.533384709368276644,0.800677992811764883,0.359374826777312251],"hpluv":[124.169042550433474,482.74240688111388,91.7152730008064481],"hsluv":[124.169042550433474,99.999999999989754,91.7152730008064481]},"#99ff99":{"lch":[91.9489728509177,79.7227767672504,127.715012949239039],"luv":[91.9489728509177,-48.7691602166467675,63.0657604984184559],"rgb":[0.6,1,0.6],"xyz":[0.546441673477349288,0.805900778455394096,0.428141504418430185],"hpluv":[127.715012949239039,453.611771943482722,91.9489728509177],"hsluv":[127.715012949239039,99.9999999999896119,91.9489728509177]},"#99ffaa":{"lch":[92.2172324754492365,71.5909188251234525,132.515331265000469],"luv":[92.2172324754492365,-48.380245540777544,52.769418223432119],"rgb":[0.6,1,0.66666666666666663],"xyz":[0.561499366442601899,0.811923855641495162,0.507445354035428786],"hpluv":[132.515331265000469,422.278899597361089,92.2172324754492365],"hsluv":[132.515331265000469,99.999999999989285,92.2172324754492365]},"#99ffbb":{"lch":[92.5209371039878334,63.4744472180726902,139.080731133451],"luv":[92.5209371039878334,-47.9634018094000325,41.5754439123617558],"rgb":[0.6,1,0.733333333333333282],"xyz":[0.578636958549938463,0.818778892484429921,0.597703339134070477],"hpluv":[139.080731133451,390.542311531215887,92.5209371039878334],"hsluv":[139.080731133451,99.9999999999889866,92.5209371039878334]},"#99ffcc":{"lch":[92.8608063839845,55.9838497302527216,148.091690615728766],"luv":[92.8608063839845,-47.524412431304512,29.5909049148346774],"rgb":[0.6,1,0.8],"xyz":[0.597929333993660217,0.826495842661918778,0.699309849804340633],"hpluv":[148.091690615728766,361.818313682118117,92.8608063839845],"hsluv":[148.091690615728766,99.999999999988475,92.8608063839845]},"#99ffdd":{"lch":[93.237403107538583,50.0214511206169306,160.217319691395858],"luv":[93.237403107538583,-47.0693412211659066,16.9299347080170577],"rgb":[0.6,1,0.866666666666666696],"xyz":[0.619447659544293816,0.835103172882172284,0.812639697704346631],"hpluv":[160.217319691395858,342.295010089686684,93.237403107538583],"hsluv":[160.217319691395858,99.999999999988,93.237403107538583]},"#99ffee":{"lch":[93.6511409780710267,46.7516947594382444,175.449324589633676],"luv":[93.6511409780710267,-46.6043124006013088,3.70931645277729727],"rgb":[0.6,1,0.933333333333333348],"xyz":[0.643259839810468526,0.844628044988642301,0.938050513772869854],"hpluv":[175.449324589633676,341.869484566500148,93.6511409780710267],"hsluv":[175.449324589633676,99.9999999999875,93.6511409780710267]},"#99ffff":{"lch":[94.102291921527609,47.1972299789563579,192.177050630060847],"luv":[94.102291921527609,-46.1353140316371437,-9.95546668362271703],"rgb":[0.6,1,1],"xyz":[0.6694308882203,0.855096464352575,1.07588470206465181],"hpluv":[192.177050630060847,372.830957625984183,94.102291921527609],"hsluv":[192.177050630060847,99.999999999986585,94.102291921527609]},"#447700":{"lch":[44.83248944102629,58.4741115144389809,115.479055163134589],"luv":[44.83248944102629,-25.1544589141716,52.7870714677211339],"rgb":[0.266666666666666663,0.466666666666666674,0],"xyz":[0.0898037965996895393,0.144222427292371835,0.0231058826388940708],"hpluv":[115.479055163134589,165.50461307776385,44.83248944102629],"hsluv":[115.479055163134589,100.00000000000216,44.83248944102629]},"#447711":{"lch":[44.8893318820142468,56.4264635629906337,116.3750363045054],"luv":[44.8893318820142468,-25.0671673404006405,50.5527735317644158],"rgb":[0.266666666666666663,0.466666666666666674,0.0666666666666666657],"xyz":[0.0908154620993266576,0.144627093492226688,0.0284339876036497],"hpluv":[116.3750363045054,159.506732057184706,44.8893318820142468],"hsluv":[116.3750363045054,95.4073228169634433,44.8893318820142468]},"#447722":{"lch":[44.9944227930058389,52.7636609180533824,118.171656995978211],"luv":[44.9944227930058389,-24.9105023189221484,46.5131248971114388],"rgb":[0.266666666666666663,0.466666666666666674,0.133333333333333331],"xyz":[0.0926908202378036866,0.145377236747617516,0.0383108737996289],"hpluv":[118.171656995978211,148.804327803607492,44.9944227930058389],"hsluv":[118.171656995978211,87.128369469673089,44.9944227930058389]},"#447733":{"lch":[45.1666686690004795,47.1090234718488,121.574089601592789],"luv":[45.1666686690004795,-24.6663168629185812,40.1351828809748881],"rgb":[0.266666666666666663,0.466666666666666674,0.2],"xyz":[0.0957785709702614202,0.146612337040600615,0.0545730276572400433],"hpluv":[121.574089601592789,132.350433634303585,45.1666686690004795],"hsluv":[121.574089601592789,74.1245535442141232,45.1666686690004795]},"#447744":{"lch":[45.4136534494367368,39.7908238780444137,127.715012949239082],"luv":[45.4136534494367368,-24.3414133770851677,31.4770592606648769],"rgb":[0.266666666666666663,0.466666666666666674,0.266666666666666663],"xyz":[0.100236566214480294,0.148395535138288209,0.0780518026101266749],"hpluv":[127.715012949239082,111.18234158710581,45.4136534494367368],"hsluv":[127.715012949239082,56.6116285441109,45.4136534494367368]},"#447755":{"lch":[45.7409133262359902,31.7219583115713704,139.030718806592802],"luv":[45.7409133262359902,-23.9520203549447466,20.798638417872084],"rgb":[0.266666666666666663,0.466666666666666674,0.333333333333333315],"xyz":[0.106198980253842293,0.150780500754033042,0.10945384988410059],"hpluv":[139.030718806592802,88.0023935360314766,45.7409133262359902],"hsluv":[139.030718806592802,58.7992252631310066,45.7409133262359902]},"#447766":{"lch":[46.1522822994750328,25.0075472636366349,160.141849635166039],"luv":[46.1522822994750328,-23.5205108300662609,8.49488024846472],"rgb":[0.266666666666666663,0.466666666666666674,0.4],"xyz":[0.113783976027350464,0.153814499063436333,0.149401494291244552],"hpluv":[160.141849635166039,68.7570511480334,46.1522822994750328],"hsluv":[160.141849635166039,61.2825519214888672,46.1522822994750328]},"#447777":{"lch":[46.650089933282672,23.6026970305602966,192.177050630060933],"luv":[46.650089933282672,-23.0716472128555,-4.97859438013953248],"rgb":[0.266666666666666663,0.466666666666666674,0.466666666666666674],"xyz":[0.123097989047552384,0.157540104271517156,0.198455296197642461],"hpluv":[192.177050630060933,64.2019875277067,46.650089933282672],"hsluv":[192.177050630060933,63.9506821134950414,46.650089933282672]},"#447788":{"lch":[47.2353114433284134,29.6592888392359697,220.273189901853613],"luv":[47.2353114433284134,-22.6291741496980734,-19.1727382434503575],"rgb":[0.266666666666666663,0.466666666666666674,0.533333333333333326],"xyz":[0.134238406149496226,0.161996271112294754,0.257128159601214601],"hpluv":[220.273189901853613,79.6770556088496,47.2353114433284134],"hsluv":[220.273189901853613,66.6958169909158585,47.2353114433284134]},"#447799":{"lch":[47.9077085122244526,40.3569508451274856,236.603980798736757],"luv":[47.9077085122244526,-22.2133832668581981,-33.6934576046404],"rgb":[0.266666666666666663,0.466666666666666674,0.6],"xyz":[0.147295370258568925,0.167219056755923912,0.325894837242332536],"hpluv":[236.603980798736757,106.893740352524901,47.9077085122244526],"hsluv":[236.603980798736757,69.4246608010291197,47.9077085122244526]},"#4477aa":{"lch":[48.6659751090485,52.9419227285019574,245.636459716194196],"luv":[48.6659751090485,-21.8398581964299439,-48.2272513849846476],"rgb":[0.266666666666666663,0.466666666666666674,0.66666666666666663],"xyz":[0.162353063223821481,0.173242133942025,0.405198686859331136],"hpluv":[245.636459716194196,138.042751347741245,48.6659751090485],"hsluv":[245.636459716194196,72.0643617009564,48.6659751090485]},"#4477bb":{"lch":[49.5078912458612,66.145388752002,251.014275727268966],"luv":[49.5078912458612,-21.5192486824625604,-62.5470573991759125],"rgb":[0.266666666666666663,0.466666666666666674,0.733333333333333282],"xyz":[0.1794906553311581,0.180097170784959765,0.495456671957972883],"hpluv":[251.014275727268966,169.536991245322184,49.5078912458612],"hsluv":[251.014275727268966,74.5637193650047578,49.5078912458612]},"#4477cc":{"lch":[50.4304819457797606,79.4031370336833,254.471410742848605],"luv":[50.4304819457797606,-21.2577420931439356,-76.5046833330565761],"rgb":[0.266666666666666663,0.466666666666666674,0.8],"xyz":[0.198783030774879854,0.187814120962448566,0.597063182628243094],"hpluv":[254.471410742848605,199.794656417231295,50.4304819457797606],"hsluv":[254.471410742848605,76.8911855438839638,50.4304819457797606]},"#4477dd":{"lch":[51.4301761714764183,92.4467030892661654,256.833353640671476],"luv":[51.4301761714764183,-21.0578873175855144,-90.0164334652001514],"rgb":[0.266666666666666663,0.466666666666666674,0.866666666666666696],"xyz":[0.220301356325513398,0.1964214511827021,0.710393030528249092],"hpluv":[256.833353640671476,228.093412194404408,51.4301761714764183],"hsluv":[256.833353640671476,79.0312420746427904,51.4301761714764183]},"#4477ee":{"lch":[52.5029598761355913,105.148975578657073,258.524369979875587],"luv":[52.5029598761355913,-20.9195063280493,-103.046985983248078],"rgb":[0.266666666666666663,0.466666666666666674,0.933333333333333348],"xyz":[0.244113536591688135,0.205946323289172145,0.835803846596772315],"hpluv":[258.524369979875587,254.132720010738154,52.5029598761355913],"hsluv":[258.524369979875587,87.6254974090696,52.5029598761355913]},"#4477ff":{"lch":[53.6445179522116,117.458222301342076,259.779939364455799],"luv":[53.6445179522116,-20.8405325230258285,-115.594576820663164],"rgb":[0.266666666666666663,0.466666666666666674,1],"xyz":[0.270284585001519528,0.216414742653104841,0.973638034888554],"hpluv":[259.779939364455799,277.841684308431127,53.6445179522116],"hsluv":[259.779939364455799,99.999999999999,53.6445179522116]},"#bbff00":{"lch":[92.6117448358007778,112.09772632761252,107.605046807390437],"luv":[92.6117448358007778,-33.9043888880720843,106.847520616749406],"rgb":[0.733333333333333282,1,0],"xyz":[0.56251493439864475,0.820836016822245496,0.128800901435937365],"hpluv":[107.605046807390437,698.685604225905081,92.6117448358007778],"hsluv":[107.605046807390437,100.000000000002302,92.6117448358007778]},"#bbff11":{"lch":[92.6295901709342,111.320425805292416,107.729052066712285],"luv":[92.6295901709342,-33.8988588935206678,106.033506813595423],"rgb":[0.733333333333333282,1,0.0666666666666666657],"xyz":[0.56352659989828191,0.821240683022100404,0.134129006400693],"hpluv":[107.729052066712285,695.618439183936061,92.6295901709342],"hsluv":[107.729052066712285,99.9999999999893703,92.6295901709342]},"#bbff22":{"lch":[92.6626551654141,109.887399193340656,107.962519071076329],"luv":[92.6626551654141,-33.888700280085942,104.531318248662245],"rgb":[0.733333333333333282,1,0.133333333333333331],"xyz":[0.565401958036758856,0.821990826277491204,0.14400589259667218],"hpluv":[107.962519071076329,689.937572971075,92.6626551654141],"hsluv":[107.962519071076329,99.9999999999891713,92.6626551654141]},"#bbff33":{"lch":[92.7170524122382318,107.550157892444602,108.357408717671873],"luv":[92.7170524122382318,-33.8722333827189388,102.076972272674624],"rgb":[0.733333333333333282,1,0.2],"xyz":[0.568489708769216673,0.823225926570474331,0.160268046454283331],"hpluv":[108.357408717671873,680.59767216104342,92.7170524122382318],"hsluv":[108.357408717671873,99.9999999999894271,92.7170524122382318]},"#bbff44":{"lch":[92.7954935084343475,104.224206838295117,108.951712424811362],"luv":[92.7954935084343475,-33.8490183743317,98.5744857768270464],"rgb":[0.733333333333333282,1,0.266666666666666663],"xyz":[0.572947704013435533,0.825009124668161897,0.183746821407169969],"hpluv":[108.951712424811362,667.142517523628385,92.7954935084343475],"hsluv":[108.951712424811362,99.9999999999890576,92.7954935084343475]},"#bbff55":{"lch":[92.9002292713318809,99.8647848732016,109.794505003516988],"luv":[92.9002292713318809,-33.8189779888925628,93.9640994505754605],"rgb":[0.733333333333333282,1,0.333333333333333315],"xyz":[0.578910118052797462,0.827394090283906647,0.215148868681143884],"hpluv":[109.794505003516988,649.201221057988732,92.9002292713318809],"hsluv":[109.794505003516988,99.9999999999888445,92.9002292713318809]},"#bbff66":{"lch":[93.0331768315467826,94.4651128464689691,110.953951756581517],"luv":[93.0331768315467826,-33.7823795150753,88.2179595059619146],"rgb":[0.733333333333333282,1,0.4],"xyz":[0.586495113826305703,0.83042808859331,0.255096513088287846],"hpluv":[110.953951756581517,626.470359589551208,93.0331768315467826],"hsluv":[110.953951756581517,99.9999999999888871,93.0331768315467826]},"#bbff77":{"lch":[93.1959878807374196,88.0576290523864742,112.529317332402641],"luv":[93.1959878807374196,-33.7398191848892566,81.3373876867131571],"rgb":[0.733333333333333282,1,0.466666666666666674],"xyz":[0.595809126846507553,0.834153693801390816,0.304150314994685755],"hpluv":[112.529317332402641,598.713569857690459,93.1959878807374196],"hsluv":[112.529317332402641,99.9999999999886455,93.1959878807374196]},"#bbff88":{"lch":[93.3900894470196334,80.7182094219550805,114.670873894576516],"luv":[93.3900894470196334,-33.6921989698203319,73.3502901212028888],"rgb":[0.733333333333333282,1,0.533333333333333326],"xyz":[0.606949543948451464,0.838609860642168359,0.362823178398257951],"hpluv":[114.670873894576516,565.785048639302204,93.3900894470196334],"hsluv":[114.670873894576516,99.9999999999880913,93.3900894470196334]},"#bbff99":{"lch":[93.6167101348934239,72.575742292483838,117.61482369288214],"luv":[93.6167101348934239,-33.6406927329059684,64.3081811417119411],"rgb":[0.733333333333333282,1,0.6],"xyz":[0.620006508057524108,0.843832646285797572,0.43158985603937583],"hpluv":[117.61482369288214,527.702623330867254,93.6167101348934239],"hsluv":[117.61482369288214,99.9999999999881,93.6167101348934239]},"#bbffaa":{"lch":[93.8768980816178384,63.8331941826517948,121.746607961207644],"luv":[93.8768980816178384,-33.5867019719833948,54.2826872050868303],"rgb":[0.733333333333333282,1,0.66666666666666663],"xyz":[0.63506420102277672,0.849855723471898639,0.510893705656374486],"hpluv":[121.746607961207644,484.836572610502856,93.8768980816178384],"hsluv":[121.746607961207644,99.9999999999878781,93.8768980816178384]},"#bbffbb":{"lch":[94.1715339943383,54.8143223318485937,127.715012949237362],"luv":[94.1715339943383,-33.5318032859449531,43.3615970772812602],"rgb":[0.733333333333333282,1,0.733333333333333282],"xyz":[0.652201793130113283,0.856710760314833397,0.601151690755016177],"hpluv":[127.715012949237362,438.38038704048256,94.1715339943383],"hsluv":[127.715012949237362,99.999999999986926,94.1715339943383]},"#bbffcc":{"lch":[94.5013412228876888,46.0666753200389323,136.612331153023604],"luv":[94.5013412228876888,-33.4776907719138919,31.6446329670924698],"rgb":[0.733333333333333282,1,0.8],"xyz":[0.671494168573835,0.864427710492322254,0.702758201425286333],"hpluv":[136.612331153023604,391.513584290668746,94.5013412228876888],"hsluv":[136.612331153023604,99.9999999999865707,94.5013412228876888]},"#bbffdd":{"lch":[94.8668940681869515,38.5674836948257322,150.076437256866],"luv":[94.8668940681869515,-33.4261169986321818,19.2391658068743077],"rgb":[0.733333333333333282,1,0.866666666666666696],"xyz":[0.693012494124468637,0.873035040712575761,0.816088049325292331],"hpluv":[150.076437256866,352.109825744613431,94.8668940681869515],"hsluv":[150.076437256866,99.9999999999853628,94.8668940681869515]},"#bbffee":{"lch":[95.2686250900245568,33.9600576278843675,169.384373669661102],"luv":[95.2686250900245568,-33.3788361105619771,6.25610214058809699],"rgb":[0.733333333333333282,1,0.933333333333333348],"xyz":[0.716824674390643346,0.882559912819045778,0.941498865393815554],"hpluv":[169.384373669661102,337.406400875084444,95.2686250900245568],"hsluv":[169.384373669661102,99.9999999999845,95.2686250900245568]},"#bbffff":{"lch":[95.7068319095003,34.1048965933827191,192.177050630060478],"luv":[95.7068319095003,-33.3375521201936849,-7.19385781613020914],"rgb":[0.733333333333333282,1,1],"xyz":[0.742995722800474767,0.893028332182978501,1.0793330536855974],"hpluv":[192.177050630060478,374.679972152143307,95.7068319095003],"hsluv":[192.177050630060478,99.9999999999829186,95.7068319095003]},"#448800":{"lch":[50.4956227619448157,68.4221216779621244,118.715311426014551],"luv":[50.4956227619448157,-32.873947818662586,60.0074186224478723],"rgb":[0.266666666666666663,0.533333333333333326,0],"xyz":[0.111876166324659992,0.18836716674231338,0.0304633392138840171],"hpluv":[118.715311426014551,171.942062028892252,50.4956227619448157],"hsluv":[118.715311426014551,100.000000000002373,50.4956227619448157]},"#448811":{"lch":[50.543205868460916,66.6756511812714763,119.435612575278299],"luv":[50.543205868460916,-32.7674265649617098,58.0683925794095899],"rgb":[0.266666666666666663,0.533333333333333326,0.0666666666666666657],"xyz":[0.112887831824297111,0.188771832942168233,0.0357914441786396503],"hpluv":[119.435612575278299,167.395510973175305,50.543205868460916],"hsluv":[119.435612575278299,96.4702491056824272,50.543205868460916]},"#448822":{"lch":[50.6312327062127565,63.5295563644356918,120.846986072134357],"luv":[50.6312327062127565,-32.5745953261955492,54.5426463530750425],"rgb":[0.266666666666666663,0.533333333333333326,0.133333333333333331],"xyz":[0.11476318996277414,0.189521976197559061,0.0456683303746188429],"hpluv":[120.846986072134357,159.219643782083125,50.6312327062127565],"hsluv":[120.846986072134357,90.0662104861249,50.6312327062127565]},"#448833":{"lch":[50.775662969350762,58.6076690216783831,123.408487274566809],"luv":[50.775662969350762,-32.2696404838739213,48.9237076599487182],"rgb":[0.266666666666666663,0.533333333333333326,0.2],"xyz":[0.117850940695231873,0.19075707649054216,0.0619304842322299931],"hpluv":[123.408487274566809,146.466455796741883,50.775662969350762],"hsluv":[123.408487274566809,79.8990388198805732,50.775662969350762]},"#448844":{"lch":[50.9830910358637652,52.0733509329185,127.715012949239537],"luv":[50.9830910358637652,-31.855056956676961,41.1933152789351382],"rgb":[0.266666666666666663,0.533333333333333326,0.266666666666666663],"xyz":[0.122308935939450747,0.192540274588229754,0.0854092591851166316],"hpluv":[127.715012949239537,129.607069016793787,50.9830910358637652],"hsluv":[127.715012949239537,65.9930987522981241,50.9830910358637652]},"#448855":{"lch":[51.2585265038955384,44.4350179761376651,134.860489600104756],"luv":[51.2585265038955384,-31.3437036744621551,31.4967151066136601],"rgb":[0.266666666666666663,0.533333333333333326,0.333333333333333315],"xyz":[0.128271349978812732,0.194925240203974587,0.116811306459090533],"hpluv":[134.860489600104756,110.001490313735033,51.2585265038955384],"hsluv":[134.860489600104756,67.3517725464548676,51.2585265038955384]},"#448866":{"lch":[51.6056896491522537,36.7437212642011914,146.829747927558799],"luv":[51.6056896491522537,-30.7562765884277063,20.1035445321824895],"rgb":[0.266666666666666663,0.533333333333333326,0.4],"xyz":[0.135856345752320917,0.197959238513377878,0.156758950866234509],"hpluv":[146.829747927558799,90.3493178961374781,51.6056896491522537],"hsluv":[146.829747927558799,68.9308752248562797,51.6056896491522537]},"#448877":{"lch":[52.0271709342862039,31.0045548915217921,166.266503182991642],"luv":[52.0271709342862039,-30.1181499011556575,7.36067052332227245],"rgb":[0.266666666666666663,0.533333333333333326,0.466666666666666674],"xyz":[0.145170358772522823,0.201684843721458701,0.205812752772632418],"hpluv":[166.266503182991642,75.6196418937204555,52.0271709342862039],"hsluv":[166.266503182991642,70.6726995402934506,52.0271709342862039]},"#448888":{"lch":[52.5245390493459041,30.1341009641634088,192.177050630061],"luv":[52.5245390493459041,-29.456097564679137,-6.35628485662009179],"rgb":[0.266666666666666663,0.533333333333333326,0.533333333333333326],"xyz":[0.156310775874466679,0.206141010562236299,0.264485616176204585],"hpluv":[192.177050630061,72.8006598676027181,52.5245390493459041],"hsluv":[192.177050630061,72.5156967272479847,52.5245390493459041]},"#448899":{"lch":[53.0984315279962118,35.4547108695225,215.690916113393854],"luv":[53.0984315279962118,-28.7954664423823949,-20.6847198484066084],"rgb":[0.266666666666666663,0.533333333333333326,0.6],"xyz":[0.169367739983539378,0.211363796205865456,0.333252293817322465],"hpluv":[215.690916113393854,84.7289026839812,53.0984315279962118],"hsluv":[215.690916113393854,74.4011420122721319,53.0984315279962118]},"#4488aa":{"lch":[53.7486427971268625,45.1587425535104146,231.425064236121358],"luv":[53.7486427971268625,-28.1581765792043193,-35.3048030832715654],"rgb":[0.266666666666666663,0.533333333333333326,0.66666666666666663],"xyz":[0.184425432948791934,0.217386873391966551,0.412556143434321065],"hpluv":[231.425064236121358,106.613859301848393,53.7486427971268625],"hsluv":[231.425064236121358,76.2778611087785,53.7486427971268625]},"#4488bb":{"lch":[54.4742155909258514,57.0545505189943469,241.113543257937238],"luv":[54.4742155909258514,-27.5616516575745152,-49.9557513488787208],"rgb":[0.266666666666666663,0.533333333333333326,0.733333333333333282],"xyz":[0.201563025056128553,0.224241910234901309,0.502814128532962812],"hpluv":[241.113543257937238,132.904176722924205,54.4742155909258514],"hsluv":[241.113543257937238,78.1047803623200707,54.4742155909258514]},"#4488cc":{"lch":[55.273536978614473,69.875332030770025,247.25266296501286],"luv":[55.273536978614473,-27.0185618464256976,-64.4403549195783398],"rgb":[0.266666666666666663,0.533333333333333326,0.8],"xyz":[0.220855400499850307,0.231958860412390111,0.604420639203233],"hpluv":[247.25266296501286,160.415361718249983,55.273536978614473],"hsluv":[247.25266296501286,79.8515774594708603,55.273536978614473]},"#4488dd":{"lch":[56.1444377207636194,82.97891177410213,251.348812353132246],"luv":[56.1444377207636194,-26.53714651812043,-78.6211145551246631],"rgb":[0.266666666666666663,0.533333333333333326,0.866666666666666696],"xyz":[0.242373726050483851,0.240566190632643645,0.717750487103239],"hpluv":[251.348812353132246,187.542769341675751,56.1444377207636194],"hsluv":[251.348812353132246,81.4979766670821,56.1444377207636194]},"#4488ee":{"lch":[57.0842924141545609,96.0325607902411775,254.216059778839536],"luv":[57.0842924141545609,-26.1218678035424112,-92.4115834426919776],"rgb":[0.266666666666666663,0.533333333333333326,0.933333333333333348],"xyz":[0.266185906316658616,0.25009106273911369,0.843161303171762189],"hpluv":[254.216059778839536,213.472145126724115,57.0842924141545609],"hsluv":[254.216059778839536,85.8050168900109469,57.0842924141545609]},"#4488ff":{"lch":[58.090117466996233,108.861046277687535,256.304473865935392],"luv":[58.090117466996233,-25.7741898685227575,-105.765866579412872],"rgb":[0.266666666666666663,0.533333333333333326,1],"xyz":[0.29235695472649,0.260559482103046358,0.980995491463544],"hpluv":[256.304473865935392,237.798754650411269,58.090117466996233],"hsluv":[256.304473865935392,99.9999999999988631,58.090117466996233]},"#449900":{"lch":[56.0984423000037538,78.159424491283,120.852962610827774],"luv":[56.0984423000037538,-40.0830169860907191,67.0987882610508279],"rgb":[0.266666666666666663,0.6,0],"xyz":[0.137745766777127493,0.240106367647249075,0.0390865393647062687],"hpluv":[120.852962610827774,176.794958777624345,56.0984423000037538],"hsluv":[120.852962610827774,100.000000000002416,56.0984423000037538]},"#449911":{"lch":[56.1389235634784143,76.6482268999804859,121.431666795625887],"luv":[56.1389235634784143,-39.9706170908808929,65.4010738159938256],"rgb":[0.266666666666666663,0.6,0.0666666666666666657],"xyz":[0.138757432276764625,0.240511033847103928,0.0444146443294619],"hpluv":[121.431666795625887,173.251641588156104,56.1389235634784143],"hsluv":[121.431666795625887,97.2234127009916,56.1389235634784143]},"#449922":{"lch":[56.21384509356389,73.9109075723002746,122.549403254372123],"luv":[56.21384509356389,-39.7660359546788555,62.3015621201611793],"rgb":[0.266666666666666663,0.6,0.133333333333333331],"xyz":[0.140632790415241626,0.241261177102494756,0.0542915305254411],"hpluv":[122.549403254372123,166.841685682494415,56.21384509356389],"hsluv":[122.549403254372123,92.1627352690631,56.21384509356389]},"#449933":{"lch":[56.3368647095541064,69.5846668696270143,124.526315047954697],"luv":[56.3368647095541064,-39.4395235157555177,57.3284383897480296],"rgb":[0.266666666666666663,0.6,0.2],"xyz":[0.143720541147699388,0.242496277395477855,0.0705536843830522342],"hpluv":[124.526315047954697,156.73291295139785,56.3368647095541064],"hsluv":[124.526315047954697,84.0665441712718859,56.3368647095541064]},"#449944":{"lch":[56.5137417426914368,63.7361451042890153,127.715012949239735],"luv":[56.5137417426914368,-38.9895886498958575,50.4193233757345922],"rgb":[0.266666666666666663,0.6,0.266666666666666663],"xyz":[0.148178536391918247,0.244279475493165449,0.0940324593359388727],"hpluv":[127.715012949239735,143.110354253444,56.5137417426914368],"hsluv":[127.715012949239735,72.8686777069245,56.5137417426914368]},"#449955":{"lch":[56.7489681974646629,56.6620380577650309,132.698160989074609],"luv":[56.7489681974646629,-38.4245724364924328,41.642992086692793],"rgb":[0.266666666666666663,0.6,0.333333333333333315],"xyz":[0.154140950431280233,0.246664441108910282,0.125434506609912788],"hpluv":[132.698160989074609,126.69910537289924,56.7489681974646629],"hsluv":[132.698160989074609,73.7405349232989664,56.7489681974646629]},"#449966":{"lch":[57.0460268500437166,48.9673458777373511,140.456743036678859],"luv":[57.0460268500437166,-37.7608817984154683,31.1755796757022061],"rgb":[0.266666666666666663,0.6,0.4],"xyz":[0.161725946204788418,0.249698439418313572,0.16538215101705675],"hpluv":[140.456743036678859,108.923224533285605,57.0460268500437166],"hsluv":[140.456743036678859,74.7718537787272766,57.0460268500437166]},"#449977":{"lch":[57.4075272841014481,41.7361359201695734,152.500832231763781],"luv":[57.4075272841014481,-37.0206846158697,19.2710651526888199],"rgb":[0.266666666666666663,0.6,0.466666666666666674],"xyz":[0.171039959224990323,0.253424044626394396,0.214435952923454659],"hpluv":[152.500832231763781,92.2534727828265915,57.4075272841014481],"hsluv":[152.500832231763781,75.9325502249844817,57.4075272841014481]},"#449988":{"lch":[57.8352917232380861,36.7607331244742284,170.245603374965924],"luv":[57.8352917232380861,-36.2292854489646174,6.22819200942437323],"rgb":[0.266666666666666663,0.6,0.533333333333333326],"xyz":[0.182180376326934179,0.257880211467172,0.273108816327026827],"hpluv":[170.245603374965924,80.6548633994409414,57.8352917232380861],"hsluv":[170.245603374965924,77.1878957355486222,57.8352917232380861]},"#449999":{"lch":[58.3304201548299517,36.2276744984656105,192.17705063006116],"luv":[58.3304201548299517,-35.4125684996312486,-7.64162232943372643],"rgb":[0.266666666666666663,0.6,0.6],"xyz":[0.195237340436006879,0.263102997110801151,0.341875493968144761],"hpluv":[192.17705063006116,78.8106081595615251,58.3304201548299517],"hsluv":[192.17705063006116,78.5021203184449803,58.3304201548299517]},"#4499aa":{"lch":[58.8933484328044585,41.0197173156303379,212.502133513081617],"luv":[58.8933484328044585,-34.5948579745346478,-22.041166266239177],"rgb":[0.266666666666666663,0.6,0.66666666666666663],"xyz":[0.210295033401259435,0.269126074296902273,0.421179343585143307],"hpluv":[212.502133513081617,88.3823902117899536,58.8933484328044585],"hsluv":[212.502133513081617,79.8414276244135692,58.8933484328044585]},"#4499bb":{"lch":[59.523905851944221,49.8962585520308082,227.36281958486083],"luv":[59.523905851944221,-33.7974051546762055,-36.7065664738854878],"rgb":[0.266666666666666663,0.6,0.733333333333333282],"xyz":[0.227432625508596054,0.275981111139837032,0.511437328683785108],"hpluv":[227.36281958486083,106.36919851968392,59.523905851944221],"hsluv":[227.36281958486083,81.1761313086710885,59.523905851944221]},"#4499cc":{"lch":[60.2213749252976385,61.1171242450200438,237.278146949597897],"luv":[60.2213749252976385,-33.0375484580145766,-51.4181219791773],"rgb":[0.266666666666666663,0.6,0.8],"xyz":[0.246725000952317808,0.283698061317325834,0.613043839354055264],"hpluv":[237.278146949597897,128.780934100622716,60.2213749252976385],"hsluv":[237.278146949597897,82.4818489079811741,60.2213749252976385]},"#4499dd":{"lch":[60.9845539619455508,73.4958381074912,243.904542785491344],"luv":[60.9845539619455508,-32.3284648877968195,-66.0038527445257728],"rgb":[0.266666666666666663,0.6,0.866666666666666696],"xyz":[0.268243326502951351,0.29230539153757934,0.726373687254061262],"hpluv":[243.904542785491344,152.926314240713424,60.9845539619455508],"hsluv":[243.904542785491344,83.7398679369964469,60.9845539619455508]},"#4499ee":{"lch":[61.8118218103912653,86.3580647779335351,248.479300934605874],"luv":[61.8118218103912653,-31.6793620640961606,-80.3376211460214193],"rgb":[0.266666666666666663,0.6,0.933333333333333348],"xyz":[0.292055506769126061,0.301830263644049357,0.851784503322584485],"hpluv":[248.479300934605874,177.284466220706,61.8118218103912653],"hsluv":[248.479300934605874,84.9368954206658344,61.8118218103912653]},"#4499ff":{"lch":[62.7012034705467585,99.3269113509348,251.755860244601337],"luv":[62.7012034705467585,-31.0959452870692914,-94.3338619225358173],"rgb":[0.266666666666666663,0.6,1],"xyz":[0.318226555178957482,0.312298683007982081,0.98961869161436633],"hpluv":[251.755860244601337,201.015886170810859,62.7012034705467585],"hsluv":[251.755860244601337,99.9999999999986073,62.7012034705467585]},"#330000":{"lch":[6.35863201887414942,21.3842798011123882,12.1770506300617836],"luv":[6.35863201887414942,20.9031433498234946,4.51065635013277699],"rgb":[0.2,0,0],"xyz":[0.0136521011456799905,0.00703936465324139522,0.000639942241203736136],"hpluv":[12.1770506300617836,426.746789183125031,6.35863201887414942],"hsluv":[12.1770506300617836,100.000000000002217,6.35863201887414942]},"#330011":{"lch":[6.72416549840036915,18.2596394021459751,358.956333183931122],"luv":[6.72416549840036915,18.2566101970553,-0.332588648601129133],"rgb":[0.2,0,0.0666666666666666657],"xyz":[0.0146637666453171122,0.00744403085309625,0.00596804720595936738],"hpluv":[358.956333183931122,344.582429927088697,6.72416549840036915],"hsluv":[358.956333183931122,99.9999999999970868,6.72416549840036915]},"#330022":{"lch":[7.4017671226143058,16.6083885778583671,334.642609555635659],"luv":[7.4017671226143058,15.0082373074967617,-7.11276205668364714],"rgb":[0.2,0,0.133333333333333331],"xyz":[0.0165391247837941326,0.00819417410848706854,0.0158449334019385643],"hpluv":[334.642609555635659,284.728805881674077,7.4017671226143058],"hsluv":[334.642609555635659,99.999999999998,7.4017671226143058]},"#330033":{"lch":[8.50665746950019,19.3767863388894384,307.715012949243601],"luv":[8.50665746950019,11.8534455994177517,-15.3282639670843448],"rgb":[0.2,0,0.2],"xyz":[0.0196268755162518696,0.00942927440147018139,0.0321070872595497075],"hpluv":[307.715012949243601,289.042783730483279,8.50665746950019],"hsluv":[307.715012949243601,99.9999999999987921,8.50665746950019]},"#330044":{"lch":[9.96321399083228343,25.9151774110163871,290.632214162589],"luv":[9.96321399083228343,9.13167627644372,-24.2530185467023678],"rgb":[0.2,0,0.266666666666666663],"xyz":[0.0240848707604707502,0.0112124724991577579,0.0555858622124363461],"hpluv":[290.632214162589,330.060881015257678,9.96321399083228343],"hsluv":[290.632214162589,99.9999999999994,9.96321399083228343]},"#330055":{"lch":[11.6870713271151807,34.2775786608295405,281.502617436257196],"luv":[11.6870713271151807,6.83538450996046,-33.589133919325],"rgb":[0.2,0,0.333333333333333315],"xyz":[0.0300472847998327422,0.0135974381149025891,0.0869879094864102614],"hpluv":[281.502617436257196,372.172061509357604,11.6870713271151807],"hsluv":[281.502617436257196,99.9999999999999289,11.6870713271151807]},"#330066":{"lch":[13.6097387714237676,43.4818398400869768,276.434806151814087],"luv":[13.6097387714237676,4.87312317733106592,-43.2079051375733059],"rgb":[0.2,0,0.4],"xyz":[0.0376322805733409205,0.0166314364243059024,0.126935553893554209],"hpluv":[276.434806151814087,405.412793254212261,13.6097387714237676],"hsluv":[276.434806151814087,100.00000000000027,13.6097387714237676]},"#330077":{"lch":[15.6735112457106673,53.108485659557914,273.408523183706109],"luv":[15.6735112457106673,3.15755804167271537,-53.0145364618510655],"rgb":[0.2,0,0.466666666666666674],"xyz":[0.046946293593542833,0.0203570416323867187,0.175989355799952119],"hpluv":[273.408523183706109,429.968801903614121,15.6735112457106673],"hsluv":[273.408523183706109,100.000000000000313,15.6735112457106673]},"#330088":{"lch":[17.8339183845063687,62.9511834901283365,271.47985970994057],"luv":[17.8339183845063687,1.62574911173865799,-62.9301870538574448],"rgb":[0.2,0,0.533333333333333326],"xyz":[0.058086710695486661,0.0248132084731643096,0.234662219203524286],"hpluv":[271.47985970994057,447.91587095992594,17.8339183845063687],"hsluv":[271.47985970994057,100.000000000000441,17.8339183845063687]},"#330099":{"lch":[20.0583065104412341,72.8932825114363,270.184356583024851],"luv":[20.0583065104412341,0.234543162084408924,-72.8929051746271313],"rgb":[0.2,0,0.6],"xyz":[0.0711436748045593814,0.0300359941167934706,0.303428896844642193],"hpluv":[270.184356583024851,461.139761646516433,20.0583065104412341],"hsluv":[270.184356583024851,100.000000000000625,20.0583065104412341]},"#3300aa":{"lch":[22.3232943619689834,82.8637729479105474,269.276671227287579],"luv":[22.3232943619689834,-1.04608331699459467,-82.8571697371855578],"rgb":[0.2,0,0.66666666666666663],"xyz":[0.0862013677698119235,0.0360590713028945756,0.382732746461640794],"hpluv":[269.276671227287579,471.026936966419044,22.3232943619689834],"hsluv":[269.276671227287579,100.000000000000554,22.3232943619689834]},"#3300bb":{"lch":[24.6123405885396807,92.8181896970849,268.61855571411644],"luv":[24.6123405885396807,-2.23769945956788,-92.7912120826788538],"rgb":[0.2,0,0.733333333333333282],"xyz":[0.10333895987714857,0.0429141081458293341,0.47299073156028254],"hpluv":[268.61855571411644,478.541387025058441,24.6123405885396807],"hsluv":[268.61855571411644,100.000000000000625,24.6123405885396807]},"#3300cc":{"lch":[26.9138017967000778,102.728605647013808,268.127719933063759],"luv":[26.9138017967000778,-3.35631165306985224,-102.673762910819349],"rgb":[0.2,0,0.8],"xyz":[0.122631335320870311,0.0506310583233181358,0.574597242230552752],"hpluv":[268.127719933063759,484.345947247320225,26.9138017967000778],"hsluv":[268.127719933063759,100.000000000000881,26.9138017967000778]},"#3300dd":{"lch":[29.2194977691074271,112.577730384171886,267.752877980499],"luv":[29.2194977691074271,-4.41413050162269105,-112.49115889867052],"rgb":[0.2,0,0.866666666666666696],"xyz":[0.144149660871503854,0.0592383885435716698,0.687927090130558749],"hpluv":[267.752877980499,488.89890937186334,29.2194977691074271],"hsluv":[267.752877980499,100.000000000000753,29.2194977691074271]},"#3300ee":{"lch":[31.5236887929336334,122.355215968494591,267.460804758990776],"luv":[31.5236887929336334,-5.42068013199621,-122.235081304851008],"rgb":[0.2,0,0.933333333333333348],"xyz":[0.167961841137678591,0.0687632606500417,0.813337906199082],"hpluv":[267.460804758990776,492.52103452607281,31.5236887929336334],"hsluv":[267.460804758990776,100.000000000000824,31.5236887929336334]},"#3300ff":{"lch":[33.8223579343154,132.055276159319874,267.229255072945307],"luv":[33.8223579343154,-6.38352242786170443,-131.900896899631505],"rgb":[0.2,0,1],"xyz":[0.194132889547509985,0.0792316800139744,0.951172094490863818],"hpluv":[267.229255072945307,495.440155164142311,33.8223579343154],"hsluv":[267.229255072945307,100.000000000000881,33.8223579343154]},"#331100":{"lch":[9.83576796362177319,19.9321083570360571,25.9770166386959609],"luv":[9.83576796362177319,17.918363864654,8.73047421223431108],"rgb":[0.2,0.0666666666666666657,0],"xyz":[0.0156565014066084,0.0110481651750982679,0.00130807566151318702],"hpluv":[25.9770166386959609,257.148675223584291,9.83576796362177319],"hsluv":[25.9770166386959609,100.000000000002302,9.83576796362177319]},"#331111":{"lch":[10.1474261289244687,16.4836545456174051,12.1770506300618813],"luv":[10.1474261289244687,16.1127799065782149,3.4769513746129066],"rgb":[0.2,0.0666666666666666657,0.0666666666666666657],"xyz":[0.0166681669062455212,0.0114528313749531225,0.00663618062626881826],"hpluv":[12.1770506300618813,206.127972902374523,10.1474261289244687],"hsluv":[12.1770506300618813,48.3021731216650707,10.1474261289244687]},"#331122":{"lch":[10.7062693823806221,14.2435433110065777,342.375847990242676],"luv":[10.7062693823806221,13.5749958919169824,-4.31254131423193],"rgb":[0.2,0.0666666666666666657,0.133333333333333331],"xyz":[0.0185435250447225398,0.0122029746303439404,0.0165130668222480161],"hpluv":[342.375847990242676,168.818174775843545,10.7062693823806221],"hsluv":[342.375847990242676,57.1044970617697913,10.7062693823806221]},"#331133":{"lch":[11.5784810016780177,17.5377888786733784,307.715012949244169],"luv":[11.5784810016780177,10.7284677021084427,-13.8735006223280077],"rgb":[0.2,0.0666666666666666657,0.2],"xyz":[0.0216312757771802804,0.0134380749233270532,0.0327752206798591628],"hpluv":[307.715012949244169,192.204068690519591,11.5784810016780177],"hsluv":[307.715012949244169,66.4967539441281,11.5784810016780177]},"#331144":{"lch":[12.7480449023252049,25.2894553184220108,288.641508688419037],"luv":[12.7480449023252049,8.08366941467993172,-23.9626968243691536],"rgb":[0.2,0.0666666666666666657,0.266666666666666663],"xyz":[0.0260892710213991574,0.0152212730210146297,0.0562539956327458],"hpluv":[288.641508688419037,251.73014018207067,12.7480449023252049],"hsluv":[288.641508688419037,74.5439781366083309,12.7480449023252049]},"#331155":{"lch":[14.1772863520069095,34.570642435857458,279.659572498507771],"luv":[14.1772863520069095,5.80074057604611415,-34.0805036230000695],"rgb":[0.2,0.0666666666666666657,0.333333333333333315],"xyz":[0.0320516850607611564,0.0176062386367594609,0.0876560429067197],"hpluv":[279.659572498507771,309.423764447612427,14.1772863520069095],"hsluv":[279.659572498507771,80.733364837348816,14.1772863520069095]},"#331166":{"lch":[15.8197098676790517,44.2946391552180785,274.993838621827194],"luv":[15.8197098676790517,3.85578699555013271,-44.1264995726595686],"rgb":[0.2,0.0666666666666666657,0.4],"xyz":[0.0396366808342693278,0.0206402369461627724,0.127603687313863678],"hpluv":[274.993838621827194,355.297359803625511,15.8197098676790517],"hsluv":[274.993838621827194,85.2848648605675095,15.8197098676790517]},"#331177":{"lch":[17.6293493428787755,54.1580116435351115,272.303494486185969],"luv":[17.6293493428787755,2.17675853502087469,-54.1142490242773135],"rgb":[0.2,0.0666666666666666657,0.466666666666666674],"xyz":[0.0489506938544712472,0.0243658421542435888,0.176657489220261588],"hpluv":[272.303494486185969,389.821469213037517,17.6293493428787755],"hsluv":[272.303494486185969,88.5936990192462588,17.6293493428787755]},"#331188":{"lch":[19.5658128626021437,64.0679547566568,270.623065923527406],"luv":[19.5658128626021437,0.696696562564985133,-64.064166587888522],"rgb":[0.2,0.0666666666666666657,0.533333333333333326],"xyz":[0.0600911109564150753,0.0288220089950211832,0.235330352623833755],"hpluv":[270.623065923527406,415.51077593183,19.5658128626021437],"hsluv":[270.623065923527406,91.0112456871911348,19.5658128626021437]},"#331199":{"lch":[21.5959931816331263,73.9854871429769645,269.508319412823],"luv":[21.5959931816331263,-0.634894604710849,-73.9827629696574576],"rgb":[0.2,0.0666666666666666657,0.6],"xyz":[0.0731480750654877887,0.0340447946386503442,0.304097030264951662],"hpluv":[269.508319412823,434.723064450461493,21.5959931816331263],"hsluv":[269.508319412823,92.7998436287799,21.5959931816331263]},"#3311aa":{"lch":[23.6938673935249824,83.8866252842298792,268.733700318675346],"luv":[23.6938673935249824,-1.85383566080119344,-83.8661385478044821],"rgb":[0.2,0.0666666666666666657,0.66666666666666663],"xyz":[0.0882057680307403308,0.0400678718247514457,0.383400879881950263],"hpluv":[268.733700318675346,449.258286440651602,23.6938673935249824],"hsluv":[268.733700318675346,94.1436997610677,23.6938673935249824]},"#3311bb":{"lch":[25.8394818705352094,93.7535423490500079,268.175268957576],"luv":[25.8394818705352094,-2.98531729009247,-93.7060007879569525],"rgb":[0.2,0.0666666666666666657,0.733333333333333282],"xyz":[0.105343360138076977,0.0469229086676862042,0.473658864980592],"hpluv":[268.175268957576,460.408371224539451,25.8394818705352094],"hsluv":[268.175268957576,95.1697562295976525,25.8394818705352094]},"#3311cc":{"lch":[28.017750605254669,103.572636018550753,267.760492630427507],"luv":[28.017750605254669,-4.04728980779695124,-103.493528189171812],"rgb":[0.2,0.0666666666666666657,0.8],"xyz":[0.124635735581798718,0.0546398588451750059,0.57526537565086211],"hpluv":[267.760492630427507,469.084508820223505,28.017750605254669],"hsluv":[267.760492630427507,95.9655004656031423,28.017750605254669]},"#3311dd":{"lch":[30.2173526676312889,113.33386550323506,267.444704079349265],"luv":[30.2173526676312889,-5.05282540459801588,-113.221173043455181],"rgb":[0.2,0.0666666666666666657,0.866666666666666696],"xyz":[0.146154061132432261,0.0632471890654285329,0.688595223550868107],"hpluv":[267.444704079349265,475.929488946899937,30.2173526676312889],"hsluv":[267.444704079349265,96.591763702558211,30.2173526676312889]},"#3311ee":{"lch":[32.429822932533412,123.030197380053124,267.199217974228532],"luv":[32.429822932533412,-6.01167404447580456,-122.883234180085807],"rgb":[0.2,0.0666666666666666657,0.933333333333333348],"xyz":[0.169966241398607,0.0727720611718985777,0.814006039619391331],"hpluv":[267.199217974228532,481.400425551936735,32.429822932533412],"hsluv":[267.199217974228532,97.0913881744298095,32.429822932533412]},"#3311ff":{"lch":[34.6488414224811834,132.657034918193688,267.004954598207064],"luv":[34.6488414224811834,-6.93127707868383425,-132.475832933200962],"rgb":[0.2,0.0666666666666666657,1],"xyz":[0.196137289808438392,0.0832404805358312738,0.951840227911173176],"hpluv":[267.004954598207064,485.826158631145177,34.6488414224811834],"hsluv":[267.004954598207064,99.999999999999531,34.6488414224811834]},"#88aa00":{"lch":[64.9493872277699467,75.8454165204624502,102.522158340464031],"luv":[64.9493872277699467,-16.4445883060260414,74.0412231301438624],"rgb":[0.533333333333333326,0.66666666666666663,0],"xyz":[0.245272120749672057,0.339833923051985953,0.0526729261635559762],"hpluv":[102.522158340464031,148.181371186867864,64.9493872277699467],"hsluv":[102.522158340464031,100.000000000002217,64.9493872277699467]},"#88aa11":{"lch":[64.9815053546997206,74.514883993558044,102.764001416735823],"luv":[64.9815053546997206,-16.4630035423646639,72.6734989589568414],"rgb":[0.533333333333333326,0.66666666666666663,0.0666666666666666657],"xyz":[0.246283786249309189,0.340238589251840806,0.0580010311283116059],"hpluv":[102.764001416735823,145.509915409181133,64.9815053546997206],"hsluv":[102.764001416735823,98.0498740713468635,64.9815053546997206]},"#88aa22":{"lch":[65.040976504183746,72.0784265262596762,103.230826782560158],"luv":[65.040976504183746,-16.4969246852166869,70.1651697527462801],"rgb":[0.533333333333333326,0.66666666666666663,0.133333333333333331],"xyz":[0.24815914438778619,0.340988732507231607,0.0678779173242908],"hpluv":[103.230826782560158,140.623392494363173,65.040976504183746],"hsluv":[103.230826782560158,94.4776072436414296,65.040976504183746]},"#88aa33":{"lch":[65.138705174337673,68.1506383708936596,104.056367163177015],"luv":[65.138705174337673,-16.5521781693680836,66.1100212389152],"rgb":[0.533333333333333326,0.66666666666666663,0.2],"xyz":[0.251246895120243952,0.342223832800214733,0.0841400711819019487],"hpluv":[104.056367163177015,132.760883332008575,65.138705174337673],"hsluv":[104.056367163177015,88.7139905695652544,65.138705174337673]},"#88aa44":{"lch":[65.2793887406011,62.6606585185119442,105.391240881396499],"luv":[65.2793887406011,-16.6306856640551395,60.4133960336360687],"rgb":[0.533333333333333326,0.66666666666666663,0.266666666666666663],"xyz":[0.255704890364462811,0.344007030897902299,0.107618846134788587],"hpluv":[105.391240881396499,121.803060858356815,65.2793887406011],"hsluv":[105.391240881396499,80.6421361820775,65.2793887406011]},"#88aa55":{"lch":[65.4667902277309821,55.6467221212728731,107.50018297907917],"luv":[65.4667902277309821,-16.7334615527701551,53.0711687011330397],"rgb":[0.533333333333333326,0.66666666666666663,0.333333333333333315],"xyz":[0.261667304403824796,0.34639199651364716,0.139020893408762503],"hpluv":[107.50018297907917,107.859366541167589,65.4667902277309821],"hsluv":[107.50018297907917,70.2829236383929157,65.4667902277309821]},"#88aa66":{"lch":[65.7039511656785606,47.2674293485405386,110.898270106627507],"luv":[65.7039511656785606,-16.8607549547505542,44.1579530727492582],"rgb":[0.533333333333333326,0.66666666666666663,0.4],"xyz":[0.269252300177333,0.349425994823050479,0.178968537815906464],"hpluv":[110.898270106627507,91.2871867148882075,65.7039511656785606],"hsluv":[110.898270106627507,57.7776943224234358,65.7039511656785606]},"#88aa77":{"lch":[65.993303036365262,37.8517489546572605,116.707912668539493],"luv":[65.993303036365262,-17.0121797895697142,33.8133204186420073],"rgb":[0.533333333333333326,0.66666666666666663,0.466666666666666674],"xyz":[0.278566313197534887,0.353151600031131274,0.228022339722304374],"hpluv":[116.707912668539493,72.782239014817236,65.993303036365262],"hsluv":[116.707912668539493,43.3670204896631262,65.993303036365262]},"#88aa88":{"lch":[66.3367341259492,28.0952907790087707,127.715012949235486],"luv":[66.3367341259492,-17.1868541575625393,22.2251526006848934],"rgb":[0.533333333333333326,0.66666666666666663,0.533333333333333326],"xyz":[0.289706730299478743,0.357607766871908872,0.286695203125876541],"hpluv":[127.715012949235486,53.7426121206727316,66.3367341259492],"hsluv":[127.715012949235486,27.3645684281827677,66.3367341259492]},"#88aa99":{"lch":[66.7356352778598705,19.8636867466165334,151.061783220075199],"luv":[66.7356352778598705,-17.3835461247401071,9.6113669837720046],"rgb":[0.533333333333333326,0.66666666666666663,0.6],"xyz":[0.302763694408551443,0.36283055251553803,0.35546188076699442],"hpluv":[151.061783220075199,37.7695130125235536,66.7356352778598705],"hsluv":[151.061783220075199,30.5390729913306274,66.7356352778598705]},"#88aaaa":{"lch":[67.1909358184889811,18.0059400546344968,192.177050630060364],"luv":[67.1909358184889811,-17.6008146924254447,-3.79805205519771905],"rgb":[0.533333333333333326,0.66666666666666663,0.66666666666666663],"xyz":[0.317821387373804,0.368853629701639152,0.434765730383993],"hpluv":[192.177050630060364,34.0051297749840913,67.1909358184889811],"hsluv":[192.177050630060364,33.872023720911649,67.1909358184889811]},"#88aabb":{"lch":[67.7031355134684674,25.1829477340388976,224.903065382651],"luv":[67.7031355134684674,-17.8371340556046292,-17.7768812016541453],"rgb":[0.533333333333333326,0.66666666666666663,0.733333333333333282],"xyz":[0.334958979481140617,0.37570866654457391,0.525023715482634823],"hpluv":[224.903065382651,47.1994684953027459,67.7031355134684674],"hsluv":[224.903065382651,37.296330310174362,67.7031355134684674]},"#88aacc":{"lch":[68.2723356589922901,36.8600300209604939,240.606662797769701],"luv":[68.2723356589922901,-18.0909926283411373,-32.1150712106857341],"rgb":[0.533333333333333326,0.66666666666666663,0.8],"xyz":[0.354251354924862372,0.383425616722062712,0.626630226152905],"hpluv":[240.606662797769701,68.5094136262693,68.2723356589922901],"hsluv":[240.606662797769701,40.7502319604911136,68.2723356589922901]},"#88aadd":{"lch":[68.8982708583434,50.1120766914241216,248.506358436024811],"luv":[68.8982708583434,-18.3609632112572676,-46.6271944285953168],"rgb":[0.533333333333333326,0.66666666666666663,0.866666666666666696],"xyz":[0.375769680475495915,0.392032946942316218,0.739960074052911],"hpluv":[248.506358436024811,92.2939864083951278,68.8982708583434],"hsluv":[248.506358436024811,59.5109742880650217,68.8982708583434]},"#88aaee":{"lch":[69.5803420919898,63.9362726255054454,253.044423586561948],"luv":[69.5803420919898,-18.6457452648911577,-61.1570367231747554],"rgb":[0.533333333333333326,0.66666666666666663,0.933333333333333348],"xyz":[0.39958186074167068,0.401557819048786235,0.8653708901214342],"hpluv":[253.044423586561948,116.600410917186778,69.5803420919898],"hsluv":[253.044423586561948,79.2673662112875093,69.5803420919898]},"#88aaff":{"lch":[70.3176511000829549,77.916964899147743,255.928474825822],"luv":[70.3176511000829549,-18.9441834980668631,-75.578907974954177],"rgb":[0.533333333333333326,0.66666666666666663,1],"xyz":[0.425752909151502046,0.412026238412718959,1.00320507841321604],"hpluv":[255.928474825822,140.607018245256825,70.3176511000829549],"hsluv":[255.928474825822,99.9999999999979394,70.3176511000829549]},"#332200":{"lch":[14.6681357538016819,18.4720509904151484,54.0318728094203635],"luv":[14.6681357538016819,10.8492842291989344,14.9502407842332925],"rgb":[0.2,0.133333333333333331,0],"xyz":[0.0193721251413763347,0.0184794126446342424,0.00254661690643579732],"hpluv":[54.0318728094203635,159.801011716648361,14.6681357538016819],"hsluv":[54.0318728094203635,100.000000000002359,14.6681357538016819]},"#332211":{"lch":[14.8903804788128475,14.003495227987683,44.8263438888978243],"luv":[14.8903804788128475,9.93193249146711,9.87190941941900668],"rgb":[0.2,0.133333333333333331,0.0666666666666666657],"xyz":[0.0203837906410134564,0.0188840788444890953,0.00787472187119143],"hpluv":[44.8263438888978243,119.33558852926538,14.8903804788128475],"hsluv":[44.8263438888978243,67.0844803779226595,14.8903804788128475]},"#332222":{"lch":[15.2941064614028619,8.70381909014442101,12.1770506300622809],"luv":[15.2941064614028619,8.50798716741232397,1.83592513820952408],"rgb":[0.2,0.133333333333333331,0.133333333333333331],"xyz":[0.0222591487794904751,0.0196342220998799166,0.0177516080671706253],"hpluv":[12.1770506300622809,72.2146104972558476,15.2941064614028619],"hsluv":[12.1770506300622809,16.9221215783466867,15.2941064614028619]},"#332233":{"lch":[15.9369990430381634,10.9638268591401484,307.7150129492465],"luv":[15.9369990430381634,6.70694938589646661,-8.67308072902737],"rgb":[0.2,0.133333333333333331,0.2],"xyz":[0.0253468995119482156,0.0208693223928630295,0.0340137619247817685],"hpluv":[307.7150129492465,87.2961214462547,15.9369990430381634],"hsluv":[307.7150129492465,30.2017993044426838,15.9369990430381634]},"#332244":{"lch":[16.8218835175385664,20.7382675483863608,283.478697838556343],"luv":[16.8218835175385664,4.83375477674434428,-20.1670661145035197],"rgb":[0.2,0.133333333333333331,0.266666666666666663],"xyz":[0.0298048947561670927,0.0226525204905506025,0.057492536877668407],"hpluv":[283.478697838556343,156.436171283708973,16.8218835175385664],"hsluv":[283.478697838556343,43.2894908809756558,16.8218835175385664]},"#332255":{"lch":[17.9355503164319856,31.8518286021958055,275.537546938931484],"luv":[17.9355503164319856,3.0736387963894658,-31.7031816992078603],"rgb":[0.2,0.133333333333333331,0.333333333333333315],"xyz":[0.0357673087955290847,0.0250374861062954354,0.0888945841516423224],"hpluv":[275.537546938931484,225.350740722061715,17.9355503164319856],"hsluv":[275.537546938931484,54.6600619512456092,17.9355503164319856]},"#332266":{"lch":[19.2543827660255502,42.9346801988288,271.988815040461645],"luv":[19.2543827660255502,1.49002234071320738,-42.9088172430781114],"rgb":[0.2,0.133333333333333331,0.4],"xyz":[0.043352304569037263,0.028071484415698747,0.12884222855878627],"hpluv":[271.988815040461645,282.955381276792764,19.2543827660255502],"hsluv":[271.988815040461645,63.8744485302889515,19.2543827660255502]},"#332277":{"lch":[20.7496984269819,53.7295137018198687,270.083996688769219],"luv":[20.7496984269819,0.0787684479011579453,-53.7294559637975908],"rgb":[0.2,0.133333333333333331,0.466666666666666674],"xyz":[0.0526663175892391755,0.0317970896237795633,0.17789603046518418],"hpluv":[270.083996688769219,328.579487011522247,20.7496984269819],"hsluv":[270.083996688769219,71.0892762838988546,20.7496984269819]},"#332288":{"lch":[22.3919640579388926,64.2366699579867,268.940142222195846],"luv":[22.3919640579388926,-1.18818265954209568,-64.2256801385464087],"rgb":[0.2,0.133333333333333331,0.533333333333333326],"xyz":[0.063806734691183,0.0362532564645571542,0.236568893868756347],"hpluv":[268.940142222195846,364.024117005976393,22.3919640579388926],"hsluv":[268.940142222195846,76.6637840765232426,22.3919640579388926]},"#332299":{"lch":[24.1535324867621668,74.5121507797046689,268.199285594367666],"luv":[24.1535324867621668,-2.34141182983712737,-74.4753543426316469],"rgb":[0.2,0.133333333333333331,0.6],"xyz":[0.076863698800255717,0.0414760421081863187,0.305335571509874282],"hpluv":[268.199285594367666,391.458538227207669,24.1535324867621668],"hsluv":[268.199285594367666,80.9654036049547301,24.1535324867621668]},"#3322aa":{"lch":[26.0100477302332607,84.6098540849434926,267.692459882235937],"luv":[26.0100477302332607,-3.40667075751279169,-84.541244387726735],"rgb":[0.2,0.133333333333333331,0.66666666666666663],"xyz":[0.0919213917655082591,0.0474991192942874202,0.384639421126872882],"hpluv":[267.692459882235937,412.780453116303818,26.0100477302332607],"hsluv":[267.692459882235937,84.3023702715129,26.0100477302332607]},"#3322bb":{"lch":[27.9408960039881222,94.5690254119923281,267.330995248517297],"luv":[27.9408960039881222,-4.40370835341661504,-94.4664380619492761],"rgb":[0.2,0.133333333333333331,0.733333333333333282],"xyz":[0.109058983872844906,0.0543541561372221788,0.474897406225514629],"hpluv":[267.330995248517297,429.484911570580266,27.9408960039881222],"hsluv":[267.330995248517297,86.9134730370406743,27.9408960039881222]},"#3322cc":{"lch":[29.9290875828623939,104.415306333233346,267.064581258752071],"luv":[29.9290875828623939,-5.34714045276937444,-104.278302084572317],"rgb":[0.2,0.133333333333333331,0.8],"xyz":[0.12835135931656666,0.0620711063147109804,0.576503916895784729],"hpluv":[267.064581258752071,442.700503900749,29.9290875828623939],"hsluv":[267.064581258752071,88.9774620844202389,29.9290875828623939]},"#3322dd":{"lch":[31.9608605817263296,114.164622106097937,266.862904678446171],"luv":[31.9608605817263296,-6.2476920173399213,-113.993540541052639],"rgb":[0.2,0.133333333333333331,0.866666666666666696],"xyz":[0.149869684867200204,0.0706784365349645144,0.689833764795790727],"hpluv":[266.862904678446171,453.265229710644405,31.9608605817263296],"hsluv":[266.862904678446171,90.6264253960307826,31.9608605817263296]},"#3322ee":{"lch":[34.0251904593745635,123.826689560879501,266.706806867468629],"luv":[34.0251904593745635,-7.11327635006579229,-123.622208147136817],"rgb":[0.2,0.133333333333333331,0.933333333333333348],"xyz":[0.173681865133374941,0.0802033086414345453,0.815244580864314],"hpluv":[266.706806867468629,461.799038215803307,34.0251904593745635],"hsluv":[266.706806867468629,93.6430785136650741,34.0251904593745635]},"#3322ff":{"lch":[36.1133053940478774,133.407509730883817,266.583697157343806],"luv":[36.1133053940478774,-7.94980801741223875,-133.170432923686747],"rgb":[0.2,0.133333333333333331,1],"xyz":[0.199852913543206334,0.0906717280053672414,0.953078769156095795],"hpluv":[266.583697157343806,468.761962088723578,36.1133053940478774],"hsluv":[266.583697157343806,99.999999999999531,36.1133053940478774]},"#aaaa00":{"lch":[67.4983691984715506,74.4102446110960472,85.8743202181747449],"luv":[67.4983691984715506,5.35340686476390193,74.217420717938225],"rgb":[0.66666666666666663,0.66666666666666663,0],"xyz":[0.309512896760441802,0.372958073182539818,0.0556842125390607443],"hpluv":[85.8743202181747449,139.887458074797593,67.4983691984715506],"hsluv":[85.8743202181747449,100.000000000002373,67.4983691984715506]},"#aaaa11":{"lch":[67.528557359020084,73.1276023311446863,85.8743202181746881],"luv":[67.528557359020084,5.26112782412359792,72.9381022286724345],"rgb":[0.66666666666666663,0.66666666666666663,0.0666666666666666657],"xyz":[0.310524562260078907,0.373362739382394671,0.061012317503816374],"hpluv":[85.8743202181746881,137.414698385368666,67.528557359020084],"hsluv":[85.8743202181746881,98.2323220941626118,67.528557359020084]},"#aaaa22":{"lch":[67.5844605157977,70.7729399531690575,85.8743202181746],"luv":[67.5844605157977,5.09172284764045369,70.589541633712912],"rgb":[0.66666666666666663,0.66666666666666663,0.133333333333333331],"xyz":[0.312399920398555964,0.374112882637785471,0.0708892036997955666],"hpluv":[85.8743202181746,132.880028295953878,67.5844605157977],"hsluv":[85.8743202181746,94.9906661574379854,67.5844605157977]},"#aaaa33":{"lch":[67.6763416895574181,66.9597491826677924,85.8743202181744607],"luv":[67.6763416895574181,4.81738479440415723,66.7862322215321882],"rgb":[0.66666666666666663,0.66666666666666663,0.2],"xyz":[0.315487671131013669,0.375347982930768598,0.0871513575574067167],"hpluv":[85.8743202181744607,125.549870841925909,67.6763416895574181],"hsluv":[85.8743202181744607,89.7506270896691376,67.6763416895574181]},"#aaaa44":{"lch":[67.8086418759902898,61.5895608625658824,85.8743202181741623],"luv":[67.8086418759902898,4.43102935143870269,61.429960004304057],"rgb":[0.66666666666666663,0.66666666666666663,0.266666666666666663],"xyz":[0.319945666375232585,0.377131181028456164,0.110630132510293355],"hpluv":[85.8743202181741623,115.255428047766188,67.8086418759902898],"hsluv":[85.8743202181741623,82.3915379076671854,67.8086418759902898]},"#aaaa55":{"lch":[67.9849384953625844,54.6449851984581514,85.8743202181737786],"luv":[67.9849384953625844,3.93140541890911,54.5033802508787772],"rgb":[0.66666666666666663,0.66666666666666663,0.333333333333333315],"xyz":[0.32590808041459457,0.379516146644201,0.142032179784267271],"hpluv":[85.8743202181737786,101.994541545207838,67.9849384953625844],"hsluv":[85.8743202181737786,72.9118556794948631,67.9849384953625844]},"#aaaa66":{"lch":[68.2081473948541515,46.1798212544818156,85.8743202181731675],"luv":[68.2081473948541515,3.32238354287766668,46.0601526125338268],"rgb":[0.66666666666666663,0.66666666666666663,0.4],"xyz":[0.333493076188102755,0.382550144953604343,0.181979824191411232],"hpluv":[85.8743202181731675,85.9122949373369806,68.2081473948541515],"hsluv":[85.8743202181731675,61.415294923296095,68.2081473948541515]},"#aaaa77":{"lch":[68.4806287458147551,36.3079853189649668,85.874320218171988],"luv":[68.4806287458147551,2.61215937225179973,36.2138981792368284],"rgb":[0.66666666666666663,0.66666666666666663,0.466666666666666674],"xyz":[0.342807089208304661,0.386275750161685139,0.231033626097809142],"hpluv":[85.874320218171988,67.2781031791916604,68.4806287458147551],"hsluv":[85.874320218171988,48.0944497134402909,68.4806287458147551]},"#aaaa88":{"lch":[68.804250183835336,25.1900382005990835,85.8743202181696574],"luv":[68.804250183835336,1.81228437202058101,25.1247616884732103],"rgb":[0.66666666666666663,0.66666666666666663,0.533333333333333326],"xyz":[0.353947506310248461,0.390731917002462736,0.289706489501381281],"hpluv":[85.8743202181696574,46.4571845078746506,68.804250183835336],"hsluv":[85.8743202181696574,33.210400093935057,68.804250183835336]},"#aaaa99":{"lch":[69.1804292601881485,13.0180161266067085,85.8743202181625236],"luv":[69.1804292601881485,0.936574490007753058,12.9842817320504498],"rgb":[0.66666666666666663,0.66666666666666663,0.6],"xyz":[0.36700447041932116,0.395954702646091894,0.358473167142499216],"hpluv":[85.8743202181625236,23.8781611725121081,69.1804292601881485],"hsluv":[85.8743202181625236,17.0695511242654057,69.1804292601881485]},"#aaaaaa":{"lch":[69.6101658300367916,3.6866289517569387e-12,0],"luv":[69.6101658300367916,3.46613397703382525e-12,1.25584564385283521e-12],"rgb":[0.66666666666666663,0.66666666666666663,0.66666666666666663],"xyz":[0.382062163384573716,0.401977779832193,0.437777016759497817],"hpluv":[0,6.72041492281092149e-12,69.6101658300367916],"hsluv":[0,4.48262290109626775e-12,69.6101658300367916]},"#aaaabb":{"lch":[70.0940699613229441,13.6540669730780309,265.874320218191428],"luv":[70.0940699613229441,-0.982334841759501587,-13.618684340418703],"rgb":[0.66666666666666663,0.66666666666666663,0.733333333333333282],"xyz":[0.399199755491910391,0.408832816675127775,0.528035001858139563],"hpluv":[265.874320218191428,24.7183841606301087,70.0940699613229441],"hsluv":[265.874320218191428,17.6184615311656536,70.0940699613229441]},"#aaaacc":{"lch":[70.6323884029978188,27.7441307883788433,265.87432021818438],"luv":[70.6323884029978188,-1.99603725260327192,-27.6722356973355303],"rgb":[0.66666666666666663,0.66666666666666663,0.8],"xyz":[0.41849213093563209,0.416549766852616576,0.629641512528409719],"hpluv":[265.87432021818438,49.8432735452352063,70.6323884029978188],"hsluv":[265.87432021818438,36.467826786828347,70.6323884029978188]},"#aaaadd":{"lch":[71.2250312240615813,42.0886841218373817,265.874320218182],"luv":[71.2250312240615813,-3.02804878123905441,-41.979617097899343],"rgb":[0.66666666666666663,0.66666666666666663,0.866666666666666696],"xyz":[0.440010456486265689,0.425157097072870083,0.742971360428415717],"hpluv":[265.874320218182,74.9845908684596,71.2250312240615813],"hsluv":[265.874320218182,56.4865697219014891,71.2250312240615813]},"#aaaaee":{"lch":[71.8715993709786432,56.5301989351418541,265.874320218180742],"luv":[71.8715993709786432,-4.0670361537863835,-56.3837087159979902],"rgb":[0.66666666666666663,0.66666666666666663,0.933333333333333348],"xyz":[0.463822636752440398,0.4346819691793401,0.86838217649693894],"hpluv":[265.874320218180742,99.8073514218055,71.8715993709786432],"hsluv":[265.874320218180742,77.6546881169827259,71.8715993709786432]},"#aaaaff":{"lch":[72.5714133442747595,70.9376272522327,265.87432021818006],"luv":[72.5714133442747595,-5.10357119085512778,-70.7538021683399],"rgb":[0.66666666666666663,0.66666666666666663,1],"xyz":[0.489993685162271819,0.445150388543272824,1.00621636478872079],"hpluv":[265.87432021818006,124.036757123492009,72.5714133442747595],"hsluv":[265.87432021818006,99.999999999997641,72.5714133442747595]},"#88bb00":{"lch":[70.0174964893220135,84.793654921948729,107.670265811619984],"luv":[70.0174964893220135,-25.7381496181260658,80.7930168347331659],"rgb":[0.533333333333333326,0.733333333333333282,0],"xyz":[0.279226618658270809,0.407742918869184512,0.0639910921330886],"hpluv":[107.670265811619984,153.672481251000221,70.0174964893220135],"hsluv":[107.670265811619984,100.000000000002288,70.0174964893220135]},"#88bb11":{"lch":[70.045943224524,83.6147085810298,107.921872667069366],"luv":[70.045943224524,-25.7299069713944561,79.5574721715938296],"rgb":[0.533333333333333326,0.733333333333333282,0.0666666666666666657],"xyz":[0.280238284157907913,0.408147585069039365,0.0693191970978442318],"hpluv":[107.921872667069366,151.474322676164348,70.045943224524],"hsluv":[107.921872667069366,98.3704135852689,70.045943224524]},"#88bb22":{"lch":[70.0986261940145567,81.4532385975490172,108.403169751544382],"luv":[70.0986261940145567,-25.7149121100318041,77.2876016784231],"rgb":[0.533333333333333326,0.733333333333333282,0.133333333333333331],"xyz":[0.28211364229638497,0.408897728324430165,0.0791960832938234244],"hpluv":[108.403169751544382,147.447759071005407,70.0986261940145567],"hsluv":[108.403169751544382,95.3794817356858431,70.0986261940145567]},"#88bb33":{"lch":[70.185227758130182,77.9617926087192643,109.240455548552404],"luv":[70.185227758130182,-25.6910124331637526,73.6071530961765887],"rgb":[0.533333333333333326,0.733333333333333282,0.2],"xyz":[0.285201393028842676,0.410132828617413292,0.0954582371514345607],"hpluv":[109.240455548552404,140.95335886915251,70.185227758130182],"hsluv":[109.240455548552404,90.5378353052476399,70.185227758130182]},"#88bb44":{"lch":[70.3099541281250708,73.067556170236557,110.558097475340105],"luv":[70.3099541281250708,-25.6581823155790048,68.4143657790612281],"rgb":[0.533333333333333326,0.733333333333333282,0.266666666666666663],"xyz":[0.289659388273061591,0.411916026715100858,0.118937012104321199],"hpluv":[110.558097475340105,131.870330314080604,70.3099541281250708],"hsluv":[110.558097475340105,83.7238240635208655,70.3099541281250708]},"#88bb55":{"lch":[70.4762099132372,66.7907607981454845,112.553407091589676],"luv":[70.4762099132372,-25.6172250438111178,61.682765089203194],"rgb":[0.533333333333333326,0.733333333333333282,0.333333333333333315],"xyz":[0.295621802312423576,0.414300992330845719,0.150339059378295115],"hpluv":[112.553407091589676,120.257778383662554,70.4762099132372],"hsluv":[112.553407091589676,74.9213657205140606,70.4762099132372]},"#88bb66":{"lch":[70.6867901559138687,59.2534136994931373,115.564788197424377],"luv":[70.6867901559138687,-25.56971066242372,53.4523800375924836],"rgb":[0.533333333333333326,0.733333333333333282,0.4],"xyz":[0.303206798085931761,0.417334990640249037,0.190286703785439076],"hpluv":[115.564788197424377,106.368844477737383,70.6867901559138687],"hsluv":[115.564788197424377,64.2082802413586791,70.6867901559138687]},"#88bb77":{"lch":[70.9439811929011483,50.7088031944788611,120.213509646437856],"luv":[70.9439811929011483,-25.5178724843925657,43.8203252530908287],"rgb":[0.533333333333333326,0.733333333333333282,0.466666666666666674],"xyz":[0.312520811106133667,0.421060595848329833,0.239340505691836986],"hpluv":[120.213509646437856,90.6999673798200519,70.9439811929011483],"hsluv":[120.213509646437856,51.7430673824667338,70.9439811929011483]},"#88bb88":{"lch":[71.2496205680497781,41.6266624709187667,127.715012949237462],"luv":[71.2496205680497781,-25.4644588867656232,32.9293237414924747],"rgb":[0.533333333333333326,0.733333333333333282,0.533333333333333326],"xyz":[0.323661228208077467,0.425516762689107431,0.298013369095409153],"hpluv":[127.715012949237462,74.1358655131278397,71.2496205680497781],"hsluv":[127.715012949237462,37.7483692132655,71.2496205680497781]},"#88bb99":{"lch":[71.605136773449729,32.9376822973712677,140.491872589160209],"luv":[71.605136773449729,-25.4125532319559895,20.9545473192710077],"rgb":[0.533333333333333326,0.733333333333333282,0.6],"xyz":[0.336718192317150167,0.430739548332736588,0.366780046736527088],"hpluv":[140.491872589160209,58.3697971606621948,71.605136773449729],"hsluv":[140.491872589160209,40.0947707109065163,71.605136773449729]},"#88bbaa":{"lch":[72.0115788449514298,26.624214972975043,162.310745910586235],"luv":[72.0115788449514298,-25.3653817896029707,8.0898843993512255],"rgb":[0.533333333333333326,0.733333333333333282,0.66666666666666663],"xyz":[0.351775885282402723,0.43676262551883771,0.446083896353525633],"hpluv":[162.310745910586235,46.9152251525928463,72.0115788449514298],"hsluv":[162.310745910586235,42.5902472855224445,72.0115788449514298]},"#88bbbb":{"lch":[72.4696411221425478,25.9090725846495289,192.177050630060563],"luv":[72.4696411221425478,-25.3261303787159093,-5.46508574835939687],"rgb":[0.533333333333333326,0.733333333333333282,0.733333333333333282],"xyz":[0.368913477389739397,0.443617662361772469,0.536341881452167435],"hpluv":[192.177050630060563,45.3664800039612786,72.4696411221425478],"hsluv":[192.177050630060563,45.1889022919971595,72.4696411221425478]},"#88bbcc":{"lch":[72.9796861172365539,31.9509756483125074,217.648879320727843],"luv":[72.9796861172365539,-25.297786835453639,-19.5163220435359541],"rgb":[0.533333333333333326,0.733333333333333282,0.8],"xyz":[0.388205852833461096,0.451334612539261271,0.637948392122437591],"hpluv":[217.648879320727843,55.5547835161394303,72.9796861172365539],"hsluv":[217.648879320727843,47.846459663484211,72.9796861172365539]},"#88bbdd":{"lch":[73.5417671198988501,42.2771793498237827,233.271065498294831],"luv":[73.5417671198988501,-25.2830202693059967,-33.8840490472881442],"rgb":[0.533333333333333326,0.733333333333333282,0.866666666666666696],"xyz":[0.409724178384094695,0.459941942759514777,0.751278240022443589],"hpluv":[233.271065498294831,72.9476439375157781,73.5417671198988501],"hsluv":[233.271065498294831,52.600286903313318,73.5417671198988501]},"#88bbee":{"lch":[74.1556513704433655,54.6140049995012049,242.42172167609948],"luv":[74.1556513704433655,-25.2841013367454792,-48.4087157615106349],"rgb":[0.533333333333333326,0.733333333333333282,0.933333333333333348],"xyz":[0.433536358650269404,0.469466814865984794,0.876689056090966812],"hpluv":[242.42172167609948,93.4542589851821646,74.1556513704433655],"hsluv":[242.42172167609948,75.5983078602269387,74.1556513704433655]},"#88bbff":{"lch":[74.8208441285393206,67.8489412305869877,248.103607922481928],"luv":[74.8208441285393206,-25.3028619495915343,-62.9543009116260492],"rgb":[0.533333333333333326,0.733333333333333282,1],"xyz":[0.459707407060100826,0.479935234229917518,1.01452324438274855],"hpluv":[248.103607922481928,115.069386567942303,74.8208441285393206],"hsluv":[248.103607922481928,99.9999999999973568,74.8208441285393206]},"#333300":{"lch":[20.3279441284931792,22.4095383785379596,85.8743202181747449],"luv":[20.3279441284931792,1.61224273913978733,22.3514671484727536],"rgb":[0.2,0.2,0],"xyz":[0.0254898472303871464,0.0307148568226560392,0.00458585760277267773],"hpluv":[85.8743202181747449,139.887458074797735,20.3279441284931792],"hsluv":[85.8743202181747449,100.000000000002458,20.3279441284931792]},"#333311":{"lch":[20.4867879892499971,17.9332091798965507,85.8743202181741],"luv":[20.4867879892499971,1.2901955319819518,17.8867377399899183],"rgb":[0.2,0.2,0.0666666666666666657],"xyz":[0.0265015127300242681,0.0311195230225108921,0.00991396256752831],"hpluv":[85.8743202181741,111.076827622251201,20.4867879892499971],"hsluv":[85.8743202181741,79.4044220625277717,20.4867879892499971]},"#333322":{"lch":[20.7776374982028358,10.4602453251552614,85.8743202181717749],"luv":[20.7776374982028358,0.752556982220839221,10.4331390411008691],"rgb":[0.2,0.2,0.133333333333333331],"xyz":[0.0283768708685012867,0.0318696662779017134,0.019790848763507507],"hpluv":[85.8743202181717749,63.8829601302186703,20.7776374982028358],"hsluv":[85.8743202181717749,45.6673964981637113,20.7776374982028358]},"#333333":{"lch":[21.246731294981295,1.12524964979295229e-12,0],"luv":[21.246731294981295,1.05794917113478783e-12,3.83314917077821647e-13],"rgb":[0.2,0.2,0.2],"xyz":[0.0314646216009590307,0.0331047665708848263,0.0360530026211186502],"hpluv":[0,6.72041492281092149e-12,21.246731294981295],"hsluv":[0,1.92419399944792236e-12,21.246731294981295]},"#333344":{"lch":[21.9038391599933462,12.2084714240410825,265.874320218182163],"luv":[21.9038391599933462,-0.878332211796974,-12.176834853004598],"rgb":[0.2,0.2,0.266666666666666663],"xyz":[0.0359226168451779043,0.0348879646685724,0.0595317775740052887],"hpluv":[265.874320218182163,70.7262082967351517,21.9038391599933462],"hsluv":[265.874320218182163,13.7757030029577514,21.9038391599933462]},"#333355":{"lch":[22.7485838486986935,25.0264321710322868,265.874320218179776],"luv":[22.7485838486986935,-1.80051382017376982,-24.9615796213830023],"rgb":[0.2,0.2,0.333333333333333315],"xyz":[0.0418850308845399,0.0372729302843172322,0.0909338248479792],"hpluv":[265.874320218179776,139.599512106194084,22.7485838486986935],"hsluv":[265.874320218179776,27.1905063829271256,22.7485838486986935]},"#333366":{"lch":[23.7726526978294,37.7235732610660364,265.874320218179],"luv":[23.7726526978294,-2.71400312032964841,-37.625817820292724],"rgb":[0.2,0.2,0.4],"xyz":[0.0494700266580480746,0.0403069285937205438,0.130881469255123173],"hpluv":[265.874320218179,201.360603518100845,23.7726526978294],"hsluv":[265.874320218179,39.2200280117306193,23.7726526978294]},"#333377":{"lch":[24.9621315786770737,49.9646270765614062,265.874320218178639],"luv":[24.9621315786770737,-3.59467945556105306,-49.8351506319748268],"rgb":[0.2,0.2,0.466666666666666674],"xyz":[0.0587840396782499941,0.0440325338018013601,0.179935271161521082],"hpluv":[265.874320218178639,253.992158426909725,24.9621315786770737],"hsluv":[265.874320218178639,49.4713434217918646,24.9621315786770737]},"#333388":{"lch":[26.2997861111378413,61.6680265106551175,265.874320218178468],"luv":[26.2997861111378413,-4.43667452222106906,-61.5082223194812912],"rgb":[0.2,0.2,0.533333333333333326],"xyz":[0.0699244567801938222,0.048488700642578958,0.238608134565093222],"hpluv":[265.874320218178468,297.541234413863208,26.2997861111378413],"hsluv":[265.874320218178468,57.953618257344317,26.2997861111378413]},"#333399":{"lch":[27.7670269025285634,72.8744236647892336,265.874320218178354],"luv":[27.7670269025285634,-5.24291301488723782,-72.6855796399362788],"rgb":[0.2,0.2,0.6],"xyz":[0.0829814208892665356,0.0537114862862081155,0.307374812206211157],"hpluv":[265.874320218178354,333.031319879373427,27.7670269025285634],"hsluv":[265.874320218178354,64.8662025552495862,27.7670269025285634]},"#3333aa":{"lch":[29.34539826905295,83.6653121043175361,265.874320218178241],"luv":[29.34539826905295,-6.01925794630032573,-83.4485049793509575],"rgb":[0.2,0.2,0.66666666666666663],"xyz":[0.0980391138545190777,0.059734563472309217,0.386678661823209757],"hpluv":[265.874320218178241,361.780166220798492,29.34539826905295],"hsluv":[265.874320218178241,70.4657614516561353,29.34539826905295]},"#3333bb":{"lch":[31.0175640968910713,94.1237197643615247,265.874320218178184],"luv":[31.0175640968910713,-6.77168271864664284,-93.8798111173964855],"rgb":[0.2,0.2,0.733333333333333282],"xyz":[0.115176705961855724,0.0665896003152439686,0.476936646921851504],"hpluv":[265.874320218178184,385.062051502536349,31.0175640968910713],"hsluv":[265.874320218178184,75.0004925607309758,31.0175640968910713]},"#3333cc":{"lch":[32.7678589751368321,104.319620441623087,265.874320218178127],"luv":[32.7678589751368321,-7.50522156082274261,-104.049290523324899],"rgb":[0.2,0.2,0.8],"xyz":[0.134469081405577451,0.0743065504927327702,0.578543157592121604],"hpluv":[265.874320218178127,403.977575952485893,32.7678589751368321],"hsluv":[265.874320218178127,79.524052836351089,32.7678589751368321]},"#3333dd":{"lch":[34.5825131799139243,114.307143948468337,265.874320218178127],"luv":[34.5825131799139243,-8.22376881440244745,-114.010932739554079],"rgb":[0.2,0.2,0.866666666666666696],"xyz":[0.155987406956211,0.0829138807129863,0.691873005492127602],"hpluv":[265.874320218178127,419.426773039758132,34.5825131799139243],"hsluv":[265.874320218178127,86.1542613798901584,34.5825131799139243]},"#3333ee":{"lch":[36.4496605331747929,124.126383834434506,265.87432021817807],"luv":[36.4496605331747929,-8.93020898923314732,-123.80472741871364],"rgb":[0.2,0.2,0.933333333333333348],"xyz":[0.179799587222385732,0.092438752819456349,0.817283821560650825],"hpluv":[265.87432021817807,432.12554656995303,36.4496605331747929],"hsluv":[265.87432021817807,92.9362870993519,36.4496605331747929]},"#3333ff":{"lch":[38.3592184432327414,133.806417871427385,265.87432021817807],"luv":[38.3592184432327414,-9.62663407069321231,-133.45967698167118],"rgb":[0.2,0.2,1],"xyz":[0.205970635632217125,0.102907172183389045,0.95511800985243267],"hpluv":[265.87432021817807,442.635784237250618,38.3592184432327414],"hsluv":[265.87432021817807,99.99999999999946,38.3592184432327414]},"#aabb00":{"lch":[72.2864137555308162,81.0402066187271686,93.9104624709461291],"luv":[72.2864137555308162,-5.52673715975233737,80.8515322376329664],"rgb":[0.66666666666666663,0.733333333333333282,0],"xyz":[0.343467394669040582,0.440867068999738376,0.0670023785085933632],"hpluv":[93.9104624709461291,142.260125307220505,72.2864137555308162],"hsluv":[93.9104624709461291,100.00000000000226,72.2864137555308162]},"#aabb11":{"lch":[72.3134178153803759,79.8795424406406198,94.0047051989067199],"luv":[72.3134178153803759,-5.5786590117117969,79.6845020324350912],"rgb":[0.66666666666666663,0.733333333333333282,0.0666666666666666657],"xyz":[0.344479060168677687,0.441271735199593229,0.072330483473349],"hpluv":[94.0047051989067199,140.170301198642704,72.3134178153803759],"hsluv":[94.0047051989067199,98.4998030851846522,72.3134178153803759]},"#aabb22":{"lch":[72.3634325080893319,77.7463008610920667,94.1853407287125179],"luv":[72.3634325080893319,-5.67416055225396132,77.5389656857163],"rgb":[0.66666666666666663,0.733333333333333282,0.133333333333333331],"xyz":[0.346354418307154743,0.44202187845498403,0.0822073696693281925],"hpluv":[94.1853407287125179,136.332658010127801,72.3634325080893319],"hsluv":[94.1853407287125179,95.7441801677588131,72.3634325080893319]},"#aabb33":{"lch":[72.4456578556837343,74.284969405898,94.5007685828256427],"luv":[72.4456578556837343,-5.82932493434540167,74.0558954469191377],"rgb":[0.66666666666666663,0.733333333333333282,0.2],"xyz":[0.349442169039612449,0.443256978747967156,0.0984695235269393288],"hpluv":[94.5007685828256427,130.115164427369336,72.4456578556837343],"hsluv":[94.5007685828256427,91.2774770665997721,72.4456578556837343]},"#aabb44":{"lch":[72.5641031469497193,69.3968632274838768,95.0004815565242922],"luv":[72.5641031469497193,-6.04891620231322502,69.1327363742496317],"rgb":[0.66666666666666663,0.733333333333333282,0.266666666666666663],"xyz":[0.353900164283831364,0.445040176845654722,0.121948298479825967],"hpluv":[95.0004815565242922,121.354905136961719,72.5641031469497193],"hsluv":[95.0004815565242922,84.978619462346515,72.5641031469497193]},"#aabb55":{"lch":[72.7220260779140659,63.0543258899363366,95.7659530899235705],"luv":[72.7220260779140659,-6.33475857174489843,62.7353078200147181],"rgb":[0.66666666666666663,0.733333333333333282,0.333333333333333315],"xyz":[0.359862578323193349,0.447425142461399583,0.153350345753799883],"hpluv":[95.7659530899235705,110.024206089370551,72.7220260779140659],"hsluv":[95.7659530899235705,76.8198788639563475,72.7220260779140659]},"#aabb66":{"lch":[72.922116394456026,55.2958006214329245,96.9449007941817342],"luv":[72.922116394456026,-6.68608027099689206,54.8900892418207675],"rgb":[0.66666666666666663,0.733333333333333282,0.4],"xyz":[0.367447574096701535,0.450459140770802902,0.193297990160943844],"hpluv":[96.9449007941817342,96.2215198645611167,72.922116394456026],"hsluv":[96.9449007941817342,66.8569788454327778,72.922116394456026]},"#aabb77":{"lch":[73.1665925415562555,46.2248747385797927,98.8352478745929801],"luv":[73.1665925415562555,-7.09985217623529596,45.6763740206356488],"rgb":[0.66666666666666663,0.733333333333333282,0.466666666666666674],"xyz":[0.37676158711690344,0.454184745978883697,0.242351792067341754],"hpluv":[98.8352478745929801,80.1682197570307267,73.1665925415562555],"hsluv":[98.8352478745929801,55.2184354086421223,73.1665925415562555]},"#aabb88":{"lch":[73.4572589636137,36.0214199172978056,102.133241078873],"luv":[73.4572589636137,-7.57119112276486117,35.2167539367396216],"rgb":[0.66666666666666663,0.733333333333333282,0.533333333333333326],"xyz":[0.387902004218847241,0.458640912819661295,0.301024655470913949],"hpluv":[102.133241078873,62.2250760292602862,73.4572589636137],"hsluv":[102.133241078873,42.0922357464751116,73.4572589636137]},"#aabb99":{"lch":[73.7955437608147236,25.0118273668521454,108.880774444702425],"luv":[73.7955437608147236,-8.09382587885112592,23.6660408786948082],"rgb":[0.66666666666666663,0.733333333333333282,0.6],"xyz":[0.40095896832792,0.463863698463290453,0.369791333112031828],"hpluv":[108.880774444702425,43.0085312761643337,73.7955437608147236],"hsluv":[108.880774444702425,27.7101400322224,73.7955437608147236]},"#aabbaa":{"lch":[74.1825262226786464,14.1574418893213867,127.715012949227386],"luv":[74.1825262226786464,-8.66059336811296632,11.1994322785447302],"rgb":[0.66666666666666663,0.733333333333333282,0.66666666666666663],"xyz":[0.416016661293172496,0.469886775649391575,0.449095182729030429],"hpluv":[127.715012949227386,24.2171200924073027,74.1825262226786464],"hsluv":[127.715012949227386,12.3308304853939106,74.1825262226786464]},"#aabbbb":{"lch":[74.6189593067414734,9.47715438031144153,192.177050630059],"luv":[74.6189593067414734,-9.26392276955498417,-1.99904729008021675],"rgb":[0.66666666666666663,0.733333333333333282,0.733333333333333282],"xyz":[0.43315425340050917,0.476741812492326333,0.539353167827672175],"hpluv":[192.177050630059,16.1164020856357908,74.6189593067414734],"hsluv":[192.177050630059,16.0533177597809029,74.6189593067414734]},"#aabbcc":{"lch":[75.1052899078477623,18.5983929047544514,237.852316168687679],"luv":[75.1052899078477623,-9.89626817417043547,-15.7468757175676597],"rgb":[0.66666666666666663,0.733333333333333282,0.8],"xyz":[0.452446628844230925,0.484458762669815135,0.640959678497942331],"hpluv":[237.852316168687679,31.4227520087917149,75.1052899078477623],"hsluv":[237.852316168687679,25.8004515395991127,75.1052899078477623]},"#aabbdd":{"lch":[75.6416785331857682,31.6798915222297,250.547006926215033],"luv":[75.6416785331857682,-10.5504613433008458,-29.8714461033234144],"rgb":[0.66666666666666663,0.733333333333333282,0.866666666666666696],"xyz":[0.473964954394864413,0.493066092890068641,0.754289526397948329],"hpluv":[250.547006926215033,53.1449318902714438,75.6416785331857682],"hsluv":[250.547006926215033,48.9122949421499484,75.6416785331857682]},"#aabbee":{"lch":[76.2280192594463699,45.6175545861468166,255.761586302643195],"luv":[76.2280192594463699,-11.2199701465387403,-44.2162137267639],"rgb":[0.66666666666666663,0.733333333333333282,0.933333333333333348],"xyz":[0.497777134661039178,0.502590964996538658,0.879700342466471552],"hpluv":[255.761586302643195,76.8288153841444483,76.2280192594463699],"hsluv":[255.761586302643195,73.6249760737912311,76.2280192594463699]},"#aabbff":{"lch":[76.863960378353255,59.8395450787859247,258.530312903596609],"luv":[76.863960378353255,-11.8990616804050067,-58.6445520603744583],"rgb":[0.66666666666666663,0.733333333333333282,1],"xyz":[0.523948183070870543,0.513059384360471382,1.01753453075825329],"hpluv":[258.530312903596609,104.151140840900069,76.863960378353255],"hsluv":[258.530312903596609,99.9999999999969305,76.863960378353255]},"#88cc00":{"lch":[75.0884647575288,93.9986167747887,111.475410134903882],"luv":[75.0884647575288,-34.413070492851,87.4727416674912348],"rgb":[0.533333333333333326,0.8,0],"xyz":[0.317450361967887784,0.484190405488419406,0.0767323399029605363],"hpluv":[111.475410134903882,158.85012628624969,75.0884647575288],"hsluv":[111.475410134903882,100.000000000002288,75.0884647575288]},"#88cc11":{"lch":[75.1138336746799,92.9472917959209752,111.713770271434171],"luv":[75.1138336746799,-34.3877142984514421,86.3520941119794685],"rgb":[0.533333333333333326,0.8,0.0666666666666666657],"xyz":[0.318462027467524889,0.484595071688274259,0.082060444867716173],"hpluv":[111.713770271434171,157.020421425354783,75.1138336746799],"hsluv":[111.713770271434171,98.6248626695712289,75.1138336746799]},"#88cc22":{"lch":[75.1608235532889495,91.0175657840787551,112.166724150973],"luv":[75.1608235532889495,-34.3412008388942667,84.2904455214339805],"rgb":[0.533333333333333326,0.8,0.133333333333333331],"xyz":[0.320337385606001945,0.48534521494366506,0.0919373310636953656],"hpluv":[112.166724150973,153.664310911800271,75.1608235532889495],"hsluv":[112.166724150973,96.0970283406349,75.1608235532889495]},"#88cc33":{"lch":[75.2380863503033908,87.8942550668024865,112.94545296029041],"luv":[75.2380863503033908,-34.2659803117460342,80.9397471396048331],"rgb":[0.533333333333333326,0.8,0.2],"xyz":[0.323425136338459651,0.486580315236648187,0.108199484921306516],"hpluv":[112.94545296029041,148.2388630129999,75.2380863503033908],"hsluv":[112.94545296029041,91.9942509365254324,75.2380863503033908]},"#88cc44":{"lch":[75.3494055810326415,83.5027286146262,114.147802574759467],"luv":[75.3494055810326415,-34.1602904869016655,76.1956707427555244],"rgb":[0.533333333333333326,0.8,0.266666666666666663],"xyz":[0.327883131582678566,0.488363513334335753,0.131678259874193154],"hpluv":[114.147802574759467,140.624231819797672,75.3494055810326415],"hsluv":[114.147802574759467,86.1974134191241177,75.3494055810326415]},"#88cc55":{"lch":[75.4978684165763241,77.8461227965530469,115.917002828128631],"luv":[75.4978684165763241,-34.0241050685150555,70.0169915716368365],"rgb":[0.533333333333333326,0.8,0.333333333333333315],"xyz":[0.333845545622040552,0.490748478950080613,0.16308030714816707],"hpluv":[115.917002828128631,130.840327774204638,75.4978684165763241],"hsluv":[115.917002828128631,78.6694108520956092,75.4978684165763241]},"#88cc66":{"lch":[75.6860396561484663,71.0106875190110287,118.477611184333398],"luv":[75.6860396561484663,-33.8589835890750237,62.4186428259808963],"rgb":[0.533333333333333326,0.8,0.4],"xyz":[0.341430541395548737,0.493782477259483932,0.203027951555311],"hpluv":[118.477611184333398,119.054896833398359,75.6860396561484663],"hsluv":[118.477611184333398,69.4467240035668141,75.6860396561484663]},"#88cc77":{"lch":[75.9160535408259705,63.1826013081171638,122.199343200922883],"luv":[75.9160535408259705,-33.6678964132470924,53.4650713940171656],"rgb":[0.533333333333333326,0.8,0.466666666666666674],"xyz":[0.350744554415750642,0.497508082467564727,0.252081753461708913],"hpluv":[122.199343200922883,105.609553255175555,75.9160535408259705],"hsluv":[122.199343200922883,58.6308874961384063,75.9160535408259705]},"#88cc88":{"lch":[76.1896681333118124,54.6887581458639929,127.715012949238314],"luv":[76.1896681333118124,-33.4549913615237,43.2622678616965288],"rgb":[0.533333333333333326,0.8,0.533333333333333326],"xyz":[0.361884971517694443,0.50196424930834227,0.310754616865281108],"hpluv":[127.715012949238314,91.92606633748386,76.1896681333118124],"hsluv":[127.715012949238314,46.3779062484352878,76.1896681333118124]},"#88cc99":{"lch":[76.5083007543168492,46.0935908553499587,136.122445502284393],"luv":[76.5083007543168492,-33.2253063874269188,31.9483666781575764],"rgb":[0.533333333333333326,0.8,0.6],"xyz":[0.374941935626767142,0.507187034951971483,0.379521294506399],"hpluv":[136.122445502284393,78.7570782006024643,76.5083007543168492],"hsluv":[136.122445502284393,48.1280089891728622,76.5083007543168492]},"#88ccaa":{"lch":[76.8730534179438223,38.4110576559043437,149.173477570542047],"luv":[76.8730534179438223,-32.9844501501569098,19.6833787378341469],"rgb":[0.533333333333333326,0.8,0.66666666666666663],"xyz":[0.389999628592019698,0.513210112138072549,0.458825144123397588],"hpluv":[149.173477570542047,66.8865090410736229,76.8730534179438223],"hsluv":[149.173477570542047,50.0095890879800891,76.8730534179438223]},"#88ccbb":{"lch":[77.2847330465352087,33.404634806871222,168.536638924911273],"luv":[77.2847330465352087,-32.73827895277973,6.638879257104497],"rgb":[0.533333333333333326,0.8,0.733333333333333282],"xyz":[0.407137220699356372,0.520065148981007308,0.54908312922203939],"hpluv":[168.536638924911273,59.444025112992847,77.2847330465352087],"hsluv":[168.536638924911273,51.9915664660802292,77.2847330465352087]},"#88cccc":{"lch":[77.7438691793350074,33.2404934388306,192.177050630060876],"luv":[77.7438691793350074,-32.4925976386916417,-7.01152642061846443],"rgb":[0.533333333333333326,0.8,0.8],"xyz":[0.426429596143078071,0.527782099158496165,0.650689639892309546],"hpluv":[192.177050630060876,60.6231146417445359,77.7438691793350074],"hsluv":[192.177050630060876,54.0427382519684585,77.7438691793350074]},"#88ccdd":{"lch":[78.2507307533704,38.5418325774740964,213.193277164244591],"luv":[78.2507307533704,-32.2529061156020589,-21.1003058159876602],"rgb":[0.533333333333333326,0.8,0.866666666666666696],"xyz":[0.44794792169371167,0.536389429378749671,0.764019487792315544],"hpluv":[213.193277164244591,72.2588367593471759,78.2507307533704],"hsluv":[213.193277164244591,56.1332045791076126,78.2507307533704]},"#88ccee":{"lch":[78.8053428571366368,47.78945312574524,227.924421751618695],"luv":[78.8053428571366368,-32.0242046898233,-35.4722728908382834],"rgb":[0.533333333333333326,0.8,0.933333333333333348],"xyz":[0.47176010195988638,0.545914301485219688,0.889430303860838767],"hpluv":[227.924421751618695,92.3999074491721473,78.8053428571366368],"hsluv":[227.924421751618695,70.4270935368067796,78.8053428571366368]},"#88ccff":{"lch":[79.4075039272108114,59.2521837878726885,237.529017152572294],"luv":[79.4075039272108114,-31.8108626015509195,-49.9889018100727327],"rgb":[0.533333333333333326,0.8,1],"xyz":[0.497931150369717801,0.556382720849152412,1.02726449215262061],"hpluv":[237.529017152572294,118.549697277888072,79.4075039272108114],"hsluv":[237.529017152572294,99.999999999996561,79.4075039272108114]},"#334400":{"lch":[26.2681529832905483,31.0251081485104194,104.276907196552472],"luv":[26.2681529832905483,-7.65105337509169647,30.0669040288198879],"rgb":[0.2,0.266666666666666663,0],"xyz":[0.034322417713353183,0.0483799977885883553,0.00753004776376127276],"hpluv":[104.276907196552472,149.872894059772364,26.2681529832905483],"hsluv":[104.276907196552472,100.000000000002302,26.2681529832905483]},"#334411":{"lch":[26.3856741683463127,27.3886432490873446,106.295788944443402],"luv":[26.3856741683463127,-7.68514827558869662,26.2883296351821087],"rgb":[0.2,0.266666666666666663,0.0666666666666666657],"xyz":[0.0353340832129903082,0.0487846639884432082,0.0128581527285169042],"hpluv":[106.295788944443402,131.716945387015755,26.3856741683463127],"hsluv":[106.295788944443402,86.6296124974134614,26.3856741683463127]},"#334422":{"lch":[26.6018195362025054,21.2226436820006832,111.412237748000109],"luv":[26.6018195362025054,-7.74787020962619799,19.7578114189793403],"rgb":[0.2,0.266666666666666663,0.133333333333333331],"xyz":[0.0372094413514673233,0.0495348072438340295,0.0227350389244961],"hpluv":[111.412237748000109,101.234249163259577,26.6018195362025054],"hsluv":[111.412237748000109,63.7673799144094,26.6018195362025054]},"#334433":{"lch":[26.9529945323855813,12.8320575385027151,127.715012949236225],"luv":[26.9529945323855813,-7.8498102472204323,10.150969399721264],"rgb":[0.2,0.266666666666666663,0.2],"xyz":[0.0402971920839250639,0.0507699075368171424,0.038997192782107247],"hpluv":[127.715012949236225,60.4127494816677171,26.9529945323855813],"hsluv":[127.715012949236225,30.7608572023581708,26.9529945323855813]},"#334444":{"lch":[27.4501004194092673,8.17817622085537721,192.177050630060421],"luv":[27.4501004194092673,-7.99417102070306651,-1.72504956193021397],"rgb":[0.2,0.266666666666666663,0.266666666666666663],"xyz":[0.0447551873281439444,0.0525531056345047154,0.0624759677349938855],"hpluv":[192.177050630060421,37.8052272806132379,27.4501004194092673],"hsluv":[192.177050630060421,37.6572465300637518,27.4501004194092673]},"#334455":{"lch":[28.0976851129048839,16.9879579660521678,241.20654356816641],"luv":[28.0976851129048839,-8.1823109542023289,-14.8875956186718064],"rgb":[0.2,0.266666666666666663,0.333333333333333315],"xyz":[0.0507176013675059364,0.0549380712502495483,0.0938780150089678],"hpluv":[241.20654356816641,76.720241835207986,28.0976851129048839],"hsluv":[241.20654356816641,44.9859363973003568,28.0976851129048839]},"#334466":{"lch":[28.8949601880565652,29.7043747380071501,253.545194757545516],"luv":[28.8949601880565652,-8.41402976058801855,-28.487786536758108],"rgb":[0.2,0.266666666666666663,0.4],"xyz":[0.0583025971410141147,0.0579720695596528598,0.133825659416111742],"hpluv":[253.545194757545516,130.448064952476017,28.8949601880565652],"hsluv":[253.545194757545516,52.1427730716471629,28.8949601880565652]},"#334477":{"lch":[29.8367962202096138,42.8398018741040758,258.299336276781332],"luv":[29.8367962202096138,-8.68785350705267589,-41.9496105590085691],"rgb":[0.2,0.266666666666666663,0.466666666666666674],"xyz":[0.0676166101612160342,0.0616976747677336762,0.182879461322509651],"hpluv":[258.299336276781332,182.19421868795277,29.8367962202096138],"hsluv":[258.299336276781332,58.7347196438674857,29.8367962202096138]},"#334488":{"lch":[30.9147794404111025,55.6960507233291082,260.699324576281469],"luv":[30.9147794404111025,-9.00134255207500189,-54.9638599302837605],"rgb":[0.2,0.266666666666666663,0.533333333333333326],"xyz":[0.0787570272631598622,0.066153841608511274,0.241552324726081818],"hpluv":[260.699324576281469,228.611238042833349,30.9147794404111025],"hsluv":[260.699324576281469,64.5716173949788583,30.9147794404111025]},"#334499":{"lch":[32.1182691124294664,68.0605660836803281,262.102678541403236],"luv":[32.1182691124294664,-9.35140200670356769,-67.4150720250304],"rgb":[0.2,0.266666666666666663,0.6],"xyz":[0.0918139913722325618,0.0713766272521404316,0.310319002367199726],"hpluv":[262.102678541403236,268.895014901030436,32.1182691124294664],"hsluv":[262.102678541403236,69.6097770986353623,32.1182691124294664]},"#3344aa":{"lch":[33.435366318838156,79.8975403264742852,263.001802037450773],"luv":[33.435366318838156,-9.73456660877536528,-79.3023023824649158],"rgb":[0.2,0.266666666666666663,0.66666666666666663],"xyz":[0.106871684337485118,0.07739970443824154,0.389622851984198326],"hpluv":[263.001802037450773,303.226149032408784,33.435366318838156],"hsluv":[263.001802037450773,73.891501645941716,33.435366318838156]},"#3344bb":{"lch":[34.8537252521307721,91.2457354427413492,263.615054402289786],"luv":[34.8537252521307721,-10.1472390443123768,-90.6797539490724773],"rgb":[0.2,0.266666666666666663,0.733333333333333282],"xyz":[0.124009276444821764,0.0842547412811763,0.479880837082840073],"hpluv":[263.615054402289786,332.202349056841342,34.8537252521307721],"hsluv":[263.615054402289786,77.4995146205371412,34.8537252521307721]},"#3344cc":{"lch":[36.3611746115969083,102.170263494902102,264.052905077601281],"luv":[36.3611746115969083,-10.5858721727669973,-101.620382074461631],"rgb":[0.2,0.266666666666666663,0.8],"xyz":[0.143301651888543491,0.0919716914586651,0.581487347753110284],"hpluv":[264.052905077601281,356.55451128807033,36.3611746115969083],"hsluv":[264.052905077601281,80.5286468598271767,36.3611746115969083]},"#3344dd":{"lch":[37.9461503215655611,112.73940211649635,264.376684246138268],"luv":[37.9461503215655611,-11.0470957042534899,-112.196855865421313],"rgb":[0.2,0.266666666666666663,0.866666666666666696],"xyz":[0.164819977439177034,0.100579021678918634,0.694817195653116282],"hpluv":[264.376684246138268,377.005191833442723,37.9461503215655611],"hsluv":[264.376684246138268,84.1625325255073,37.9461503215655611]},"#3344ee":{"lch":[39.5979632159824462,123.014623823289881,264.622878978329823],"luv":[39.5979632159824462,-11.5277944422180187,-122.473293536523641],"rgb":[0.2,0.266666666666666663,0.933333333333333348],"xyz":[0.188632157705351772,0.110103893785388651,0.820228011721639505],"hpluv":[264.622878978329823,394.205992168221826,39.5979632159824462],"hsluv":[264.622878978329823,91.9832832027675664,39.5979632159824462]},"#3344ff":{"lch":[41.3069357297154482,133.047388274610427,264.814390787746049],"luv":[41.3069357297154482,-12.0251481753234213,-132.502842754623401],"rgb":[0.2,0.266666666666666663,1],"xyz":[0.214803206115183165,0.120572313149321361,0.95806220001342135],"hpluv":[264.814390787746049,408.716999433792864,41.3069357297154482],"hsluv":[264.814390787746049,99.9999999999994458,41.3069357297154482]},"#aacc00":{"lch":[77.1199831352121,88.8460909387721,100.173289143969555],"luv":[77.1199831352121,-15.692520471132994,87.4492577233428108],"rgb":[0.66666666666666663,0.8,0],"xyz":[0.381691137978657502,0.517314555618973326,0.0797436262784653],"hpluv":[100.173289143969555,156.730643533439519,77.1199831352121],"hsluv":[100.173289143969555,100.000000000002373,77.1199831352121]},"#aacc11":{"lch":[77.1442576556984676,87.800209961997254,100.311366942902],"luv":[77.1442576556984676,-15.7160097521192821,86.3821967007212237],"rgb":[0.66666666666666663,0.8,0.0666666666666666657],"xyz":[0.382702803478294606,0.517719221818828235,0.085071731243220941],"hpluv":[100.311366942902,155.08420894585916,77.1442576556984676],"hsluv":[100.311366942902,98.7181568051142,77.1442576556984676]},"#aacc22":{"lch":[77.1892227090432641,85.8765024717939411,100.574350259733862],"luv":[77.1892227090432641,-15.7593085348968636,84.4181134075499102],"rgb":[0.66666666666666663,0.8,0.133333333333333331],"xyz":[0.384578161616771663,0.518469365074219,0.0949486174392001336],"hpluv":[100.574350259733862,152.047171814071362,77.1892227090432641],"hsluv":[100.574350259733862,96.3604791744028404,77.1892227090432641]},"#aacc33":{"lch":[77.2631626362465482,82.7513779572315116,101.028364552392574],"luv":[77.2631626362465482,-15.8299191574657527,81.2231753460099668],"rgb":[0.66666666666666663,0.8,0.2],"xyz":[0.387665912349229369,0.519704465367202162,0.111210771296811284],"hpluv":[101.028364552392574,147.088857703341773,77.2631626362465482],"hsluv":[101.028364552392574,92.5301726329619,77.2631626362465482]},"#aacc44":{"lch":[77.3697083481362569,78.3307208035327278,101.734312614214147],"luv":[77.3697083481362569,-15.9304072801298968,76.6937021240348],"rgb":[0.66666666666666663,0.8,0.266666666666666663],"xyz":[0.392123907593448284,0.521487663464889728,0.134689546249697922],"hpluv":[101.734312614214147,140.021584702469511,77.3697083481362569],"hsluv":[101.734312614214147,87.1104907412273377,77.3697083481362569]},"#aacc55":{"lch":[77.5118305539362495,72.5836718124644875,102.784946304826448],"luv":[77.5118305539362495,-16.0622064150904862,70.7841432727597493],"rgb":[0.66666666666666663,0.8,0.333333333333333315],"xyz":[0.398086321632810269,0.523872629080634478,0.16609159352367181],"hpluv":[102.784946304826448,130.736122666873541,77.5118305539362495],"hsluv":[102.784946304826448,80.0585735006639,77.5118305539362495]},"#aacc66":{"lch":[77.6920071630818114,65.5409770618580865,104.333567867024144],"luv":[77.6920071630818114,-16.225762577214013,63.5007425390513731],"rgb":[0.66666666666666663,0.8,0.4],"xyz":[0.405671317406318455,0.526906627390037796,0.2060392379308158],"hpluv":[104.333567867024144,119.198186871977654,77.6920071630818114],"hsluv":[104.333567867024144,71.3979720959128,77.6920071630818114]},"#aacc77":{"lch":[77.912311817127474,57.2990991241466574,106.653185897117098],"luv":[77.912311817127474,-16.4206512214041886,54.8958010589496865],"rgb":[0.66666666666666663,0.8,0.466666666666666674],"xyz":[0.41498533042652036,0.530632232598118647,0.255093039837213709],"hpluv":[106.653185897117098,105.457526508453554,77.912311817127474],"hsluv":[106.653185897117098,61.2114900666368769,77.912311817127474]},"#aacc88":{"lch":[78.1744663257663,48.0371110011961946,110.274462486898784],"luv":[78.1744663257663,-16.6457037997795574,45.0608985524173633],"rgb":[0.66666666666666663,0.8,0.533333333333333326],"xyz":[0.42612574752846416,0.53508839943889619,0.313765903240785848],"hpluv":[110.274462486898784,89.6844859178180513,78.1744663257663],"hsluv":[110.274462486898784,49.6324036967210418,78.1744663257663]},"#aacc99":{"lch":[78.4798746855988583,38.0746183254558517,116.349336294343573],"luv":[78.4798746855988583,-16.8991518201031816,34.1188397866961779],"rgb":[0.66666666666666663,0.8,0.6],"xyz":[0.43918271163753686,0.540311185082525403,0.382532580881903783],"hpluv":[116.349336294343573,72.2917022308792383,78.4798746855988583],"hsluv":[116.349336294343573,36.8338589582570535,78.4798746855988583]},"#aaccaa":{"lch":[78.8296472340984593,28.0820980315160789,127.715012949234293],"luv":[78.8296472340984593,-17.1787837008838338,22.2147163027108476],"rgb":[0.66666666666666663,0.8,0.66666666666666663],"xyz":[0.454240404602789416,0.546334262268626469,0.461836430498902384],"hpluv":[127.715012949234293,54.3703242245777503,78.8296472340984593],"hsluv":[127.715012949234293,23.0170216670413055,78.8296472340984593]},"#aaccbb":{"lch":[79.2246195207133,19.8998018903229301,151.462718702096396],"luv":[79.2246195207133,-17.4821042808439238,9.50674209115818236],"rgb":[0.66666666666666663,0.8,0.733333333333333282],"xyz":[0.47137799671012609,0.553189299111561228,0.55209441559754413],"hpluv":[151.462718702096396,39.3999249764932173,79.2246195207133],"hsluv":[151.462718702096396,25.9022649263565761,79.2246195207133]},"#aacccc":{"lch":[79.665368512397464,18.216345023755192,192.177050630059796],"luv":[79.665368512397464,-17.80648564660072,-3.84243346616347603],"rgb":[0.66666666666666663,0.8,0.8],"xyz":[0.490670372153847789,0.560906249289050085,0.653700926267814286],"hpluv":[192.177050630059796,36.9937893704297878,79.665368512397464],"hsluv":[192.177050630059796,28.9019874878943099,79.665368512397464]},"#aaccdd":{"lch":[80.1522276755556504,25.332665849504842,224.238778454296437],"luv":[80.1522276755556504,-18.1492995031005968,-17.6733382978265112],"rgb":[0.66666666666666663,0.8,0.866666666666666696],"xyz":[0.512188697704481388,0.569513579509303591,0.767030774167820284],"hpluv":[224.238778454296437,52.9363308364733882,80.1522276755556504],"hsluv":[224.238778454296437,37.9969627853472787,80.1522276755556504]},"#aaccee":{"lch":[80.6853018377357216,36.8247992939862954,239.828051209207672],"luv":[80.6853018377357216,-18.5080244281037345,-31.8358112007702587],"rgb":[0.66666666666666663,0.8,0.933333333333333348],"xyz":[0.536000877970656098,0.579038451615773608,0.892441590236343507],"hpluv":[239.828051209207672,79.4490805971393854,80.6853018377357216],"hsluv":[239.828051209207672,67.7857500876551313,80.6853018377357216]},"#aaccff":{"lch":[81.2644823279674284,49.9029399741520834,247.769045833277914],"luv":[81.2644823279674284,-18.8803249793402337,-46.1934708236816434],"rgb":[0.66666666666666663,0.8,1],"xyz":[0.562171926380487519,0.589506870979706332,1.03027577852812535],"hpluv":[247.769045833277914,111.562078640814406,81.2644823279674284],"hsluv":[247.769045833277914,99.9999999999962625,81.2644823279674284]},"#88dd00":{"lch":[80.1491214608994085,103.252993693735874,114.339076779275487],"luv":[80.1491214608994085,-42.5542610136121837,94.0761158653142218],"rgb":[0.533333333333333326,0.866666666666666696,0],"xyz":[0.360084352515062933,0.569458386582770926,0.0909436700853518548],"hpluv":[114.339076779275487,215.722602995807392,80.1491214608994085],"hsluv":[114.339076779275487,100.000000000002288,80.1491214608994085]},"#88dd11":{"lch":[80.1718911006532551,102.308936337717924,114.55620444532569],"luv":[80.1718911006532551,-42.518128048011647,93.0555062414261727],"rgb":[0.533333333333333326,0.866666666666666696,0.0666666666666666657],"xyz":[0.361096018014700038,0.569863052782625834,0.0962717750501074915],"hpluv":[114.55620444532569,214.038948901986089,80.1718911006532551],"hsluv":[114.55620444532569,98.8288322371321186,80.1718911006532551]},"#88dd22":{"lch":[80.2140714473537315,100.574216022873557,114.966813202702411],"luv":[80.2140714473537315,-42.4516967311958453,91.1757992740300125],"rgb":[0.533333333333333326,0.866666666666666696,0.133333333333333331],"xyz":[0.362971376153177094,0.570613196038016635,0.106148661246086684],"hpluv":[114.966813202702411,210.937294411552,80.2140714473537315],"hsluv":[114.966813202702411,96.6732644510524,80.2140714473537315]},"#88dd33":{"lch":[80.283440325316,97.7612202004146695,115.666709499512805],"luv":[80.283440325316,-42.3438510501166832,88.1150069699792908],"rgb":[0.533333333333333326,0.866666666666666696,0.2],"xyz":[0.3660591268856348,0.571848296330999761,0.122410815103697834],"hpluv":[115.666709499512805,205.88559104418357,80.283440325316],"hsluv":[115.666709499512805,93.1672856447162303,80.283440325316]},"#88dd44":{"lch":[80.3834168948860821,93.7943752395521,116.732715571790365],"luv":[80.3834168948860821,-42.1914333437924896,83.7691338081886698],"rgb":[0.533333333333333326,0.866666666666666696,0.266666666666666663],"xyz":[0.370517122129853715,0.573631494428687327,0.145889590056584473],"hpluv":[116.732715571790365,198.714220363605108,80.3834168948860821],"hsluv":[116.732715571790365,88.1979852499996184,80.3834168948860821]},"#88dd55":{"lch":[80.5168087418625475,88.6629430887769,118.270203219525229],"luv":[80.5168087418625475,-41.9934519908601374,78.0875628192801088],"rgb":[0.533333333333333326,0.866666666666666696,0.333333333333333315],"xyz":[0.376479536169215701,0.576016460044432077,0.17729163733055836],"hpluv":[118.270203219525229,189.352414361266369,80.5168087418625475],"hsluv":[118.270203219525229,81.7170886524359474,80.5168087418625475]},"#88dd66":{"lch":[80.6859701106092757,82.4238546620344437,120.433562333743893],"luv":[80.6859701106092757,-41.7508898851674672,71.0672569552589266],"rgb":[0.533333333333333326,0.866666666666666696,0.4],"xyz":[0.384064531942723886,0.579050458353835396,0.21723928173770235],"hpluv":[120.433562333743893,177.835721711884361,80.6859701106092757],"hsluv":[120.433562333743893,73.7344666622195604,80.6859701106092757]},"#88dd77":{"lch":[80.8928858528116734,75.2114908165065827,123.458458278308711],"luv":[80.8928858528116734,-41.4665196955592208,62.7478772165182832],"rgb":[0.533333333333333326,0.866666666666666696,0.466666666666666674],"xyz":[0.393378544962925791,0.582776063561916247,0.266293083644100259],"hpluv":[123.458458278308711,164.332036041008877,80.8928858528116734],"hsluv":[123.458458278308711,64.312379996729149,80.8928858528116734]},"#88dd88":{"lch":[81.1392211885512,67.2590471315356524,127.71501294923884],"luv":[81.1392211885512,-41.1446687958856145,53.2061617739807531],"rgb":[0.533333333333333326,0.866666666666666696,0.533333333333333326],"xyz":[0.404518962064869592,0.587232230402693789,0.324965947047672399],"hpluv":[127.71501294923884,149.199726190229825,81.1392211885512],"hsluv":[127.71501294923884,53.5585775308776633,81.1392211885512]},"#88dd99":{"lch":[81.4263538436063072,58.943488890057,133.791370377408185],"luv":[81.4263538436063072,-40.7909253788266,42.5492102073736831],"rgb":[0.533333333333333326,0.866666666666666696,0.6],"xyz":[0.417575926173942347,0.592455016046323,0.393732624688790334],"hpluv":[133.791370377408185,133.11083868071384,81.4263538436063072],"hsluv":[133.791370377408185,54.8771054313611515,81.4263538436063072]},"#88ddaa":{"lch":[81.7553965772464437,50.8758256364689956,142.591286230634154],"luv":[81.7553965772464437,-40.4117997418374131,30.906893661738728],"rgb":[0.533333333333333326,0.866666666666666696,0.66666666666666663],"xyz":[0.432633619139194847,0.598478093232424069,0.473036474305788934],"hpluv":[142.591286230634154,117.302359569381537,81.7553965772464437],"hsluv":[142.591286230634154,56.3076629138628,81.7553965772464437]},"#88ddbb":{"lch":[82.1272144034785327,44.0521153731503716,155.27715859232552],"luv":[82.1272144034785327,-40.0143654100278567,18.4238820470094566],"rgb":[0.533333333333333326,0.866666666666666696,0.733333333333333282],"xyz":[0.449771211246531522,0.605333130075358827,0.563294459404430681],"hpluv":[155.27715859232552,104.020343594656595,82.1272144034785327],"hsluv":[155.27715859232552,57.829298146967858,82.1272144034785327]},"#88ddcc":{"lch":[82.542438979776648,39.9525966793572422,172.446474622419316],"luv":[82.542438979776648,-39.6059077008678173,5.25186220437346396],"rgb":[0.533333333333333326,0.866666666666666696,0.8],"xyz":[0.469063586690253276,0.613050080252847684,0.664900970074700837],"hpluv":[172.446474622419316,96.9346789585341355,82.542438979776648],"hsluv":[172.446474622419316,59.4202271347422908,82.542438979776648]},"#88dddd":{"lch":[83.0014816422074375,40.0957403917498354,192.177050630060734],"luv":[83.0014816422074375,-39.1936046909777,-8.4575261684472629],"rgb":[0.533333333333333326,0.866666666666666696,0.866666666666666696],"xyz":[0.490581912240886764,0.621657410473101191,0.778230817974706834],"hpluv":[192.177050630060734,100.308679558078737,83.0014816422074375],"hsluv":[192.177050630060734,61.0588228331018783,83.0014816422074375]},"#88ddee":{"lch":[83.5045459788204,44.8677054153188,210.184175125347622],"luv":[83.5045459788204,-38.7842593009493157,-22.5586395802706683],"rgb":[0.533333333333333326,0.866666666666666696,0.933333333333333348],"xyz":[0.514394092507061584,0.631182282579571208,0.903641634043230058],"hpluv":[210.184175125347622,116.175045715242419,83.5045459788204],"hsluv":[210.184175125347622,62.7244468832174746,83.5045459788204]},"#88ddff":{"lch":[84.0516404633952732,53.2556266987753659,223.883407592331508],"luv":[84.0516404633952732,-38.3840933399078779,-36.9164347351224436],"rgb":[0.533333333333333326,0.866666666666666696,1],"xyz":[0.540565140916892894,0.641650701943503932,1.04147582233501179],"hpluv":[223.883407592331508,143.298172182841085,84.0516404633952732],"hsluv":[223.883407592331508,99.9999999999952,84.0516404633952732]},"#335500":{"lch":[32.2593993637483862,41.1235506245754365,113.326494368716226],"luv":[32.2593993637483862,-16.2836990313566261,37.7622504868051223],"rgb":[0.2,0.333333333333333315,0],"xyz":[0.0461356744276991415,0.0720065112172806193,0.0114678000018764836],"hpluv":[113.326494368716226,161.760937136611716,32.2593993637483862],"hsluv":[113.326494368716226,100.000000000002288,32.2593993637483862]},"#335511":{"lch":[32.3496341583576381,38.1897920123001313,115.090818108356473],"luv":[32.3496341583576381,-16.1945453684027605,34.5860797757347456],"rgb":[0.2,0.333333333333333315,0.0666666666666666657],"xyz":[0.0471473399273362598,0.0724111774171354722,0.016795904966632115],"hpluv":[115.090818108356473,149.801873896373706,32.3496341583576381],"hsluv":[115.090818108356473,90.8995446090399923,32.3496341583576381]},"#335522":{"lch":[32.5160201858231659,33.1206139518783189,118.966642902489184],"luv":[32.5160201858231659,-16.0403246718637718,28.9772851207727022],"rgb":[0.2,0.333333333333333315,0.133333333333333331],"xyz":[0.0490226980658132819,0.0731613206725262866,0.0266727911626113111],"hpluv":[118.966642902489184,129.252907346834121,32.5160201858231659],"hsluv":[118.966642902489184,74.935129302234273,32.5160201858231659]},"#335533":{"lch":[32.7875119073456176,25.8516304293262671,127.715012949238741],"luv":[32.7875119073456176,-15.8143300747053051,20.4502753072602665],"rgb":[0.2,0.333333333333333315,0.2],"xyz":[0.0521104487982710224,0.0743964209655094,0.0429349450202224578],"hpluv":[127.715012949238741,100.050394151032577,32.7875119073456176],"hsluv":[127.715012949238741,50.9434831873252207,32.7875119073456176]},"#335544":{"lch":[33.1742322541989836,18.1915220066791647,148.674883917516439],"luv":[33.1742322541989836,-15.539762262897943,9.45765624941535421],"rgb":[0.2,0.333333333333333315,0.266666666666666663],"xyz":[0.0565684440424899,0.0761796190631969794,0.0664137199731090894],"hpluv":[148.674883917516439,69.5836942134034899,33.1742322541989836],"hsluv":[148.674883917516439,54.5088767633859703,33.1742322541989836]},"#335555":{"lch":[33.6821363315134121,15.5994691341387064,192.177050630060819],"luv":[33.6821363315134121,-15.2484882598238034,-3.29044724269541522],"rgb":[0.2,0.333333333333333315,0.333333333333333315],"xyz":[0.0625308580818519,0.0785645846789418123,0.097815767247083],"hpluv":[192.177050630060819,58.7691644617976934,33.6821363315134121],"hsluv":[192.177050630060819,58.539124710901028,33.6821363315134121]},"#335566":{"lch":[34.3136156967701496,22.6822476529859181,228.692277460856218],"luv":[34.3136156967701496,-14.9726179113300351,-17.0383412183435361],"rgb":[0.2,0.333333333333333315,0.4],"xyz":[0.0701158538553600663,0.0815985829883451308,0.137763411654226953],"hpluv":[228.692277460856218,83.8800984368335,34.3136156967701496],"hsluv":[228.692277460856218,62.7386213411417089,34.3136156967701496]},"#335577":{"lch":[35.0679836745485218,34.4527831327976131,244.673076132176305],"luv":[35.0679836745485218,-14.7383029974912176,-31.1412377780608658],"rgb":[0.2,0.333333333333333315,0.466666666666666674],"xyz":[0.0794298668755619858,0.0853241881964259402,0.186817213560624862],"hpluv":[244.673076132176305,124.667382519216758,35.0679836745485218],"hsluv":[244.673076132176305,66.8604241763398335,35.0679836745485218]},"#335588":{"lch":[35.9419713942028523,47.4274747217606318,252.117898483801355],"luv":[35.9419713942028523,-14.5630489263951493,-45.1362710516793229],"rgb":[0.2,0.333333333333333315,0.533333333333333326],"xyz":[0.0905702839775058138,0.089780355037203538,0.245490076964197029],"hpluv":[252.117898483801355,167.443168522882189,35.9419713942028523],"hsluv":[252.117898483801355,70.7327730687023433,35.9419713942028523]},"#335599":{"lch":[36.9302538454711851,60.4953772811161272,256.174865065393647],"luv":[36.9302538454711851,-14.4559426241851021,-58.7427986669927833],"rgb":[0.2,0.333333333333333315,0.6],"xyz":[0.103627248086578527,0.0950031406808327,0.314256754605314936],"hpluv":[256.174865065393647,207.863972679723531,36.9302538454711851],"hsluv":[256.174865065393647,74.2581677802949258,36.9302538454711851]},"#3355aa":{"lch":[38.0259842211890557,73.2582460718320903,258.648348715518409],"luv":[38.0259842211890557,-14.4194259870406505,-71.8251402485603165],"rgb":[0.2,0.333333333333333315,0.66666666666666663],"xyz":[0.118684941051831069,0.101026217866933804,0.393560604222313537],"hpluv":[258.648348715518409,244.464262316607687,38.0259842211890557],"hsluv":[258.648348715518409,77.3978910060545,38.0259842211890557]},"#3355bb":{"lch":[39.2213032744107579,85.5750988898230815,260.277622363739169],"luv":[39.2213032744107579,-14.4514388960387397,-84.3460340729607623],"rgb":[0.2,0.333333333333333315,0.733333333333333282],"xyz":[0.135822533159167702,0.107881254709868563,0.483818589320955283],"hpluv":[260.277622363739169,276.862869377010384,39.2213032744107579],"hsluv":[260.277622363739169,80.1529964351826578,39.2213032744107579]},"#3355cc":{"lch":[40.5077939091134667,97.4185991778777,261.412040351160215],"luv":[40.5077939091134667,-14.5472816309580448,-96.326320717286734],"rgb":[0.2,0.333333333333333315,0.8],"xyz":[0.155114908602889456,0.115598204887357364,0.585425099991225495],"hpluv":[261.412040351160215,305.17054630009352,40.5077939091134667],"hsluv":[261.412040351160215,82.5478264076183734,40.5077939091134667]},"#3355dd":{"lch":[41.8768615158020552,108.813506268261335,262.235450095721887],"luv":[41.8768615158020552,-14.7009821832840935,-107.815862790406285],"rgb":[0.2,0.333333333333333315,0.866666666666666696],"xyz":[0.176633234153523,0.124205535107610898,0.698754947891231493],"hpluv":[262.235450095721887,329.72206067647727,41.8768615158020552],"hsluv":[262.235450095721887,84.6180359154754456,41.8768615158020552]},"#3355ee":{"lch":[43.3200322197542533,119.805986402952101,262.852770803428143],"luv":[43.3200322197542533,-14.9061911990543372,-118.875059797762361],"rgb":[0.2,0.333333333333333315,0.933333333333333348],"xyz":[0.200445414419697737,0.133730407214080915,0.824165763959754716],"hpluv":[262.852770803428143,350.936931775297865,43.3200322197542533],"hsluv":[262.852770803428143,90.8055999978327577,43.3200322197542533]},"#3355ff":{"lch":[44.8291710285026497,130.447860525532377,263.327743444412704],"luv":[44.8291710285026497,-15.1567128937849134,-129.564340657235334],"rgb":[0.2,0.333333333333333315,1],"xyz":[0.226616462829529131,0.144198826578013639,0.961999952251536561],"hpluv":[263.327743444412704,369.245812735261836,44.8291710285026497],"hsluv":[263.327743444412704,99.9999999999993,44.8291710285026497]},"#aadd00":{"lch":[81.9783608763648175,97.3184216433040916,105.014728605041086],"luv":[81.9783608763648175,-25.2120246284188454,93.9958988747909245],"rgb":[0.66666666666666663,0.866666666666666696,0],"xyz":[0.424325128525832707,0.602582536713324846,0.0939549564608566229],"hpluv":[105.014728605041086,227.603505169437568,81.9783608763648175],"hsluv":[105.014728605041086,100.000000000002203,81.9783608763648175]},"#aadd11":{"lch":[82.0002885274849262,96.374791846509865,105.167446282879951],"luv":[82.0002885274849262,-25.2155818179290208,93.017605521973266],"rgb":[0.66666666666666663,0.866666666666666696,0.0666666666666666657],"xyz":[0.425336794025469811,0.602987202913179754,0.0992830614256122596],"hpluv":[105.167446282879951,225.71449396257529,82.0002885274849262],"hsluv":[105.167446282879951,98.8971907906987298,82.0002885274849262]},"#aadd22":{"lch":[82.0409106120811,94.6380623122949345,105.456830413527484],"luv":[82.0409106120811,-25.2222030700150874,91.2151484706391216],"rgb":[0.66666666666666663,0.866666666666666696,0.133333333333333331],"xyz":[0.427212152163946868,0.603737346168570554,0.109159947621591452],"hpluv":[105.456830413527484,222.227322886837186,82.0409106120811],"hsluv":[105.456830413527484,96.86659260915998,82.0409106120811]},"#aadd33":{"lch":[82.1077210543303693,91.8137349028061891,105.951891130476156],"luv":[82.1077210543303693,-25.2331804702422886,88.2782448860360773],"rgb":[0.66666666666666663,0.866666666666666696,0.2],"xyz":[0.430299902896404574,0.604972446461553681,0.125422101479202602],"hpluv":[105.951891130476156,216.526835376233663,82.1077210543303693],"hsluv":[105.951891130476156,93.5615293661406469,82.1077210543303693]},"#aadd44":{"lch":[82.204019596801416,87.812555976334508,106.710442618715334],"luv":[82.204019596801416,-25.2491908313752447,84.1042409718896238],"rgb":[0.66666666666666663,0.866666666666666696,0.266666666666666663],"xyz":[0.434757898140623489,0.606755644559241247,0.148900876432089241],"hpluv":[106.710442618715334,208.386709262610594,82.204019596801416],"hsluv":[106.710442618715334,88.8720213109455415,82.204019596801416]},"#aadd55":{"lch":[82.332521082647844,82.6008871447080537,107.814707884186447],"luv":[82.332521082647844,-25.2708912490316564,78.6402480449573],"rgb":[0.66666666666666663,0.866666666666666696,0.333333333333333315],"xyz":[0.440720312179985474,0.609140610174986,0.180302923706063156],"hpluv":[107.814707884186447,197.666387369374576,82.332521082647844],"hsluv":[107.814707884186447,82.7472331150865,82.332521082647844]},"#aadd66":{"lch":[82.495508489392364,76.2000100439918526,109.390646830849064],"luv":[82.495508489392364,-25.2989483474785786,71.8777068583581666],"rgb":[0.66666666666666663,0.866666666666666696,0.4],"xyz":[0.448305307953493659,0.612174608484389315,0.22025056811320709],"hpluv":[109.390646830849064,184.308617744019813,82.495508489392364],"hsluv":[109.390646830849064,75.1895211365387723,82.495508489392364]},"#aadd77":{"lch":[82.694914273715753,68.6905071379487,111.642517734809914],"luv":[82.694914273715753,-25.3340491820501299,63.8480361711309499],"rgb":[0.66666666666666663,0.866666666666666696,0.466666666666666674],"xyz":[0.457619320973695565,0.615900213692470166,0.269304370019605],"hpluv":[111.642517734809914,168.351618208890358,82.694914273715753],"hsluv":[111.642517734809914,66.2494286969421182,82.694914273715753]},"#aadd88":{"lch":[82.9323686283524921,60.2252781448786436,114.920875432447886],"luv":[82.9323686283524921,-25.3769003534370228,54.6177357282387277],"rgb":[0.66666666666666663,0.866666666666666696,0.533333333333333326],"xyz":[0.468759738075639365,0.620356380533247709,0.327977233423177195],"hpluv":[114.920875432447886,149.967217229555729,82.9323686283524921],"hsluv":[114.920875432447886,56.0198042099318698,82.9323686283524921]},"#aadd99":{"lch":[83.2092305924335,51.0640475908324305,119.865599423026282],"luv":[83.2092305924335,-25.4282188712646082,44.2825320120006438],"rgb":[0.66666666666666663,0.866666666666666696,0.6],"xyz":[0.481816702184712065,0.625579166176876922,0.396743911064295074],"hpluv":[119.865599423026282,129.562195810811914,83.2092305924335],"hsluv":[119.865599423026282,44.6286172342680487,83.2092305924335]},"#aaddaa":{"lch":[83.526609727912188,41.6663179647472717,127.715012949236481],"luv":[83.526609727912188,-25.4887175141036408,32.9606937461220255],"rgb":[0.66666666666666663,0.866666666666666696,0.66666666666666663],"xyz":[0.496874395149964621,0.631602243362978,0.476047760681293675],"hpluv":[127.715012949236481,108.050849780995421,83.526609727912188],"hsluv":[127.715012949236481,32.2306770176982198,83.526609727912188]},"#aaddbb":{"lch":[83.8853825066367449,32.9442078204095523,140.880295511025736],"luv":[83.8853825066367449,-25.5590871805440472,20.7859060762739638],"rgb":[0.66666666666666663,0.866666666666666696,0.733333333333333282],"xyz":[0.514011987257301239,0.638457280205912747,0.566305745779935421],"hpluv":[140.880295511025736,87.605014056209555,83.8853825066367449],"hsluv":[140.880295511025736,34.4766875289621382,83.8853825066367449]},"#aaddcc":{"lch":[84.2862057978904602,26.8294893367150316,162.87488866986746],"luv":[84.2862057978904602,-25.639978502468459,7.90018990036700242],"rgb":[0.66666666666666663,0.866666666666666696,0.8],"xyz":[0.533304362701023,0.646174230383401604,0.667912256450205577],"hpluv":[162.87488866986746,73.4171355960865526,84.2862057978904602],"hsluv":[162.87488866986746,36.8333761539634708,84.2862057978904602]},"#aadddd":{"lch":[84.729528894444158,26.3242685722419552,192.177050630060421],"luv":[84.729528894444158,-25.7319846477226655,-5.55266440124834],"rgb":[0.66666666666666663,0.866666666666666696,0.866666666666666696],"xyz":[0.554822688251656593,0.654781560603655111,0.781242104350211575],"hpluv":[192.177050630060421,74.4077864529294146,84.729528894444158],"hsluv":[192.177050630060421,39.269697519551606,84.729528894444158]},"#aaddee":{"lch":[85.2156049558348769,32.3281965376105802,216.94937298104162],"luv":[85.2156049558348769,-25.8356267715816657,-19.4327733659894548],"rgb":[0.66666666666666663,0.866666666666666696,0.933333333333333348],"xyz":[0.578634868517831302,0.664306432710125128,0.906652920418734798],"hpluv":[216.94937298104162,94.7745998726022094,85.2156049558348769],"hsluv":[216.94937298104162,58.4216362813771397,85.2156049558348769]},"#aaddff":{"lch":[85.744502396509489,42.4619511969095527,232.326067904807843],"luv":[85.744502396509489,-25.9513430438233641,-33.608705623253762],"rgb":[0.66666666666666663,0.866666666666666696,1],"xyz":[0.604805916927662723,0.674774852074057852,1.04448710871051675],"hpluv":[232.326067904807843,129.682154580054771,85.744502396509489],"hsluv":[232.326067904807843,99.9999999999945572,85.744502396509489]},"#88ee00":{"lch":[85.1906878331824515,112.448241602139106,116.535675589642423],"luv":[85.1906878331824515,-50.2368100475369914,100.602534538950536],"rgb":[0.533333333333333326,0.933333333333333348,0],"xyz":[0.40726312885557775,0.663815939263801891,0.106669928865523039],"hpluv":[116.535675589642423,329.03324103323672,85.1906878331824515],"hsluv":[116.535675589642423,100.000000000002416,85.1906878331824515]},"#88ee11":{"lch":[85.2112458075113182,111.594873497969587,116.730132104203335],"luv":[85.2112458075113182,-50.1941202672300193,99.669283541253],"rgb":[0.533333333333333326,0.933333333333333348,0.0666666666666666657],"xyz":[0.408274794355214854,0.664220605463656799,0.111998033830278676],"hpluv":[116.730132104203335,327.047318494663614,85.2112458075113182],"hsluv":[116.730132104203335,98.9939616796445,85.2112458075113182]},"#88ee22":{"lch":[85.2493327369145,110.025246585506409,117.096539077460619],"luv":[85.2493327369145,-50.115524286233132,97.9489107224652429],"rgb":[0.533333333333333326,0.933333333333333348,0.133333333333333331],"xyz":[0.410150152493691911,0.6649707487190476,0.121874920026257869],"hpluv":[117.096539077460619,323.384561507736407,85.2493327369145],"hsluv":[117.096539077460619,97.140453749143191,85.2493327369145]},"#88ee33":{"lch":[85.3119799721786,107.475578977757436,117.717135468026783],"luv":[85.3119799721786,-49.9876247553973769,95.1432469906181097],"rgb":[0.533333333333333326,0.933333333333333348,0.2],"xyz":[0.413237903226149617,0.666205849012030726,0.138137073883869],"hpluv":[117.717135468026783,317.406918528502,85.3119799721786],"hsluv":[117.717135468026783,94.120593299189423,85.3119799721786]},"#88ee44":{"lch":[85.4022915890189864,103.870397610997969,118.652974854946393],"luv":[85.4022915890189864,-49.8062112723248518,91.1504296126099],"rgb":[0.533333333333333326,0.933333333333333348,0.266666666666666663],"xyz":[0.417695898470368532,0.667989047109718292,0.161615848836755643],"hpluv":[118.652974854946393,308.894438519259097,85.4022915890189864],"hsluv":[118.652974854946393,89.8292917088674869,85.4022915890189864]},"#88ee55":{"lch":[85.5228293578601466,99.1885702075232,119.98340282305692],"luv":[85.5228293578601466,-49.5693999595221584,85.9141842041562],"rgb":[0.533333333333333326,0.933333333333333348,0.333333333333333315],"xyz":[0.423658312509730517,0.670374012725463,0.193017896110729559],"hpluv":[119.98340282305692,297.731707367046795,85.5228293578601466],"hsluv":[119.98340282305692,84.2131356884780473,85.5228293578601466]},"#88ee66":{"lch":[85.6757572108422,93.4644574192068234,121.818598205465591],"luv":[85.6757572108422,-49.2774194314266083,79.4187681524083189],"rgb":[0.533333333333333326,0.933333333333333348,0.4],"xyz":[0.431243308283238702,0.673408011034866361,0.232965540517873521],"hpluv":[121.818598205465591,283.912655540997662,85.6757572108422],"hsluv":[121.818598205465591,77.2651144072775082,85.6757572108422]},"#88ee77":{"lch":[85.8629182835971676,86.7937408847250822,124.317503927832064],"luv":[85.8629182835971676,-48.9324360738715,71.6852157466327071],"rgb":[0.533333333333333326,0.933333333333333348,0.466666666666666674],"xyz":[0.440557321303440608,0.677133616242947212,0.282019342424271402],"hpluv":[124.317503927832064,267.563092583833793,85.8629182835971676],"hsluv":[124.317503927832064,69.0205357789205749,85.8629182835971676]},"#88ee88":{"lch":[86.0858807036169793,79.3454652904755164,127.71501294923921],"luv":[86.0858807036169793,-48.5383458294846,62.7672832477191918],"rgb":[0.533333333333333326,0.933333333333333348,0.533333333333333326],"xyz":[0.451697738405384408,0.681589783083724754,0.340692205827843597],"hpluv":[127.71501294923921,248.989760930573482,86.0858807036169793],"hsluv":[127.71501294923921,59.5524101967812,86.0858807036169793]},"#88ee99":{"lch":[86.3459670558122525,71.3853284581525429,132.362204285947513],"luv":[86.3459670558122525,-48.1005130697284287,52.7466184841000825],"rgb":[0.533333333333333326,0.933333333333333348,0.6],"xyz":[0.464754702514457163,0.686812568727354,0.409458883468961532],"hpluv":[132.362204285947513,228.778132650246619,86.3459670558122525],"hsluv":[132.362204285947513,60.5562348819982645,86.3459670558122525]},"#88eeaa":{"lch":[86.6442747471204768,63.319361027400987,138.776693085718904],"luv":[86.6442747471204768,-47.625461320552418,41.7271723811105204],"rgb":[0.533333333333333326,0.933333333333333348,0.66666666666666663],"xyz":[0.479812395479709664,0.692835645913455,0.488762733085960077],"hpluv":[138.776693085718904,207.981038552319745,86.6442747471204768],"hsluv":[138.776693085718904,61.6537348625427342,86.6442747471204768]},"#88eebb":{"lch":[86.9816911545789679,55.7684583245382299,147.664608842749317],"luv":[86.9816911545789679,-47.1205330954276,29.8291184029711189],"rgb":[0.533333333333333326,0.933333333333333348,0.733333333333333282],"xyz":[0.496949987587046338,0.699690682756389792,0.579020718184601879],"hpluv":[147.664608842749317,188.458500832318975,86.9816911545789679],"hsluv":[147.664608842749317,62.830800627143077,86.9816911545789679]},"#88eecc":{"lch":[87.3589058048410294,49.6608679924305463,159.75715297219557],"luv":[87.3589058048410294,-46.5935415809549696,17.182656741768227],"rgb":[0.533333333333333326,0.933333333333333348,0.8],"xyz":[0.516242363030768092,0.70740763293387865,0.680627228854872],"hpluv":[159.75715297219557,173.371642714007834,87.3589058048410294],"hsluv":[159.75715297219557,64.0722902507549179,87.3589058048410294]},"#88eedd":{"lch":[87.7764209496729,46.2191498548509543,175.132102674355139],"luv":[87.7764209496729,-46.0524373199716166,3.92209512827700335],"rgb":[0.533333333333333326,0.933333333333333348,0.866666666666666696],"xyz":[0.53776068858140158,0.716014963154132156,0.793957076754878],"hpluv":[175.132102674355139,167.447502067072264,87.7764209496729],"hsluv":[175.132102674355139,65.3626972838926434,87.7764209496729]},"#88eeee":{"lch":[88.2345613859691866,46.5524177333431339,192.177050630060933],"luv":[88.2345613859691866,-45.5050097647113958,-9.8194543195231],"rgb":[0.533333333333333326,0.933333333333333348,0.933333333333333348],"xyz":[0.56157286884757629,0.725539835260602173,0.919367892823401256],"hpluv":[192.177050630060933,175.887543813927181,88.2345613859691866],"hsluv":[192.177050630060933,66.6867488369664443,88.2345613859691866]},"#88eeff":{"lch":[88.7334840469836763,50.9233073192915242,208.009521596121829],"luv":[88.7334840469836763,-44.9586380478967271,-23.9145163700465169],"rgb":[0.533333333333333326,0.933333333333333348,1],"xyz":[0.587743917257407711,0.736008254624534897,1.05720208111518299],"hpluv":[208.009521596121829,201.749007974481685,88.7334840469836763],"hsluv":[208.009521596121829,99.9999999999925109,88.7334840469836763]},"#336600":{"lch":[38.2101034680229574,51.4017776291135888,118.130952889189317],"luv":[38.2101034680229574,-24.2353400261634,45.3298029694491902],"rgb":[0.2,0.4,0],"xyz":[0.0611637321335456105,0.10206262662897396,0.0164771525704918292],"hpluv":[118.130952889189317,170.702252266418213,38.2101034680229574],"hsluv":[118.130952889189317,100.000000000002288,38.2101034680229574]},"#336611":{"lch":[38.2816545292110959,48.9828222693822468,119.470954908934345],"luv":[38.2816545292110959,-24.0986808399199681,42.6447002480913682],"rgb":[0.2,0.4,0.0666666666666666657],"xyz":[0.0621753976331827357,0.102467292828828813,0.021805257535247459],"hpluv":[119.470954908934345,162.365005406289157,38.2816545292110959],"hsluv":[119.470954908934345,93.5286374368429,38.2816545292110959]},"#336622":{"lch":[38.4137944304132617,44.7307250918699282,122.230818066602779],"luv":[38.4137944304132617,-23.8562978467226365,37.8380076152656173],"rgb":[0.2,0.4,0.133333333333333331],"xyz":[0.0640507557716597509,0.103217436084219627,0.0316821437312266585],"hpluv":[122.230818066602779,147.760399550800031,38.4137944304132617],"hsluv":[122.230818066602779,81.994947572555219,38.4137944304132617]},"#336633":{"lch":[38.6299730126545171,38.3921679396875817,127.715012949239437],"luv":[38.6299730126545171,-23.4858075099586969,30.3706339201924216],"rgb":[0.2,0.4,0.2],"xyz":[0.0671385065041174844,0.10445253637720274,0.0479442975888378],"hpluv":[127.715012949239437,126.112332565807833,38.6299730126545171],"hsluv":[127.715012949239437,64.2136550115152,38.6299730126545171]},"#336644":{"lch":[38.9390987599147635,30.7877900918170191,138.353415806708398],"luv":[38.9390987599147635,-23.0064236741332095,20.4595329483365589],"rgb":[0.2,0.4,0.266666666666666663],"xyz":[0.0715965017483363719,0.10623573447489032,0.0714230725417244472],"hpluv":[138.353415806708398,100.330262339301328,38.9390987599147635],"hsluv":[138.353415806708398,66.1490613915476899,38.9390987599147635]},"#336655":{"lch":[39.3471830293532108,24.0314899024670439,159.111050143656939],"luv":[39.3471830293532108,-22.4519783641565418,8.56861566811244479],"rgb":[0.2,0.4,0.333333333333333315],"xyz":[0.077558915787698357,0.108620700090635153,0.102825119815698349],"hpluv":[159.111050143656939,77.5008343503898089,39.3471830293532108],"hsluv":[159.111050143656939,68.4324421599544337,39.3471830293532108]},"#336666":{"lch":[39.8577781510875653,22.3660784387423632,192.177050630061],"luv":[39.8577781510875653,-21.8628519700770774,-4.71775036033837925],"rgb":[0.2,0.4,0.4],"xyz":[0.0851439115612065422,0.111654698400038471,0.142772764222842297],"hpluv":[192.177050630061,71.205917149352544,39.8577781510875653],"hsluv":[192.177050630061,70.9271962998489727,39.8577781510875653]},"#336677":{"lch":[40.4722660639059,28.403364995264031,221.483563289625266],"luv":[40.4722660639059,-21.2782609928981294,-18.8145356618838697],"rgb":[0.2,0.4,0.466666666666666674],"xyz":[0.0944579245814084478,0.115380303608119281,0.191826566129240206],"hpluv":[221.483563289625266,89.0536244466218534,40.4722660639059],"hsluv":[221.483563289625266,73.4989606489913,40.4722660639059]},"#336688":{"lch":[41.1901179582142731,39.1584560294521253,238.034471274574031],"luv":[41.1901179582142731,-20.7308371309926542,-33.2207325394668516],"rgb":[0.2,0.4,0.533333333333333326],"xyz":[0.105598341683352276,0.119836470448896878,0.250499429532812401],"hpluv":[238.034471274574031,120.634589470818128,41.1901179582142731],"hsluv":[238.034471274574031,76.0346320246428746,41.1901179582142731]},"#336699":{"lch":[42.0091634944821948,51.6886413393569626,246.942440261812],"luv":[42.0091634944821948,-20.2441498032976277,-47.5593318103852951],"rgb":[0.2,0.4,0.6],"xyz":[0.118655305792425,0.12505925609252605,0.31926610717393028],"hpluv":[246.942440261812,156.131455895945,42.0091634944821948],"hsluv":[246.942440261812,78.4511744564818514,42.0091634944821948]},"#3366aa":{"lch":[42.9258754740709847,64.6951641030825,252.148217293940775],"luv":[42.9258754740709847,-19.832670948043944,-61.5802681172418218],"rgb":[0.2,0.4,0.66666666666666663],"xyz":[0.133712998757677531,0.131082333278627144,0.398569956790928881],"hpluv":[252.148217293940775,191.245834212653307,42.9258754740709847],"hsluv":[252.148217293940775,80.6959595489171,42.9258754740709847]},"#3366bb":{"lch":[43.9356615222631106,77.6311657782158164,255.449757662516049],"luv":[43.9356615222631106,-19.5031901130623,-75.1413566253536374],"rgb":[0.2,0.4,0.733333333333333282],"xyz":[0.150850590865014178,0.137937370121561903,0.488827941889570627],"hpluv":[255.449757662516049,224.211696450950683,43.9356615222631106],"hsluv":[255.449757662516049,82.7420790911240402,43.9356615222631106]},"#3366cc":{"lch":[45.0331492258045287,90.2591849706621332,257.681278432902445],"luv":[45.0331492258045287,-19.2567634880452658,-88.1810497302775786],"rgb":[0.2,0.4,0.8],"xyz":[0.170142966308735932,0.145654320299050705,0.590434452559840839],"hpluv":[257.681278432902445,254.330482568364204,45.0331492258045287],"hsluv":[257.681278432902445,84.5818015821218694,45.0331492258045287]},"#3366dd":{"lch":[46.2124513047425367,102.485732700579547,259.264483160570819],"luv":[46.2124513047425367,-19.0906003056708045,-100.691977769551045],"rgb":[0.2,0.4,0.866666666666666696],"xyz":[0.191661291859369476,0.154261650519304239,0.703764300459846837],"hpluv":[259.264483160570819,281.412724566330553,46.2124513047425367],"hsluv":[259.264483160570819,86.2202337385041488,46.2124513047425367]},"#3366ee":{"lch":[47.467400384741687,114.289765210034219,260.43068521754094],"luv":[47.467400384741687,-18.99960653492559,-112.699447129445844],"rgb":[0.2,0.4,0.933333333333333348],"xyz":[0.215473472125544213,0.163786522625774256,0.82917511652837006],"hpluv":[260.43068521754094,305.528142270574733,47.467400384741687],"hsluv":[260.43068521754094,89.4216395109538524,47.467400384741687]},"#3366ff":{"lch":[48.7917470574018068,125.686826272807437,261.315666926990161],"luv":[48.7917470574018068,-18.9775194272026404,-124.245853270525785],"rgb":[0.2,0.4,1],"xyz":[0.241644520535375606,0.17425494198970698,0.967009304820151905],"hpluv":[261.315666926990161,326.875761207371056,48.7917470574018068],"hsluv":[261.315666926990161,99.9999999999992184,48.7917470574018068]},"#aaee00":{"lch":[86.8465682321076713,106.130019137569278,108.773889799394041],"luv":[86.8465682321076713,-34.1562767274136,100.483479847491182],"rgb":[0.66666666666666663,0.933333333333333348,0],"xyz":[0.471503904866347523,0.696940089394355811,0.109681215241027807],"hpluv":[108.773889799394041,354.560190530248747,86.8465682321076713],"hsluv":[108.773889799394041,100.000000000002302,86.8465682321076713]},"#aaee11":{"lch":[86.8664697406872364,105.275413073012288,108.926122010215039],"luv":[86.8664697406872364,-34.1459453835818323,99.5839696515197801],"rgb":[0.66666666666666663,0.933333333333333348,0.0666666666666666657],"xyz":[0.472515570365984627,0.697344755594210719,0.115009320205783444],"hpluv":[108.926122010215039,352.296735211520456,86.8664697406872364],"hsluv":[108.926122010215039,99.0448212343627,86.8664697406872364]},"#aaee22":{"lch":[86.9033414770782286,103.701584155213482,109.21343759479339],"luv":[86.9033414770782286,-34.1269596340241961,97.9253245204656224],"rgb":[0.66666666666666663,0.933333333333333348,0.133333333333333331],"xyz":[0.474390928504461684,0.69809489884960152,0.124886206401762637],"hpluv":[109.21343759479339,348.114419217609168,86.9033414770782286],"hsluv":[109.21343759479339,97.2844700630890742,86.9033414770782286]},"#aaee33":{"lch":[86.9639927659971,101.139559122436452,109.701502859778287],"luv":[86.9639927659971,-34.0961634116812462,95.2190215245081504],"rgb":[0.66666666666666663,0.933333333333333348,0.2],"xyz":[0.47747867923691939,0.699329999142584646,0.141148360259373773],"hpluv":[109.701502859778287,341.266668172598315,86.9639927659971],"hsluv":[109.701502859778287,94.4148698146506,86.9639927659971]},"#aaee44":{"lch":[87.0514332975086091,97.5044422856038864,110.440992284795044],"luv":[87.0514332975086091,-34.052698770047833,91.3648180204122298],"rgb":[0.66666666666666663,0.933333333333333348,0.266666666666666663],"xyz":[0.481936674481138305,0.701113197240272212,0.164627135212260411],"hpluv":[110.440992284795044,331.464832239423686,87.0514332975086091],"hsluv":[110.440992284795044,90.3338544995677353,87.0514332975086091]},"#aaee55":{"lch":[87.1681505263978,92.7597711807761556,111.499860176168639],"luv":[87.1681505263978,-33.9963593100021271,86.3054036730909644],"rgb":[0.66666666666666663,0.933333333333333348,0.333333333333333315],"xyz":[0.48789908852050029,0.703498162856017,0.196029182486234327],"hpluv":[111.499860176168639,318.513853400728863,87.1681505263978],"hsluv":[111.499860176168639,84.9871568734489813,87.1681505263978]},"#aaee66":{"lch":[87.3162499846890086,86.9168013961255923,112.975973936880195],"luv":[87.3162499846890086,-33.9275471197994563,80.0215715377255492],"rgb":[0.66666666666666663,0.933333333333333348,0.4],"xyz":[0.495484084294008476,0.70653216116542028,0.235976826893378289],"hpluv":[112.975973936880195,302.308385752370668,87.3162499846890086],"hsluv":[112.975973936880195,78.3634586897027106,87.3162499846890086]},"#aaee77":{"lch":[87.4975302296396,80.0378594698754853,115.017197938190947],"luv":[87.4975302296396,-33.8472328521792534,72.5287789554594298],"rgb":[0.66666666666666663,0.933333333333333348,0.466666666666666674],"xyz":[0.504798097314210326,0.710257766373501132,0.285030628799776198],"hpluv":[115.017197938190947,282.845349503141222,87.4975302296396],"hsluv":[115.017197938190947,70.4907283307095,87.4975302296396]},"#aaee88":{"lch":[87.7135274362348838,72.2451165326571072,117.856267937731204],"luv":[87.7135274362348838,-33.7569011423620324,63.8735351149597861],"rgb":[0.66666666666666663,0.933333333333333348,0.533333333333333326],"xyz":[0.515938514416154237,0.714713933214278674,0.343703492203348393],"hpluv":[117.856267937731204,260.261444274219798,87.7135274362348838],"hsluv":[117.856267937731204,61.4321883079204412,87.7135274362348838]},"#aaee99":{"lch":[87.9655440812905312,63.7405265694191954,121.874104620002555],"luv":[87.9655440812905312,-33.6584769753751445,54.1291202131068871],"rgb":[0.66666666666666663,0.933333333333333348,0.6],"xyz":[0.528995478525226881,0.719936718857907887,0.412470169844466272],"hpluv":[121.874104620002555,234.922523447188695,87.9655440812905312],"hsluv":[121.874104620002555,51.2814060811362182,87.9655440812905312]},"#aaeeaa":{"lch":[88.2546687059401,54.8509913255605497,127.715012949237604],"luv":[88.2546687059401,-33.5542349686064441,43.3906045713616138],"rgb":[0.66666666666666663,0.933333333333333348,0.66666666666666663],"xyz":[0.544053171490479492,0.725959796044009,0.491774019461464873],"hpluv":[127.715012949237604,207.631017102058365,88.2546687059401],"hsluv":[127.715012949237604,42.8122115000723795,88.2546687059401]},"#aaeebb":{"lch":[88.5817905154621457,46.1299748711590425,136.47329364537066],"luv":[88.5817905154621457,-33.4466969972147226,31.7693726974624511],"rgb":[0.66666666666666663,0.933333333333333348,0.733333333333333282],"xyz":[0.561190763597816056,0.732814832886943712,0.582032004560106619],"hpluv":[136.47329364537066,180.106084736741337,88.5817905154621457],"hsluv":[136.47329364537066,42.5306558804052,88.5817905154621457]},"#aaeecc":{"lch":[88.947610994722524,38.5659339652702471,149.820563383504265],"luv":[88.947610994722524,-33.3385252257337896,19.3874701388989088],"rgb":[0.66666666666666663,0.933333333333333348,0.8],"xyz":[0.58048313904153781,0.740531783064432569,0.683638515230376775],"hpluv":[149.820563383504265,156.025185046421541,88.947610994722524],"hsluv":[149.820563383504265,43.7743007306855176,88.947610994722524]},"#aaeedd":{"lch":[89.3526538659385636,33.8378115459028308,169.14561851222],"luv":[89.3526538659385636,-33.2324178366612202,6.37211856022751721],"rgb":[0.66666666666666663,0.933333333333333348,0.866666666666666696],"xyz":[0.602001464592171409,0.749139113284686076,0.796968363130382773],"hpluv":[169.14561851222,142.575756051086472,89.3526538659385636],"hsluv":[169.14561851222,45.7128350403065866,89.3526538659385636]},"#aaeeee":{"lch":[89.797274219494,33.893604395025335,192.177050630060734],"luv":[89.797274219494,-33.1310138990311174,-7.14928925898844092],"rgb":[0.66666666666666663,0.933333333333333348,0.933333333333333348],"xyz":[0.625813644858346119,0.758663985391156093,0.922379179198906],"hpluv":[192.177050630060734,149.574468983420843,89.797274219494],"hsluv":[192.177050630060734,47.7079369778472326,89.797274219494]},"#aaeeff":{"lch":[90.2816673401601406,39.1749897548907384,212.508271358442045],"luv":[90.2816673401601406,-33.0368122621910558,-21.0534761464356919],"rgb":[0.66666666666666663,0.933333333333333348,1],"xyz":[0.65198469326817754,0.769132404755088817,1.06021336749068773],"hpluv":[212.508271358442045,182.211685385120148,90.2816673401601406],"hsluv":[212.508271358442045,99.9999999999910898,90.2816673401601406]},"#88ff00":{"lch":[90.2073775103659727,121.530167505498795,118.25137340908573],"luv":[90.2073775103659727,-57.5251845782800331,107.053420090856534],"rgb":[0.533333333333333326,1,0],"xyz":[0.459115501285251582,0.767520684123151,0.12395405300874715],"hpluv":[118.25137340908573,560.639311859311,90.2073775103659727],"hsluv":[118.25137340908573,100.00000000000226,90.2073775103659727]},"#88ff11":{"lch":[90.2260397586701828,120.75410845816802,118.424372307304225],"luv":[90.2260397586701828,-57.4787561773275684,106.196738640291272],"rgb":[0.533333333333333326,1,0.0666666666666666657],"xyz":[0.460127166784888686,0.767925350323005906,0.129282157973502787],"hpluv":[118.424372307304225,558.207032378019221,90.2260397586701828],"hsluv":[118.424372307304225,99.9999999999909335,90.2260397586701828]},"#88ff22":{"lch":[90.260617257984066,119.32542599803422,118.749452026898098],"luv":[90.260617257984066,-57.393189210317729,104.616342518179295],"rgb":[0.533333333333333326,1,0.133333333333333331],"xyz":[0.462002524923365743,0.768675493578396707,0.139159044169481966],"hpluv":[118.749452026898098,553.71568515647823,90.260617257984066],"hsluv":[118.749452026898098,99.9999999999907772,90.260617257984066]},"#88ff33":{"lch":[90.3174996442954665,117.001153508636776,119.297411154505227],"luv":[90.3174996442954665,-57.253701051451273,102.035697862378711],"rgb":[0.533333333333333326,1,0.2],"xyz":[0.465090275655823449,0.769910593871379834,0.155421198027093116],"hpluv":[119.297411154505227,546.370637823869743,90.3174996442954665],"hsluv":[119.297411154505227,99.9999999999907914,90.3174996442954665]},"#88ff44":{"lch":[90.399517385893148,113.706822542904789,120.117552028257023],"luv":[90.399517385893148,-57.0553255590242614,98.3561452994036074],"rgb":[0.533333333333333326,1,0.266666666666666663],"xyz":[0.469548270900042364,0.7716937919690674,0.178899972979979754],"hpluv":[120.117552028257023,535.877566613280692,90.399517385893148],"hsluv":[120.117552028257023,99.9999999999907914,90.399517385893148]},"#88ff55":{"lch":[90.5090160073098389,109.413894688598035,121.271093020798972],"luv":[90.5090160073098389,-56.7954345723420317,93.518334901057969],"rgb":[0.533333333333333326,1,0.333333333333333315],"xyz":[0.475510684939404349,0.774078757584812149,0.21030202025395367],"hpluv":[121.271093020798972,522.05545338002139,90.5090160073098389],"hsluv":[121.271093020798972,99.9999999999906493,90.5090160073098389]},"#88ff66":{"lch":[90.6479884721694,104.139810410505333,122.839359042112989],"luv":[90.6479884721694,-56.4735097148607039,87.4976731851854908],"rgb":[0.533333333333333326,1,0.4],"xyz":[0.483095680712912534,0.777112755894215468,0.250249664661097659],"hpluv":[122.839359042112989,504.839052288882328,90.6479884721694],"hsluv":[122.839359042112989,99.9999999999905498,90.6479884721694]},"#88ff77":{"lch":[90.8181461195308515,97.9515013566305441,124.934550835890477],"luv":[90.8181461195308515,-56.0909812525741813,80.3012978733306],"rgb":[0.533333333333333326,1,0.466666666666666674],"xyz":[0.49240969373311444,0.780838361102296319,0.299303466567495513],"hpluv":[124.934550835890477,484.301391198376791,90.8181461195308515],"hsluv":[124.934550835890477,99.9999999999904,90.8181461195308515]},"#88ff88":{"lch":[91.0209609702079803,90.9725812653771,127.715012949239437],"luv":[91.0209609702079803,-55.6510519447396348,71.9650676337452779],"rgb":[0.533333333333333326,1,0.533333333333333326],"xyz":[0.503550110835058295,0.785294527943073861,0.357976329971067708],"hpluv":[127.715012949239437,460.703998076760797,91.0209609702079803],"hsluv":[127.715012949239437,99.9999999999902087,91.0209609702079803]},"#88ff99":{"lch":[91.2576929391802167,83.3964386150156116,131.406800448379954],"luv":[91.2576929391802167,-55.158478848678719,62.5500454417735057],"rgb":[0.533333333333333326,1,0.6],"xyz":[0.51660707494413094,0.790517313586703074,0.426743007612185643],"hpluv":[131.406800448379954,434.595507650037121,91.2576929391802167],"hsluv":[131.406800448379954,99.9999999999900524,91.2576929391802167]},"#88ffaa":{"lch":[91.5294084976530229,75.5094657025462226,136.33125230150921],"luv":[91.5294084976530229,-54.6193101996060264,52.1383770748881048],"rgb":[0.533333333333333326,1,0.66666666666666663],"xyz":[0.531664767909383551,0.796540390772804141,0.506046857229184188],"hpluv":[136.33125230150921,406.99849880976177,91.5294084976530229],"hsluv":[136.33125230150921,99.9999999999897824,91.5294084976530229]},"#88ffbb":{"lch":[91.8369943060547911,67.7301008509963225,142.928263991524119],"luv":[91.8369943060547911,-54.0405872892441,40.8286846067776423],"rgb":[0.533333333333333326,1,0.733333333333333282],"xyz":[0.548802360016720114,0.8033954276157389,0.596304842327826],"hpluv":[142.928263991524119,379.751065707187763,91.8369943060547911],"hsluv":[142.928263991524119,99.9999999999894413,91.8369943060547911]},"#88ffcc":{"lch":[92.1811678623774498,60.665065650155249,151.731515164157571],"luv":[92.1811678623774498,-53.4300279465168941,28.7312078404662543],"rgb":[0.533333333333333326,1,0.8],"xyz":[0.568094735460441869,0.811112377793227757,0.697911352998096146],"hpluv":[151.731515164157571,356.080713038752435,92.1811678623774498],"hsluv":[151.731515164157571,99.9999999999893134,92.1811678623774498]},"#88ffdd":{"lch":[92.5624864174544371,55.1561732277505712,163.177123134509742],"luv":[92.5624864174544371,-52.7957106082625316,15.9629692256241533],"rgb":[0.533333333333333326,1,0.866666666666666696],"xyz":[0.589613061011075468,0.819719708013481263,0.811241200898102144],"hpluv":[163.177123134509742,341.369587308077,92.5624864174544371],"hsluv":[163.177123134509742,99.9999999999887,92.5624864174544371]},"#88ffee":{"lch":[92.9813549493531752,52.2127257219241301,177.098205352907513],"luv":[92.9813549493531752,-52.1457771028834927,2.64322864112605771],"rgb":[0.533333333333333326,1,0.933333333333333348],"xyz":[0.613425241277250177,0.82924458011995128,0.936652016966625367],"hpluv":[177.098205352907513,343.566349205584061,92.9813549493531752],"hsluv":[177.098205352907513,99.9999999999882,92.9813549493531752]},"#88ffff":{"lch":[93.4380337051328524,52.6732939730945162,192.177050630061075],"luv":[93.4380337051328524,-51.4881691068088543,-11.1105508416409933],"rgb":[0.533333333333333326,1,1],"xyz":[0.639596289687081598,0.839712999483884,1.07448620525840721],"hpluv":[192.177050630061075,372.044084252862206,93.4380337051328524],"hsluv":[192.177050630061075,99.9999999999874802,93.4380337051328524]},"#337700":{"lch":[44.0848685544221084,61.4877933810524127,120.932619831412623],"luv":[44.0848685544221084,-31.6065510805688668,52.7425318283298168],"rgb":[0.2,0.466666666666666674,0],"xyz":[0.0796174701869632462,0.138970102735809731,0.0226283985882975332],"hpluv":[120.932619831412623,176.985906279588789,44.0848685544221084],"hsluv":[120.932619831412623,100.000000000002217,44.0848685544221084]},"#337711":{"lch":[44.1431322932100159,59.4532082216814146,121.943929432148849],"luv":[44.1431322932100159,-31.4560442613915434,50.449987584497805],"rgb":[0.2,0.466666666666666674,0.0666666666666666657],"xyz":[0.0806291356866003645,0.139374768935664584,0.0279565035530531664],"hpluv":[121.943929432148849,170.903703930819205,44.1431322932100159],"hsluv":[121.943929432148849,95.223210781581642,44.1431322932100159]},"#337722":{"lch":[44.2508401312458517,55.8308883755444327,123.957293362486936],"luv":[44.2508401312458517,-31.1857277137109214,46.3091619851707605],"rgb":[0.2,0.466666666666666674,0.133333333333333331],"xyz":[0.0825044938250774,0.140124912191055412,0.037833389749032359],"hpluv":[123.957293362486936,160.100373243526178,44.2508401312458517],"hsluv":[123.957293362486936,86.6219708852072,44.2508401312458517]},"#337733":{"lch":[44.4273451577554681,50.2894934834324943,127.715012949239792],"luv":[44.4273451577554681,-30.7638100974309978,39.782171171385329],"rgb":[0.2,0.466666666666666674,0.2],"xyz":[0.0855922445575351271,0.141360012484038511,0.0540955436066435091],"hpluv":[127.715012949239792,143.636966976451419,44.4273451577554681],"hsluv":[127.715012949239792,73.1368174441878409,44.4273451577554681]},"#337744":{"lch":[44.6803728315295743,43.2379901525315873,134.305487238163835],"luv":[44.6803728315295743,-30.2010367205865329,30.9422231494797764],"rgb":[0.2,0.466666666666666674,0.266666666666666663],"xyz":[0.090050239801754,0.143143210581726105,0.0775743185595301477],"hpluv":[134.305487238163835,122.797079037201513,44.6803728315295743],"hsluv":[134.305487238163835,74.2422920898123664,44.6803728315295743]},"#337755":{"lch":[45.0155248592042057,35.7001949681147,145.791078733963843],"luv":[45.0155248592042057,-29.5238129364495734,20.071083439987369],"rgb":[0.2,0.466666666666666674,0.333333333333333315],"xyz":[0.096012653841116,0.145528176197470938,0.108976365833504049],"hpluv":[145.791078733963843,100.634662922797503,45.0155248592042057],"hsluv":[145.791078733963843,75.5860232244433377,45.0155248592042057]},"#337766":{"lch":[45.436632811343884,29.7520619336037022,165.22669317203713],"luv":[45.436632811343884,-28.7685269489331041,7.58663604567268468],"rgb":[0.2,0.466666666666666674,0.4],"xyz":[0.103597649614624171,0.148562174506874228,0.148924010240648025],"hpluv":[165.22669317203713,83.0902864995861847,45.436632811343884],"hsluv":[165.22669317203713,77.1054195363406194,45.436632811343884]},"#337777":{"lch":[45.9459628200325696,28.6191137838588361,192.177050630061018],"luv":[45.9459628200325696,-27.9751968985082726,-6.03672363647301413],"rgb":[0.2,0.466666666666666674,0.466666666666666674],"xyz":[0.11291166263482609,0.152287779714955052,0.197977812147045934],"hpluv":[192.177050630061018,79.0402219352416324,45.9459628200325696],"hsluv":[192.177050630061018,78.7308353184449743,45.9459628200325696]},"#337788":{"lch":[46.5443737533918309,33.948531272854666,216.805091226728479],"luv":[46.5443737533918309,-27.1818468531358306,-20.3383867904182836],"rgb":[0.2,0.466666666666666674,0.533333333333333326],"xyz":[0.124052079736769919,0.156743946555732649,0.256650675550618101],"hpluv":[216.805091226728479,92.5535593562344587,46.5443737533918309],"hsluv":[216.805091226728479,80.3955897349876381,46.5443737533918309]},"#337799":{"lch":[47.2314677007312085,43.7891028043947799,232.889035089769209],"luv":[47.2314677007312085,-26.4206199262946413,-34.9204290798973105],"rgb":[0.2,0.466666666666666674,0.6],"xyz":[0.137109043845842632,0.161966732199361807,0.325417353191736],"hpluv":[232.889035089769209,117.645124104106614,47.2314677007312085],"hsluv":[232.889035089769209,82.0429045074046144,47.2314677007312085]},"#3377aa":{"lch":[48.0057466772197472,55.756363166772573,242.534195481556935],"luv":[48.0057466772197472,-25.7159019754829359,-49.471854818395343],"rgb":[0.2,0.466666666666666674,0.66666666666666663],"xyz":[0.15216673681109516,0.167989809385462902,0.404721202808734581],"hpluv":[242.534195481556935,147.380673097935755,48.0057466772197472],"hsluv":[242.534195481556935,83.6292827510673078,48.0057466772197472]},"#3377bb":{"lch":[48.8647777502949623,68.5281348418467076,248.528316013511841],"luv":[48.8647777502949623,-25.0841318464231762,-63.7721851155626],"rgb":[0.2,0.466666666666666674,0.733333333333333282],"xyz":[0.169304328918431835,0.17484484622839766,0.494979187907376328],"hpluv":[248.528316013511841,177.955866809146045,48.8647777502949623],"hsluv":[248.528316013511841,85.1249045257873,48.8647777502949623]},"#3377cc":{"lch":[49.8053630390326845,81.4640551302433096,252.471981644912631],"luv":[49.8053630390326845,-24.5347040681135518,-77.6816617648812553],"rgb":[0.2,0.466666666666666674,0.8],"xyz":[0.188596704362153561,0.182561796405886462,0.596585698577646539],"hpluv":[252.471981644912631,207.553107999557341,49.8053630390326845],"hsluv":[252.471981644912631,86.5120902950020678,49.8053630390326845]},"#3377dd":{"lch":[50.8237086019957047,94.2508792352234,255.202895611269554],"luv":[50.8237086019957047,-24.0713820337122506,-91.1251710758325],"rgb":[0.2,0.466666666666666674,0.866666666666666696],"xyz":[0.210115029912787105,0.19116912662614,0.709915546477652537],"hpluv":[255.202895611269554,235.319753343529385,50.8237086019957047],"hsluv":[255.202895611269554,87.7828608732328,50.8237086019957047]},"#3377ee":{"lch":[51.9155858415672498,106.73807185779232,257.174602046687482],"luv":[51.9155858415672498,-23.6937959642247655,-104.075069141100855],"rgb":[0.2,0.466666666666666674,0.933333333333333348],"xyz":[0.233927210178961842,0.200693998732610041,0.83532636254617576],"hpluv":[257.174602046687482,260.892095272406607,51.9155858415672498],"hsluv":[257.174602046687482,88.9363454602875692,51.9155858415672498]},"#3377ff":{"lch":[53.0764799083082721,118.861737619173724,258.646767383963777],"luv":[53.0764799083082721,-23.3987809317452253,-116.535873106771263],"rgb":[0.2,0.466666666666666674,1],"xyz":[0.260098258588793207,0.211162418096542737,0.973160550837957605],"hpluv":[258.646767383963777,284.170694785425781,53.0764799083082721],"hsluv":[258.646767383963777,99.9999999999990763,53.0764799083082721]},"#aaff00":{"lch":[91.7137860391432156,115.080534629040301,111.722667154579099],"luv":[91.7137860391432156,-42.5929524944460596,106.908230966149674],"rgb":[0.66666666666666663,1,0],"xyz":[0.523356277296021299,0.800644834253704918,0.126965339384251918],"hpluv":[111.722667154579099,635.020942157405898,91.7137860391432156],"hsluv":[111.722667154579099,100.000000000002359,91.7137860391432156]},"#aaff11":{"lch":[91.7319300755291209,114.302910123776968,111.867287470019974],"luv":[91.7319300755291209,-42.5730312099484394,106.078707931238455],"rgb":[0.66666666666666663,1,0.0666666666666666657],"xyz":[0.524367942795658459,0.801049500453559826,0.132293444349007555],"hpluv":[111.867287470019974,632.205251281199821,91.7319300755291209],"hsluv":[111.867287470019974,99.9999999999902087,91.7319300755291209]},"#aaff22":{"lch":[91.76554812600844,112.870020698142184,112.139393409643191],"luv":[91.76554812600844,-42.5363318976714595,104.548084827461963],"rgb":[0.66666666666666663,1,0.133333333333333331],"xyz":[0.526243300934135405,0.801799643708950627,0.142170330544986734],"hpluv":[112.139393409643191,626.996151229530483,91.76554812600844],"hsluv":[112.139393409643191,99.9999999999901,91.76554812600844]},"#aaff33":{"lch":[91.8208541183991116,110.535111156119868,112.599114759903571],"luv":[91.8208541183991116,-42.4765495373732875,102.047800258971023],"rgb":[0.66666666666666663,1,0.2],"xyz":[0.529331051666593222,0.803034744001933753,0.158432484402597884],"hpluv":[112.599114759903571,618.449193227995465,91.8208541183991116],"hsluv":[112.599114759903571,99.9999999999900808,91.8208541183991116]},"#aaff44":{"lch":[91.9006031807778498,107.217215837920833,113.289723447654],"luv":[91.9006031807778498,-42.3916247074254713,98.4808688360338],"rgb":[0.66666666666666663,1,0.266666666666666663],"xyz":[0.533789046910812082,0.80481794209962132,0.181911259355484523],"hpluv":[113.289723447654,606.175591066234915,91.9006031807778498],"hsluv":[113.289723447654,99.9999999999900808,91.9006031807778498]},"#aaff55":{"lch":[92.0070808640835338,102.877427982590888,114.266397603879824],"luv":[92.0070808640835338,-42.2805422001356135,93.7876374559873796],"rgb":[0.66666666666666663,1,0.333333333333333315],"xyz":[0.539751460950174,0.807202907715366069,0.213313306629458438],"hpluv":[114.266397603879824,589.885725054723707,92.0070808640835338],"hsluv":[114.266397603879824,99.9999999999897,92.0070808640835338]},"#aaff66":{"lch":[92.142232175119787,97.5178938455906,115.604656391492952],"luv":[92.142232175119787,-42.1432392632638226,87.9413839126902559],"rgb":[0.66666666666666663,1,0.4],"xyz":[0.547336456723682252,0.810236906024769388,0.2532609510366024],"hpluv":[115.604656391492952,569.381090837871511,92.142232175119787],"hsluv":[115.604656391492952,99.9999999999898,92.142232175119787]},"#aaff77":{"lch":[92.3077308115560555,91.1840841453542197,117.412488820025033],"luv":[92.3077308115560555,-41.9805406670279666,80.9454841651530899],"rgb":[0.66666666666666663,1,0.466666666666666674],"xyz":[0.556650469743884102,0.813962511232850239,0.302314752943000309],"hpluv":[117.412488820025033,544.56608764574878,92.3077308115560555],"hsluv":[117.412488820025033,99.9999999999895692,92.3077308115560555]},"#aaff88":{"lch":[92.5050204995058749,83.9705472319660657,119.849478645386625],"luv":[92.5050204995058749,-41.7940850853900727,72.8306752289927601],"rgb":[0.66666666666666663,1,0.533333333333333326],"xyz":[0.567790886845828,0.818418678073627781,0.360987616346572504],"hpluv":[119.849478645386625,515.487838204951345,92.5050204995058749],"hsluv":[119.849478645386625,99.9999999999892708,92.5050204995058749]},"#aaff99":{"lch":[92.7353415895377,76.0327408171719,123.158131820453576],"luv":[92.7353415895377,-41.5862309318022625,63.6518897838709137],"rgb":[0.66666666666666663,1,0.6],"xyz":[0.580847850954900657,0.823641463717257,0.429754293987690383],"hpluv":[123.158131820453576,482.430180447041607,92.7353415895377],"hsluv":[123.158131820453576,99.9999999999891145,92.7353415895377]},"#aaffaa":{"lch":[92.9997492696274435,67.6109506527765802,127.715012949238414],"luv":[92.9997492696274435,-41.3599402641421108,53.4845397242865488],"rgb":[0.66666666666666663,1,0.66666666666666663],"xyz":[0.595905543920153269,0.829664540903358061,0.509058143604689],"hpluv":[127.715012949238414,446.121940639593902,92.9997492696274435],"hsluv":[127.715012949238414,99.9999999999887308,92.9997492696274435]},"#aaffbb":{"lch":[93.2991268167713201,59.0781485982363,134.10730048328],"luv":[93.2991268167713201,-41.1186450338129887,42.4203332421914823],"rgb":[0.66666666666666663,1,0.733333333333333282],"xyz":[0.613043136027489832,0.836519577746292819,0.599316128703330731],"hpluv":[134.10730048328,408.190288953842469,93.2991268167713201],"hsluv":[134.10730048328,99.9999999999883613,93.2991268167713201]},"#aaffcc":{"lch":[93.6341958749929404,51.0306218960527929,143.208028901391231],"luv":[93.6341958749929404,-40.8661030238149436,30.5628204644932246],"rgb":[0.66666666666666663,1,0.8],"xyz":[0.632335511471211587,0.844236527923781677,0.700922639373600886],"hpluv":[143.208028901391231,372.11656739719416,93.6341958749929404],"hsluv":[143.208028901391231,99.9999999999879492,93.6341958749929404]},"#aaffdd":{"lch":[94.005524978734,44.4262644213682094,156.066165366624773],"luv":[94.005524978734,-40.6062520520773305,18.0229094410556279],"rgb":[0.66666666666666663,1,0.866666666666666696],"xyz":[0.653853837021845186,0.852843858144035183,0.814252487273606884],"hpluv":[156.066165366624773,345.018188987702331,94.005524978734],"hsluv":[156.066165366624773,99.999999999986926,94.005524978734]},"#aaffee":{"lch":[94.4135370960349576,40.641316399200953,173.054449077896464],"luv":[94.4135370960349576,-40.3430708217409446,4.91459411670529711],"rgb":[0.66666666666666663,1,0.933333333333333348],"xyz":[0.677666017288019895,0.8623687302505052,0.939663303342130107],"hpluv":[173.054449077896464,339.745490646316398,94.4135370960349576],"hsluv":[173.054449077896464,99.9999999999862865,94.4135370960349576]},"#aaffff":{"lch":[94.8585166918378633,41.0030022313427764,192.177050630060705],"luv":[94.8585166918378633,-40.0804535568370639,-8.64889788711415264],"rgb":[0.66666666666666663,1,1],"xyz":[0.703837065697851316,0.872837149614437924,1.07749749163391195],"hpluv":[192.177050630060705,373.711432895013843,94.8585166918378633],"hsluv":[192.177050630060705,99.9999999999852491,94.8585166918378633]},"#338800":{"lch":[49.8717454753508918,71.2965557675853461,122.69380865426514],"luv":[49.8717454753508918,-38.5107906934601871,60.0009821960016509],"rgb":[0.2,0.533333333333333326,0],"xyz":[0.101689839911933699,0.183114842185751275,0.0299858551632874795],"hpluv":[122.69380865426514,181.406693814272955,49.8717454753508918],"hsluv":[122.69380865426514,100.000000000002245,49.8717454753508918]},"#338811":{"lch":[49.9202331837381053,69.5570511040883162,123.47043015419375],"luv":[49.9202331837381053,-38.361169332567485,58.0224443274741475],"rgb":[0.2,0.533333333333333326,0.0666666666666666657],"xyz":[0.102701505411570818,0.183519508385606128,0.0353139601280431092],"hpluv":[123.47043015419375,176.808802540010674,49.9202331837381053],"hsluv":[123.47043015419375,96.3624965314944291,49.9202331837381053]},"#338822":{"lch":[50.0099282713402,66.4316762124597915,124.985970570646856],"luv":[50.0099282713402,-38.0903182709230137,54.426971791721833],"rgb":[0.2,0.533333333333333326,0.133333333333333331],"xyz":[0.104576863550047847,0.184269651640996956,0.0451908463240223088],"hpluv":[124.985970570646856,168.561468288507513,50.0099282713402],"hsluv":[124.985970570646856,89.7672781446156876,50.0099282713402]},"#338833":{"lch":[50.1570811029395429,61.5658815699287487,127.715012949239991],"luv":[50.1570811029395429,-37.6619639194057143,48.7025076070614134],"rgb":[0.2,0.533333333333333326,0.2],"xyz":[0.10766461428250558,0.185504751933980055,0.061453000181633452],"hpluv":[127.715012949239991,155.756856758587162,50.1570811029395429],"hsluv":[127.715012949239991,79.3080015418374416,50.1570811029395429]},"#338844":{"lch":[50.3683877843642165,55.1600753981733334,132.238380805917416],"luv":[50.3683877843642165,-37.0795228857786441,40.8380080377971524],"rgb":[0.2,0.533333333333333326,0.266666666666666663],"xyz":[0.112122609526724454,0.187287950031667649,0.0849317751345200905],"hpluv":[132.238380805917416,138.965222681713072,50.3683877843642165],"hsluv":[132.238380805917416,79.9701630926319922,50.3683877843642165]},"#338855":{"lch":[50.648916869713247,47.7759983149871488,139.558488969535745],"luv":[50.648916869713247,-36.3608093871966886,30.990926990033774],"rgb":[0.2,0.533333333333333326,0.333333333333333315],"xyz":[0.118085023566086453,0.189672915647412482,0.116333822408493992],"hpluv":[139.558488969535745,119.695806374350084,50.648916869713247],"hsluv":[139.558488969535745,80.7922551095087726,50.648916869713247]},"#338866":{"lch":[51.0024095938582747,40.50700493167151,151.3112863122482],"luv":[51.0024095938582747,-35.5343950908498,19.4454162738124445],"rgb":[0.2,0.533333333333333326,0.4],"xyz":[0.125670019339594624,0.192706913956815773,0.156281466815637954],"hpluv":[151.3112863122482,100.78102351571394,51.0024095938582747],"hsluv":[151.3112863122482,81.7453783644028249,51.0024095938582747]},"#338877":{"lch":[51.4314426692160964,35.2513066472794421,169.271441625736571],"luv":[51.4314426692160964,-34.635118433957949,6.56225505495134165],"rgb":[0.2,0.533333333333333326,0.466666666666666674],"xyz":[0.134984032359796557,0.196432519164896596,0.205335268722035863],"hpluv":[169.271441625736571,86.9732781104886499,51.4314426692160964],"hsluv":[169.271441625736571,82.7938072280844182,51.4314426692160964]},"#338888":{"lch":[51.9375397067754818,34.4751674240590873,192.177050630061075],"luv":[51.9375397067754818,-33.6994920276336458,-7.27196025816705482],"rgb":[0.2,0.533333333333333326,0.533333333333333326],"xyz":[0.146124449461740358,0.200888686005674194,0.26400813212560803],"hpluv":[192.177050630061075,84.229522237058,51.9375397067754818],"hsluv":[192.177050630061075,83.8998231764876579,51.9375397067754818]},"#338899":{"lch":[52.5212658253882267,39.2899369869163,213.503984387174484],"luv":[52.5212658253882267,-32.7618132949538179,-21.68784770470414],"rgb":[0.2,0.533333333333333326,0.6],"xyz":[0.159181413570813085,0.206111471649303352,0.332774809766725965],"hpluv":[213.503984387174484,94.9260641143146415,52.5212658253882267],"hsluv":[213.503984387174484,85.0278067813718081,52.5212658253882267]},"#3388aa":{"lch":[53.1823203703714142,48.3403865273999855,228.783963154055925],"luv":[53.1823203703714142,-31.8514822326876157,-36.3631138545534753],"rgb":[0.2,0.533333333333333326,0.66666666666666663],"xyz":[0.174239106536065613,0.212134548835404446,0.412078659383724566],"hpluv":[228.783963154055925,115.340588590435829,53.1823203703714142],"hsluv":[228.783963154055925,86.1470646970195588,53.1823203703714142]},"#3388bb":{"lch":[53.9196335036436238,59.7107302664646866,238.732819450220632],"luv":[53.9196335036436238,-30.9916356267104831,-51.0381213421469],"rgb":[0.2,0.533333333333333326,0.733333333333333282],"xyz":[0.191376698643402288,0.218989585678339205,0.502336644482366257],"hpluv":[238.732819450220632,140.522147305520861,53.9196335036436238],"hsluv":[238.732819450220632,87.2332789223686262,53.9196335036436238]},"#3388cc":{"lch":[54.7314676322995268,72.1439684856409826,245.254262274299492],"luv":[54.7314676322995268,-30.1989009668194051,-65.5192992121664446],"rgb":[0.2,0.533333333333333326,0.8],"xyz":[0.210669074087124014,0.226706535855828,0.603943155152636413],"hpluv":[245.254262274299492,167.263916186866481,54.7314676322995268],"hsluv":[245.254262274299492,88.2687848362996,54.7314676322995268]},"#3388dd":{"lch":[55.6155220749816692,84.9545141717074728,249.692682338977761],"luv":[55.6155220749816692,-29.4839257322198733,-79.6741338300441697],"rgb":[0.2,0.533333333333333326,0.866666666666666696],"xyz":[0.232187399637757558,0.23531386607608154,0.717273003052642411],"hpluv":[249.692682338977761,193.833915517882872,55.6155220749816692],"hsluv":[249.692682338977761,89.2420383366021923,55.6155220749816692]},"#3388ee":{"lch":[56.5690381344568323,97.7754852991564434,252.83721230554255],"luv":[56.5690381344568323,-28.8523290085395629,-93.4215640859675602],"rgb":[0.2,0.533333333333333326,0.933333333333333348],"xyz":[0.255999579903932295,0.244838738182551585,0.842683819121165634],"hpluv":[252.83721230554255,219.32619909500923,56.5690381344568323],"hsluv":[252.83721230554255,90.146641202583325,56.5690381344568323]},"#3388ff":{"lch":[57.5889013880528182,110.410831334845568,255.145344615238457],"luv":[57.5889013880528182,-28.3057941013035759,-106.720821287817699],"rgb":[0.2,0.533333333333333326,1],"xyz":[0.282170628313763716,0.255307157546484254,0.980518007412947479],"hpluv":[255.145344615238457,243.283252172694205,57.5889013880528182],"hsluv":[255.145344615238457,99.9999999999988489,57.5889013880528182]},"#339900":{"lch":[55.5688440832231,80.82821284508357,123.866754715109295],"luv":[55.5688440832231,-45.0426054376311527,67.1145564473163603],"rgb":[0.2,0.6,0],"xyz":[0.127559440364401172,0.23485404309068697,0.0386090553141097345],"hpluv":[123.866754715109295,184.574176757765827,55.5688440832231],"hsluv":[123.866754715109295,100.00000000000226,55.5688440832231]},"#339911":{"lch":[55.6099261578814463,79.3206910999707446,124.475743785225987],"luv":[55.6099261578814463,-44.9000555787807372,65.3892731692238556],"rgb":[0.2,0.6,0.0666666666666666657],"xyz":[0.128571105864038304,0.235258709290541823,0.0439371602788653642],"hpluv":[124.475743785225987,180.997883954149785,55.6099261578814463],"hsluv":[124.475743785225987,97.1571693172972601,55.6099261578814463]},"#339922":{"lch":[55.6859569378682124,76.5942224429011418,125.649114872203555],"luv":[55.6859569378682124,-44.6406262928881503,62.240576763164114],"rgb":[0.2,0.6,0.133333333333333331],"xyz":[0.130446464002515305,0.236008852545932651,0.0538140464748445638],"hpluv":[125.649114872203555,174.537861698610129,55.6859569378682124],"hsluv":[125.649114872203555,91.9778413864117113,55.6859569378682124]},"#339933":{"lch":[55.8107903110879278,72.2971425020977563,127.715012949240148],"luv":[55.8107903110879278,-44.2266447414942618,57.191613973364035],"rgb":[0.2,0.6,0.2],"xyz":[0.133534214734973067,0.23724395283891575,0.070076200332455707],"hpluv":[127.715012949240148,164.377468022308932,55.8107903110879278],"hsluv":[127.715012949240148,83.6974291768240874,55.8107903110879278]},"#339944":{"lch":[55.9902586993563602,66.5149718399310501,131.021169741293448],"luv":[55.9902586993563602,-43.6562926505411042,50.1833597009719128],"rgb":[0.2,0.6,0.266666666666666663],"xyz":[0.137992209979191927,0.239027150936603344,0.0935549752853423455],"hpluv":[131.021169741293448,150.746162046382238,55.9902586993563602],"hsluv":[131.021169741293448,84.1112663411127386,55.9902586993563602]},"#339955":{"lch":[56.2289015921924,59.572114639014508,136.121417864766215],"luv":[56.2289015921924,-42.9401916463123783,41.2913645202220323],"rgb":[0.2,0.6,0.333333333333333315],"xyz":[0.143954624018553912,0.241412116552348177,0.124957022559316261],"hpluv":[136.121417864766215,134.438216783596687,56.2289015921924],"hsluv":[136.121417864766215,84.6329955380286236,56.2289015921924]},"#339966":{"lch":[56.5302268191487514,52.1043875673731947,143.898662284026642],"luv":[56.5302268191487514,-42.0991012865816785,30.700698275986678],"rgb":[0.2,0.6,0.4],"xyz":[0.151539619792062097,0.244446114861751468,0.164904666966460223],"hpluv":[143.898662284026642,116.958797396111564,56.5302268191487514],"hsluv":[143.898662284026642,85.2491724948614689,56.5302268191487514]},"#339977":{"lch":[56.8968484427531678,45.1992705399313124,155.596009487994166],"luv":[56.8968484427531678,-41.1609366004351855,18.6748856895258584],"rgb":[0.2,0.6,0.466666666666666674],"xyz":[0.160853632812264,0.248171720069832291,0.213958468872858132],"hpluv":[155.596009487994166,100.805108459810327,56.8968484427531678],"hsluv":[155.596009487994166,85.9413862611579873,56.8968484427531678]},"#339988":{"lch":[57.330574208667926,40.5351988689668303,172.17134267960472],"luv":[57.330574208667926,-40.1574041849560217,5.52134371985359085],"rgb":[0.2,0.6,0.533333333333333326],"xyz":[0.171994049914207858,0.252627886910609889,0.272631332276430272],"hpluv":[172.17134267960472,89.7191897797317,57.330574208667926],"hsluv":[172.17134267960472,86.6885468018933665,57.330574208667926]},"#339999":{"lch":[57.8324724587931627,40.0212192418936539,192.177050630061103],"luv":[57.8324724587931627,-39.1207602326874735,-8.44180717763071],"rgb":[0.2,0.6,0.6],"xyz":[0.185051014023280558,0.257850672554239047,0.341398009917548206],"hpluv":[192.177050630061103,87.8128114771670312,57.8324724587931627],"hsluv":[192.177050630061103,87.4690863712762194,57.8324724587931627]},"#3399aa":{"lch":[58.4029323329449568,44.4430671798845367,211.035048784986628],"luv":[58.4029323329449568,-38.0811346860811923,-22.913170914918652],"rgb":[0.2,0.6,0.66666666666666663],"xyz":[0.200108706988533114,0.263873749740340169,0.420701859534546807],"hpluv":[211.035048784986628,96.5625435737210154,58.4029323329449568],"hsluv":[211.035048784986628,88.2627766327166,58.4029323329449568]},"#3399bb":{"lch":[59.0417237507550823,52.8166449153409445,225.431517702392057],"luv":[59.0417237507550823,-37.064675814253917,-37.6272213549907448],"rgb":[0.2,0.6,0.733333333333333282],"xyz":[0.217246299095869733,0.270728786583274927,0.510959844633188554],"hpluv":[225.431517702392057,113.514439229551684,59.0417237507550823],"hsluv":[225.431517702392057,89.0519907331041196,59.0417237507550823]},"#3399cc":{"lch":[59.7480598269018373,63.5982744854026194,235.423336237979868],"luv":[59.7480598269018373,-36.0925574956591646,-52.364757336811472],"rgb":[0.2,0.6,0.8],"xyz":[0.236538674539591487,0.278445736760763729,0.612566355303458709],"hpluv":[235.423336237979868,135.070607162709791,59.7480598269018373],"hsluv":[235.423336237979868,89.8223822716188636,59.7480598269018373]},"#3399dd":{"lch":[60.5206621982976856,75.6357863680042186,242.281144195606601],"luv":[60.5206621982976856,-35.1807304699237235,-66.9558689220665286],"rgb":[0.2,0.6,0.866666666666666696],"xyz":[0.25805700009022503,0.287053066981017235,0.725896203203464707],"hpluv":[242.281144195606601,158.58531958905732,60.5206621982976856],"hsluv":[242.281144195606601,90.5630616197976508,60.5206621982976856]},"#3399ee":{"lch":[61.3578284965586818,88.2341933332873083,247.095644636752098],"luv":[61.3578284965586818,-34.3402162860227946,-81.277441019049661],"rgb":[0.2,0.6,0.933333333333333348],"xyz":[0.28186918035639974,0.296577939087487252,0.85130701927198793],"hpluv":[247.095644636752098,182.476215369006297,61.3578284965586818],"hsluv":[247.095644636752098,91.2664056494933504,61.3578284965586818]},"#3399ff":{"lch":[62.2575005434706554,100.992674077385175,250.5808182685887],"luv":[62.2575005434706554,-33.5777301361133595,-95.2473425151972],"rgb":[0.2,0.6,1],"xyz":[0.308040228766231161,0.30704635845142,0.989141207563769775],"hpluv":[250.5808182685887,205.84367033720622,62.2575005434706554],"hsluv":[250.5808182685887,99.9999999999985789,62.2575005434706554]},"#220000":{"lch":[3.07250446727781679,10.3329293192956264,12.1770506300617765],"luv":[3.07250446727781679,10.1004431663672367,2.17955870775360072],"rgb":[0.133333333333333331,0,0],"xyz":[0.00659672420629513,0.00340143591887099878,0.000309221447170077699],"hpluv":[12.1770506300617765,426.746789183125429,3.07250446727781679],"hsluv":[12.1770506300617765,100.000000000002217,3.07250446727781679]},"#220011":{"lch":[3.43803794680403607,8.12070857757986353,344.488545895364155],"luv":[3.43803794680403607,7.82492808895188574,-2.17172931202554675],"rgb":[0.133333333333333331,0,0.0666666666666666657],"xyz":[0.00760838970593225201,0.00380610211872585338,0.00563732641192570948],"hpluv":[344.488545895364155,299.724735916282839,3.43803794680403607],"hsluv":[344.488545895364155,99.9999999999976836,3.43803794680403607]},"#220022":{"lch":[4.11563957101797229,9.37475958111893348,307.715012949243601],"luv":[4.11563957101797229,5.73486236359989565,-7.41602797151862436],"rgb":[0.133333333333333331,0,0.133333333333333331],"xyz":[0.00948374784440927,0.00455624537411667124,0.0155142126079049047],"hpluv":[307.715012949243601,289.042783730483393,4.11563957101797229],"hsluv":[307.715012949243601,99.9999999999988205,4.11563957101797229]},"#220033":{"lch":[5.23130109110515384,14.2535250315243012,286.735013267555587],"luv":[5.23130109110515384,4.10424250296207127,-13.6498413654214126],"rgb":[0.133333333333333331,0,0.2],"xyz":[0.0125714985768670112,0.00579134566709978496,0.0317763664655160497],"hpluv":[286.735013267555587,345.74180296647927,5.23130109110515384],"hsluv":[286.735013267555587,99.9999999999995737,5.23130109110515384]},"#220044":{"lch":[6.84205732813722722,21.3889830656619786,277.641816515271671],"luv":[6.84205732813722722,2.84430225454687724,-21.1990221771654959],"rgb":[0.133333333333333331,0,0.266666666666666663],"xyz":[0.01702949382108589,0.0075745437647873606,0.0552551414184026882],"hpluv":[277.641816515271671,396.682237683346386,6.84205732813722722],"hsluv":[277.641816515271671,100.000000000000085,6.84205732813722722]},"#220055":{"lch":[8.95766614306443,30.4428627575942237,273.263558660643355],"luv":[8.95766614306443,1.73308321478426808,-30.3934913336449455],"rgb":[0.133333333333333331,0,0.333333333333333315],"xyz":[0.0229919078604478855,0.00995950938053219263,0.0866571886923766],"hpluv":[273.263558660643355,431.250830347711485,8.95766614306443],"hsluv":[273.263558660643355,100.000000000000242,8.95766614306443]},"#220066":{"lch":[11.2709410858812937,40.3162667149428913,270.881506896841],"luv":[11.2709410858812937,0.620249265146302853,-40.3114952920317435],"rgb":[0.133333333333333331,0,0.4],"xyz":[0.0305769036339560568,0.0129935076899355059,0.126604833099520558],"hpluv":[270.881506896841,453.899240935372916,11.2709410858812937],"hsluv":[270.881506896841,100.000000000000469,11.2709410858812937]},"#220077":{"lch":[13.6616791408408957,50.492834518379162,269.459540268375122],"luv":[13.6616791408408957,-0.476281836738408071,-50.4905881656414763],"rgb":[0.133333333333333331,0,0.466666666666666674],"xyz":[0.0398909166541579763,0.0167191128980163223,0.175658635005918468],"hpluv":[269.459540268375122,468.991527020998944,13.6616791408408957],"hsluv":[269.459540268375122,100.000000000000711,13.6616791408408957]},"#220088":{"lch":[16.0923146306383913,60.7890037695263104,268.549935621017426],"luv":[16.0923146306383913,-1.53830805749361632,-60.7695366743217278],"rgb":[0.133333333333333331,0,0.533333333333333326],"xyz":[0.0510313337561018043,0.0211752797387939132,0.234331498409490635],"hpluv":[268.549935621017426,479.34239057424071,16.0923146306383913],"hsluv":[268.549935621017426,100.000000000000711,16.0923146306383913]},"#220099":{"lch":[18.5394450926422749,71.1015482986176437,267.936483797094468],"luv":[18.5394450926422749,-2.56017951479828287,-71.0554406876254916],"rgb":[0.133333333333333331,0,0.6],"xyz":[0.0640882978651745178,0.0263980653824230742,0.30309817605060857],"hpluv":[267.936483797094468,486.655519564945394,18.5394450926422749],"hsluv":[267.936483797094468,100.000000000000739,18.5394450926422749]},"#2200aa":{"lch":[20.9885603179873783,81.3727160976321,267.505178931910336],"luv":[20.9885603179873783,-3.54207977840461252,-81.2955878012407851],"rgb":[0.133333333333333331,0,0.66666666666666663],"xyz":[0.0791459908304270598,0.0324211425685241791,0.382402025667607171],"hpluv":[267.505178931910336,491.966452636739518,20.9885603179873783],"hsluv":[267.505178931910336,100.000000000000782,20.9885603179873783]},"#2200bb":{"lch":[23.4306921856835828,91.57073581353,267.191578225858507],"luv":[23.4306921856835828,-4.48665301772878333,-91.4607544366971155],"rgb":[0.133333333333333331,0,0.733333333333333282],"xyz":[0.0962835829377637,0.0392761794114589377,0.472660010766248917],"hpluv":[267.191578225858507,495.919187528698728,23.4306921856835828],"hsluv":[267.191578225858507,100.000000000000909,23.4306921856835828]},"#2200cc":{"lch":[25.860342630381858,101.678845182637474,266.957159441292106],"luv":[25.860342630381858,-5.39738007409318588,-101.535490573545474],"rgb":[0.133333333333333331,0,0.8],"xyz":[0.115575958381485447,0.0469931295889477393,0.574266521436519],"hpluv":[266.957159441292106,498.925449111647538,25.860342630381858],"hsluv":[266.957159441292106,100.000000000000881,25.860342630381858]},"#2200dd":{"lch":[28.2742062228116282,111.689036790699618,266.777814373778199],"luv":[28.2742062228116282,-6.27782958394359714,-111.512464751476173],"rgb":[0.133333333333333331,0,0.866666666666666696],"xyz":[0.137094283932118977,0.0556004598092012733,0.687596369336525],"hpluv":[266.777814373778199,501.255846139694427,28.2742062228116282],"hsluv":[266.777814373778199,100.000000000000838,28.2742062228116282]},"#2200ee":{"lch":[30.6703766456275062,121.598437280905173,266.637867063772376],"luv":[30.6703766456275062,-7.13133722672581882,-121.389142753859758],"rgb":[0.133333333333333331,0,0.933333333333333348],"xyz":[0.160906464198293714,0.0651253319156713,0.813007185405048238],"hpluv":[266.637867063772376,503.092926092128948,30.6703766456275062],"hsluv":[266.637867063772376,100.000000000000838,30.6703766456275062]},"#2200ff":{"lch":[33.0478477502328261,131.407178056457695,266.526788769360394],"luv":[33.0478477502328261,-7.96089030872800674,-131.165813649189772],"rgb":[0.133333333333333331,0,1],"xyz":[0.187077512608125107,0.0755937512796040073,0.950841373696830083],"hpluv":[266.526788769360394,504.562807291912918,33.0478477502328261],"hsluv":[266.526788769360394,100.000000000000824,33.0478477502328261]},"#221100":{"lch":[6.69363913087575835,9.72440836304526535,42.3457761997067053],"luv":[6.69363913087575835,7.18724369375563921,6.55039282011655288],"rgb":[0.133333333333333331,0.0666666666666666657,0],"xyz":[0.00860112446722354,0.00741023644072787233,0.000977354867479528471],"hpluv":[42.3457761997067053,184.348759610596915,6.69363913087575835],"hsluv":[42.3457761997067053,100.000000000002402,6.69363913087575835]},"#221111":{"lch":[7.0591726104019763,6.19439175917428564,12.1770506300621],"luv":[7.0591726104019763,6.05502079617615863,1.30660339200560327],"rgb":[0.133333333333333331,0.0666666666666666657,0.0666666666666666657],"xyz":[0.00961278996686066103,0.00781490264058272606,0.00630545983223516],"hpluv":[12.1770506300621,111.348454543071412,7.0591726104019763],"hsluv":[12.1770506300621,26.092394217240134,7.0591726104019763]},"#221122":{"lch":[7.73677423461591474,7.55259268754738677,307.715012949245249],"luv":[7.73677423461591474,4.62018030186617779,-5.97457866985129],"rgb":[0.133333333333333331,0.0666666666666666657,0.133333333333333331],"xyz":[0.0114881481053376797,0.00856504589597354565,0.0161823460282143547],"hpluv":[307.715012949245249,123.872660774597591,7.73677423461591474],"hsluv":[307.715012949245249,42.856167926372315,7.73677423461591474]},"#221133":{"lch":[8.8238329822443653,14.9761175001236957,282.095598903329574],"luv":[8.8238329822443653,3.13814740657790647,-14.6436377390353236],"rgb":[0.133333333333333331,0.0666666666666666657,0.2],"xyz":[0.0145758988377954202,0.00980014618895665851,0.0324444998858255],"hpluv":[282.095598903329574,215.36805510923017,8.8238329822443653],"hsluv":[282.095598903329574,58.3941618505161273,8.8238329822443653]},"#221144":{"lch":[10.2463738670161,23.9334379374521049,274.255517801158362],"luv":[10.2463738670161,1.77596948547040223,-23.8674544912638211],"rgb":[0.133333333333333331,0.0666666666666666657,0.266666666666666663],"xyz":[0.0190338940820143,0.011583344286644235,0.0559232748387121364],"hpluv":[274.255517801158362,296.397281412249697,10.2463738670161],"hsluv":[274.255517801158362,70.1230959508528287,10.2463738670161]},"#221155":{"lch":[11.9365395500671561,33.3852442414483903,270.945812779521702],"luv":[11.9365395500671561,0.551083463009601,-33.3806956200430349],"rgb":[0.133333333333333331,0.0666666666666666657,0.333333333333333315],"xyz":[0.0249963081213762928,0.0139683099023890662,0.0873253221126860518],"hpluv":[270.945812779521702,354.907717298979946,11.9365395500671561],"hsluv":[270.945812779521702,78.3035236172291,11.9365395500671561]},"#221166":{"lch":[13.8282163263251512,43.1006504094303509,269.247085426223],"luv":[13.8282163263251512,-0.566362377205730683,-43.0969291176716496],"rgb":[0.133333333333333331,0.0666666666666666657,0.4],"xyz":[0.0325813038948844641,0.0170023082117923795,0.12727296651983],"hpluv":[269.247085426223,395.509560036398682,13.8282163263251512],"hsluv":[269.247085426223,83.9084652674952167,13.8282163263251512]},"#221177":{"lch":[15.8647012598499089,52.9790758801604,268.263491631539182],"luv":[15.8647012598499089,-1.60543281970815044,-52.954745458525224],"rgb":[0.133333333333333331,0.0666666666666666657,0.466666666666666674],"xyz":[0.0418953169150863836,0.0207279134198731958,0.176326768426227909],"hpluv":[268.263491631539182,423.75204448359591,15.8647012598499089],"hsluv":[268.263491631539182,87.783734282584831,15.8647012598499089]},"#221188":{"lch":[18.0016522099437424,62.9493123294311872,267.645454528547475],"luv":[18.0016522099437424,-2.58614693443793442,-62.8961665507666297],"rgb":[0.133333333333333331,0.0666666666666666657,0.533333333333333326],"xyz":[0.0530357340170302116,0.0251840802606507867,0.234999631829800076],"hpluv":[267.645454528547475,443.729139668046173,18.0016522099437424],"hsluv":[267.645454528547475,90.5156952975567464,18.0016522099437424]},"#221199":{"lch":[20.2061107483083475,72.9561611588118524,267.23334268313738],"luv":[20.2061107483083475,-3.52148568403582729,-72.8711231531918742],"rgb":[0.133333333333333331,0.0666666666666666657,0.6],"xyz":[0.066092698126102925,0.0304068659042799477,0.303766309470918],"hpluv":[267.23334268313738,458.161478440778865,20.2061107483083475],"hsluv":[267.23334268313738,92.4853336382361704,20.2061107483083475]},"#2211aa":{"lch":[22.4542330055690798,82.9584275230068471,266.945798214496847],"luv":[22.4542330055690798,-4.42007776686241449,-82.8405915576709759],"rgb":[0.133333333333333331,0.0666666666666666657,0.66666666666666663],"xyz":[0.0811503910913554671,0.0364299430903810492,0.383070159087916584],"hpluv":[266.945798214496847,468.815123306781686,22.4542330055690798],"hsluv":[266.945798214496847,93.9373181855700921,22.4542330055690798]},"#2211bb":{"lch":[24.7289983316777295,92.9268656932788701,266.737844101991243],"luv":[24.7289983316777295,-5.28796663316276483,-92.7762888698575097],"rgb":[0.133333333333333331,0.0666666666666666657,0.733333333333333282],"xyz":[0.0982879831986921138,0.0432849799333158078,0.473328144186558331],"hpluv":[266.737844101991243,476.841549380862261,24.7289983316777295],"hsluv":[266.737844101991243,95.0302193246277369,24.7289983316777295]},"#2211cc":{"lch":[27.0183279904475668,102.841627589427389,266.583003116257],"luv":[27.0183279904475668,-6.12961814831514129,-102.658794784462174],"rgb":[0.133333333333333331,0.0666666666666666657,0.8],"xyz":[0.117580358642413854,0.0510019301108046094,0.574934654856828486],"hpluv":[266.583003116257,483.002966655360069,27.0183279904475668],"hsluv":[266.583003116257,95.8686128249461689,27.0183279904475668]},"#2211dd":{"lch":[29.313669578695368,112.689841457512074,266.464886381494523],"luv":[29.313669578695368,-6.94848190374932617,-112.475414944566779],"rgb":[0.133333333333333331,0.0666666666666666657,0.866666666666666696],"xyz":[0.139098684193047384,0.0596092603310581434,0.688264502756834484],"hpluv":[266.464886381494523,487.813602393737767,29.313669578695368],"hsluv":[266.464886381494523,96.5228774582602256,29.313669578695368]},"#2211ee":{"lch":[31.6089746608533417,122.463629630364608,266.372923821556242],"luv":[31.6089746608533417,-7.74731231829930689,-122.21832814306471],"rgb":[0.133333333333333331,0.0666666666666666657,0.933333333333333348],"xyz":[0.162910864459222149,0.0691341324375281813,0.813675318825357707],"hpluv":[266.372923821556242,491.627361233059389,31.6089746608533417],"hsluv":[266.372923821556242,97.0413663214109761,31.6089746608533417]},"#2211ff":{"lch":[33.8999739889387115,132.15860685194221,266.300059947999785],"luv":[33.8999739889387115,-8.52836196764118,-131.883146789857562],"rgb":[0.133333333333333331,0.0666666666666666657,1],"xyz":[0.189081912869053514,0.0796025518014608774,0.951509507117139552],"hpluv":[266.300059947999785,494.692599475339,33.8999739889387115],"hsluv":[266.300059947999785,99.9999999999995737,33.8999739889387115]},"#77aa00":{"lch":[63.8935034159882491,78.4053265973676616,109.262687899665323],"luv":[63.8935034159882491,-25.8658938451783591,74.0158819067222424],"rgb":[0.466666666666666674,0.66666666666666663,0],"xyz":[0.219816749274909073,0.326708497135311,0.0514797056256764834],"hpluv":[109.262687899665323,155.714190603412163,63.8935034159882491],"hsluv":[109.262687899665323,100.000000000002132,63.8935034159882491]},"#77aa11":{"lch":[63.9264755829735662,77.0719876411919,109.595002167467626],"luv":[63.9264755829735662,-25.8475857965541422,72.6084952843247464],"rgb":[0.466666666666666674,0.66666666666666663,0.0666666666666666657],"xyz":[0.220828414774546206,0.32711316333516588,0.0568078105904321132],"hpluv":[109.595002167467626,152.98720995680398,63.9264755829735662],"hsluv":[109.595002167467626,97.9667163347824612,63.9264755829735662]},"#77aa22":{"lch":[63.9875253363426424,74.6349938152274603,110.235118064089221],"luv":[63.9875253363426424,-25.8142561390327501,70.0286118796271],"rgb":[0.466666666666666674,0.66666666666666663,0.133333333333333331],"xyz":[0.222703772913023207,0.32786330659055668,0.0666846967864113127],"hpluv":[110.235118064089221,148.008450888663447,63.9875253363426424],"hsluv":[110.235118064089221,94.2440053809013421,63.9875253363426424]},"#77aa33":{"lch":[64.0878403339217328,70.7199026331045,111.362593229805157],"luv":[64.0878403339217328,-25.7610573917560757,65.8610093340090685],"rgb":[0.466666666666666674,0.66666666666666663,0.2],"xyz":[0.22579152364548094,0.329098406883539807,0.0829468506440224629],"hpluv":[111.362593229805157,140.024923426145421,64.0878403339217328],"hsluv":[111.362593229805157,88.2427941375042,64.0878403339217328]},"#77aa44":{"lch":[64.2322300921174616,65.2796522257345,113.17268826837423],"luv":[64.2322300921174616,-25.6877867579927681,60.0130869576689463],"rgb":[0.466666666666666674,0.66666666666666663,0.266666666666666663],"xyz":[0.230249518889699828,0.330881604981227373,0.106425625596909101],"hpluv":[113.17268826837423,128.962712139229978,64.2322300921174616],"hsluv":[113.17268826837423,79.8488372015295482,64.2322300921174616]},"#77aa55":{"lch":[64.4245377454048338,58.3957340906732298,115.996670283872277],"luv":[64.4245377454048338,-25.5959546947607706,52.487225714952487],"rgb":[0.466666666666666674,0.66666666666666663,0.333333333333333315],"xyz":[0.236211932929061841,0.333266570596972234,0.137827672870883],"hpluv":[115.996670283872277,115.018880896771989,64.4245377454048338],"hsluv":[115.996670283872277,69.0944053471027075,64.4245377454048338]},"#77aa66":{"lch":[64.6678576456364,50.3036055521827663,120.443938093288892],"luv":[64.6678576456364,-25.4885877435648602,43.368013862617552],"rgb":[0.466666666666666674,0.66666666666666663,0.4],"xyz":[0.24379692870257,0.336300568906375552,0.177775317278026979],"hpluv":[120.443938093288892,98.707457943709727,64.6678576456364],"hsluv":[120.443938093288892,56.1391996219007723,64.6678576456364]},"#77aa77":{"lch":[64.964649263009,41.4721527505437351,127.71501294923786],"luv":[64.964649263009,-25.3699399849719889,32.8070967768157118],"rgb":[0.466666666666666674,0.66666666666666663,0.466666666666666674],"xyz":[0.253110941722771932,0.340026174114456348,0.226829119184424888],"hpluv":[127.71501294923786,81.006302212696113,64.964649263009],"hsluv":[127.71501294923786,41.2466460512923874,64.964649263009]},"#77aa88":{"lch":[65.3168057391263375,32.8409027786736161,140.238161573904051],"luv":[65.3168057391263375,-25.2451203613846147,21.004970679758074],"rgb":[0.466666666666666674,0.66666666666666663,0.533333333333333326],"xyz":[0.264251358824715732,0.344482340955233945,0.285501982587997],"hpluv":[140.238161573904051,63.8012923553667,65.3168057391263375],"hsluv":[140.238161573904051,43.6199696205744232,65.3168057391263375]},"#77aa99":{"lch":[65.7257012160132,26.4214783611449491,161.939459903532622],"luv":[65.7257012160132,-25.1196781367095241,8.19123245284666],"rgb":[0.466666666666666674,0.66666666666666663,0.6],"xyz":[0.277308322933788487,0.349705126598863103,0.354268660229114962],"hpluv":[161.939459903532622,51.0106916742292213,65.7257012160132],"hsluv":[161.939459903532622,46.1685656356417766,65.7257012160132]},"#77aaaa":{"lch":[66.1922284915170565,25.5746156232648509,192.177050630060677],"luv":[66.1922284915170565,-24.9991985449953802,-5.39453764336142338],"rgb":[0.466666666666666674,0.66666666666666663,0.66666666666666663],"xyz":[0.292366015899041,0.355728203784964225,0.433572509846113563],"hpluv":[192.177050630060677,49.0276908522131265,66.1922284915170565],"hsluv":[192.177050630060677,48.8357820868943122,66.1922284915170565]},"#77aabb":{"lch":[66.7168329685055568,31.6300901405034409,218.105494045696133],"luv":[66.7168329685055568,-24.8889541052261336,-19.519287021925777],"rgb":[0.466666666666666674,0.66666666666666663,0.733333333333333282],"xyz":[0.309503608006377662,0.362583240627899,0.523830494944755309],"hpluv":[218.105494045696133,60.1595160354738923,66.7168329685055568],"hsluv":[218.105494045696133,51.56699221483656,66.7168329685055568]},"#77aacc":{"lch":[67.2995460165272306,42.0550186755790207,233.874741843371567],"luv":[67.2995460165272306,-24.7936410920562054,-33.9691029790543908],"rgb":[0.466666666666666674,0.66666666666666663,0.8],"xyz":[0.328795983450099416,0.370300190805387786,0.625437005615025465],"hpluv":[233.874741843371567,79.2948573353567099,67.2995460165272306],"hsluv":[233.874741843371567,54.3124963748670382,67.2995460165272306]},"#77aadd":{"lch":[67.9400192524912,54.4863937886276304,243.022531341574677],"luv":[67.9400192524912,-24.7172120267711577,-48.557456046554158],"rgb":[0.466666666666666674,0.66666666666666663,0.866666666666666696],"xyz":[0.350314309000732904,0.378907521025641292,0.738766853515031463],"hpluv":[243.022531341574677,101.765770647841308,67.9400192524912],"hsluv":[243.022531341574677,60.6446157506369659,67.9400192524912]},"#77aaee":{"lch":[68.6375602707836,67.7758398266106781,248.660849953701415],"luv":[68.6375602707836,-24.6627990544268876,-63.1293181256010882],"rgb":[0.466666666666666674,0.66666666666666663,0.933333333333333348],"xyz":[0.374126489266907669,0.388432393132111309,0.864177669583554686],"hpluv":[248.660849953701415,125.300382334337471,68.6375602707836],"hsluv":[248.660849953701415,79.8712566390148453,68.6375602707836]},"#77aaff":{"lch":[69.3911697465266428,81.3794470542267874,252.380781260055755],"luv":[69.3911697465266428,-24.6327125013740549,-77.5618712878715399],"rgb":[0.466666666666666674,0.66666666666666663,1],"xyz":[0.400297537676739035,0.398900812496044033,1.00201185787533653],"hpluv":[252.380781260055755,148.816077288451226,69.3911697465266428],"hsluv":[252.380781260055755,99.9999999999980531,69.3911697465266428]},"#222200":{"lch":[12.5069288045758107,13.787646171799997,85.8743202181747307],"luv":[12.5069288045758107,0.991945128669063814,13.751917387057734],"rgb":[0.133333333333333331,0.133333333333333331,0],"xyz":[0.0123167482019914745,0.014841483910263846,0.002215896112402139],"hpluv":[85.8743202181747307,139.887458074797621,12.5069288045758107],"hsluv":[85.8743202181747307,100.000000000002359,12.5069288045758107]},"#222211":{"lch":[12.7636979604368612,8.34346759842367,85.8743202181729828],"luv":[12.7636979604368612,0.600266494900015157,8.32184665209868513],"rgb":[0.133333333333333331,0.133333333333333331,0.0666666666666666657],"xyz":[0.0133284137016285963,0.0152461501101187,0.00754400107715777046],"hpluv":[85.8743202181729828,82.9486632734846552,12.7636979604368612],"hsluv":[85.8743202181729828,59.2967120963297631,12.7636979604368612]},"#222222":{"lch":[13.2279109842717837,6.86787642036123471e-13,0],"luv":[13.2279109842717837,6.53891093021720259e-13,2.10008818196756883e-13],"rgb":[0.133333333333333331,0.133333333333333331,0.133333333333333331],"xyz":[0.0152037718401056149,0.0159962933655095202,0.0174208872731369674],"hpluv":[0,6.58825703928357502e-12,13.2279109842717837],"hsluv":[0,1.88635445986832e-12,13.2279109842717837]},"#222233":{"lch":[13.9615854376221584,10.5260121123804868,265.874320218180912],"luv":[13.9615854376221584,-0.757288539977712838,-10.4987354027615698],"rgb":[0.133333333333333331,0.133333333333333331,0.2],"xyz":[0.0182915225725633554,0.017231393658492633,0.0336830411307481106],"hpluv":[265.874320218180912,95.6683874279760431,13.9615854376221584],"hsluv":[265.874320218180912,18.6338179823007195,13.9615854376221584]},"#222244":{"lch":[14.9613810506728697,21.7214686924654536,265.874320218179207],"luv":[14.9613810506728697,-1.5627399186581008,-21.6651805001571454],"rgb":[0.133333333333333331,0.133333333333333331,0.266666666666666663],"xyz":[0.0227495178167822359,0.0190145917561802061,0.0571618160836347491],"hpluv":[265.874320218179207,184.228505509793536,14.9613810506728697],"hsluv":[265.874320218179207,35.8831222215914138,14.9613810506728697]},"#222255":{"lch":[16.2052187005970154,32.8139057554865161,265.874320218178639],"luv":[16.2052187005970154,-2.3607796110480268,-32.728873041368395],"rgb":[0.133333333333333331,0.133333333333333331,0.333333333333333315],"xyz":[0.028711931856144228,0.021399557371925039,0.0885638633576086576],"hpluv":[265.874320218178639,256.946292996249099,16.2052187005970154],"hsluv":[265.874320218178639,50.0467352240393097,16.2052187005970154]},"#222266":{"lch":[17.6604729086265309,43.5908485911403716,265.874320218178354],"luv":[17.6604729086265309,-3.13612123314657865,-43.477888915018994],"rgb":[0.133333333333333331,0.133333333333333331,0.4],"xyz":[0.0362969276296524063,0.0244335556813283505,0.128511507764752619],"hpluv":[265.874320218178354,313.207621322876264,17.6604729086265309],"hsluv":[265.874320218178354,61.00504004829466,17.6604729086265309]},"#222277":{"lch":[19.2910482951380544,54.0745009411091573,265.874320218178241],"luv":[19.2910482951380544,-3.89036222175517965,-53.9343743248547867],"rgb":[0.133333333333333331,0.133333333333333331,0.466666666666666674],"xyz":[0.0456109406498543188,0.0281591608894091669,0.177565309671150529],"hpluv":[265.874320218178241,355.693573155256843,19.2910482951380544],"hsluv":[265.874320218178241,69.2802447897283429,19.2910482951380544]},"#222288":{"lch":[21.0622605487373207,64.3390225585563371,265.874320218178184],"luv":[21.0622605487373207,-4.62883796225993471,-64.1722968492601353],"rgb":[0.133333333333333331,0.133333333333333331,0.533333333333333326],"xyz":[0.0567513577517981468,0.0326153277301867578,0.236238173074722696],"hpluv":[265.874320218178184,387.622344883614403,21.0622605487373207],"hsluv":[265.874320218178184,75.4991739133377706,21.0622605487373207]},"#222299":{"lch":[22.9434551626666803,74.4470789880776351,265.874320218178127],"luv":[22.9434551626666803,-5.35605689510984373,-74.2541596437089737],"rgb":[0.133333333333333331,0.133333333333333331,0.6],"xyz":[0.0698083218608708533,0.0378381133738159223,0.305004850715840603],"hpluv":[265.874320218178127,411.744842564929684,22.9434551626666803],"hsluv":[265.874320218178127,80.1976353712613559,22.9434551626666803]},"#2222aa":{"lch":[24.9089307040763188,84.4389391258505526,265.87432021817807],"luv":[24.9089307040763188,-6.07491614537627278,-84.2201272530844705],"rgb":[0.133333333333333331,0.133333333333333331,0.66666666666666663],"xyz":[0.0848660148261234093,0.0438611905599170238,0.384308700332839204],"hpluv":[265.87432021817807,430.157015573344836,24.9089307040763188],"hsluv":[265.87432021817807,83.7838678741945557,24.9089307040763188]},"#2222bb":{"lch":[26.937850813592469,94.3371638934954149,265.87432021817807],"luv":[26.937850813592469,-6.78703884698804139,-94.0927021354881106],"rgb":[0.133333333333333331,0.133333333333333331,0.733333333333333282],"xyz":[0.102003606933460056,0.0507162274028517823,0.47456668543148095],"hpluv":[265.87432021817807,444.384803230596,26.937850813592469],"hsluv":[265.87432021817807,86.5550863782758,26.937850813592469]},"#2222cc":{"lch":[29.0136770200274086,104.153206308830732,265.874320218178],"luv":[29.0136770200274086,-7.49324898143496743,-103.883307629821275],"rgb":[0.133333333333333331,0.133333333333333331,0.8],"xyz":[0.121295982377181782,0.058433177580340584,0.576173196101751106],"hpluv":[265.874320218178,455.521834046362642,29.0136770200274086],"hsluv":[265.874320218178,88.7243024658832695,29.0136770200274086]},"#2222dd":{"lch":[31.1234509916598299,113.892375340460845,265.874320218178],"luv":[31.1234509916598299,-8.19392849973896809,-113.597238947227837],"rgb":[0.133333333333333331,0.133333333333333331,0.866666666666666696],"xyz":[0.142814307927815326,0.067040507800594118,0.689503044001757104],"hpluv":[265.874320218178,464.350835522916555,31.1234509916598299],"hsluv":[265.874320218178,90.4439719502614565,31.1234509916598299]},"#2222ee":{"lch":[33.2570959032629503,123.556928623667645,265.874320218178],"luv":[33.2570959032629503,-8.88923982631188103,-123.236747872639071],"rgb":[0.133333333333333331,0.133333333333333331,0.933333333333333348],"xyz":[0.166626488193990063,0.0765653799070641489,0.814913860070280327],"hpluv":[265.874320218178,471.435310205520636,33.2570959032629503],"hsluv":[265.874320218178,93.8546607467714296,33.2570959032629503]},"#2222ff":{"lch":[35.4068078244889,133.147814572056944,265.874320218177957],"luv":[35.4068078244889,-9.57925119428392335,-132.802780361977625],"rgb":[0.133333333333333331,0.133333333333333331,1],"xyz":[0.192797536603821457,0.0870337992709968589,0.952748048362062172],"hpluv":[265.874320218177957,477.184793215987838,35.4068078244889],"hsluv":[265.874320218177957,99.999999999999531,35.4068078244889]},"#77bb00":{"lch":[69.0844312744863629,87.8096536524333544,113.037133893102563],"luv":[69.0844312744863629,-34.3623439699837476,80.8069588058406225],"rgb":[0.466666666666666674,0.733333333333333282,0],"xyz":[0.253771247183507853,0.394617492952509585,0.0627978715952091093],"hpluv":[113.037133893102563,161.287757631366873,69.0844312744863629],"hsluv":[113.037133893102563,100.000000000002331,69.0844312744863629]},"#77bb11":{"lch":[69.1135050244688216,86.6316159473835654,113.342165034517933],"luv":[69.1135050244688216,-34.3252912529264051,79.5412550948043275],"rgb":[0.466666666666666674,0.733333333333333282,0.0666666666666666657],"xyz":[0.254782912683144958,0.395022159152364438,0.068125976559964746],"hpluv":[113.342165034517933,159.057013433643618,69.1135050244688216],"hsluv":[113.342165034517933,98.3127503818399,69.1135050244688216]},"#77bb22":{"lch":[69.1673475306790664,84.4748154027895595,113.924619678029501],"luv":[69.1673475306790664,-34.2574435126740582,77.2167209955934197],"rgb":[0.466666666666666674,0.733333333333333282,0.133333333333333331],"xyz":[0.256658270821622,0.395772302407755239,0.0780028627559439386],"hpluv":[113.924619678029501,154.976360107776344,69.1673475306790664],"hsluv":[113.924619678029501,95.2170715716625438,69.1673475306790664]},"#77bb33":{"lch":[69.2558504240405313,80.9996568929936132,114.934551128374181],"luv":[69.2558504240405313,-34.1480550559542593,73.4496749664571666],"rgb":[0.466666666666666674,0.733333333333333282,0.2],"xyz":[0.25974602155407972,0.397007402700738365,0.0942650166135550749],"hpluv":[114.934551128374181,148.410982175614635,69.2558504240405313],"hsluv":[114.934551128374181,90.2088459481891363,69.2558504240405313]},"#77bb44":{"lch":[69.3833048234310752,76.148419012573342,116.514961433737128],"luv":[69.3833048234310752,-33.9950520676451049,68.1389620777462426],"rgb":[0.466666666666666674,0.733333333333333282,0.266666666666666663],"xyz":[0.264204016798298635,0.398790600798425932,0.117743791566441713],"hpluv":[116.514961433737128,139.266042804817573,69.3833048234310752],"hsluv":[116.514961433737128,83.166634884803841,69.3833048234310752]},"#77bb55":{"lch":[69.5531781358710788,69.9670725739878918,118.886197685461212],"luv":[69.5531781358710788,-33.7990968432466516,61.2618339356121666],"rgb":[0.466666666666666674,0.733333333333333282,0.333333333333333315],"xyz":[0.270166430837660621,0.401175566414170792,0.149145838840415629],"hpluv":[118.886197685461212,127.648598426560824,69.5531781358710788],"hsluv":[118.886197685461212,74.0801666731923092,69.5531781358710788]},"#77bb66":{"lch":[69.7683097004737647,62.6192143930699672,122.411113057511386],"luv":[69.7683097004737647,-33.5633071802414804,52.8646424591145],"rgb":[0.466666666666666674,0.733333333333333282,0.4],"xyz":[0.277751426611168806,0.404209564723574111,0.189093483247559591],"hpluv":[122.411113057511386,113.8908252780179,69.7683097004737647],"hsluv":[122.411113057511386,63.0377921091212627,69.7683097004737647]},"#77bb77":{"lch":[70.0310134677453391,54.4237865803123384,127.71501294923867],"luv":[70.0310134677453391,-33.2928991557924476,43.0526585885427053],"rgb":[0.466666666666666674,0.733333333333333282,0.466666666666666674],"xyz":[0.287065439631370711,0.407935169931654906,0.2381472851539575],"hpluv":[127.71501294923867,98.6137944921033522,70.0310134677453391],"hsluv":[127.71501294923867,50.2119979074062357,70.0310134677453391]},"#77bb88":{"lch":[70.3431390634792422,45.948041729110173,135.896820739423845],"luv":[70.3431390634792422,-32.9947227526694,31.9776610966863863],"rgb":[0.466666666666666674,0.733333333333333282,0.533333333333333326],"xyz":[0.298205856733314512,0.412391336772432504,0.296820148557529695],"hpluv":[135.896820739423845,82.8866502392756246,70.3431390634792422],"hsluv":[135.896820739423845,51.9268484553617711,70.3431390634792422]},"#77bb99":{"lch":[70.7061124793432612,38.2197788608509725,148.75629343317604],"luv":[70.7061124793432612,-32.6767203094589,19.8238100775241328],"rgb":[0.466666666666666674,0.733333333333333282,0.6],"xyz":[0.311262820842387211,0.417614122416061662,0.365586826198647574],"hpluv":[148.75629343317604,68.5915373148405,70.7061124793432612],"hsluv":[148.75629343317604,53.7921873551213565,70.7061124793432612]},"#77bbaa":{"lch":[71.1209666334754615,33.0529501718716148,168.140026251468868],"luv":[71.1209666334754615,-32.3473621836046874,6.79306078486928744],"rgb":[0.466666666666666674,0.733333333333333282,0.66666666666666663],"xyz":[0.326320513807639767,0.423637199602162784,0.444890675815646175],"hpluv":[168.140026251468868,58.9728212370576585,71.1209666334754615],"hsluv":[168.140026251468868,55.7713219876506372,71.1209666334754615]},"#77bbbb":{"lch":[71.5883672123020744,32.7520226121926044,192.177050630060876],"luv":[71.5883672123020744,-32.0151171807858432,-6.90849166534396097],"rgb":[0.466666666666666674,0.733333333333333282,0.733333333333333282],"xyz":[0.343458105914976441,0.430492236445097542,0.535148660914287921],"hpluv":[192.177050630060876,58.0543804308889762,71.5883672123020744],"hsluv":[192.177050630060876,57.8271385543864938,71.5883672123020744]},"#77bbcc":{"lch":[72.1086367753872111,38.0603267014846267,213.636027248927832],"luv":[72.1086367753872111,-31.6880044447458609,-21.0821925551758049],"rgb":[0.466666666666666674,0.733333333333333282,0.8],"xyz":[0.36275048135869814,0.438209186622586344,0.636755171584558077],"hpluv":[213.636027248927832,66.97682452789428,72.1086367753872111],"hsluv":[213.636027248927832,59.9241419588218278,72.1086367753872111]},"#77bbdd":{"lch":[72.6817787487410101,47.4106862821029651,228.567760630430627],"luv":[72.6817787487410101,-31.3732552756954277,-35.5456330249727728],"rgb":[0.466666666666666674,0.733333333333333282,0.866666666666666696],"xyz":[0.384268806909331739,0.44681651684283985,0.750085019484564075],"hpluv":[228.567760630430627,82.7732525696479371,72.6817787487410101],"hsluv":[228.567760630430627,62.0300015657167449,72.6817787487410101]},"#77bbee":{"lch":[73.3075021126589803,58.9885691422652769,238.208313348868131],"luv":[73.3075021126589803,-31.0770938488335098,-50.1384635520735316],"rgb":[0.466666666666666674,0.733333333333333282,0.933333333333333348],"xyz":[0.408080987175506449,0.456341388949309867,0.875495835553087298],"hpluv":[238.208313348868131,102.107764199280055,73.3075021126589803],"hsluv":[238.208313348868131,76.3238953534044,73.3075021126589803]},"#77bbff":{"lch":[73.9852470697490219,71.6819577745528846,244.548916872628638],"luv":[73.9852470697490219,-30.8046295043453391,-64.7254036023940102],"rgb":[0.466666666666666674,0.733333333333333282,1],"xyz":[0.43425203558533787,0.466809808313242591,1.01333002384486903],"hpluv":[244.548916872628638,122.943070755930805,73.9852470697490219],"hsluv":[244.548916872628638,99.9999999999974,73.9852470697490219]},"#223300":{"lch":[18.8330192465532917,22.9063411551717806,108.204985820955727],"luv":[18.8330192465532917,-7.15634373768739707,21.7597612446731326],"rgb":[0.133333333333333331,0.2,0],"xyz":[0.0184344702910022862,0.0270769280882856428,0.00425513680873902],"hpluv":[108.204985820955727,154.338793470845559,18.8330192465532917],"hsluv":[108.204985820955727,100.000000000002331,18.8330192465532917]},"#223311":{"lch":[19.0056890338669575,18.4529510656336271,112.754551304246377],"luv":[19.0056890338669575,-7.13731020483261602,17.0167625026225657],"rgb":[0.133333333333333331,0.2,0.0666666666666666657],"xyz":[0.0194461357906394079,0.0274815942881404957,0.0095832417734946513],"hpluv":[112.754551304246377,123.203072156705915,19.0056890338669575],"hsluv":[112.754551304246377,76.6034511576994248,19.0056890338669575]},"#223322":{"lch":[19.3213416797184507,11.6344605438365232,127.71501294923759],"luv":[19.3213416797184507,-7.11719904028337247,9.20359440474635],"rgb":[0.133333333333333331,0.2,0.133333333333333331],"xyz":[0.0213214939291164265,0.028231737543531317,0.0194601279694738491],"hpluv":[127.71501294923759,76.4096652359405084,19.3213416797184507],"hsluv":[127.71501294923759,38.9061385447444366,19.3213416797184507]},"#223333":{"lch":[19.8290945906418372,7.27996715422488894,192.177050630060677],"luv":[19.8290945906418372,-7.11617124458192585,-1.53558737438758408],"rgb":[0.133333333333333331,0.2,0.2],"xyz":[0.0244092446615741671,0.0294668378365144298,0.0357222818270849923],"hpluv":[192.177050630060677,46.5871198449043149,19.8290945906418372],"hsluv":[192.177050630060677,46.4047641905018935,19.8290945906418372]},"#223344":{"lch":[20.5377244517829496,15.5714684077650816,242.621028364370432],"luv":[20.5377244517829496,-7.16091210703038339,-13.8272183091687548],"rgb":[0.133333333333333331,0.2,0.266666666666666663],"xyz":[0.0288672399057930476,0.031250035934202,0.0592010567799716309],"hpluv":[242.621028364370432,96.2091932027738181,20.5377244517829496],"hsluv":[242.621028364370432,54.472556800898019,20.5377244517829496]},"#223355":{"lch":[21.4445377167678828,27.4997828393463344,254.670418676715883],"luv":[21.4445377167678828,-7.27014529691604761,-26.5213695644274097],"rgb":[0.133333333333333331,0.2,0.333333333333333315],"xyz":[0.0348296539451550397,0.0336350015499468358,0.0906031040539455323],"hpluv":[254.670418676715883,162.72410902482622,21.4445377167678828],"hsluv":[254.670418676715883,62.1025047738862597,21.4445377167678828]},"#223366":{"lch":[22.538163137523668,39.6650934211933617,259.172698399253136],"luv":[22.538163137523668,-7.45106225263504562,-38.9589695374422647],"rgb":[0.133333333333333331,0.2,0.4],"xyz":[0.042414649718663211,0.0366689998593501473,0.130550748461089494],"hpluv":[259.172698399253136,223.320859110196579,22.538163137523668],"hsluv":[259.172698399253136,68.7622962285398103,22.538163137523668]},"#223377":{"lch":[23.8014699151847751,51.4679604591091,261.393782909523054],"luv":[23.8014699151847751,-7.70180102721624227,-50.8884389105972517],"rgb":[0.133333333333333331,0.2,0.466666666666666674],"xyz":[0.0517286627388651304,0.0403946050674309637,0.179604550367487403],"hpluv":[261.393782909523054,274.392670476726266,23.8014699151847751],"hsluv":[261.393782909523054,74.3066649079193837,23.8014699151847751]},"#223388":{"lch":[25.214303338898695,62.8010579136007649,262.667168962641028],"luv":[25.214303338898695,-8.01548446335257658,-62.2874376089207189],"rgb":[0.133333333333333331,0.2,0.533333333333333326],"xyz":[0.0628690798408089585,0.0448507719082085615,0.238277413771059571],"hpluv":[262.667168962641028,316.052560368409843,25.214303338898695],"hsluv":[262.667168962641028,78.8060188103052184,25.214303338898695]},"#223399":{"lch":[26.7557115473943199,73.7050787305795723,263.468936800572067],"luv":[26.7557115473943199,-8.38335327394953111,-73.2267575314180732],"rgb":[0.133333333333333331,0.2,0.6],"xyz":[0.0759260439498816719,0.0500735575518377191,0.307044091412177478],"hpluv":[263.468936800572067,349.558796760350788,26.7557115473943199],"hsluv":[263.468936800572067,82.4151943494814105,26.7557115473943199]},"#2233aa":{"lch":[28.4055164492709622,84.2578478733767184,264.007358934798901],"luv":[28.4055164492709622,-8.79658068794244485,-83.7974050699281],"rgb":[0.133333333333333331,0.2,0.66666666666666663],"xyz":[0.090983736915134214,0.0560966347379388205,0.386347941029176078],"hpluv":[264.007358934798901,376.397732872534505,28.4055164492709622],"hsluv":[264.007358934798901,85.301735461295209,28.4055164492709622]},"#2233bb":{"lch":[30.1452579578322855,94.5340435151979506,264.386468786418391],"luv":[30.1452579578322855,-9.24712484322681583,-94.0806891209195868],"rgb":[0.133333333333333331,0.2,0.733333333333333282],"xyz":[0.108121329022470861,0.0629516715808735861,0.476605926127817825],"hpluv":[264.386468786418391,397.931717533943186,30.1452579578322855],"hsluv":[264.386468786418391,87.6154589527103553,30.1452579578322855]},"#2233cc":{"lch":[31.9586404471462444,104.593501952517812,264.663323368501551],"luv":[31.9586404471462444,-9.72802821613955615,-104.140127317558722],"rgb":[0.133333333333333331,0.2,0.8],"xyz":[0.127413704466192601,0.0706686217583623877,0.578212436798088],"hpluv":[264.663323368501551,415.294074833826699,31.9586404471462444],"hsluv":[264.663323368501551,89.4797268300864,31.9586404471462444]},"#2233dd":{"lch":[33.8316358854510284,114.480561125644712,264.87147297862515],"luv":[33.8316358854510284,-10.233440845943651,-114.022259072932982],"rgb":[0.133333333333333331,0.2,0.866666666666666696],"xyz":[0.148932030016826145,0.0792759519786159217,0.691542284698094],"hpluv":[264.87147297862515,429.386195390892226,33.8316358854510284],"hsluv":[264.87147297862515,90.9921469937159,33.8316358854510284]},"#2233ee":{"lch":[35.7523793143002209,124.226868169083772,265.031742065807748],"luv":[35.7523793143002209,-10.7585230682670669,-123.760126682580946],"rgb":[0.133333333333333331,0.2,0.933333333333333348],"xyz":[0.172744210283000882,0.0888008240850859387,0.816953100766617202],"hpluv":[265.031742065807748,440.909964314972513,35.7523793143002209],"hsluv":[265.031742065807748,93.1343838757889557,35.7523793143002209]},"#2233ff":{"lch":[37.7109573358094536,133.854664271403067,265.157628752861342],"luv":[37.7109573358094536,-11.2993072928814158,-133.376897556927247],"rgb":[0.133333333333333331,0.2,1],"xyz":[0.198915258692832275,0.0992692434490186487,0.954787289058399],"hpluv":[265.157628752861342,450.407151983715153,37.7109573358094536],"hsluv":[265.157628752861342,99.9999999999994884,37.7109573358094536]},"#77cc00":{"lch":[74.2578384949046892,97.2071675743180776,115.806356387580706],"luv":[74.2578384949046892,-42.3172913249353897,87.5127435448238202],"rgb":[0.466666666666666674,0.8,0],"xyz":[0.291994990493124773,0.47106497957174448,0.0755391193650810505],"hpluv":[115.806356387580706,166.109821583261578,74.2578384949046892],"hsluv":[115.806356387580706,100.000000000002331,74.2578384949046892]},"#77cc11":{"lch":[74.283676291108776,96.1575231653334441,116.077287726142885],"luv":[74.283676291108776,-42.2692272766684525,86.3688698937585144],"rgb":[0.466666666666666674,0.8,0.0666666666666666657],"xyz":[0.293006655992761877,0.471469645771599333,0.0808672243298366872],"hpluv":[116.077287726142885,164.2590118749402,74.283676291108776],"hsluv":[116.077287726142885,98.5840266713216522,74.283676291108776]},"#77cc22":{"lch":[74.3315335987815331,94.2328042547367914,116.591431825394338],"luv":[74.3315335987815331,-42.1809937248656581,84.2649699821603519],"rgb":[0.466666666666666674,0.8,0.133333333333333331],"xyz":[0.294882014131238934,0.472219789026990133,0.0907441105258158798],"hpluv":[116.591431825394338,160.867513369155,74.3315335987815331],"hsluv":[116.591431825394338,95.9817736999432611,74.3315335987815331]},"#77cc33":{"lch":[74.410219680569412,91.1231466477069176,117.473161926834081],"luv":[74.410219680569412,-42.0381214847294515,80.8469182901527148],"rgb":[0.466666666666666674,0.8,0.2],"xyz":[0.29796976486369664,0.47345488931997326,0.10700626438342703],"hpluv":[117.473161926834081,155.394430123968846,74.410219680569412],"hsluv":[117.473161926834081,91.7599970515073551,74.410219680569412]},"#77cc44":{"lch":[74.5235830687713445,86.7634188586395,118.828926444460791],"luv":[74.5235830687713445,-41.8369758074171045,76.0102513305232748],"rgb":[0.466666666666666674,0.8,0.266666666666666663],"xyz":[0.302427760107915555,0.475238087417660826,0.130485039336313668],"hpluv":[118.828926444460791,147.734611978654129,74.5235830687713445],"hsluv":[118.828926444460791,85.7987877580492153,74.5235830687713445]},"#77cc55":{"lch":[74.6747602628398,81.1723246922669688,120.810965560633605],"luv":[74.6747602628398,-41.5770530159641396,69.7158156981220571],"rgb":[0.466666666666666674,0.8,0.333333333333333315],"xyz":[0.30839017414727754,0.477623053033405687,0.161887086610287556],"hpluv":[120.810965560633605,137.934680546119694,74.6747602628398],"hsluv":[120.810965560633605,78.0638956664307671,74.6747602628398]},"#77cc66":{"lch":[74.866352492363319,74.4599116278811692,123.651008617564372],"luv":[74.866352492363319,-41.2606832822808798,61.982533464768764],"rgb":[0.466666666666666674,0.8,0.4],"xyz":[0.315975169920785726,0.480657051342809,0.201834731017431546],"hpluv":[123.651008617564372,126.204595224585091,74.866352492363319],"hsluv":[123.651008617564372,68.5978490432360388,74.866352492363319]},"#77cc77":{"lch":[75.1005189251371519,66.8471540376336719,127.715012949239053],"luv":[75.1005189251371519,-40.8926996459993219,52.8803282761483189],"rgb":[0.466666666666666674,0.8,0.466666666666666674],"xyz":[0.325289182940987631,0.484382656550889801,0.250888532923829455],"hpluv":[127.715012949239053,112.948199149412858,75.1005189251371519],"hsluv":[127.715012949239053,57.5107647824030153,75.1005189251371519]},"#77cc88":{"lch":[75.3790318815133,58.7087525381891311,133.590980823477452],"luv":[75.3790318815133,-40.4800101313413947,42.5215992685696946],"rgb":[0.466666666666666674,0.8,0.533333333333333326],"xyz":[0.336429600042931432,0.488838823391667399,0.309561396327401595],"hpluv":[133.590980823477452,98.8306436104363542,75.3790318815133],"hsluv":[133.590980823477452,58.7660231359317748,75.3790318815133]},"#77cc99":{"lch":[75.7033128937519848,50.6622606125816759,142.200076129410462],"luv":[75.7033128937519848,-40.0310804193600305,31.0512036938324556],"rgb":[0.466666666666666674,0.8,0.6],"xyz":[0.349486564152004187,0.494061609035296556,0.378328073968519529],"hpluv":[142.200076129410462,84.9198084445103802,75.7033128937519848],"hsluv":[142.200076129410462,60.1459848784672815,75.7033128937519848]},"#77ccaa":{"lch":[76.0744587192654,43.7254195479873289,154.773618890386814],"luv":[76.0744587192654,-39.5553661600219684,18.6355928962322395],"rgb":[0.466666666666666674,0.8,0.66666666666666663],"xyz":[0.364544257117256687,0.500084686221397678,0.45763192358551813],"hpluv":[154.773618890386814,73.067319501552376,76.0744587192654],"hsluv":[154.773618890386814,61.6269813218812459,76.0744587192654]},"#77ccbb":{"lch":[76.4932621718819235,39.4413790272598561,172.054536865796422],"luv":[76.4932621718819235,-39.0627454070693716,5.45199970968949721],"rgb":[0.466666666666666674,0.8,0.733333333333333282],"xyz":[0.381681849224593361,0.506939723064332437,0.547889908684159876],"hpluv":[172.054536865796422,67.3385729198675733,76.4932621718819235],"hsluv":[172.054536865796422,63.1840553036415713,76.4932621718819235]},"#77cccc":{"lch":[76.9602305249106,39.4506200876857847,192.177050630060961],"luv":[76.9602305249106,-38.5629992967744357,-8.32144882456723778],"rgb":[0.466666666666666674,0.8,0.8],"xyz":[0.400974224668315116,0.514656673241821183,0.64949641935443],"hpluv":[192.177050630060961,69.0111626451701312,76.9602305249106],"hsluv":[192.177050630060961,64.792316690459316,76.9602305249106]},"#77ccdd":{"lch":[77.4756030772436475,44.2250390945155942,210.602473757279853],"luv":[77.4756030772436475,-38.0653777824919359,-22.5140200139291444],"rgb":[0.466666666666666674,0.8,0.866666666666666696],"xyz":[0.422492550218948604,0.5232640034620748,0.762826267254436],"hpluv":[210.602473757279853,79.5030322309331439,77.4756030772436475],"hsluv":[210.602473757279853,66.4280770246703156,77.4756030772436475]},"#77ccee":{"lch":[78.0393687787239116,52.7144148097026246,224.531483635923479],"luv":[78.0393687787239116,-37.5782716813780482,-36.9686762837126182],"rgb":[0.466666666666666674,0.8,0.933333333333333348],"xyz":[0.446304730485123369,0.532788875568544817,0.888237083322959253],"hpluv":[224.531483635923479,97.6926138158747648,78.0393687787239116],"hsluv":[224.531483635923479,71.3781641956177282,78.0393687787239116]},"#77ccff":{"lch":[78.6512843692400736,63.5145451324089052,234.249283216901347],"luv":[78.6512843692400736,-37.1089966152940249,-51.5462880679385549],"rgb":[0.466666666666666674,0.8,1],"xyz":[0.472475778894954734,0.54325729493247743,1.0260712716147411],"hpluv":[234.249283216901347,121.749546403725816,78.6512843692400736],"hsluv":[234.249283216901347,99.9999999999968168,78.6512843692400736]},"#224400":{"lch":[25.1809799681870601,33.4179584834008523,116.999863609689683],"luv":[25.1809799681870601,-15.1713647924420147,29.7756551486773162],"rgb":[0.133333333333333331,0.266666666666666663,0],"xyz":[0.0272670407739683193,0.0447420690542179589,0.00719932696972761486],"hpluv":[116.999863609689683,168.401755360818214,25.1809799681870601],"hsluv":[116.999863609689683,100.000000000002217,25.1809799681870601]},"#224411":{"lch":[25.304760275593587,29.8643723317269938,120.153298663054528],"luv":[25.304760275593587,-15.0013316265206242,25.8232605261065515],"rgb":[0.133333333333333331,0.266666666666666663,0.0666666666666666657],"xyz":[0.0282787062736054411,0.0451467352540728117,0.0125274319344832463],"hpluv":[120.153298663054528,149.758158325470362,25.304760275593587],"hsluv":[120.153298663054528,85.5029145399767287,25.304760275593587]},"#224422":{"lch":[25.5322735505540379,24.0578500603585184,127.715012949239281],"luv":[25.5322735505540379,-14.7170130248608242,19.0312815425753499],"rgb":[0.133333333333333331,0.266666666666666663,0.133333333333333331],"xyz":[0.0301540644120824597,0.0458968785094636331,0.0224043181304624424],"hpluv":[127.715012949239281,119.565711231297882,25.5322735505540379],"hsluv":[127.715012949239281,60.8802579098014363,25.5322735505540379]},"#224433":{"lch":[25.9015299317797343,16.981905402382786,147.498859327993841],"luv":[25.9015299317797343,-14.3222120947549634,9.12465625699578098],"rgb":[0.133333333333333331,0.266666666666666663,0.2],"xyz":[0.0332418151445402,0.0471319788024467459,0.0386664719880735891],"hpluv":[147.498859327993841,83.1955939146196357,25.9015299317797343],"hsluv":[147.498859327993841,64.09678513773909,25.9015299317797343]},"#224444":{"lch":[26.423438440277998,14.1959776348833024,192.177050630061],"luv":[26.423438440277998,-13.8765746732054378,-2.99440417262938974],"rgb":[0.133333333333333331,0.266666666666666663,0.266666666666666663],"xyz":[0.0376998103887590807,0.048915176900134319,0.0621452469409602276],"hpluv":[192.177050630061,68.1734546180548762,26.423438440277998],"hsluv":[192.177050630061,67.9066037165366367,26.423438440277998]},"#224455":{"lch":[27.1020089847707979,21.1158760403194243,230.453768193421723],"luv":[27.1020089847707979,-13.4444916811297333,-16.2826860310628518],"rgb":[0.133333333333333331,0.266666666666666663,0.333333333333333315],"xyz":[0.0436622244281210728,0.0513001425158791519,0.0935472942149341291],"hpluv":[230.453768193421723,98.865995891455,27.1020089847707979],"hsluv":[230.453768193421723,71.8953118433392717,27.1020089847707979]},"#224466":{"lch":[27.935501760142138,32.6185654266362306,246.366656325875056],"luv":[27.935501760142138,-13.0762038460066634,-29.8828329224226863],"rgb":[0.133333333333333331,0.266666666666666663,0.4],"xyz":[0.0512472202016292511,0.0543341408252824634,0.133494938622078091],"hpluv":[246.366656325875056,148.165710166053657,27.935501760142138],"hsluv":[246.366656325875056,75.7322080769735351,27.935501760142138]},"#224477":{"lch":[28.9175817086007072,45.1016041758277453,253.511262930840303],"luv":[28.9175817086007072,-12.8010466495854338,-43.2468253621948548],"rgb":[0.133333333333333331,0.266666666666666663,0.466666666666666674],"xyz":[0.0605612332218311636,0.0580597460333632798,0.182548740528476],"hpluv":[253.511262930840303,197.910731630760921,28.9175817086007072],"hsluv":[253.511262930840303,79.2164102145581381,28.9175817086007072]},"#224488":{"lch":[30.0385370730522183,57.5093846577101502,257.31357801273],"luv":[30.0385370730522183,-12.6299243743950456,-56.1053859625395432],"rgb":[0.133333333333333331,0.266666666666666663,0.533333333333333326],"xyz":[0.0717016503237749847,0.0625159128741408776,0.241221603932048168],"hpluv":[257.31357801273,242.94013543841632,30.0385370730522183],"hsluv":[257.31357801273,82.2624245727818106,30.0385370730522183]},"#224499":{"lch":[31.2864747985506213,69.5224780150470139,259.59064804278853],"luv":[31.2864747985506213,-12.5612993437317204,-68.3782765807230675],"rgb":[0.133333333333333331,0.266666666666666663,0.6],"xyz":[0.084758614432847712,0.0677386985177700351,0.309988281573166102],"hpluv":[259.59064804278853,281.973268281811727,31.2864747985506213],"hsluv":[259.59064804278853,84.8626039888072796,31.2864747985506213]},"#2244aa":{"lch":[32.6483868166792277,81.0719578322086676,261.068394107427196],"luv":[32.6483868166792277,-12.5868550230291323,-80.0889095154670372],"rgb":[0.133333333333333331,0.266666666666666663,0.66666666666666663],"xyz":[0.0998163073981002402,0.0737617757038711297,0.389292131190164703],"hpluv":[261.068394107427196,315.099896322028769,32.6483868166792277],"hsluv":[261.068394107427196,87.0515845849570695,32.6483868166792277]},"#2244bb":{"lch":[34.1110146972578292,92.183713113584,262.084105297610279],"luv":[34.1110146972578292,-12.6954785449376448,-91.3053217940914266],"rgb":[0.133333333333333331,0.266666666666666663,0.733333333333333282],"xyz":[0.116953899505436887,0.0806168125468058883,0.479550116288806449],"hpluv":[262.084105297610279,342.924793116778346,34.1110146972578292],"hsluv":[262.084105297610279,88.8814901896574128,34.1110146972578292]},"#2244cc":{"lch":[35.6614866183058439,102.915147630289923,262.812952152813068],"luv":[35.6614866183058439,-12.875606592693158,-102.106544191029045],"rgb":[0.133333333333333331,0.266666666666666663,0.8],"xyz":[0.136246274949158641,0.0883337627242946899,0.58115662695907655],"hpluv":[262.812952152813068,366.200711918304478,35.6614866183058439],"hsluv":[262.812952152813068,90.4075680541016453,35.6614866183058439]},"#2244dd":{"lch":[37.2877389569632456,113.32806156453313,263.353781276912969],"luv":[37.2877389569632456,-13.1164125913708496,-112.566465959927598],"rgb":[0.133333333333333331,0.266666666666666663,0.866666666666666696],"xyz":[0.157764600499792185,0.0969410929445482239,0.694486474859082548],"hpluv":[263.353781276912969,385.665452845521429,37.2877389569632456],"hsluv":[263.353781276912969,91.6811227311716408,37.2877389569632456]},"#2244ee":{"lch":[38.9787575249373575,123.477944203962494,263.76603971616106],"luv":[38.9787575249373575,-13.4082956886680194,-122.74779147325674],"rgb":[0.133333333333333331,0.266666666666666663,0.933333333333333348],"xyz":[0.181576780765966922,0.106465965051018269,0.819897290927605771],"hpluv":[263.76603971616106,401.976556214066079,38.9787575249373575],"hsluv":[263.76603971616106,92.7467647141115208,38.9787575249373575]},"#2244ff":{"lch":[40.7246816385265333,133.410810959437413,264.087324287658078],"luv":[40.7246816385265333,-13.7429938745542355,-132.701072340123574],"rgb":[0.133333333333333331,0.266666666666666663,1],"xyz":[0.207747829175798315,0.116934384414950965,0.957731479219387616],"hpluv":[264.087324287658078,415.692943868353552,40.7246816385265333],"hsluv":[264.087324287658078,99.9999999999994174,40.7246816385265333]},"#77dd00":{"lch":[79.4046595803128525,106.500737968556749,117.886764510297155],"luv":[79.4046595803128525,-49.8131268255250319,94.1332012826045457],"rgb":[0.466666666666666674,0.866666666666666696,0],"xyz":[0.3346289810403,0.556332960666096,0.089750449547472369],"hpluv":[117.886764510297155,213.048114553231642,79.4046595803128525],"hsluv":[117.886764510297155,100.000000000002288,79.4046595803128525]},"#77dd11":{"lch":[79.427785829561941,105.558219679332908,118.124490997004173],"luv":[79.427785829561941,-49.7589732732473422,93.0944806133132801],"rgb":[0.466666666666666674,0.866666666666666696,0.0666666666666666657],"xyz":[0.335640646539937082,0.556737626865951,0.095078554512228],"hpluv":[118.124490997004173,211.44368721760469,79.427785829561941],"hsluv":[118.124490997004173,98.7993418471683498,79.427785829561941]},"#77dd22":{"lch":[79.4706261070012658,103.827566318990023,118.57359388187615],"luv":[79.4706261070012658,-49.6593926395600249,91.1817319993116],"rgb":[0.466666666666666674,0.866666666666666696,0.133333333333333331],"xyz":[0.337516004678414139,0.557487770121341764,0.104955440708207198],"hpluv":[118.57359388187615,208.49071074424171,79.4706261070012658],"hsluv":[118.57359388187615,96.5898934808467,79.4706261070012658]},"#77dd33":{"lch":[79.5410783702752582,101.02472031386101,119.337697767432388],"luv":[79.5410783702752582,-49.4976803830995067,88.0680063995226874],"rgb":[0.466666666666666674,0.866666666666666696,0.2],"xyz":[0.340603755410871845,0.55872287041432489,0.121217594565818348],"hpluv":[119.337697767432388,203.689012727245881,79.5410783702752582],"hsluv":[119.337697767432388,92.9973786049096276,79.5410783702752582]},"#77dd44":{"lch":[79.6426121547728485,97.0801788178617073,120.498016398630853],"luv":[79.6426121547728485,-49.2690191092090188,83.6488187323909642],"rgb":[0.466666666666666674,0.866666666666666696,0.266666666666666663],"xyz":[0.34506175065509076,0.560506068512012456,0.144696369518705],"hpluv":[120.498016398630853,196.890303230407255,79.6426121547728485],"hsluv":[120.498016398630853,87.9077551580221126,79.6426121547728485]},"#77dd55":{"lch":[79.7780740091910729,91.9929116678805912,122.163902680224],"luv":[79.7780740091910729,-48.9717875622404577,77.8746417012192325],"rgb":[0.466666666666666674,0.866666666666666696,0.333333333333333315],"xyz":[0.351024164694452745,0.562891034127757206,0.176098416792678902],"hpluv":[122.163902680224,188.049297266091,79.7780740091910729],"hsluv":[122.163902680224,81.2740392578912889,79.7780740091910729]},"#77dd66":{"lch":[79.9498479155991788,85.8342168020908645,124.492086237753256],"luv":[79.9498479155991788,-48.6072648253697466,70.7449403153661],"rgb":[0.466666666666666674,0.866666666666666696,0.4],"xyz":[0.35860916046796093,0.565925032437160525,0.216046061199822836],"hpluv":[124.492086237753256,177.233761467474238,79.9498479155991788],"hsluv":[124.492086237753256,73.1095665987697174,79.9498479155991788]},"#77dd77":{"lch":[80.1599403321921,78.7586110849663896,127.715012949239352],"luv":[80.1599403321921,-48.1793469594900188,62.3030444407821093],"rgb":[0.466666666666666674,0.866666666666666696,0.466666666666666674],"xyz":[0.367923173488162836,0.569650637645241376,0.265099863106220746],"hpluv":[127.715012949239352,164.652954432832814,80.1599403321921],"hsluv":[127.715012949239352,63.4818861677236654,80.1599403321921]},"#77dd88":{"lch":[80.4100305893493754,71.0258644695610855,132.183293417803185],"luv":[80.4100305893493754,-47.69419139775556,52.6301959958607597],"rgb":[0.466666666666666674,0.866666666666666696,0.533333333333333326],"xyz":[0.379063590590106636,0.574106804486018918,0.323772726509792941],"hpluv":[132.183293417803185,150.716476916292407,80.4100305893493754],"hsluv":[132.183293417803185,64.4129914780986184,80.4100305893493754]},"#77dd99":{"lch":[80.7015034668449829,63.0436351039456042,138.421724913218469],"luv":[80.7015034668449829,-47.1597772740100254,41.838443261971527],"rgb":[0.466666666666666674,0.866666666666666696,0.6],"xyz":[0.392120554699179391,0.579329590129648131,0.39253940415091082],"hpluv":[138.421724913218469,136.149613262507529,80.7015034668449829],"hsluv":[138.421724913218469,65.4455974050235909,80.7015034668449829]},"#77ddaa":{"lch":[81.0354720941451916,55.4433276111880673,147.164903113494319],"luv":[81.0354720941451916,-46.5854032558204594,30.0626475895607292],"rgb":[0.466666666666666674,0.866666666666666696,0.66666666666666663],"xyz":[0.407178247664431892,0.585352667315749198,0.471843253767909421],"hpluv":[147.164903113494319,122.204418643173668,81.0354720941451916],"hsluv":[147.164903113494319,66.5644374268903505,81.0354720941451916]},"#77ddbb":{"lch":[81.4127955433910415,49.1817473647014651,159.215751775487576],"luv":[81.4127955433910415,-45.9811599326092804,17.452140415923953],"rgb":[0.466666666666666674,0.866666666666666696,0.733333333333333282],"xyz":[0.424315839771768566,0.592207704158684,0.562101238866551167],"hpluv":[159.215751775487576,110.971854928909636,81.4127955433910415],"hsluv":[159.215751775487576,67.7527973989238461,81.4127955433910415]},"#77ddcc":{"lch":[81.8340936239464298,45.5480287935550479,174.756411210455894],"luv":[81.8340936239464298,-45.3574175840417197,4.16264304083146897],"rgb":[0.466666666666666674,0.866666666666666696,0.8],"xyz":[0.44360821521549032,0.599924654336172813,0.663707749536821323],"hpluv":[174.756411210455894,105.54602277980743,81.8340936239464298],"hsluv":[174.756411210455894,68.9933910523739371,81.8340936239464298]},"#77dddd":{"lch":[82.299760373596115,45.7538051586653296,192.177050630060847],"luv":[82.299760373596115,-44.7243656053231931,-9.65100034703627],"rgb":[0.466666666666666674,0.866666666666666696,0.866666666666666696],"xyz":[0.465126540766123808,0.60853198455642632,0.777037597436827321],"hpluv":[192.177050630060847,109.256318691998032,82.299760373596115],"hsluv":[192.177050630060847,70.2691471280789557,82.299760373596115]},"#77ddee":{"lch":[82.8099771424448221,50.1244355238275574,208.400620203695752],"luv":[82.8099771424448221,-44.0916301090396274,-23.8408722766172367],"rgb":[0.466666666666666674,0.866666666666666696,0.933333333333333348],"xyz":[0.488938721032298573,0.618056856662896337,0.902448413505350544],"hpluv":[208.400620203695752,123.794681382199428,82.8099771424448221],"hsluv":[208.400620203695752,71.5638635335918,82.8099771424448221]},"#77ddff":{"lch":[83.364725787715372,57.9146258331384161,221.361714592462022],"luv":[83.364725787715372,-43.4679842885535521,-38.2705921992655504],"rgb":[0.466666666666666674,0.866666666666666696,1],"xyz":[0.515109769442129939,0.628525276026829061,1.0402826017971325],"hpluv":[221.361714592462022,148.517135389694232,83.364725787715372],"hsluv":[221.361714592462022,99.9999999999953531,83.364725787715372]},"#225500":{"lch":[31.4325909084541877,43.9203091385023825,121.065637009975248],"luv":[31.4325909084541877,-22.6637443991712324,37.6211143459447541],"rgb":[0.133333333333333331,0.333333333333333315,0],"xyz":[0.0390802974883142848,0.0683685824829102229,0.0111370792078428239],"hpluv":[121.065637009975248,177.306450001223254,31.4325909084541877],"hsluv":[121.065637009975248,100.000000000002373,31.4325909084541877]},"#225511":{"lch":[31.5259896590935043,41.027632513747335,123.178290947815412],"luv":[31.5259896590935043,-22.452213479362328,34.3389682366875704],"rgb":[0.133333333333333331,0.333333333333333315,0.0666666666666666657],"xyz":[0.04009196298795141,0.0687732486827650757,0.0164651841725984571],"hpluv":[123.178290947815412,165.138012967735222,31.5259896590935043],"hsluv":[123.178290947815412,90.3912533003173877,31.5259896590935043]},"#225522":{"lch":[31.6981615382414716,36.1013694166085486,127.715012949239792],"luv":[31.6981615382414716,-22.0844473877159331,28.5584673491706482],"rgb":[0.133333333333333331,0.333333333333333315,0.133333333333333331],"xyz":[0.0419673211264284252,0.0695233919381558901,0.0263420703685776497],"hpluv":[127.715012949239792,144.520324593974209,31.6981615382414716],"hsluv":[127.715012949239792,73.5866039174798345,31.6981615382414716]},"#225533":{"lch":[31.9789617713411829,29.2625646618711706,137.400330584271074],"luv":[31.9789617713411829,-21.5402028917408828,19.8070025489176231],"rgb":[0.133333333333333331,0.333333333333333315,0.2],"xyz":[0.0450550718588861657,0.070758492231139,0.0426042242261888],"hpluv":[137.400330584271074,116.114739730974975,31.9789617713411829],"hsluv":[137.400330584271074,75.0932106461487,31.9789617713411829]},"#225544":{"lch":[32.3786649626227785,22.5648709259736577,157.632626155133437],"luv":[32.3786649626227785,-20.8671549807805796,8.58692278490586247],"rgb":[0.133333333333333331,0.333333333333333315,0.266666666666666663],"xyz":[0.0495130671031050462,0.072541690328826583,0.0660829991790754384],"hpluv":[157.632626155133437,88.4327727432137465,32.3786649626227785],"hsluv":[157.632626155133437,76.9882679005547459,32.3786649626227785]},"#225555":{"lch":[32.9031430542149863,20.5945867127178737,192.177050630061132],"luv":[32.9031430542149863,-20.1312179923833199,-4.34408379417313384],"rgb":[0.133333333333333331,0.333333333333333315,0.333333333333333315],"xyz":[0.0554754811424670383,0.0749266559445714159,0.0974850464530493399],"hpluv":[192.177050630061132,79.4245973683706268,32.9031430542149863],"hsluv":[192.177050630061132,79.1137061933639245,32.9031430542149863]},"#225566":{"lch":[33.5545056011551,26.6006796322727546,223.177731373198952],"luv":[33.5545056011551,-19.398136743372234,-18.2018803364993715],"rgb":[0.133333333333333331,0.333333333333333315,0.4],"xyz":[0.0630604769159752165,0.0779606542539747344,0.137432690860193302],"hpluv":[223.177731373198952,100.596116474312993,33.5545056011551],"hsluv":[223.177731373198952,81.3097794801720113,33.5545056011551]},"#225577":{"lch":[34.3316296590174,37.3644949384619807,239.932022094073261],"luv":[34.3316296590174,-18.7206257951117045,-32.3364137134245127],"rgb":[0.133333333333333331,0.333333333333333315,0.466666666666666674],"xyz":[0.0723744899361771221,0.0816862594620555438,0.186486492766591211],"hpluv":[239.932022094073261,138.103289638438355,34.3316296590174],"hsluv":[239.932022094073261,83.4469752602442298,34.3316296590174]},"#225588":{"lch":[35.230707776085,49.7211482448765594,248.610781811292384],"luv":[35.230707776085,-18.1333810040152876,-46.2965773697387775],"rgb":[0.133333333333333331,0.333333333333333315,0.533333333333333326],"xyz":[0.0835149070381209502,0.0861424263028331416,0.245159356170163378],"hpluv":[248.610781811292384,179.084957393431893,35.230707776085],"hsluv":[248.610781811292384,85.4385601139613158,35.230707776085]},"#225599":{"lch":[36.2458273864096512,62.3718238545276336,253.557833057747018],"luv":[36.2458273864096512,-17.6541819100499602,-59.8211858126123],"rgb":[0.133333333333333331,0.333333333333333315,0.6],"xyz":[0.0965718711471936775,0.0913652119464623,0.313926033811281313],"hpluv":[253.557833057747018,218.35832406203005,36.2458273864096512],"hsluv":[253.557833057747018,87.2381583586425791,36.2458273864096512]},"#2255aa":{"lch":[37.3695533294905928,74.8190204360075,256.640324292617947],"luv":[37.3695533294905928,-17.2879233745104131,-72.7943234352841841],"rgb":[0.133333333333333331,0.333333333333333315,0.66666666666666663],"xyz":[0.111629564112446206,0.0973882891325634,0.393229883428279914],"hpluv":[256.640324292617947,254.058329165629146,37.3695533294905928],"hsluv":[256.640324292617947,88.8301308270208807,37.3695533294905928]},"#2255bb":{"lch":[38.5934754222231291,86.8805221786483,258.695157685582501],"luv":[38.5934754222231291,-17.0311035792378,-85.1948745225196831],"rgb":[0.133333333333333331,0.333333333333333315,0.733333333333333282],"xyz":[0.128767156219782852,0.104243325975498152,0.48348786852692166],"hpluv":[258.695157685582501,285.658965815982469,38.5934754222231291],"hsluv":[258.695157685582501,90.2188193496234874,38.5934754222231291]},"#2255cc":{"lch":[39.9086891196534097,98.5112685419302,260.136263381096],"luv":[39.9086891196534097,-16.8755295039118458,-97.0550695930042],"rgb":[0.133333333333333331,0.333333333333333315,0.8],"xyz":[0.148059531663504607,0.111960276152986954,0.585094379197191761],"hpluv":[260.136263381096,313.22597901471056,39.9086891196534097],"hsluv":[260.136263381096,91.4196885710314433,39.9086891196534097]},"#2255dd":{"lch":[41.3061900239028503,109.727240919989157,261.187210775965298],"luv":[41.3061900239028503,-16.8109176424286737,-108.431823962952976],"rgb":[0.133333333333333331,0.333333333333333315,0.866666666666666696],"xyz":[0.16957785721413815,0.120567606373240488,0.698424227097197758],"hpluv":[261.187210775965298,337.084394380702577,41.3061900239028503],"hsluv":[261.187210775965298,92.4531471705562353,41.3061900239028503]},"#2255ee":{"lch":[42.7771763125841602,120.569176865205208,261.977669343247612],"luv":[42.7771763125841602,-16.8265186863462972,-119.389256965822398],"rgb":[0.133333333333333331,0.333333333333333315,0.933333333333333348],"xyz":[0.193390037480312887,0.130092478479710533,0.823835043165721],"hpluv":[261.977669343247612,357.654347674158601,42.7771763125841602],"hsluv":[261.977669343247612,93.3407272081067,42.7771763125841602]},"#2255ff":{"lch":[44.3132637322964129,131.084767922007643,262.587267096581058],"luv":[44.3132637322964129,-16.9120289519133,-129.989229007238322],"rgb":[0.133333333333333331,0.333333333333333315,1],"xyz":[0.219561085890144281,0.140560897843643229,0.961669231457502827],"hpluv":[262.587267096581058,375.368494421854962,44.3132637322964129],"hsluv":[262.587267096581058,99.9999999999993463,44.3132637322964129]},"#77ee00":{"lch":[84.5193058633960703,115.647601499010833,119.483871035599748],"luv":[84.5193058633960703,-56.9192667804191,100.670575649757225],"rgb":[0.466666666666666674,0.933333333333333348,0],"xyz":[0.381807757380814794,0.650690513347127,0.105476708327643554],"hpluv":[119.483871035599748,321.869538605652735,84.5193058633960703],"hsluv":[119.483871035599748,100.000000000002359,84.5193058633960703]},"#77ee11":{"lch":[84.5401392884337355,114.795422022346642,119.691827475064969],"luv":[84.5401392884337355,-56.862163274863434,99.7230329712822083],"rgb":[0.466666666666666674,0.933333333333333348,0.0666666666666666657],"xyz":[0.382819422880451898,0.651095179546981928,0.11080481329239919],"hpluv":[119.691827475064969,319.985367790437692,84.5401392884337355],"hsluv":[119.691827475064969,98.9722780394741477,84.5401392884337355]},"#77ee22":{"lch":[84.5787360835130499,113.228793274865538,120.083373039169615],"luv":[84.5787360835130499,-56.7570256545281637,97.9765260934141651],"rgb":[0.466666666666666674,0.933333333333333348,0.133333333333333331],"xyz":[0.384694781018928955,0.651845322802372729,0.120681699488378383],"hpluv":[120.083373039169615,316.512949618186383,84.5787360835130499],"hsluv":[120.083373039169615,97.0790709390529,84.5787360835130499]},"#77ee33":{"lch":[84.6422206992536275,110.686316006337648,120.745647293955486],"luv":[84.6422206992536275,-56.585921413754825,95.1288286946244313],"rgb":[0.466666666666666674,0.933333333333333348,0.2],"xyz":[0.387782531751386661,0.653080423095355855,0.136943853345989519],"hpluv":[120.745647293955486,310.853610471304819,84.6422206992536275],"hsluv":[120.745647293955486,93.9952250088888093,84.6422206992536275]},"#77ee44":{"lch":[84.7337366993681513,107.096480548503891,121.742158736883837],"luv":[84.7337366993681513,-56.3431952848259598,91.0774422728923412],"rgb":[0.466666666666666674,0.933333333333333348,0.266666666666666663],"xyz":[0.392240526995605576,0.654863621193043421,0.160422628298876158],"hpluv":[121.742158736883837,302.811644310583176,84.7337366993681513],"hsluv":[121.742158736883837,89.6144795711786628,84.7337366993681513]},"#77ee55":{"lch":[84.8558768548969766,102.444399932600575,123.154228511336783],"luv":[84.8558768548969766,-56.0262879596216621,85.7666026785261266],"rgb":[0.466666666666666674,0.933333333333333348,0.333333333333333315],"xyz":[0.398202941034967561,0.657248586808788171,0.191824675572850073],"hpluv":[123.154228511336783,292.298881153811294,84.8558768548969766],"hsluv":[123.154228511336783,83.883891015311761,84.8558768548969766]},"#77ee66":{"lch":[85.0108293450033159,96.7735040486586,125.092887734820366],"luv":[85.0108293450033159,-55.6354444449268186,79.1821217654036],"rgb":[0.466666666666666674,0.933333333333333348,0.4],"xyz":[0.405787936808475747,0.66028258511819149,0.231772319979994035],"hpluv":[125.092887734820366,279.341716913636219,85.0108293450033159],"hsluv":[125.092887734820366,76.7984153057879411,85.0108293450033159]},"#77ee77":{"lch":[85.2004556710930814,90.1918871908529667,127.71501294923965],"luv":[85.2004556710930814,-55.1734745704367882,71.3474892261312306],"rgb":[0.466666666666666674,0.933333333333333348,0.466666666666666674],"xyz":[0.415101949828677652,0.664008190326272341,0.280826121886391944],"hpluv":[127.71501294923965,264.105357222364148,85.2004556710930814],"hsluv":[127.71501294923965,68.3966317942099522,85.2004556710930814]},"#77ee88":{"lch":[85.4263369442757323,82.8846309918514521,131.246169999264879],"luv":[85.4263369442757323,-54.6454688778224167,62.3196179848555],"rgb":[0.466666666666666674,0.933333333333333348,0.533333333333333326],"xyz":[0.426242366930621452,0.668464357167049883,0.339498985289964139],"hpluv":[131.246169999264879,246.94310788397641,85.4263369442757323],"hsluv":[131.246169999264879,69.0963798671032379,85.4263369442757323]},"#77ee99":{"lch":[85.6898036798217,75.1362836057233,136.010896750223054],"luv":[85.6898036798217,-54.0584447513185395,52.1837682153016473],"rgb":[0.466666666666666674,0.933333333333333348,0.6],"xyz":[0.439299331039694207,0.673687142810679096,0.408265662931082],"hpluv":[136.010896750223054,228.489214549916312,85.6898036798217],"hsluv":[136.010896750223054,69.8780652000076827,85.6898036798217]},"#77eeaa":{"lch":[85.9919564191548602,67.3699388554866232,142.461966648640384],"luv":[85.9919564191548602,-53.4209300451477489,41.0476904892764551],"rgb":[0.466666666666666674,0.933333333333333348,0.66666666666666663],"xyz":[0.454357024004946708,0.679710219996780163,0.487569512548080619],"hpluv":[142.461966648640384,209.826142071523691,85.9919564191548602],"hsluv":[142.461966648640384,70.7318226594993575,85.9919564191548602]},"#77eebb":{"lch":[86.3336811163097337,60.2064759054885243,151.166773543866697],"luv":[86.3336811163097337,-52.7425080063862524,29.0352818163428843],"rgb":[0.466666666666666674,0.933333333333333348,0.733333333333333282],"xyz":[0.471494616112283382,0.686565256839714921,0.577827497646722366],"hpluv":[151.166773543866697,192.758378827545073,86.3336811163097337],"hsluv":[151.166773543866697,71.6464628016145895,86.3336811163097337]},"#77eecc":{"lch":[86.7156615657761449,54.5207620102438284,162.626180625161169],"luv":[86.7156615657761449,-52.0333543078463094,16.2801575438255028],"rgb":[0.466666666666666674,0.933333333333333348,0.8],"xyz":[0.490786991556005137,0.694282207017203778,0.679434008316992522],"hpluv":[162.626180625161169,180.150974339718545,86.7156615657761449],"hsluv":[162.626180625161169,72.6100300694190111,86.7156615657761449]},"#77eedd":{"lch":[87.1383902516757445,51.3868015721907483,176.742975614533037],"luv":[87.1383902516757445,-51.3037971188162771,2.91955082350760353],"rgb":[0.466666666666666674,0.933333333333333348,0.866666666666666696],"xyz":[0.512305317106638625,0.702889537237457285,0.792763856216998519],"hpluv":[176.742975614533037,175.997429168902841,87.1383902516757445],"hsluv":[176.742975614533037,73.6103328445444305,87.1383902516757445]},"#77eeee":{"lch":[87.6021784736708327,51.7277775307036,192.177050630061075],"luv":[87.6021784736708327,-50.5639263491039941,-10.9111099540033418],"rgb":[0.466666666666666674,0.933333333333333348,0.933333333333333348],"xyz":[0.536117497372813334,0.712414409343927302,0.918174672285521742],"hpluv":[192.177050630061075,184.503896016801804,87.6021784736708327],"hsluv":[192.177050630061075,74.6354143053272594,87.6021784736708327]},"#77eeff":{"lch":[88.107166277409533,55.7808213308350673,206.722210113893169],"luv":[88.107166277409533,-49.8232704905303336,-25.0826981397535107],"rgb":[0.466666666666666674,0.933333333333333348,1],"xyz":[0.562288545782644755,0.72288282870786,1.05600886057730348],"hpluv":[206.722210113893169,208.278116369071,88.107166277409533],"hsluv":[206.722210113893169,99.9999999999928804,88.107166277409533]},"#226600":{"lch":[37.5582057574881532,54.1200869321592961,123.236537452327113],"luv":[37.5582057574881532,-29.6630419039077431,45.2668505040000824],"rgb":[0.133333333333333331,0.4,0],"xyz":[0.0541083551941607538,0.0984246978946035633,0.0161464317764581713],"hpluv":[123.236537452327113,182.849162381267462,37.5582057574881532],"hsluv":[123.236537452327113,100.000000000002288,37.5582057574881532]},"#226611":{"lch":[37.6315056544729529,51.7196180195473119,124.710513292064419],"luv":[37.6315056544729529,-29.4507212427394194,42.5155725160833242],"rgb":[0.133333333333333331,0.4,0.0666666666666666657],"xyz":[0.0551200206937978721,0.0988293640944584162,0.0214745367412138],"hpluv":[124.710513292064419,174.398618448608886,37.6315056544729529],"hsluv":[124.710513292064419,93.2756924270169918,37.6315056544729529]},"#226622":{"lch":[37.7668566222969062,47.5272711912458519,127.715012949240034],"luv":[37.7668566222969062,-29.0740638670039928,37.5970785719263176],"rgb":[0.133333333333333331,0.4,0.133333333333333331],"xyz":[0.0569953788322748942,0.0995795073498492306,0.031351422937193],"hpluv":[127.715012949240034,159.687663587322874,37.7668566222969062],"hsluv":[127.715012949240034,81.309482828258183,37.7668566222969062]},"#226633":{"lch":[37.9882367851431084,41.3581300307957349,133.555287588173542],"luv":[37.9882367851431084,-28.497993426715972,29.9726423642471254],"rgb":[0.133333333333333331,0.4,0.2],"xyz":[0.0600831295647326347,0.100814607642832343,0.0476135767948041438],"hpluv":[133.555287588173542,138.150062101989391,37.9882367851431084],"hsluv":[133.555287588173542,82.0766642375396742,37.9882367851431084]},"#226644":{"lch":[38.3046909892153806,34.1393686276432291,144.379277801066621],"luv":[38.3046909892153806,-27.7515572052733894,19.8833488873617412],"rgb":[0.133333333333333331,0.4,0.266666666666666663],"xyz":[0.0645411248089515083,0.102597805740519923,0.0710923517476907824],"hpluv":[144.379277801066621,113.094855071532635,38.3046909892153806],"hsluv":[144.379277801066621,83.0794073538424414,38.3046909892153806]},"#226655":{"lch":[38.7222568592555234,28.0005039743963025,163.778220785970291],"luv":[38.7222568592555234,-26.8857357715149732,7.82211191715276755],"rgb":[0.133333333333333331,0.4,0.333333333333333315],"xyz":[0.0705035388483135073,0.104982771356264756,0.102494399021664684],"hpluv":[163.778220785970291,91.7581213405574516,38.7222568592555234],"hsluv":[163.778220785970291,84.2573678500350809,38.7222568592555234]},"#226666":{"lch":[39.2444156655659739,26.5583838540848376,192.177050630061103],"luv":[39.2444156655659739,-25.9608324434988,-5.60204710632589631],"rgb":[0.133333333333333331,0.4,0.4],"xyz":[0.0780885346218216786,0.108016769665668075,0.142442043428808646],"hpluv":[192.177050630061103,85.8742788705857691,39.2444156655659739],"hsluv":[192.177050630061103,85.5381417500271652,39.2444156655659739]},"#226677":{"lch":[39.8723950361637449,31.9118423017057466,218.325872967111877],"luv":[39.8723950361637449,-25.034725973132506,-19.7895976345933065],"rgb":[0.133333333333333331,0.4,0.466666666666666674],"xyz":[0.0874025476420236,0.111742374873748884,0.191495845335206555],"hpluv":[218.325872967111877,101.559108573692257,39.8723950361637449],"hsluv":[218.325872967111877,86.8516914397336137,39.8723950361637449]},"#226688":{"lch":[40.6054458094686836,41.8995680003496318,234.7955790683381],"luv":[40.6054458094686836,-24.1549067561574908,-34.2361545477476241],"rgb":[0.133333333333333331,0.4,0.533333333333333326],"xyz":[0.0985429647439674261,0.116198541714526482,0.250168708738778722],"hpluv":[234.7955790683381,130.937664052949941,40.6054458094686836],"hsluv":[234.7955790683381,88.1401386465251733,40.6054458094686836]},"#226699":{"lch":[41.4411308461218226,53.8933488408681782,244.319142730286046],"luv":[41.4411308461218226,-23.3551142576285748,-48.5698639826860301],"rgb":[0.133333333333333331,0.4,0.6],"xyz":[0.11159992885304014,0.12142132735815564,0.318935386379896657],"hpluv":[244.319142730286046,165.022400136876769,41.4411308461218226],"hsluv":[244.319142730286046,89.3619383181549267,41.4411308461218226]},"#2266aa":{"lch":[42.3756299296545578,66.5269840788925251,250.089735516440328],"luv":[42.3756299296545578,-22.655631138578233,-62.5504755245386193],"rgb":[0.133333333333333331,0.4,0.66666666666666663],"xyz":[0.126657621818292682,0.127444404544256734,0.398239235996895258],"hpluv":[250.089735516440328,199.214522587526545,42.3756299296545578],"hsluv":[250.089735516440328,90.4915899210210597,42.3756299296545578]},"#2266bb":{"lch":[43.404050412459263,79.1834510223872599,253.819475134999237],"luv":[43.404050412459263,-22.0656311263342282,-76.0468726432017803],"rgb":[0.133333333333333331,0.4,0.733333333333333282],"xyz":[0.143795213925629328,0.134299441387191493,0.488497221095537],"hpluv":[253.819475134999237,231.496000814517572,43.404050412459263],"hsluv":[253.819475134999237,91.5168425909476895,43.404050412459263]},"#2266cc":{"lch":[44.520728505208055,91.5877705166709,256.367788484306971],"luv":[44.520728505208055,-21.5861851194902563,-89.0076194502553193],"rgb":[0.133333333333333331,0.4,0.8],"xyz":[0.163087589369351083,0.142016391564680294,0.590103731765807105],"hpluv":[256.367788484306971,261.044502527732277,44.520728505208055],"hsluv":[256.367788484306971,92.43509558526695,44.520728505208055]},"#2266dd":{"lch":[45.7195068588792211,103.627896901795907,258.1878164043369],"luv":[45.7195068588792211,-21.2130654589597789,-101.433460308337743],"rgb":[0.133333333333333331,0.4,0.866666666666666696],"xyz":[0.184605914919984626,0.150623721784933828,0.703433579665813102],"hpluv":[258.1878164043369,287.616948003961852,45.7195068588792211],"hsluv":[258.1878164043369,93.2500413525610696,45.7195068588792211]},"#2266ee":{"lch":[46.9939777237187144,115.273293340910215,259.534328145616598],"luv":[46.9939777237187144,-20.9389771714321675,-113.35559709460216],"rgb":[0.133333333333333331,0.4,0.933333333333333348],"xyz":[0.208418095186159336,0.160148593891403873,0.828844395734336326],"hpluv":[259.534328145616598,311.261797341727515,46.9939777237187144],"hsluv":[259.534328145616598,93.969002023907521,46.9939777237187144]},"#2266ff":{"lch":[48.3376856243364728,126.534150990995641,260.559220542156197],"luv":[48.3376856243364728,-20.75515631493003,-124.820330288598825],"rgb":[0.133333333333333331,0.4,1],"xyz":[0.234589143595990757,0.170617013255336569,0.966678584026118171],"hpluv":[260.559220542156197,332.170629177470857,48.3376856243364728],"hsluv":[260.559220542156197,99.9999999999992184,48.3376856243364728]},"#77ff00":{"lch":[89.5984732569245921,124.632639236881928,120.733702851753719],"luv":[89.5984732569245921,-63.6933378884713406,107.128210438594465],"rgb":[0.466666666666666674,1,0],"xyz":[0.433660129810488626,0.754395258206476127,0.122760832470867665],"hpluv":[120.733702851753719,538.628162219261071,89.5984732569245921],"hsluv":[120.733702851753719,100.000000000002359,89.5984732569245921]},"#77ff11":{"lch":[89.6173512893739144,123.857431845856226,120.915842858481739],"luv":[89.6173512893739144,-63.635285050623331,106.260123846986147],"rgb":[0.466666666666666674,1,0.0666666666666666657],"xyz":[0.43467179531012573,0.754799924406331,0.128088937435623301],"hpluv":[120.915842858481739,536.333532616984598,89.6173512893739144],"hsluv":[120.915842858481739,99.9999999999912461,89.6173512893739144]},"#77ff22":{"lch":[89.6523282897647107,122.430860002153082,121.257903913559275],"luv":[89.6523282897647107,-63.5282943614823736,104.658832863679763],"rgb":[0.466666666666666674,1,0.133333333333333331],"xyz":[0.436547153448602787,0.755550067661721836,0.13796582363160248],"hpluv":[121.257903913559275,532.099457877515,89.6523282897647107],"hsluv":[121.257903913559275,99.9999999999912319,89.6523282897647107]},"#77ff33":{"lch":[89.7098670229763684,120.111567958755899,121.833904144252088],"luv":[89.7098670229763684,-63.3538816193187557,102.044472860004433],"rgb":[0.466666666666666674,1,0.2],"xyz":[0.439634904181060493,0.756785167954705,0.15422797748921363],"hpluv":[121.833904144252088,525.184015431200237,89.7098670229763684],"hsluv":[121.833904144252088,99.9999999999911893,89.7098670229763684]},"#77ff44":{"lch":[89.7928292607091834,116.827732221897932,122.694629127971339],"luv":[89.7928292607091834,-63.1058355300939766,98.317712230097257],"rgb":[0.466666666666666674,1,0.266666666666666663],"xyz":[0.444092899425279408,0.758568366052392529,0.177706752442100269],"hpluv":[122.694629127971339,515.324540814372313,89.7928292607091834],"hsluv":[122.694629127971339,99.9999999999912319,89.7928292607091834]},"#77ff55":{"lch":[89.9035853929870683,112.554947355203538,123.902387884937639],"luv":[89.9035853929870683,-62.7808648215699492,93.4193726503684161],"rgb":[0.466666666666666674,1,0.333333333333333315],"xyz":[0.450055313464641393,0.760953331668137278,0.209108799716074184],"hpluv":[123.902387884937639,502.374863630046946,89.9035853929870683],"hsluv":[123.902387884937639,99.9999999999911466,89.9035853929870683]},"#77ff66":{"lch":[90.0441481999633169,107.316590618570714,125.538864396596409],"luv":[90.0441481999633169,-62.3783098318914213,87.3258099562234662],"rgb":[0.466666666666666674,1,0.4],"xyz":[0.457640309238149579,0.763987329977540597,0.249056444123218146],"hpluv":[125.538864396596409,486.310350268178581,90.0441481999633169],"hsluv":[125.538864396596409,99.9999999999909193,90.0441481999633169]},"#77ff77":{"lch":[90.2162444924982,101.18761180958829,127.715012949239778],"luv":[90.2162444924982,-61.8999369112410065,80.0458031011764746],"rgb":[0.466666666666666674,1,0.466666666666666674],"xyz":[0.466954322258351484,0.767712935185621448,0.298110246029616055],"hpluv":[127.715012949239778,467.252180695244249,90.2162444924982],"hsluv":[127.715012949239778,99.9999999999908908,90.2162444924982]},"#77ff88":{"lch":[90.4213578195287084,94.3018691223763312,130.584388318929172],"luv":[90.4213578195287084,-61.3497133683486666,71.6174223886566352],"rgb":[0.466666666666666674,1,0.533333333333333326],"xyz":[0.478094739360295284,0.772169102026399,0.35678310943318825],"hpluv":[130.584388318929172,445.517691352744919,90.4213578195287084],"hsluv":[130.584388318929172,99.999999999990834,90.4213578195287084]},"#77ff99":{"lch":[90.660755936805927,86.8649116623181,134.360625617567337],"luv":[90.660755936805927,-60.7335297134313734,62.1043577106315],"rgb":[0.466666666666666674,1,0.6],"xyz":[0.491151703469368,0.777391887670028203,0.425549787074306129],"hpluv":[134.360625617567337,421.714412879972315,90.660755936805927],"hsluv":[134.360625617567337,99.9999999999904645,90.660755936805927]},"#77ffaa":{"lch":[90.9355096576679927,79.1755179707932513,139.336843070371486],"luv":[90.9355096576679927,-60.0588662825700368,51.5916197341755947],"rgb":[0.466666666666666674,1,0.66666666666666663],"xyz":[0.506209396434620595,0.78341496485612927,0.504853636691304786],"hpluv":[139.336843070371486,396.909453229520182,90.9355096576679927],"hsluv":[139.336843070371486,99.9999999999902371,90.9355096576679927]},"#77ffbb":{"lch":[91.2465066485729466,71.6593730134265599,145.894485367843032],"luv":[91.2465066485729466,-59.3344173347434776,40.1807498713488229],"rgb":[0.466666666666666674,1,0.733333333333333282],"xyz":[0.523346988541957159,0.790270001699064,0.595111621789946477],"hpluv":[145.894485367843032,372.920765055848051,91.2465066485729466],"hsluv":[145.894485367843032,99.9999999999901803,91.2465066485729466]},"#77ffcc":{"lch":[91.5944622372901591,64.9119206982031329,154.461378490718602],"luv":[91.5944622372901591,-58.5696939322881676,27.9847887504604707],"rgb":[0.466666666666666674,1,0.8],"xyz":[0.542639363985678913,0.797986951876552886,0.696718132460216633],"hpluv":[154.461378490718602,352.767904832744364,91.5944622372901591],"hsluv":[154.461378490718602,99.999999999989825,91.5944622372901591]},"#77ffdd":{"lch":[91.9799284987297,59.7212008687906604,165.331177548206284],"luv":[91.9799284987297,-57.7746296637575298,15.1232933062250314],"rgb":[0.466666666666666674,1,0.866666666666666696],"xyz":[0.564157689536312512,0.806594282096806392,0.81004798036022263],"hpluv":[165.331177548206284,341.200809564626638,91.9799284987297],"hsluv":[165.331177548206284,99.9999999999894698,91.9799284987297]},"#77ffee":{"lch":[92.4033024177180238,56.9851054432815545,178.272694676027839],"luv":[92.4033024177180238,-56.9592119034112,1.71767916801026743],"rgb":[0.466666666666666674,1,0.933333333333333348],"xyz":[0.587969869802487222,0.816119154203276409,0.935458796428745853],"hpluv":[178.272694676027839,344.865805035808421,92.4033024177180238],"hsluv":[178.272694676027839,99.9999999999889582,92.4033024177180238]},"#77ffff":{"lch":[92.8648336399367196,57.4251975820971623,192.177050630061018],"luv":[92.8648336399367196,-56.1331570721439945,-12.112885471963672],"rgb":[0.466666666666666674,1,1],"xyz":[0.614140918212318643,0.826587573567209133,1.0732929847205277],"hpluv":[192.177050630061018,371.354821198433683,92.8648336399367196],"hsluv":[192.177050630061018,99.9999999999883187,92.8648336399367196]},"#227700":{"lch":[43.5559297152692295,63.9882214930525208,124.519604676885976],"luv":[43.5559297152692295,-36.2613695379953711,52.7219647687080268],"rgb":[0.133333333333333331,0.466666666666666674,0],"xyz":[0.0725620932475783825,0.13533217400143932,0.0222976777942638753],"hpluv":[124.519604676885976,186.419817132403381,43.5559297152692295],"hsluv":[124.519604676885976,100.000000000002331,43.5559297152692295]},"#227711":{"lch":[43.6152314308602769,61.9621092027414093,125.591738779589861],"luv":[43.6152314308602769,-36.0623023987336282,50.3866383335378174],"rgb":[0.133333333333333331,0.466666666666666674,0.0666666666666666657],"xyz":[0.0735737587472155,0.135736840201294173,0.0276257827590195085],"hpluv":[125.591738779589861,180.271610265320959,43.6152314308602769],"hsluv":[125.591738779589861,95.0867888092805345,43.6152314308602769]},"#227722":{"lch":[43.7248500006056062,58.3665782213362476,127.715012949240148],"luv":[43.7248500006056062,-35.7048401974777292,46.1716562377823081],"rgb":[0.133333333333333331,0.466666666666666674,0.133333333333333331],"xyz":[0.0754491168856925298,0.136486983456685,0.0375026689549987],"hpluv":[127.715012949240148,169.385110384242353,43.7248500006056062],"hsluv":[127.715012949240148,86.2472116803111248,43.7248500006056062]},"#227733":{"lch":[43.9044636679785,52.8998675233047422,131.63685913347058],"luv":[43.9044636679785,-35.1470498804547518,39.5358175416168365],"rgb":[0.133333333333333331,0.466666666666666674,0.2],"xyz":[0.0785368676181502634,0.137722083749668101,0.0537648228126098443],"hpluv":[131.63685913347058,152.892166506547881,43.9044636679785],"hsluv":[131.63685913347058,86.6671370230467204,43.9044636679785]},"#227744":{"lch":[44.1618994548856207,46.0187725021067919,138.382113458020484],"luv":[44.1618994548856207,-34.403210499316,30.5638107889119937],"rgb":[0.133333333333333331,0.466666666666666674,0.266666666666666663],"xyz":[0.082994862862369137,0.139505281847355694,0.0772435977654964828],"hpluv":[138.382113458020484,132.228969104156789,44.1618994548856207],"hsluv":[138.382113458020484,87.230083060842972,44.1618994548856207]},"#227755":{"lch":[44.5028042963196171,38.7961505601339098,149.7341572603126],"luv":[44.5028042963196171,-33.5080868304533865,19.5537570621958743],"rgb":[0.133333333333333331,0.466666666666666674,0.333333333333333315],"xyz":[0.088957276901731136,0.141890247463100527,0.108645645039470398],"hpluv":[149.7341572603126,110.621765171639552,44.5028042963196171],"hsluv":[149.7341572603126,87.9126674499387235,44.5028042963196171]},"#227766":{"lch":[44.9310046324235657,33.2418513983527504,167.948858330193701],"luv":[44.9310046324235657,-32.5092552143098246,6.94038974417402166],"rgb":[0.133333333333333331,0.466666666666666674,0.4],"xyz":[0.0965422726752393073,0.144924245772503818,0.148593289446614346],"hpluv":[167.948858330193701,93.8811500215461,44.9310046324235657],"hsluv":[167.948858330193701,88.6822605795820778,44.9310046324235657]},"#227777":{"lch":[45.4487163896678652,32.1827345016432886,192.177050630061217],"luv":[45.4487163896678652,-31.4586377906525136,-6.7884098550242733],"rgb":[0.133333333333333331,0.466666666666666674,0.466666666666666674],"xyz":[0.105856285695441227,0.148649850980584641,0.197647091353012255],"hpluv":[192.177050630061217,89.8546686552558,45.4487163896678652],"hsluv":[192.177050630061217,89.5029511213474,45.4487163896678652]},"#227788":{"lch":[46.0567093690380389,37.0457871068229778,214.840569513336618],"luv":[46.0567093690380389,-30.4051407329018595,-21.1640676472289648],"rgb":[0.133333333333333331,0.466666666666666674,0.533333333333333326],"xyz":[0.116996702797385055,0.153106017821362239,0.256319954756584423],"hpluv":[214.840569513336618,102.066975938242322,46.0567093690380389],"hsluv":[214.840569513336618,90.3407286635711415,46.0567093690380389]},"#227799":{"lch":[46.7544651468991219,46.3079141704010908,230.605362437026685],"luv":[46.7544651468991219,-29.3896969252833173,-35.7864308006991223],"rgb":[0.133333333333333331,0.466666666666666674,0.6],"xyz":[0.130053666906457754,0.158328803464991397,0.325086632397702358],"hpluv":[230.605362437026685,125.681528260779189,46.7544651468991219],"hsluv":[230.605362437026685,91.1669787694701,46.7544651468991219]},"#2277aa":{"lch":[47.5403420753171133,57.8256716053654429,240.536105931551504],"luv":[47.5403420753171133,-28.4430017925967782,-50.3468365007961935],"rgb":[0.133333333333333331,0.466666666666666674,0.66666666666666663],"xyz":[0.14511135987171031,0.164351880651092491,0.404390482014700958],"hpluv":[240.536105931551504,154.346828351852139,47.5403420753171133],"hsluv":[240.536105931551504,91.9600907928071365,47.5403420753171133]},"#2277bb":{"lch":[48.4117490016133161,70.2708193466387172,246.886175208709233],"luv":[48.4117490016133161,-27.5854458877112236,-64.6299561103370337],"rgb":[0.133333333333333331,0.466666666666666674,0.733333333333333282],"xyz":[0.162248951979046957,0.17120691749402725,0.494648467113342705],"hpluv":[246.886175208709233,184.188949495161438,48.4117490016133161],"hsluv":[246.886175208709233,92.7055270960754427,48.4117490016133161]},"#2277cc":{"lch":[49.3653235224945348,82.9601291275659634,251.131977113837081],"luv":[49.3653235224945348,-26.8284223951791141,-78.5023488607078],"rgb":[0.133333333333333331,0.466666666666666674,0.8],"xyz":[0.181541327422768684,0.178923867671516051,0.596254977783612805],"hpluv":[251.131977113837081,213.248879712122147,49.3653235224945348],"hsluv":[251.131977113837081,93.3949294454883301,49.3653235224945348]},"#2277dd":{"lch":[50.3971082370692898,95.5506012475210156,254.100456017762497],"luv":[50.3971082370692898,-26.1762366694964186,-91.8951687118820928],"rgb":[0.133333333333333331,0.466666666666666674,0.866666666666666696],"xyz":[0.203059652973402227,0.187531197891769585,0.709584825683618803],"hpluv":[254.100456017762497,240.584217083197558,50.3971082370692898],"hsluv":[254.100456017762497,94.0248036114472399,50.3971082370692898]},"#2277ee":{"lch":[51.5027182397596448,107.874744495734575,256.256689112315712],"luv":[51.5027182397596448,-25.6280715933506258,-104.786270314512635],"rgb":[0.133333333333333331,0.466666666666666674,0.933333333333333348],"xyz":[0.226871833239577,0.19705606999823963,0.834995641752142],"hpluv":[256.256689112315712,265.784074864026707,51.5027182397596448],"hsluv":[256.256689112315712,94.5951642228933594,51.5027182397596448]},"#2277ff":{"lch":[52.6774941409559432,119.859275592882611,257.873120264558906],"luv":[52.6774941409559432,-25.1797078347732324,-117.18459053564186],"rgb":[0.133333333333333331,0.466666666666666674,1],"xyz":[0.253042881649408358,0.207524489362172326,0.972829830043923871],"hpluv":[257.873120264558906,288.725982332353851,52.6774941409559432],"hsluv":[257.873120264558906,99.9999999999990195,52.6774941409559432]},"#228800":{"lch":[49.4326013626652951,73.5543249838887903,125.335546592141156],"luv":[49.4326013626652951,-42.5411625112882845,60.0040683289365475],"rgb":[0.133333333333333331,0.533333333333333326,0],"xyz":[0.0946344629725488357,0.179476913451380865,0.0296551343692538216],"hpluv":[125.335546592141156,188.81394887832684,49.4326013626652951],"hsluv":[125.335546592141156,100.000000000002359,49.4326013626652951]},"#228811":{"lch":[49.4817413630627669,71.8188220709608,126.143293588176633],"luv":[49.4817413630627669,-42.3592238010278379,57.9968909738682825],"rgb":[0.133333333333333331,0.533333333333333326,0.0666666666666666657],"xyz":[0.0956461284721859539,0.179881579651235718,0.0349832393340094513],"hpluv":[126.143293588176633,184.175827324420425,49.4817413630627669],"hsluv":[126.143293588176633,96.2839239867753776,49.4817413630627669]},"#228822":{"lch":[49.5726392440562904,68.7061860444130161,127.715012949240233],"luv":[49.5726392440562904,-42.0299333634258545,54.3509402148249521],"rgb":[0.133333333333333331,0.533333333333333326,0.133333333333333331],"xyz":[0.097521486610662983,0.180631722906626546,0.0448601255299886509],"hpluv":[127.715012949240233,175.870551812838869,49.5726392440562904],"hsluv":[127.715012949240233,89.549457305464,49.5726392440562904]},"#228833":{"lch":[49.7217546026668913,63.8760413965615115,130.529662443073192],"luv":[49.7217546026668913,-41.5093107949551552,48.5502397710151357],"rgb":[0.133333333333333331,0.533333333333333326,0.2],"xyz":[0.100609237343120717,0.181866823199609645,0.0611222793875997941],"hpluv":[130.529662443073192,163.016240956960957,49.7217546026668913],"hsluv":[130.529662443073192,89.7937238944362122,49.7217546026668913]},"#228844":{"lch":[49.9358562328630171,57.5522088774297558,135.149605574971361],"luv":[49.9358562328630171,-40.8016788905052792,40.5891579906186308],"rgb":[0.133333333333333331,0.533333333333333326,0.266666666666666663],"xyz":[0.10506723258733959,0.183650021297297239,0.0846010543404864257],"hpluv":[135.149605574971361,146.247625060139768,49.9358562328630171],"hsluv":[135.149605574971361,90.1269016918236616,49.9358562328630171]},"#228855":{"lch":[50.2200542052193697,50.3265642713731509,142.503880569306347],"luv":[50.2200542052193697,-39.9288227743001443,30.6341669254964764],"rgb":[0.133333333333333331,0.533333333333333326,0.333333333333333315],"xyz":[0.111029646626701589,0.186034986913042072,0.116003101614460341],"hpluv":[142.503880569306347,127.162609675202816,50.2200542052193697],"hsluv":[142.503880569306347,90.5399352865824341,50.2200542052193697]},"#228866":{"lch":[50.5781035519961648,43.3062651916131074,154.006170397495453],"luv":[50.5781035519961648,-38.9254575775356315,18.9800252166796355],"rgb":[0.133333333333333331,0.533333333333333326,0.4],"xyz":[0.11861464240020976,0.189068985222445363,0.155950746021604303],"hpluv":[154.006170397495453,108.649446020320369,50.5781035519961648],"hsluv":[154.006170397495453,91.0179493017372607,50.5781035519961648]},"#228877":{"lch":[51.0125694858746357,38.3061120533697519,170.992189866461246],"luv":[51.0125694858746357,-37.8336830583721451,5.997553408179356],"rgb":[0.133333333333333331,0.533333333333333326,0.466666666666666674],"xyz":[0.12792865542041168,0.192794590430526186,0.205004547928002212],"hpluv":[170.992189866461246,95.2862426106229634,51.0125694858746357],"hsluv":[170.992189866461246,91.5427076584867621,51.0125694858746357]},"#228888":{"lch":[51.5249413470067594,37.5420496271247259,192.177050630061103],"luv":[51.5249413470067594,-36.6973707929670923,-7.91886779085127834],"rgb":[0.133333333333333331,0.533333333333333326,0.533333333333333326],"xyz":[0.139069072522355508,0.197250757271303784,0.263677411331574407],"hpluv":[192.177050630061103,92.4570004995607775,51.5249413470067594],"hsluv":[192.177050630061103,92.0950966753639761,51.5249413470067594]},"#228899":{"lch":[52.1157302062907064,42.0223592343639183,212.203992327233067],"luv":[52.1157302062907064,-35.5574728144251,-22.3951959730954577],"rgb":[0.133333333333333331,0.533333333333333326,0.6],"xyz":[0.152126036631428208,0.202473542914932941,0.332444088972692287],"hpluv":[212.203992327233067,102.317738016510475,52.1157302062907064],"hsluv":[212.203992327233067,92.6571999954113465,52.1157302062907064]},"#2288aa":{"lch":[52.784565077464336,50.6329849579481888,227.127925237574203],"luv":[52.784565077464336,-34.4488478228089221,-37.1076279143892478],"rgb":[0.133333333333333331,0.533333333333333326,0.66666666666666663],"xyz":[0.167183729596680763,0.208496620101034036,0.411747938589690887],"hpluv":[227.127925237574203,121.72111165959474,52.784565077464336],"hsluv":[227.127925237574203,93.213704377986,52.784565077464336]},"#2288bb":{"lch":[53.5302933631107294,61.6316847476891141,237.186375672219185],"luv":[53.5302933631107294,-33.3987075035381409,-51.7975955226846381],"rgb":[0.133333333333333331,0.533333333333333326,0.733333333333333282],"xyz":[0.18432132170401741,0.215351656943968794,0.502005923688332634],"hpluv":[237.186375672219185,146.097822373379188,53.5302933631107294],"hsluv":[237.186375672219185,93.7525919029994,53.5302933631107294]},"#2288cc":{"lch":[54.351086283976727,73.7818378825302261,243.928624140525301],"luv":[54.351086283976727,-32.4264148607849876,-66.274333045306733],"rgb":[0.133333333333333331,0.533333333333333326,0.8],"xyz":[0.203613697147739137,0.223068607121457596,0.60361243435860279],"hpluv":[243.928624140525301,172.258462735913952,54.351086283976727],"hsluv":[243.928624140525301,94.2652369190112864,54.351086283976727]},"#2288dd":{"lch":[55.2445474530087779,86.375042864399532,248.580085361336785],"luv":[55.2445474530087779,-31.544198041281593,-80.4090268549449831],"rgb":[0.133333333333333331,0.533333333333333326,0.866666666666666696],"xyz":[0.22513202269837268,0.23167593734171113,0.716942282258608787],"hpluv":[248.580085361336785,198.39840761978212,55.2445474530087779],"hsluv":[248.580085361336785,94.7460999996689566,55.2445474530087779]},"#2288ee":{"lch":[56.2078215466105604,99.0227420546019772,251.903461744910402],"luv":[56.2078215466105604,-30.7583451142169402,-94.1245326673496265],"rgb":[0.133333333333333331,0.533333333333333326,0.933333333333333348],"xyz":[0.248944202964547445,0.241200809448181175,0.842353098327132],"hpluv":[251.903461744910402,223.551465466634539,56.2078215466105604],"hsluv":[251.903461744910402,95.1922101623356838,56.2078215466105604]},"#2288ff":{"lch":[57.2376997180489866,111.514610807296222,254.356224713070389],"luv":[57.2376997180489866,-30.0705415498761575,-107.383755542446536],"rgb":[0.133333333333333331,0.533333333333333326,1],"xyz":[0.275115251374378811,0.251669228812113843,0.980187286618913856],"hpluv":[254.356224713070389,247.223031548482197,57.2376997180489866],"hsluv":[254.356224713070389,99.9999999999988773,57.2376997180489866]},"#229900":{"lch":[55.1973816023000694,82.8565734474734086,125.883775052172936],"luv":[55.1973816023000694,-48.5657961090338617,67.1310301704979508],"rgb":[0.133333333333333331,0.6,0],"xyz":[0.120504063425016322,0.23121611435631656,0.0382783345200760766],"hpluv":[125.883775052172936,190.479314261094402,55.1973816023000694],"hsluv":[125.883775052172936,100.000000000002331,55.1973816023000694]},"#229911":{"lch":[55.2388931006948951,81.3509781714907376,126.510168490119042],"luv":[55.2388931006948951,-48.4010205856972817,65.3859530459048273],"rgb":[0.133333333333333331,0.6,0.0666666666666666657],"xyz":[0.121515728924653441,0.231620780556171413,0.0436064394848317063],"hpluv":[126.510168490119042,186.877552842351321,55.2388931006948951],"hsluv":[126.510168490119042,97.109403045153627,55.2388931006948951]},"#229922":{"lch":[55.3157166450500739,78.6308396618125869,127.715012949240275],"luv":[55.3157166450500739,-48.1011847922964293,62.2019691609440102],"rgb":[0.133333333333333331,0.6,0.133333333333333331],"xyz":[0.12339108706313047,0.232370923811562241,0.0534833256808109059],"hpluv":[127.715012949240275,180.378053709807,55.3157166450500739],"hsluv":[127.715012949240275,91.8445791693357592,55.3157166450500739]},"#229933":{"lch":[55.4418461137647,74.3518111171957656,129.829614369777261],"luv":[55.4418461137647,-47.6228343175573201,57.0986643273697],"rgb":[0.133333333333333331,0.6,0.2],"xyz":[0.126478837795588217,0.23360602410454534,0.0697454795384220561],"hpluv":[129.829614369777261,170.173995330187722,55.4418461137647],"hsluv":[129.829614369777261,91.9941043082508827,55.4418461137647]},"#229944":{"lch":[55.6231658975890042,68.6117263626113925,133.195472742568398],"luv":[55.6231658975890042,-46.964006542137362,50.0195070344354846],"rgb":[0.133333333333333331,0.6,0.266666666666666663],"xyz":[0.130936833039807077,0.235389222202232934,0.0932242544913087],"hpluv":[133.195472742568398,156.524371813771666,55.6231658975890042],"hsluv":[133.195472742568398,92.2005608183228844,55.6231658975890042]},"#229955":{"lch":[55.8642490130281715,61.7521412094073696,138.342726405552],"luv":[55.8642490130281715,-46.1371272258517706,41.0450049980768625],"rgb":[0.133333333333333331,0.6,0.333333333333333315],"xyz":[0.136899247079169062,0.237774187817977767,0.124626301765282596],"hpluv":[138.342726405552,140.267605312348593,55.8642490130281715],"hsluv":[138.342726405552,92.4605995247666357,55.8642490130281715]},"#229966":{"lch":[56.1686206396836383,54.4254646973719787,146.085824005346524],"luv":[56.1686206396836383,-45.1662924386951516,30.3667126121210664],"rgb":[0.133333333333333331,0.6,0.4],"xyz":[0.144484242852677247,0.240808186127381058,0.164573946172426544],"hpluv":[146.085824005346524,122.955430161041207,56.1686206396836383],"hsluv":[146.085824005346524,92.7673635780271,56.1686206396836383]},"#229977":{"lch":[56.5388973522399,47.7139826201784629,157.505617321427167],"luv":[56.5388973522399,-44.0837619060267798,18.2550287233801534],"rgb":[0.133333333333333331,0.6,0.466666666666666674],"xyz":[0.153798255872879153,0.244533791335461881,0.213627748078824453],"hpluv":[157.505617321427167,107.087223886255089,56.5388973522399],"hsluv":[157.505617321427167,93.1115325865156,56.5388973522399]},"#229988":{"lch":[56.9768757530356,43.2189787336254057,173.325138204180888],"luv":[56.9768757530356,-42.9260293704251126,5.02355703331473169],"rgb":[0.133333333333333331,0.6,0.533333333333333326],"xyz":[0.164938672974823,0.248989958176239479,0.272300611482396648],"hpluv":[173.325138204180888,96.2532040641867,56.9768757530356],"hsluv":[173.325138204180888,93.4824878896153706,56.9768757530356]},"#229999":{"lch":[57.4836007022547477,42.6905833214490045,192.177050630061103],"luv":[57.4836007022547477,-41.7300648492924537,-9.00486490733903366],"rgb":[0.133333333333333331,0.6,0.6],"xyz":[0.177995637083895708,0.254212743819868636,0.341067289123514528],"hpluv":[192.177050630061103,94.2383018299879467,57.4836007022547477],"hsluv":[192.177050630061103,93.8694254698009587,57.4836007022547477]},"#2299aa":{"lch":[58.0594270662980563,46.8633307325653,210.133219640519371],"luv":[58.0594270662980563,-40.5302437993065823,-23.5259666096543114],"rgb":[0.133333333333333331,0.6,0.66666666666666663],"xyz":[0.193053330049148264,0.260235821005969759,0.420371138740513128],"hpluv":[210.133219640519371,102.423528384682896,58.0594270662980563],"hsluv":[210.133219640519371,94.2622655036202701,58.0594270662980563]},"#2299bb":{"lch":[58.704081470592044,54.8976329577059445,224.200669016044458],"luv":[58.704081470592044,-39.3562485070025474,-38.2731734745639],"rgb":[0.133333333333333331,0.6,0.733333333333333282],"xyz":[0.210190922156484883,0.267090857848904517,0.51062912383915493],"hpluv":[224.200669016044458,118.665547847191604,58.704081470592044],"hsluv":[224.200669016044458,94.6522748426748279,58.704081470592044]},"#2299cc":{"lch":[59.4167266489170771,65.3729917945351247,234.209137470411804],"luv":[59.4167266489170771,-38.231976961148348,-53.0277662532618663],"rgb":[0.133333333333333331,0.6,0.8],"xyz":[0.229483297600206637,0.274807808026393319,0.612235634509425086],"hpluv":[234.209137470411804,139.613998456385502,59.4167266489170771],"hsluv":[234.209137470411804,95.032392249276171,59.4167266489170771]},"#2299dd":{"lch":[60.1960287785942114,77.1664383037622201,241.199920521286145],"luv":[60.1960287785942114,-37.1753089722913614,-67.6214137925481],"rgb":[0.133333333333333331,0.6,0.866666666666666696],"xyz":[0.251001623150840181,0.283415138246646825,0.725565482409431084],"hpluv":[241.199920521286145,162.667181112599422,60.1960287785942114],"hsluv":[241.199920521286145,95.397300800485425,60.1960287785942114]},"#2299ee":{"lch":[61.0402269370523243,89.5733454479413211,246.163931095701571],"luv":[61.0402269370523243,-36.1984881015500051,-81.9332269222821],"rgb":[0.133333333333333331,0.6,0.933333333333333348],"xyz":[0.27481380341701489,0.292940010353116842,0.850976298477954307],"hpluv":[246.163931095701571,186.209563381880429,61.0402269370523243],"hsluv":[246.163931095701571,95.74331870201,61.0402269370523243]},"#2299ff":{"lch":[61.9472031658153384,102.178145565387652,249.783903318571561],"luv":[61.9472031658153384,-35.3088685699608078,-95.8835607989752532],"rgb":[0.133333333333333331,0.6,1],"xyz":[0.300984851826846311,0.303408429717049566,0.988810486769736152],"hpluv":[249.783903318571561,209.303089797111312,61.9472031658153384],"hsluv":[249.783903318571561,99.9999999999986,61.9472031658153384]},"#110000":{"lch":[1.07666134976862637,3.62084603829176643,12.1770506300617818],"luv":[1.07666134976862637,3.53937866928378497,0.763756943295526236],"rgb":[0.0666666666666666657,0,0],"xyz":[0.00231161193210362246,0.00119192490249095569,0.000108356809317355026],"hpluv":[12.1770506300617818,426.746789183125145,1.07666134976862637],"hsluv":[12.1770506300617818,100.000000000002203,1.07666134976862637]},"#110011":{"lch":[1.44219482929484544,3.28508596549136378,307.715012949243601],"luv":[1.44219482929484544,2.00959989444743092,-2.59871084672866193],"rgb":[0.0666666666666666657,0,0.0666666666666666657],"xyz":[0.0033232774317407442,0.00159659110234581,0.00543646177407298634],"hpluv":[307.715012949243601,289.042783730483393,1.44219482929484544],"hsluv":[307.715012949243601,99.9999999999988347,1.44219482929484544]},"#110022":{"lch":[2.1197964535087821,6.27745605271938789,280.884754167684719],"luv":[2.1197964535087821,1.18539805862553327,-6.16451830530416167],"rgb":[0.0666666666666666657,0,0.133333333333333331],"xyz":[0.00519863557021776369,0.00234673435773662814,0.0153133479700521824],"hpluv":[280.884754167684719,375.775833064690062,2.1197964535087821],"hsluv":[280.884754167684719,99.9999999999998721,2.1197964535087821]},"#110033":{"lch":[3.23545797359596321,11.0622687483975319,272.972319481398301],"luv":[3.23545797359596321,0.57361730895702967,-11.0473867065762477],"rgb":[0.0666666666666666657,0,0.2],"xyz":[0.00828638630267550247,0.00358183465071974143,0.0315755018276633256],"hpluv":[272.972319481398301,433.858158519435221,3.23545797359596321],"hsluv":[272.972319481398301,100.000000000000355,3.23545797359596321]},"#110044":{"lch":[4.84621421062803659,17.7312810137515946,269.891014646828467],"luv":[4.84621421062803659,-0.0337275934556249754,-17.7312489362161827],"rgb":[0.0666666666666666657,0,0.266666666666666663],"xyz":[0.012744381546894383,0.0053650327484073175,0.0550542767805499642],"hpluv":[269.891014646828467,464.276639746945534,4.84621421062803659],"hsluv":[269.891014646828467,100.000000000000711,4.84621421062803659]},"#110055":{"lch":[7.00054481789469563,26.532890242342738,268.413820694361107],"luv":[7.00054481789469563,-0.734444075336115332,-26.5227233992365541],"rgb":[0.0666666666666666657,0,0.333333333333333315],"xyz":[0.0187067955862563751,0.00774999836415214954,0.0864563240545238726],"hpluv":[268.413820694361107,480.941270902403687,7.00054481789469563],"hsluv":[268.413820694361107,100.000000000000682,7.00054481789469563]},"#110066":{"lch":[9.62818818466394,37.2351477319955,267.604082628906383],"luv":[9.62818818466394,-1.55659527409507947,-37.20259719127408],"rgb":[0.0666666666666666657,0,0.4],"xyz":[0.0262917913597645499,0.010783996673555462,0.126403968461667848],"hpluv":[267.604082628906383,490.735908571457742,9.62818818466394],"hsluv":[267.604082628906383,100.000000000000753,9.62818818466394]},"#110077":{"lch":[12.2928363787590555,48.1341065988899643,267.117295446388],"luv":[12.2928363787590555,-2.42073458662620622,-48.0731969202633138],"rgb":[0.0666666666666666657,0,0.466666666666666674],"xyz":[0.0356058043799664659,0.0145096018816362783,0.175457770368065757],"hpluv":[267.117295446388,496.866985521105335,12.2928363787590555],"hsluv":[267.117295446388,100.000000000000739,12.2928363787590555]},"#110088":{"lch":[14.9348588897968106,58.9551979191609803,266.804247897724281],"luv":[14.9348588897968106,-3.28660375460643372,-58.8635166928348781],"rgb":[0.0666666666666666657,0,0.533333333333333326],"xyz":[0.0467462214819102939,0.0189657687224138727,0.234130633771637925],"hpluv":[266.804247897724281,500.910695182750828,14.9348588897968106],"hsluv":[266.804247897724281,100.000000000000753,14.9348588897968106]},"#110099":{"lch":[17.5475874535139624,69.6538923837914297,266.59230255326986],"luv":[17.5475874535139624,-4.14026096141065292,-69.5307339482636],"rgb":[0.0666666666666666657,0,0.6],"xyz":[0.0598031855909830073,0.0241885543660430302,0.302897311412755832],"hpluv":[266.59230255326986,503.694607743992833,17.5475874535139624],"hsluv":[266.59230255326986,100.000000000000796,17.5475874535139624]},"#1100aa":{"lch":[20.1284543895036734,80.2134478690449,266.442863009455],"luv":[20.1284543895036734,-4.97675334080985809,-80.0589104673847203],"rgb":[0.0666666666666666657,0,0.66666666666666663],"xyz":[0.0748608785562355494,0.0302116315521441317,0.382201161029754433],"hpluv":[266.442863009455,505.680355905096519,20.1284543895036734],"hsluv":[266.442863009455,100.000000000000782,20.1284543895036734]},"#1100bb":{"lch":[22.6769756305364183,90.6302333913987894,266.3339747285724],"luv":[22.6769756305364183,-5.79494806122388795,-90.444777525002138],"rgb":[0.0666666666666666657,0,0.733333333333333282],"xyz":[0.0919984706635722,0.0370666683950788903,0.472459146128396179],"hpluv":[266.3339747285724,507.139328846885462,22.6769756305364183],"hsluv":[266.3339747285724,100.000000000001,22.6769756305364183]},"#1100cc":{"lch":[25.1937235339869332,100.906819147977927,266.252448568601267],"luv":[25.1937235339869332,-6.59531864805210422,-100.691051849175651],"rgb":[0.0666666666666666657,0,0.8],"xyz":[0.111290846107293936,0.0447836185725676919,0.574065656798666279],"hpluv":[266.252448568601267,508.238409831726415,25.1937235339869332],"hsluv":[266.252448568601267,100.000000000000824,25.1937235339869332]},"#1100dd":{"lch":[27.6797893663012289,111.048607057141055,266.189998210144608],"luv":[27.6797893663012289,-7.37896669992084409,-110.803176758488192],"rgb":[0.0666666666666666657,0,0.866666666666666696],"xyz":[0.132809171657927494,0.0533909487928212259,0.687395504698672277],"hpluv":[266.189998210144608,509.084249760461944,27.6797893663012289],"hsluv":[266.189998210144608,100.000000000000938,27.6797893663012289]},"#1100ee":{"lch":[30.1364964584496846,121.062148077250455,266.141219022825339],"luv":[30.1364964584496846,-8.14718371295858823,-120.787694301304626],"rgb":[0.0666666666666666657,0,0.933333333333333348],"xyz":[0.156621351924102231,0.0629158208992912638,0.8128063207671955],"hpluv":[266.141219022825339,509.74730741907581,30.1364964584496846],"hsluv":[266.141219022825339,100.000000000000952,30.1364964584496846]},"#1100ff":{"lch":[32.5652456752648263,130.954293728553409,266.102472093749839],"luv":[32.5652456752648263,-8.90125725083502495,-130.651424275813781],"rgb":[0.0666666666666666657,0,1],"xyz":[0.182792400333933625,0.0733842402632239599,0.950640509058977345],"hpluv":[266.102472093749839,510.275492181060656,32.5652456752648263],"hsluv":[266.102472093749839,100.000000000001108,32.5652456752648263]},"#111100":{"lch":[4.69779601336656771,5.17885327658484673,85.8743202181747307],"luv":[4.69779601336656771,0.372589941443898953,5.16543299210515716],"rgb":[0.0666666666666666657,0.0666666666666666657,0],"xyz":[0.00431601219303203148,0.00520072542434782924,0.000776490229626805866],"hpluv":[85.8743202181747307,139.887458074797621,4.69779601336656771],"hsluv":[85.8743202181747307,100.000000000002359,4.69779601336656771]},"#111111":{"lch":[5.06332949289278655,2.68159353999537178e-13,0],"luv":[5.06332949289278655,2.52120910544652531e-13,9.13481559944393266e-14],"rgb":[0.0666666666666666657,0.0666666666666666657,0.0666666666666666657],"xyz":[0.00532767769266915322,0.00560539162420268383,0.00610459519438243722],"hpluv":[0,6.72041492281092e-12,5.06332949289278655],"hsluv":[0,1.92419399944792277e-12,5.06332949289278655]},"#111122":{"lch":[5.74093111710672321,6.60006851394265048,265.874320218179719],"luv":[5.74093111710672321,-0.474838542395297381,-6.58296534605743222],"rgb":[0.0666666666666666657,0.0666666666666666657,0.133333333333333331],"xyz":[0.00720303583114617271,0.00635553487959350169,0.0159814813903616341],"hpluv":[265.874320218179719,145.883251481840432,5.74093111710672321],"hsluv":[265.874320218179719,28.41442223352254,5.74093111710672321]},"#111133":{"lch":[6.85659263719390388,14.212336546779186,265.874320218178582],"luv":[6.85659263719390388,-1.02249925976518052,-14.1755072354640976],"rgb":[0.0666666666666666657,0.0666666666666666657,0.2],"xyz":[0.0102907865636039132,0.00759063517257661455,0.0322436352479727809],"hpluv":[265.874320218178582,263.024656142887807,6.85659263719390388],"hsluv":[265.874320218178582,51.2306489028398957,6.85659263719390388]},"#111144":{"lch":[8.45853257854777141,22.7927945223118087,265.874320218178241],"luv":[8.45853257854777141,-1.63981590573345759,-22.7337301367732181],"rgb":[0.0666666666666666657,0.0666666666666666657,0.266666666666666663],"xyz":[0.0147487818078227903,0.00937383327026419105,0.0557224102008594194],"hpluv":[265.874320218178241,341.933676209697239,8.45853257854777141],"hsluv":[265.874320218178241,66.600159737267461,8.45853257854777141]},"#111155":{"lch":[10.3782295585045325,32.1242805487719707,265.874320218178127],"luv":[10.3782295585045325,-2.31116487943396587,-32.0410349033279545],"rgb":[0.0666666666666666657,0.0666666666666666657,0.333333333333333315],"xyz":[0.0207111958471847858,0.011758798886009024,0.0871244574748333278],"hpluv":[265.874320218178127,392.780088665713265,10.3782295585045325],"hsluv":[265.874320218178127,76.5037738801481453,10.3782295585045325]},"#111166":{"lch":[12.4757228248048477,41.8651930040424887,265.87432021817807],"luv":[12.4757228248048477,-3.01196982745712916,-41.7567051265328644],"rgb":[0.0666666666666666657,0.0666666666666666657,0.4],"xyz":[0.0282961916206929606,0.0147927971954123355,0.12707210188197729],"hpluv":[265.87432021817807,425.820638501567,12.4757228248048477],"hsluv":[265.87432021817807,82.9392496755345263,12.4757228248048477]},"#111177":{"lch":[14.6896895275036599,51.8467212520223697,265.874320218178],"luv":[14.6896895275036599,-3.73008575521422614,-51.7123676197837199],"rgb":[0.0666666666666666657,0.0666666666666666657,0.466666666666666674],"xyz":[0.0376102046408948731,0.0185184024034931519,0.176125903788375199],"hpluv":[265.874320218178,447.865910041391658,14.6896895275036599],"hsluv":[265.874320218178,87.2331192419333235,14.6896895275036599]},"#111188":{"lch":[16.9766940539391484,61.9476661879793511,265.874320218178],"luv":[16.9766940539391484,-4.45679305530888747,-61.7871373491236469],"rgb":[0.0666666666666666657,0.0666666666666666657,0.533333333333333326],"xyz":[0.0487506217428387,0.0229745692442707428,0.234798767191947366],"hpluv":[265.874320218178,463.03215765547759,16.9766940539391484],"hsluv":[265.874320218178,90.1871263608273495,16.9766940539391484]},"#111199":{"lch":[19.3069968916820471,72.0861980616198537,265.874320218178],"luv":[19.3069968916820471,-5.18620452834737478,-71.8993966147786],"rgb":[0.0666666666666666657,0.0666666666666666657,0.6],"xyz":[0.0618075858519114146,0.0281973548878999072,0.303565444833065246],"hpluv":[265.874320218178,473.779996738615694,19.3069968916820471],"hsluv":[265.874320218178,92.280537596895428,19.3069968916820471]},"#1111aa":{"lch":[21.6605350192491244,82.2093341223612839,265.874320218177957],"luv":[21.6605350192491244,-5.91450835752722703,-81.9962999636616274],"rgb":[0.0666666666666666657,0.0666666666666666657,0.66666666666666663],"xyz":[0.0768652788171639567,0.0342204320740010087,0.382869294450063846],"hpluv":[265.874320218177957,481.605322004481,21.6605350192491244],"hsluv":[265.874320218177957,93.8047159652847569,21.6605350192491244]},"#1111bb":{"lch":[24.0238472654082429,92.2838634174554215,265.874320218177957],"luv":[24.0238472654082429,-6.63931519789526092,-92.0447225046312241],"rgb":[0.0666666666666666657,0.0666666666666666657,0.733333333333333282],"xyz":[0.0940028709245006,0.0410754689169357673,0.473127279548705593],"hpluv":[265.874320218177957,487.441538809997496,24.0238472654082429],"hsluv":[265.874320218177957,94.9414655706975736,24.0238472654082429]},"#1111cc":{"lch":[26.3879200105999,102.289669569688542,265.874320218177957],"luv":[26.3879200105999,-7.35917778701558589,-102.024599989292597],"rgb":[0.0666666666666666657,0.0666666666666666657,0.8],"xyz":[0.113295246368222344,0.0487924190944245689,0.574733790218975749],"hpluv":[265.874320218177957,491.887677819884516,26.3879200105999],"hsluv":[265.874320218177957,95.8074626598259727,26.3879200105999]},"#1111dd":{"lch":[28.7467318202544035,112.215160110792439,265.874320218177957],"luv":[28.7467318202544035,-8.07326211070735766,-111.924369989661315],"rgb":[0.0666666666666666657,0.0666666666666666657,0.866666666666666696],"xyz":[0.134813571918855901,0.0573997493146781,0.688063638118981746],"hpluv":[265.874320218177957,495.338839734480189,28.7467318202544035],"hsluv":[265.874320218177957,96.479663003878315,28.7467318202544035]},"#1111ee":{"lch":[31.096282761883856,122.054240127147821,265.874320218177957],"luv":[31.096282761883856,-8.78112967353786367,-121.737953386246701],"rgb":[0.0666666666666666657,0.0666666666666666657,0.933333333333333348],"xyz":[0.158625752185030638,0.0669246214211481338,0.813474454187505],"hpluv":[265.874320218177957,498.062358817216193,31.096282761883856],"hsluv":[265.874320218177957,97.0101366558694451,31.096282761883856]},"#1111ff":{"lch":[33.4339475813396589,131.804336466263976,265.874320218177957],"luv":[33.4339475813396589,-9.48259535137154863,-131.462783694528071],"rgb":[0.0666666666666666657,0.0666666666666666657,1],"xyz":[0.184796800594862032,0.07739304078508083,0.951308642479286815],"hpluv":[265.874320218177957,500.243401112503761,33.4339475813396589],"hsluv":[265.874320218177957,99.9999999999995168,33.4339475813396589]},"#66aa00":{"lch":[62.9888010115071921,81.5107592316300185,114.758667910078074],"luv":[62.9888010115071921,-34.136471206054587,74.0182761493062884],"rgb":[0.4,0.66666666666666663,0],"xyz":[0.198534632170994735,0.315734905503604946,0.0504821063864305253],"hpluv":[114.758667910078074,164.206718875588678,62.9888010115071921],"hsluv":[114.758667910078074,100.000000000002245,62.9888010115071921]},"#66aa11":{"lch":[63.0225323172591345,80.1801511939703744,115.156040801232848],"luv":[63.0225323172591345,-34.0833758310267285,72.5753411114886262],"rgb":[0.4,0.66666666666666663,0.0666666666666666657],"xyz":[0.199546297670631867,0.316139571703459799,0.055810211351186155],"hpluv":[115.156040801232848,161.439702186697787,63.0225323172591345],"hsluv":[115.156040801232848,97.8915472494395,63.0225323172591345]},"#66aa22":{"lch":[63.0849851082382287,77.7526522520100372,115.919582231606014],"luv":[63.0849851082382287,-33.9864002990590066,69.9313915701248],"rgb":[0.4,0.66666666666666663,0.133333333333333331],"xyz":[0.201421655809108868,0.316889714958850599,0.0656870975471653545],"hpluv":[115.919582231606014,156.397041701241,63.0849851082382287],"hsluv":[115.919582231606014,94.0329763727763748,63.0849851082382287]},"#66aa33":{"lch":[63.1875983682703577,73.8659889058236416,117.258215410479664],"luv":[63.1875983682703577,-33.8307250746429062,65.6632801340230827],"rgb":[0.4,0.66666666666666663,0.2],"xyz":[0.20450940654156663,0.318124815251833726,0.0819492514047764908],"hpluv":[117.258215410479664,148.337854737344315,63.1875983682703577],"hsluv":[117.258215410479664,87.8175568215645228,63.1875983682703577]},"#66aa44":{"lch":[63.3352806074861121,68.495891054581449,119.389904478135335],"luv":[63.3352806074861121,-33.6143748396710436,59.6804900742209057],"rgb":[0.4,0.66666666666666663,0.266666666666666663],"xyz":[0.208967401785785489,0.319908013349521292,0.105428026357663129],"hpluv":[119.389904478135335,137.232870385557277,63.3352806074861121],"hsluv":[119.389904478135335,79.1339200396795093,63.3352806074861121]},"#66aa55":{"lch":[63.5319451116367162,61.7628687774086131,122.670093374403834],"luv":[63.5319451116367162,-33.3396585938880747,51.9915293529473],"rgb":[0.4,0.66666666666666663,0.333333333333333315],"xyz":[0.214929815825147474,0.322292978965266153,0.136830073631637045],"hpluv":[122.670093374403834,123.360077774302084,63.5319451116367162],"hsluv":[122.670093374403834,68.0252461175988401,63.5319451116367162]},"#66aa66":{"lch":[63.7807317293932101,53.9656100581627314,127.715012949238869],"luv":[63.7807317293932101,-33.0126168434810836,42.6902119706049703],"rgb":[0.4,0.66666666666666663,0.4],"xyz":[0.22251481159865566,0.325326977274669471,0.176777718038781],"hpluv":[127.715012949238869,107.366036241042551,63.7807317293932101],"hsluv":[127.715012949238869,54.6684489206366493,63.7807317293932101]},"#66aa77":{"lch":[64.0841229578331308,45.668717811445795,135.623736827110406],"luv":[64.0841229578331308,-32.6422859505805931,31.9392071670853355],"rgb":[0.4,0.66666666666666663,0.466666666666666674],"xyz":[0.231828824618857565,0.329052582482750267,0.225831519945178916],"hpluv":[135.623736827110406,90.428994130424627,64.0841229578331308],"hsluv":[135.623736827110406,56.3153951517164302,64.0841229578331308]},"#66aa88":{"lch":[64.4440140424290888,37.9133385548872752,148.25026899586868],"luv":[64.4440140424290888,-32.239785461804118,19.9503752785341248],"rgb":[0.4,0.66666666666666663,0.533333333333333326],"xyz":[0.242969241720801421,0.333508749323527864,0.284504383348751055],"hpluv":[148.25026899586868,74.65325904191441,64.4440140424290888],"hsluv":[148.25026899586868,58.1346686170252127,64.4440140424290888]},"#66aa99":{"lch":[64.861761772217136,32.5704605989434484,167.654678216446086],"luv":[64.861761772217136,-31.8173259789585323,6.96366793981576304],"rgb":[0.4,0.66666666666666663,0.6],"xyz":[0.256026205829874121,0.338731534967157,0.353271060989869],"hpluv":[167.654678216446086,63.7198120272805681,64.861761772217136],"hsluv":[167.654678216446086,60.083023100845935,64.861761772217136]},"#66aaaa":{"lch":[65.3382237636027,32.1097126044189949,192.177050630060876],"luv":[65.3382237636027,-31.387258852500235,-6.77300710648746396],"rgb":[0.4,0.66666666666666663,0.66666666666666663],"xyz":[0.271083898795126677,0.344754612153258144,0.432574910606867591],"hpluv":[192.177050630060876,62.3603323483304592,65.3382237636027],"hsluv":[192.177050630060876,62.1162357127798757,65.3382237636027]},"#66aabb":{"lch":[65.8737942906507641,37.4229485671739255,214.174175962111633],"luv":[65.8737942906507641,-30.9612713447490577,-21.020864781881972],"rgb":[0.4,0.66666666666666663,0.733333333333333282],"xyz":[0.288221490902463295,0.351609648996192903,0.522832895705509282],"hpluv":[214.174175962111633,72.0882777495769744,65.8737942906507641],"hsluv":[214.174175962111633,64.192083786910942,65.8737942906507641]},"#66aacc":{"lch":[66.4684397846860833,46.8829891397435361,229.336310284400895],"luv":[66.4684397846860833,-30.5497910563422188,-35.5629714322516],"rgb":[0.4,0.66666666666666663,0.8],"xyz":[0.30751386634618505,0.359326599173681704,0.624439406375779438],"hpluv":[229.336310284400895,89.5033179536005,66.4684397846860833],"hsluv":[229.336310284400895,66.2725553364081748,66.4684397846860833]},"#66aadd":{"lch":[67.1217354618507471,58.5746749070863473,239.007496148652194],"luv":[67.1217354618507471,-30.1616186688116876,-50.2122425285710676],"rgb":[0.4,0.66666666666666663,0.866666666666666696],"xyz":[0.329032191896818593,0.367933929393935211,0.737769254275785435],"hpluv":[239.007496148652194,110.735287258409116,67.1217354618507471],"hsluv":[239.007496148652194,68.3252248927570349,67.1217354618507471]},"#66aaee":{"lch":[67.8329035309127,71.3390505041132,245.305718817638592],"luv":[67.8329035309127,-29.803771094245274,-64.8150858627082584],"rgb":[0.4,0.66666666666666663,0.933333333333333348],"xyz":[0.352844372162993358,0.377458801500405228,0.863180070344308659],"hpluv":[245.305718817638592,133.452355648257935,67.8329035309127],"hsluv":[245.305718817638592,80.362890995181445,67.8329035309127]},"#66aaff":{"lch":[68.6008528128324144,84.5574659264264312,249.594848961048797],"luv":[68.6008528128324144,-29.4814940521041038,-79.2515397475312],"rgb":[0.4,0.66666666666666663,1],"xyz":[0.379015420572824724,0.387927220864337952,1.00101425863609061],"hpluv":[249.594848961048797,156.409011428865199,68.6008528128324144],"hsluv":[249.594848961048797,99.9999999999981,68.6008528128324144]},"#112200":{"lch":[11.0156269675282488,14.1286449823385087,113.920199516574741],"luv":[11.0156269675282488,-5.72865521459208082,12.9151507335100835],"rgb":[0.0666666666666666657,0.133333333333333331,0],"xyz":[0.00803163592779996757,0.0126319728938838038,0.00201503147454941628],"hpluv":[113.920199516574741,162.753605553330914,11.0156269675282488],"hsluv":[113.920199516574741,100.000000000002302,11.0156269675282488]},"#112211":{"lch":[11.3010826742418828,9.17677244733547,127.715012949238741],"luv":[11.3010826742418828,-5.61374683501564142,7.25940762201209555],"rgb":[0.0666666666666666657,0.133333333333333331,0.0666666666666666657],"xyz":[0.00904330142743709,0.0130366390937386584,0.00734313643930504731],"hpluv":[127.715012949238741,103.040803658029205,11.3010826742418828],"hsluv":[127.715012949238741,52.4661346244892783,11.3010826742418828]},"#112222":{"lch":[11.8149934741043623,5.60956124878379736,192.177050630060876],"luv":[11.8149934741043623,-5.48334870304322308,-1.18324317225625331],"rgb":[0.0666666666666666657,0.133333333333333331,0.133333333333333331],"xyz":[0.0109186595659141079,0.0137867823491294762,0.0172200226352842434],"hpluv":[192.177050630060876,60.2469040904941551,11.8149934741043623],"hsluv":[192.177050630060876,60.0110800331641911,11.8149934741043623]},"#112233":{"lch":[12.6219648570067733,12.7575995118883281,244.93155638428982],"luv":[12.6219648570067733,-5.40540262923445,-11.5558629154900672],"rgb":[0.0666666666666666657,0.133333333333333331,0.2],"xyz":[0.0140064102983718484,0.0150218826421125891,0.0334821764928953866],"hpluv":[244.93155638428982,128.257072990564865,12.6219648570067733],"hsluv":[244.93155638428982,68.2965554989448265,12.6219648570067733]},"#112244":{"lch":[13.7124312845167182,23.0561698733830092,256.354402060867073],"luv":[13.7124312845167182,-5.43930918870511082,-22.4053762472305387],"rgb":[0.0666666666666666657,0.133333333333333331,0.266666666666666663],"xyz":[0.0184644055425907255,0.0168050807398001656,0.0569609514457820251],"hpluv":[256.354402060867073,213.359519949101497,13.7124312845167182],"hsluv":[256.354402060867073,75.5965994738604508,13.7124312845167182]},"#112255":{"lch":[15.056320299603339,33.5848303856462849,260.40485184836416],"luv":[15.056320299603339,-5.59809589119781581,-33.114983835502386],"rgb":[0.0666666666666666657,0.133333333333333331,0.333333333333333315],"xyz":[0.024426819581952721,0.019190046355545,0.0883629987197559336],"hpluv":[260.40485184836416,283.050313811336878,15.056320299603339],"hsluv":[260.40485184836416,81.3424686793067,15.056320299603339]},"#112266":{"lch":[16.6136212231118279,43.9645077489691118,262.329755848243337],"luv":[16.6136212231118279,-5.86800935048734384,-43.5711419160865958],"rgb":[0.0666666666666666657,0.133333333333333331,0.4],"xyz":[0.0320118153554608958,0.02222404466494831,0.128310643126899909],"hpluv":[262.329755848243337,335.797328537363626,16.6136212231118279],"hsluv":[262.329755848243337,85.6428490187558396,16.6136212231118279]},"#112277":{"lch":[18.3427569840269769,54.1821774694947678,263.400149453671133],"luv":[18.3427569840269769,-6.22740469049246936,-53.8231157232341815],"rgb":[0.0666666666666666657,0.133333333333333331,0.466666666666666674],"xyz":[0.0413258283756628153,0.0259496498730291264,0.177364445033297818],"hpluv":[263.400149453671133,374.827260372181627,18.3427569840269769],"hsluv":[263.400149453671133,88.8099744527525559,18.3427569840269769]},"#112288":{"lch":[20.2056943122802366,64.2803592359499,264.056887374403459],"luv":[20.2056943122802366,-6.65565132438349316,-63.9348644242795103],"rgb":[0.0666666666666666657,0.133333333333333331,0.533333333333333326],"xyz":[0.0524662454776066434,0.0304058167138067173,0.236037308436869986],"hpluv":[264.056887374403459,403.686144257890874,20.2056943122802366],"hsluv":[264.056887374403459,91.1461001738222762,20.2056943122802366]},"#112299":{"lch":[22.17018380613613,74.2918952905243799,264.488199331991609],"luv":[22.17018380613613,-7.13579321215933149,-73.9484020185124677],"rgb":[0.0666666666666666657,0.133333333333333331,0.6],"xyz":[0.0655232095866793568,0.0356286023574358818,0.304803986077987865],"hpluv":[264.488199331991609,425.217833826531262,22.17018380613613],"hsluv":[264.488199331991609,92.8866294242426136,22.17018380613613]},"#1122aa":{"lch":[24.2101316823922517,84.2333021684004848,264.786067280823943],"luv":[24.2101316823922517,-7.6546801533155886,-83.8847725510625537],"rgb":[0.0666666666666666657,0.133333333333333331,0.66666666666666663],"xyz":[0.0805809025519319,0.0416516795435369833,0.384107835694986466],"hpluv":[264.786067280823943,441.495215422381477,24.2101316823922517],"hsluv":[264.786067280823943,94.2012423737010209,24.2101316823922517]},"#1122bb":{"lch":[26.3050242232650149,94.1101405136049891,264.999933480500431],"luv":[26.3050242232650149,-8.20234804116949334,-93.7520134935884926],"rgb":[0.0666666666666666657,0.133333333333333331,0.733333333333333282],"xyz":[0.0977184946592685455,0.0485067163864717418,0.474365820793628212],"hpluv":[264.999933480500431,453.98033637772636,26.3050242232650149],"hsluv":[264.999933480500431,95.2089691602506605,26.3050242232650149]},"#1122cc":{"lch":[28.4390102065576187,103.92243186966887,265.158337172634162],"luv":[28.4390102065576187,-8.77130520241401612,-103.551610565708117],"rgb":[0.0666666666666666657,0.133333333333333331,0.8],"xyz":[0.117010870102990286,0.0562236665639605435,0.575972331463898368],"hpluv":[265.158337172634162,463.69685512523705,28.4390102065576187],"hsluv":[265.158337172634162,95.9928942328389496,28.4390102065576187]},"#1122dd":{"lch":[30.599961250020371,113.668086087716972,265.278693166229971],"luv":[30.599961250020371,-9.35592092097037664,-113.282392888591403],"rgb":[0.0666666666666666657,0.133333333333333331,0.866666666666666696],"xyz":[0.138529195653623816,0.0648309967842140705,0.689302179363904366],"hpluv":[265.278693166229971,471.364637015548908,30.599961250020371],"hsluv":[265.278693166229971,96.6113336559982,30.599961250020371]},"#1122ee":{"lch":[32.7786459144851463,123.344693870669801,265.37211393361406],"luv":[32.7786459144851463,-9.95194954038693247,-122.942556531067964],"rgb":[0.0666666666666666657,0.133333333333333331,0.933333333333333348],"xyz":[0.162341375919798553,0.0743558688906841,0.814712995432427589],"hpluv":[265.37211393361406,477.494956838131543,32.7786459144851463],"hsluv":[265.37211393361406,97.1056530386567118,32.7786459144851463]},"#1122ff":{"lch":[34.9680553815075,132.950321242967135,265.445956583698],"luv":[34.9680553815075,-10.5561742154436597,-132.530581770930752],"rgb":[0.0666666666666666657,0.133333333333333331,1],"xyz":[0.188512424329629946,0.0848242882546168114,0.952547183724209434],"hpluv":[265.445956583698,482.455471693424897,34.9680553815075],"hsluv":[265.445956583698,99.9999999999995595,34.9680553815075]},"#66bb00":{"lch":[68.2883247343563,91.0397787832552297,117.384795663234385],"luv":[68.2883247343563,-41.875036539852637,80.8376313092488914],"rgb":[0.4,0.733333333333333282,0],"xyz":[0.232489130079593515,0.383643901320803504,0.0618002723559631373],"hpluv":[117.384795663234385,169.170277477244,68.2883247343563],"hsluv":[117.384795663234385,100.000000000002402,68.2883247343563]},"#66bb11":{"lch":[68.3179499939719079,89.8644626985519466,117.727722441428654],"luv":[68.3179499939719079,-41.8112733484955896,79.5452014710932644],"rgb":[0.4,0.733333333333333282,0.0666666666666666657],"xyz":[0.233500795579230647,0.384048567520658357,0.0671283773207187739],"hpluv":[117.727722441428654,166.91389144855998,68.3179499939719079],"hsluv":[117.727722441428654,98.2613130840239108,68.3179499939719079]},"#66bb22":{"lch":[68.3728123300379309,87.7153655991844374,118.381366327960222],"luv":[68.3728123300379309,-41.6944557120635579,77.1722600749346839],"rgb":[0.4,0.733333333333333282,0.133333333333333331],"xyz":[0.235376153717707648,0.384798710776049158,0.0770052635166979665],"hpluv":[118.381366327960222,162.791438416492724,68.3728123300379309],"hsluv":[118.381366327960222,95.072259168186676,68.3728123300379309]},"#66bb33":{"lch":[68.4629872592027766,84.2604886941914515,119.511012469656151],"luv":[68.4629872592027766,-41.5059446288263274,73.3286200296498691],"rgb":[0.4,0.733333333333333282,0.2],"xyz":[0.238463904450165409,0.386033811069032284,0.0932674173743091],"hpluv":[119.511012469656151,156.173540237969377,68.4629872592027766],"hsluv":[119.511012469656151,89.9157079277594846,68.4629872592027766]},"#66bb44":{"lch":[68.5928402387875451,79.4555052917154683,121.268984442668796],"luv":[68.5928402387875451,-41.2418962487648457,67.9137932600435761],"rgb":[0.4,0.733333333333333282,0.266666666666666663],"xyz":[0.242921899694384269,0.38781700916671985,0.116746192327195741],"hpluv":[121.268984442668796,146.988898097842537,68.5928402387875451],"hsluv":[121.268984442668796,82.6706505658268,68.5928402387875451]},"#66bb55":{"lch":[68.7658933773114711,73.3682686647690474,123.883282583110088],"luv":[68.7658933773114711,-40.9030232283392365,60.9085013577552417],"rgb":[0.4,0.733333333333333282,0.333333333333333315],"xyz":[0.248884313733746254,0.390201974782464711,0.148148239601169657],"hpluv":[123.883282583110088,135.386233996967292,68.7658933773114711],"hsluv":[123.883282583110088,73.3323147762666565,68.7658933773114711]},"#66bb66":{"lch":[68.985024233854773,66.1955602149500493,127.715012949239338],"luv":[68.985024233854773,-40.4940973290304953,52.3648763359380354],"rgb":[0.4,0.733333333333333282,0.4],"xyz":[0.256469309507254439,0.39323597309186803,0.188095884008313619],"hpluv":[127.715012949239338,121.76244699215377,68.985024233854773],"hsluv":[127.715012949239338,61.9987879490855889,68.985024233854773]},"#66bb77":{"lch":[69.2525700917713,58.3030977404443149,133.351332140289912],"luv":[69.2525700917713,-40.0233333378199134,42.395565742911792],"rgb":[0.4,0.733333333333333282,0.466666666666666674],"xyz":[0.265783322527456345,0.396961578299948825,0.237149685914711528],"hpluv":[133.351332140289912,106.830450835327468,69.2525700917713],"hsluv":[133.351332140289912,63.1630001095548,69.2525700917713]},"#66bb88":{"lch":[69.5703900447947632,50.3125315521488901,141.732198444264128],"luv":[69.5703900447947632,-39.5016033478381487,31.1604583428427624],"rgb":[0.4,0.733333333333333282,0.533333333333333326],"xyz":[0.276923739629400201,0.401417745140726423,0.295822549318283667],"hpluv":[141.732198444264128,91.7679559652102625,69.5703900447947632],"hsluv":[141.732198444264128,64.4651291783298888,69.5703900447947632]},"#66bb99":{"lch":[69.9399065468101924,43.264635747530761,154.168279853010262],"luv":[69.9399065468101924,-38.9415329854338594,18.8516767188195544],"rgb":[0.4,0.733333333333333282,0.6],"xyz":[0.2899807037384729,0.406640530784355581,0.364589226959401602],"hpluv":[154.168279853010262,78.4959645714096865,69.9399065468101924],"hsluv":[154.168279853010262,65.8787579381207848,69.9399065468101924]},"#66bbaa":{"lch":[70.3621368583926881,38.7745898249838348,171.579209782291855],"luv":[70.3621368583926881,-38.3565710720190296,5.67822786553099768],"rgb":[0.4,0.733333333333333282,0.66666666666666663],"xyz":[0.305038396703725456,0.412663607970456703,0.443893076576400203],"hpluv":[171.579209782291855,69.9274221790226278,70.3621368583926881],"hsluv":[171.579209782291855,67.37547943529961,70.3621368583926881]},"#66bbbb":{"lch":[70.8377198879813221,38.6292683935386592,192.177050630060933],"luv":[70.8377198879813221,-37.7601276376370194,-8.14819841495072161],"rgb":[0.4,0.733333333333333282,0.733333333333333282],"xyz":[0.322175988811062075,0.419518644813391461,0.534151061675042],"hpluv":[192.177050630060933,69.1976324805594629,70.8377198879813221],"hsluv":[192.177050630060933,68.9267726464228758,70.8377198879813221]},"#66bbcc":{"lch":[71.3669414392261103,43.4063518114314,211.106579982723787],"luv":[71.3669414392261103,-37.1648552128157,-22.4250956427882215],"rgb":[0.4,0.733333333333333282,0.8],"xyz":[0.341468364254783829,0.427235594990880263,0.635757572345312161],"hpluv":[211.106579982723787,77.1783568223693806,71.3669414392261103],"hsluv":[211.106579982723787,70.5055674968506736,71.3669414392261103]},"#66bbdd":{"lch":[71.9497594848613602,52.0084901368895629,225.300588521911806],"luv":[71.9497594848613602,-36.5821167433876298,-36.9679831866995059],"rgb":[0.4,0.733333333333333282,0.866666666666666696],"xyz":[0.362986689805417373,0.435842925211133769,0.749087420245318159],"hpluv":[225.300588521911806,91.724261948179759,71.9497594848613602],"hsluv":[225.300588521911806,72.0874065633031336,71.9497594848613602]},"#66bbee":{"lch":[72.5858302461357852,62.9426478584387183,235.089705553804919],"luv":[72.5858302461357852,-36.0216507769597953,-51.6160594653851135],"rgb":[0.4,0.733333333333333282,0.933333333333333348],"xyz":[0.386798870071592082,0.445367797317603786,0.874498236313841382],"hpluv":[235.089705553804919,110.035415213757233,72.5858302461357852],"hsluv":[235.089705553804919,76.908955535231712,72.5858302461357852]},"#66bbff":{"lch":[73.2745353232689638,75.1445669264803513,241.815748730615525],"luv":[73.2745353232689638,-35.4914181095182641,-66.2349241650025817],"rgb":[0.4,0.733333333333333282,1],"xyz":[0.412969918481423504,0.45583621668153651,1.01233242460562312],"hpluv":[241.815748730615525,130.131920555189879,73.2745353232689638],"hsluv":[241.815748730615525,99.9999999999976552,73.2745353232689638]},"#113300":{"lch":[17.8585390793191152,25.0449080182821966,121.332554648991049],"luv":[17.8585390793191152,-13.0234653569097247,21.3924465113644295],"rgb":[0.0666666666666666657,0.2,0],"xyz":[0.0141493580168107792,0.0248674170719056023,0.00405427217088629669],"hpluv":[121.332554648991049,177.956083469309505,17.8585390793191152],"hsluv":[121.332554648991049,100.000000000002288,17.8585390793191152]},"#113311":{"lch":[18.041211184449395,20.8015074137336562,127.715012949239792],"luv":[18.041211184449395,-12.7249964056056086,16.4553084796651738],"rgb":[0.0666666666666666657,0.2,0.0666666666666666657],"xyz":[0.015161023516447901,0.0252720832717604552,0.00938237713564192902],"hpluv":[127.715012949239792,146.308124837666583,18.041211184449395],"hsluv":[127.715012949239792,74.4969128915689254,18.041211184449395]},"#113322":{"lch":[18.3747440863758129,14.8635488733567129,145.575764327225926],"luv":[18.3747440863758129,-12.2605616690393529,8.40260154180516672],"rgb":[0.0666666666666666657,0.2,0.133333333333333331],"xyz":[0.0170363816549249196,0.0260222265271512765,0.0192592633316211251],"hpluv":[145.575764327225926,102.645648490479701,18.3747440863758129],"hsluv":[145.575764327225926,76.8412554017051,18.3747440863758129]},"#113333":{"lch":[18.910205854271,11.9516732098830207,192.177050630061075],"luv":[18.910205854271,-11.6827660646039035,-2.5210056714682163],"rgb":[0.0666666666666666657,0.2,0.2],"xyz":[0.0201241323873826601,0.0272573268201343893,0.0355214171892322683],"hpluv":[192.177050630061075,80.19952200231,18.910205854271],"hsluv":[192.177050630061075,79.885597544945341,18.910205854271]},"#113344":{"lch":[19.6554681695294136,18.5554908550806559,233.185939638237187],"luv":[19.6554681695294136,-11.1188227079461566,-14.8552355236207116],"rgb":[0.0666666666666666657,0.2,0.266666666666666663],"xyz":[0.0245821276316015372,0.0290405249178219624,0.0590001921421189068],"hpluv":[233.185939638237187,119.79215597403514,19.6554681695294136],"hsluv":[233.185939638237187,83.0941728600946163,19.6554681695294136]},"#113355":{"lch":[20.6059777210847557,29.4541985213363553,248.778672986371305],"luv":[20.6059777210847557,-10.6615827984222822,-27.4568837045772334],"rgb":[0.0666666666666666657,0.2,0.333333333333333315],"xyz":[0.0305445416709635327,0.0314254905335667953,0.0904022394160928222],"hpluv":[248.778672986371305,181.381634101163,20.6059777210847557],"hsluv":[248.778672986371305,86.0667890851332089,20.6059777210847557]},"#113366":{"lch":[21.7480278014825927,41.0513772817531262,255.392805777322508],"luv":[21.7480278014825927,-10.3527823296753354,-39.7244946445288178],"rgb":[0.0666666666666666657,0.2,0.4],"xyz":[0.0381295374444717075,0.0344594888429701068,0.130349883823236784],"hpluv":[255.392805777322508,239.522976201191227,21.7480278014825927],"hsluv":[255.392805777322508,88.6137215649990537,21.7480278014825927]},"#113377":{"lch":[23.0621320749224097,52.4639032010768602,258.793139915612699],"luv":[23.0621320749224097,-10.1964540550792755,-51.4635158514711293],"rgb":[0.0666666666666666657,0.2,0.466666666666666674],"xyz":[0.04744355046467362,0.0381850940510509232,0.179403685729634693],"hpluv":[258.793139915612699,288.669213908808,23.0621320749224097],"hsluv":[258.793139915612699,90.7010140503724926,23.0621320749224097]},"#113388":{"lch":[24.5260866455155693,63.5079254673071389,260.778240759541745],"luv":[24.5260866455155693,-10.1775299952298717,-62.6871157444433322],"rgb":[0.0666666666666666657,0.2,0.533333333333333326],"xyz":[0.0585839675666174481,0.0426412608918285141,0.238076549133206861],"hpluv":[260.778240759541745,328.5783880762134,24.5260866455155693],"hsluv":[260.778240759541745,92.3732755032704,24.5260866455155693]},"#113399":{"lch":[26.1173586094444445,74.1961224571638667,262.040130643645512],"luv":[26.1173586094444445,-10.2746398160742789,-73.4812653968914447],"rgb":[0.0666666666666666657,0.2,0.6],"xyz":[0.0716409316756901615,0.0478640465354576786,0.30684322677432474],"hpluv":[262.040130643645512,360.488391101723778,26.1173586094444445],"hsluv":[262.040130643645512,93.700931793532277,26.1173586094444445]},"#1133aa":{"lch":[27.8146812937100378,84.589542856674214,262.892366774415223],"luv":[27.8146812937100378,-10.4665753413372666,-83.9395113240792767],"rgb":[0.0666666666666666657,0.2,0.66666666666666663],"xyz":[0.0866986246409427,0.0538871237215587801,0.386147076391323341],"hpluv":[262.892366774415223,385.906342473210088,27.8146812937100378],"hsluv":[262.892366774415223,94.7540719156047544,27.8146812937100378]},"#1133bb":{"lch":[29.5989386642012917,94.7497677250031245,263.494633441352278],"luv":[29.5989386642012917,-10.734795769033445,-94.1396974912241],"rgb":[0.0666666666666666657,0.2,0.733333333333333282],"xyz":[0.10383621674827935,0.0607421605644935386,0.476405061489965087],"hpluv":[263.494633441352278,406.201330660618282,29.5989386642012917],"hsluv":[263.494633441352278,95.59270717643426,29.5989386642012917]},"#1133cc":{"lch":[31.4535171675710927,104.725970292241058,263.935552719695806],"luv":[31.4535171675710927,-11.0639900580249932,-104.139891384844844],"rgb":[0.0666666666666666657,0.2,0.8],"xyz":[0.123128592192001091,0.0684591107419823403,0.578011572160235243],"hpluv":[263.935552719695806,422.497850271701509,31.4535171675710927],"hsluv":[263.935552719695806,96.2648935085394299,31.4535171675710927]},"#1133dd":{"lch":[33.3643121953656845,114.554023382916327,264.267643395871801],"luv":[33.3643121953656845,-11.4418472625073555,-113.981175658242762],"rgb":[0.0666666666666666657,0.2,0.866666666666666696],"xyz":[0.144646917742634634,0.0770664409622358743,0.691341420060241241],"hpluv":[264.267643395871801,435.679872957086786,33.3643121953656845],"hsluv":[264.267643395871801,96.8079128297289913,33.3643121953656845]},"#1133ee":{"lch":[35.3195411096734375,124.259061611723823,264.523680461367292],"luv":[35.3195411096734375,-11.8585821660500468,-123.691909281234786],"rgb":[0.0666666666666666657,0.2,0.933333333333333348],"xyz":[0.168459098008809371,0.0865913130687059,0.816752236128764464],"hpluv":[264.523680461367292,446.428943593210363,35.3195411096734375],"hsluv":[264.523680461367292,97.2502875158067752,35.3195411096734375]},"#1133ff":{"lch":[37.3094684856901466,133.858437412957159,264.724991571549936],"luv":[37.3094684856901466,-12.3064438760062309,-133.291532760957],"rgb":[0.0666666666666666657,0.2,1],"xyz":[0.194630146418640765,0.0970597324326386,0.954586424420546309],"hpluv":[264.724991571549936,455.266836240216,37.3094684856901466],"hsluv":[264.724991571549936,99.9999999999995168,37.3094684856901466]},"#66cc00":{"lch":[73.5514640948473328,100.417876322708906,119.311479215942285],"luv":[73.5514640948473328,-49.1602904566029579,87.5614968315714322],"rgb":[0.4,0.8,0],"xyz":[0.270712873389210462,0.460091387940038399,0.0745415201258350923],"hpluv":[119.311479215942285,173.244332851636557,73.5514640948473328],"hsluv":[119.311479215942285,100.00000000000226,73.5514640948473328]},"#66cc11":{"lch":[73.5777109322390572,99.3703085818509,119.605548775623987],"luv":[73.5777109322390572,-49.0915230219986611,86.397225621155485],"rgb":[0.4,0.8,0.0666666666666666657],"xyz":[0.271724538888847567,0.460496054139893252,0.079869625090590729],"hpluv":[119.605548775623987,171.375877908330068,73.5777109322390572],"hsluv":[119.605548775623987,98.5479766016144652,73.5777109322390572]},"#66cc22":{"lch":[73.626324929263788,97.4510710028789333,120.162888823436575],"luv":[73.626324929263788,-48.965269014871545,84.2562381661406192],"rgb":[0.4,0.8,0.133333333333333331],"xyz":[0.273599897027324623,0.461246197395284052,0.0897465112865699216],"hpluv":[120.162888823436575,167.954954584373922,73.626324929263788],"hsluv":[120.162888823436575,95.8800576342850377,73.626324929263788]},"#66cc33":{"lch":[73.7062524827218084,94.3550745227874,121.116489614327122],"luv":[73.7062524827218084,-48.7607908304490252,80.779114663321],"rgb":[0.4,0.8,0.2],"xyz":[0.276687647759782329,0.462481297688267179,0.106008665144181058],"hpluv":[121.116489614327122,162.442721914772306,73.7062524827218084],"hsluv":[121.116489614327122,91.5533619475712896,73.7062524827218084]},"#66cc44":{"lch":[73.8213986639243,90.0253172969507318,122.577193203242018],"luv":[73.8213986639243,-48.472817822786439,75.8613451418811451],"rgb":[0.4,0.8,0.266666666666666663],"xyz":[0.281145643004001244,0.464264495785954745,0.129487440097067696],"hpluv":[122.577193203242018,154.746814564283426,73.8213986639243],"hsluv":[122.577193203242018,85.4474048693987527,73.8213986639243]},"#66cc55":{"lch":[73.974942724102462,84.4934421806047879,124.700104619680829],"luv":[73.974942724102462,-48.100513339115345,69.4656921655632118],"rgb":[0.4,0.8,0.333333333333333315],"xyz":[0.28710805704336323,0.466649461401699606,0.160889487371041612],"hpluv":[124.700104619680829,144.936474170198323,73.974942724102462],"hsluv":[124.700104619680829,77.5306238992907,73.974942724102462]},"#66cc66":{"lch":[74.1695172801941567,77.8884466842553564,127.715012949239551],"luv":[74.1695172801941567,-47.6470375142611218,61.6146893443493937],"rgb":[0.4,0.8,0.4],"xyz":[0.294693052816871415,0.469683459711102924,0.200837131778185574],"hpluv":[127.715012949239551,133.256044234036153,74.1695172801941567],"hsluv":[127.715012949239551,67.8510775159793,74.1695172801941567]},"#66cc77":{"lch":[74.407302734023375,70.4570986939790203,131.971622948486811],"luv":[74.407302734023375,-47.1190629819757234,52.3831715350808551],"rgb":[0.4,0.8,0.466666666666666674],"xyz":[0.30400706583707332,0.47340906491918372,0.249890933684583483],"hpluv":[131.971622948486811,120.156846155807528,74.407302734023375],"hsluv":[131.971622948486811,68.6882673601907499,74.407302734023375]},"#66cc88":{"lch":[74.6900832163393602,62.6050444414555045,138.002106903522986],"luv":[74.6900832163393602,-46.5261552249599859,41.8892404980031543],"rgb":[0.4,0.8,0.533333333333333326],"xyz":[0.315147482939017121,0.477865231759961318,0.308563797088155622],"hpluv":[138.002106903522986,106.361808066007058,74.6900832163393602],"hsluv":[138.002106903522986,69.6340873295455367,74.6900832163393602]},"#66cc99":{"lch":[75.0192831982140405,54.9734389641357382,146.572693391746668],"luv":[75.0192831982140405,-45.8800303566060634,30.2836887782922481],"rgb":[0.4,0.8,0.6],"xyz":[0.32820444704808982,0.483088017403590475,0.377330474729273557],"hpluv":[146.572693391746668,92.9863760296957338,75.0192831982140405],"hsluv":[146.572693391746668,70.6723780843603,75.0192831982140405]},"#66ccaa":{"lch":[75.3959940236094,48.5503126646653,158.569930493367366],"luv":[75.3959940236094,-45.1937477629490587,17.7386026218441692],"rgb":[0.4,0.8,0.66666666666666663],"xyz":[0.343262140013342376,0.489111094589691597,0.456634324346272158],"hpluv":[158.569930493367366,81.7114817988577187,75.3959940236094],"hsluv":[158.569930493367366,71.7849539596152368,75.3959940236094]},"#66ccbb":{"lch":[75.8209952994642,44.7015709258060667,174.304687468137473],"luv":[75.8209952994642,-44.4809102105153755,4.43610979112772],"rgb":[0.4,0.8,0.733333333333333282],"xyz":[0.360399732120679051,0.495966131432626356,0.546892309444913849],"hpluv":[174.304687468137473,74.8122352806046109,75.8209952994642],"hsluv":[174.304687468137473,72.9527506991265113,75.8209952994642]},"#66cccc":{"lch":[76.2947739303160262,44.7620652034609634,192.177050630061018],"luv":[76.2947739303160262,-43.7549393425641924,-9.44180938207391],"rgb":[0.4,0.8,0.8],"xyz":[0.379692107564400749,0.503683081610115102,0.648498820115184],"hpluv":[192.177050630061018,75.6461904464395,76.2947739303160262],"hsluv":[192.177050630061018,74.1568646821725679,76.2947739303160262]},"#66ccdd":{"lch":[76.8175423984245782,49.1342213212598082,208.868111129197587],"luv":[76.8175423984245782,-43.0284772118039101,-23.7217590764220851],"rgb":[0.4,0.8,0.866666666666666696],"xyz":[0.401210433115034348,0.512290411830368719,0.76182866801519],"hpluv":[208.868111129197587,85.3113130970085791,76.8175423984245782],"hsluv":[208.868111129197587,75.3794120212671714,76.8175423984245782]},"#66ccee":{"lch":[77.3892571801628435,57.0358051623713038,222.109360872917676],"luv":[77.3892571801628435,-42.312941633688304,-38.245235531031426],"rgb":[0.4,0.8,0.933333333333333348],"xyz":[0.425022613381209058,0.521815283936838736,0.887239484083713226],"hpluv":[222.109360872917676,102.061631830010029,77.3892571801628435],"hsluv":[222.109360872917676,76.6041682601332923,77.3892571801628435]},"#66ccff":{"lch":[78.0096377377628158,67.2874731922355664,231.792303901557148],"luv":[78.0096377377628158,-41.6182406850010267,-52.872734853430309],"rgb":[0.4,0.8,1],"xyz":[0.451193661791040479,0.53228370330077146,1.02507367237549518],"hpluv":[231.792303901557148,124.498094909356865,78.0096377377628158],"hsluv":[231.792303901557148,99.9999999999966604,78.0096377377628158]},"#114400":{"lch":[24.4916204196936391,35.767443133059956,124.131260038140155],"luv":[24.4916204196936391,-20.0687794552527912,29.6066559991685239],"rgb":[0.0666666666666666657,0.266666666666666663,0],"xyz":[0.0229819284997768124,0.0425325580378379114,0.00699846233187489172],"hpluv":[124.131260038140155,185.314627891622,24.4916204196936391],"hsluv":[124.131260038140155,100.000000000002416,24.4916204196936391]},"#114411":{"lch":[24.6196313539200702,32.2821952767626144,127.715012949240105],"luv":[24.6196313539200702,-19.7481274165088401,25.5372589646650674],"rgb":[0.0666666666666666657,0.266666666666666663,0.0666666666666666657],"xyz":[0.0239935939994139341,0.0429372242376927643,0.0123265672966305223],"hpluv":[127.715012949240105,166.387555424049935,24.6196313539200702],"hsluv":[127.715012949240105,84.7209219338948,24.6196313539200702]},"#114422":{"lch":[24.8548180969752792,26.7199561105771828,135.968420687644709],"luv":[24.8548180969752792,-19.2104947057918238,18.5718321042894203],"rgb":[0.0666666666666666657,0.266666666666666663,0.133333333333333331],"xyz":[0.0258689521378909527,0.0436873674930835856,0.0222034534926097184],"hpluv":[135.968420687644709,136.415738329938534,24.8548180969752792],"hsluv":[135.968420687644709,85.5945702875542338,24.8548180969752792]},"#114433":{"lch":[25.2362525898650887,20.3101465248311648,155.348193219538018],"luv":[25.2362525898650887,-18.4590663004995292,8.4714180143512],"rgb":[0.0666666666666666657,0.266666666666666663,0.2],"xyz":[0.0289567028703486933,0.0449224677860667,0.0384656073502208651],"hpluv":[155.348193219538018,102.123929581721498,25.2362525898650887],"hsluv":[155.348193219538018,86.8340768870874911,25.2362525898650887]},"#114444":{"lch":[25.774812755707849,18.0038630185053101,192.177050630061132],"luv":[25.774812755707849,-17.5987843886529483,-3.79761393914762779],"rgb":[0.0666666666666666657,0.266666666666666663,0.266666666666666663],"xyz":[0.0334146981145675703,0.0467056658837542715,0.0619443823031075036],"hpluv":[192.177050630061132,88.6358691141452226,25.774812755707849],"hsluv":[192.177050630061132,88.2889223192016743,25.774812755707849]},"#114455":{"lch":[26.4741010086829718,23.9697809957076196,225.699525295295985],"luv":[26.4741010086829718,-16.7410035671662349,-17.1548593857925162],"rgb":[0.0666666666666666657,0.266666666666666663,0.333333333333333315],"xyz":[0.0393771121539295693,0.0490906314994991044,0.0933464295770814],"hpluv":[225.699525295295985,114.889984549549212,26.4741010086829718],"hsluv":[225.699525295295985,89.7968555301121398,26.4741010086829718]},"#114466":{"lch":[27.3316922889079734,34.6428172107851182,242.548035964380944],"luv":[27.3316922889079734,-15.9705048052882308,-30.7419544037807526],"rgb":[0.0666666666666666657,0.266666666666666663,0.4],"xyz":[0.0469621079274377407,0.052124629808902416,0.133294073984225381],"hpluv":[242.548035964380944,160.837015687659374,27.3316922889079734],"hsluv":[242.548035964380944,91.2329185483074525,27.3316922889079734]},"#114477":{"lch":[28.3404051997208484,46.6267191674415,250.798290317077829],"luv":[28.3404051997208484,-15.3352867062553546,-44.0327142242719844],"rgb":[0.0666666666666666657,0.266666666666666663,0.466666666666666674],"xyz":[0.0562761209476396601,0.0558502350169832323,0.18234787589062329],"hpluv":[250.798290317077829,208.770018220734585,28.3404051997208484],"hsluv":[250.798290317077829,92.5248535524246734,28.3404051997208484]},"#114488":{"lch":[29.4896359978219706,58.6954673108201632,255.342505689020953],"luv":[29.4896359978219706,-14.8523182742844106,-56.7852667926718055],"rgb":[0.0666666666666666657,0.266666666666666663,0.533333333333333326],"xyz":[0.0674165380495834882,0.0603064018577608302,0.241020739294195457],"hpluv":[255.342505689020953,252.565763352450517,29.4896359978219706],"hsluv":[255.342505689020953,93.6449802292742817,29.4896359978219706]},"#114499":{"lch":[30.7666487879374699,70.4540899928233699,258.107815399211404],"luv":[30.7666487879374699,-14.5185243824624628,-68.9419411278265102],"rgb":[0.0666666666666666657,0.266666666666666663,0.6],"xyz":[0.0804735021586562,0.0655291875013899877,0.309787416935313364],"hpluv":[258.107815399211404,290.579747717257874,30.7666487879374699],"hsluv":[258.107815399211404,94.5943513350065359,30.7666487879374699]},"#1144aa":{"lch":[32.1577052090601185,81.8040240174920541,259.917940759024589],"luv":[32.1577052090601185,-14.3204852090806973,-80.5408098347099894],"rgb":[0.0666666666666666657,0.266666666666666663,0.66666666666666663],"xyz":[0.0955311951239087437,0.0715522646874911,0.389091266552311965],"hpluv":[259.917940759024589,322.796594575352628,32.1577052090601185],"hsluv":[259.917940759024589,95.3887741756132925,32.1577052090601185]},"#1144bb":{"lch":[33.6489603009756664,92.7573184463875435,261.168522985608377],"luv":[33.6489603009756664,-14.2409127099882671,-91.6576048702508928],"rgb":[0.0666666666666666657,0.266666666666666663,0.733333333333333282],"xyz":[0.11266878723124539,0.0784073015304258547,0.479349251650953712],"hpluv":[261.168522985608377,349.796823816496214,33.6489603009756664],"hsluv":[261.168522985608377,96.0495339612535872,33.6489603009756664]},"#1144cc":{"lch":[35.2271045850644597,103.362934076908545,262.068884255867147],"luv":[35.2271045850644597,-14.262270250582695,-102.374234005860515],"rgb":[0.0666666666666666657,0.266666666666666663,0.8],"xyz":[0.131961162674967131,0.0861242517079146563,0.580955762321223812],"hpluv":[262.068884255867147,372.329293739207799,35.2271045850644597],"hsluv":[262.068884255867147,96.5982694251149638,35.2271045850644597]},"#1144dd":{"lch":[36.8797734412618,113.676357292171801,262.73849416957313],"luv":[36.8797734412618,-14.3684841809298494,-112.764625967365617],"rgb":[0.0666666666666666657,0.266666666666666663,0.866666666666666696],"xyz":[0.153479488225600674,0.0947315819281681903,0.69428561022122981],"hpluv":[262.73849416957313,391.13009227787353,36.8797734412618],"hsluv":[262.73849416957313,97.0546019825808,36.8797734412618]},"#1144ee":{"lch":[38.5957670998368911,123.747928777943088,263.249741523271325],"luv":[38.5957670998368911,-14.5455638799169762,-122.890099065165245],"rgb":[0.0666666666666666657,0.266666666666666663,0.933333333333333348],"xyz":[0.177291668491775412,0.104256454034638207,0.819696426289753],"hpluv":[263.249741523271325,406.853061330967478,38.5957670998368911],"hsluv":[263.249741523271325,97.4353215147193623,38.5957670998368911]},"#1144ff":{"lch":[40.3651306844127546,133.619394536005728,263.648645306126298],"luv":[40.3651306844127546,-14.7816672391382209,-132.799265471613751],"rgb":[0.0666666666666666657,0.266666666666666663,1],"xyz":[0.203462716901606805,0.114724873398570917,0.957530614581534878],"hpluv":[263.648645306126298,420.051425771921231,40.3651306844127546],"hsluv":[263.648645306126298,99.9999999999994458,40.3651306844127546]},"#66dd00":{"lch":[78.7732081443282084,109.616469768408933,120.762072840728067],"luv":[78.7732081443282084,-56.0659919017112145,94.1932853050883],"rgb":[0.4,0.866666666666666696,0],"xyz":[0.313346863936385611,0.54535936903439,0.0887528503082264109],"hpluv":[120.762072840728067,211.559351010719155,78.7732081443282084],"hsluv":[120.762072840728067,100.000000000002444,78.7732081443282084]},"#66dd11":{"lch":[78.7966434753788576,108.675393583239966,121.014553037765893],"luv":[78.7966434753788576,-55.9956244091473678,93.1387739746547],"rgb":[0.4,0.866666666666666696,0.0666666666666666657],"xyz":[0.314358529436022716,0.545764035234244882,0.0940809552729820475],"hpluv":[121.014553037765893,210.019013530063148,78.7966434753788576],"hsluv":[121.014553037765893,98.7735218244661866,78.7966434753788576]},"#66dd22":{"lch":[78.8400557089289435,106.948443645027297,121.491090191754736],"luv":[78.8400557089289435,-55.866227309203758,91.1972271745690506],"rgb":[0.4,0.866666666666666696,0.133333333333333331],"xyz":[0.316233887574499772,0.546514178489635682,0.10395784146896124],"hpluv":[121.491090191754736,207.186246213049145,78.8400557089289435],"hsluv":[121.491090191754736,96.5169147905729,78.8400557089289435]},"#66dd33":{"lch":[78.911446872650572,104.154611952746194,122.300539429107701],"luv":[78.911446872650572,-55.6560904548950788,88.037394249850891],"rgb":[0.4,0.866666666666666696,0.2],"xyz":[0.319321638306957478,0.547749278782618809,0.120219995326572376],"hpluv":[122.300539429107701,202.586476802368111,78.911446872650572],"hsluv":[122.300539429107701,92.8487034899531807,78.911446872650572]},"#66dd44":{"lch":[79.0143300648071687,100.229492569308348,123.526451276321851],"luv":[79.0143300648071687,-55.3589437481663,83.5544045983716899],"rgb":[0.4,0.866666666666666696,0.266666666666666663],"xyz":[0.323779633551176393,0.549532476880306375,0.143698770279459015],"hpluv":[123.526451276321851,196.088207898644384,79.0143300648071687],"hsluv":[123.526451276321851,87.6539206040991843,79.0143300648071687]},"#66dd55":{"lch":[79.1515854502963,95.1800529291645603,125.27945296022996],"luv":[79.1515854502963,-54.9726586351532518,77.699737954393882],"rgb":[0.4,0.866666666666666696,0.333333333333333315],"xyz":[0.329742047590538379,0.551917442496051125,0.17510081755343293],"hpluv":[125.27945296022996,187.665730733793509,79.1515854502963],"hsluv":[125.27945296022996,80.8868034505971707,79.1515854502963]},"#66dd66":{"lch":[79.3256225689869723,89.0890908185611607,127.715012949239735],"luv":[79.3256225689869723,-54.4988561596450722,70.4751075215082921],"rgb":[0.4,0.866666666666666696,0.4],"xyz":[0.337327043364046564,0.554951440805454443,0.215048461960576892],"hpluv":[127.715012949239735,177.410630109117562,79.3256225689869723],"hsluv":[127.715012949239735,72.5638298210149,79.3256225689869723]},"#66dd77":{"lch":[79.538466322575843,82.1265081512392072,131.057978326052336],"luv":[79.538466322575843,-53.9425296262626048,61.9271090770055395],"rgb":[0.4,0.866666666666666696,0.466666666666666674],"xyz":[0.346641056384248469,0.558677046013535294,0.264102263866974774],"hpluv":[131.057978326052336,165.560886464635786,79.538466322575843],"hsluv":[131.057978326052336,73.175897046832489,79.538466322575843]},"#66dd88":{"lch":[79.7918079202835173,74.5708009722257543,135.636001638862723],"luv":[79.7918079202835173,-53.3115731427918,52.1409678341327378],"rgb":[0.4,0.866666666666666696,0.533333333333333326],"xyz":[0.35778147348619227,0.563133212854312837,0.322775127270546969],"hpluv":[135.636001638862723,152.557764790666909,79.7918079202835173],"hsluv":[135.636001638862723,73.8730513922454435,79.7918079202835173]},"#66dd99":{"lch":[80.0870378401123162,66.8478260511747919,141.915708870878916],"luv":[80.0870378401123162,-52.6162023759431392,41.2330825345609924],"rgb":[0.4,0.866666666666666696,0.6],"xyz":[0.370838437595265,0.568355998497942,0.391541804911664904],"hpluv":[141.915708870878916,139.150468179242381,80.0870378401123162],"hsluv":[141.915708870878916,74.6453790933081791,80.0870378401123162]},"#66ddaa":{"lch":[80.4252690581998877,59.592891473004542,150.502508447871207],"luv":[80.4252690581998877,-51.8682972227800931,29.3426729750825572],"rgb":[0.4,0.866666666666666696,0.66666666666666663],"xyz":[0.385896130560517525,0.574379075684043117,0.470845654528663449],"hpluv":[150.502508447871207,126.571308780245914,80.4252690581998877],"hsluv":[150.502508447871207,75.4812281571350638,80.4252690581998877]},"#66ddbb":{"lch":[80.807354973374558,53.7174771102931672,161.973645166837599],"luv":[80.807354973374558,-51.0807157732000334,16.6231111165276104],"rgb":[0.4,0.866666666666666696,0.733333333333333282],"xyz":[0.4030337226678542,0.581234112526977875,0.561103639627305251],"hpluv":[161.973645166837599,116.757770235740637,80.807354973374558],"hsluv":[161.973645166837599,76.3679029554368753,80.807354973374558]},"#66ddcc":{"lch":[81.2339045655681389,50.3705316419042148,176.319314132685548],"luv":[81.2339045655681389,-50.2666331071559256,3.23358221770368903],"rgb":[0.4,0.866666666666666696,0.8],"xyz":[0.422326098111575954,0.588951062704466732,0.662710150297575407],"hpluv":[176.319314132685548,112.393665646206941,81.2339045655681389],"hsluv":[176.319314132685548,77.2923330418296501,81.2339045655681389]},"#66dddd":{"lch":[81.7052962965957903,50.5769089008318389,192.177050630061],"luv":[81.7052962965957903,-49.4389517336029,-10.6683534552210038],"rgb":[0.4,0.866666666666666696,0.866666666666666696],"xyz":[0.443844423662209442,0.597558392924720239,0.776039998197581404],"hpluv":[192.177050630061,116.242714563462513,81.7052962965957903],"hsluv":[192.177050630061,78.2416694753709407,81.7052962965957903]},"#66ddee":{"lch":[82.2216916522674524,54.6311568672274745,207.154140846621715],"luv":[82.2216916522674524,-48.6098170936026577,-24.9328895793911158],"rgb":[0.4,0.866666666666666696,0.933333333333333348],"xyz":[0.467656603928384207,0.607083265031190256,0.901450814266104627],"hpluv":[207.154140846621715,129.793318723999505,82.2216916522674524],"hsluv":[207.154140846621715,79.2037752530793,82.2216916522674524]},"#66ddff":{"lch":[82.7830488398693376,61.9519841783888339,219.519505956683815],"luv":[82.7830488398693376,-47.7902556034158366,-39.4225799891321387],"rgb":[0.4,0.866666666666666696,1],"xyz":[0.493827652338215572,0.617551684395123,1.03928500255788636],"hpluv":[219.519505956683815,152.730665075356086,82.7830488398693376],"hsluv":[219.519505956683815,99.9999999999957,82.7830488398693376]},"#115500":{"lch":[30.9160157060817227,46.0913193883500583,125.457330883646421],"luv":[30.9160157060817227,-26.7374134918097575,37.543580579466358],"rgb":[0.0666666666666666657,0.333333333333333315,0],"xyz":[0.0347951852141227744,0.0661590714665301755,0.0109362145699901016],"hpluv":[125.457330883646421,189.179880792461034,30.9160157060817227],"hsluv":[125.457330883646421,100.000000000002402,30.9160157060817227]},"#115511":{"lch":[31.0114762783458957,43.2230667766736616,127.715012949240275],"luv":[31.0114762783458957,-26.4410342208804181,34.1921805521528697],"rgb":[0.0666666666666666657,0.333333333333333315,0.0666666666666666657],"xyz":[0.0358068507137599,0.0665637376663850283,0.0162643195347457331],"hpluv":[127.715012949240275,176.861157643680144,31.0114762783458957],"hsluv":[127.715012949240275,90.0538522348087156,31.0114762783458957]},"#115522":{"lch":[31.1874163697014737,38.3803455570512071,132.492971129528541],"luv":[31.1874163697014737,-25.925914044022,28.3001396827055132],"rgb":[0.0666666666666666657,0.333333333333333315,0.133333333333333331],"xyz":[0.0376822088522369147,0.0673138809217758427,0.0261412057307249292],"hpluv":[132.492971129528541,156.159643444286843,31.1874163697014737],"hsluv":[132.492971129528541,90.4316047034468653,31.1874163697014737]},"#115533":{"lch":[31.4742731349983,31.7764378074468219,142.363318860140765],"luv":[31.4742731349983,-25.163724938647551,19.4043538140960301],"rgb":[0.0666666666666666657,0.333333333333333315,0.2],"xyz":[0.0407699595846946553,0.0685489812147589556,0.0424033595883360759],"hpluv":[142.363318860140765,128.111709873485438,31.4742731349983],"hsluv":[142.363318860140765,90.9947325890089616,31.4742731349983]},"#115544":{"lch":[31.8824114421380642,25.5202649789159608,161.635705606154772],"luv":[31.8824114421380642,-24.2205825435089714,8.04035483341083435],"rgb":[0.0666666666666666657,0.333333333333333315,0.266666666666666663],"xyz":[0.0452279548289135358,0.0703321793124465355,0.0658821345412227144],"hpluv":[161.635705606154772,101.571845607751229,31.8824114421380642],"hsluv":[161.635705606154772,91.6999843863076194,31.8824114421380642]},"#115555":{"lch":[32.417637609391285,23.7206023942150033,192.177050630061103],"luv":[32.417637609391285,-23.1868997601056,-5.00346454561771115],"rgb":[0.0666666666666666657,0.333333333333333315,0.333333333333333315],"xyz":[0.0511903688682755278,0.0727171449281913684,0.0972841818151966159],"hpluv":[192.177050630061103,92.8503782686988899,32.417637609391285],"hsluv":[192.177050630061103,92.4869346485079,32.417637609391285]},"#115566":{"lch":[33.0818646063754045,29.1355194477524577,220.509575549450261],"luv":[33.0818646063754045,-22.1516601517912761,-18.9257085999416219],"rgb":[0.0666666666666666657,0.333333333333333315,0.4],"xyz":[0.0587753646417837061,0.0757511432375946869,0.137231826222340592],"hpluv":[220.509575549450261,111.756325010930979,33.0818646063754045],"hsluv":[220.509575549450261,93.2955878193037904,33.0818646063754045]},"#115577":{"lch":[33.8736729304774826,39.2775515041961185,237.359341141202208],"luv":[33.8736729304774826,-21.1850732372535866,-33.0744421585153958],"rgb":[0.0666666666666666657,0.333333333333333315,0.466666666666666674],"xyz":[0.0680893776619856117,0.0794767484456755,0.186285628128738501],"hpluv":[237.359341141202208,147.13684637222039,33.8736729304774826],"hsluv":[237.359341141202208,94.078253732623736,33.8736729304774826]},"#115588":{"lch":[34.7888943497230514,51.2161985161337938,246.60972521059881],"luv":[34.7888943497230514,-20.3324266151093482,-47.0073549392562455],"rgb":[0.0666666666666666657,0.333333333333333315,0.533333333333333326],"xyz":[0.0792297947639294398,0.0839329152864531,0.244958491532310668],"hpluv":[246.60972521059881,186.812546427038342,34.7888943497230514],"hsluv":[246.60972521059881,94.8038015691112719,34.7888943497230514]},"#115599":{"lch":[35.8212274371681403,63.5782184467896,252.028930114170464],"luv":[35.8212274371681403,-19.6162163870228632,-60.476391389741444],"rgb":[0.0666666666666666657,0.333333333333333315,0.6],"xyz":[0.0922867588730021671,0.0891557009300822517,0.313725169173428575],"hpluv":[252.028930114170464,225.22013661091745,35.8212274371681403],"hsluv":[252.028930114170464,95.4562831747131355,35.8212274371681403]},"#1155aa":{"lch":[36.9628521043173777,75.808874965898184,255.452401876993463],"luv":[36.9628521043173777,-19.0419916394553752,-73.3783897206670588],"rgb":[0.0666666666666666657,0.333333333333333315,0.66666666666666663],"xyz":[0.107344451838254695,0.0951787781161833601,0.393029018790427176],"hpluv":[255.452401876993463,260.251896817562397,36.9628521043173777],"hsluv":[255.452401876993463,96.0310300088164155,36.9628521043173777]},"#1155bb":{"lch":[38.2050019251475845,87.6984258792502089,257.752076786877694],"luv":[38.2050019251475845,-18.6045414354547205,-85.7023041678273216],"rgb":[0.0666666666666666657,0.333333333333333315,0.733333333333333282],"xyz":[0.124482043945591342,0.102033814959118119,0.483287003889068922],"hpluv":[257.752076786877694,291.280156181798475,38.2050019251475845],"hsluv":[257.752076786877694,96.5305142623785,38.2050019251475845]},"#1155cc":{"lch":[39.5384610498345523,99.1886562531622,259.372402836059223],"luv":[39.5384610498345523,-18.292845239891637,-97.4872368176334447],"rgb":[0.0666666666666666657,0.333333333333333315,0.8],"xyz":[0.143774419389313096,0.10975076513660692,0.584893514559339],"hpluv":[259.372402836059223,318.332933912315752,39.5384610498345523],"hsluv":[259.372402836059223,96.9610449958707,39.5384610498345523]},"#1155dd":{"lch":[40.9539668975822053,110.288480556245688,260.557616930578945],"luv":[40.9539668975822053,-18.0934548393737415,-108.7941902648341],"rgb":[0.0666666666666666657,0.333333333333333315,0.866666666666666696],"xyz":[0.16529274493994664,0.118358095356860454,0.698223362459345],"hpluv":[260.557616930578945,341.722445031840948,40.9539668975822053],"hsluv":[260.557616930578945,97.330522563257,40.9539668975822053]},"#1155ee":{"lch":[42.4425141949683038,121.034132372772049,261.450904748640312],"luv":[42.4425141949683038,-17.992549051743687,-119.689303523123172],"rgb":[0.0666666666666666657,0.333333333333333315,0.933333333333333348],"xyz":[0.189104925206121377,0.127882967463330471,0.823634178527868244],"hpluv":[261.450904748640312,361.864588035447412,42.4425141949683038],"hsluv":[261.450904748640312,97.6470858685672596,42.4425141949683038]},"#1155ff":{"lch":[43.9955669218353762,131.469960671873054,262.140820458865903],"luv":[43.9955669218353762,-17.9770474653633769,-130.235081001594637],"rgb":[0.0666666666666666657,0.333333333333333315,1],"xyz":[0.21527597361595277,0.138351386827263168,0.961468366819650089],"hpluv":[262.140820458865903,379.190057269809415,43.9955669218353762],"hsluv":[262.140820458865903,99.9999999999993321,43.9955669218353762]},"#66ee00":{"lch":[83.9510288300903511,118.631054776009961,121.878900606421581],"luv":[83.9510288300903511,-62.6521043104729145,100.737485489455693],"rgb":[0.4,0.933333333333333348,0],"xyz":[0.360525640276900428,0.639716921715420939,0.104479109088397595],"hpluv":[121.878900606421581,316.932305812441825,83.9510288300903511],"hsluv":[121.878900606421581,100.000000000002245,83.9510288300903511]},"#66ee11":{"lch":[83.9720997528394406,117.779830021225337,122.096631719604488],"luv":[83.9720997528394406,-62.5821687959979371,99.7775551344988401],"rgb":[0.4,0.933333333333333348,0.0666666666666666657],"xyz":[0.361537305776537532,0.640121587915275847,0.109807214053153232],"hpluv":[122.096631719604488,315.12898496103287,83.9720997528394406],"hsluv":[122.096631719604488,98.9534187198870825,83.9720997528394406]},"#66ee22":{"lch":[84.0111361497279461,116.215639794016113,122.506307539641156],"luv":[84.0111361497279461,-62.4534076072217061,98.0084017366813498],"rgb":[0.4,0.933333333333333348,0.133333333333333331],"xyz":[0.363412663915014589,0.640871731170666648,0.119684100249132425],"hpluv":[122.506307539641156,311.807725961995743,84.0111361497279461],"hsluv":[122.506307539641156,97.0256918708191,84.0111361497279461]},"#66ee33":{"lch":[84.0753427139745213,113.679067087327056,123.198426402241765],"luv":[84.0753427139745213,-62.2438639038254564,95.1242960560921],"rgb":[0.4,0.933333333333333348,0.2],"xyz":[0.366500414647472295,0.642106831463649774,0.135946254106743575],"hpluv":[123.198426402241765,306.400922934277446,84.0753427139745213],"hsluv":[123.198426402241765,93.8862320250161133,84.0753427139745213]},"#66ee44":{"lch":[84.1678970009459704,110.10189342016568,124.237870325737177],"luv":[84.1678970009459704,-61.946619900698991,91.0222127702015626],"rgb":[0.4,0.933333333333333348,0.266666666666666663],"xyz":[0.37095840989169121,0.64389002956133734,0.159425029059630213],"hpluv":[124.237870325737177,298.731636810455427,84.1678970009459704],"hsluv":[124.237870325737177,89.4277949312148337,84.1678970009459704]},"#66ee55":{"lch":[84.2914184237995414,105.474359140243067,125.706632503417083],"luv":[84.2914184237995414,-61.5585501093914829,85.6468641835444657],"rgb":[0.4,0.933333333333333348,0.333333333333333315],"xyz":[0.376920823931053195,0.64627499517708209,0.190827076333604129],"hpluv":[125.706632503417083,288.732343582820249,84.2914184237995414],"hsluv":[125.706632503417083,83.5978964235977315,84.2914184237995414]},"#66ee66":{"lch":[84.4481159447294374,99.8471979874678652,127.715012949239849],"luv":[84.4481159447294374,-61.0799597466417339,78.9854509596370633],"rgb":[0.4,0.933333333333333348,0.4],"xyz":[0.38450581970456138,0.649308993486485408,0.230774720740748063],"hpluv":[127.715012949239849,276.453302697114395,84.4481159447294374],"hsluv":[127.715012949239849,76.3932656313124454,84.4481159447294374]},"#66ee77":{"lch":[84.6398667383604391,93.3381964812165,130.416076861551431],"luv":[84.6398667383604391,-60.5142850922984863,71.0636350191446127],"rgb":[0.4,0.933333333333333348,0.466666666666666674],"xyz":[0.393819832724763286,0.65303459869456626,0.279828522647145972],"hpluv":[130.416076861551431,262.087365127001192,84.6398667383604391],"hsluv":[130.416076861551431,76.8478121958162461,84.6398667383604391]},"#66ee88":{"lch":[84.8682629083727704,86.1443361377895513,134.024834696689027],"luv":[84.8682629083727704,-59.8677379892917187,61.9411058721588503],"rgb":[0.4,0.933333333333333348,0.533333333333333326],"xyz":[0.404960249826707086,0.657490765535343802,0.338501386050718167],"hpluv":[134.024834696689027,246.018013362770375,84.8682629083727704],"hsluv":[134.024834696689027,77.3690194462974858,84.8682629083727704]},"#66ee99":{"lch":[85.1346415661787432,78.5628931277068,138.840952739605655],"luv":[85.1346415661787432,-59.1488647733143296,51.7062856200641718],"rgb":[0.4,0.933333333333333348,0.6],"xyz":[0.418017213935779841,0.662713551178973,0.407268063691836046],"hpluv":[138.840952739605655,228.905884969324347,85.1346415661787432],"hsluv":[138.840952739605655,77.9507906120806,85.1346415661787432]},"#66eeaa":{"lch":[85.4401056772853451,71.025817565124143,145.263991147699045],"luv":[85.4401056772853451,-58.3680297483556387,40.4702342974360576],"rgb":[0.4,0.933333333333333348,0.66666666666666663],"xyz":[0.433074906901032342,0.668736628365074082,0.486571913308834647],"hpluv":[145.263991147699045,211.83630636980061,85.4401056772853451],"hsluv":[145.263991147699045,78.5856392083502868,85.4401056772853451]},"#66eebb":{"lch":[85.7855396574798448,64.1465768711300228,153.7611846199909],"luv":[85.7855396574798448,-57.5368534805651,28.3600743271201026],"rgb":[0.4,0.933333333333333348,0.733333333333333282],"xyz":[0.450212499008369,0.67559166520800884,0.576829898407476449],"hpluv":[153.7611846199909,196.542528595596508,85.7855396574798448],"hsluv":[153.7611846199909,79.2651091664321683,85.7855396574798448]},"#66eecc":{"lch":[86.1716220205593,58.7524914026155827,164.690737532459508],"luv":[86.1716220205593,-56.6676444389915517,15.5123602250092176],"rgb":[0.4,0.933333333333333348,0.8],"xyz":[0.46950487445209077,0.683308615385497697,0.678436409077746605],"hpluv":[164.690737532459508,185.645341664818176,86.1716220205593],"hsluv":[164.690737532459508,79.9801993176568118,86.1716220205593]},"#66eedd":{"lch":[86.5988364705929285,55.8111450312658164,177.877712634427581],"luv":[86.5988364705929285,-55.7728621696499403,2.06682246606168096],"rgb":[0.4,0.933333333333333348,0.866666666666666696],"xyz":[0.491023200002724258,0.691915945605751204,0.791766256977752603],"hpluv":[177.877712634427581,182.628088950326941,86.5988364705929285],"hsluv":[177.877712634427581,80.7217641095277543,86.5988364705929285]},"#66eeee":{"lch":[87.0674822997282263,56.1274864183573783,192.177050630061075],"luv":[87.0674822997282263,-54.8646438121880493,-11.8391549953798521],"rgb":[0.4,0.933333333333333348,0.933333333333333348],"xyz":[0.514835380268899,0.701440817712221221,0.917177073046275826],"hpluv":[192.177050630061075,191.066910285097691,87.0674822997282263],"hsluv":[192.177050630061075,81.4808670778618165,87.0674822997282263]},"#66eeff":{"lch":[87.5776846199412518,59.9248574237073512,205.793536431897621],"luv":[87.5776846199412518,-53.9544158989052178,-26.0750751151289606],"rgb":[0.4,0.933333333333333348,1],"xyz":[0.541006428678730389,0.711909237076154,1.05501126133805756],"hpluv":[205.793536431897621,213.276590696447101,87.5776846199412518],"hsluv":[205.793536431897621,99.9999999999933351,87.5776846199412518]},"#116600":{"lch":[37.1543973335168118,56.0416844920186463,126.180156646926719],"luv":[37.1543973335168118,-33.0828721903909511,45.2348755755691201],"rgb":[0.0666666666666666657,0.4,0],"xyz":[0.0498232429199692434,0.0962151868782235159,0.0159455671386054508],"hpluv":[126.180156646926719,191.399273993181851,37.1543973335168118],"hsluv":[126.180156646926719,100.000000000002359,37.1543973335168118]},"#116611":{"lch":[37.2288128297302237,53.6508389550451668,127.715012949240304],"luv":[37.2288128297302237,-32.820060550512963,42.4412081124095124],"rgb":[0.0666666666666666657,0.4,0.0666666666666666657],"xyz":[0.0508349084196063616,0.0966198530780783688,0.021273672103361084],"hpluv":[127.715012949240304,182.867554307566394,37.2288128297302237],"hsluv":[127.715012949240304,93.1121786917857719,37.2288128297302237]},"#116622":{"lch":[37.366211587350719,49.4912288674311,130.823584918521846],"luv":[37.366211587350719,-32.3540076461773722,37.4513006989015125],"rgb":[0.0666666666666666657,0.4,0.133333333333333331],"xyz":[0.0527102665580833837,0.0973699963334691831,0.0311505582993402766],"hpluv":[130.823584918521846,168.069340269208539,37.366211587350719],"hsluv":[130.823584918521846,93.2954788878505639,37.366211587350719]},"#116633":{"lch":[37.5909073580641291,43.4152735453156,136.786924005406348],"luv":[37.5909073580641291,-31.6415889136076061,29.7270218494359924],"rgb":[0.0666666666666666657,0.4,0.2],"xyz":[0.0557980172905411242,0.0986050966264523,0.0474127121569514198],"hpluv":[136.786924005406348,146.554466726503705,37.5909073580641291],"hsluv":[136.786924005406348,93.5769168130898095,37.5909073580641291]},"#116644":{"lch":[37.9120295698984506,36.3990668435195417,147.559563985674146],"luv":[37.9120295698984506,-30.7189764474867033,19.525279846848818],"rgb":[0.0666666666666666657,0.4,0.266666666666666663],"xyz":[0.0602560125347600048,0.100388294724139876,0.0708914871098380583],"hpluv":[147.559563985674146,121.829522477327146,37.9120295698984506],"hsluv":[147.559563985674146,93.9439470857740559,37.9120295698984506]},"#116655":{"lch":[38.335629212958338,30.5483862618043851,166.063087397862887],"luv":[38.335629212958338,-29.6490880228798659,7.35768187759708869],"rgb":[0.0666666666666666657,0.4,0.333333333333333315],"xyz":[0.066218426574122,0.102773260339884709,0.102293534383811974],"hpluv":[166.063087397862887,101.117192726530064,38.335629212958338],"hsluv":[166.063087397862887,94.3739252192313529,38.335629212958338]},"#116666":{"lch":[38.8651381017916293,29.1618890828208741,192.177050630061217],"luv":[38.8651381017916293,-28.5057600031098204,-6.15121301239451324],"rgb":[0.0666666666666666657,0.4,0.4],"xyz":[0.0738034223476301682,0.105807258649288027,0.142241178790955936],"hpluv":[192.177050630061217,95.2126746116157392,38.8651381017916293],"hsluv":[192.177050630061217,94.8399842705083245,38.8651381017916293]},"#116677":{"lch":[39.5016809883423079,34.1234106492309124,216.700227589977857],"luv":[39.5016809883423079,-27.3592385518708738,-20.3931169809293316],"rgb":[0.0666666666666666657,0.4,0.466666666666666674],"xyz":[0.0831174353678320876,0.109532863857368837,0.191294980697353845],"hpluv":[216.700227589977857,109.616563248578402,39.5016809883423079],"hsluv":[216.700227589977857,95.3164106037614687,39.5016809883423079]},"#116688":{"lch":[40.2443638992953723,43.6497103352843823,233.004065811630028],"luv":[40.2443638992953723,-26.2665776267255495,-34.862072688430807],"rgb":[0.0666666666666666657,0.4,0.533333333333333326],"xyz":[0.0942578524697759157,0.113989030698146435,0.249967844100926],"hpluv":[233.004065811630028,137.630797119362086,40.2443638992953723],"hsluv":[233.004065811630028,95.7822055324918864,40.2443638992953723]},"#116699":{"lch":[41.090575936542443,55.3002439505846866,242.81143298809],"luv":[41.090575936542443,-25.2678118474637223,-49.189985418125],"rgb":[0.0666666666666666657,0.4,0.6],"xyz":[0.107314816578848629,0.119211816341775592,0.318734521742043919],"hpluv":[242.81143298809,170.774941475023041,41.090575936542443],"hsluv":[242.81143298809,96.2225162944548202,41.090575936542443]},"#1166aa":{"lch":[42.0363074660961757,67.6887016451143,248.882871092507173],"luv":[42.0363074660961757,-24.3865946332867658,-63.1431257746482615],"rgb":[0.0666666666666666657,0.4,0.66666666666666663],"xyz":[0.122372509544101171,0.125234893527876701,0.39803837135904252],"hpluv":[248.882871092507173,204.329442679703192,42.0363074660961757],"hsluv":[248.882871092507173,96.6284204735347885,42.0363074660961757]},"#1166bb":{"lch":[43.0764730814379746,80.16050208662584,252.853006907061769],"luv":[43.0764730814379746,-23.6332520973097289,-76.5974901030376429],"rgb":[0.0666666666666666657,0.4,0.733333333333333282],"xyz":[0.139510101651437818,0.132089930370811459,0.488296356457684266],"hpluv":[252.853006907061769,236.134594524550181,43.0764730814379746],"hsluv":[252.853006907061769,96.9958197331145,43.0764730814379746]},"#1166cc":{"lch":[44.2052232400861271,92.4179309088515737,255.583916344807051],"luv":[44.2052232400861271,-23.008531750755072,-89.5079964033815259],"rgb":[0.0666666666666666657,0.4,0.8],"xyz":[0.158802477095159544,0.139806880548300261,0.589902867127954367],"hpluv":[255.583916344807051,265.290671800528912,44.2052232400861271],"hsluv":[255.583916344807051,97.3240770235992159,44.2052232400861271]},"#1166dd":{"lch":[45.4162296513266455,104.336857924373376,257.542523527564185],"luv":[45.4162296513266455,-22.507022318245486,-101.880390006599782],"rgb":[0.0666666666666666657,0.4,0.866666666666666696],"xyz":[0.180320802645793088,0.148414210768553795,0.703232715027960364],"hpluv":[257.542523527564185,291.518421142394175,45.4162296513266455],"hsluv":[257.542523527564185,97.6147741074162,45.4162296513266455]},"#1166ee":{"lch":[46.7029335650228674,115.880201424536907,258.995545526323895],"luv":[46.7029335650228674,-22.1198283610194721,-113.74943637429719],"rgb":[0.0666666666666666657,0.4,0.933333333333333348],"xyz":[0.204132982911967853,0.157939082875023812,0.828643531096483588],"hpluv":[258.995545526323895,314.850514307077333,46.7029335650228674],"hsluv":[258.995545526323895,97.870742288996567,46.7029335650228674]},"#1166ff":{"lch":[48.0587511138394348,127.054293237547355,260.103604495506659],"luv":[48.0587511138394348,-21.8364562757409573,-125.163743182322264],"rgb":[0.0666666666666666657,0.4,1],"xyz":[0.230304031321799219,0.168407502238956508,0.966477719388265433],"hpluv":[260.103604495506659,335.471932494038299,48.0587511138394348],"hsluv":[260.103604495506659,99.9999999999992184,48.0587511138394348]},"#66ff00":{"lch":[89.0839511722278417,127.467952451328657,122.755484474710229],"luv":[89.0839511722278417,-68.9671698198214074,107.198919720201],"rgb":[0.4,1,0],"xyz":[0.41237801270657426,0.74342166657477,0.121763233231621706],"hpluv":[122.755484474710229,522.717702913530729,89.0839511722278417],"hsluv":[122.755484474710229,100.000000000002402,89.0839511722278417]},"#66ff11":{"lch":[89.1030144718140917,126.693355761899767,122.944319876693868],"luv":[89.1030144718140917,-68.8988566751164342,106.320994836735167],"rgb":[0.4,1,0.0666666666666666657],"xyz":[0.413389678206211364,0.743826332774625,0.127091338196377329],"hpluv":[122.944319876693868,520.53129302948,89.1030144718140917],"hsluv":[122.944319876693868,99.9999999999913456,89.1030144718140917]},"#66ff22":{"lch":[89.1383344673707825,125.268361506965746,123.29878008449495],"luv":[89.1383344673707825,-68.7729595958538482,104.70168300016438],"rgb":[0.4,1,0.133333333333333331],"xyz":[0.415265036344688421,0.744576476030015755,0.136968224392356536],"hpluv":[123.29878008449495,516.49933125362179,89.1383344673707825],"hsluv":[123.29878008449495,99.9999999999914877,89.1383344673707825]},"#66ff33":{"lch":[89.1964366933732,122.952924407393425,123.895139690212403],"luv":[89.1964366933732,-68.5677350303770368,102.0582546055644],"rgb":[0.4,1,0.2],"xyz":[0.418352787077146127,0.745811576322998881,0.153230378249967686],"hpluv":[123.895139690212403,509.920932540516333,89.1964366933732],"hsluv":[123.895139690212403,99.9999999999913456,89.1964366933732]},"#66ff44":{"lch":[89.2802097655713,119.677402261160566,124.785058224819977],"luv":[89.2802097655713,-68.2758869475835439,98.2908127624369143],"rgb":[0.4,1,0.266666666666666663],"xyz":[0.422810782321365042,0.747594774420686448,0.176709153202854324],"hpluv":[124.785058224819977,500.557479589511445,89.2802097655713],"hsluv":[124.785058224819977,99.9999999999914451,89.2802097655713]},"#66ff55":{"lch":[89.392045372062455,115.420778437487911,126.031255758612545],"luv":[89.392045372062455,-67.8935601171189802,93.3403481337991536],"rgb":[0.4,1,0.333333333333333315],"xyz":[0.428773196360727,0.749979740036431197,0.20811120047682824],"hpluv":[126.031255758612545,488.288652672415253,89.392045372062455],"hsluv":[126.031255758612545,99.9999999999912177,89.392045372062455]},"#66ff66":{"lch":[89.5339732348528088,110.211236984550467,127.715012949239977],"luv":[89.5339732348528088,-67.4199983006921428,87.1840615410833664],"rgb":[0.4,1,0.4],"xyz":[0.436358192134235212,0.753013738345834516,0.248058844883972174],"hpluv":[127.715012949239977,473.1190638884799,89.5339732348528088],"hsluv":[127.715012949239977,99.9999999999912177,89.5339732348528088]},"#66ff77":{"lch":[89.7077333531255,104.130085615398272,129.945267186452298],"luv":[89.7077333531255,-66.8572982376138754,79.8321764869086223],"rgb":[0.4,1,0.466666666666666674],"xyz":[0.445672205154437118,0.756739343553915367,0.297112646790370083],"hpluv":[129.945267186452298,455.203211628206077,89.7077333531255],"hsluv":[129.945267186452298,99.9999999999911466,89.7077333531255]},"#66ff88":{"lch":[89.9148190538961529,97.3190386909276413,132.870301628739924],"luv":[89.9148190538961529,-66.2101394375234378,71.3246992800528687],"rgb":[0.4,1,0.533333333333333326],"xyz":[0.456812622256380918,0.761195510394692909,0.355785510193942278],"hpluv":[132.870301628739924,434.894743355908361,89.9148190538961529],"hsluv":[132.870301628739924,99.999999999990834,89.9148190538961529]},"#66ff99":{"lch":[90.1565046807361,89.9924560427222247,136.692010716646195],"luv":[90.1565046807361,-65.4854512845448795,61.7276098246221707],"rgb":[0.4,1,0.6],"xyz":[0.469869586365453618,0.766418296038322122,0.424552187835060157],"hpluv":[136.692010716646195,412.835114866532763,90.1565046807361],"hsluv":[136.692010716646195,99.9999999999909903,90.1565046807361]},"#66ffaa":{"lch":[90.4338646074596113,82.4570841698328678,141.679424663280656],"luv":[90.4338646074596113,-64.6920148236146,51.1284064669742264],"rgb":[0.4,1,0.66666666666666663],"xyz":[0.484927279330706174,0.772441373224423189,0.503856037452058758],"hpluv":[141.679424663280656,390.10709074414774,90.4338646074596113],"hsluv":[141.679424663280656,99.9999999999905924,90.4338646074596113]},"#66ffbb":{"lch":[90.747787175062669,75.1410408914244101,148.168460326052468],"luv":[90.747787175062669,-63.84001546278364,39.631155067172358],"rgb":[0.4,1,0.733333333333333282],"xyz":[0.502064871438042792,0.779296410067358,0.59411402255070056],"hpluv":[148.168460326052468,368.486167720556807,90.747787175062669],"hsluv":[148.168460326052468,99.9999999999904077,90.747787175062669]},"#66ffcc":{"lch":[91.0989856399247486,68.6265957122477,156.512275503644645],"luv":[91.0989856399247486,-62.9405723747737085,27.3513068826366492],"rgb":[0.4,1,0.8],"xyz":[0.521357246881764547,0.787013360244846805,0.695720533220970716],"hpluv":[156.512275503644645,350.804850059399143,91.0989856399247486],"hsluv":[156.512275503644645,99.9999999999903508,91.0989856399247486]},"#66ffdd":{"lch":[91.4880074096490716,63.6578272942329875,166.916209854529029],"luv":[91.4880074096490716,-62.0052733715472826,14.410588119229697],"rgb":[0.4,1,0.866666666666666696],"xyz":[0.542875572432398146,0.795620690465100311,0.809050381120976714],"hpluv":[166.916209854529029,341.336295176875581,91.4880074096490716],"hsluv":[166.916209854529029,99.9999999999898819,91.4880074096490716]},"#66ffee":{"lch":[91.9152423718395113,61.0528599966611765,179.125088100836763],"luv":[91.9152423718395113,-61.045742111776633,0.93224663816584552],"rgb":[0.4,1,0.933333333333333348],"xyz":[0.566687752698572855,0.805145562571570328,0.934461197189499937],"hpluv":[179.125088100836763,345.840646438583576,91.9152423718395113],"hsluv":[179.125088100836763,99.9999999999894,91.9152423718395113]},"#66ffff":{"lch":[92.3809308294128,61.4559907165056,192.17705063006116],"luv":[92.3809308294128,-60.0732592166006256,-12.9631139022354667],"rgb":[0.4,1,1],"xyz":[0.592858801108404276,0.815613981935503,1.07229538548128178],"hpluv":[192.17705063006116,370.76546272919029,92.3809308294128],"hsluv":[192.17705063006116,99.9999999999889866,92.3809308294128]},"#117700":{"lch":[43.2300348418233042,65.6725964696673685,126.613348243544976],"luv":[43.2300348418233042,-39.1679175007181684,52.7139845365981],"rgb":[0.0666666666666666657,0.466666666666666674,0],"xyz":[0.0682769809733868721,0.133122662985059287,0.0220968131564111547],"hpluv":[126.613348243544976,192.769325646383436,43.2300348418233042],"hsluv":[126.613348243544976,100.000000000002359,43.2300348418233042]},"#117711":{"lch":[43.289989941732955,63.6505577690815443,127.715012949240403],"luv":[43.289989941732955,-38.9372319378938414,50.351618378457772],"rgb":[0.0666666666666666657,0.466666666666666674,0.0666666666666666657],"xyz":[0.0692886464730239904,0.13352732918491414,0.0274249181211667845],"hpluv":[127.715012949240403,186.57525992916959,43.289989941732955],"hsluv":[127.715012949240403,95.0000616991484321,43.289989941732955]},"#117722":{"lch":[43.400811094951429,60.069144786817489,129.889765673233825],"luv":[43.400811094951429,-38.5230987158151308,46.089836414888758],"rgb":[0.0666666666666666657,0.466666666666666674,0.133333333333333331],"xyz":[0.0711640046115010194,0.134277472440304968,0.037301804317145984],"hpluv":[129.889765673233825,175.627665872500842,43.400811094951429],"hsluv":[129.889765673233825,95.0973605906006725,43.400811094951429]},"#117733":{"lch":[43.5823807888255317,54.6433249694405205,133.881596062605809],"luv":[43.5823807888255317,-37.8771324094584756,39.3854770715327476],"rgb":[0.0666666666666666657,0.466666666666666674,0.2],"xyz":[0.074251755343958753,0.135512572733288067,0.0535639581747571272],"hpluv":[133.881596062605809,159.098283206795713,43.5823807888255317],"hsluv":[133.881596062605809,95.249567515942033,43.5823807888255317]},"#117744":{"lch":[43.8425891980029,47.8554364611196803,140.669149905405504],"luv":[43.8425891980029,-37.0161352468332083,30.3306533110056051],"rgb":[0.0666666666666666657,0.466666666666666674,0.266666666666666663],"xyz":[0.0787097505881776266,0.137295770830975661,0.0770427331276437588],"hpluv":[140.669149905405504,138.507858249946878,43.8425891980029],"hsluv":[140.669149905405504,95.4533619015585373,43.8425891980029]},"#117755":{"lch":[44.18711059062651,40.7988283335817243,151.872601466806259],"luv":[44.18711059062651,-35.9805491223838843,19.2339407882209947],"rgb":[0.0666666666666666657,0.466666666666666674,0.333333333333333315],"xyz":[0.0846721646275396256,0.139680736446720494,0.108444780401617674],"hpluv":[151.872601466806259,117.163251003272293,44.18711059062651],"hsluv":[151.872601466806259,95.7000805167539426,44.18711059062651]},"#117766":{"lch":[44.6197667240920879,35.4343089397309186,169.362936023125116],"luv":[44.6197667240920879,-34.8254110013137463,6.54071850990925796],"rgb":[0.0666666666666666657,0.466666666666666674,0.4],"xyz":[0.0922571604010478,0.142714734756123784,0.148392424808761636],"hpluv":[169.362936023125116,100.771099800457392,44.6197667240920879],"hsluv":[169.362936023125116,95.9777414193434453,44.6197667240920879]},"#117777":{"lch":[45.1427402486772138,34.384087641882445,192.177050630061217],"luv":[45.1427402486772138,-33.6104614986274584,-7.25274850066749],"rgb":[0.0666666666666666657,0.466666666666666674,0.466666666666666674],"xyz":[0.101571173421249716,0.146440339964204608,0.197446226715159545],"hpluv":[192.177050630061217,96.651570122263351,45.1427402486772138],"hsluv":[192.177050630061217,96.2732475219964385,45.1427402486772138]},"#117788":{"lch":[45.7567431438856502,38.9735922704815891,213.78628123605418],"luv":[45.7567431438856502,-32.3916401681270685,-21.6730833451154119],"rgb":[0.0666666666666666657,0.466666666666666674,0.533333333333333326],"xyz":[0.112711590523193544,0.150896506804982206,0.256119090118731685],"hpluv":[213.78628123605418,108.082320192335175,45.7567431438856502],"hsluv":[213.78628123605418,96.5742797371803192,45.7567431438856502]},"#117799":{"lch":[46.4611794427891169,47.8902134896154763,229.321579893426758],"luv":[46.4611794427891169,-31.2154548044213769,-36.3189747850083791],"rgb":[0.0666666666666666657,0.466666666666666674,0.6],"xyz":[0.125768554632266272,0.156119292448611363,0.32488576775984962],"hpluv":[229.321579893426758,130.796423620493698,46.4611794427891169],"hsluv":[229.321579893426758,96.8705519561321,46.4611794427891169]},"#1177aa":{"lch":[47.254315604307827,59.1280670765604199,239.379878554404911],"luv":[47.254315604307827,-30.1165063567495856,-50.8834389666627231],"rgb":[0.0666666666666666657,0.466666666666666674,0.66666666666666663],"xyz":[0.1408262475975188,0.162142369634712458,0.40418961737684822],"hpluv":[239.379878554404911,158.77844008322549,47.254315604307827],"hsluv":[239.379878554404911,97.1543662497403488,47.254315604307827]},"#1177bb":{"lch":[48.1334597651774914,71.3648635001192133,245.920143546346225],"luv":[48.1334597651774914,-29.1175429122131746,-65.1545273725937761],"rgb":[0.0666666666666666657,0.466666666666666674,0.733333333333333282],"xyz":[0.157963839704855447,0.168997406477647216,0.494447602475489967],"hpluv":[245.920143546346225,188.138070935962588,48.1334597651774914],"hsluv":[245.920143546346225,97.4206074841270464,48.1334597651774914]},"#1177cc":{"lch":[49.0951452720171488,83.8954152066927463,250.336037436893122],"luv":[49.0951452720171488,-28.2310616920000612,-79.0028344329863756],"rgb":[0.0666666666666666657,0.466666666666666674,0.8],"xyz":[0.177256215148577201,0.176714356655136018,0.596054113145760178],"hpluv":[250.336037436893122,216.83980339157776,49.0951452720171488],"hsluv":[250.336037436893122,97.666394869173061,49.0951452720171488]},"#1177dd":{"lch":[50.1353116048344702,96.3594544857749,253.441700788778064],"luv":[50.1353116048344702,-27.4615589113116805,-92.3634519220491512],"rgb":[0.0666666666666666657,0.466666666666666674,0.866666666666666696],"xyz":[0.198774540699210744,0.185321686875389552,0.709383961045766176],"hpluv":[253.441700788778064,243.887723915279508,50.1353116048344702],"hsluv":[253.441700788778064,97.8905898818146341,50.1353116048344702]},"#1177ee":{"lch":[51.2494756916451593,108.579054392530807,255.706052301270915],"luv":[51.2494756916451593,-26.8078049752198453,-105.217644172385562],"rgb":[0.0666666666666666657,0.466666666666666674,0.933333333333333348],"xyz":[0.222586720965385454,0.194846558981859597,0.834794777114289399],"hpluv":[255.706052301270915,268.841280267375566,51.2494756916451593],"hsluv":[255.706052301270915,98.0932983984315,51.2494756916451593]},"#1177ff":{"lch":[52.4328877873246739,120.474912105814852,257.407785454377859],"luv":[52.4328877873246739,-26.2648114927385947,-117.577056112809359],"rgb":[0.0666666666666666657,0.466666666666666674,1],"xyz":[0.248757769375216875,0.205314978345792293,0.972628965406071133],"hpluv":[257.407785454377859,291.562836812545811,52.4328877873246739],"hsluv":[257.407785454377859,99.9999999999990905,52.4328877873246739]},"#118800":{"lch":[49.1629818744817157,75.0325981068150725,126.891404302910644],"luv":[49.1629818744817157,-45.0420871994947447,60.0091756264985],"rgb":[0.0666666666666666657,0.533333333333333326,0],"xyz":[0.0903493506983573252,0.177267402435000831,0.0294542697314011],"hpluv":[126.891404302910644,193.664979881129256,49.1629818744817157],"hsluv":[126.891404302910644,100.000000000002487,49.1629818744817157]},"#118811":{"lch":[49.2125288978643,73.2988946552939211,127.715012949240403],"luv":[49.2125288978643,-44.8394509336223663,57.9840633075946883],"rgb":[0.0666666666666666657,0.533333333333333326,0.0666666666666666657],"xyz":[0.0913610161979944435,0.177672068634855684,0.0347823746961567343],"hpluv":[127.715012949240403,188.999680167490567,49.2125288978643],"hsluv":[127.715012949240403,96.2345237189928326,49.2125288978643]},"#118822":{"lch":[49.3041772439320312,70.1927728141533,129.31476933948187],"luv":[49.3041772439320312,-44.4727599639014315,54.3065279366352556],"rgb":[0.0666666666666666657,0.533333333333333326,0.133333333333333331],"xyz":[0.0932363743364714725,0.178422211890246513,0.0446592608921359269],"hpluv":[129.31476933948187,180.6541776618526,49.3041772439320312],"hsluv":[129.31476933948187,96.2899748067816859,49.3041772439320312]},"#118833":{"lch":[49.454516912369769,65.3819990709954766,132.170105234646456],"luv":[49.454516912369769,-43.8931572746598917,48.4581938064309767],"rgb":[0.0666666666666666657,0.533333333333333326,0.2],"xyz":[0.0963241250689292,0.179657312183229612,0.060921414749747077],"hpluv":[132.170105234646456,167.761213036429979,49.454516912369769],"hsluv":[132.170105234646456,96.3778002926358,49.454516912369769]},"#118844":{"lch":[49.6703617695526,59.1036258375550787,136.829676092870073],"luv":[49.6703617695526,-43.1056388924535057,40.4368950689726887],"rgb":[0.0666666666666666657,0.533333333333333326,0.266666666666666663],"xyz":[0.10078212031314808,0.181440510280917205,0.0844001897026337156],"hpluv":[136.829676092870073,150.9927614306973,49.6703617695526],"hsluv":[136.829676092870073,96.4975069627829356,49.6703617695526]},"#118855":{"lch":[49.9568473676091145,51.9652717779864091,144.176427678513875],"luv":[49.9568473676091145,-42.1346422468413806,30.4148219408018328],"rgb":[0.0666666666666666657,0.533333333333333326,0.333333333333333315],"xyz":[0.106744534352510079,0.183825475896662038,0.115802236976607617],"hpluv":[144.176427678513875,131.995007799011802,49.9568473676091145],"hsluv":[144.176427678513875,96.6457662191899658,49.9568473676091145]},"#118866":{"lch":[50.3177367885428879,45.0776565581224133,155.49998607369966],"luv":[50.3177367885428879,-41.0189171061503615,18.6934095394821433],"rgb":[0.0666666666666666657,0.533333333333333326,0.4],"xyz":[0.11432953012601825,0.186859474206065329,0.155749881383751593],"hpluv":[155.49998607369966,113.67882025976219,50.3177367885428879],"hsluv":[155.49998607369966,96.8171590628882512,50.3177367885428879]},"#118877":{"lch":[50.7555873970602391,40.2042284802375036,171.921706717236162],"luv":[50.7555873970602391,-39.8052806191025255,5.64974535051283322],"rgb":[0.0666666666666666657,0.533333333333333326,0.466666666666666674],"xyz":[0.12364354314622017,0.190585079414146152,0.204803683290149502],"hpluv":[171.921706717236162,100.514149141729121,50.7555873970602391],"hsluv":[171.921706717236162,97.0050762990714333,50.7555873970602391]},"#118888":{"lch":[51.2718664023781088,39.4294820301430349,192.17705063006116],"luv":[51.2718664023781088,-38.5423368357954814,-8.3169901046866368],"rgb":[0.0666666666666666657,0.533333333333333326,0.533333333333333326],"xyz":[0.134783960248164,0.19504124625492375,0.263476546693721669],"hpluv":[192.17705063006116,97.5845966821491118,51.2718664023781088],"hsluv":[192.17705063006116,97.2026219422035,51.2718664023781088]},"#118899":{"lch":[51.8670503792929907,43.7110075029310678,211.486174513119295],"luv":[51.8670503792929907,-37.2752705782940623,-22.8299448145688864],"rgb":[0.0666666666666666657,0.533333333333333326,0.6],"xyz":[0.147840924357236725,0.200264031898552908,0.332243224334839549],"hpluv":[211.486174513119295,106.93960912970239,51.8670503792929907],"hsluv":[211.486174513119295,97.4033619208845,51.8670503792929907]},"#1188aa":{"lch":[52.5407237145479371,52.059033028958666,226.184651315961702],"luv":[52.5407237145479371,-36.0423686073764102,-37.5644856890150507],"rgb":[0.0666666666666666657,0.533333333333333326,0.66666666666666663],"xyz":[0.162898617322489253,0.206287109084654,0.411547073951838149],"hpluv":[226.184651315961702,125.730132415512543,52.5407237145479371],"hsluv":[226.184651315961702,97.6018250350267,52.5407237145479371]},"#1188bb":{"lch":[53.2916815113449047,62.8295543710454396,236.286042109927791],"luv":[53.2916815113449047,-34.8733609598062557,-52.2628127623381573],"rgb":[0.0666666666666666657,0.533333333333333326,0.733333333333333282],"xyz":[0.1800362094298259,0.213142145927588761,0.501805059050479896],"hpluv":[236.286042109927791,149.604233097343041,53.2916815113449047],"hsluv":[236.286042109927791,97.7937430875757201,53.2916815113449047]},"#1188cc":{"lch":[54.1180375597057548,74.8024459991104607,243.146336149822275],"luv":[54.1180375597057548,-33.7892633498457826,-66.735984369188742],"rgb":[0.0666666666666666657,0.533333333333333326,0.8],"xyz":[0.199328584873547654,0.220859096105077563,0.60341156972075],"hpluv":[243.146336149822275,175.393335022858878,54.1180375597057548],"hsluv":[243.146336149822275,97.9760759990174819,54.1180375597057548]},"#1188dd":{"lch":[55.0173353812408266,87.2581949437380331,247.918019831454984],"luv":[55.0173353812408266,-32.8032215872693484,-80.8575366823396138],"rgb":[0.0666666666666666657,0.533333333333333326,0.866666666666666696],"xyz":[0.220846910424181198,0.229466426325331097,0.716741417620756],"hpluv":[247.918019831454984,201.254684785248685,55.0173353812408266],"hsluv":[247.918019831454984,98.1468934162311513,55.0173353812408266]},"#1188ee":{"lch":[55.9866591638471363,99.7959623087877645,251.344854654704591],"luv":[55.9866591638471363,-31.921869990719685,-94.5527805483930734],"rgb":[0.0666666666666666657,0.533333333333333326,0.933333333333333348],"xyz":[0.244659090690355907,0.238991298431801141,0.842152233689279273],"hpluv":[251.344854654704591,226.187053837960264,55.9866591638471363],"hsluv":[251.344854654704591,98.3051827042817,55.9866591638471363]},"#1188ff":{"lch":[57.0227411270994082,112.196885547184024,253.882464988485651],"luv":[57.0227411270994082,-31.1468293758358783,-107.786901552649141],"rgb":[0.0666666666666666657,0.533333333333333326,1],"xyz":[0.270830139100187328,0.249459717795733837,0.979986421981061118],"hpluv":[253.882464988485651,249.673263359937977,57.0227411270994082],"hsluv":[253.882464988485651,99.9999999999988916,57.0227411270994082]},"#119900":{"lch":[54.9698669410824721,84.160615619067471,127.079428544988929],"luv":[54.9698669410824721,-50.7422517332937772,67.1433772639973],"rgb":[0.0666666666666666657,0.6,0],"xyz":[0.116218951150824812,0.229006603339936526,0.0380774698822233526],"hpluv":[127.079428544988929,194.277964405092661,54.9698669410824721],"hsluv":[127.079428544988929,100.000000000002373,54.9698669410824721]},"#119911":{"lch":[55.0116447857556494,82.6558224500047,127.715012949240403],"luv":[55.0116447857556494,-50.563404981135136,65.3859852078442],"rgb":[0.0666666666666666657,0.6,0.0666666666666666657],"xyz":[0.11723061665046193,0.229411269539791379,0.0434055748469789823],"hpluv":[127.715012949240403,190.659367551848248,55.0116447857556494],"hsluv":[127.715012949240403,97.0796004133795094,55.0116447857556494]},"#119922":{"lch":[55.0889600096002852,79.9388272851777657,128.936266554168185],"luv":[55.0889600096002852,-50.237998627918941,62.1800579091938204],"rgb":[0.0666666666666666657,0.6,0.133333333333333331],"xyz":[0.119105974788938959,0.230161412795182208,0.0532824610429581819],"hpluv":[128.936266554168185,184.133380166819137,55.0889600096002852],"hsluv":[128.936266554168185,97.113065541928691,55.0889600096002852]},"#119933":{"lch":[55.215893256771821,75.6695179958245916,131.075562701176153],"luv":[55.215893256771821,-49.7189430335536,57.0429895547794175],"rgb":[0.0666666666666666657,0.6,0.2],"xyz":[0.122193725521396693,0.231396513088165307,0.0695446149005693182],"hpluv":[131.075562701176153,173.898642472918851,55.215893256771821],"hsluv":[131.075562701176153,97.1665253707361,55.215893256771821]},"#119944":{"lch":[55.398361036949,69.9528706873860671,134.469703140623466],"luv":[55.398361036949,-49.0042253731102591,49.9198358669935303],"rgb":[0.0666666666666666657,0.6,0.266666666666666663],"xyz":[0.126651720765615566,0.2331797111858529,0.0930233898534559567],"hpluv":[134.469703140623466,160.231519707698453,55.398361036949],"hsluv":[134.469703140623466,97.2403070889690184,55.398361036949]},"#119955":{"lch":[55.6409569880907497,63.1400511875114887,139.633471194580181],"luv":[55.6409569880907497,-48.1074656204671172,40.8942271664002206],"rgb":[0.0666666666666666657,0.6,0.333333333333333315],"xyz":[0.132614134804977579,0.235564676801597733,0.124425437127429872],"hpluv":[139.633471194580181,143.995747016857166,55.6409569880907497],"hsluv":[139.633471194580181,97.3331834328701575,55.6409569880907497]},"#119966":{"lch":[55.9472168173363,55.8918514512489466,147.340496807064056],"luv":[55.9472168173363,-47.0549257965888,30.1617807320125095],"rgb":[0.0666666666666666657,0.6,0.4],"xyz":[0.140199130578485737,0.238598675111001024,0.164373081534573834],"hpluv":[147.340496807064056,126.76791164907155,55.9472168173363],"hsluv":[147.340496807064056,97.4426708460479,55.9472168173363]},"#119977":{"lch":[56.319758368673476,49.2851425936320169,158.582299284916047],"luv":[56.319758368673476,-45.8816608646539308,17.9971796894826],"rgb":[0.0666666666666666657,0.6,0.466666666666666674],"xyz":[0.14951314359868767,0.242324280319081847,0.213426883440971743],"hpluv":[158.582299284916047,111.043862853999471,56.319758368673476],"hsluv":[158.582299284916047,97.5654087237770398,56.319758368673476]},"#119988":{"lch":[56.7603710001512951,44.8759084930006864,173.96527373508107],"luv":[56.7603710001512951,-44.6272223318454451,4.71785862613608131],"rgb":[0.0666666666666666657,0.6,0.533333333333333326],"xyz":[0.16065356070063147,0.246780447159859445,0.27209974684454391],"hpluv":[173.96527373508107,100.324581054675164,56.7603710001512951],"hsluv":[173.96527373508107,97.6975811674153647,56.7603710001512951]},"#119999":{"lch":[57.2700846473106822,44.3289506401906692,192.177050630061103],"luv":[57.2700846473106822,-43.3315696575835219,-9.35045110518458422],"rgb":[0.0666666666666666657,0.6,0.6],"xyz":[0.173710524809704198,0.252003232803488575,0.340866424485661845],"hpluv":[192.177050630061103,98.2197789195824384,57.2700846473106822],"hsluv":[192.177050630061103,97.8353178900151903,57.2700846473106822]},"#1199aa":{"lch":[57.849232550626823,48.3524707931101716,209.625127722111756],"luv":[57.849232550626823,-42.0317498411296384,-23.9017454821038378],"rgb":[0.0666666666666666657,0.6,0.66666666666666663],"xyz":[0.188768217774956726,0.258026309989589697,0.42017027410266039],"hpluv":[209.625127722111756,106.062142541807418,57.849232550626823],"hsluv":[209.625127722111756,97.9750198241805492,57.849232550626823]},"#1199bb":{"lch":[58.4975141278551263,56.1838887208170235,223.492153209811363],"luv":[58.4975141278551263,-40.7596491137071553,-38.6688551152037832],"rgb":[0.0666666666666666657,0.6,0.733333333333333282],"xyz":[0.2059058098822934,0.264881346832524456,0.510428259201302192],"hpluv":[223.492153209811363,121.8747424026255,58.4975141278551263],"hsluv":[223.492153209811363,98.1135798876595686,58.4975141278551263]},"#1199cc":{"lch":[59.2140605434028515,66.4726101728698211,233.498474693243395],"luv":[59.2140605434028515,-39.5408457239066138,-53.4334111079625274],"rgb":[0.0666666666666666657,0.6,0.8],"xyz":[0.225198185326015127,0.272598297010013257,0.612034769871572348],"hpluv":[233.498474693243395,142.448281943894045,59.2140605434028515],"hsluv":[233.498474693243395,98.2484961488154482,59.2140605434028515]},"#1199dd":{"lch":[59.9975033067865553,78.1149919905427907,240.560044488236258],"luv":[59.9975033067865553,-38.3943918665613637,-68.0281018909060151],"rgb":[0.0666666666666666657,0.6,0.866666666666666696],"xyz":[0.24671651087664867,0.281205627230266819,0.725364617771578346],"hpluv":[240.560044488236258,165.211601361935521,59.9975033067865553],"hsluv":[240.560044488236258,98.3778942246892285,59.9975033067865553]},"#1199ee":{"lch":[60.8460449735814706,90.4022578402124,245.60857134482],"luv":[60.8460449735814706,-37.3332566635070862,-82.3334450239084106],"rgb":[0.0666666666666666657,0.6,0.933333333333333348],"xyz":[0.270528691142823408,0.290730499336736836,0.850775433840101569],"hpluv":[245.60857134482,188.532510112076068,60.8460449735814706],"hsluv":[245.60857134482,98.5004851129029788,60.8460449735814706]},"#1199ff":{"lch":[61.7575303771721877,102.910627792409826,249.306643617498082],"luv":[61.7575303771721877,-36.3651553748586,-96.2713497733895167],"rgb":[0.0666666666666666657,0.6,1],"xyz":[0.296699739552654829,0.301198918700669505,0.988609622131883414],"hpluv":[249.306643617498082,211.450946466820028,61.7575303771721877],"hsluv":[249.306643617498082,99.9999999999986215,61.7575303771721877]},"#000000":{"lch":[0,0,0],"luv":[0,0,0],"rgb":[0,0,0],"xyz":[0,0,0],"hpluv":[0,0,0],"hsluv":[0,0,0]},"#000011":{"lch":[0.365533479526218952,1.47895322486610792,265.8743202181779],"luv":[0.365533479526218952,-0.106402530834795422,-1.47512072142377915],"rgb":[0,0,0.0666666666666666657],"xyz":[0.00101166549963712174,0.000404666199854854377,0.00532810496475563146],"hpluv":[265.8743202181779,513.41269684428039,0.365533479526218952],"hsluv":[265.8743202181779,100.000000000000867,0.365533479526218952]},"#000022":{"lch":[1.04313510374015572,4.22053823263236,265.8743202181779],"luv":[1.04313510374015572,-0.303644457367982512,-4.20960128950726],"rgb":[0,0,0.133333333333333331],"xyz":[0.0028870236381141408,0.00115480945524567245,0.0152049911607348275],"hpluv":[265.8743202181779,513.41269684428039,1.04313510374015572],"hsluv":[265.8743202181779,100.000000000000838,1.04313510374015572]},"#000033":{"lch":[2.15879662382733661,8.73451929157831,265.8743202181779],"luv":[2.15879662382733661,-0.62840050829424543,-8.71188498868810868],"rgb":[0,0,0.2],"xyz":[0.00597477437057188088,0.00238990974822878574,0.0314671450183459725],"hpluv":[265.8743202181779,513.412696844280276,2.15879662382733661],"hsluv":[265.8743202181779,100.000000000000838,2.15879662382733661]},"#000044":{"lch":[3.76955286085941,15.251660031516769,265.874320218177957],"luv":[3.76955286085941,-1.0972728545435857,-15.2121374566379668],"rgb":[0,0,0.266666666666666663],"xyz":[0.0104327696147907597,0.00417310784591636182,0.054945919971232611],"hpluv":[265.874320218177957,513.41269684428039,3.76955286085941],"hsluv":[265.874320218177957,100.000000000000981,3.76955286085941]},"#000055":{"lch":[5.92388346812606947,23.9681097618519345,265.8743202181779],"luv":[5.92388346812606947,-1.7243733575266309,-23.905999708860417],"rgb":[0,0,0.333333333333333315],"xyz":[0.0163951836541527535,0.00655807346166119385,0.0863479672452065194],"hpluv":[265.8743202181779,513.41269684428039,5.92388346812606947],"hsluv":[265.8743202181779,100.000000000000838,5.92388346812606947]},"#000066":{"lch":[8.64689012997685,34.9854302247980513,265.8743202181779],"luv":[8.64689012997685,-2.51700882467034193,-34.8947703043127149],"rgb":[0,0,0.4],"xyz":[0.0239801794276609283,0.00959207177106450627,0.126295611652350481],"hpluv":[265.8743202181779,513.412696844280276,8.64689012997685],"hsluv":[265.8743202181779,100.000000000000838,8.64689012997685]},"#000077":{"lch":[11.4958709948623863,46.5124439559768703,265.874320218177957],"luv":[11.4958709948623863,-3.34631391244679577,-46.3919133681426672],"rgb":[0,0,0.466666666666666674],"xyz":[0.0332941924478628443,0.0133176769791453226,0.17534941355874839],"hpluv":[265.874320218177957,513.412696844280276,11.4958709948623863],"hsluv":[265.874320218177957,100.000000000001,11.4958709948623863]},"#000088":{"lch":[14.2727431262745554,57.7477048111956535,265.874320218177957],"luv":[14.2727431262745554,-4.15462898927595781,-57.598059593379169],"rgb":[0,0,0.533333333333333326],"xyz":[0.0444346095498066723,0.0177738438199229153,0.234022276962320558],"hpluv":[265.874320218177957,513.41269684428039,14.2727431262745554],"hsluv":[265.874320218177957,100.000000000000952,14.2727431262745554]},"#000099":{"lch":[16.9872454361813823,68.7306165552763701,265.874320218177957],"luv":[16.9872454361813823,-4.94478893879780923,-68.5525106354185567],"rgb":[0,0,0.6],"xyz":[0.0574915736588793858,0.0229966294635520763,0.302788954603438465],"hpluv":[265.874320218177957,513.412696844280163,16.9872454361813823],"hsluv":[265.874320218177957,100.000000000000952,16.9872454361813823]},"#0000aa":{"lch":[19.6469460262523299,79.4917998262647529,265.8743202181779],"luv":[19.6469460262523299,-5.71899674710351302,-79.2858077831434116],"rgb":[0,0,0.66666666666666663],"xyz":[0.0725492666241319278,0.0290197066496531778,0.382092804220437066],"hpluv":[265.8743202181779,513.41269684428039,19.6469460262523299],"hsluv":[265.8743202181779,100.000000000000824,19.6469460262523299]},"#0000bb":{"lch":[22.2578820656552736,90.0556810893410926,265.8743202181779],"luv":[22.2578820656552736,-6.47900976369593895,-89.8223142039161644],"rgb":[0,0,0.733333333333333282],"xyz":[0.0896868587314685745,0.0358747434925879363,0.472350789319078812],"hpluv":[265.8743202181779,513.41269684428039,22.2578820656552736],"hsluv":[265.8743202181779,100.000000000000796,22.2578820656552736]},"#0000cc":{"lch":[24.8249727536546274,100.442163488877583,265.874320218177957],"luv":[24.8249727536546274,-7.22625991008361535,-100.18188146585355],"rgb":[0,0,0.8],"xyz":[0.108979234175190315,0.043591693670076738,0.573957299989349],"hpluv":[265.874320218177957,513.41269684428039,24.8249727536546274],"hsluv":[265.874320218177957,100.000000000001,24.8249727536546274]},"#0000dd":{"lch":[27.3522973211786535,110.667751646404724,265.8743202181779],"luv":[27.3522973211786535,-7.96193460279319343,-110.380971421034161],"rgb":[0,0,0.866666666666666696],"xyz":[0.130497559725823858,0.052199023890330272,0.687287147889355],"hpluv":[265.8743202181779,513.412696844280276,27.3522973211786535],"hsluv":[265.8743202181779,100.000000000000824,27.3522973211786535]},"#0000ee":{"lch":[29.8432887766479737,120.746335558760222,265.8743202181779],"luv":[29.8432887766479737,-8.68703315051946,-120.433438072283309],"rgb":[0,0,0.933333333333333348],"xyz":[0.154309739991998596,0.0617238959968003,0.812697963957878189],"hpluv":[265.8743202181779,513.41269684428039,29.8432887766479737],"hsluv":[265.8743202181779,100.000000000000838,29.8432887766479737]},"#0000ff":{"lch":[32.3008729039800215,130.68975298582734,265.8743202181779],"luv":[32.3008729039800215,-9.40240721482262,-130.351088503561101],"rgb":[0,0,1],"xyz":[0.18048078840183,0.072192315360733,0.95053215224966],"hpluv":[265.8743202181779,513.41269684428039,32.3008729039800215],"hsluv":[265.8743202181779,100.000000000000824,32.3008729039800215]},"#001100":{"lch":[3.62113466359794112,5.60448249758782424,127.715012949240474],"luv":[3.62113466359794112,-3.42845440085753106,4.43350025228474376],"rgb":[0,0.0666666666666666657,0],"xyz":[0.00200440026092840902,0.00400880052185687355,0.00066813342030945088],"hpluv":[127.715012949240474,196.394882900214469,3.62113466359794112],"hsluv":[127.715012949240474,100.000000000002217,3.62113466359794112]},"#001111":{"lch":[3.9866681431241604,3.15408977882195618,192.17705063006116],"luv":[3.9866681431241604,-3.08312421078118115,-0.665302512969894178],"rgb":[0,0.0666666666666666657,0.0666666666666666657],"xyz":[0.00301606576056553076,0.00441346672171172814,0.00599623838506508234],"hpluv":[192.17705063006116,100.392967527320764,3.9866681431241604],"hsluv":[192.17705063006116,99.9999999999914,3.9866681431241604]},"#001122":{"lch":[4.66426976733809706,7.30142401028103372,246.87889630792742],"luv":[4.66426976733809706,-2.86709314837997242,-6.71495118794031054],"rgb":[0,0.0666666666666666657,0.133333333333333331],"xyz":[0.00489142389904254939,0.005163609977102546,0.0158731245810442775],"hpluv":[246.87889630792742,198.638412351210178,4.66426976733809706],"hsluv":[246.87889630792742,99.9999999999921414,4.66426976733809706]},"#001133":{"lch":[5.77993128742527773,13.8979406242137369,257.974087263939282],"luv":[5.77993128742527773,-2.89569220292521434,-13.5929290537429299],"rgb":[0,0.0666666666666666657,0.2],"xyz":[0.00797917463150029,0.00639871027008565886,0.0321352784386554208],"hpluv":[257.974087263939282,305.117489912579458,5.77993128742527773],"hsluv":[257.974087263939282,99.9999999999925,5.77993128742527773]},"#001144":{"lch":[7.39068752445735111,21.802452480470059,261.611708702028636],"luv":[7.39068752445735111,-3.1805605696034065,-21.569213444774455],"rgb":[0,0.0666666666666666657,0.266666666666666663],"xyz":[0.0124371698757191687,0.00818190836777323537,0.0556140533915420593],"hpluv":[261.611708702028636,374.334482048802613,7.39068752445735111],"hsluv":[261.611708702028636,99.9999999999929656,7.39068752445735111]},"#001155":{"lch":[9.4550232844459714,31.0886305445366773,263.238579866128873],"luv":[9.4550232844459714,-3.6602302532303379,-30.8724094237562916],"rgb":[0,0.0666666666666666657,0.333333333333333315],"xyz":[0.0183995839150811608,0.0105668739835180665,0.0870161006655159747],"hpluv":[263.238579866128873,417.232678203522596,9.4550232844459714],"hsluv":[263.238579866128873,99.9999999999929514,9.4550232844459714]},"#001166":{"lch":[11.6894020192987682,40.9340765206813302,264.100423242359113],"luv":[11.6894020192987682,-4.20741678933990659,-40.7172723123955791],"rgb":[0,0.0666666666666666657,0.4],"xyz":[0.025984579688589339,0.0136008722929213798,0.126963745072659923],"hpluv":[264.100423242359113,444.357002567308371,11.6894020192987682],"hsluv":[264.100423242359113,99.9999999999928235,11.6894020192987682]},"#001177":{"lch":[14.0165943101603965,51.0460922578313898,264.608714664977526],"luv":[14.0165943101603965,-4.79613195559092276,-50.8202779710972621],"rgb":[0,0.0666666666666666657,0.466666666666666674],"xyz":[0.0352985927087912515,0.0173264775010021979,0.176017546979057832],"hpluv":[264.608714664977526,462.124851551559573,14.0165943101603965],"hsluv":[264.608714664977526,99.9999999999931504,14.0165943101603965]},"#001188":{"lch":[16.3962585295353378,61.2721603523949625,264.931782730652174],"luv":[16.3962585295353378,-5.41289085195630371,-61.0325998698597871],"rgb":[0,0.0666666666666666657,0.533333333333333326],"xyz":[0.0464390098107350796,0.0217826443417797888,0.23469041038263],"hpluv":[264.931782730652174,474.195864485329537,16.3962585295353378],"hsluv":[264.931782730652174,99.9999999999933209,16.3962585295353378]},"#001199":{"lch":[18.8023327262484941,71.5200065602600148,265.148843888859801],"luv":[18.8023327262484941,-6.04826966448705239,-71.2638040834565771],"rgb":[0,0.0666666666666666657,0.6],"xyz":[0.059495973919807793,0.0270054299854089498,0.303457088023747934],"hpluv":[265.148843888859801,482.675370310212884,18.8023327262484941],"hsluv":[265.148843888859801,99.9999999999930651,18.8023327262484941]},"#0011aa":{"lch":[21.2181090603332123,81.7349311996174919,265.301088447161305],"luv":[21.2181090603332123,-6.69569086805443892,-81.4602154551880488],"rgb":[0,0.0666666666666666657,0.66666666666666663],"xyz":[0.0745536668850603351,0.0330285071715100548,0.382760937640746535],"hpluv":[265.301088447161305,488.81030222212587,21.2181090603332123],"hsluv":[265.301088447161305,99.9999999999931788,21.2181090603332123]},"#0011bb":{"lch":[23.6329047323064216,91.8852368853417,265.411605614461337],"luv":[23.6329047323064216,-7.35054503717070418,-91.590754146539723],"rgb":[0,0.0666666666666666657,0.733333333333333282],"xyz":[0.0916912589923969817,0.0398835440144448133,0.473018922739388281],"hpluv":[265.411605614461337,493.364573724961247,23.6329047323064216],"hsluv":[265.411605614461337,99.999999999993,23.6329047323064216]},"#0011cc":{"lch":[26.0399131129061345,101.953231398784169,265.494123438592396],"luv":[26.0399131129061345,-8.00958293333115,-101.638122640513785],"rgb":[0,0.0666666666666666657,0.8],"xyz":[0.110983634436118722,0.047600494191933615,0.574625433409658437],"hpluv":[265.494123438592396,496.821968194535657,26.0399131129061345],"hsluv":[265.494123438592396,99.9999999999927383,26.0399131129061345]},"#0011dd":{"lch":[28.43483595206839,111.929749681002491,265.557201901085818],"luv":[28.43483595206839,-8.67050070949402496,-111.593419524175076],"rgb":[0,0.0666666666666666657,0.866666666666666696],"xyz":[0.132501959986752266,0.056207824412187149,0.687955281309664435],"hpluv":[265.557201901085818,499.498435149301031,28.43483595206839],"hsluv":[265.557201901085818,99.9999999999932214,28.43483595206839]},"#0011ee":{"lch":[30.8150119654139019,121.810820553676152,265.60639254385444],"luv":[30.8150119654139019,-9.33165721729429798,-121.452855781734542],"rgb":[0,0.0666666666666666657,0.933333333333333348],"xyz":[0.156314140252927,0.0657326965186571799,0.813366097378187658],"hpluv":[265.60639254385444,501.606152289563909,30.8150119654139019],"hsluv":[265.60639254385444,99.9999999999933635,30.8150119654139019]},"#0011ff":{"lch":[33.1788572452669683,131.59562707663585,265.645416939351662],"luv":[33.1788572452669683,-9.99188030865750321,-131.215743695604147],"rgb":[0,0.0666666666666666657,1],"xyz":[0.182485188662758396,0.076201115882589876,0.951200285669969503],"hpluv":[265.645416939351662,503.291227463659,33.1788572452669683],"hsluv":[265.645416939351662,99.9999999999995,33.1788572452669683]},"#55aa00":{"lch":[62.2364297391950743,84.7105424007581291,119.071642820441127],"luv":[62.2364297391950743,-41.1610955154551661,74.0380997176333437],"rgb":[0.333333333333333315,0.66666666666666663,0],"xyz":[0.181203244729902568,0.306798408854291604,0.0496696976001293408],"hpluv":[119.071642820441127,172.715819722381468,62.2364297391950743],"hsluv":[119.071642820441127,100.00000000000216,62.2364297391950743]},"#55aa11":{"lch":[62.270812500354296,83.3839078255156352,119.512873370738717],"luv":[62.270812500354296,-41.0765057562956173,72.5644317769187808],"rgb":[0.333333333333333315,0.66666666666666663,0.0666666666666666657],"xyz":[0.182214910229539701,0.307203075054146457,0.0549978025648849705],"hpluv":[119.512873370738717,169.917081036602212,62.270812500354296],"hsluv":[119.512873370738717,97.826098763204655,62.270812500354296]},"#55aa22":{"lch":[62.3344691942433826,80.9675552156414,120.358690899927907],"luv":[62.3344691942433826,-40.9219560187625078,69.8651451955580285],"rgb":[0.333333333333333315,0.66666666666666663,0.133333333333333331],"xyz":[0.184090268368016702,0.307953218309537258,0.0648746887608641631],"hpluv":[120.358690899927907,164.824621464176317,62.3344691942433826],"hsluv":[120.358690899927907,93.8493385636837729,62.3344691942433826]},"#55aa33":{"lch":[62.4390542004851312,77.1100321042589343,121.835090998601942],"luv":[62.4390542004851312,-40.6737079775314143,65.5103543760705094],"rgb":[0.333333333333333315,0.66666666666666663,0.2],"xyz":[0.187178019100474435,0.309188318602520384,0.0811368426184753133],"hpluv":[121.835090998601942,156.708983850290963,62.4390542004851312],"hsluv":[121.835090998601942,87.4478443822902,62.4390542004851312]},"#55aa44":{"lch":[62.5895604608427192,71.8060360850404322,124.168545167949461],"luv":[62.5895604608427192,-40.3283690350335959,59.4115264003566281],"rgb":[0.333333333333333315,0.66666666666666663,0.266666666666666663],"xyz":[0.191636014344693323,0.310971516700207951,0.104615617571361952],"hpluv":[124.168545167949461,145.578881327618376,62.5895604608427192],"hsluv":[124.168545167949461,78.5131262768233569,62.5895604608427192]},"#55aa55":{"lch":[62.7899606618147317,65.2067785819955361,127.715012949239551],"luv":[62.7899606618147317,-39.8892256495404212,51.582687503865472],"rgb":[0.333333333333333315,0.66666666666666663,0.333333333333333315],"xyz":[0.197598428384055336,0.313356482315952811,0.136017664845335867],"hpluv":[127.715012949239551,131.777681042751937,62.7899606618147317],"hsluv":[127.715012949239551,67.0983271543339583,62.7899606618147317]},"#55aa66":{"lch":[63.0434325957243402,57.6560159218084,133.059858461454269],"luv":[63.0434325957243402,-39.3653397911167744,42.1258376190401904],"rgb":[0.333333333333333315,0.66666666666666663,0.4],"xyz":[0.205183424157563493,0.31639048062535613,0.175965309252479829],"hpluv":[133.059858461454269,116.049721847977636,63.0434325957243402],"hsluv":[133.059858461454269,68.1368400599560289,63.0434325957243402]},"#55aa77":{"lch":[63.3524771250310863,49.7736139598232441,141.163090238883626],"luv":[63.3524771250310863,-38.7703675351212311,31.2133184364163512],"rgb":[0.333333333333333315,0.66666666666666663,0.466666666666666674],"xyz":[0.214497437177765427,0.320116085833436925,0.225019111158877738],"hpluv":[141.163090238883626,99.6953496544650903,63.3524771250310863],"hsluv":[141.163090238883626,69.3257510819996696,63.3524771250310863]},"#55aa88":{"lch":[63.7189896387035901,42.62351374085884,153.427389325734708],"luv":[63.7189896387035901,-38.1211143540371324,19.0668446268281784],"rgb":[0.333333333333333315,0.66666666666666663,0.533333333333333326],"xyz":[0.225637854279709227,0.324572252674214523,0.283691974562449878],"hpluv":[153.427389325734708,84.882799477410984,63.7189896387035901],"hsluv":[153.427389325734708,70.6362499177174783,63.7189896387035901]},"#55aa99":{"lch":[64.1443101574831473,37.9035590936142697,170.991128647613664],"luv":[64.1443101574831473,-37.4359848569684885,5.93521943587048106],"rgb":[0.333333333333333315,0.66666666666666663,0.6],"xyz":[0.238694818388781954,0.329795038317843681,0.352458652203567813],"hpluv":[170.991128647613664,74.9827180661079211,64.1443101574831473],"hsluv":[170.991128647613664,72.0364673991159918,64.1443101574831473]},"#55aaaa":{"lch":[64.6292640862610881,37.5790288142004414,192.177050630061],"luv":[64.6292640862610881,-36.7335179653569526,-7.92666793219602717],"rgb":[0.333333333333333315,0.66666666666666663,0.66666666666666663],"xyz":[0.253752511354034482,0.335818115503944803,0.431762501820566413],"hpluv":[192.177050630061,73.7828909738526,64.6292640862610881],"hsluv":[192.177050630061,73.4940830927894808,64.6292640862610881]},"#55aabb":{"lch":[65.1741997434662466,42.3607987370151307,211.725401595501864],"luv":[65.1741997434662466,-36.0311661131296148,-22.2753751520813346],"rgb":[0.333333333333333315,0.66666666666666663,0.733333333333333282],"xyz":[0.270890103461371157,0.342673152346879561,0.522020486919208104],"hpluv":[211.725401595501864,82.4760322189960249,65.1741997434662466],"hsluv":[211.725401595501864,74.9784994025983,65.1741997434662466]},"#55aacc":{"lch":[65.7790257871148327,51.0903516363502916,226.227071697937646],"luv":[65.7790257871148327,-35.3444111183519212,-36.8916878581455236],"rgb":[0.333333333333333315,0.66666666666666663,0.8],"xyz":[0.290182478905092855,0.350390102524368363,0.62362699758947826],"hpluv":[226.227071697937646,98.5577501957325808,65.7790257871148327],"hsluv":[226.227071697937646,76.4624197891718,65.7790257871148327]},"#55aadd":{"lch":[66.4432499478878071,62.1650528283955595,236.084470311275709],"luv":[66.4432499478878071,-34.6862381636523693,-51.5883579425784404],"rgb":[0.333333333333333315,0.66666666666666663,0.866666666666666696],"xyz":[0.311700804455726455,0.358997432744621869,0.736956845489484258],"hpluv":[236.084470311275709,118.722973851074883,66.4432499478878071],"hsluv":[236.084470311275709,77.9227939155192928,66.4432499478878071]},"#55aaee":{"lch":[67.1660194476775274,74.4631251020179832,242.774049894046698],"luv":[67.1660194476775274,-34.0669326024190866,-66.2133000462974763],"rgb":[0.333333333333333315,0.66666666666666663,0.933333333333333348],"xyz":[0.335512984721901164,0.368522304851091886,0.862367661558007481],"hpluv":[242.774049894046698,140.679551339708695,67.1660194476775274],"hsluv":[242.774049894046698,80.7550915423080085,67.1660194476775274]},"#55aaff":{"lch":[67.9461628502375135,87.3278464079016,247.446578213330071],"luv":[67.9461628502375135,-33.4941307575646476,-80.6492155140842897],"rgb":[0.333333333333333315,0.66666666666666663,1],"xyz":[0.361684033131732585,0.37899072421502461,1.00020184984978933],"hpluv":[247.446578213330071,163.089927997179217,67.9461628502375135],"hsluv":[247.446578213330071,99.9999999999981,67.9461628502375135]},"#002200":{"lch":[10.1376941245203973,15.6902558355344119,127.715012949240474],"luv":[10.1376941245203973,-9.59826829561359141,12.4119850914324186],"rgb":[0,0.133333333333333331,0],"xyz":[0.00572002399569634425,0.0114400479913928481,0.00190667466523206119],"hpluv":[127.715012949240474,196.394882900214583,10.1376941245203973],"hsluv":[127.715012949240474,100.000000000002331,10.1376941245203973]},"#002211":{"lch":[10.4423176349325608,11.2803579121031614,143.951720967420982],"luv":[10.4423176349325608,-9.12041102953238614,6.63811549142769763],"rgb":[0,0.133333333333333331,0.0666666666666666657],"xyz":[0.00673168949533346599,0.0118447141912477027,0.00723477962998769243],"hpluv":[143.951720967420982,137.077225818420459,10.4423176349325608],"hsluv":[143.951720967420982,99.9999999999911,10.4423176349325608]},"#002222":{"lch":[10.9891417742670896,8.69416226881610399,192.17705063006116],"luv":[10.9891417742670896,-8.49854762011842,-1.83388819318003415],"rgb":[0,0.133333333333333331,0.133333333333333331],"xyz":[0.00860704763381048461,0.0125948574466385205,0.0171116658259668902],"hpluv":[192.17705063006116,100.392967527320849,10.9891417742670896],"hsluv":[192.17705063006116,99.9999999999915,10.9891417742670896]},"#002233":{"lch":[11.8439988341371283,14.4341695325786503,236.81663495428262],"luv":[11.8439988341371283,-7.90011340243738758,-12.0802921456333543],"rgb":[0,0.133333333333333331,0.2],"xyz":[0.0116947983662682251,0.0138299577396216334,0.0333738196835780335],"hpluv":[236.81663495428262,154.643892414528665,11.8439988341371283],"hsluv":[236.81663495428262,99.9999999999918572,11.8439988341371283]},"#002244":{"lch":[12.9926705590666103,23.9154033254141893,251.756603241059679],"luv":[12.9926705590666103,-7.48682111947174356,-22.713300635140282],"rgb":[0,0.133333333333333331,0.266666666666666663],"xyz":[0.0161527936104871039,0.0156131558373092099,0.056852594636464672],"hpluv":[251.756603241059679,233.570832873869165,12.9926705590666103],"hsluv":[251.756603241059679,99.9999999999922551,12.9926705590666103]},"#002255":{"lch":[14.3995425627967926,34.0053227001087492,257.612107564284656],"luv":[14.3995425627967926,-7.29512566501762105,-33.2135983216232162],"rgb":[0,0.133333333333333331,0.333333333333333315],"xyz":[0.022115207649849096,0.0179981214530540411,0.0882546419104385804],"hpluv":[257.612107564284656,299.666041626864057,14.3995425627967926],"hsluv":[257.612107564284656,99.9999999999922551,14.3995425627967926]},"#002266":{"lch":[16.0198287291043684,44.1221041927951489,260.479541157990241],"luv":[16.0198287291043684,-7.29778599254304705,-43.514392998258792],"rgb":[0,0.133333333333333331,0.4],"xyz":[0.0297002034233572743,0.0210321197624573561,0.128202286317582542],"hpluv":[260.479541157990241,349.492349810916096,16.0198287291043684],"hsluv":[260.479541157990241,99.9999999999926672,16.0198287291043684]},"#002277":{"lch":[17.8086814865908138,54.1839210795750787,262.094384047744654],"luv":[17.8086814865908138,-7.45254493353373,-53.6689563674502708],"rgb":[0,0.133333333333333331,0.466666666666666674],"xyz":[0.0390142164435591868,0.0247577249705381724,0.177256088223980451],"hpluv":[262.094384047744654,386.080609388904179,17.8086814865908138],"hsluv":[262.094384047744654,99.9999999999926246,17.8086814865908138]},"#002288":{"lch":[19.7262797638069571,64.1945165648047862,263.091662768615947],"luv":[19.7262797638069571,-7.7213996360385595,-63.7284547486409778],"rgb":[0,0.133333333333333331,0.533333333333333326],"xyz":[0.0501546335455030148,0.0292138918113157633,0.235928951627552619],"hpluv":[263.091662768615947,412.944865974292611,19.7262797638069571],"hsluv":[263.091662768615947,99.9999999999928093,19.7262797638069571]},"#002299":{"lch":[21.7396965211461932,74.1610579713059082,263.749129578079874],"luv":[21.7396965211461932,-8.0748025544340809,-73.7201470639492129],"rgb":[0,0.133333333333333331,0.6],"xyz":[0.0632115976545757352,0.0344366774549449278,0.304695629268670554],"hpluv":[263.749129578079874,432.874263951475,21.7396965211461932],"hsluv":[263.749129578079874,99.9999999999928662,21.7396965211461932]},"#0022aa":{"lch":[23.8228560713303921,84.0831956926279389,264.204285416148139],"luv":[23.8228560713303921,-8.49087961251211532,-83.6533846373868641],"rgb":[0,0.133333333333333331,0.66666666666666663],"xyz":[0.0782692906198282773,0.0404597546410460224,0.383999478885669154],"hpluv":[264.204285416148139,447.872821658188343,23.8228560713303921],"hsluv":[264.204285416148139,99.9999999999925251,23.8228560713303921]},"#0022bb":{"lch":[25.9556350824861326,93.9557715434331868,264.531619021467236],"luv":[25.9556350824861326,-8.95364890679069,-93.5281731756572725],"rgb":[0,0.133333333333333331,0.733333333333333282],"xyz":[0.0954068827271649239,0.0473147914839807809,0.474257463984310901],"hpluv":[264.531619021467236,459.336683180505304,25.9556350824861326],"hsluv":[264.531619021467236,99.9999999999932783,25.9556350824861326]},"#0022cc":{"lch":[28.122733334265547,103.772183036952711,264.774345627526145],"luv":[28.122733334265547,-9.45141286238599143,-103.340876555018355],"rgb":[0,0.133333333333333331,0.8],"xyz":[0.114699258170886664,0.0550317416614695826,0.575863974654581057],"hpluv":[264.774345627526145,468.233789407088068,28.122733334265547],"hsluv":[264.774345627526145,99.9999999999932,28.122733334265547]},"#0022dd":{"lch":[30.3126112219004114,113.526334495176528,264.958927468127968],"luv":[30.3126112219004114,-9.97554123069502552,-113.087210599012522],"rgb":[0,0.133333333333333331,0.866666666666666696],"xyz":[0.136217583721520208,0.0636390718817231166,0.689193822554587],"hpluv":[264.958927468127968,475.239568383116307,30.3126112219004114],"hsluv":[264.958927468127968,99.9999999999930651,30.3126112219004114]},"#0022ee":{"lch":[32.516600051948771,123.213441320075319,265.102292473050682],"luv":[32.516600051948771,-10.519601137712538,-122.76355368691101],"rgb":[0,0.133333333333333331,0.933333333333333348],"xyz":[0.160029763987694945,0.0731639439881931475,0.814604638623110278],"hpluv":[265.102292473050682,480.830806343612153,32.516600051948771],"hsluv":[265.102292473050682,99.9999999999931504,32.516600051948771]},"#0022ff":{"lch":[34.728199222084136,132.830192238289243,265.215668718406278],"luv":[34.728199222084136,-11.0787458291525667,-132.367372720447662],"rgb":[0,0.133333333333333331,1],"xyz":[0.186200812397526339,0.0836323633521258575,0.952438826914892123],"hpluv":[265.215668718406278,485.348691920142073,34.728199222084136],"hsluv":[265.215668718406278,99.9999999999995595,34.728199222084136]},"#55bb00":{"lch":[67.6287132051522093,94.1564927152114421,120.799924159261636],"luv":[67.6287132051522093,-48.2120532219748839,80.8767150949587403],"rgb":[0.333333333333333315,0.733333333333333282,0],"xyz":[0.215157742638501348,0.374707404671490163,0.0609878635696619598],"hpluv":[120.799924159261636,176.668237076728246,67.6287132051522093],"hsluv":[120.799924159261636,100.000000000002245,67.6287132051522093]},"#55bb11":{"lch":[67.658807387059241,92.983820197622,121.168613223743336],"luv":[67.658807387059241,-48.1245535730997,79.5614112615755],"rgb":[0.333333333333333315,0.733333333333333282,0.0666666666666666657],"xyz":[0.21616940813813848,0.375112070871345,0.0663159685344176],"hpluv":[121.168613223743336,174.390319462510746,67.658807387059241],"hsluv":[121.168613223743336,98.2170484527892853,67.658807387059241]},"#55bb22":{"lch":[67.7145367797011,90.8418307914021739,121.8702408444057],"luv":[67.7145367797011,-47.9642424389893733,77.1470651987980318],"rgb":[0.333333333333333315,0.733333333333333282,0.133333333333333331],"xyz":[0.218044766276615481,0.375862214126735816,0.076192854730396789],"hpluv":[121.8702408444057,170.232819736279453,67.7145367797011],"hsluv":[121.8702408444057,94.9476871157098401,67.7145367797011]},"#55bb33":{"lch":[67.8061331119394595,87.4049119918652337,123.079288563119889],"luv":[67.8061331119394595,-47.7055226907732077,73.2379802090816128],"rgb":[0.333333333333333315,0.733333333333333282,0.2],"xyz":[0.221132517009073215,0.377097314419718943,0.0924550085880079253],"hpluv":[123.079288563119889,163.570954697809668,67.8061331119394595],"hsluv":[123.079288563119889,89.6636954368763526,67.8061331119394595]},"#55bb44":{"lch":[67.9380247917114701,82.6396215824211851,124.951716096499126],"luv":[67.9380247917114701,-47.3430758547011195,67.7343356349037293],"rgb":[0.333333333333333315,0.733333333333333282,0.266666666666666663],"xyz":[0.225590512253292103,0.378880512517406509,0.115933783540894564],"hpluv":[124.951716096499126,154.352877500253584,67.9380247917114701],"hsluv":[124.951716096499126,82.2446152582935213,67.9380247917114701]},"#55bb55":{"lch":[68.1137800414251,76.6309713561306154,127.715012949239735],"luv":[68.1137800414251,-46.8777966745344372,60.6199467990950964],"rgb":[0.333333333333333315,0.733333333333333282,0.333333333333333315],"xyz":[0.231552926292654115,0.38126547813315137,0.147335830814868479],"hpluv":[127.715012949239735,142.760701907139094,68.1137800414251],"hsluv":[127.715012949239735,72.6906423420812189,68.1137800414251]},"#55bb66":{"lch":[68.3363083667640723,69.6002362161904813,131.717534816394789],"luv":[68.3363083667640723,-46.3160914021311,51.9520216986687728],"rgb":[0.333333333333333315,0.733333333333333282,0.4],"xyz":[0.239137922066162273,0.384299476442554688,0.187283475222012441],"hpluv":[131.717534816394789,129.240469264566769,68.3363083667640723],"hsluv":[131.717534816394789,73.4099839145656432,68.3363083667640723]},"#55bb77":{"lch":[68.6079661831172416,61.943926665161591,137.498849513297245],"luv":[68.6079661831172416,-45.6690129611091,41.8496273084595956],"rgb":[0.333333333333333315,0.733333333333333282,0.466666666666666674],"xyz":[0.248451935086364206,0.388025081650635484,0.23633727712841035],"hpluv":[137.498849513297245,114.568047908441656,68.6079661831172416],"hsluv":[137.498849513297245,74.2430874467708719,68.6079661831172416]},"#55bb88":{"lch":[68.930619778887035,54.3103726013937376,145.860320527647957],"luv":[68.930619778887035,-44.9511677919681389,30.4796503628330058],"rgb":[0.333333333333333315,0.733333333333333282,0.533333333333333326],"xyz":[0.259592352188308,0.392481248491413082,0.29501014053198249],"hpluv":[145.860320527647957,99.9792617157038421,68.930619778887035],"hsluv":[145.860320527647957,75.173468866550067,68.930619778887035]},"#55bb99":{"lch":[69.3056876145919176,47.7211055743842465,157.786981113384826],"luv":[69.3056876145919176,-44.1794697421466793,18.0410191104680564],"rgb":[0.333333333333333315,0.733333333333333282,0.6],"xyz":[0.272649316297380762,0.397704034135042239,0.363776818173100425],"hpluv":[157.786981113384826,87.3737441175344713,69.3056876145919176],"hsluv":[157.786981113384826,76.1818306173187807,69.3056876145919176]},"#55bbaa":{"lch":[69.7341725511637378,43.6310575063277497,173.751690425302456],"luv":[69.7341725511637378,-43.37186937951342,4.74869725787034813],"rgb":[0.333333333333333315,0.733333333333333282,0.66666666666666663],"xyz":[0.287707009262633262,0.403727111321143362,0.443080667790099],"hpluv":[173.751690425302456,79.3943164161001675,69.7341725511637378],"hsluv":[173.751690425302456,77.247554342351421,69.7341725511637378]},"#55bbbb":{"lch":[70.2166895771587605,43.5254926875218899,192.177050630061075],"luv":[70.2166895771587605,-42.5461891389785691,-9.18097508120914796],"rgb":[0.333333333333333315,0.733333333333333282,0.733333333333333282],"xyz":[0.304844601369969936,0.41058214816407812,0.533338652888740716],"hpluv":[192.177050630061075,78.6579587560082274,70.2166895771587605],"hsluv":[192.177050630061075,78.350068429440185,70.2166895771587605]},"#55bbcc":{"lch":[70.753492069254392,47.9033609117661214,209.436295084806801],"luv":[70.753492069254392,-41.719164640327179,-23.5423721905035848],"rgb":[0.333333333333333315,0.733333333333333282,0.8],"xyz":[0.324136976813691691,0.418299098341566922,0.634945163559010872],"hpluv":[209.436295084806801,85.9127126132272849,70.753492069254392],"hsluv":[209.436295084806801,79.4699741443966445,70.753492069254392]},"#55bbdd":{"lch":[71.3444981992470701,55.9344204047748121,223.003151043067675],"luv":[71.3444981992470701,-40.905747403701568,-38.1494327004039633],"rgb":[0.333333333333333315,0.733333333333333282,0.866666666666666696],"xyz":[0.345655302364325179,0.426906428561820428,0.74827501145901687],"hpluv":[223.003151043067675,99.4850863142100081,71.3444981992470701],"hsluv":[223.003151043067675,80.5898663629362,71.3444981992470701]},"#55bbee":{"lch":[71.9893182406489,66.3452770137575385,232.793079173014576],"luv":[71.9893182406489,-40.1186787976363846,-52.8411524624918272],"rgb":[0.333333333333333315,0.733333333333333282,0.933333333333333348],"xyz":[0.369467482630499944,0.436431300668290445,0.873685827527540093],"hpluv":[232.793079173014576,116.944897502912525,71.9893182406489],"hsluv":[232.793079173014576,81.6948376758296888,71.9893182406489]},"#55bbff":{"lch":[72.6872829834048417,78.1278426582451146,239.741904567598624],"luv":[72.6872829834048417,-39.3683093588317803,-67.4840426816504788],"rgb":[0.333333333333333315,0.733333333333333282,1],"xyz":[0.395638531040331309,0.446899720032223169,1.01152001581932205],"hpluv":[239.741904567598624,136.39131713467242,72.6872829834048417],"hsluv":[239.741904567598624,99.9999999999976126,72.6872829834048417]},"#003300":{"lch":[17.3086983277836381,26.7889227675687067,127.71501294924046],"luv":[17.3086983277836381,-16.3877039844862402,21.1917328494772867],"rgb":[0,0.2,0],"xyz":[0.0118377460847071559,0.0236754921694146449,0.00394591536156894181],"hpluv":[127.71501294924046,196.394882900214611,17.3086983277836381],"hsluv":[127.71501294924046,100.000000000002402,17.3086983277836381]},"#003311":{"lch":[17.4974002223845133,22.6621201022865968,134.58430385811792],"luv":[17.4974002223845133,-15.9078557679049606,16.1403783226414816],"rgb":[0,0.2,0.0666666666666666657],"xyz":[0.0128494115843442776,0.0240801583692694977,0.00927402032632457241],"hpluv":[134.58430385811792,164.348724425256108,17.4974002223845133],"hsluv":[134.58430385811792,99.9999999999909335,17.4974002223845133]},"#003322":{"lch":[17.8416856931397234,17.1190432019509622,152.323942273369369],"luv":[17.8416856931397234,-15.1604156821769873,7.95131665159082601],"rgb":[0,0.2,0.133333333333333331],"xyz":[0.0147247697228212963,0.0248303016246603156,0.0191509065223037685],"hpluv":[152.323942273369369,121.753913655152402,17.8416856931397234],"hsluv":[152.323942273369369,99.9999999999912177,17.8416856931397234]},"#003333":{"lch":[18.3937448040413543,14.5523831926532932,192.17705063006116],"luv":[18.3937448040413543,-14.2249612699966086,-3.06958196712752551],"rgb":[0,0.2,0.2],"xyz":[0.017812520455279035,0.0260654019176434319,0.0354130603799149152],"hpluv":[192.17705063006116,100.392967527320849,18.3937448040413543],"hsluv":[192.17705063006116,99.9999999999915,18.3937448040413543]},"#003344":{"lch":[19.1608294605123817,20.3566459399555,229.223567805483242],"luv":[19.1608294605123817,-13.2951121246929258,-15.41535038578591],"rgb":[0,0.2,0.266666666666666663],"xyz":[0.0222705156994979156,0.0278486000153310084,0.0588918353328015537],"hpluv":[229.223567805483242,134.812835768594709,19.1608294605123817],"hsluv":[229.223567805483242,99.9999999999917577,19.1608294605123817]},"#003355":{"lch":[20.1371955335767296,30.6237106081975696,245.893961784182551],"luv":[20.1371955335767296,-12.5075398018694361,-27.9530517031554915],"rgb":[0,0.2,0.333333333333333315],"xyz":[0.0282329297388599076,0.0302335656310758379,0.0902938826067754552],"hpluv":[245.893961784182551,192.973712242731381,20.1371955335767296],"hsluv":[245.893961784182551,99.9999999999920419,20.1371955335767296]},"#003366":{"lch":[21.3076868402923836,41.8514919359335167,253.451236278131262],"luv":[21.3076868402923836,-11.9206140697212764,-40.1179054471226308],"rgb":[0,0.2,0.4],"xyz":[0.0358179255123680859,0.0332675639404791529,0.130241527013919417],"hpluv":[253.451236278131262,249.237832456686277,21.3076868402923836],"hsluv":[253.451236278131262,99.9999999999920846,21.3076868402923836]},"#003377":{"lch":[22.6513946103128916,53.0186284648852251,257.430711853641924],"luv":[22.6513946103128916,-11.5379190314963687,-51.7479602372902434],"rgb":[0,0.2,0.466666666666666674],"xyz":[0.04513193853257,0.0369931691485599692,0.179295328920317326],"hpluv":[257.430711853641924,297.011229333042763,22.6513946103128916],"hsluv":[257.430711853641924,99.9999999999922409,22.6513946103128916]},"#003388":{"lch":[24.1449124481648099,63.8887963004775941,259.778872090702237],"luv":[24.1449124481648099,-11.3369168899634012,-62.8748964862287636],"rgb":[0,0.2,0.533333333333333326],"xyz":[0.0562723556345138265,0.0414493359893375601,0.237968192323889494],"hpluv":[259.778872090702237,335.767299249073346,24.1449124481648099],"hsluv":[259.778872090702237,99.9999999999925677,24.1449124481648099]},"#003399":{"lch":[25.764809398314533,74.4520642325545481,261.279947020055374],"luv":[25.764809398314533,-11.2874373109462987,-73.5914643653724596],"rgb":[0,0.2,0.6],"xyz":[0.0693293197435865399,0.0466721216329667177,0.306734869965007428],"hpluv":[261.279947020055374,366.681615332004242,25.764809398314533],"hsluv":[261.279947020055374,99.9999999999928662,25.764809398314533]},"#0033aa":{"lch":[27.4892253326185596,84.7561178753388447,262.297068677869788],"luv":[27.4892253326185596,-11.360446037840406,-83.9913077831251],"rgb":[0,0.2,0.66666666666666663],"xyz":[0.084387012708839082,0.0526951988190678261,0.386038719582006029],"hpluv":[262.297068677869788,391.244172205097584,27.4892253326185596],"hsluv":[262.297068677869788,99.9999999999925819,27.4892253326185596]},"#0033bb":{"lch":[29.2987082140811808,94.8530383242648725,263.01737082090068],"luv":[29.2987082140811808,-11.531133966499155,-94.1495184734957178],"rgb":[0,0.2,0.733333333333333282],"xyz":[0.101524604816175729,0.0595502356620025847,0.476296704680647776],"hpluv":[263.01737082090068,410.811034734971429,29.2987082140811808],"hsluv":[263.01737082090068,99.999999999992923,29.2987082140811808]},"#0033cc":{"lch":[31.1765026722858281,104.784892642773883,263.545454640352943],"luv":[31.1765026722858281,-11.7793879173059235,-104.120697973319764],"rgb":[0,0.2,0.8],"xyz":[0.120816980259897469,0.0672671858394913863,0.577903215350917931],"hpluv":[263.545454640352943,426.491720029659064,31.1765026722858281],"hsluv":[263.545454640352943,99.9999999999928519,31.1765026722858281]},"#0033dd":{"lch":[33.108496036114694,114.582250296133722,263.943596884481394],"luv":[33.108496036114694,-12.0892798728815123,-113.942711022166648],"rgb":[0,0.2,0.866666666666666696],"xyz":[0.142335305810531026,0.0758745160597449203,0.691233063250923929],"hpluv":[263.943596884481394,439.154381827523366,33.108496036114694],"hsluv":[263.943596884481394,99.999999999992724,33.108496036114694]},"#0033ee":{"lch":[35.0829820911796091,124.266344101148519,264.250786122927309],"luv":[35.0829820911796091,-12.4483077284590724,-123.641271066592637],"rgb":[0,0.2,0.933333333333333348],"xyz":[0.166147486076705764,0.0853993881662149512,0.816643879319447152],"hpluv":[264.250786122927309,449.46548401365061,35.0829820911796091],"hsluv":[264.250786122927309,99.9999999999932214,35.0829820911796091]},"#0033ff":{"lch":[37.0903499028545482,133.851694130242549,264.492451291459133],"luv":[37.0903499028545482,-12.8466699872586325,-133.233776092154926],"rgb":[0,0.2,1],"xyz":[0.192318534486537157,0.0958678075301476473,0.954478067611229],"hpluv":[264.492451291459133,457.933345064777,37.0903499028545482],"hsluv":[264.492451291459133,99.999999999999531,37.0903499028545482]},"#55cc00":{"lch":[72.9678739916599,103.392643433537373,122.072672834653702],"luv":[72.9678739916599,-54.9009234662034089,87.6123696673744661],"rgb":[0.333333333333333315,0.8,0],"xyz":[0.253381485948118268,0.451154891290725057,0.0737291113395339148],"hpluv":[122.072672834653702,179.803140433373983,72.9678739916599],"hsluv":[122.072672834653702,100.000000000002444,72.9678739916599]},"#55cc11":{"lch":[72.9944661394807497,102.34674561848017,122.382691003133885],"luv":[72.9944661394807497,-54.8140205324080085,86.4307786136781431],"rgb":[0.333333333333333315,0.8,0.0666666666666666657],"xyz":[0.254393151447755372,0.45155955749057991,0.0790572163042895515],"hpluv":[122.382691003133885,177.91945009175069,72.9944661394807497],"hsluv":[122.382691003133885,98.5172338886757757,72.9944661394807497]},"#55cc22":{"lch":[73.0437189009647909,100.431941691916791,122.969611448584445],"luv":[73.0437189009647909,-54.6544745496639663,84.2583130836875114],"rgb":[0.333333333333333315,0.8,0.133333333333333331],"xyz":[0.256268509586232429,0.452309700745970711,0.0889341025002687441],"hpluv":[122.969611448584445,174.473032354427772,73.0437189009647909],"hsluv":[122.969611448584445,95.7933392549395,73.0437189009647909]},"#55cc33":{"lch":[73.1246943704287702,97.3470237033586,123.971835615120114],"luv":[73.1246943704287702,-54.3960871275936384,80.7310889875115123],"rgb":[0.333333333333333315,0.8,0.2],"xyz":[0.259356260318690135,0.453544801038953838,0.10519625635787988],"hpluv":[123.971835615120114,168.926560877595364,73.1246943704287702],"hsluv":[123.971835615120114,91.3772697810403542,73.1246943704287702]},"#55cc44":{"lch":[73.2413452172043,93.0415252478239836,125.502056943833935],"luv":[73.2413452172043,-54.0322080150887771,75.7446098244333399],"rgb":[0.333333333333333315,0.8,0.266666666666666663],"xyz":[0.26381425556290905,0.455327999136641404,0.128675031310766519],"hpluv":[125.502056943833935,161.198069131808353,73.2413452172043],"hsluv":[125.502056943833935,85.148140842768953,73.2413452172043]},"#55cc55":{"lch":[73.3968865779486919,87.5572640326508207,127.71501294923992],"luv":[73.3968865779486919,-53.5617851120033066,69.2633356148757144],"rgb":[0.333333333333333315,0.8,0.333333333333333315],"xyz":[0.269776669602271035,0.457712964752386264,0.160077078584740434],"hpluv":[127.71501294923992,151.374900584602614,73.3968865779486919],"hsluv":[127.71501294923992,77.0768048277098,73.3968865779486919]},"#55cc66":{"lch":[73.5939772793636,81.0375847478920832,130.834727778769576],"luv":[73.5939772793636,-52.9887999422805,61.3129449826769175],"rgb":[0.333333333333333315,0.8,0.4],"xyz":[0.277361665375779221,0.460746963061789583,0.200024722991884396],"hpluv":[130.834727778769576,139.728031568505,73.5939772793636],"hsluv":[130.834727778769576,77.5857883184082766,73.5939772793636]},"#55cc77":{"lch":[73.8348152761848553,73.7475179973278898,135.191797127350526],"luv":[73.8348152761848553,-52.3216404431773,51.972515352838883],"rgb":[0.333333333333333315,0.8,0.466666666666666674],"xyz":[0.286675678395981126,0.464472568269870378,0.249078524898282305],"hpluv":[135.191797127350526,126.743455190439619,73.8348152761848553],"hsluv":[135.191797127350526,78.1806978106980779,73.8348152761848553]},"#55cc88":{"lch":[74.1211942127210648,66.1117924559585646,141.267644806662588],"luv":[74.1211942127210648,-51.5723023085178269,41.3650424433311343],"rgb":[0.333333333333333315,0.8,0.533333333333333326],"xyz":[0.297816095497924926,0.468928735110648,0.307751388301854445],"hpluv":[141.267644806662588,113.181605649052202,74.1211942127210648],"hsluv":[141.267644806662588,78.852064841283763,74.1211942127210648]},"#55cc99":{"lch":[74.4545405069311,58.7794373107374923,149.710693018120253],"luv":[74.4545405069311,-50.7554383804248,29.646377947024483],"rgb":[0.333333333333333315,0.8,0.6],"xyz":[0.310873059606997626,0.474151520754277134,0.37651806594297238],"hpluv":[149.710693018120253,100.178278207809555,74.4545405069311],"hsluv":[149.710693018120253,79.5881732610030355,74.4545405069311]},"#55ccaa":{"lch":[74.8359403329188808,52.7021878309829361,161.189357777818884],"luv":[74.8359403329188808,-49.8873315971569866,16.9933736582089097],"rgb":[0.333333333333333315,0.8,0.66666666666666663],"xyz":[0.325930752572250182,0.480174597940378256,0.455821915559971],"hpluv":[161.189357777818884,89.3630022499163772,74.8359403329188808],"hsluv":[161.189357777818884,80.3759073289738097,74.8359403329188808]},"#55ccbb":{"lch":[75.2661614985634,49.1164256219739315,175.805780272408356],"luv":[75.2661614985634,-48.9848849956305372,3.59225665059547428],"rgb":[0.333333333333333315,0.8,0.733333333333333282],"xyz":[0.343068344679586856,0.487029634783313,0.546079900658612782],"hpluv":[175.805780272408356,82.8068592257523619,75.2661614985634],"hsluv":[175.805780272408356,81.2015846585734238,75.2661614985634]},"#55cccc":{"lch":[75.7456730324682894,49.1710405410584386,192.177050630061103],"luv":[75.7456730324682894,-48.0647147647340063,-10.3718090261618983],"rgb":[0.333333333333333315,0.8,0.8],"xyz":[0.362360720123308555,0.494746584960801816,0.647686411328882938],"hpluv":[192.177050630061103,82.3741405590198639,75.7456730324682894],"hsluv":[192.177050630061103,82.0517040066532815,75.7456730324682894]},"#55ccdd":{"lch":[76.2746640882933349,53.2320113470533514,207.674227909684788],"luv":[76.2746640882933349,-47.1424090239802069,-24.7232745296525458],"rgb":[0.333333333333333315,0.8,0.866666666666666696],"xyz":[0.383879045673942154,0.503353915181055322,0.761016259228888936],"hpluv":[207.674227909684788,89.8673986045394,76.2746640882933349],"hsluv":[207.674227909684788,82.913556803619926,76.2746640882933349]},"#55ccee":{"lch":[76.8530630513789674,60.6801737900983298,220.368363670310828],"luv":[76.8530630513789674,-46.2319850937693673,-39.3025068600722207],"rgb":[0.333333333333333315,0.8,0.933333333333333348],"xyz":[0.407691225940116864,0.51287878728752534,0.886427075297412159],"hpluv":[220.368363670310828,105.55411204702996,76.8530630513789674],"hsluv":[220.368363670310828,83.7756757275922865,76.8530630513789674]},"#55ccff":{"lch":[77.4805572724897758,70.4908339109135511,229.9629437526429],"luv":[77.4805572724897758,-45.3455492712466395,-53.9697955040126445],"rgb":[0.333333333333333315,0.8,1],"xyz":[0.433862274349948285,0.523347206651458063,1.02426126358919389],"hpluv":[229.9629437526429,126.754412601721029,77.4805572724897758],"hsluv":[229.9629437526429,99.9999999999968878,77.4805572724897758]},"#004400":{"lch":[24.1097877444294397,37.3150672336374782,127.715012949240432],"luv":[24.1097877444294397,-22.8269080205926969,29.5185791133361732],"rgb":[0,0.266666666666666663,0],"xyz":[0.0206703165676731908,0.0413406331353469575,0.00689010552255753684],"hpluv":[127.715012949240432,196.39488290021464,24.1097877444294397],"hsluv":[127.715012949240432,100.000000000002458,24.1097877444294397]},"#004411":{"lch":[24.2402356883412295,33.8624764720942082,131.447767669063751],"luv":[24.2402356883412295,-22.4148262696793807,25.3819399598065552],"rgb":[0,0.266666666666666663,0.0666666666666666657],"xyz":[0.0216819820673103125,0.0417452993352018104,0.0122182104873131692],"hpluv":[131.447767669063751,177.264269230781338,24.2402356883412295],"hsluv":[131.447767669063751,99.9999999999909335,24.2402356883412295]},"#004422":{"lch":[24.4798388415780295,28.4164365287723264,139.862893984056171],"luv":[24.4798388415780295,-21.7244820008415864,18.3177713379345413],"rgb":[0,0.266666666666666663,0.133333333333333331],"xyz":[0.0235573402057873311,0.0424954425905926317,0.0220950966832923652],"hpluv":[139.862893984056171,147.299199898382369,24.4798388415780295],"hsluv":[139.862893984056171,99.9999999999911466,24.4798388415780295]},"#004433":{"lch":[24.8682723444395748,22.2877633761795622,158.664607016269599],"luv":[24.8682723444395748,-20.760308528761005,8.10888316004269427],"rgb":[0,0.266666666666666663,0.2],"xyz":[0.0266450909382450717,0.0437305428835757445,0.0383572505409035119],"hpluv":[158.664607016269599,113.726114076625834,24.8682723444395748],"hsluv":[158.664607016269599,99.9999999999913172,24.8682723444395748]},"#004444":{"lch":[25.4163828994624552,20.1084089871091685,192.17705063006116],"luv":[25.4163828994624552,-19.6559790417892835,-4.24153273022775057],"rgb":[0,0.266666666666666663,0.266666666666666663],"xyz":[0.0311030861824639487,0.0455137409812633176,0.0618360254937901505],"hpluv":[192.17705063006116,100.392967527320792,25.4163828994624552],"hsluv":[192.17705063006116,99.9999999999914166,25.4163828994624552]},"#004455":{"lch":[26.1275223832094383,25.5944772375096541,223.546306053382096],"luv":[26.1275223832094383,-18.5513329588178841,-17.6330743352507042],"rgb":[0,0.266666666666666663,0.333333333333333315],"xyz":[0.0370655002218259477,0.0478987065970081505,0.093238072767764052],"hpluv":[223.546306053382096,124.304646155287358,26.1275223832094383],"hsluv":[223.546306053382096,99.999999999991644,26.1275223832094383]},"#004466":{"lch":[26.9988561724938734,35.8050932952910514,240.647496291889979],"luv":[26.9988561724938734,-17.5509899640931621,-31.2084516944496499],"rgb":[0,0.266666666666666663,0.4],"xyz":[0.0446504959953341191,0.050932704906411462,0.133185717174908],"hpluv":[240.647496291889979,168.282428552664811,26.9988561724938734],"hsluv":[240.647496291889979,99.9999999999920135,26.9988561724938734]},"#004477":{"lch":[28.0227048150185141,47.4927479988473422,249.396343090395135],"luv":[28.0227048150185141,-16.7127641209025413,-44.4549730392572684],"rgb":[0,0.266666666666666663,0.466666666666666674],"xyz":[0.0539645090155360385,0.0546583101144922784,0.182239519081305923],"hpluv":[249.396343090395135,215.05848085050232,28.0227048150185141],"hsluv":[249.396343090395135,99.9999999999921698,28.0227048150185141]},"#004488":{"lch":[29.1879465441319326,59.3592998069098,254.306666373838311],"luv":[29.1879465441319326,-16.0560040952153962,-57.1465765034181956],"rgb":[0,0.266666666666666663,0.533333333333333326],"xyz":[0.0651049261174798666,0.0591144769552698762,0.24091238248487809],"hpluv":[254.306666373838311,258.06229412425995,29.1879465441319326],"hsluv":[254.306666373838311,99.9999999999923,29.1879465441319326]},"#004499":{"lch":[30.4813623757938217,70.9684349502494,257.321762040288718],"luv":[30.4813623757938217,-15.5758442205369825,-69.2380808233832141],"rgb":[0,0.266666666666666663,0.6],"xyz":[0.07816189022655258,0.0643372625988990338,0.309679060125996],"hpluv":[257.321762040288718,295.440602563868879,30.4813623757938217],"hsluv":[257.321762040288718,99.9999999999926672,30.4813623757938217]},"#0044aa":{"lch":[31.8888011745219231,82.2033012029853,259.305022310013101],"luv":[31.8888011745219231,-15.2553283345918977,-80.7753532092093138],"rgb":[0,0.266666666666666663,0.66666666666666663],"xyz":[0.0932195831918051221,0.0703603397850001422,0.388982909742994598],"hpluv":[259.305022310013101,327.107417663034141,31.8888011745219231],"hsluv":[259.305022310013101,99.9999999999925109,31.8888011745219231]},"#0044bb":{"lch":[33.3960915948532602,93.0667571364503,260.679203518012741],"luv":[33.3960915948532602,-15.0732787327803415,-91.8379962332527],"rgb":[0,0.266666666666666663,0.733333333333333282],"xyz":[0.110357175299141769,0.0772153766279349,0.479240894841636345],"hpluv":[260.679203518012741,353.621176249907,33.3960915948532602],"hsluv":[260.679203518012741,99.9999999999929656,33.3960915948532602]},"#0044cc":{"lch":[34.9896851087579108,103.60206818965716,261.670396128603272],"luv":[34.9896851087579108,-15.0085679377548828,-102.509177255659253],"rgb":[0,0.266666666666666663,0.8],"xyz":[0.129649550742863495,0.0849323268054237,0.5808474055119065],"hpluv":[261.670396128603272,375.722944942957042,34.9896851087579108],"hsluv":[261.670396128603272,99.999999999992923,34.9896851087579108]},"#0044dd":{"lch":[36.6570567010139499,113.860579159150092,262.408492682931296],"luv":[36.6570567010139499,-15.0420602661110987,-112.862606338006245],"rgb":[0,0.266666666666666663,0.866666666666666696],"xyz":[0.151167876293497039,0.0935396570256772364,0.694177253411912498],"hpluv":[262.408492682931296,394.144185167595538,36.6570567010139499],"hsluv":[262.408492682931296,99.9999999999929088,36.6570567010139499]},"#0044ee":{"lch":[38.386911506645724,123.889384104134805,262.972536787865295],"luv":[38.386911506645724,-15.1572566165017264,-122.958680318078251],"rgb":[0,0.266666666666666663,0.933333333333333348],"xyz":[0.174980056559671776,0.103064529132147253,0.819588069480435721],"hpluv":[262.972536787865295,409.534269399062566,38.386911506645724],"hsluv":[262.972536787865295,99.9999999999931,38.386911506645724]},"#0044ff":{"lch":[40.1692504091911928,133.727629508879147,263.412926975584469],"luv":[40.1692504091911928,-15.3403008413028115,-132.844849595919101],"rgb":[0,0.266666666666666663,1],"xyz":[0.201151104969503169,0.113532948496079963,0.957422257772217566],"hpluv":[263.412926975584469,422.441664595501038,40.1692504091911928],"hsluv":[263.412926975584469,99.9999999999994174,40.1692504091911928]},"#55dd00":{"lch":[78.2526895057908121,112.425836873112019,123.034721453117925],"luv":[78.2526895057908121,-61.2886270790004488,94.2511166373683267],"rgb":[0.333333333333333315,0.866666666666666696,0],"xyz":[0.296015476495293473,0.536422872385076577,0.0879404415219252333],"hpluv":[123.034721453117925,210.800433631405241,78.2526895057908121],"hsluv":[123.034721453117925,100.000000000002288,78.2526895057908121]},"#55dd11":{"lch":[78.2763843013059102,111.485784004679431,123.297526334296066],"luv":[78.2763843013059102,-61.2042162992655108,93.1832814529020368],"rgb":[0.333333333333333315,0.866666666666666696,0.0666666666666666657],"xyz":[0.297027141994930577,0.536827538584931485,0.09326854648668087],"hpluv":[123.297526334296066,209.310421322213443,78.2763843013059102],"hsluv":[123.297526334296066,98.7516598856555561,78.2763843013059102]},"#55dd22":{"lch":[78.3202766586626353,109.761570808260174,123.793166282380056],"luv":[78.3202766586626353,-61.0490014413279738,91.2174426812846235],"rgb":[0.333333333333333315,0.866666666666666696,0.133333333333333331],"xyz":[0.298902500133407634,0.537577681840322286,0.103145432682660063],"hpluv":[123.793166282380056,206.571995072092733,78.3202766586626353],"hsluv":[123.793166282380056,96.4551350157602201,78.3202766586626353]},"#55dd33":{"lch":[78.3924559312840898,106.97461234521991,124.633900466047606],"luv":[78.3924559312840898,-60.7969536029841819,88.018737317724927],"rgb":[0.333333333333333315,0.866666666666666696,0.2],"xyz":[0.30199025086586534,0.538812782133305412,0.119407586540271199],"hpluv":[124.633900466047606,202.130538056106332,78.3924559312840898],"hsluv":[124.633900466047606,92.7228817840519355,78.3924559312840898]},"#55dd44":{"lch":[78.4964717161501255,103.064578059178857,125.904361390923313],"luv":[78.4964717161501255,-60.4405744101571756,83.4819993500804],"rgb":[0.333333333333333315,0.866666666666666696,0.266666666666666663],"xyz":[0.306448246110084255,0.540595980230993,0.142886361493157837],"hpluv":[125.904361390923313,195.867385876976442,78.4964717161501255],"hsluv":[125.904361390923313,87.4391970363123221,78.4964717161501255]},"#55dd55":{"lch":[78.635232286968062,98.0447483954765175,127.715012949239977],"luv":[78.635232286968062,-59.9773394353739,77.559599291037074],"rgb":[0.333333333333333315,0.866666666666666696,0.333333333333333315],"xyz":[0.31241066014944624,0.542980945846737728,0.174288408767131753],"hpluv":[127.715012949239977,187.771435495127037,78.635232286968062],"hsluv":[127.715012949239977,80.5594181605674891,78.635232286968062]},"#55dd66":{"lch":[78.8111684825228451,92.0067823672703469,130.218539636235505],"luv":[78.8111684825228451,-59.4092211255214551,70.2551951590567],"rgb":[0.333333333333333315,0.866666666666666696,0.4],"xyz":[0.319995655922954425,0.546014944156141,0.214236053174275715],"hpluv":[130.218539636235505,177.951388767985407,78.8111684825228451],"hsluv":[130.218539636235505,80.9267337864342693,78.8111684825228451]},"#55dd77":{"lch":[79.0263204832261863,85.1319563310668315,133.631202536406704],"luv":[79.0263204832261863,-58.7422260542947043,61.618186170487121],"rgb":[0.333333333333333315,0.866666666666666696,0.466666666666666674],"xyz":[0.329309668943156331,0.549740549364221898,0.263289855080673596],"hpluv":[133.631202536406704,166.66460441184762,79.0263204832261863],"hsluv":[133.631202536406704,81.3592233632428,79.0263204832261863]},"#55dd88":{"lch":[79.2823892178289,77.7115996221609322,138.259418470179128],"luv":[79.2823892178289,-57.9858175415186921,51.7371982221375],"rgb":[0.333333333333333315,0.866666666666666696,0.533333333333333326],"xyz":[0.340450086045100131,0.55419671620499944,0.321962718484245791],"hpluv":[138.259418470179128,154.371102046011828,79.2823892178289],"hsluv":[138.259418470179128,81.8514411788724,79.2823892178289]},"#55dd99":{"lch":[79.5807696492298504,70.1818875082800133,144.522564094970761],"luv":[79.5807696492298504,-57.1522092721799737,40.7323251181885624],"rgb":[0.333333333333333315,0.866666666666666696,0.6],"xyz":[0.353507050154172831,0.559419501848628653,0.390729396125363726],"hpluv":[144.522564094970761,141.828030979619143,79.5807696492298504],"hsluv":[144.522564094970761,82.3962440946128538,79.5807696492298504]},"#55ddaa":{"lch":[79.9225742847085,63.1747442044720913,152.933070337002903],"luv":[79.9225742847085,-56.2555676549498145,28.7464678372812266],"rgb":[0.333333333333333315,0.866666666666666696,0.66666666666666663],"xyz":[0.368564743119425386,0.56544257903472972,0.470033245742362271],"hpluv":[152.933070337002903,130.236824512138128,79.9225742847085],"hsluv":[152.933070337002903,82.9852754707380313,79.9225742847085]},"#55ddbb":{"lch":[80.3086513857730466,57.5612329714098649,163.927126105934775],"luv":[80.3086513857730466,-55.3111838467604926,15.9363886328987263],"rgb":[0.333333333333333315,0.866666666666666696,0.733333333333333282],"xyz":[0.385702335226762061,0.572297615877664478,0.560291230841004073],"hpluv":[163.927126105934775,121.406580229851471,80.3086513857730466],"hsluv":[163.927126105934775,83.6094665313934,80.3086513857730466]},"#55ddcc":{"lch":[80.7396004409482657,54.3905283694756534,177.403333860877041],"luv":[80.7396004409482657,-54.3346805898883076,2.46415533308082235],"rgb":[0.333333333333333315,0.866666666666666696,0.8],"xyz":[0.40499471067048376,0.580014566055153336,0.661897741511274229],"hpluv":[177.403333860877041,117.73427745544555,80.7396004409482657],"hsluv":[177.403333860877041,84.2595162876674664,80.7396004409482657]},"#55dddd":{"lch":[81.2157864208401605,54.5690893966631236,192.177050630061103],"luv":[81.2157864208401605,-53.3413100060750764,-11.5104371948595805],"rgb":[0.333333333333333315,0.866666666666666696,0.866666666666666696],"xyz":[0.426513036221117359,0.588621896275406842,0.775227589411280227],"hpluv":[192.177050630061103,121.625211000731653,81.2157864208401605],"hsluv":[192.177050630061103,84.9263164151063847,81.2157864208401605]},"#55ddee":{"lch":[81.73735371635685,58.3741450028570412,206.269517439458],"luv":[81.73735371635685,-52.3453816136692609,-25.8360567528002605],"rgb":[0.333333333333333315,0.866666666666666696,0.933333333333333348],"xyz":[0.450325216487292068,0.598146768381876859,0.90063840547980345],"hpluv":[206.269517439458,134.436687270459231,81.73735371635685],"hsluv":[206.269517439458,85.6012975649288421,81.73735371635685]},"#55ddff":{"lch":[82.3042402700550753,65.3293790133507599,218.171205050819623],"luv":[82.3042402700550753,-51.3598401525014268,-40.374429801293],"rgb":[0.333333333333333315,0.866666666666666696,1],"xyz":[0.476496264897123489,0.608615187745809583,1.0384725937715853],"hpluv":[218.171205050819623,156.046773818868189,82.3042402700550753],"hsluv":[218.171205050819623,99.9999999999958078,82.3042402700550753]},"#005500":{"lch":[30.6325595368381371,47.4104554868850059,127.715012949240474],"luv":[30.6325595368381371,-29.0026036892131067,37.5046699588244152],"rgb":[0,0.333333333333333315,0],"xyz":[0.0324835732820191528,0.0649671465640392215,0.0108278577606727468],"hpluv":[127.715012949240474,196.39488290021464,30.6325595368381371],"hsluv":[127.715012949240474,100.000000000002331,30.6325595368381371]},"#005511":{"lch":[30.7291805540017933,44.5531719728198325,130.030983014983661],"luv":[30.7291805540017933,-28.6566785608310113,34.1142185415534129],"rgb":[0,0.333333333333333315,0.0666666666666666657],"xyz":[0.033495238781656278,0.0653718127638940744,0.01615596272542838],"hpluv":[130.030983014983661,183.978458821492183,30.7291805540017933],"hsluv":[130.030983014983661,99.9999999999909335,30.7291805540017933]},"#005522":{"lch":[30.9072407208055395,39.7502752239143149,134.89425658266407],"luv":[30.9072407208055395,-28.0557665948475297,28.1595159964153758],"rgb":[0,0.333333333333333315,0.133333333333333331],"xyz":[0.0353705969201332932,0.0661219560192848888,0.0260328489214075726],"hpluv":[134.89425658266407,163.199653312489744,30.9072407208055395],"hsluv":[134.89425658266407,99.9999999999909903,30.9072407208055395]},"#005533":{"lch":[31.1975029455576802,33.2574057268159,144.773587953954916],"luv":[31.1975029455576802,-27.1672793055155033,19.1831689460880241],"rgb":[0,0.333333333333333315,0.2],"xyz":[0.0384583476525910337,0.067357056312268,0.0422950027790187227],"hpluv":[144.773587953954916,135.271984326190278,31.1975029455576802],"hsluv":[144.773587953954916,99.9999999999912177,31.1975029455576802]},"#005544":{"lch":[31.6103799108948778,27.1932751339722678,163.464109831123295],"luv":[31.6103799108948778,-26.0686058468900157,7.73963834500076331],"rgb":[0,0.333333333333333315,0.266666666666666663],"xyz":[0.0429163428968099142,0.0691402544099555816,0.0657737777319053613],"hpluv":[163.464109831123295,109.16191048912313,31.6103799108948778],"hsluv":[163.464109831123295,99.999999999991374,31.6103799108948778]},"#005555":{"lch":[32.1516370434520482,25.4370682812028797,192.17705063006116],"luv":[32.1516370434520482,-24.8647459548099441,-5.36552433088697445],"rgb":[0,0.333333333333333315,0.333333333333333315],"xyz":[0.0488787569361719063,0.0715252200257004145,0.0971758250058792628],"hpluv":[192.17705063006116,100.392967527320877,32.1516370434520482],"hsluv":[192.17705063006116,99.9999999999915,32.1516370434520482]},"#005566":{"lch":[32.8230722751799036,30.545644410021449,219.238547792689275],"luv":[32.8230722751799036,-23.6581848019048806,-19.3216636007977201],"rgb":[0,0.333333333333333315,0.4],"xyz":[0.0564637527096800845,0.074559218335103733,0.137123469413023225],"hpluv":[219.238547792689275,118.088984839520307,32.8230722751799036],"hsluv":[219.238547792689275,99.9999999999916298,32.8230722751799036]},"#005577":{"lch":[33.6230950493472065,40.3511971197610322,236.060106868306946],"luv":[33.6230950493472065,-22.5289967279924532,-33.4763112577822142],"rgb":[0,0.333333333333333315,0.466666666666666674],"xyz":[0.065777765729882,0.0782848235431845424,0.186177271319421134],"hpluv":[236.060106868306946,152.285327594300298,33.6230950493472065],"hsluv":[236.060106868306946,99.9999999999918,33.6230950493472065]},"#005588":{"lch":[34.5473308406039266,52.0529464564925703,245.569923252468897],"luv":[34.5473308406039266,-21.5281838547339461,-47.3924733973576764],"rgb":[0,0.333333333333333315,0.533333333333333326],"xyz":[0.076918182831825832,0.0827409903839621402,0.244850134722993301],"hpluv":[245.569923252468897,191.192188881903292,34.5473308406039266],"hsluv":[245.569923252468897,99.9999999999919709,34.5473308406039266]},"#005599":{"lch":[35.5892574919693772,64.2489447401961655,251.22324643469841],"luv":[35.5892574919693772,-20.6805523421639172,-60.8296116628390067],"rgb":[0,0.333333333333333315,0.6],"xyz":[0.0899751469408985316,0.0879637760275913,0.313616812364111208],"hpluv":[251.22324643469841,229.079590546614583,35.5892574919693772],"hsluv":[251.22324643469841,99.9999999999922125,35.5892574919693772]},"#0055aa":{"lch":[36.7408379507026,76.3552968047486189,254.821646708521541],"luv":[36.7408379507026,-19.9916927982920107,-73.6916791042243347],"rgb":[0,0.333333333333333315,0.66666666666666663],"xyz":[0.105032839906151088,0.0939868532136924,0.392920661981109809],"hpluv":[254.821646708521541,263.711724718685957,36.7408379507026],"hsluv":[254.821646708521541,99.9999999999921556,36.7408379507026]},"#0055bb":{"lch":[37.993106438468665,88.146943006458784,257.249085911334646],"luv":[37.993106438468665,-19.4551758320548949,-85.9731335635018],"rgb":[0,0.333333333333333315,0.733333333333333282],"xyz":[0.122170432013487734,0.100841890056627165,0.483178647079751555],"hpluv":[257.249085911334646,294.402692429224658,37.993106438468665],"hsluv":[257.249085911334646,99.9999999999924114,37.993106438468665]},"#0055cc":{"lch":[39.3366742314503384,99.5579220492412,258.963845190076711],"luv":[39.3366742314503384,-19.0582121518786707,-97.7167559446012888],"rgb":[0,0.333333333333333315,0.8],"xyz":[0.141462807457209461,0.108558840234115966,0.584785157750021711],"hpluv":[258.963845190076711,321.157087606315883,39.3366742314503384],"hsluv":[258.963845190076711,99.9999999999926,39.3366742314503384]},"#0055dd":{"lch":[40.7621365800243538,110.592821589198408,260.220233587680809],"luv":[40.7621365800243538,-18.7854624460211568,-108.985680654613518],"rgb":[0,0.333333333333333315,0.866666666666666696],"xyz":[0.162981133007843,0.1171661704543695,0.698115005650027709],"hpluv":[260.220233587680809,344.278042660470817,40.7621365800243538],"hsluv":[260.220233587680809,99.9999999999926672,40.7621365800243538]},"#0055ee":{"lch":[42.2603772648371105,121.285075365136905,261.168248695532611],"luv":[42.2603772648371105,-18.6213165580406681,-119.847052846418293],"rgb":[0,0.333333333333333315,0.933333333333333348],"xyz":[0.186793313274017742,0.126691042560839517,0.823525821718550932],"hpluv":[261.168248695532611,364.177675198016914,42.2603772648371105],"hsluv":[261.168248695532611,99.9999999999924256,42.2603772648371105]},"#0055ff":{"lch":[43.8227784910393,131.676969611306021,261.90102950371454],"luv":[43.8227784910393,-18.5511048350842884,-130.363648443170376],"rgb":[0,0.333333333333333315,1],"xyz":[0.212964361683849135,0.137159461924772241,0.961360010010332777],"hpluv":[261.90102950371454,381.28457852045068,43.8227784910393],"hsluv":[261.90102950371454,99.9999999999993321,43.8227784910393]},"#55ee00":{"lch":[83.4834241678481277,121.26988118033438,123.77813801339137],"luv":[83.4834241678481277,-67.423446821455,100.799121524975831],"rgb":[0.333333333333333315,0.933333333333333348,0],"xyz":[0.343194252835808289,0.630780425066107542,0.103666700302096418],"hpluv":[123.77813801339137,313.542875178701877,83.4834241678481277],"hsluv":[123.77813801339137,100.000000000002402,83.4834241678481277]},"#55ee11":{"lch":[83.5046935730824487,120.419265504422668,124.002811201886018],"luv":[83.5046935730824487,-67.3424968648776456,99.8287915414615412],"rgb":[0.333333333333333315,0.933333333333333348,0.0666666666666666657],"xyz":[0.344205918335445393,0.63118509126596245,0.108994805266852055],"hpluv":[124.002811201886018,311.80236567126093,83.5046935730824487],"hsluv":[124.002811201886018,98.9375412624106616,83.5046935730824487]},"#55ee22":{"lch":[83.5440973470955868,118.856748008926118,124.425313598414533],"luv":[83.5440973470955868,-67.1934622190367463,98.0406302625408728],"rgb":[0.333333333333333315,0.933333333333333348,0.133333333333333331],"xyz":[0.34608127647392245,0.631935234521353251,0.118871691462831247],"hpluv":[124.425313598414533,308.59848358059196,83.5440973470955868],"hsluv":[124.425313598414533,96.9807587800033133,83.5440973470955868]},"#55ee33":{"lch":[83.6089072227085524,116.32446068797897,125.138397832270286],"luv":[83.6089072227085524,-66.950941309724243,95.1259775880964469],"rgb":[0.333333333333333315,0.933333333333333348,0.2],"xyz":[0.349169027206380156,0.633170334814336377,0.135133845320442397],"hpluv":[125.138397832270286,303.387603747434184,83.6089072227085524],"hsluv":[125.138397832270286,93.7945051225822084,83.6089072227085524]},"#55ee44":{"lch":[83.7023291233000748,112.756808619009803,126.207644663357115],"luv":[83.7023291233000748,-66.6069499756988535,90.9813832873448547],"rgb":[0.333333333333333315,0.933333333333333348,0.266666666666666663],"xyz":[0.353627022450599071,0.634953532912023944,0.158612620273329036],"hpluv":[126.207644663357115,296.007020538140409,83.7023291233000748],"hsluv":[126.207644663357115,89.2707337544585,83.7023291233000748]},"#55ee55":{"lch":[83.8270046653184,108.148092962556504,127.715012949240077],"luv":[83.8270046653184,-66.1579022543843,85.5519840841642747],"rgb":[0.333333333333333315,0.933333333333333348,0.333333333333333315],"xyz":[0.359589436489961056,0.637338498527768693,0.190014667547302951],"hpluv":[127.715012949240077,286.404562223907249,83.8270046653184],"hsluv":[127.715012949240077,83.3573838846113091,83.8270046653184]},"#55ee66":{"lch":[83.985160091985378,102.554744038676162,129.769393513035965],"luv":[83.985160091985378,-65.6041880698479645,78.8261760618539853],"rgb":[0.333333333333333315,0.933333333333333348,0.4],"xyz":[0.367174432263469241,0.640372496837172,0.229962311954446885],"hpluv":[129.769393513035965,274.647728218817576,83.985160091985378],"hsluv":[129.769393513035965,83.6273111034757477,83.985160091985378]},"#55ee77":{"lch":[84.1786855608653752,96.1019099790829756,132.519661951802362],"luv":[84.1786855608653752,-64.9498200787083,70.8314758661090451],"rgb":[0.333333333333333315,0.933333333333333348,0.466666666666666674],"xyz":[0.376488445283671147,0.644098102045252863,0.279016113860844794],"hpluv":[132.519661951802362,260.948457539577589,84.1786855608653752],"hsluv":[132.519661951802362,83.9470254314832687,84.1786855608653752]},"#55ee88":{"lch":[84.4091822183787741,88.9952087097784,136.170997575445568],"luv":[84.4091822183787741,-64.2020140446184371,61.6299323860706],"rgb":[0.333333333333333315,0.933333333333333348,0.533333333333333326],"xyz":[0.387628862385614947,0.648554268886030405,0.337688977264417],"hpluv":[136.170997575445568,245.709397001158351,84.4091822183787741],"hsluv":[136.170997575445568,84.3134084109568533,84.4091822183787741]},"#55ee99":{"lch":[84.6779925165317877,81.540352796223317,141.002136712429774],"luv":[84.6779925165317877,-63.3706695007570531,51.3126434824633151],"rgb":[0.333333333333333315,0.933333333333333348,0.6],"xyz":[0.400685826494687647,0.653777054529659618,0.406455654905534869],"hpluv":[141.002136712429774,229.604367075154897,84.6779925165317877],"hsluv":[141.002136712429774,84.7220894550445394,84.6779925165317877]},"#55eeaa":{"lch":[84.9862212486181363,74.1734332109310373,147.37159021859884],"luv":[84.9862212486181363,-62.4677637576075426,39.9934580327855755],"rgb":[0.333333333333333315,0.933333333333333348,0.66666666666666663],"xyz":[0.415743519459940203,0.659800131715760685,0.48575950452253347],"hpluv":[147.37159021859884,213.709694911287,84.9862212486181363],"hsluv":[147.37159021859884,85.1677250765186358,84.9862212486181363]},"#55eebb":{"lch":[85.334751323756052,67.4984157699475418,155.676120933413],"luv":[85.334751323756052,-61.5066955643592337,27.8022037293077737],"rgb":[0.333333333333333315,0.933333333333333348,0.733333333333333282],"xyz":[0.432881111567276877,0.666655168558695443,0.576017489621175272],"hpluv":[155.676120933413,199.690784145783283,85.334751323756052],"hsluv":[155.676120933413,85.6443005177139298,85.334751323756052]},"#55eecc":{"lch":[85.7242566025865784,62.3040769944455,166.184583472908372],"luv":[85.7242566025865784,-60.5016239571924643,14.8778865660505755],"rgb":[0.333333333333333315,0.933333333333333348,0.8],"xyz":[0.452173487010998576,0.674372118736184301,0.677624000291445427],"hpluv":[166.184583472908372,189.979166061651426,85.7242566025865784],"hsluv":[166.184583472908372,86.1454332210543186,85.7242566025865784]},"#55eedd":{"lch":[86.1552131978466349,59.4824491826881427,178.687660418725557],"luv":[86.1552131978466349,-59.4668469392298462,1.36230535390821395],"rgb":[0.333333333333333315,0.933333333333333348,0.866666666666666696],"xyz":[0.473691812561632175,0.682979448956437807,0.790953848191451425],"hpluv":[178.687660418725557,187.703134777137279,86.1552131978466349],"hsluv":[178.687660418725557,86.6646578889921,86.1552131978466349]},"#55eeee":{"lch":[86.6279101052896578,59.7608483004272202,192.177050630061245],"luv":[86.6279101052896578,-58.4162567245265265,-12.6055519466972967],"rgb":[0.333333333333333315,0.933333333333333348,0.933333333333333348],"xyz":[0.497503992827806885,0.692504321062907824,0.916364664259974648],"hpluv":[192.177050630061245,196.025490067494644,86.6279101052896578],"hsluv":[192.177050630061245,87.195676441965972,86.6279101052896578]},"#55eeff":{"lch":[87.1424596935915901,63.3545065705612274,205.119112492248092],"luv":[87.1424596935915901,-57.3628964007582169,-26.8940814923128677],"rgb":[0.333333333333333315,0.933333333333333348,1],"xyz":[0.523675041237638306,0.702972740426840548,1.05419885255175649],"hpluv":[205.119112492248092,217.06231600799947,87.1424596935915901],"hsluv":[205.119112492248092,99.9999999999933,87.1424596935915901]},"#006600":{"lch":[36.9339903888407548,57.1632711650289735,127.71501294924046],"luv":[36.9339903888407548,-34.9687359497521086,45.2197642227726249],"rgb":[0,0.4,0],"xyz":[0.0475116309878656218,0.0950232619757325619,0.0158372103292880942],"hpluv":[127.71501294924046,196.394882900214554,36.9339903888407548],"hsluv":[127.71501294924046,100.000000000002331,36.9339903888407548]},"#006611":{"lch":[37.0090255636121412,54.7765813256580216,129.276595687178855],"luv":[37.0090255636121412,-34.6771211058740789,42.4024897091546933],"rgb":[0,0.4,0.0666666666666666657],"xyz":[0.04852329648750274,0.0954279281755874148,0.0211653152940437239],"hpluv":[129.276595687178855,187.813410896691579,37.0090255636121412],"hsluv":[129.276595687178855,99.9999999999908908,37.0090255636121412]},"#006622":{"lch":[37.1475616040544949,50.6324758020482761,132.428423847637788],"luv":[37.1475616040544949,-34.160143827310165,37.3728802682170453],"rgb":[0,0.4,0.133333333333333331],"xyz":[0.0503986546259797621,0.0961780714309782292,0.0310422014900229234],"hpluv":[132.428423847637788,172.957013965329963,37.1475616040544949],"hsluv":[132.428423847637788,99.9999999999909619,37.1475616040544949]},"#006633":{"lch":[37.3740982281225911,44.601943170857588,138.432874640413417],"luv":[37.3740982281225911,-33.3702331720845464,29.5932572160807972],"rgb":[0,0.4,0.2],"xyz":[0.0534864053584375,0.0974131717239613421,0.0473043553476340667],"hpluv":[138.432874640413417,151.43364776149042,37.3740982281225911],"hsluv":[138.432874640413417,99.9999999999910187,37.3740982281225911]},"#006644":{"lch":[37.6978110334583292,37.6830106217376226,149.139540405640531],"luv":[37.6978110334583292,-32.3478161181420845,19.3294615006434647],"rgb":[0,0.4,0.266666666666666663],"xyz":[0.0579444006026563832,0.099196369821648922,0.0707831303005207],"hpluv":[149.139540405640531,126.843666215367492,37.6978110334583292],"hsluv":[149.139540405640531,99.9999999999911893,37.6978110334583292]},"#006655":{"lch":[38.1247572916394191,31.9621551107412678,167.158861879927684],"luv":[38.1247572916394191,-31.1627826377188839,7.10354401671241],"rgb":[0,0.4,0.333333333333333315],"xyz":[0.0639068146420183752,0.101581335437393755,0.102185177574494607],"hpluv":[167.158861879927684,106.382034992292617,38.1247572916394191],"hsluv":[167.158861879927684,99.9999999999912461,38.1247572916394191]},"#006666":{"lch":[38.6583399620500714,30.584907136256998,192.177050630061132],"luv":[38.6583399620500714,-29.8967608054288689,-6.45137488264605441],"rgb":[0,0.4,0.4],"xyz":[0.0714918104155265466,0.104615333746797073,0.142132821981638569],"hpluv":[192.177050630061132,100.392967527320849,38.6583399620500714],"hsluv":[192.177050630061132,99.9999999999914877,38.6583399620500714]},"#006677":{"lch":[39.2996251720959648,35.3400629634721852,215.899751113488037],"luv":[39.2996251720959648,-28.6270125920824867,-20.7223116547099835],"rgb":[0,0.4,0.466666666666666674],"xyz":[0.080805823435728466,0.108340938954877883,0.191186623888036478],"hpluv":[215.899751113488037,114.108563264217921,39.2996251720959648],"hsluv":[215.899751113488037,99.999999999991644,39.2996251720959648]},"#006688":{"lch":[40.0476371065618721,44.619030030948764,232.088426656893603],"luv":[40.0476371065618721,-27.4159210327312195,-35.2026293738089109],"rgb":[0,0.4,0.533333333333333326],"xyz":[0.0919462405376723,0.112797105795655481,0.249859487291608645],"hpluv":[232.088426656893603,141.378234692038774,40.0476371065618721],"hsluv":[232.088426656893603,99.9999999999918145,40.0476371065618721]},"#006699":{"lch":[40.8996671875350728,56.0796471869528546,242.024131169727298],"luv":[40.8996671875350728,-26.3069429553173038,-49.5264735364712863],"rgb":[0,0.4,0.6],"xyz":[0.105003204646745008,0.118019891439284638,0.318626164932726552],"hpluv":[242.024131169727298,173.990215160848891,40.8996671875350728],"hsluv":[242.024131169727298,99.9999999999919,40.8996671875350728]},"#0066aa":{"lch":[41.8515997707465104,68.3303466488807345,248.245335088520562],"luv":[41.8515997707465104,-25.3254853434547229,-63.4638169768779861],"rgb":[0,0.4,0.66666666666666663],"xyz":[0.12006089761199755,0.124042968625385747,0.397930014549725153],"hpluv":[248.245335088520562,207.176688473106537,41.8515997707465104],"hsluv":[248.245335088520562,99.9999999999921,41.8515997707465104]},"#0066bb":{"lch":[42.8982420202673396,80.6980154219041452,252.339105133311591],"luv":[42.8982420202673396,-24.4823887435570384,-76.8946183711398],"rgb":[0,0.4,0.733333333333333282],"xyz":[0.137198489719334182,0.130898005468320505,0.488187999648366899],"hpluv":[252.339105133311591,238.705643004687346,42.8982420202673396],"hsluv":[252.339105133311591,99.9999999999922125,42.8982420202673396]},"#0066cc":{"lch":[44.0336413015701211,92.8728169416488356,255.165448618736946],"luv":[44.0336413015701211,-23.7781103155697018,-89.7772888680517696],"rgb":[0,0.4,0.8],"xyz":[0.156490865163055937,0.138614955645809307,0.589794510318637],"hpluv":[255.165448618736946,267.63526922347819,44.0336413015701211],"hsluv":[255.165448618736946,99.9999999999922835,44.0336413015701211]},"#0066dd":{"lch":[45.2513748624169807,104.723900430114114,257.197154574648096],"luv":[45.2513748624169807,-23.2064943358636171,-102.120291528843495],"rgb":[0,0.4,0.866666666666666696],"xyz":[0.17800919071368948,0.147222285866062841,0.703124358218643],"hpluv":[257.197154574648096,293.665789717253858,45.2513748624169807],"hsluv":[257.197154574648096,99.9999999999923119,45.2513748624169807]},"#0066ee":{"lch":[46.5448008930790422,116.210429262859975,258.70668283343889],"luv":[46.5448008930790422,-22.7576936505684415,-113.960305585607557],"rgb":[0,0.4,0.933333333333333348],"xyz":[0.201821370979864217,0.156747157972532858,0.828535174287166276],"hpluv":[258.70668283343889,316.82048544727013,46.5448008930790422],"hsluv":[258.70668283343889,99.9999999999923119,46.5448008930790422]},"#0066ff":{"lch":[47.9072652547968758,127.336469583599694,259.859032010401279],"luv":[47.9072652547968758,-22.4202120236612075,-125.347160234402949],"rgb":[0,0.4,1],"xyz":[0.227992419389695611,0.167215577336465582,0.966369362578948121],"hpluv":[259.859032010401279,337.280125749862,47.9072652547968758],"hsluv":[259.859032010401279,99.9999999999992326,47.9072652547968758]},"#55ff00":{"lch":[88.6611895097861691,129.940408372856581,124.363532639485271],"luv":[88.6611895097861691,-73.3437881830395213,107.262288168144963],"rgb":[0.333333333333333315,1,0],"xyz":[0.395046625265482121,0.734485169925456649,0.120950824445320529],"hpluv":[124.363532639485271,511.214684976108288,88.6611895097861691],"hsluv":[124.363532639485271,100.000000000002203,88.6611895097861691]},"#55ff11":{"lch":[88.6804070841335488,129.16615931328721,124.557188606571273],"luv":[88.6804070841335488,-73.2667318726085597,106.376137890284312],"rgb":[0.333333333333333315,1,0.0666666666666666657],"xyz":[0.396058290765119225,0.734889836125311557,0.126278929410076152],"hpluv":[124.557188606571273,509.111714190739917,88.6804070841335488],"hsluv":[124.557188606571273,99.999999999991374,88.6804070841335488]},"#55ff22":{"lch":[88.7160126920472862,127.742171235629925,124.920549061750862],"luv":[88.7160126920472862,-73.1247263453711867,104.741762009752222],"rgb":[0.333333333333333315,1,0.133333333333333331],"xyz":[0.397933648903596282,0.735639979380702358,0.136155815606055358],"hpluv":[124.920549061750862,505.235489858807625,88.7160126920472862],"hsluv":[124.920549061750862,99.9999999999912461,88.7160126920472862]},"#55ff33":{"lch":[88.7745841250638819,125.429409451765778,125.531442964179078],"luv":[88.7745841250638819,-72.893256299655377,102.074041467218606],"rgb":[0.333333333333333315,1,0.2],"xyz":[0.401021399636054,0.736875079673685485,0.152417969463666508],"hpluv":[125.531442964179078,498.916518871762833,88.7745841250638819],"hsluv":[125.531442964179078,99.9999999999915445,88.7745841250638819]},"#55ff44":{"lch":[88.8590323294941271,122.159967165607114,126.442013329478428],"luv":[88.8590323294941271,-72.5641116581323189,98.2726171279075658],"rgb":[0.333333333333333315,1,0.266666666666666663],"xyz":[0.405479394880272903,0.738658277771373,0.175896744416553147],"hpluv":[126.442013329478428,489.934204596741552,88.8590323294941271],"hsluv":[126.442013329478428,99.9999999999914735,88.8590323294941271]},"#55ff55":{"lch":[88.9717666926620154,117.915518658848484,127.715012949240119],"luv":[88.9717666926620154,-72.1329719647303,93.2786357968462],"rgb":[0.333333333333333315,1,0.333333333333333315],"xyz":[0.411441808919634888,0.7410432433871178,0.207298791690527062],"hpluv":[127.715012949240119,478.187207442594797,88.9717666926620154],"hsluv":[127.715012949240119,99.9999999999912461,88.9717666926620154]},"#55ff66":{"lch":[89.1148309932425,112.728028648536309,129.430986513959965],"luv":[89.1148309932425,-71.5990188667543919,87.0700232014633713],"rgb":[0.333333333333333315,1,0.4],"xyz":[0.419026804693143073,0.744077241696521119,0.247246436097671],"hpluv":[129.430986513959965,463.701047487447568,89.1148309932425],"hsluv":[129.430986513959965,99.999999999991374,89.1148309932425]},"#55ff77":{"lch":[89.2899761450384233,106.6837193332601,131.696695826109391],"luv":[89.2899761450384233,-70.9646547782272705,79.6582308552282825],"rgb":[0.333333333333333315,1,0.466666666666666674],"xyz":[0.428340817713345,0.747802846904602,0.296300238004068905],"hpluv":[131.696695826109391,446.653165807945641,89.2899761450384233],"hsluv":[131.696695826109391,99.9999999999911466,89.2899761450384233]},"#55ff88":{"lch":[89.4987035327786344,99.9302046144725722,134.655503696120093],"luv":[89.4987035327786344,-70.2351927280585784,71.0849034376696807],"rgb":[0.333333333333333315,1,0.533333333333333326],"xyz":[0.439481234815288779,0.752259013745379512,0.354973101407641101],"hpluv":[134.655503696120093,427.420708471833962,89.4987035327786344],"hsluv":[134.655503696120093,99.9999999999910472,89.4987035327786344]},"#55ff99":{"lch":[89.7422928839939544,92.6881300553494185,138.499225093055145],"luv":[89.7422928839939544,-69.4184746025382395,61.4179520744067275],"rgb":[0.333333333333333315,1,0.6],"xyz":[0.452538198924361534,0.757481799389008725,0.423739779048759],"hpluv":[138.499225093055145,406.664135605650245,89.7422928839939544],"hsluv":[138.499225093055145,99.9999999999909193,89.7422928839939544]},"#55ffaa":{"lch":[90.021821419032733,85.2692799565717081,143.477548510033301],"luv":[90.021821419032733,-68.524415632830582,50.7469660816416095],"rgb":[0.333333333333333315,1,0.66666666666666663],"xyz":[0.467595891889614035,0.763504876575109792,0.503043628665757581],"hpluv":[143.477548510033301,385.467603776639692,90.021821419032733],"hsluv":[143.477548510033301,99.9999999999908908,90.021821419032733]},"#55ffbb":{"lch":[90.3381779071049635,78.1017696608261929,149.892156464581973],"luv":[90.3381779071049635,-67.5644942943643514,39.178125719584358],"rgb":[0.333333333333333315,1,0.733333333333333282],"xyz":[0.484733483996950709,0.770359913418044551,0.593301613764399383],"hpluv":[149.892156464581973,365.560319764238727,90.3381779071049635],"hsluv":[149.892156464581973,99.9999999999906,90.3381779071049635]},"#55ffcc":{"lch":[90.6920737330737836,71.7555158590460849,158.04408297895796],"luv":[90.6920737330737836,-66.5512174426729217,26.828893251416094],"rgb":[0.333333333333333315,1,0.8],"xyz":[0.504025859440672463,0.778076863595533408,0.694908124434669539],"hpluv":[158.04408297895796,349.620992563925881,90.6920737330737836],"hsluv":[158.04408297895796,99.9999999999905214,90.6920737330737836]},"#55ffdd":{"lch":[91.0840522607878142,66.9403052018893874,168.083008151042208],"luv":[91.0840522607878142,-65.4975936461766,13.8227959213187273],"rgb":[0.333333333333333315,1,0.866666666666666696],"xyz":[0.525544184991306,0.786684193815786914,0.808237972334675536],"hpluv":[168.083008151042208,341.570927955438208,91.0840522607878142],"hsluv":[168.083008151042208,99.9999999999901092,91.0840522607878142]},"#55ffee":{"lch":[91.5144973031429,64.4172738793593,179.746868091755],"luv":[91.5144973031429,-64.4166452130874347,0.284593639433804613],"rgb":[0.333333333333333315,1,0.933333333333333348],"xyz":[0.549356365257480661,0.796209065922256931,0.933648788403198759],"hpluv":[179.746868091755,346.559914030924404,91.5144973031429],"hsluv":[179.746868091755,99.9999999999898108,91.5144973031429]},"#55ffff":{"lch":[91.9836412143362,64.7784688708661918,192.177050630061103],"luv":[91.9836412143362,-63.3209831419883,-13.663935128132529],"rgb":[0.333333333333333315,1,1],"xyz":[0.575527413667312082,0.806677485286189655,1.07148297669498049],"hpluv":[192.177050630061103,370.276433987554753,91.9836412143362],"hsluv":[192.177050630061103,99.9999999999890719,91.9836412143362]},"#007700":{"lch":[43.052730924646589,66.6333343982289534,127.715012949240503],"luv":[43.052730924646589,-40.7618988300426395,52.7111834129681611],"rgb":[0,0.466666666666666674,0],"xyz":[0.0659653690412832505,0.131930738082568333,0.0219884563470937981],"hpluv":[127.715012949240503,196.394882900214441,43.052730924646589],"hsluv":[127.715012949240503,100.000000000002217,43.052730924646589]},"#007711":{"lch":[43.1130460407029,64.6129906803504497,128.830381027920708],"luv":[43.1130460407029,-40.513441406878222,50.333881531534],"rgb":[0,0.466666666666666674,0.0666666666666666657],"xyz":[0.0669770345409203688,0.132335404282423186,0.0273165613118494313],"hpluv":[128.830381027920708,190.173702516526191,43.1130460407029],"hsluv":[128.830381027920708,99.9999999999908908,43.1130460407029]},"#007722":{"lch":[43.2245297597171856,61.038201507507992,131.028383581415682],"luv":[43.2245297597171856,-40.0674788501528809,46.0462721820529381],"rgb":[0,0.466666666666666674,0.133333333333333331],"xyz":[0.0688523926793974,0.133085547537814014,0.0371934475078286239],"hpluv":[131.028383581415682,179.188765673473426,43.2245297597171856],"hsluv":[131.028383581415682,99.9999999999909193,43.2245297597171856]},"#007733":{"lch":[43.4071769639209251,55.6324991773261601,135.049443606961],"luv":[43.4071769639209251,-39.3720497464739694,39.3041558041433419],"rgb":[0,0.466666666666666674,0.2],"xyz":[0.0719401434118551314,0.134320647830797113,0.0534556013654397671],"hpluv":[135.049443606961,162.632131787412106,43.4071769639209251],"hsluv":[135.049443606961,99.9999999999909193,43.4071769639209251]},"#007744":{"lch":[43.6689123670523855,48.8909209361139787,141.845848120172377],"luv":[43.6689123670523855,-38.4454486392046704,30.2038015639029105],"rgb":[0,0.466666666666666674,0.266666666666666663],"xyz":[0.076398138656074,0.136103845928484707,0.0769343763183264],"hpluv":[141.845848120172377,142.067640978907804,43.6689123670523855],"hsluv":[141.845848120172377,99.9999999999910614,43.6689123670523855]},"#007755":{"lch":[44.0154249216106,41.9153980271179,152.953344682219807],"luv":[44.0154249216106,-37.3313854656975224,19.0595973457790286],"rgb":[0,0.466666666666666674,0.333333333333333315],"xyz":[0.082360552695436,0.13848881154422954,0.108336423592300321],"hpluv":[152.953344682219807,120.839250305189026,44.0154249216106],"hsluv":[152.953344682219807,99.9999999999912461,44.0154249216106]},"#007766":{"lch":[44.4505333250062549,36.6388362985735725,170.062665906075836],"luv":[44.4505333250062549,-36.0891470448365865,6.32279929223085357],"rgb":[0,0.466666666666666674,0.4],"xyz":[0.0899455484689441753,0.141522809853632831,0.148284067999444269],"hpluv":[170.062665906075836,104.593337643625588,44.4505333250062549],"hsluv":[170.062665906075836,99.9999999999913314,44.4505333250062549]},"#007777":{"lch":[44.9764013416840669,35.58350047386471,192.17705063006116],"luv":[44.9764013416840669,-34.7828880940388601,-7.50574458738768],"rgb":[0,0.466666666666666674,0.466666666666666674],"xyz":[0.0992595614891461,0.145248415061713654,0.197337869905842178],"hpluv":[192.17705063006116,100.392967527320835,44.9764013416840669],"hsluv":[192.17705063006116,99.9999999999914451,44.9764013416840669]},"#007788":{"lch":[45.5937085159301603,40.0276538709377,213.25546015720218],"luv":[45.5937085159301603,-33.4724811425817,-21.9500815618326577],"rgb":[0,0.466666666666666674,0.533333333333333326],"xyz":[0.110399978591089923,0.149704581902491252,0.256010733309414373],"hpluv":[213.25546015720218,111.402399127386914,45.5937085159301603],"hsluv":[213.25546015720218,99.9999999999916156,45.5937085159301603]},"#007799":{"lch":[46.3018156057360244,48.7595612734022907,228.659125647543163],"luv":[46.3018156057360244,-32.2075160625452597,-36.6083422822662357],"rgb":[0,0.466666666666666674,0.6],"xyz":[0.123456942700162636,0.154927367546120409,0.324777410950532253],"hpluv":[228.659125647543163,133.62911578541167,46.3018156057360244],"hsluv":[228.659125647543163,99.9999999999917577,46.3018156057360244]},"#0077aa":{"lch":[47.0989379645613795,59.8445186957143,238.773531847525192],"luv":[47.0989379645613795,-31.0247207616125031,-51.1745358511991597],"rgb":[0,0.466666666666666674,0.66666666666666663],"xyz":[0.138514635665415164,0.160950444732221504,0.404081260567530853],"hpluv":[238.773531847525192,161.232500989130415,47.0989379645613795],"hsluv":[238.773531847525192,99.999999999991914,47.0989379645613795]},"#0077bb":{"lch":[47.9823278818304146,71.9659744020705432,245.408717039049918],"luv":[47.9823278818304146,-29.9480972873728,-65.4386196408934495],"rgb":[0,0.466666666666666674,0.733333333333333282],"xyz":[0.155652227772751839,0.167805481575156262,0.4943392456661726],"hpluv":[245.408717039049918,190.32034768447943,47.9823278818304146],"hsluv":[245.408717039049918,99.9999999999920561,47.9823278818304146]},"#0077cc":{"lch":[48.9484610491917067,84.4081580704908276,249.9122747909542],"luv":[48.9484610491917067,-28.9906993044602252,-79.2734287305105454],"rgb":[0,0.466666666666666674,0.8],"xyz":[0.174944603216473565,0.175522431752645064,0.595945756336442756],"hpluv":[249.9122747909542,218.818838178067409,48.9484610491917067],"hsluv":[249.9122747909542,99.9999999999922125,48.9484610491917067]},"#0077dd":{"lch":[49.9932200675849,96.8017840095652389,253.089738624096071],"luv":[49.9932200675849,-28.15707849035525,-92.6162206005108715],"rgb":[0,0.466666666666666674,0.866666666666666696],"xyz":[0.196462928767107109,0.184129761972898598,0.709275604236448753],"hpluv":[253.089738624096071,245.70363248193695,49.9932200675849],"hsluv":[253.089738624096071,99.9999999999921272,49.9932200675849]},"#0077ee":{"lch":[51.1120678627821547,108.963279527823246,255.411176145550684],"luv":[51.1120678627821547,-27.4457353077348785,-105.450120430828804],"rgb":[0,0.466666666666666674,0.933333333333333348],"xyz":[0.220275109033281846,0.193654634079368643,0.834686420304972],"hpluv":[255.411176145550684,270.517920771775039,51.1120678627821547],"hsluv":[255.411176145550684,99.9999999999922551,51.1120678627821547]},"#0077ff":{"lch":[52.300205122294,120.810007187166491,257.158195690943],"luv":[52.300205122294,-26.851223719183885,-117.788240590245493],"rgb":[0,0.466666666666666674,1],"xyz":[0.24644615744311324,0.204123053443301339,0.972520608596753822],"hpluv":[257.158195690943,293.11554041762389,52.300205122294],"hsluv":[257.158195690943,99.9999999999991189,52.300205122294]},"#008800":{"lch":[49.0166039301270473,75.8637069146273291,127.71501294924046],"luv":[49.0166039301270473,-46.4084346679225348,60.0129920808956214],"rgb":[0,0.533333333333333326,0],"xyz":[0.0880377387662537,0.176075477532509878,0.0293459129220837445],"hpluv":[127.71501294924046,196.394882900214583,49.0166039301270473],"hsluv":[127.71501294924046,100.000000000002359,49.0166039301270473]},"#008811":{"lch":[49.066374048408079,74.1307167522113133,128.546257021813432],"luv":[49.066374048408079,-46.1942790787678064,57.9780281364371461],"rgb":[0,0.533333333333333326,0.0666666666666666657],"xyz":[0.0890494042658908219,0.17648014373236473,0.0346740178868393742],"hpluv":[128.546257021813432,191.713881645209739,49.066374048408079],"hsluv":[128.546257021813432,99.9999999999908908,49.066374048408079]},"#008822":{"lch":[49.1584337135343503,71.0276132120671,130.159311596065152],"luv":[49.1584337135343503,-45.8067815452400779,54.2831521106656112],"rgb":[0,0.533333333333333326,0.133333333333333331],"xyz":[0.090924762404367851,0.177230286987755559,0.0445509040828185737],"hpluv":[130.159311596065152,183.344763498744726,49.1584337135343503],"hsluv":[130.159311596065152,99.9999999999909335,49.1584337135343503]},"#008833":{"lch":[49.3094443496477197,66.226384742663825,133.033255321350083],"luv":[49.3094443496477197,-45.1943905199784481,48.4086882864121648],"rgb":[0,0.533333333333333326,0.2],"xyz":[0.0940125131368255845,0.178465387280738658,0.060813057940429717],"hpluv":[133.033255321350083,170.427732437953466,49.3094443496477197],"hsluv":[133.033255321350083,99.9999999999909903,49.3094443496477197]},"#008844":{"lch":[49.5262444349700388,59.9709063982634589,137.708745518338219],"luv":[49.5262444349700388,-44.3625073014275202,40.3543995143041],"rgb":[0,0.533333333333333326,0.266666666666666663],"xyz":[0.0984705083810444581,0.180248585378426252,0.0842918328933163485],"hpluv":[137.708745518338219,153.654237765673173,49.5262444349700388],"hsluv":[137.708745518338219,99.9999999999910756,49.5262444349700388]},"#008855":{"lch":[49.8139833497656355,52.876539169604392,145.043769270071607],"luv":[49.8139833497656355,-43.3370811793054074,30.2956397756013871],"rgb":[0,0.533333333333333326,0.333333333333333315],"xyz":[0.104432922420406457,0.182633550994171084,0.115693880167290264],"hpluv":[145.043769270071607,134.694876863850226,49.8139833497656355],"hsluv":[145.043769270071607,99.9999999999911893,49.8139833497656355]},"#008866":{"lch":[50.1764284055384593,46.0546718070978613,156.264738854980266],"luv":[50.1764284055384593,-42.1591397878491918,18.5375221539472825],"rgb":[0,0.533333333333333326,0.4],"xyz":[0.112017918193914628,0.185667549303574375,0.155641524574434226],"hpluv":[156.264738854980266,116.469784961641182,50.1764284055384593],"hsluv":[156.264738854980266,99.9999999999912461,50.1764284055384593]},"#008877":{"lch":[50.6161324463586766,41.2412500498738694,172.391379993232761],"luv":[50.6161324463586766,-40.8781468825216336,5.46056893805106114],"rgb":[0,0.533333333333333326,0.466666666666666674],"xyz":[0.121331931214116548,0.189393154511655198,0.204695326480832135],"hpluv":[172.391379993232761,103.390869865470918,50.6161324463586766],"hsluv":[172.391379993232761,99.9999999999913456,50.6161324463586766]},"#008888":{"lch":[51.1345503085294695,40.4555776108317602,192.177050630061132],"luv":[51.1345503085294695,-39.545345738280993,-8.53342781453345],"rgb":[0,0.533333333333333326,0.533333333333333326],"xyz":[0.132472348316060362,0.193849321352432796,0.263368189884404302],"hpluv":[192.177050630061132,100.392967527320849,51.1345503085294695],"hsluv":[192.177050630061132,99.9999999999914877,51.1345503085294695]},"#008899":{"lch":[51.7321394091786715,44.6308971675799881,211.11913642158629],"luv":[51.7321394091786715,-38.208266400248,-23.066108485628412],"rgb":[0,0.533333333333333326,0.6],"xyz":[0.145529312425133089,0.199072106996061954,0.332134867525522237],"hpluv":[211.11913642158629,109.474886689832829,51.7321394091786715],"hsluv":[211.11913642158629,99.999999999991573,51.7321394091786715]},"#0088aa":{"lch":[52.4084594351014914,52.8385448128107598,225.694192047300788],"luv":[52.4084594351014914,-36.9070805124816346,-37.8124215831333572],"rgb":[0,0.533333333333333326,0.66666666666666663],"xyz":[0.160587005390385618,0.205095184182163048,0.411438717142520782],"hpluv":[225.694192047300788,127.934825585488483,52.4084594351014914],"hsluv":[225.694192047300788,99.9999999999917,52.4084594351014914]},"#0088bb":{"lch":[53.1622766119302952,63.4852929684367,235.812153399491365],"luv":[53.1622766119302952,-35.672889398211332,-52.5150205681309856],"rgb":[0,0.533333333333333326,0.733333333333333282],"xyz":[0.177724597497722292,0.211950221025097807,0.501696702241162584],"hpluv":[235.812153399491365,151.533580059798538,53.1622766119302952],"hsluv":[235.812153399491365,99.9999999999918572,53.1622766119302952]},"#0088cc":{"lch":[53.9916730817088961,75.3609801883338406,242.731381598031476],"luv":[53.9916730817088961,-34.5275961267233455,-66.9859868976812578],"rgb":[0,0.533333333333333326,0.8],"xyz":[0.197016972941444019,0.219667171202586609,0.60330321291143274],"hpluv":[242.731381598031476,177.116523654060018,53.9916730817088961],"hsluv":[242.731381598031476,99.9999999999919282,53.9916730817088961]},"#0088dd":{"lch":[54.894159312243417,87.7409205251226,247.565131731451658],"luv":[54.894159312243417,-33.4848266090853,-81.1001573460580545],"rgb":[0,0.533333333333333326,0.866666666666666696],"xyz":[0.218535298492077562,0.228274501422840143,0.716633060811438738],"hpluv":[247.565131731451658,202.822146488853946,54.894159312243417],"hsluv":[247.565131731451658,99.9999999999921414,54.894159312243417]},"#0088ee":{"lch":[55.8667862779657725,100.217939448335898,251.046181944553609],"luv":[55.8667862779657725,-32.551381555669181,-94.7841914355319091],"rgb":[0,0.533333333333333326,0.933333333333333348],"xyz":[0.242347478758252299,0.237799373529310187,0.842043876879962],"hpluv":[251.046181944553609,227.630842720065772,55.8667862779657725],"hsluv":[251.046181944553609,99.9999999999923261,55.8667862779657725]},"#0088ff":{"lch":[56.9062538959811803,112.568622459607909,253.628629682131134],"luv":[56.9062538959811803,-31.728824885135996,-108.00452043253614],"rgb":[0,0.533333333333333326,1],"xyz":[0.268518527168083665,0.248267792893242883,0.979878065171743806],"hpluv":[253.628629682131134,251.013269675548315,56.9062538959811803],"hsluv":[253.628629682131134,99.9999999999989,56.9062538959811803]},"#009900":{"lch":[54.8465256129575778,84.8867610313905629,127.71501294924046],"luv":[54.8465256129575778,-51.9281467214630865,67.1507987776363677],"rgb":[0,0.6,0],"xyz":[0.11390733921872119,0.227814678437445572,0.037969113072906],"hpluv":[127.71501294924046,196.394882900214611,54.8465256129575778],"hsluv":[127.71501294924046,100.000000000002359,54.8465256129575778]},"#009911":{"lch":[54.8884489227774139,83.3822613920475533,128.355135015114286],"luv":[54.8884489227774139,-51.7415219578455918,65.3866685214771195],"rgb":[0,0.6,0.0666666666666666657],"xyz":[0.114919004718358309,0.228219344637300425,0.0432972180376616292],"hpluv":[128.355135015114286,192.766711025891595,54.8884489227774139],"hsluv":[128.355135015114286,99.9999999999908908,54.8884489227774139]},"#009922":{"lch":[54.9660326693047665,80.6666974094322882,129.584419925030318],"luv":[54.9660326693047665,-51.4019848556742147,62.168738316310943],"rgb":[0,0.6,0.133333333333333331],"xyz":[0.116794362856835338,0.228969487892691254,0.0531741042336408287],"hpluv":[129.584419925030318,186.225526863887183,54.9660326693047665],"hsluv":[129.584419925030318,99.9999999999908766,54.9660326693047665]},"#009933":{"lch":[55.0934048637144826,76.4021664793699529,131.735569901926],"luv":[55.0934048637144826,-50.8604445821364948,57.0132109221080725],"rgb":[0,0.6,0.2],"xyz":[0.119882113589293071,0.230204588185674353,0.0694362580912519789],"hpluv":[131.735569901926,175.972736191316358,55.0934048637144826],"hsluv":[131.735569901926,99.9999999999909903,55.0934048637144826]},"#009944":{"lch":[55.2764995203901321,70.6973886175228614,135.142608572152881],"luv":[55.2764995203901321,-50.1148739946869739,49.8660221176072795],"rgb":[0,0.6,0.266666666666666663],"xyz":[0.124340108833511945,0.231987786283361946,0.0929150330441386174],"hpluv":[135.142608572152881,162.293888564466016,55.2764995203901321],"hsluv":[135.142608572152881,99.9999999999910472,55.2764995203901321]},"#009955":{"lch":[55.5199214835444792,63.9084670453141044,140.311824754994205],"luv":[55.5199214835444792,-49.1795700812718,40.8125231602173173],"rgb":[0,0.6,0.333333333333333315],"xyz":[0.130302522872873944,0.234372751899106779,0.124317080318112519],"hpluv":[140.311824754994205,146.065915008593578,55.5199214835444792],"hsluv":[140.311824754994205,99.999999999991033,55.5199214835444792]},"#009966":{"lch":[55.8272121342916847,56.7002292022714229,147.995210176352344],"luv":[55.8272121342916847,-48.0820094218291771,30.0505634148387166],"rgb":[0,0.6,0.4],"xyz":[0.137887518646382129,0.23740675020851007,0.164264724725256495],"hpluv":[147.995210176352344,128.877825594911201,55.8272121342916847],"hsluv":[147.995210176352344,99.9999999999911893,55.8272121342916847]},"#009977":{"lch":[56.2009899164422393,50.1460500452165832,159.138923639260469],"luv":[56.2009899164422393,-46.85880632633,17.8571723631952],"rgb":[0,0.6,0.466666666666666674],"xyz":[0.147201531666584035,0.241132355416590893,0.213318526631654404],"hpluv":[159.138923639260469,113.222330796973324,56.2009899164422393],"hsluv":[159.138923639260469,99.9999999999912887,56.2009899164422393]},"#009988":{"lch":[56.6430401241061077,45.7780774967248476,174.293450088826631],"luv":[56.6430401241061077,-45.5512109338885409,4.55187453172192669],"rgb":[0,0.6,0.533333333333333326],"xyz":[0.158341948768527863,0.245588522257368491,0.271991390035226543],"hpluv":[174.293450088826631,102.553461073272217,56.6430401241061077],"hsluv":[174.293450088826631,99.9999999999913456,56.6430401241061077]},"#009999":{"lch":[57.1543844255405133,45.2182256610376498,192.177050630061132],"luv":[57.1543844255405133,-44.2008363998384866,-9.53802880511673301],"rgb":[0,0.6,0.6],"xyz":[0.171398912877600562,0.250811307900997649,0.340758067676344478],"hpluv":[192.177050630061132,100.392967527320849,57.1543844255405133],"hsluv":[192.177050630061132,99.9999999999914877,57.1543844255405133]},"#0099aa":{"lch":[57.7353441317496,49.1617433665336065,209.362441333496832],"luv":[57.7353441317496,-42.8462007667450138,-24.1056028900479831],"rgb":[0,0.6,0.66666666666666663],"xyz":[0.186456605842853118,0.256834385087098771,0.420061917293343079],"hpluv":[209.362441333496832,108.050017888493571,57.7353441317496],"hsluv":[209.362441333496832,99.9999999999915872,57.7353441317496]},"#0099bb":{"lch":[58.3856036871333686,56.8846197873520509,223.121526867409756],"luv":[58.3856036871333686,-41.5203973647636531,-38.8833713947714656],"rgb":[0,0.6,0.733333333333333282],"xyz":[0.203594197950189765,0.26368942193003353,0.51031990239198477],"hpluv":[223.121526867409756,123.631292939903787,58.3856036871333686],"hsluv":[223.121526867409756,99.9999999999917151,58.3856036871333686]},"#0099cc":{"lch":[59.1042769117952531,67.0724902608298237,233.123241992210865],"luv":[59.1042769117952531,-40.2499186561976856,-53.6531732328907225],"rgb":[0,0.6,0.8],"xyz":[0.222886573393911491,0.271406372107522331,0.611926413062254926],"hpluv":[233.123241992210865,144.000781521109104,59.1042769117952531],"hsluv":[233.123241992210865,99.9999999999918572,59.1042769117952531]},"#0099dd":{"lch":[59.889976295668248,78.6325369214165448,240.220044999287609],"luv":[59.889976295668248,-39.0544489896310338,-68.2482664747921888],"rgb":[0,0.6,0.866666666666666696],"xyz":[0.244404898944545035,0.280013702327775837,0.725256260962260924],"hpluv":[240.220044999287609,166.60478591483178,59.889976295668248],"hsluv":[240.220044999287609,99.9999999999918288,59.889976295668248]},"#0099ee":{"lch":[60.7408843834734853,90.8542474807105549,245.312254820906361],"luv":[60.7408843834734853,-37.9473430473261288,-82.5499451298106521],"rgb":[0,0.6,0.933333333333333348],"xyz":[0.2682170792107198,0.289538574434245854,0.850667077030784147],"hpluv":[245.312254820906361,189.803165481490907,60.7408843834734853],"hsluv":[245.312254820906361,99.9999999999919424,60.7408843834734853]},"#0099ff":{"lch":[61.6548256470178444,103.309645725501895,249.051296659176671],"luv":[61.6548256470178444,-36.936501733242423,-96.4809708680364082],"rgb":[0,0.6,1],"xyz":[0.294388127620551165,0.300006993798178578,0.988501265322566],"hpluv":[249.051296659176671,212.624411607996194,61.6548256470178444],"hsluv":[249.051296659176671,99.9999999999986926,61.6548256470178444]},"#44aa00":{"lch":[61.6346835386869714,87.655425968627469,122.331376925101353],"luv":[61.6346835386869714,-46.8794507107122556,74.0661245293922],"rgb":[0.266666666666666663,0.66666666666666663,0],"xyz":[0.167579386406696784,0.29977360690638849,0.0490310792412290836],"hpluv":[122.331376925101353,180.464989524422549,61.6346835386869714],"hsluv":[122.331376925101353,100.00000000000226,61.6346835386869714]},"#44aa11":{"lch":[61.6696010074672927,86.3319887480293175,122.80087722620695],"luv":[61.6696010074672927,-46.7678581574140253,72.5670705248452492],"rgb":[0.266666666666666663,0.66666666666666663,0.0666666666666666657],"xyz":[0.168591051906333916,0.300178273106243343,0.0543591842059847133],"hpluv":[122.80087722620695,177.639660035048053,61.6696010074672927],"hsluv":[122.80087722620695,97.7717273205757778,61.6696010074672927]},"#44aa22":{"lch":[61.7342457720645541,83.9245562706402097,123.699102784065559],"luv":[61.7342457720645541,-46.5639790081192,69.8221097085679],"rgb":[0.266666666666666663,0.66666666666666663,0.133333333333333331],"xyz":[0.170466410044810918,0.300928416361634143,0.0642360704019639128],"hpluv":[123.699102784065559,172.505216938407472,61.7342457720645541],"hsluv":[123.699102784065559,93.6968530578778882,61.7342457720645541]},"#44aa33":{"lch":[61.8404488118369784,80.0901636841586111,125.261260913590505],"luv":[61.8404488118369784,-46.2365065380172098,65.3958697634278],"rgb":[0.266666666666666663,0.66666666666666663,0.2],"xyz":[0.173554160777268651,0.30216351665461727,0.080498224259575063],"hpluv":[125.261260913590505,164.340980941234676,61.8404488118369784],"hsluv":[125.261260913590505,87.1410828818075913,61.8404488118369784]},"#44aa44":{"lch":[61.9932720073472,74.8379874444649573,127.71501294923992],"luv":[61.9932720073472,-45.7809668449718501,59.2015830825281526],"rgb":[0.266666666666666663,0.66666666666666663,0.266666666666666663],"xyz":[0.178012156021487539,0.303946714752304836,0.103976999212461702],"hpluv":[127.71501294923992,153.185220958209158,61.9932720073472],"hsluv":[127.71501294923992,77.998580561819125,61.9932720073472]},"#44aa55":{"lch":[62.1967362447927883,68.3415808764166854,131.40733952388851],"luv":[62.1967362447927883,-45.2016647888952292,51.2579864704043118],"rgb":[0.266666666666666663,0.66666666666666663,0.333333333333333315],"xyz":[0.183974570060849552,0.306331680368049697,0.135379046486435617],"hpluv":[131.40733952388851,139.430168232009549,62.1967362447927883],"hsluv":[131.40733952388851,78.575415606985473,62.1967362447927883]},"#44aa66":{"lch":[62.4540496972210377,60.9745995384144,136.885019691281769],"luv":[62.4540496972210377,-44.510458035487396,41.6739836629655684],"rgb":[0.266666666666666663,0.66666666666666663,0.4],"xyz":[0.191559565834357709,0.309365678677453,0.175326690893579551],"hpluv":[136.885019691281769,123.88755407265441,62.4540496972210377],"hsluv":[136.885019691281769,79.2669246679894854,62.4540496972210377]},"#44aa77":{"lch":[62.7677273349888196,53.3862032124370103,144.988299459670287],"luv":[62.7677273349888196,-43.7251633677153,30.629998072253084],"rgb":[0.266666666666666663,0.66666666666666663,0.466666666666666674],"xyz":[0.200873578854559642,0.313091283885533811,0.22438049279997746],"hpluv":[144.988299459670287,107.927460302012818,62.7677273349888196],"hsluv":[144.988299459670287,80.0573307147673603,62.7677273349888196]},"#44aa88":{"lch":[63.1396635168947142,46.6323085826041606,156.819414130132799],"luv":[63.1396635168947142,-42.8676249510766354,18.3558964585511255],"rgb":[0.266666666666666663,0.66666666666666663,0.533333333333333326],"xyz":[0.212013995956503443,0.317547450726311409,0.283053356203549655],"hpluv":[156.819414130132799,93.7182088199909,63.1396635168947142],"hsluv":[156.819414130132799,80.9270306732118456,63.1396635168947142]},"#44aa99":{"lch":[63.5711832083111,42.2713825005608328,173.059905511526438],"luv":[63.5711832083111,-41.9616613239929848,5.10771548142927578],"rgb":[0.266666666666666663,0.66666666666666663,0.6],"xyz":[0.22507096006557617,0.322770236369940566,0.351820033844667535],"hpluv":[173.059905511526438,84.3772726773670598,63.5711832083111],"hsluv":[173.059905511526438,81.8544924931781281,63.5711832083111]},"#44aaaa":{"lch":[64.0630839897801536,41.9755778813547948,192.177050630061],"luv":[64.0630839897801536,-41.03114670244819,-8.85404646225986802],"rgb":[0.266666666666666663,0.66666666666666663,0.66666666666666663],"xyz":[0.240128653030828698,0.328793313556041689,0.431123883461666135],"hpluv":[192.177050630061,83.1434743556685731,64.0630839897801536],"hsluv":[192.177050630061,82.8180264051213868,64.0630839897801536]},"#44aabb":{"lch":[64.6156750410269893,46.3675567205894481,210.140689328835606],"luv":[64.6156750410269893,-40.0984334486196374,-23.2823098339426302],"rgb":[0.266666666666666663,0.66666666666666663,0.733333333333333282],"xyz":[0.257266245138165373,0.335648350398976447,0.521381868560307882],"hpluv":[210.140689328835606,91.0574853549996135,64.6156750410269893],"hsluv":[210.140689328835606,83.7972417316187,64.6156750410269893]},"#44aacc":{"lch":[65.2288162125558131,54.5527176111565382,224.088695054270687],"luv":[65.2288162125558131,-39.1832309762682058,-37.956203827872514],"rgb":[0.266666666666666663,0.66666666666666663,0.8],"xyz":[0.276558620581887071,0.343365300576465249,0.622988379230578],"hpluv":[224.088695054270687,106.124637545316332,65.2288162125558131],"hsluv":[224.088695054270687,84.7740840933985424,65.2288162125558131]},"#44aadd":{"lch":[65.9019585504415772,65.1392687949415574,233.984713087438024],"luv":[65.9019585504415772,-38.3019605797345406,-52.6885581021924381],"rgb":[0.266666666666666663,0.66666666666666663,0.866666666666666696],"xyz":[0.29807694613252067,0.351972630796718755,0.736318227130584],"hpluv":[233.984713087438024,125.424934833645892,65.9019585504415772],"hsluv":[233.984713087438024,85.7334354760652246,65.9019585504415772]},"#44aaee":{"lch":[66.634186587349916,77.0517400481588,240.904642753345257],"luv":[66.634186587349916,-37.4675316968449081,-67.3287064556787698],"rgb":[0.266666666666666663,0.66666666666666663,0.933333333333333348],"xyz":[0.32188912639869538,0.361497502903188772,0.861729043199107259],"hpluv":[240.904642753345257,146.73194579095005,66.634186587349916],"hsluv":[240.904642753345257,86.6633273618325717,66.634186587349916]},"#44aaff":{"lch":[67.4242620727880677,89.6163291450103827,245.832487512483851],"luv":[67.4242620727880677,-36.6894434071527229,-81.7616731231704534],"rgb":[0.266666666666666663,0.66666666666666663,1],"xyz":[0.348060174808526801,0.371965922267121496,0.999563231490889104],"hpluv":[245.832487512483851,168.659292786049974,67.4242620727880677],"hsluv":[245.832487512483851,99.9999999999982094,67.4242620727880677]},"#44bb00":{"lch":[67.1028050092269126,96.9162111575721497,123.392710981560953],"luv":[67.1028050092269126,-53.3402140179528601,80.9170782570533476],"rgb":[0.266666666666666663,0.733333333333333282,0],"xyz":[0.201533884315295564,0.367682602723587049,0.0603492452107617],"hpluv":[123.392710981560953,183.271561122122193,67.1028050092269126],"hsluv":[123.392710981560953,100.00000000000226,67.1028050092269126]},"#44bb11":{"lch":[67.1332810832727347,95.7453830613523138,123.778355355208646],"luv":[67.1332810832727347,-53.2326764896654581,79.5830417319651673],"rgb":[0.266666666666666663,0.733333333333333282,0.0666666666666666657],"xyz":[0.202545549814932696,0.368087268923441902,0.0656773501755173322],"hpluv":[123.778355355208646,180.975295348072393,67.1332810832727347],"hsluv":[123.778355355208646,98.1806384027583334,67.1332810832727347]},"#44bb22":{"lch":[67.1897165718252438,93.6085464076245728,124.511290753684577],"luv":[67.1897165718252438,-53.03566579282883,77.1348048189646391],"rgb":[0.266666666666666663,0.733333333333333282,0.133333333333333331],"xyz":[0.204420907953409697,0.368837412178832702,0.0755542363714965248],"hpluv":[124.511290753684577,176.787689053856155,67.1897165718252438],"hsluv":[124.511290753684577,94.8452524510698538,67.1897165718252438]},"#44bb33":{"lch":[67.2824703298360873,90.1849869824975627,125.771296969252688],"luv":[67.2824703298360873,-52.7177504009765485,73.1721987485246501],"rgb":[0.266666666666666663,0.733333333333333282,0.2],"xyz":[0.207508658685867431,0.370072512471815829,0.091816390229107675],"hpluv":[125.771296969252688,170.087205132927863,67.2824703298360873],"hsluv":[125.771296969252688,89.4565739304913308,67.2824703298360873]},"#44bb44":{"lch":[67.4160218575577375,85.4495691526201284,127.715012949240077],"luv":[67.4160218575577375,-52.2724357759646807,67.5960156105081182],"rgb":[0.266666666666666663,0.733333333333333282,0.266666666666666663],"xyz":[0.211966653930086318,0.371855710569503395,0.115295165181994314],"hpluv":[127.715012949240077,160.837043785954393,67.4160218575577375],"hsluv":[127.715012949240077,81.8947222100884318,67.4160218575577375]},"#44bb55":{"lch":[67.5939766620447813,79.5000401119176,130.566112214394138],"luv":[67.5939766620447813,-51.7008659583180759,60.3926886051327756],"rgb":[0.266666666666666663,0.733333333333333282,0.333333333333333315],"xyz":[0.217929067969448331,0.374240676185248256,0.146697212455968229],"hpluv":[130.566112214394138,149.244617358403957,67.5939766620447813],"hsluv":[130.566112214394138,82.2871698148834412,67.5939766620447813]},"#44bb66":{"lch":[67.8192698910356313,72.5749222232247,134.657948179728322],"luv":[67.8192698910356313,-51.0109407747319139,51.6236695420221778],"rgb":[0.266666666666666663,0.733333333333333282,0.4],"xyz":[0.225514063742956489,0.377274674494651574,0.186644856863112191],"hpluv":[134.657948179728322,135.791565604529097,67.8192698910356313],"hsluv":[134.657948179728322,82.7624878443234451,67.8192698910356313]},"#44bb77":{"lch":[68.0942730594189527,65.0902087481164671,140.487577627549143],"luv":[68.0942730594189527,-50.2162275054035163,41.4133525568618168],"rgb":[0.266666666666666663,0.733333333333333282,0.466666666666666674],"xyz":[0.234828076763158422,0.38100027970273237,0.2356986587695101],"hpluv":[140.487577627549143,121.295420087000366,68.0942730594189527],"hsluv":[140.487577627549143,83.3123735080707206,68.0942730594189527]},"#44bb88":{"lch":[68.4208577329380461,57.7058903955470939,148.752185803016886],"luv":[68.4208577329380461,-49.3345927236295907,29.9343907092910229],"rgb":[0.266666666666666663,0.733333333333333282,0.533333333333333326],"xyz":[0.245968493865102222,0.385456446543509967,0.294371522173082267],"hpluv":[148.752185803016886,107.021481540968693,68.4208577329380461],"hsluv":[148.752185803016886,83.9257037652282776,68.4208577329380461]},"#44bb99":{"lch":[68.8004384509552267,51.4171630403873507,160.23039633414129],"luv":[68.8004384509552267,-48.3866530594068536,17.3912754227620781],"rgb":[0.266666666666666663,0.733333333333333282,0.6],"xyz":[0.259025457974175,0.390679232187139125,0.363138199814200147],"hpluv":[160.23039633414129,94.8322885243955,68.8004384509552267],"hsluv":[160.23039633414129,84.5895330052649683,68.8004384509552267]},"#44bbaa":{"lch":[69.2340056114394571,47.5630236168925,175.171204236910796],"luv":[69.2340056114394571,-47.3942071553531576,4.003791165451279],"rgb":[0.266666666666666663,0.733333333333333282,0.66666666666666663],"xyz":[0.274083150939427478,0.396702309373240247,0.442442049431198747],"hpluv":[175.171204236910796,87.1744714415039113,69.2340056114394571],"hsluv":[175.171204236910796,85.2901010545764251,69.2340056114394571]},"#44bbbb":{"lch":[69.722153945093,47.4463312905994243,192.177050630061103],"luv":[69.722153945093,-46.3788106784417877,-10.0080104411700219],"rgb":[0.266666666666666663,0.733333333333333282,0.733333333333333282],"xyz":[0.291220743046764152,0.403557346216175,0.532700034529840494],"hpluv":[192.177050630061103,86.3517549054621156,69.722153945093],"hsluv":[192.177050630061103,86.0137488036252,69.722153945093]},"#44bbcc":{"lch":[70.265109629848,51.5238495855336254,208.311647260201596],"luv":[70.265109629848,-45.3606162241423405,-24.4360711219862],"rgb":[0.266666666666666663,0.733333333333333282,0.8],"xyz":[0.310513118490485907,0.411274296393663807,0.63430654520011065],"hpluv":[208.311647260201596,93.0481841100277478,70.265109629848],"hsluv":[208.311647260201596,86.7476639801695484,70.265109629848]},"#44bbdd":{"lch":[70.8627576511434683,59.1258582536945,221.390354970453018],"luv":[70.8627576511434683,-44.357542252504274,-39.0931651258026491],"rgb":[0.266666666666666663,0.733333333333333282,0.866666666666666696],"xyz":[0.332031444041119395,0.419881626613917314,0.747636393100116647],"hpluv":[221.390354970453018,105.876295000483495,70.8627576511434683],"hsluv":[221.390354970453018,87.4804162985680449,70.8627576511434683]},"#44bbee":{"lch":[71.5146701379092207,69.1277260896420813,231.126492355228834],"luv":[71.5146701379092207,-43.3847784652122499,-53.8182451576511269],"rgb":[0.266666666666666663,0.733333333333333282,0.933333333333333348],"xyz":[0.35584362430729416,0.429406498720387331,0.873047209168639871],"hpluv":[231.126492355228834,122.65816352572412,71.5146701379092207],"hsluv":[231.126492355228834,88.202277385306985,71.5146701379092207]},"#44bbff":{"lch":[72.2201358507708,80.5712163793027685,238.202407995552562],"luv":[72.2201358507708,-42.4545914747530801,-68.4786723845625573],"rgb":[0.266666666666666663,0.733333333333333282,1],"xyz":[0.382014672717125525,0.439874918084320055,1.01088139746042183],"hpluv":[238.202407995552562,141.566646923483631,72.2201358507708],"hsluv":[238.202407995552562,99.9999999999976694,72.2201358507708]},"#44cc00":{"lch":[72.503692055952385,105.959797206167082,124.178253965335855],"luv":[72.503692055952385,-59.5249745926526543,87.6598883396283384],"rgb":[0.266666666666666663,0.8,0],"xyz":[0.239757627624912484,0.444130089342821943,0.0730904929806336506],"hpluv":[124.178253965335855,185.447217969921951,72.503692055952385],"hsluv":[124.178253965335855,100.000000000002359,72.503692055952385]},"#44cc11":{"lch":[72.5305637479271752,104.914943747871533,124.498982817725434],"luv":[72.5305637479271752,-59.4229434801529877,86.4642076802510928],"rgb":[0.266666666666666663,0.8,0.0666666666666666657],"xyz":[0.240769293124549616,0.444534755542676796,0.0784185979453892873],"hpluv":[124.498982817725434,183.55052269402043,72.5305637479271752],"hsluv":[124.498982817725434,98.4921383302381628,72.5305637479271752]},"#44cc22":{"lch":[72.5803335982668,103.003123626508128,125.105641856618192],"luv":[72.5803335982668,-59.2356349500081265,84.2661440252673088],"rgb":[0.266666666666666663,0.8,0.133333333333333331],"xyz":[0.242644651263026617,0.445284898798067597,0.0882954841413684799],"hpluv":[125.105641856618192,180.082189217111164,72.5803335982668],"hsluv":[125.105641856618192,95.7225658430248387,72.5803335982668]},"#44cc33":{"lch":[72.6621573160580283,99.9260617146724144,126.139923542820412],"luv":[72.6621573160580283,-58.9323161564504758,80.6982027200153],"rgb":[0.266666666666666663,0.8,0.2],"xyz":[0.245732401995484351,0.446519999091050723,0.10455763799897963],"hpluv":[126.139923542820412,174.505777504147545,72.6621573160580283],"hsluv":[126.139923542820412,91.233607132201584,72.6621573160580283]},"#44cc44":{"lch":[72.780026014363628,95.6382843785450518,127.715012949240148],"luv":[72.780026014363628,-58.5052227586060383,75.6559339961998],"rgb":[0.266666666666666663,0.8,0.266666666666666663],"xyz":[0.250190397239703266,0.448303197188738289,0.128036412951866269],"hpluv":[127.715012949240148,166.747333178852926,72.780026014363628],"hsluv":[127.715012949240148,84.9041129363740339,72.780026014363628]},"#44cc55":{"lch":[72.9371837422115732,90.1892610669535912,129.983942971096695],"luv":[72.9371837422115732,-57.9531752136704,69.1052262456084492],"rgb":[0.266666666666666663,0.8,0.333333333333333315],"xyz":[0.256152811279065251,0.45068816280448315,0.159438460225840184],"hpluv":[129.983942971096695,156.908028239254975,72.9371837422115732],"hsluv":[129.983942971096695,85.1779272269293557,72.9371837422115732]},"#44cc66":{"lch":[73.1363103507417236,83.732792729713168,133.164212643981188],"luv":[73.1363103507417236,-57.28090462038152,61.074368962666],"rgb":[0.266666666666666663,0.8,0.4],"xyz":[0.263737807052573436,0.453722161113886469,0.199386104632984118],"hpluv":[133.164212643981188,145.278670258241675,73.1363103507417236],"hsluv":[133.164212643981188,85.5122241677148764,73.1363103507417236]},"#44cc77":{"lch":[73.3796177536812309,76.5464624175537,137.569101073773794],"luv":[73.3796177536812309,-56.4983001604517625,51.6459387330839],"rgb":[0.266666666666666663,0.8,0.466666666666666674],"xyz":[0.273051820072775342,0.457447766321967264,0.248439906539382027],"hpluv":[137.569101073773794,132.369828459728325,73.3796177536812309],"hsluv":[137.569101073773794,85.9026534082125153,73.3796177536812309]},"#44cc88":{"lch":[73.6689069899719442,69.0664605730878378,143.639563525196422],"luv":[73.6689069899719442,-55.6194534086204087,40.9469459010095278],"rgb":[0.266666666666666663,0.8,0.533333333333333326],"xyz":[0.284192237174719142,0.461903933162744862,0.307112769942954222],"hpluv":[143.639563525196422,118.965846887396481,73.6689069899719442],"hsluv":[143.639563525196422,86.3428682965135863,73.6689069899719442]},"#44cc99":{"lch":[74.0056056952011,61.9424628035573548,151.940118655705163],"luv":[74.0056056952011,-54.661526046940331,29.1373689338922652],"rgb":[0.266666666666666663,0.8,0.6],"xyz":[0.297249201283791842,0.467126718806374,0.375879447584072102],"hpluv":[151.940118655705163,106.209454381597496,74.0056056952011],"hsluv":[151.940118655705163,86.8250568088678,74.0056056952011]},"#44ccaa":{"lch":[74.3907954563299256,56.0938540204294327,163.002493202880316],"luv":[74.3907954563299256,-53.6435329798001206,16.3979214631106132],"rgb":[0.266666666666666663,0.8,0.66666666666666663],"xyz":[0.312306894249044398,0.473149795992475142,0.455183297201070702],"hpluv":[163.002493202880316,95.6831366692641581,74.3907954563299256],"hsluv":[163.002493202880316,87.3405106459777727,74.3907954563299256]},"#44ccbb":{"lch":[74.8252340948823331,52.6660587979454959,176.823724318960615],"luv":[74.8252340948823331,-52.5851528012588929,2.91812511330579927],"rgb":[0.266666666666666663,0.8,0.733333333333333282],"xyz":[0.329444486356381072,0.4800048328354099,0.545441282299712449],"hpluv":[176.823724318960615,89.3145186414393493,74.8252340948823331],"hsluv":[176.823724318960615,87.8801809558037235,74.8252340948823331]},"#44cccc":{"lch":[75.3093757141467393,52.6911947618550442,192.177050630061103],"luv":[75.3093757141467393,-51.5056671360628826,-11.1143267137884898],"rgb":[0.266666666666666663,0.8,0.8],"xyz":[0.348736861800102771,0.487721783012898702,0.647047792969982605],"hpluv":[192.177050630061103,88.7826952764381758,75.3093757141467393],"hsluv":[192.177050630061103,88.4351737608208168,75.3093757141467393]},"#44ccdd":{"lch":[75.8433901234223669,56.5143539908888,206.846753698803184],"luv":[75.8433901234223669,-50.423101427505074,-25.5222069860548118],"rgb":[0.266666666666666663,0.8,0.866666666666666696],"xyz":[0.37025518735073637,0.496329113233152208,0.760377640869988602],"hpluv":[206.846753698803184,94.5540981724771257,75.8433901234223669],"hsluv":[206.846753698803184,88.9971515077065334,75.8433901234223669]},"#44ccee":{"lch":[76.4271825186181104,63.6191993934700264,219.125479385679029],"luv":[76.4271825186181104,-49.3536035237008,-40.1450414209705926],"rgb":[0.266666666666666663,0.8,0.933333333333333348],"xyz":[0.39406736761691108,0.505853985339622225,0.885788456938511826],"hpluv":[219.125479385679029,108.248092211119214,76.4271825186181104],"hsluv":[219.125479385679029,89.5586239337052,76.4271825186181104]},"#44ccff":{"lch":[77.0604138316104752,73.087044724203011,228.6232677289035],"luv":[77.0604138316104752,-48.3110621928290342,-54.8430248647743426],"rgb":[0.266666666666666663,0.8,1],"xyz":[0.420238416026742501,0.516322404703555,1.02362264523029367],"hpluv":[228.6232677289035,128.526456918779161,77.0604138316104752],"hsluv":[228.6232677289035,99.9999999999969731,77.0604138316104752]},"#44dd00":{"lch":[77.8394471675691193,114.806757868746558,124.774603647715026],"luv":[77.8394471675691193,-65.4799812263264869,94.3025116894186],"rgb":[0.266666666666666663,0.866666666666666696,0],"xyz":[0.282391618172087688,0.529398070437173462,0.0873018231630249691],"hpluv":[124.774603647715026,210.465861771712326,77.8394471675691193],"hsluv":[124.774603647715026,100.000000000002174,77.8394471675691193]},"#44dd11":{"lch":[77.8633510332093692,113.867279553553601,125.04447057905567],"luv":[77.8633510332093692,-65.3839645843072503,93.2238946202376724],"rgb":[0.266666666666666663,0.866666666666666696,0.0666666666666666657],"xyz":[0.283403283671724793,0.529802736637028371,0.0926299281277806],"hpluv":[125.04447057905567,209.014039294370775,77.8633510332093692],"hsluv":[125.04447057905567,98.7339197526847272,77.8633510332093692]},"#44dd22":{"lch":[77.9076302523257738,112.144788460185168,125.553114236235714],"luv":[77.9076302523257738,-65.2074178024426914,91.2384033306006472],"rgb":[0.266666666666666663,0.866666666666666696,0.133333333333333331],"xyz":[0.28527864181020185,0.530552879892419171,0.102506814323759798],"hpluv":[125.553114236235714,206.347170822894697,77.9076302523257738],"hsluv":[125.553114236235714,96.4050109160080382,77.9076302523257738]},"#44dd33":{"lch":[77.9804445180848802,109.362510567887881,126.41495586461761],"luv":[77.9804445180848802,-64.9207541848309546,88.0082632130877869],"rgb":[0.266666666666666663,0.866666666666666696,0.2],"xyz":[0.288366392542659555,0.531787980185402298,0.118768968181370949],"hpluv":[126.41495586461761,202.025685311970193,77.9804445180848802],"hsluv":[126.41495586461761,92.6208241654068729,77.9804445180848802]},"#44dd44":{"lch":[78.0853727898892345,105.463232003770898,127.715012949240119],"luv":[78.0853727898892345,-64.5154806081751389,83.428089194092081],"rgb":[0.266666666666666663,0.866666666666666696,0.266666666666666663],"xyz":[0.292824387786878471,0.533571178283089864,0.142247743134257587],"hpluv":[127.715012949240119,195.940425098340825,78.0853727898892345],"hsluv":[127.715012949240119,87.2650912217990395,78.0853727898892345]},"#44dd55":{"lch":[78.2253459168282888,100.46502238820301,129.562971792001804],"luv":[78.2253459168282888,-63.9887749627021662,77.4510000079714303],"rgb":[0.266666666666666663,0.866666666666666696,0.333333333333333315],"xyz":[0.298786801826240456,0.535956143898834614,0.173649790408231475],"hpluv":[129.562971792001804,188.090878204767051,78.2253459168282888],"hsluv":[129.562971792001804,87.4605090914447,78.2253459168282888]},"#44dd66":{"lch":[78.4028117957757615,94.4661355921174,132.108441056441876],"luv":[78.4028117957757615,-63.3429373931831776,70.0822592109557],"rgb":[0.266666666666666663,0.866666666666666696,0.4],"xyz":[0.306371797599748641,0.538990142208237932,0.213597434815375464],"hpluv":[132.108441056441876,178.59774401526758,78.4028117957757615],"hsluv":[132.108441056441876,87.7006053461373654,78.4028117957757615]},"#44dd77":{"lch":[78.6198227824069278,87.656024220764337,135.559861003190832],"luv":[78.6198227824069278,-62.584854150819659,61.3735660778470375],"rgb":[0.266666666666666663,0.866666666666666696,0.466666666666666674],"xyz":[0.315685810619950546,0.542715747416318783,0.262651236721773373],"hpluv":[135.559861003190832,167.73117312681623,78.6198227824069278],"hsluv":[135.559861003190832,87.9831439767702221,78.6198227824069278]},"#44dd88":{"lch":[78.8780874692010201,80.3346414261830404,140.206181380764804],"luv":[78.8780874692010201,-61.7253288138421823,51.416324216113189],"rgb":[0.266666666666666663,0.866666666666666696,0.533333333333333326],"xyz":[0.326826227721894347,0.547171914257096326,0.321324100125345513],"hpluv":[140.206181380764804,155.961921377148798,78.8780874692010201],"hsluv":[140.206181380764804,88.3044935606717729,78.8780874692010201]},"#44dd99":{"lch":[79.1790042342924,72.9438114093828602,146.430978952194238],"luv":[79.1790042342924,-60.7782665628728651,40.3336328210091182],"rgb":[0.266666666666666663,0.866666666666666696,0.6],"xyz":[0.339883191830967046,0.552394699900725539,0.390090777766463448],"hpluv":[146.430978952194238,144.047423549525234,79.1790042342924],"hsluv":[146.430978952194238,88.6599152631773109,79.1790042342924]},"#44ddaa":{"lch":[79.5236849812282,66.109750002698334,154.681927012774025],"luv":[79.5236849812282,-59.7597565852220498,28.2713731236083063],"rgb":[0.266666666666666663,0.866666666666666696,0.66666666666666663],"xyz":[0.354940884796219602,0.558417777086826606,0.469394627383462049],"hpluv":[154.681927012774025,133.15854000611057,79.5236849812282],"hsluv":[154.681927012774025,89.0438856180527267,79.5236849812282]},"#44ddbb":{"lch":[79.9129735834354733,60.6712530747818448,165.306614809553963],"luv":[79.9129735834354733,-58.687123678359157,15.3890371376899697],"rgb":[0.266666666666666663,0.866666666666666696,0.733333333333333282],"xyz":[0.372078476903556277,0.565272813929761364,0.55965261248210374],"hpluv":[165.306614809553963,125.005338667233715,79.9129735834354733],"hsluv":[165.306614809553963,89.4504295982059574,79.9129735834354733]},"#44ddcc":{"lch":[80.3474616163736783,57.6077690930220925,178.158710030216184],"luv":[80.3474616163736783,-57.5780241737671616,1.85099760130491053],"rgb":[0.266666666666666663,0.866666666666666696,0.8],"xyz":[0.391370852347278,0.572989764107250221,0.661259123152373895],"hpluv":[178.158710030216184,121.786592068950441,80.3474616163736783],"hsluv":[178.158710030216184,89.8734379183952399,80.3474616163736783]},"#44dddd":{"lch":[80.8275029051271758,57.7489755309586,192.177050630061132],"luv":[80.8275029051271758,-56.4496501662069505,-12.1811810177875159],"rgb":[0.266666666666666663,0.866666666666666696,0.866666666666666696],"xyz":[0.412889177897911575,0.581597094327503727,0.774588971052379893],"hpluv":[192.177050630061132,125.674721736272474,80.8275029051271758],"hsluv":[192.177050630061132,90.3069463225795204,80.8275029051271758]},"#44ddee":{"lch":[81.3532277894993143,61.361693698739991,205.642938459455962],"luv":[81.3532277894993143,-55.3180860243278758,-26.5549771640468073],"rgb":[0.266666666666666663,0.866666666666666696,0.933333333333333348],"xyz":[0.436701358164086284,0.591121966433973745,0.899999787120903116],"hpluv":[205.642938459455962,137.939634766348263,81.3532277894993143],"hsluv":[205.642938459455962,90.7453615563817806,81.3532277894993143]},"#44ddff":{"lch":[81.9245576129038113,68.0382655080336463,217.195369709248553],"luv":[81.9245576129038113,-54.1978382178125813,-41.1314953029609],"rgb":[0.266666666666666663,0.866666666666666696,1],"xyz":[0.462872406573917705,0.601590385797906468,1.03783397541268507],"hpluv":[217.195369709248553,158.576151866946,81.9245576129038113],"hsluv":[217.195369709248553,99.9999999999957367,81.9245576129038113]},"#44ee00":{"lch":[83.112739541513335,123.476763986331008,125.23710114083579],"luv":[83.112739541513335,-71.241317589729718,100.852297507867192],"rgb":[0.266666666666666663,0.933333333333333348,0],"xyz":[0.329570394512602505,0.623755623118204428,0.103028081943196154],"hpluv":[125.23710114083579,311.240798427125753,83.112739541513335],"hsluv":[125.23710114083579,100.000000000002402,83.112739541513335]},"#44ee11":{"lch":[83.1341682891089135,122.626446998812852,125.466600012922257],"luv":[83.1341682891089135,-71.1513320296005674,99.8735873690646656],"rgb":[0.266666666666666663,0.933333333333333348,0.0666666666666666657],"xyz":[0.330582060012239609,0.624160289318059336,0.10835618690795179],"hpluv":[125.466600012922257,309.547675363147619,83.1341682891089135],"hsluv":[125.466600012922257,98.9247180409442279,83.1341682891089135]},"#44ee22":{"lch":[83.1738669889620184,121.064908518289769,125.897986234483838],"luv":[83.1738669889620184,-70.9856689153146192,98.0701120789979],"rgb":[0.266666666666666663,0.933333333333333348,0.133333333333333331],"xyz":[0.332457418150716666,0.624910432573450136,0.118233073103930983],"hpluv":[125.897986234483838,306.432309176179558,83.1738669889620184],"hsluv":[125.897986234483838,96.9444732717922,83.1738669889620184]},"#44ee33":{"lch":[83.2391611795664517,118.535427876706891,126.625494433478437],"luv":[83.2391611795664517,-70.7161072615436694,95.1308563805026921],"rgb":[0.266666666666666663,0.933333333333333348,0.2],"xyz":[0.335545168883174372,0.626145532866433263,0.134495226961542119],"hpluv":[126.625494433478437,301.369067751793693,83.2391611795664517],"hsluv":[126.625494433478437,93.7204451717133651,83.2391611795664517]},"#44ee44":{"lch":[83.3332795320092714,114.974418092600288,127.715012949240275],"luv":[83.3332795320092714,-70.3337997514069855,90.9520391649414],"rgb":[0.266666666666666663,0.933333333333333348,0.266666666666666663],"xyz":[0.340003164127393287,0.627928730964120829,0.157974001914428758],"hpluv":[127.715012949240275,294.205765091151079,83.3332795320092714],"hsluv":[127.715012949240275,89.1439564147074321,83.3332795320092714]},"#44ee55":{"lch":[83.4588814464859183,110.379279114867671,129.248151137931956],"luv":[83.4588814464859183,-69.8347997913980123,85.479155330485213],"rgb":[0.266666666666666663,0.933333333333333348,0.333333333333333315],"xyz":[0.345965578166755272,0.630313696579865579,0.189376049188402673],"hpluv":[129.248151137931956,284.901382538762221,83.4588814464859183],"hsluv":[129.248151137931956,89.2862876088480419,83.4588814464859183]},"#44ee66":{"lch":[83.6182069813856,104.810737833959209,131.33226272314829],"luv":[83.6182069813856,-69.2195888954281,78.7015837099029],"rgb":[0.266666666666666663,0.933333333333333348,0.4],"xyz":[0.353550573940263457,0.633347694889268897,0.229323693595546635],"hpluv":[131.33226272314829,273.53562680177663,83.6182069813856],"hsluv":[131.33226272314829,89.462046779026835,83.6182069813856]},"#44ee77":{"lch":[83.8131566406418642,98.3993759238413759,134.112401675041724],"luv":[83.8131566406418642,-68.4926783274834889,70.6483559449852123],"rgb":[0.266666666666666663,0.933333333333333348,0.466666666666666674],"xyz":[0.362864586960465363,0.637073300097349748,0.278377495501944572],"hpluv":[134.112401675041724,260.333399951005049,83.8131566406418642],"hsluv":[134.112401675041724,89.6701381262035682,83.8131566406418642]},"#44ee88":{"lch":[84.045338735079568,91.3569443918750892,137.785521400150031],"luv":[84.045338735079568,-67.6621349200187439,61.3834406553211949],"rgb":[0.266666666666666663,0.933333333333333348,0.533333333333333326],"xyz":[0.374005004062409163,0.641529466938127291,0.337050358905516712],"hpluv":[137.785521400150031,245.709311488591595,84.045338735079568],"hsluv":[137.785521400150031,89.9084899734552323,84.045338735079568]},"#44ee99":{"lch":[84.3160998906388386,83.9946679616676306,142.613931790318958],"luv":[84.3160998906388386,-66.738995210465,51.0001055321292895],"rgb":[0.266666666666666663,0.933333333333333348,0.6],"xyz":[0.387061968171481863,0.646752252581756504,0.405817036546634591],"hpluv":[142.613931790318958,230.343048149298568,84.3160998906388386],"hsluv":[142.613931790318958,90.1742147406472725,84.3160998906388386]},"#44eeaa":{"lch":[84.626546237332235,76.7502660373389887,148.925817786423067],"luv":[84.626546237332235,-65.7365837009088239,39.6144531722415607],"rgb":[0.266666666666666663,0.933333333333333348,0.66666666666666663],"xyz":[0.402119661136734419,0.652775329767857571,0.485120886163633247],"hpluv":[148.925817786423067,215.298316825794302,84.626546237332235],"hsluv":[148.925817786423067,90.4637941794664897,84.626546237332235]},"#44eebb":{"lch":[84.9775593290447,70.218708007349818,157.069253127653155],"luv":[84.9775593290447,-64.6697768267590618,27.3584889823731068],"rgb":[0.266666666666666663,0.933333333333333348,0.733333333333333282],"xyz":[0.419257253244071093,0.659630366610792329,0.575378871262274938],"hpluv":[157.069253127653155,202.183693696822303,84.9775593290447],"hsluv":[157.069253127653155,90.7732788992861401,84.9775593290447]},"#44eecc":{"lch":[85.3698091329633826,65.1592886039499462,167.256585364158155],"luv":[85.3698091329633826,-63.5542641697608914,14.3731832665241086],"rgb":[0.266666666666666663,0.933333333333333348,0.8],"xyz":[0.438549628687792792,0.667347316788281186,0.676985381932545094],"hpluv":[167.256585364158155,193.290067765431047,85.3698091329633826],"hsluv":[167.256585364158155,91.0984884260964,85.3698091329633826]},"#44eedd":{"lch":[85.803765500838054,62.4110099600490216,179.263728091065275],"luv":[85.803765500838054,-62.4058570040272613,0.801982435119061421],"rgb":[0.266666666666666663,0.933333333333333348,0.866666666666666696],"xyz":[0.460067954238426391,0.675954647008534693,0.790315229832551092],"hpluv":[179.263728091065275,191.499842549603557,85.803765500838054],"hsluv":[179.263728091065275,91.4351983708881875,85.803765500838054]},"#44eeee":{"lch":[86.2797089909746546,62.6494691870182407,192.17705063006116],"luv":[86.2797089909746546,-61.2398849709435922,-13.2148582346064085],"rgb":[0.266666666666666663,0.933333333333333348,0.933333333333333348],"xyz":[0.4838801345046011,0.68547951911500471,0.915726045901074315],"hpluv":[192.17705063006116,199.700166684316315,86.2797089909746546],"hsluv":[192.17705063006116,91.7793037580661775,86.2797089909746546]},"#44eeff":{"lch":[86.7977415696122847,66.0848691943621134,204.633388514668525],"luv":[86.7977415696122847,-60.0707080483631159,-27.5448719547627086],"rgb":[0.266666666666666663,0.933333333333333348,1],"xyz":[0.510051182914432522,0.695947938478937433,1.05356023419285627],"hpluv":[204.633388514668525,219.870556477974674,86.7977415696122847],"hsluv":[204.633388514668525,99.9999999999936904,86.7977415696122847]},"#44ff00":{"lch":[88.3264513606833,131.987460278186802,125.602389702763816],"luv":[88.3264513606833,-76.837408418496949,107.315899745634312],"rgb":[0.266666666666666663,1,0],"xyz":[0.381422766942276337,0.727460367977553535,0.120312206086420265],"hpluv":[125.602389702763816,502.990651378155178,88.3264513606833],"hsluv":[125.602389702763816,100.000000000002331,88.3264513606833]},"#44ff11":{"lch":[88.3457924202418496,131.213348009411362,125.799444038401859],"luv":[88.3457924202418496,-76.7532223203665609,106.423143908077066],"rgb":[0.266666666666666663,1,0.0666666666666666657],"xyz":[0.382434432441913441,0.727865034177408443,0.125640311051175901],"hpluv":[125.799444038401859,500.950310911531346,88.3457924202418496],"hsluv":[125.799444038401859,99.9999999999917577,88.3457924202418496]},"#44ff22":{"lch":[88.3816266358799538,129.789896608084,126.169061428897493],"luv":[88.3816266358799538,-76.5980824061806089,104.776672180562713],"rgb":[0.266666666666666663,1,0.133333333333333331],"xyz":[0.384309790580390498,0.728615177432799244,0.13551719724715508],"hpluv":[126.169061428897493,497.190929074143924,88.3816266358799538],"hsluv":[126.169061428897493,99.9999999999915445,88.3816266358799538]},"#44ff33":{"lch":[88.4405736189592204,127.478814054469,126.790121098902588],"luv":[88.4405736189592204,-76.3452168675528071,102.089450454884],"rgb":[0.266666666666666663,1,0.2],"xyz":[0.387397541312848204,0.72985027772578237,0.15177935110476623],"hpluv":[126.790121098902588,491.06642972530841,88.4405736189592204],"hsluv":[126.790121098902588,99.9999999999916,88.4405736189592204]},"#44ff44":{"lch":[88.5255621746627099,124.213522374992053,127.715012949240247],"luv":[88.5255621746627099,-75.9856771103925,98.2607552122302],"rgb":[0.266666666666666663,1,0.266666666666666663],"xyz":[0.391855536557067119,0.731633475823469936,0.175258126057652869],"hpluv":[127.715012949240247,482.369437382385513,88.5255621746627099],"hsluv":[127.715012949240247,99.9999999999915872,88.5255621746627099]},"#44ff55":{"lch":[88.6390158335401,119.977757557138,129.006344472088813],"luv":[88.6390158335401,-75.5147735105559832,93.2318684253877734],"rgb":[0.266666666666666663,1,0.333333333333333315],"xyz":[0.397817950596429104,0.734018441439214686,0.206660173331626784],"hpluv":[129.006344472088813,471.012302242813519,88.6390158335401],"hsluv":[129.006344472088813,99.9999999999916724,88.6390158335401]},"#44ff66":{"lch":[88.7829895920100256,114.806361082699226,130.743859599912923],"luv":[88.7829895920100256,-74.9316504675157518,86.9813100801842438],"rgb":[0.266666666666666663,1,0.4],"xyz":[0.405402946369937289,0.737052439748618,0.246607817738770746],"hpluv":[130.743859599912923,457.03528250903878,88.7829895920100256],"hsluv":[130.743859599912923,99.999999999991374,88.7829895920100256]},"#44ff77":{"lch":[88.9592430558717524,108.789243130847709,133.032335199193767],"luv":[88.9592430558717524,-74.2389756563468239,79.5215311376676226],"rgb":[0.266666666666666663,1,0.466666666666666674],"xyz":[0.414716959390139195,0.740778044956698856,0.295661619645168683],"hpluv":[133.032335199193767,440.631455855157412,88.9592430558717524],"hsluv":[133.032335199193767,99.999999999991374,88.9592430558717524]},"#44ff88":{"lch":[89.1692840038805343,102.078340317719523,136.01097660716411],"luv":[89.1692840038805343,-73.4425963051882462,70.8955048643657904],"rgb":[0.266666666666666663,1,0.533333333333333326],"xyz":[0.425857376492083,0.745234211797476398,0.354334483048740823],"hpluv":[136.01097660716411,422.1930512248951,89.1692840038805343],"hsluv":[136.01097660716411,99.9999999999912177,89.1692840038805343]},"#44ff99":{"lch":[89.4143964062191117,94.8987049380611438,139.863519733640288],"luv":[89.4143964062191117,-72.5511163277215303,61.1727040314764139],"rgb":[0.266666666666666663,1,0.6],"xyz":[0.43891434060115575,0.750456997441105611,0.423101160689858702],"hpluv":[139.863519733640288,402.3908266141122,89.4143964062191117],"hsluv":[139.863519733640288,99.9999999999912,89.4143964062191117]},"#44ffaa":{"lch":[89.695659684091666,87.5652599917726207,144.82485232612342],"luv":[89.695659684091666,-71.5753927145854192,50.4444042008586777],"rgb":[0.266666666666666663,1,0.66666666666666663],"xyz":[0.453972033566408251,0.756480074627206678,0.502405010306857358],"hpluv":[144.82485232612342,382.304282325397367,89.695659684091666],"hsluv":[144.82485232612342,99.9999999999909335,89.695659684091666]},"#44ffbb":{"lch":[90.0139628620153616,80.5050918065685153,151.171682460988421],"luv":[90.0139628620153616,-70.527972915407986,38.8184858440859557],"rgb":[0.266666666666666663,1,0.733333333333333282],"xyz":[0.471109625673744925,0.763335111470141436,0.592662995405499],"hpluv":[151.171682460988421,363.621116250194575,90.0139628620153616],"hsluv":[151.171682460988421,99.999999999990834,90.0139628620153616]},"#44ffcc":{"lch":[90.3700157308713443,74.2777558665274853,159.169074542576084],"luv":[90.3700157308713443,-69.4225064855060481,26.4140229771485018],"rgb":[0.266666666666666663,1,0.8],"xyz":[0.490402001117466679,0.771052061647630294,0.694269506075769205],"hpluv":[159.169074542576084,348.900804743837909,90.3700157308713443],"hsluv":[159.169074542576084,99.9999999999905924,90.3700157308713443]},"#44ffdd":{"lch":[90.7643583149998,69.56728840997188,168.931262835156701],"luv":[90.7643583149998,-68.2731674827513899,13.3559806299794577],"rgb":[0.266666666666666663,1,0.866666666666666696],"xyz":[0.511920326668100167,0.7796593918678838,0.807599353975775203],"hpluv":[168.931262835156701,341.810509676969502,90.7643583149998],"hsluv":[168.931262835156701,99.9999999999902798,90.7643583149998]},"#44ffee":{"lch":[91.1973694573754869,67.0945142582603182,180.196137266844971],"luv":[91.1973694573754869,-67.094121132442,-0.229680249688981986],"rgb":[0.266666666666666663,1,0.933333333333333348],"xyz":[0.535732506934274877,0.789184263974353817,0.933010170044298426],"hpluv":[180.196137266844971,347.079488330816218,91.1973694573754869],"hsluv":[180.196137266844971,99.999999999989825,91.1973694573754869]},"#44ffff":{"lch":[91.6692750397398726,67.4158875874256,192.177050630061103],"luv":[91.6692750397398726,-65.8990611515587261,-14.2202545175369188],"rgb":[0.266666666666666663,1,1],"xyz":[0.561903555344106298,0.799652683338286541,1.07084435833608027],"hpluv":[192.177050630061103,369.886157390881351,91.6692750397398726],"hsluv":[192.177050630061103,99.9999999999897,91.6692750397398726]},"#33aa00":{"lch":[61.1785977172963129,90.1064171712311435,124.683940112874311],"luv":[61.1785977172963129,-51.2749716142469723,74.09482911373847],"rgb":[0.2,0.66666666666666663,0],"xyz":[0.157393059993970491,0.294521282349826385,0.0485535951906325494],"hpluv":[124.683940112874311,186.894073454811917,61.1785977172963129],"hsluv":[124.683940112874311,100.000000000002302,61.1785977172963129]},"#33aa11":{"lch":[61.2139288108167818,88.7849168066190089,125.171000261233829],"luv":[61.2139288108167818,-51.1417680861379793,72.5760360544852148],"rgb":[0.2,0.66666666666666663,0.0666666666666666657],"xyz":[0.158404725493607623,0.294925948549681238,0.0538817001553881791],"hpluv":[125.171000261233829,184.046797309440706,61.2139288108167818],"hsluv":[125.171000261233829,97.729263879491441,61.2139288108167818]},"#33aa22":{"lch":[61.2793378507832642,86.3832953662584657,126.10140218084841],"luv":[61.2793378507832642,-50.8984310656693708,69.7955831939783593],"rgb":[0.2,0.66666666666666663,0.133333333333333331],"xyz":[0.160280083632084625,0.295676091805072039,0.0637585863513673717],"hpluv":[126.10140218084841,178.877217305585333,61.2793378507832642],"hsluv":[126.10140218084841,93.5778090815338146,61.2793378507832642]},"#33aa33":{"lch":[61.3867923044640946,82.5646745763668548,127.715012949240119],"luv":[61.3867923044640946,-50.5076466968263134,65.3138814728533],"rgb":[0.2,0.66666666666666663,0.2],"xyz":[0.163367834364542386,0.296911192098055166,0.0800207402089785219],"hpluv":[127.715012949240119,170.670578118814461,61.3867923044640946],"hsluv":[127.715012949240119,86.9017438736093339,61.3867923044640946]},"#33aa44":{"lch":[61.5414071550205364,77.3485744588317488,130.237764523164799],"luv":[61.5414071550205364,-49.9641607354037305,59.0456146789935588],"rgb":[0.2,0.66666666666666663,0.266666666666666663],"xyz":[0.167825829608761246,0.298694390195742732,0.10349951516186516],"hpluv":[130.237764523164799,159.486606837004757,61.5414071550205364],"hsluv":[130.237764523164799,87.1702267355774723,61.5414071550205364]},"#33aa55":{"lch":[61.7472402279952775,70.9239260559490106,134.00596147156574],"luv":[61.7472402279952775,-49.2732069613111605,51.0132763399638876],"rgb":[0.2,0.66666666666666663,0.333333333333333315],"xyz":[0.173788243648123231,0.301079355811487592,0.134901562435839062],"hpluv":[134.00596147156574,145.752006815371971,61.7472402279952775],"hsluv":[134.00596147156574,87.512567621072165,61.7472402279952775]},"#33aa66":{"lch":[62.0075227235960824,63.6834089970413046,139.532932917076664],"luv":[62.0075227235960824,-48.4490087982300253,41.3312246123130436],"rgb":[0.2,0.66666666666666663,0.4],"xyz":[0.181373239421631416,0.304113354120890911,0.174849206842983024],"hpluv":[139.532932917076664,130.323054003441854,62.0075227235960824],"hsluv":[139.532932917076664,87.9225345315596769,62.0075227235960824]},"#33aa77":{"lch":[62.3247799262656201,56.2910074750267,147.571074265173024],"luv":[62.3247799262656201,-47.5128361285441727,30.1862207898839152],"rgb":[0.2,0.66666666666666663,0.466666666666666674],"xyz":[0.190687252441833321,0.307838959328971706,0.223903008749380933],"hpluv":[147.571074265173024,114.608702125460667,62.3247799262656201],"hsluv":[147.571074265173024,88.3905588997681519,62.3247799262656201]},"#33aa88":{"lch":[62.7009046876535052,49.786919253891476,159.033972270618222],"luv":[62.7009046876535052,-46.4906641824602147,17.8144736848221363],"rgb":[0.2,0.66666666666666663,0.533333333333333326],"xyz":[0.201827669543777177,0.312295126169749304,0.2825758721529531],"hpluv":[159.033972270618222,100.758286424528237,62.7009046876535052],"hsluv":[159.033972270618222,88.9048289963628804,62.7009046876535052]},"#33aa99":{"lch":[63.1372095297142835,45.6309193537352797,174.368717478757389],"luv":[63.1372095297142835,-45.4107033068770818,4.47759156711236095],"rgb":[0.2,0.66666666666666663,0.6],"xyz":[0.214884633652849877,0.317517911813378462,0.351342549794071035],"hpluv":[174.368717478757389,91.7092542399893631,63.1372095297142835],"hsluv":[174.368717478757389,89.4524406674979,63.1372095297142835]},"#33aaaa":{"lch":[63.6344696573538897,45.3208071547743288,192.17705063006116],"luv":[63.6344696573538897,-44.3011098571894,-9.5596666563997],"rgb":[0.2,0.66666666666666663,0.66666666666666663],"xyz":[0.229942326618102433,0.323540988999479584,0.430646399411069636],"hpluv":[192.17705063006116,90.3742140686623117,63.6344696573538897],"hsluv":[192.17705063006116,90.0204628815860559,63.6344696573538897]},"#33aabb":{"lch":[64.1929631055189844,49.4317459506583177,209.109442205543161],"luv":[64.1929631055189844,-43.188124160558381,-24.0475245965695663],"rgb":[0.2,0.66666666666666663,0.733333333333333282],"xyz":[0.247079918725439052,0.330396025842414343,0.520904384509711327],"hpluv":[209.109442205543161,97.7142389408223835,64.1929631055189844],"hsluv":[209.109442205543161,90.5968047396532228,64.1929631055189844]},"#33aacc":{"lch":[64.8125111239688181,57.2242456540803062,222.641155468482083],"luv":[64.8125111239688181,-42.0947673064025736,-38.7639633693247347],"rgb":[0.2,0.66666666666666663,0.8],"xyz":[0.266372294169160806,0.338112976019903144,0.622510895179981483],"hpluv":[222.641155468482083,112.036763534802631,64.8125111239688181],"hsluv":[222.641155468482083,91.1708232266795875,64.8125111239688181]},"#33aadd":{"lch":[65.4925201274692199,67.4454999587780151,232.519386199289158],"luv":[65.4925201274692199,-41.0401119544032653,-53.5220017886062465],"rgb":[0.2,0.66666666666666663,0.866666666666666696],"xyz":[0.28789061971979435,0.34672030624015665,0.73584074307998748],"hpluv":[232.519386199289158,130.67743538587149,65.4925201274692199],"hsluv":[232.519386199289158,91.7336648454097485,65.4925201274692199]},"#33aaee":{"lch":[66.23202547083838,79.0605595482254,239.573325902293959],"luv":[66.23202547083838,-40.039054494753934,-68.1721804788773],"rgb":[0.2,0.66666666666666663,0.933333333333333348],"xyz":[0.311702799985969059,0.356245178346626667,0.861251559148510704],"hpluv":[239.573325902293959,151.471586303299148,66.23202547083838],"hsluv":[239.573325902293959,92.278374899274425,66.23202547083838]},"#33aaff":{"lch":[67.0297366624436,91.3892467801412778,244.667711773110682],"luv":[67.0297366624436,-39.1024682991195291,-82.6014007142609898],"rgb":[0.2,0.66666666666666663,1],"xyz":[0.33787384839580048,0.366713597710559391,0.999085747440292549],"hpluv":[244.667711773110682,173.00828905748071,67.0297366624436],"hsluv":[244.667711773110682,99.9999999999982094,67.0297366624436]},"#33bb00":{"lch":[66.705199456007648,99.1588934495857757,125.274120260315158],"luv":[66.705199456007648,-57.2631629787864327,80.9531735993793262],"rgb":[0.2,0.733333333333333282,0],"xyz":[0.191347557902569271,0.362430278167024944,0.0598717611601651684],"hpluv":[125.274120260315158,188.630237299381349,66.705199456007648],"hsluv":[125.274120260315158,100.000000000002331,66.705199456007648]},"#33bb11":{"lch":[66.7359690986495764,97.9890755357957914,125.670572132139952],"luv":[66.7359690986495764,-57.1397853669544133,79.6046723036925385],"rgb":[0.2,0.733333333333333282,0.0666666666666666657],"xyz":[0.192359223402206403,0.362834944366879797,0.0651998661249208],"hpluv":[125.670572132139952,186.318944611331347,66.7359690986495764],"hsluv":[125.670572132139952,98.1524285745497451,66.7359690986495764]},"#33bb22":{"lch":[66.7929473545782,95.8553977164860243,126.423299967719473],"luv":[66.7929473545782,-56.9137739802675,77.1302768224563],"rgb":[0.2,0.733333333333333282,0.133333333333333331],"xyz":[0.194234581540683404,0.363585087622270597,0.0750767523209],"hpluv":[126.423299967719473,182.106434833594022,66.7929473545782],"hsluv":[126.423299967719473,94.7659081903439073,66.7929473545782]},"#33bb33":{"lch":[66.8865907457163,92.4406335233364302,127.715012949240233],"luv":[66.8865907457163,-56.5491099236273058,73.126389853740946],"rgb":[0.2,0.733333333333333282,0.2],"xyz":[0.197322332273141166,0.364820187915253724,0.0913389061785111478],"hpluv":[127.715012949240233,175.373180985258983,66.8865907457163],"hsluv":[127.715012949240233,89.2962069049265637,66.8865907457163]},"#33bb44":{"lch":[67.0214179407225572,87.725631811763563,129.70178400392939],"luv":[67.0214179407225572,-56.0384119529137763,67.4943172612971409],"rgb":[0.2,0.733333333333333282,0.266666666666666663],"xyz":[0.201780327517360025,0.36660338601294129,0.114817681131397786],"hpluv":[129.70178400392939,166.093340387543549,67.0214179407225572],"hsluv":[129.70178400392939,89.4761749642590871,67.0214179407225572]},"#33bb55":{"lch":[67.2010629421400552,81.8171313208689099,132.60288320444127],"luv":[67.2010629421400552,-55.3830806540106479,60.2225651632978796],"rgb":[0.2,0.733333333333333282,0.333333333333333315],"xyz":[0.207742741556722,0.368988351628686151,0.146219728405371674],"hpluv":[132.60288320444127,154.492511096020365,67.2010629421400552],"hsluv":[132.60288320444127,89.7076242739581,67.2010629421400552]},"#33bb66":{"lch":[67.4284803792762091,74.9653268862145,136.738510871982356],"luv":[67.4284803792762091,-54.5922668909562248,51.3759148907695788],"rgb":[0.2,0.733333333333333282,0.4],"xyz":[0.215327737330230196,0.372022349938089469,0.186167372812515663],"hpluv":[136.738510871982356,141.07705768332076,67.4284803792762091],"hsluv":[136.738510871982356,89.9877463438330096,67.4284803792762091]},"#33bb77":{"lch":[67.7060530794905446,67.5982244112705,142.572908280802977],"luv":[67.7060530794905446,-53.681598162732449,41.0829156980295878],"rgb":[0.2,0.733333333333333282,0.466666666666666674],"xyz":[0.224641750350432101,0.375747955146170265,0.235221174718913573],"hpluv":[142.572908280802977,126.69139486293237,67.7060530794905446],"hsluv":[142.572908280802977,90.3115397167098,67.7060530794905446]},"#33bb88":{"lch":[68.0356563096068641,60.380187227113133,150.730801091974854],"luv":[68.0356563096068641,-52.67158330257773,29.5206931148449],"rgb":[0.2,0.733333333333333282,0.533333333333333326],"xyz":[0.235782167452375957,0.380204121986947863,0.293894038122485712],"hpluv":[150.730801091974854,112.615249481580875,68.0356563096068641],"hsluv":[150.730801091974854,90.6723452470342437,68.0356563096068641]},"#33bb99":{"lch":[68.4187011865960244,54.2829584497859159,161.862695711717],"luv":[68.4187011865960244,-51.585814888834193,16.8980259295610082],"rgb":[0.2,0.733333333333333282,0.6],"xyz":[0.248839131561448657,0.385426907630577,0.362660715763603647],"hpluv":[161.862695711717,100.676477021468287,68.4187011865960244],"hsluv":[161.862695711717,91.0624469223214,68.4187011865960244]},"#33bbaa":{"lch":[68.8561680799326439,50.5661966451060749,176.101011456941364],"luv":[68.8561680799326439,-50.4491601398581224,3.43838397135738649],"rgb":[0.2,0.733333333333333282,0.66666666666666663],"xyz":[0.263896824526701212,0.391449984816678143,0.441964565380602248],"hpluv":[176.101011456941364,93.1873079321678404,68.8561680799326439],"hsluv":[176.101011456941364,91.473675634614068,68.8561680799326439]},"#33bbbb":{"lch":[69.3486356756669835,50.4205674478029,192.177050630061103],"luv":[69.3486356756669835,-49.286127891295429,-10.635375839212843],"rgb":[0.2,0.733333333333333282,0.733333333333333282],"xyz":[0.281034416634037831,0.398305021659612901,0.532222550479243939],"hpluv":[192.177050630061103,92.2590830970113132,69.3486356756669835],"hsluv":[192.177050630061103,91.8979539795913922,69.3486356756669835]},"#33bbcc":{"lch":[69.8963087653012423,54.2786660468549442,207.559867588447844],"luv":[69.8963087653012423,-48.1195504219082224,-25.1133919457216273],"rgb":[0.2,0.733333333333333282,0.8],"xyz":[0.300326792077759586,0.406021971837101703,0.633829061149514095],"hpluv":[207.559867588447844,98.540384199822455,69.8963087653012423],"hsluv":[207.559867588447844,92.3277362004695306,69.8963087653012423]},"#33bbdd":{"lch":[70.4990463576295241,61.569428837921933,220.28187220447964],"luv":[70.4990463576295241,-46.9696505240293618,-39.807618580850594],"rgb":[0.2,0.733333333333333282,0.866666666666666696],"xyz":[0.321845117628393129,0.414629302057355209,0.747158909049520092],"hpluv":[220.28187220447964,110.820781636478685,70.4990463576295241],"hsluv":[220.28187220447964,92.7563200135089119,70.4990463576295241]},"#33bbee":{"lch":[71.1563908243766576,71.2672074810155181,229.953995552192254],"luv":[71.1563908243766576,-45.8534981630350487,-54.557048750410388],"rgb":[0.2,0.733333333333333282,0.933333333333333348],"xyz":[0.345657297894567894,0.424154174163825226,0.872569725118043316],"hpluv":[229.953995552192254,127.091105244163856,71.1563908243766576],"hsluv":[229.953995552192254,93.1780289437208893,71.1563908243766576]},"#33bbff":{"lch":[71.8675982303626597,82.4526478797043296,237.101125866277243],"luv":[71.8675982303626597,-44.7848112977892,-69.2297610814592161],"rgb":[0.2,0.733333333333333282,1],"xyz":[0.37182834630439926,0.43462259352775795,1.01040391340982527],"hpluv":[237.101125866277243,145.583046200088774,71.8675982303626597],"hsluv":[237.101125866277243,99.9999999999977831,71.8675982303626597]},"#33cc00":{"lch":[72.1534232831706532,108.011475964841438,125.713046635977918],"luv":[72.1534232831706532,-63.0491190384013507,87.6999859098336287],"rgb":[0.2,0.8,0],"xyz":[0.229571301212186191,0.438877764786259839,0.0726130089300371234],"hpluv":[125.713046635977918,189.955680955455,72.1534232831706532],"hsluv":[125.713046635977918,100.000000000002402,72.1534232831706532]},"#33cc11":{"lch":[72.1805088449519,106.967132064598133,126.040754358939225],"luv":[72.1805088449519,-62.9352412435677095,86.493483868665578],"rgb":[0.2,0.8,0.0666666666666666657],"xyz":[0.230582966711823323,0.439282430986114691,0.0779411138947927601],"hpluv":[126.040754358939225,188.048441784684599,72.1805088449519],"hsluv":[126.040754358939225,98.4728126855506645,72.1805088449519]},"#33cc22":{"lch":[72.2306742907645543,105.057034533260762,126.660198785960176],"luv":[72.2306742907645543,-62.7261976516662614,84.2757653960309199],"rgb":[0.2,0.8,0.133333333333333331],"xyz":[0.232458324850300324,0.440032574241505492,0.0878180000907719527],"hpluv":[126.660198785960176,184.562215611711281,72.2306742907645543],"hsluv":[126.660198785960176,95.6680740449206866,72.2306742907645543]},"#33cc33":{"lch":[72.31314692234902,101.984984863208481,127.715012949240304],"luv":[72.31314692234902,-62.3877173898115416,80.6765756365369668],"rgb":[0.2,0.8,0.2],"xyz":[0.235546075582758085,0.441267674534488619,0.104080153948383103],"hpluv":[127.715012949240304,178.960959976488198,72.31314692234902],"hsluv":[127.715012949240304,91.1230258822071306,72.31314692234902]},"#33cc44":{"lch":[72.4319472107582669,97.7091257880760651,129.318260791805528],"luv":[72.4319472107582669,-61.9111863445413135,75.5915224590797123],"rgb":[0.2,0.8,0.266666666666666663],"xyz":[0.240004070826976945,0.443050872632176185,0.127558928901269741],"hpluv":[129.318260791805528,171.176559629977817,72.4319472107582669],"hsluv":[129.318260791805528,91.2471619418673612,72.4319472107582669]},"#33cc55":{"lch":[72.590341240881628,92.2844112105744756,131.621023493746776],"luv":[72.590341240881628,-61.2953573189119396,68.9876200751215407],"rgb":[0.2,0.8,0.333333333333333315],"xyz":[0.24596648486633893,0.445435838247921045,0.158960976175243629],"hpluv":[131.621023493746776,161.32023063104279,72.590341240881628],"hsluv":[131.621023493746776,91.4078622695478,72.590341240881628]},"#33cc66":{"lch":[72.7910248315973405,85.8719567505974197,134.835055825888389],"luv":[72.7910248315973405,-60.5455878238572112,60.8951948123993319],"rgb":[0.2,0.8,0.4],"xyz":[0.253551480639847115,0.448469836557324364,0.198908620582387619],"hpluv":[134.835055825888389,149.696915507144809,72.7910248315973405],"hsluv":[134.835055825888389,91.6039613293452533,72.7910248315973405]},"#33cc77":{"lch":[73.0362204241858421,78.757716060864837,139.259917231121676],"luv":[73.0362204241858421,-59.6729854923348,51.3995393126768079],"rgb":[0.2,0.8,0.466666666666666674],"xyz":[0.262865493660049,0.452195441765405159,0.247962422488785528],"hpluv":[139.259917231121676,136.834039856532058,73.0362204241858421],"hsluv":[139.259917231121676,91.8328510325735294,73.0362204241858421]},"#33cc88":{"lch":[73.3277345291399,71.3846311778678597,145.306874573990314],"luv":[73.3277345291399,-58.6933246064594201,40.6307668527313197],"rgb":[0.2,0.8,0.533333333333333326],"xyz":[0.274005910761992877,0.456651608606182757,0.306635285892357667],"hpluv":[145.306874573990314,123.530949311180805,73.3277345291399],"hsluv":[145.306874573990314,92.0907512285691894,73.3277345291399]},"#33cc99":{"lch":[73.6669954969027714,64.400374936046,153.483372150156],"luv":[73.6669954969027714,-57.6257667092137709,28.7520312861295437],"rgb":[0.2,0.8,0.6],"xyz":[0.287062874871065576,0.461874394249811915,0.375401963533475602],"hpluv":[153.483372150156,110.931469165383049,73.6669954969027714],"hsluv":[153.483372150156,92.3730273510429072,73.6669954969027714]},"#33ccaa":{"lch":[74.0550811623464114,58.6991946004706691,164.236139418897579],"luv":[74.0550811623464114,-56.4914910882685106,15.9470022690160835],"rgb":[0.2,0.8,0.66666666666666663],"xyz":[0.302120567836318132,0.467897471435913037,0.454705813150474203],"hpluv":[164.236139418897579,100.581152280716978,74.0550811623464114],"hsluv":[164.236139418897579,92.6745296641919794,74.0550811623464114]},"#33ccbb":{"lch":[74.4927414449451106,55.3647402049724846,177.507530206592946],"luv":[74.4927414449451106,-55.3123621552270137,2.40770653799565881],"rgb":[0.2,0.8,0.733333333333333282],"xyz":[0.319258159943654751,0.474752508278847796,0.544963798249115894],"hpluv":[177.507530206592946,94.310193436061823,74.4927414449451106],"hsluv":[177.507530206592946,92.9899230693886,74.4927414449451106]},"#33cccc":{"lch":[74.9804187561532416,55.3552144916165361,192.177050630061132],"luv":[74.9804187561532416,-54.1097476482840918,-11.6762571422475752],"rgb":[0.2,0.8,0.8],"xyz":[0.338550535387376506,0.482469458456336597,0.646570308919386],"hpluv":[192.177050630061132,93.6806731785530928,74.9804187561532416],"hsluv":[192.177050630061132,93.3139795405001422,74.9804187561532416]},"#33ccdd":{"lch":[75.5182678303382602,59.0031963362726231,206.282454691493683],"luv":[75.5182678303382602,-52.9035678654544128,-26.1264173778571198],"rgb":[0.2,0.8,0.866666666666666696],"xyz":[0.360068860938010049,0.491076788676590104,0.759900156819392],"hpluv":[206.282454691493683,99.1431801932779564,75.5182678303382602],"hsluv":[206.282454691493683,93.6418135046530296,75.5182678303382602]},"#33ccee":{"lch":[76.106175853756767,65.8577115847402439,218.26062431545347],"luv":[76.106175853756767,-51.7116147040808585,-40.7817003063324606],"rgb":[0.2,0.8,0.933333333333333348],"xyz":[0.383881041204184759,0.500601660783060121,0.885310972887915271],"hpluv":[218.26062431545347,110.229350215344013,76.106175853756767],"hsluv":[218.26062431545347,93.969050662624,76.106175853756767]},"#33ccff":{"lch":[76.7437832939395435,75.0714180144803,227.674056146546604],"luv":[76.7437832939395435,-50.5491406549608,-55.5022718611574248],"rgb":[0.2,0.8,1],"xyz":[0.41005208961401618,0.511070080146992844,1.02314516117969712],"hpluv":[227.674056146546604,129.845560156838474,76.7437832939395435],"hsluv":[227.674056146546604,99.9999999999969731,76.7437832939395435]},"#33dd00":{"lch":[77.5280782787270653,116.686614644285086,126.047543424376144],"luv":[77.5280782787270653,-68.6649809221669187,94.3445092843369508],"rgb":[0.2,0.866666666666666696,0],"xyz":[0.272205291759361367,0.524145745880611358,0.0868243391124284419],"hpluv":[126.047543424376144,210.356208283509261,77.5280782787270653],"hsluv":[126.047543424376144,100.000000000002416,77.5280782787270653]},"#33dd11":{"lch":[77.5521415069474926,115.747372453695789,126.322097671746874],"luv":[77.5521415069474926,-68.5599423432795,93.2576459912042],"rgb":[0.2,0.866666666666666696,0.0666666666666666657],"xyz":[0.273216957258998472,0.524550412080466266,0.0921524440771840786],"hpluv":[126.322097671746874,208.932074165120611,77.5521415069474926],"hsluv":[126.322097671746874,98.7203227917640902,77.5521415069474926]},"#33dd22":{"lch":[77.5967156031793337,114.025807364398673,126.839335004613],"luv":[77.5967156031793337,-68.36681588768,91.2571270119929778],"rgb":[0.2,0.866666666666666696,0.133333333333333331],"xyz":[0.275092315397475529,0.525300555335857067,0.102029330273163271],"hpluv":[126.839335004613,206.31706664059891,77.5967156031793337],"hsluv":[126.839335004613,96.3665979525037102,77.5967156031793337]},"#33dd33":{"lch":[77.670013861504259,111.246421345384377,127.715012949240332],"luv":[77.670013861504259,-68.0532561222895,88.0029578668175247],"rgb":[0.2,0.866666666666666696,0.2],"xyz":[0.278180066129933234,0.526535655628840193,0.118291484130774421],"hpluv":[127.715012949240332,202.082466523340599,77.670013861504259],"hsluv":[127.715012949240332,92.5426273046004439,77.670013861504259]},"#33dd44":{"lch":[77.7756375941771267,107.354265763003397,129.034195217585733],"luv":[77.7756375941771267,-67.6100090567609726,83.3895979895470134],"rgb":[0.2,0.866666666666666696,0.266666666666666663],"xyz":[0.28263806137415215,0.52831885372652776,0.14177025908366106],"hpluv":[129.034195217585733,196.125875311323085,77.7756375941771267],"hsluv":[129.034195217585733,92.6304308505642098,77.7756375941771267]},"#33dd55":{"lch":[77.9165348137244,102.370875286307594,130.905664069221132],"luv":[77.9165348137244,-67.0340391276217105,77.3707548439410431],"rgb":[0.2,0.866666666666666696,0.333333333333333315],"xyz":[0.288600475413514135,0.530703819342272509,0.173172306357634975],"hpluv":[130.905664069221132,188.454179514464698,77.9165348137244],"hsluv":[130.905664069221132,92.7446831943234287,77.9165348137244]},"#33dd66":{"lch":[78.095166356878579,96.3992072274516261,133.476315028685519],"luv":[78.095166356878579,-66.3279238591037767,69.9529389705828777],"rgb":[0.2,0.866666666666666696,0.4],"xyz":[0.29618547118702232,0.533737817651675828,0.213119950764778909],"hpluv":[133.476315028685519,179.196222734944627,78.095166356878579],"hsluv":[133.476315028685519,92.8850067954864187,78.095166356878579]},"#33dd77":{"lch":[78.3135937781308513,89.6343875602499196,136.948304354896891],"luv":[78.3135937781308513,-65.499258897229538,61.1896275296294192],"rgb":[0.2,0.866666666666666696,0.466666666666666674],"xyz":[0.305499484207224226,0.537463422859756679,0.262173752671176818],"hpluv":[136.948304354896891,168.630388284117117,78.3135937781308513],"hsluv":[136.948304354896891,93.050064801238122,78.3135937781308513]},"#33dd88":{"lch":[78.5735314106716487,82.3820261839553609,141.59738099104726],"luv":[78.5735314106716487,-64.5599157920348432,51.1743638074698],"rgb":[0.2,0.866666666666666696,0.533333333333333326],"xyz":[0.316639901309168,0.541919589700534221,0.320846616074749],"hpluv":[141.59738099104726,157.233383580683977,78.5735314106716487],"hsluv":[141.59738099104726,93.2377028740416449,78.5735314106716487]},"#33dd99":{"lch":[78.8763801167060592,75.0869406053615762,147.781507566587862],"luv":[78.8763801167060592,-63.5251386535812799,40.0325543591259105],"rgb":[0.2,0.866666666666666696,0.6],"xyz":[0.329696865418240725,0.547142375344163434,0.389613293715866893],"hpluv":[147.781507566587862,145.760006886720333,78.8763801167060592],"hsluv":[147.781507566587862,93.4451205095912343,78.8763801167060592]},"#33ddaa":{"lch":[79.2232512041385633,68.3697583649377094,155.904677195463563],"luv":[79.2232512041385633,-62.4125308872686801,27.9123601138582131],"rgb":[0.2,0.866666666666666696,0.66666666666666663],"xyz":[0.344754558383493281,0.553165452530264501,0.468917143332865494],"hpluv":[155.904677195463563,135.355769729163313,79.2232512041385633],"hsluv":[155.904677195463563,93.6690625743759,79.2232512041385633]},"#33ddbb":{"lch":[79.6149850527770866,63.045401416642612,166.259028854183981],"luv":[79.6149850527770866,-61.2410113290283604,14.9753521221847095],"rgb":[0.2,0.866666666666666696,0.733333333333333282],"xyz":[0.361892150490829956,0.560020489373199259,0.559175128431507296],"hpluv":[166.259028854183981,127.658944712944631,79.6149850527770866],"hsluv":[166.259028854183981,93.9060163408359614,79.6149850527770866]},"#33ddcc":{"lch":[80.0521670478692613,60.0458591823856054,178.675787060338223],"luv":[80.0521670478692613,-60.0298228841068138,1.3876488942262355],"rgb":[0.2,0.866666666666666696,0.8],"xyz":[0.381184525934551655,0.567737439550688117,0.660781639101777452],"hpluv":[178.675787060338223,124.734340702728062,80.0521670478692613],"hsluv":[178.675787060338223,94.1523985056595905,80.0521670478692613]},"#33dddd":{"lch":[80.5351423549551555,60.1510343961145963,192.177050630061245],"luv":[80.5351423549551555,-58.7976638126828,-12.6878551809710149],"rgb":[0.2,0.866666666666666696,0.866666666666666696],"xyz":[0.402702851485185254,0.576344769770941623,0.774111487001783449],"hpluv":[192.177050630061245,128.603021497070955,80.5351423549551555],"hsluv":[192.177050630061245,94.4047190696773271,80.5351423549551555]},"#33ddee":{"lch":[81.0640304387754,63.6213092914002303,205.209077734070348],"luv":[81.0640304387754,-57.5619892131040913,-27.0977562499646396],"rgb":[0.2,0.866666666666666696,0.933333333333333348],"xyz":[0.426515031751359963,0.58586964187741164,0.899522303070306672],"hpluv":[205.209077734070348,140.476637056352985,81.0640304387754],"hsluv":[205.209077734070348,94.6597131799347835,81.0640304387754]},"#33ddff":{"lch":[81.6387398294900208,70.0938175080633528,216.50946924270437],"luv":[81.6387398294900208,-56.3385046754299452,-41.7027114680837769],"rgb":[0.2,0.866666666666666696,1],"xyz":[0.452686080161191384,0.596338061241344364,1.03735649136208852],"hpluv":[216.50946924270437,160.421433033358312,81.6387398294900208],"hsluv":[216.50946924270437,99.999999999996,81.6387398294900208]},"#33ee00":{"lch":[82.833762600699373,125.203353646442437,126.3077634478595],"luv":[82.833762600699373,-74.1357070958390239,100.894879442497455],"rgb":[0.2,0.933333333333333348,0],"xyz":[0.319384068099876184,0.618503298561642323,0.102550597892599626],"hpluv":[126.3077634478595,309.713105305240845,82.833762600699373],"hsluv":[126.3077634478595,100.000000000002302,82.833762600699373]},"#33ee11":{"lch":[82.85531245284119,124.353122892884315,126.540515263097504],"luv":[82.85531245284119,-74.0387382831010541,99.9097813362598544],"rgb":[0.2,0.933333333333333348,0.0666666666666666657],"xyz":[0.320395733599513288,0.618907964761497231,0.107878702857355263],"hpluv":[126.540515263097504,308.054239915702169,82.85531245284119],"hsluv":[126.540515263097504,98.9149262576223833,82.85531245284119]},"#33ee22":{"lch":[82.8952353009988,122.792060636983948,126.977870705292972],"luv":[82.8952353009988,-73.860225327277135,98.0946342573363808],"rgb":[0.2,0.933333333333333348,0.133333333333333331],"xyz":[0.322271091737990345,0.619658108016888,0.117755589053334456],"hpluv":[126.977870705292972,305.002845011722627,82.8952353009988],"hsluv":[126.977870705292972,96.9167682151396264,82.8952353009988]},"#33ee33":{"lch":[82.9608975691188846,120.264250910780831,127.715012949240375],"luv":[82.9608975691188846,-73.5697721383487391,95.1366316128687259],"rgb":[0.2,0.933333333333333348,0.2],"xyz":[0.325358842470448051,0.620893208309871159,0.134017742910945592],"hpluv":[127.715012949240375,300.046240285686,82.9608975691188846],"hsluv":[127.715012949240375,93.6639064416312834,82.9608975691188846]},"#33ee44":{"lch":[83.0555452014946241,116.707569363843,128.817932535493583],"luv":[83.0555452014946241,-73.1578713419028,90.9317469728687513],"rgb":[0.2,0.933333333333333348,0.266666666666666663],"xyz":[0.329816837714666966,0.622676406407558725,0.157496517863832231],"hpluv":[128.817932535493583,293.039720989359807,83.0555452014946241],"hsluv":[128.817932535493583,93.7274034182796356,83.0555452014946241]},"#33ee55":{"lch":[83.1818510898783643,112.121671621867506,130.367812557605703],"luv":[83.1818510898783643,-72.6203079673681202,85.4257579305358092],"rgb":[0.2,0.933333333333333348,0.333333333333333315],"xyz":[0.335779251754028951,0.625061372023303474,0.188898565137806146],"hpluv":[130.367812557605703,283.950089878719211,83.1818510898783643],"hsluv":[130.367812557605703,93.8103653792530139,83.1818510898783643]},"#33ee66":{"lch":[83.3420657578551,106.5703857928128,132.470647679843353],"luv":[83.3420657578551,-71.9576476395269,78.6088040502757224],"rgb":[0.2,0.933333333333333348,0.4],"xyz":[0.343364247527537136,0.628095370332706793,0.228846209544950108],"hpluv":[132.470647679843353,272.865433725808,83.3420657578551],"hsluv":[132.470647679843353,93.912785079345241,83.3420657578551]},"#33ee77":{"lch":[83.5380975272703523,100.188150337510052,135.268396470867572],"luv":[83.5380975272703523,-71.1748024762597851,70.5110839550557387],"rgb":[0.2,0.933333333333333348,0.466666666666666674],"xyz":[0.352678260547739042,0.631820975540787644,0.277900011451348],"hpluv":[135.268396470867572,260.019238129472967,83.5380975272703523],"hsluv":[135.268396470867572,94.0340074276028304,83.5380975272703523]},"#33ee88":{"lch":[83.7715600973053682,93.1909370684561651,138.951686086792108],"luv":[83.7715600973053682,-70.2805135444840801,61.1980405537673],"rgb":[0.2,0.933333333333333348,0.533333333333333326],"xyz":[0.363818677649682842,0.636277142381565186,0.336572874854920157],"hpluv":[138.951686086792108,245.83342468256393,83.7715600973053682],"hsluv":[138.951686086792108,94.1728069818675237,83.7715600973053682]},"#33ee99":{"lch":[84.0438031984902807,85.8935006436990278,143.770719305914184],"luv":[84.0438031984902807,-69.2867121669879822,50.7646035138469784],"rgb":[0.2,0.933333333333333348,0.6],"xyz":[0.376875641758755542,0.641499928025194399,0.405339552496038091],"hpluv":[143.770719305914184,230.989810482694878,84.0438031984902807],"hsluv":[143.770719305914184,94.3274826341768886,84.0438031984902807]},"#33eeaa":{"lch":[84.3559338989094698,78.7339796376561907,150.032255922422308],"luv":[84.3559338989094698,-68.2077782157370223,39.328596980513943],"rgb":[0.2,0.933333333333333348,0.66666666666666663],"xyz":[0.391933334724008098,0.647523005211295466,0.484643402113036692],"hpluv":[150.032255922422308,216.540119706931335,84.3559338989094698],"hsluv":[150.032255922422308,94.495967075681591,84.3559338989094698]},"#33eebb":{"lch":[84.7088326356722,72.2999891840671,158.051587623557367],"luv":[84.7088326356722,-67.0597412553262,27.0236847743774931],"rgb":[0.2,0.933333333333333348,0.733333333333333282],"xyz":[0.409070926831344772,0.654378042054230225,0.574901387211678383],"hpluv":[158.051587623557367,204.04938686040532,84.7088326356722],"hsluv":[158.051587623557367,94.6759444498571838,84.7088326356722]},"#33eecc":{"lch":[85.1031663228954,67.3294619946068451,168.005441410177127],"luv":[85.1031663228954,-65.8594808644086,13.992327638881461],"rgb":[0.2,0.933333333333333348,0.8],"xyz":[0.428363302275066471,0.662094992231719082,0.676507897881948539],"hpluv":[168.005441410177127,195.708498626929867,85.1031663228954],"hsluv":[168.005441410177127,94.8649680125767389,85.1031663228954]},"#33eedd":{"lch":[85.539399954776755,64.6250931348259314,179.663789762776076],"luv":[85.539399954776755,-64.6239805156479861,0.37921629457989664],"rgb":[0.2,0.933333333333333348,0.866666666666666696],"xyz":[0.44988162782570007,0.670702322451972588,0.789837745781954537],"hpluv":[179.663789762776076,194.233009793031641,85.539399954776755],"hsluv":[179.663789762776076,95.0605698730458926,85.539399954776755]},"#33eeee":{"lch":[86.0178075751720286,64.8282855412949601,192.177050630061217],"luv":[86.0178075751720286,-63.3696789602654533,-13.6744431219908602],"rgb":[0.2,0.933333333333333348,0.933333333333333348],"xyz":[0.47369380809187478,0.680227194558442605,0.91524856185047776],"hpluv":[192.177050630061217,202.327515221469156,86.0178075751720286],"hsluv":[192.177050630061217,95.2603564020327127,86.0178075751720286]},"#33eeff":{"lch":[86.538483142230433,68.1460620684978124,204.293044736593487],"luv":[86.538483142230433,-62.1119480142598803,-28.035543321245509],"rgb":[0.2,0.933333333333333348,1],"xyz":[0.499864856501706201,0.690695613922375329,1.05308275014225972],"hpluv":[204.293044736593487,221.878852364873978,86.538483142230433],"hsluv":[204.293044736593487,99.999999999993932,86.538483142230433]},"#33ff00":{"lch":[88.074762753062231,133.577745567808222,126.513803819973305],"luv":[88.074762753062231,-79.4809541468946,107.358241597361044],"rgb":[0.2,1,0],"xyz":[0.37123644052955,0.72220804342099143,0.119834722035823737],"hpluv":[126.513803819973305,497.272976699974663,88.074762753062231],"hsluv":[126.513803819973305,100.00000000000226,88.074762753062231]},"#33ff11":{"lch":[88.0941974462199,132.80363803677966,126.71317891025123],"luv":[88.0941974462199,-79.3912833442141448,106.460464045403725],"rgb":[0.2,1,0.0666666666666666657],"xyz":[0.37224810602918712,0.722612709620846339,0.125162827000579374],"hpluv":[126.71317891025123,495.277769978645495,88.0941974462199],"hsluv":[126.71317891025123,99.9999999999917861,88.0941974462199]},"#33ff22":{"lch":[88.1302050034733355,131.38040615815558,127.087058789859782],"luv":[88.1302050034733355,-79.2260405323659285,104.804797713872986],"rgb":[0.2,1,0.133333333333333331],"xyz":[0.374123464167664177,0.723362852876237139,0.135039713196558553],"hpluv":[127.087058789859782,491.602558840386564,88.1302050034733355],"hsluv":[127.087058789859782,99.9999999999915161,88.1302050034733355]},"#33ff33":{"lch":[88.1894367416410745,129.070276381710187,127.715012949240347],"luv":[88.1894367416410745,-78.9567203165017162,102.10275491931047],"rgb":[0.2,1,0.2],"xyz":[0.377211214900121883,0.724597953169220266,0.151301867054169703],"hpluv":[127.715012949240347,485.618062737129037,88.1894367416410745],"hsluv":[127.715012949240347,99.9999999999917577,88.1894367416410745]},"#33ff44":{"lch":[88.2748349985884,125.807640063387211,128.649544439126117],"luv":[88.2748349985884,-78.5738101086462137,98.2533391968394909],"rgb":[0.2,1,0.266666666666666663],"xyz":[0.381669210144340798,0.726381151266907832,0.174780642007056342],"hpluv":[128.649544439126117,477.126267833886629,88.2748349985884],"hsluv":[128.649544439126117,99.9999999999917151,88.2748349985884]},"#33ff55":{"lch":[88.3888340150102181,121.57774004888698,129.95306271607248],"luv":[88.3888340150102181,-78.0723424240601,93.1979410921456122],"rgb":[0.2,1,0.333333333333333315],"xyz":[0.387631624183702783,0.728766116882652581,0.206182689281030257],"hpluv":[129.95306271607248,466.04908765344419,88.3888340150102181],"hsluv":[129.95306271607248,99.999999999991644,88.3888340150102181]},"#33ff66":{"lch":[88.5334972733264,116.417510431790106,131.704600668064415],"luv":[88.5334972733264,-77.4514410423726929,86.9155395518881],"rgb":[0.2,1,0.4],"xyz":[0.395216619957210968,0.7318001151920559,0.246130333688174219],"hpluv":[131.704600668064415,452.43688525451455,88.5334972733264],"hsluv":[131.704600668064415,99.9999999999913882,88.5334972733264]},"#33ff77":{"lch":[88.7105909437740081,110.419515958012653,134.007319384137503],"luv":[88.7105909437740081,-76.7139872603015505,79.419353202025647],"rgb":[0.2,1,0.466666666666666674],"xyz":[0.404530632977412874,0.735525720400136751,0.295184135594572128],"hpluv":[134.007319384137503,436.493157669178117,88.7105909437740081],"hsluv":[134.007319384137503,99.9999999999915,88.7105909437740081]},"#33ff88":{"lch":[88.9216276204312379,103.738746998712813,136.99719245927011],"luv":[88.9216276204312379,-75.8662497359534882,70.7533729221786558],"rgb":[0.2,1,0.533333333333333326],"xyz":[0.415671050079356674,0.739981887240914293,0.353856998998144268],"hpluv":[136.99719245927011,418.619650658891032,88.9216276204312379],"hsluv":[136.99719245927011,99.9999999999912603,88.9216276204312379]},"#33ff99":{"lch":[89.1678944508512359,96.6032590942606788,140.85189111032139],"luv":[89.1678944508512359,-74.9174292298428242,60.9882649796200695],"rgb":[0.2,1,0.6],"xyz":[0.428728014188429429,0.745204672884543506,0.422623676639262202],"hpluv":[140.85189111032139,399.492483487252343,89.1678944508512359],"hsluv":[140.85189111032139,99.9999999999913456,89.1678944508512359]},"#33ffaa":{"lch":[89.4504724790268426,89.3298939826383105,145.795546705853383],"luv":[89.4504724790268426,-73.8791171714821,50.2165909327964926],"rgb":[0.2,1,0.66666666666666663],"xyz":[0.44378570715368193,0.751227750070644573,0.501927526256260803],"hpluv":[145.795546705853383,380.184928602968114,89.4504724790268426],"hsluv":[145.795546705853383,99.9999999999912,89.4504724790268426]},"#33ffbb":{"lch":[89.7702508712150262,82.3444719603705,152.087330110215447],"luv":[89.7702508712150262,-72.7646918614874494,38.5475249625060314],"rgb":[0.2,1,0.733333333333333282],"xyz":[0.460923299261018604,0.758082786913579332,0.592185511354902605],"hpluv":[152.087330110215447,362.351543222333419,89.7702508712150262],"hsluv":[152.087330110215447,99.9999999999909761,89.7702508712150262]},"#33ffcc":{"lch":[90.127938152783571,76.1985663634222,159.968053619612647],"luv":[90.127938152783571,-71.5886883295869723,26.1013643147272063],"rgb":[0.2,1,0.8],"xyz":[0.480215674704740358,0.765799737091068189,0.693792022025172761],"hpluv":[159.968053619612647,348.464440630653087,90.127938152783571],"hsluv":[159.968053619612647,99.999999999990834,90.127938152783571]},"#33ffdd":{"lch":[90.5240717550146314,71.5577226375514357,169.529475161807255],"luv":[90.5240717550146314,-70.3661811113599924,13.0041618290463337],"rgb":[0.2,1,0.866666666666666696],"xyz":[0.501734000255373846,0.774407067311321695,0.807121869925178759],"hpluv":[169.529475161807255,342.013155745428833,90.5240717550146314],"hsluv":[169.529475161807255,99.9999999999904077,90.5240717550146314]},"#33ffee":{"lch":[90.9590266887802,69.1149718308150511,180.51167449693034],"luv":[90.9590266887802,-69.1122158161064561,-0.61721646306864264],"rgb":[0.2,1,0.933333333333333348],"xyz":[0.525546180521548667,0.783931939417791712,0.932532685993702],"hpluv":[180.51167449693034,347.442342228089899,90.9590266887802],"hsluv":[180.51167449693034,99.9999999999901519,90.9590266887802]},"#33ffff":{"lch":[91.4330238629877243,69.4028497051403122,192.177050630061132],"luv":[91.4330238629877243,-67.8413175363212702,-14.6393709608822622],"rgb":[0.2,1,1],"xyz":[0.55171722893138,0.794400358781724436,1.07036687428548372],"hpluv":[192.177050630061132,369.590917988860895,91.4330238629877243],"hsluv":[192.177050630061132,99.9999999999897256,91.4330238629877243]},"#22aa00":{"lch":[60.8595101229647923,91.9296409673314656,126.268252023172565],"luv":[60.8595101229647923,-54.3824975763784053,74.1188427172042594],"rgb":[0.133333333333333331,0.66666666666666663,0],"xyz":[0.150337683054585614,0.290883353615456,0.0482228743965988915],"hpluv":[126.268252023172565,191.675426474830772,60.8595101229647923],"hsluv":[126.268252023172565,100.000000000002288,60.8595101229647923]},"#22aa11":{"lch":[60.8951349805759605,90.6090655032342482,126.765726538166419],"luv":[60.8951349805759605,-54.2335583573106,72.5859759132132893],"rgb":[0.133333333333333331,0.66666666666666663,0.0666666666666666657],"xyz":[0.151349348554222746,0.291288019815310828,0.0535509793613545212],"hpluv":[126.765726538166419,188.811473003651798,60.8951349805759605],"hsluv":[126.765726538166419,97.6988909499644365,60.8951349805759605]},"#22aa22":{"lch":[60.9610867967894592,88.21068058626,127.715012949240347],"luv":[60.9610867967894592,-53.9615024560723953,69.7802294505720226],"rgb":[0.133333333333333331,0.66666666666666663,0.133333333333333331],"xyz":[0.153224706692699747,0.292038163070701628,0.0634278655573337208],"hpluv":[127.715012949240347,183.614848439340193,60.9610867967894592],"hsluv":[127.715012949240347,93.4926845994439475,60.9610867967894592]},"#22aa33":{"lch":[61.0694299105106495,84.4016098893730629,129.358188857231823],"luv":[61.0694299105106495,-53.5246691509727626,65.259034196016259],"rgb":[0.133333333333333331,0.66666666666666663,0.2],"xyz":[0.156312457425157481,0.293273263363684755,0.0796900194149448571],"hpluv":[129.358188857231823,175.374397166590711,61.0694299105106495],"hsluv":[129.358188857231823,93.5882360519160699,61.0694299105106495]},"#22aa44":{"lch":[61.2253168994486145,79.2082340196825214,131.918899994809664],"luv":[61.2253168994486145,-52.917281977470445,58.938150671985575],"rgb":[0.133333333333333331,0.66666666666666663,0.266666666666666663],"xyz":[0.160770452669376368,0.295056461461372321,0.103168794367831496],"hpluv":[131.918899994809664,164.164260791814144,61.2253168994486145],"hsluv":[131.918899994809664,93.7213426507132397,61.2253168994486145]},"#22aa55":{"lch":[61.4328316402448422,72.8294169380228169,135.724592815827151],"luv":[61.4328316402448422,-52.1453123372646488,50.8428005993127883],"rgb":[0.133333333333333331,0.66666666666666663,0.333333333333333315],"xyz":[0.166732866708738381,0.297441427077117182,0.134570841641805411],"hpluv":[135.724592815827151,150.433869175471955,61.4328316402448422],"hsluv":[135.724592815827151,93.8909627694616802,61.4328316402448422]},"#22aa66":{"lch":[61.695221435526193,65.6694032551541511,141.26425661379642],"luv":[61.695221435526193,-51.2247747289881588,41.0912761769754056],"rgb":[0.133333333333333331,0.66666666666666663,0.4],"xyz":[0.174317862482246538,0.3004754253865205,0.174518486048949373],"hpluv":[141.26425661379642,135.067502346464636,61.695221435526193],"hsluv":[141.26425661379642,94.0939374356695737,61.695221435526193]},"#22aa77":{"lch":[62.015018576984005,58.3994247120946,149.232117680428786],"luv":[62.015018576984005,-50.1795183581889,29.8748848373309741],"rgb":[0.133333333333333331,0.66666666666666663,0.466666666666666674],"xyz":[0.183631875502448472,0.304201030594601296,0.223572287955347282],"hpluv":[149.232117680428786,119.495353216490457,62.015018576984005],"hsluv":[149.232117680428786,94.3254538020573534,62.015018576984005]},"#22aa88":{"lch":[62.3941144695078265,52.0455462506657582,160.428514439052776],"luv":[62.3941144695078265,-49.0385773736463904,17.4343572780611709],"rgb":[0.133333333333333331,0.66666666666666663,0.533333333333333326],"xyz":[0.194772292604392272,0.308657197435378894,0.282245151358919477],"hpluv":[160.428514439052776,105.847175197261592,62.3941144695078265],"hsluv":[160.428514439052776,94.5795977554836753,62.3941144695078265]},"#22aa99":{"lch":[62.8338123759312168,48.0032947436357915,175.177921691935865],"luv":[62.8338123759312168,-47.8333890460383486,4.03524455451089725],"rgb":[0.133333333333333331,0.66666666666666663,0.6],"xyz":[0.207829256713465,0.313879983079008051,0.351011829000037356],"hpluv":[175.177921691935865,96.9431131493944918,62.8338123759312168],"hsluv":[175.177921691935865,94.8499327714938119,62.8338123759312168]},"#22aaaa":{"lch":[63.334871160235295,47.6677335272966047,192.177050630061132],"luv":[63.334871160235295,-46.595231466735612,-10.0547115418935782],"rgb":[0.133333333333333331,0.66666666666666663,0.66666666666666663],"xyz":[0.222886949678717528,0.319903060265109174,0.430315678617035957],"hpluv":[192.177050630061132,95.5038628742744748,63.334871160235295],"hsluv":[192.177050630061132,95.1300327368807075,63.334871160235295]},"#22aabb":{"lch":[63.8975462810157211,51.5875561200845425,208.460106210027732],"luv":[63.8975462810157211,-45.3531553267970224,-24.5838818811491713],"rgb":[0.133333333333333331,0.66666666666666663,0.733333333333333282],"xyz":[0.240024541786054202,0.326758097108043932,0.520573663715677704],"hpluv":[208.460106210027732,102.447201536891086,63.8975462810157211],"hsluv":[208.460106210027732,95.4139121453229393,63.8975462810157211]},"#22aacc":{"lch":[64.5216311304052681,59.1142282054053112,221.706391964203618],"luv":[64.5216311304052681,-44.1325525375176184,-39.3295027027292079],"rgb":[0.133333333333333331,0.66666666666666663,0.8],"xyz":[0.259316917229775901,0.334475047285532734,0.62218017438594786],"hpluv":[221.706391964203618,116.258847224370101,64.5216311304052681],"hsluv":[221.706391964203618,95.6963242429470853,64.5216311304052681]},"#22aadd":{"lch":[65.2065000175346796,69.0826091468118619,231.553565124642319],"luv":[65.2065000175346796,-42.9543721979751538,-54.1047945713593279],"rgb":[0.133333333333333331,0.66666666666666663,0.866666666666666696],"xyz":[0.2808352427804095,0.34308237750578624,0.735510022285953857],"hpluv":[231.553565124642319,134.436491082611866,65.2065000175346796],"hsluv":[231.553565124642319,95.9729250289437,65.2065000175346796]},"#22aaee":{"lch":[65.951153016283925,80.4876559434330687,238.683318882444183],"luv":[65.951153016283925,-41.8348964739996418,-68.7612114224159825],"rgb":[0.133333333333333331,0.66666666666666663,0.933333333333333348],"xyz":[0.304647423046584209,0.352607249612256257,0.86092083835447708],"hpluv":[238.683318882444183,154.862481256054423,65.951153016283925],"hsluv":[238.683318882444183,96.2403212652285305,65.951153016283925]},"#22aaff":{"lch":[66.7542622474436911,92.6475815050926741,243.881654723446388],"luv":[66.7542622474436911,-40.785937465112724,-83.187028218555227],"rgb":[0.133333333333333331,0.66666666666666663,1],"xyz":[0.33081847145641563,0.363075668976189,0.998755026646258925],"hpluv":[243.881654723446388,176.114215620682756,66.7542622474436911],"hsluv":[243.881654723446388,99.9999999999982521,66.7542622474436911]},"#22bb00":{"lch":[66.4275479271698117,100.802558180890344,126.547308547849156],"luv":[66.4275479271698117,-60.0265444602621798,80.9812922592122533],"rgb":[0.133333333333333331,0.733333333333333282,0],"xyz":[0.184292180963184393,0.358792349432654534,0.0595410403661315105],"hpluv":[126.547308547849156,192.558484368086766,66.4275479271698117],"hsluv":[126.547308547849156,100.000000000002402,66.4275479271698117]},"#22bb11":{"lch":[66.4585250929908682,99.6331665050874449,126.950333401467461],"luv":[66.4585250929908682,-59.891738470658936,79.6225315522727612],"rgb":[0.133333333333333331,0.733333333333333282,0.0666666666666666657],"xyz":[0.185303846462821525,0.359197015632509387,0.0648691453308871402],"hpluv":[126.950333401467461,190.235936561387632,66.4585250929908682],"hsluv":[126.950333401467461,98.1323711753334464,66.4585250929908682]},"#22bb22":{"lch":[66.5158870179191553,97.5011623585143496,127.715012949240375],"luv":[66.5158870179191553,-59.6448091899021904,77.1295883430057785],"rgb":[0.133333333333333331,0.733333333333333282,0.133333333333333331],"xyz":[0.187179204601298527,0.359947158887900187,0.0747460315268663328],"hpluv":[127.715012949240375,186.004620566556611,66.5158870179191553],"hsluv":[127.715012949240375,94.7095045552014341,66.5158870179191553]},"#22bb33":{"lch":[66.6101592341861561,94.091611241079562,129.025604662043349],"luv":[66.6101592341861561,-59.2464412491434089,73.0964465979998721],"rgb":[0.133333333333333331,0.733333333333333282,0.2],"xyz":[0.19026695533375626,0.361182259180883314,0.091008185384477483],"hpluv":[129.025604662043349,179.246118589082698,66.6101592341861561],"hsluv":[129.025604662043349,94.7728361420699628,66.6101592341861561]},"#22bb44":{"lch":[66.7458880420052907,89.3893698914418735,131.03732282887168],"luv":[66.7458880420052907,-58.6886365964374903,67.424797990356],"rgb":[0.133333333333333331,0.733333333333333282,0.266666666666666663],"xyz":[0.194724950577975148,0.36296545727857088,0.114486960337364121],"hpluv":[131.03732282887168,169.941985039444177,66.7458880420052907],"hsluv":[131.03732282887168,94.8616428317247511,66.7458880420052907]},"#22bb55":{"lch":[66.9267274999506,83.5071173210959472,133.96576260666626],"luv":[66.9267274999506,-57.9730125462468777,60.1046459068846488],"rgb":[0.133333333333333331,0.733333333333333282,0.333333333333333315],"xyz":[0.200687364617337161,0.365350422894315741,0.145889007611338023],"hpluv":[133.96576260666626,158.330006142604873,66.9267274999506],"hsluv":[133.96576260666626,94.9758066387206128,66.9267274999506]},"#22bb66":{"lch":[67.1556458878222315,76.7025221245859541,138.121353671725132],"luv":[67.1556458878222315,-57.1096598103208919,51.2031606116460054],"rgb":[0.133333333333333331,0.733333333333333282,0.4],"xyz":[0.208272360390845318,0.368384421203719059,0.185836652018481985],"hpluv":[138.121353671725132,144.932719296840418,67.1556458878222315],"hsluv":[138.121353671725132,95.1139083236691363,67.1556458878222315]},"#22bb77":{"lch":[67.4350338747947831,69.4107315991336407,143.945643371462126],"luv":[67.4350338747947831,-56.1157304677756557,40.8518598743670935],"rgb":[0.133333333333333331,0.733333333333333282,0.466666666666666674],"xyz":[0.217586373411047251,0.372110026411799855,0.234890453924879894],"hpluv":[143.945643371462126,130.611184627207962,67.4350338747947831],"hsluv":[143.945643371462126,95.2734443978328471,67.4350338747947831]},"#22bb88":{"lch":[67.7667691572368653,62.2973404800357571,152.016434409622292],"luv":[67.7667691572368653,-55.0136735570032656,29.2310511724943218],"rgb":[0.133333333333333331,0.733333333333333282,0.533333333333333326],"xyz":[0.228726790512991052,0.376566193252577452,0.293563317328452089],"hpluv":[152.016434409622292,116.65196328010299,67.7667691572368653],"hsluv":[152.016434409622292,95.4510958201536823,67.7667691572368653]},"#22bb99":{"lch":[68.1522602188863402,56.3167420179958214,162.907285030510934],"luv":[68.1522602188863402,-53.8292536917802948,16.552549003324323],"rgb":[0.133333333333333331,0.733333333333333282,0.6],"xyz":[0.241783754622063779,0.38178897889620661,0.362329994969569968],"hpluv":[162.907285030510934,104.856796539193,68.1522602188863402],"hsluv":[162.907285030510934,95.6430286983925555,68.1522602188863402]},"#22bbaa":{"lch":[68.5924801056558238,52.6774965449754617,176.68900923381463],"luv":[68.5924801056558238,-52.5895649511659542,3.04241688349887474],"rgb":[0.133333333333333331,0.733333333333333282,0.66666666666666663],"xyz":[0.256841447587316307,0.387812056082307732,0.441633844586568569],"hpluv":[176.68900923381463,97.4513697523019,68.5924801056558238],"hsluv":[176.68900923381463,95.8451953079369616,68.5924801056558238]},"#22bbbb":{"lch":[69.087995915136645,52.5025293878432677,192.177050630061075],"luv":[69.087995915136645,-51.3212466461144174,-11.0745309069971647],"rgb":[0.133333333333333331,0.733333333333333282,0.733333333333333282],"xyz":[0.273979039694653,0.394667092925242491,0.531891829685210316],"hpluv":[192.177050630061075,96.4310638968393903,69.087995915136645],"hsluv":[192.177050630061075,96.05360442262905,69.087995915136645]},"#22bbcc":{"lch":[69.6389970716796824,56.2104265974936,207.07804051519031],"luv":[69.6389970716796824,-50.0490518690675117,-25.5871933841835393],"rgb":[0.133333333333333331,0.733333333333333282,0.8],"xyz":[0.293271415138374736,0.402384043102731292,0.633498340355480472],"hpluv":[207.07804051519031,102.424464009042,69.6389970716796824],"hsluv":[207.07804051519031,96.2645382772070519,69.6389970716796824]},"#22bbdd":{"lch":[70.2453239794146924,63.2897284454122868,219.558412279776348],"luv":[70.2453239794146924,-48.7948432782897541,-40.3069844585422956],"rgb":[0.133333333333333331,0.733333333333333282,0.866666666666666696],"xyz":[0.314789740689008224,0.410991373322984799,0.746828188255486469],"hpluv":[219.558412279776348,114.328666738486675,70.2453239794146924],"hsluv":[219.558412279776348,96.4747049793171101,70.2453239794146924]},"#22bbee":{"lch":[70.9064977498674409,72.7777709471329644,229.176572531806158],"luv":[70.9064977498674409,-47.5770176148035588,-55.072963774560229],"rgb":[0.133333333333333331,0.733333333333333282,0.933333333333333348],"xyz":[0.338601920955183,0.420516245429454816,0.872239004324009692],"hpluv":[229.176572531806158,130.242295294742263,70.9064977498674409],"hsluv":[229.176572531806158,96.6813261778791286,70.9064977498674409]},"#22bbff":{"lch":[71.621751136046143,83.782469360031385,236.362391595167765],"luv":[71.621751136046143,-46.4103062114400586,-69.7537500742789121],"rgb":[0.133333333333333331,0.733333333333333282,1],"xyz":[0.364772969365014355,0.43098466479338754,1.01007319261579154],"hpluv":[236.362391595167765,148.438838585801221,71.621751136046143],"hsluv":[236.362391595167765,99.9999999999977405,71.621751136046143]},"#22cc00":{"lch":[71.9091745039523431,109.499123564337054,126.755635680122666],"luv":[71.9091745039523431,-65.5246489265194185,87.7301455852794732],"rgb":[0.133333333333333331,0.8,0],"xyz":[0.222515924272801313,0.435239836051889428,0.0722822881360034586],"hpluv":[126.755635680122666,193.226045742870838,71.9091745039523431],"hsluv":[126.755635680122666,100.000000000002288,71.9091745039523431]},"#22cc11":{"lch":[71.9364107151438077,108.454952609175663,127.087674169957992],"luv":[71.9364107151438077,-65.4022833696805,86.5159989567857508],"rgb":[0.133333333333333331,0.8,0.0666666666666666657],"xyz":[0.223527589772438445,0.435644502251744281,0.0776103931007591],"hpluv":[127.087674169957992,191.311003889673145,71.9364107151438077],"hsluv":[127.087674169957992,98.4591341389350418,71.9364107151438077]},"#22cc22":{"lch":[71.9868548113652196,106.54571101335867,127.715012949240403],"luv":[71.9868548113652196,-65.1776701905061771,84.2843985793322332],"rgb":[0.133333333333333331,0.8,0.133333333333333331],"xyz":[0.225402947910915447,0.436394645507135082,0.0874872792967382878],"hpluv":[127.715012949240403,187.811464536348922,71.9868548113652196],"hsluv":[127.715012949240403,95.6295101801496,71.9868548113652196]},"#22cc33":{"lch":[72.0697845089905229,103.47656324227728,128.782383231673776],"luv":[72.0697845089905229,-64.8140104316899084,80.6631464312780224],"rgb":[0.133333333333333331,0.8,0.2],"xyz":[0.22849069864337318,0.437629745800118208,0.103749433154349424],"hpluv":[128.782383231673776,182.191494825933376,72.0697845089905229],"hsluv":[128.782383231673776,95.6728206524347,72.0697845089905229]},"#22cc44":{"lch":[72.1892409305665126,99.2080881077430092,130.402545810446583],"luv":[72.1892409305665126,-64.3020931154350563,75.5479024657046381],"rgb":[0.133333333333333331,0.8,0.266666666666666663],"xyz":[0.232948693887592068,0.439412943897805774,0.127228208107236063],"hpluv":[130.402545810446583,174.38692971209278,72.1892409305665126],"hsluv":[130.402545810446583,95.7338579762306807,72.1892409305665126]},"#22cc55":{"lch":[72.3485056391290584,93.798910065649892,132.724941359454647],"luv":[72.3485056391290584,-63.6406395178356732,68.9064912128369116],"rgb":[0.133333333333333331,0.8,0.333333333333333315],"xyz":[0.23891110792695408,0.441797909513550635,0.158630255381209978],"hpluv":[132.724941359454647,164.515777124050715,72.3485056391290584],"hsluv":[132.724941359454647,95.8128514989610665,72.3485056391290584]},"#22cc66":{"lch":[72.5502856399570106,87.4149553130202577,135.957009780349864],"luv":[72.5502856399570106,-62.8354766726053597,60.7706942835425821],"rgb":[0.133333333333333331,0.8,0.4],"xyz":[0.246496103700462238,0.444831907822953954,0.19857789978835394],"hpluv":[135.957009780349864,152.89241471165704,72.5502856399570106],"hsluv":[135.957009780349864,95.9092114165347454,72.5502856399570106]},"#22cc77":{"lch":[72.7968107106438,80.347487444586676,140.388595454497391],"luv":[72.7968107106438,-61.8986076052927601,51.2277377519640922],"rgb":[0.133333333333333331,0.8,0.466666666666666674],"xyz":[0.255810116720664171,0.448557513031034749,0.247631701694751849],"hpluv":[140.388595454497391,140.055211607516185,72.7968107106438],"hsluv":[140.388595454497391,96.0216367005683651,72.7968107106438]},"#22cc88":{"lch":[73.0898911189871399,73.0433057087839899,146.410934307510047],"luv":[73.0898911189871399,-60.8470337434031379,40.4099368162836328],"rgb":[0.133333333333333331,0.8,0.533333333333333326],"xyz":[0.266950533822607972,0.453013679871812347,0.306304565098324044],"hpluv":[146.410934307510047,126.812607157634474,73.0898911189871399],"hsluv":[146.410934307510047,96.1482500942118463,73.0898911189871399]},"#22cc99":{"lch":[73.4309556061454316,66.1476907411168,154.494840416347301],"luv":[73.4309556061454316,-59.7013675833161201,28.4826912187770667],"rgb":[0.133333333333333331,0.8,0.6],"xyz":[0.280007497931680671,0.458236465515441505,0.375071242739441923],"hpluv":[154.494840416347301,114.307528246897718,73.4309556061454316],"hsluv":[154.494840416347301,96.2867563581127826,73.4309556061454316]},"#22ccaa":{"lch":[73.8210792378530272,60.5373530055450857,165.03572853292485],"luv":[73.8210792378530272,-58.4843517505691963,15.631753236079188],"rgb":[0.133333333333333331,0.8,0.66666666666666663],"xyz":[0.295065190896933227,0.464259542701542627,0.454375092356440524],"hpluv":[165.03572853292485,104.059650734936554,73.8210792378530272],"hsluv":[165.03572853292485,96.4346108423233233,73.8210792378530272]},"#22ccbb":{"lch":[74.2610062314211916,57.2561659312404601,177.947236116536601],"luv":[74.2610062314211916,-57.2194225987583565,2.05090580243043252],"rgb":[0.133333333333333331,0.8,0.733333333333333282],"xyz":[0.312202783004269901,0.471114579544477385,0.544633077455082271],"hpluv":[177.947236116536601,97.8364666306377302,74.2610062314211916],"hsluv":[177.947236116536601,96.5891828531354406,74.2610062314211916]},"#22cccc":{"lch":[74.7511706210643467,57.2167927817266,192.177050630061132],"luv":[74.7511706210643467,-55.9294412838427633,-12.0689259631595149],"rgb":[0.133333333333333331,0.8,0.8],"xyz":[0.3314951584479916,0.478831529721966187,0.646239588125352427],"hpluv":[192.177050630061132,97.128087782713564,74.7511706210643467],"hsluv":[192.177050630061132,96.747899952527,74.7511706210643467]},"#22ccdd":{"lch":[75.2917163799825602,60.7443465218384091,205.915913497891523],"luv":[75.2917163799825602,-54.6356779140553357,-26.5484148912282159],"rgb":[0.133333333333333331,0.8,0.866666666666666696],"xyz":[0.353013483998625199,0.487438859942219693,0.759569436025358424],"hpluv":[205.915913497891523,102.375961416692178,75.2917163799825602],"hsluv":[205.915913497891523,96.9083635301369,75.2917163799825602]},"#22ccee":{"lch":[75.8825178700112843,67.4282526949852894,217.691288579377613],"luv":[75.8825178700112843,-53.3570890727704779,-41.2260877015904583],"rgb":[0.133333333333333331,0.8,0.933333333333333348],"xyz":[0.376825664264799909,0.49696373204868971,0.884980252093881647],"hpluv":[217.691288579377613,112.755958051566466,75.8825178700112843],"hsluv":[217.691288579377613,97.0684311053177851,75.8825178700112843]},"#22ccff":{"lch":[76.5232010138481,76.4669756721874165,227.041443142980768],"luv":[76.5232010138481,-52.1098871667616095,-55.9621124325938553],"rgb":[0.133333333333333331,0.8,1],"xyz":[0.40299671267463133,0.507432151412622434,1.02281444038566338],"hpluv":[227.041443142980768,130.754689276117347,76.5232010138481],"hsluv":[227.041443142980768,99.999999999997,76.5232010138481]},"#22dd00":{"lch":[77.3111928538645543,118.038829613749726,126.914864539429317],"luv":[77.3111928538645543,-70.8973873693031607,94.3754510494695],"rgb":[0.133333333333333331,0.866666666666666696,0],"xyz":[0.265149914819976518,0.520507817146241,0.0864936183183947771],"hpluv":[126.914864539429317,210.347075729226248,77.3111928538645543],"hsluv":[126.914864539429317,100.000000000002288,77.3111928538645543]},"#22dd11":{"lch":[77.3353680300965323,117.099630973594756,127.192375056145337],"luv":[77.3353680300965323,-70.7859197567446756,93.2827805028547346],"rgb":[0.133333333333333331,0.866666666666666696,0.0666666666666666657],"xyz":[0.266161580319613622,0.520912483346095856,0.0918217232831504138],"hpluv":[127.192375056145337,208.941659016378082,77.3353680300965323],"hsluv":[127.192375056145337,98.7107326231664217,77.3353680300965323]},"#22dd22":{"lch":[77.3801492665193535,115.37848303888174,127.715012949240432],"luv":[77.3801492665193535,-70.5809801545768636,91.2716801027172409],"rgb":[0.133333333333333331,0.866666666666666696,0.133333333333333331],"xyz":[0.268036938458090679,0.521662626601486656,0.101698609479129606],"hpluv":[127.715012949240432,206.361699793513822,77.3801492665193535],"hsluv":[127.715012949240432,96.3395071146262154,77.3801492665193535]},"#22dd33":{"lch":[77.4537875025684315,112.600723810091978,128.59932725776207],"luv":[77.4537875025684315,-70.24826089977104,88.0005956974969195],"rgb":[0.133333333333333331,0.866666666666666696,0.2],"xyz":[0.271124689190548385,0.522897726894469783,0.117960763336740743],"hpluv":[128.59932725776207,202.185786680839726,77.4537875025684315],"hsluv":[128.59932725776207,96.3699377868481122,77.4537875025684315]},"#22dd44":{"lch":[77.5598997380018,108.71293616133481,129.930302741787841],"luv":[77.5598997380018,-69.7779723132927217,83.3638834787812],"rgb":[0.133333333333333331,0.866666666666666696,0.266666666666666663],"xyz":[0.2755826844347673,0.524680924992157349,0.141439538289627381],"hpluv":[129.930302741787841,196.316024449944422,77.5598997380018],"hsluv":[129.930302741787841,96.4129906320409162,77.5598997380018]},"#22dd55":{"lch":[77.7014460191091416,103.73899221962921,131.815952634500974],"luv":[77.7014460191091416,-69.1669361195931,77.3156740549574266],"rgb":[0.133333333333333331,0.866666666666666696,0.333333333333333315],"xyz":[0.281545098474129285,0.527065890607902099,0.172841585563601297],"hpluv":[131.815952634500974,188.764163413831653,77.7014460191091416],"hsluv":[131.815952634500974,96.4690009350202189,77.7014460191091416]},"#22dd66":{"lch":[77.880896240080375,97.784990294992113,134.401120560320578],"luv":[77.880896240080375,-68.4179393254247117,69.8633659756971923],"rgb":[0.133333333333333331,0.866666666666666696,0.4],"xyz":[0.28913009424763747,0.530099888917305417,0.212789229970745258],"hpluv":[134.401120560320578,179.664283635232721,77.880896240080375],"hsluv":[134.401120560320578,96.5377748783722467,77.880896240080375]},"#22dd77":{"lch":[78.1003183749745205,91.0497694522495635,137.883451987021573],"luv":[78.1003183749745205,-67.5390964016577584,61.0616980975421],"rgb":[0.133333333333333331,0.866666666666666696,0.466666666666666674],"xyz":[0.298444107267839376,0.533825494125386268,0.261843031877143195],"hpluv":[137.883451987021573,169.299836923025936,78.1003183749745205],"hsluv":[137.883451987021573,96.6186469084632478,78.1003183749745205]},"#22dd88":{"lch":[78.3614307373917285,83.8424849668191143,142.529576014285681],"luv":[78.3614307373917285,-66.5430534683674608,51.0057283108209205],"rgb":[0.133333333333333331,0.866666666666666696,0.533333333333333326],"xyz":[0.309584524369783176,0.538281660966163811,0.320515895280715335],"hpluv":[142.529576014285681,158.150702843881334,78.3614307373917285],"hsluv":[142.529576014285681,96.7105501690208,78.3614307373917285]},"#22dd99":{"lch":[78.665635872828048,76.6094810635621144,148.680389056502293],"luv":[78.665635872828048,-65.4460211356496586,39.8224924677044854],"rgb":[0.133333333333333331,0.866666666666666696,0.6],"xyz":[0.322641488478855876,0.543504446609793,0.389282572921833214],"hpluv":[148.680389056502293,146.968629494944878,78.665635872828048],"hsluv":[148.680389056502293,96.8121015046769884,78.665635872828048]},"#22ddaa":{"lch":[79.0140446006893882,69.96699558248838,156.711923446039975],"luv":[79.0140446006893882,-64.2666918031728613,27.6617569130368608],"rgb":[0.133333333333333331,0.866666666666666696,0.66666666666666663],"xyz":[0.337699181444108432,0.549527523795894091,0.46858642253883187],"hpluv":[156.711923446039975,136.880679993502099,79.0140446006893882],"hsluv":[156.711923446039975,96.9216963326973513,79.0140446006893882]},"#22ddbb":{"lch":[79.4074947696843196,64.7136880558744849,166.88262774299784],"luv":[79.4074947696843196,-63.0251268096233161,14.6865520944819572],"rgb":[0.133333333333333331,0.866666666666666696,0.733333333333333282],"xyz":[0.354836773551445106,0.556382560638828849,0.558844407637473561],"hpluv":[166.88262774299784,129.476815865977585,79.4074947696843196],"hsluv":[166.88262774299784,97.0376060255481,79.4074947696843196]},"#22ddcc":{"lch":[79.8465673347569123,61.7508733998812431,179.012513434233142],"luv":[79.8465673347569123,-61.7417023409151184,1.06421693934889783],"rgb":[0.133333333333333331,0.866666666666666696,0.8],"xyz":[0.374129148995166805,0.564099510816317706,0.660450918307743717],"hpluv":[179.012513434233142,126.735630147597362,79.8465673347569123],"hsluv":[179.012513434233142,97.1580701030331824,79.8465673347569123]},"#22dddd":{"lch":[80.3316012938198867,61.8272738566169,192.177050630061245],"luv":[80.3316012938198867,-60.4361886569793,-13.0414298740249546],"rgb":[0.133333333333333331,0.866666666666666696,0.866666666666666696],"xyz":[0.395647474545800404,0.572706841036571213,0.773780766207749715],"hpluv":[192.177050630061245,130.583134255532286,80.3316012938198867],"hsluv":[192.177050630061245,97.2813767637234434,80.3316012938198867]},"#22ddee":{"lch":[80.8627083873859078,65.1993477029452606,204.924336649163848],"luv":[80.8627083873859078,-59.1270126845314579,-27.4763773429615092],"rgb":[0.133333333333333331,0.866666666666666696,0.933333333333333348],"xyz":[0.419459654811975113,0.58223171314304123,0.899191582276272938],"hpluv":[204.924336649163848,142.193638870282854,80.8627083873859078],"hsluv":[204.924336649163848,97.405927410883,80.8627083873859078]},"#22ddff":{"lch":[81.4397880620905141,71.5324096951162574,216.054756332513932],"luv":[81.4397880620905141,-57.8307265123863,-42.1009822669203544],"rgb":[0.133333333333333331,0.866666666666666696,1],"xyz":[0.445630703221806534,0.592700132506974,1.03702577056805478],"hpluv":[216.054756332513932,161.676156351457934,81.4397880620905141],"hsluv":[216.054756332513932,99.9999999999961,81.4397880620905141]},"#22ee00":{"lch":[82.639607109796458,126.437751030410212,127.039022267349651],"luv":[82.639607109796458,-76.1608929793909368,100.92583052028732],"rgb":[0.133333333333333331,0.933333333333333348,0],"xyz":[0.312328691160491334,0.614865369827271913,0.102219877098565962],"hpluv":[127.039022267349651,308.746810598848469,82.639607109796458],"hsluv":[127.039022267349651,100.000000000002203,82.639607109796458]},"#22ee11":{"lch":[82.6612418520526262,125.587498690937579,127.273852876359626],"luv":[82.6612418520526262,-76.0589691017437,99.9362449095734462],"rgb":[0.133333333333333331,0.933333333333333348,0.0666666666666666657],"xyz":[0.313340356660128438,0.615270036027126821,0.107547982063321598],"hpluv":[127.273852876359626,307.111076239802628,82.6612418520526262],"hsluv":[127.273852876359626,98.9080389542438638,82.6612418520526262]},"#22ee22":{"lch":[82.7013218186993271,124.026614606467561,127.715012949240375],"luv":[82.7013218186993271,-75.8713392100017643,98.112899341636421],"rgb":[0.133333333333333331,0.933333333333333348,0.133333333333333331],"xyz":[0.315215714798605495,0.616020179282517621,0.117424868259300791],"hpluv":[127.715012949240375,304.102865014696874,82.7013218186993271],"hsluv":[127.715012949240375,96.8972824334497176,82.7013218186993271]},"#22ee33":{"lch":[82.7672420886773921,121.499708898279266,128.458265706389938],"luv":[82.7672420886773921,-75.5660658728233443,95.1417308591278754],"rgb":[0.133333333333333331,0.933333333333333348,0.2],"xyz":[0.318303465531063201,0.617255279575500748,0.133687022116911941],"hpluv":[128.458265706389938,299.21821405622444,82.7672420886773921],"hsluv":[128.458265706389938,96.9191735237910308,82.7672420886773921]},"#22ee44":{"lch":[82.8622607061112575,117.945648419515081,129.569612755667265],"luv":[82.8622607061112575,-75.1331770294334,90.918544261133448],"rgb":[0.133333333333333331,0.933333333333333348,0.266666666666666663],"xyz":[0.322761460775282116,0.619038477673188314,0.15716579706979858],"hpluv":[129.569612755667265,292.317409010606752,82.8622607061112575],"hsluv":[129.569612755667265,96.9502397298715692,82.8622607061112575]},"#22ee55":{"lch":[82.9890600071846194,113.365618159982461,131.129866929811442],"luv":[82.9890600071846194,-74.5682726576598185,85.3893207236587],"rgb":[0.133333333333333331,0.933333333333333348,0.333333333333333315],"xyz":[0.328723874814644101,0.621423443288933064,0.188567844343772495],"hpluv":[131.129866929811442,283.372415217622233,82.9890600071846194],"hsluv":[131.129866929811442,96.9908233877961266,82.9890600071846194]},"#22ee66":{"lch":[83.1498978333136,107.825536766413322,133.243989823694022],"luv":[83.1498978333136,-73.8719849852999175,78.5447402013449647],"rgb":[0.133333333333333331,0.933333333333333348,0.4],"xyz":[0.336308870588152287,0.624457441598336382,0.228515488750916429],"hpluv":[133.243989823694022,272.476761047092111,83.1498978333136],"hsluv":[133.243989823694022,97.0409162623008683,83.1498978333136]},"#22ee77":{"lch":[83.3466879629012709,101.462411308546436,136.05169958656856],"luv":[83.3466879629012709,-73.0495185954435726,70.415827350948561],"rgb":[0.133333333333333331,0.933333333333333348,0.466666666666666674],"xyz":[0.345622883608354192,0.628183046806417233,0.277569290657314338],"hpluv":[136.05169958656856,259.869348467080897,83.3466879629012709],"hsluv":[136.05169958656856,97.1001922741487391,83.3466879629012709]},"#22ee88":{"lch":[83.5810478428977746,94.494960715205238,139.739189865999265],"luv":[83.5810478428977746,-72.1101014829990277,61.0690663485185681],"rgb":[0.133333333333333331,0.933333333333333348,0.533333333333333326],"xyz":[0.356763300710298,0.632639213647194776,0.336242154060886533],"hpluv":[139.739189865999265,245.976403795765407,83.5810478428977746],"hsluv":[139.739189865999265,97.1680458209452098,83.5810478428977746]},"#22ee99":{"lch":[83.8543293451422187,87.2401092672494514,144.548413258572367],"luv":[83.8543293451422187,-71.0663081347816,50.6005584263049286],"rgb":[0.133333333333333331,0.933333333333333348,0.6],"xyz":[0.369820264819370692,0.637861999290824,0.405008831702004413],"hpluv":[144.548413258572367,231.480208097577446,83.8543293451422187],"hsluv":[144.548413258572367,97.2436385928483844,83.8543293451422187]},"#22eeaa":{"lch":[84.1676401551603846,80.1359348037682508,150.771943883792943],"luv":[84.1676401551603846,-69.9332745317766324,39.1293388665967328],"rgb":[0.133333333333333331,0.933333333333333348,0.66666666666666663],"xyz":[0.384877957784623248,0.643885076476925056,0.484312681319003],"hpluv":[150.771943883792943,217.42312560604816,84.1676401551603846],"hsluv":[150.771943883792943,97.3259536357082311,84.1676401551603846]},"#22eebb":{"lch":[84.5218598825754697,73.7647249619211181,158.704077932293842],"luv":[84.5218598825754697,-68.7278540770417834,26.7902355844945639],"rgb":[0.133333333333333331,0.933333333333333348,0.733333333333333282],"xyz":[0.402015549891959922,0.650740113319859814,0.57457066641764476],"hpluv":[158.704077932293842,205.339796192481117,84.5218598825754697],"hsluv":[158.704077932293842,97.4138533690930331,84.5218598825754697]},"#22eecc":{"lch":[84.9176532530853621,68.8500130904050422,168.499772582144715],"luv":[84.9176532530853621,-67.467774257192545,13.7267526869778429],"rgb":[0.133333333333333331,0.933333333333333348,0.8],"xyz":[0.421307925335681621,0.658457063497348671,0.676177177087914916],"hpluv":[168.499772582144715,197.354512375483154,84.9176532530853621],"hsluv":[168.499772582144715,97.5061375012374896,84.9176532530853621]},"#22eedd":{"lch":[85.3554818050158275,66.1709053937965166,179.926877690260085],"luv":[85.3554818050158275,-66.170851505859261,0.0844489448895467398],"rgb":[0.133333333333333331,0.933333333333333348,0.866666666666666696],"xyz":[0.44282625088631522,0.667064393717602178,0.789507024987920913],"hpluv":[179.926877690260085,196.075052309852396,85.3554818050158275],"hsluv":[179.926877690260085,97.6015969291830174,85.3554818050158275]},"#22eeee":{"lch":[85.8356149635753667,66.3470894225537648,192.177050630061245],"luv":[85.8356149635753667,-64.8543104533760868,-13.9948094114017536],"rgb":[0.133333333333333331,0.933333333333333348,0.933333333333333348],"xyz":[0.46663843115248993,0.676589265824072195,0.914917841056444137],"hpluv":[192.177050630061245,204.089886920334152,85.8356149635753667],"hsluv":[192.177050630061245,97.6990604766853608,85.8356149635753667]},"#22eeff":{"lch":[86.35814102124138,69.583621560973242,204.067857145017655],"luv":[86.35814102124138,-63.5342376580599435,-28.377474072755291],"rgb":[0.133333333333333331,0.933333333333333348,1],"xyz":[0.492809479562321351,0.687057685188004919,1.05275202934822598],"hpluv":[204.067857145017655,223.225826840448832,86.35814102124138],"hsluv":[204.067857145017655,99.9999999999940883,86.35814102124138]},"#22ff00":{"lch":[87.8997189713237361,134.70927246092154,127.137510750393233],"luv":[87.8997189713237361,-81.328032504319566,107.388729464162736],"rgb":[0.133333333333333331,1,0],"xyz":[0.364181063590165166,0.718570114686621,0.119504001241790073],"hpluv":[127.137510750393233,493.515561032875894,87.8997189713237361],"hsluv":[127.137510750393233,100.000000000002359,87.8997189713237361]},"#22ff11":{"lch":[87.9192191859362708,133.935112153716517,127.338384986715198],"luv":[87.9192191859362708,-81.2344832365115792,106.487431187561],"rgb":[0.133333333333333331,1,0.0666666666666666657],"xyz":[0.36519272908980227,0.718974780886475928,0.124832106206545709],"hpluv":[127.338384986715198,491.550771148457443,87.9192191859362708],"hsluv":[127.338384986715198,99.9999999999918572,87.9192191859362708]},"#22ff22":{"lch":[87.9553480404818089,132.511927889398493,127.71501294924046],"luv":[87.9553480404818089,-81.0620967295481449,104.825319015849075],"rgb":[0.133333333333333331,1,0.133333333333333331],"xyz":[0.367068087228279327,0.719724924141866729,0.134708992402524902],"hpluv":[127.71501294924046,487.932270281505453,87.9553480404818089],"hsluv":[127.71501294924046,99.9999999999918,87.9553480404818089]},"#22ff33":{"lch":[88.0147790356886,130.202284180175667,128.347396099003475],"luv":[88.0147790356886,-80.7811428723405101,102.112887345201102],"rgb":[0.133333333333333331,1,0.2],"xyz":[0.370155837960737033,0.720960024434849855,0.150971146260136052],"hpluv":[128.347396099003475,482.0420586134328,88.0147790356886],"hsluv":[128.347396099003475,99.9999999999918572,88.0147790356886]},"#22ff44":{"lch":[88.1004639745127349,126.941230298117631,129.288082018787549],"luv":[88.1004639745127349,-80.3817123888383,98.2489504424236486],"rgb":[0.133333333333333331,1,0.266666666666666663],"xyz":[0.374613833204955948,0.722743222532537422,0.174449921213022691],"hpluv":[129.288082018787549,473.688351575452941,88.1004639745127349],"hsluv":[129.288082018787549,99.9999999999917719,88.1004639745127349]},"#22ff55":{"lch":[88.2148445849976497,122.715034192366474,130.599301535876663],"luv":[88.2148445849976497,-79.8586444797792865,93.1749779645044498],"rgb":[0.133333333333333331,1,0.333333333333333315],"xyz":[0.380576247244317933,0.725128188148282171,0.205851968486996606],"hpluv":[130.599301535876663,462.799362736769183,88.2148445849976497],"hsluv":[130.599301535876663,99.9999999999917,88.2148445849976497]},"#22ff66":{"lch":[88.3599902775167863,117.562049147645283,132.359544385640646],"luv":[88.3599902775167863,-79.2110524978463104,86.8702743288911279],"rgb":[0.133333333333333331,1,0.4],"xyz":[0.388161243017826119,0.72816218645768549,0.24579961289414054],"hpluv":[132.359544385640646,449.432018335727776,88.3599902775167863],"hsluv":[132.359544385640646,99.999999999991644,88.3599902775167863]},"#22ff77":{"lch":[88.5376718023346427,111.576626717172417,134.67079586388752],"luv":[88.5376718023346427,-78.441973739162,79.3486004003085839],"rgb":[0.133333333333333331,1,0.466666666666666674],"xyz":[0.397475256038028,0.731887791665766341,0.294853414800538449],"hpluv":[134.67079586388752,433.796433649144,88.5376718023346427],"hsluv":[134.67079586388752,99.9999999999914593,88.5376718023346427]},"#22ff88":{"lch":[88.7494051061703,104.915784817642518,137.666744209541747],"luv":[88.7494051061703,-77.5579802767934581,70.6546643845003786],"rgb":[0.133333333333333331,1,0.533333333333333326],"xyz":[0.408615673139971824,0.736343958506543883,0.353526278204110644],"hpluv":[137.666744209541747,416.300130961303353,88.7494051061703],"hsluv":[137.666744209541747,99.9999999999915161,88.7494051061703]},"#22ff99":{"lch":[88.996479539624346,97.8095196496336143,141.520869213027311],"luv":[88.996479539624346,-76.5687003963823827,60.8599725082183696],"rgb":[0.133333333333333331,1,0.6],"xyz":[0.42167263724904458,0.741566744150173096,0.422292955845228524],"hpluv":[141.520869213027311,397.621886071746928,88.996479539624346],"hsluv":[141.520869213027311,99.9999999999913882,88.996479539624346]},"#22ffaa":{"lch":[89.2799772586324281,90.5758041558366784,146.450029989774293],"luv":[89.2799772586324281,-75.4862499862398,50.057989986528554],"rgb":[0.133333333333333331,1,0.66666666666666663],"xyz":[0.43673033021429708,0.747589821336274163,0.50159680546222718],"hpluv":[146.450029989774293,378.829469872945424,89.2799772586324281],"hsluv":[146.450029989774293,99.9999999999911893,89.2799772586324281]},"#22ffbb":{"lch":[89.6007875020334552,83.6393655876379825,152.701818689515648],"luv":[89.6007875020334552,-74.3245992165371661,38.3587985630895787],"rgb":[0.133333333333333331,1,0.733333333333333282],"xyz":[0.453867922321633754,0.754444858179208921,0.591854790560868871],"hpluv":[152.701818689515648,361.553698033539774,89.6007875020334552],"hsluv":[152.701818689515648,99.9999999999909903,89.6007875020334552]},"#22ffcc":{"lch":[89.9596178804745,77.5461751086222,160.50148390925915],"luv":[89.9596178804745,-73.0989125181650223,25.8835519710636532],"rgb":[0.133333333333333331,1,0.8],"xyz":[0.473160297765355509,0.762161808356697779,0.693461301231139],"hpluv":[160.50148390925915,348.207300802542932,89.9596178804745],"hsluv":[160.50148390925915,99.999999999990834,89.9596178804745]},"#22ffdd":{"lch":[90.3570039795250466,72.9493687180361,169.926987012389134],"luv":[90.3570039795250466,-71.8249031216737421,12.7590629719491808],"rgb":[0.133333333333333331,1,0.866666666666666696],"xyz":[0.494678623315989,0.770769138576951285,0.806791149131145],"hpluv":[169.926987012389134,342.16275562632859,90.3570039795250466],"hsluv":[169.926987012389134,99.9999999999906,90.3570039795250466]},"#22ffee":{"lch":[90.793318095908873,70.5238201303846637,180.720785562676866],"luv":[90.793318095908873,-70.5182397089352,-0.887171987837557796],"rgb":[0.133333333333333331,1,0.933333333333333348],"xyz":[0.518490803582163817,0.780294010683421302,0.932201965199668248],"hpluv":[180.720785562676866,347.681124246536797,90.793318095908873],"hsluv":[180.720785562676866,99.9999999999901661,90.793318095908873]},"#22ffff":{"lch":[91.2687776254429082,70.7867026205843786,192.177050630061217],"luv":[91.2687776254429082,-69.1940343982234225,-14.9312715999851058],"rgb":[0.133333333333333331,1,1],"xyz":[0.544661851991995127,0.790762430047354,1.0700361534914502],"hpluv":[192.177050630061217,369.384676987995,91.2687776254429082],"hsluv":[192.177050630061217,99.9999999999901803,91.2687776254429082]},"#11aa00":{"lch":[60.6644104521350869,93.0873160838275,127.211890667698796],"luv":[60.6644104521350869,-56.2958954857129186,74.1351506854346241],"rgb":[0.0666666666666666657,0.66666666666666663,0],"xyz":[0.146052570780394131,0.288673842599075969,0.0480220097587461675],"hpluv":[127.211890667698796,194.713406103753528,60.6644104521350869],"hsluv":[127.211890667698796,100.000000000002444,60.6644104521350869]},"#11aa11":{"lch":[60.7002167335786424,91.7670835597914447,127.715012949240375],"luv":[60.7002167335786424,-56.1370762813229547,72.5935692169401],"rgb":[0.0666666666666666657,0.66666666666666663,0.0666666666666666657],"xyz":[0.147064236280031263,0.289078508798930822,0.0533501147235018],"hpluv":[127.715012949240375,191.838607973199288,60.7002167335786424],"hsluv":[127.715012949240375,97.6800439707354826,60.7002167335786424]},"#11aa22":{"lch":[60.7665037483511696,89.3702510768545153,128.6744569519864],"luv":[60.7665037483511696,-55.8469935821418844,69.7721655488506229],"rgb":[0.0666666666666666657,0.66666666666666663,0.133333333333333331],"xyz":[0.148939594418508264,0.289828652054321623,0.063227000919481],"hpluv":[128.6744569519864,186.624241227076766,60.7665037483511696],"hsluv":[128.6744569519864,97.7012125574833163,60.7665037483511696]},"#11aa33":{"lch":[60.8753956347493101,85.5662665428975799,130.333267948257316],"luv":[60.8753956347493101,-55.3812688292774595,65.2265362636212274],"rgb":[0.0666666666666666657,0.66666666666666663,0.2],"xyz":[0.152027345150966,0.291063752347304749,0.0794891547770921469],"hpluv":[130.333267948257316,178.361088002118152,60.8753956347493101],"hsluv":[130.333267948257316,97.7352371443594876,60.8753956347493101]},"#11aa44":{"lch":[61.0320681383245898,80.3855440613202603,132.913331110856149],"luv":[61.0320681383245898,-54.7338170014505394,58.8731260464924233],"rgb":[0.0666666666666666657,0.66666666666666663,0.266666666666666663],"xyz":[0.156485340395184885,0.292846950444992316,0.102967929729978785],"hpluv":[132.913331110856149,167.131840298358668,61.0320681383245898],"hsluv":[132.913331110856149,97.7826211010278428,61.0320681383245898]},"#11aa55":{"lch":[61.2406211479126199,74.0326893716562466,136.73626291081149],"luv":[61.2406211479126199,-53.9110982897111626,50.7388665304739064],"rgb":[0.0666666666666666657,0.66666666666666663,0.333333333333333315],"xyz":[0.162447754434546898,0.295231916060737176,0.134369977003952701],"hpluv":[136.73626291081149,153.399260409180499,61.2406211479126199],"hsluv":[136.73626291081149,97.8429805383323412,61.2406211479126199]},"#11aa66":{"lch":[61.5043118059827236,66.9183608277608926,142.276062400218507],"luv":[61.5043118059827236,-52.9302802927860938,40.944504442006675],"rgb":[0.0666666666666666657,0.66666666666666663,0.4],"xyz":[0.170032750208055056,0.298265914370140495,0.174317621411096635],"hpluv":[142.276062400218507,138.063556785316223,61.5043118059827236],"hsluv":[142.276062400218507,97.9151756761398246,61.5043118059827236]},"#11aa77":{"lch":[61.8256765996828648,59.7171413308715628,150.193024237310198],"luv":[61.8256765996828648,-51.8168585560505335,29.6841731923518672],"rgb":[0.0666666666666666657,0.66666666666666663,0.466666666666666674],"xyz":[0.179346763228257,0.30199151957822129,0.223371423317494544],"hpluv":[150.193024237310198,122.565843528602272,61.8256765996828648],"hsluv":[150.193024237310198,97.9974781059027578,61.8256765996828648]},"#11aa88":{"lch":[62.2066058842594,53.445591933814967,161.225226782668472],"luv":[62.2066058842594,-50.6018085779820197,17.201403018159084],"rgb":[0.0666666666666666657,0.66666666666666663,0.533333333333333326],"xyz":[0.190487180330200789,0.306447686418998888,0.282044286721066739],"hpluv":[161.225226782668472,109.022142353571084,62.2066058842594],"hsluv":[161.225226782668472,98.0877698343988698,62.2066058842594]},"#11aa99":{"lch":[62.6483970296267643,49.4620441969123803,175.635441576327452],"luv":[62.6483970296267643,-49.3186051456987613,3.76417356400704],"rgb":[0.0666666666666666657,0.66666666666666663,0.6],"xyz":[0.203544144439273517,0.311670472062628046,0.350810964362184619],"hpluv":[175.635441576327452,100.184705161952,62.6483970296267643],"hsluv":[175.635441576327452,98.1837511724305756,62.6483970296267643]},"#11aaaa":{"lch":[63.1517986220979424,49.10533458105958,192.177050630061103],"luv":[63.1517986220979424,-48.0004871585874326,-10.3579494522848794],"rgb":[0.0666666666666666657,0.66666666666666663,0.66666666666666663],"xyz":[0.218601837404526045,0.317693549248729168,0.430114813979183219],"hpluv":[192.177050630061103,98.6693521766944741,63.1517986220979424],"hsluv":[192.177050630061103,98.283131385506934,63.1517986220979424]},"#11aabb":{"lch":[63.7170519890822931,52.9100997091116483,208.088870357104184],"luv":[63.7170519890822931,-46.6782604891356812,-24.9122188681885817],"rgb":[0.0666666666666666657,0.66666666666666663,0.733333333333333282],"xyz":[0.235739429511862719,0.324548586091663926,0.520372799077825],"hpluv":[208.088870357104184,105.371274370578277,63.7170519890822931],"hsluv":[208.088870357104184,98.3837818799450474,63.7170519890822931]},"#11aacc":{"lch":[64.3439331362496603,60.2774830024396,221.163749704229559],"luv":[64.3439331362496603,-45.3787880982832661,-39.6754401089704345],"rgb":[0.0666666666666666657,0.66666666666666663,0.8],"xyz":[0.255031804955584418,0.332265536269152728,0.621979309748095122],"hpluv":[221.163749704229559,118.873987633214512,64.3439331362496603],"hsluv":[221.163749704229559,98.4838416101877385,64.3439331362496603]},"#11aadd":{"lch":[65.0317963778061738,70.0923801470555,230.985682804055784],"luv":[65.0317963778061738,-44.1241742926816372,-54.4609860144708762],"rgb":[0.0666666666666666657,0.66666666666666663,0.866666666666666696],"xyz":[0.276550130506218,0.340872866489406234,0.735309157648101119],"hpluv":[230.985682804055784,136.767964522831733,65.0317963778061738],"hsluv":[230.985682804055784,98.5817742563244,65.0317963778061738]},"#11aaee":{"lch":[65.7796198544585877,81.3683973110580325,238.155251398024461],"luv":[65.7796198544585877,-42.9315457639956293,-69.1208974137644248],"rgb":[0.0666666666666666657,0.66666666666666663,0.933333333333333348],"xyz":[0.300362310772392727,0.350397738595876251,0.860719973716624343],"hpluv":[238.155251398024461,156.965326989669,65.7796198544585877],"hsluv":[238.155251398024461,98.676383948407647,65.7796198544585877]},"#11aaff":{"lch":[66.5860524818013317,93.423779787985481,243.412392023658668],"luv":[66.5860524818013317,-41.8132782993845566,-83.5443139162218529],"rgb":[0.0666666666666666657,0.66666666666666663,1],"xyz":[0.326533359182224148,0.360866157959809,0.998554162008406188],"hpluv":[243.412392023658668,178.038321821181739,66.5860524818013317],"hsluv":[243.412392023658668,99.9999999999982805,66.5860524818013317]},"#11bb00":{"lch":[66.2579979425279788,101.837028338191359,127.308350947248712],"luv":[66.2579979425279788,-61.7238643700190792,80.9996599251199285],"rgb":[0.0666666666666666657,0.733333333333333282,0],"xyz":[0.180007068688992911,0.356582838416274528,0.0593401757282787864],"hpluv":[127.308350947248712,195.032386644097869,66.2579979425279788],"hsluv":[127.308350947248712,100.000000000002416,66.2579979425279788]},"#11bb11":{"lch":[66.2891028676776,100.667761827005108,127.715012949240403],"luv":[66.2891028676776,-61.5819268253258301,79.6345688739434507],"rgb":[0.0666666666666666657,0.733333333333333282,0.0666666666666666657],"xyz":[0.181018734188630043,0.356987504616129381,0.0646682806930344162],"hpluv":[127.715012949240403,192.702610495025482,66.2891028676776],"hsluv":[127.715012949240403,98.1199752505464318,66.2891028676776]},"#11bb22":{"lch":[66.3467009890152895,98.5365229927559199,128.48627008521666],"luv":[66.3467009890152895,-61.3219466901703356,77.130183570569983],"rgb":[0.0666666666666666657,0.733333333333333282,0.133333333333333331],"xyz":[0.182894092327107044,0.357737647871520181,0.0745451668890136088],"hpluv":[128.48627008521666,188.459149582366734,66.3467009890152895],"hsluv":[128.48627008521666,98.1339007760711155,66.3467009890152895]},"#11bb33":{"lch":[66.4413603116689586,95.1297105779412107,129.807139434656818],"luv":[66.4413603116689586,-60.9025570517959949,73.0790009455219121],"rgb":[0.0666666666666666657,0.733333333333333282,0.2],"xyz":[0.185981843059564778,0.358972748164503308,0.0908073207466247589],"hpluv":[129.807139434656818,181.684126992490178,66.4413603116689586],"hsluv":[129.807139434656818,98.1563849168539093,66.4413603116689586]},"#11bb44":{"lch":[66.5776441235544,90.4345556189602888,131.832147550242752],"luv":[66.5776441235544,-60.3153845158839061,67.3829595721343679],"rgb":[0.0666666666666666657,0.733333333333333282,0.266666666666666663],"xyz":[0.190439838303783665,0.360755946262190874,0.114286095699511397],"hpluv":[131.832147550242752,172.363503065423913,66.5776441235544],"hsluv":[131.832147550242752,98.1879073212924567,66.5776441235544]},"#11bb55":{"lch":[66.7592187944261,84.5672269635890501,134.774448398028227],"luv":[66.7592187944261,-59.5621947933412841,60.0329978237906374],"rgb":[0.0666666666666666657,0.733333333333333282,0.333333333333333315],"xyz":[0.196402252343145678,0.363140911877935735,0.145688142973485313],"hpluv":[134.774448398028227,160.742297130584,66.7592187944261],"hsluv":[134.774448398028227,98.2284201297941451,66.7592187944261]},"#11bb66":{"lch":[66.9890609579081513,77.7896938122995749,138.938350400658521],"luv":[66.9890609579081513,-58.6536805127572336,51.0977712402284752],"rgb":[0.0666666666666666657,0.733333333333333282,0.4],"xyz":[0.203987248116653835,0.366174910187339053,0.185635787380629275],"hpluv":[138.938350400658521,147.352496635070423,66.9890609579081513],"hsluv":[138.938350400658521,98.2774122804504486,66.9890609579081513]},"#11bb77":{"lch":[67.2695660469751573,70.5410036497719375,144.751753478195667],"luv":[67.2695660469751573,-57.6079608572489548,40.7106379437464625],"rgb":[0.0666666666666666657,0.733333333333333282,0.466666666666666674],"xyz":[0.213301261136855769,0.369900515395419849,0.234689589287027184],"hpluv":[144.751753478195667,133.064539371584743,67.2695660469751573],"hsluv":[144.751753478195667,98.33398740837616,67.2695660469751573]},"#11bb88":{"lch":[67.6026131767386289,63.4868829762913904,152.765342955174589],"luv":[67.6026131767386289,-56.44870944299889,29.0538725863731493],"rgb":[0.0666666666666666657,0.733333333333333282,0.533333333333333326],"xyz":[0.224441678238799569,0.374356682236197447,0.293362452690599351],"hpluv":[152.765342955174589,119.168054047142519,67.6026131767386289],"hsluv":[152.765342955174589,98.3969602233376293,67.6026131767386289]},"#11bb99":{"lch":[67.9896091217093357,57.5709210660889568,163.510238814203348],"luv":[67.9896091217093357,-55.2030563361408468,16.3411604100414145],"rgb":[0.0666666666666666657,0.733333333333333282,0.6],"xyz":[0.237498642347872296,0.379579467879826604,0.362129130331717231],"hpluv":[163.510238814203348,107.448401728013394,67.9896091217093357],"hsluv":[163.510238814203348,98.464964167861,67.9896091217093357]},"#11bbaa":{"lch":[68.431522322705149,53.97217733059707,177.026074660918823],"luv":[68.431522322705149,-53.8994902384006807,2.80015675382041573],"rgb":[0.0666666666666666657,0.733333333333333282,0.66666666666666663],"xyz":[0.252556335313124825,0.385602545065927726,0.441432979948715831],"hpluv":[177.026074660918823,100.081328983600983,68.431522322705149],"hsluv":[177.026074660918823,98.5365589333087684,68.431522322705149]},"#11bbbb":{"lch":[68.9289126417652511,53.7759127589290102,192.177050630061103],"luv":[68.9289126417652511,-52.5659794775517426,-11.3431298424003177],"rgb":[0.0666666666666666657,0.733333333333333282,0.733333333333333282],"xyz":[0.269693927420461499,0.392457581908862485,0.531690965047357578],"hpluv":[192.177050630061103,98.9978332941913095,68.9289126417652511],"hsluv":[192.177050630061103,98.6103267315429122,68.9289126417652511]},"#11bbcc":{"lch":[69.4819599404948463,57.3930965266865485,206.799543430538137],"luv":[69.4819599404948463,-51.2284702417124365,-25.8768499940688805],"rgb":[0.0666666666666666657,0.733333333333333282,0.8],"xyz":[0.288986302864183253,0.400174532086351287,0.633297475717627734],"hpluv":[206.799543430538137,104.81584090136549,69.4819599404948463],"hsluv":[206.799543430538137,98.6849492658553658,69.4819599404948463]},"#11bbdd":{"lch":[70.0904930703520535,64.3454332007566876,219.135570681285316],"luv":[70.0904930703520535,-49.9098388382008054,-40.6121011637893901],"rgb":[0.0666666666666666657,0.733333333333333282,0.866666666666666696],"xyz":[0.310504628414816741,0.408781862306604793,0.746627323617633731],"hpluv":[219.135570681285316,116.492493254234162,70.0904930703520535],"hsluv":[219.135570681285316,98.7592614999562244,70.0904930703520535]},"#11bbee":{"lch":[70.7540199625255184,73.7064384587933858,228.717665412779098],"luv":[70.7540199625255184,-48.6292974270947838,-55.3879996211006826],"rgb":[0.0666666666666666657,0.733333333333333282,0.933333333333333348],"xyz":[0.334316808680991506,0.41830673441307481,0.872038139686157],"hpluv":[228.717665412779098,132.188487390259695,70.7540199625255184],"hsluv":[228.717665412779098,98.8322822642660412,70.7540199625255184]},"#11bbff":{"lch":[71.471758937406932,84.600620314641418,235.923069973878228],"luv":[71.471758937406932,-47.4021956671632836,-70.0735099988154246],"rgb":[0.0666666666666666657,0.733333333333333282,1],"xyz":[0.360487857090822872,0.428775153777007534,1.00987232797793891],"hpluv":[235.923069973878228,150.202929688167188,71.471758937406932],"hsluv":[235.923069973878228,99.9999999999978115,71.471758937406932]},"#11cc00":{"lch":[71.760164015117,110.429324102022079,127.380540485202317],"luv":[71.760164015117,-67.042304751477019,87.7494444155603617],"rgb":[0.0666666666666666657,0.8,0],"xyz":[0.21823081199860983,0.433030325035509422,0.0720814234981507346],"hpluv":[127.380540485202317,195.272154443078705,71.760164015117],"hsluv":[127.380540485202317,100.000000000002245,71.760164015117]},"#11cc11":{"lch":[71.7874927519263366,109.385174124956521,127.715012949240432],"luv":[71.7874927519263366,-66.9146672826053219,86.5305935539869466],"rgb":[0.0666666666666666657,0.8,0.0666666666666666657],"xyz":[0.219242477498246963,0.433434991235364275,0.0774095284629063712],"hpluv":[127.715012949240432,193.352149077988855,71.7874927519263366],"hsluv":[127.715012949240432,98.4507061603193563,71.7874927519263366]},"#11cc22":{"lch":[71.8381079866900905,107.476295008714118,128.346772012349533],"luv":[71.8381079866900905,-66.680384726115463,84.2904519004221129],"rgb":[0.0666666666666666657,0.8,0.133333333333333331],"xyz":[0.221117835636723964,0.434185134490755076,0.0872864146588855638],"hpluv":[128.346772012349533,189.84411001864018,71.8381079866900905],"hsluv":[128.346772012349533,98.4601754700601361,71.8381079866900905]},"#11cc33":{"lch":[71.9213183931711626,104.40864440796355,129.421122123890029],"luv":[71.9213183931711626,-66.3010906987881441,80.6556284412913556],"rgb":[0.0666666666666666657,0.8,0.2],"xyz":[0.224205586369181697,0.435420234783738203,0.103548568516496714],"hpluv":[129.421122123890029,184.212095875088124,71.9213183931711626],"hsluv":[129.421122123890029,98.4755168761512749,71.9213183931711626]},"#11cc44":{"lch":[72.0411777660314669,100.144250866202455,131.050559631523186],"luv":[72.0411777660314669,-65.7672084530810395,75.5218198525557085],"rgb":[0.0666666666666666657,0.8,0.266666666666666663],"xyz":[0.228663581613400585,0.437203432881425769,0.127027343469383353],"hpluv":[131.050559631523186,176.394298837834185,72.0411777660314669],"hsluv":[131.050559631523186,98.4971346697200261,72.0411777660314669]},"#11cc55":{"lch":[72.2009771566369523,94.7439152050601621,133.383427271112737],"luv":[72.2009771566369523,-65.077446685205,68.8573554627095],"rgb":[0.0666666666666666657,0.8,0.333333333333333315],"xyz":[0.234625995652762598,0.439588398497170629,0.158429390743357268],"hpluv":[133.383427271112737,166.512782767528847,72.2009771566369523],"hsluv":[133.383427271112737,98.5251071985599225,72.2009771566369523]},"#11cc66":{"lch":[72.4034304155724,88.37638367841096,136.624435218533876],"luv":[72.4034304155724,-64.2379326004453333,60.6949191225620339],"rgb":[0.0666666666666666657,0.8,0.4],"xyz":[0.242210991426270755,0.442622396806573948,0.198377035150501202],"hpluv":[136.624435218533876,154.887514188688357,72.4034304155724],"hsluv":[136.624435218533876,98.5592219307307289,72.4034304155724]},"#11cc77":{"lch":[72.6507717937069657,81.3359578844494422,141.057484765247835],"luv":[72.6507717937069657,-63.261234579889333,51.1229326663597],"rgb":[0.0666666666666666657,0.8,0.466666666666666674],"xyz":[0.251525004446472689,0.446348002014654743,0.247430837056899111],"hpluv":[141.057484765247835,142.063228414279422,72.6507717937069657],"hsluv":[141.057484765247835,98.5990140248714795,72.6507717937069657]},"#11cc88":{"lch":[72.9448138267759703,74.0714793913140284,147.061910762632237],"luv":[72.9448138267759703,-62.1651250648783815,40.2750702654370087],"rgb":[0.0666666666666666657,0.8,0.533333333333333326],"xyz":[0.262665421548416489,0.450804168855432341,0.306103700460471306],"hpluv":[147.061910762632237,128.853412583983044,72.9448138267759703],"hsluv":[147.061910762632237,98.6438145792393755,72.9448138267759703]},"#11cc99":{"lch":[73.286985449663689,67.2264361640895203,155.087429558943455],"luv":[73.286985449663689,-60.9711251229010074,28.3181147072320734],"rgb":[0.0666666666666666657,0.8,0.6],"xyz":[0.275722385657489188,0.456026954499061499,0.374870378101589186],"hpluv":[155.087429558943455,116.399886643338576,73.286985449663689],"hsluv":[155.087429558943455,98.6928071276572609,73.286985449663689]},"#11ccaa":{"lch":[73.6783599756885224,61.6669147974486336,165.501022011161467],"luv":[73.6783599756885224,-59.7029534543248275,15.4390974304365383],"rgb":[0.0666666666666666657,0.8,0.66666666666666663],"xyz":[0.290780078622741744,0.462050031685162621,0.454174227718587786],"hpluv":[165.501022011161467,106.206622375239988,73.6783599756885224],"hsluv":[165.501022011161467,98.7450877264532494,73.6783599756885224]},"#11ccbb":{"lch":[74.1196780643846864,58.4137876130139801,178.201908682105085],"luv":[74.1196780643846864,-58.3850250256368426,1.83287644266177074],"rgb":[0.0666666666666666657,0.8,0.733333333333333282],"xyz":[0.307917670730078419,0.46890506852809738,0.544432212817229533],"hpluv":[178.201908682105085,100.004874571957387,74.1196780643846864],"hsluv":[178.201908682105085,98.7997230732590452,74.1196780643846864]},"#11cccc":{"lch":[74.6113685470067,58.3540675645504,192.177050630061103],"luv":[74.6113685470067,-57.0411279075965751,-12.3088150671508707],"rgb":[0.0666666666666666657,0.8,0.8],"xyz":[0.327210046173800118,0.476622018705586181,0.646038723487499689],"hpluv":[192.177050630061103,99.244272920381249,74.6113685470067],"hsluv":[192.177050630061103,98.8558017207376167,74.6113685470067]},"#11ccdd":{"lch":[75.1535687293590087,61.8087365466066316,205.702276410621693],"luv":[75.1535687293590087,-55.6933672323303881,-26.8061328768737823],"rgb":[0.0666666666666666657,0.8,0.866666666666666696],"xyz":[0.348728371724433717,0.485229348925839687,0.759368571387505686],"hpluv":[205.702276410621693,104.361325002032586,75.1535687293590087],"hsluv":[205.702276410621693,98.9124749687685352,75.1535687293590087]},"#11ccee":{"lch":[75.7461450403856418,68.3900229325434168,217.356690237772426],"luv":[75.7461450403856418,-54.3614174191380712,-41.4973677827407],"rgb":[0.0666666666666666657,0.8,0.933333333333333348],"xyz":[0.372540551990608426,0.494754221032309704,0.88477938745602891],"hpluv":[217.356690237772426,114.570165581500433,75.7461450403856418],"hsluv":[217.356690237772426,98.968985855810871,75.7461450403856418]},"#11ccff":{"lch":[76.3887144168947714,77.3228649101567811,226.666757851513921],"luv":[76.3887144168947714,-53.0620799518220849,-56.2426982736496726],"rgb":[0.0666666666666666657,0.8,1],"xyz":[0.398711600400439847,0.505222640396242428,1.02261357574781075],"hpluv":[226.666757851513921,131.304642630845649,76.3887144168947714],"hsluv":[226.666757851513921,99.9999999999969162,76.3887144168947714]},"#11dd00":{"lch":[77.1789729208637851,118.880191052714352,127.435820588671049],"luv":[77.1789729208637851,-72.2639845338074,94.3950017957916572],"rgb":[0.0666666666666666657,0.866666666666666696,0],"xyz":[0.260864802545785,0.518298306129860942,0.0862927536805420531],"hpluv":[127.435820588671049,210.367240137055802,77.1789729208637851],"hsluv":[127.435820588671049,100.000000000002302,77.1789729208637851]},"#11dd11":{"lch":[77.2032167276219,117.940964566200989,127.715012949240474],"luv":[77.2032167276219,-72.148538100067,93.2987651195291],"rgb":[0.0666666666666666657,0.866666666666666696,0.0666666666666666657],"xyz":[0.261876468045422084,0.51870297232971585,0.0916208586452976897],"hpluv":[127.715012949240474,208.973000844217893,77.2032167276219],"hsluv":[127.715012949240474,98.7048375113237739,77.2032167276219]},"#11dd22":{"lch":[77.2481249515021773,116.219968574506154,128.240715222563949],"luv":[77.2481249515021773,-71.936288170647174,91.2811674974022509],"rgb":[0.0666666666666666657,0.866666666666666696,0.133333333333333331],"xyz":[0.263751826183899141,0.519453115585106651,0.101497744841276882],"hpluv":[128.240715222563949,206.413967447437244,77.2481249515021773],"hsluv":[128.240715222563949,98.7114617332334348,77.2481249515021773]},"#11dd33":{"lch":[77.3219716074714114,113.443027450646795,129.129905575085218],"luv":[77.3219716074714114,-71.591714193384675,87.9996984996024],"rgb":[0.0666666666666666657,0.866666666666666696,0.2],"xyz":[0.266839576916356847,0.520688215878089777,0.117759898698888033],"hpluv":[129.129905575085218,202.273081507843187,77.3219716074714114],"hsluv":[129.129905575085218,98.7222220245650419,77.3219716074714114]},"#11dd44":{"lch":[77.4283833065767,109.557638087167803,130.467479357182611],"luv":[77.4283833065767,-71.1046976382296378,83.3486534805139],"rgb":[0.0666666666666666657,0.866666666666666696,0.266666666666666663],"xyz":[0.271297572160575762,0.522471413975777343,0.141238673651774671],"hpluv":[130.467479357182611,196.45511110559741,77.4283833065767],"hsluv":[130.467479357182611,98.737444128486942,77.4283833065767]},"#11dd55":{"lch":[77.5703274630482156,104.589066335953675,132.360930841179908],"luv":[77.5703274630482156,-70.4719757705036471,77.2824263854860192],"rgb":[0.0666666666666666657,0.866666666666666696,0.333333333333333315],"xyz":[0.277259986199937747,0.524856379591522093,0.172640720925748559],"hpluv":[132.360930841179908,188.974657198429043,77.5703274630482156],"hsluv":[132.360930841179908,98.7572451358875583,77.5703274630482156]},"#11dd66":{"lch":[77.7502795105496176,98.645271303892585,134.953797592355841],"luv":[77.7502795105496176,-69.6964700953403167,69.8089650895062732],"rgb":[0.0666666666666666657,0.866666666666666696,0.4],"xyz":[0.284844981973445932,0.527890377900925412,0.212588365332892548],"hpluv":[134.953797592355841,179.968822287066047,77.7502795105496176],"hsluv":[134.953797592355841,98.7815546318288114,77.7502795105496176]},"#11dd77":{"lch":[77.9703113413929714,91.9272626112809377,138.440937564009943],"luv":[77.9703113413929714,-68.7866216277350588,60.9837871589344616],"rgb":[0.0666666666666666657,0.866666666666666696,0.466666666666666674],"xyz":[0.294158994993647838,0.531615983109006263,0.261642167239290457],"hpluv":[138.440937564009943,169.723893920939275,77.9703113413929714],"hsluv":[138.440937564009943,98.8101351189296,77.9703113413929714]},"#11dd88":{"lch":[78.2321436880382919,84.7462074021241705,143.083472555296623],"luv":[78.2321436880382919,-67.7555613828794492,50.90288371727776],"rgb":[0.0666666666666666657,0.866666666666666696,0.533333333333333326],"xyz":[0.305299412095591638,0.536072149949783805,0.320315030642862597],"hpluv":[143.083472555296623,158.721324423216174,78.2321436880382919],"hsluv":[143.083472555296623,98.842607114853692,78.2321436880382919]},"#11dd99":{"lch":[78.5371801027425,77.5491781494168748,149.212222309724666],"luv":[78.5371801027425,-66.6201031545698,39.6942928810235145],"rgb":[0.0666666666666666657,0.866666666666666696,0.6],"xyz":[0.318356376204664393,0.541294935593413,0.389081708283980532],"hpluv":[149.212222309724666,147.710574340426348,78.5371801027425],"hsluv":[149.212222309724666,98.8784794246756746,78.5371801027425]},"#11ddaa":{"lch":[78.8865310768390771,70.9495750262721288,157.187121587348372],"luv":[78.8865310768390771,-65.3996173248364414,27.5087667875819264],"rgb":[0.0666666666666666657,0.866666666666666696,0.66666666666666663],"xyz":[0.333414069169916893,0.547318012779514085,0.468385557900979133],"hpluv":[157.187121587348372,137.807232739715857,78.8865310768390771],"hsluv":[157.187121587348372,98.9171828916172728,78.8865310768390771]},"#11ddbb":{"lch":[79.2810328759594398,65.7363215025974483,167.247861929956969],"luv":[79.2810328759594398,-64.1148749316804611,14.5102300873497096],"rgb":[0.0666666666666666657,0.866666666666666696,0.733333333333333282],"xyz":[0.350551661277253568,0.554173049622448843,0.558643542999620824],"hpluv":[167.247861929956969,130.572542181043048,79.2810328759594398],"hsluv":[167.247861929956969,98.9581049946704496,79.2810328759594398]},"#11ddcc":{"lch":[79.7212637056701396,62.7929370759791,179.209087927276954],"luv":[79.7212637056701396,-62.7869545437069903,0.866767416521026846],"rgb":[0.0666666666666666657,0.866666666666666696,0.8],"xyz":[0.369844036720975322,0.561889999799937701,0.660250053669891],"hpluv":[179.209087927276954,127.935201467087722,79.7212637056701396],"hsluv":[179.209087927276954,99.0006225499112,79.7212637056701396]},"#11dddd":{"lch":[80.2075587483664378,62.8503941808937796,192.177050630061132],"luv":[80.2075587483664378,-61.4362892449526,-13.2572400032679489],"rgb":[0.0666666666666666657,0.866666666666666696,0.866666666666666696],"xyz":[0.39136236227160881,0.570497330020191207,0.773579901569897],"hpluv":[192.177050630061132,131.767009082741112,80.2075587483664378],"hsluv":[192.177050630061132,99.0441302201931109,80.2075587483664378]},"#11ddee":{"lch":[80.7400249746916643,66.1629514334268691,204.757295278220823],"luv":[80.7400249746916643,-60.0819052998990202,-27.707414132610225],"rgb":[0.0666666666666666657,0.866666666666666696,0.933333333333333348],"xyz":[0.415174542537783575,0.580022202126661224,0.8989907176384202],"hpluv":[204.757295278220823,143.22067561241397,80.7400249746916643],"hsluv":[204.757295278220823,99.0880633014724594,80.7400249746916643]},"#11ddff":{"lch":[81.3185562290371848,72.4120095186264194,215.786316478612605],"luv":[81.3185562290371848,-58.7408753400219084,-42.3439332940817934],"rgb":[0.0666666666666666657,0.866666666666666696,1],"xyz":[0.441345590947614941,0.590490621490594,1.03682490593020216],"hpluv":[215.786316478612605,162.428807277722512,81.3185562290371848],"hsluv":[215.786316478612605,99.9999999999959925,81.3185562290371848]}} \ No newline at end of file diff --git a/vendor/github.com/lucasb-eyer/go-colorful/hsluv.go b/vendor/github.com/lucasb-eyer/go-colorful/hsluv.go new file mode 100644 index 000000000..d19fb6443 --- /dev/null +++ b/vendor/github.com/lucasb-eyer/go-colorful/hsluv.go @@ -0,0 +1,207 @@ +package colorful + +import "math" + +// Source: https://github.com/hsluv/hsluv-go +// Under MIT License +// Modified so that Saturation and Luminance are in [0..1] instead of [0..100]. + +// HSLuv uses a rounded version of the D65. This has no impact on the final RGB +// values, but to keep high levels of accuracy for internal operations and when +// comparing to the test values, this modified white reference is used internally. +// +// See this GitHub thread for details on these values: +// https://github.com/hsluv/hsluv/issues/79 +var hSLuvD65 = [3]float64{0.95045592705167, 1.0, 1.089057750759878} + +func LuvLChToHSLuv(l, c, h float64) (float64, float64, float64) { + // [-1..1] but the code expects it to be [-100..100] + c *= 100.0 + l *= 100.0 + + var s, max float64 + if l > 99.9999999 || l < 0.00000001 { + s = 0.0 + } else { + max = maxChromaForLH(l, h) + s = c / max * 100.0 + } + return h, clamp01(s / 100.0), clamp01(l / 100.0) +} + +func HSLuvToLuvLCh(h, s, l float64) (float64, float64, float64) { + l *= 100.0 + s *= 100.0 + + var c, max float64 + if l > 99.9999999 || l < 0.00000001 { + c = 0.0 + } else { + max = maxChromaForLH(l, h) + c = max / 100.0 * s + } + + // c is [-100..100], but for LCh it's supposed to be almost [-1..1] + return clamp01(l / 100.0), c / 100.0, h +} + +func LuvLChToHPLuv(l, c, h float64) (float64, float64, float64) { + // [-1..1] but the code expects it to be [-100..100] + c *= 100.0 + l *= 100.0 + + var s, max float64 + if l > 99.9999999 || l < 0.00000001 { + s = 0.0 + } else { + max = maxSafeChromaForL(l) + s = c / max * 100.0 + } + return h, s / 100.0, l / 100.0 +} + +func HPLuvToLuvLCh(h, s, l float64) (float64, float64, float64) { + // [-1..1] but the code expects it to be [-100..100] + l *= 100.0 + s *= 100.0 + + var c, max float64 + if l > 99.9999999 || l < 0.00000001 { + c = 0.0 + } else { + max = maxSafeChromaForL(l) + c = max / 100.0 * s + } + return l / 100.0, c / 100.0, h +} + +// HSLuv creates a new Color from values in the HSLuv color space. +// Hue in [0..360], a Saturation [0..1], and a Luminance (lightness) in [0..1]. +// +// The returned color values are clamped (using .Clamped), so this will never output +// an invalid color. +func HSLuv(h, s, l float64) Color { + // HSLuv -> LuvLCh -> CIELUV -> CIEXYZ -> Linear RGB -> sRGB + l, u, v := LuvLChToLuv(HSLuvToLuvLCh(h, s, l)) + return LinearRgb(XyzToLinearRgb(LuvToXyzWhiteRef(l, u, v, hSLuvD65))).Clamped() +} + +// HPLuv creates a new Color from values in the HPLuv color space. +// Hue in [0..360], a Saturation [0..1], and a Luminance (lightness) in [0..1]. +// +// The returned color values are clamped (using .Clamped), so this will never output +// an invalid color. +func HPLuv(h, s, l float64) Color { + // HPLuv -> LuvLCh -> CIELUV -> CIEXYZ -> Linear RGB -> sRGB + l, u, v := LuvLChToLuv(HPLuvToLuvLCh(h, s, l)) + return LinearRgb(XyzToLinearRgb(LuvToXyzWhiteRef(l, u, v, hSLuvD65))).Clamped() +} + +// HSLuv returns the Hue, Saturation and Luminance of the color in the HSLuv +// color space. Hue in [0..360], a Saturation [0..1], and a Luminance +// (lightness) in [0..1]. +func (col Color) HSLuv() (h, s, l float64) { + // sRGB -> Linear RGB -> CIEXYZ -> CIELUV -> LuvLCh -> HSLuv + return LuvLChToHSLuv(col.LuvLChWhiteRef(hSLuvD65)) +} + +// HPLuv returns the Hue, Saturation and Luminance of the color in the HSLuv +// color space. Hue in [0..360], a Saturation [0..1], and a Luminance +// (lightness) in [0..1]. +// +// Note that HPLuv can only represent pastel colors, and so the Saturation +// value could be much larger than 1 for colors it can't represent. +func (col Color) HPLuv() (h, s, l float64) { + return LuvLChToHPLuv(col.LuvLChWhiteRef(hSLuvD65)) +} + +// DistanceHSLuv calculates Euclidan distance in the HSLuv colorspace. No idea +// how useful this is. +// +// The Hue value is divided by 100 before the calculation, so that H, S, and L +// have the same relative ranges. +func (c1 Color) DistanceHSLuv(c2 Color) float64 { + h1, s1, l1 := c1.HSLuv() + h2, s2, l2 := c2.HSLuv() + return math.Sqrt(sq((h1-h2)/100.0) + sq(s1-s2) + sq(l1-l2)) +} + +// DistanceHPLuv calculates Euclidean distance in the HPLuv colorspace. No idea +// how useful this is. +// +// The Hue value is divided by 100 before the calculation, so that H, S, and L +// have the same relative ranges. +func (c1 Color) DistanceHPLuv(c2 Color) float64 { + h1, s1, l1 := c1.HPLuv() + h2, s2, l2 := c2.HPLuv() + return math.Sqrt(sq((h1-h2)/100.0) + sq(s1-s2) + sq(l1-l2)) +} + +var m = [3][3]float64{ + {3.2409699419045214, -1.5373831775700935, -0.49861076029300328}, + {-0.96924363628087983, 1.8759675015077207, 0.041555057407175613}, + {0.055630079696993609, -0.20397695888897657, 1.0569715142428786}, +} + +const kappa = 903.2962962962963 +const epsilon = 0.0088564516790356308 + +func maxChromaForLH(l, h float64) float64 { + hRad := h / 360.0 * math.Pi * 2.0 + minLength := math.MaxFloat64 + for _, line := range getBounds(l) { + length := lengthOfRayUntilIntersect(hRad, line[0], line[1]) + if length > 0.0 && length < minLength { + minLength = length + } + } + return minLength +} + +func getBounds(l float64) [6][2]float64 { + var sub2 float64 + var ret [6][2]float64 + sub1 := math.Pow(l+16.0, 3.0) / 1560896.0 + if sub1 > epsilon { + sub2 = sub1 + } else { + sub2 = l / kappa + } + for i := range m { + for k := 0; k < 2; k++ { + top1 := (284517.0*m[i][0] - 94839.0*m[i][2]) * sub2 + top2 := (838422.0*m[i][2]+769860.0*m[i][1]+731718.0*m[i][0])*l*sub2 - 769860.0*float64(k)*l + bottom := (632260.0*m[i][2]-126452.0*m[i][1])*sub2 + 126452.0*float64(k) + ret[i*2+k][0] = top1 / bottom + ret[i*2+k][1] = top2 / bottom + } + } + return ret +} + +func lengthOfRayUntilIntersect(theta, x, y float64) (length float64) { + length = y / (math.Sin(theta) - x*math.Cos(theta)) + return +} + +func maxSafeChromaForL(l float64) float64 { + minLength := math.MaxFloat64 + for _, line := range getBounds(l) { + m1 := line[0] + b1 := line[1] + x := intersectLineLine(m1, b1, -1.0/m1, 0.0) + dist := distanceFromPole(x, b1+x*m1) + if dist < minLength { + minLength = dist + } + } + return minLength +} + +func intersectLineLine(x1, y1, x2, y2 float64) float64 { + return (y1 - y2) / (x2 - x1) +} + +func distanceFromPole(x, y float64) float64 { + return math.Sqrt(math.Pow(x, 2.0) + math.Pow(y, 2.0)) +} diff --git a/vendor/github.com/lucasb-eyer/go-colorful/soft_palettegen.go b/vendor/github.com/lucasb-eyer/go-colorful/soft_palettegen.go new file mode 100644 index 000000000..9f7bf6f7c --- /dev/null +++ b/vendor/github.com/lucasb-eyer/go-colorful/soft_palettegen.go @@ -0,0 +1,185 @@ +// Largely inspired by the descriptions in http://lab.medialab.sciences-po.fr/iwanthue/ +// but written from scratch. + +package colorful + +import ( + "fmt" + "math" + "math/rand" +) + +// The algorithm works in L*a*b* color space and converts to RGB in the end. +// L* in [0..1], a* and b* in [-1..1] +type lab_t struct { + L, A, B float64 +} + +type SoftPaletteSettings struct { + // A function which can be used to restrict the allowed color-space. + CheckColor func(l, a, b float64) bool + + // The higher, the better quality but the slower. Usually two figures. + Iterations int + + // Use up to 160000 or 8000 samples of the L*a*b* space (and thus calls to CheckColor). + // Set this to true only if your CheckColor shapes the Lab space weirdly. + ManySamples bool +} + +// Yeah, windows-stype Foo, FooEx, screw you golang... +// Uses K-means to cluster the color-space and return the means of the clusters +// as a new palette of distinctive colors. Falls back to K-medoid if the mean +// happens to fall outside of the color-space, which can only happen if you +// specify a CheckColor function. +func SoftPaletteEx(colorsCount int, settings SoftPaletteSettings) ([]Color, error) { + + // Checks whether it's a valid RGB and also fulfills the potentially provided constraint. + check := func(col lab_t) bool { + c := Lab(col.L, col.A, col.B) + return c.IsValid() && (settings.CheckColor == nil || settings.CheckColor(col.L, col.A, col.B)) + } + + // Sample the color space. These will be the points k-means is run on. + dl := 0.05 + dab := 0.1 + if settings.ManySamples { + dl = 0.01 + dab = 0.05 + } + + samples := make([]lab_t, 0, int(1.0/dl*2.0/dab*2.0/dab)) + for l := 0.0; l <= 1.0; l += dl { + for a := -1.0; a <= 1.0; a += dab { + for b := -1.0; b <= 1.0; b += dab { + if check(lab_t{l, a, b}) { + samples = append(samples, lab_t{l, a, b}) + } + } + } + } + + // That would cause some infinite loops down there... + if len(samples) < colorsCount { + return nil, fmt.Errorf("palettegen: more colors requested (%v) than samples available (%v). Your requested color count may be wrong, you might want to use many samples or your constraint function makes the valid color space too small", colorsCount, len(samples)) + } else if len(samples) == colorsCount { + return labs2cols(samples), nil // Oops? + } + + // We take the initial means out of the samples, so they are in fact medoids. + // This helps us avoid infinite loops or arbitrary cutoffs with too restrictive constraints. + means := make([]lab_t, colorsCount) + for i := 0; i < colorsCount; i++ { + for means[i] = samples[rand.Intn(len(samples))]; in(means, i, means[i]); means[i] = samples[rand.Intn(len(samples))] { + } + } + + clusters := make([]int, len(samples)) + samples_used := make([]bool, len(samples)) + + // The actual k-means/medoid iterations + for i := 0; i < settings.Iterations; i++ { + // Reassing the samples to clusters, i.e. to their closest mean. + // By the way, also check if any sample is used as a medoid and if so, mark that. + for isample, sample := range samples { + samples_used[isample] = false + mindist := math.Inf(+1) + for imean, mean := range means { + dist := lab_dist(sample, mean) + if dist < mindist { + mindist = dist + clusters[isample] = imean + } + + // Mark samples which are used as a medoid. + if lab_eq(sample, mean) { + samples_used[isample] = true + } + } + } + + // Compute new means according to the samples. + for imean := range means { + // The new mean is the average of all samples belonging to it.. + nsamples := 0 + newmean := lab_t{0.0, 0.0, 0.0} + for isample, sample := range samples { + if clusters[isample] == imean { + nsamples++ + newmean.L += sample.L + newmean.A += sample.A + newmean.B += sample.B + } + } + if nsamples > 0 { + newmean.L /= float64(nsamples) + newmean.A /= float64(nsamples) + newmean.B /= float64(nsamples) + } else { + // That mean doesn't have any samples? Get a new mean from the sample list! + var inewmean int + for inewmean = rand.Intn(len(samples_used)); samples_used[inewmean]; inewmean = rand.Intn(len(samples_used)) { + } + newmean = samples[inewmean] + samples_used[inewmean] = true + } + + // But now we still need to check whether the new mean is an allowed color. + if nsamples > 0 && check(newmean) { + // It does, life's good (TM) + means[imean] = newmean + } else { + // New mean isn't an allowed color or doesn't have any samples! + // Switch to medoid mode and pick the closest (unused) sample. + // This should always find something thanks to len(samples) >= colorsCount + mindist := math.Inf(+1) + for isample, sample := range samples { + if !samples_used[isample] { + dist := lab_dist(sample, newmean) + if dist < mindist { + mindist = dist + newmean = sample + } + } + } + } + } + } + return labs2cols(means), nil +} + +// A wrapper which uses common parameters. +func SoftPalette(colorsCount int) ([]Color, error) { + return SoftPaletteEx(colorsCount, SoftPaletteSettings{nil, 50, false}) +} + +func in(haystack []lab_t, upto int, needle lab_t) bool { + for i := 0; i < upto && i < len(haystack); i++ { + if haystack[i] == needle { + return true + } + } + return false +} + +const LAB_DELTA = 1e-6 + +func lab_eq(lab1, lab2 lab_t) bool { + return math.Abs(lab1.L-lab2.L) < LAB_DELTA && + math.Abs(lab1.A-lab2.A) < LAB_DELTA && + math.Abs(lab1.B-lab2.B) < LAB_DELTA +} + +// That's faster than using colorful's DistanceLab since we would have to +// convert back and forth for that. Here is no conversion. +func lab_dist(lab1, lab2 lab_t) float64 { + return math.Sqrt(sq(lab1.L-lab2.L) + sq(lab1.A-lab2.A) + sq(lab1.B-lab2.B)) +} + +func labs2cols(labs []lab_t) (cols []Color) { + cols = make([]Color, len(labs)) + for k, v := range labs { + cols[k] = Lab(v.L, v.A, v.B) + } + return cols +} diff --git a/vendor/github.com/lucasb-eyer/go-colorful/warm_palettegen.go b/vendor/github.com/lucasb-eyer/go-colorful/warm_palettegen.go new file mode 100644 index 000000000..00f42a5cc --- /dev/null +++ b/vendor/github.com/lucasb-eyer/go-colorful/warm_palettegen.go @@ -0,0 +1,25 @@ +package colorful + +import ( + "math/rand" +) + +// Uses the HSV color space to generate colors with similar S,V but distributed +// evenly along their Hue. This is fast but not always pretty. +// If you've got time to spare, use Lab (the non-fast below). +func FastWarmPalette(colorsCount int) (colors []Color) { + colors = make([]Color, colorsCount) + + for i := 0; i < colorsCount; i++ { + colors[i] = Hsv(float64(i)*(360.0/float64(colorsCount)), 0.55+rand.Float64()*0.2, 0.35+rand.Float64()*0.2) + } + return +} + +func WarmPalette(colorsCount int) ([]Color, error) { + warmy := func(l, a, b float64) bool { + _, c, _ := LabToHcl(l, a, b) + return 0.1 <= c && c <= 0.4 && 0.2 <= l && l <= 0.5 + } + return SoftPaletteEx(colorsCount, SoftPaletteSettings{warmy, 50, true}) +} diff --git a/vendor/github.com/macabu/inamedparam/.golangci.yml b/vendor/github.com/macabu/inamedparam/.golangci.yml index f0efa1cb6..7f301af5a 100644 --- a/vendor/github.com/macabu/inamedparam/.golangci.yml +++ b/vendor/github.com/macabu/inamedparam/.golangci.yml @@ -1,33 +1,21 @@ run: - deadline: 30s + timeout: 30s linters: enable-all: true disable: - cyclop - - deadcode - depguard - - exhaustivestruct - exhaustruct - forcetypeassert - gochecknoglobals - gocognit - - golint - - ifshort - - interfacer - - maligned - nilnil - - nosnakecase - paralleltest - - scopelint - - structcheck - - varcheck linters-settings: gci: sections: - standard - default - - prefix(github.com/macabu/inamedparam) - section-separators: - - newLine + - localmodule diff --git a/vendor/github.com/macabu/inamedparam/README.md b/vendor/github.com/macabu/inamedparam/README.md index 3336cb950..56fce4ff0 100644 --- a/vendor/github.com/macabu/inamedparam/README.md +++ b/vendor/github.com/macabu/inamedparam/README.md @@ -15,7 +15,7 @@ You can run it standalone through `go vet`. You must install the binary to your `$GOBIN` folder like so: ```sh -$ go install github.com/macabu/inamedparam/cmd/inamedparam +$ go install github.com/macabu/inamedparam/cmd/inamedparam@latest ``` And then navigate to your Go project's root folder, where can run `go vet` in the following way: @@ -29,10 +29,16 @@ $ go vet -vettool=$(which inamedparam) ./... To enable it, you can add it to your `.golangci.yml` file, as such: ```yaml run: - deadline: 30s + timeout: 30s linters: disable-all: true enable: - inamedparam + +linters-settings: + inamedparam: + # Skips check for interface methods with only a single parameter. + # Default: false + skip-single-param: true ``` diff --git a/vendor/github.com/macabu/inamedparam/inamedparam.go b/vendor/github.com/macabu/inamedparam/inamedparam.go index 8ba7fe188..932bd3b59 100644 --- a/vendor/github.com/macabu/inamedparam/inamedparam.go +++ b/vendor/github.com/macabu/inamedparam/inamedparam.go @@ -33,14 +33,17 @@ func flags() flag.FlagSet { return *flags } -func run(pass *analysis.Pass) (interface{}, error) { +func run(pass *analysis.Pass) (any, error) { inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) types := []ast.Node{ &ast.InterfaceType{}, } - skipSingleParam := pass.Analyzer.Flags.Lookup(flagSkipSingleParam).Value.(flag.Getter).Get().(bool) + var skipSingleParam bool + if f := pass.Analyzer.Flags.Lookup(flagSkipSingleParam); f != nil { + skipSingleParam, _ = f.Value.(flag.Getter).Get().(bool) + } inspect.Preorder(types, func(n ast.Node) { interfaceType, ok := n.(*ast.InterfaceType) diff --git a/vendor/github.com/magiconair/properties/.gitignore b/vendor/github.com/magiconair/properties/.gitignore deleted file mode 100644 index e7081ff52..000000000 --- a/vendor/github.com/magiconair/properties/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -*.sublime-project -*.sublime-workspace -*.un~ -*.swp -.idea/ -*.iml diff --git a/vendor/github.com/magiconair/properties/CHANGELOG.md b/vendor/github.com/magiconair/properties/CHANGELOG.md deleted file mode 100644 index 842e8e24f..000000000 --- a/vendor/github.com/magiconair/properties/CHANGELOG.md +++ /dev/null @@ -1,205 +0,0 @@ -## Changelog - -### [1.8.7](https://github.com/magiconair/properties/tree/v1.8.7) - 08 Dec 2022 - - * [PR #65](https://github.com/magiconair/properties/pull/65): Speedup Merge - - Thanks to [@AdityaVallabh](https://github.com/AdityaVallabh) for the patch. - - * [PR #66](https://github.com/magiconair/properties/pull/66): use github actions - -### [1.8.6](https://github.com/magiconair/properties/tree/v1.8.6) - 23 Feb 2022 - - * [PR #57](https://github.com/magiconair/properties/pull/57):Fix "unreachable code" lint error - - Thanks to [@ellie](https://github.com/ellie) for the patch. - - * [PR #63](https://github.com/magiconair/properties/pull/63): Make TestMustGetParsedDuration backwards compatible - - This patch ensures that the `TestMustGetParsedDuration` still works with `go1.3` to make the - author happy until it affects real users. - - Thanks to [@maage](https://github.com/maage) for the patch. - -### [1.8.5](https://github.com/magiconair/properties/tree/v1.8.5) - 24 Mar 2021 - - * [PR #55](https://github.com/magiconair/properties/pull/55): Fix: Encoding Bug in Comments - - When reading comments \ are loaded correctly, but when writing they are then - replaced by \\. This leads to wrong comments when writing and reading multiple times. - - Thanks to [@doxsch](https://github.com/doxsch) for the patch. - -### [1.8.4](https://github.com/magiconair/properties/tree/v1.8.4) - 23 Sep 2020 - - * [PR #50](https://github.com/magiconair/properties/pull/50): enhance error message for circular references - - Thanks to [@sriv](https://github.com/sriv) for the patch. - -### [1.8.3](https://github.com/magiconair/properties/tree/v1.8.3) - 14 Sep 2020 - - * [PR #49](https://github.com/magiconair/properties/pull/49): Include the key in error message causing the circular reference - - The change is include the key in the error message which is causing the circular - reference when parsing/loading the properties files. - - Thanks to [@haroon-sheikh](https://github.com/haroon-sheikh) for the patch. - -### [1.8.2](https://github.com/magiconair/properties/tree/v1.8.2) - 25 Aug 2020 - - * [PR #36](https://github.com/magiconair/properties/pull/36): Escape backslash on write - - This patch ensures that backslashes are escaped on write. Existing applications which - rely on the old behavior may need to be updated. - - Thanks to [@apesternikov](https://github.com/apesternikov) for the patch. - - * [PR #42](https://github.com/magiconair/properties/pull/42): Made Content-Type check whitespace agnostic in LoadURL() - - Thanks to [@aliras1](https://github.com/aliras1) for the patch. - - * [PR #41](https://github.com/magiconair/properties/pull/41): Make key/value separator configurable on Write() - - Thanks to [@mkjor](https://github.com/mkjor) for the patch. - - * [PR #40](https://github.com/magiconair/properties/pull/40): Add method to return a sorted list of keys - - Thanks to [@mkjor](https://github.com/mkjor) for the patch. - -### [1.8.1](https://github.com/magiconair/properties/tree/v1.8.1) - 10 May 2019 - - * [PR #35](https://github.com/magiconair/properties/pull/35): Close body always after request - - This patch ensures that in `LoadURL` the response body is always closed. - - Thanks to [@liubog2008](https://github.com/liubog2008) for the patch. - -### [1.8](https://github.com/magiconair/properties/tree/v1.8) - 15 May 2018 - - * [PR #26](https://github.com/magiconair/properties/pull/26): Disable expansion during loading - - This adds the option to disable property expansion during loading. - - Thanks to [@kmala](https://github.com/kmala) for the patch. - -### [1.7.6](https://github.com/magiconair/properties/tree/v1.7.6) - 14 Feb 2018 - - * [PR #29](https://github.com/magiconair/properties/pull/29): Reworked expansion logic to handle more complex cases. - - See PR for an example. - - Thanks to [@yobert](https://github.com/yobert) for the fix. - -### [1.7.5](https://github.com/magiconair/properties/tree/v1.7.5) - 13 Feb 2018 - - * [PR #28](https://github.com/magiconair/properties/pull/28): Support duplicate expansions in the same value - - Values which expand the same key multiple times (e.g. `key=${a} ${a}`) will no longer fail - with a `circular reference error`. - - Thanks to [@yobert](https://github.com/yobert) for the fix. - -### [1.7.4](https://github.com/magiconair/properties/tree/v1.7.4) - 31 Oct 2017 - - * [Issue #23](https://github.com/magiconair/properties/issues/23): Ignore blank lines with whitespaces - - * [PR #24](https://github.com/magiconair/properties/pull/24): Update keys when DisableExpansion is enabled - - Thanks to [@mgurov](https://github.com/mgurov) for the fix. - -### [1.7.3](https://github.com/magiconair/properties/tree/v1.7.3) - 10 Jul 2017 - - * [Issue #17](https://github.com/magiconair/properties/issues/17): Add [SetValue()](http://godoc.org/github.com/magiconair/properties#Properties.SetValue) method to set values generically - * [Issue #22](https://github.com/magiconair/properties/issues/22): Add [LoadMap()](http://godoc.org/github.com/magiconair/properties#LoadMap) function to load properties from a string map - -### [1.7.2](https://github.com/magiconair/properties/tree/v1.7.2) - 20 Mar 2017 - - * [Issue #15](https://github.com/magiconair/properties/issues/15): Drop gocheck dependency - * [PR #21](https://github.com/magiconair/properties/pull/21): Add [Map()](http://godoc.org/github.com/magiconair/properties#Properties.Map) and [FilterFunc()](http://godoc.org/github.com/magiconair/properties#Properties.FilterFunc) - -### [1.7.1](https://github.com/magiconair/properties/tree/v1.7.1) - 13 Jan 2017 - - * [Issue #14](https://github.com/magiconair/properties/issues/14): Decouple TestLoadExpandedFile from `$USER` - * [PR #12](https://github.com/magiconair/properties/pull/12): Load from files and URLs - * [PR #16](https://github.com/magiconair/properties/pull/16): Keep gofmt happy - * [PR #18](https://github.com/magiconair/properties/pull/18): Fix Delete() function - -### [1.7.0](https://github.com/magiconair/properties/tree/v1.7.0) - 20 Mar 2016 - - * [Issue #10](https://github.com/magiconair/properties/issues/10): Add [LoadURL,LoadURLs,MustLoadURL,MustLoadURLs](http://godoc.org/github.com/magiconair/properties#LoadURL) method to load properties from a URL. - * [Issue #11](https://github.com/magiconair/properties/issues/11): Add [LoadString,MustLoadString](http://godoc.org/github.com/magiconair/properties#LoadString) method to load properties from an UTF8 string. - * [PR #8](https://github.com/magiconair/properties/pull/8): Add [MustFlag](http://godoc.org/github.com/magiconair/properties#Properties.MustFlag) method to provide overrides via command line flags. (@pascaldekloe) - -### [1.6.0](https://github.com/magiconair/properties/tree/v1.6.0) - 11 Dec 2015 - - * Add [Decode](http://godoc.org/github.com/magiconair/properties#Properties.Decode) method to populate struct from properties via tags. - -### [1.5.6](https://github.com/magiconair/properties/tree/v1.5.6) - 18 Oct 2015 - - * Vendored in gopkg.in/check.v1 - -### [1.5.5](https://github.com/magiconair/properties/tree/v1.5.5) - 31 Jul 2015 - - * [PR #6](https://github.com/magiconair/properties/pull/6): Add [Delete](http://godoc.org/github.com/magiconair/properties#Properties.Delete) method to remove keys including comments. (@gerbenjacobs) - -### [1.5.4](https://github.com/magiconair/properties/tree/v1.5.4) - 23 Jun 2015 - - * [Issue #5](https://github.com/magiconair/properties/issues/5): Allow disabling of property expansion [DisableExpansion](http://godoc.org/github.com/magiconair/properties#Properties.DisableExpansion). When property expansion is disabled Properties become a simple key/value store and don't check for circular references. - -### [1.5.3](https://github.com/magiconair/properties/tree/v1.5.3) - 02 Jun 2015 - - * [Issue #4](https://github.com/magiconair/properties/issues/4): Maintain key order in [Filter()](http://godoc.org/github.com/magiconair/properties#Properties.Filter), [FilterPrefix()](http://godoc.org/github.com/magiconair/properties#Properties.FilterPrefix) and [FilterRegexp()](http://godoc.org/github.com/magiconair/properties#Properties.FilterRegexp) - -### [1.5.2](https://github.com/magiconair/properties/tree/v1.5.2) - 10 Apr 2015 - - * [Issue #3](https://github.com/magiconair/properties/issues/3): Don't print comments in [WriteComment()](http://godoc.org/github.com/magiconair/properties#Properties.WriteComment) if they are all empty - * Add clickable links to README - -### [1.5.1](https://github.com/magiconair/properties/tree/v1.5.1) - 08 Dec 2014 - - * Added [GetParsedDuration()](http://godoc.org/github.com/magiconair/properties#Properties.GetParsedDuration) and [MustGetParsedDuration()](http://godoc.org/github.com/magiconair/properties#Properties.MustGetParsedDuration) for values specified compatible with - [time.ParseDuration()](http://golang.org/pkg/time/#ParseDuration). - -### [1.5.0](https://github.com/magiconair/properties/tree/v1.5.0) - 18 Nov 2014 - - * Added support for single and multi-line comments (reading, writing and updating) - * The order of keys is now preserved - * Calling [Set()](http://godoc.org/github.com/magiconair/properties#Properties.Set) with an empty key now silently ignores the call and does not create a new entry - * Added a [MustSet()](http://godoc.org/github.com/magiconair/properties#Properties.MustSet) method - * Migrated test library from launchpad.net/gocheck to [gopkg.in/check.v1](http://gopkg.in/check.v1) - -### [1.4.2](https://github.com/magiconair/properties/tree/v1.4.2) - 15 Nov 2014 - - * [Issue #2](https://github.com/magiconair/properties/issues/2): Fixed goroutine leak in parser which created two lexers but cleaned up only one - -### [1.4.1](https://github.com/magiconair/properties/tree/v1.4.1) - 13 Nov 2014 - - * [Issue #1](https://github.com/magiconair/properties/issues/1): Fixed bug in Keys() method which returned an empty string - -### [1.4.0](https://github.com/magiconair/properties/tree/v1.4.0) - 23 Sep 2014 - - * Added [Keys()](http://godoc.org/github.com/magiconair/properties#Properties.Keys) to get the keys - * Added [Filter()](http://godoc.org/github.com/magiconair/properties#Properties.Filter), [FilterRegexp()](http://godoc.org/github.com/magiconair/properties#Properties.FilterRegexp) and [FilterPrefix()](http://godoc.org/github.com/magiconair/properties#Properties.FilterPrefix) to get a subset of the properties - -### [1.3.0](https://github.com/magiconair/properties/tree/v1.3.0) - 18 Mar 2014 - -* Added support for time.Duration -* Made MustXXX() failure beha[ior configurable (log.Fatal, panic](https://github.com/magiconair/properties/tree/vior configurable (log.Fatal, panic) - custom) -* Changed default of MustXXX() failure from panic to log.Fatal - -### [1.2.0](https://github.com/magiconair/properties/tree/v1.2.0) - 05 Mar 2014 - -* Added MustGet... functions -* Added support for int and uint with range checks on 32 bit platforms - -### [1.1.0](https://github.com/magiconair/properties/tree/v1.1.0) - 20 Jan 2014 - -* Renamed from goproperties to properties -* Added support for expansion of environment vars in - filenames and value expressions -* Fixed bug where value expressions were not at the - start of the string - -### [1.0.0](https://github.com/magiconair/properties/tree/v1.0.0) - 7 Jan 2014 - -* Initial release diff --git a/vendor/github.com/magiconair/properties/LICENSE.md b/vendor/github.com/magiconair/properties/LICENSE.md deleted file mode 100644 index 79c87e3e6..000000000 --- a/vendor/github.com/magiconair/properties/LICENSE.md +++ /dev/null @@ -1,24 +0,0 @@ -Copyright (c) 2013-2020, Frank Schroeder - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/magiconair/properties/README.md b/vendor/github.com/magiconair/properties/README.md deleted file mode 100644 index e2edda025..000000000 --- a/vendor/github.com/magiconair/properties/README.md +++ /dev/null @@ -1,128 +0,0 @@ -[![](https://img.shields.io/github/tag/magiconair/properties.svg?style=flat-square&label=release)](https://github.com/magiconair/properties/releases) -[![Travis CI Status](https://img.shields.io/travis/magiconair/properties.svg?branch=master&style=flat-square&label=travis)](https://travis-ci.org/magiconair/properties) -[![License](https://img.shields.io/badge/License-BSD%202--Clause-orange.svg?style=flat-square)](https://raw.githubusercontent.com/magiconair/properties/master/LICENSE) -[![GoDoc](http://img.shields.io/badge/godoc-reference-5272B4.svg?style=flat-square)](http://godoc.org/github.com/magiconair/properties) - -# Overview - -#### Please run `git pull --tags` to update the tags. See [below](#updated-git-tags) why. - -properties is a Go library for reading and writing properties files. - -It supports reading from multiple files or URLs and Spring style recursive -property expansion of expressions like `${key}` to their corresponding value. -Value expressions can refer to other keys like in `${key}` or to environment -variables like in `${USER}`. Filenames can also contain environment variables -like in `/home/${USER}/myapp.properties`. - -Properties can be decoded into structs, maps, arrays and values through -struct tags. - -Comments and the order of keys are preserved. Comments can be modified -and can be written to the output. - -The properties library supports both ISO-8859-1 and UTF-8 encoded data. - -Starting from version 1.3.0 the behavior of the MustXXX() functions is -configurable by providing a custom `ErrorHandler` function. The default has -changed from `panic` to `log.Fatal` but this is configurable and custom -error handling functions can be provided. See the package documentation for -details. - -Read the full documentation on [![GoDoc](http://img.shields.io/badge/godoc-reference-5272B4.svg?style=flat-square)](http://godoc.org/github.com/magiconair/properties) - -## Getting Started - -```go -import ( - "flag" - "github.com/magiconair/properties" -) - -func main() { - // init from a file - p := properties.MustLoadFile("${HOME}/config.properties", properties.UTF8) - - // or multiple files - p = properties.MustLoadFiles([]string{ - "${HOME}/config.properties", - "${HOME}/config-${USER}.properties", - }, properties.UTF8, true) - - // or from a map - p = properties.LoadMap(map[string]string{"key": "value", "abc": "def"}) - - // or from a string - p = properties.MustLoadString("key=value\nabc=def") - - // or from a URL - p = properties.MustLoadURL("http://host/path") - - // or from multiple URLs - p = properties.MustLoadURL([]string{ - "http://host/config", - "http://host/config-${USER}", - }, true) - - // or from flags - p.MustFlag(flag.CommandLine) - - // get values through getters - host := p.MustGetString("host") - port := p.GetInt("port", 8080) - - // or through Decode - type Config struct { - Host string `properties:"host"` - Port int `properties:"port,default=9000"` - Accept []string `properties:"accept,default=image/png;image;gif"` - Timeout time.Duration `properties:"timeout,default=5s"` - } - var cfg Config - if err := p.Decode(&cfg); err != nil { - log.Fatal(err) - } -} - -``` - -## Installation and Upgrade - -``` -$ go get -u github.com/magiconair/properties -``` - -## License - -2 clause BSD license. See [LICENSE](https://github.com/magiconair/properties/blob/master/LICENSE) file for details. - -## ToDo - -* Dump contents with passwords and secrets obscured - -## Updated Git tags - -#### 13 Feb 2018 - -I realized that all of the git tags I had pushed before v1.7.5 were lightweight tags -and I've only recently learned that this doesn't play well with `git describe` 😞 - -I have replaced all lightweight tags with signed tags using this script which should -retain the commit date, name and email address. Please run `git pull --tags` to update them. - -Worst case you have to reclone the repo. - -```shell -#!/bin/bash -tag=$1 -echo "Updating $tag" -date=$(git show ${tag}^0 --format=%aD | head -1) -email=$(git show ${tag}^0 --format=%aE | head -1) -name=$(git show ${tag}^0 --format=%aN | head -1) -GIT_COMMITTER_DATE="$date" GIT_COMMITTER_NAME="$name" GIT_COMMITTER_EMAIL="$email" git tag -s -f ${tag} ${tag}^0 -m ${tag} -``` - -I apologize for the inconvenience. - -Frank - diff --git a/vendor/github.com/magiconair/properties/decode.go b/vendor/github.com/magiconair/properties/decode.go deleted file mode 100644 index 8e6aa441d..000000000 --- a/vendor/github.com/magiconair/properties/decode.go +++ /dev/null @@ -1,289 +0,0 @@ -// Copyright 2013-2022 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package properties - -import ( - "fmt" - "reflect" - "strconv" - "strings" - "time" -) - -// Decode assigns property values to exported fields of a struct. -// -// Decode traverses v recursively and returns an error if a value cannot be -// converted to the field type or a required value is missing for a field. -// -// The following type dependent decodings are used: -// -// String, boolean, numeric fields have the value of the property key assigned. -// The property key name is the name of the field. A different key and a default -// value can be set in the field's tag. Fields without default value are -// required. If the value cannot be converted to the field type an error is -// returned. -// -// time.Duration fields have the result of time.ParseDuration() assigned. -// -// time.Time fields have the vaule of time.Parse() assigned. The default layout -// is time.RFC3339 but can be set in the field's tag. -// -// Arrays and slices of string, boolean, numeric, time.Duration and time.Time -// fields have the value interpreted as a comma separated list of values. The -// individual values are trimmed of whitespace and empty values are ignored. A -// default value can be provided as a semicolon separated list in the field's -// tag. -// -// Struct fields are decoded recursively using the field name plus "." as -// prefix. The prefix (without dot) can be overridden in the field's tag. -// Default values are not supported in the field's tag. Specify them on the -// fields of the inner struct instead. -// -// Map fields must have a key of type string and are decoded recursively by -// using the field's name plus ".' as prefix and the next element of the key -// name as map key. The prefix (without dot) can be overridden in the field's -// tag. Default values are not supported. -// -// Examples: -// -// // Field is ignored. -// Field int `properties:"-"` -// -// // Field is assigned value of 'Field'. -// Field int -// -// // Field is assigned value of 'myName'. -// Field int `properties:"myName"` -// -// // Field is assigned value of key 'myName' and has a default -// // value 15 if the key does not exist. -// Field int `properties:"myName,default=15"` -// -// // Field is assigned value of key 'Field' and has a default -// // value 15 if the key does not exist. -// Field int `properties:",default=15"` -// -// // Field is assigned value of key 'date' and the date -// // is in format 2006-01-02 -// Field time.Time `properties:"date,layout=2006-01-02"` -// -// // Field is assigned the non-empty and whitespace trimmed -// // values of key 'Field' split by commas. -// Field []string -// -// // Field is assigned the non-empty and whitespace trimmed -// // values of key 'Field' split by commas and has a default -// // value ["a", "b", "c"] if the key does not exist. -// Field []string `properties:",default=a;b;c"` -// -// // Field is decoded recursively with "Field." as key prefix. -// Field SomeStruct -// -// // Field is decoded recursively with "myName." as key prefix. -// Field SomeStruct `properties:"myName"` -// -// // Field is decoded recursively with "Field." as key prefix -// // and the next dotted element of the key as map key. -// Field map[string]string -// -// // Field is decoded recursively with "myName." as key prefix -// // and the next dotted element of the key as map key. -// Field map[string]string `properties:"myName"` -func (p *Properties) Decode(x interface{}) error { - t, v := reflect.TypeOf(x), reflect.ValueOf(x) - if t.Kind() != reflect.Ptr || v.Elem().Type().Kind() != reflect.Struct { - return fmt.Errorf("not a pointer to struct: %s", t) - } - if err := dec(p, "", nil, nil, v); err != nil { - return err - } - return nil -} - -func dec(p *Properties, key string, def *string, opts map[string]string, v reflect.Value) error { - t := v.Type() - - // value returns the property value for key or the default if provided. - value := func() (string, error) { - if val, ok := p.Get(key); ok { - return val, nil - } - if def != nil { - return *def, nil - } - return "", fmt.Errorf("missing required key %s", key) - } - - // conv converts a string to a value of the given type. - conv := func(s string, t reflect.Type) (val reflect.Value, err error) { - var v interface{} - - switch { - case isDuration(t): - v, err = time.ParseDuration(s) - - case isTime(t): - layout := opts["layout"] - if layout == "" { - layout = time.RFC3339 - } - v, err = time.Parse(layout, s) - - case isBool(t): - v, err = boolVal(s), nil - - case isString(t): - v, err = s, nil - - case isFloat(t): - v, err = strconv.ParseFloat(s, 64) - - case isInt(t): - v, err = strconv.ParseInt(s, 10, 64) - - case isUint(t): - v, err = strconv.ParseUint(s, 10, 64) - - default: - return reflect.Zero(t), fmt.Errorf("unsupported type %s", t) - } - if err != nil { - return reflect.Zero(t), err - } - return reflect.ValueOf(v).Convert(t), nil - } - - // keydef returns the property key and the default value based on the - // name of the struct field and the options in the tag. - keydef := func(f reflect.StructField) (string, *string, map[string]string) { - _key, _opts := parseTag(f.Tag.Get("properties")) - - var _def *string - if d, ok := _opts["default"]; ok { - _def = &d - } - if _key != "" { - return _key, _def, _opts - } - return f.Name, _def, _opts - } - - switch { - case isDuration(t) || isTime(t) || isBool(t) || isString(t) || isFloat(t) || isInt(t) || isUint(t): - s, err := value() - if err != nil { - return err - } - val, err := conv(s, t) - if err != nil { - return err - } - v.Set(val) - - case isPtr(t): - return dec(p, key, def, opts, v.Elem()) - - case isStruct(t): - for i := 0; i < v.NumField(); i++ { - fv := v.Field(i) - fk, def, opts := keydef(t.Field(i)) - if !fv.CanSet() { - return fmt.Errorf("cannot set %s", t.Field(i).Name) - } - if fk == "-" { - continue - } - if key != "" { - fk = key + "." + fk - } - if err := dec(p, fk, def, opts, fv); err != nil { - return err - } - } - return nil - - case isArray(t): - val, err := value() - if err != nil { - return err - } - vals := split(val, ";") - a := reflect.MakeSlice(t, 0, len(vals)) - for _, s := range vals { - val, err := conv(s, t.Elem()) - if err != nil { - return err - } - a = reflect.Append(a, val) - } - v.Set(a) - - case isMap(t): - valT := t.Elem() - m := reflect.MakeMap(t) - for postfix := range p.FilterStripPrefix(key + ".").m { - pp := strings.SplitN(postfix, ".", 2) - mk, mv := pp[0], reflect.New(valT) - if err := dec(p, key+"."+mk, nil, nil, mv); err != nil { - return err - } - m.SetMapIndex(reflect.ValueOf(mk), mv.Elem()) - } - v.Set(m) - - default: - return fmt.Errorf("unsupported type %s", t) - } - return nil -} - -// split splits a string on sep, trims whitespace of elements -// and omits empty elements -func split(s string, sep string) []string { - var a []string - for _, v := range strings.Split(s, sep) { - if v = strings.TrimSpace(v); v != "" { - a = append(a, v) - } - } - return a -} - -// parseTag parses a "key,k=v,k=v,..." -func parseTag(tag string) (key string, opts map[string]string) { - opts = map[string]string{} - for i, s := range strings.Split(tag, ",") { - if i == 0 { - key = s - continue - } - - pp := strings.SplitN(s, "=", 2) - if len(pp) == 1 { - opts[pp[0]] = "" - } else { - opts[pp[0]] = pp[1] - } - } - return key, opts -} - -func isArray(t reflect.Type) bool { return t.Kind() == reflect.Array || t.Kind() == reflect.Slice } -func isBool(t reflect.Type) bool { return t.Kind() == reflect.Bool } -func isDuration(t reflect.Type) bool { return t == reflect.TypeOf(time.Second) } -func isMap(t reflect.Type) bool { return t.Kind() == reflect.Map } -func isPtr(t reflect.Type) bool { return t.Kind() == reflect.Ptr } -func isString(t reflect.Type) bool { return t.Kind() == reflect.String } -func isStruct(t reflect.Type) bool { return t.Kind() == reflect.Struct } -func isTime(t reflect.Type) bool { return t == reflect.TypeOf(time.Time{}) } -func isFloat(t reflect.Type) bool { - return t.Kind() == reflect.Float32 || t.Kind() == reflect.Float64 -} -func isInt(t reflect.Type) bool { - return t.Kind() == reflect.Int || t.Kind() == reflect.Int8 || t.Kind() == reflect.Int16 || t.Kind() == reflect.Int32 || t.Kind() == reflect.Int64 -} -func isUint(t reflect.Type) bool { - return t.Kind() == reflect.Uint || t.Kind() == reflect.Uint8 || t.Kind() == reflect.Uint16 || t.Kind() == reflect.Uint32 || t.Kind() == reflect.Uint64 -} diff --git a/vendor/github.com/magiconair/properties/doc.go b/vendor/github.com/magiconair/properties/doc.go deleted file mode 100644 index 7c7979315..000000000 --- a/vendor/github.com/magiconair/properties/doc.go +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2013-2022 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package properties provides functions for reading and writing -// ISO-8859-1 and UTF-8 encoded .properties files and has -// support for recursive property expansion. -// -// Java properties files are ISO-8859-1 encoded and use Unicode -// literals for characters outside the ISO character set. Unicode -// literals can be used in UTF-8 encoded properties files but -// aren't necessary. -// -// To load a single properties file use MustLoadFile(): -// -// p := properties.MustLoadFile(filename, properties.UTF8) -// -// To load multiple properties files use MustLoadFiles() -// which loads the files in the given order and merges the -// result. Missing properties files can be ignored if the -// 'ignoreMissing' flag is set to true. -// -// Filenames can contain environment variables which are expanded -// before loading. -// -// f1 := "/etc/myapp/myapp.conf" -// f2 := "/home/${USER}/myapp.conf" -// p := MustLoadFiles([]string{f1, f2}, properties.UTF8, true) -// -// All of the different key/value delimiters ' ', ':' and '=' are -// supported as well as the comment characters '!' and '#' and -// multi-line values. -// -// ! this is a comment -// # and so is this -// -// # the following expressions are equal -// key value -// key=value -// key:value -// key = value -// key : value -// key = val\ -// ue -// -// Properties stores all comments preceding a key and provides -// GetComments() and SetComments() methods to retrieve and -// update them. The convenience functions GetComment() and -// SetComment() allow access to the last comment. The -// WriteComment() method writes properties files including -// the comments and with the keys in the original order. -// This can be used for sanitizing properties files. -// -// Property expansion is recursive and circular references -// and malformed expressions are not allowed and cause an -// error. Expansion of environment variables is supported. -// -// # standard property -// key = value -// -// # property expansion: key2 = value -// key2 = ${key} -// -// # recursive expansion: key3 = value -// key3 = ${key2} -// -// # circular reference (error) -// key = ${key} -// -// # malformed expression (error) -// key = ${ke -// -// # refers to the users' home dir -// home = ${HOME} -// -// # local key takes precedence over env var: u = foo -// USER = foo -// u = ${USER} -// -// The default property expansion format is ${key} but can be -// changed by setting different pre- and postfix values on the -// Properties object. -// -// p := properties.NewProperties() -// p.Prefix = "#[" -// p.Postfix = "]#" -// -// Properties provides convenience functions for getting typed -// values with default values if the key does not exist or the -// type conversion failed. -// -// # Returns true if the value is either "1", "on", "yes" or "true" -// # Returns false for every other value and the default value if -// # the key does not exist. -// v = p.GetBool("key", false) -// -// # Returns the value if the key exists and the format conversion -// # was successful. Otherwise, the default value is returned. -// v = p.GetInt64("key", 999) -// v = p.GetUint64("key", 999) -// v = p.GetFloat64("key", 123.0) -// v = p.GetString("key", "def") -// v = p.GetDuration("key", 999) -// -// As an alternative properties may be applied with the standard -// library's flag implementation at any time. -// -// # Standard configuration -// v = flag.Int("key", 999, "help message") -// flag.Parse() -// -// # Merge p into the flag set -// p.MustFlag(flag.CommandLine) -// -// Properties provides several MustXXX() convenience functions -// which will terminate the app if an error occurs. The behavior -// of the failure is configurable and the default is to call -// log.Fatal(err). To have the MustXXX() functions panic instead -// of logging the error set a different ErrorHandler before -// you use the Properties package. -// -// properties.ErrorHandler = properties.PanicHandler -// -// # Will panic instead of logging an error -// p := properties.MustLoadFile("config.properties") -// -// You can also provide your own ErrorHandler function. The only requirement -// is that the error handler function must exit after handling the error. -// -// properties.ErrorHandler = func(err error) { -// fmt.Println(err) -// os.Exit(1) -// } -// -// # Will write to stdout and then exit -// p := properties.MustLoadFile("config.properties") -// -// Properties can also be loaded into a struct via the `Decode` -// method, e.g. -// -// type S struct { -// A string `properties:"a,default=foo"` -// D time.Duration `properties:"timeout,default=5s"` -// E time.Time `properties:"expires,layout=2006-01-02,default=2015-01-01"` -// } -// -// See `Decode()` method for the full documentation. -// -// The following documents provide a description of the properties -// file format. -// -// http://en.wikipedia.org/wiki/.properties -// -// http://docs.oracle.com/javase/7/docs/api/java/util/Properties.html#load%28java.io.Reader%29 -package properties diff --git a/vendor/github.com/magiconair/properties/integrate.go b/vendor/github.com/magiconair/properties/integrate.go deleted file mode 100644 index 35d0ae97b..000000000 --- a/vendor/github.com/magiconair/properties/integrate.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2013-2022 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package properties - -import "flag" - -// MustFlag sets flags that are skipped by dst.Parse when p contains -// the respective key for flag.Flag.Name. -// -// It's use is recommended with command line arguments as in: -// -// flag.Parse() -// p.MustFlag(flag.CommandLine) -func (p *Properties) MustFlag(dst *flag.FlagSet) { - m := make(map[string]*flag.Flag) - dst.VisitAll(func(f *flag.Flag) { - m[f.Name] = f - }) - dst.Visit(func(f *flag.Flag) { - delete(m, f.Name) // overridden - }) - - for name, f := range m { - v, ok := p.Get(name) - if !ok { - continue - } - - if err := f.Value.Set(v); err != nil { - ErrorHandler(err) - } - } -} diff --git a/vendor/github.com/magiconair/properties/lex.go b/vendor/github.com/magiconair/properties/lex.go deleted file mode 100644 index 3d15a1f6e..000000000 --- a/vendor/github.com/magiconair/properties/lex.go +++ /dev/null @@ -1,395 +0,0 @@ -// Copyright 2013-2022 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// -// Parts of the lexer are from the template/text/parser package -// For these parts the following applies: -// -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file of the go 1.2 -// distribution. - -package properties - -import ( - "fmt" - "strconv" - "strings" - "unicode/utf8" -) - -// item represents a token or text string returned from the scanner. -type item struct { - typ itemType // The type of this item. - pos int // The starting position, in bytes, of this item in the input string. - val string // The value of this item. -} - -func (i item) String() string { - switch { - case i.typ == itemEOF: - return "EOF" - case i.typ == itemError: - return i.val - case len(i.val) > 10: - return fmt.Sprintf("%.10q...", i.val) - } - return fmt.Sprintf("%q", i.val) -} - -// itemType identifies the type of lex items. -type itemType int - -const ( - itemError itemType = iota // error occurred; value is text of error - itemEOF - itemKey // a key - itemValue // a value - itemComment // a comment -) - -// defines a constant for EOF -const eof = -1 - -// permitted whitespace characters space, FF and TAB -const whitespace = " \f\t" - -// stateFn represents the state of the scanner as a function that returns the next state. -type stateFn func(*lexer) stateFn - -// lexer holds the state of the scanner. -type lexer struct { - input string // the string being scanned - state stateFn // the next lexing function to enter - pos int // current position in the input - start int // start position of this item - width int // width of last rune read from input - lastPos int // position of most recent item returned by nextItem - runes []rune // scanned runes for this item - items chan item // channel of scanned items -} - -// next returns the next rune in the input. -func (l *lexer) next() rune { - if l.pos >= len(l.input) { - l.width = 0 - return eof - } - r, w := utf8.DecodeRuneInString(l.input[l.pos:]) - l.width = w - l.pos += l.width - return r -} - -// peek returns but does not consume the next rune in the input. -func (l *lexer) peek() rune { - r := l.next() - l.backup() - return r -} - -// backup steps back one rune. Can only be called once per call of next. -func (l *lexer) backup() { - l.pos -= l.width -} - -// emit passes an item back to the client. -func (l *lexer) emit(t itemType) { - i := item{t, l.start, string(l.runes)} - l.items <- i - l.start = l.pos - l.runes = l.runes[:0] -} - -// ignore skips over the pending input before this point. -func (l *lexer) ignore() { - l.start = l.pos -} - -// appends the rune to the current value -func (l *lexer) appendRune(r rune) { - l.runes = append(l.runes, r) -} - -// accept consumes the next rune if it's from the valid set. -func (l *lexer) accept(valid string) bool { - if strings.ContainsRune(valid, l.next()) { - return true - } - l.backup() - return false -} - -// acceptRun consumes a run of runes from the valid set. -func (l *lexer) acceptRun(valid string) { - for strings.ContainsRune(valid, l.next()) { - } - l.backup() -} - -// lineNumber reports which line we're on, based on the position of -// the previous item returned by nextItem. Doing it this way -// means we don't have to worry about peek double counting. -func (l *lexer) lineNumber() int { - return 1 + strings.Count(l.input[:l.lastPos], "\n") -} - -// errorf returns an error token and terminates the scan by passing -// back a nil pointer that will be the next state, terminating l.nextItem. -func (l *lexer) errorf(format string, args ...interface{}) stateFn { - l.items <- item{itemError, l.start, fmt.Sprintf(format, args...)} - return nil -} - -// nextItem returns the next item from the input. -func (l *lexer) nextItem() item { - i := <-l.items - l.lastPos = i.pos - return i -} - -// lex creates a new scanner for the input string. -func lex(input string) *lexer { - l := &lexer{ - input: input, - items: make(chan item), - runes: make([]rune, 0, 32), - } - go l.run() - return l -} - -// run runs the state machine for the lexer. -func (l *lexer) run() { - for l.state = lexBeforeKey(l); l.state != nil; { - l.state = l.state(l) - } -} - -// state functions - -// lexBeforeKey scans until a key begins. -func lexBeforeKey(l *lexer) stateFn { - switch r := l.next(); { - case isEOF(r): - l.emit(itemEOF) - return nil - - case isEOL(r): - l.ignore() - return lexBeforeKey - - case isComment(r): - return lexComment - - case isWhitespace(r): - l.ignore() - return lexBeforeKey - - default: - l.backup() - return lexKey - } -} - -// lexComment scans a comment line. The comment character has already been scanned. -func lexComment(l *lexer) stateFn { - l.acceptRun(whitespace) - l.ignore() - for { - switch r := l.next(); { - case isEOF(r): - l.ignore() - l.emit(itemEOF) - return nil - case isEOL(r): - l.emit(itemComment) - return lexBeforeKey - default: - l.appendRune(r) - } - } -} - -// lexKey scans the key up to a delimiter -func lexKey(l *lexer) stateFn { - var r rune - -Loop: - for { - switch r = l.next(); { - - case isEscape(r): - err := l.scanEscapeSequence() - if err != nil { - return l.errorf(err.Error()) - } - - case isEndOfKey(r): - l.backup() - break Loop - - case isEOF(r): - break Loop - - default: - l.appendRune(r) - } - } - - if len(l.runes) > 0 { - l.emit(itemKey) - } - - if isEOF(r) { - l.emit(itemEOF) - return nil - } - - return lexBeforeValue -} - -// lexBeforeValue scans the delimiter between key and value. -// Leading and trailing whitespace is ignored. -// We expect to be just after the key. -func lexBeforeValue(l *lexer) stateFn { - l.acceptRun(whitespace) - l.accept(":=") - l.acceptRun(whitespace) - l.ignore() - return lexValue -} - -// lexValue scans text until the end of the line. We expect to be just after the delimiter. -func lexValue(l *lexer) stateFn { - for { - switch r := l.next(); { - case isEscape(r): - if isEOL(l.peek()) { - l.next() - l.acceptRun(whitespace) - } else { - err := l.scanEscapeSequence() - if err != nil { - return l.errorf(err.Error()) - } - } - - case isEOL(r): - l.emit(itemValue) - l.ignore() - return lexBeforeKey - - case isEOF(r): - l.emit(itemValue) - l.emit(itemEOF) - return nil - - default: - l.appendRune(r) - } - } -} - -// scanEscapeSequence scans either one of the escaped characters -// or a unicode literal. We expect to be after the escape character. -func (l *lexer) scanEscapeSequence() error { - switch r := l.next(); { - - case isEscapedCharacter(r): - l.appendRune(decodeEscapedCharacter(r)) - return nil - - case atUnicodeLiteral(r): - return l.scanUnicodeLiteral() - - case isEOF(r): - return fmt.Errorf("premature EOF") - - // silently drop the escape character and append the rune as is - default: - l.appendRune(r) - return nil - } -} - -// scans a unicode literal in the form \uXXXX. We expect to be after the \u. -func (l *lexer) scanUnicodeLiteral() error { - // scan the digits - d := make([]rune, 4) - for i := 0; i < 4; i++ { - d[i] = l.next() - if d[i] == eof || !strings.ContainsRune("0123456789abcdefABCDEF", d[i]) { - return fmt.Errorf("invalid unicode literal") - } - } - - // decode the digits into a rune - r, err := strconv.ParseInt(string(d), 16, 0) - if err != nil { - return err - } - - l.appendRune(rune(r)) - return nil -} - -// decodeEscapedCharacter returns the unescaped rune. We expect to be after the escape character. -func decodeEscapedCharacter(r rune) rune { - switch r { - case 'f': - return '\f' - case 'n': - return '\n' - case 'r': - return '\r' - case 't': - return '\t' - default: - return r - } -} - -// atUnicodeLiteral reports whether we are at a unicode literal. -// The escape character has already been consumed. -func atUnicodeLiteral(r rune) bool { - return r == 'u' -} - -// isComment reports whether we are at the start of a comment. -func isComment(r rune) bool { - return r == '#' || r == '!' -} - -// isEndOfKey reports whether the rune terminates the current key. -func isEndOfKey(r rune) bool { - return strings.ContainsRune(" \f\t\r\n:=", r) -} - -// isEOF reports whether we are at EOF. -func isEOF(r rune) bool { - return r == eof -} - -// isEOL reports whether we are at a new line character. -func isEOL(r rune) bool { - return r == '\n' || r == '\r' -} - -// isEscape reports whether the rune is the escape character which -// prefixes unicode literals and other escaped characters. -func isEscape(r rune) bool { - return r == '\\' -} - -// isEscapedCharacter reports whether we are at one of the characters that need escaping. -// The escape character has already been consumed. -func isEscapedCharacter(r rune) bool { - return strings.ContainsRune(" :=fnrt", r) -} - -// isWhitespace reports whether the rune is a whitespace character. -func isWhitespace(r rune) bool { - return strings.ContainsRune(whitespace, r) -} diff --git a/vendor/github.com/magiconair/properties/load.go b/vendor/github.com/magiconair/properties/load.go deleted file mode 100644 index 635368dc8..000000000 --- a/vendor/github.com/magiconair/properties/load.go +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright 2013-2022 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package properties - -import ( - "fmt" - "io/ioutil" - "net/http" - "os" - "strings" -) - -// Encoding specifies encoding of the input data. -type Encoding uint - -const ( - // utf8Default is a private placeholder for the zero value of Encoding to - // ensure that it has the correct meaning. UTF8 is the default encoding but - // was assigned a non-zero value which cannot be changed without breaking - // existing code. Clients should continue to use the public constants. - utf8Default Encoding = iota - - // UTF8 interprets the input data as UTF-8. - UTF8 - - // ISO_8859_1 interprets the input data as ISO-8859-1. - ISO_8859_1 -) - -type Loader struct { - // Encoding determines how the data from files and byte buffers - // is interpreted. For URLs the Content-Type header is used - // to determine the encoding of the data. - Encoding Encoding - - // DisableExpansion configures the property expansion of the - // returned property object. When set to true, the property values - // will not be expanded and the Property object will not be checked - // for invalid expansion expressions. - DisableExpansion bool - - // IgnoreMissing configures whether missing files or URLs which return - // 404 are reported as errors. When set to true, missing files and 404 - // status codes are not reported as errors. - IgnoreMissing bool -} - -// Load reads a buffer into a Properties struct. -func (l *Loader) LoadBytes(buf []byte) (*Properties, error) { - return l.loadBytes(buf, l.Encoding) -} - -// LoadAll reads the content of multiple URLs or files in the given order into -// a Properties struct. If IgnoreMissing is true then a 404 status code or -// missing file will not be reported as error. Encoding sets the encoding for -// files. For the URLs see LoadURL for the Content-Type header and the -// encoding. -func (l *Loader) LoadAll(names []string) (*Properties, error) { - all := NewProperties() - for _, name := range names { - n, err := expandName(name) - if err != nil { - return nil, err - } - - var p *Properties - switch { - case strings.HasPrefix(n, "http://"): - p, err = l.LoadURL(n) - case strings.HasPrefix(n, "https://"): - p, err = l.LoadURL(n) - default: - p, err = l.LoadFile(n) - } - if err != nil { - return nil, err - } - all.Merge(p) - } - - all.DisableExpansion = l.DisableExpansion - if all.DisableExpansion { - return all, nil - } - return all, all.check() -} - -// LoadFile reads a file into a Properties struct. -// If IgnoreMissing is true then a missing file will not be -// reported as error. -func (l *Loader) LoadFile(filename string) (*Properties, error) { - data, err := ioutil.ReadFile(filename) - if err != nil { - if l.IgnoreMissing && os.IsNotExist(err) { - LogPrintf("properties: %s not found. skipping", filename) - return NewProperties(), nil - } - return nil, err - } - return l.loadBytes(data, l.Encoding) -} - -// LoadURL reads the content of the URL into a Properties struct. -// -// The encoding is determined via the Content-Type header which -// should be set to 'text/plain'. If the 'charset' parameter is -// missing, 'iso-8859-1' or 'latin1' the encoding is set to -// ISO-8859-1. If the 'charset' parameter is set to 'utf-8' the -// encoding is set to UTF-8. A missing content type header is -// interpreted as 'text/plain; charset=utf-8'. -func (l *Loader) LoadURL(url string) (*Properties, error) { - resp, err := http.Get(url) - if err != nil { - return nil, fmt.Errorf("properties: error fetching %q. %s", url, err) - } - defer resp.Body.Close() - - if resp.StatusCode == 404 && l.IgnoreMissing { - LogPrintf("properties: %s returned %d. skipping", url, resp.StatusCode) - return NewProperties(), nil - } - - if resp.StatusCode != 200 { - return nil, fmt.Errorf("properties: %s returned %d", url, resp.StatusCode) - } - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("properties: %s error reading response. %s", url, err) - } - - ct := resp.Header.Get("Content-Type") - ct = strings.Join(strings.Fields(ct), "") - var enc Encoding - switch strings.ToLower(ct) { - case "text/plain", "text/plain;charset=iso-8859-1", "text/plain;charset=latin1": - enc = ISO_8859_1 - case "", "text/plain;charset=utf-8": - enc = UTF8 - default: - return nil, fmt.Errorf("properties: invalid content type %s", ct) - } - - return l.loadBytes(body, enc) -} - -func (l *Loader) loadBytes(buf []byte, enc Encoding) (*Properties, error) { - p, err := parse(convert(buf, enc)) - if err != nil { - return nil, err - } - p.DisableExpansion = l.DisableExpansion - if p.DisableExpansion { - return p, nil - } - return p, p.check() -} - -// Load reads a buffer into a Properties struct. -func Load(buf []byte, enc Encoding) (*Properties, error) { - l := &Loader{Encoding: enc} - return l.LoadBytes(buf) -} - -// LoadString reads an UTF8 string into a properties struct. -func LoadString(s string) (*Properties, error) { - l := &Loader{Encoding: UTF8} - return l.LoadBytes([]byte(s)) -} - -// LoadMap creates a new Properties struct from a string map. -func LoadMap(m map[string]string) *Properties { - p := NewProperties() - for k, v := range m { - p.Set(k, v) - } - return p -} - -// LoadFile reads a file into a Properties struct. -func LoadFile(filename string, enc Encoding) (*Properties, error) { - l := &Loader{Encoding: enc} - return l.LoadAll([]string{filename}) -} - -// LoadFiles reads multiple files in the given order into -// a Properties struct. If 'ignoreMissing' is true then -// non-existent files will not be reported as error. -func LoadFiles(filenames []string, enc Encoding, ignoreMissing bool) (*Properties, error) { - l := &Loader{Encoding: enc, IgnoreMissing: ignoreMissing} - return l.LoadAll(filenames) -} - -// LoadURL reads the content of the URL into a Properties struct. -// See Loader#LoadURL for details. -func LoadURL(url string) (*Properties, error) { - l := &Loader{Encoding: UTF8} - return l.LoadAll([]string{url}) -} - -// LoadURLs reads the content of multiple URLs in the given order into a -// Properties struct. If IgnoreMissing is true then a 404 status code will -// not be reported as error. See Loader#LoadURL for the Content-Type header -// and the encoding. -func LoadURLs(urls []string, ignoreMissing bool) (*Properties, error) { - l := &Loader{Encoding: UTF8, IgnoreMissing: ignoreMissing} - return l.LoadAll(urls) -} - -// LoadAll reads the content of multiple URLs or files in the given order into a -// Properties struct. If 'ignoreMissing' is true then a 404 status code or missing file will -// not be reported as error. Encoding sets the encoding for files. For the URLs please see -// LoadURL for the Content-Type header and the encoding. -func LoadAll(names []string, enc Encoding, ignoreMissing bool) (*Properties, error) { - l := &Loader{Encoding: enc, IgnoreMissing: ignoreMissing} - return l.LoadAll(names) -} - -// MustLoadString reads an UTF8 string into a Properties struct and -// panics on error. -func MustLoadString(s string) *Properties { - return must(LoadString(s)) -} - -// MustLoadFile reads a file into a Properties struct and -// panics on error. -func MustLoadFile(filename string, enc Encoding) *Properties { - return must(LoadFile(filename, enc)) -} - -// MustLoadFiles reads multiple files in the given order into -// a Properties struct and panics on error. If 'ignoreMissing' -// is true then non-existent files will not be reported as error. -func MustLoadFiles(filenames []string, enc Encoding, ignoreMissing bool) *Properties { - return must(LoadFiles(filenames, enc, ignoreMissing)) -} - -// MustLoadURL reads the content of a URL into a Properties struct and -// panics on error. -func MustLoadURL(url string) *Properties { - return must(LoadURL(url)) -} - -// MustLoadURLs reads the content of multiple URLs in the given order into a -// Properties struct and panics on error. If 'ignoreMissing' is true then a 404 -// status code will not be reported as error. -func MustLoadURLs(urls []string, ignoreMissing bool) *Properties { - return must(LoadURLs(urls, ignoreMissing)) -} - -// MustLoadAll reads the content of multiple URLs or files in the given order into a -// Properties struct. If 'ignoreMissing' is true then a 404 status code or missing file will -// not be reported as error. Encoding sets the encoding for files. For the URLs please see -// LoadURL for the Content-Type header and the encoding. It panics on error. -func MustLoadAll(names []string, enc Encoding, ignoreMissing bool) *Properties { - return must(LoadAll(names, enc, ignoreMissing)) -} - -func must(p *Properties, err error) *Properties { - if err != nil { - ErrorHandler(err) - } - return p -} - -// expandName expands ${ENV_VAR} expressions in a name. -// If the environment variable does not exist then it will be replaced -// with an empty string. Malformed expressions like "${ENV_VAR" will -// be reported as error. -func expandName(name string) (string, error) { - return expand(name, []string{}, "${", "}", make(map[string]string)) -} - -// Interprets a byte buffer either as an ISO-8859-1 or UTF-8 encoded string. -// For ISO-8859-1 we can convert each byte straight into a rune since the -// first 256 unicode code points cover ISO-8859-1. -func convert(buf []byte, enc Encoding) string { - switch enc { - case utf8Default, UTF8: - return string(buf) - case ISO_8859_1: - runes := make([]rune, len(buf)) - for i, b := range buf { - runes[i] = rune(b) - } - return string(runes) - default: - ErrorHandler(fmt.Errorf("unsupported encoding %v", enc)) - } - panic("ErrorHandler should exit") -} diff --git a/vendor/github.com/magiconair/properties/parser.go b/vendor/github.com/magiconair/properties/parser.go deleted file mode 100644 index fccfd39f6..000000000 --- a/vendor/github.com/magiconair/properties/parser.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2013-2022 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package properties - -import ( - "fmt" - "runtime" -) - -type parser struct { - lex *lexer -} - -func parse(input string) (properties *Properties, err error) { - p := &parser{lex: lex(input)} - defer p.recover(&err) - - properties = NewProperties() - key := "" - comments := []string{} - - for { - token := p.expectOneOf(itemComment, itemKey, itemEOF) - switch token.typ { - case itemEOF: - goto done - case itemComment: - comments = append(comments, token.val) - continue - case itemKey: - key = token.val - if _, ok := properties.m[key]; !ok { - properties.k = append(properties.k, key) - } - } - - token = p.expectOneOf(itemValue, itemEOF) - if len(comments) > 0 { - properties.c[key] = comments - comments = []string{} - } - switch token.typ { - case itemEOF: - properties.m[key] = "" - goto done - case itemValue: - properties.m[key] = token.val - } - } - -done: - return properties, nil -} - -func (p *parser) errorf(format string, args ...interface{}) { - format = fmt.Sprintf("properties: Line %d: %s", p.lex.lineNumber(), format) - panic(fmt.Errorf(format, args...)) -} - -func (p *parser) expectOneOf(expected ...itemType) (token item) { - token = p.lex.nextItem() - for _, v := range expected { - if token.typ == v { - return token - } - } - p.unexpected(token) - panic("unexpected token") -} - -func (p *parser) unexpected(token item) { - p.errorf(token.String()) -} - -// recover is the handler that turns panics into returns from the top level of Parse. -func (p *parser) recover(errp *error) { - e := recover() - if e != nil { - if _, ok := e.(runtime.Error); ok { - panic(e) - } - *errp = e.(error) - } -} diff --git a/vendor/github.com/magiconair/properties/properties.go b/vendor/github.com/magiconair/properties/properties.go deleted file mode 100644 index fb2f7b404..000000000 --- a/vendor/github.com/magiconair/properties/properties.go +++ /dev/null @@ -1,848 +0,0 @@ -// Copyright 2013-2022 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package properties - -// BUG(frank): Set() does not check for invalid unicode literals since this is currently handled by the lexer. -// BUG(frank): Write() does not allow to configure the newline character. Therefore, on Windows LF is used. - -import ( - "bytes" - "fmt" - "io" - "log" - "os" - "regexp" - "sort" - "strconv" - "strings" - "time" - "unicode/utf8" -) - -const maxExpansionDepth = 64 - -// ErrorHandlerFunc defines the type of function which handles failures -// of the MustXXX() functions. An error handler function must exit -// the application after handling the error. -type ErrorHandlerFunc func(error) - -// ErrorHandler is the function which handles failures of the MustXXX() -// functions. The default is LogFatalHandler. -var ErrorHandler ErrorHandlerFunc = LogFatalHandler - -// LogHandlerFunc defines the function prototype for logging errors. -type LogHandlerFunc func(fmt string, args ...interface{}) - -// LogPrintf defines a log handler which uses log.Printf. -var LogPrintf LogHandlerFunc = log.Printf - -// LogFatalHandler handles the error by logging a fatal error and exiting. -func LogFatalHandler(err error) { - log.Fatal(err) -} - -// PanicHandler handles the error by panicking. -func PanicHandler(err error) { - panic(err) -} - -// ----------------------------------------------------------------------------- - -// A Properties contains the key/value pairs from the properties input. -// All values are stored in unexpanded form and are expanded at runtime -type Properties struct { - // Pre-/Postfix for property expansion. - Prefix string - Postfix string - - // DisableExpansion controls the expansion of properties on Get() - // and the check for circular references on Set(). When set to - // true Properties behaves like a simple key/value store and does - // not check for circular references on Get() or on Set(). - DisableExpansion bool - - // Stores the key/value pairs - m map[string]string - - // Stores the comments per key. - c map[string][]string - - // Stores the keys in order of appearance. - k []string - - // WriteSeparator specifies the separator of key and value while writing the properties. - WriteSeparator string -} - -// NewProperties creates a new Properties struct with the default -// configuration for "${key}" expressions. -func NewProperties() *Properties { - return &Properties{ - Prefix: "${", - Postfix: "}", - m: map[string]string{}, - c: map[string][]string{}, - k: []string{}, - } -} - -// Load reads a buffer into the given Properties struct. -func (p *Properties) Load(buf []byte, enc Encoding) error { - l := &Loader{Encoding: enc, DisableExpansion: p.DisableExpansion} - newProperties, err := l.LoadBytes(buf) - if err != nil { - return err - } - p.Merge(newProperties) - return nil -} - -// Get returns the expanded value for the given key if exists. -// Otherwise, ok is false. -func (p *Properties) Get(key string) (value string, ok bool) { - v, ok := p.m[key] - if p.DisableExpansion { - return v, ok - } - if !ok { - return "", false - } - - expanded, err := p.expand(key, v) - - // we guarantee that the expanded value is free of - // circular references and malformed expressions - // so we panic if we still get an error here. - if err != nil { - ErrorHandler(err) - } - - return expanded, true -} - -// MustGet returns the expanded value for the given key if exists. -// Otherwise, it panics. -func (p *Properties) MustGet(key string) string { - if v, ok := p.Get(key); ok { - return v - } - ErrorHandler(invalidKeyError(key)) - panic("ErrorHandler should exit") -} - -// ---------------------------------------------------------------------------- - -// ClearComments removes the comments for all keys. -func (p *Properties) ClearComments() { - p.c = map[string][]string{} -} - -// ---------------------------------------------------------------------------- - -// GetComment returns the last comment before the given key or an empty string. -func (p *Properties) GetComment(key string) string { - comments, ok := p.c[key] - if !ok || len(comments) == 0 { - return "" - } - return comments[len(comments)-1] -} - -// ---------------------------------------------------------------------------- - -// GetComments returns all comments that appeared before the given key or nil. -func (p *Properties) GetComments(key string) []string { - if comments, ok := p.c[key]; ok { - return comments - } - return nil -} - -// ---------------------------------------------------------------------------- - -// SetComment sets the comment for the key. -func (p *Properties) SetComment(key, comment string) { - p.c[key] = []string{comment} -} - -// ---------------------------------------------------------------------------- - -// SetComments sets the comments for the key. If the comments are nil then -// all comments for this key are deleted. -func (p *Properties) SetComments(key string, comments []string) { - if comments == nil { - delete(p.c, key) - return - } - p.c[key] = comments -} - -// ---------------------------------------------------------------------------- - -// GetBool checks if the expanded value is one of '1', 'yes', -// 'true' or 'on' if the key exists. The comparison is case-insensitive. -// If the key does not exist the default value is returned. -func (p *Properties) GetBool(key string, def bool) bool { - v, err := p.getBool(key) - if err != nil { - return def - } - return v -} - -// MustGetBool checks if the expanded value is one of '1', 'yes', -// 'true' or 'on' if the key exists. The comparison is case-insensitive. -// If the key does not exist the function panics. -func (p *Properties) MustGetBool(key string) bool { - v, err := p.getBool(key) - if err != nil { - ErrorHandler(err) - } - return v -} - -func (p *Properties) getBool(key string) (value bool, err error) { - if v, ok := p.Get(key); ok { - return boolVal(v), nil - } - return false, invalidKeyError(key) -} - -func boolVal(v string) bool { - v = strings.ToLower(v) - return v == "1" || v == "true" || v == "yes" || v == "on" -} - -// ---------------------------------------------------------------------------- - -// GetDuration parses the expanded value as an time.Duration (in ns) if the -// key exists. If key does not exist or the value cannot be parsed the default -// value is returned. In almost all cases you want to use GetParsedDuration(). -func (p *Properties) GetDuration(key string, def time.Duration) time.Duration { - v, err := p.getInt64(key) - if err != nil { - return def - } - return time.Duration(v) -} - -// MustGetDuration parses the expanded value as an time.Duration (in ns) if -// the key exists. If key does not exist or the value cannot be parsed the -// function panics. In almost all cases you want to use MustGetParsedDuration(). -func (p *Properties) MustGetDuration(key string) time.Duration { - v, err := p.getInt64(key) - if err != nil { - ErrorHandler(err) - } - return time.Duration(v) -} - -// ---------------------------------------------------------------------------- - -// GetParsedDuration parses the expanded value with time.ParseDuration() if the key exists. -// If key does not exist or the value cannot be parsed the default -// value is returned. -func (p *Properties) GetParsedDuration(key string, def time.Duration) time.Duration { - s, ok := p.Get(key) - if !ok { - return def - } - v, err := time.ParseDuration(s) - if err != nil { - return def - } - return v -} - -// MustGetParsedDuration parses the expanded value with time.ParseDuration() if the key exists. -// If key does not exist or the value cannot be parsed the function panics. -func (p *Properties) MustGetParsedDuration(key string) time.Duration { - s, ok := p.Get(key) - if !ok { - ErrorHandler(invalidKeyError(key)) - } - v, err := time.ParseDuration(s) - if err != nil { - ErrorHandler(err) - } - return v -} - -// ---------------------------------------------------------------------------- - -// GetFloat64 parses the expanded value as a float64 if the key exists. -// If key does not exist or the value cannot be parsed the default -// value is returned. -func (p *Properties) GetFloat64(key string, def float64) float64 { - v, err := p.getFloat64(key) - if err != nil { - return def - } - return v -} - -// MustGetFloat64 parses the expanded value as a float64 if the key exists. -// If key does not exist or the value cannot be parsed the function panics. -func (p *Properties) MustGetFloat64(key string) float64 { - v, err := p.getFloat64(key) - if err != nil { - ErrorHandler(err) - } - return v -} - -func (p *Properties) getFloat64(key string) (value float64, err error) { - if v, ok := p.Get(key); ok { - value, err = strconv.ParseFloat(v, 64) - if err != nil { - return 0, err - } - return value, nil - } - return 0, invalidKeyError(key) -} - -// ---------------------------------------------------------------------------- - -// GetInt parses the expanded value as an int if the key exists. -// If key does not exist or the value cannot be parsed the default -// value is returned. If the value does not fit into an int the -// function panics with an out of range error. -func (p *Properties) GetInt(key string, def int) int { - v, err := p.getInt64(key) - if err != nil { - return def - } - return intRangeCheck(key, v) -} - -// MustGetInt parses the expanded value as an int if the key exists. -// If key does not exist or the value cannot be parsed the function panics. -// If the value does not fit into an int the function panics with -// an out of range error. -func (p *Properties) MustGetInt(key string) int { - v, err := p.getInt64(key) - if err != nil { - ErrorHandler(err) - } - return intRangeCheck(key, v) -} - -// ---------------------------------------------------------------------------- - -// GetInt64 parses the expanded value as an int64 if the key exists. -// If key does not exist or the value cannot be parsed the default -// value is returned. -func (p *Properties) GetInt64(key string, def int64) int64 { - v, err := p.getInt64(key) - if err != nil { - return def - } - return v -} - -// MustGetInt64 parses the expanded value as an int if the key exists. -// If key does not exist or the value cannot be parsed the function panics. -func (p *Properties) MustGetInt64(key string) int64 { - v, err := p.getInt64(key) - if err != nil { - ErrorHandler(err) - } - return v -} - -func (p *Properties) getInt64(key string) (value int64, err error) { - if v, ok := p.Get(key); ok { - value, err = strconv.ParseInt(v, 10, 64) - if err != nil { - return 0, err - } - return value, nil - } - return 0, invalidKeyError(key) -} - -// ---------------------------------------------------------------------------- - -// GetUint parses the expanded value as an uint if the key exists. -// If key does not exist or the value cannot be parsed the default -// value is returned. If the value does not fit into an int the -// function panics with an out of range error. -func (p *Properties) GetUint(key string, def uint) uint { - v, err := p.getUint64(key) - if err != nil { - return def - } - return uintRangeCheck(key, v) -} - -// MustGetUint parses the expanded value as an int if the key exists. -// If key does not exist or the value cannot be parsed the function panics. -// If the value does not fit into an int the function panics with -// an out of range error. -func (p *Properties) MustGetUint(key string) uint { - v, err := p.getUint64(key) - if err != nil { - ErrorHandler(err) - } - return uintRangeCheck(key, v) -} - -// ---------------------------------------------------------------------------- - -// GetUint64 parses the expanded value as an uint64 if the key exists. -// If key does not exist or the value cannot be parsed the default -// value is returned. -func (p *Properties) GetUint64(key string, def uint64) uint64 { - v, err := p.getUint64(key) - if err != nil { - return def - } - return v -} - -// MustGetUint64 parses the expanded value as an int if the key exists. -// If key does not exist or the value cannot be parsed the function panics. -func (p *Properties) MustGetUint64(key string) uint64 { - v, err := p.getUint64(key) - if err != nil { - ErrorHandler(err) - } - return v -} - -func (p *Properties) getUint64(key string) (value uint64, err error) { - if v, ok := p.Get(key); ok { - value, err = strconv.ParseUint(v, 10, 64) - if err != nil { - return 0, err - } - return value, nil - } - return 0, invalidKeyError(key) -} - -// ---------------------------------------------------------------------------- - -// GetString returns the expanded value for the given key if exists or -// the default value otherwise. -func (p *Properties) GetString(key, def string) string { - if v, ok := p.Get(key); ok { - return v - } - return def -} - -// MustGetString returns the expanded value for the given key if exists or -// panics otherwise. -func (p *Properties) MustGetString(key string) string { - if v, ok := p.Get(key); ok { - return v - } - ErrorHandler(invalidKeyError(key)) - panic("ErrorHandler should exit") -} - -// ---------------------------------------------------------------------------- - -// Filter returns a new properties object which contains all properties -// for which the key matches the pattern. -func (p *Properties) Filter(pattern string) (*Properties, error) { - re, err := regexp.Compile(pattern) - if err != nil { - return nil, err - } - - return p.FilterRegexp(re), nil -} - -// FilterRegexp returns a new properties object which contains all properties -// for which the key matches the regular expression. -func (p *Properties) FilterRegexp(re *regexp.Regexp) *Properties { - pp := NewProperties() - for _, k := range p.k { - if re.MatchString(k) { - // TODO(fs): we are ignoring the error which flags a circular reference. - // TODO(fs): since we are just copying a subset of keys this cannot happen (fingers crossed) - pp.Set(k, p.m[k]) - } - } - return pp -} - -// FilterPrefix returns a new properties object with a subset of all keys -// with the given prefix. -func (p *Properties) FilterPrefix(prefix string) *Properties { - pp := NewProperties() - for _, k := range p.k { - if strings.HasPrefix(k, prefix) { - // TODO(fs): we are ignoring the error which flags a circular reference. - // TODO(fs): since we are just copying a subset of keys this cannot happen (fingers crossed) - pp.Set(k, p.m[k]) - } - } - return pp -} - -// FilterStripPrefix returns a new properties object with a subset of all keys -// with the given prefix and the prefix removed from the keys. -func (p *Properties) FilterStripPrefix(prefix string) *Properties { - pp := NewProperties() - n := len(prefix) - for _, k := range p.k { - if len(k) > len(prefix) && strings.HasPrefix(k, prefix) { - // TODO(fs): we are ignoring the error which flags a circular reference. - // TODO(fs): since we are modifying keys I am not entirely sure whether we can create a circular reference - // TODO(fs): this function should probably return an error but the signature is fixed - pp.Set(k[n:], p.m[k]) - } - } - return pp -} - -// Len returns the number of keys. -func (p *Properties) Len() int { - return len(p.m) -} - -// Keys returns all keys in the same order as in the input. -func (p *Properties) Keys() []string { - keys := make([]string, len(p.k)) - copy(keys, p.k) - return keys -} - -// Set sets the property key to the corresponding value. -// If a value for key existed before then ok is true and prev -// contains the previous value. If the value contains a -// circular reference or a malformed expression then -// an error is returned. -// An empty key is silently ignored. -func (p *Properties) Set(key, value string) (prev string, ok bool, err error) { - if key == "" { - return "", false, nil - } - - // if expansion is disabled we allow circular references - if p.DisableExpansion { - prev, ok = p.Get(key) - p.m[key] = value - if !ok { - p.k = append(p.k, key) - } - return prev, ok, nil - } - - // to check for a circular reference we temporarily need - // to set the new value. If there is an error then revert - // to the previous state. Only if all tests are successful - // then we add the key to the p.k list. - prev, ok = p.Get(key) - p.m[key] = value - - // now check for a circular reference - _, err = p.expand(key, value) - if err != nil { - - // revert to the previous state - if ok { - p.m[key] = prev - } else { - delete(p.m, key) - } - - return "", false, err - } - - if !ok { - p.k = append(p.k, key) - } - - return prev, ok, nil -} - -// SetValue sets property key to the default string value -// as defined by fmt.Sprintf("%v"). -func (p *Properties) SetValue(key string, value interface{}) error { - _, _, err := p.Set(key, fmt.Sprintf("%v", value)) - return err -} - -// MustSet sets the property key to the corresponding value. -// If a value for key existed before then ok is true and prev -// contains the previous value. An empty key is silently ignored. -func (p *Properties) MustSet(key, value string) (prev string, ok bool) { - prev, ok, err := p.Set(key, value) - if err != nil { - ErrorHandler(err) - } - return prev, ok -} - -// String returns a string of all expanded 'key = value' pairs. -func (p *Properties) String() string { - var s string - for _, key := range p.k { - value, _ := p.Get(key) - s = fmt.Sprintf("%s%s = %s\n", s, key, value) - } - return s -} - -// Sort sorts the properties keys in alphabetical order. -// This is helpfully before writing the properties. -func (p *Properties) Sort() { - sort.Strings(p.k) -} - -// Write writes all unexpanded 'key = value' pairs to the given writer. -// Write returns the number of bytes written and any write error encountered. -func (p *Properties) Write(w io.Writer, enc Encoding) (n int, err error) { - return p.WriteComment(w, "", enc) -} - -// WriteComment writes all unexpanced 'key = value' pairs to the given writer. -// If prefix is not empty then comments are written with a blank line and the -// given prefix. The prefix should be either "# " or "! " to be compatible with -// the properties file format. Otherwise, the properties parser will not be -// able to read the file back in. It returns the number of bytes written and -// any write error encountered. -func (p *Properties) WriteComment(w io.Writer, prefix string, enc Encoding) (n int, err error) { - var x int - - for _, key := range p.k { - value := p.m[key] - - if prefix != "" { - if comments, ok := p.c[key]; ok { - // don't print comments if they are all empty - allEmpty := true - for _, c := range comments { - if c != "" { - allEmpty = false - break - } - } - - if !allEmpty { - // add a blank line between entries but not at the top - if len(comments) > 0 && n > 0 { - x, err = fmt.Fprintln(w) - if err != nil { - return - } - n += x - } - - for _, c := range comments { - x, err = fmt.Fprintf(w, "%s%s\n", prefix, c) - if err != nil { - return - } - n += x - } - } - } - } - sep := " = " - if p.WriteSeparator != "" { - sep = p.WriteSeparator - } - x, err = fmt.Fprintf(w, "%s%s%s\n", encode(key, " :", enc), sep, encode(value, "", enc)) - if err != nil { - return - } - n += x - } - return -} - -// Map returns a copy of the properties as a map. -func (p *Properties) Map() map[string]string { - m := make(map[string]string) - for k, v := range p.m { - m[k] = v - } - return m -} - -// FilterFunc returns a copy of the properties which includes the values which passed all filters. -func (p *Properties) FilterFunc(filters ...func(k, v string) bool) *Properties { - pp := NewProperties() -outer: - for k, v := range p.m { - for _, f := range filters { - if !f(k, v) { - continue outer - } - pp.Set(k, v) - } - } - return pp -} - -// ---------------------------------------------------------------------------- - -// Delete removes the key and its comments. -func (p *Properties) Delete(key string) { - delete(p.m, key) - delete(p.c, key) - newKeys := []string{} - for _, k := range p.k { - if k != key { - newKeys = append(newKeys, k) - } - } - p.k = newKeys -} - -// Merge merges properties, comments and keys from other *Properties into p -func (p *Properties) Merge(other *Properties) { - for _, k := range other.k { - if _, ok := p.m[k]; !ok { - p.k = append(p.k, k) - } - } - for k, v := range other.m { - p.m[k] = v - } - for k, v := range other.c { - p.c[k] = v - } -} - -// ---------------------------------------------------------------------------- - -// check expands all values and returns an error if a circular reference or -// a malformed expression was found. -func (p *Properties) check() error { - for key, value := range p.m { - if _, err := p.expand(key, value); err != nil { - return err - } - } - return nil -} - -func (p *Properties) expand(key, input string) (string, error) { - // no pre/postfix -> nothing to expand - if p.Prefix == "" && p.Postfix == "" { - return input, nil - } - - return expand(input, []string{key}, p.Prefix, p.Postfix, p.m) -} - -// expand recursively expands expressions of '(prefix)key(postfix)' to their corresponding values. -// The function keeps track of the keys that were already expanded and stops if it -// detects a circular reference or a malformed expression of the form '(prefix)key'. -func expand(s string, keys []string, prefix, postfix string, values map[string]string) (string, error) { - if len(keys) > maxExpansionDepth { - return "", fmt.Errorf("expansion too deep") - } - - for { - start := strings.Index(s, prefix) - if start == -1 { - return s, nil - } - - keyStart := start + len(prefix) - keyLen := strings.Index(s[keyStart:], postfix) - if keyLen == -1 { - return "", fmt.Errorf("malformed expression") - } - - end := keyStart + keyLen + len(postfix) - 1 - key := s[keyStart : keyStart+keyLen] - - // fmt.Printf("s:%q pp:%q start:%d end:%d keyStart:%d keyLen:%d key:%q\n", s, prefix + "..." + postfix, start, end, keyStart, keyLen, key) - - for _, k := range keys { - if key == k { - var b bytes.Buffer - b.WriteString("circular reference in:\n") - for _, k1 := range keys { - fmt.Fprintf(&b, "%s=%s\n", k1, values[k1]) - } - return "", fmt.Errorf(b.String()) - } - } - - val, ok := values[key] - if !ok { - val = os.Getenv(key) - } - new_val, err := expand(val, append(keys, key), prefix, postfix, values) - if err != nil { - return "", err - } - s = s[:start] + new_val + s[end+1:] - } -} - -// encode encodes a UTF-8 string to ISO-8859-1 and escapes some characters. -func encode(s string, special string, enc Encoding) string { - switch enc { - case UTF8: - return encodeUtf8(s, special) - case ISO_8859_1: - return encodeIso(s, special) - default: - panic(fmt.Sprintf("unsupported encoding %v", enc)) - } -} - -func encodeUtf8(s string, special string) string { - v := "" - for pos := 0; pos < len(s); { - r, w := utf8.DecodeRuneInString(s[pos:]) - pos += w - v += escape(r, special) - } - return v -} - -func encodeIso(s string, special string) string { - var r rune - var w int - var v string - for pos := 0; pos < len(s); { - switch r, w = utf8.DecodeRuneInString(s[pos:]); { - case r < 1<<8: // single byte rune -> escape special chars only - v += escape(r, special) - case r < 1<<16: // two byte rune -> unicode literal - v += fmt.Sprintf("\\u%04x", r) - default: // more than two bytes per rune -> can't encode - v += "?" - } - pos += w - } - return v -} - -func escape(r rune, special string) string { - switch r { - case '\f': - return "\\f" - case '\n': - return "\\n" - case '\r': - return "\\r" - case '\t': - return "\\t" - case '\\': - return "\\\\" - default: - if strings.ContainsRune(special, r) { - return "\\" + string(r) - } - return string(r) - } -} - -func invalidKeyError(key string) error { - return fmt.Errorf("unknown property: %s", key) -} diff --git a/vendor/github.com/magiconair/properties/rangecheck.go b/vendor/github.com/magiconair/properties/rangecheck.go deleted file mode 100644 index dbd60b36e..000000000 --- a/vendor/github.com/magiconair/properties/rangecheck.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2013-2022 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package properties - -import ( - "fmt" - "math" -) - -// make this a var to overwrite it in a test -var is32Bit = ^uint(0) == math.MaxUint32 - -// intRangeCheck checks if the value fits into the int type and -// panics if it does not. -func intRangeCheck(key string, v int64) int { - if is32Bit && (v < math.MinInt32 || v > math.MaxInt32) { - panic(fmt.Sprintf("Value %d for key %s out of range", v, key)) - } - return int(v) -} - -// uintRangeCheck checks if the value fits into the uint type and -// panics if it does not. -func uintRangeCheck(key string, v uint64) uint { - if is32Bit && v > math.MaxUint32 { - panic(fmt.Sprintf("Value %d for key %s out of range", v, key)) - } - return uint(v) -} diff --git a/vendor/github.com/manuelarte/embeddedstructfieldcheck/LICENSE b/vendor/github.com/manuelarte/embeddedstructfieldcheck/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/vendor/github.com/manuelarte/embeddedstructfieldcheck/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/manuelarte/embeddedstructfieldcheck/analyzer/analyzer.go b/vendor/github.com/manuelarte/embeddedstructfieldcheck/analyzer/analyzer.go new file mode 100644 index 000000000..dc137d71e --- /dev/null +++ b/vendor/github.com/manuelarte/embeddedstructfieldcheck/analyzer/analyzer.go @@ -0,0 +1,64 @@ +package analyzer + +import ( + "go/ast" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/ast/inspector" + + "github.com/manuelarte/embeddedstructfieldcheck/internal" +) + +const ( + EmptyLineCheck = "empty-line" + ForbidMutexCheck = "forbid-mutex" +) + +func NewAnalyzer() *analysis.Analyzer { + var ( + emptyLine bool + forbidMutex bool + ) + + a := &analysis.Analyzer{ + Name: "embeddedstructfieldcheck", + Doc: "Embedded types should be at the top of the field list of a struct, " + + "and there must be an empty line separating embedded fields from regular fields.", + URL: "https://github.com/manuelarte/embeddedstructfieldcheck", + Run: func(pass *analysis.Pass) (any, error) { + run(pass, emptyLine, forbidMutex) + + //nolint:nilnil // impossible case. + return nil, nil + }, + Requires: []*analysis.Analyzer{inspect.Analyzer}, + } + + a.Flags.BoolVar(&emptyLine, EmptyLineCheck, true, + "Checks that there is an empty space between the embedded fields and regular fields.") + a.Flags.BoolVar(&forbidMutex, ForbidMutexCheck, false, + "Checks that sync.Mutex and sync.RWMutex are not used as an embedded fields.") + + return a +} + +func run(pass *analysis.Pass, emptyLine, forbidMutex bool) { + insp, found := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + if !found { + return + } + + nodeFilter := []ast.Node{ + (*ast.StructType)(nil), + } + + insp.Preorder(nodeFilter, func(n ast.Node) { + node, ok := n.(*ast.StructType) + if !ok { + return + } + + internal.Analyze(pass, node, emptyLine, forbidMutex) + }) +} diff --git a/vendor/github.com/manuelarte/embeddedstructfieldcheck/internal/diag.go b/vendor/github.com/manuelarte/embeddedstructfieldcheck/internal/diag.go new file mode 100644 index 000000000..337b0dff7 --- /dev/null +++ b/vendor/github.com/manuelarte/embeddedstructfieldcheck/internal/diag.go @@ -0,0 +1,48 @@ +package internal + +import ( + "fmt" + "go/ast" + + "golang.org/x/tools/go/analysis" +) + +func NewMisplacedEmbeddedFieldDiag(embeddedField *ast.Field) analysis.Diagnostic { + return analysis.Diagnostic{ + Pos: embeddedField.Pos(), + Message: "embedded fields should be listed before regular fields", + } +} + +func NewMissingSpaceDiag( + lastEmbeddedField *ast.Field, + firstRegularField *ast.Field, +) analysis.Diagnostic { + suggestedPos := firstRegularField.Pos() + if firstRegularField.Doc != nil { + suggestedPos = firstRegularField.Doc.Pos() + } + + return analysis.Diagnostic{ + Pos: lastEmbeddedField.Pos(), + Message: "there must be an empty line separating embedded fields from regular fields", + SuggestedFixes: []analysis.SuggestedFix{ + { + Message: "adding extra line separating embedded fields from regular fields", + TextEdits: []analysis.TextEdit{ + { + Pos: suggestedPos, + NewText: []byte("\n\n"), + }, + }, + }, + }, + } +} + +func NewForbiddenEmbeddedFieldDiag(forbidField *ast.SelectorExpr) analysis.Diagnostic { + return analysis.Diagnostic{ + Pos: forbidField.Pos(), + Message: fmt.Sprintf("%s.%s should not be embedded", forbidField.X, forbidField.Sel.Name), + } +} diff --git a/vendor/github.com/manuelarte/embeddedstructfieldcheck/internal/structanalyzer.go b/vendor/github.com/manuelarte/embeddedstructfieldcheck/internal/structanalyzer.go new file mode 100644 index 000000000..2df53692a --- /dev/null +++ b/vendor/github.com/manuelarte/embeddedstructfieldcheck/internal/structanalyzer.go @@ -0,0 +1,88 @@ +package internal + +import ( + "go/ast" + + "golang.org/x/tools/go/analysis" +) + +func Analyze(pass *analysis.Pass, st *ast.StructType, emptyLine, forbidMutex bool) { + var firstEmbeddedField *ast.Field + + var lastEmbeddedField *ast.Field + + var firstNotEmbeddedField *ast.Field + + for _, field := range st.Fields.List { + if isFieldEmbedded(field) { + checkForbiddenEmbeddedField(pass, field, forbidMutex) + + if firstEmbeddedField == nil { + firstEmbeddedField = field + } + + if lastEmbeddedField == nil || lastEmbeddedField.Pos() < field.Pos() { + lastEmbeddedField = field + } + + if firstNotEmbeddedField != nil && firstNotEmbeddedField.Pos() < field.Pos() { + pass.Report(NewMisplacedEmbeddedFieldDiag(field)) + return + } + } else if firstNotEmbeddedField == nil { + firstNotEmbeddedField = field + } + } + + if emptyLine { + checkMissingSpace(pass, lastEmbeddedField, firstNotEmbeddedField) + } +} + +func checkForbiddenEmbeddedField(pass *analysis.Pass, field *ast.Field, forbidMutex bool) { + if !forbidMutex { + return + } + + switch e := field.Type.(type) { + case *ast.StarExpr: + if se, isSelectorExpr := e.X.(*ast.SelectorExpr); isSelectorExpr { + reportSyncMutex(pass, se) + } + + case *ast.SelectorExpr: + reportSyncMutex(pass, e) + } +} + +func checkMissingSpace(pass *analysis.Pass, lastEmbeddedField, firstNotEmbeddedField *ast.Field) { + if lastEmbeddedField != nil && firstNotEmbeddedField != nil { + // check for missing space + // TODO: isn't it easy to remove as many lines as comments between last embedded type and first not embedded + line := pass.Fset.Position(lastEmbeddedField.End()).Line + + nextLine := pass.Fset.Position(firstNotEmbeddedField.Pos()).Line + if firstNotEmbeddedField.Doc != nil { + nextLine = pass.Fset.Position(firstNotEmbeddedField.Doc.Pos()).Line + } + + if nextLine != line+2 { + pass.Report(NewMissingSpaceDiag(lastEmbeddedField, firstNotEmbeddedField)) + } + } +} + +func isFieldEmbedded(field *ast.Field) bool { + return len(field.Names) == 0 +} + +func reportSyncMutex(pass *analysis.Pass, se *ast.SelectorExpr) { + packageName, isIdent := se.X.(*ast.Ident) + if !isIdent { + return + } + + if packageName.Name == "sync" && (se.Sel.Name == "Mutex" || se.Sel.Name == "RWMutex") { + pass.Report(NewForbiddenEmbeddedFieldDiag(se)) + } +} diff --git a/vendor/github.com/manuelarte/funcorder/LICENSE b/vendor/github.com/manuelarte/funcorder/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/vendor/github.com/manuelarte/funcorder/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/manuelarte/funcorder/analyzer/analyzer.go b/vendor/github.com/manuelarte/funcorder/analyzer/analyzer.go new file mode 100644 index 000000000..c3112107d --- /dev/null +++ b/vendor/github.com/manuelarte/funcorder/analyzer/analyzer.go @@ -0,0 +1,97 @@ +package analyzer + +import ( + "go/ast" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/ast/inspector" + + "github.com/manuelarte/funcorder/internal" +) + +const ( + ConstructorCheckName = "constructor" + StructMethodCheckName = "struct-method" + AlphabeticalCheckName = "alphabetical" +) + +func NewAnalyzer() *analysis.Analyzer { + f := funcorder{} + + a := &analysis.Analyzer{ + Name: "funcorder", + Doc: "checks the order of functions, methods, and constructors", + URL: "https://github.com/manuelarte/funcorder", + Run: f.run, + Requires: []*analysis.Analyzer{inspect.Analyzer}, + } + + a.Flags.BoolVar(&f.constructorCheck, ConstructorCheckName, true, + "Checks that constructors are placed after the structure declaration.") + a.Flags.BoolVar(&f.structMethodCheck, StructMethodCheckName, true, + "Checks if the exported methods of a structure are placed before the unexported ones.") + a.Flags.BoolVar(&f.alphabeticalCheck, AlphabeticalCheckName, false, + "Checks if the constructors and/or structure methods are sorted alphabetically.") + + return a +} + +type funcorder struct { + constructorCheck bool + structMethodCheck bool + alphabeticalCheck bool +} + +func (f *funcorder) run(pass *analysis.Pass) (any, error) { + var enabledCheckers internal.Feature + if f.constructorCheck { + enabledCheckers.Enable(internal.ConstructorCheck) + } + + if f.structMethodCheck { + enabledCheckers.Enable(internal.StructMethodCheck) + } + + if f.alphabeticalCheck { + enabledCheckers.Enable(internal.AlphabeticalCheck) + } + + fp := internal.NewFileProcessor(pass.Fset, enabledCheckers) + + insp, found := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + if !found { + //nolint:nilnil // impossible case. + return nil, nil + } + + nodeFilter := []ast.Node{ + (*ast.File)(nil), + (*ast.FuncDecl)(nil), + (*ast.TypeSpec)(nil), + } + + insp.Preorder(nodeFilter, func(n ast.Node) { + switch node := n.(type) { + case *ast.File: + for _, report := range fp.Analyze() { + pass.Report(report) + } + + fp.NewFileNode(node) + + case *ast.FuncDecl: + fp.NewFuncDecl(node) + + case *ast.TypeSpec: + fp.NewTypeSpec(node) + } + }) + + for _, report := range fp.Analyze() { + pass.Report(report) + } + + //nolint:nilnil //any, error + return nil, nil +} diff --git a/vendor/github.com/manuelarte/funcorder/internal/astutils.go b/vendor/github.com/manuelarte/funcorder/internal/astutils.go new file mode 100644 index 000000000..af7fa8c81 --- /dev/null +++ b/vendor/github.com/manuelarte/funcorder/internal/astutils.go @@ -0,0 +1,93 @@ +package internal + +import ( + "bytes" + "go/ast" + "go/format" + "go/token" + "strings" +) + +func FuncCanBeConstructor(n *ast.FuncDecl) bool { + if !n.Name.IsExported() || n.Recv != nil { + return false + } + + if n.Type.Results == nil || len(n.Type.Results.List) == 0 { + return false + } + + for _, prefix := range []string{"new", "must"} { + if strings.HasPrefix(strings.ToLower(n.Name.Name), prefix) && + len(n.Name.Name) > len(prefix) { // TODO(ldez): bug if the name is just `New`. + return true + } + } + + return false +} + +func FuncIsMethod(n *ast.FuncDecl) (*ast.Ident, bool) { + if n.Recv == nil { + return nil, false + } + + if len(n.Recv.List) != 1 { + return nil, false + } + + if recv, ok := GetIdent(n.Recv.List[0].Type); ok { + return recv, true + } + + return nil, false +} + +func GetIdent(expr ast.Expr) (*ast.Ident, bool) { + switch exp := expr.(type) { + case *ast.StarExpr: + return GetIdent(exp.X) + + case *ast.Ident: + return exp, true + + default: + return nil, false + } +} + +// GetStartingPos returns the token starting position of the function +// taking into account if there are comments. +func GetStartingPos(function *ast.FuncDecl) token.Pos { + startingPos := function.Pos() + if function.Doc != nil { + startingPos = function.Doc.Pos() + } + + return startingPos +} + +// NodeToBytes convert the ast.Node in bytes. +func NodeToBytes(fset *token.FileSet, node ast.Node) ([]byte, error) { + var buf bytes.Buffer + if err := format.Node(&buf, fset, node); err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +// SplitExportedUnexported split functions/methods based on whether they are exported or not. +// +//nolint:nonamedreturns // names serve as documentation +func SplitExportedUnexported(funcDecls []*ast.FuncDecl) (exported, unexported []*ast.FuncDecl) { + for _, f := range funcDecls { + if f.Name.IsExported() { + exported = append(exported, f) + } else { + unexported = append(unexported, f) + } + } + + return exported, unexported +} diff --git a/vendor/github.com/manuelarte/funcorder/internal/diag.go b/vendor/github.com/manuelarte/funcorder/internal/diag.go new file mode 100644 index 000000000..faf2ffdd1 --- /dev/null +++ b/vendor/github.com/manuelarte/funcorder/internal/diag.go @@ -0,0 +1,69 @@ +package internal + +import ( + "fmt" + "go/ast" + + "golang.org/x/tools/go/analysis" +) + +func NewConstructorNotAfterStructType(structSpec *ast.TypeSpec, constructor *ast.FuncDecl) analysis.Diagnostic { + return analysis.Diagnostic{ + Pos: constructor.Pos(), + Message: fmt.Sprintf("constructor %q for struct %q should be placed after the struct declaration", + constructor.Name, structSpec.Name), + URL: "https://github.com/manuelarte/funcorder?tab=readme-ov-file#check-constructors-functions-are-placed-after-struct-declaration", //nolint:lll // url + } +} + +func NewConstructorNotBeforeStructMethod( + structSpec *ast.TypeSpec, + constructor *ast.FuncDecl, + method *ast.FuncDecl, +) analysis.Diagnostic { + return analysis.Diagnostic{ + Pos: constructor.Pos(), + URL: "https://github.com/manuelarte/funcorder?tab=readme-ov-file#check-constructors-functions-are-placed-after-struct-declaration", //nolint:lll // url + Message: fmt.Sprintf("constructor %q for struct %q should be placed before struct method %q", + constructor.Name, structSpec.Name, method.Name), + } +} + +func NewAdjacentConstructorsNotSortedAlphabetically( + structSpec *ast.TypeSpec, + constructorNotSorted *ast.FuncDecl, + otherConstructorNotSorted *ast.FuncDecl, +) analysis.Diagnostic { + return analysis.Diagnostic{ + Pos: otherConstructorNotSorted.Pos(), + URL: "https://github.com/manuelarte/funcorder?tab=readme-ov-file#check-constructorsmethods-are-sorted-alphabetically", + Message: fmt.Sprintf("constructor %q for struct %q should be placed before constructor %q", + otherConstructorNotSorted.Name, structSpec.Name, constructorNotSorted.Name), + } +} + +func NewUnexportedMethodBeforeExportedForStruct( + structSpec *ast.TypeSpec, + privateMethod *ast.FuncDecl, + publicMethod *ast.FuncDecl, +) analysis.Diagnostic { + return analysis.Diagnostic{ + Pos: privateMethod.Pos(), + URL: "https://github.com/manuelarte/funcorder?tab=readme-ov-file#check-exported-methods-are-placed-before-unexported-methods", //nolint:lll // url + Message: fmt.Sprintf("unexported method %q for struct %q should be placed after the exported method %q", + privateMethod.Name, structSpec.Name, publicMethod.Name), + } +} + +func NewAdjacentStructMethodsNotSortedAlphabetically( + structSpec *ast.TypeSpec, + method *ast.FuncDecl, + otherMethod *ast.FuncDecl, +) analysis.Diagnostic { + return analysis.Diagnostic{ + Pos: otherMethod.Pos(), + URL: "https://github.com/manuelarte/funcorder?tab=readme-ov-file#check-constructorsmethods-are-sorted-alphabetically", + Message: fmt.Sprintf("method %q for struct %q should be placed before method %q", + otherMethod.Name, structSpec.Name, method.Name), + } +} diff --git a/vendor/github.com/manuelarte/funcorder/internal/features.go b/vendor/github.com/manuelarte/funcorder/internal/features.go new file mode 100644 index 000000000..55d5caba3 --- /dev/null +++ b/vendor/github.com/manuelarte/funcorder/internal/features.go @@ -0,0 +1,17 @@ +package internal + +const ( + ConstructorCheck Feature = 1 << iota + StructMethodCheck + AlphabeticalCheck +) + +type Feature uint8 + +func (f *Feature) Enable(other Feature) { + *f |= other +} + +func (f *Feature) IsEnabled(other Feature) bool { + return *f&other != 0 +} diff --git a/vendor/github.com/manuelarte/funcorder/internal/file_processor.go b/vendor/github.com/manuelarte/funcorder/internal/file_processor.go new file mode 100644 index 000000000..88ae00f2e --- /dev/null +++ b/vendor/github.com/manuelarte/funcorder/internal/file_processor.go @@ -0,0 +1,82 @@ +package internal + +import ( + "go/ast" + "go/token" + + "golang.org/x/tools/go/analysis" +) + +// FileProcessor Holder to store all the functions that are potential to be constructors and all the structs. +type FileProcessor struct { + fset *token.FileSet + structs map[string]*StructHolder + features Feature +} + +// NewFileProcessor creates a new file processor. +func NewFileProcessor(fset *token.FileSet, checkers Feature) *FileProcessor { + return &FileProcessor{ + fset: fset, + structs: make(map[string]*StructHolder), + features: checkers, + } +} + +// Analyze check whether the order of the methods in the constructor is correct. +func (fp *FileProcessor) Analyze() []analysis.Diagnostic { + var reports []analysis.Diagnostic + + for _, sh := range fp.structs { + // filter out structs that are not declared inside that file + if sh.Struct != nil { + reports = append(reports, sh.Analyze()...) + } + } + + return reports +} + +func (fp *FileProcessor) NewFileNode(_ *ast.File) { + fp.structs = make(map[string]*StructHolder) +} + +func (fp *FileProcessor) NewFuncDecl(n *ast.FuncDecl) { + if sc, ok := NewStructConstructor(n); ok { + fp.addConstructor(sc) + return + } + + if st, ok := FuncIsMethod(n); ok { + fp.addMethod(st.Name, n) + } +} + +func (fp *FileProcessor) NewTypeSpec(n *ast.TypeSpec) { + sh := fp.getOrCreate(n.Name.Name) + sh.Struct = n +} + +func (fp *FileProcessor) addConstructor(sc StructConstructor) { + sh := fp.getOrCreate(sc.GetStructReturn().Name) + sh.AddConstructor(sc.GetConstructor()) +} + +func (fp *FileProcessor) addMethod(st string, n *ast.FuncDecl) { + sh := fp.getOrCreate(st) + sh.AddMethod(n) +} + +func (fp *FileProcessor) getOrCreate(structName string) *StructHolder { + if holder, ok := fp.structs[structName]; ok { + return holder + } + + created := &StructHolder{ + Fset: fp.fset, + Features: fp.features, + } + fp.structs[structName] = created + + return created +} diff --git a/vendor/github.com/manuelarte/funcorder/internal/struct_constructor.go b/vendor/github.com/manuelarte/funcorder/internal/struct_constructor.go new file mode 100644 index 000000000..fc4b252df --- /dev/null +++ b/vendor/github.com/manuelarte/funcorder/internal/struct_constructor.go @@ -0,0 +1,37 @@ +package internal + +import ( + "go/ast" +) + +type StructConstructor struct { + constructor *ast.FuncDecl + structReturn *ast.Ident +} + +func NewStructConstructor(funcDec *ast.FuncDecl) (StructConstructor, bool) { + if !FuncCanBeConstructor(funcDec) { + return StructConstructor{}, false + } + + expr := funcDec.Type.Results.List[0].Type + + returnType, ok := GetIdent(expr) + if !ok { + return StructConstructor{}, false + } + + return StructConstructor{ + constructor: funcDec, + structReturn: returnType, + }, true +} + +// GetStructReturn Return the struct linked to this "constructor". +func (sc StructConstructor) GetStructReturn() *ast.Ident { + return sc.structReturn +} + +func (sc StructConstructor) GetConstructor() *ast.FuncDecl { + return sc.constructor +} diff --git a/vendor/github.com/manuelarte/funcorder/internal/structholder.go b/vendor/github.com/manuelarte/funcorder/internal/structholder.go new file mode 100644 index 000000000..424b2ddd7 --- /dev/null +++ b/vendor/github.com/manuelarte/funcorder/internal/structholder.go @@ -0,0 +1,141 @@ +package internal + +import ( + "cmp" + "go/ast" + "go/token" + "slices" + + "golang.org/x/tools/go/analysis" +) + +type ( + ExportedMethods []*ast.FuncDecl + UnexportedMethods []*ast.FuncDecl +) + +// StructHolder contains all the information around a Go struct. +type StructHolder struct { + // The fileset + Fset *token.FileSet + // The features to be analyzed + Features Feature + + // The struct declaration + Struct *ast.TypeSpec + + // A Struct constructor is considered if starts with `New...` and the 1st output parameter is a struct + Constructors []*ast.FuncDecl + + // Struct methods + StructMethods []*ast.FuncDecl +} + +func (sh *StructHolder) AddConstructor(fn *ast.FuncDecl) { + sh.Constructors = append(sh.Constructors, fn) +} + +func (sh *StructHolder) AddMethod(fn *ast.FuncDecl) { + sh.StructMethods = append(sh.StructMethods, fn) +} + +// Analyze applies the linter to the struct holder. +func (sh *StructHolder) Analyze() []analysis.Diagnostic { + // TODO maybe sort constructors and then report also, like NewXXX before MustXXX + slices.SortFunc(sh.StructMethods, func(a, b *ast.FuncDecl) int { + return cmp.Compare(a.Pos(), b.Pos()) + }) + + var reports []analysis.Diagnostic + + if sh.Features.IsEnabled(ConstructorCheck) { + reports = append(reports, sh.analyzeConstructor()...) + } + + if sh.Features.IsEnabled(StructMethodCheck) { + reports = append(reports, sh.analyzeStructMethod()...) + } + + // TODO also check that the methods are declared after the struct + return reports +} + +func (sh *StructHolder) analyzeConstructor() []analysis.Diagnostic { + var reports []analysis.Diagnostic + + for i, constructor := range sh.Constructors { + if constructor.Pos() < sh.Struct.Pos() { + reports = append(reports, NewConstructorNotAfterStructType(sh.Struct, constructor)) + } + + if len(sh.StructMethods) > 0 && constructor.Pos() > sh.StructMethods[0].Pos() { + reports = append(reports, NewConstructorNotBeforeStructMethod(sh.Struct, constructor, sh.StructMethods[0])) + } + + if sh.Features.IsEnabled(AlphabeticalCheck) && + i < len(sh.Constructors)-1 && sh.Constructors[i].Name.Name > sh.Constructors[i+1].Name.Name { + reports = append(reports, + NewAdjacentConstructorsNotSortedAlphabetically(sh.Struct, sh.Constructors[i], sh.Constructors[i+1]), + ) + } + } + + return reports +} + +func (sh *StructHolder) analyzeStructMethod() []analysis.Diagnostic { + var lastExportedMethod *ast.FuncDecl + + for _, m := range sh.StructMethods { + if !m.Name.IsExported() { + continue + } + + if lastExportedMethod == nil { + lastExportedMethod = m + } + + if lastExportedMethod.Pos() < m.Pos() { + lastExportedMethod = m + } + } + + var reports []analysis.Diagnostic + + if lastExportedMethod != nil { + for _, m := range sh.StructMethods { + if m.Name.IsExported() || m.Pos() >= lastExportedMethod.Pos() { + continue + } + + reports = append(reports, NewUnexportedMethodBeforeExportedForStruct(sh.Struct, m, lastExportedMethod)) + } + } + + if sh.Features.IsEnabled(AlphabeticalCheck) { + exported, unexported := SplitExportedUnexported(sh.StructMethods) + reports = slices.Concat(reports, + sortDiagnostics(sh.Struct, exported), + sortDiagnostics(sh.Struct, unexported), + ) + } + + return reports +} + +func sortDiagnostics(typeSpec *ast.TypeSpec, funcDecls []*ast.FuncDecl) []analysis.Diagnostic { + var reports []analysis.Diagnostic + + for i := range funcDecls { + if i >= len(funcDecls)-1 { + continue + } + + if funcDecls[i].Name.Name > funcDecls[i+1].Name.Name { + reports = append(reports, + NewAdjacentStructMethodsNotSortedAlphabetically(typeSpec, funcDecls[i], funcDecls[i+1])) + } + } + + return reports +} diff --git a/vendor/github.com/maratori/testableexamples/pkg/testableexamples/testableexamples.go b/vendor/github.com/maratori/testableexamples/pkg/testableexamples/testableexamples.go index 26d22c703..91a8509d2 100644 --- a/vendor/github.com/maratori/testableexamples/pkg/testableexamples/testableexamples.go +++ b/vendor/github.com/maratori/testableexamples/pkg/testableexamples/testableexamples.go @@ -13,7 +13,7 @@ func NewAnalyzer() *analysis.Analyzer { return &analysis.Analyzer{ Name: "testableexamples", Doc: "linter checks if examples are testable (have an expected output)", - Run: func(pass *analysis.Pass) (interface{}, error) { + Run: func(pass *analysis.Pass) (any, error) { testFiles := make([]*ast.File, 0, len(pass.Files)) for _, file := range pass.Files { fileName := pass.Fset.File(file.Pos()).Name() diff --git a/vendor/github.com/maratori/testpackage/pkg/testpackage/testpackage.go b/vendor/github.com/maratori/testpackage/pkg/testpackage/testpackage.go index 2e0572972..6eebabc2d 100644 --- a/vendor/github.com/maratori/testpackage/pkg/testpackage/testpackage.go +++ b/vendor/github.com/maratori/testpackage/pkg/testpackage/testpackage.go @@ -2,11 +2,11 @@ package testpackage import ( "flag" + "go/ast" "regexp" + "slices" "strings" - "go/ast" - "golang.org/x/tools/go/analysis" ) @@ -25,10 +25,8 @@ const ( func processTestFile(pass *analysis.Pass, f *ast.File, allowedPackages []string) { packageName := f.Name.Name - for _, p := range allowedPackages { - if p == packageName { - return - } + if slices.Contains(allowedPackages, packageName) { + return } if !strings.HasSuffix(packageName, "_test") { @@ -51,7 +49,7 @@ func NewAnalyzer() *analysis.Analyzer { Name: "testpackage", Doc: "linter that makes you use a separate _test package", Flags: fs, - Run: func(pass *analysis.Pass) (interface{}, error) { + Run: func(pass *analysis.Pass) (any, error) { allowedPackages := strings.Split(allowPackagesStr, ",") skipFile, err := regexp.Compile(skipFileRegexp) if err != nil { diff --git a/vendor/github.com/matoous/godox/.golangci.yml b/vendor/github.com/matoous/godox/.golangci.yml index 3f0fcdb19..8d080b28a 100644 --- a/vendor/github.com/matoous/godox/.golangci.yml +++ b/vendor/github.com/matoous/godox/.golangci.yml @@ -1,10 +1,4 @@ linters-settings: - depguard: - list-type: blacklist - include-go-root: true - packages: - # we are using "github.com/json-iterator/go" instead of json encoder from stdlib - - "encoding/json" dupl: threshold: 100 gocritic: @@ -19,10 +13,9 @@ linters-settings: - unnamedResult # it is experimental currently and doesn't handle typed channels correctly gocyclo: min-complexity: 14 # TODO go lower - golint: - min-confidence: 0 govet: - check-shadowing: true + enable: + - shadow goconst: min-len: 2 min-occurrences: 3 @@ -30,39 +23,47 @@ linters-settings: local-prefixes: gitlab.skypicker.com/search-team/gonuts/conveyance-store lll: line-length: 140 - maligned: - suggest-new: true misspell: locale: US linters: enable-all: true disable: + - depguard # prealloc is not recommended by `golangci-lint` developers. - prealloc - gochecknoglobals + # deprecated + - maligned + - exhaustivestruct + - nosnakecase + - scopelint + - structcheck + - ifshort + - varcheck + - deadcode + - golint + - interfacer + issues: + exclude-dirs: + - "fixtures" exclude-rules: - path: _test\.go linters: + - exhaustruct - goconst - dupl - - path: fixtures - linters: - - gocritic - - varcheck - - deadcode - - unused - run: modules-download-mode: readonly # output configuration options output: # colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number" - format: tab + formats: + - format: tab # print lines of code with issue, default is true print-issued-lines: true diff --git a/vendor/github.com/matoous/godox/.revive.toml b/vendor/github.com/matoous/godox/.revive.toml index db0e4edb6..a4a30464d 100644 --- a/vendor/github.com/matoous/godox/.revive.toml +++ b/vendor/github.com/matoous/godox/.revive.toml @@ -1,5 +1,6 @@ ignoreGeneratedHeader = false severity = "warning" +exclude = ["./fixtures/..."] # confidence <= 0.2 generate a lot of errors from package-comments rule. It marks files that do not contain # package-level comments as a warning irrespective of existing package-level coment in one file. diff --git a/vendor/github.com/matoous/godox/Makefile b/vendor/github.com/matoous/godox/Makefile new file mode 100644 index 000000000..694aa21d6 --- /dev/null +++ b/vendor/github.com/matoous/godox/Makefile @@ -0,0 +1,20 @@ +## Help display. +## Pulls comments from beside commands and prints a nicely formatted +## display with the commands and their usage information. + +.DEFAULT_GOAL := help + +help: ## Prints this help + @grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +.PHONY: lint +lint: ## Lint the application + golangci-lint run --max-same-issues=0 --timeout=1m ./... + +.PHONY: test +test: ## Run unit tests + go test -race -shuffle=on ./... + +.PHONY: vet +vet: ## Run go vet + go vet ./... diff --git a/vendor/github.com/matoous/godox/godox.go b/vendor/github.com/matoous/godox/godox.go index 3903525c8..5bcc7e980 100644 --- a/vendor/github.com/matoous/godox/godox.go +++ b/vendor/github.com/matoous/godox/godox.go @@ -1,3 +1,5 @@ +// Package godox is a linter that scans Go code for comments containing certain keywords +// (like TODO, BUG, FIXME) which typically indicate areas that require attention. package godox import ( @@ -20,22 +22,17 @@ type Message struct { Message string } -func getMessages(comment *ast.Comment, fset *token.FileSet, keywords []string) []Message { +func getMessages(comment *ast.Comment, fset *token.FileSet, keywords []string) ([]Message, error) { commentText := extractComment(comment.Text) - b := bufio.NewReader(bytes.NewBufferString(commentText)) + scanner := bufio.NewScanner(bytes.NewBufferString(commentText)) var comments []Message - for lineNum := 0; ; lineNum++ { - line, _, err := b.ReadLine() - if err != nil { - break - } - + for lineNum := 0; scanner.Scan(); lineNum++ { const minimumSize = 4 - sComment := bytes.TrimSpace(line) + sComment := bytes.TrimSpace(scanner.Bytes()) if len(sComment) < minimumSize { continue } @@ -68,21 +65,22 @@ func getMessages(comment *ast.Comment, fset *token.FileSet, keywords []string) [ } } - return comments + if err := scanner.Err(); err != nil { + return nil, fmt.Errorf("scan: %w", err) + } + + return comments, nil } func extractComment(commentText string) string { switch commentText[1] { case '/': - commentText = commentText[2:] - if len(commentText) > 0 && commentText[0] == ' ' { - commentText = commentText[1:] - } + return strings.TrimPrefix(commentText[2:], " ") case '*': - commentText = commentText[2 : len(commentText)-2] + return commentText[2 : len(commentText)-2] + default: + return commentText } - - return commentText } func hasAlphanumRuneAdjacent(rest []byte) bool { @@ -102,7 +100,7 @@ func hasAlphanumRuneAdjacent(rest []byte) bool { // Run runs the godox linter on given file. // Godox searches for comments starting with given keywords and reports them. -func Run(file *ast.File, fset *token.FileSet, keywords ...string) []Message { +func Run(file *ast.File, fset *token.FileSet, keywords ...string) ([]Message, error) { if len(keywords) == 0 { keywords = defaultKeywords } @@ -111,9 +109,14 @@ func Run(file *ast.File, fset *token.FileSet, keywords ...string) []Message { for _, c := range file.Comments { for _, ci := range c.List { - messages = append(messages, getMessages(ci, fset, keywords)...) + msgs, err := getMessages(ci, fset, keywords) + if err != nil { + return nil, err + } + + messages = append(messages, msgs...) } } - return messages + return messages, nil } diff --git a/vendor/github.com/mattn/go-colorable/colorable_appengine.go b/vendor/github.com/mattn/go-colorable/colorable_appengine.go deleted file mode 100644 index 416d1bbbf..000000000 --- a/vendor/github.com/mattn/go-colorable/colorable_appengine.go +++ /dev/null @@ -1,38 +0,0 @@ -//go:build appengine -// +build appengine - -package colorable - -import ( - "io" - "os" - - _ "github.com/mattn/go-isatty" -) - -// NewColorable returns new instance of Writer which handles escape sequence. -func NewColorable(file *os.File) io.Writer { - if file == nil { - panic("nil passed instead of *os.File to NewColorable()") - } - - return file -} - -// NewColorableStdout returns new instance of Writer which handles escape sequence for stdout. -func NewColorableStdout() io.Writer { - return os.Stdout -} - -// NewColorableStderr returns new instance of Writer which handles escape sequence for stderr. -func NewColorableStderr() io.Writer { - return os.Stderr -} - -// EnableColorsStdout enable colors if possible. -func EnableColorsStdout(enabled *bool) func() { - if enabled != nil { - *enabled = true - } - return func() {} -} diff --git a/vendor/github.com/mattn/go-colorable/colorable_others.go b/vendor/github.com/mattn/go-colorable/colorable_others.go index 766d94603..c1a78aa94 100644 --- a/vendor/github.com/mattn/go-colorable/colorable_others.go +++ b/vendor/github.com/mattn/go-colorable/colorable_others.go @@ -1,5 +1,5 @@ -//go:build !windows && !appengine -// +build !windows,!appengine +//go:build !windows || appengine +// +build !windows appengine package colorable diff --git a/vendor/github.com/mattn/go-colorable/colorable_windows.go b/vendor/github.com/mattn/go-colorable/colorable_windows.go index 1846ad5ab..2df7b8598 100644 --- a/vendor/github.com/mattn/go-colorable/colorable_windows.go +++ b/vendor/github.com/mattn/go-colorable/colorable_windows.go @@ -11,7 +11,7 @@ import ( "strconv" "strings" "sync" - "syscall" + syscall "golang.org/x/sys/windows" "unsafe" "github.com/mattn/go-isatty" @@ -73,7 +73,7 @@ type consoleCursorInfo struct { } var ( - kernel32 = syscall.NewLazyDLL("kernel32.dll") + kernel32 = syscall.NewLazySystemDLL("kernel32.dll") procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute") procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition") @@ -87,8 +87,8 @@ var ( procCreateConsoleScreenBuffer = kernel32.NewProc("CreateConsoleScreenBuffer") ) -// Writer provides colorable Writer to the console -type Writer struct { +// writer provides colorable Writer to the console +type writer struct { out io.Writer handle syscall.Handle althandle syscall.Handle @@ -98,7 +98,7 @@ type Writer struct { mutex sync.Mutex } -// NewColorable returns new instance of Writer which handles escape sequence from File. +// NewColorable returns new instance of writer which handles escape sequence from File. func NewColorable(file *os.File) io.Writer { if file == nil { panic("nil passed instead of *os.File to NewColorable()") @@ -112,17 +112,17 @@ func NewColorable(file *os.File) io.Writer { var csbi consoleScreenBufferInfo handle := syscall.Handle(file.Fd()) procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) - return &Writer{out: file, handle: handle, oldattr: csbi.attributes, oldpos: coord{0, 0}} + return &writer{out: file, handle: handle, oldattr: csbi.attributes, oldpos: coord{0, 0}} } return file } -// NewColorableStdout returns new instance of Writer which handles escape sequence for stdout. +// NewColorableStdout returns new instance of writer which handles escape sequence for stdout. func NewColorableStdout() io.Writer { return NewColorable(os.Stdout) } -// NewColorableStderr returns new instance of Writer which handles escape sequence for stderr. +// NewColorableStderr returns new instance of writer which handles escape sequence for stderr. func NewColorableStderr() io.Writer { return NewColorable(os.Stderr) } @@ -434,7 +434,7 @@ func atoiWithDefault(s string, def int) (int, error) { } // Write writes data on console -func (w *Writer) Write(data []byte) (n int, err error) { +func (w *writer) Write(data []byte) (n int, err error) { w.mutex.Lock() defer w.mutex.Unlock() var csbi consoleScreenBufferInfo @@ -560,7 +560,7 @@ loop: } procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'E': - n, err = strconv.Atoi(buf.String()) + n, err = atoiWithDefault(buf.String(), 1) if err != nil { continue } @@ -569,7 +569,7 @@ loop: csbi.cursorPosition.y += short(n) procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'F': - n, err = strconv.Atoi(buf.String()) + n, err = atoiWithDefault(buf.String(), 1) if err != nil { continue } diff --git a/vendor/github.com/mgechev/revive/config/config.go b/vendor/github.com/mgechev/revive/config/config.go index 16559f5ec..d01f409c5 100644 --- a/vendor/github.com/mgechev/revive/config/config.go +++ b/vendor/github.com/mgechev/revive/config/config.go @@ -1,4 +1,4 @@ -// Package config implements revive's configuration data structures and related methods +// Package config implements revive's configuration data structures and related methods. package config import ( @@ -83,6 +83,7 @@ var allRules = append([]lint.Rule{ &rule.UselessBreak{}, &rule.UncheckedTypeAssertionRule{}, &rule.TimeEqualRule{}, + &rule.TimeDateRule{}, &rule.BannedCharsRule{}, &rule.OptimizeOperandsOrderRule{}, &rule.UseAnyRule{}, @@ -98,18 +99,40 @@ var allRules = append([]lint.Rule{ &rule.CommentsDensityRule{}, &rule.FileLengthLimitRule{}, &rule.FilenameFormatRule{}, + &rule.RedundantBuildTagRule{}, + &rule.UseErrorsNewRule{}, + &rule.RedundantTestMainExitRule{}, + &rule.UnnecessaryFormatRule{}, + &rule.UseFmtPrintRule{}, + &rule.EnforceSwitchStyleRule{}, + &rule.IdenticalSwitchConditionsRule{}, + &rule.IdenticalIfElseIfConditionsRule{}, + &rule.IdenticalIfElseIfBranchesRule{}, + &rule.IdenticalSwitchBranchesRule{}, + &rule.UselessFallthroughRule{}, + &rule.PackageDirectoryMismatchRule{}, + &rule.UseWaitGroupGoRule{}, + &rule.UnsecureURLSchemeRule{}, + &rule.InefficientMapLookupRule{}, + &rule.ForbiddenCallInWgGoRule{}, + &rule.UnnecessaryIfRule{}, + &rule.EpochNamingRule{}, + &rule.UseSlicesSort{}, + &rule.PackageNamingRule{}, }, defaultRules...) +// allFormatters is a list of all available formatters to output the linting results. +// Keep the list sorted and in sync with available formatters in README.md. var allFormatters = []lint.Formatter{ - &formatter.Stylish{}, + &formatter.Checkstyle{}, + &formatter.Default{}, &formatter.Friendly{}, &formatter.JSON{}, &formatter.NDJSON{}, - &formatter.Default{}, - &formatter.Unix{}, - &formatter.Checkstyle{}, &formatter.Plain{}, &formatter.Sarif{}, + &formatter.Stylish{}, + &formatter.Unix{}, } func getFormatters() map[string]lint.Formatter { @@ -120,7 +143,7 @@ func getFormatters() map[string]lint.Formatter { return result } -// GetLintingRules yields the linting rules that must be applied by the linter +// GetLintingRules yields the linting rules that must be applied by the linter. func GetLintingRules(config *lint.Config, extraRules []lint.Rule) ([]lint.Rule, error) { rulesMap := map[string]lint.Rule{} for _, r := range allRules { @@ -145,6 +168,12 @@ func GetLintingRules(config *lint.Config, extraRules []lint.Rule) ([]lint.Rule, continue // skip disabled rules } + if r, ok := r.(lint.ConfigurableRule); ok { + if err := r.Configure(ruleConfig.Arguments); err != nil { + return nil, fmt.Errorf("cannot configure rule: %q: %w", name, err) + } + } + lintingRules = append(lintingRules, r) } @@ -160,19 +189,15 @@ func actualRuleName(name string) string { } } -func parseConfig(path string, config *lint.Config) error { - file, err := os.ReadFile(path) +func parseConfig(data []byte, config *lint.Config) error { + err := toml.Unmarshal(data, config) if err != nil { - return errors.New("cannot read the config file") - } - _, err = toml.Decode(string(file), config) - if err != nil { - return fmt.Errorf("cannot parse the config file: %v", err) + return fmt.Errorf("cannot parse the config file: %w", err) } for k, r := range config.Rules { err := r.Initialize() if err != nil { - return fmt.Errorf("error in config of rule [%s] : [%v]", k, err) + return fmt.Errorf("error in config of rule [%s] : [%w]", k, err) } config.Rules[k] = r } @@ -180,23 +205,33 @@ func parseConfig(path string, config *lint.Config) error { return nil } +func validateConfig(config *lint.Config) error { + if config.EnableAllRules && config.EnableDefaultRules { + return errors.New("config options enableAllRules and enableDefaultRules cannot be combined") + } + return nil +} + func normalizeConfig(config *lint.Config) { if len(config.Rules) == 0 { config.Rules = map[string]lint.RuleConfig{} } - if config.EnableAllRules { - // Add to the configuration all rules not yet present in it - for _, r := range allRules { + + addRules := func(config *lint.Config, rules []lint.Rule) { + for _, r := range rules { ruleName := r.Name() - _, alreadyInConf := config.Rules[ruleName] - if alreadyInConf { - continue + if _, ok := config.Rules[ruleName]; !ok { + config.Rules[ruleName] = lint.RuleConfig{} } - // Add the rule with an empty conf for - config.Rules[ruleName] = lint.RuleConfig{} } } + if config.EnableAllRules { + addRules(config, allRules) + } else if config.EnableDefaultRules { + addRules(config, defaultRules) + } + severity := config.Severity if severity != "" { for k, v := range config.Rules { @@ -216,13 +251,17 @@ func normalizeConfig(config *lint.Config) { const defaultConfidence = 0.8 -// GetConfig yields the configuration +// GetConfig yields the configuration. func GetConfig(configPath string) (*lint.Config, error) { config := &lint.Config{} switch { case configPath != "": config.Confidence = defaultConfidence - err := parseConfig(configPath, config) + data, err := os.ReadFile(configPath) //nolint:gosec // ignore G304: potential file inclusion via variable + if err != nil { + return nil, errors.New("cannot read the config file") + } + err = parseConfig(data, config) if err != nil { return nil, err } @@ -231,22 +270,25 @@ func GetConfig(configPath string) (*lint.Config, error) { config = defaultConfig() } + if err := validateConfig(config); err != nil { + return nil, err + } + normalizeConfig(config) return config, nil } -// GetFormatter yields the formatter for lint failures +// GetFormatter yields the formatter for lint failures. func GetFormatter(formatterName string) (lint.Formatter, error) { formatters := getFormatters() - fmtr := formatters["default"] - if formatterName != "" { - f, ok := formatters[formatterName] - if !ok { - return nil, fmt.Errorf("unknown formatter %v", formatterName) - } - fmtr = f + if formatterName == "" { + return formatters["default"], nil + } + f, ok := formatters[formatterName] + if !ok { + return nil, fmt.Errorf("unknown formatter %v", formatterName) } - return fmtr, nil + return f, nil } func defaultConfig() *lint.Config { diff --git a/vendor/github.com/mgechev/revive/formatter/checkstyle.go b/vendor/github.com/mgechev/revive/formatter/checkstyle.go index f45b63c92..1df1f5573 100644 --- a/vendor/github.com/mgechev/revive/formatter/checkstyle.go +++ b/vendor/github.com/mgechev/revive/formatter/checkstyle.go @@ -8,13 +8,13 @@ import ( "github.com/mgechev/revive/lint" ) -// Checkstyle is an implementation of the Formatter interface +// Checkstyle is an implementation of the [lint.Formatter] interface // which formats the errors to Checkstyle-like format. type Checkstyle struct { Metadata lint.FormatterMetadata } -// Name returns the name of the formatter +// Name returns the name of the formatter. func (*Checkstyle) Name() string { return "checkstyle" } @@ -43,9 +43,9 @@ func (*Checkstyle) Format(failures <-chan lint.Failure, config lint.Config) (str Severity: severity(config, failure), RuleName: failure.RuleName, } - fn := failure.GetFilename() + fn := failure.Filename() if issues[fn] == nil { - issues[fn] = make([]issue, 0) + issues[fn] = []issue{} } issues[fn] = append(issues[fn], iss) } diff --git a/vendor/github.com/mgechev/revive/formatter/default.go b/vendor/github.com/mgechev/revive/formatter/default.go index 2d5a04434..b6a6af223 100644 --- a/vendor/github.com/mgechev/revive/formatter/default.go +++ b/vendor/github.com/mgechev/revive/formatter/default.go @@ -7,13 +7,13 @@ import ( "github.com/mgechev/revive/lint" ) -// Default is an implementation of the Formatter interface +// Default is an implementation of the [lint.Formatter] interface // which formats the errors to text. type Default struct { Metadata lint.FormatterMetadata } -// Name returns the name of the formatter +// Name returns the name of the formatter. func (*Default) Name() string { return "default" } @@ -21,8 +21,17 @@ func (*Default) Name() string { // Format formats the failures gotten from the lint. func (*Default) Format(failures <-chan lint.Failure, _ lint.Config) (string, error) { var buf bytes.Buffer + prefix := "" for failure := range failures { - fmt.Fprintf(&buf, "%v: %s\n", failure.Position.Start, failure.Failure) + _, err := fmt.Fprintf(&buf, "%s%v: %s", prefix, failure.Position.Start, failure.Failure) + if err != nil { + return "", err + } + prefix = "\n" } return buf.String(), nil } + +func ruleDescriptionURL(ruleName string) string { + return "https://revive.run/r#" + ruleName +} diff --git a/vendor/github.com/mgechev/revive/formatter/friendly.go b/vendor/github.com/mgechev/revive/formatter/friendly.go index 5ff329a23..cb1afcb3d 100644 --- a/vendor/github.com/mgechev/revive/formatter/friendly.go +++ b/vendor/github.com/mgechev/revive/formatter/friendly.go @@ -2,76 +2,89 @@ package formatter import ( "bytes" + "cmp" "fmt" "io" - "sort" + "slices" + "strings" + "text/tabwriter" "github.com/fatih/color" + "github.com/mgechev/revive/lint" - "github.com/olekukonko/tablewriter" ) -func getErrorEmoji() string { - return color.RedString("✘") -} - -func getWarningEmoji() string { - return color.YellowString("⚠") -} - -// Friendly is an implementation of the Formatter interface -// which formats the errors to JSON. +// Friendly is an implementation of the [lint.Formatter] interface +// which formats the errors to a friendly, human-readable format. type Friendly struct { Metadata lint.FormatterMetadata } -// Name returns the name of the formatter +// Name returns the name of the formatter. func (*Friendly) Name() string { return "friendly" } // Format formats the failures gotten from the lint. func (f *Friendly) Format(failures <-chan lint.Failure, config lint.Config) (string, error) { - var buf bytes.Buffer + var buf strings.Builder errorMap := map[string]int{} warningMap := map[string]int{} totalErrors := 0 totalWarnings := 0 + warningEmoji := color.YellowString("⚠") + errorEmoji := color.RedString("✘") for failure := range failures { sev := severity(config, failure) - f.printFriendlyFailure(&buf, failure, sev) - if sev == lint.SeverityWarning { + firstCol := warningEmoji + if sev == lint.SeverityError { + firstCol = errorEmoji + } + if err := f.printFriendlyFailure(&buf, firstCol, failure); err != nil { + return "", err + } + switch sev { + case lint.SeverityWarning: warningMap[failure.RuleName]++ totalWarnings++ - } - if sev == lint.SeverityError { + case lint.SeverityError: errorMap[failure.RuleName]++ totalErrors++ } } - f.printSummary(&buf, totalErrors, totalWarnings) - f.printStatistics(&buf, color.RedString("Errors:"), errorMap) - f.printStatistics(&buf, color.YellowString("Warnings:"), warningMap) + + emoji := warningEmoji + if totalErrors > 0 { + emoji = errorEmoji + } + if err := f.printSummary(&buf, emoji, totalErrors, totalWarnings); err != nil { + return "", err + } + if err := f.printStatistics(&buf, color.RedString("Errors:"), errorMap); err != nil { + return "", err + } + if err := f.printStatistics(&buf, color.YellowString("Warnings:"), warningMap); err != nil { + return "", err + } return buf.String(), nil } -func (f *Friendly) printFriendlyFailure(w io.Writer, failure lint.Failure, severity lint.Severity) { - f.printHeaderRow(w, failure, severity) - f.printFilePosition(w, failure) - fmt.Fprintln(w) - fmt.Fprintln(w) +func (f *Friendly) printFriendlyFailure(sb *strings.Builder, firstColumn string, failure lint.Failure) error { + f.printHeaderRow(sb, firstColumn, failure) + if err := f.printFilePosition(sb, failure); err != nil { + return err + } + _, err := sb.WriteString("\n\n") + return err } -func (f *Friendly) printHeaderRow(w io.Writer, failure lint.Failure, severity lint.Severity) { - emoji := getWarningEmoji() - if severity == lint.SeverityError { - emoji = getErrorEmoji() - } - fmt.Fprint(w, f.table([][]string{{emoji, "https://revive.run/r#" + failure.RuleName, color.GreenString(failure.Failure)}})) +func (*Friendly) printHeaderRow(sb *strings.Builder, firstColumn string, failure lint.Failure) { + sb.WriteString(table([][]string{{firstColumn, ruleDescriptionURL(failure.RuleName), color.GreenString(failure.Failure)}})) } -func (*Friendly) printFilePosition(w io.Writer, failure lint.Failure) { - fmt.Fprintf(w, " %s:%d:%d", failure.GetFilename(), failure.Position.Start.Line, failure.Position.Start.Column) +func (*Friendly) printFilePosition(sb *strings.Builder, failure lint.Failure) error { + _, err := fmt.Fprintf(sb, " %s:%d:%d", failure.Filename(), failure.Position.Start.Line, failure.Position.Start.Column) + return err } type statEntry struct { @@ -79,11 +92,7 @@ type statEntry struct { failures int } -func (*Friendly) printSummary(w io.Writer, errors, warnings int) { - emoji := getWarningEmoji() - if errors > 0 { - emoji = getErrorEmoji() - } +func (*Friendly) printSummary(w io.Writer, firstColumn string, errors, warnings int) error { problemsLabel := "problems" if errors+warnings == 1 { problemsLabel = "problem" @@ -98,44 +107,53 @@ func (*Friendly) printSummary(w io.Writer, errors, warnings int) { } str := fmt.Sprintf("%d %s (%d %s, %d %s)", errors+warnings, problemsLabel, errors, errorsLabel, warnings, warningsLabel) if errors > 0 { - fmt.Fprintf(w, "%s %s\n", emoji, color.RedString(str)) - fmt.Fprintln(w) - return + _, err := fmt.Fprintf(w, "%s %s\n\n", firstColumn, color.RedString(str)) + return err } if warnings > 0 { - fmt.Fprintf(w, "%s %s\n", emoji, color.YellowString(str)) - fmt.Fprintln(w) - return + _, err := fmt.Fprintf(w, "%s %s\n\n", firstColumn, color.YellowString(str)) + return err } + return nil } -func (f *Friendly) printStatistics(w io.Writer, header string, stats map[string]int) { +func (*Friendly) printStatistics(w io.Writer, header string, stats map[string]int) error { if len(stats) == 0 { - return + return nil } - var data []statEntry + data := make([]statEntry, 0, len(stats)) for name, total := range stats { data = append(data, statEntry{name, total}) } - sort.Slice(data, func(i, j int) bool { - return data[i].failures > data[j].failures + slices.SortFunc(data, func(a, b statEntry) int { + return -cmp.Compare(a.failures, b.failures) }) formatted := [][]string{} for _, entry := range data { formatted = append(formatted, []string{color.GreenString(fmt.Sprintf("%d", entry.failures)), entry.name}) } - fmt.Fprintln(w, header) - fmt.Fprintln(w, f.table(formatted)) + if _, err := fmt.Fprintln(w, header); err != nil { + return err + } + if _, err := fmt.Fprintln(w, table(formatted)); err != nil { + return err + } + return nil } -func (*Friendly) table(rows [][]string) string { - buf := new(bytes.Buffer) - table := tablewriter.NewWriter(buf) - table.SetBorder(false) - table.SetColumnSeparator("") - table.SetRowSeparator("") - table.SetAutoWrapText(false) - table.AppendBulk(rows) - table.Render() +func table(rows [][]string) string { + var buf bytes.Buffer + tw := tabwriter.NewWriter(&buf, 0, 0, 2, ' ', 0) + for _, row := range rows { + _, _ = tw.Write([]byte{'\t'}) + for i, col := range row { + _, _ = tw.Write([]byte(col)) + if i < len(row)-1 { + _, _ = tw.Write([]byte{'\t'}) + } + } + _, _ = tw.Write([]byte{'\n'}) + } + _ = tw.Flush() return buf.String() } diff --git a/vendor/github.com/mgechev/revive/formatter/json.go b/vendor/github.com/mgechev/revive/formatter/json.go index 7cace89ec..46a61980c 100644 --- a/vendor/github.com/mgechev/revive/formatter/json.go +++ b/vendor/github.com/mgechev/revive/formatter/json.go @@ -6,20 +6,21 @@ import ( "github.com/mgechev/revive/lint" ) -// JSON is an implementation of the Formatter interface +// JSON is an implementation of the [lint.Formatter] interface // which formats the errors to JSON. type JSON struct { Metadata lint.FormatterMetadata } -// Name returns the name of the formatter +// Name returns the name of the formatter. func (*JSON) Name() string { return "json" } -// jsonObject defines a JSON object of an failure +// jsonObject defines a JSON object of an failure. type jsonObject struct { - Severity lint.Severity + Severity lint.Severity `json:"Severity"` + //nolint:embeddedstructfieldcheck // backward compatibility lint.Failure `json:",inline"` } diff --git a/vendor/github.com/mgechev/revive/formatter/ndjson.go b/vendor/github.com/mgechev/revive/formatter/ndjson.go index 58b35dc44..f80b5bcbc 100644 --- a/vendor/github.com/mgechev/revive/formatter/ndjson.go +++ b/vendor/github.com/mgechev/revive/formatter/ndjson.go @@ -7,13 +7,13 @@ import ( "github.com/mgechev/revive/lint" ) -// NDJSON is an implementation of the Formatter interface +// NDJSON is an implementation of the [lint.Formatter] interface // which formats the errors to NDJSON stream. type NDJSON struct { Metadata lint.FormatterMetadata } -// Name returns the name of the formatter +// Name returns the name of the formatter. func (*NDJSON) Name() string { return "ndjson" } diff --git a/vendor/github.com/mgechev/revive/formatter/plain.go b/vendor/github.com/mgechev/revive/formatter/plain.go index 09ebf6cdc..80dede3a1 100644 --- a/vendor/github.com/mgechev/revive/formatter/plain.go +++ b/vendor/github.com/mgechev/revive/formatter/plain.go @@ -1,28 +1,31 @@ package formatter import ( - "bytes" "fmt" + "strings" "github.com/mgechev/revive/lint" ) -// Plain is an implementation of the Formatter interface -// which formats the errors to JSON. +// Plain is an implementation of the [lint.Formatter] interface +// which formats the errors to plain text. type Plain struct { Metadata lint.FormatterMetadata } -// Name returns the name of the formatter +// Name returns the name of the formatter. func (*Plain) Name() string { return "plain" } // Format formats the failures gotten from the lint. func (*Plain) Format(failures <-chan lint.Failure, _ lint.Config) (string, error) { - var buf bytes.Buffer + var sb strings.Builder for failure := range failures { - fmt.Fprintf(&buf, "%v: %s %s\n", failure.Position.Start, failure.Failure, "https://revive.run/r#"+failure.RuleName) + _, err := fmt.Fprintf(&sb, "%v: %s %s\n", failure.Position.Start, failure.Failure, ruleDescriptionURL(failure.RuleName)) + if err != nil { + return "", err + } } - return buf.String(), nil + return sb.String(), nil } diff --git a/vendor/github.com/mgechev/revive/formatter/sarif.go b/vendor/github.com/mgechev/revive/formatter/sarif.go index c42da73eb..cb1a97294 100644 --- a/vendor/github.com/mgechev/revive/formatter/sarif.go +++ b/vendor/github.com/mgechev/revive/formatter/sarif.go @@ -5,17 +5,18 @@ import ( "fmt" "strings" - "github.com/chavacava/garif" + "codeberg.org/chavacava/garif" + "github.com/mgechev/revive/lint" ) -// Sarif is an implementation of the Formatter interface +// Sarif is an implementation of the [lint.Formatter] interface // which formats revive failures into SARIF format. type Sarif struct { Metadata lint.FormatterMetadata } -// Name returns the name of the formatter +// Name returns the name of the formatter. func (*Sarif) Name() string { return "sarif" } @@ -27,17 +28,21 @@ func (*Sarif) Format(failures <-chan lint.Failure, cfg lint.Config) (string, err sarifLog := newReviveRunLog(cfg) for failure := range failures { - sarifLog.AddResult(failure) + sarifLog.addResult(failure) } buf := new(bytes.Buffer) - sarifLog.PrettyWrite(buf) + err := sarifLog.PrettyWrite(buf) + if err != nil { + return "", err + } return buf.String(), nil } type reviveRunLog struct { *garif.LogFile + run *garif.Run rules map[string]lint.RuleConfig } @@ -72,7 +77,7 @@ func (l *reviveRunLog) addRules(cfg map[string]lint.RuleConfig) { } } -func (l *reviveRunLog) AddResult(failure lint.Failure) { +func (l *reviveRunLog) addResult(failure lint.Failure) { positiveOrZero := func(x int) int { if x > 0 { return x diff --git a/vendor/github.com/mgechev/revive/formatter/stylish.go b/vendor/github.com/mgechev/revive/formatter/stylish.go index 828228c72..100a7927b 100644 --- a/vendor/github.com/mgechev/revive/formatter/stylish.go +++ b/vendor/github.com/mgechev/revive/formatter/stylish.go @@ -1,34 +1,37 @@ package formatter import ( - "bytes" "fmt" + "slices" "github.com/fatih/color" + "github.com/mgechev/revive/lint" - "github.com/olekukonko/tablewriter" ) -// Stylish is an implementation of the Formatter interface -// which formats the errors to JSON. +// Stylish is an implementation of the [lint.Formatter] interface +// which formats the errors to a stylish, human-readable format. type Stylish struct { Metadata lint.FormatterMetadata } -// Name returns the name of the formatter +var _ lint.Formatter = (*Stylish)(nil) + +// Name returns the name of the formatter. func (*Stylish) Name() string { return "stylish" } func formatFailure(failure lint.Failure, severity lint.Severity) []string { fString := color.CyanString(failure.Failure) - fName := color.RedString("https://revive.run/r#" + failure.RuleName) lineColumn := failure.Position pos := fmt.Sprintf("(%d, %d)", lineColumn.Start.Line, lineColumn.Start.Column) + fURL := ruleDescriptionURL(failure.RuleName) + fName := color.RedString(fURL) if severity == lint.SeverityWarning { - fName = color.YellowString("https://revive.run/r#" + failure.RuleName) + fName = color.YellowString(fURL) } - return []string{failure.GetFilename(), pos, fName, fString} + return []string{failure.Filename(), pos, fName, fString} } // Format formats the failures gotten from the lint. @@ -43,45 +46,50 @@ func (*Stylish) Format(failures <-chan lint.Failure, config lint.Config) (string if currentType == lint.SeverityError { totalErrors++ } - result = append(result, formatFailure(f, lint.Severity(currentType))) - } - ps := "problems" - if total == 1 { - ps = "problem" + result = append(result, formatFailure(f, currentType)) } - fileReport := make(map[string][][]string) + fileReport := map[string][][]string{} + var files []string for _, row := range result { if _, ok := fileReport[row[0]]; !ok { fileReport[row[0]] = [][]string{} + files = append(files, row[0]) } fileReport[row[0]] = append(fileReport[row[0]], []string{row[1], row[2], row[3]}) } + slices.Sort(files) output := "" - for filename, val := range fileReport { - buf := new(bytes.Buffer) - table := tablewriter.NewWriter(buf) - table.SetBorder(false) - table.SetColumnSeparator("") - table.SetRowSeparator("") - table.SetAutoWrapText(false) - table.AppendBulk(val) - table.Render() + for _, filename := range files { c := color.New(color.Underline) output += c.SprintfFunc()(filename + "\n") - output += buf.String() + "\n" + output += table(fileReport[filename]) + "\n" } - suffix := fmt.Sprintf(" %d %s (%d errors) (%d warnings)", total, ps, totalErrors, total-totalErrors) + problemsLabel := "problems" + if total == 1 { + problemsLabel = "problem" + } + totalWarnings := total - totalErrors + warningsLabel := "warnings" + if totalWarnings == 1 { + warningsLabel = "warning" + } + errorsLabel := "errors" + if totalErrors == 1 { + errorsLabel = "error" + } + suffix := fmt.Sprintf(" %d %s (%d %s) (%d %s)", total, problemsLabel, totalErrors, errorsLabel, totalWarnings, warningsLabel) - if total > 0 && totalErrors > 0 { + switch { + case total > 0 && totalErrors > 0: suffix = color.RedString("\n ✖" + suffix) - } else if total > 0 && totalErrors == 0 { + case total > 0 && totalErrors == 0: suffix = color.YellowString("\n ✖" + suffix) - } else { + default: suffix, output = "", "" } diff --git a/vendor/github.com/mgechev/revive/formatter/unix.go b/vendor/github.com/mgechev/revive/formatter/unix.go index e46f3c275..b79566859 100644 --- a/vendor/github.com/mgechev/revive/formatter/unix.go +++ b/vendor/github.com/mgechev/revive/formatter/unix.go @@ -1,30 +1,33 @@ package formatter import ( - "bytes" "fmt" + "strings" "github.com/mgechev/revive/lint" ) -// Unix is an implementation of the Formatter interface -// which formats the errors to a simple line based error format +// Unix is an implementation of the [lint.Formatter] interface +// which formats the errors to a simple line based error format: // // main.go:24:9: [errorf] should replace errors.New(fmt.Sprintf(...)) with fmt.Errorf(...) type Unix struct { Metadata lint.FormatterMetadata } -// Name returns the name of the formatter +// Name returns the name of the formatter. func (*Unix) Name() string { return "unix" } // Format formats the failures gotten from the lint. func (*Unix) Format(failures <-chan lint.Failure, _ lint.Config) (string, error) { - var buf bytes.Buffer + var sb strings.Builder for failure := range failures { - fmt.Fprintf(&buf, "%v: [%s] %s\n", failure.Position.Start, failure.RuleName, failure.Failure) + _, err := fmt.Fprintf(&sb, "%v: [%s] %s\n", failure.Position.Start, failure.RuleName, failure.Failure) + if err != nil { + return "", err + } } - return buf.String(), nil + return sb.String(), nil } diff --git a/vendor/github.com/mgechev/revive/internal/astutils/ast_utils.go b/vendor/github.com/mgechev/revive/internal/astutils/ast_utils.go new file mode 100644 index 000000000..b0fbc5a0d --- /dev/null +++ b/vendor/github.com/mgechev/revive/internal/astutils/ast_utils.go @@ -0,0 +1,221 @@ +// Package astutils provides utility functions for working with AST nodes. +package astutils + +import ( + "bytes" + "crypto/md5" //nolint:gosec // G501: Blocklisted import crypto/md5: weak cryptographic primitive + "encoding/hex" + "fmt" + "go/ast" + "go/printer" + "go/token" + "regexp" + "slices" +) + +// FuncSignatureIs returns true if the given func decl satisfies a signature characterized +// by the given name, parameters types and return types; false otherwise. +// +// Example: To check if a function declaration has the signature +// +// Foo(int, string) (bool, error) +// +// call to +// +// FuncSignatureIs(funcDecl, "Foo", []string{"int", "string"}, []string{"bool", "error"}) +func FuncSignatureIs(funcDecl *ast.FuncDecl, wantName string, wantParametersTypes, wantResultsTypes []string) bool { + if wantName != funcDecl.Name.String() { + return false // func name doesn't match expected one + } + + funcResultsTypes := GetTypeNames(funcDecl.Type.Results) + if !slices.Equal(wantResultsTypes, funcResultsTypes) { + return false // func has not the expected return values + } + + // Name and return values are those we expected, + // the final result depends on parameters being what we want. + return funcParametersSignatureIs(funcDecl, wantParametersTypes) +} + +// funcParametersSignatureIs returns true if the function has parameters of the given type and order, +// false otherwise. +func funcParametersSignatureIs(funcDecl *ast.FuncDecl, wantParametersTypes []string) bool { + funcParametersTypes := GetTypeNames(funcDecl.Type.Params) + + return slices.Equal(wantParametersTypes, funcParametersTypes) +} + +// GetTypeNames yields an slice with the string representation of the types of given fields. +// It yields nil if the field list is nil. +func GetTypeNames(fields *ast.FieldList) []string { + if fields == nil { + return nil + } + + result := []string{} + + for _, field := range fields.List { + typeName := getFieldTypeName(field.Type) + if field.Names == nil { // unnamed field + result = append(result, typeName) + continue + } + + for range field.Names { // add one type name for each field name + result = append(result, typeName) + } + } + + return result +} + +func getFieldTypeName(typ ast.Expr) string { + switch f := typ.(type) { + case *ast.Ident: + return f.Name + case *ast.SelectorExpr: + return getFieldTypeName(f.X) + "." + getFieldTypeName(f.Sel) + case *ast.StarExpr: + return "*" + getFieldTypeName(f.X) + case *ast.IndexExpr: + return getFieldTypeName(f.X) + "[" + getFieldTypeName(f.Index) + "]" + case *ast.ArrayType: + return "[]" + getFieldTypeName(f.Elt) + case *ast.InterfaceType: + return "interface{}" + default: + return "UNHANDLED_TYPE" + } +} + +// IsStringLiteral returns true if the given expression is a string literal, false otherwise. +func IsStringLiteral(e ast.Expr) bool { + sl, ok := e.(*ast.BasicLit) + + return ok && sl.Kind == token.STRING +} + +// IsCgoExported returns true if the given function declaration is exported as Cgo function, false otherwise. +func IsCgoExported(f *ast.FuncDecl) bool { + if f.Recv != nil || f.Doc == nil { + return false + } + + cgoExport := regexp.MustCompile(fmt.Sprintf("(?m)^//export %s$", regexp.QuoteMeta(f.Name.Name))) + for _, c := range f.Doc.List { + if cgoExport.MatchString(c.Text) { + return true + } + } + return false +} + +// IsIdent returns true if the given expression is the identifier with name ident, false otherwise. +func IsIdent(expr ast.Expr, ident string) bool { + id, ok := expr.(*ast.Ident) + return ok && id.Name == ident +} + +// IsPkgDotName returns true if the given expression is a selector expression of the form ., false otherwise. +func IsPkgDotName(expr ast.Expr, pkg, name string) bool { + sel, ok := expr.(*ast.SelectorExpr) + return ok && IsIdent(sel.X, pkg) && IsIdent(sel.Sel, name) +} + +// PickNodes yields a list of nodes by picking them from a sub-ast with root node n. +// Nodes are selected by applying the selector function. +func PickNodes(n ast.Node, selector func(n ast.Node) bool) []ast.Node { + var result []ast.Node + + if n == nil { + return result + } + + onSelect := func(n ast.Node) { + result = append(result, n) + } + p := picker{selector: selector, onSelect: onSelect} + ast.Walk(p, n) + return result +} + +type picker struct { + selector func(n ast.Node) bool + onSelect func(n ast.Node) +} + +func (p picker) Visit(node ast.Node) ast.Visitor { + if p.selector == nil { + return nil + } + + if p.selector(node) { + p.onSelect(node) + } + + return p +} + +// SeekNode yields the first node selected by the given selector function in the AST subtree with root n. +// The function returns nil if no matching node is found in the subtree. +func SeekNode[T ast.Node](n ast.Node, selector func(n ast.Node) bool) T { + var result T + + if n == nil { + return result + } + + if selector == nil { + return result + } + + onSelect := func(n ast.Node) { + result, _ = n.(T) + } + + p := &seeker{selector: selector, onSelect: onSelect, found: false} + ast.Walk(p, n) + + return result +} + +type seeker struct { + selector func(n ast.Node) bool + onSelect func(n ast.Node) + found bool +} + +func (s *seeker) Visit(node ast.Node) ast.Visitor { + if s.found { + return nil // stop visiting subtree + } + + if s.selector(node) { + s.onSelect(node) + s.found = true + return nil // skip visiting node children + } + + return s +} + +var gofmtConfig = &printer.Config{Tabwidth: 8} + +// GoFmt returns a string representation of an AST subtree. +func GoFmt(x any) string { + buf := bytes.Buffer{} + fs := token.NewFileSet() + _ = gofmtConfig.Fprint(&buf, fs, x) + return buf.String() +} + +// NodeHash yields the MD5 hash of the given AST node. +func NodeHash(node ast.Node) string { + hasher := func(in string) string { + binHash := md5.Sum([]byte(in)) //nolint:gosec // G401: Weak cryptographic primitive + return hex.EncodeToString(binHash[:]) + } + str := GoFmt(node) + return hasher(str) +} diff --git a/vendor/github.com/mgechev/revive/internal/ifelse/args.go b/vendor/github.com/mgechev/revive/internal/ifelse/args.go index c6e647e69..288a8e630 100644 --- a/vendor/github.com/mgechev/revive/internal/ifelse/args.go +++ b/vendor/github.com/mgechev/revive/internal/ifelse/args.go @@ -1,11 +1,8 @@ package ifelse -// PreserveScope is a configuration argument that prevents suggestions -// that would enlarge variable scope -const PreserveScope = "preserveScope" - -// Args contains arguments common to the early-return, indent-error-flow -// and superfluous-else rules (currently just preserveScope) +// Args contains arguments common to the early-return, indent-error-flow, +// and superfluous-else rules. type Args struct { PreserveScope bool + AllowJump bool } diff --git a/vendor/github.com/mgechev/revive/internal/ifelse/branch.go b/vendor/github.com/mgechev/revive/internal/ifelse/branch.go index 6e6036b89..5acf83840 100644 --- a/vendor/github.com/mgechev/revive/internal/ifelse/branch.go +++ b/vendor/github.com/mgechev/revive/internal/ifelse/branch.go @@ -9,11 +9,12 @@ import ( // Branch contains information about a branch within an if-else chain. type Branch struct { BranchKind - Call // The function called at the end for kind Panic or Exit. - HasDecls bool // The branch has one or more declarations (at the top level block) + Call // The function called at the end for kind Panic or Exit. + + block []ast.Stmt } -// BlockBranch gets the Branch of an ast.BlockStmt. +// BlockBranch gets the Branch of an [ast.BlockStmt]. func BlockBranch(block *ast.BlockStmt) Branch { blockLen := len(block.List) if blockLen == 0 { @@ -21,11 +22,11 @@ func BlockBranch(block *ast.BlockStmt) Branch { } branch := StmtBranch(block.List[blockLen-1]) - branch.HasDecls = hasDecls(block) + branch.block = block.List return branch } -// StmtBranch gets the Branch of an ast.Stmt. +// StmtBranch gets the Branch of an [ast.Stmt]. func StmtBranch(stmt ast.Stmt) Branch { switch stmt := stmt.(type) { case *ast.ReturnStmt: @@ -58,28 +59,31 @@ func StmtBranch(stmt ast.Stmt) Branch { return Regular.Branch() } -// String returns a brief string representation +// String returns a brief string representation. func (b Branch) String() string { switch b.BranchKind { + case Empty: + return "{ }" + case Regular: + return "{ ... }" case Panic, Exit: - return fmt.Sprintf("... %v()", b.Call) - default: - return b.BranchKind.String() + return fmt.Sprintf("{ ... %v() }", b.Call) } + return fmt.Sprintf("{ ... %v }", b.BranchKind) } -// LongString returns a longer form string representation +// LongString returns a longer form string representation. func (b Branch) LongString() string { switch b.BranchKind { case Panic, Exit: return fmt.Sprintf("call to %v function", b.Call) - default: - return b.BranchKind.LongString() } + return b.BranchKind.LongString() } -func hasDecls(block *ast.BlockStmt) bool { - for _, stmt := range block.List { +// HasDecls returns whether the branch has any top-level declarations. +func (b Branch) HasDecls() bool { + for _, stmt := range b.block { switch stmt := stmt.(type) { case *ast.DeclStmt: return true @@ -91,3 +95,24 @@ func hasDecls(block *ast.BlockStmt) bool { } return false } + +// IsShort returns whether the branch is empty or consists of a single statement. +func (b Branch) IsShort() bool { + switch len(b.block) { + case 0: + return true + case 1: + return isShortStmt(b.block[0]) + case 2: + return isShortStmt(b.block[1]) + } + return false +} + +func isShortStmt(stmt ast.Stmt) bool { + switch stmt.(type) { + case *ast.BlockStmt, *ast.IfStmt, *ast.SwitchStmt, *ast.TypeSwitchStmt, *ast.SelectStmt, *ast.ForStmt, *ast.RangeStmt: + return false + } + return true +} diff --git a/vendor/github.com/mgechev/revive/internal/ifelse/branch_kind.go b/vendor/github.com/mgechev/revive/internal/ifelse/branch_kind.go index 41601d1e1..3f6c76996 100644 --- a/vendor/github.com/mgechev/revive/internal/ifelse/branch_kind.go +++ b/vendor/github.com/mgechev/revive/internal/ifelse/branch_kind.go @@ -5,35 +5,35 @@ package ifelse type BranchKind int const ( - // Empty branches do nothing + // Empty branches do nothing. Empty BranchKind = iota - // Return branches return from the current function + // Return branches return from the current function. Return - // Continue branches continue a surrounding "for" loop + // Continue branches continue a surrounding "for" loop. Continue - // Break branches break a surrounding "for" loop + // Break branches break a surrounding "for" loop. Break - // Goto branches conclude with a "goto" statement + // Goto branches conclude with a "goto" statement. Goto - // Panic branches panic the current function + // Panic branches panic the current function. Panic - // Exit branches end the program + // Exit branches end the program. Exit - // Regular branches do not fit any category above + // Regular branches do not fit any category above. Regular ) -// IsEmpty tests if the branch is empty +// IsEmpty tests if the branch is empty. func (k BranchKind) IsEmpty() bool { return k == Empty } -// Returns tests if the branch returns from the current function +// Returns tests if the branch returns from the current function. func (k BranchKind) Returns() bool { return k == Return } // Deviates tests if the control does not flow to the first @@ -44,39 +44,35 @@ func (k BranchKind) Deviates() bool { return false case Return, Continue, Break, Goto, Panic, Exit: return true - default: - panic("invalid kind") } + panic("invalid kind") } -// Branch returns a Branch with the given kind +// Branch returns a Branch with the given kind. func (k BranchKind) Branch() Branch { return Branch{BranchKind: k} } -// String returns a brief string representation +// String returns a brief string representation. func (k BranchKind) String() string { switch k { - case Empty: + case Empty, Regular: return "" - case Regular: - return "..." case Return: - return "... return" + return "return" case Continue: - return "... continue" + return "continue" case Break: - return "... break" + return "break" case Goto: - return "... goto" + return "goto" case Panic: - return "... panic()" + return "panic()" case Exit: - return "... os.Exit()" - default: - panic("invalid kind") + return "os.Exit()" } + panic("invalid kind") } -// LongString returns a longer form string representation +// LongString returns a longer form string representation. func (k BranchKind) LongString() string { switch k { case Empty: @@ -95,7 +91,6 @@ func (k BranchKind) LongString() string { return "a function call that panics" case Exit: return "a function call that exits the program" - default: - panic("invalid kind") } + panic("invalid kind") } diff --git a/vendor/github.com/mgechev/revive/internal/ifelse/chain.go b/vendor/github.com/mgechev/revive/internal/ifelse/chain.go index 9891635ee..e3c8898ce 100644 --- a/vendor/github.com/mgechev/revive/internal/ifelse/chain.go +++ b/vendor/github.com/mgechev/revive/internal/ifelse/chain.go @@ -2,9 +2,11 @@ package ifelse // Chain contains information about an if-else chain. type Chain struct { - If Branch // what happens at the end of the "if" block - Else Branch // what happens at the end of the "else" block - HasInitializer bool // is there an "if"-initializer somewhere in the chain? - HasPriorNonDeviating bool // is there a prior "if" block that does NOT deviate control flow? - AtBlockEnd bool // whether the chain is placed at the end of the surrounding block + If Branch // what happens at the end of the "if" block + HasElse bool // is there an "else" block? + Else Branch // what happens at the end of the "else" block + HasInitializer bool // is there an "if"-initializer somewhere in the chain? + HasPriorNonDeviating bool // is there a prior "if" block that does NOT deviate control flow? + AtBlockEnd bool // whether the chain is placed at the end of the surrounding block + BlockEndKind BranchKind // control flow at end of surrounding block (e.g. "return" for function body) } diff --git a/vendor/github.com/mgechev/revive/internal/ifelse/doc.go b/vendor/github.com/mgechev/revive/internal/ifelse/doc.go index 0aa2c9817..77d93cd00 100644 --- a/vendor/github.com/mgechev/revive/internal/ifelse/doc.go +++ b/vendor/github.com/mgechev/revive/internal/ifelse/doc.go @@ -1,6 +1,6 @@ -// Package ifelse provides helpers for analysing the control flow in if-else chains, +// Package ifelse provides helpers for analyzing the control flow in if-else chains, // presently used by the following rules: -// - early-return -// - indent-error-flow -// - superfluous-else +// - early-return +// - indent-error-flow +// - superfluous-else package ifelse diff --git a/vendor/github.com/mgechev/revive/internal/ifelse/func.go b/vendor/github.com/mgechev/revive/internal/ifelse/func.go index 7ba351918..cd27cc592 100644 --- a/vendor/github.com/mgechev/revive/internal/ifelse/func.go +++ b/vendor/github.com/mgechev/revive/internal/ifelse/func.go @@ -23,7 +23,7 @@ var DeviatingFuncs = map[Call]BranchKind{ {"log", "Panicln"}: Panic, } -// ExprCall gets the Call of an ExprStmt, if any. +// ExprCall gets the [Call] of an [ast.ExprStmt], if any. func ExprCall(expr *ast.ExprStmt) (Call, bool) { call, ok := expr.X.(*ast.CallExpr) if !ok { @@ -40,12 +40,10 @@ func ExprCall(expr *ast.ExprStmt) (Call, bool) { return Call{}, false } -// String returns the function name with package qualifier (if any) +// String returns the function name with package qualifier (if any). func (f Call) String() string { - switch { - case f.Pkg != "": + if f.Pkg != "" { return fmt.Sprintf("%s.%s", f.Pkg, f.Name) - default: - return f.Name } + return f.Name } diff --git a/vendor/github.com/mgechev/revive/internal/ifelse/rule.go b/vendor/github.com/mgechev/revive/internal/ifelse/rule.go index 07ad456b6..347487661 100644 --- a/vendor/github.com/mgechev/revive/internal/ifelse/rule.go +++ b/vendor/github.com/mgechev/revive/internal/ifelse/rule.go @@ -7,15 +7,15 @@ import ( "github.com/mgechev/revive/lint" ) -// Rule is an interface for linters operating on if-else chains -type Rule interface { - CheckIfElse(chain Chain, args Args) (failMsg string) -} +// CheckFunc evaluates a rule against the given if-else chain and returns a message +// describing the proposed refactor, along with a indicator of whether such a refactor +// could be found. +type CheckFunc func(Chain) (string, bool) // Apply evaluates the given Rule on if-else chains found within the given AST, // and returns the failures. // -// Note that in if-else chain with multiple "if" blocks, only the *last* one is checked, +// Note that in if-else chain with multiple "if" blocks, only the "last" one is checked, // that is to say, given: // // if foo { @@ -28,13 +28,9 @@ type Rule interface { // // Only the block following "bar" is linted. This is because the rules that use this function // do not presently have anything to say about earlier blocks in the chain. -func Apply(rule Rule, node ast.Node, target Target, args lint.Arguments) []lint.Failure { - v := &visitor{rule: rule, target: target} - for _, arg := range args { - if arg == PreserveScope { - v.args.PreserveScope = true - } - } +func Apply(check CheckFunc, node ast.Node, target Target, args Args) []lint.Failure { + v := &visitor{check: check, target: target} + v.args = args ast.Walk(v, node) return v.failures } @@ -42,64 +38,99 @@ func Apply(rule Rule, node ast.Node, target Target, args lint.Arguments) []lint. type visitor struct { failures []lint.Failure target Target - rule Rule + check CheckFunc args Args } func (v *visitor) Visit(node ast.Node) ast.Visitor { - block, ok := node.(*ast.BlockStmt) - if !ok { + switch stmt := node.(type) { + case *ast.FuncDecl: + v.visitBody(stmt.Body, Return) + case *ast.FuncLit: + v.visitBody(stmt.Body, Return) + case *ast.ForStmt: + v.visitBody(stmt.Body, Continue) + case *ast.RangeStmt: + v.visitBody(stmt.Body, Continue) + case *ast.CaseClause: + v.visitBlock(stmt.Body, Break) + case *ast.BlockStmt: + v.visitBlock(stmt.List, Regular) + default: return v } + return nil +} - for i, stmt := range block.List { - if ifStmt, ok := stmt.(*ast.IfStmt); ok { - v.visitChain(ifStmt, Chain{AtBlockEnd: i == len(block.List)-1}) +func (v *visitor) visitBody(body *ast.BlockStmt, endKind BranchKind) { + if body != nil { + v.visitBlock(body.List, endKind) + } +} + +func (v *visitor) visitBlock(stmts []ast.Stmt, endKind BranchKind) { + for i, stmt := range stmts { + ifStmt, ok := stmt.(*ast.IfStmt) + if !ok { + ast.Walk(v, stmt) continue } - ast.Walk(v, stmt) + var chain Chain + if i == len(stmts)-1 { + chain.AtBlockEnd = true + chain.BlockEndKind = endKind + } + v.visitIf(ifStmt, chain) } - return nil } -func (v *visitor) visitChain(ifStmt *ast.IfStmt, chain Chain) { +func (v *visitor) visitIf(ifStmt *ast.IfStmt, chain Chain) { // look for other if-else chains nested inside this if { } block - ast.Walk(v, ifStmt.Body) - - if ifStmt.Else == nil { - // no else branch - return - } + v.visitBlock(ifStmt.Body.List, chain.BlockEndKind) if as, ok := ifStmt.Init.(*ast.AssignStmt); ok && as.Tok == token.DEFINE { chain.HasInitializer = true } chain.If = BlockBranch(ifStmt.Body) + if ifStmt.Else == nil { + if v.args.AllowJump { + v.checkRule(ifStmt, chain) + } + return + } + switch elseBlock := ifStmt.Else.(type) { case *ast.IfStmt: if !chain.If.Deviates() { chain.HasPriorNonDeviating = true } - v.visitChain(elseBlock, chain) + v.visitIf(elseBlock, chain) case *ast.BlockStmt: // look for other if-else chains nested inside this else { } block - ast.Walk(v, elseBlock) + v.visitBlock(elseBlock.List, chain.BlockEndKind) + chain.HasElse = true chain.Else = BlockBranch(elseBlock) - if failMsg := v.rule.CheckIfElse(chain, v.args); failMsg != "" { - if chain.HasInitializer { - // if statement has a := initializer, so we might need to move the assignment - // onto its own line in case the body references it - failMsg += " (move short variable declaration to its own line if necessary)" - } - v.failures = append(v.failures, lint.Failure{ - Confidence: 1, - Node: v.target.node(ifStmt), - Failure: failMsg, - }) - } + v.checkRule(ifStmt, chain) default: - panic("invalid node type for else") + panic("unexpected node type for else") + } +} + +func (v *visitor) checkRule(ifStmt *ast.IfStmt, chain Chain) { + msg, found := v.check(chain) + if !found { + return // passed the check + } + if chain.HasInitializer { + // if statement has a := initializer, so we might need to move the assignment + // onto its own line in case the body references it + msg += " (move short variable declaration to its own line if necessary)" } + v.failures = append(v.failures, lint.Failure{ + Confidence: 1, + Node: v.target.node(ifStmt), + Failure: msg, + }) } diff --git a/vendor/github.com/mgechev/revive/internal/ifelse/target.go b/vendor/github.com/mgechev/revive/internal/ifelse/target.go index 81ff1c303..d54fc537b 100644 --- a/vendor/github.com/mgechev/revive/internal/ifelse/target.go +++ b/vendor/github.com/mgechev/revive/internal/ifelse/target.go @@ -6,10 +6,10 @@ import "go/ast" type Target int const ( - // TargetIf means the text refers to the "if" + // TargetIf means the text refers to the "if". TargetIf Target = iota - // TargetElse means the text refers to the "else" + // TargetElse means the text refers to the "else". TargetElse ) @@ -19,7 +19,6 @@ func (t Target) node(ifStmt *ast.IfStmt) ast.Node { return ifStmt case TargetElse: return ifStmt.Else - default: - panic("bad target") } + panic("bad target") } diff --git a/vendor/github.com/mgechev/revive/internal/rule/name.go b/vendor/github.com/mgechev/revive/internal/rule/name.go new file mode 100644 index 000000000..60257674a --- /dev/null +++ b/vendor/github.com/mgechev/revive/internal/rule/name.go @@ -0,0 +1,135 @@ +// Package rule defines utility functions some revive rules can share. +package rule + +import ( + "strings" + "unicode" +) + +// commonInitialisms is a set of common initialisms. +// Only add entries that are highly unlikely to be non-initialisms. +// For instance, "ID" is fine (Freudian code is rare), but "AND" is not. +var commonInitialisms = map[string]bool{ + "ACL": true, + "API": true, + "ASCII": true, + "CPU": true, + "CSS": true, + "DNS": true, + "EOF": true, + "GUID": true, + "HTML": true, + "HTTP": true, + "HTTPS": true, + "ID": true, + "IDS": true, + "IP": true, + "JSON": true, + "LHS": true, + "QPS": true, + "RAM": true, + "RHS": true, + "RPC": true, + "SLA": true, + "SMTP": true, + "SQL": true, + "SSH": true, + "TCP": true, + "TLS": true, + "TTL": true, + "UDP": true, + "UI": true, + "UID": true, + "UUID": true, + "URI": true, + "URL": true, + "UTF8": true, + "VM": true, + "XML": true, + "XMPP": true, + "XSRF": true, + "XSS": true, +} + +// Name returns a different name of struct, var, const, or function if it should be different. +func Name(name string, allowlist, blocklist []string, skipInitialismNameChecks bool) (should string) { + // Fast path for simple cases: "_" and all lowercase. + if name == "_" { + return name + } + allLower := true + for _, r := range name { + if !unicode.IsLower(r) { + allLower = false + break + } + } + if allLower { + return name + } + + // Split camelCase at any lower->upper transition, and split on underscores. + // Check each word for common initialisms. + runes := []rune(name) + w, i := 0, 0 // index of start of word, scan + for i+1 <= len(runes) { + eow := false // whether we hit the end of a word + switch { + case i+1 == len(runes): + eow = true + case runes[i+1] == '_': + // underscore; shift the remainder forward over any run of underscores + eow = true + n := 1 + for i+n+1 < len(runes) && runes[i+n+1] == '_' { + n++ + } + + // Leave at most one underscore if the underscore is between two digits + if i+n+1 < len(runes) && unicode.IsDigit(runes[i]) && unicode.IsDigit(runes[i+n+1]) { + n-- + } + + copy(runes[i+1:], runes[i+n+1:]) + runes = runes[:len(runes)-n] + case unicode.IsLower(runes[i]) && !unicode.IsLower(runes[i+1]): + // lower->non-lower + eow = true + } + i++ + if !eow { + continue + } + + // [w,i) is a word. + word := string(runes[w:i]) + ignoreInitWarnings := map[string]bool{} + for _, i := range allowlist { + ignoreInitWarnings[i] = true + } + + extraInits := map[string]bool{} + for _, i := range blocklist { + extraInits[i] = true + } + + if u := strings.ToUpper(word); !skipInitialismNameChecks && (commonInitialisms[u] || extraInits[u]) && !ignoreInitWarnings[u] { + // Keep consistent case, which is lowercase only at the start. + if w == 0 && unicode.IsLower(runes[w]) { + u = strings.ToLower(u) + } + // Keep lowercase s for IDs + if u == "IDS" { + u = "IDs" + } + // All the common initialisms are ASCII, + // so we can replace the bytes exactly. + copy(runes[w:], []rune(u)) + } else if w > 0 && strings.ToLower(word) == word { + // already all lowercase, and not the first word, so uppercase the first character. + runes[w] = unicode.ToUpper(runes[w]) + } + w = i + } + return string(runes) +} diff --git a/vendor/github.com/mgechev/revive/internal/syncset/syncset.go b/vendor/github.com/mgechev/revive/internal/syncset/syncset.go new file mode 100644 index 000000000..8f20e91ca --- /dev/null +++ b/vendor/github.com/mgechev/revive/internal/syncset/syncset.go @@ -0,0 +1,44 @@ +// Package syncset provides a simple, mutex-protected set for strings. +package syncset + +import ( + "maps" + "slices" + "sync" +) + +// Set is a concurrency-safe set of strings. +type Set struct { + mu sync.Mutex + elements map[string]struct{} +} + +// New returns an initialized, empty Set. +func New() *Set { + return &Set{elements: map[string]struct{}{}} +} + +// AddIfAbsent adds str to the set if it is not already present, and reports whether it was added. +func (s *Set) AddIfAbsent(str string) bool { + s.mu.Lock() + defer s.mu.Unlock() + + if s.elements == nil { + s.elements = map[string]struct{}{str: {}} + return true + } + + _, exists := s.elements[str] + if !exists { + s.elements[str] = struct{}{} + } + return !exists +} + +// Elements returns a slice of all elements in the set. +func (s *Set) Elements() []string { + s.mu.Lock() + defer s.mu.Unlock() + + return slices.Collect(maps.Keys(s.elements)) +} diff --git a/vendor/github.com/mgechev/revive/internal/typeparams/typeparams.go b/vendor/github.com/mgechev/revive/internal/typeparams/typeparams.go index 33c4f203e..e3e0ecd77 100644 --- a/vendor/github.com/mgechev/revive/internal/typeparams/typeparams.go +++ b/vendor/github.com/mgechev/revive/internal/typeparams/typeparams.go @@ -6,12 +6,6 @@ import ( "go/ast" ) -// Enabled reports whether type parameters are enabled in the current build -// environment. -func Enabled() bool { - return enabled -} - // ReceiverType returns the named type of the method receiver, sans "*" and type // parameters, or "invalid-type" if fn.Recv is ill formed. func ReceiverType(fn *ast.FuncDecl) string { @@ -19,11 +13,19 @@ func ReceiverType(fn *ast.FuncDecl) string { if s, ok := e.(*ast.StarExpr); ok { e = s.X } - if enabled { - e = unpackIndexExpr(e) - } + e = unpackIndexExpr(e) if id, ok := e.(*ast.Ident); ok { return id.Name } return "invalid-type" } + +func unpackIndexExpr(e ast.Expr) ast.Expr { + switch e := e.(type) { + case *ast.IndexExpr: + return e.X + case *ast.IndexListExpr: + return e.X + } + return e +} diff --git a/vendor/github.com/mgechev/revive/internal/typeparams/typeparams_go117.go b/vendor/github.com/mgechev/revive/internal/typeparams/typeparams_go117.go deleted file mode 100644 index 913a7316e..000000000 --- a/vendor/github.com/mgechev/revive/internal/typeparams/typeparams_go117.go +++ /dev/null @@ -1,12 +0,0 @@ -//go:build !go1.18 -// +build !go1.18 - -package typeparams - -import ( - "go/ast" -) - -const enabled = false - -func unpackIndexExpr(e ast.Expr) ast.Expr { return e } diff --git a/vendor/github.com/mgechev/revive/internal/typeparams/typeparams_go118.go b/vendor/github.com/mgechev/revive/internal/typeparams/typeparams_go118.go deleted file mode 100644 index 0f7fd88d3..000000000 --- a/vendor/github.com/mgechev/revive/internal/typeparams/typeparams_go118.go +++ /dev/null @@ -1,20 +0,0 @@ -//go:build go1.18 -// +build go1.18 - -package typeparams - -import ( - "go/ast" -) - -const enabled = true - -func unpackIndexExpr(e ast.Expr) ast.Expr { - switch e := e.(type) { - case *ast.IndexExpr: - return e.X - case *ast.IndexListExpr: - return e.X - } - return e -} diff --git a/vendor/github.com/mgechev/revive/lint/config.go b/vendor/github.com/mgechev/revive/lint/config.go index d7ecd964a..533ce054c 100644 --- a/vendor/github.com/mgechev/revive/lint/config.go +++ b/vendor/github.com/mgechev/revive/lint/config.go @@ -5,7 +5,7 @@ import ( ) // Arguments is type used for the arguments of a rule. -type Arguments = []interface{} +type Arguments = []any // FileFilters is type used for modeling file filters to apply to rules. type FileFilters = []*FileFilter @@ -15,13 +15,13 @@ type RuleConfig struct { Arguments Arguments Severity Severity Disabled bool - // Exclude - rule-level file excludes, TOML related (strings) + // Exclude is rule-level file excludes, TOML related (strings). Exclude []string - // excludeFilters - regex-based file filters, initialized from Exclude + // excludeFilters is regex-based file filters, initialized from Exclude. excludeFilters []*FileFilter } -// Initialize - should be called after reading from TOML file +// Initialize should be called after reading from TOML file. func (rc *RuleConfig) Initialize() error { for _, f := range rc.Exclude { ff, err := ParseFileFilter(f) @@ -36,7 +36,7 @@ func (rc *RuleConfig) Initialize() error { // RulesConfig defines the config for all rules. type RulesConfig = map[string]RuleConfig -// MustExclude - checks if given filename `name` must be excluded +// MustExclude checks if given filename `name` must be excluded. func (rc *RuleConfig) MustExclude(name string) bool { for _, exclude := range rc.excludeFilters { if exclude.MatchFileName(name) { @@ -56,10 +56,11 @@ type DirectivesConfig = map[string]DirectiveConfig // Config defines the config of the linter. type Config struct { - IgnoreGeneratedHeader bool `toml:"ignoreGeneratedHeader"` - Confidence float64 - Severity Severity + IgnoreGeneratedHeader bool `toml:"ignoreGeneratedHeader"` + Confidence float64 `toml:"confidence"` + Severity Severity `toml:"severity"` EnableAllRules bool `toml:"enableAllRules"` + EnableDefaultRules bool `toml:"enableDefaultRules"` Rules RulesConfig `toml:"rule"` ErrorCode int `toml:"errorCode"` WarningCode int `toml:"warningCode"` @@ -67,5 +68,5 @@ type Config struct { Exclude []string `toml:"exclude"` // If set, overrides the go language version specified in go.mod of // packages being linted, and assumes this specific language version. - GoVersion *goversion.Version + GoVersion *goversion.Version `toml:"goVersion"` } diff --git a/vendor/github.com/mgechev/revive/lint/failure.go b/vendor/github.com/mgechev/revive/lint/failure.go index 479b0cb48..01ed09115 100644 --- a/vendor/github.com/mgechev/revive/lint/failure.go +++ b/vendor/github.com/mgechev/revive/lint/failure.go @@ -6,7 +6,56 @@ import ( ) const ( - // SeverityWarning declares failures of type warning + // FailureCategoryArgOrder indicates argument order issues. + FailureCategoryArgOrder FailureCategory = "arg-order" + // FailureCategoryBadPractice indicates bad practice issues. + FailureCategoryBadPractice FailureCategory = "bad practice" + // FailureCategoryCodeStyle indicates code style issues. + // + // Deprecated: use FailureCategoryStyle instead. + FailureCategoryCodeStyle FailureCategory = "code-style" + // FailureCategoryComments indicates comment issues. + FailureCategoryComments FailureCategory = "comments" + // FailureCategoryComplexity indicates complexity issues. + FailureCategoryComplexity FailureCategory = "complexity" + // FailureCategoryContent indicates content issues. + FailureCategoryContent FailureCategory = "content" + // FailureCategoryErrors indicates error handling issues. + FailureCategoryErrors FailureCategory = "errors" + // FailureCategoryImports indicates import issues. + FailureCategoryImports FailureCategory = "imports" + // FailureCategoryLogic indicates logic issues. + FailureCategoryLogic FailureCategory = "logic" + // FailureCategoryMaintenance indicates maintenance issues. + FailureCategoryMaintenance FailureCategory = "maintenance" + // FailureCategoryNaming indicates naming issues. + FailureCategoryNaming FailureCategory = "naming" + // FailureCategoryOptimization indicates optimization issues. + FailureCategoryOptimization FailureCategory = "optimization" + // FailureCategoryStyle indicates style issues. + FailureCategoryStyle FailureCategory = "style" + // FailureCategoryTime indicates time-related issues. + FailureCategoryTime FailureCategory = "time" + // FailureCategoryTypeInference indicates type inference issues. + FailureCategoryTypeInference FailureCategory = "type-inference" + // FailureCategoryUnaryOp indicates unary operation issues. + FailureCategoryUnaryOp FailureCategory = "unary-op" + // FailureCategoryUnexportedTypeInAPI indicates unexported type in API issues. + FailureCategoryUnexportedTypeInAPI FailureCategory = "unexported-type-in-api" + // FailureCategoryZeroValue indicates zero value issues. + FailureCategoryZeroValue FailureCategory = "zero-value" + + // failureCategoryInternal indicates internal failures. + failureCategoryInternal FailureCategory = "REVIVE_INTERNAL" + // failureCategoryValidity indicates validity issues. + failureCategoryValidity FailureCategory = "validity" +) + +// FailureCategory is the type for the failure categories. +type FailureCategory string + +const ( + // SeverityWarning declares failures of type warning. SeverityWarning = "warning" // SeverityError declares failures of type error. SeverityError = "error" @@ -15,25 +64,44 @@ const ( // Severity is the type for the failure types. type Severity string -// FailurePosition returns the failure position +// FailurePosition returns the failure position. type FailurePosition struct { - Start token.Position - End token.Position + Start token.Position `json:"Start"` + End token.Position `json:"End"` } // Failure defines a struct for a linting failure. type Failure struct { - Failure string - RuleName string - Category string - Position FailurePosition - Node ast.Node `json:"-"` - Confidence float64 - // For future use - ReplacementLine string + Failure string `json:"Failure"` + RuleName string `json:"RuleName"` + Category FailureCategory `json:"Category"` + Position FailurePosition `json:"Position"` + Node ast.Node `json:"-"` + Confidence float64 `json:"Confidence"` + ReplacementLine string `json:"ReplacementLine"` } // GetFilename returns the filename. +// +// Deprecated: Use [Failure.Filename] instead. func (f *Failure) GetFilename() string { + return f.Filename() +} + +// Filename returns the filename. +func (f *Failure) Filename() string { return f.Position.Start.Filename } + +// IsInternal returns true if this failure is internal, false otherwise. +func (f *Failure) IsInternal() bool { + return f.Category == failureCategoryInternal +} + +// NewInternalFailure yields an internal failure with the given message as failure message. +func NewInternalFailure(message string) Failure { + return Failure{ + Category: failureCategoryInternal, + Failure: message, + } +} diff --git a/vendor/github.com/mgechev/revive/lint/file.go b/vendor/github.com/mgechev/revive/lint/file.go index e34f8b7f4..15b7aa850 100644 --- a/vendor/github.com/mgechev/revive/lint/file.go +++ b/vendor/github.com/mgechev/revive/lint/file.go @@ -2,6 +2,7 @@ package lint import ( "bytes" + "errors" "go/ast" "go/parser" "go/printer" @@ -23,12 +24,29 @@ type File struct { // IsTest returns if the file contains tests. func (f *File) IsTest() bool { return strings.HasSuffix(f.Name, "_test.go") } +// IsImportable returns if the symbols defined in this file can be imported in other packages. +// +// Symbols from the package `main` or test files are not exported, so they cannot be imported. +func (f *File) IsImportable() bool { + if f.IsTest() { + // Test files cannot be imported. + return false + } + + if f.Pkg.IsMain() { + // The package `main` cannot be imported. + return false + } + + return true +} + // Content returns the file's content. func (f *File) Content() []byte { return f.content } -// NewFile creates a new file +// NewFile creates a new file. func NewFile(name string, content []byte, pkg *Package) (*File, error) { f, err := parser.ParseFile(pkg.fset, name, content, parser.ParseComments) if err != nil { @@ -48,7 +66,7 @@ func (f *File) ToPosition(pos token.Pos) token.Position { } // Render renders a node. -func (f *File) Render(x interface{}) string { +func (f *File) Render(x any) string { var buf bytes.Buffer if err := printer.Fprint(&buf, f.Pkg.fset, x); err != nil { panic(err) @@ -72,7 +90,7 @@ var basicTypeKinds = map[types.BasicKind]string{ // IsUntypedConst reports whether expr is an untyped constant, // and indicates what its default type is. -// scope may be nil. +// Scope may be nil. func (f *File) IsUntypedConst(expr ast.Expr) (defType string, ok bool) { // Re-evaluate expr outside its context to see if it's untyped. // (An expr evaluated within, for example, an assignment context will get the type of the LHS.) @@ -96,7 +114,7 @@ func (f *File) isMain() bool { const directiveSpecifyDisableReason = "specify-disable-reason" -func (f *File) lint(rules []Rule, config Config, failures chan Failure) { +func (f *File) lint(rules []Rule, config Config, failures chan Failure) error { rulesConfig := config.Rules _, mustSpecifyDisableReason := config.Directives[directiveSpecifyDisableReason] disabledIntervals := f.disabledIntervals(rules, mustSpecifyDisableReason, failures) @@ -107,6 +125,10 @@ func (f *File) lint(rules []Rule, config Config, failures chan Failure) { } currentFailures := currentRule.Apply(f, ruleConfig.Arguments) for idx, failure := range currentFailures { + if failure.IsInternal() { + return errors.New(failure.Failure) + } + if failure.RuleName == "" { failure.RuleName = currentRule.Name() } @@ -122,6 +144,7 @@ func (f *File) lint(rules []Rule, config Config, failures chan Failure) { } } } + return nil } type enableDisableConfig struct { @@ -129,25 +152,26 @@ type enableDisableConfig struct { position int } +type disabledIntervalsMap = map[string][]DisabledInterval + const ( - directiveRE = `^//[\s]*revive:(enable|disable)(?:-(line|next-line))?(?::([^\s]+))?[\s]*(?: (.+))?$` directivePos = 1 modifierPos = 2 rulesPos = 3 reasonPos = 4 ) -var re = regexp.MustCompile(directiveRE) +var directiveRegexp = regexp.MustCompile(`^//[\s]*revive:(enable|disable)(?:-(line|next-line))?(?::([^\s]+))?[\s]*(?: (.+))?$`) func (f *File) disabledIntervals(rules []Rule, mustSpecifyDisableReason bool, failures chan Failure) disabledIntervalsMap { - enabledDisabledRulesMap := make(map[string][]enableDisableConfig) + enabledDisabledRulesMap := map[string][]enableDisableConfig{} getEnabledDisabledIntervals := func() disabledIntervalsMap { - result := make(disabledIntervalsMap) + result := disabledIntervalsMap{} for ruleName, disabledArr := range enabledDisabledRulesMap { ruleResult := []DisabledInterval{} - for i := 0; i < len(disabledArr); i++ { + for i := range disabledArr { interval := DisabledInterval{ RuleName: ruleName, From: token.Position{ @@ -188,35 +212,33 @@ func (f *File) disabledIntervals(rules []Rule, mustSpecifyDisableReason bool, fa enabledDisabledRulesMap[name] = existing } - handleRules := func(_, modifier string, isEnabled bool, line int, ruleNames []string) []DisabledInterval { - var result []DisabledInterval + handleRules := func(modifier string, isEnabled bool, line int, ruleNames []string) { for _, name := range ruleNames { - if modifier == "line" { + switch modifier { + case "line": handleConfig(isEnabled, line, name) handleConfig(!isEnabled, line, name) - } else if modifier == "next-line" { + case "next-line": handleConfig(isEnabled, line+1, name) handleConfig(!isEnabled, line+1, name) - } else { + default: handleConfig(isEnabled, line, name) } } - return result } - handleComment := func(filename string, c *ast.CommentGroup, line int) { + handleComment := func(c *ast.CommentGroup, line int) { comments := c.List for _, c := range comments { - match := re.FindStringSubmatch(c.Text) + match := directiveRegexp.FindStringSubmatch(c.Text) if len(match) == 0 { continue } ruleNames := []string{} - tempNames := strings.Split(match[rulesPos], ",") - for _, name := range tempNames { + for name := range strings.SplitSeq(match[rulesPos], ",") { name = strings.Trim(name, "\n") - if len(name) > 0 { + if name != "" { ruleNames = append(ruleNames, name) } } @@ -240,19 +262,18 @@ func (f *File) disabledIntervals(rules []Rule, mustSpecifyDisableReason bool, fa } } - handleRules(filename, match[modifierPos], match[directivePos] == "enable", line, ruleNames) + handleRules(match[modifierPos], match[directivePos] == "enable", line, ruleNames) } } - comments := f.AST.Comments - for _, c := range comments { - handleComment(f.Name, c, f.ToPosition(c.End()).Line) + for _, c := range f.AST.Comments { + handleComment(c, f.ToPosition(c.End()).Line) } return getEnabledDisabledIntervals() } -func (File) filterFailures(failures []Failure, disabledIntervals disabledIntervalsMap) []Failure { +func (*File) filterFailures(failures []Failure, disabledIntervals disabledIntervalsMap) []Failure { result := []Failure{} for _, failure := range failures { fStart := failure.Position.Start.Line @@ -260,21 +281,22 @@ func (File) filterFailures(failures []Failure, disabledIntervals disabledInterva intervals, ok := disabledIntervals[failure.RuleName] if !ok { result = append(result, failure) - } else { - include := true - for _, interval := range intervals { - intStart := interval.From.Line - intEnd := interval.To.Line - if (fStart >= intStart && fStart <= intEnd) || - (fEnd >= intStart && fEnd <= intEnd) { - include = false - break - } - } - if include { - result = append(result, failure) + continue + } + + include := true + for _, interval := range intervals { + intStart := interval.From.Line + intEnd := interval.To.Line + if (fStart >= intStart && fStart <= intEnd) || + (fEnd >= intStart && fEnd <= intEnd) { + include = false + break } } + if include { + result = append(result, failure) + } } return result } diff --git a/vendor/github.com/mgechev/revive/lint/filefilter.go b/vendor/github.com/mgechev/revive/lint/filefilter.go index 8da090b9c..3a523f2a5 100644 --- a/vendor/github.com/mgechev/revive/lint/filefilter.go +++ b/vendor/github.com/mgechev/revive/lint/filefilter.go @@ -6,12 +6,12 @@ import ( "strings" ) -// FileFilter - file filter to exclude some files for rule -// supports whole -// 1. file/dir names : pkg/mypkg/my.go, -// 2. globs: **/*.pb.go, -// 3. regexes (~ prefix) ~-tmp\.\d+\.go -// 4. special test marker `TEST` - treats as `~_test\.go` +// FileFilter filters file to exclude some files for a rule. +// Supports the following: +// - File or directory names: pkg/mypkg/my.go +// - Globs: **/*.pb.go, +// - Regexes (with ~ prefix): ~-tmp\.\d+\.go +// - Special test marker `TEST` (treated as `~_test\.go`). type FileFilter struct { // raw definition of filter inside config raw string @@ -23,15 +23,15 @@ type FileFilter struct { matchesNothing bool } -// ParseFileFilter - creates [FileFilter] for given raw filter -// if empty string, it matches nothing -// if `*`, or `~`, it matches everything -// while regexp could be invalid, it could return it's compilation error +// ParseFileFilter creates a [FileFilter] for the given raw filter. +// If the string is empty, it matches nothing. +// If the string is `*` or `~`, it matches everything. +// If the regular expression is invalid, it returns a compilation error. func ParseFileFilter(rawFilter string) (*FileFilter, error) { rawFilter = strings.TrimSpace(rawFilter) result := new(FileFilter) result.raw = rawFilter - result.matchesNothing = len(result.raw) == 0 + result.matchesNothing = result.raw == "" result.matchesAll = result.raw == "*" || result.raw == "~" if !result.matchesAll && !result.matchesNothing { if err := result.prepareRegexp(); err != nil { @@ -41,9 +41,10 @@ func ParseFileFilter(rawFilter string) (*FileFilter, error) { return result, nil } +// String returns the original raw filter definition as it appears in the configuration. func (ff *FileFilter) String() string { return ff.raw } -// MatchFileName - checks if file name matches filter +// MatchFileName checks if the file name matches the filter. func (ff *FileFilter) MatchFileName(name string) bool { if ff.matchesAll { return true @@ -55,19 +56,21 @@ func (ff *FileFilter) MatchFileName(name string) bool { return ff.rx.MatchString(name) } -var fileFilterInvalidGlobRegexp = regexp.MustCompile(`[^/]\*\*[^/]`) -var escapeRegexSymbols = ".+{}()[]^$" +var ( + fileFilterInvalidGlobRegexp = regexp.MustCompile(`[^/]\*\*[^/]`) + escapeRegexSymbols = ".+{}()[]^$" +) func (ff *FileFilter) prepareRegexp() error { var err error - var src = ff.raw + src := ff.raw if src == "TEST" { src = "~_test\\.go" } if strings.HasPrefix(src, "~") { ff.rx, err = regexp.Compile(src[1:]) if err != nil { - return fmt.Errorf("invalid file filter [%s], regexp compile error: [%v]", ff.raw, err) + return fmt.Errorf("invalid file filter [%s], regexp compile error: [%w]", ff.raw, err) } return nil } @@ -110,19 +113,19 @@ func (ff *FileFilter) prepareRegexp() error { rxBuild.WriteByte('$') ff.rx, err = regexp.Compile(rxBuild.String()) if err != nil { - return fmt.Errorf("invalid file filter [%s], regexp compile error after glob expand: [%v]", ff.raw, err) + return fmt.Errorf("invalid file filter [%s], regexp compile error after glob expand: [%w]", ff.raw, err) } return nil } - // it's whole file mask, just escape dots and normilze separators + // it's whole file mask, just escape dots and normalize separators fillRx := src fillRx = strings.ReplaceAll(fillRx, "\\", "/") fillRx = strings.ReplaceAll(fillRx, ".", `\.`) fillRx = "^" + fillRx + "$" ff.rx, err = regexp.Compile(fillRx) if err != nil { - return fmt.Errorf("invalid file filter [%s], regexp compile full path: [%v]", ff.raw, err) + return fmt.Errorf("invalid file filter [%s], regexp compile full path: [%w]", ff.raw, err) } return nil } diff --git a/vendor/github.com/mgechev/revive/lint/formatter.go b/vendor/github.com/mgechev/revive/lint/formatter.go index 7c19af278..c770fdf2d 100644 --- a/vendor/github.com/mgechev/revive/lint/formatter.go +++ b/vendor/github.com/mgechev/revive/lint/formatter.go @@ -1,13 +1,13 @@ package lint -// FormatterMetadata configuration of a formatter +// FormatterMetadata configuration of a formatter. type FormatterMetadata struct { Name string Description string Sample string } -// Formatter defines an interface for failure formatters +// Formatter defines an interface for failure formatters. type Formatter interface { Format(<-chan Failure, Config) (string, error) Name() string diff --git a/vendor/github.com/mgechev/revive/lint/linter.go b/vendor/github.com/mgechev/revive/lint/linter.go index b777f9251..46ae3f9c1 100644 --- a/vendor/github.com/mgechev/revive/lint/linter.go +++ b/vendor/github.com/mgechev/revive/lint/linter.go @@ -10,24 +10,22 @@ import ( "regexp" "strconv" "strings" - "sync" goversion "github.com/hashicorp/go-version" "golang.org/x/mod/modfile" + "golang.org/x/sync/errgroup" ) // ReadFile defines an abstraction for reading files. type ReadFile func(path string) (result []byte, err error) -type disabledIntervalsMap = map[string][]DisabledInterval - // Linter is used for linting set of files. type Linter struct { reader ReadFile fileReadTokens chan struct{} } -// New creates a new Linter +// New creates a new Linter. func New(reader ReadFile, maxOpenFiles int) Linter { var fileReadTokens chan struct{} if maxOpenFiles > 0 { @@ -39,7 +37,7 @@ func New(reader ReadFile, maxOpenFiles int) Linter { } } -func (l Linter) readFile(path string) (result []byte, err error) { +func (l *Linter) readFile(path string) (result []byte, err error) { if l.fileReadTokens != nil { // "take" a token by writing to the channel. // It will block if no more space in the channel's buffer @@ -54,8 +52,8 @@ func (l Linter) readFile(path string) (result []byte, err error) { } var ( - genHdr = []byte("// Code generated ") - genFtr = []byte(" DO NOT EDIT.") + generatedPrefix = []byte("// Code generated ") + generatedSuffix = []byte(" DO NOT EDIT.") defaultGoVersion = goversion.Must(goversion.NewVersion("1.0")) ) @@ -63,7 +61,7 @@ var ( func (l *Linter) Lint(packages [][]string, ruleSet []Rule, config Config) (<-chan Failure, error) { failures := make(chan Failure) - perModVersions := make(map[string]*goversion.Version) + perModVersions := map[string]*goversion.Version{} perPkgVersions := make([]*goversion.Version, len(packages)) for n, files := range packages { if len(files) == 0 { @@ -101,20 +99,23 @@ func (l *Linter) Lint(packages [][]string, ruleSet []Rule, config Config) (<-cha perPkgVersions[n] = v } - var wg sync.WaitGroup + var wg errgroup.Group for n := range packages { - wg.Add(1) - go func(pkg []string, gover *goversion.Version) { + wg.Go(func() error { + pkg := packages[n] + gover := perPkgVersions[n] if err := l.lintPackage(pkg, gover, ruleSet, config, failures); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) + return fmt.Errorf("error during linting: %w", err) } - wg.Done() - }(packages[n], perPkgVersions[n]) + return nil + }) } go func() { - wg.Wait() + err := wg.Wait() + if err != nil { + failures <- NewInternalFailure(err.Error()) + } close(failures) }() @@ -152,9 +153,7 @@ func (l *Linter) lintPackage(filenames []string, gover *goversion.Version, ruleS return nil } - pkg.lint(ruleSet, config, failures) - - return nil + return pkg.lint(ruleSet, config, failures) } func detectGoMod(dir string) (rootDir string, ver *goversion.Version, err error) { @@ -163,14 +162,14 @@ func detectGoMod(dir string) (rootDir string, ver *goversion.Version, err error) return "", nil, fmt.Errorf("%q doesn't seem to be part of a Go module", dir) } - mod, err := os.ReadFile(modFileName) + mod, err := os.ReadFile(modFileName) //nolint:gosec // ignore G304: potential file inclusion via variable if err != nil { - return "", nil, fmt.Errorf("failed to read %q, got %v", modFileName, err) + return "", nil, fmt.Errorf("failed to read %q, got %w", modFileName, err) } modAst, err := modfile.ParseLax(modFileName, mod, nil) if err != nil { - return "", nil, fmt.Errorf("failed to parse %q, got %v", modFileName, err) + return "", nil, fmt.Errorf("failed to parse %q, got %w", modFileName, err) } if modAst.Go == nil { @@ -203,36 +202,38 @@ func retrieveModFile(dir string) (string, error) { } // isGenerated reports whether the source file is generated code -// according the rules from https://golang.org/s/generatedcode. +// according to the rules from https://go.dev/s/generatedcode. // This is inherited from the original go lint. func isGenerated(src []byte) bool { sc := bufio.NewScanner(bytes.NewReader(src)) for sc.Scan() { b := sc.Bytes() - if bytes.HasPrefix(b, genHdr) && bytes.HasSuffix(b, genFtr) && len(b) >= len(genHdr)+len(genFtr) { + if bytes.HasPrefix(b, generatedPrefix) && bytes.HasSuffix(b, generatedSuffix) && len(b) >= len(generatedPrefix)+len(generatedSuffix) { return true } } return false } -// addInvalidFileFailure adds a failure for an invalid formatted file +// addInvalidFileFailure adds a failure for an invalid formatted file. func addInvalidFileFailure(filename, errStr string, failures chan Failure) { position := getPositionInvalidFile(filename, errStr) failures <- Failure{ Confidence: 1, Failure: fmt.Sprintf("invalid file %s: %v", filename, errStr), - Category: "validity", + Category: failureCategoryValidity, Position: position, } } -// errPosRegexp matches with an NewFile error message -// i.e. : corrupted.go:10:4: expected '}', found 'EOF -// first group matches the line and the second group, the column +// errPosRegexp matches with a NewFile error message: +// +// corrupted.go:10:4: expected '}', found 'EOF +// +// The first group matches the line, and the second group matches the column. var errPosRegexp = regexp.MustCompile(`.*:(\d*):(\d*):.*$`) -// getPositionInvalidFile gets the position of the error in an invalid file +// getPositionInvalidFile gets the position of the error in an invalid file. func getPositionInvalidFile(filename, s string) FailurePosition { pos := errPosRegexp.FindStringSubmatch(s) if len(pos) < 3 { diff --git a/vendor/github.com/mgechev/revive/lint/name.go b/vendor/github.com/mgechev/revive/lint/name.go index 6ccfb0ef2..23ca06c22 100644 --- a/vendor/github.com/mgechev/revive/lint/name.go +++ b/vendor/github.com/mgechev/revive/lint/name.go @@ -1,133 +1,10 @@ package lint -import ( - "strings" - "unicode" -) +import "github.com/mgechev/revive/internal/rule" // Name returns a different name if it should be different. -func Name(name string, allowlist, blocklist []string) (should string) { - // Fast path for simple cases: "_" and all lowercase. - if name == "_" { - return name - } - allLower := true - for _, r := range name { - if !unicode.IsLower(r) { - allLower = false - break - } - } - if allLower { - return name - } - - // Split camelCase at any lower->upper transition, and split on underscores. - // Check each word for common initialisms. - runes := []rune(name) - w, i := 0, 0 // index of start of word, scan - for i+1 <= len(runes) { - eow := false // whether we hit the end of a word - if i+1 == len(runes) { - eow = true - } else if runes[i+1] == '_' { - // underscore; shift the remainder forward over any run of underscores - eow = true - n := 1 - for i+n+1 < len(runes) && runes[i+n+1] == '_' { - n++ - } - - // Leave at most one underscore if the underscore is between two digits - if i+n+1 < len(runes) && unicode.IsDigit(runes[i]) && unicode.IsDigit(runes[i+n+1]) { - n-- - } - - copy(runes[i+1:], runes[i+n+1:]) - runes = runes[:len(runes)-n] - } else if unicode.IsLower(runes[i]) && !unicode.IsLower(runes[i+1]) { - // lower->non-lower - eow = true - } - i++ - if !eow { - continue - } - - // [w,i) is a word. - word := string(runes[w:i]) - ignoreInitWarnings := map[string]bool{} - for _, i := range allowlist { - ignoreInitWarnings[i] = true - } - - extraInits := map[string]bool{} - for _, i := range blocklist { - extraInits[i] = true - } - - if u := strings.ToUpper(word); (commonInitialisms[u] || extraInits[u]) && !ignoreInitWarnings[u] { - // Keep consistent case, which is lowercase only at the start. - if w == 0 && unicode.IsLower(runes[w]) { - u = strings.ToLower(u) - } - // Keep lowercase s for IDs - if u == "IDS" { - u = "IDs" - } - // All the common initialisms are ASCII, - // so we can replace the bytes exactly. - copy(runes[w:], []rune(u)) - } else if w > 0 && strings.ToLower(word) == word { - // already all lowercase, and not the first word, so uppercase the first character. - runes[w] = unicode.ToUpper(runes[w]) - } - w = i - } - return string(runes) -} - -// commonInitialisms is a set of common initialisms. -// Only add entries that are highly unlikely to be non-initialisms. -// For instance, "ID" is fine (Freudian code is rare), but "AND" is not. -var commonInitialisms = map[string]bool{ - "ACL": true, - "API": true, - "ASCII": true, - "CPU": true, - "CSS": true, - "DNS": true, - "EOF": true, - "GUID": true, - "HTML": true, - "HTTP": true, - "HTTPS": true, - "ID": true, - "IDS": true, - "IP": true, - "JSON": true, - "LHS": true, - "QPS": true, - "RAM": true, - "RHS": true, - "RPC": true, - "SLA": true, - "SMTP": true, - "SQL": true, - "SSH": true, - "TCP": true, - "TLS": true, - "TTL": true, - "UDP": true, - "UI": true, - "UID": true, - "UUID": true, - "URI": true, - "URL": true, - "UTF8": true, - "VM": true, - "XML": true, - "XMPP": true, - "XSRF": true, - "XSS": true, +// +// Deprecated: Do not use this function, it will be removed in the next major release. +func Name(name string, allowlist, blocklist []string) string { + return rule.Name(name, allowlist, blocklist, false) } diff --git a/vendor/github.com/mgechev/revive/lint/package.go b/vendor/github.com/mgechev/revive/lint/package.go index 4a633f35a..eaaf64134 100644 --- a/vendor/github.com/mgechev/revive/lint/package.go +++ b/vendor/github.com/mgechev/revive/lint/package.go @@ -1,6 +1,7 @@ package lint import ( + "errors" "go/ast" "go/importer" "go/token" @@ -8,48 +9,60 @@ import ( "sync" goversion "github.com/hashicorp/go-version" + "golang.org/x/sync/errgroup" + "github.com/mgechev/revive/internal/astutils" "github.com/mgechev/revive/internal/typeparams" ) // Package represents a package in the project. type Package struct { - fset *token.FileSet + fset *token.FileSet + + mu sync.RWMutex files map[string]*File goVersion *goversion.Version - typesPkg *types.Package typesInfo *types.Info - // sortable is the set of types in the package that implement sort.Interface. sortable map[string]bool // main is whether this is a "main" package. main int - sync.RWMutex } var ( trueValue = 1 falseValue = 2 - notSet = 3 - go121 = goversion.Must(goversion.NewVersion("1.21")) - go122 = goversion.Must(goversion.NewVersion("1.22")) + // Go115 is a constant representing the Go version 1.15. + Go115 = goversion.Must(goversion.NewVersion("1.15")) + // Go121 is a constant representing the Go version 1.21. + Go121 = goversion.Must(goversion.NewVersion("1.21")) + // Go122 is a constant representing the Go version 1.22. + Go122 = goversion.Must(goversion.NewVersion("1.22")) + // Go124 is a constant representing the Go version 1.24. + Go124 = goversion.Must(goversion.NewVersion("1.24")) + // Go125 is a constant representing the Go version 1.25. + Go125 = goversion.Must(goversion.NewVersion("1.25")) ) // Files return package's files. func (p *Package) Files() map[string]*File { + p.mu.RLock() + defer p.mu.RUnlock() + return p.files } // IsMain returns if that's the main package. func (p *Package) IsMain() bool { - p.Lock() - defer p.Unlock() + p.mu.Lock() + defer p.mu.Unlock() - if p.main == trueValue { + switch p.main { + case trueValue: return true - } else if p.main == falseValue { + case falseValue: return false } for _, f := range p.files { @@ -62,47 +75,50 @@ func (p *Package) IsMain() bool { return false } -// TypesPkg yields information on this package +// TypesPkg yields information on this package. func (p *Package) TypesPkg() *types.Package { - p.RLock() - defer p.RUnlock() + p.mu.RLock() + defer p.mu.RUnlock() + return p.typesPkg } -// TypesInfo yields type information of this package identifiers +// TypesInfo yields type information of this package identifiers. func (p *Package) TypesInfo() *types.Info { - p.RLock() - defer p.RUnlock() + p.mu.RLock() + defer p.mu.RUnlock() + return p.typesInfo } -// Sortable yields a map of sortable types in this package +// Sortable yields a map of sortable types in this package. func (p *Package) Sortable() map[string]bool { - p.RLock() - defer p.RUnlock() + p.mu.RLock() + defer p.mu.RUnlock() + return p.sortable } // TypeCheck performs type checking for given package. func (p *Package) TypeCheck() error { - p.Lock() - defer p.Unlock() + p.mu.Lock() + defer p.mu.Unlock() - // If type checking has already been performed - // skip it. - if p.typesInfo != nil || p.typesPkg != nil { + alreadyTypeChecked := p.typesInfo != nil || p.typesPkg != nil + if alreadyTypeChecked { return nil } + config := &types.Config{ // By setting a no-op error reporter, the type checker does as much work as possible. Error: func(error) {}, Importer: importer.Default(), } info := &types.Info{ - Types: make(map[ast.Expr]types.TypeAndValue), - Defs: make(map[*ast.Ident]types.Object), - Uses: make(map[*ast.Ident]types.Object), - Scopes: make(map[ast.Node]*types.Scope), + Types: map[ast.Expr]types.TypeAndValue{}, + Defs: map[*ast.Ident]types.Object{}, + Uses: map[*ast.Ident]types.Object{}, + Scopes: map[ast.Node]*types.Scope{}, } var anyFile *File var astFiles []*ast.File @@ -111,6 +127,11 @@ func (p *Package) TypeCheck() error { astFiles = append(astFiles, f.AST) } + if anyFile == nil { + // this is unlikely to happen, but technically guarantees anyFile to not be nil + return errors.New("no ast.File found") + } + typesPkg, err := check(config, anyFile.AST.Name.Name, p.fset, astFiles, info) // Remember the typechecking info, even if config.Check failed, @@ -121,8 +142,8 @@ func (p *Package) TypeCheck() error { return err } -// check function encapsulates the call to go/types.Config.Check method and -// recovers if the called method panics (see issue #59) +// check function encapsulates the call to [go/types.Config.Check] method and +// recovers if the called method panics (see issue #59). func check(config *types.Config, n string, fset *token.FileSet, astFiles []*ast.File, info *types.Info) (p *types.Package, err error) { defer func() { if r := recover(); r != nil { @@ -135,72 +156,82 @@ func check(config *types.Config, n string, fset *token.FileSet, astFiles []*ast. return config.Check(n, fset, astFiles, info) } -// TypeOf returns the type of an expression. +// TypeOf returns the type of expression. func (p *Package) TypeOf(expr ast.Expr) types.Type { + p.mu.RLock() + defer p.mu.RUnlock() + if p.typesInfo == nil { return nil } + return p.typesInfo.TypeOf(expr) } -type walker struct { - nmap map[string]int - has map[string]int -} +type sortableMethodsFlags int -func (w *walker) Visit(n ast.Node) ast.Visitor { - fn, ok := n.(*ast.FuncDecl) - if !ok || fn.Recv == nil || len(fn.Recv.List) == 0 { - return w - } - // TODO(dsymonds): We could check the signature to be more precise. - recv := typeparams.ReceiverType(fn) - if i, ok := w.nmap[fn.Name.Name]; ok { - w.has[recv] |= i - } - return w -} +// flags for sortable interface methods. +const ( + bfLen sortableMethodsFlags = 1 << iota + bfLess + bfSwap +) func (p *Package) scanSortable() { - p.sortable = make(map[string]bool) - - // bitfield for which methods exist on each type. - const ( - bfLen = 1 << iota - bfLess - bfSwap - ) - nmap := map[string]int{"Len": bfLen, "Less": bfLess, "Swap": bfSwap} - has := make(map[string]int) + p.mu.Lock() + defer p.mu.Unlock() + + sortableFlags := map[string]sortableMethodsFlags{} for _, f := range p.files { - ast.Walk(&walker{nmap, has}, f.AST) + for _, decl := range f.AST.Decls { + fn, ok := decl.(*ast.FuncDecl) + isAMethodDeclaration := ok && fn.Recv != nil && len(fn.Recv.List) != 0 + if !isAMethodDeclaration { + continue + } + + recvType := typeparams.ReceiverType(fn) + sortableFlags[recvType] |= getSortableMethodFlagForFunction(fn) + } } - for typ, ms := range has { + + p.sortable = make(map[string]bool, len(sortableFlags)) + for typ, ms := range sortableFlags { if ms == bfLen|bfLess|bfSwap { p.sortable[typ] = true } } } -func (p *Package) lint(rules []Rule, config Config, failures chan Failure) { +func (p *Package) lint(rules []Rule, config Config, failures chan Failure) error { p.scanSortable() - var wg sync.WaitGroup - for _, file := range p.files { - wg.Add(1) - go (func(file *File) { - file.lint(rules, config, failures) - wg.Done() - })(file) + var eg errgroup.Group + for _, file := range p.Files() { + eg.Go(func() error { + return file.lint(rules, config, failures) + }) } - wg.Wait() + + return eg.Wait() } -// IsAtLeastGo121 returns true if the Go version for this package is 1.21 or higher, false otherwise -func (p *Package) IsAtLeastGo121() bool { - return p.goVersion.GreaterThanOrEqual(go121) +// IsAtLeastGoVersion returns true if the Go version for this package is v or higher, false otherwise. +func (p *Package) IsAtLeastGoVersion(v *goversion.Version) bool { + p.mu.RLock() + defer p.mu.RUnlock() + + return p.goVersion.GreaterThanOrEqual(v) } -// IsAtLeastGo122 returns true if the Go version for this package is 1.22 or higher, false otherwise -func (p *Package) IsAtLeastGo122() bool { - return p.goVersion.GreaterThanOrEqual(go122) +func getSortableMethodFlagForFunction(fn *ast.FuncDecl) sortableMethodsFlags { + switch { + case astutils.FuncSignatureIs(fn, "Len", []string{}, []string{"int"}): + return bfLen + case astutils.FuncSignatureIs(fn, "Less", []string{"int", "int"}, []string{"bool"}): + return bfLess + case astutils.FuncSignatureIs(fn, "Swap", []string{"int", "int"}, []string{}): + return bfSwap + default: + return 0 + } } diff --git a/vendor/github.com/mgechev/revive/lint/rule.go b/vendor/github.com/mgechev/revive/lint/rule.go index ccc66691c..e682c1c80 100644 --- a/vendor/github.com/mgechev/revive/lint/rule.go +++ b/vendor/github.com/mgechev/revive/lint/rule.go @@ -11,15 +11,15 @@ type DisabledInterval struct { RuleName string } -// Rule defines an abstract rule interface +// Rule defines an abstract rule interface. type Rule interface { Name() string Apply(*File, Arguments) []Failure } -// AbstractRule defines an abstract rule. -type AbstractRule struct { - Failures []Failure +// ConfigurableRule defines an abstract configurable rule interface. +type ConfigurableRule interface { + Configure(Arguments) error } // ToFailurePosition returns the failure position. diff --git a/vendor/github.com/mgechev/revive/logging/logger.go b/vendor/github.com/mgechev/revive/logging/logger.go new file mode 100644 index 000000000..12fef0160 --- /dev/null +++ b/vendor/github.com/mgechev/revive/logging/logger.go @@ -0,0 +1,50 @@ +// Package logging provides a logger and related methods. +package logging + +import ( + "io" + "log/slog" + "os" + "sync" + "testing" +) + +// GetLogger retrieves an instance of an application logger. +// The log level can be configured via the REVIVE_LOG_LEVEL environment variable. +// If REVIVE_LOG_LEVEL is unset or empty, logging is disabled. +// If it is set to an invalid value, the log level defaults to WARN. +// +//nolint:unparam // err is always nil, but is included in the signature for future extensibility. +func GetLogger() (*slog.Logger, error) { + return getLogger(), nil +} + +var getLogger = sync.OnceValue(initLogger(os.Stderr)) + +func initLogger(out io.Writer) func() *slog.Logger { + return func() *slog.Logger { + logLevel := os.Getenv("REVIVE_LOG_LEVEL") + if logLevel == "" { + return slog.New(slog.DiscardHandler) + } + + leveler := &slog.LevelVar{} + opts := &slog.HandlerOptions{Level: leveler} + + level := slog.LevelWarn + _ = level.UnmarshalText([]byte(logLevel)) // Ignore error and default to WARN if invalid + leveler.Set(level) + logger := slog.New(slog.NewTextHandler(out, opts)) + + logger.Info("Logger initialized", "logLevel", logLevel) + + return logger + } +} + +// InitForTesting initializes the logger singleton cache for testing purposes. +// This function should only be called in tests. +func InitForTesting(tb testing.TB, out io.Writer) { + tb.Helper() + getLogger = sync.OnceValue(initLogger(out)) +} diff --git a/vendor/github.com/mgechev/revive/rule/add_constant.go b/vendor/github.com/mgechev/revive/rule/add_constant.go index 399382c8b..d0770a104 100644 --- a/vendor/github.com/mgechev/revive/rule/add_constant.go +++ b/vendor/github.com/mgechev/revive/rule/add_constant.go @@ -1,12 +1,12 @@ package rule import ( + "errors" "fmt" "go/ast" "regexp" "strconv" "strings" - "sync" "github.com/mgechev/revive/lint" ) @@ -25,25 +25,20 @@ func newAllowList() allowList { } func (wl allowList) add(kind, list string) { - elems := strings.Split(list, ",") - for _, e := range elems { + for e := range strings.SplitSeq(list, ",") { wl[kind][e] = true } } -// AddConstantRule lints unused params in functions. +// AddConstantRule suggests using constants instead of magic numbers and string literals. type AddConstantRule struct { allowList allowList ignoreFunctions []*regexp.Regexp strLitLimit int - - configureOnce sync.Once } // Apply applies the rule to given file. -func (r *AddConstantRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(arguments) }) - +func (r *AddConstantRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure onFailure := func(failure lint.Failure) { @@ -52,11 +47,11 @@ func (r *AddConstantRule) Apply(file *lint.File, arguments lint.Arguments) []lin w := &lintAddConstantRule{ onFailure: onFailure, - strLits: make(map[string]int), + strLits: map[string]int{}, strLitLimit: r.strLitLimit, allowList: r.allowList, ignoreFunctions: r.ignoreFunctions, - structTags: make(map[*ast.BasicLit]struct{}), + structTags: map[*ast.BasicLit]struct{}{}, } ast.Walk(w, file.AST) @@ -175,7 +170,7 @@ func (w *lintAddConstantRule) checkStrLit(n *ast.BasicLit) { w.onFailure(lint.Failure{ Confidence: 1, Node: n, - Category: "style", + Category: lint.FailureCategoryStyle, Failure: fmt.Sprintf("string literal %s appears, at least, %d times, create a named constant for it", n.Value, w.strLits[n.Value]), }) w.strLits[n.Value] = -1 // mark it to avoid failing again on the same literal @@ -191,7 +186,7 @@ func (w *lintAddConstantRule) checkNumLit(kind string, n *ast.BasicLit) { w.onFailure(lint.Failure{ Confidence: 1, Node: n, - Category: "style", + Category: lint.FailureCategoryStyle, Failure: fmt.Sprintf("avoid magic numbers like '%s', create a named constant for it", n.Value), }) } @@ -201,67 +196,71 @@ func (w *lintAddConstantRule) isStructTag(n *ast.BasicLit) bool { return ok } -func (r *AddConstantRule) configure(arguments lint.Arguments) { - if r.allowList == nil { - r.strLitLimit = defaultStrLitLimit - r.allowList = newAllowList() - if len(arguments) > 0 { - args, ok := arguments[0].(map[string]any) +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *AddConstantRule) Configure(arguments lint.Arguments) error { + r.strLitLimit = defaultStrLitLimit + r.allowList = newAllowList() + if len(arguments) == 0 { + return nil + } + args, ok := arguments[0].(map[string]any) + if !ok { + return fmt.Errorf("invalid argument to the add-constant rule, expecting a k,v map. Got %T", arguments[0]) + } + for k, v := range args { + kind := "" + switch { + case isRuleOption(k, "allowFloats"): + kind = kindFLOAT + fallthrough + case isRuleOption(k, "allowInts"): + if kind == "" { + kind = kindINT + } + fallthrough + case isRuleOption(k, "allowStrs"): + if kind == "" { + kind = kindSTRING + } + list, ok := v.(string) + if !ok { + return fmt.Errorf("invalid argument to the add-constant rule, string expected. Got '%v' (%T)", v, v) + } + r.allowList.add(kind, list) + case isRuleOption(k, "maxLitCount"): + sl, ok := v.(string) + if !ok { + return fmt.Errorf("invalid argument to the add-constant rule, expecting string representation of an integer. Got '%v' (%T)", v, v) + } + + limit, err := strconv.Atoi(sl) + if err != nil { + return fmt.Errorf("invalid argument to the add-constant rule, expecting string representation of an integer. Got '%v'", v) + } + r.strLitLimit = limit + case isRuleOption(k, "ignoreFuncs"): + excludes, ok := v.(string) if !ok { - panic(fmt.Sprintf("Invalid argument to the add-constant rule. Expecting a k,v map, got %T", arguments[0])) + return fmt.Errorf("invalid argument to the ignoreFuncs parameter of add-constant rule, string expected. Got '%v' (%T)", v, v) } - for k, v := range args { - kind := "" - switch k { - case "allowFloats": - kind = kindFLOAT - fallthrough - case "allowInts": - if kind == "" { - kind = kindINT - } - fallthrough - case "allowStrs": - if kind == "" { - kind = kindSTRING - } - list, ok := v.(string) - if !ok { - panic(fmt.Sprintf("Invalid argument to the add-constant rule, string expected. Got '%v' (%T)", v, v)) - } - r.allowList.add(kind, list) - case "maxLitCount": - sl, ok := v.(string) - if !ok { - panic(fmt.Sprintf("Invalid argument to the add-constant rule, expecting string representation of an integer. Got '%v' (%T)", v, v)) - } - - limit, err := strconv.Atoi(sl) - if err != nil { - panic(fmt.Sprintf("Invalid argument to the add-constant rule, expecting string representation of an integer. Got '%v'", v)) - } - r.strLitLimit = limit - case "ignoreFuncs": - excludes, ok := v.(string) - if !ok { - panic(fmt.Sprintf("Invalid argument to the ignoreFuncs parameter of add-constant rule, string expected. Got '%v' (%T)", v, v)) - } - - for _, exclude := range strings.Split(excludes, ",") { - exclude = strings.Trim(exclude, " ") - if exclude == "" { - panic("Invalid argument to the ignoreFuncs parameter of add-constant rule, expected regular expression must not be empty.") - } - - exp, err := regexp.Compile(exclude) - if err != nil { - panic(fmt.Sprintf("Invalid argument to the ignoreFuncs parameter of add-constant rule: regexp %q does not compile: %v", exclude, err)) - } - - r.ignoreFunctions = append(r.ignoreFunctions, exp) - } + + for exclude := range strings.SplitSeq(excludes, ",") { + exclude = strings.Trim(exclude, " ") + if exclude == "" { + return errors.New("invalid argument to the ignoreFuncs parameter of add-constant rule, expected regular expression must not be empty") } + + exp, err := regexp.Compile(exclude) + if err != nil { + return fmt.Errorf("invalid argument to the ignoreFuncs parameter of add-constant rule: regexp %q does not compile: %w", exclude, err) + } + + r.ignoreFunctions = append(r.ignoreFunctions, exp) } } } + + return nil } diff --git a/vendor/github.com/mgechev/revive/rule/argument_limit.go b/vendor/github.com/mgechev/revive/rule/argument_limit.go index b4d56de0e..7fd6a382d 100644 --- a/vendor/github.com/mgechev/revive/rule/argument_limit.go +++ b/vendor/github.com/mgechev/revive/rule/argument_limit.go @@ -1,84 +1,67 @@ package rule import ( + "errors" "fmt" "go/ast" - "sync" "github.com/mgechev/revive/lint" ) -// ArgumentsLimitRule lints given else constructs. +// ArgumentsLimitRule lints the number of arguments a function can receive. type ArgumentsLimitRule struct { max int - - configureOnce sync.Once } const defaultArgumentsLimit = 8 -func (r *ArgumentsLimitRule) configure(arguments lint.Arguments) { +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *ArgumentsLimitRule) Configure(arguments lint.Arguments) error { if len(arguments) < 1 { r.max = defaultArgumentsLimit - return + return nil } maxArguments, ok := arguments[0].(int64) // Alt. non panicking version if !ok { - panic(`invalid value passed as argument number to the "argument-limit" rule`) + return errors.New(`invalid value passed as argument number to the "argument-limit" rule`) } r.max = int(maxArguments) + return nil } // Apply applies the rule to given file. -func (r *ArgumentsLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(arguments) }) - +func (r *ArgumentsLimitRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure - onFailure := func(failure lint.Failure) { - failures = append(failures, failure) - } - - walker := lintArgsNum{ - max: r.max, - onFailure: onFailure, - } - - ast.Walk(walker, file.AST) - - return failures -} - -// Name returns the rule name. -func (*ArgumentsLimitRule) Name() string { - return "argument-limit" -} -type lintArgsNum struct { - max int - onFailure func(lint.Failure) -} + for _, decl := range file.AST.Decls { + funcDecl, ok := decl.(*ast.FuncDecl) + if !ok { + continue + } -func (w lintArgsNum) Visit(n ast.Node) ast.Visitor { - node, ok := n.(*ast.FuncDecl) - if !ok { - return w - } + numParams := 0 + for _, l := range funcDecl.Type.Params.List { + numParams += len(l.Names) + } - num := 0 - for _, l := range node.Type.Params.List { - for range l.Names { - num++ + if numParams <= r.max { + continue } - } - if num > w.max { - w.onFailure(lint.Failure{ + failures = append(failures, lint.Failure{ Confidence: 1, - Failure: fmt.Sprintf("maximum number of arguments per function exceeded; max %d but got %d", w.max, num), - Node: node.Type, + Failure: fmt.Sprintf("maximum number of arguments per function exceeded; max %d but got %d", r.max, numParams), + Node: funcDecl.Type, }) } - return nil // skip visiting the body of the function + return failures +} + +// Name returns the rule name. +func (*ArgumentsLimitRule) Name() string { + return "argument-limit" } diff --git a/vendor/github.com/mgechev/revive/rule/atomic.go b/vendor/github.com/mgechev/revive/rule/atomic.go index 287b28c21..83a7daeae 100644 --- a/vendor/github.com/mgechev/revive/rule/atomic.go +++ b/vendor/github.com/mgechev/revive/rule/atomic.go @@ -5,10 +5,11 @@ import ( "go/token" "go/types" + "github.com/mgechev/revive/internal/astutils" "github.com/mgechev/revive/lint" ) -// AtomicRule lints given else constructs. +// AtomicRule lints usages of the `sync/atomic` package. type AtomicRule struct{} // Apply applies the rule to given file. @@ -76,9 +77,9 @@ func (w atomic) Visit(node ast.Node) ast.Visitor { broken := false if uarg, ok := arg.(*ast.UnaryExpr); ok && uarg.Op == token.AND { - broken = gofmt(left) == gofmt(uarg.X) + broken = astutils.GoFmt(left) == astutils.GoFmt(uarg.X) } else if star, ok := left.(*ast.StarExpr); ok { - broken = gofmt(star.X) == gofmt(arg) + broken = astutils.GoFmt(star.X) == astutils.GoFmt(arg) } if broken { diff --git a/vendor/github.com/mgechev/revive/rule/banned_characters.go b/vendor/github.com/mgechev/revive/rule/banned_characters.go index 926b32c21..b113c8db9 100644 --- a/vendor/github.com/mgechev/revive/rule/banned_characters.go +++ b/vendor/github.com/mgechev/revive/rule/banned_characters.go @@ -4,7 +4,6 @@ import ( "fmt" "go/ast" "strings" - "sync" "github.com/mgechev/revive/lint" ) @@ -12,23 +11,27 @@ import ( // BannedCharsRule checks if a file contains banned characters. type BannedCharsRule struct { bannedCharList []string - - configureOnce sync.Once } const bannedCharsRuleName = "banned-characters" -func (r *BannedCharsRule) configure(arguments lint.Arguments) { +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *BannedCharsRule) Configure(arguments lint.Arguments) error { if len(arguments) > 0 { - checkNumberOfArguments(1, arguments, bannedCharsRuleName) - r.bannedCharList = r.getBannedCharsList(arguments) + list, err := r.getBannedCharsList(arguments) + if err != nil { + return err + } + + r.bannedCharList = list } + return nil } // Apply applied the rule to the given file. -func (r *BannedCharsRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(arguments) }) - +func (r *BannedCharsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure onFailure := func(failure lint.Failure) { failures = append(failures, failure) @@ -43,23 +46,23 @@ func (r *BannedCharsRule) Apply(file *lint.File, arguments lint.Arguments) []lin return failures } -// Name returns the rule name +// Name returns the rule name. func (*BannedCharsRule) Name() string { return bannedCharsRuleName } -// getBannedCharsList converts arguments into the banned characters list -func (r *BannedCharsRule) getBannedCharsList(args lint.Arguments) []string { +// getBannedCharsList converts arguments into the banned characters list. +func (r *BannedCharsRule) getBannedCharsList(args lint.Arguments) ([]string, error) { var bannedChars []string for _, char := range args { charStr, ok := char.(string) if !ok { - panic(fmt.Sprintf("Invalid argument for the %s rule: expecting a string, got %T", r.Name(), char)) + return nil, fmt.Errorf("invalid argument for the %s rule: expecting a string, got %T", r.Name(), char) } bannedChars = append(bannedChars, charStr) } - return bannedChars + return bannedChars, nil } type lintBannedCharsRule struct { @@ -67,7 +70,7 @@ type lintBannedCharsRule struct { onFailure func(lint.Failure) } -// Visit checks for each node if an identifier contains banned characters +// Visit checks for each node if an identifier contains banned characters. func (w lintBannedCharsRule) Visit(node ast.Node) ast.Visitor { n, ok := node.(*ast.Ident) if !ok { diff --git a/vendor/github.com/mgechev/revive/rule/bare_return.go b/vendor/github.com/mgechev/revive/rule/bare_return.go index 147fa84db..f2c907405 100644 --- a/vendor/github.com/mgechev/revive/rule/bare_return.go +++ b/vendor/github.com/mgechev/revive/rule/bare_return.go @@ -6,7 +6,7 @@ import ( "github.com/mgechev/revive/lint" ) -// BareReturnRule lints given else constructs. +// BareReturnRule lints bare returns. type BareReturnRule struct{} // Apply applies the rule to given file. @@ -42,14 +42,14 @@ func (w lintBareReturnRule) Visit(node ast.Node) ast.Visitor { return w } -// checkFunc will verify if the given function has named result and bare returns +// checkFunc will verify if the given function has named result and bare returns. func (w lintBareReturnRule) checkFunc(results *ast.FieldList, body *ast.BlockStmt) { hasNamedResults := results != nil && len(results.List) > 0 && results.List[0].Names != nil if !hasNamedResults || body == nil { return // nothing to do } - brf := bareReturnFinder{w.onFailure} + brf := bareReturnFinder(w) ast.Walk(brf, body) } @@ -60,8 +60,8 @@ type bareReturnFinder struct { func (w bareReturnFinder) Visit(node ast.Node) ast.Visitor { _, ok := node.(*ast.FuncLit) if ok { - // skip analysing function literals - // they will be analysed by the lintBareReturnRule.Visit method + // skip analyzing function literals + // they will be analyzed by the lintBareReturnRule.Visit method return nil } diff --git a/vendor/github.com/mgechev/revive/rule/blank_imports.go b/vendor/github.com/mgechev/revive/rule/blank_imports.go index 0ddb4aad2..b3f7a3cdc 100644 --- a/vendor/github.com/mgechev/revive/rule/blank_imports.go +++ b/vendor/github.com/mgechev/revive/rule/blank_imports.go @@ -7,7 +7,7 @@ import ( "github.com/mgechev/revive/lint" ) -// BlankImportsRule lints given else constructs. +// BlankImportsRule lints blank imports. type BlankImportsRule struct{} // Name returns the rule name. @@ -23,7 +23,6 @@ func (r *BlankImportsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failu const ( message = "a blank import should be only in a main or test package, or have a comment justifying it" - category = "imports" embedImportPath = `"embed"` ) @@ -55,7 +54,7 @@ func (r *BlankImportsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failu // This is the first blank import of a group. if imp.Doc == nil && imp.Comment == nil { - failures = append(failures, lint.Failure{Failure: message, Category: category, Node: imp, Confidence: 1}) + failures = append(failures, lint.Failure{Failure: message, Category: lint.FailureCategoryImports, Node: imp, Confidence: 1}) } } @@ -73,3 +72,7 @@ func (*BlankImportsRule) fileHasValidEmbedComment(fileAst *ast.File) bool { return false } + +// isBlank returns whether id is the blank identifier "_". +// If id == nil, the answer is false. +func isBlank(id *ast.Ident) bool { return id != nil && id.Name == "_" } diff --git a/vendor/github.com/mgechev/revive/rule/bool_literal_in_expr.go b/vendor/github.com/mgechev/revive/rule/bool_literal_in_expr.go index 71551e55a..f6c8cbc61 100644 --- a/vendor/github.com/mgechev/revive/rule/bool_literal_in_expr.go +++ b/vendor/github.com/mgechev/revive/rule/bool_literal_in_expr.go @@ -7,7 +7,7 @@ import ( "github.com/mgechev/revive/lint" ) -// BoolLiteralRule warns when logic expressions contains Boolean literals. +// BoolLiteralRule warns when logic expressions contain boolean literals. type BoolLiteralRule struct{} // Apply applies the rule to given file. @@ -36,8 +36,7 @@ type lintBoolLiteral struct { } func (w *lintBoolLiteral) Visit(node ast.Node) ast.Visitor { - switch n := node.(type) { - case *ast.BinaryExpr: + if n, ok := node.(*ast.BinaryExpr); ok { if !isBoolOp(n.Op) { return w } @@ -53,16 +52,16 @@ func (w *lintBoolLiteral) Visit(node ast.Node) ast.Visitor { isConstant := (n.Op == token.LAND && lexeme == "false") || (n.Op == token.LOR && lexeme == "true") if isConstant { - w.addFailure(n, "Boolean expression seems to always evaluate to "+lexeme, "logic") + w.addFailure(n, "Boolean expression seems to always evaluate to "+lexeme, lint.FailureCategoryLogic) } else { - w.addFailure(n, "omit Boolean literal in expression", "style") + w.addFailure(n, "omit Boolean literal in expression", lint.FailureCategoryStyle) } } return w } -func (w lintBoolLiteral) addFailure(node ast.Node, msg, cat string) { +func (w *lintBoolLiteral) addFailure(node ast.Node, msg string, cat lint.FailureCategory) { w.onFailure(lint.Failure{ Confidence: 1, Node: node, @@ -70,3 +69,23 @@ func (w lintBoolLiteral) addFailure(node ast.Node, msg, cat string) { Failure: msg, }) } + +// isBoolOp returns true if the given token corresponds to a bool operator. +func isBoolOp(t token.Token) bool { + switch t { + case token.LAND, token.LOR, token.EQL, token.NEQ: + return true + } + + return false +} + +func isExprABooleanLit(n ast.Node) (lexeme string, ok bool) { + oper, ok := n.(*ast.Ident) + + if !ok { + return "", false + } + + return oper.Name, oper.Name == "true" || oper.Name == "false" +} diff --git a/vendor/github.com/mgechev/revive/rule/call_to_gc.go b/vendor/github.com/mgechev/revive/rule/call_to_gc.go index 9c68380a4..b0bc8bbd4 100644 --- a/vendor/github.com/mgechev/revive/rule/call_to_gc.go +++ b/vendor/github.com/mgechev/revive/rule/call_to_gc.go @@ -3,6 +3,7 @@ package rule import ( "go/ast" + "github.com/mgechev/revive/internal/astutils" "github.com/mgechev/revive/lint" ) @@ -16,11 +17,7 @@ func (*CallToGCRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { failures = append(failures, failure) } - gcTriggeringFunctions := map[string]map[string]bool{ - "runtime": {"GC": true}, - } - - w := lintCallToGC{onFailure, gcTriggeringFunctions} + w := lintCallToGC{onFailure} ast.Walk(w, file.AST) return failures @@ -32,37 +29,23 @@ func (*CallToGCRule) Name() string { } type lintCallToGC struct { - onFailure func(lint.Failure) - gcTriggeringFunctions map[string]map[string]bool + onFailure func(lint.Failure) } func (w lintCallToGC) Visit(node ast.Node) ast.Visitor { ce, ok := node.(*ast.CallExpr) if !ok { - return w // nothing to do, the node is not a call - } - - fc, ok := ce.Fun.(*ast.SelectorExpr) - if !ok { - return nil // nothing to do, the call is not of the form pkg.func(...) - } - - id, ok := fc.X.(*ast.Ident) - - if !ok { - return nil // in case X is not an id (it should be!) + return w // nothing to do, the node is not a function call } - fn := fc.Sel.Name - pkg := id.Name - if !w.gcTriggeringFunctions[pkg][fn] { - return nil // it isn't a call to a GC triggering function + if !astutils.IsPkgDotName(ce.Fun, "runtime", "GC") { + return nil // nothing to do, the call is not a call to the Garbage Collector } w.onFailure(lint.Failure{ Confidence: 1, Node: node, - Category: "bad practice", + Category: lint.FailureCategoryBadPractice, Failure: "explicit call to the garbage collector", }) diff --git a/vendor/github.com/mgechev/revive/rule/cognitive_complexity.go b/vendor/github.com/mgechev/revive/rule/cognitive_complexity.go index ecde3882e..d9937713e 100644 --- a/vendor/github.com/mgechev/revive/rule/cognitive_complexity.go +++ b/vendor/github.com/mgechev/revive/rule/cognitive_complexity.go @@ -4,39 +4,39 @@ import ( "fmt" "go/ast" "go/token" - "sync" - "github.com/mgechev/revive/lint" "golang.org/x/tools/go/ast/astutil" + + "github.com/mgechev/revive/lint" ) -// CognitiveComplexityRule lints given else constructs. +// CognitiveComplexityRule sets restriction for maximum cognitive complexity. type CognitiveComplexityRule struct { maxComplexity int - - configureOnce sync.Once } const defaultMaxCognitiveComplexity = 7 -func (r *CognitiveComplexityRule) configure(arguments lint.Arguments) { +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *CognitiveComplexityRule) Configure(arguments lint.Arguments) error { if len(arguments) < 1 { r.maxComplexity = defaultMaxCognitiveComplexity - return + return nil } complexity, ok := arguments[0].(int64) if !ok { - panic(fmt.Sprintf("invalid argument type for cognitive-complexity, expected int64, got %T", arguments[0])) + return fmt.Errorf("invalid argument type for cognitive-complexity, expected int64, got %T", arguments[0]) } r.maxComplexity = int(complexity) + return nil } // Apply applies the rule to given file. -func (r *CognitiveComplexityRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(arguments) }) - +func (r *CognitiveComplexityRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure linter := cognitiveComplexityLinter{ @@ -67,12 +67,14 @@ func (w cognitiveComplexityLinter) lintCognitiveComplexity() { f := w.file for _, decl := range f.AST.Decls { if fn, ok := decl.(*ast.FuncDecl); ok && fn.Body != nil { - v := cognitiveComplexityVisitor{} + v := cognitiveComplexityVisitor{ + name: fn.Name, + } c := v.subTreeComplexity(fn.Body) if c > w.maxComplexity { w.onFailure(lint.Failure{ Confidence: 1, - Category: "maintenance", + Category: lint.FailureCategoryMaintenance, Failure: fmt.Sprintf("function %s has cognitive complexity %d (> max enabled %d)", funcName(fn), c, w.maxComplexity), Node: fn, }) @@ -82,22 +84,22 @@ func (w cognitiveComplexityLinter) lintCognitiveComplexity() { } type cognitiveComplexityVisitor struct { + name *ast.Ident complexity int nestingLevel int } // subTreeComplexity calculates the cognitive complexity of an AST-subtree. -func (v cognitiveComplexityVisitor) subTreeComplexity(n ast.Node) int { - ast.Walk(&v, n) +func (v *cognitiveComplexityVisitor) subTreeComplexity(n ast.Node) int { + ast.Walk(v, n) return v.complexity } -// Visit implements the ast.Visitor interface. +// Visit implements the [ast.Visitor] interface. func (v *cognitiveComplexityVisitor) Visit(n ast.Node) ast.Visitor { switch n := n.(type) { case *ast.IfStmt: - targets := []ast.Node{n.Cond, n.Body, n.Else} - v.walk(1, targets...) + v.walkIfElse(n) return nil case *ast.ForStmt: targets := []ast.Node{n.Cond, n.Body} @@ -120,13 +122,20 @@ func (v *cognitiveComplexityVisitor) Visit(n ast.Node) ast.Visitor { return nil case *ast.BinaryExpr: v.complexity += v.binExpComplexity(n) - return nil // skip visiting binexp sub-tree (already visited by binExpComplexity) + return nil // skip visiting binexp subtree (already visited by binExpComplexity) case *ast.BranchStmt: if n.Label != nil { v.complexity++ } + case *ast.CallExpr: + if ident, ok := n.Fun.(*ast.Ident); ok { + if ident.Obj == v.name.Obj && ident.Name == v.name.Name { + // called by same function directly (direct recursion) + v.complexity++ + return nil + } + } } - // TODO handle (at least) direct recursion return v } @@ -147,7 +156,30 @@ func (v *cognitiveComplexityVisitor) walk(complexityIncrement int, targets ...as v.nestingLevel = nesting } -func (cognitiveComplexityVisitor) binExpComplexity(n *ast.BinaryExpr) int { +func (v *cognitiveComplexityVisitor) walkIfElse(n *ast.IfStmt) { + var w func(n *ast.IfStmt) + w = func(n *ast.IfStmt) { + ast.Walk(v, n.Cond) + ast.Walk(v, n.Body) + if n.Else != nil { + if elif, ok := n.Else.(*ast.IfStmt); ok { + v.complexity++ + w(elif) + } else { + ast.Walk(v, n.Else) + } + } + } + + // Nesting level is incremented in 'if' and 'else' blocks, but only the first 'if' in an 'if-else-if' chain sees its + // complexity increased by the nesting level. + v.complexity += 1 + v.nestingLevel + v.nestingLevel++ + w(n) + v.nestingLevel-- +} + +func (*cognitiveComplexityVisitor) binExpComplexity(n *ast.BinaryExpr) int { calculator := binExprComplexityCalculator{opsStack: []token.Token{}} astutil.Apply(n, calculator.pre, calculator.post) diff --git a/vendor/github.com/mgechev/revive/rule/comment_spacings.go b/vendor/github.com/mgechev/revive/rule/comment_spacings.go index 7bdc0e71d..d28bce04f 100644 --- a/vendor/github.com/mgechev/revive/rule/comment_spacings.go +++ b/vendor/github.com/mgechev/revive/rule/comment_spacings.go @@ -3,34 +3,33 @@ package rule import ( "fmt" "strings" - "sync" "github.com/mgechev/revive/lint" ) -// CommentSpacingsRule check the whether there is a space between -// the comment symbol( // ) and the start of the comment text +// CommentSpacingsRule checks whether there is a space between +// the comment symbol // and the start of the comment text. type CommentSpacingsRule struct { allowList []string - - configureOnce sync.Once } -func (r *CommentSpacingsRule) configure(arguments lint.Arguments) { +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *CommentSpacingsRule) Configure(arguments lint.Arguments) error { r.allowList = []string{} for _, arg := range arguments { allow, ok := arg.(string) // Alt. non panicking version if !ok { - panic(fmt.Sprintf("invalid argument %v for %s; expected string but got %T", arg, r.Name(), arg)) + return fmt.Errorf("invalid argument %v for %s; expected string but got %T", arg, r.Name(), arg) } r.allowList = append(r.allowList, `//`+allow) } + return nil } // Apply the rule. -func (r *CommentSpacingsRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(args) }) - +func (r *CommentSpacingsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure for _, cg := range file.AST.Comments { @@ -58,7 +57,7 @@ func (r *CommentSpacingsRule) Apply(file *lint.File, args lint.Arguments) []lint failures = append(failures, lint.Failure{ Node: comment, Confidence: 1, - Category: "style", + Category: lint.FailureCategoryStyle, Failure: "no space between comment delimiter and comment text", }) } diff --git a/vendor/github.com/mgechev/revive/rule/comments_density.go b/vendor/github.com/mgechev/revive/rule/comments_density.go index f2382b1f0..e83c20add 100644 --- a/vendor/github.com/mgechev/revive/rule/comments_density.go +++ b/vendor/github.com/mgechev/revive/rule/comments_density.go @@ -4,37 +4,36 @@ import ( "fmt" "go/ast" "strings" - "sync" "github.com/mgechev/revive/lint" ) -// CommentsDensityRule lints given else constructs. +// CommentsDensityRule enforces a minimum comment / code relation. type CommentsDensityRule struct { minimumCommentsDensity int64 - - configureOnce sync.Once } const defaultMinimumCommentsPercentage = 0 -func (r *CommentsDensityRule) configure(arguments lint.Arguments) { +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *CommentsDensityRule) Configure(arguments lint.Arguments) error { if len(arguments) < 1 { r.minimumCommentsDensity = defaultMinimumCommentsPercentage - return + return nil } var ok bool r.minimumCommentsDensity, ok = arguments[0].(int64) if !ok { - panic(fmt.Sprintf("invalid argument for %q rule: argument should be an int, got %T", r.Name(), arguments[0])) + return fmt.Errorf("invalid argument for %q rule: argument should be an int, got %T", r.Name(), arguments[0]) } + return nil } // Apply applies the rule to given file. -func (r *CommentsDensityRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(arguments) }) - +func (r *CommentsDensityRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { commentsLines := countDocLines(file.AST.Comments) statementsCount := countStatements(file.AST) density := (float32(commentsLines) / float32(statementsCount+commentsLines)) * 100 diff --git a/vendor/github.com/mgechev/revive/rule/confusing_naming.go b/vendor/github.com/mgechev/revive/rule/confusing_naming.go index 32f6dd803..ef78b60a7 100644 --- a/vendor/github.com/mgechev/revive/rule/confusing_naming.go +++ b/vendor/github.com/mgechev/revive/rule/confusing_naming.go @@ -6,6 +6,7 @@ import ( "strings" "sync" + "github.com/mgechev/revive/internal/astutils" "github.com/mgechev/revive/lint" ) @@ -35,7 +36,7 @@ func (ps *packages) methodNames(lp *lint.Package) pkgMethods { } } - pkgm := pkgMethods{pkg: lp, methods: make(map[string]map[string]*referenceMethod), mu: &sync.Mutex{}} + pkgm := pkgMethods{pkg: lp, methods: map[string]map[string]*referenceMethod{}, mu: &sync.Mutex{}} ps.pkgs = append(ps.pkgs, pkgm) return pkgm @@ -43,7 +44,7 @@ func (ps *packages) methodNames(lp *lint.Package) pkgMethods { var allPkgs = packages{pkgs: make([]pkgMethods, 1)} -// ConfusingNamingRule lints method names that differ only by capitalization +// ConfusingNamingRule lints method names that differ only by capitalization. type ConfusingNamingRule struct{} // Apply applies the rule to given file. @@ -69,7 +70,8 @@ func (*ConfusingNamingRule) Name() string { return "confusing-naming" } -// checkMethodName checks if a given method/function name is similar (just case differences) to other method/function of the same struct/file. +// checkMethodName checks if a given method/function name is similar (just case differences) to other method/function +// of the same struct/file. func checkMethodName(holder string, id *ast.Ident, w *lintConfusingNames) { if id.Name == "init" && holder == defaultStructName { // ignore init functions @@ -102,7 +104,7 @@ func checkMethodName(holder string, id *ast.Ident, w *lintConfusingNames) { Failure: fmt.Sprintf("Method '%s' differs only by capitalization to %s '%s' in %s", id.Name, kind, refMethod.id.Name, fileName), Confidence: 1, Node: id, - Category: "naming", + Category: lint.FailureCategoryNaming, }) return @@ -112,9 +114,6 @@ func checkMethodName(holder string, id *ast.Ident, w *lintConfusingNames) { } // update the block list - if pkgm.methods[holder] == nil { - println("no entry for '", holder, "'") - } pkgm.methods[holder][name] = &referenceMethod{fileName: w.fileName, id: id} } @@ -126,7 +125,7 @@ type lintConfusingNames struct { const defaultStructName = "_" // used to map functions -// getStructName of a function receiver. Defaults to defaultStructName +// getStructName of a function receiver. Defaults to defaultStructName. func getStructName(r *ast.FieldList) string { result := defaultStructName @@ -159,8 +158,7 @@ func extractFromStarExpr(expr *ast.StarExpr) string { } func extractFromIndexExpr(expr *ast.IndexExpr) string { - switch v := expr.X.(type) { - case *ast.Ident: + if v, ok := expr.X.(*ast.Ident); ok { return v.Name } return defaultStructName @@ -170,13 +168,18 @@ func checkStructFields(fields *ast.FieldList, structName string, w *lintConfusin bl := make(map[string]bool, len(fields.List)) for _, f := range fields.List { for _, id := range f.Names { + // Skip blank identifiers + if id.Name == "_" { + continue + } + normName := strings.ToUpper(id.Name) if bl[normName] { w.onFailure(lint.Failure{ Failure: fmt.Sprintf("Field '%s' differs only by capitalization to other field in the struct type %s", id.Name, structName), Confidence: 1, Node: id, - Category: "naming", + Category: lint.FailureCategoryNaming, }) } else { bl[normName] = true @@ -191,7 +194,7 @@ func (w *lintConfusingNames) Visit(n ast.Node) ast.Visitor { // Exclude naming warnings for functions that are exported to C but // not exported in the Go API. // See https://github.com/golang/lint/issues/144. - if ast.IsExported(v.Name.Name) || !isCgoExported(v) { + if ast.IsExported(v.Name.Name) || !astutils.IsCgoExported(v) { checkMethodName(getStructName(v.Recv), v.Name, w) } case *ast.TypeSpec: diff --git a/vendor/github.com/mgechev/revive/rule/confusing_results.go b/vendor/github.com/mgechev/revive/rule/confusing_results.go index 1b79ada9c..559c357f9 100644 --- a/vendor/github.com/mgechev/revive/rule/confusing_results.go +++ b/vendor/github.com/mgechev/revive/rule/confusing_results.go @@ -3,64 +3,53 @@ package rule import ( "go/ast" + "github.com/mgechev/revive/internal/astutils" "github.com/mgechev/revive/lint" ) -// ConfusingResultsRule lints given function declarations +// ConfusingResultsRule lints given function declarations. type ConfusingResultsRule struct{} // Apply applies the rule to given file. func (*ConfusingResultsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure - fileAst := file.AST - walker := lintConfusingResults{ - onFailure: func(failure lint.Failure) { - failures = append(failures, failure) - }, - } - - ast.Walk(walker, fileAst) + for _, decl := range file.AST.Decls { + funcDecl, ok := decl.(*ast.FuncDecl) - return failures -} + isFunctionWithMoreThanOneResult := ok && funcDecl.Type.Results != nil && len(funcDecl.Type.Results.List) > 1 + if !isFunctionWithMoreThanOneResult { + continue + } -// Name returns the rule name. -func (*ConfusingResultsRule) Name() string { - return "confusing-results" -} + resultsAreNamed := len(funcDecl.Type.Results.List[0].Names) > 0 + if resultsAreNamed { + continue + } -type lintConfusingResults struct { - onFailure func(lint.Failure) -} + lastType := "" + for _, result := range funcDecl.Type.Results.List { + resultTypeName := astutils.GoFmt(result.Type) -func (w lintConfusingResults) Visit(n ast.Node) ast.Visitor { - fn, ok := n.(*ast.FuncDecl) - if !ok || fn.Type.Results == nil || len(fn.Type.Results.List) < 2 { - return w - } - lastType := "" - for _, result := range fn.Type.Results.List { - if len(result.Names) > 0 { - return w - } + if resultTypeName == lastType { + failures = append(failures, lint.Failure{ + Node: result, + Confidence: 1, + Category: lint.FailureCategoryNaming, + Failure: "unnamed results of the same type may be confusing, consider using named results", + }) - t, ok := result.Type.(*ast.Ident) - if !ok { - return w - } + break + } - if t.Name == lastType { - w.onFailure(lint.Failure{ - Node: n, - Confidence: 1, - Category: "naming", - Failure: "unnamed results of the same type may be confusing, consider using named results", - }) - break + lastType = resultTypeName } - lastType = t.Name } - return w + return failures +} + +// Name returns the rule name. +func (*ConfusingResultsRule) Name() string { + return "confusing-results" } diff --git a/vendor/github.com/mgechev/revive/rule/constant_logical_expr.go b/vendor/github.com/mgechev/revive/rule/constant_logical_expr.go index 9e34d3d16..9bee07e02 100644 --- a/vendor/github.com/mgechev/revive/rule/constant_logical_expr.go +++ b/vendor/github.com/mgechev/revive/rule/constant_logical_expr.go @@ -4,6 +4,7 @@ import ( "go/ast" "go/token" + "github.com/mgechev/revive/internal/astutils" "github.com/mgechev/revive/lint" ) @@ -35,13 +36,12 @@ type lintConstantLogicalExpr struct { } func (w *lintConstantLogicalExpr) Visit(node ast.Node) ast.Visitor { - switch n := node.(type) { - case *ast.BinaryExpr: + if n, ok := node.(*ast.BinaryExpr); ok { if !w.isOperatorWithLogicalResult(n.Op) { return w } - subExpressionsAreNotEqual := gofmt(n.X) != gofmt(n.Y) + subExpressionsAreNotEqual := astutils.GoFmt(n.X) != astutils.GoFmt(n.Y) if subExpressionsAreNotEqual { return w // nothing to say } @@ -91,11 +91,11 @@ func (*lintConstantLogicalExpr) isInequalityOperator(t token.Token) bool { return false } -func (w lintConstantLogicalExpr) newFailure(node ast.Node, msg string) { +func (w *lintConstantLogicalExpr) newFailure(node ast.Node, msg string) { w.onFailure(lint.Failure{ Confidence: 1, Node: node, - Category: "logic", + Category: lint.FailureCategoryLogic, Failure: msg, }) } diff --git a/vendor/github.com/mgechev/revive/rule/context_as_argument.go b/vendor/github.com/mgechev/revive/rule/context_as_argument.go index 8bc5f8b61..588bbabf0 100644 --- a/vendor/github.com/mgechev/revive/rule/context_as_argument.go +++ b/vendor/github.com/mgechev/revive/rule/context_as_argument.go @@ -4,98 +4,85 @@ import ( "fmt" "go/ast" "strings" - "sync" + "github.com/mgechev/revive/internal/astutils" "github.com/mgechev/revive/lint" ) -// ContextAsArgumentRule lints given else constructs. +// ContextAsArgumentRule suggests that [context.Context] should be the first argument of a function. type ContextAsArgumentRule struct { - allowTypesLUT map[string]struct{} - - configureOnce sync.Once + allowTypes map[string]struct{} } // Apply applies the rule to given file. -func (r *ContextAsArgumentRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(args) }) - +func (r *ContextAsArgumentRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure - walker := lintContextArguments{ - allowTypesLUT: r.allowTypesLUT, - onFailure: func(failure lint.Failure) { - failures = append(failures, failure) - }, - } + for _, decl := range file.AST.Decls { + fn, ok := decl.(*ast.FuncDecl) + if !ok || len(fn.Type.Params.List) <= 1 { + continue // not a function or a function with less than 2 parameters + } + + fnArgs := fn.Type.Params.List + + // A context.Context should be the first parameter of a function. + // Flag any that show up after the first. + isCtxStillAllowed := true + for _, arg := range fnArgs { + argIsCtx := astutils.IsPkgDotName(arg.Type, "context", "Context") + if argIsCtx && !isCtxStillAllowed { + failures = append(failures, lint.Failure{ + Node: arg, + Category: lint.FailureCategoryArgOrder, + Failure: "context.Context should be the first parameter of a function", + Confidence: 0.9, + }) + + break // only flag one + } - ast.Walk(walker, file.AST) + typeName := astutils.GoFmt(arg.Type) + // a parameter of type context.Context is still allowed if the current arg type is in the allow types LookUpTable + _, isCtxStillAllowed = r.allowTypes[typeName] + } + } return failures } -func (r *ContextAsArgumentRule) configure(arguments lint.Arguments) { - r.allowTypesLUT = getAllowTypesFromArguments(arguments) -} - // Name returns the rule name. func (*ContextAsArgumentRule) Name() string { return "context-as-argument" } -type lintContextArguments struct { - allowTypesLUT map[string]struct{} - onFailure func(lint.Failure) -} - -func (w lintContextArguments) Visit(n ast.Node) ast.Visitor { - fn, ok := n.(*ast.FuncDecl) - if !ok || len(fn.Type.Params.List) <= 1 { - return w +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *ContextAsArgumentRule) Configure(arguments lint.Arguments) error { + types, err := r.getAllowTypesFromArguments(arguments) + if err != nil { + return err } - - fnArgs := fn.Type.Params.List - - // A context.Context should be the first parameter of a function. - // Flag any that show up after the first. - isCtxStillAllowed := true - for _, arg := range fnArgs { - argIsCtx := isPkgDot(arg.Type, "context", "Context") - if argIsCtx && !isCtxStillAllowed { - w.onFailure(lint.Failure{ - Node: arg, - Category: "arg-order", - Failure: "context.Context should be the first parameter of a function", - Confidence: 0.9, - }) - break // only flag one - } - - typeName := gofmt(arg.Type) - // a parameter of type context.Context is still allowed if the current arg type is in the LUT - _, isCtxStillAllowed = w.allowTypesLUT[typeName] - } - - return nil // avoid visiting the function body + r.allowTypes = types + return nil } -func getAllowTypesFromArguments(args lint.Arguments) map[string]struct{} { +func (*ContextAsArgumentRule) getAllowTypesFromArguments(args lint.Arguments) (map[string]struct{}, error) { allowTypesBefore := []string{} if len(args) >= 1 { argKV, ok := args[0].(map[string]any) if !ok { - panic(fmt.Sprintf("Invalid argument to the context-as-argument rule. Expecting a k,v map, got %T", args[0])) + return nil, fmt.Errorf("invalid argument to the context-as-argument rule. Expecting a k,v map, got %T", args[0]) } for k, v := range argKV { - switch k { - case "allowTypesBefore": - typesBefore, ok := v.(string) - if !ok { - panic(fmt.Sprintf("Invalid argument to the context-as-argument.allowTypesBefore rule. Expecting a string, got %T", v)) - } - allowTypesBefore = append(allowTypesBefore, strings.Split(typesBefore, ",")...) - default: - panic(fmt.Sprintf("Invalid argument to the context-as-argument rule. Unrecognized key %s", k)) + if !isRuleOption(k, "allowTypesBefore") { + return nil, fmt.Errorf("invalid argument to the context-as-argument rule. Unrecognized key %s", k) + } + typesBefore, ok := v.(string) + if !ok { + return nil, fmt.Errorf("invalid argument to the context-as-argument.allowTypesBefore rule. Expecting a string, got %T", v) } + allowTypesBefore = append(allowTypesBefore, strings.Split(typesBefore, ",")...) } } @@ -105,5 +92,5 @@ func getAllowTypesFromArguments(args lint.Arguments) map[string]struct{} { } result["context.Context"] = struct{}{} // context.Context is always allowed before another context.Context - return result + return result, nil } diff --git a/vendor/github.com/mgechev/revive/rule/context_keys_type.go b/vendor/github.com/mgechev/revive/rule/context_keys_type.go index 60ccec560..98f631ee9 100644 --- a/vendor/github.com/mgechev/revive/rule/context_keys_type.go +++ b/vendor/github.com/mgechev/revive/rule/context_keys_type.go @@ -5,10 +5,11 @@ import ( "go/ast" "go/types" + "github.com/mgechev/revive/internal/astutils" "github.com/mgechev/revive/lint" ) -// ContextKeysType lints given else constructs. +// ContextKeysType disallows the usage of basic types in [context.WithValue]. type ContextKeysType struct{} // Apply applies the rule to given file. @@ -42,8 +43,7 @@ type lintContextKeyTypes struct { } func (w lintContextKeyTypes) Visit(n ast.Node) ast.Visitor { - switch n := n.(type) { - case *ast.CallExpr: + if n, ok := n.(*ast.CallExpr); ok { checkContextKeyType(w, n) } @@ -52,15 +52,7 @@ func (w lintContextKeyTypes) Visit(n ast.Node) ast.Visitor { func checkContextKeyType(w lintContextKeyTypes, x *ast.CallExpr) { f := w.file - sel, ok := x.Fun.(*ast.SelectorExpr) - if !ok { - return - } - pkg, ok := sel.X.(*ast.Ident) - if !ok || pkg.Name != "context" { - return - } - if sel.Sel.Name != "WithValue" { + if !astutils.IsPkgDotName(x.Fun, "context", "WithValue") { return } @@ -74,7 +66,7 @@ func checkContextKeyType(w lintContextKeyTypes, x *ast.CallExpr) { w.onFailure(lint.Failure{ Confidence: 1, Node: x, - Category: "content", + Category: lint.FailureCategoryContent, Failure: fmt.Sprintf("should not use basic type %s as key in context.WithValue", key.Type), }) } diff --git a/vendor/github.com/mgechev/revive/rule/cyclomatic.go b/vendor/github.com/mgechev/revive/rule/cyclomatic.go index c1a2de97a..6025b65e8 100644 --- a/vendor/github.com/mgechev/revive/rule/cyclomatic.go +++ b/vendor/github.com/mgechev/revive/rule/cyclomatic.go @@ -4,87 +4,63 @@ import ( "fmt" "go/ast" "go/token" - "sync" "github.com/mgechev/revive/lint" ) // Based on https://github.com/fzipp/gocyclo -// CyclomaticRule lints given else constructs. +// CyclomaticRule sets restriction for maximum cyclomatic complexity. type CyclomaticRule struct { maxComplexity int - - configureOnce sync.Once } const defaultMaxCyclomaticComplexity = 10 -func (r *CyclomaticRule) configure(arguments lint.Arguments) { +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *CyclomaticRule) Configure(arguments lint.Arguments) error { if len(arguments) < 1 { r.maxComplexity = defaultMaxCyclomaticComplexity - return + return nil } complexity, ok := arguments[0].(int64) // Alt. non panicking version if !ok { - panic(fmt.Sprintf("invalid argument for cyclomatic complexity; expected int but got %T", arguments[0])) + return fmt.Errorf("invalid argument for cyclomatic complexity; expected int but got %T", arguments[0]) } r.maxComplexity = int(complexity) + return nil } // Apply applies the rule to given file. -func (r *CyclomaticRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(arguments) }) - +func (r *CyclomaticRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure - fileAst := file.AST - - walker := lintCyclomatic{ - file: file, - complexity: r.maxComplexity, - onFailure: func(failure lint.Failure) { - failures = append(failures, failure) - }, - } - - ast.Walk(walker, fileAst) - - return failures -} - -// Name returns the rule name. -func (*CyclomaticRule) Name() string { - return "cyclomatic" -} - -type lintCyclomatic struct { - file *lint.File - complexity int - onFailure func(lint.Failure) -} - -func (w lintCyclomatic) Visit(_ ast.Node) ast.Visitor { - f := w.file - for _, decl := range f.AST.Decls { + for _, decl := range file.AST.Decls { fn, ok := decl.(*ast.FuncDecl) if !ok { continue } c := complexity(fn) - if c > w.complexity { - w.onFailure(lint.Failure{ + if c > r.maxComplexity { + failures = append(failures, lint.Failure{ Confidence: 1, - Category: "maintenance", + Category: lint.FailureCategoryMaintenance, Failure: fmt.Sprintf("function %s has cyclomatic complexity %d (> max enabled %d)", - funcName(fn), c, w.complexity), + funcName(fn), c, r.maxComplexity), Node: fn, }) } } - return nil + return failures +} + +// Name returns the rule name. +func (*CyclomaticRule) Name() string { + return "cyclomatic" } // funcName returns the name representation of a function or method: @@ -123,7 +99,7 @@ type complexityVisitor struct { Complexity int } -// Visit implements the ast.Visitor interface. +// Visit implements the [ast.Visitor] interface. func (v *complexityVisitor) Visit(n ast.Node) ast.Visitor { switch n := n.(type) { case *ast.FuncDecl, *ast.IfStmt, *ast.ForStmt, *ast.RangeStmt, *ast.CaseClause, *ast.CommClause: diff --git a/vendor/github.com/mgechev/revive/rule/datarace.go b/vendor/github.com/mgechev/revive/rule/datarace.go index 21a7a706e..fd2dcdf2b 100644 --- a/vendor/github.com/mgechev/revive/rule/datarace.go +++ b/vendor/github.com/mgechev/revive/rule/datarace.go @@ -4,58 +4,58 @@ import ( "fmt" "go/ast" + "github.com/mgechev/revive/internal/astutils" "github.com/mgechev/revive/lint" ) -// DataRaceRule lints assignments to value method-receivers. +//nolint:staticcheck // TODO: ast.Object is deprecated +type nodeUID *ast.Object // type of the unique id for AST nodes + +// DataRaceRule spots potential dataraces caused by goroutines capturing (by-reference) +// particular identifiers of the function from which goroutines are created. type DataRaceRule struct{} // Apply applies the rule to given file. -func (*DataRaceRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { +func (r *DataRaceRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { + isGo122 := file.Pkg.IsAtLeastGoVersion(lint.Go122) var failures []lint.Failure - onFailure := func(failure lint.Failure) { - failures = append(failures, failure) - } - w := lintDataRaces{onFailure: onFailure, go122for: file.Pkg.IsAtLeastGo122()} + for _, decl := range file.AST.Decls { + funcDecl, ok := decl.(*ast.FuncDecl) + if !ok || funcDecl.Body == nil { + continue // not function declaration or empty function + } - ast.Walk(w, file.AST) + funcResults := funcDecl.Type.Results - return failures -} + returnIDs := map[nodeUID]struct{}{} + if funcResults != nil { + returnIDs = r.extractReturnIDs(funcResults.List) + } -// Name returns the rule name. -func (*DataRaceRule) Name() string { - return "datarace" -} + onFailure := func(failure lint.Failure) { + failures = append(failures, failure) + } -type lintDataRaces struct { - onFailure func(failure lint.Failure) - go122for bool -} + fl := &lintFunctionForDataRaces{ + onFailure: onFailure, + returnIDs: returnIDs, + rangeIDs: map[nodeUID]struct{}{}, + go122for: isGo122, + } -func (w lintDataRaces) Visit(n ast.Node) ast.Visitor { - node, ok := n.(*ast.FuncDecl) - if !ok { - return w // not function declaration - } - if node.Body == nil { - return nil // empty body + ast.Walk(fl, funcDecl.Body) } - results := node.Type.Results - - returnIDs := map[*ast.Object]struct{}{} - if results != nil { - returnIDs = w.ExtractReturnIDs(results.List) - } - fl := &lintFunctionForDataRaces{onFailure: w.onFailure, returnIDs: returnIDs, rangeIDs: map[*ast.Object]struct{}{}, go122for: w.go122for} - ast.Walk(fl, node.Body) + return failures +} - return nil +// Name returns the rule name. +func (*DataRaceRule) Name() string { + return "datarace" } -func (lintDataRaces) ExtractReturnIDs(fields []*ast.Field) map[*ast.Object]struct{} { - r := map[*ast.Object]struct{}{} +func (*DataRaceRule) extractReturnIDs(fields []*ast.Field) map[nodeUID]struct{} { + r := map[nodeUID]struct{}{} for _, f := range fields { for _, id := range f.Names { r[id.Obj] = struct{}{} @@ -66,11 +66,11 @@ func (lintDataRaces) ExtractReturnIDs(fields []*ast.Field) map[*ast.Object]struc } type lintFunctionForDataRaces struct { - _ struct{} onFailure func(failure lint.Failure) - returnIDs map[*ast.Object]struct{} - rangeIDs map[*ast.Object]struct{} - go122for bool + returnIDs map[nodeUID]struct{} + rangeIDs map[nodeUID]struct{} + + go122for bool } func (w lintFunctionForDataRaces) Visit(node ast.Node) ast.Visitor { @@ -113,7 +113,7 @@ func (w lintFunctionForDataRaces) Visit(node ast.Node) ast.Visitor { return ok } - ids := pick(funcLit.Body, selectIDs) + ids := astutils.PickNodes(funcLit.Body, selectIDs) for _, id := range ids { id := id.(*ast.Ident) _, isRangeID := w.rangeIDs[id.Obj] @@ -124,14 +124,14 @@ func (w lintFunctionForDataRaces) Visit(node ast.Node) ast.Visitor { w.onFailure(lint.Failure{ Confidence: 1, Node: id, - Category: "logic", + Category: lint.FailureCategoryLogic, Failure: fmt.Sprintf("datarace: range value %s is captured (by-reference) in goroutine", id.Name), }) case isReturnID: w.onFailure(lint.Failure{ Confidence: 0.8, Node: id, - Category: "logic", + Category: lint.FailureCategoryLogic, Failure: fmt.Sprintf("potential datarace: return value %s is captured (by-reference) in goroutine", id.Name), }) } diff --git a/vendor/github.com/mgechev/revive/rule/deep_exit.go b/vendor/github.com/mgechev/revive/rule/deep_exit.go index 7b3dd0f82..c1042a6aa 100644 --- a/vendor/github.com/mgechev/revive/rule/deep_exit.go +++ b/vendor/github.com/mgechev/revive/rule/deep_exit.go @@ -3,11 +3,15 @@ package rule import ( "fmt" "go/ast" + "strings" + "unicode" + "unicode/utf8" + "github.com/mgechev/revive/internal/astutils" "github.com/mgechev/revive/lint" ) -// DeepExitRule lints program exit at functions other than main or init. +// DeepExitRule lints program exit in functions other than main or init. type DeepExitRule struct{} // Apply applies the rule to given file. @@ -17,20 +21,7 @@ func (*DeepExitRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { failures = append(failures, failure) } - exitFunctions := map[string]map[string]bool{ - "os": {"Exit": true}, - "syscall": {"Exit": true}, - "log": { - "Fatal": true, - "Fatalf": true, - "Fatalln": true, - "Panic": true, - "Panicf": true, - "Panicln": true, - }, - } - - w := lintDeepExit{onFailure, exitFunctions, file.IsTest()} + w := &lintDeepExit{onFailure: onFailure, isTestFile: file.IsTest()} ast.Walk(w, file.AST) return failures } @@ -41,12 +32,11 @@ func (*DeepExitRule) Name() string { } type lintDeepExit struct { - onFailure func(lint.Failure) - exitFunctions map[string]map[string]bool - isTestFile bool + onFailure func(lint.Failure) + isTestFile bool } -func (w lintDeepExit) Visit(node ast.Node) ast.Visitor { +func (w *lintDeepExit) Visit(node ast.Node) ast.Visitor { if fd, ok := node.(*ast.FuncDecl); ok { if w.mustIgnore(fd) { return nil // skip analysis of this function @@ -75,13 +65,18 @@ func (w lintDeepExit) Visit(node ast.Node) ast.Visitor { pkg := id.Name fn := fc.Sel.Name - isACallToExitFunction := w.exitFunctions[pkg] != nil && w.exitFunctions[pkg][fn] - if isACallToExitFunction { + if isCallToExitFunction(pkg, fn, ce.Args) { + msg := fmt.Sprintf("calls to %s.%s only in main() or init() functions", pkg, fn) + + if pkg == "flag" && fn == "NewFlagSet" && + len(ce.Args) == 2 && astutils.IsPkgDotName(ce.Args[1], "flag", "ExitOnError") { + msg = "calls to flag.NewFlagSet with flag.ExitOnError only in main() or init() functions" + } w.onFailure(lint.Failure{ Confidence: 1, Node: ce, - Category: "bad practice", - Failure: fmt.Sprintf("calls to %s.%s only in main() or init() functions", pkg, fn), + Category: lint.FailureCategoryBadPractice, + Failure: msg, }) } @@ -91,5 +86,32 @@ func (w lintDeepExit) Visit(node ast.Node) ast.Visitor { func (w *lintDeepExit) mustIgnore(fd *ast.FuncDecl) bool { fn := fd.Name.Name - return fn == "init" || fn == "main" || (w.isTestFile && fn == "TestMain") + return fn == "init" || fn == "main" || w.isTestMain(fd) || w.isTestExample(fd) +} + +func (w *lintDeepExit) isTestMain(fd *ast.FuncDecl) bool { + return w.isTestFile && fd.Name.Name == "TestMain" +} + +// isTestExample returns true if the function is a testable example function. +// See https://go.dev/blog/examples#examples-are-tests for more information. +// +// Inspired by https://github.com/golang/go/blob/go1.23.0/src/go/doc/example.go#L72-L77 +func (w *lintDeepExit) isTestExample(fd *ast.FuncDecl) bool { + if !w.isTestFile { + return false + } + name := fd.Name.Name + const prefix = "Example" + if !strings.HasPrefix(name, prefix) { + return false + } + if len(name) == len(prefix) { // "Example" is a package level example + return len(fd.Type.Params.List) == 0 + } + r, _ := utf8.DecodeRuneInString(name[len(prefix):]) + if unicode.IsLower(r) { + return false + } + return len(fd.Type.Params.List) == 0 } diff --git a/vendor/github.com/mgechev/revive/rule/defer.go b/vendor/github.com/mgechev/revive/rule/defer.go index f7c716eb6..a85336846 100644 --- a/vendor/github.com/mgechev/revive/rule/defer.go +++ b/vendor/github.com/mgechev/revive/rule/defer.go @@ -3,26 +3,39 @@ package rule import ( "fmt" "go/ast" - "sync" + "github.com/mgechev/revive/internal/astutils" "github.com/mgechev/revive/lint" ) -// DeferRule lints unused params in functions. +var ( + deferOptionLoop = normalizeRuleOption("loop") + deferOptionCallChain = normalizeRuleOption("callChain") + deferOptionMethodCall = normalizeRuleOption("methodCall") + deferOptionReturn = normalizeRuleOption("return") + deferOptionRecover = normalizeRuleOption("recover") + deferOptionImmediateRecover = normalizeRuleOption("immediateRecover") +) + +// DeferRule lints gotchas in defer statements. type DeferRule struct { allow map[string]bool - - configureOnce sync.Once } -func (r *DeferRule) configure(arguments lint.Arguments) { - r.allow = r.allowFromArgs(arguments) +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *DeferRule) Configure(arguments lint.Arguments) error { + list, err := r.allowFromArgs(arguments) + if err != nil { + return err + } + r.allow = list + return nil } // Apply applies the rule to given file. -func (r *DeferRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(arguments) }) - +func (r *DeferRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure onFailure := func(failure lint.Failure) { failures = append(failures, failure) @@ -39,42 +52,42 @@ func (*DeferRule) Name() string { return "defer" } -func (*DeferRule) allowFromArgs(args lint.Arguments) map[string]bool { +func (*DeferRule) allowFromArgs(args lint.Arguments) (map[string]bool, error) { if len(args) < 1 { allow := map[string]bool{ - "loop": true, - "call-chain": true, - "method-call": true, - "return": true, - "recover": true, - "immediate-recover": true, + deferOptionLoop: true, + deferOptionCallChain: true, + deferOptionMethodCall: true, + deferOptionReturn: true, + deferOptionRecover: true, + deferOptionImmediateRecover: true, } - return allow + return allow, nil } aa, ok := args[0].([]any) if !ok { - panic(fmt.Sprintf("Invalid argument '%v' for 'defer' rule. Expecting []string, got %T", args[0], args[0])) + return nil, fmt.Errorf("invalid argument '%v' for 'defer' rule. Expecting []string, got %T", args[0], args[0]) } allow := make(map[string]bool, len(aa)) for _, subcase := range aa { sc, ok := subcase.(string) if !ok { - panic(fmt.Sprintf("Invalid argument '%v' for 'defer' rule. Expecting string, got %T", subcase, subcase)) + return nil, fmt.Errorf("invalid argument '%v' for 'defer' rule. Expecting string, got %T", subcase, subcase) } - allow[sc] = true + allow[normalizeRuleOption(sc)] = true } - return allow + return allow, nil } type lintDeferRule struct { onFailure func(lint.Failure) inALoop bool inADefer bool - inAFuncLit bool + inAFuncLit byte // 0 = not in func lit, 1 = in top-level func lit, >1 = nested func lit allow map[string]bool } @@ -87,58 +100,58 @@ func (w lintDeferRule) Visit(node ast.Node) ast.Visitor { w.visitSubtree(n.Body, w.inADefer, true, w.inAFuncLit) return nil case *ast.FuncLit: - w.visitSubtree(n.Body, w.inADefer, false, true) + w.visitSubtree(n.Body, w.inADefer, false, w.inAFuncLit+1) return nil case *ast.ReturnStmt: - if len(n.Results) != 0 && w.inADefer && w.inAFuncLit { - w.newFailure("return in a defer function has no effect", n, 1.0, "logic", "return") + if len(n.Results) != 0 && w.inADefer && w.inAFuncLit == 1 { + w.newFailure("return in a defer function has no effect", n, 1.0, lint.FailureCategoryLogic, deferOptionReturn) } case *ast.CallExpr: - isCallToRecover := isIdent(n.Fun, "recover") + isCallToRecover := astutils.IsIdent(n.Fun, "recover") switch { case !w.inADefer && isCallToRecover: // func fn() { recover() } // // confidence is not 1 because recover can be in a function that is deferred elsewhere - w.newFailure("recover must be called inside a deferred function", n, 0.8, "logic", "recover") - case w.inADefer && !w.inAFuncLit && isCallToRecover: + w.newFailure("recover must be called inside a deferred function", n, 0.8, lint.FailureCategoryLogic, deferOptionRecover) + case w.inADefer && w.inAFuncLit == 0 && isCallToRecover: // defer helper(recover()) // // confidence is not truly 1 because this could be in a correctly-deferred func, // but it is very likely to be a misunderstanding of defer's behavior around arguments. - w.newFailure("recover must be called inside a deferred function, this is executing recover immediately", n, 1, "logic", "immediate-recover") + w.newFailure("recover must be called inside a deferred function, this is executing recover immediately", n, 1, lint.FailureCategoryLogic, deferOptionImmediateRecover) } return nil // no need to analyze the arguments of the function call case *ast.DeferStmt: - if isIdent(n.Call.Fun, "recover") { + if astutils.IsIdent(n.Call.Fun, "recover") { // defer recover() // // confidence is not truly 1 because this could be in a correctly-deferred func, // but normally this doesn't suppress a panic, and even if it did it would silently discard the value. - w.newFailure("recover must be called inside a deferred function, this is executing recover immediately", n, 1, "logic", "immediate-recover") + w.newFailure("recover must be called inside a deferred function, this is executing recover immediately", n, 1, lint.FailureCategoryLogic, deferOptionImmediateRecover) } - w.visitSubtree(n.Call.Fun, true, false, false) + w.visitSubtree(n.Call.Fun, true, false, 0) for _, a := range n.Call.Args { switch a.(type) { case *ast.FuncLit: continue // too hard to analyze deferred calls with func literals args default: - w.visitSubtree(a, true, false, false) // check arguments, they should not contain recover() + w.visitSubtree(a, true, false, 0) // check arguments, they should not contain recover() } } if w.inALoop { - w.newFailure("prefer not to defer inside loops", n, 1.0, "bad practice", "loop") + w.newFailure("prefer not to defer inside loops", n, 1.0, lint.FailureCategoryBadPractice, deferOptionLoop) } switch fn := n.Call.Fun.(type) { case *ast.CallExpr: - w.newFailure("prefer not to defer chains of function calls", fn, 1.0, "bad practice", "call-chain") + w.newFailure("prefer not to defer chains of function calls", fn, 1.0, lint.FailureCategoryBadPractice, deferOptionCallChain) case *ast.SelectorExpr: if id, ok := fn.X.(*ast.Ident); ok { isMethodCall := id != nil && id.Obj != nil && id.Obj.Kind == ast.Typ if isMethodCall { - w.newFailure("be careful when deferring calls to methods without pointer receiver", fn, 0.8, "bad practice", "method-call") + w.newFailure("be careful when deferring calls to methods without pointer receiver", fn, 0.8, lint.FailureCategoryBadPractice, deferOptionMethodCall) } } } @@ -149,7 +162,7 @@ func (w lintDeferRule) Visit(node ast.Node) ast.Visitor { return w } -func (w lintDeferRule) visitSubtree(n ast.Node, inADefer, inALoop, inAFuncLit bool) { +func (w lintDeferRule) visitSubtree(n ast.Node, inADefer, inALoop bool, inAFuncLit byte) { nw := lintDeferRule{ onFailure: w.onFailure, inADefer: inADefer, @@ -160,7 +173,7 @@ func (w lintDeferRule) visitSubtree(n ast.Node, inADefer, inALoop, inAFuncLit bo ast.Walk(nw, n) } -func (w lintDeferRule) newFailure(msg string, node ast.Node, confidence float64, cat, subcase string) { +func (w lintDeferRule) newFailure(msg string, node ast.Node, confidence float64, cat lint.FailureCategory, subcase string) { if !w.allow[subcase] { return } diff --git a/vendor/github.com/mgechev/revive/rule/dot_imports.go b/vendor/github.com/mgechev/revive/rule/dot_imports.go index f6c7fbcfb..5252e716a 100644 --- a/vendor/github.com/mgechev/revive/rule/dot_imports.go +++ b/vendor/github.com/mgechev/revive/rule/dot_imports.go @@ -3,22 +3,18 @@ package rule import ( "fmt" "go/ast" - "sync" + "strconv" "github.com/mgechev/revive/lint" ) -// DotImportsRule lints given else constructs. +// DotImportsRule forbids dot imports. type DotImportsRule struct { allowedPackages allowPackages - - configureOnce sync.Once } // Apply applies the rule to given file. -func (r *DotImportsRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(arguments) }) - +func (r *DotImportsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure fileAst := file.AST @@ -41,30 +37,37 @@ func (*DotImportsRule) Name() string { return "dot-imports" } -func (r *DotImportsRule) configure(arguments lint.Arguments) { - r.allowedPackages = make(allowPackages) +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *DotImportsRule) Configure(arguments lint.Arguments) error { + r.allowedPackages = allowPackages{} if len(arguments) == 0 { - return + return nil } args, ok := arguments[0].(map[string]any) if !ok { - panic(fmt.Sprintf("Invalid argument to the dot-imports rule. Expecting a k,v map, got %T", arguments[0])) + return fmt.Errorf("invalid argument to the dot-imports rule. Expecting a k,v map, got %T", arguments[0]) } - if allowedPkgArg, ok := args["allowedPackages"]; ok { - pkgs, ok := allowedPkgArg.([]any) + for k, v := range args { + if !isRuleOption(k, "allowedPackages") { + continue + } + pkgs, ok := v.([]any) if !ok { - panic(fmt.Sprintf("Invalid argument to the dot-imports rule, []string expected. Got '%v' (%T)", allowedPkgArg, allowedPkgArg)) + return fmt.Errorf("invalid argument to the dot-imports rule, []string expected. Got '%v' (%T)", v, v) } for _, p := range pkgs { pkg, ok := p.(string) if !ok { - panic(fmt.Sprintf("Invalid argument to the dot-imports rule, string expected. Got '%v' (%T)", p, p)) + return fmt.Errorf("invalid argument to the dot-imports rule, string expected. Got '%v' (%T)", p, p) } r.allowedPackages.add(pkg) } } + return nil } type lintImports struct { @@ -82,7 +85,7 @@ func (w lintImports) Visit(_ ast.Node) ast.Visitor { Confidence: 1, Failure: "should not use dot imports", Node: importSpec, - Category: "imports", + Category: lint.FailureCategoryImports, }) } } @@ -92,7 +95,7 @@ func (w lintImports) Visit(_ ast.Node) ast.Visitor { type allowPackages map[string]struct{} func (ap allowPackages) add(pkg string) { - ap[fmt.Sprintf(`"%s"`, pkg)] = struct{}{} // import path strings are with double quotes + ap[strconv.Quote(pkg)] = struct{}{} // import path strings are with double quotes } func (ap allowPackages) isAllowedPackage(pkg string) bool { diff --git a/vendor/github.com/mgechev/revive/rule/duplicated_imports.go b/vendor/github.com/mgechev/revive/rule/duplicated_imports.go index 2b177fac6..60955c427 100644 --- a/vendor/github.com/mgechev/revive/rule/duplicated_imports.go +++ b/vendor/github.com/mgechev/revive/rule/duplicated_imports.go @@ -6,7 +6,7 @@ import ( "github.com/mgechev/revive/lint" ) -// DuplicatedImportsRule lints given else constructs. +// DuplicatedImportsRule looks for packages that are imported two or more times. type DuplicatedImportsRule struct{} // Apply applies the rule to given file. @@ -22,7 +22,7 @@ func (*DuplicatedImportsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fa Confidence: 1, Failure: fmt.Sprintf("Package %s already imported", path), Node: imp, - Category: "imports", + Category: lint.FailureCategoryImports, }) continue } diff --git a/vendor/github.com/mgechev/revive/rule/early_return.go b/vendor/github.com/mgechev/revive/rule/early_return.go index 62d491f27..7b158ccf1 100644 --- a/vendor/github.com/mgechev/revive/rule/early_return.go +++ b/vendor/github.com/mgechev/revive/rule/early_return.go @@ -9,11 +9,42 @@ import ( // EarlyReturnRule finds opportunities to reduce nesting by inverting // the condition of an "if" block. -type EarlyReturnRule struct{} +type EarlyReturnRule struct { + // preserveScope prevents suggestions that would enlarge variable scope. + preserveScope bool + // allowJump permits early-return to suggest introducing a new jump + // (return, continue, etc) statement to reduce nesting. + // By default, suggestions only bring existing jumps earlier. + allowJump bool +} + +var _ lint.ConfigurableRule = (*EarlyReturnRule)(nil) + +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (e *EarlyReturnRule) Configure(arguments lint.Arguments) error { + for _, arg := range arguments { + sarg, ok := arg.(string) + if !ok { + continue + } + switch { + case isRuleOption(sarg, "preserveScope"): + e.preserveScope = true + case isRuleOption(sarg, "allowJump"): + e.allowJump = true + } + } + return nil +} // Apply applies the rule to given file. -func (e *EarlyReturnRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure { - return ifelse.Apply(e, file.AST, ifelse.TargetIf, args) +func (e *EarlyReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { + return ifelse.Apply(e.checkIfElse, file.AST, ifelse.TargetIf, ifelse.Args{ + PreserveScope: e.preserveScope, + AllowJump: e.allowJump, + }) } // Name returns the rule name. @@ -21,31 +52,40 @@ func (*EarlyReturnRule) Name() string { return "early-return" } -// CheckIfElse evaluates the rule against an ifelse.Chain and returns a failure message if applicable. -func (*EarlyReturnRule) CheckIfElse(chain ifelse.Chain, args ifelse.Args) string { - if !chain.Else.Deviates() { - // this rule only applies if the else-block deviates control flow - return "" +func (e *EarlyReturnRule) checkIfElse(chain ifelse.Chain) (string, bool) { + if chain.HasElse { + if !chain.Else.Deviates() { + // this rule only applies if the else-block deviates control flow + return "", false + } + } else if !e.allowJump || !chain.AtBlockEnd || !chain.BlockEndKind.Deviates() || chain.If.IsShort() { + // this kind of refactor requires introducing a new indented "return", "continue" or "break" statement, + // so ignore unless we are able to outdent multiple statements in exchange. + return "", false } if chain.HasPriorNonDeviating && !chain.If.IsEmpty() { // if we de-indent this block then a previous branch - // might flow into it, affecting program behaviour - return "" + // might flow into it, affecting program behavior + return "", false } - if chain.If.Deviates() { + if chain.HasElse && chain.If.Deviates() { // avoid overlapping with superfluous-else - return "" + return "", false } - if args.PreserveScope && !chain.AtBlockEnd && (chain.HasInitializer || chain.If.HasDecls) { + if e.preserveScope && !chain.AtBlockEnd && (chain.HasInitializer || chain.If.HasDecls()) { // avoid increasing variable scope - return "" + return "", false + } + + if !chain.HasElse { + return fmt.Sprintf("if c { ... } can be rewritten if !c { %v } ... to reduce nesting", chain.BlockEndKind), true } if chain.If.IsEmpty() { - return fmt.Sprintf("if c { } else { %[1]v } can be simplified to if !c { %[1]v }", chain.Else) + return fmt.Sprintf("if c { } else %[1]v can be simplified to if !c %[1]v", chain.Else), true } - return fmt.Sprintf("if c { ... } else { %[1]v } can be simplified to if !c { %[1]v } ...", chain.Else) + return fmt.Sprintf("if c { ... } else %[1]v can be simplified to if !c %[1]v ...", chain.Else), true } diff --git a/vendor/github.com/mgechev/revive/rule/empty_block.go b/vendor/github.com/mgechev/revive/rule/empty_block.go index 25a052a0e..210692c94 100644 --- a/vendor/github.com/mgechev/revive/rule/empty_block.go +++ b/vendor/github.com/mgechev/revive/rule/empty_block.go @@ -6,7 +6,7 @@ import ( "github.com/mgechev/revive/lint" ) -// EmptyBlockRule lints given else constructs. +// EmptyBlockRule warns on empty code blocks. type EmptyBlockRule struct{} // Apply applies the rule to given file. @@ -17,7 +17,7 @@ func (*EmptyBlockRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { failures = append(failures, failure) } - w := lintEmptyBlock{make(map[*ast.BlockStmt]bool), onFailure} + w := lintEmptyBlock{map[*ast.BlockStmt]bool{}, onFailure} ast.Walk(w, file.AST) return failures } @@ -55,7 +55,7 @@ func (w lintEmptyBlock) Visit(node ast.Node) ast.Visitor { w.onFailure(lint.Failure{ Confidence: 0.9, Node: n, - Category: "logic", + Category: lint.FailureCategoryLogic, Failure: "this block is empty, you can remove it", }) return nil // skip visiting the range subtree (it will produce a duplicated failure) @@ -65,7 +65,7 @@ func (w lintEmptyBlock) Visit(node ast.Node) ast.Visitor { w.onFailure(lint.Failure{ Confidence: 1, Node: n, - Category: "logic", + Category: lint.FailureCategoryLogic, Failure: "this block is empty, you can remove it", }) } diff --git a/vendor/github.com/mgechev/revive/rule/empty_lines.go b/vendor/github.com/mgechev/revive/rule/empty_lines.go index 2710a8979..a2f8dc6fd 100644 --- a/vendor/github.com/mgechev/revive/rule/empty_lines.go +++ b/vendor/github.com/mgechev/revive/rule/empty_lines.go @@ -60,7 +60,7 @@ func (w lintEmptyLines) checkStart(block *ast.BlockStmt) { w.onFailure(lint.Failure{ Confidence: 1, Node: block, - Category: "style", + Category: lint.FailureCategoryStyle, Failure: "extra empty line at the start of a block", }) } @@ -79,7 +79,7 @@ func (w lintEmptyLines) checkEnd(block *ast.BlockStmt) { w.onFailure(lint.Failure{ Confidence: 1, Node: block, - Category: "style", + Category: lint.FailureCategoryStyle, Failure: "extra empty line at the end of a block", }) } diff --git a/vendor/github.com/mgechev/revive/rule/enforce_map_style.go b/vendor/github.com/mgechev/revive/rule/enforce_map_style.go index 7ddf31e35..3292db0ba 100644 --- a/vendor/github.com/mgechev/revive/rule/enforce_map_style.go +++ b/vendor/github.com/mgechev/revive/rule/enforce_map_style.go @@ -3,8 +3,8 @@ package rule import ( "fmt" "go/ast" - "sync" + "github.com/mgechev/revive/internal/astutils" "github.com/mgechev/revive/lint" ) @@ -40,39 +40,38 @@ func mapStyleFromString(s string) (enforceMapStyleType, error) { // EnforceMapStyleRule implements a rule to enforce `make(map[type]type)` over `map[type]type{}`. type EnforceMapStyleRule struct { enforceMapStyle enforceMapStyleType - - configureOnce sync.Once } -func (r *EnforceMapStyleRule) configure(arguments lint.Arguments) { +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *EnforceMapStyleRule) Configure(arguments lint.Arguments) error { if len(arguments) < 1 { r.enforceMapStyle = enforceMapStyleTypeAny - return + return nil } enforceMapStyle, ok := arguments[0].(string) if !ok { - panic(fmt.Sprintf("Invalid argument '%v' for 'enforce-map-style' rule. Expecting string, got %T", arguments[0], arguments[0])) + return fmt.Errorf("invalid argument '%v' for 'enforce-map-style' rule. Expecting string, got %T", arguments[0], arguments[0]) } var err error r.enforceMapStyle, err = mapStyleFromString(enforceMapStyle) if err != nil { - panic(fmt.Sprintf("Invalid argument to the enforce-map-style rule: %v", err)) + return fmt.Errorf("invalid argument to the enforce-map-style rule: %w", err) } + + return nil } // Apply applies the rule to given file. -func (r *EnforceMapStyleRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(arguments) }) - +func (r *EnforceMapStyleRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { if r.enforceMapStyle == enforceMapStyleTypeAny { // this linter is not configured return nil } - var failures []lint.Failure - astFile := file.AST ast.Inspect(astFile, func(n ast.Node) bool { switch v := n.(type) { @@ -93,7 +92,7 @@ func (r *EnforceMapStyleRule) Apply(file *lint.File, arguments lint.Arguments) [ failures = append(failures, lint.Failure{ Confidence: 1, Node: v, - Category: "style", + Category: lint.FailureCategoryStyle, Failure: "use make(map[type]type) instead of map[type]type{}", }) case *ast.CallExpr: @@ -103,8 +102,7 @@ func (r *EnforceMapStyleRule) Apply(file *lint.File, arguments lint.Arguments) [ return true } - ident, ok := v.Fun.(*ast.Ident) - if !ok || ident.Name != "make" { + if !astutils.IsIdent(v.Fun, "make") { return true } @@ -121,7 +119,7 @@ func (r *EnforceMapStyleRule) Apply(file *lint.File, arguments lint.Arguments) [ failures = append(failures, lint.Failure{ Confidence: 1, Node: v.Args[0], - Category: "style", + Category: lint.FailureCategoryStyle, Failure: "use map[type]type{} instead of make(map[type]type)", }) } diff --git a/vendor/github.com/mgechev/revive/rule/enforce_repeated_arg_type_style.go b/vendor/github.com/mgechev/revive/rule/enforce_repeated_arg_type_style.go index 3f9712aef..9def128aa 100644 --- a/vendor/github.com/mgechev/revive/rule/enforce_repeated_arg_type_style.go +++ b/vendor/github.com/mgechev/revive/rule/enforce_repeated_arg_type_style.go @@ -3,8 +3,8 @@ package rule import ( "fmt" "go/ast" - "sync" + "github.com/mgechev/revive/internal/astutils" "github.com/mgechev/revive/lint" ) @@ -16,14 +16,14 @@ const ( enforceRepeatedArgTypeStyleTypeFull enforceRepeatedArgTypeStyleType = "full" ) -func repeatedArgTypeStyleFromString(s string) enforceRepeatedArgTypeStyleType { +func repeatedArgTypeStyleFromString(s string) (enforceRepeatedArgTypeStyleType, error) { switch s { case string(enforceRepeatedArgTypeStyleTypeAny), "": - return enforceRepeatedArgTypeStyleTypeAny + return enforceRepeatedArgTypeStyleTypeAny, nil case string(enforceRepeatedArgTypeStyleTypeShort): - return enforceRepeatedArgTypeStyleTypeShort + return enforceRepeatedArgTypeStyleTypeShort, nil case string(enforceRepeatedArgTypeStyleTypeFull): - return enforceRepeatedArgTypeStyleTypeFull + return enforceRepeatedArgTypeStyleTypeFull, nil default: err := fmt.Errorf( "invalid repeated arg type style: %s (expecting one of %v)", @@ -35,7 +35,7 @@ func repeatedArgTypeStyleFromString(s string) enforceRepeatedArgTypeStyleType { }, ) - panic(fmt.Sprintf("Invalid argument to the enforce-repeated-arg-type-style rule: %v", err)) + return "", fmt.Errorf("invalid argument to the enforce-repeated-arg-type-style rule: %w", err) } } @@ -43,50 +43,66 @@ func repeatedArgTypeStyleFromString(s string) enforceRepeatedArgTypeStyleType { type EnforceRepeatedArgTypeStyleRule struct { funcArgStyle enforceRepeatedArgTypeStyleType funcRetValStyle enforceRepeatedArgTypeStyleType - - configureOnce sync.Once } -func (r *EnforceRepeatedArgTypeStyleRule) configure(arguments lint.Arguments) { +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *EnforceRepeatedArgTypeStyleRule) Configure(arguments lint.Arguments) error { r.funcArgStyle = enforceRepeatedArgTypeStyleTypeAny r.funcRetValStyle = enforceRepeatedArgTypeStyleTypeAny if len(arguments) == 0 { - return + return nil } switch funcArgStyle := arguments[0].(type) { case string: - r.funcArgStyle = repeatedArgTypeStyleFromString(funcArgStyle) - r.funcRetValStyle = repeatedArgTypeStyleFromString(funcArgStyle) + argstyle, err := repeatedArgTypeStyleFromString(funcArgStyle) + if err != nil { + return err + } + r.funcArgStyle = argstyle + valstyle, err := repeatedArgTypeStyleFromString(funcArgStyle) + if err != nil { + return err + } + r.funcRetValStyle = valstyle case map[string]any: // expecting map[string]string for k, v := range funcArgStyle { - switch k { - case "funcArgStyle": + switch { + case isRuleOption(k, "funcArgStyle"): val, ok := v.(string) if !ok { - panic(fmt.Sprintf("Invalid map value type for 'enforce-repeated-arg-type-style' rule. Expecting string, got %T", v)) + return fmt.Errorf("invalid map value type for 'enforce-repeated-arg-type-style' rule. Expecting string, got %T", v) + } + valstyle, err := repeatedArgTypeStyleFromString(val) + if err != nil { + return err } - r.funcArgStyle = repeatedArgTypeStyleFromString(val) - case "funcRetValStyle": + r.funcArgStyle = valstyle + case isRuleOption(k, "funcRetValStyle"): val, ok := v.(string) if !ok { - panic(fmt.Sprintf("Invalid map value '%v' for 'enforce-repeated-arg-type-style' rule. Expecting string, got %T", v, v)) + return fmt.Errorf("invalid map value '%v' for 'enforce-repeated-arg-type-style' rule. Expecting string, got %T", v, v) + } + argstyle, err := repeatedArgTypeStyleFromString(val) + if err != nil { + return err } - r.funcRetValStyle = repeatedArgTypeStyleFromString(val) + r.funcRetValStyle = argstyle default: - panic(fmt.Sprintf("Invalid map key for 'enforce-repeated-arg-type-style' rule. Expecting 'funcArgStyle' or 'funcRetValStyle', got %v", k)) + return fmt.Errorf("invalid map key for 'enforce-repeated-arg-type-style' rule. Expecting 'funcArgStyle' or 'funcRetValStyle', got %v", k) } } default: - panic(fmt.Sprintf("Invalid argument '%v' for 'import-alias-naming' rule. Expecting string or map[string]string, got %T", arguments[0], arguments[0])) + return fmt.Errorf("invalid argument '%v' for 'import-alias-naming' rule. Expecting string or map[string]string, got %T", arguments[0], arguments[0]) } + return nil } // Apply applies the rule to a given file. -func (r *EnforceRepeatedArgTypeStyleRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(arguments) }) - +func (r *EnforceRepeatedArgTypeStyleRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { if r.funcArgStyle == enforceRepeatedArgTypeStyleTypeAny && r.funcRetValStyle == enforceRepeatedArgTypeStyleTypeAny { // This linter is not configured, return no failures. return nil @@ -96,34 +112,32 @@ func (r *EnforceRepeatedArgTypeStyleRule) Apply(file *lint.File, arguments lint. astFile := file.AST ast.Inspect(astFile, func(n ast.Node) bool { - switch fn := n.(type) { - case *ast.FuncDecl: - if r.funcArgStyle == enforceRepeatedArgTypeStyleTypeFull { + if fn, ok := n.(*ast.FuncDecl); ok { + switch r.funcArgStyle { + case enforceRepeatedArgTypeStyleTypeFull: if fn.Type.Params != nil { for _, field := range fn.Type.Params.List { if len(field.Names) > 1 { failures = append(failures, lint.Failure{ Confidence: 1, Node: field, - Category: "style", + Category: lint.FailureCategoryStyle, Failure: "argument types should not be omitted", }) } } } - } - - if r.funcArgStyle == enforceRepeatedArgTypeStyleTypeShort { - var prevType ast.Expr + case enforceRepeatedArgTypeStyleTypeShort: if fn.Type.Params != nil { + var prevType ast.Expr for _, field := range fn.Type.Params.List { - prevTypeStr := gofmt(prevType) - currentTypeStr := gofmt(field.Type) + prevTypeStr := astutils.GoFmt(prevType) + currentTypeStr := astutils.GoFmt(field.Type) if currentTypeStr == prevTypeStr { failures = append(failures, lint.Failure{ Confidence: 1, Node: prevType, - Category: "style", + Category: lint.FailureCategoryStyle, Failure: fmt.Sprintf("repeated argument type %q can be omitted", prevTypeStr), }) } @@ -132,32 +146,31 @@ func (r *EnforceRepeatedArgTypeStyleRule) Apply(file *lint.File, arguments lint. } } - if r.funcRetValStyle == enforceRepeatedArgTypeStyleTypeFull { + switch r.funcRetValStyle { + case enforceRepeatedArgTypeStyleTypeFull: if fn.Type.Results != nil { for _, field := range fn.Type.Results.List { if len(field.Names) > 1 { failures = append(failures, lint.Failure{ Confidence: 1, Node: field, - Category: "style", + Category: lint.FailureCategoryStyle, Failure: "return types should not be omitted", }) } } } - } - - if r.funcRetValStyle == enforceRepeatedArgTypeStyleTypeShort { - var prevType ast.Expr + case enforceRepeatedArgTypeStyleTypeShort: if fn.Type.Results != nil { + var prevType ast.Expr for _, field := range fn.Type.Results.List { - prevTypeStr := gofmt(prevType) - currentTypeStr := gofmt(field.Type) + prevTypeStr := astutils.GoFmt(prevType) + currentTypeStr := astutils.GoFmt(field.Type) if field.Names != nil && currentTypeStr == prevTypeStr { failures = append(failures, lint.Failure{ Confidence: 1, Node: prevType, - Category: "style", + Category: lint.FailureCategoryStyle, Failure: fmt.Sprintf("repeated return type %q can be omitted", prevTypeStr), }) } diff --git a/vendor/github.com/mgechev/revive/rule/enforce_slice_style.go b/vendor/github.com/mgechev/revive/rule/enforce_slice_style.go index 7170379d9..9bc26a6a4 100644 --- a/vendor/github.com/mgechev/revive/rule/enforce_slice_style.go +++ b/vendor/github.com/mgechev/revive/rule/enforce_slice_style.go @@ -3,8 +3,8 @@ package rule import ( "fmt" "go/ast" - "sync" + "github.com/mgechev/revive/internal/astutils" "github.com/mgechev/revive/lint" ) @@ -44,32 +44,32 @@ func sliceStyleFromString(s string) (enforceSliceStyleType, error) { // EnforceSliceStyleRule implements a rule to enforce `make([]type)` over `[]type{}`. type EnforceSliceStyleRule struct { enforceSliceStyle enforceSliceStyleType - - configureOnce sync.Once } -func (r *EnforceSliceStyleRule) configure(arguments lint.Arguments) { +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *EnforceSliceStyleRule) Configure(arguments lint.Arguments) error { if len(arguments) < 1 { r.enforceSliceStyle = enforceSliceStyleTypeAny - return + return nil } enforceSliceStyle, ok := arguments[0].(string) if !ok { - panic(fmt.Sprintf("Invalid argument '%v' for 'enforce-slice-style' rule. Expecting string, got %T", arguments[0], arguments[0])) + return fmt.Errorf("invalid argument '%v' for 'enforce-slice-style' rule. Expecting string, got %T", arguments[0], arguments[0]) } var err error r.enforceSliceStyle, err = sliceStyleFromString(enforceSliceStyle) if err != nil { - panic(fmt.Sprintf("Invalid argument to the enforce-slice-style rule: %v", err)) + return fmt.Errorf("invalid argument to the enforce-slice-style rule: %w", err) } + return nil } // Apply applies the rule to given file. -func (r *EnforceSliceStyleRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(arguments) }) - +func (r *EnforceSliceStyleRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { if r.enforceSliceStyle == enforceSliceStyleTypeAny { // this linter is not configured return nil @@ -106,7 +106,7 @@ func (r *EnforceSliceStyleRule) Apply(file *lint.File, arguments lint.Arguments) failures = append(failures, lint.Failure{ Confidence: 1, Node: v, - Category: "style", + Category: lint.FailureCategoryStyle, Failure: failureMessage, }) case *ast.CallExpr: @@ -118,8 +118,7 @@ func (r *EnforceSliceStyleRule) Apply(file *lint.File, arguments lint.Arguments) return true } - ident, ok := v.Fun.(*ast.Ident) - if !ok || ident.Name != "make" { + if !astutils.IsIdent(v.Fun, "make") { return true } @@ -166,7 +165,7 @@ func (r *EnforceSliceStyleRule) Apply(file *lint.File, arguments lint.Arguments) failures = append(failures, lint.Failure{ Confidence: 1, Node: v.Args[0], - Category: "style", + Category: lint.FailureCategoryStyle, Failure: failureMessage, }) } diff --git a/vendor/github.com/mgechev/revive/rule/enforce_switch_style.go b/vendor/github.com/mgechev/revive/rule/enforce_switch_style.go new file mode 100644 index 000000000..5f2e31223 --- /dev/null +++ b/vendor/github.com/mgechev/revive/rule/enforce_switch_style.go @@ -0,0 +1,142 @@ +package rule + +import ( + "fmt" + "go/ast" + "go/token" + + "github.com/mgechev/revive/lint" +) + +// EnforceSwitchStyleRule implements a rule to enforce default clauses use and/or position. +type EnforceSwitchStyleRule struct { + allowNoDefault bool // allow absence of default + allowDefaultNotLast bool // allow default, if present, not being the last case +} + +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *EnforceSwitchStyleRule) Configure(arguments lint.Arguments) error { + if len(arguments) < 1 { + return nil + } + + for _, arg := range arguments { + argStr, ok := arg.(string) + if !ok { + return fmt.Errorf("invalid argument for rule %s; expected string but got %T", r.Name(), arg) + } + switch { + case isRuleOption(argStr, "allowNoDefault"): + r.allowNoDefault = true + case isRuleOption(argStr, "allowDefaultNotLast"): + r.allowDefaultNotLast = true + default: + return fmt.Errorf(`invalid argument %q for rule %s; expected "allowNoDefault" or "allowDefaultNotLast"`, argStr, r.Name()) + } + } + + return nil +} + +// Apply applies the rule to given file. +func (r *EnforceSwitchStyleRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { + var failures []lint.Failure + astFile := file.AST + ast.Inspect(astFile, func(n ast.Node) bool { + var body *ast.BlockStmt + var node ast.Node + switch s := n.(type) { + case *ast.SwitchStmt: + body = s.Body + node = s + case *ast.TypeSwitchStmt: + body = s.Body + node = s + default: + return true // not a switch statement + } + + defaultClause, isLast := r.seekDefaultCase(body) + hasDefault := defaultClause != nil + + if !hasDefault && r.allowNoDefault { + return true // switch without default but the rule is configured to don´t care + } + + if !hasDefault && !r.allowNoDefault { + // switch without default + if !r.allBranchesEndWithJumpStmt(body) { + failures = append(failures, lint.Failure{ + Confidence: 1, + Node: node, + Category: lint.FailureCategoryStyle, + Failure: "switch must have a default case clause", + }) + } + + return true + } + + // the switch has a default + + if r.allowDefaultNotLast || isLast { + return true + } + + failures = append(failures, lint.Failure{ + Confidence: 1, + Node: defaultClause, + Category: lint.FailureCategoryStyle, + Failure: "default case clause must be the last one", + }) + + return true + }) + + return failures +} + +func (*EnforceSwitchStyleRule) seekDefaultCase(body *ast.BlockStmt) (defaultClause *ast.CaseClause, isLast bool) { + var last *ast.CaseClause + for _, stmt := range body.List { + cc, _ := stmt.(*ast.CaseClause) // no need to check for ok + last = cc + if cc.List == nil { // a nil List means "default" + defaultClause = cc + } + } + + return defaultClause, defaultClause == last +} + +func (*EnforceSwitchStyleRule) allBranchesEndWithJumpStmt(body *ast.BlockStmt) bool { + for _, stmt := range body.List { + caseClause := stmt.(*ast.CaseClause) // safe to assume stmt is a case clause + + caseBody := caseClause.Body + if caseBody == nil { + return false + } + + lastStmt := caseBody[len(caseBody)-1] + + if _, ok := lastStmt.(*ast.ReturnStmt); ok { + continue + } + + if jump, ok := lastStmt.(*ast.BranchStmt); ok && jump.Tok == token.BREAK { + continue + } + + return false + } + + return true +} + +// Name returns the rule name. +func (*EnforceSwitchStyleRule) Name() string { + return "enforce-switch-style" +} diff --git a/vendor/github.com/mgechev/revive/rule/epoch_naming.go b/vendor/github.com/mgechev/revive/rule/epoch_naming.go new file mode 100644 index 000000000..ac5906713 --- /dev/null +++ b/vendor/github.com/mgechev/revive/rule/epoch_naming.go @@ -0,0 +1,149 @@ +package rule + +import ( + "fmt" + "go/ast" + "go/token" + "go/types" + "strings" + + "github.com/mgechev/revive/lint" +) + +// EpochNamingRule lints epoch time variable naming. +type EpochNamingRule struct{} + +// Apply applies the rule to given file. +func (*EpochNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { + var failures []lint.Failure + + walker := lintEpochNaming{ + file: file, + onFailure: func(failure lint.Failure) { + failures = append(failures, failure) + }, + } + + if err := file.Pkg.TypeCheck(); err != nil { + return []lint.Failure{ + lint.NewInternalFailure(fmt.Sprintf("Unable to type check file %q: %v", file.Name, err)), + } + } + ast.Walk(walker, file.AST) + + return failures +} + +// Name returns the rule name. +func (*EpochNamingRule) Name() string { + return "epoch-naming" +} + +type lintEpochNaming struct { + file *lint.File + onFailure func(lint.Failure) +} + +var epochUnits = map[string][]string{ + "Unix": {"Sec", "Second", "Seconds"}, + "UnixMilli": {"Milli", "Ms"}, + "UnixMicro": {"Micro", "Microsecond", "Microseconds", "Us"}, + "UnixNano": {"Nano", "Ns"}, +} + +func (w lintEpochNaming) Visit(node ast.Node) ast.Visitor { + switch v := node.(type) { + case *ast.ValueSpec: + // Handle var declarations + valuesLen := len(v.Values) + for i, name := range v.Names { + if i >= valuesLen { + break + } + + w.check(name, v.Values[i]) + } + case *ast.AssignStmt: + // Handle both short variable declarations (:=) and regular assignments (=) + if v.Tok != token.DEFINE && v.Tok != token.ASSIGN { + return w + } + + rhsLen := len(v.Rhs) + + for i, lhs := range v.Lhs { + if i >= rhsLen { + break + } + ident, ok := lhs.(*ast.Ident) + if !ok || ident.Name == "_" { + continue + } + w.check(ident, v.Rhs[i]) + } + } + + return w +} + +func (w lintEpochNaming) check(name *ast.Ident, value ast.Expr) { + call, ok := value.(*ast.CallExpr) + if !ok { + return + } + + selector, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return + } + + // Check if the receiver is of type time.Time + receiverType := w.file.Pkg.TypeOf(selector.X) + if receiverType == nil { + return + } + if !isTime(receiverType) { + return + } + + methodName := selector.Sel.Name + suffixes, ok := epochUnits[methodName] + if !ok { + return + } + + varName := name.Name + if !hasAnySuffix(varName, suffixes) { + w.onFailure(lint.Failure{ + Confidence: 0.9, + Node: name, + Category: lint.FailureCategoryNaming, + Failure: fmt.Sprintf("var %s should have one of these suffixes: %s", varName, strings.Join(suffixes, ", ")), + }) + } +} + +func isTime(typ types.Type) bool { + named, ok := typ.(*types.Named) + if !ok { + return false + } + + obj := named.Obj() + if obj == nil { + return false + } + + pkg := obj.Pkg() + return pkg != nil && pkg.Path() == "time" && obj.Name() == "Time" +} + +func hasAnySuffix(s string, suffixes []string) bool { + lowerName := strings.ToLower(s) + for _, suffix := range suffixes { + if strings.HasSuffix(lowerName, strings.ToLower(suffix)) { + return true + } + } + return false +} diff --git a/vendor/github.com/mgechev/revive/rule/error_naming.go b/vendor/github.com/mgechev/revive/rule/error_naming.go index a4f24f3f0..6de9c3116 100644 --- a/vendor/github.com/mgechev/revive/rule/error_naming.go +++ b/vendor/github.com/mgechev/revive/rule/error_naming.go @@ -6,10 +6,11 @@ import ( "go/token" "strings" + "github.com/mgechev/revive/internal/astutils" "github.com/mgechev/revive/lint" ) -// ErrorNamingRule lints given else constructs. +// ErrorNamingRule lints naming of error variables. type ErrorNamingRule struct{} // Apply applies the rule to given file. @@ -56,11 +57,22 @@ func (w lintErrors) Visit(_ ast.Node) ast.Visitor { if !ok { continue } - if !isPkgDot(ce.Fun, "errors", "New") && !isPkgDot(ce.Fun, "fmt", "Errorf") { + if !astutils.IsPkgDotName(ce.Fun, "errors", "New") && !astutils.IsPkgDotName(ce.Fun, "fmt", "Errorf") { continue } id := spec.Names[0] + if id.Name == "_" { + // avoid false positive for blank identifier + + // The fact that the error variable is not used + // is out of the scope of the rule + + // This pattern that can be found in benchmarks and examples + // should be allowed. + continue + } + prefix := "err" if id.IsExported() { prefix = "Err" @@ -69,7 +81,7 @@ func (w lintErrors) Visit(_ ast.Node) ast.Visitor { w.onFailure(lint.Failure{ Node: id, Confidence: 0.9, - Category: "naming", + Category: lint.FailureCategoryNaming, Failure: fmt.Sprintf("error var %s should have name of the form %sFoo", id.Name, prefix), }) } diff --git a/vendor/github.com/mgechev/revive/rule/error_return.go b/vendor/github.com/mgechev/revive/rule/error_return.go index a724e001c..812ca753c 100644 --- a/vendor/github.com/mgechev/revive/rule/error_return.go +++ b/vendor/github.com/mgechev/revive/rule/error_return.go @@ -3,26 +3,45 @@ package rule import ( "go/ast" + "github.com/mgechev/revive/internal/astutils" "github.com/mgechev/revive/lint" ) -// ErrorReturnRule lints given else constructs. +// ErrorReturnRule ensures that the error return parameter is the last parameter. type ErrorReturnRule struct{} // Apply applies the rule to given file. func (*ErrorReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure - fileAst := file.AST - walker := lintErrorReturn{ - file: file, - fileAst: fileAst, - onFailure: func(failure lint.Failure) { - failures = append(failures, failure) - }, - } + for _, decl := range file.AST.Decls { + funcDecl, ok := decl.(*ast.FuncDecl) + isFunctionWithMoreThanOneResult := ok && funcDecl.Type.Results != nil && len(funcDecl.Type.Results.List) > 1 + if !isFunctionWithMoreThanOneResult { + continue + } + + funcResults := funcDecl.Type.Results.List + isLastResultError := astutils.IsIdent(funcResults[len(funcResults)-1].Type, "error") + if isLastResultError { + continue + } - ast.Walk(walker, fileAst) + // An error return parameter should be the last parameter. + // Flag any error parameters found before the last. + for _, r := range funcResults[:len(funcResults)-1] { + if astutils.IsIdent(r.Type, "error") { + failures = append(failures, lint.Failure{ + Category: lint.FailureCategoryStyle, + Confidence: 0.9, + Node: funcDecl, + Failure: "error should be the last type when returning multiple items", + }) + + break // only flag one + } + } + } return failures } @@ -31,37 +50,3 @@ func (*ErrorReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure func (*ErrorReturnRule) Name() string { return "error-return" } - -type lintErrorReturn struct { - file *lint.File - fileAst *ast.File - onFailure func(lint.Failure) -} - -func (w lintErrorReturn) Visit(n ast.Node) ast.Visitor { - fn, ok := n.(*ast.FuncDecl) - if !ok || fn.Type.Results == nil { - return w - } - ret := fn.Type.Results.List - if len(ret) <= 1 { - return w - } - if isIdent(ret[len(ret)-1].Type, "error") { - return nil - } - // An error return parameter should be the last parameter. - // Flag any error parameters found before the last. - for _, r := range ret[:len(ret)-1] { - if isIdent(r.Type, "error") { - w.onFailure(lint.Failure{ - Category: "arg-order", - Confidence: 0.9, - Node: fn, - Failure: "error should be the last type when returning multiple items", - }) - break // only flag one - } - } - return w -} diff --git a/vendor/github.com/mgechev/revive/rule/error_strings.go b/vendor/github.com/mgechev/revive/rule/error_strings.go index 97a0f4d06..53a585bfb 100644 --- a/vendor/github.com/mgechev/revive/rule/error_strings.go +++ b/vendor/github.com/mgechev/revive/rule/error_strings.go @@ -1,25 +1,26 @@ package rule import ( + "fmt" "go/ast" "go/token" "strconv" "strings" - "sync" "unicode" "unicode/utf8" "github.com/mgechev/revive/lint" ) -// ErrorStringsRule lints given else constructs. +// ErrorStringsRule lints error strings. type ErrorStringsRule struct { errorFunctions map[string]map[string]struct{} - - configureOnce sync.Once } -func (r *ErrorStringsRule) configure(arguments lint.Arguments) { +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *ErrorStringsRule) Configure(arguments lint.Arguments) error { r.errorFunctions = map[string]map[string]struct{}{ "fmt": { "Errorf": {}, @@ -36,26 +37,30 @@ func (r *ErrorStringsRule) configure(arguments lint.Arguments) { var invalidCustomFunctions []string for _, argument := range arguments { - if functionName, ok := argument.(string); ok { - fields := strings.Split(strings.TrimSpace(functionName), ".") - if len(fields) != 2 || len(fields[0]) == 0 || len(fields[1]) == 0 { - invalidCustomFunctions = append(invalidCustomFunctions, functionName) - continue - } - r.errorFunctions[fields[0]] = map[string]struct{}{fields[1]: {}} + pkgFunction, ok := argument.(string) + if !ok { + continue + } + pkg, function, ok := strings.Cut(strings.TrimSpace(pkgFunction), ".") + if !ok || pkg == "" || function == "" { + invalidCustomFunctions = append(invalidCustomFunctions, pkgFunction) + continue + } + if _, ok := r.errorFunctions[pkg]; !ok { + r.errorFunctions[pkg] = map[string]struct{}{} } + r.errorFunctions[pkg][function] = struct{}{} } if len(invalidCustomFunctions) != 0 { - panic("found invalid custom function: " + strings.Join(invalidCustomFunctions, ",")) + return fmt.Errorf("found invalid custom function: %s", strings.Join(invalidCustomFunctions, ",")) } + return nil } // Apply applies the rule to given file. -func (r *ErrorStringsRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { +func (r *ErrorStringsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure - r.configureOnce.Do(func() { r.configure(arguments) }) - fileAst := file.AST walker := lintErrorStrings{ file: file, @@ -83,7 +88,7 @@ type lintErrorStrings struct { onFailure func(lint.Failure) } -// Visit browses the AST +// Visit browses the AST. func (w lintErrorStrings) Visit(n ast.Node) ast.Visitor { ce, ok := n.(*ast.CallExpr) if !ok { @@ -115,14 +120,14 @@ func (w lintErrorStrings) Visit(n ast.Node) ast.Visitor { w.onFailure(lint.Failure{ Node: str, Confidence: conf, - Category: "errors", + Category: lint.FailureCategoryErrors, Failure: "error strings should not be capitalized or end with punctuation or a newline", }) return w } -// match returns true if the expression corresponds to the known pkg.function -// i.e.: errors.Wrap +// match returns true if the expression corresponds to the known pkg.function, +// i.e.: errors.Wrap. func (w lintErrorStrings) match(expr *ast.CallExpr) bool { sel, ok := expr.Fun.(*ast.SelectorExpr) if !ok { @@ -142,8 +147,8 @@ func (w lintErrorStrings) match(expr *ast.CallExpr) bool { return ok } -// getMessage returns the message depending on its position -// returns false if the cast is unsuccessful +// getMessage returns the message depending on its position. +// Returns false if the cast is unsuccessful. func (w lintErrorStrings) getMessage(expr *ast.CallExpr) (s *ast.BasicLit, success bool) { str, ok := w.checkArg(expr, 0) if ok { @@ -173,21 +178,29 @@ func (lintErrorStrings) checkArg(expr *ast.CallExpr, arg int) (s *ast.BasicLit, func lintErrorString(s string) (isClean bool, conf float64) { const basicConfidence = 0.8 const capConfidence = basicConfidence - 0.2 - first, firstN := utf8.DecodeRuneInString(s) + last, _ := utf8.DecodeLastRuneInString(s) if last == '.' || last == ':' || last == '!' || last == '\n' { return false, basicConfidence } - if unicode.IsUpper(first) { - // People use proper nouns and exported Go identifiers in error strings, - // so decrease the confidence of warnings for capitalization. - if len(s) <= firstN { - return false, capConfidence + + first, firstN := utf8.DecodeRuneInString(s) + if !unicode.IsUpper(first) { + return true, 0 + } + + // People use proper nouns and exported Go identifiers in error strings, + // so decrease the confidence of warnings for capitalization. + for _, r := range s[firstN:] { + if unicode.IsSpace(r) { + break } - // Flag strings starting with something that doesn't look like an initialism. - if second, _ := utf8.DecodeRuneInString(s[firstN:]); !unicode.IsUpper(second) { - return false, capConfidence + + if unicode.IsUpper(r) || unicode.IsDigit(r) { + return true, 0 // accept words with more than 2 capital letters or digits (e.g. GitHub, URLs, I2000) } } - return true, 0 + + // Flag strings starting with something that doesn't look like an initialism. + return false, capConfidence } diff --git a/vendor/github.com/mgechev/revive/rule/errorf.go b/vendor/github.com/mgechev/revive/rule/errorf.go index 1588a745d..a7c115944 100644 --- a/vendor/github.com/mgechev/revive/rule/errorf.go +++ b/vendor/github.com/mgechev/revive/rule/errorf.go @@ -6,10 +6,11 @@ import ( "regexp" "strings" + "github.com/mgechev/revive/internal/astutils" "github.com/mgechev/revive/lint" ) -// ErrorfRule lints given else constructs. +// ErrorfRule suggests using `fmt.Errorf` instead of `errors.New(fmt.Sprintf())`. type ErrorfRule struct{} // Apply applies the rule to given file. @@ -47,7 +48,7 @@ func (w lintErrorf) Visit(n ast.Node) ast.Visitor { if !ok || len(ce.Args) != 1 { return w } - isErrorsNew := isPkgDot(ce.Fun, "errors", "New") + isErrorsNew := astutils.IsPkgDotName(ce.Fun, "errors", "New") var isTestingError bool se, ok := ce.Fun.(*ast.SelectorExpr) if ok && se.Sel.Name == "Error" { @@ -60,7 +61,7 @@ func (w lintErrorf) Visit(n ast.Node) ast.Visitor { } arg := ce.Args[0] ce, ok = arg.(*ast.CallExpr) - if !ok || !isPkgDot(ce.Fun, "fmt", "Sprintf") { + if !ok || !astutils.IsPkgDotName(ce.Fun, "fmt", "Sprintf") { return w } errorfPrefix := "fmt" @@ -69,7 +70,7 @@ func (w lintErrorf) Visit(n ast.Node) ast.Visitor { } failure := lint.Failure{ - Category: "errors", + Category: lint.FailureCategoryErrors, Node: n, Confidence: 1, Failure: fmt.Sprintf("should replace %s(fmt.Sprintf(...)) with %s.Errorf(...)", w.file.Render(se), errorfPrefix), diff --git a/vendor/github.com/mgechev/revive/rule/exported.go b/vendor/github.com/mgechev/revive/rule/exported.go index 7ee27b309..9d8ace8e5 100644 --- a/vendor/github.com/mgechev/revive/rule/exported.go +++ b/vendor/github.com/mgechev/revive/rule/exported.go @@ -5,7 +5,6 @@ import ( "go/ast" "go/token" "strings" - "sync" "unicode" "unicode/utf8" @@ -13,23 +12,25 @@ import ( "github.com/mgechev/revive/lint" ) -// disabledChecks store ignored warnings types +// disabledChecks store ignored warnings types. type disabledChecks struct { Const bool Function bool Method bool PrivateReceivers bool PublicInterfaces bool - Stuttering bool + RepetitiveNames bool Type bool Var bool } -const checkNamePrivateReceivers = "privateReceivers" -const checkNamePublicInterfaces = "publicInterfaces" -const checkNameStuttering = "stuttering" +const ( + checkNamePrivateReceivers = "privateReceivers" + checkNamePublicInterfaces = "publicInterfaces" + checkNameStuttering = "stuttering" +) -// isDisabled returns true if the given check is disabled, false otherwise +// isDisabled returns true if the given check is disabled, false otherwise. func (dc *disabledChecks) isDisabled(checkName string) bool { switch checkName { case "var": @@ -45,7 +46,7 @@ func (dc *disabledChecks) isDisabled(checkName string) bool { case checkNamePublicInterfaces: return dc.PublicInterfaces case checkNameStuttering: - return dc.Stuttering + return dc.RepetitiveNames case "type": return dc.Type default: @@ -53,71 +54,78 @@ func (dc *disabledChecks) isDisabled(checkName string) bool { } } -// ExportedRule lints given else constructs. -type ExportedRule struct { - stuttersMsg string - disabledChecks disabledChecks +var commonMethods = map[string]bool{ + "Error": true, + "Read": true, + "ServeHTTP": true, + "String": true, + "Write": true, + "Unwrap": true, +} - configureOnce sync.Once +// ExportedRule lints naming and commenting conventions on exported symbols. +type ExportedRule struct { + isRepetitiveMsg string + disabledChecks disabledChecks } -func (r *ExportedRule) configure(arguments lint.Arguments) { +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configure makes the rule implement the [lint.ConfigurableRule] interface. +func (r *ExportedRule) Configure(arguments lint.Arguments) error { r.disabledChecks = disabledChecks{PrivateReceivers: true, PublicInterfaces: true} - r.stuttersMsg = "stutters" + r.isRepetitiveMsg = "stutters" for _, flag := range arguments { switch flag := flag.(type) { case string: - switch flag { - case "checkPrivateReceivers": + switch { + case isRuleOption(flag, "checkPrivateReceivers"): r.disabledChecks.PrivateReceivers = false - case "disableStutteringCheck": - r.disabledChecks.Stuttering = true - case "sayRepetitiveInsteadOfStutters": - r.stuttersMsg = "is repetitive" - case "checkPublicInterface": + case isRuleOption(flag, "disableStutteringCheck"): + r.disabledChecks.RepetitiveNames = true + case isRuleOption(flag, "sayRepetitiveInsteadOfStutters"): + r.isRepetitiveMsg = "is repetitive" + case isRuleOption(flag, "checkPublicInterface"): r.disabledChecks.PublicInterfaces = false - case "disableChecksOnConstants": + case isRuleOption(flag, "disableChecksOnConstants"): r.disabledChecks.Const = true - case "disableChecksOnFunctions": + case isRuleOption(flag, "disableChecksOnFunctions"): r.disabledChecks.Function = true - case "disableChecksOnMethods": + case isRuleOption(flag, "disableChecksOnMethods"): r.disabledChecks.Method = true - case "disableChecksOnTypes": + case isRuleOption(flag, "disableChecksOnTypes"): r.disabledChecks.Type = true - case "disableChecksOnVariables": + case isRuleOption(flag, "disableChecksOnVariables"): r.disabledChecks.Var = true default: - panic(fmt.Sprintf("Unknown configuration flag %s for %s rule", flag, r.Name())) + return fmt.Errorf("unknown configuration flag %s for %s rule", flag, r.Name()) } default: - panic(fmt.Sprintf("Invalid argument for the %s rule: expecting a string, got %T", r.Name(), flag)) + return fmt.Errorf("invalid argument for the %s rule: expecting a string, got %T", r.Name(), flag) } } + + return nil } // Apply applies the rule to given file. -func (r *ExportedRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(args) }) - - var failures []lint.Failure - if file.IsTest() { - return failures +func (r *ExportedRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { + if !file.IsImportable() { + return nil } - fileAst := file.AST - + var failures []lint.Failure walker := lintExported{ - file: file, - fileAst: fileAst, + file: file, onFailure: func(failure lint.Failure) { failures = append(failures, failure) }, - genDeclMissingComments: make(map[*ast.GenDecl]bool), - stuttersMsg: r.stuttersMsg, + genDeclMissingComments: map[*ast.GenDecl]bool{}, + isRepetitiveMsg: r.isRepetitiveMsg, disabledChecks: r.disabledChecks, } - ast.Walk(&walker, fileAst) + ast.Walk(&walker, file.AST) return failures } @@ -129,11 +137,10 @@ func (*ExportedRule) Name() string { type lintExported struct { file *lint.File - fileAst *ast.File - lastGen *ast.GenDecl + lastGenDecl *ast.GenDecl // the last visited general declaration in the AST genDeclMissingComments map[*ast.GenDecl]bool onFailure func(lint.Failure) - stuttersMsg string + isRepetitiveMsg string disabledChecks disabledChecks } @@ -144,26 +151,13 @@ func (w *lintExported) lintFuncDoc(fn *ast.FuncDecl) { kind := "function" name := fn.Name.Name - isMethod := fn.Recv != nil && len(fn.Recv.List) > 0 - if isMethod { - kind = "method" - recv := typeparams.ReceiverType(fn) - - if !ast.IsExported(recv) && w.disabledChecks.PrivateReceivers { - return - } - - if commonMethods[name] { + if isMethod := fn.Recv != nil && len(fn.Recv.List) > 0; isMethod { + if !w.mustCheckMethod(fn) { return } - switch name { - case "Len", "Less", "Swap": - sortables := w.file.Pkg.Sortable() - if sortables[recv] { - return - } - } + kind = "method" + recv := typeparams.ReceiverType(fn) name = recv + "." + name } @@ -171,42 +165,52 @@ func (w *lintExported) lintFuncDoc(fn *ast.FuncDecl) { return } - if fn.Doc == nil { - w.onFailure(lint.Failure{ - Node: fn, - Confidence: 1, - Category: "comments", - Failure: fmt.Sprintf("exported %s %s should have comment or be unexported", kind, name), - }) + status := w.checkGoDocStatus(fn.Doc, fn.Name.Name) + switch status { + case exportedGoDocStatusOK: + return // comment is fine + case exportedGoDocStatusMissing: + w.addFailuref(fn, status.confidence(), lint.FailureCategoryComments, + "exported %s %s should have comment or be unexported", kind, name, + ) return } - s := normalizeText(fn.Doc.Text()) - prefix := fn.Name.Name + " " - if !strings.HasPrefix(s, prefix) { - w.onFailure(lint.Failure{ - Node: fn.Doc, - Confidence: 0.8, - Category: "comments", - Failure: fmt.Sprintf(`comment on exported %s %s should be of the form "%s..."`, kind, name, prefix), - }) + firstCommentLine := w.firstCommentLine(fn.Doc) + w.addFailuref(fn.Doc, status.confidence(), lint.FailureCategoryComments, + `comment on exported %s %s should be of the form "%s ..."%s`, kind, name, fn.Name.Name, status.correctionHint(firstCommentLine), + ) +} + +func (*lintExported) hasPrefixInsensitive(s, prefix string) bool { + return strings.HasPrefix(strings.ToLower(s), strings.ToLower(prefix)) +} + +func (*lintExported) stripFirstRune(s string) string { + // Decode the first rune to handle multi-byte characters. + firstRune, size := utf8.DecodeRuneInString(s) + if firstRune == utf8.RuneError { + return s // no valid first rune found } + + // Return the string without the first rune. + return s[size:] } -func (w *lintExported) checkStutter(id *ast.Ident, thing string) { - if w.disabledChecks.Stuttering { +func (w *lintExported) checkRepetitiveNames(id *ast.Ident, thing string) { + if w.disabledChecks.RepetitiveNames { return } - pkg, name := w.fileAst.Name.Name, id.Name + pkg, name := w.file.AST.Name.Name, id.Name if !ast.IsExported(name) { // unexported name return } - // A name stutters if the package name is a strict prefix + // A name is repetitive if the package name is a strict prefix // and the next character of the name starts a new word. if len(name) <= len(pkg) { - // name is too short to stutter. + // name is too short to be a repetition. // This permits the name to be the same as the package name. return } @@ -215,61 +219,73 @@ func (w *lintExported) checkStutter(id *ast.Ident, thing string) { } // We can assume the name is well-formed UTF-8. // If the next rune after the package name is uppercase or an underscore - // the it's starting a new word and thus this name stutters. + // the it's starting a new word and thus this name is repetitive. rem := name[len(pkg):] if next, _ := utf8.DecodeRuneInString(rem); next == '_' || unicode.IsUpper(next) { - w.onFailure(lint.Failure{ - Node: id, - Confidence: 0.8, - Category: "naming", - Failure: fmt.Sprintf("%s name will be used as %s.%s by other packages, and that %s; consider calling this %s", thing, pkg, name, w.stuttersMsg, rem), - }) + w.addFailuref(id, 0.8, lint.FailureCategoryNaming, + "%s name will be used as %s.%s by other packages, and that %s; consider calling this %s", thing, pkg, name, w.isRepetitiveMsg, rem, + ) } } -func (w *lintExported) lintTypeDoc(t *ast.TypeSpec, doc *ast.CommentGroup) { +var articles = [...]string{"A", "An", "The", "This"} + +func (w *lintExported) lintTypeDoc(t *ast.TypeSpec, doc *ast.CommentGroup, firstCommentLine string) { if w.disabledChecks.isDisabled("type") { return } - if !ast.IsExported(t.Name.Name) { + typeName := t.Name.Name + + if !ast.IsExported(typeName) { return } - if doc == nil { - w.onFailure(lint.Failure{ - Node: t, - Confidence: 1, - Category: "comments", - Failure: fmt.Sprintf("exported type %v should have comment or be unexported", t.Name), - }) + if firstCommentLine == "" { + w.addFailuref(t, 1, lint.FailureCategoryComments, + "exported type %v should have comment or be unexported", t.Name, + ) return } - s := normalizeText(doc.Text()) - articles := [...]string{"A", "An", "The", "This"} + expectedPrefix := typeName for _, a := range articles { - if t.Name.Name == a { + if typeName == a { continue } - if strings.HasPrefix(s, a+" ") { - s = s[len(a)+1:] + var found bool + if firstCommentLine, found = strings.CutPrefix(firstCommentLine, a+" "); found { + expectedPrefix = a + " " + typeName break } } - // if comment starts with name of type and has some text after - it's ok - expectedPrefix := t.Name.Name + " " - if strings.HasPrefix(s, expectedPrefix) { + status := w.checkGoDocStatus(doc, expectedPrefix) + if status == exportedGoDocStatusOK { return } + w.addFailuref(doc, status.confidence(), lint.FailureCategoryComments, + `comment on exported type %v should be of the form "%s ..." (with optional leading article)%s`, t.Name, typeName, status.correctionHint(firstCommentLine), + ) +} - w.onFailure(lint.Failure{ - Node: doc, - Confidence: 1, - Category: "comments", - Failure: fmt.Sprintf(`comment on exported type %v should be of the form "%s..." (with optional leading article)`, t.Name, expectedPrefix), - }) +// checkValueNames returns true if names check, false otherwise. +func (w *lintExported) checkValueNames(names []*ast.Ident, nodeToBlame ast.Node, kind string) bool { + // Check that none are exported except for the first. + if len(names) < 2 { + return true // nothing to check + } + + for _, n := range names[1:] { + if ast.IsExported(n.Name) { + w.addFailuref(nodeToBlame, 1, lint.FailureCategoryComments, + "exported %s %s should have its own declaration", kind, n.Name, + ) + return false + } + } + + return true } func (w *lintExported) lintValueSpecDoc(vs *ast.ValueSpec, gd *ast.GenDecl, genDeclMissingComments map[*ast.GenDecl]bool) { @@ -282,19 +298,8 @@ func (w *lintExported) lintValueSpecDoc(vs *ast.ValueSpec, gd *ast.GenDecl, genD return } - if len(vs.Names) > 1 { - // Check that none are exported except for the first. - for _, n := range vs.Names[1:] { - if ast.IsExported(n.Name) { - w.onFailure(lint.Failure{ - Category: "comments", - Confidence: 1, - Failure: fmt.Sprintf("exported %s %s should have its own declaration", kind, n.Name), - Node: vs, - }) - return - } - } + if !w.checkValueNames(vs.Names, vs, kind) { + return } // Only one name. @@ -303,7 +308,9 @@ func (w *lintExported) lintValueSpecDoc(vs *ast.ValueSpec, gd *ast.GenDecl, genD return } - if vs.Doc == nil && gd.Doc == nil { + vsFirstCommentLine := w.firstCommentLine(vs.Doc) + gdFirstCommentLine := w.firstCommentLine(gd.Doc) + if vsFirstCommentLine == "" && gdFirstCommentLine == "" { if genDeclMissingComments[gd] { return } @@ -311,77 +318,151 @@ func (w *lintExported) lintValueSpecDoc(vs *ast.ValueSpec, gd *ast.GenDecl, genD if kind == "const" && gd.Lparen.IsValid() { block = " (or a comment on this block)" } - w.onFailure(lint.Failure{ - Confidence: 1, - Node: vs, - Category: "comments", - Failure: fmt.Sprintf("exported %s %s should have comment%s or be unexported", kind, name, block), - }) + w.addFailuref(vs, 1, lint.FailureCategoryComments, + "exported %s %s should have comment%s or be unexported", kind, name, block, + ) genDeclMissingComments[gd] = true return } + // If this GenDecl has parens and a comment, we don't check its comment form. - if gd.Doc != nil && gd.Lparen.IsValid() { + if gdFirstCommentLine != "" && gd.Lparen.IsValid() { return } + // The relevant text to check will be on either vs.Doc or gd.Doc. // Use vs.Doc preferentially. var doc *ast.CommentGroup switch { - case vs.Doc != nil: + case vsFirstCommentLine != "": doc = vs.Doc - case vs.Comment != nil && gd.Doc == nil: + case vsFirstCommentLine != "" && gdFirstCommentLine == "": doc = vs.Comment default: doc = gd.Doc } + firstCommentLine := w.firstCommentLine(doc) - prefix := name + " " - s := normalizeText(doc.Text()) - if !strings.HasPrefix(s, prefix) { - w.onFailure(lint.Failure{ - Confidence: 1, - Node: doc, - Category: "comments", - Failure: fmt.Sprintf(`comment on exported %s %s should be of the form "%s..."`, kind, name, prefix), - }) + status := w.checkGoDocStatus(doc, name) + if status == exportedGoDocStatusOK { + return } + w.addFailuref(doc, status.confidence(), lint.FailureCategoryComments, + `comment on exported %s %s should be of the form "%s ..."%s`, kind, name, name, status.correctionHint(firstCommentLine), + ) } -// normalizeText is a helper function that normalizes comment strings by: -// * removing one leading space -// -// This function is needed because ast.CommentGroup.Text() does not handle //-style and /*-style comments uniformly -func normalizeText(t string) string { - return strings.TrimSpace(t) +type exportedGoDocStatus int + +const ( + exportedGoDocStatusOK exportedGoDocStatus = iota + exportedGoDocStatusMissing + exportedGoDocStatusCaseMismatch + exportedGoDocStatusFirstLetterMismatch + exportedGoDocStatusUnexpected +) + +func (gds exportedGoDocStatus) confidence() float64 { + if gds == exportedGoDocStatusUnexpected { + return 0.8 + } + return 1 +} + +func (gds exportedGoDocStatus) correctionHint(firstCommentLine string) string { + firstWord := strings.Split(firstCommentLine, " ")[0] + switch gds { + case exportedGoDocStatusCaseMismatch: + return ` by using its correct casing, not "` + firstWord + ` ..."` + case exportedGoDocStatusFirstLetterMismatch: + return ` to match its exported status, not "` + firstWord + ` ..."` + } + + return "" +} + +func (w *lintExported) checkGoDocStatus(comment *ast.CommentGroup, name string) exportedGoDocStatus { + firstCommentLine := w.firstCommentLine(comment) + if firstCommentLine == "" { + return exportedGoDocStatusMissing + } + + name = strings.TrimSpace(name) + // Make sure the expected prefix has a space at the end. + expectedPrefix := name + " " + if strings.HasPrefix(firstCommentLine, expectedPrefix) { + return exportedGoDocStatusOK + } + + if !w.hasPrefixInsensitive(firstCommentLine, expectedPrefix) { + return exportedGoDocStatusUnexpected + } + + if strings.HasPrefix(w.stripFirstRune(firstCommentLine), w.stripFirstRune(expectedPrefix)) { + // Only the first character differs, such as "sendJSON" became "SendJSON". + // so we consider the scope has changed. + return exportedGoDocStatusFirstLetterMismatch + } + + return exportedGoDocStatusCaseMismatch +} + +// firstCommentLine yields the first line of interest in comment group or "" if there is nothing of interest. +// An "interesting line" is a comment line that is neither a directive (e.g. `//go:...`) or a deprecation comment +// (lines from the first line with a prefix `// Deprecated:` to the end of the comment group). +// Empty or spaces-only lines are discarded. +func (*lintExported) firstCommentLine(comment *ast.CommentGroup) (result string) { + if comment == nil { + return "" + } + + commentWithoutDirectives := comment.Text() // removes directives from the comment block + for line := range strings.SplitSeq(commentWithoutDirectives, "\n") { + line := strings.TrimSpace(line) + if line == "" { + continue // ignore empty lines + } + if strings.HasPrefix(line, "Deprecated: ") { + break // ignore deprecation comment line and the subsequent lines of the original comment + } + + result = line + break // first non-directive/non-empty/non-deprecation comment line found + } + + return result } func (w *lintExported) Visit(n ast.Node) ast.Visitor { switch v := n.(type) { case *ast.GenDecl: - if v.Tok == token.IMPORT { + switch v.Tok { + case token.IMPORT: return nil + case token.CONST, token.TYPE, token.VAR: + w.lastGenDecl = v } - // token.CONST, token.TYPE or token.VAR - w.lastGen = v return w case *ast.FuncDecl: w.lintFuncDoc(v) if v.Recv == nil { - // Only check for stutter on functions, not methods. + // Only check for repetitive names on functions, not methods. // Method names are not used package-qualified. - w.checkStutter(v.Name, "func") + w.checkRepetitiveNames(v.Name, "func") } // Don't proceed inside funcs. return nil case *ast.TypeSpec: // inside a GenDecl, which usually has the doc doc := v.Doc - if doc == nil { - doc = w.lastGen.Doc + + fcl := w.firstCommentLine(doc) + if fcl == "" { + doc = w.lastGenDecl.Doc + fcl = w.firstCommentLine(doc) } - w.lintTypeDoc(v, doc) - w.checkStutter(v.Name, "type") + w.lintTypeDoc(v, doc, fcl) + w.checkRepetitiveNames(v.Name, "type") if !w.disabledChecks.PublicInterfaces { if iface, ok := v.Type.(*ast.InterfaceType); ok { @@ -393,7 +474,7 @@ func (w *lintExported) Visit(n ast.Node) ast.Visitor { return nil case *ast.ValueSpec: - w.lintValueSpecDoc(v, w.lastGen, w.genDeclMissingComments) + w.lintValueSpecDoc(v, w.lastGenDecl, w.genDeclMissingComments) return nil } return w @@ -412,24 +493,54 @@ func (w *lintExported) lintInterfaceMethod(typeName string, m *ast.Field) { if !ast.IsExported(m.Names[0].Name) { return } + name := m.Names[0].Name - if m.Doc == nil { - w.onFailure(lint.Failure{ - Node: m, - Confidence: 1, - Category: "comments", - Failure: fmt.Sprintf("public interface method %s.%s should be commented", typeName, name), - }) + status := w.checkGoDocStatus(m.Doc, name) + switch status { + case exportedGoDocStatusOK: + return // comment is fine + case exportedGoDocStatusMissing: + w.addFailuref(m, status.confidence(), lint.FailureCategoryComments, + "public interface method %s.%s should be commented", typeName, name, + ) return } - s := normalizeText(m.Doc.Text()) - expectedPrefix := m.Names[0].Name + " " - if !strings.HasPrefix(s, expectedPrefix) { - w.onFailure(lint.Failure{ - Node: m.Doc, - Confidence: 0.8, - Category: "comments", - Failure: fmt.Sprintf(`comment on exported interface method %s.%s should be of the form "%s..."`, typeName, name, expectedPrefix), - }) + + firstCommentLine := w.firstCommentLine(m.Doc) + w.addFailuref(m.Doc, status.confidence(), lint.FailureCategoryComments, + `comment on exported interface method %s.%s should be of the form "%s ..."%s`, typeName, name, name, status.correctionHint(firstCommentLine), + ) +} + +// mustCheckMethod returns true if the method must be checked by this rule, false otherwise. +func (w *lintExported) mustCheckMethod(fn *ast.FuncDecl) bool { + recv := typeparams.ReceiverType(fn) + + if !ast.IsExported(recv) && w.disabledChecks.PrivateReceivers { + return false + } + + name := fn.Name.Name + if commonMethods[name] { + return false + } + + switch name { + case "Len", "Less", "Swap": + sortables := w.file.Pkg.Sortable() + if sortables[recv] { + return false + } } + + return true +} + +func (w *lintExported) addFailuref(node ast.Node, confidence float64, category lint.FailureCategory, message string, args ...any) { + w.onFailure(lint.Failure{ + Node: node, + Confidence: confidence, + Category: category, + Failure: fmt.Sprintf(message, args...), + }) } diff --git a/vendor/github.com/mgechev/revive/rule/file_header.go b/vendor/github.com/mgechev/revive/rule/file_header.go index 52513d8e8..a6538b51c 100644 --- a/vendor/github.com/mgechev/revive/rule/file_header.go +++ b/vendor/github.com/mgechev/revive/rule/file_header.go @@ -3,16 +3,14 @@ package rule import ( "fmt" "regexp" - "sync" + "strings" "github.com/mgechev/revive/lint" ) -// FileHeaderRule lints given else constructs. +// FileHeaderRule lints the header that each file should have. type FileHeaderRule struct { header string - - configureOnce sync.Once } var ( @@ -20,22 +18,24 @@ var ( singleRegexp = regexp.MustCompile("^//") ) -func (r *FileHeaderRule) configure(arguments lint.Arguments) { +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *FileHeaderRule) Configure(arguments lint.Arguments) error { if len(arguments) < 1 { - return + return nil } var ok bool r.header, ok = arguments[0].(string) if !ok { - panic(fmt.Sprintf("invalid argument for \"file-header\" rule: argument should be a string, got %T", arguments[0])) + return fmt.Errorf(`invalid argument for "file-header" rule: argument should be a string, got %T`, arguments[0]) } + return nil } // Apply applies the rule to given file. -func (r *FileHeaderRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(arguments) }) - +func (r *FileHeaderRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { if r.header == "" { return nil } @@ -56,7 +56,7 @@ func (r *FileHeaderRule) Apply(file *lint.File, arguments lint.Arguments) []lint if g == nil { return failure } - comment := "" + var comment strings.Builder for _, c := range g.List { text := c.Text if multiRegexp.MatchString(text) { @@ -64,15 +64,15 @@ func (r *FileHeaderRule) Apply(file *lint.File, arguments lint.Arguments) []lint } else if singleRegexp.MatchString(text) { text = text[2:] } - comment += text + comment.WriteString(text) } regex, err := regexp.Compile(r.header) if err != nil { - panic(err.Error()) + return newInternalFailureError(err) } - if !regex.MatchString(comment) { + if !regex.MatchString(comment.String()) { return failure } return nil diff --git a/vendor/github.com/mgechev/revive/rule/file_length_limit.go b/vendor/github.com/mgechev/revive/rule/file_length_limit.go index 0fe075c56..c24db4353 100644 --- a/vendor/github.com/mgechev/revive/rule/file_length_limit.go +++ b/vendor/github.com/mgechev/revive/rule/file_length_limit.go @@ -7,7 +7,6 @@ import ( "go/ast" "go/token" "strings" - "sync" "github.com/mgechev/revive/lint" ) @@ -20,14 +19,10 @@ type FileLengthLimitRule struct { skipComments bool // skipBlankLines indicates whether to skip blank lines when counting lines. skipBlankLines bool - - configureOnce sync.Once } // Apply applies the rule to given file. -func (r *FileLengthLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(arguments) }) - +func (r *FileLengthLimitRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { if r.max <= 0 { // when max is negative or 0 the rule is disabled return nil @@ -44,7 +39,7 @@ func (r *FileLengthLimitRule) Apply(file *lint.File, arguments lint.Arguments) [ } if err := scanner.Err(); err != nil { - panic(err.Error()) + return newInternalFailureError(err) } lines := all @@ -62,7 +57,7 @@ func (r *FileLengthLimitRule) Apply(file *lint.File, arguments lint.Arguments) [ return []lint.Failure{ { - Category: "code-style", + Category: lint.FailureCategoryStyle, Confidence: 1, Position: lint.FailurePosition{ Start: token.Position{ @@ -75,37 +70,41 @@ func (r *FileLengthLimitRule) Apply(file *lint.File, arguments lint.Arguments) [ } } -func (r *FileLengthLimitRule) configure(arguments lint.Arguments) { +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *FileLengthLimitRule) Configure(arguments lint.Arguments) error { if len(arguments) < 1 { - return // use default + return nil // use default } argKV, ok := arguments[0].(map[string]any) if !ok { - panic(fmt.Sprintf(`invalid argument to the "file-length-limit" rule. Expecting a k,v map, got %T`, arguments[0])) + return fmt.Errorf(`invalid argument to the "file-length-limit" rule. Expecting a k,v map, got %T`, arguments[0]) } for k, v := range argKV { - switch k { - case "max": + switch { + case isRuleOption(k, "max"): maxLines, ok := v.(int64) if !ok || maxLines < 0 { - panic(fmt.Sprintf(`invalid configuration value for max lines in "file-length-limit" rule; need positive int64 but got %T`, arguments[0])) + return fmt.Errorf(`invalid configuration value for max lines in "file-length-limit" rule; need positive int64 but got %T`, v) } r.max = int(maxLines) - case "skipComments": + case isRuleOption(k, "skipComments"): skipComments, ok := v.(bool) if !ok { - panic(fmt.Sprintf(`invalid configuration value for skip comments in "file-length-limit" rule; need bool but got %T`, arguments[1])) + return fmt.Errorf(`invalid configuration value for skip comments in "file-length-limit" rule; need bool but got %T`, v) } r.skipComments = skipComments - case "skipBlankLines": + case isRuleOption(k, "skipBlankLines"): skipBlankLines, ok := v.(bool) if !ok { - panic(fmt.Sprintf(`invalid configuration value for skip blank lines in "file-length-limit" rule; need bool but got %T`, arguments[2])) + return fmt.Errorf(`invalid configuration value for skip blank lines in "file-length-limit" rule; need bool but got %T`, v) } r.skipBlankLines = skipBlankLines } } + return nil } // Name returns the rule name. diff --git a/vendor/github.com/mgechev/revive/rule/filename_format.go b/vendor/github.com/mgechev/revive/rule/filename_format.go index 9d8047829..960ebb0c8 100644 --- a/vendor/github.com/mgechev/revive/rule/filename_format.go +++ b/vendor/github.com/mgechev/revive/rule/filename_format.go @@ -4,23 +4,19 @@ import ( "fmt" "path/filepath" "regexp" - "sync" + "strings" "unicode" "github.com/mgechev/revive/lint" ) -// FilenameFormatRule lints source filenames according to a set of regular expressions given as arguments +// FilenameFormatRule lints source filenames according to a set of regular expressions given as arguments. type FilenameFormatRule struct { format *regexp.Regexp - - configureOnce sync.Once } // Apply applies the rule to the given file. -func (r *FilenameFormatRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(arguments) }) - +func (r *FilenameFormatRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { filename := filepath.Base(file.Name) if r.format.MatchString(filename) { return nil @@ -35,17 +31,17 @@ func (r *FilenameFormatRule) Apply(file *lint.File, arguments lint.Arguments) [] }} } -func (r *FilenameFormatRule) getMsgForNonASCIIChars(str string) string { - result := "" +func (*FilenameFormatRule) getMsgForNonASCIIChars(str string) string { + var result strings.Builder for _, c := range str { if c <= unicode.MaxASCII { continue } - result += fmt.Sprintf(" Non ASCII character %c (%U) found.", c, c) + fmt.Fprintf(&result, " Non ASCII character %c (%U) found.", c, c) } - return result + return result.String() } // Name returns the rule name. @@ -53,29 +49,34 @@ func (*FilenameFormatRule) Name() string { return "filename-format" } -var defaultFormat = regexp.MustCompile("^[_A-Za-z0-9][_A-Za-z0-9-]*.go$") +var defaultFormat = regexp.MustCompile(`^[_A-Za-z0-9][_A-Za-z0-9-]*\.go$`) -func (r *FilenameFormatRule) configure(arguments lint.Arguments) { +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *FilenameFormatRule) Configure(arguments lint.Arguments) error { argsCount := len(arguments) if argsCount == 0 { r.format = defaultFormat - return + return nil } if argsCount > 1 { - panic(fmt.Sprintf("rule %q expects only one argument, got %d %v", r.Name(), argsCount, arguments)) + return fmt.Errorf("rule %q expects only one argument, got %d %v", r.Name(), argsCount, arguments) } arg := arguments[0] str, ok := arg.(string) if !ok { - panic(fmt.Sprintf("rule %q expects a string argument, got %v of type %T", r.Name(), arg, arg)) + return fmt.Errorf("rule %q expects a string argument, got %v of type %T", r.Name(), arg, arg) } format, err := regexp.Compile(str) if err != nil { - panic(fmt.Sprintf("rule %q expects a valid regexp argument, got %v for %s", r.Name(), err, arg)) + return fmt.Errorf("rule %q expects a valid regexp argument, got error for %s: %w", r.Name(), str, err) } r.format = format + + return nil } diff --git a/vendor/github.com/mgechev/revive/rule/flag_param.go b/vendor/github.com/mgechev/revive/rule/flag_param.go index f9bfb712c..54edcadc6 100644 --- a/vendor/github.com/mgechev/revive/rule/flag_param.go +++ b/vendor/github.com/mgechev/revive/rule/flag_param.go @@ -4,67 +4,58 @@ import ( "fmt" "go/ast" + "github.com/mgechev/revive/internal/astutils" "github.com/mgechev/revive/lint" ) -// FlagParamRule lints given else constructs. +// FlagParamRule warns on boolean parameters that create a control coupling. type FlagParamRule struct{} // Apply applies the rule to given file. func (*FlagParamRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure - onFailure := func(failure lint.Failure) { failures = append(failures, failure) } - w := lintFlagParamRule{onFailure: onFailure} - ast.Walk(w, file.AST) - return failures -} - -// Name returns the rule name. -func (*FlagParamRule) Name() string { - return "flag-parameter" -} - -type lintFlagParamRule struct { - onFailure func(lint.Failure) -} - -func (w lintFlagParamRule) Visit(node ast.Node) ast.Visitor { - fd, ok := node.(*ast.FuncDecl) - if !ok { - return w - } - - if fd.Body == nil { - return nil // skip whole function declaration - } + for _, decl := range file.AST.Decls { + fd, ok := decl.(*ast.FuncDecl) + isFuncWithNonEmptyBody := ok && fd.Body != nil + if !isFuncWithNonEmptyBody { + continue + } - for _, p := range fd.Type.Params.List { - t := p.Type + boolParams := map[string]struct{}{} + for _, param := range fd.Type.Params.List { + if !astutils.IsIdent(param.Type, "bool") { + continue + } - id, ok := t.(*ast.Ident) - if !ok { - continue + for _, paramIdent := range param.Names { + boolParams[paramIdent.Name] = struct{}{} + } } - if id.Name != "bool" { + if len(boolParams) == 0 { continue } - cv := conditionVisitor{p.Names, fd, w} + cv := conditionVisitor{boolParams, fd, onFailure} ast.Walk(cv, fd.Body) } - return w + return failures +} + +// Name returns the rule name. +func (*FlagParamRule) Name() string { + return "flag-parameter" } type conditionVisitor struct { - ids []*ast.Ident - fd *ast.FuncDecl - linter lintFlagParamRule + idents map[string]struct{} + fd *ast.FuncDecl + onFailure func(lint.Failure) } func (w conditionVisitor) Visit(node ast.Node) ast.Visitor { @@ -73,32 +64,30 @@ func (w conditionVisitor) Visit(node ast.Node) ast.Visitor { return w } - fselect := func(n ast.Node) bool { + findUsesOfIdents := func(n ast.Node) bool { ident, ok := n.(*ast.Ident) if !ok { return false } - for _, id := range w.ids { - if ident.Name == id.Name { - return true - } + _, ok = w.idents[ident.Name] + if !ok { + return false } - return false + return w.idents[ident.Name] == struct{}{} } - uses := pick(ifStmt.Cond, fselect) - - if len(uses) < 1 { + uses := astutils.SeekNode[*ast.Ident](ifStmt.Cond, findUsesOfIdents) + if uses == nil { return w } - w.linter.onFailure(lint.Failure{ + w.onFailure(lint.Failure{ Confidence: 1, Node: w.fd.Type.Params, - Category: "bad practice", - Failure: fmt.Sprintf("parameter '%s' seems to be a control flag, avoid control coupling", uses[0]), + Category: lint.FailureCategoryBadPractice, + Failure: fmt.Sprintf("parameter '%s' seems to be a control flag, avoid control coupling", uses.Name), }) return nil diff --git a/vendor/github.com/mgechev/revive/rule/forbidden_call_in_wg_go.go b/vendor/github.com/mgechev/revive/rule/forbidden_call_in_wg_go.go new file mode 100644 index 000000000..20a393621 --- /dev/null +++ b/vendor/github.com/mgechev/revive/rule/forbidden_call_in_wg_go.go @@ -0,0 +1,113 @@ +package rule + +import ( + "fmt" + "go/ast" + "strings" + + "github.com/mgechev/revive/internal/astutils" + "github.com/mgechev/revive/lint" +) + +// ForbiddenCallInWgGoRule spots calls to panic or wg.Done when using [sync.WaitGroup.Go]. +type ForbiddenCallInWgGoRule struct{} + +// Apply applies the rule to given file. +func (*ForbiddenCallInWgGoRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { + if !file.Pkg.IsAtLeastGoVersion(lint.Go125) { + return nil // skip analysis if Go version < 1.25 + } + + var failures []lint.Failure + + onFailure := func(failure lint.Failure) { + failures = append(failures, failure) + } + + w := &lintForbiddenCallInWgGo{ + onFailure: onFailure, + } + + // Iterate over declarations looking for function declarations + for _, decl := range file.AST.Decls { + fn, ok := decl.(*ast.FuncDecl) + if !ok { + continue // not a function + } + + if fn.Body == nil { + continue // external (no-Go) function + } + + // Analyze the function body + ast.Walk(w, fn.Body) + } + + return failures +} + +// Name returns the rule name. +func (*ForbiddenCallInWgGoRule) Name() string { + return "forbidden-call-in-wg-go" +} + +type lintForbiddenCallInWgGo struct { + onFailure func(lint.Failure) +} + +func (w *lintForbiddenCallInWgGo) Visit(node ast.Node) ast.Visitor { + call, ok := node.(*ast.CallExpr) + if !ok { + return w // not a call of statements + } + + if !astutils.IsPkgDotName(call.Fun, "wg", "Go") { + return w // not a call to wg.Go + } + + if len(call.Args) != 1 { + return nil // no argument (impossible) + } + + funcLit, ok := call.Args[0].(*ast.FuncLit) + if !ok { + return nil // the argument is not a function literal + } + + var callee string + + forbiddenCallPicker := func(n ast.Node) bool { + call, ok := n.(*ast.CallExpr) + if !ok { + return false + } + + if astutils.IsPkgDotName(call.Fun, "wg", "Done") || + astutils.IsIdent(call.Fun, "panic") || + astutils.IsPkgDotName(call.Fun, "log", "Panic") || + astutils.IsPkgDotName(call.Fun, "log", "Panicf") || + astutils.IsPkgDotName(call.Fun, "log", "Panicln") { + callee = astutils.GoFmt(n) + callee, _, _ = strings.Cut(callee, "(") + return true + } + + return false + } + + // search a forbidden call in the body of the function literal + forbiddenCall := astutils.SeekNode[*ast.CallExpr](funcLit.Body, forbiddenCallPicker) + if forbiddenCall == nil { + return nil // there is no forbidden call in the call to wg.Go + } + + msg := fmt.Sprintf("do not call %s inside wg.Go", callee) + w.onFailure(lint.Failure{ + Confidence: 1, + Node: forbiddenCall, + Category: lint.FailureCategoryErrors, + Failure: msg, + }) + + return nil +} diff --git a/vendor/github.com/mgechev/revive/rule/function_length.go b/vendor/github.com/mgechev/revive/rule/function_length.go index c58cd4c0f..53cb6827c 100644 --- a/vendor/github.com/mgechev/revive/rule/function_length.go +++ b/vendor/github.com/mgechev/revive/rule/function_length.go @@ -4,7 +4,6 @@ import ( "fmt" "go/ast" "reflect" - "sync" "github.com/mgechev/revive/lint" ) @@ -13,32 +12,58 @@ import ( type FunctionLength struct { maxStmt int maxLines int - - configureOnce sync.Once } -func (r *FunctionLength) configure(arguments lint.Arguments) { - maxStmt, maxLines := r.parseArguments(arguments) +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *FunctionLength) Configure(arguments lint.Arguments) error { + maxStmt, maxLines, err := r.parseArguments(arguments) + if err != nil { + return err + } r.maxStmt = int(maxStmt) r.maxLines = int(maxLines) + return nil } // Apply applies the rule to given file. -func (r *FunctionLength) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(arguments) }) - +func (r *FunctionLength) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure + for _, decl := range file.AST.Decls { + funcDecl, ok := decl.(*ast.FuncDecl) + if !ok { + continue + } - walker := lintFuncLength{ - file: file, - maxStmt: r.maxStmt, - maxLines: r.maxLines, - onFailure: func(failure lint.Failure) { - failures = append(failures, failure) - }, - } + body := funcDecl.Body + emptyBody := body == nil || len(body.List) == 0 + if emptyBody { + return nil + } - ast.Walk(walker, file.AST) + if r.maxStmt > 0 { + stmtCount := r.countStmts(body.List) + if stmtCount > r.maxStmt { + failures = append(failures, lint.Failure{ + Confidence: 1, + Failure: fmt.Sprintf("maximum number of statements per function exceeded; max %d but got %d", r.maxStmt, stmtCount), + Node: funcDecl, + }) + } + } + + if r.maxLines > 0 { + lineCount := r.countLines(body, file) + if lineCount > r.maxLines { + failures = append(failures, lint.Failure{ + Confidence: 1, + Failure: fmt.Sprintf("maximum number of lines per function exceeded; max %d but got %d", r.maxLines, lineCount), + Node: funcDecl, + }) + } + } + } return failures } @@ -48,111 +73,69 @@ func (*FunctionLength) Name() string { return "function-length" } -const defaultFuncStmtsLimit = 50 -const defaultFuncLinesLimit = 75 +const ( + defaultFuncStmtsLimit = 50 + defaultFuncLinesLimit = 75 +) -func (*FunctionLength) parseArguments(arguments lint.Arguments) (maxStmt, maxLines int64) { +func (*FunctionLength) parseArguments(arguments lint.Arguments) (maxStmt, maxLines int64, err error) { if len(arguments) == 0 { - return defaultFuncStmtsLimit, defaultFuncLinesLimit + return defaultFuncStmtsLimit, defaultFuncLinesLimit, nil } const minArguments = 2 if len(arguments) != minArguments { - panic(fmt.Sprintf(`invalid configuration for "function-length" rule, expected %d arguments but got %d`, minArguments, len(arguments))) + return 0, 0, fmt.Errorf(`invalid configuration for "function-length" rule, expected %d arguments but got %d`, minArguments, len(arguments)) } maxStmt, maxStmtOk := arguments[0].(int64) if !maxStmtOk { - panic(fmt.Sprintf(`invalid configuration value for max statements in "function-length" rule; need int64 but got %T`, arguments[0])) + return 0, 0, fmt.Errorf(`invalid configuration value for max statements in "function-length" rule; need int64 but got %T`, arguments[0]) } if maxStmt < 0 { - panic(fmt.Sprintf(`the configuration value for max statements in "function-length" rule cannot be negative, got %d`, maxStmt)) + return 0, 0, fmt.Errorf(`the configuration value for max statements in "function-length" rule cannot be negative, got %d`, maxStmt) } maxLines, maxLinesOk := arguments[1].(int64) if !maxLinesOk { - panic(fmt.Sprintf(`invalid configuration value for max lines in "function-length" rule; need int64 but got %T`, arguments[1])) + return 0, 0, fmt.Errorf(`invalid configuration value for max lines in "function-length" rule; need int64 but got %T`, arguments[1]) } if maxLines < 0 { - panic(fmt.Sprintf(`the configuration value for max statements in "function-length" rule cannot be negative, got %d`, maxLines)) - } - - return maxStmt, maxLines -} - -type lintFuncLength struct { - file *lint.File - maxStmt int - maxLines int - onFailure func(lint.Failure) -} - -func (w lintFuncLength) Visit(n ast.Node) ast.Visitor { - node, ok := n.(*ast.FuncDecl) - if !ok { - return w - } - - body := node.Body - emptyBody := body == nil || len(node.Body.List) == 0 - if emptyBody { - return nil + return 0, 0, fmt.Errorf(`the configuration value for max statements in "function-length" rule cannot be negative, got %d`, maxLines) } - if w.maxStmt > 0 { - stmtCount := w.countStmts(node.Body.List) - if stmtCount > w.maxStmt { - w.onFailure(lint.Failure{ - Confidence: 1, - Failure: fmt.Sprintf("maximum number of statements per function exceeded; max %d but got %d", w.maxStmt, stmtCount), - Node: node, - }) - } - } - - if w.maxLines > 0 { - lineCount := w.countLines(node.Body) - if lineCount > w.maxLines { - w.onFailure(lint.Failure{ - Confidence: 1, - Failure: fmt.Sprintf("maximum number of lines per function exceeded; max %d but got %d", w.maxLines, lineCount), - Node: node, - }) - } - } - - return nil + return maxStmt, maxLines, nil } -func (w lintFuncLength) countLines(b *ast.BlockStmt) int { - return w.file.ToPosition(b.End()).Line - w.file.ToPosition(b.Pos()).Line - 1 +func (*FunctionLength) countLines(b *ast.BlockStmt, file *lint.File) int { + return file.ToPosition(b.End()).Line - file.ToPosition(b.Pos()).Line - 1 } -func (w lintFuncLength) countStmts(b []ast.Stmt) int { +func (r *FunctionLength) countStmts(b []ast.Stmt) int { count := 0 for _, s := range b { switch stmt := s.(type) { case *ast.BlockStmt: - count += w.countStmts(stmt.List) + count += r.countStmts(stmt.List) case *ast.IfStmt: - count += 1 + w.countBodyListStmts(stmt) + count += 1 + r.countBodyListStmts(stmt) if stmt.Else != nil { elseBody, ok := stmt.Else.(*ast.BlockStmt) if ok { - count += w.countStmts(elseBody.List) + count += r.countStmts(elseBody.List) } } case *ast.ForStmt, *ast.RangeStmt, *ast.SwitchStmt, *ast.TypeSwitchStmt, *ast.SelectStmt: - count += 1 + w.countBodyListStmts(stmt) + count += 1 + r.countBodyListStmts(stmt) case *ast.CaseClause: - count += w.countStmts(stmt.Body) + count += r.countStmts(stmt.Body) case *ast.AssignStmt: - count += 1 + w.countFuncLitStmts(stmt.Rhs[0]) + count += 1 + r.countFuncLitStmts(stmt.Rhs[0]) case *ast.GoStmt: - count += 1 + w.countFuncLitStmts(stmt.Call.Fun) + count += 1 + r.countFuncLitStmts(stmt.Call.Fun) case *ast.DeferStmt: - count += 1 + w.countFuncLitStmts(stmt.Call.Fun) + count += 1 + r.countFuncLitStmts(stmt.Call.Fun) default: count++ } @@ -161,14 +144,15 @@ func (w lintFuncLength) countStmts(b []ast.Stmt) int { return count } -func (w lintFuncLength) countFuncLitStmts(stmt ast.Expr) int { +func (r *FunctionLength) countFuncLitStmts(stmt ast.Expr) int { if block, ok := stmt.(*ast.FuncLit); ok { - return w.countStmts(block.Body.List) + return r.countStmts(block.Body.List) } + return 0 } -func (w lintFuncLength) countBodyListStmts(t any) int { +func (r *FunctionLength) countBodyListStmts(t any) int { i := reflect.ValueOf(t).Elem().FieldByName(`Body`).Elem().FieldByName(`List`).Interface() - return w.countStmts(i.([]ast.Stmt)) + return r.countStmts(i.([]ast.Stmt)) } diff --git a/vendor/github.com/mgechev/revive/rule/function_result_limit.go b/vendor/github.com/mgechev/revive/rule/function_result_limit.go index 5b72f01ab..b5508f368 100644 --- a/vendor/github.com/mgechev/revive/rule/function_result_limit.go +++ b/vendor/github.com/mgechev/revive/rule/function_result_limit.go @@ -1,53 +1,43 @@ package rule import ( + "errors" "fmt" "go/ast" - "sync" "github.com/mgechev/revive/lint" ) -// FunctionResultsLimitRule lints given else constructs. +// FunctionResultsLimitRule limits the maximum number of results a function can return. type FunctionResultsLimitRule struct { max int - - configureOnce sync.Once -} - -const defaultResultsLimit = 3 - -func (r *FunctionResultsLimitRule) configure(arguments lint.Arguments) { - if len(arguments) < 1 { - r.max = defaultResultsLimit - return - } - - maxResults, ok := arguments[0].(int64) // Alt. non panicking version - if !ok { - panic(fmt.Sprintf(`invalid value passed as return results number to the "function-result-limit" rule; need int64 but got %T`, arguments[0])) - } - if maxResults < 0 { - panic(`the value passed as return results number to the "function-result-limit" rule cannot be negative`) - } - - r.max = int(maxResults) } // Apply applies the rule to given file. -func (r *FunctionResultsLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(arguments) }) - +func (r *FunctionResultsLimitRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure + for _, decl := range file.AST.Decls { + funcDecl, ok := decl.(*ast.FuncDecl) + if !ok { + continue + } - walker := lintFunctionResultsNum{ - max: r.max, - onFailure: func(failure lint.Failure) { - failures = append(failures, failure) - }, - } + num := 0 + hasResults := funcDecl.Type.Results != nil + if hasResults { + num = funcDecl.Type.Results.NumFields() + } - ast.Walk(walker, file.AST) + if num <= r.max { + continue + } + + failures = append(failures, lint.Failure{ + Confidence: 1, + Failure: fmt.Sprintf("maximum number of return results per function exceeded; max %d but got %d", r.max, num), + Node: funcDecl.Type, + }) + } return failures } @@ -57,29 +47,25 @@ func (*FunctionResultsLimitRule) Name() string { return "function-result-limit" } -type lintFunctionResultsNum struct { - max int - onFailure func(lint.Failure) -} +const defaultResultsLimit = 3 -func (w lintFunctionResultsNum) Visit(n ast.Node) ast.Visitor { - node, ok := n.(*ast.FuncDecl) - if ok { - num := 0 - hasResults := node.Type.Results != nil - if hasResults { - num = node.Type.Results.NumFields() - } - if num > w.max { - w.onFailure(lint.Failure{ - Confidence: 1, - Failure: fmt.Sprintf("maximum number of return results per function exceeded; max %d but got %d", w.max, num), - Node: node.Type, - }) - } +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *FunctionResultsLimitRule) Configure(arguments lint.Arguments) error { + if len(arguments) < 1 { + r.max = defaultResultsLimit + return nil + } - return nil // skip visiting function's body + maxResults, ok := arguments[0].(int64) // Alt. non panicking version + if !ok { + return fmt.Errorf(`invalid value passed as return results number to the "function-result-limit" rule; need int64 but got %T`, arguments[0]) + } + if maxResults < 0 { + return errors.New(`the value passed as return results number to the "function-result-limit" rule cannot be negative`) } - return w + r.max = int(maxResults) + return nil } diff --git a/vendor/github.com/mgechev/revive/rule/get_return.go b/vendor/github.com/mgechev/revive/rule/get_return.go index 06323a087..a6230e082 100644 --- a/vendor/github.com/mgechev/revive/rule/get_return.go +++ b/vendor/github.com/mgechev/revive/rule/get_return.go @@ -5,22 +5,43 @@ import ( "go/ast" "strings" + "github.com/mgechev/revive/internal/astutils" "github.com/mgechev/revive/lint" ) -// GetReturnRule lints given else constructs. +// GetReturnRule warns on getters that do not yield any result. type GetReturnRule struct{} // Apply applies the rule to given file. func (*GetReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure - onFailure := func(failure lint.Failure) { - failures = append(failures, failure) + for _, decl := range file.AST.Decls { + fd, ok := decl.(*ast.FuncDecl) + if !ok { + continue + } + + if !isGetter(fd.Name.Name) { + continue + } + + if hasResults(fd.Type.Results) { + continue + } + + if isHTTPHandler(fd.Type.Params) { + continue // the Get prefix in the function name refers to HTTP GET + } + + failures = append(failures, lint.Failure{ + Confidence: 0.8, + Node: fd, + Category: lint.FailureCategoryLogic, + Failure: fmt.Sprintf("function '%s' seems to be a getter but it does not return any result", fd.Name.Name), + }) } - w := lintReturnRule{onFailure} - ast.Walk(w, file.AST) return failures } @@ -29,10 +50,6 @@ func (*GetReturnRule) Name() string { return "get-return" } -type lintReturnRule struct { - onFailure func(lint.Failure) -} - const getterPrefix = "GET" var lenGetterPrefix = len(getterPrefix) @@ -58,23 +75,14 @@ func hasResults(rs *ast.FieldList) bool { return rs != nil && len(rs.List) > 0 } -func (w lintReturnRule) Visit(node ast.Node) ast.Visitor { - fd, ok := node.(*ast.FuncDecl) - if !ok { - return w - } - - if !isGetter(fd.Name.Name) { - return w - } - if !hasResults(fd.Type.Results) { - w.onFailure(lint.Failure{ - Confidence: 0.8, - Node: fd, - Category: "logic", - Failure: fmt.Sprintf("function '%s' seems to be a getter but it does not return any result", fd.Name.Name), - }) +// isHTTPHandler returns true if the given params match with the signature of an HTTP handler, false otherwise +// A params list is considered to be an HTTP handler if the first two parameters are +// http.ResponseWriter, *http.Request in that order. +func isHTTPHandler(params *ast.FieldList) bool { + typeNames := astutils.GetTypeNames(params) + if len(typeNames) < 2 { + return false } - return w + return typeNames[0] == "http.ResponseWriter" && typeNames[1] == "*http.Request" } diff --git a/vendor/github.com/mgechev/revive/rule/identical_branches.go b/vendor/github.com/mgechev/revive/rule/identical_branches.go index c6008925f..22895cde6 100644 --- a/vendor/github.com/mgechev/revive/rule/identical_branches.go +++ b/vendor/github.com/mgechev/revive/rule/identical_branches.go @@ -3,10 +3,11 @@ package rule import ( "go/ast" + "github.com/mgechev/revive/internal/astutils" "github.com/mgechev/revive/lint" ) -// IdenticalBranchesRule warns on constant logical expressions. +// IdenticalBranchesRule warns on if...else statements with both branches being the same. type IdenticalBranchesRule struct{} // Apply applies the rule to given file. @@ -17,9 +18,16 @@ func (*IdenticalBranchesRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fa failures = append(failures, failure) } - astFile := file.AST - w := &lintIdenticalBranches{astFile, onFailure} - ast.Walk(w, astFile) + w := &lintIdenticalBranches{onFailure: onFailure} + for _, decl := range file.AST.Decls { + fn, ok := decl.(*ast.FuncDecl) + if !ok || fn.Body == nil { + continue + } + + ast.Walk(w, fn.Body) + } + return failures } @@ -29,59 +37,45 @@ func (*IdenticalBranchesRule) Name() string { } type lintIdenticalBranches struct { - file *ast.File onFailure func(lint.Failure) } func (w *lintIdenticalBranches) Visit(node ast.Node) ast.Visitor { - n, ok := node.(*ast.IfStmt) + ifStmt, ok := node.(*ast.IfStmt) if !ok { return w } - noElseBranch := n.Else == nil - if noElseBranch { - return w + if ifStmt.Else == nil { + return w // if without else } - branches := []*ast.BlockStmt{n.Body} - - elseBranch, ok := n.Else.(*ast.BlockStmt) - if !ok { // if-else-if construction + elseBranch, ok := ifStmt.Else.(*ast.BlockStmt) + if !ok { // if-else-if construction, the rule only copes with single if...else statements return w } - branches = append(branches, elseBranch) - if w.identicalBranches(branches) { - w.newFailure(n, "both branches of the if are identical") + if w.identicalBranches(ifStmt.Body, elseBranch) { + w.onFailure(lint.Failure{ + Confidence: 1.0, + Node: ifStmt, + Category: lint.FailureCategoryLogic, + Failure: "both branches of the if are identical", + }) } - return w + ast.Walk(w, ifStmt.Body) + ast.Walk(w, ifStmt.Else) + return nil } -func (lintIdenticalBranches) identicalBranches(branches []*ast.BlockStmt) bool { - if len(branches) < 2 { - return false // only one branch to compare thus we return +func (*lintIdenticalBranches) identicalBranches(body, elseBranch *ast.BlockStmt) bool { + if len(body.List) != len(elseBranch.List) { + return false // branches don't have the same number of statements } - referenceBranch := gofmt(branches[0]) - referenceBranchSize := len(branches[0].List) - for i := 1; i < len(branches); i++ { - currentBranch := branches[i] - currentBranchSize := len(currentBranch.List) - if currentBranchSize != referenceBranchSize || gofmt(currentBranch) != referenceBranch { - return false - } - } - - return true -} + bodyStr := astutils.GoFmt(body) + elseStr := astutils.GoFmt(elseBranch) -func (w lintIdenticalBranches) newFailure(node ast.Node, msg string) { - w.onFailure(lint.Failure{ - Confidence: 1, - Node: node, - Category: "logic", - Failure: msg, - }) + return bodyStr == elseStr } diff --git a/vendor/github.com/mgechev/revive/rule/identical_ifelseif_branches.go b/vendor/github.com/mgechev/revive/rule/identical_ifelseif_branches.go new file mode 100644 index 000000000..b661e44f8 --- /dev/null +++ b/vendor/github.com/mgechev/revive/rule/identical_ifelseif_branches.go @@ -0,0 +1,186 @@ +package rule + +import ( + "fmt" + "go/ast" + + "github.com/mgechev/revive/internal/astutils" + "github.com/mgechev/revive/lint" +) + +// IdenticalIfElseIfBranchesRule warns on if...else if chains with identical branches. +type IdenticalIfElseIfBranchesRule struct{} + +// Apply applies the rule to given file. +func (*IdenticalIfElseIfBranchesRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { + var failures []lint.Failure + + onFailure := func(failure lint.Failure) { + failures = append(failures, failure) + } + + getStmtLine := func(s ast.Stmt) int { + return file.ToPosition(s.Pos()).Line + } + + w := &rootWalkerIfElseIfIdenticalBranches{getStmtLine: getStmtLine, onFailure: onFailure} + for _, decl := range file.AST.Decls { + fn, ok := decl.(*ast.FuncDecl) + if !ok || fn.Body == nil { + continue + } + + ast.Walk(w, fn.Body) + } + + return failures +} + +// Name returns the rule name. +func (*IdenticalIfElseIfBranchesRule) Name() string { + return "identical-ifelseif-branches" +} + +type rootWalkerIfElseIfIdenticalBranches struct { + getStmtLine func(ast.Stmt) int + onFailure func(lint.Failure) +} + +func (w *rootWalkerIfElseIfIdenticalBranches) Visit(node ast.Node) ast.Visitor { + n, ok := node.(*ast.IfStmt) + if !ok { + return w + } + + _, isIfElseIf := n.Else.(*ast.IfStmt) + if isIfElseIf { + walker := &lintIfChainIdenticalBranches{ + onFailure: w.onFailure, + getStmtLine: w.getStmtLine, + rootWalker: w, + } + + ast.Walk(walker, n) + return nil // the walker already analyzed inner branches + } + + return w +} + +// walkBranch analyzes the given branch. +func (w *rootWalkerIfElseIfIdenticalBranches) walkBranch(branch ast.Stmt) { + if branch == nil { + return + } + + walker := &rootWalkerIfElseIfIdenticalBranches{ + onFailure: w.onFailure, + getStmtLine: w.getStmtLine, + } + + ast.Walk(walker, branch) +} + +type lintIfChainIdenticalBranches struct { + getStmtLine func(ast.Stmt) int + onFailure func(lint.Failure) + branches []ast.Stmt // hold branches to compare + rootWalker *rootWalkerIfElseIfIdenticalBranches // the walker to use to recursively analyze inner branches + hasComplexCondition bool // indicates if one of the if conditions is "complex" +} + +// addBranch adds a branch to the list of branches to be compared. +func (w *lintIfChainIdenticalBranches) addBranch(branch ast.Stmt) { + if branch == nil { + return + } + + if w.branches == nil { + w.resetBranches() + } + + w.branches = append(w.branches, branch) +} + +// resetBranches resets (clears) the list of branches to compare. +func (w *lintIfChainIdenticalBranches) resetBranches() { + w.branches = []ast.Stmt{} + w.hasComplexCondition = false +} + +func (w *lintIfChainIdenticalBranches) Visit(node ast.Node) ast.Visitor { + n, ok := node.(*ast.IfStmt) + if !ok { + return w + } + + // recursively analyze the then-branch + w.rootWalker.walkBranch(n.Body) + + if n.Init == nil { // only check if without initialization to avoid false positives + w.addBranch(n.Body) + } + + if w.isComplexCondition(n.Cond) { + w.hasComplexCondition = true + } + + if n.Else != nil { + if chainedIf, ok := n.Else.(*ast.IfStmt); ok { + w.Visit(chainedIf) + } else { + w.addBranch(n.Else) + w.rootWalker.walkBranch(n.Else) + } + } + + identicalBranches := w.identicalBranches(w.branches) + for _, branchPair := range identicalBranches { + msg := fmt.Sprintf(`"if...else if" chain with identical branches (lines %d and %d)`, branchPair[0], branchPair[1]) + confidence := 1.0 + if w.hasComplexCondition { + confidence = 0.8 + } + w.onFailure(lint.Failure{ + Confidence: confidence, + Node: w.branches[0], + Category: lint.FailureCategoryLogic, + Failure: msg, + }) + } + + w.resetBranches() + return nil +} + +// isComplexCondition returns true if the given expression is "complex", false otherwise. +// An expression is considered complex if it has a function call. +func (*lintIfChainIdenticalBranches) isComplexCondition(expr ast.Expr) bool { + call := astutils.SeekNode[*ast.CallExpr](expr, func(n ast.Node) bool { + _, ok := n.(*ast.CallExpr) + return ok + }) + + return call != nil +} + +// identicalBranches yields pairs of (line numbers) of identical branches from the given branches. +func (w *lintIfChainIdenticalBranches) identicalBranches(branches []ast.Stmt) [][]int { + result := [][]int{} + if len(branches) < 2 { + return result // no other branch to compare thus we return + } + + hashes := map[string]int{} // branch code hash -> branch line + for _, branch := range branches { + hash := astutils.NodeHash(branch) + branchLine := w.getStmtLine(branch) + if match, ok := hashes[hash]; ok { + result = append(result, []int{match, branchLine}) + } + + hashes[hash] = branchLine + } + + return result +} diff --git a/vendor/github.com/mgechev/revive/rule/identical_ifelseif_condition.go b/vendor/github.com/mgechev/revive/rule/identical_ifelseif_condition.go new file mode 100644 index 000000000..0ba9d68c9 --- /dev/null +++ b/vendor/github.com/mgechev/revive/rule/identical_ifelseif_condition.go @@ -0,0 +1,148 @@ +package rule + +import ( + "fmt" + "go/ast" + + "github.com/mgechev/revive/internal/astutils" + "github.com/mgechev/revive/lint" +) + +// IdenticalIfElseIfConditionsRule warns on if...else if chains with identical conditions. +type IdenticalIfElseIfConditionsRule struct{} + +// Apply applies the rule to given file. +func (*IdenticalIfElseIfConditionsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { + var failures []lint.Failure + + onFailure := func(failure lint.Failure) { + failures = append(failures, failure) + } + + getStmtLine := func(s ast.Stmt) int { + return file.ToPosition(s.Pos()).Line + } + + w := &rootWalkerIfElseIfIdenticalConditions{getStmtLine: getStmtLine, onFailure: onFailure} + for _, decl := range file.AST.Decls { + fn, ok := decl.(*ast.FuncDecl) + if !ok || fn.Body == nil { + continue + } + + ast.Walk(w, fn.Body) + } + + return failures +} + +// Name returns the rule name. +func (*IdenticalIfElseIfConditionsRule) Name() string { + return "identical-ifelseif-conditions" +} + +type rootWalkerIfElseIfIdenticalConditions struct { + getStmtLine func(ast.Stmt) int + onFailure func(lint.Failure) +} + +func (w *rootWalkerIfElseIfIdenticalConditions) Visit(node ast.Node) ast.Visitor { + n, ok := node.(*ast.IfStmt) + if !ok { + return w + } + + _, isIfElseIf := n.Else.(*ast.IfStmt) + if isIfElseIf { + walker := &lintIfChainIdenticalConditions{ + onFailure: w.onFailure, + getStmtLine: w.getStmtLine, + rootWalker: w, + } + + ast.Walk(walker, n) + return nil // the walker already analyzed inner branches + } + + return w +} + +// walkBranch analyzes the given branch. +func (w *rootWalkerIfElseIfIdenticalConditions) walkBranch(branch ast.Stmt) { + if branch == nil { + return + } + + walker := &rootWalkerIfElseIfIdenticalConditions{ + onFailure: w.onFailure, + getStmtLine: w.getStmtLine, + } + + ast.Walk(walker, branch) +} + +type lintIfChainIdenticalConditions struct { + getStmtLine func(ast.Stmt) int + onFailure func(lint.Failure) + conditions map[string]int // condition hash -> line of the condition + rootWalker *rootWalkerIfElseIfIdenticalConditions // the walker to use to recursively analyze inner branches +} + +// addCondition adds a condition to the set of if...else if conditions. +// If the set already contains the same condition it returns the line number of the identical condition. +func (w *lintIfChainIdenticalConditions) addCondition(condition ast.Expr, conditionLine int) (line int, match bool) { + if condition == nil { + return 0, false + } + + if w.conditions == nil { + w.resetConditions() + } + + hash := astutils.NodeHash(condition) + identical, ok := w.conditions[hash] + if ok { + return identical, true + } + + w.conditions[hash] = conditionLine + return 0, false +} + +func (w *lintIfChainIdenticalConditions) resetConditions() { + w.conditions = map[string]int{} +} + +func (w *lintIfChainIdenticalConditions) Visit(node ast.Node) ast.Visitor { + n, ok := node.(*ast.IfStmt) + if !ok { + return w + } + + // recursively analyze the then-branch + w.rootWalker.walkBranch(n.Body) + + if n.Init == nil { // only check if without initialization to avoid false positives + currentCondLine := w.rootWalker.getStmtLine(n) + identicalCondLine, match := w.addCondition(n.Cond, currentCondLine) + if match { + w.onFailure(lint.Failure{ + Confidence: 1.0, + Node: n, + Category: lint.FailureCategoryLogic, + Failure: fmt.Sprintf(`"if...else if" chain with identical conditions (lines %d and %d)`, identicalCondLine, currentCondLine), + }) + } + } + + if n.Else != nil { + if chainedIf, ok := n.Else.(*ast.IfStmt); ok { + w.Visit(chainedIf) + } else { + w.rootWalker.walkBranch(n.Else) + } + } + + w.resetConditions() + return nil +} diff --git a/vendor/github.com/mgechev/revive/rule/identical_switch_branches.go b/vendor/github.com/mgechev/revive/rule/identical_switch_branches.go new file mode 100644 index 000000000..fc1d620b3 --- /dev/null +++ b/vendor/github.com/mgechev/revive/rule/identical_switch_branches.go @@ -0,0 +1,94 @@ +package rule + +import ( + "fmt" + "go/ast" + "go/token" + + "github.com/mgechev/revive/internal/astutils" + "github.com/mgechev/revive/lint" +) + +// IdenticalSwitchBranchesRule warns on identical switch branches. +type IdenticalSwitchBranchesRule struct{} + +// Apply applies the rule to given file. +func (*IdenticalSwitchBranchesRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { + var failures []lint.Failure + + onFailure := func(failure lint.Failure) { + failures = append(failures, failure) + } + + getStmtLine := func(s ast.Stmt) int { + return file.ToPosition(s.Pos()).Line + } + + w := &lintIdenticalSwitchBranches{getStmtLine: getStmtLine, onFailure: onFailure} + for _, decl := range file.AST.Decls { + fn, ok := decl.(*ast.FuncDecl) + if !ok || fn.Body == nil { + continue + } + + ast.Walk(w, fn.Body) + } + + return failures +} + +// Name returns the rule name. +func (*IdenticalSwitchBranchesRule) Name() string { + return "identical-switch-branches" +} + +type lintIdenticalSwitchBranches struct { + getStmtLine func(ast.Stmt) int + onFailure func(lint.Failure) +} + +func (w *lintIdenticalSwitchBranches) Visit(node ast.Node) ast.Visitor { + switchStmt, ok := node.(*ast.SwitchStmt) + if !ok { + return w + } + + if switchStmt.Tag == nil { + return w // do not lint untagged switches (order of case evaluation might be important) + } + + doesFallthrough := func(stmts []ast.Stmt) bool { + if len(stmts) == 0 { + return false + } + + ft, ok := stmts[len(stmts)-1].(*ast.BranchStmt) + return ok && ft.Tok == token.FALLTHROUGH + } + + hashes := map[string]int{} // map hash(branch code) -> branch line + for _, cc := range switchStmt.Body.List { + caseClause := cc.(*ast.CaseClause) + if doesFallthrough(caseClause.Body) { + continue // skip fallthrough branches + } + branch := &ast.BlockStmt{ + List: caseClause.Body, + } + hash := astutils.NodeHash(branch) + branchLine := w.getStmtLine(caseClause) + if matchLine, ok := hashes[hash]; ok { + w.onFailure(lint.Failure{ + Confidence: 1.0, + Node: node, + Category: lint.FailureCategoryLogic, + Failure: fmt.Sprintf(`"switch" with identical branches (lines %d and %d)`, matchLine, branchLine), + }) + } + + hashes[hash] = branchLine + ast.Walk(w, branch) + } + + return nil // switch branches already analyzed +} diff --git a/vendor/github.com/mgechev/revive/rule/identical_switch_conditions.go b/vendor/github.com/mgechev/revive/rule/identical_switch_conditions.go new file mode 100644 index 000000000..15826d9b0 --- /dev/null +++ b/vendor/github.com/mgechev/revive/rule/identical_switch_conditions.go @@ -0,0 +1,78 @@ +package rule + +import ( + "fmt" + "go/ast" + "go/token" + + "github.com/mgechev/revive/internal/astutils" + "github.com/mgechev/revive/lint" +) + +// IdenticalSwitchConditionsRule warns on switch case clauses with identical conditions. +type IdenticalSwitchConditionsRule struct{} + +// Apply applies the rule to given file. +func (*IdenticalSwitchConditionsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { + var failures []lint.Failure + + onFailure := func(failure lint.Failure) { + failures = append(failures, failure) + } + + w := &lintIdenticalSwitchConditions{toPosition: file.ToPosition, onFailure: onFailure} + for _, decl := range file.AST.Decls { + fn, ok := decl.(*ast.FuncDecl) + if !ok || fn.Body == nil { + continue + } + + ast.Walk(w, fn.Body) + } + + return failures +} + +// Name returns the rule name. +func (*IdenticalSwitchConditionsRule) Name() string { + return "identical-switch-conditions" +} + +type lintIdenticalSwitchConditions struct { + toPosition func(token.Pos) token.Position + onFailure func(lint.Failure) +} + +func (w *lintIdenticalSwitchConditions) Visit(node ast.Node) ast.Visitor { + switchStmt, ok := node.(*ast.SwitchStmt) + if !ok { // not a switch statement, keep walking the AST + return w + } + + if switchStmt.Tag != nil { + return w // Not interested in tagged switches + } + + hashes := map[string]int{} // map hash(condition code) -> condition line + for _, cc := range switchStmt.Body.List { + caseClause := cc.(*ast.CaseClause) + caseClauseLine := w.toPosition(caseClause.Pos()).Line + for _, expr := range caseClause.List { + hash := astutils.NodeHash(expr) + if matchLine, ok := hashes[hash]; ok { + w.onFailure(lint.Failure{ + Confidence: 1.0, + Node: caseClause, + Category: lint.FailureCategoryLogic, + Failure: fmt.Sprintf(`case clause at line %d has the same condition`, matchLine), + }) + } + + hashes[hash] = caseClauseLine + } + + ast.Walk(w, caseClause) + } + + return nil // switch branches already analyzed +} diff --git a/vendor/github.com/mgechev/revive/rule/if_return.go b/vendor/github.com/mgechev/revive/rule/if_return.go index a6a3113ad..15c7ca18a 100644 --- a/vendor/github.com/mgechev/revive/rule/if_return.go +++ b/vendor/github.com/mgechev/revive/rule/if_return.go @@ -8,7 +8,7 @@ import ( "github.com/mgechev/revive/lint" ) -// IfReturnRule lints given else constructs. +// IfReturnRule searches for redundant `if` when returning an error. type IfReturnRule struct{} // Apply applies the rule to given file. @@ -36,15 +36,15 @@ type lintElseError struct { } func (w *lintElseError) Visit(node ast.Node) ast.Visitor { - switch v := node.(type) { - case *ast.BlockStmt: - for i := 0; i < len(v.List)-1; i++ { + if v, ok := node.(*ast.BlockStmt); ok { + for i := range len(v.List) - 1 { // if var := whatever; var != nil { return var } s, ok := v.List[i].(*ast.IfStmt) if !ok || s.Body == nil || len(s.Body.List) != 1 || s.Else != nil { continue } assign, ok := s.Init.(*ast.AssignStmt) + //nolint:staticcheck // QF1001: it's readable enough if !ok || len(assign.Lhs) != 1 || !(assign.Tok == token.DEFINE || assign.Tok == token.ASSIGN) { continue } diff --git a/vendor/github.com/mgechev/revive/rule/import_alias_naming.go b/vendor/github.com/mgechev/revive/rule/import_alias_naming.go index 043bf0d76..a46c331ef 100644 --- a/vendor/github.com/mgechev/revive/rule/import_alias_naming.go +++ b/vendor/github.com/mgechev/revive/rule/import_alias_naming.go @@ -3,7 +3,6 @@ package rule import ( "fmt" "regexp" - "sync" "github.com/mgechev/revive/lint" ) @@ -12,47 +11,58 @@ import ( type ImportAliasNamingRule struct { allowRegexp *regexp.Regexp denyRegexp *regexp.Regexp - - configureOnce sync.Once } const defaultImportAliasNamingAllowRule = "^[a-z][a-z0-9]{0,}$" +//nolint:gocritic // regexpSimplify: backward compatibility var defaultImportAliasNamingAllowRegexp = regexp.MustCompile(defaultImportAliasNamingAllowRule) -func (r *ImportAliasNamingRule) configure(arguments lint.Arguments) { +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *ImportAliasNamingRule) Configure(arguments lint.Arguments) error { if len(arguments) == 0 { r.allowRegexp = defaultImportAliasNamingAllowRegexp - return + return nil } switch namingRule := arguments[0].(type) { case string: - r.setAllowRule(namingRule) + err := r.setAllowRule(namingRule) + if err != nil { + return err + } case map[string]any: // expecting map[string]string for k, v := range namingRule { - switch k { - case "allowRegex": - r.setAllowRule(v) - case "denyRegex": - r.setDenyRule(v) + switch { + case isRuleOption(k, "allowRegex"): + err := r.setAllowRule(v) + if err != nil { + return err + } + case isRuleOption(k, "denyRegex"): + err := r.setDenyRule(v) + if err != nil { + return err + } + default: - panic(fmt.Sprintf("Invalid map key for 'import-alias-naming' rule. Expecting 'allowRegex' or 'denyRegex', got %v", k)) + return fmt.Errorf("invalid map key for 'import-alias-naming' rule. Expecting 'allowRegex' or 'denyRegex', got %v", k) } } default: - panic(fmt.Sprintf("Invalid argument '%v' for 'import-alias-naming' rule. Expecting string or map[string]string, got %T", arguments[0], arguments[0])) + return fmt.Errorf("invalid argument '%v' for 'import-alias-naming' rule. Expecting string or map[string]string, got %T", arguments[0], arguments[0]) } if r.allowRegexp == nil && r.denyRegexp == nil { r.allowRegexp = defaultImportAliasNamingAllowRegexp } + return nil } // Apply applies the rule to given file. -func (r *ImportAliasNamingRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(arguments) }) - +func (r *ImportAliasNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure for _, is := range file.AST.Imports { @@ -71,7 +81,7 @@ func (r *ImportAliasNamingRule) Apply(file *lint.File, arguments lint.Arguments) Confidence: 1, Failure: fmt.Sprintf("import name (%s) must match the regular expression: %s", alias.Name, r.allowRegexp.String()), Node: alias, - Category: "imports", + Category: lint.FailureCategoryImports, }) } @@ -80,7 +90,7 @@ func (r *ImportAliasNamingRule) Apply(file *lint.File, arguments lint.Arguments) Confidence: 1, Failure: fmt.Sprintf("import name (%s) must NOT match the regular expression: %s", alias.Name, r.denyRegexp.String()), Node: alias, - Category: "imports", + Category: lint.FailureCategoryImports, }) } } @@ -93,28 +103,30 @@ func (*ImportAliasNamingRule) Name() string { return "import-alias-naming" } -func (r *ImportAliasNamingRule) setAllowRule(value any) { +func (r *ImportAliasNamingRule) setAllowRule(value any) error { namingRule, ok := value.(string) if !ok { - panic(fmt.Sprintf("Invalid argument '%v' for import-alias-naming allowRegexp rule. Expecting string, got %T", value, value)) + return fmt.Errorf("invalid argument '%v' for import-alias-naming allowRegexp rule. Expecting string, got %T", value, value) } namingRuleRegexp, err := regexp.Compile(namingRule) if err != nil { - panic(fmt.Sprintf("Invalid argument to the import-alias-naming allowRegexp rule. Expecting %q to be a valid regular expression, got: %v", namingRule, err)) + return fmt.Errorf("invalid argument to the import-alias-naming allowRegexp rule. Expecting %q to be a valid regular expression, got: %w", namingRule, err) } r.allowRegexp = namingRuleRegexp + return nil } -func (r *ImportAliasNamingRule) setDenyRule(value any) { +func (r *ImportAliasNamingRule) setDenyRule(value any) error { namingRule, ok := value.(string) if !ok { - panic(fmt.Sprintf("Invalid argument '%v' for import-alias-naming denyRegexp rule. Expecting string, got %T", value, value)) + return fmt.Errorf("invalid argument '%v' for import-alias-naming denyRegexp rule. Expecting string, got %T", value, value) } namingRuleRegexp, err := regexp.Compile(namingRule) if err != nil { - panic(fmt.Sprintf("Invalid argument to the import-alias-naming denyRegexp rule. Expecting %q to be a valid regular expression, got: %v", namingRule, err)) + return fmt.Errorf("invalid argument to the import-alias-naming denyRegexp rule. Expecting %q to be a valid regular expression, got: %w", namingRule, err) } r.denyRegexp = namingRuleRegexp + return nil } diff --git a/vendor/github.com/mgechev/revive/rule/import_shadowing.go b/vendor/github.com/mgechev/revive/rule/import_shadowing.go index 046aeb688..0028d9673 100644 --- a/vendor/github.com/mgechev/revive/rule/import_shadowing.go +++ b/vendor/github.com/mgechev/revive/rule/import_shadowing.go @@ -9,16 +9,16 @@ import ( "github.com/mgechev/revive/lint" ) -// ImportShadowingRule lints given else constructs. +// ImportShadowingRule spots identifiers that shadow an import. type ImportShadowingRule struct{} // Apply applies the rule to given file. -func (*ImportShadowingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { +func (r *ImportShadowingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure importNames := map[string]struct{}{} for _, imp := range file.AST.Imports { - importNames[getName(imp)] = struct{}{} + importNames[r.getName(imp)] = struct{}{} } fileAst := file.AST @@ -28,7 +28,7 @@ func (*ImportShadowingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fail onFailure: func(failure lint.Failure) { failures = append(failures, failure) }, - alreadySeen: map[*ast.Object]struct{}{}, + alreadySeen: map[*ast.Object]struct{}{}, //nolint:staticcheck // TODO: ast.Object is deprecated skipIdents: map[*ast.Ident]struct{}{}, } @@ -42,31 +42,34 @@ func (*ImportShadowingRule) Name() string { return "import-shadowing" } -func getName(imp *ast.ImportSpec) string { +func (r *ImportShadowingRule) getName(imp *ast.ImportSpec) string { const pathSep = "/" const strDelim = `"` if imp.Name != nil { return imp.Name.Name } - path := imp.Path.Value - i := strings.LastIndex(path, pathSep) - if i == -1 { - return strings.Trim(path, strDelim) + path := strings.Trim(imp.Path.Value, strDelim) + parts := strings.Split(path, pathSep) + + lastSegment := parts[len(parts)-1] + if r.isVersion(lastSegment) && len(parts) >= 2 { + // Use the previous segment when current is a version (v1, v2, etc.). + return parts[len(parts)-2] } - return strings.Trim(path[i+1:], strDelim) + return lastSegment } type importShadowing struct { packageNameIdent *ast.Ident importNames map[string]struct{} onFailure func(lint.Failure) - alreadySeen map[*ast.Object]struct{} + alreadySeen map[*ast.Object]struct{} //nolint:staticcheck // TODO: ast.Object is deprecated skipIdents map[*ast.Ident]struct{} } -// Visit visits AST nodes and checks if id nodes (ast.Ident) shadow an import name +// Visit visits AST nodes and checks if id nodes (ast.Ident) shadow an import name. func (w importShadowing) Visit(n ast.Node) ast.Visitor { switch n := n.(type) { case *ast.AssignStmt: @@ -103,7 +106,7 @@ func (w importShadowing) Visit(n ast.Node) ast.Visitor { w.onFailure(lint.Failure{ Confidence: 1, Node: n, - Category: "naming", + Category: lint.FailureCategoryNaming, Failure: fmt.Sprintf("The name '%s' shadows an import name", id), }) @@ -113,3 +116,17 @@ func (w importShadowing) Visit(n ast.Node) ast.Visitor { return w } + +func (*ImportShadowingRule) isVersion(name string) bool { + if len(name) < 2 || (name[0] != 'v' && name[0] != 'V') { + return false + } + + for i := 1; i < len(name); i++ { + if name[i] < '0' || name[i] > '9' { + return false + } + } + + return true +} diff --git a/vendor/github.com/mgechev/revive/rule/imports_blocklist.go b/vendor/github.com/mgechev/revive/rule/imports_blocklist.go index 18d77ca1c..8d3b08693 100644 --- a/vendor/github.com/mgechev/revive/rule/imports_blocklist.go +++ b/vendor/github.com/mgechev/revive/rule/imports_blocklist.go @@ -3,33 +3,34 @@ package rule import ( "fmt" "regexp" - "sync" "github.com/mgechev/revive/lint" ) -// ImportsBlocklistRule lints given else constructs. +// ImportsBlocklistRule disallows importing the specified packages. type ImportsBlocklistRule struct { blocklist []*regexp.Regexp - - configureOnce sync.Once } var replaceImportRegexp = regexp.MustCompile(`/?\*\*/?`) -func (r *ImportsBlocklistRule) configure(arguments lint.Arguments) { +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *ImportsBlocklistRule) Configure(arguments lint.Arguments) error { r.blocklist = []*regexp.Regexp{} for _, arg := range arguments { argStr, ok := arg.(string) if !ok { - panic(fmt.Sprintf("Invalid argument to the imports-blocklist rule. Expecting a string, got %T", arg)) + return fmt.Errorf("invalid argument to the imports-blocklist rule. Expecting a string, got %T", arg) } - regStr, err := regexp.Compile(fmt.Sprintf(`(?m)"%s"$`, replaceImportRegexp.ReplaceAllString(argStr, `(\W|\w)*`))) + regStr, err := regexp.Compile(fmt.Sprintf(`(?m)"%s"$`, replaceImportRegexp.ReplaceAllString(argStr, `(\W|\w)*`))) //nolint:gocritic // regexpSimplify: false positive if err != nil { - panic(fmt.Sprintf("Invalid argument to the imports-blocklist rule. Expecting %q to be a valid regular expression, got: %v", argStr, err)) + return fmt.Errorf("invalid argument to the imports-blocklist rule. Expecting %q to be a valid regular expression, got: %w", argStr, err) } r.blocklist = append(r.blocklist, regStr) } + return nil } func (r *ImportsBlocklistRule) isBlocklisted(path string) bool { @@ -42,9 +43,7 @@ func (r *ImportsBlocklistRule) isBlocklisted(path string) bool { } // Apply applies the rule to given file. -func (r *ImportsBlocklistRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(arguments) }) - +func (r *ImportsBlocklistRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure for _, is := range file.AST.Imports { @@ -54,7 +53,7 @@ func (r *ImportsBlocklistRule) Apply(file *lint.File, arguments lint.Arguments) Confidence: 1, Failure: "should not use the following blocklisted import: " + path.Value, Node: is, - Category: "imports", + Category: lint.FailureCategoryImports, }) } } diff --git a/vendor/github.com/mgechev/revive/rule/increment_decrement.go b/vendor/github.com/mgechev/revive/rule/increment_decrement.go index 34a8e1ec5..538bd9314 100644 --- a/vendor/github.com/mgechev/revive/rule/increment_decrement.go +++ b/vendor/github.com/mgechev/revive/rule/increment_decrement.go @@ -8,7 +8,7 @@ import ( "github.com/mgechev/revive/lint" ) -// IncrementDecrementRule lints given else constructs. +// IncrementDecrementRule suggests replacing `i += 1` and `i -= 1` with `i++` and `i--`. type IncrementDecrementRule struct{} // Apply applies the rule to given file. @@ -61,7 +61,7 @@ func (w lintIncrementDecrement) Visit(n ast.Node) ast.Visitor { w.onFailure(lint.Failure{ Confidence: 0.8, Node: as, - Category: "unary-op", + Category: lint.FailureCategoryUnaryOp, Failure: fmt.Sprintf("should replace %s with %s%s", w.file.Render(as), w.file.Render(as.Lhs[0]), suffix), }) return w diff --git a/vendor/github.com/mgechev/revive/rule/indent_error_flow.go b/vendor/github.com/mgechev/revive/rule/indent_error_flow.go index ebc1e793a..f900d8e22 100644 --- a/vendor/github.com/mgechev/revive/rule/indent_error_flow.go +++ b/vendor/github.com/mgechev/revive/rule/indent_error_flow.go @@ -5,12 +5,36 @@ import ( "github.com/mgechev/revive/lint" ) -// IndentErrorFlowRule lints given else constructs. -type IndentErrorFlowRule struct{} +// IndentErrorFlowRule prevents redundant else statements. +type IndentErrorFlowRule struct { + // preserveScope prevents suggestions that would enlarge variable scope. + preserveScope bool +} + +var _ lint.ConfigurableRule = (*IndentErrorFlowRule)(nil) + +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (e *IndentErrorFlowRule) Configure(arguments lint.Arguments) error { + for _, arg := range arguments { + sarg, ok := arg.(string) + if !ok { + continue + } + if isRuleOption(sarg, "preserveScope") { + e.preserveScope = true + } + } + return nil +} // Apply applies the rule to given file. -func (e *IndentErrorFlowRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure { - return ifelse.Apply(e, file.AST, ifelse.TargetElse, args) +func (e *IndentErrorFlowRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { + return ifelse.Apply(e.checkIfElse, file.AST, ifelse.TargetElse, ifelse.Args{ + PreserveScope: e.preserveScope, + // AllowJump is not used by this rule + }) } // Name returns the rule name. @@ -18,28 +42,31 @@ func (*IndentErrorFlowRule) Name() string { return "indent-error-flow" } -// CheckIfElse evaluates the rule against an ifelse.Chain and returns a failure message if applicable. -func (*IndentErrorFlowRule) CheckIfElse(chain ifelse.Chain, args ifelse.Args) string { +func (e *IndentErrorFlowRule) checkIfElse(chain ifelse.Chain) (string, bool) { + if !chain.HasElse { + return "", false + } + if !chain.If.Deviates() { // this rule only applies if the if-block deviates control flow - return "" + return "", false } if chain.HasPriorNonDeviating { // if we de-indent the "else" block then a previous branch - // might flow into it, affecting program behaviour - return "" + // might flow into it, affecting program behavior + return "", false } if !chain.If.Returns() { // avoid overlapping with superfluous-else - return "" + return "", false } - if args.PreserveScope && !chain.AtBlockEnd && (chain.HasInitializer || chain.Else.HasDecls) { + if e.preserveScope && !chain.AtBlockEnd && (chain.HasInitializer || chain.Else.HasDecls()) { // avoid increasing variable scope - return "" + return "", false } - return "if block ends with a return statement, so drop this else and outdent its block" + return "if block ends with a return statement, so drop this else and outdent its block", true } diff --git a/vendor/github.com/mgechev/revive/rule/inefficient_map_lookup.go b/vendor/github.com/mgechev/revive/rule/inefficient_map_lookup.go new file mode 100644 index 000000000..c6944200b --- /dev/null +++ b/vendor/github.com/mgechev/revive/rule/inefficient_map_lookup.go @@ -0,0 +1,174 @@ +package rule + +import ( + "fmt" + "go/ast" + "go/token" + "strings" + + "github.com/mgechev/revive/internal/astutils" + "github.com/mgechev/revive/lint" +) + +// InefficientMapLookupRule spots potential inefficient map lookups. +type InefficientMapLookupRule struct{} + +// Apply applies the rule to given file. +func (*InefficientMapLookupRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { + var failures []lint.Failure + + onFailure := func(failure lint.Failure) { + failures = append(failures, failure) + } + + w := &lintInefficientMapLookup{ + file: file, + onFailure: onFailure, + } + + if err := file.Pkg.TypeCheck(); err != nil { + return []lint.Failure{ + lint.NewInternalFailure(fmt.Sprintf("Unable to type check file %q: %v", file.Name, err)), + } + } + + // Iterate over declarations looking for function declarations + for _, decl := range file.AST.Decls { + fn, ok := decl.(*ast.FuncDecl) + if !ok { + continue // not a function + } + + if fn.Body == nil { + continue // external (no-Go) function + } + + // Analyze the function body + ast.Walk(w, fn.Body) + } + + return failures +} + +// Name returns the rule name. +func (*InefficientMapLookupRule) Name() string { + return "inefficient-map-lookup" +} + +type lintInefficientMapLookup struct { + file *lint.File + onFailure func(lint.Failure) +} + +func (w *lintInefficientMapLookup) Visit(node ast.Node) ast.Visitor { + // Only interested in blocks of statements + block, ok := node.(*ast.BlockStmt) + if !ok { + return w // not a block of statements + } + + w.analyzeBlock(block) + + return w +} + +// analyzeBlock searches AST subtrees with the following form +// +// for := range { +// if == { +// ... +// } +func (w *lintInefficientMapLookup) analyzeBlock(b *ast.BlockStmt) { + for _, stmt := range b.List { + if !w.isRangeOverMapKey(stmt) { + continue + } + + rangeOverMap := stmt.(*ast.RangeStmt) + key := rangeOverMap.Key.(*ast.Ident) + + // Here we have identified a range over the keys of a map + // Let's check if the range body is + // { if == { ... } } + // or + // { if != { continue } ... } + if !isKeyLookup(key.Name, rangeOverMap.Body) { + continue + } + + w.onFailure(lint.Failure{ + Confidence: 1, + Node: rangeOverMap, + Category: lint.FailureCategoryStyle, + Failure: "inefficient lookup of map key", + }) + } +} + +func isKeyLookup(keyName string, blockStmt *ast.BlockStmt) bool { + blockLen := len(blockStmt.List) + if blockLen == 0 { + return false // empty + } + + firstStmt := blockStmt.List[0] + ifStmt, ok := firstStmt.(*ast.IfStmt) + if !ok { + return false // the first statement of the body is not an if + } + + binExp, ok := ifStmt.Cond.(*ast.BinaryExpr) + if !ok { + return false // the if condition is not a binary expression + } + + if !astutils.IsIdent(binExp.X, keyName) { + return false // the if condition is not + } + + switch binExp.Op { + case token.EQL: + // if key == ... should be the single statement in the block + return blockLen == 1 + + case token.NEQ: + // if key != ... + ifBodyStmts := ifStmt.Body.List + if len(ifBodyStmts) < 1 { + return false // if key != ... { /* empty */ } + } + + branchStmt, ok := ifBodyStmts[0].(*ast.BranchStmt) + if !ok || branchStmt.Tok != token.CONTINUE { + return false // if key != ... { } + } + + return true + } + + return false +} + +func (w *lintInefficientMapLookup) isRangeOverMapKey(stmt ast.Stmt) bool { + rangeStmt, ok := stmt.(*ast.RangeStmt) + if !ok { + return false // not a range + } + + // Check if we range on the key + if rangeStmt.Key == nil { + return false // no key in range + } + + // Check if we range only on key + // for key := range ... + // for key, _ := range ... + hasValueVariable := rangeStmt.Value != nil && !astutils.IsIdent(rangeStmt.Value, "_") + if hasValueVariable { + return false // range over both key and value + } + + // Check if we range over a map + t := w.file.Pkg.TypeOf(rangeStmt.X) + return t != nil && strings.HasPrefix(t.String(), "map[") +} diff --git a/vendor/github.com/mgechev/revive/rule/line_length_limit.go b/vendor/github.com/mgechev/revive/rule/line_length_limit.go index 415761e1e..f2c9a1467 100644 --- a/vendor/github.com/mgechev/revive/rule/line_length_limit.go +++ b/vendor/github.com/mgechev/revive/rule/line_length_limit.go @@ -3,42 +3,42 @@ package rule import ( "bufio" "bytes" + "errors" "fmt" "go/token" "strings" - "sync" "unicode/utf8" "github.com/mgechev/revive/lint" ) -// LineLengthLimitRule lints given else constructs. +// LineLengthLimitRule lints the number of characters in a line. type LineLengthLimitRule struct { max int - - configureOnce sync.Once } const defaultLineLengthLimit = 80 -func (r *LineLengthLimitRule) configure(arguments lint.Arguments) { +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *LineLengthLimitRule) Configure(arguments lint.Arguments) error { if len(arguments) < 1 { r.max = defaultLineLengthLimit - return + return nil } maxLength, ok := arguments[0].(int64) // Alt. non panicking version if !ok || maxLength < 0 { - panic(`invalid value passed as argument number to the "line-length-limit" rule`) + return errors.New(`invalid value passed as argument number to the "line-length-limit" rule`) } r.max = int(maxLength) + return nil } // Apply applies the rule to given file. -func (r *LineLengthLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(arguments) }) - +func (r *LineLengthLimitRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure checker := lintLineLengthNum{ @@ -76,7 +76,7 @@ func (r lintLineLengthNum) check() { c := utf8.RuneCountInString(t) if c > r.max { r.onFailure(lint.Failure{ - Category: "code-style", + Category: lint.FailureCategoryStyle, Position: lint.FailurePosition{ // Offset not set; it is non-trivial, and doesn't appear to be needed. Start: token.Position{ diff --git a/vendor/github.com/mgechev/revive/rule/max_control_nesting.go b/vendor/github.com/mgechev/revive/rule/max_control_nesting.go index b2c5af70e..b1ac459dc 100644 --- a/vendor/github.com/mgechev/revive/rule/max_control_nesting.go +++ b/vendor/github.com/mgechev/revive/rule/max_control_nesting.go @@ -1,26 +1,22 @@ package rule import ( + "errors" "fmt" "go/ast" - "sync" "github.com/mgechev/revive/lint" ) -// MaxControlNestingRule lints given else constructs. +// MaxControlNestingRule sets restriction for maximum nesting of control structures. type MaxControlNestingRule struct { max int64 - - configureOnce sync.Once } const defaultMaxControlNesting = 5 // Apply applies the rule to given file. -func (r *MaxControlNestingRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(arguments) }) - +func (r *MaxControlNestingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure fileAst := file.AST @@ -55,7 +51,7 @@ func (w *lintMaxControlNesting) Visit(n ast.Node) ast.Visitor { Failure: fmt.Sprintf("control flow nesting exceeds %d", w.max), Confidence: 1, Node: w.lastCtrlStmt, - Category: "complexity", + Category: lint.FailureCategoryComplexity, }) return nil // stop visiting deeper } @@ -107,17 +103,19 @@ func (w *lintMaxControlNesting) walkControlledBlock(b ast.Node) { w.nestingLevelAcc = oldNestingLevel } -func (r *MaxControlNestingRule) configure(arguments lint.Arguments) { +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *MaxControlNestingRule) Configure(arguments lint.Arguments) error { if len(arguments) < 1 { r.max = defaultMaxControlNesting - return + return nil } - checkNumberOfArguments(1, arguments, r.Name()) - maxNesting, ok := arguments[0].(int64) // Alt. non panicking version if !ok { - panic(`invalid value passed as argument number to the "max-control-nesting" rule`) + return errors.New(`invalid value passed as argument number to the "max-control-nesting" rule`) } r.max = maxNesting + return nil } diff --git a/vendor/github.com/mgechev/revive/rule/max_public_structs.go b/vendor/github.com/mgechev/revive/rule/max_public_structs.go index d6f91e375..070277229 100644 --- a/vendor/github.com/mgechev/revive/rule/max_public_structs.go +++ b/vendor/github.com/mgechev/revive/rule/max_public_structs.go @@ -1,42 +1,40 @@ package rule import ( + "errors" "fmt" "go/ast" "strings" - "sync" "github.com/mgechev/revive/lint" ) -// MaxPublicStructsRule lints given else constructs. +// MaxPublicStructsRule lints the number of public structs in a file. type MaxPublicStructsRule struct { max int64 - - configureOnce sync.Once } const defaultMaxPublicStructs = 5 -func (r *MaxPublicStructsRule) configure(arguments lint.Arguments) { +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *MaxPublicStructsRule) Configure(arguments lint.Arguments) error { if len(arguments) < 1 { r.max = defaultMaxPublicStructs - return + return nil } - checkNumberOfArguments(1, arguments, r.Name()) - maxStructs, ok := arguments[0].(int64) // Alt. non panicking version if !ok { - panic(`invalid value passed as argument number to the "max-public-structs" rule`) + return errors.New(`invalid value passed as argument number to the "max-public-structs" rule`) } r.max = maxStructs + return nil } // Apply applies the rule to given file. -func (r *MaxPublicStructsRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(arguments) }) - +func (r *MaxPublicStructsRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure if r.max < 1 { @@ -59,7 +57,7 @@ func (r *MaxPublicStructsRule) Apply(file *lint.File, arguments lint.Arguments) Failure: fmt.Sprintf("you have exceeded the maximum number (%d) of public struct declarations", r.max), Confidence: 1, Node: fileAst, - Category: "style", + Category: lint.FailureCategoryStyle, }) } @@ -78,8 +76,7 @@ type lintMaxPublicStructs struct { } func (w *lintMaxPublicStructs) Visit(n ast.Node) ast.Visitor { - switch v := n.(type) { - case *ast.TypeSpec: + if v, ok := n.(*ast.TypeSpec); ok { name := v.Name.Name first := string(name[0]) if strings.ToUpper(first) == first { diff --git a/vendor/github.com/mgechev/revive/rule/modifies_param.go b/vendor/github.com/mgechev/revive/rule/modifies_param.go index a68ae2501..f35239027 100644 --- a/vendor/github.com/mgechev/revive/rule/modifies_param.go +++ b/vendor/github.com/mgechev/revive/rule/modifies_param.go @@ -4,12 +4,22 @@ import ( "fmt" "go/ast" + "github.com/mgechev/revive/internal/astutils" "github.com/mgechev/revive/lint" ) -// ModifiesParamRule lints given else constructs. +// ModifiesParamRule warns on assignments to function parameters. type ModifiesParamRule struct{} +// modifyingParamPositions are parameter positions that are modified by a function. +type modifyingParamPositions = []int + +// modifyingFunctions maps function names to the positions of parameters they modify. +var modifyingFunctions = map[string]modifyingParamPositions{ + "slices.Delete": {0}, + "slices.DeleteFunc": {0}, +} + // Apply applies the rule to given file. func (*ModifiesParamRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure @@ -19,7 +29,7 @@ func (*ModifiesParamRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failur } w := lintModifiesParamRule{onFailure: onFailure} - ast.Walk(w, file.AST) + ast.Walk(&w, file.AST) return failures } @@ -47,22 +57,29 @@ func retrieveParamNames(pl []*ast.Field) map[string]bool { return result } -func (w lintModifiesParamRule) Visit(node ast.Node) ast.Visitor { +func (w *lintModifiesParamRule) Visit(node ast.Node) ast.Visitor { switch v := node.(type) { case *ast.FuncDecl: w.params = retrieveParamNames(v.Type.Params.List) case *ast.IncDecStmt: if id, ok := v.X.(*ast.Ident); ok { - checkParam(id, &w) + checkParam(id, w) } case *ast.AssignStmt: lhs := v.Lhs - for _, e := range lhs { + for i, e := range lhs { id, ok := e.(*ast.Ident) - if ok { - checkParam(id, &w) + if !ok { + continue + } + + if i < len(v.Rhs) { + w.checkModifyingFunction(v.Rhs[i]) } + checkParam(id, w) } + case *ast.ExprStmt: + w.checkModifyingFunction(v.X) } return w @@ -73,8 +90,44 @@ func checkParam(id *ast.Ident, w *lintModifiesParamRule) { w.onFailure(lint.Failure{ Confidence: 0.5, // confidence is low because of shadow variables Node: id, - Category: "bad practice", + Category: lint.FailureCategoryBadPractice, Failure: fmt.Sprintf("parameter '%s' seems to be modified", id), }) } } + +func (w *lintModifiesParamRule) checkModifyingFunction(callNode ast.Node) { + callExpr, ok := callNode.(*ast.CallExpr) + if !ok { + return + } + + funcName := astutils.GoFmt(callExpr.Fun) + positions, found := modifyingFunctions[funcName] + if !found { + return + } + + for _, pos := range positions { + if pos >= len(callExpr.Args) { + return + } + + id, ok := callExpr.Args[pos].(*ast.Ident) + if !ok { + continue + } + + _, match := w.params[id.Name] + if !match { + continue + } + + w.onFailure(lint.Failure{ + Confidence: 0.5, // confidence is low because of shadow variables + Node: callExpr, + Category: lint.FailureCategoryBadPractice, + Failure: fmt.Sprintf("parameter '%s' seems to be modified by '%s'", id.Name, funcName), + }) + } +} diff --git a/vendor/github.com/mgechev/revive/rule/modifies_value_receiver.go b/vendor/github.com/mgechev/revive/rule/modifies_value_receiver.go index 2f92991f5..d8daace08 100644 --- a/vendor/github.com/mgechev/revive/rule/modifies_value_receiver.go +++ b/vendor/github.com/mgechev/revive/rule/modifies_value_receiver.go @@ -5,6 +5,7 @@ import ( "go/token" "strings" + "github.com/mgechev/revive/internal/astutils" "github.com/mgechev/revive/lint" ) @@ -12,99 +13,35 @@ import ( type ModifiesValRecRule struct{} // Apply applies the rule to given file. -func (*ModifiesValRecRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { +func (r *ModifiesValRecRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure - onFailure := func(failure lint.Failure) { - failures = append(failures, failure) - } - - w := lintModifiesValRecRule{file: file, onFailure: onFailure} file.Pkg.TypeCheck() - ast.Walk(w, file.AST) - - return failures -} - -// Name returns the rule name. -func (*ModifiesValRecRule) Name() string { - return "modifies-value-receiver" -} - -type lintModifiesValRecRule struct { - file *lint.File - onFailure func(lint.Failure) -} - -func (w lintModifiesValRecRule) Visit(node ast.Node) ast.Visitor { - switch n := node.(type) { - case *ast.FuncDecl: - if n.Recv == nil { - return nil // skip, not a method - } - - receiver := n.Recv.List[0] - if _, ok := receiver.Type.(*ast.StarExpr); ok { - return nil // skip, method with pointer receiver + for _, decl := range file.AST.Decls { + funcDecl, ok := decl.(*ast.FuncDecl) + isAMethod := ok && funcDecl.Recv != nil + if !isAMethod { + continue // skip, not a method } - if w.skipType(receiver.Type) { - return nil // skip, receiver is a map or array - } - - if len(receiver.Names) < 1 { - return nil // skip, anonymous receiver + receiver := funcDecl.Recv.List[0] + if r.mustSkip(receiver, file.Pkg) { + continue } receiverName := receiver.Names[0].Name - if receiverName == "_" { - return nil // skip, anonymous receiver - } - - receiverAssignmentFinder := func(n ast.Node) bool { - // look for assignments with the receiver in the right hand - assignment, ok := n.(*ast.AssignStmt) - if !ok { - return false - } - - for _, exp := range assignment.Lhs { - switch e := exp.(type) { - case *ast.IndexExpr: // receiver...[] = ... - continue - case *ast.StarExpr: // *receiver = ... - continue - case *ast.SelectorExpr: // receiver.field = ... - name := w.getNameFromExpr(e.X) - if name == "" || name != receiverName { - continue - } - case *ast.Ident: // receiver := ... - if e.Name != receiverName { - continue - } - default: - continue - } - - return true - } - - return false - } - - assignmentsToReceiver := pick(n.Body, receiverAssignmentFinder) + assignmentsToReceiver := r.getReceiverModifications(receiverName, funcDecl.Body) if len(assignmentsToReceiver) == 0 { - return nil // receiver is not modified + continue // receiver is not modified } - methodReturnsReceiver := len(w.findReturnReceiverStatements(receiverName, n.Body)) > 0 + methodReturnsReceiver := r.seekReturnReceiverStatement(receiverName, funcDecl.Body) != nil if methodReturnsReceiver { - return nil // modification seems legit (see issue #1066) + continue // modification seems legit (see issue #1066) } for _, assignment := range assignmentsToReceiver { - w.onFailure(lint.Failure{ + failures = append(failures, lint.Failure{ Node: assignment, Confidence: 1, Failure: "suspicious assignment to a by-value method receiver", @@ -112,11 +49,16 @@ func (w lintModifiesValRecRule) Visit(node ast.Node) ast.Visitor { } } - return w + return failures +} + +// Name returns the rule name. +func (*ModifiesValRecRule) Name() string { + return "modifies-value-receiver" } -func (w lintModifiesValRecRule) skipType(t ast.Expr) bool { - rt := w.file.Pkg.TypeOf(t) +func (*ModifiesValRecRule) skipType(t ast.Expr, pkg *lint.Package) bool { + rt := pkg.TypeOf(t) if rt == nil { return false } @@ -128,7 +70,7 @@ func (w lintModifiesValRecRule) skipType(t ast.Expr) bool { return strings.HasPrefix(rtName, "[]") || strings.HasPrefix(rtName, "map[") } -func (lintModifiesValRecRule) getNameFromExpr(ie ast.Expr) string { +func (*ModifiesValRecRule) getNameFromExpr(ie ast.Expr) string { ident, ok := ie.(*ast.Ident) if !ok { return "" @@ -137,7 +79,7 @@ func (lintModifiesValRecRule) getNameFromExpr(ie ast.Expr) string { return ident.Name } -func (w lintModifiesValRecRule) findReturnReceiverStatements(receiverName string, target ast.Node) []ast.Node { +func (r *ModifiesValRecRule) seekReturnReceiverStatement(receiverName string, target ast.Node) ast.Node { finder := func(n ast.Node) bool { // look for returns with the receiver as value returnStatement, ok := n.(*ast.ReturnStmt) @@ -148,7 +90,7 @@ func (w lintModifiesValRecRule) findReturnReceiverStatements(receiverName string for _, exp := range returnStatement.Results { switch e := exp.(type) { case *ast.SelectorExpr: // receiver.field = ... - name := w.getNameFromExpr(e.X) + name := r.getNameFromExpr(e.X) if name == "" || name != receiverName { continue } @@ -160,7 +102,7 @@ func (w lintModifiesValRecRule) findReturnReceiverStatements(receiverName string if e.Op != token.AND { continue } - name := w.getNameFromExpr(e.X) + name := r.getNameFromExpr(e.X) if name == "" || name != receiverName { continue } @@ -175,5 +117,68 @@ func (w lintModifiesValRecRule) findReturnReceiverStatements(receiverName string return false } - return pick(target, finder) + return astutils.SeekNode[ast.Node](target, finder) +} + +func (r *ModifiesValRecRule) mustSkip(receiver *ast.Field, pkg *lint.Package) bool { + if _, ok := receiver.Type.(*ast.StarExpr); ok { + return true // skip, method with pointer receiver + } + + if len(receiver.Names) < 1 { + return true // skip, anonymous receiver + } + + receiverName := receiver.Names[0].Name + if receiverName == "_" { + return true // skip, anonymous receiver + } + + if r.skipType(receiver.Type, pkg) { + return true // skip, receiver is a map or array + } + + return false +} + +func (r *ModifiesValRecRule) getReceiverModifications(receiverName string, funcBody *ast.BlockStmt) []ast.Node { + receiverModificationFinder := func(n ast.Node) bool { + switch node := n.(type) { + case *ast.IncDecStmt: + se, ok := node.X.(*ast.SelectorExpr) + if !ok { + return false + } + + name := r.getNameFromExpr(se.X) + return name == receiverName + case *ast.AssignStmt: + // look for assignments with the receiver in the right hand + for _, exp := range node.Lhs { + switch e := exp.(type) { + case *ast.IndexExpr: // receiver...[] = ... + continue + case *ast.StarExpr: // *receiver = ... + continue + case *ast.SelectorExpr: // receiver.field = ... + name := r.getNameFromExpr(e.X) + if name == "" || name != receiverName { + continue + } + case *ast.Ident: // receiver := ... + if e.Name != receiverName { + continue + } + default: + continue + } + + return true + } + } + + return false + } + + return astutils.PickNodes(funcBody, receiverModificationFinder) } diff --git a/vendor/github.com/mgechev/revive/rule/nested_structs.go b/vendor/github.com/mgechev/revive/rule/nested_structs.go index 147bd482b..49e240b6f 100644 --- a/vendor/github.com/mgechev/revive/rule/nested_structs.go +++ b/vendor/github.com/mgechev/revive/rule/nested_structs.go @@ -68,7 +68,7 @@ func (l *lintStruct) Visit(n ast.Node) ast.Visitor { func (l *lintStruct) fail(n ast.Node) { l.onFailure(lint.Failure{ Failure: "no nested structs are allowed", - Category: "style", + Category: lint.FailureCategoryStyle, Node: n, Confidence: 1, }) diff --git a/vendor/github.com/mgechev/revive/rule/optimize_operands_order.go b/vendor/github.com/mgechev/revive/rule/optimize_operands_order.go index 43d982d6b..e384f4876 100644 --- a/vendor/github.com/mgechev/revive/rule/optimize_operands_order.go +++ b/vendor/github.com/mgechev/revive/rule/optimize_operands_order.go @@ -5,10 +5,11 @@ import ( "go/ast" "go/token" + "github.com/mgechev/revive/internal/astutils" "github.com/mgechev/revive/lint" ) -// OptimizeOperandsOrderRule lints given else constructs. +// OptimizeOperandsOrderRule checks inefficient conditional expressions. type OptimizeOperandsOrderRule struct{} // Apply applies the rule to given file. @@ -18,7 +19,7 @@ func (*OptimizeOperandsOrderRule) Apply(file *lint.File, _ lint.Arguments) []lin onFailure := func(failure lint.Failure) { failures = append(failures, failure) } - w := lintOptimizeOperandsOrderlExpr{ + w := lintOptimizeOperandsOrderExpr{ onFailure: onFailure, } ast.Walk(w, file.AST) @@ -30,13 +31,13 @@ func (*OptimizeOperandsOrderRule) Name() string { return "optimize-operands-order" } -type lintOptimizeOperandsOrderlExpr struct { +type lintOptimizeOperandsOrderExpr struct { onFailure func(failure lint.Failure) } // Visit checks boolean AND and OR expressions to determine // if swapping their operands may result in an execution speedup. -func (w lintOptimizeOperandsOrderlExpr) Visit(node ast.Node) ast.Visitor { +func (w lintOptimizeOperandsOrderExpr) Visit(node ast.Node) ast.Visitor { binExpr, ok := node.(*ast.BinaryExpr) if !ok { return w @@ -63,22 +64,22 @@ func (w lintOptimizeOperandsOrderlExpr) Visit(node ast.Node) ast.Visitor { } // check if the left sub-expression contains a function call - nodes := pick(binExpr.X, isCaller) - if len(nodes) < 1 { + call := astutils.SeekNode[*ast.CallExpr](binExpr.X, isCaller) + if call == nil { return w } // check if the right sub-expression does not contain a function call - nodes = pick(binExpr.Y, isCaller) - if len(nodes) > 0 { + call = astutils.SeekNode[*ast.CallExpr](binExpr.Y, isCaller) + if call != nil { return w } newExpr := ast.BinaryExpr{X: binExpr.Y, Y: binExpr.X, Op: binExpr.Op} w.onFailure(lint.Failure{ - Failure: fmt.Sprintf("for better performance '%v' might be rewritten as '%v'", gofmt(binExpr), gofmt(&newExpr)), + Failure: fmt.Sprintf("for better performance '%v' might be rewritten as '%v'", astutils.GoFmt(binExpr), astutils.GoFmt(&newExpr)), Node: node, - Category: "optimization", + Category: lint.FailureCategoryOptimization, Confidence: 0.3, }) diff --git a/vendor/github.com/mgechev/revive/rule/package_comments.go b/vendor/github.com/mgechev/revive/rule/package_comments.go index f1e5462fe..74af62679 100644 --- a/vendor/github.com/mgechev/revive/rule/package_comments.go +++ b/vendor/github.com/mgechev/revive/rule/package_comments.go @@ -88,7 +88,7 @@ func (l *lintPackageComments) checkPackageComment() []lint.Failure { if docFile != nil { pkgFile := l.file.Pkg.Files()[fileSource] return []lint.Failure{{ - Category: "comments", + Category: lint.FailureCategoryComments, Position: lint.FailurePosition{ Start: pkgFile.ToPosition(docFile.Pos()), End: pkgFile.ToPosition(docFile.Name.End()), @@ -131,7 +131,7 @@ func (l *lintPackageComments) Visit(_ ast.Node) ast.Visitor { Column: 1, } l.onFailure(lint.Failure{ - Category: "comments", + Category: lint.FailureCategoryComments, Position: lint.FailurePosition{ Start: pos, End: pos, @@ -143,7 +143,7 @@ func (l *lintPackageComments) Visit(_ ast.Node) ast.Visitor { } } - if l.fileAst.Doc == nil { + if isEmptyDoc(l.fileAst.Doc) { for _, failure := range l.checkPackageComment() { l.onFailure(failure) } @@ -154,7 +154,7 @@ func (l *lintPackageComments) Visit(_ ast.Node) ast.Visitor { // Only non-main packages need to keep to this form. if !l.file.Pkg.IsMain() && !strings.HasPrefix(s, prefix) && !isDirectiveComment(s) { l.onFailure(lint.Failure{ - Category: "comments", + Category: lint.FailureCategoryComments, Node: l.fileAst.Doc, Confidence: 1, Failure: fmt.Sprintf(`package comment should be of the form "%s..."`, prefix), @@ -162,3 +162,7 @@ func (l *lintPackageComments) Visit(_ ast.Node) ast.Visitor { } return nil } + +func isEmptyDoc(commentGroup *ast.CommentGroup) bool { + return commentGroup == nil || commentGroup.Text() == "" +} diff --git a/vendor/github.com/mgechev/revive/rule/package_directory_mismatch.go b/vendor/github.com/mgechev/revive/rule/package_directory_mismatch.go new file mode 100644 index 000000000..ea8df9d1e --- /dev/null +++ b/vendor/github.com/mgechev/revive/rule/package_directory_mismatch.go @@ -0,0 +1,194 @@ +package rule + +import ( + "fmt" + "os" + "path/filepath" + "regexp" + "strings" + + "github.com/mgechev/revive/lint" +) + +// PackageDirectoryMismatchRule detects when package name doesn't match directory name. +type PackageDirectoryMismatchRule struct { + ignoredDirs *regexp.Regexp +} + +const defaultIgnoredDirs = "testdata" + +// Configure the rule to exclude certain directories. +func (r *PackageDirectoryMismatchRule) Configure(arguments lint.Arguments) error { + if len(arguments) < 1 { + var err error + r.ignoredDirs, err = r.buildIgnoreRegex([]string{defaultIgnoredDirs}) + return err + } + + args, ok := arguments[0].(map[string]any) + if !ok { + return fmt.Errorf("invalid argument type: expected map[string]any, got %T", arguments[0]) + } + + for k, v := range args { + if !isRuleOption(k, "ignoreDirectories") { + return fmt.Errorf("unknown argument %s for %s rule", k, r.Name()) + } + + ignoredAny, ok := v.([]any) + if !ok { + return fmt.Errorf("invalid value %v for argument %s of rule %s, expected []string got %T", v, k, r.Name(), v) + } + + ignoredDirs := make([]string, len(ignoredAny)) + for i, item := range ignoredAny { + str, ok := item.(string) + if !ok { + return fmt.Errorf("invalid value in %s argument of rule %s: expected string, got %T", k, r.Name(), item) + } + ignoredDirs[i] = str + } + + var err error + r.ignoredDirs, err = r.buildIgnoreRegex(ignoredDirs) + return err + } + + return nil +} + +func (*PackageDirectoryMismatchRule) buildIgnoreRegex(ignoredDirs []string) (*regexp.Regexp, error) { + if len(ignoredDirs) == 0 { + return nil, nil + } + + patterns := make([]string, len(ignoredDirs)) + for i, dir := range ignoredDirs { + patterns[i] = regexp.QuoteMeta(dir) + } + pattern := strings.Join(patterns, "|") + + regex, err := regexp.Compile(pattern) + if err != nil { + return nil, fmt.Errorf("failed to compile regex for ignored directories: %w", err) + } + + return regex, nil +} + +// skipDirs contains directory names that should be unconditionally ignored when checking. +// These entries handle edge cases where [filepath.Base] might return these values. +var skipDirs = map[string]struct{}{ + ".": {}, // Current directory + "/": {}, // Root directory + "": {}, // Empty path +} + +// semanticallyEqual checks if package and directory names are semantically equal to each other. +func (*PackageDirectoryMismatchRule) semanticallyEqual(packageName, dirName string) bool { + normDir := normalizePath(dirName) + normPkg := normalizePath(packageName) + return normDir == normPkg || normDir == "go"+normPkg +} + +// Apply applies the rule to the given file. +func (r *PackageDirectoryMismatchRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { + if file.Pkg.IsMain() { + return nil + } + + absPath, err := filepath.Abs(file.Name) + if err != nil { + return nil + } + + dirPath := filepath.Dir(absPath) + dirName := filepath.Base(dirPath) + + if r.ignoredDirs != nil && r.ignoredDirs.MatchString(dirPath) { + return nil + } + + // Check if we got an invalid directory. + if _, skipDir := skipDirs[dirName]; skipDir { + return nil + } + + // Files directly in 'internal/' (like 'internal/abcd.go') should not be checked. + // But files in subdirectories of 'internal/' (like 'internal/foo/abcd.go') should be checked. + if dirName == "internal" { + return nil + } + + packageName := file.AST.Name.Name + + if r.semanticallyEqual(packageName, dirName) { + return nil + } + + if isRootDir(dirPath) { + return nil + } + + if file.IsTest() { + // treat main_test differently because it's a common package name for tests + if packageName == "main_test" { + return nil + } + // External test package (directory + '_test' suffix) + if r.semanticallyEqual(packageName, dirName+"_test") { + return nil + } + } + + // define a default failure message + failure := fmt.Sprintf("package name %q does not match directory name %q", packageName, dirName) + + // For version directories (v1, v2, etc.), we need to check also the parent directory + if isVersionPath(dirName) { + parentDirName := filepath.Base(filepath.Dir(dirPath)) + if r.semanticallyEqual(packageName, parentDirName) { + return nil + } + + if file.IsTest() { + // External test package (directory + '_test' suffix) + if r.semanticallyEqual(packageName, parentDirName+"_test") { + return nil + } + } + + failure = fmt.Sprintf("package name %q does not match directory name %q or parent directory name %q", packageName, dirName, parentDirName) + } + + return []lint.Failure{ + { + Failure: failure, + Confidence: 1, + Node: file.AST.Name, + Category: lint.FailureCategoryNaming, + }, + } +} + +// isRootDir checks if the given directory contains go.mod or .git, indicating it's a root directory. +func isRootDir(dirPath string) bool { + entries, err := os.ReadDir(dirPath) + if err != nil { + return false + } + + for _, e := range entries { + switch e.Name() { + case "go.mod", ".git": + return true + } + } + + return false +} + +// Name returns the rule name. +func (*PackageDirectoryMismatchRule) Name() string { + return "package-directory-mismatch" +} diff --git a/vendor/github.com/mgechev/revive/rule/package_naming.go b/vendor/github.com/mgechev/revive/rule/package_naming.go new file mode 100644 index 000000000..642b16a13 --- /dev/null +++ b/vendor/github.com/mgechev/revive/rule/package_naming.go @@ -0,0 +1,315 @@ +package rule + +import ( + "errors" + "fmt" + "go/ast" + "path/filepath" + "regexp" + "strings" + + gopackages "golang.org/x/tools/go/packages" + + "github.com/mgechev/revive/internal/syncset" + "github.com/mgechev/revive/lint" +) + +// defaultBadNames is the list of "bad" package names from https://go.dev/blog/package-names#bad-package-names. +var defaultBadNames = map[string]struct{}{ + "common": {}, + "interface": {}, + "interfaces": {}, + "misc": {}, + "type": {}, + "types": {}, + "util": {}, + "utils": {}, +} + +// extraBadNames is the list of additional "bad" package names that are not recommended. +var extraBadNames = map[string]struct{}{ + "api": {}, + "helpers": {}, + "miscellaneous": {}, + "models": {}, + "shared": {}, + "utilities": {}, +} + +// commonStdNames is the list of standard library package names that are commonly used in Go programs. +// This list is based on the most popular standard library packages according to importedby tab in pkg.go.dev. +// For example, "http" imported by 1,705,800 times https://pkg.go.dev/net/http?tab=importedby +var commonStdNames = map[string]string{ + "bytes": "bytes", + "bufio": "bufio", + "flag": "flag", + "context": "context", + "errors": "errors", + "filepath": "path/filepath", + "fmt": "fmt", + "http": "net/http", + "io": "io", + "ioutil": "io/ioutil", + "json": "encoding/json", + "log": "log", + "math": "math", + "net": "net", + "os": "os", + "strconv": "strconv", + "reflect": "reflect", + "regexp": "regexp", + "runtime": "runtime", + "sort": "sort", + "strings": "strings", + "sync": "sync", + "time": "time", + "url": "net/url", +} + +// nonPublicPackageSegments are package path segments that indicate the std package is not public. +var nonPublicPackageSegments = map[string]struct{}{ + "internal": {}, + "vendor": {}, +} + +// forbiddenTopLevelNames is the set of forbidden top level package names. +var forbiddenTopLevelNames = map[string]struct{}{ + "pkg": {}, +} + +// PackageNamingRule is a rule that checks package names. +type PackageNamingRule struct { + skipConventionNameCheck bool // if true - skip checks for package name conventions (e.g., no underscores, no MixedCaps etc.) + conventionNameCheckRegex *regexp.Regexp // the regex used to check package name conventions + + skipTopLevelCheck bool // if true - skip checks for top level package names (e.g., "pkg") + + skipDefaultBadNameCheck bool // if true - skip checks for default bad package names (e.g., "util", "misc" etc.) + checkExtraBadName bool // if true - enable check for extra bad package names (e.g., "helpers", "models" etc.) + userDefinedBadNames map[string]struct{} // set of user defined bad package names + + skipCollisionWithCommonStd bool // if true - skip checks for collisions with common Go standard library package names (e.g., "http", "json", "rand" etc.) + + checkCollisionWithAllStd bool // if true - enable checks for collisions with all Go standard library package names (including "version", "metrics" etc.) + // allStdNames holds name -> path of standard library packages excluding internal and vendor. + // Populated only if checkCollisionWithAllStd is true. `net/http` stored as `http`, `math/rand/v2` as `rand` etc. + allStdNames map[string]string + + // alreadyCheckedNames is keyed by fileDir (package directory path) to track which package directories + // have already been checked and avoid duplicate checks across files in the same package. + alreadyCheckedNames *syncset.Set +} + +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *PackageNamingRule) Configure(arguments lint.Arguments) error { + r.alreadyCheckedNames = syncset.New() + + if len(arguments) == 0 { + return nil + } + + if len(arguments) > 1 { + return fmt.Errorf("invalid arguments to the package-naming rule: expected at most 1 argument, but got %d", len(arguments)) + } + + args, ok := arguments[0].(map[string]any) + if !ok { + return fmt.Errorf("invalid argument to the package-naming rule: expecting a k,v map, but got %T", arguments[0]) + } + + for k, v := range args { + switch { + case isRuleOption(k, "skipConventionNameCheck"): + r.skipConventionNameCheck, ok = v.(bool) + if !ok { + return fmt.Errorf("invalid argument to the package-naming rule: expecting skipConventionNameCheck to be a boolean, but got %T", v) + } + case isRuleOption(k, "conventionNameCheckRegex"): + regexStr, ok := v.(string) + if !ok { + return fmt.Errorf("invalid argument to the package-naming rule: expecting conventionNameCheckRegex to be a string, but got %T", v) + } + if regexStr == "" { + return errors.New("invalid argument to the package-naming rule: conventionNameCheckRegex cannot be an empty string") + } + regex, err := regexp.Compile(regexStr) + if err != nil { + return fmt.Errorf("invalid argument to the package-naming rule: invalid regex for conventionNameCheckRegex: %w", err) + } + r.conventionNameCheckRegex = regex + case isRuleOption(k, "skipTopLevelCheck"): + r.skipTopLevelCheck, ok = v.(bool) + if !ok { + return fmt.Errorf("invalid argument to the package-naming rule: expecting skipTopLevelCheck to be a boolean, but got %T", v) + } + case isRuleOption(k, "skipDefaultBadNameCheck"): + r.skipDefaultBadNameCheck, ok = v.(bool) + if !ok { + return fmt.Errorf("invalid argument to the package-naming rule: expecting skipDefaultBadNameCheck to be a boolean, but got %T", v) + } + case isRuleOption(k, "checkExtraBadName"): + r.checkExtraBadName, ok = v.(bool) + if !ok { + return fmt.Errorf("invalid argument to the package-naming rule: expecting checkExtraBadName to be a boolean, but got %T", v) + } + case isRuleOption(k, "userDefinedBadNames"): + userDefinedBadNames, ok := v.([]any) + if !ok { + return fmt.Errorf("invalid argument to the package-naming rule: expecting userDefinedBadNames of type slice of strings, but got %T", v) + } + for i, name := range userDefinedBadNames { + if r.userDefinedBadNames == nil { + r.userDefinedBadNames = map[string]struct{}{} + } + n, ok := name.(string) + if !ok { + return fmt.Errorf("invalid argument to the package-naming rule: expecting element %d of userDefinedBadNames to be a string, but got %v(%T)", i, name, name) + } + if n == "" { + return fmt.Errorf("invalid argument to the package-naming rule: userDefinedBadNames cannot contain empty string (index %d)", i) + } + r.userDefinedBadNames[strings.ToLower(n)] = struct{}{} + } + case isRuleOption(k, "skipCollisionWithCommonStd"): + r.skipCollisionWithCommonStd, ok = v.(bool) + if !ok { + return fmt.Errorf("invalid argument to the package-naming rule: expecting skipCollisionWithCommonStd to be a boolean, but got %T", v) + } + case isRuleOption(k, "checkCollisionWithAllStd"): + r.checkCollisionWithAllStd, ok = v.(bool) + if !ok { + return fmt.Errorf("invalid argument to the package-naming rule: expecting checkCollisionWithAllStd to be a boolean, but got %T", v) + } + } + } + + if r.skipConventionNameCheck && r.conventionNameCheckRegex != nil { + return errors.New("invalid configuration for package-naming rule: skipConventionNameCheck and conventionNameCheckRegex cannot be both set") + } + + if r.skipCollisionWithCommonStd && r.checkCollisionWithAllStd { + return errors.New("invalid configuration for package-naming rule: skipCollisionWithCommonStd and checkCollisionWithAllStd cannot be both set") + } + + if r.checkCollisionWithAllStd && r.allStdNames == nil { + pkgs, err := gopackages.Load(nil, "std") + if err != nil { + return fmt.Errorf("load std packages: %w", err) + } + + r.allStdNames = map[string]string{} + for _, pkg := range pkgs { + if isNonPublicPackage(pkg.PkgPath) { + continue + } + if existingPath, ok := r.allStdNames[pkg.Name]; !ok || pkg.PkgPath < existingPath { + r.allStdNames[pkg.Name] = pkg.PkgPath + } + } + } + + return nil +} + +// isNonPublicPackage reports whether the path represents an internal or vendor directory. +func isNonPublicPackage(path string) bool { + for p := range strings.SplitSeq(path, "/") { + if _, ok := nonPublicPackageSegments[p]; ok { + return true + } + } + return false +} + +// Apply applies the rule to given file. +func (r *PackageNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { + var failures []lint.Failure + onFailure := func(failure lint.Failure) { + failures = append(failures, failure) + } + + fileDir := filepath.Dir(file.Name) + + if !r.alreadyCheckedNames.AddIfAbsent(fileDir) { + return failures + } + + node := file.AST.Name + pkgName := node.Name + pkgNameWithoutTestSuffix := strings.TrimSuffix(pkgName, "_test") + + if r.conventionNameCheckRegex != nil { + if !r.conventionNameCheckRegex.MatchString(pkgNameWithoutTestSuffix) { + onFailure(r.pkgNameFailure(node, "package name %q doesn't match the convention defined by conventionNameCheckRegex", pkgName)) + return failures + } + } else if !r.skipConventionNameCheck { + // Package names need slightly different handling than other names. + if strings.Contains(pkgNameWithoutTestSuffix, "_") { + onFailure(r.pkgNameFailure(node, "don't use package name %q that contains an underscore", pkgName)) + return failures + } + if hasUpperCaseLetter(pkgNameWithoutTestSuffix) { + onFailure(r.pkgNameFailure(node, "don't use package name %q that contains MixedCaps", pkgName)) + return failures + } + } + + pkgNameLower := strings.ToLower(pkgName) + if !r.skipTopLevelCheck { + if _, ok := forbiddenTopLevelNames[pkgNameLower]; ok && filepath.Base(fileDir) != pkgName { + onFailure(r.pkgNameFailure(node, "don't use %q as a root level package name", pkgName)) + return failures + } + } + + if !r.skipDefaultBadNameCheck { + if _, ok := defaultBadNames[pkgNameLower]; ok { + onFailure(r.pkgNameFailure(node, "don't use %q because it is a bad package name according to https://go.dev/blog/package-names#bad-package-names", pkgName)) + return failures + } + } + + if r.checkExtraBadName { + if _, ok := extraBadNames[pkgNameLower]; ok { + onFailure(r.pkgNameFailure(node, "don't use %q because it is a bad package name (extra)", pkgName)) + return failures + } + } + + if r.userDefinedBadNames != nil { + if _, ok := r.userDefinedBadNames[pkgNameLower]; ok { + onFailure(r.pkgNameFailure(node, "don't use %q because it is a bad package name (user-defined)", pkgName)) + return failures + } + } + + if r.checkCollisionWithAllStd { + // all std names are also common std names, so no need to check separately + if std, ok := r.allStdNames[pkgNameLower]; ok { + onFailure(r.pkgNameFailure(node, "don't use %q because it conflicts with Go standard library package %q", pkgName, std)) + } + } else if !r.skipCollisionWithCommonStd { + if std, ok := commonStdNames[pkgNameLower]; ok { + onFailure(r.pkgNameFailure(node, "don't use %q because it conflicts with common Go standard library package %q", pkgName, std)) + } + } + + return failures +} + +// Name returns the rule name. +func (*PackageNamingRule) Name() string { + return "package-naming" +} + +func (*PackageNamingRule) pkgNameFailure(node ast.Node, msg string, args ...any) lint.Failure { + return lint.Failure{ + Failure: fmt.Sprintf(msg, args...), + Confidence: 1, + Node: node, + Category: lint.FailureCategoryNaming, + } +} diff --git a/vendor/github.com/mgechev/revive/rule/range.go b/vendor/github.com/mgechev/revive/rule/range.go index 9d483a673..2772f11b8 100644 --- a/vendor/github.com/mgechev/revive/rule/range.go +++ b/vendor/github.com/mgechev/revive/rule/range.go @@ -5,10 +5,11 @@ import ( "go/ast" "strings" + "github.com/mgechev/revive/internal/astutils" "github.com/mgechev/revive/lint" ) -// RangeRule lints given else constructs. +// RangeRule prevents redundant variables when iterating over a collection. type RangeRule struct{} // Apply applies the rule to given file. @@ -43,7 +44,7 @@ func (w *lintRanges) Visit(node ast.Node) ast.Visitor { // for x = range m { ... } return w // single var form } - if !isIdent(rs.Value, "_") { + if !astutils.IsIdent(rs.Value, "_") { // for ?, y = range m { ... } return w } diff --git a/vendor/github.com/mgechev/revive/rule/range_val_address.go b/vendor/github.com/mgechev/revive/rule/range_val_address.go index d2ab0392a..6622cd5a5 100644 --- a/vendor/github.com/mgechev/revive/rule/range_val_address.go +++ b/vendor/github.com/mgechev/revive/rule/range_val_address.go @@ -9,14 +9,14 @@ import ( "github.com/mgechev/revive/lint" ) -// RangeValAddress lints +// RangeValAddress warns if address of range value is used dangerously. type RangeValAddress struct{} // Apply applies the rule to given file. func (*RangeValAddress) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure - if file.Pkg.IsAtLeastGo122() { + if file.Pkg.IsAtLeastGoVersion(lint.Go122) { return failures } @@ -70,7 +70,7 @@ func (w rangeValAddress) Visit(node ast.Node) ast.Visitor { type rangeBodyVisitor struct { valueIsStarExpr bool - valueID *ast.Object + valueID *ast.Object //nolint:staticcheck // TODO: ast.Object is deprecated onFailure func(lint.Failure) } @@ -140,7 +140,7 @@ func (bw rangeBodyVisitor) isAccessingRangeValueAddress(exp ast.Expr) bool { v, ok := u.X.(*ast.Ident) if !ok { var s *ast.SelectorExpr - s, ok = u.X.(*ast.SelectorExpr) + s, ok = u.X.(*ast.SelectorExpr) // TODO: possible BUG: if it's `=` and not `:=`, it means that in the last return `ok` is always true if !ok { return false } @@ -154,7 +154,7 @@ func (bw rangeBodyVisitor) isAccessingRangeValueAddress(exp ast.Expr) bool { } } - return ok && v.Obj == bw.valueID + return ok && v.Obj == bw.valueID // TODO: ok is always true due to the previous TODO remark } func (bw rangeBodyVisitor) newFailure(node ast.Node) lint.Failure { diff --git a/vendor/github.com/mgechev/revive/rule/range_val_in_closure.go b/vendor/github.com/mgechev/revive/rule/range_val_in_closure.go index 6f9255a74..a99376fbf 100644 --- a/vendor/github.com/mgechev/revive/rule/range_val_in_closure.go +++ b/vendor/github.com/mgechev/revive/rule/range_val_in_closure.go @@ -7,14 +7,14 @@ import ( "github.com/mgechev/revive/lint" ) -// RangeValInClosureRule lints given else constructs. +// RangeValInClosureRule warns if range value is used in a closure dispatched as goroutine. type RangeValInClosureRule struct{} // Apply applies the rule to given file. func (*RangeValInClosureRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure - if file.Pkg.IsAtLeastGo122() { + if file.Pkg.IsAtLeastGoVersion(lint.Go122) { return failures } diff --git a/vendor/github.com/mgechev/revive/rule/receiver_naming.go b/vendor/github.com/mgechev/revive/rule/receiver_naming.go index c83bacc2f..e2737ed89 100644 --- a/vendor/github.com/mgechev/revive/rule/receiver_naming.go +++ b/vendor/github.com/mgechev/revive/rule/receiver_naming.go @@ -3,62 +3,103 @@ package rule import ( "fmt" "go/ast" - "sync" "github.com/mgechev/revive/internal/typeparams" "github.com/mgechev/revive/lint" ) -// ReceiverNamingRule lints given else constructs. +// ReceiverNamingRule lints a receiver name. type ReceiverNamingRule struct { receiverNameMaxLength int - - configureOnce sync.Once } const defaultReceiverNameMaxLength = -1 // thus will not check - -func (r *ReceiverNamingRule) configure(arguments lint.Arguments) { +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *ReceiverNamingRule) Configure(arguments lint.Arguments) error { r.receiverNameMaxLength = defaultReceiverNameMaxLength if len(arguments) < 1 { - return + return nil } args, ok := arguments[0].(map[string]any) if !ok { - panic(fmt.Sprintf("Unable to get arguments for rule %s. Expected object of key-value-pairs.", r.Name())) + return fmt.Errorf("unable to get arguments for rule %s. Expected object of key-value-pairs", r.Name()) } for k, v := range args { - switch k { - case "maxLength": - value, ok := v.(int64) - if !ok { - panic(fmt.Sprintf("Invalid value %v for argument %s of rule %s, expected integer value got %T", v, k, r.Name(), v)) - } - r.receiverNameMaxLength = int(value) - default: - panic(fmt.Sprintf("Unknown argument %s for %s rule.", k, r.Name())) + if !isRuleOption(k, "maxLength") { + return fmt.Errorf("unknown argument %s for %s rule", k, r.Name()) } + value, ok := v.(int64) + if !ok { + return fmt.Errorf("invalid value %v for argument %s of rule %s, expected integer value got %T", v, k, r.Name(), v) + } + r.receiverNameMaxLength = int(value) } + return nil } // Apply applies the rule to given file. -func (r *ReceiverNamingRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(args) }) - +func (r *ReceiverNamingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { + typeReceiver := map[string]string{} var failures []lint.Failure + for _, decl := range file.AST.Decls { + fn, ok := decl.(*ast.FuncDecl) + if !ok || fn.Recv == nil || len(fn.Recv.List) == 0 { + continue + } - fileAst := file.AST - walker := lintReceiverName{ - onFailure: func(failure lint.Failure) { - failures = append(failures, failure) - }, - typeReceiver: map[string]string{}, - receiverNameMaxLength: r.receiverNameMaxLength, - } + names := fn.Recv.List[0].Names + if len(names) < 1 { + continue + } + name := names[0].Name + + if name == "_" { + failures = append(failures, lint.Failure{ + Node: decl, + Confidence: 1, + Category: lint.FailureCategoryNaming, + Failure: "receiver name should not be an underscore, omit the name if it is unused", + }) + continue + } + + if name == "this" || name == "self" { + failures = append(failures, lint.Failure{ + Node: decl, + Confidence: 1, + Category: lint.FailureCategoryNaming, + Failure: `receiver name should be a reflection of its identity; don't use generic names such as "this" or "self"`, + }) + continue + } + + if r.receiverNameMaxLength > 0 && len([]rune(name)) > r.receiverNameMaxLength { + failures = append(failures, lint.Failure{ + Node: decl, + Confidence: 1, + Category: lint.FailureCategoryNaming, + Failure: fmt.Sprintf("receiver name %s is longer than %d characters", name, r.receiverNameMaxLength), + }) + continue + } + + recv := typeparams.ReceiverType(fn) + if prev, ok := typeReceiver[recv]; ok && prev != name { + failures = append(failures, lint.Failure{ + Node: decl, + Confidence: 1, + Category: lint.FailureCategoryNaming, + Failure: fmt.Sprintf("receiver name %s should be consistent with previous receiver name %s for %s", name, prev, recv), + }) + continue + } - ast.Walk(walker, fileAst) + typeReceiver[recv] = name + } return failures } @@ -67,62 +108,3 @@ func (r *ReceiverNamingRule) Apply(file *lint.File, args lint.Arguments) []lint. func (*ReceiverNamingRule) Name() string { return "receiver-naming" } - -type lintReceiverName struct { - onFailure func(lint.Failure) - typeReceiver map[string]string - receiverNameMaxLength int -} - -func (w lintReceiverName) Visit(n ast.Node) ast.Visitor { - fn, ok := n.(*ast.FuncDecl) - if !ok || fn.Recv == nil || len(fn.Recv.List) == 0 { - return w - } - names := fn.Recv.List[0].Names - if len(names) < 1 { - return w - } - name := names[0].Name - if name == "_" { - w.onFailure(lint.Failure{ - Node: n, - Confidence: 1, - Category: "naming", - Failure: "receiver name should not be an underscore, omit the name if it is unused", - }) - return w - } - if name == "this" || name == "self" { - w.onFailure(lint.Failure{ - Node: n, - Confidence: 1, - Category: "naming", - Failure: `receiver name should be a reflection of its identity; don't use generic names such as "this" or "self"`, - }) - return w - } - - if w.receiverNameMaxLength > 0 && len([]rune(name)) > w.receiverNameMaxLength { - w.onFailure(lint.Failure{ - Node: n, - Confidence: 1, - Category: "naming", - Failure: fmt.Sprintf("receiver name %s is longer than %d characters", name, w.receiverNameMaxLength), - }) - return w - } - - recv := typeparams.ReceiverType(fn) - if prev, ok := w.typeReceiver[recv]; ok && prev != name { - w.onFailure(lint.Failure{ - Node: n, - Confidence: 1, - Category: "naming", - Failure: fmt.Sprintf("receiver name %s should be consistent with previous receiver name %s for %s", name, prev, recv), - }) - return w - } - w.typeReceiver[recv] = name - return w -} diff --git a/vendor/github.com/mgechev/revive/rule/redefines_builtin_id.go b/vendor/github.com/mgechev/revive/rule/redefines_builtin_id.go index 10ea16ae1..52c679f17 100644 --- a/vendor/github.com/mgechev/revive/rule/redefines_builtin_id.go +++ b/vendor/github.com/mgechev/revive/rule/redefines_builtin_id.go @@ -78,7 +78,7 @@ func (*RedefinesBuiltinIDRule) Apply(file *lint.File, _ lint.Arguments) []lint.F astFile := file.AST builtFuncs := maps.Clone(builtFunctions) - if file.Pkg.IsAtLeastGo121() { + if file.Pkg.IsAtLeastGoVersion(lint.Go121) { maps.Copy(builtFuncs, builtFunctionsAfterGo121) } w := &lintRedefinesBuiltinID{ @@ -198,11 +198,11 @@ func (w *lintRedefinesBuiltinID) Visit(node ast.Node) ast.Visitor { return w } -func (w lintRedefinesBuiltinID) addFailure(node ast.Node, msg string) { +func (w *lintRedefinesBuiltinID) addFailure(node ast.Node, msg string) { w.onFailure(lint.Failure{ Confidence: 1, Node: node, - Category: "logic", + Category: lint.FailureCategoryLogic, Failure: msg, }) } diff --git a/vendor/github.com/mgechev/revive/rule/redundant_build_tag.go b/vendor/github.com/mgechev/revive/rule/redundant_build_tag.go new file mode 100644 index 000000000..d195ce6e4 --- /dev/null +++ b/vendor/github.com/mgechev/revive/rule/redundant_build_tag.go @@ -0,0 +1,41 @@ +package rule + +import ( + "strings" + + "github.com/mgechev/revive/lint" +) + +// RedundantBuildTagRule lints the presence of redundant build tags. +type RedundantBuildTagRule struct{} + +// Apply triggers if an old build tag `// +build` is found after a new one `//go:build`. +// `//go:build` comments are automatically added by gofmt when Go 1.17+ is used. +// See https://pkg.go.dev/cmd/go#hdr-Build_constraints +func (*RedundantBuildTagRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { + for _, group := range file.AST.Comments { + hasGoBuild := false + for _, comment := range group.List { + if strings.HasPrefix(comment.Text, "//go:build ") { + hasGoBuild = true + continue + } + + if hasGoBuild && strings.HasPrefix(comment.Text, "// +build ") { + return []lint.Failure{{ + Category: lint.FailureCategoryStyle, + Confidence: 1, + Node: comment, + Failure: `The build tag "// +build" is redundant since Go 1.17 and can be removed`, + }} + } + } + } + + return []lint.Failure{} +} + +// Name returns the rule name. +func (*RedundantBuildTagRule) Name() string { + return "redundant-build-tag" +} diff --git a/vendor/github.com/mgechev/revive/rule/redundant_import_alias.go b/vendor/github.com/mgechev/revive/rule/redundant_import_alias.go index fa5281f24..9c2edb013 100644 --- a/vendor/github.com/mgechev/revive/rule/redundant_import_alias.go +++ b/vendor/github.com/mgechev/revive/rule/redundant_import_alias.go @@ -8,7 +8,7 @@ import ( "github.com/mgechev/revive/lint" ) -// RedundantImportAlias lints given else constructs. +// RedundantImportAlias warns on import aliases matching the imported package name. type RedundantImportAlias struct{} // Apply applies the rule to given file. @@ -23,9 +23,9 @@ func (*RedundantImportAlias) Apply(file *lint.File, _ lint.Arguments) []lint.Fai if getImportPackageName(imp) == imp.Name.Name { failures = append(failures, lint.Failure{ Confidence: 1, - Failure: fmt.Sprintf("Import alias \"%s\" is redundant", imp.Name.Name), + Failure: fmt.Sprintf("Import alias %q is redundant", imp.Name.Name), Node: imp, - Category: "imports", + Category: lint.FailureCategoryImports, }) } } diff --git a/vendor/github.com/mgechev/revive/rule/redundant_test_main_exit.go b/vendor/github.com/mgechev/revive/rule/redundant_test_main_exit.go new file mode 100644 index 000000000..04e643e5f --- /dev/null +++ b/vendor/github.com/mgechev/revive/rule/redundant_test_main_exit.go @@ -0,0 +1,84 @@ +package rule + +import ( + "fmt" + "go/ast" + + "github.com/mgechev/revive/lint" +) + +// RedundantTestMainExitRule suggests removing redundant [os.Exit] or [syscall.Exit] calls in TestMain function. +type RedundantTestMainExitRule struct{} + +// Apply applies the rule to given file. +func (*RedundantTestMainExitRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { + var failures []lint.Failure + + if !file.IsTest() || !file.Pkg.IsAtLeastGoVersion(lint.Go115) { + // skip analysis for non-test files or for Go versions before 1.15 + return failures + } + + onFailure := func(failure lint.Failure) { + failures = append(failures, failure) + } + + w := &lintRedundantTestMainExit{onFailure: onFailure} + ast.Walk(w, file.AST) + return failures +} + +// Name returns the rule name. +func (*RedundantTestMainExitRule) Name() string { + return "redundant-test-main-exit" +} + +type lintRedundantTestMainExit struct { + onFailure func(lint.Failure) +} + +func (w *lintRedundantTestMainExit) Visit(node ast.Node) ast.Visitor { + if fd, ok := node.(*ast.FuncDecl); ok { + if fd.Name.Name != "TestMain" { + return nil // skip analysis for other functions than TestMain + } + + return w + } + + se, ok := node.(*ast.ExprStmt) + if !ok { + return w + } + ce, ok := se.X.(*ast.CallExpr) + if !ok { + return w + } + + fc, ok := ce.Fun.(*ast.SelectorExpr) + if !ok { + return w + } + id, ok := fc.X.(*ast.Ident) + if !ok { + return w + } + + pkg := id.Name + // skip flag calls because they are commonly used in TestMain + if pkg == "flag" { + return w + } + + fn := fc.Sel.Name + if isCallToExitFunction(pkg, fn, ce.Args) { + w.onFailure(lint.Failure{ + Confidence: 1, + Node: ce, + Category: lint.FailureCategoryStyle, + Failure: fmt.Sprintf("redundant call to %s.%s in TestMain function, the test runner will handle it automatically as of Go 1.15", pkg, fn), + }) + } + + return w +} diff --git a/vendor/github.com/mgechev/revive/rule/string_format.go b/vendor/github.com/mgechev/revive/rule/string_format.go index ecac3fa7c..0cf05e37a 100644 --- a/vendor/github.com/mgechev/revive/rule/string_format.go +++ b/vendor/github.com/mgechev/revive/rule/string_format.go @@ -11,21 +11,27 @@ import ( "github.com/mgechev/revive/lint" ) -// #region Revive API - -// StringFormatRule lints strings and/or comments according to a set of regular expressions given as Arguments -type StringFormatRule struct{} +// StringFormatRule lints strings and/or comments according to a set of regular expressions given as arguments. +type StringFormatRule struct { + rules []stringFormatSubrule +} // Apply applies the rule to the given file. -func (*StringFormatRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { +func (r *StringFormatRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure onFailure := func(failure lint.Failure) { failures = append(failures, failure) } - w := lintStringFormatRule{onFailure: onFailure} - w.parseArguments(arguments) + for i := range r.rules { + r.rules[i].onFailure = onFailure + } + + w := &lintStringFormatRule{ + rules: r.rules, + } + ast.Walk(w, file.AST) return failures @@ -36,37 +42,31 @@ func (*StringFormatRule) Name() string { return "string-format" } -// ParseArgumentsTest is a public wrapper around w.parseArguments used for testing. Returns the error message provided to panic, or nil if no error was encountered -func (StringFormatRule) ParseArgumentsTest(arguments lint.Arguments) *string { - w := lintStringFormatRule{} - c := make(chan any) - // Parse the arguments in a goroutine, defer a recover() call, return the error encountered (or nil if there was no error) - go func() { - defer func() { - err := recover() - c <- err - }() - w.parseArguments(arguments) - }() - err := <-c - if err != nil { - e := fmt.Sprintf("%s", err) - return &e +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *StringFormatRule) Configure(arguments lint.Arguments) error { + for i, argument := range arguments { + scopes, regex, negated, errorMessage, err := r.parseArgument(argument, i) + if err != nil { + return err + } + r.rules = append(r.rules, stringFormatSubrule{ + scopes: scopes, + regexp: regex, + negated: negated, + errorMessage: errorMessage, + }) } return nil } -// #endregion - -// #region Internal structure - type lintStringFormatRule struct { - onFailure func(lint.Failure) - rules []stringFormatSubrule + rules []stringFormatSubrule } type stringFormatSubrule struct { - parent *lintStringFormatRule + onFailure func(lint.Failure) scopes stringFormatSubruleScopes regexp *regexp.Regexp negated bool @@ -81,51 +81,35 @@ type stringFormatSubruleScope struct { field string // (optional) If the argument to be checked is a struct, which member of the struct is checked against the rule (top level members only) } -// Regex inserted to match valid function/struct field identifiers +// identRegex matches valid function/struct field identifiers. const identRegex = "[_A-Za-z][_A-Za-z0-9]*" var parseStringFormatScope = regexp.MustCompile( fmt.Sprintf("^(%s(?:\\.%s)?)(?:\\[([0-9]+)\\](?:\\.(%s))?)?$", identRegex, identRegex, identRegex)) -// #endregion - -// #region Argument parsing - -func (w *lintStringFormatRule) parseArguments(arguments lint.Arguments) { - for i, argument := range arguments { - scopes, regex, negated, errorMessage := w.parseArgument(argument, i) - w.rules = append(w.rules, stringFormatSubrule{ - parent: w, - scopes: scopes, - regexp: regex, - negated: negated, - errorMessage: errorMessage, - }) - } -} - -func (w lintStringFormatRule) parseArgument(argument any, ruleNum int) (scopes stringFormatSubruleScopes, regex *regexp.Regexp, negated bool, errorMessage string) { +//revive:disable-next-line:function-result-limit +func (r *StringFormatRule) parseArgument(argument any, ruleNum int) (scopes stringFormatSubruleScopes, regex *regexp.Regexp, negated bool, errorMessage string, err error) { g, ok := argument.([]any) // Cast to generic slice first if !ok { - w.configError("argument is not a slice", ruleNum, 0) + return stringFormatSubruleScopes{}, regex, false, "", r.configError("argument is not a slice", ruleNum, 0) } if len(g) < 2 { - w.configError("less than two slices found in argument, scope and regex are required", ruleNum, len(g)-1) + return stringFormatSubruleScopes{}, regex, false, "", r.configError("less than two slices found in argument, scope and regex are required", ruleNum, len(g)-1) } rule := make([]string, len(g)) for i, obj := range g { val, ok := obj.(string) if !ok { - w.configError("unexpected value, string was expected", ruleNum, i) + return stringFormatSubruleScopes{}, regex, false, "", r.configError("unexpected value, string was expected", ruleNum, i) } rule[i] = val } // Validate scope and regex length if rule[0] == "" { - w.configError("empty scope provided", ruleNum, 0) + return stringFormatSubruleScopes{}, regex, false, "", r.configError("empty scope provided", ruleNum, 0) } else if len(rule[1]) < 2 { - w.configError("regex is too small (regexes should begin and end with '/')", ruleNum, 1) + return stringFormatSubruleScopes{}, regex, false, "", r.configError("regex is too small (regexes should begin and end with '/')", ruleNum, 1) } // Parse rule scopes @@ -135,28 +119,29 @@ func (w lintStringFormatRule) parseArgument(argument any, ruleNum int) (scopes s for scopeNum, rawScope := range rawScopes { rawScope = strings.TrimSpace(rawScope) - if len(rawScope) == 0 { - w.parseScopeError("empty scope in rule scopes:", ruleNum, 0, scopeNum) + if rawScope == "" { + return stringFormatSubruleScopes{}, regex, false, "", r.parseScopeError("empty scope in rule scopes:", ruleNum, 0, scopeNum) } scope := stringFormatSubruleScope{} matches := parseStringFormatScope.FindStringSubmatch(rawScope) if matches == nil { // The rule's scope didn't match the parsing regex at all, probably a configuration error - w.parseScopeError("unable to parse rule scope", ruleNum, 0, scopeNum) + return stringFormatSubruleScopes{}, regex, false, "", r.parseScopeError("unable to parse rule scope", ruleNum, 0, scopeNum) } else if len(matches) != 4 { // The rule's scope matched the parsing regex, but an unexpected number of submatches was returned, probably a bug - w.parseScopeError(fmt.Sprintf("unexpected number of submatches when parsing scope: %d, expected 4", len(matches)), ruleNum, 0, scopeNum) + return stringFormatSubruleScopes{}, regex, false, "", + r.parseScopeError(fmt.Sprintf("unexpected number of submatches when parsing scope: %d, expected 4", len(matches)), ruleNum, 0, scopeNum) } scope.funcName = matches[1] - if len(matches[2]) > 0 { + if matches[2] != "" { var err error scope.argument, err = strconv.Atoi(matches[2]) if err != nil { - w.parseScopeError("unable to parse argument number in rule scope", ruleNum, 0, scopeNum) + return stringFormatSubruleScopes{}, regex, false, "", r.parseScopeError("unable to parse argument number in rule scope", ruleNum, 0, scopeNum) } } - if len(matches[3]) > 0 { + if matches[3] != "" { scope.field = matches[3] } @@ -169,38 +154,35 @@ func (w lintStringFormatRule) parseArgument(argument any, ruleNum int) (scopes s if negated { offset++ } - regex, err := regexp.Compile(rule[1][offset : len(rule[1])-1]) - if err != nil { - w.parseError(fmt.Sprintf("unable to compile %s as regexp", rule[1]), ruleNum, 1) + regex, errr := regexp.Compile(rule[1][offset : len(rule[1])-1]) + if errr != nil { + return stringFormatSubruleScopes{}, regex, false, "", r.parseError(fmt.Sprintf("unable to compile %s as regexp", rule[1]), ruleNum, 1) } // Use custom error message if provided if len(rule) == 3 { errorMessage = rule[2] } - return scopes, regex, negated, errorMessage + return scopes, regex, negated, errorMessage, nil } -// Report an invalid config, this is specifically the user's fault -func (lintStringFormatRule) configError(msg string, ruleNum, option int) { - panic(fmt.Sprintf("invalid configuration for string-format: %s [argument %d, option %d]", msg, ruleNum, option)) +// configError reports an invalid config, this is specifically the user's fault. +func (*StringFormatRule) configError(msg string, ruleNum, option int) error { + return fmt.Errorf("invalid configuration for string-format: %s [argument %d, option %d]", msg, ruleNum, option) } -// Report a general config parsing failure, this may be the user's fault, but it isn't known for certain -func (lintStringFormatRule) parseError(msg string, ruleNum, option int) { - panic(fmt.Sprintf("failed to parse configuration for string-format: %s [argument %d, option %d]", msg, ruleNum, option)) +// parseError reports a general config parsing failure, this may be the user's fault, but it isn't known for certain. +func (*StringFormatRule) parseError(msg string, ruleNum, option int) error { + return fmt.Errorf("failed to parse configuration for string-format: %s [argument %d, option %d]", msg, ruleNum, option) } -// Report a general scope config parsing failure, this may be the user's fault, but it isn't known for certain -func (lintStringFormatRule) parseScopeError(msg string, ruleNum, option, scopeNum int) { - panic(fmt.Sprintf("failed to parse configuration for string-format: %s [argument %d, option %d, scope index %d]", msg, ruleNum, option, scopeNum)) +// parseScopeError reports a general scope config parsing failure, this may be the user's fault, +// but it isn't known for certain. +func (*StringFormatRule) parseScopeError(msg string, ruleNum, option, scopeNum int) error { + return fmt.Errorf("failed to parse configuration for string-format: %s [argument %d, option %d, scope index %d]", msg, ruleNum, option, scopeNum) } -// #endregion - -// #region Node traversal - -func (w lintStringFormatRule) Visit(node ast.Node) ast.Visitor { +func (w *lintStringFormatRule) Visit(node ast.Node) ast.Visitor { // First, check if node is a call expression call, ok := node.(*ast.CallExpr) if !ok { @@ -224,8 +206,8 @@ func (w lintStringFormatRule) Visit(node ast.Node) ast.Visitor { return w } -// Return the name of a call expression in the form of package.Func or Func -func (lintStringFormatRule) getCallName(call *ast.CallExpr) (callName string, ok bool) { +// getCallName returns the name of a call expression in the form of package.Func or Func. +func (*lintStringFormatRule) getCallName(call *ast.CallExpr) (callName string, ok bool) { if ident, ok := call.Fun.(*ast.Ident); ok { // Local function call return ident.Name, true @@ -247,11 +229,8 @@ func (lintStringFormatRule) getCallName(call *ast.CallExpr) (callName string, ok return "", false } -// #endregion - -// #region Linting logic - -// apply a single format rule to a call expression (should be done after verifying the that the call expression matches the rule's scope) +// apply a single format rule to a call expression +// (should be done after verifying the that the call expression matches the rule's scope). func (r *stringFormatSubrule) apply(call *ast.CallExpr, scope *stringFormatSubruleScope) { if len(call.Args) <= scope.argument { return @@ -259,7 +238,7 @@ func (r *stringFormatSubrule) apply(call *ast.CallExpr, scope *stringFormatSubru arg := call.Args[scope.argument] var lit *ast.BasicLit - if len(scope.field) > 0 { + if scope.field != "" { // Try finding the scope's Field, treating arg as a composite literal composite, ok := arg.(*ast.CompositeLit) if !ok { @@ -289,6 +268,12 @@ func (r *stringFormatSubrule) apply(call *ast.CallExpr, scope *stringFormatSubru return } } + + // extra safety check + if lit == nil { + return + } + // Unquote the string literal before linting unquoted := lit.Value[1 : len(lit.Value)-1] if r.stringIsOK(unquoted) { @@ -310,7 +295,7 @@ func (r *stringFormatSubrule) stringIsOK(s string) bool { func (r *stringFormatSubrule) generateFailure(node ast.Node) { var failure string switch { - case len(r.errorMessage) > 0: + case r.errorMessage != "": failure = r.errorMessage case r.negated: failure = fmt.Sprintf("string literal matches user defined regex /%s/", r.regexp.String()) @@ -318,11 +303,9 @@ func (r *stringFormatSubrule) generateFailure(node ast.Node) { failure = fmt.Sprintf("string literal doesn't match user defined regex /%s/", r.regexp.String()) } - r.parent.onFailure(lint.Failure{ + r.onFailure(lint.Failure{ Confidence: 1, Failure: failure, Node: node, }) } - -// #endregion diff --git a/vendor/github.com/mgechev/revive/rule/string_of_int.go b/vendor/github.com/mgechev/revive/rule/string_of_int.go index 3bec1d6ac..839d0dfd5 100644 --- a/vendor/github.com/mgechev/revive/rule/string_of_int.go +++ b/vendor/github.com/mgechev/revive/rule/string_of_int.go @@ -7,7 +7,7 @@ import ( "github.com/mgechev/revive/lint" ) -// StringOfIntRule warns when logic expressions contains Boolean literals. +// StringOfIntRule warns when an integer is converted to a string using a string cast. type StringOfIntRule struct{} // Apply applies the rule to given file. diff --git a/vendor/github.com/mgechev/revive/rule/struct_tag.go b/vendor/github.com/mgechev/revive/rule/struct_tag.go index 4dd927827..c245f51fc 100644 --- a/vendor/github.com/mgechev/revive/rule/struct_tag.go +++ b/vendor/github.com/mgechev/revive/rule/struct_tag.go @@ -3,57 +3,147 @@ package rule import ( "fmt" "go/ast" + "slices" "strconv" "strings" - "sync" "github.com/fatih/structtag" + + "github.com/mgechev/revive/internal/astutils" "github.com/mgechev/revive/lint" ) // StructTagRule lints struct tags. type StructTagRule struct { - userDefined map[string][]string // map: key -> []option + userDefined map[tagKey][]string // map: key -> []option + omittedTags map[tagKey]struct{} // set of tags that must not be analyzed +} + +type tagKey string + +const ( + keyASN1 tagKey = "asn1" + keyBSON tagKey = "bson" + keyCbor tagKey = "cbor" + keyCodec tagKey = "codec" + keyDatastore tagKey = "datastore" + keyDefault tagKey = "default" + keyJSON tagKey = "json" + keyMapstructure tagKey = "mapstructure" + keyProperties tagKey = "properties" + keyProtobuf tagKey = "protobuf" + keyRequired tagKey = "required" + keySpanner tagKey = "spanner" + keyTOML tagKey = "toml" + keyURL tagKey = "url" + keyValidate tagKey = "validate" + keyXML tagKey = "xml" + keyYAML tagKey = "yaml" +) + +type tagChecker func(checkCtx *checkContext, tag *structtag.Tag, field *ast.Field) (message string, succeeded bool) + +var tagCheckers = map[tagKey]tagChecker{ + keyASN1: checkASN1Tag, + keyBSON: checkBSONTag, + keyCbor: checkCborTag, + keyCodec: checkCodecTag, + keyDatastore: checkDatastoreTag, + keyDefault: checkDefaultTag, + keyJSON: checkJSONTag, + keyMapstructure: checkMapstructureTag, + keyProperties: checkPropertiesTag, + keyProtobuf: checkProtobufTag, + keyRequired: checkRequiredTag, + keySpanner: checkSpannerTag, + keyTOML: checkTOMLTag, + keyURL: checkURLTag, + keyValidate: checkValidateTag, + keyXML: checkXMLTag, + keyYAML: checkYAMLTag, +} + +type checkContext struct { + userDefined map[tagKey][]string // map: key -> []option + usedTagNbr map[int]bool // list of used tag numbers + usedTagName map[string]bool // list of used tag keys + commonOptions map[string]bool // list of options defined for all fields + isAtLeastGo124 bool +} + +func (checkCtx *checkContext) isUserDefined(key tagKey, opt string) bool { + if checkCtx.userDefined == nil { + return false + } + + options := checkCtx.userDefined[key] + return slices.Contains(options, opt) +} + +func (checkCtx *checkContext) isCommonOption(opt string) bool { + if checkCtx.commonOptions == nil { + return false + } + + _, ok := checkCtx.commonOptions[opt] + return ok +} + +func (checkCtx *checkContext) addCommonOption(opt string) { + if checkCtx.commonOptions == nil { + checkCtx.commonOptions = map[string]bool{} + } - configureOnce sync.Once + checkCtx.commonOptions[opt] = true } -func (r *StructTagRule) configure(arguments lint.Arguments) { +// Configure validates the rule configuration, and configures the rule accordingly. +// +// Configuration implements the [lint.ConfigurableRule] interface. +func (r *StructTagRule) Configure(arguments lint.Arguments) error { if len(arguments) == 0 { - return + return nil } - checkNumberOfArguments(1, arguments, r.Name()) - r.userDefined = make(map[string][]string, len(arguments)) + r.userDefined = map[tagKey][]string{} + r.omittedTags = map[tagKey]struct{}{} for _, arg := range arguments { item, ok := arg.(string) if !ok { - panic(fmt.Sprintf("Invalid argument to the %s rule. Expecting a string, got %v (of type %T)", r.Name(), arg, arg)) + return fmt.Errorf("invalid argument to the %s rule. Expecting a string, got %v (of type %T)", r.Name(), arg, arg) } + parts := strings.Split(item, ",") - if len(parts) < 2 { - panic(fmt.Sprintf("Invalid argument to the %s rule. Expecting a string of the form key[,option]+, got %s", r.Name(), item)) + keyStr := strings.TrimSpace(parts[0]) + keyStr, isOmitted := strings.CutPrefix(keyStr, "!") + key := tagKey(keyStr) + if isOmitted { + r.omittedTags[key] = struct{}{} + continue } - key := strings.TrimSpace(parts[0]) + for i := 1; i < len(parts); i++ { option := strings.TrimSpace(parts[i]) r.userDefined[key] = append(r.userDefined[key], option) } } + + return nil } // Apply applies the rule to given file. -func (r *StructTagRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure { - r.configureOnce.Do(func() { r.configure(args) }) - +func (r *StructTagRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { var failures []lint.Failure onFailure := func(failure lint.Failure) { failures = append(failures, failure) } w := lintStructTagRule{ - onFailure: onFailure, - userDefined: r.userDefined, + onFailure: onFailure, + userDefined: r.userDefined, + omittedTags: r.omittedTags, + isAtLeastGo124: file.Pkg.IsAtLeastGoVersion(lint.Go124), + tagCheckers: tagCheckers, } ast.Walk(w, file.AST) @@ -67,25 +157,30 @@ func (*StructTagRule) Name() string { } type lintStructTagRule struct { - onFailure func(lint.Failure) - userDefined map[string][]string // map: key -> []option - usedTagNbr map[int]bool // list of used tag numbers - usedTagName map[string]bool // list of used tag keys + onFailure func(lint.Failure) + userDefined map[tagKey][]string // map: key -> []option + omittedTags map[tagKey]struct{} + isAtLeastGo124 bool + tagCheckers map[tagKey]tagChecker } func (w lintStructTagRule) Visit(node ast.Node) ast.Visitor { - switch n := node.(type) { - case *ast.StructType: + if n, ok := node.(*ast.StructType); ok { isEmptyStruct := n.Fields == nil || n.Fields.NumFields() < 1 if isEmptyStruct { return nil // skip empty structs } - w.usedTagNbr = map[int]bool{} - w.usedTagName = map[string]bool{} + checkCtx := &checkContext{ + userDefined: w.userDefined, + usedTagNbr: map[int]bool{}, + usedTagName: map[string]bool{}, + isAtLeastGo124: w.isAtLeastGo124, + } + for _, f := range n.Fields.List { if f.Tag != nil { - w.checkTaggedField(f) + w.checkTaggedField(checkCtx, f) } } } @@ -93,28 +188,85 @@ func (w lintStructTagRule) Visit(node ast.Node) ast.Visitor { return w } -const keyASN1 = "asn1" -const keyBSON = "bson" -const keyDefault = "default" -const keyJSON = "json" -const keyProtobuf = "protobuf" -const keyRequired = "required" -const keyXML = "xml" -const keyYAML = "yaml" +// checkTaggedField checks the tag of the given field. +// precondition: the field has a tag +func (w lintStructTagRule) checkTaggedField(checkCtx *checkContext, field *ast.Field) { + tags, err := structtag.Parse(strings.Trim(field.Tag.Value, "`")) + if err != nil || tags == nil { + w.addFailuref(field.Tag, "malformed tag") + return + } + + analyzedTags := map[tagKey]struct{}{} + for _, tag := range tags.Tags() { + _, mustOmit := w.omittedTags[tagKey(tag.Key)] + if mustOmit { + continue + } -func (w lintStructTagRule) checkTagNameIfNeed(tag *structtag.Tag) (string, bool) { + if msg, ok := w.checkTagNameIfNeed(checkCtx, tag); !ok { + w.addFailureWithTagKey(field.Tag, msg, tag.Key) + } + + if msg, ok := checkOptionsOnIgnoredField(tag); !ok { + w.addFailureWithTagKey(field.Tag, msg, tag.Key) + } + + key := tagKey(tag.Key) + checker, ok := w.tagCheckers[key] + if !ok { + continue // we don't have a checker for the tag + } + + msg, ok := checker(checkCtx, tag, field) + if !ok { + w.addFailureWithTagKey(field.Tag, msg, tag.Key) + } + + analyzedTags[key] = struct{}{} + } + + if w.shallWarnOnUnexportedField(field.Names, analyzedTags) { + w.addFailuref(field, "tag on not-exported field %s", field.Names[0].Name) + } +} + +// tagKeyToSpecialField maps tag keys to their "special" meaning struct fields. +var tagKeyToSpecialField = map[tagKey]string{ + "codec": structTagCodecSpecialField, +} + +func (lintStructTagRule) shallWarnOnUnexportedField(fieldNames []*ast.Ident, tags map[tagKey]struct{}) bool { + if len(fieldNames) != 1 { // only handle the case of single field name (99.999% of cases) + return false + } + + if fieldNames[0].IsExported() { + return false + } + + fieldNameStr := fieldNames[0].Name + + for key := range tags { + specialField, ok := tagKeyToSpecialField[key] + if ok && specialField == fieldNameStr { + return false + } + } + + return true +} + +func (w lintStructTagRule) checkTagNameIfNeed(checkCtx *checkContext, tag *structtag.Tag) (message string, succeeded bool) { isUnnamedTag := tag.Name == "" || tag.Name == "-" if isUnnamedTag { return "", true } - needsToCheckTagName := tag.Key == keyBSON || - tag.Key == keyJSON || - tag.Key == keyXML || - tag.Key == keyYAML || - tag.Key == keyProtobuf - - if !needsToCheckTagName { + key := tagKey(tag.Key) + switch key { + case keyBSON, keyCodec, keyJSON, keyProtobuf, keySpanner, keyXML, keyYAML: // keys that need to check for duplicated tags + default: return "", true } @@ -125,22 +277,23 @@ func (w lintStructTagRule) checkTagNameIfNeed(tag *structtag.Tag) (string, bool) // We concat the key and name as the mapping key here // to allow the same tag name in different tag type. - key := tag.Key + ":" + tagName - if _, ok := w.usedTagName[key]; ok { - return fmt.Sprintf("duplicate tag name: '%s'", tagName), false + mapKey := tag.Key + ":" + tagName + if _, ok := checkCtx.usedTagName[mapKey]; ok { + return fmt.Sprintf("duplicated tag name %q", tagName), false } - w.usedTagName[key] = true + checkCtx.usedTagName[mapKey] = true return "", true } func (lintStructTagRule) getTagName(tag *structtag.Tag) string { - switch tag.Key { + key := tagKey(tag.Key) + switch key { case keyProtobuf: for _, option := range tag.Options { - if strings.HasPrefix(option, "name=") { - return strings.TrimPrefix(option, "name=") + if tagKey, found := strings.CutPrefix(option, "name="); found { + return tagKey } } return "" // protobuf tag lacks 'name' option @@ -149,276 +302,759 @@ func (lintStructTagRule) getTagName(tag *structtag.Tag) string { } } -// checkTaggedField checks the tag of the given field. -// precondition: the field has a tag -func (w lintStructTagRule) checkTaggedField(f *ast.Field) { - if len(f.Names) > 0 && !f.Names[0].IsExported() { - w.addFailure(f, "tag on not-exported field "+f.Names[0].Name) +func checkASN1Tag(checkCtx *checkContext, tag *structtag.Tag, field *ast.Field) (message string, succeeded bool) { + fieldType := field.Type + checkList := slices.Concat(tag.Options, []string{tag.Name}) + for _, opt := range checkList { + switch opt { + case "application", "explicit", "generalized", "ia5", "omitempty", "optional", "set", "utf8": + // do nothing + default: + msg, ok := checkCompoundANS1Option(checkCtx, opt, fieldType) + if !ok { + return msg, false + } + } } - tags, err := structtag.Parse(strings.Trim(f.Tag.Value, "`")) - if err != nil || tags == nil { - w.addFailure(f.Tag, "malformed tag") - return - } + return "", true +} - for _, tag := range tags.Tags() { - if msg, ok := w.checkTagNameIfNeed(tag); !ok { - w.addFailure(f.Tag, msg) +func checkCompoundANS1Option(checkCtx *checkContext, opt string, fieldType ast.Expr) (message string, succeeded bool) { + key, value, _ := strings.Cut(opt, ":") + switch key { + case "tag": + number, err := strconv.Atoi(value) + if err != nil { + return fmt.Sprintf("tag must be a number but is %q", value), false } + if checkCtx.usedTagNbr[number] { + return fmt.Sprintf(msgDuplicatedTagNumber, number), false + } + checkCtx.usedTagNbr[number] = true + case "default": + if !typeValueMatch(fieldType, value) { + return msgTypeMismatch, false + } + default: + if !checkCtx.isUserDefined(keyASN1, opt) { + return fmt.Sprintf(msgUnknownOption, opt), false + } + } + return "", true +} - switch key := tag.Key; key { - case keyASN1: - msg, ok := w.checkASN1Tag(f.Type, tag) - if !ok { - w.addFailure(f.Tag, msg) - } - case keyBSON: - msg, ok := w.checkBSONTag(tag.Options) - if !ok { - w.addFailure(f.Tag, msg) - } - case keyDefault: - if !w.typeValueMatch(f.Type, tag.Name) { - w.addFailure(f.Tag, "field's type and default value's type mismatch") - } - case keyJSON: - msg, ok := w.checkJSONTag(tag.Name, tag.Options) - if !ok { - w.addFailure(f.Tag, msg) - } - case keyProtobuf: - msg, ok := w.checkProtobufTag(tag) - if !ok { - w.addFailure(f.Tag, msg) - } - case keyRequired: - if tag.Name != "true" && tag.Name != "false" { - w.addFailure(f.Tag, "required should be 'true' or 'false'") - } - case keyXML: - msg, ok := w.checkXMLTag(tag.Options) - if !ok { - w.addFailure(f.Tag, msg) - } - case keyYAML: - msg, ok := w.checkYAMLTag(tag.Options) - if !ok { - w.addFailure(f.Tag, msg) - } +func checkDatastoreTag(checkCtx *checkContext, tag *structtag.Tag, _ *ast.Field) (message string, succeeded bool) { + for _, opt := range tag.Options { + switch opt { + case "flatten", "noindex", "omitempty": default: - // unknown key + if checkCtx.isUserDefined(keyDatastore, opt) { + continue + } + return fmt.Sprintf(msgUnknownOption, opt), false } } + + return "", true } -func (w lintStructTagRule) checkASN1Tag(t ast.Expr, tag *structtag.Tag) (string, bool) { - checkList := append(tag.Options, tag.Name) - for _, opt := range checkList { - switch opt { - case "application", "explicit", "generalized", "ia5", "omitempty", "optional", "set", "utf8": +func checkDefaultTag(_ *checkContext, tag *structtag.Tag, field *ast.Field) (message string, succeeded bool) { + if !typeValueMatch(field.Type, tag.Name) { + return msgTypeMismatch, false + } - default: - if strings.HasPrefix(opt, "tag:") { - parts := strings.Split(opt, ":") - tagNumber := parts[1] - number, err := strconv.Atoi(tagNumber) - if err != nil { - return fmt.Sprintf("ASN1 tag must be a number, got '%s'", tagNumber), false - } - if w.usedTagNbr[number] { - return fmt.Sprintf("duplicated tag number %v", number), false - } - w.usedTagNbr[number] = true + return "", true +} +func checkBSONTag(checkCtx *checkContext, tag *structtag.Tag, _ *ast.Field) (message string, succeeded bool) { + for _, opt := range tag.Options { + switch opt { + case "inline", "minsize", "omitempty": + default: + if checkCtx.isUserDefined(keyBSON, opt) { continue } + return fmt.Sprintf(msgUnknownOption, opt), false + } + } + + return "", true +} - if strings.HasPrefix(opt, "default:") { - parts := strings.Split(opt, ":") - if len(parts) < 2 { - return "malformed default for ASN1 tag", false - } - if !w.typeValueMatch(t, parts[1]) { - return "field's type and default value's type mismatch", false - } +func checkCborTag(checkCtx *checkContext, tag *structtag.Tag, _ *ast.Field) (message string, succeeded bool) { + hasToArray := false + hasOmitEmptyOrZero := false + hasKeyAsInt := false - continue + for _, opt := range tag.Options { + switch opt { + case "omitempty", "omitzero": + hasOmitEmptyOrZero = true + case "toarray": + if tag.Name != "" { + return `tag name for option "toarray" should be empty`, false + } + hasToArray = true + case "keyasint": + intKey, err := strconv.Atoi(tag.Name) + if err != nil { + return `tag name for option "keyasint" should be an integer`, false } - if w.isUserDefined(keyASN1, opt) { - continue + _, ok := checkCtx.usedTagNbr[intKey] + if ok { + return fmt.Sprintf("duplicated integer key %d", intKey), false } - return fmt.Sprintf("unknown option '%s' in ASN1 tag", opt), false + checkCtx.usedTagNbr[intKey] = true + hasKeyAsInt = true + continue + + default: + if !checkCtx.isUserDefined(keyCbor, opt) { + return fmt.Sprintf(msgUnknownOption, opt), false + } + } + } + + // Check for duplicated tag names + if tag.Name != "" { + _, ok := checkCtx.usedTagName[tag.Name] + if ok { + return fmt.Sprintf("duplicated tag name %s", tag.Name), false } + checkCtx.usedTagName[tag.Name] = true + } + + // Check for integer tag names without keyasint option + if !hasKeyAsInt { + _, err := strconv.Atoi(tag.Name) + if err == nil { + return `integer tag names are only allowed in presence of "keyasint" option`, false + } + } + + if hasToArray && hasOmitEmptyOrZero { + return `options "omitempty" and "omitzero" are ignored in presence of "toarray" option`, false } return "", true } -func (w lintStructTagRule) checkBSONTag(options []string) (string, bool) { - for _, opt := range options { +const structTagCodecSpecialField = "_struct" + +func checkCodecTag(checkCtx *checkContext, tag *structtag.Tag, field *ast.Field) (message string, succeeded bool) { + fieldNames := field.Names + mustAddToCommonOptions := len(fieldNames) == 1 && fieldNames[0].Name == structTagCodecSpecialField // see https://github.com/mgechev/revive/issues/1477#issuecomment-3191493076 + for _, opt := range tag.Options { + if mustAddToCommonOptions { + checkCtx.addCommonOption(opt) + } else if checkCtx.isCommonOption(opt) { + return fmt.Sprintf("redundant option %q, already set for all fields", opt), false + } + switch opt { - case "inline", "minsize", "omitempty": + case "omitempty", "toarray", "int", "uint", "float", "-", "omitemptyarray": default: - if w.isUserDefined(keyBSON, opt) { + if checkCtx.isUserDefined(keyCodec, opt) { continue } - return fmt.Sprintf("unknown option '%s' in BSON tag", opt), false + return fmt.Sprintf(msgUnknownOption, opt), false } } return "", true } -func (w lintStructTagRule) checkJSONTag(name string, options []string) (string, bool) { - for _, opt := range options { +func checkJSONTag(checkCtx *checkContext, tag *structtag.Tag, _ *ast.Field) (message string, succeeded bool) { + for _, opt := range tag.Options { switch opt { case "omitempty", "string": case "": // special case for JSON key "-" - if name != "-" { - return "option can not be empty in JSON tag", false + if tag.Name != "-" { + return "option can not be empty", false + } + case "omitzero": + if checkCtx.isAtLeastGo124 { + continue } + return `prior Go 1.24, option "omitzero" is unsupported`, false default: - if w.isUserDefined(keyJSON, opt) { + if checkCtx.isUserDefined(keyJSON, opt) { continue } - return fmt.Sprintf("unknown option '%s' in JSON tag", opt), false + return fmt.Sprintf(msgUnknownOption, opt), false } } return "", true } -func (w lintStructTagRule) checkXMLTag(options []string) (string, bool) { - for _, opt := range options { +func checkMapstructureTag(checkCtx *checkContext, tag *structtag.Tag, _ *ast.Field) (message string, succeeded bool) { + for _, opt := range tag.Options { switch opt { - case "any", "attr", "cdata", "chardata", "comment", "innerxml", "omitempty", "typeattr": + case "omitempty", "reminder", "squash": default: - if w.isUserDefined(keyXML, opt) { + if checkCtx.isUserDefined(keyMapstructure, opt) { continue } - return fmt.Sprintf("unknown option '%s' in XML tag", opt), false + return fmt.Sprintf(msgUnknownOption, opt), false } } return "", true } -func (w lintStructTagRule) checkYAMLTag(options []string) (string, bool) { +func checkPropertiesTag(_ *checkContext, tag *structtag.Tag, field *ast.Field) (message string, succeeded bool) { + options := tag.Options + if len(options) == 0 { + return "", true + } + + seenOptions := map[string]bool{} + fieldType := field.Type for _, opt := range options { - switch opt { - case "flow", "inline", "omitempty": - default: - if w.isUserDefined(keyYAML, opt) { - continue - } - return fmt.Sprintf("unknown option '%s' in YAML tag", opt), false + msg, ok := fmt.Sprintf("unknown or malformed option %q", opt), false + if key, value, found := strings.Cut(opt, "="); found { + msg, ok = checkCompoundPropertiesOption(key, value, fieldType, seenOptions) + } + + if !ok { + return msg, false } } return "", true } -func (lintStructTagRule) typeValueMatch(t ast.Expr, val string) bool { - tID, ok := t.(*ast.Ident) - if !ok { - return true +func checkCompoundPropertiesOption(key, value string, fieldType ast.Expr, seenOptions map[string]bool) (message string, succeeded bool) { + if _, ok := seenOptions[key]; ok { + return fmt.Sprintf(msgDuplicatedOption, key), false } + seenOptions[key] = true - typeMatches := true - switch tID.Name { - case "bool": - typeMatches = val == "true" || val == "false" - case "float64": - _, err := strconv.ParseFloat(val, 64) - typeMatches = err == nil - case "int": - _, err := strconv.ParseInt(val, 10, 64) - typeMatches = err == nil - case "string": - case "nil": - default: - // unchecked type + if strings.TrimSpace(value) == "" { + return fmt.Sprintf("option %q not of the form %s=value", key, key), false } - return typeMatches + switch key { + case "default": + if !typeValueMatch(fieldType, value) { + return msgTypeMismatch, false + } + case "layout": + if astutils.GoFmt(fieldType) != "time.Time" { + return "layout option is only applicable to fields of type time.Time", false + } + } + + return "", true } -func (w lintStructTagRule) checkProtobufTag(tag *structtag.Tag) (string, bool) { +func checkProtobufTag(checkCtx *checkContext, tag *structtag.Tag, _ *ast.Field) (message string, succeeded bool) { // check name switch tag.Name { case "bytes", "fixed32", "fixed64", "group", "varint", "zigzag32", "zigzag64": // do nothing default: - return fmt.Sprintf("invalid protobuf tag name '%s'", tag.Name), false + return fmt.Sprintf("invalid tag name %q", tag.Name), false } - // check options + return checkProtobufOptions(checkCtx, tag.Options) +} + +func checkProtobufOptions(checkCtx *checkContext, options []string) (message string, succeeded bool) { seenOptions := map[string]bool{} - for _, opt := range tag.Options { + hasName := false + for _, opt := range options { + opt := strings.Split(opt, "=")[0] + if number, err := strconv.Atoi(opt); err == nil { - _, alreadySeen := w.usedTagNbr[number] + _, alreadySeen := checkCtx.usedTagNbr[number] if alreadySeen { - return fmt.Sprintf("duplicated tag number %v", number), false + return fmt.Sprintf(msgDuplicatedTagNumber, number), false } - w.usedTagNbr[number] = true + checkCtx.usedTagNbr[number] = true continue // option is an integer } - switch { - case opt == "opt" || opt == "proto3" || opt == "rep" || opt == "req": + switch opt { + case "json", "opt", "proto3", "rep", "req": // do nothing - case strings.Contains(opt, "="): - o := strings.Split(opt, "=")[0] - _, alreadySeen := seenOptions[o] - if alreadySeen { - return fmt.Sprintf("protobuf tag has duplicated option '%s'", o), false + case "name": + hasName = true + default: + if checkCtx.isUserDefined(keyProtobuf, opt) { + continue } - seenOptions[o] = true - continue + return fmt.Sprintf(msgUnknownOption, opt), false + } + + _, alreadySeen := seenOptions[opt] + if alreadySeen { + return fmt.Sprintf(msgDuplicatedOption, opt), false } + seenOptions[opt] = true } - _, hasName := seenOptions["name"] + if !hasName { - return "protobuf tag lacks mandatory option 'name'", false + return `mandatory option "name" not found`, false } - for k := range seenOptions { - switch k { - case "name", "json": - // do nothing + return "", true +} + +func checkRequiredTag(_ *checkContext, tag *structtag.Tag, _ *ast.Field) (message string, succeeded bool) { + switch tag.Name { + case "true", "false": + return "", true + default: + return `required should be "true" or "false"`, false + } +} + +func checkTOMLTag(checkCtx *checkContext, tag *structtag.Tag, _ *ast.Field) (message string, succeeded bool) { + for _, opt := range tag.Options { + switch opt { + case "omitempty": default: - if w.isUserDefined(keyProtobuf, k) { + if checkCtx.isUserDefined(keyTOML, opt) { continue } - return fmt.Sprintf("unknown option '%s' in protobuf tag", k), false + return fmt.Sprintf(msgUnknownOption, opt), false } } return "", true } -func (w lintStructTagRule) addFailure(n ast.Node, msg string) { +func checkURLTag(checkCtx *checkContext, tag *structtag.Tag, _ *ast.Field) (message string, succeeded bool) { + var delimiter string + for _, opt := range tag.Options { + switch opt { + case "int", "omitempty", "numbered", "brackets", + "unix", "unixmilli", "unixnano": // TODO : check that the field is of type time.Time + case "comma", "semicolon", "space": + if delimiter == "" { + delimiter = opt + continue + } + return fmt.Sprintf("can not set both %q and %q as delimiters", opt, delimiter), false + default: + if checkCtx.isUserDefined(keyURL, opt) { + continue + } + return fmt.Sprintf(msgUnknownOption, opt), false + } + } + + return "", true +} + +func checkValidateTag(checkCtx *checkContext, tag *structtag.Tag, _ *ast.Field) (message string, succeeded bool) { + previousOption := "" + seenKeysOption := false + options := append([]string{tag.Name}, tag.Options...) + for _, opt := range options { + switch opt { + case "keys": + if previousOption != "dive" { + return `option "keys" must follow a "dive" option`, false + } + seenKeysOption = true + case "endkeys": + if !seenKeysOption { + return `option "endkeys" without a previous "keys" option`, false + } + seenKeysOption = false + default: + parts := strings.Split(opt, "|") + errMsg, ok := checkValidateOptionsAlternatives(checkCtx, parts) + if !ok { + return errMsg, false + } + } + previousOption = opt + } + + return "", true +} + +func checkXMLTag(checkCtx *checkContext, tag *structtag.Tag, _ *ast.Field) (message string, succeeded bool) { + for _, opt := range tag.Options { + switch opt { + case "any", "attr", "cdata", "chardata", "comment", "innerxml", "omitempty", "typeattr": + default: + if checkCtx.isUserDefined(keyXML, opt) { + continue + } + return fmt.Sprintf(msgUnknownOption, opt), false + } + } + + return "", true +} + +func checkYAMLTag(checkCtx *checkContext, tag *structtag.Tag, _ *ast.Field) (message string, succeeded bool) { + for _, opt := range tag.Options { + switch opt { + case "flow", "inline", "omitempty": + default: + if checkCtx.isUserDefined(keyYAML, opt) { + continue + } + return fmt.Sprintf(msgUnknownOption, opt), false + } + } + + return "", true +} + +func checkSpannerTag(checkCtx *checkContext, tag *structtag.Tag, _ *ast.Field) (message string, succeeded bool) { + for _, opt := range tag.Options { + if !checkCtx.isUserDefined(keySpanner, opt) { + return fmt.Sprintf(msgUnknownOption, opt), false + } + } + + return "", true +} + +// checkOptionsOnIgnoredField checks if an ignored struct field (tag name "-") has any options specified. +// It returns a message and false if there are useless options present, or an empty message and true if valid. +func checkOptionsOnIgnoredField(tag *structtag.Tag) (message string, succeeded bool) { + if tag.Name != "-" { + return "", true + } + + switch len(tag.Options) { + case 0: + return "", true + case 1: + opt := strings.TrimSpace(tag.Options[0]) + if opt == "" { + return "", true // accept "-," as options + } + + return fmt.Sprintf("useless option %s for ignored field", opt), false + default: + return fmt.Sprintf("useless options %s for ignored field", strings.Join(tag.Options, ",")), false + } +} + +func checkValidateOptionsAlternatives(checkCtx *checkContext, alternatives []string) (message string, succeeded bool) { + for _, alternative := range alternatives { + alternative := strings.TrimSpace(alternative) + lhs, _, found := strings.Cut(alternative, "=") + if found { + _, ok := validateLHS[lhs] + if ok || checkCtx.isUserDefined(keyValidate, lhs) { + continue + } + return fmt.Sprintf(msgUnknownOption, lhs), false + } + + badOpt, ok := areValidateOpts(alternative) + if ok || checkCtx.isUserDefined(keyValidate, badOpt) { + continue + } + + return fmt.Sprintf(msgUnknownOption, badOpt), false + } + + return "", true +} + +func typeValueMatch(t ast.Expr, val string) bool { + tID, ok := t.(*ast.Ident) + if !ok { + return true + } + + typeMatches := true + switch tID.Name { + case "bool": + typeMatches = val == "true" || val == "false" + case "float64": + _, err := strconv.ParseFloat(val, 64) + typeMatches = err == nil + case "int": + _, err := strconv.ParseInt(val, 10, 64) + typeMatches = err == nil + default: // "string", "nil", ... + // unchecked type + } + + return typeMatches +} + +func (w lintStructTagRule) addFailureWithTagKey(n ast.Node, msg, tagKey string) { + w.addFailuref(n, "%s in %s tag", msg, tagKey) +} + +func (w lintStructTagRule) addFailuref(n ast.Node, msg string, args ...any) { w.onFailure(lint.Failure{ Node: n, - Failure: msg, + Failure: fmt.Sprintf(msg, args...), Confidence: 1, }) } -func (w lintStructTagRule) isUserDefined(key, opt string) bool { - if w.userDefined == nil { - return false - } - - options := w.userDefined[key] - for _, o := range options { - if opt == o { - return true +func areValidateOpts(opts string) (string, bool) { + for opt := range strings.SplitSeq(opts, "|") { + _, ok := validateSingleOptions[opt] + if !ok { + return opt, false } } - return false + + return "", true +} + +const ( + msgDuplicatedOption = "duplicated option %q" + msgDuplicatedTagNumber = "duplicated tag number %v" + msgUnknownOption = "unknown option %q" + msgTypeMismatch = "type mismatch between field type and default value type" +) + +var validateSingleOptions = map[string]struct{}{ + "alpha": {}, + "alphanum": {}, + "alphanumunicode": {}, + "alphaunicode": {}, + "ascii": {}, + "base32": {}, + "base64": {}, + "base64rawurl": {}, + "base64url": {}, + "bcp47_language_tag": {}, + "bic": {}, + "boolean": {}, + "btc_addr": {}, + "btc_addr_bech32": {}, + "cidr": {}, + "cidrv4": {}, + "cidrv6": {}, + "contains": {}, + "containsany": {}, + "containsrune": {}, + "credit_card": {}, + "cron": {}, + "cve": {}, + "datauri": {}, + "datetime": {}, + "dir": {}, + "dirpath": {}, + "dive": {}, + "dns_rfc1035_label": {}, + "e164": {}, + "ein": {}, + "email": {}, + "endsnotwith": {}, + "endswith": {}, + "eq": {}, + "eq_ignore_case": {}, + "eqcsfield": {}, + "eqfield": {}, + "eth_addr": {}, + "eth_addr_checksum": {}, + "excluded_if": {}, + "excluded_unless": {}, + "excluded_with": {}, + "excluded_with_all": {}, + "excluded_without": {}, + "excluded_without_all": {}, + "excludes": {}, + "excludesall": {}, + "excludesrune": {}, + "fieldcontains": {}, + "fieldexcludes": {}, + "file": {}, + "filepath": {}, + "fqdn": {}, + "gt": {}, + "gtcsfield": {}, + "gte": {}, + "gtecsfield": {}, + "gtefield": {}, + "gtfield": {}, + "hexadecimal": {}, + "hexcolor": {}, + "hostname": {}, + "hostname_port": {}, + "hostname_rfc1123": {}, + "hsl": {}, + "hsla": {}, + "html": {}, + "html_encoded": {}, + "http_url": {}, + "image": {}, + "ip": {}, + "ip4_addr": {}, + "ip6_addr": {}, + "ip_addr": {}, + "ipv4": {}, + "ipv6": {}, + "isbn": {}, + "isbn10": {}, + "isbn13": {}, + "isdefault": {}, + "iso3166_1_alpha2": {}, + "iso3166_1_alpha2_eu": {}, + "iso3166_1_alpha3": {}, + "iso3166_1_alpha3_eu": {}, + "iso3166_1_alpha_numeric": {}, + "iso3166_1_alpha_numeric_eu": {}, + "iso3166_2": {}, + "iso4217": {}, + "iso4217_numeric": {}, + "issn": {}, + "json": {}, + "jwt": {}, + "latitude": {}, + "len": {}, + "longitude": {}, + "lowercase": {}, + "lt": {}, + "ltcsfield": {}, + "lte": {}, + "ltecsfield": {}, + "ltefield": {}, + "ltfield": {}, + "luhn_checksum": {}, + "mac": {}, + "max": {}, + "md4": {}, + "md5": {}, + "min": {}, + "mongodb": {}, + "mongodb_connection_string": {}, + "multibyte": {}, + "ne": {}, + "ne_ignore_case": {}, + "necsfield": {}, + "nefield": {}, + "number": {}, + "numeric": {}, + "omitempty": {}, + "omitnil": {}, + "omitzero": {}, + "oneof": {}, + "oneofci": {}, + "port": {}, + "postcode_iso3166_alpha2": {}, + "postcode_iso3166_alpha2_field": {}, + "printascii": {}, + "required": {}, + "required_if": {}, + "required_unless": {}, + "required_with": {}, + "required_with_all": {}, + "required_without": {}, + "required_without_all": {}, + "rgb": {}, + "rgba": {}, + "ripemd128": {}, + "ripemd160": {}, + "semver": {}, + "sha256": {}, + "sha384": {}, + "sha512": {}, + "skip_unless": {}, + "spicedb": {}, + "ssn": {}, + "startsnotwith": {}, + "startswith": {}, + "tcp4_addr": {}, + "tcp6_addr": {}, + "tcp_addr": {}, + "tiger128": {}, + "tiger160": {}, + "tiger192": {}, + "timezone": {}, + "udp4_addr": {}, + "udp6_addr": {}, + "udp_addr": {}, + "ulid": {}, + "unique": {}, + "unix_addr": {}, + "uppercase": {}, + "uri": {}, + "url": {}, + "url_encoded": {}, + "urn_rfc2141": {}, + "uuid": {}, + "uuid3": {}, + "uuid3_rfc4122": {}, + "uuid4": {}, + "uuid4_rfc4122": {}, + "uuid5": {}, + "uuid5_rfc4122": {}, + "uuid_rfc4122": {}, + "validateFn": {}, +} + +// validateLHS are options that are used in expressions of the form: +// +//